[Adduser-devel] Bug#243929: adduser: Reserve specific UIDs for users that will be created at a later time

Christoph Biedl debian.packages.hhqj at manchmal.in-ulm.de
Sun May 17 18:19:39 UTC 2009


Hilko Bengen wrote...

> If the maintainers think that this feature might be useful, I promise
> to provide a patch.

As I was looking for a solution to have unified system ids and Hilko
was no longer interested in that topic I took the opportunity and
hacked some stuff together.  Attached you'll find a patch against
adduser 3.110 that adds a "UID_POOL" and "GID_POOL" option for a file
containing the pre- defined user or group name and an preferred id,
separated by a colon. Using one file for both user and group ids is
possible and probably a good idea.  The whole concept is disabled by
default.

While this works for me I am not very happy about it since it
completely ignores the barrier between "regular user" and "system
user".  Therefore it's the administrator's task to add useful values,
and there's no protection against the linear id search stealing ids
that are reserved in the pool.

To do:
* Documentation (surprise)
* A sample adduser-pool.conf
* Alter adduser.conf to add a number space for the pool, or
  at least suggest this.

Other ideas:
* This mechanism could be enhanced to pre-load the entire
  getpw information for an account to be created. Perhaps a cool idea
  but appearently there was no demand for it yet, and larger
  installations probably prefer $LDAP for that.
* While the functionality provided by adduser only applies to newly
  created users, we can expect an administrator might wish to renumber
  existing accounts.  We could provide a list of todos and caveats for
  this, but it will always remain incomplete and ugly.  The scripts I
  wrote for that task shall never see the light.

Thanks for your consideration.

    Christoph
-------------- next part --------------
diff --git a/AdduserCommon.pm b/AdduserCommon.pm
index 688a518..96bd64f 100644
--- a/AdduserCommon.pm
+++ b/AdduserCommon.pm
@@ -10,7 +10,7 @@ use vars qw(@EXPORT $VAR1);
 #                     Ian A. Murdock <imurdock at gnu.ai.mit.edu>
 #
 
