home *** CD-ROM | disk | FTP | other *** search
/ PC World 2000 February / PCWorld_2000-02_cd.bin / live / usr / sbin / adduser < prev    next >
Text File  |  1998-07-27  |  21KB  |  691 lines

  1. #!/usr/bin/perl -w
  2. #
  3. # adduser 3.8
  4. #
  5. # adduser: a utility to add users to the system
  6. # addgroup: a utility to add groups to the system
  7.  
  8. # Copyright (C) 1997 Guy Maor <maor@debian.org>
  9. # Copyright (C) 1995 Ted Hajek <tedhajek@boombox.micro.umn.edu>
  10. #                     Ian A. Murdock <imurdock@gnu.ai.mit.edu>
  11. # General scheme of the program adapted by the original debian 'adduser'
  12. #  program by Ian A. Murdock <imurdock@gnu.ai.mit.edu>.
  13. #
  14. #    This program is free software; you can redistribute it and/or modify
  15. #    it under the terms of the GNU General Public License as published by
  16. #    the Free Software Foundation; either version 2 of the License, or
  17. #    (at your option) any later version.
  18. #
  19. #    This program is distributed in the hope that it will be useful,
  20. #    but WITHOUT ANY WARRANTY; without even the implied warranty of
  21. #    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  22. #    GNU General Public License for more details.
  23. #
  24. #    You should have received a copy of the GNU General Public License
  25. #    along with this program; if not, write to the Free Software
  26. #    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  27. #
  28. #
  29. ####################
  30. # the program can be called as:
  31. #
  32. #  adduser [--home DIR] [--uid ID] [--ingroup GROUP | --gid ID]
  33. #  [--disabled-password] [--gecos GECOS] user
  34. #      add a normal user to the system
  35. #      example: adduser fred
  36. #      $action = "adduser"
  37. #
  38. #  adduser --group [--gid ID] group
  39. #  addgroup [--gid ID] group
  40. #      add a system group
  41. #      example: addgroup --quiet www-data
  42. #      $action = "addgroup"
  43. #
  44. #  adduser --system [--home DIR] [--uid ID] [--group | --ingroup GROUP
  45. #  | --gid ID] [--disabled-password] [--gecos GECOS] user
  46. #      add a system user.  Create a like-named, like-id'd group with
  47. #      --group, add to an existing group with --ingroup or --gid.  Add
  48. #      to "nogroup" with neither.
  49. #      example: adduser --system --home /home/gopher-data --group gopher
  50. #      $action = "addsysuser"
  51. #
  52. #  adduser user group
  53. #      add the existing user to an existing group.
  54. #      $action = "addusertogroup"
  55. #
  56. #  all commands take the following options:
  57. #      --quiet          don't give progress information on STDOUT
  58. #      --force-badname  disable checking of names for funny characters
  59. #      --help           usage message
  60. #      --version        version number and copyright
  61. #      --conf FILE      use FILE instead of /etc/adduser.conf
  62. ############
  63.  
  64. $verbose = 1;            # should we be verbose?
  65. $allow_badname = 0;        # should we allow bad names?
  66. $ask_passwd = 1;        # ask for a passwd?
  67.  
  68. $defaults = "/etc/adduser.conf";
  69. $nogroup_id = getgrnam("nogroup") || 65534;
  70. $0 =~ s+.*/++; 
  71.  
  72. $config{"dshell"} = "/bin/bash";
  73. $config{"first_system_uid"} = 100;
  74. $config{"last_system_uid"} = 999;
  75. $config{"first_uid"} = 1000;
  76. $config{"last_uid"} = 29999;
  77. $config{"dhome"} = "/home";
  78. $config{"skel"} = "/etc/skel";
  79. $config{"usergroups"} = "yes";
  80. $config{"users_gid"} = "100";
  81. $config{"grouphomes"} = "no";
  82. $config{"letterhomes"} = "no";
  83. $config{"quotauser"} = "";
  84.  
  85. $action = $0 eq "addgroup" ? "addgroup" : "adduser";
  86.  
  87. while ($arg = shift(@ARGV)) {
  88.     die "$0: No options allowed after names.\n" 
  89.     if ($names[0] && $arg =~ /^--/);
  90.     if ($arg eq "--quiet") {
  91.     $verbose = 0;
  92.     } elsif ($arg eq "--force-badname") {
  93.     $allow_badname = 1;
  94.     } elsif ($arg eq "--help") {
  95.     &usage();
  96.     exit 0;
  97.     } elsif ($arg eq "--version") {
  98.     &version();
  99.     exit 0;
  100.     } elsif ($arg eq "--system") {
  101.     $action = "addsysuser";
  102.     } elsif ($arg eq "--group") {
  103.     $found_group_opt = 1;
  104.     } elsif ($arg eq "--ingroup") {
  105.     die "$0: --ingroup requires an argument.\n"
  106.         if (!($ingroup_name = shift(@ARGV)));
  107.     } elsif ($arg eq "--home") {
  108.     die "$0: --home requires an argument.\n"
  109.         if (!($special_home = shift(@ARGV)));
  110.     print "$0: Warning: The home dir you specified already exists.\n"
  111.         if (-d $special_home && $verbose);
  112.     die "$0: The home dir must be an absolute path.\n"
  113.         if ($special_home !~ m+^/+ );
  114.     } elsif ($arg eq "--gecos") {
  115.     $new_gecos = shift(@ARGV);
  116.     } elsif ($arg eq "--disabled-password") {
  117.     $ask_passwd = 0;
  118.     } elsif ($arg eq "--uid") {
  119.     die "$0: --uid requires a numeric argument.\n"
  120.         if (!($new_uid = shift(@ARGV)) || $new_uid !~ /^\d+$/);
  121.     } elsif ($arg eq "--gid") {
  122.     die "$0: --gid requires a numeric argument.\n"
  123.         if (!($new_gid = shift(@ARGV)) || $new_gid !~ /^\d+$/);
  124.     } elsif ($arg eq "--conf") {
  125.     die "$0: --conf requires an argument.\n"
  126.         if (!($defaults = shift(@ARGV)));
  127.     die "$0: `$defaults' doesn't exist.\n"
  128.         if (! -f $defaults);
  129.     } elsif ($arg eq "--debug") {
  130.     $debugging = 1;
  131.     } elsif ($arg =~ /^--/) {    # bad argument!
  132.     die "$0: Unknown argument `$arg'.\n";
  133.     } else {            # it's a username
  134.     push (@names, $arg);
  135.     }
  136. }
  137.  
  138. die "$0: Only root may add a user or group to the system.\n" if ($> != 0);
  139.  
  140. die "$0: I need a name to add.\n" if (@names == 0);
  141. die "$0: No more than two names.\n" if (@names > 2);
  142. if (@names == 2) {    # must be addusertogroup
  143.     die "$0: Specify only one name in this mode.\n"
  144.     if ($action eq "addsysuser" || $found_group_opt);
  145.     $action = "addusertogroup";
  146.     $existing_user = shift (@names);
  147.     $existing_group = shift (@names);
  148. }
  149. else {
  150.     $new_name = shift (@names);
  151. }
  152.  
  153. if ($found_group_opt) {
  154.     if ($action eq "addsysuser") {
  155.     $make_group_also = 1;
  156.     }
  157.     else {
  158.     $action = "addgroup";
  159.     }
  160. }
  161. die "$0: --group, --ingroup, and --gid options are mutually exclusive.\n" if
  162.     ($action ne "addgroup" &&
  163.      defined($found_group_opt) +defined($ingroup_name) +defined($new_gid) > 1);
  164.  
  165.  
  166. #####
  167. # OK, we've processed the arguments.  $action equals one of the following,
  168. # and the appropriate variables have been set:
  169. #
  170. # $action = "adduser"
  171. #    $new_name                - the name of the new user.
  172. #    $ingroup_name | $new_gid - the group to add the user to
  173. #    $special_home, $new_uid, $new_gecos - optional overrides
  174. # $action = "addgroup"
  175. #    $new_name                - the name of the new group
  176. #    $new_gid                 - optional override
  177. # $action = "addsysuser"
  178. #    $new_name                - the name of the new user
  179. #    $make_group_also | $ingroup_name | $new_gid | 0  - which group
  180. #    $special_home, $new_uid, $new_gecos - optional overrides
  181. # $action = "addusertogroup"
  182. #    $existing_user           - the user to be added
  183. #    $existing_group          - the group to add her to
  184. #####
  185.  
  186. &read_config($defaults);
  187. &checkname($new_name) if $new_name;
  188. $SIG{'INT'} = $SIG{'QUIT'} = $SIG{'HUP'} = 'handler';
  189.  
  190. ##############
  191. ## addgroup ##
  192. ##############
  193. if ($action eq "addgroup") {
  194.     die "$0: The group `$new_name' already exists.\n"
  195.     if (getgrnam($new_name));
  196.     die "$0: The GID `$new_gid' is already in use.\n"
  197.     if (defined($new_gid) && getgrgid($new_gid));
  198.     if (!defined($new_gid)) {
  199.         $new_gid = &first_avail_id($config{"first_system_uid"},
  200.                    $config{"last_system_uid"},
  201.                    &get_current_gids);
  202.     die "$0: No GID is available in the range ",
  203.     "$config{\"first_system_uid\"} - $config{\"last_system_uid\"}\n",
  204.     "(FIRST_SYS_UID - LAST_SYS_UID).  ",
  205.     "Group `$new_name' not created.\n" if ($new_gid == -1);
  206.     }
  207.  
  208.     print "Adding group $new_name ($new_gid)...\n" if $verbose;
  209.     &systemcall('groupadd', '-g', $new_gid, $new_name);
  210.     print "Done.\n" if $verbose;
  211.     exit 0;
  212. }
  213.  
  214.  
  215. ####################
  216. ## addusertogroup ##
  217. ####################
  218. elsif ($action eq "addusertogroup") {
  219.     die "$0: The user `$existing_user' doesn't exist.\n"
  220.     if (!getpwnam($existing_user));
  221.     die "$0: The group `$existing_group' doesn't exist.\n"
  222.     if (!getgrnam($existing_group));
  223.     if (&user_is_member($existing_user, $existing_group)) {
  224.     print "The user `$existing_user' is already a member of ",
  225.     "`$existing_group'.\n" if $verbose;
  226.     exit 0;            # not really an error
  227.     }
  228.  
  229.     print "Adding user $existing_user to group $existing_group...\n"
  230.     if $verbose;
  231.     &systemcall('usermod', '-G',
  232.         join(",", get_users_groups($existing_user), $existing_group), 
  233.         $existing_user);
  234.     print "Done.\n" if $verbose;
  235.     exit 0;
  236. }
  237.  
  238.  
  239. ################
  240. ## addsysuser ##
  241. ################
  242. elsif ($action eq "addsysuser") {
  243.     $new_gid = $nogroup_id
  244.     if (!$ingroup_name && !defined($new_gid) && !$make_group_also);
  245.     &check_user_group();
  246.     print "Adding system user $new_name...\n" if $verbose;
  247.  
  248.     if (!defined($new_uid) && $make_group_also) {
  249.     $new_uid = &first_avail_id($config{"first_system_uid"},
  250.                    $config{"last_system_uid"},
  251.                    &get_current_uids, &get_current_gids);
  252.     die "$0: No UID/GID pair is available in the range ",
  253.     "$config{\"first_system_uid\"} - $config{\"last_system_uid\"}\n",
  254.     "(FIRST_SYS_UID - LAST_SYS_UID).  ",
  255.     "User `$new_name' not created.\n" if ($new_uid == -1);
  256.     $new_gid = $new_uid;
  257.     $ingroup_name = $new_name;
  258.     }
  259.     elsif (!defined($new_uid) && !$make_group_also) {
  260.     $new_uid = &first_avail_id($config{"first_system_uid"},
  261.                    $config{"last_system_uid"},
  262.                    &get_current_uids);
  263.     die "$0: No UID is available in the range ",
  264.     "$config{\"first_system_uid\"} - $config{\"last_system_uid\"}\n",
  265.     "(FIRST_SYS_UID - LAST_SYS_UID).  ",
  266.     "User `$new_name' not created.\n" if ($new_uid == -1);
  267.     if (defined($new_gid)) { $ingroup_name = getgrgid($new_gid); }
  268.     elsif ($ingroup_name) { $new_gid = getgrnam($ingroup_name); }
  269.     else { die "Internal error"; }
  270.     }
  271.     else {
  272.     if (defined($new_gid)) { $ingroup_name = getgrgid($new_gid); }
  273.     elsif ($ingroup_name) { $new_gid = getgrnam($ingroup_name); }
  274.     elsif ($make_group_also){ $new_gid=$new_uid; $ingroup_name=$new_name; }
  275.     else { die "Internal error"; }
  276.     }
  277.     
  278.     if ($make_group_also) {
  279.     print "Adding new group $new_name ($new_gid).\n" if $verbose;
  280.     $undogroup = $new_name;
  281.     &systemcall('groupadd', '-g', $new_gid, $new_name);
  282.     }
  283.  
  284.     print "Adding new user $new_name ($new_uid) with group $ingroup_name.\n"
  285.     if $verbose;
  286.     $home_dir = $special_home || &homedir($new_name, $ingroup_name);
  287.     $undouser = $new_name;
  288.     &systemcall('useradd', '-d', $home_dir, '-g', $ingroup_name, '-s',
  289.         '/bin/false', '-u', $new_uid, $new_name);
  290.     &systemcall('chfn', '-f', $new_gecos, $new_name) if ($new_gecos);
  291.  
  292.     if (-d $home_dir) {
  293.     print "Home directory $home_dir already exists.\n" if $verbose;
  294.     } else {
  295.     print "Creating home directory $home_dir.\n" if $verbose;
  296.     $undohome = $home_dir;
  297.     &mktree($home_dir) || &cleanup("Couldn't create $home_dir: $!.\n");
  298.     chown($new_uid, $new_gid, $home_dir)
  299.         || &cleanup("chown $new_uid:$new_gid $home_dir: $!\n");
  300.     $dir_mode = $make_group_also ? 02755 : 0755;
  301.     chmod ($dir_mode, $home_dir) ||
  302.         &cleanup("chmod $dir_mode $home_dir: $!\n");
  303.     }
  304.  
  305.     exit 0;
  306. }
  307.  
  308.  
  309. #############
  310. ## adduser ##
  311. #############
  312. elsif ($action eq "adduser") {
  313.     if (!$ingroup_name && !defined($new_gid)) {
  314.     if ($config{"usergroups"} eq "yes") { $make_group_also = 1; }
  315.     else { $new_gid = $config{"users_gid"}; }
  316.     }
  317.     &check_user_group();
  318.     print "Adding user $new_name...\n" if $verbose;
  319.  
  320.     if (!defined($new_uid) && $make_group_also) {
  321.     $new_uid = &first_avail_id($config{"first_uid"},
  322.                    $config{"last_uid"},
  323.                    &get_current_uids, &get_current_gids);
  324.     die "$0: No UID/GID pair is available in the range ",
  325.     "$config{\"first_uid\"} - $config{\"last_uid\"}\n",
  326.     "(FIRST_UID - LAST_UID).  ",
  327.     "User `$new_name' not created.\n" if ($new_uid == -1);
  328.     $new_gid = $new_uid;
  329.     $ingroup_name = $new_name;
  330.     }
  331.     elsif (!defined($new_uid) && !$make_group_also) {
  332.     $new_uid = &first_avail_id($config{"first_uid"},
  333.                    $config{"last_uid"},
  334.                    &get_current_uids);
  335.     die "$0: No UID is available in the range ",
  336.     "$config{\"first_uid\"} - $config{\"last_uid\"}\n",
  337.     "(FIRST_UID - LAST_UID).  ",
  338.     "User `$new_name' not created.\n" if ($new_uid == -1);
  339.     if (defined($new_gid)) { $ingroup_name = getgrgid($new_gid); }
  340.     elsif ($ingroup_name) { $new_gid = getgrnam($ingroup_name); }
  341.     else { die "Internal error"; }
  342.     }
  343.     else {
  344.     if (defined($new_gid)) { $ingroup_name = getgrgid($new_gid); }
  345.     elsif ($ingroup_name) { $new_gid = getgrnam($ingroup_name); }
  346.     elsif ($make_group_also){ $new_gid=$new_uid; $ingroup_name=$new_name; }
  347.     else { die "Internal error"; }
  348.     }
  349.  
  350.     if ($make_group_also) {
  351.     print "Adding new group $new_name ($new_gid).\n" if $verbose;
  352.     $undogroup = $new_name;
  353.     &systemcall('groupadd', '-g', $new_gid, $new_name);
  354.     }
  355.  
  356.     print "Adding new user $new_name ($new_uid) with group $ingroup_name.\n"
  357.     if $verbose;
  358.     $home_dir = $special_home || &homedir($new_name, $ingroup_name);
  359.     $undouser = $new_name;
  360.     &systemcall('useradd', '-d', $home_dir, '-g', $ingroup_name, '-s',
  361.         $config{dshell}, '-u', $new_uid, $new_name);
  362.  
  363.     if (-d $home_dir) {
  364.     print "Home directory $home_dir already exists.  Not copying from",
  365.     " $config{skel}\n" if $verbose;
  366.     }
  367.     else {
  368.     print "Creating home directory $home_dir.\n" if $verbose;
  369.     $undohome = $home_dir;
  370.     &mktree($home_dir) || &cleanup("Couldn't create $home_dir: $!.\n");
  371.     chown($new_uid, $new_gid, $home_dir)
  372.         || &cleanup("chown $new_uid:$new_gid $home_dir: $!\n");
  373.     $dir_mode = $make_group_also ? 02755 : 0755;
  374.     chmod ($dir_mode, $home_dir) ||
  375.         &cleanup("chmod $dir_mode $home_dir: $!\n");
  376.  
  377.     if ($config{"skel"}) {
  378.         print "Copying files from $config{skel}\n" if $verbose;
  379.         open(FIND, "cd $config{skel}; find .  -print |")
  380.         || &cleanup("fork for find: $!\n");
  381.         while (<FIND>) {
  382.         chop;
  383.         next if ($_ eq ".");
  384.         ©_to_dir($config{"skel"}, $_, $home_dir, $new_uid,
  385.                  $new_gid, $make_group_also);
  386.         }
  387.     }
  388.     }
  389.  
  390.     if ($ask_passwd) {
  391.     &systemcall('passwd', $new_name);
  392.     }
  393.  
  394.     if ($new_gecos) {
  395.     &systemcall('chfn', '-f', $new_gecos, $new_name);
  396.     }
  397.     else {
  398.     for (;;) {
  399.         &systemcall('chfn', $new_name);
  400.         print "Is the information correct? [y/n] ";
  401.         chop ($answer=<STDIN>);
  402.         last if ($answer =~ /^y/i);
  403.     }
  404.     }
  405.  
  406.     if ($config{"quotauser"}) {
  407.     print "Setting quota from $config{quotauser}.\n";
  408.     &systemcall('edquota', '-p', $config{quotauser}, $new_name);
  409.     }
  410.  
  411.     &systemcall('/usr/local/sbin/adduser.local', $new_name, $new_uid,
  412.         $new_gid, $home_dir) if (-x "/usr/local/sbin/adduser.local");
  413.     
  414.     exit 0;
  415. }
  416.  
  417.  
  418. # calculate home directory
  419. sub homedir {
  420.     my $dir = $config{"dhome"};
  421.     $dir .= '/' . $_[1] if ($config{"grouphomes"} =~ /yes/i);
  422.     $dir .= '/' . substr($_[0],0,1) if ($config{"letterhomes"} =~ /yes/i);
  423.     $dir .= '/' . $_[0];
  424. }
  425.  
  426.  
  427. # create a directory and all leading directories
  428. sub mktree {
  429.     my($tree) = @_;
  430.     my($done, @path);
  431.     my $default_dir_mode = 0755;
  432.  
  433.     $tree =~ s:^/*(.*)/*$:$1:; # chop off leading & trailing slashes
  434.     @path = split(/\//, $tree);
  435.  
  436.     $done = "";
  437.     while (@path) {
  438.     $done .= '/' . shift(@path);
  439.     -d $done || mkdir($done, $default_dir_mode) || return 0;
  440.     }
  441.     1;
  442. }
  443.  
  444.  
  445. sub check_user_group() {
  446.     die "$0: The user `$new_name' already exists.\n" if (getpwnam($new_name));
  447.     die "$0: The UID `$new_uid' already exists.\n"
  448.     if (defined($new_uid) && getpwuid($new_uid));
  449.     if ($make_group_also) {
  450.     die "$0: The group `$new_name' already exists.\n"
  451.         if (getgrnam($new_name));
  452.     die "$0: The GID `$new_uid' already exists.\n"
  453.         if (defined($new_uid) && getgrgid($new_uid));
  454.     }
  455.     else {
  456.     die "$0: The group `$ingroup_name' doesn't exist.\n"
  457.         if ($ingroup_name && !getgrnam($ingroup_name));
  458.     die "$0: The GID `$new_gid' doesn't exist.\n"
  459.         if (defined($new_gid) && !getgrgid($new_gid));
  460.     }
  461. }
  462.  
  463.  
  464. # copy files, directories, symlinks    
  465. sub copy_to_dir {
  466.     my($fromdir, $file, $todir, $newu, $newg, $sgiddir) = @_;
  467.  
  468.     if (-l "$fromdir/$file") {
  469.     symlink(readlink("$fromdir/$file"), "$todir/$file")
  470.         || &cleanup("symlink: $!\n");
  471.     }
  472.     elsif (-f "$fromdir/$file") {
  473.     open (FILE, "$fromdir/$file") || &cleanup("open $fromdir/$file: $!");
  474.     open (NEWFILE, ">$todir/$file") || &cleanup("open >$todir/$file: $!");
  475.  
  476.     (print NEWFILE <FILE>) || &cleanup("print $todir/$file: $!");
  477.     close FILE;
  478.     close(NEWFILE)  || &cleanup("close $todir/$file ");
  479.  
  480.     }
  481.     elsif (-d "$fromdir/$file") {
  482.     mkdir("$todir/$file", 700) || &cleanup("mkdir: $!");
  483.     }
  484.     else {
  485.     &cleanup("Can't deal with $fromdir/$file.  "
  486.          ."Not a dir, file, or symlink.\n");
  487.     }
  488.     
  489.     chown($newu, $newg, "$todir/$file")
  490.     || &cleanup("chown $newu:$newg $todir/$file: $!\n");
  491.     $perm = (stat("$fromdir/$file"))[2] & 07777;
  492.     $perm |= 02000 if (-d "$fromdir/$file" && ($perm & 010) && $sgiddir);
  493.     chmod($perm, "$todir/$file") || &cleanup("chmod $todir/$file: $!\n");
  494. }
  495.        
  496.  
  497. # is name ok?
  498. sub checkname {
  499.     my ($name) = @_;
  500.     if ($allow_badname && $name !~ /^[A-Za-z_][-_A-Za-z0-9]*$/) {
  501.     print STDERR
  502. "$0: To avoid problems, the username should consist of a letter or
  503. underscore followed by letters, digits, underscores, and dashes.\n";
  504.     exit 1;
  505.     }
  506.     elsif ($name !~ /^[a-z][a-z0-9]*$/) {
  507.     if (!$allow_badname) {
  508.         print STDERR
  509. "$0: Please enter a username consisting of a lower case letter
  510. followed by lower case letters and numbers.  Use the `--force-badname'
  511. option to allow underscores, dashes, and uppercase.\n";
  512.         exit 1;
  513.     }
  514.     print "Allowing use of questionable username.\n" if ($verbose);
  515.     }
  516. }
  517.  
  518.  
  519. # return the smallest X such that
  520. # $min <= X <= $max, and X is not an element of @ids
  521. # or -1 if no such X
  522. sub first_avail_id {
  523.     my ($min, $max, @ids) = @_;
  524.     @ids = sort {$a <=> $b} @ids;
  525.     print "Selecting from $min $max (" . join(",",@ids) . ").\n" if $debugging;
  526.     
  527.     while ($min <= $max) {
  528.     return $min if ($min <  $ids[0] || @ids==0);
  529.     shift @ids  if ($min >  $ids[0]);
  530.     $min++      if ($min == $ids[0]);
  531.     }
  532.  
  533.     -1;                # nothing available
  534. }
  535.  
  536.  
  537. # return an array containing all the GIDs
  538. sub get_current_gids {
  539.     my(@gids, $gid);
  540.     setgrent;
  541.     push @gids, $gid while defined($gid = (getgrent)[2]);
  542.     endgrent;
  543.     @gids;
  544. }
  545.  
  546.  
  547. # return an array containing all the UIDs
  548. sub get_current_uids {
  549.     my(@uids, $uid);
  550.     setpwent;
  551.     push @uids, $uid while defined($uid = (getpwent)[2]);
  552.     endpwent;
  553.     @uids;
  554. }
  555.  
  556.  
  557. # return a user's groups
  558. sub get_users_groups {
  559.     my($user) = @_;
  560.     my($name,$members,@groups);
  561.     setgrent;
  562.     while (($name,$members) = (getgrent)[0,3]) {
  563.     for (split(/ /, $members)) {
  564.         if ($user eq $_) {
  565.         push @groups, $name;
  566.         last;
  567.         }
  568.     }
  569.     }
  570.     endgrent;
  571.     @groups;
  572. }
  573.  
  574.  
  575. # user is member of group?
  576. sub user_is_member {
  577.     my($user, $group) = @_;
  578.     for (split(/ /, (getgrnam($group))[3])) {
  579.     return 1 if ($user eq $_);
  580.     }
  581.     0;
  582. }
  583.  
  584.  
  585. # parse the configuration file
  586. sub read_config {
  587.     my ($conf_file) = @_;
  588.     my ($var, $lcvar, $val);
  589.  
  590.     if (! -f $conf_file) {
  591.     print "$0: $conf_file doesn't exist.  Using defaults.\n" if $verbose;
  592.     return;
  593.     }
  594.  
  595.     open (CONF, $conf_file) || die "$0: $conf_file: $!\n";
  596.     while (<CONF>) {
  597.     chomp;
  598.     next if /^#/ || /^\s*$/;
  599.  
  600.     if ((($var, $val) = /^\s*(\S+)\s*=\s*(.*)/) != 2) {
  601.         warn "$0: Couldn't parse $conf_file:$..\n";
  602.         next;
  603.     }
  604.     $lcvar = lc $var;
  605.     if (!defined($config{$lcvar})) {
  606.         warn "$0: Unknown variable `$var' at $conf_file:$..\n";
  607.         next;
  608.     }
  609.         
  610.     $val =~ s/^"(.*)"$/$1/;
  611.     $val =~ s/^'(.*)'$/$1/;
  612.  
  613.     $config{$lcvar} = $val;
  614.     }
  615.  
  616.     close CONF || die "$!";
  617. }
  618.  
  619.  
  620. sub systemcall {
  621.     my $c = join(' ', @_);
  622.     print "$c\n" if $debugging;
  623.     system(@_) && &cleanup("$0: `$c' returned error code $?.  Aborting.\n");
  624. }
  625.  
  626.  
  627. sub cleanup {
  628.     print "@{_}Cleaning up.\n";
  629.     if ($undohome) {
  630.     print "Removing directory `$undohome'\n";
  631.     system('rm', '-rf', $undohome);
  632.     }
  633.     if ($undouser) {
  634.     print "Removing user `$undouser'.\n";
  635.     system('userdel', $undouser);
  636.     }
  637.     if ($undogroup) {
  638.     print "Removing group `$undogroup'.\n";
  639.     system('groupdel', $undogroup);
  640.     }
  641.     exit 1;
  642. }
  643.  
  644.  
  645. sub handler {
  646.     my($sig) = @_;
  647.     &cleanup("Caught a SIG$sig.\n");
  648. }
  649.     
  650.  
  651. sub version {
  652.     print "$0: add a user or group to the system.  Version 3.8
  653. Copyright (C) 1997 Guy Maor <maor\@debian.org>
  654. Copyright (C) 1995 Ian Murdock <imurdock\@gnu.ai.mit.edu>,
  655.                    Ted Hajek <tedhajek\@boombox.micro.umn.edu>, 
  656.     
  657. This program is free software; you can redistribute it and/or modify
  658. it under the terms of the GNU General Public License as published by
  659. the Free Software Foundation; either version 2 of the License, or (at
  660. your option) any later version.
  661.  
  662. This program is distributed in the hope that it will be useful, but
  663. WITHOUT ANY WARRANTY; without even the implied warranty of
  664. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  665. General Public License, /usr/doc/copyright/GPL, for more details.
  666. ";
  667. }
  668.  
  669.  
  670. sub usage {
  671.     print "adduser [--home DIR] [--uid ID] [--ingroup GROUP | --gid ID]
  672. [--disabled-password] [--gecos GECOS] user
  673.    Add a normal user
  674.  
  675. adduser --system [--home DIR] [--uid ID] [--group | --ingroup GROUP |
  676. --gid ID] [--disabled-password] [--gecos GECOS] user
  677.    Add a system user
  678.  
  679. adduser --group [--gid ID] group
  680. addgroup [--gid ID] group
  681.    Add a system group
  682.  
  683. adduser user group
  684.    Add an existing user to an existing group
  685.  
  686. Global configuration is in the file $defaults.
  687. Other options are [--quiet] [--force-badname] [--help] [--version] [--conf
  688. FILE].
  689. ";
  690. }
  691.