home *** CD-ROM | disk | FTP | other *** search
/ Personal Computer World 2007 September / PCWSEP07.iso / Software / Linux / Linux Mint 3.0 Light / LinuxMint-3.0-Light.iso / casper / filesystem.squashfs / usr / sbin / adduser < prev    next >
Encoding:
Text File  |  2006-11-28  |  31.4 KB  |  984 lines

  1. #!/usr/bin/perl
  2.  
  3. # adduser: a utility to add users to the system
  4. # addgroup: a utility to add groups to the system
  5. my $version = "3.100";
  6.  
  7. # Copyright (C) 1997, 1998, 1999 Guy Maor <maor@debian.org>
  8. # Copyright (C) 1995 Ted Hajek <tedhajek@boombox.micro.umn.edu>
  9. #                     Ian A. Murdock <imurdock@gnu.ai.mit.edu>
  10. # Bugfixes and other improvements Roland Bauerschmidt <rb@debian.org>
  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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  27. #
  28. #
  29. ####################
  30. # See the usage subroutine for explanation about how the program can be called
  31. ####################
  32.  
  33. use warnings;
  34. use strict;
  35. use Debian::AdduserCommon;
  36. use Getopt::Long;
  37.  
  38. BEGIN {
  39.     eval 'use Locale::gettext';
  40.     if ($@) {
  41.     *gettext = sub { shift };
  42.     *textdomain = sub { "" };
  43.     *LC_MESSAGES = sub { 5 };
  44.     }
  45.     eval {
  46.     require POSIX;
  47.     import POSIX qw(setlocale);
  48.     };
  49.     if ($@) {
  50.     *setlocale = sub { return 1 };
  51.     }
  52.     eval {
  53.     require I18N::Langinfo;
  54.     import I18N::Langinfo qw(langinfo YESEXPR NOEXPR);
  55.     };
  56.     if ($@) {
  57.     *langinfo = sub { return shift; };
  58.     *YESEXPR  = sub { "^[yY]" };
  59.     *NOEXPR   = sub { "^[nN]" };
  60.     }
  61. }
  62.  
  63. setlocale(LC_MESSAGES, "");
  64. textdomain("adduser");
  65. my $yesexpr = langinfo(YESEXPR());
  66.  
  67. my %config;            # configuration hash
  68.  
  69. my @defaults = ("/etc/adduser.conf");
  70. my $nogroup_id = getgrnam("nogroup") || 65534;
  71. $0 =~ s+.*/++; 
  72.  
  73. our $verbose = 1;        # should we be verbose?
  74. my $allow_badname = 0;        # should we allow bad names?
  75. my $ask_passwd = 1;        # ask for a passwd? 
  76. my $disabled_login = 0;        # leave the new account disabled?
  77.  
  78. our $configfile = undef;
  79. our $found_group_opt = undef;
  80. our $found_sys_opt = undef;
  81. our $ingroup_name = undef;
  82. our $new_firstuid = undef;
  83. our $new_gecos = undef;
  84. our $new_gid = undef;
  85. our $new_lastuid = undef;
  86. our $new_uid = undef;
  87. our $no_create_home = undef;
  88. our $special_home = undef;
  89. our $special_shell = undef;
  90. our $add_extra_groups = 0;
  91.  
  92. # Global variables we need later
  93. my $existing_user = undef;
  94. my $existing_group = undef;
  95. my $new_name = undef;
  96. my $make_group_also = 0;
  97. my $home_dir = undef;
  98. my $undohome = undef;
  99. my $undouser = undef;
  100. my $undogroup = undef;
  101. my $shell = undef;
  102. my $first_uid = undef;
  103. my $last_uid = undef;
  104. my $dir_mode = undef;
  105. my $perm = undef;
  106.  
  107. our @names;
  108.  
  109. # Parse options, sanity checks
  110. unless ( GetOptions ("quiet|q" => sub { $verbose = 0 },
  111.             "force-badname" => \$allow_badname,
  112.         "help|h" => sub { &usage(); exit 0 },
  113.         "version|v" => sub { &version(); exit 0 },
  114.         "system" => \$found_sys_opt,
  115.         "group" => \$found_group_opt,
  116.         "ingroup=s" => \$ingroup_name,
  117.         "home=s" => \$special_home,
  118.         "gecos=s" => \$new_gecos,
  119.         "shell=s" => \$special_shell,
  120.         "disabled-password" => sub { $ask_passwd = 0 },
  121.         "disabled-login" => sub { $disabled_login = 1; $ask_passwd = 0 },
  122.         "uid=i" => \$new_uid,
  123.         "firstuid=i" => \$new_firstuid,
  124.         "lastuid=i" => \$new_lastuid,
  125.         "gid=i" => \$new_gid,
  126.         "conf=s" => \$configfile,
  127.         "no-create-home" => \$no_create_home,
  128.             "add_extra_groups" => \$add_extra_groups,
  129.         "debug" => sub { $verbose = 2 } ) ) {
  130.     &usage();
  131.     exit 1;
  132. }
  133.  
  134. # everyone can issue "--help" and "--version", but only root can go on
  135. dief (gtx("Only root may add a user or group to the system.\n")) if ($> != 0);
  136.  
  137. if( defined($configfile) ) { @defaults = ($configfile); }
  138.  
  139. # detect the right mode
  140. my $action = $0 eq "addgroup" ? "addgroup" : "adduser";
  141. if (defined($found_sys_opt)) {
  142.   $action = "addsysuser" if ($action eq "adduser");
  143.   $action = "addsysgroup" if ($action eq "addgroup");
  144. }
  145.  
  146.  
  147.  
  148. ############################
  149. # checks related to @names #
  150. ############################
  151.  
  152.  
  153. while (defined(my $arg = shift(@ARGV))) {
  154.   push (@names, $arg);
  155. }
  156.  
  157. if ( (! defined $names[0]) || length($names[0]) == 0 || @names > 2) {
  158.     dief (gtx("Only one or two names allowed.\n"));
  159. }
  160.         
  161.  
  162. if (@names == 2) {    # must be addusertogroup
  163.     dief (gtx("Specify only one name in this mode.\n"))
  164.     if ($action eq "addsysuser" || $found_group_opt);
  165.     $action = "addusertogroup";
  166.     $existing_user = shift (@names);
  167.     $existing_group = shift (@names);
  168. }
  169. else {
  170.     $new_name = shift (@names);
  171. }
  172.  
  173. ###################################
  174. # check for consistent parameters #
  175. ###################################
  176.  
  177. if ($action ne "addgroup" &&
  178.     defined($found_group_opt) +defined($ingroup_name) +defined($new_gid) > 1 ) {
  179.     dief (gtx("The --group, --ingroup, and --gid options are mutually exclusive.\n"));
  180. }
  181.  
  182.  
  183. if ((defined($special_home)) && ($special_home !~ m+^/+ )) {
  184.   dief (gtx("The home dir must be an absolute path.\n"));
  185. }
  186.        
  187. if (defined($special_home) && $verbose) {
  188.     print gtx("Warning: The home dir you specified already exists.\n")
  189.       if (!defined($no_create_home) && -d $special_home);
  190.     print gtx("Warning: The home dir you specified does not exist.\n")
  191.       if (defined($no_create_home) && ! -d $special_home);
  192. }
  193.  
  194.  
  195. if ($found_group_opt) {
  196.     if ($action eq "addsysuser") {
  197.     $make_group_also = 1;
  198.     }
  199.     elsif ($found_sys_opt) {
  200.     $action = "addsysgroup";
  201.     }
  202.     else {
  203.     $action = "addgroup";
  204.     }
  205. }
  206.  
  207.  
  208. $ENV{"VERBOSE"} = $verbose;
  209. $ENV{"DEBUG"}   = $verbose;
  210.  
  211.  
  212. # preseed configuration data and then read the config file
  213. preseed_config(\@defaults,\%config);
  214.  
  215. &checkname($new_name) if defined $new_name;
  216. $SIG{'INT'} = $SIG{'QUIT'} = $SIG{'HUP'} = 'handler';
  217.  
  218. #####
  219. # OK, we've processed the arguments.  $action equals one of the following,
  220. # and the appropriate variables have been set:
  221. #
  222. # $action = "adduser"
  223. #    $new_name                - the name of the new user.
  224. #    $ingroup_name | $new_gid - the group to add the user to
  225. #    $special_home, $new_uid, $new_gecos - optional overrides
  226. # $action = "addgroup"
  227. #    $new_name                - the name of the new group
  228. #    $new_gid                 - optional override
  229. # $action = "addsysgroup"
  230. #    $new_name                - the name of the new group
  231. #    $new_gid                 - optional override
  232. # $action = "addsysuser"
  233. #    $new_name                - the name of the new user
  234. #    $make_group_also | $ingroup_name | $new_gid | 0  - which group
  235. #    $special_home, $new_uid, $new_gecos - optional overrides
  236. # $action = "addusertogroup"
  237. #    $existing_user           - the user to be added
  238. #    $existing_group          - the group to add her to
  239. #####
  240.  
  241.  
  242. #################
  243. ## addsysgroup ##
  244. #################
  245. if ($action eq "addsysgroup") {
  246.     # Check if requested group already exists and we can exit safely
  247.     if (existing_group_ok($new_name, $new_gid) == 1) {
  248.     printf (gtx("The group `%s' already exists as a system group. Exiting.\n"), $new_name) if $verbose;
  249.     exit 0;
  250.     }
  251.     if (existing_group_ok($new_name, $new_gid) == 2) {
  252.     printf (gtx("The group `%s' already exists, but has a different GID. Exiting.\n"), $new_name) if $verbose;
  253.     exit 1;
  254.     }
  255.  
  256.     dief (gtx("The group `%s' already exists and is not a system group.\n"),$new_name)
  257.     if (defined getgrnam($new_name));
  258.     dief (gtx("The GID `%s' is already in use.\n"),$new_gid)
  259.     if (defined($new_gid) && defined(getgrgid($new_gid)));
  260.     if (!defined($new_gid)) {
  261.         $new_gid = &first_avail_gid($config{"first_system_gid"},
  262.                    $config{"last_system_gid"});
  263.  
  264.         if ($new_gid == -1) {
  265.         print STDERR "$0: ";
  266.         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"};
  267.             dief (gtx("The group `%s' was not created.\n"),$new_name);
  268.         }
  269.     }
  270.  
  271.     printf (gtx("Adding group `%s' (GID %d) ...\n"),$new_name,$new_gid) if $verbose;
  272.     &invalidate_nscd("group");
  273.     my $groupadd = &which('groupadd');
  274.     &systemcall($groupadd, '-g', $new_gid, $new_name);
  275.     &invalidate_nscd("group");
  276.     print (gtx("Done.\n")) if $verbose;
  277.     exit 0;
  278. }
  279.  
  280.  
  281. ##############
  282. ## addgroup ##
  283. ##############
  284. if ($action eq "addgroup") {
  285.     dief (gtx("The group `%s' already exists.\n"),$new_name)
  286.     if (defined getgrnam($new_name));
  287.     dief (gtx("The GID `%s' is already in use.\n"),$new_gid)
  288.     if (defined($new_gid) && defined(getgrgid($new_gid)));
  289.     if (!defined($new_gid)) {
  290.         $new_gid = &first_avail_gid($config{"first_gid"},
  291.                    $config{"last_gid"});
  292.  
  293.         if ($new_gid == -1) {
  294.         print STDERR "$0: ";
  295.         printf STDERR gtx("No GID is available in the range %d-%d (FIRST_GID - LAST_GID).\n"),$config{"first_gid"},$config{"last_gid"};
  296.             dief (gtx("The group `%s' was not created.\n"),$new_name);
  297.         }
  298.     }
  299.  
  300.     printf (gtx("Adding group `%s' (GID %d) ...\n"),$new_name,$new_gid) if $verbose;
  301.     &invalidate_nscd("group");
  302.     my $groupadd = &which('groupadd');
  303.     &systemcall($groupadd, '-g', $new_gid, $new_name);
  304.     &invalidate_nscd("group");
  305.     print (gtx("Done.\n")) if $verbose;
  306.     exit 0;
  307. }
  308.  
  309.  
  310. ####################
  311. ## addusertogroup ##
  312. ####################
  313. if ($action eq "addusertogroup") {
  314.     dief (gtx("The user `%s' does not exist.\n"),$existing_user)
  315.     if (!defined getpwnam($existing_user));
  316.     dief (gtx("The group `%s' does not exist.\n"),$existing_group)
  317.     if (!defined getgrnam($existing_group));
  318.     if (&user_is_member($existing_user, $existing_group)) {
  319.     printf gtx("The user `%s' is already a member of `%s'.\n"),
  320.                 $existing_user,$existing_group if $verbose;
  321.     exit 0;            # not really an error
  322.     }
  323.  
  324.     printf gtx("Adding user `%s' to group `%s' ...\n"),$existing_user,$existing_group
  325.     if $verbose;
  326.     &invalidate_nscd();
  327.     # FIXME - the next line has a race condition.
  328.     #&systemcall('usermod', '-G',
  329.         #join(",", get_users_groups($existing_user), $existing_group), 
  330.         #$existing_user);
  331.     my $gpasswd = &which('gpasswd');
  332.     &systemcall($gpasswd, '-M',
  333.         join(',', get_group_members($existing_group), $existing_user),
  334.         $existing_group);
  335.     #&systemcall('gpasswd', '-a',$existing_user,$existing_group);
  336.     &invalidate_nscd();
  337.     print (gtx("Done.\n")) if $verbose;
  338.     exit 0;
  339. }
  340.  
  341.  
  342. ################
  343. ## addsysuser ##
  344. ################
  345. if ($action eq "addsysuser") {
  346.     if (existing_user_ok($new_name, $new_uid) == 1) {
  347.     printf (gtx("The user `%s' already exists as a system user. Exiting.\n"), $new_name) if $verbose;
  348.     exit 0;
  349.     }
  350.     if (existing_user_ok($new_name, $new_uid) == 2) {
  351.     printf (gtx("The user `%s' already exists with a different UID. Exiting.\n"), $new_name) if $verbose;
  352.     exit 1;
  353.     }
  354.  
  355.     if (!$ingroup_name && !defined($new_gid) && !$make_group_also) {
  356.       $new_gid = $nogroup_id;
  357.     }
  358.     check_user_group(1);
  359.  
  360.     if (!defined($new_uid) && $make_group_also) {
  361.     $new_uid = &first_avail_uid($config{"first_system_uid"},
  362.                    $config{"last_system_uid"});
  363.         if ($new_uid == -1) {
  364.         print STDERR "$0: ";
  365.         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"};
  366.             dief (gtx("The user `%s' was not created.\n"),$new_name);
  367.         }
  368.         $new_gid = &first_avail_gid($config{"first_system_gid"},
  369.                                 $config{"last_system_gid"});
  370.     $ingroup_name = $new_name;
  371.     }
  372.     elsif (!defined($new_uid) && !$make_group_also) {
  373.     $new_uid = &first_avail_uid($config{"first_system_uid"},
  374.                    $config{"last_system_uid"});
  375.         if ($new_uid == -1) {
  376.         print STDERR "$0: ";
  377.         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"};
  378.         dief (gtx("The user `%s' was not created.\n"),$new_name);
  379.         }
  380.         if (defined($new_gid)) { $ingroup_name = getgrgid($new_gid); }
  381.     elsif ($ingroup_name) { $new_gid = getgrnam($ingroup_name); }
  382.     else { dief (gtx("Internal error")); }
  383.     }
  384.     else {
  385.     if (defined($new_gid)) { $ingroup_name = getgrgid($new_gid); }
  386.     elsif ($ingroup_name) { $new_gid = getgrnam($ingroup_name); }
  387.     elsif ($make_group_also){ $new_gid=$new_uid; $ingroup_name=$new_name; }
  388.     else { dief (gtx("Internal error")); }
  389.     }
  390.     printf (gtx("Adding system user `%s' (UID %d) ...\n"),$new_name,$new_uid) if $verbose;
  391.  
  392.     &invalidate_nscd();
  393.     # if we reach this point, and the group does already exist, we can use it.
  394.     if ($make_group_also && !getgrnam($new_name)) {
  395.     printf (gtx("Adding new group `%s' (GID %d) ...\n"),$new_name,$new_gid) if $verbose;
  396.     $undogroup = $new_name;
  397.        my $groupadd = &which('groupadd');
  398.     &systemcall($groupadd, '-g', $new_gid, $new_name);
  399.     &invalidate_nscd("group");
  400.     }
  401.  
  402.     printf gtx("Adding new user `%s' (UID %d) with group `%s' ...\n"),$new_name,$new_uid,$ingroup_name
  403.     if $verbose;
  404.     $home_dir = $special_home || &homedir($new_name, $ingroup_name);
  405.     $shell = $special_shell || '/bin/false';
  406.     $undouser = $new_name;
  407.     my $useradd = &which('useradd');
  408.     &systemcall($useradd, '-d', $home_dir, '-g', $ingroup_name, '-s',
  409.         $shell, '-u', $new_uid, $new_name);
  410.     my $chage = &which('chage');
  411.     print "$chage -M 99999 $new_name\n" if ($verbose > 1);
  412.     # do _not_ use systemcall() here, since systemcall() dies on
  413.     # non-zero exit code and we need to do special handling here!
  414.     if (system($chage, '-M', '99999', $new_name)) {
  415.     if( ($?>>8) ne 15 ) {
  416.         &cleanup(sprintf((gtx("`%s' returned error code %d. Exiting.\n")), "$chage -M 99999 $new_name", $?>>8))
  417.           if ($?>>8);
  418.         &cleanup(sprintf((gtx("`%s' exited from signal %d. Exiting.\n")), "$chage -M 99999 $new_name", $?&255));
  419.     } else {
  420.         printf (gtx("%s failed with return code 15, shadow not enabled, password aging cannot be set. Continuing.\n"), $chage);
  421.     }
  422.     }
  423.     &invalidate_nscd();
  424.  
  425.     if(defined($new_gecos)) {
  426.     &ch_gecos($new_gecos);
  427.     }
  428.  
  429.     create_homedir (0);
  430.  
  431.     exit 0;
  432. }
  433.  
  434.  
  435. #############
  436. ## adduser ##
  437. #############
  438. if ($action eq "adduser") {
  439.     if (!$ingroup_name && !defined($new_gid)) {
  440.     if ($config{"usergroups"} =~  /yes/i) { $make_group_also = 1; }
  441.     else { $new_gid = $config{"users_gid"}; }
  442.     }
  443.     check_user_group(0);
  444.     $first_uid = $new_firstuid || $config{"first_uid"};
  445.     $last_uid = $new_lastuid || $config{"last_uid"};
  446.     printf (gtx("Adding user `%s' ...\n"),$new_name) if $verbose;
  447.  
  448.     if (!defined($new_uid) && $make_group_also) {
  449.     $new_uid = &first_avail_uid($first_uid,
  450.                    $last_uid);
  451.                 
  452.         if ($new_uid == -1) {
  453.         print STDERR "$0: ";
  454.             printf STDERR gtx("No UID/GID pair is available in the range %d-%d (FIRST_UID - LAST_UID).\n"),$first_uid,$last_uid;
  455.         dief (gtx("The user `%s' was not created.\n"),$new_name);
  456.         }
  457.     $new_gid = &first_avail_gid($config{"first_gid"}, 
  458.                                 $config{"last_gid"});
  459.     $ingroup_name = $new_name;
  460.     }
  461.     elsif (!defined($new_uid) && !$make_group_also) {
  462.     $new_uid = &first_avail_uid($first_uid,
  463.                    $last_uid);
  464.     if ($new_uid == -1) {
  465.         print STDERR "$0: ";
  466.         printf STDERR gtx("No UID is available in the range %d-%d (FIRST_UID - LAST_UID).\n"),$config{"first_uid"},$config{"last_uid"};
  467.             dief (gtx("The user `%s' was not created.\n"),$new_name);
  468.         }
  469.     if (defined($new_gid)) { $ingroup_name = getgrgid($new_gid); }
  470.     elsif ($ingroup_name) { $new_gid = getgrnam($ingroup_name); }
  471.     else { dief (gtx("Internal error")); }
  472.     }
  473.     else {
  474.     if (defined($new_gid)) { $ingroup_name = getgrgid($new_gid); }
  475.     elsif ($ingroup_name) { $new_gid = getgrnam($ingroup_name); }
  476.     elsif ($make_group_also){ $new_gid=$new_uid; $ingroup_name=$new_name; }
  477.     else { dief (gtx("Internal error")); }
  478.     }
  479.  
  480.     &invalidate_nscd();
  481.     if ($make_group_also) {
  482.     printf (gtx("Adding new group `%s' (%d) ...\n"),$new_name,$new_gid) if $verbose;
  483.     $undogroup = $new_name;
  484.        my $groupadd = &which('groupadd');
  485.     &systemcall($groupadd, '-g', $new_gid, $new_name);
  486.     &invalidate_nscd();
  487.     }
  488.  
  489.     printf gtx("Adding new user `%s' (%d) with group `%s' ...\n"),$new_name,$new_uid,$ingroup_name
  490.     if $verbose;
  491.     $home_dir = $special_home || &homedir($new_name, $ingroup_name);
  492.     $shell = $special_shell || $config{"dshell"};
  493.     $undouser = $new_name;
  494.     my $useradd = &which('useradd');
  495.     &systemcall($useradd, '-d', $home_dir, '-g', $ingroup_name, '-s',
  496.         $shell, '-u', $new_uid, $new_name);
  497.     &invalidate_nscd();
  498.  
  499.     create_homedir (1); # copy skeleton data
  500.  
  501.     # useradd without -p has left the account disabled (password string is '!')
  502.     if ($ask_passwd) {
  503.     for (;;) {
  504.           my $passwd = &which('passwd');
  505.       # do _not_ use systemcall() here, since systemcall() dies on
  506.       # non-zero exit code and we need to do special handling here!
  507.           system($passwd, $new_name);
  508.       my $ok = $?>>8;
  509.       if ($ok != 0) {
  510.         my $noexpr = langinfo(NOEXPR());
  511.             my $answer;
  512.             # hm, error, should we break now?
  513.         print (gtx("Permission denied\n")) if ($ok == 1);
  514.         print (gtx("invalid combination of options\n")) if ($ok == 2);
  515.         print (gtx("unexpected failure, nothing done\n")) if ($ok == 3);
  516.         print (gtx("unexpected failure, passwd file missing\n")) if ($ok == 3);
  517.         print (gtx("passwd file busy, try again\n")) if ($ok == 4);
  518.         print (gtx("invalid argument to option\n")) if ($ok == 5);
  519.         
  520.         # Translators: [Y/n] has to be replaced by values defined in your
  521.         # locale.  You can see by running "locale noexpr" which regular
  522.         # expression will be checked to find positive answer.
  523.         print (gtx("Try again? [Y/n] "));
  524.         chop ($answer=<STDIN>);
  525.         last if ($answer =~ m/$noexpr/o);
  526.       }
  527.       else {
  528.         last; ## passwd ok
  529.       }
  530.     }
  531.     } else {
  532.     if(!$disabled_login) {
  533.            my $usermod = &which('usermod');
  534.         &systemcall($usermod, '-p', '*', $new_name);
  535.     }
  536.     }
  537.  
  538.     if (defined($new_gecos)) {
  539.     &ch_gecos($new_gecos);
  540.     }
  541.     else {
  542.     my $yesexpr = langinfo(YESEXPR());
  543.     for (;;) {
  544.            my $chfn = &which('chfn');
  545.         &systemcall($chfn, $new_name);
  546.         # Translators: [y/N] has to be replaced by values defined in your
  547.         # locale.  You can see by running "locale yesexpr" which regular
  548.         # expression will be checked to find positive answer.
  549.         print (gtx("Is the information correct? [y/N] "));
  550.         chop (my $answer=<STDIN>);
  551.         last if ($answer =~ m/$yesexpr/o);
  552.     }
  553.     }
  554.  
  555.     if ( ( $add_extra_groups || $config{"add_extra_groups"} ) && defined($config{"extra_groups"}) ) {
  556.         printf (gtx("Adding new user `%s' to extra groups ...\n"), $new_name);
  557.         foreach my $newgrp ( split ' ', $config{"extra_groups"} ) {
  558.             if (!defined getgrnam($newgrp)) {
  559.                 warnf (gtx("The group `%s' does not exist.\n"),$newgrp);
  560.                 next;
  561.             }
  562.             if (&user_is_member($new_name, $newgrp)) {
  563.                 printf gtx("The user `%s' is already a member of `%s'.\n"),
  564.                         $new_name,$newgrp if $verbose;
  565.                 next;
  566.  
  567.             }
  568.  
  569.             printf gtx("Adding user `%s' to group `%s' ...\n"),$new_name,$newgrp
  570.                 if $verbose;
  571.             &invalidate_nscd();
  572.             my $gpasswd = &which('gpasswd');
  573.             &systemcall($gpasswd, '-M',
  574.                         join(',', get_group_members($newgrp), $new_name),
  575.                         $newgrp);
  576.             &invalidate_nscd();
  577.         }
  578.     }
  579.  
  580.  
  581.     if ($config{"quotauser"}) {
  582.     printf (gtx("Setting quota for user `%s' to values of user `%s' ...\n"), $new_name, $config{quotauser});
  583.     my $edquota = &which('edquota');
  584.     &systemcall($edquota, '-p', $config{quotauser}, $new_name);
  585.     }
  586.  
  587.     &systemcall('/usr/local/sbin/adduser.local', $new_name, $new_uid,
  588.         $new_gid, $home_dir) if (-x "/usr/local/sbin/adduser.local");
  589.     
  590.     exit 0;
  591. }
  592.  
  593. #
  594. # we never go here
  595. #
  596.  
  597.  
  598. # calculate home directory
  599. sub homedir {
  600.     my $dir = $config{"dhome"};
  601.     $dir .= '/' . $_[1] if ($config{"grouphomes"} =~ /yes/i);
  602.     $dir .= '/' . substr($_[0],0,1) if ($config{"letterhomes"} =~ /yes/i);
  603.     $dir .= '/' . $_[0];
  604.     return $dir;
  605. }
  606.  
  607.  
  608. # create_homedir -- create the homedirectory
  609. # parameter 1: $copy_skeleton: 
  610. #       if 0  -> don't copy the skeleton data
  611. #       if 1  -> copy the files in /etc/skel to the newly created home directory
  612. sub create_homedir {
  613.   my ($copy_skeleton) = @_;
  614.  
  615.   if ($no_create_home) {
  616.       printf gtx("Not creating home directory `%s'.\n"), $home_dir if $verbose;
  617.   }
  618.   elsif (-e $home_dir) {
  619.       printf gtx("The home directory `%s' already exists.  Not copying from `%s'.\n"),
  620.       $home_dir,$config{skel} if $verbose && !$no_create_home;
  621.       my @homedir_stat = stat($home_dir);
  622.       my $home_uid = $homedir_stat[4];
  623.       my $home_gid = $homedir_stat[5];
  624.       if (($home_uid != $new_uid) || ($home_gid != $new_gid)) {
  625.           # post-etch, see #397916
  626.       # warnf gtx("Warning: The home directory `%s' does not belong to the user you are currently creating.\n"), $home_dir;
  627.           warnf gtx("Warning: that home directory does not belong to the user you are currently creating.\n");
  628.       }
  629.       undef @homedir_stat; undef $home_uid; undef $home_gid;
  630.   }
  631.   else {
  632.       printf gtx("Creating home directory `%s' ...\n"),$home_dir if $verbose;
  633.       $undohome = $home_dir;
  634.       &mktree($home_dir) || &cleanup(sprintf(gtx("Couldn't create home directory `%s': %s.\n"), $home_dir, $!));
  635.       chown($new_uid, $new_gid, $home_dir)
  636.       || &cleanup("chown $new_uid:$new_gid $home_dir: $!\n");
  637.       $dir_mode = get_dir_mode($make_group_also);
  638.       chmod ($dir_mode, $home_dir) ||
  639.       &cleanup("chmod $dir_mode $home_dir: $!\n");
  640.  
  641.       if ($config{"skel"} && $copy_skeleton) {
  642.       printf gtx("Copying files from `%s' ...\n"),$config{skel} if $verbose;
  643.       open(FIND, "cd $config{skel}; find .  -print |")
  644.           || &cleanup(sprintf(gtx("fork for `find' failed: %s\n"), $!));
  645.       while (<FIND>) {
  646.           chop;
  647.           next if ($_ eq ".");
  648.           next if ($_ =~ qr/$config{skel_ignore_regex}/ );
  649.           ©_to_dir($config{"skel"}, $_, $home_dir, $new_uid,
  650.                 $new_gid, ($config{"setgid_home"} =~ /yes/i));
  651.       }
  652.       }
  653.   }
  654. }
  655.  
  656. # create a directory and all parent directories
  657. # we don't care about the rights and so on
  658. sub mktree {
  659.     my($tree) = @_;
  660.     my($done, @path);
  661.     my $default_dir_mode = 0755;
  662.  
  663.     $tree =~ s:^/*(.*)/*$:$1:; # chop off leading & trailing slashes
  664.     @path = split(/\//, $tree);
  665.  
  666.     $done = "";
  667.     while (@path) {
  668.     $done .= '/' . shift(@path);
  669.     -d $done || mkdir($done, $default_dir_mode) || return 0;
  670.     }
  671.     return 1;
  672. }
  673.  
  674. # returns 0 if the the user doesn't exist or
  675. # returns 1 if the user already exists with the specified uid (or $new_uid wasn't specified)
  676. # returns 2 if the user already exists, but $new_uid doesn't matches its uid
  677. sub existing_user_ok {
  678.     my($new_name,$new_uid) = @_;
  679.     my ($dummy1,$dummy2,$uid);
  680.     if (($dummy1,$dummy2,$uid) = getpwnam($new_name)) {
  681.     if( defined($new_uid) && $uid == $new_uid ) {
  682.         return 1;
  683.     }
  684.     if (! defined($new_uid)) { 
  685.         return 1;
  686.     }
  687.     if( $uid >= $config{"first_system_uid"} &&
  688.         $uid <= $config{"last_system_uid" } ) {
  689.         return 2;
  690.     }
  691.     } else {
  692.     return 0;
  693.     }
  694. }
  695.  
  696. # returns 0 if the group doesn't exist or
  697. # returns 1 if the group already exists with the specified gid (or $new_gid wasn't specified)
  698. # returns 2 if the group already exists, but $new_gid doesn't match its gid 
  699. sub existing_group_ok {
  700.     my($new_name,$new_gid) = @_;
  701.     my ($dummy1,$dummy2,$gid);
  702.     if (($dummy1,$dummy2,$gid) = getgrnam($new_name)) {
  703.     if( defined($new_gid) && $gid == $new_gid ) {
  704.         return 1;
  705.     }
  706.     if (! defined($new_gid)) {
  707.         return 1;
  708.     }
  709.     if( $gid >= $config{"first_system_gid"} &&
  710.         $gid <= $config{"last_system_gid" } ) {
  711.         return 2;
  712.     }
  713.     } else {
  714.     return 0;
  715.     }
  716. }
  717.  
  718. sub check_user_group {
  719.     my ($system) = @_;
  720.     if( !$system || !existing_user_ok($new_name, $new_uid) ) {
  721.     if( defined getpwnam($new_name) ) {
  722.         if( $system ) {
  723.         dief (gtx("The user `%s' already exists, and is not a system user.\n"),$new_name);
  724.         } else {
  725.         dief (gtx("The user `%s' already exists.\n"),$new_name);
  726.         }
  727.     }
  728.     dief (gtx("The UID %d is already in use.\n"),$new_uid)
  729.       if (defined($new_uid) && getpwuid($new_uid));
  730.     }
  731.     if ($make_group_also) {
  732.     if( !$system || !existing_group_ok($new_name, $new_uid) ) {
  733.         dief (gtx("The group `%s' already exists.\n"),$new_name)
  734.           if (defined getgrnam($new_name));
  735.         dief (gtx("The GID %d is already in use.\n"),$new_uid)
  736.           if (defined($new_uid) && defined(getgrgid($new_uid)));
  737.     }
  738.     }
  739.     else {
  740.     dief (gtx("The group `%s' does not exist.\n"),$ingroup_name)
  741.         if ($ingroup_name && !defined(getgrnam($ingroup_name)));
  742.     dief (gtx("The GID %d does not exist.\n"),$new_gid)
  743.         if (defined($new_gid) && !defined(getgrgid($new_gid)));
  744.     }
  745. }
  746.  
  747.  
  748. # copy files, directories, symlinks    
  749. sub copy_to_dir {
  750.     my($fromdir, $file, $todir, $newu, $newg, $sgiddir) = @_;
  751.  
  752.     if (-l "$fromdir/$file") {
  753.     my $target=readlink("$fromdir/$file") or &cleanup("readlink: $!\n");
  754.     my $curgid="$)";
  755.     my $curuid="$>";
  756.     my $error="";
  757.     $)="$newg";
  758.     $>="$newu";
  759.     symlink("$target", "$todir/$file") or $error="$!";
  760.         $>="$curuid";
  761.         $)="$curgid";
  762.     if( "$error" ne "" ) {
  763.         &cleanup("symlink: $!\n");
  764.     }
  765.     return;
  766.     }
  767.     elsif (-f "$fromdir/$file") {
  768.     open (FILE, "$fromdir/$file") || &cleanup("open $fromdir/$file: $!");
  769.     open (NEWFILE, ">$todir/$file") || &cleanup("open >$todir/$file: $!");
  770.  
  771.     (print NEWFILE <FILE>) || &cleanup("print $todir/$file: $!");
  772.     close FILE;
  773.     close(NEWFILE)  || &cleanup("close $todir/$file ");
  774.  
  775.     }
  776.     elsif (-d "$fromdir/$file") {
  777.     mkdir("$todir/$file", 700) || &cleanup("mkdir: $!");
  778.     }
  779.     else {
  780.     &cleanup(sprintf((gtx("Cannot deal with %s.\nIt is not a dir, file, or symlink.\n")), "$fromdir/$file"));
  781.     }
  782.     
  783.     chown($newu, $newg, "$todir/$file")
  784.     || &cleanup("chown $newu:$newg $todir/$file: $!\n");
  785.     $perm = (stat("$fromdir/$file"))[2] & 07777;
  786.     $perm |= 02000 if (-d "$fromdir/$file" && ($perm & 010) && $sgiddir);
  787.     chmod($perm, "$todir/$file") || &cleanup("chmod $todir/$file: $!\n");
  788. }
  789.        
  790.  
  791. # check if the given name matches some sanity checks
  792. sub checkname {
  793.     my ($name) = @_;
  794.     if ($name !~ /^[_.A-Za-z0-9][-\@_.A-Za-z0-9]*\$?$/) {
  795.     printf STDERR
  796. (gtx("%s: To avoid problems, the username should consist only of
  797. letters, digits, underscores, periods, at signs and dashes, and not start with
  798. a dash (as defined by IEEE Std 1003.1-2001). For compatibility with Samba
  799. machine accounts \$ is also supported at the end of the username\n"), $0);
  800.         exit 1;
  801.     }
  802.     if ($name !~ qr/$config{"name_regex"}/) {
  803.       if ($allow_badname) {
  804.     print (gtx("Allowing use of questionable username.\n")) if ($verbose);
  805.       }
  806.       else {
  807.         printf STDERR
  808. (gtx("%s: Please enter a username matching the regular expression configured
  809. via the NAME_REGEX configuration variable.  Use the `--force-badname'
  810. option to relax this check or reconfigure NAME_REGEX.\n"), $0);
  811.         exit 1;
  812.       }
  813.     }
  814. }
  815.  
  816. # return the first available uid in given range
  817. # return -1 if no free uid is available
  818. sub first_avail_uid {
  819.     my ($min, $max) = @_;
  820.     printf (gtx("Selecting UID from range %d to %d ...\n"),$min,$max) if ($verbose > 1);
  821.  
  822.     my $t = $min;
  823.     while ($t <= $max) {
  824.        return $t if (!defined(getpwuid($t)));
  825.        $t++;
  826.     }
  827.     return -1; # nothing available
  828. }
  829.  
  830. # return the first available gid in given range
  831. # return -1 if no free gid is available
  832. sub first_avail_gid {
  833.     my ($min, $max) = @_;
  834.     printf (gtx("Selecting GID from range %d to %d ...\n"),$min,$max) if ($verbose > 1);
  835.  
  836.     my $t = $min;
  837.     while ($t <= $max) {
  838.        return $t if (!defined(getgrgid($t)));
  839.        $t++;
  840.     }
  841.     return -1; # nothing available
  842. }
  843.  
  844. sub ch_gecos {
  845.     my $chfn = &which('chfn');
  846.     my $gecos = shift;
  847.     if($gecos =~ /,/)
  848.       {
  849.       my($gecos_name,$gecos_room,$gecos_work,$gecos_home,$gecos_other)
  850.         = split(/,/,$gecos);
  851.  
  852.       &systemcall($chfn, '-f', $gecos_name, '-r', $gecos_room, $new_name);
  853.       &systemcall($chfn,'-w',$gecos_work,$new_name)
  854.         if(defined($gecos_work));
  855.       &systemcall($chfn,'-h',$gecos_home,$new_name)
  856.         if(defined($gecos_home));
  857.       &systemcall($chfn,'-o',$gecos_other,$new_name)
  858.         if(defined($gecos_other));
  859.       }
  860.     else
  861.       {
  862.       &systemcall($chfn, '-f', $gecos, $new_name);
  863.       }
  864. }
  865.  
  866. # user is member of group?
  867. sub user_is_member {
  868.     my($user, $group) = @_;
  869.     for (split(/ /, (getgrnam($group))[3])) {
  870.     return 1 if ($user eq $_);
  871.     }
  872.     return 0;
  873. }
  874.  
  875.  
  876. sub cleanup {
  877.     my ($msg) = @_;
  878.     printf (gtx("Stopped: %s\n"),$msg);
  879.     if ($undohome) {
  880.     printf (gtx("Removing directory `%s' ...\n"),$undohome);
  881.     &systemcall('rm', '-rf', $undohome);
  882.     }
  883.     if ($undouser) {
  884.     printf (gtx("Removing user `%s' ...\n"),$undouser);
  885.     &systemcall('userdel', $undouser);
  886.     }
  887.     if ($undogroup) {
  888.     printf (gtx("Removing group `%s' ...\n"),$undogroup);
  889.     &systemcall('groupdel', $undogroup);
  890.     }
  891.     # do we need to invalidate the nscd cache here, too?
  892.     exit 1;
  893. }
  894.  
  895. sub handler {
  896.     my($sig) = @_;
  897.     # Translators: the variable %s is INT, QUIT, or HUP.
  898.     # Please do not insert a space character between SIG and %s.
  899.     &cleanup(sprintf(gtx("Caught a SIG%s.\n"), $sig));
  900. }
  901.     
  902.  
  903. sub version {
  904.     printf (gtx("adduser version %s\n\n"), $version);
  905.     print gtx("Adds a user or group to the system.
  906.   
  907. Copyright (C) 1997, 1998, 1999 Guy Maor <maor\@debian.org>
  908. Copyright (C) 1995 Ian Murdock <imurdock\@gnu.ai.mit.edu>,
  909.                    Ted Hajek <tedhajek\@boombox.micro.umn.edu>
  910. \n");
  911.     print gtx(
  912. "This program is free software; you can redistribute it and/or modify
  913. it under the terms of the GNU General Public License as published by
  914. the Free Software Foundation; either version 2 of the License, or (at
  915. your option) any later version.
  916.  
  917. This program is distributed in the hope that it will be useful, but
  918. WITHOUT ANY WARRANTY; without even the implied warranty of
  919. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  920. General Public License, /usr/share/common-licenses/GPL, for more details.
  921. ");
  922. }
  923.  
  924. sub usage {
  925.     printf gtx(
  926. "adduser [--home DIR] [--shell SHELL] [--no-create-home] [--uid ID]
  927. [--firstuid ID] [--lastuid ID] [--gecos GECOS] [--ingroup GROUP | --gid ID]
  928. [--disabled-password] [--disabled-login] USER
  929.    Add a normal user
  930.  
  931. adduser --system [--home DIR] [--shell SHELL] [--no-create-home] [--uid ID]
  932. [--gecos GECOS] [--group | --ingroup GROUP | --gid ID] [--disabled-password]
  933. [--disabled-login] USER
  934.    Add a system user
  935.  
  936. adduser --group [--gid ID] GROUP
  937. addgroup [--gid ID] GROUP
  938.    Add a user group
  939.  
  940. addgroup --system [--gid ID] GROUP
  941.    Add a system group
  942.  
  943. adduser USER GROUP
  944.    Add an existing user to an existing group
  945.  
  946. general options:
  947.   --quiet | -q      don't give process information to stdout
  948.   --force-badname   allow usernames which do not match the
  949.                     NAME_REGEX configuration variable
  950.   --help | -h       usage message
  951.   --version | -v    version number and copyright
  952.   --conf | -c FILE  use FILE as configuration file\n\n");
  953. }
  954.  
  955. sub get_dir_mode
  956.   {
  957.       my $setgid = shift;
  958.       # no longer make home directories setgid per default (closes: #64806)
  959.       $setgid = 0 unless $config{"setgid_home"} =~  /yes/i;
  960.  
  961.       my $dir_mode = $config{"dir_mode"};
  962.       if(!defined($dir_mode) || ! ($dir_mode =~ /[0-7]{3}/ ||
  963.                    $dir_mode =~ /[0-7]{4}/))
  964.     {
  965.         $dir_mode = $setgid ? 2755 : 0755;
  966.     }
  967.       else
  968.     {
  969.         $dir_mode = $config{"dir_mode"};
  970.         if($setgid && (length($dir_mode) == 3 || $dir_mode =~ /^[0-1|4-5][0-7]{3}$/))
  971.           {
  972.           $dir_mode += 2000;
  973.           }
  974.     }
  975.       return oct($dir_mode);
  976.   }
  977.  
  978. # Local Variables:
  979. # mode:cperl
  980. # cperl-indent-level:4
  981. # End:
  982.  
  983. # vim:set ai et sts=4 sw=4 tw=0:
  984.