From c0bebf23d458aee4253179e4366216f4a4f5a03b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Lesimple?= Date: Tue, 13 Jul 2021 11:42:28 +0000 Subject: [PATCH] fix: accountCreate --uid-auto: rare case where a free UID couldn't be found This happened when a free UID was found, along with a corresponding GID, but the corresponding GID for the ttyrec group of the account was not available. Now this is checked directly in get_next_available_uid() --- bin/helper/osh-accountCreate | 2 +- lib/perl/OVH/Bastion/allowkeeper.inc | 32 +++++++++++++++++++++++++--- 2 files changed, 30 insertions(+), 4 deletions(-) diff --git a/bin/helper/osh-accountCreate b/bin/helper/osh-accountCreate index 6d41ca6..7bbc17b 100755 --- a/bin/helper/osh-accountCreate +++ b/bin/helper/osh-accountCreate @@ -120,7 +120,7 @@ if (defined $uid) { getgrgid($uid) and HEXIT('ERR_GID_COLLISION', msg => "This GID ($uid) is already taken"); } elsif ($uidAuto) { - $fnret = OVH::Bastion::get_next_available_uid(); + $fnret = OVH::Bastion::get_next_available_uid(available_gid => 1, available_gid_ttyrec => 1); $fnret or HEXIT($fnret); $uid = $fnret->value(); } diff --git a/lib/perl/OVH/Bastion/allowkeeper.inc b/lib/perl/OVH/Bastion/allowkeeper.inc index 78ea921..da59987 100644 --- a/lib/perl/OVH/Bastion/allowkeeper.inc +++ b/lib/perl/OVH/Bastion/allowkeeper.inc @@ -114,14 +114,40 @@ sub is_valid_uid { sub get_next_available_uid { my %params = @_; + # if true, also check for the availablility of the corresponding GID: + my $available_gid = $params{'available_gid'}; + + # if true, also check for the availability of the corresponding GID + the ttyrec offset: + my $available_gid_ttyrec = $params{'available_gid_ttyrec'}; + my $higher = OVH::Bastion::config('accountUidMax')->value(); my $lower = OVH::Bastion::config('accountUidMin')->value(); my $next = $higher; - while ($next >= $lower) { - last if not scalar(getpwuid($next)); + my $found = 0; + while (1) { + + # find the first available UID, starting from the upper ID allowed and decrementing + while ($next >= $lower) { + last if not scalar(getpwuid($next)); + $next--; + } + + # did we get out of the loop because we found a candidate, or because we're out of bounds? + last if $next < $lower; + + # if $available_gid, also check if the corresponding GID is available + # if $available_gid_ttyrec, also check if the corresponding GID + the ttyrec offset is available + if ( (!$available_gid || !scalar(getgrgid($next))) + && (!$available_gid_ttyrec || !scalar(getgrgid($next + OVH::Bastion::config('ttyrecGroupIdOffset')->value)))) + { + $found = 1; + last; + } + + # if we're here, at least one of the $available_gid* check failed, so continue looking $next--; } - return R('OK', value => $next) if not scalar(getpwuid($next)); + return R('OK', value => $next) if $found; return R('ERR_UID_COLLISION', msg => "No available UID in the allowed range"); }