- at EXPORT = qw(invalidate_nscd gtx dief warnf read_config get_users_groups get_group_members s_print s_printf systemcall);
+ at EXPORT = qw(invalidate_nscd gtx dief warnf read_config read_pool get_users_groups get_group_members s_print s_printf systemcall);
 
 sub invalidate_nscd {
     # Check if we need to do make -C /var/yp for NIS
@@ -107,6 +107,42 @@ sub read_config {
     close CONF || die "$!";
 }
 
+# read names and IDs from a pool file
+# parameters:
+#  -- filename of the pool file
+#  -- a hash for the pool data
+sub read_pool {
+    my ($pool_file, $poolref) = @_;
+    my ($name, $id);
+    my %ids = ();
+
+    if (! -f $pool_file) {
+	dief gtx("`%s' does not exist.\n"),$pool_file if $verbose;
+    }
+
+    open (POOL, $pool_file) || dief ("%s: `%s'\n",$pool_file,$!);
+    while (<POOL>) {
+	chomp;
+	next if /^#/ || /^\s*$/;
+
+	if ((($name, $id) = /^([_a-zA-Z0-9]+):(\d+)/) != 2) {
+	    warnf gtx("Couldn't parse `%s', line %d.\n"),$pool_file,$.;
+	    next;
+	}
+	if (defined($poolref->{$name})) {
+	    dief gtx("Duplicate name `%s' at `%s', line %d.\n"),$name,$pool_file,$.;
+	}
+	if (defined($ids{$id})) {
+	    dief gtx("Duplicate ID `%s' at `%s', line %d.\n"),$id,$pool_file,$.;
+	}
+
+	$poolref->{$name} = $id;
+    }
+
+    close POOL || die "$!";
+}
+
+
 # return a user's groups
 sub get_users_groups {
     my($user) = @_;
@@ -212,6 +248,8 @@ sub preseed_config {
   $configref->{"skel_ignore_regex"} = "dpkg-(old|new|dist)\$";
   $configref->{"extra_groups"} = "dialout cdrom floppy audio video plugdev users games";
   $configref->{"add_extra_groups"} = 0;
+  $configref->{"uid_pool"} = "";
+  $configref->{"gid_pool"} = "";
 
   foreach( @$conflistref ) {
       read_config($_,$configref);
diff --git a/adduser b/adduser
index ef569b8..1054bcd 100755
--- a/adduser
+++ b/adduser
@@ -104,6 +104,8 @@ my $first_uid = undef;
 my $last_uid = undef;
 my $dir_mode = undef;
 my $perm = undef;
+my $uid_pool = {};
+my $gid_pool = {};
 
 our @names;
 
@@ -216,6 +218,14 @@ $ENV{"DEBUG"}   = $verbose;
 # preseed configuration data and then read the config file
 preseed_config(\@defaults,\%config);
 
+# read the uid and gid pool
+if ($config{"uid_pool"}) {
+    read_pool ($config{"uid_pool"}, $uid_pool);
+}
+if ($config{"gid_pool"}) {
+    read_pool ($config{"gid_pool"}, $gid_pool);
+}
+
 &checkname($new_name) if defined $new_name;
 $SIG{'INT'} = $SIG{'QUIT'} = $SIG{'HUP'} = 'handler';
 
@@ -274,7 +284,8 @@ if ($action eq "addsysgroup") {
 
     if (!defined($new_gid)) {
         $new_gid = &first_avail_gid($config{"first_system_gid"},
-				   $config{"last_system_gid"});
+				   $config{"last_system_gid"},
+				   $gid_pool->{$new_name});
         if ($new_gid == -1) {
 	    print STDERR "$0: ";
 	    printf STDERR gtx("No GID is available in the range %d-%d (FIRST_SYS_GID - LAST_SYS_GID).\n"),$config{"first_system_gid"},$config{"last_system_gid"};
@@ -303,7 +314,8 @@ if ($action eq "addgroup") {
 	if (defined($new_gid) && defined(getgrgid($new_gid)));
     if (!defined($new_gid)) {
         $new_gid = &first_avail_gid($config{"first_gid"},
-				   $config{"last_gid"});
+				   $config{"last_gid"},
+				   $gid_pool->{$new_name});
 
         if ($new_gid == -1) {
 	    print STDERR "$0: ";
@@ -374,19 +386,22 @@ if ($action eq "addsysuser") {
 
     if (!defined($new_uid) && $make_group_also) {
 	$new_uid = &first_avail_uid($config{"first_system_uid"},
-				   $config{"last_system_uid"});
+				   $config{"last_system_uid"},
+				   $uid_pool->{$new_name});
         if ($new_uid == -1) {
 	    print STDERR "$0: ";
 	    printf STDERR gtx("No UID/GID pair is available in the range %d-%d (FIRST_SYS_UID - LAST_SYS_UID).\n"),$config{"first_system_uid"},$config{"last_system_uid"};
             dief (gtx("The user `%s' was not created.\n"),$new_name);
         }
         $new_gid = &first_avail_gid($config{"first_system_gid"},
-	                            $config{"last_system_gid"});
+	                            $config{"last_system_gid"},
+				    $gid_pool->{$new_name});
 	$ingroup_name = $new_name;
     }
     elsif (!defined($new_uid) && !$make_group_also) {
 	$new_uid = &first_avail_uid($config{"first_system_uid"},
-				   $config{"last_system_uid"});
+				   $config{"last_system_uid"},
+				   $uid_pool->{$new_name});
         if ($new_uid == -1) {
 	    print STDERR "$0: ";
 	    printf STDERR gtx("No UID is available in the range %d-%d (FIRST_SYS_UID - LAST_SYS_UID).\n"),$config{"first_system_uid"},$config{"last_system_uid"};
@@ -465,7 +480,8 @@ if ($action eq "adduser") {
 
     if (!defined($new_uid) && $make_group_also) {
 	$new_uid = &first_avail_uid($first_uid,
-				   $last_uid);
+				   $last_uid,
+				   $uid_pool->{$new_name});
 				
         if ($new_uid == -1) {
 	    print STDERR "$0: ";
@@ -473,12 +489,14 @@ if ($action eq "adduser") {
 	    dief (gtx("The user `%s' was not created.\n"),$new_name);
         }
 	$new_gid = &first_avail_gid($config{"first_gid"}, 
-	                            $config{"last_gid"});
+	                            $config{"last_gid"},
+				    $gid_pool->{$new_name});
 	$ingroup_name = $new_name;
     }
     elsif (!defined($new_uid) && !$make_group_also) {
 	$new_uid = &first_avail_uid($first_uid,
-				   $last_uid);
+				   $last_uid,
+				   $uid_pool->{$new_name});
 	if ($new_uid == -1) {
 	    print STDERR "$0: ";
 	    printf STDERR gtx("No UID is available in the range %d-%d (FIRST_UID - LAST_UID).\n"),$config{"first_uid"},$config{"last_uid"};
@@ -874,11 +892,16 @@ option to relax this check or reconfigure NAME_REGEX.\n"), $0);
 # first_avail_uid: return the first available uid in given range
 # parameters:
 #   min, max: the range
+#   pool_id: user id suggested from pool
 # return values:
 #   -1 if no free uid is available
 #  otherwise the choosen uid
 sub first_avail_uid {
-    my ($min, $max) = @_;
+    my ($min, $max, $pool_id) = @_;
+    if (defined ($pool_id)) {
+       return $pool_id if (!defined(getpwuid($pool_id)));
+       return -1;
+    }
     printf (gtx("Selecting UID from range %d to %d ...\n"),$min,$max) if ($verbose > 1);
 
     my $t = $min;
@@ -892,11 +915,16 @@ sub first_avail_uid {
 # first_avail_gid: return the first available gid in given range
 # parameters:
 #   min, max: the range
+#   pool_id: group id suggested from pool
 # return values:
 #   -1 if no free gid is available
 #   otherwise the choosen gid
 sub first_avail_gid {
-    my ($min, $max) = @_;
+    my ($min, $max, $pool_id) = @_;
+    if (defined ($pool_id)) {
+       return $pool_id if (!defined(getgrgid($pool_id)));
+       return -1;
+    }
     printf (gtx("Selecting GID from range %d to %d ...\n"),$min,$max) if ($verbose > 1);
 
     my $t = $min;
diff --git a/adduser.conf b/adduser.conf
index f80ecbb..748c586 100644
--- a/adduser.conf
+++ b/adduser.conf
@@ -83,3 +83,6 @@ SKEL_IGNORE_REGEX="dpkg-(old|new|dist|save)"
 
 # check user and group names also against this regular expression.
 #NAME_REGEX="^[a-z][-a-z0-9]*\$"
+
+#UID_POOL=/etc/adduser-pool.conf
+#GID_POOL=/etc/adduser-pool.conf
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 197 bytes
Desc: Digital signature
URL: <http://lists.alioth.debian.org/pipermail/adduser-devel/attachments/20090517/66de07c0/attachment.pgp>


More information about the Adduser-devel mailing list