adduser Revision 393136383262 (Sun Jul 26 2009 at 08:46) - Diff Link to this snippet: https://friendpaste.com/5cjyY5bbRu7WiGCGzobRdU Embed: manni perldoc borland colorful default murphy trac fruity autumn bw emacs pastie friendly Show line numbers Wrap lines 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999#!/usr/bin/perl# adduser: a utility to add users to the system# addgroup: a utility to add groups to the systemmy $version = "3.102";# Copyright (C) 1997, 1998, 1999 Guy Maor <maor@debian.org># Copyright (C) 1995 Ted Hajek <tedhajek@boombox.micro.umn.edu># Ian A. Murdock <imurdock@gnu.ai.mit.edu># Bugfixes and other improvements Roland Bauerschmidt <rb@debian.org># General scheme of the program adapted by the original debian 'adduser'# program by Ian A. Murdock <imurdock@gnu.ai.mit.edu>.## This program is free software; you can redistribute it and/or modify# it under the terms of the GNU General Public License as published by# the Free Software Foundation; either version 2 of the License, or# (at your option) any later version.## This program is distributed in the hope that it will be useful,# but WITHOUT ANY WARRANTY; without even the implied warranty of# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the# GNU General Public License for more details.## You should have received a copy of the GNU General Public License# along with this program; if not, write to the Free Software# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA####################### See the usage subroutine for explanation about how the program can be called####################use warnings;use strict;use Debian::AdduserCommon;use Getopt::Long;BEGIN { eval 'use Locale::gettext'; if ($@) { *gettext = sub { shift }; *textdomain = sub { "" }; *LC_MESSAGES = sub { 5 }; } eval { require POSIX; import POSIX qw(setlocale); }; if ($@) { *setlocale = sub { return 1 }; } eval { require I18N::Langinfo; import I18N::Langinfo qw(langinfo YESEXPR NOEXPR); }; if ($@) { *langinfo = sub { return shift; }; *YESEXPR = sub { "^[yY]" }; *NOEXPR = sub { "^[nN]" }; }}setlocale(LC_MESSAGES, "");textdomain("adduser");my $yesexpr = langinfo(YESEXPR());my %config; # configuration hashmy @defaults = ("/etc/adduser.conf");my $nogroup_id = getgrnam("nogroup") || 65534;$0 =~ s+.*/++; our $verbose = 1; # should we be verbose?my $allow_badname = 0; # should we allow bad names?my $ask_passwd = 1; # ask for a passwd? my $disabled_login = 0; # leave the new account disabled?our $configfile = undef;our $found_group_opt = undef;our $found_sys_opt = undef;our $ingroup_name = undef;our $new_firstuid = undef;our $new_gecos = undef;our $new_gid = undef;our $new_lastuid = undef;our $new_uid = undef;our $no_create_home = undef;our $special_home = undef;our $special_shell = undef;our $add_extra_groups = 0;# Global variables we need latermy $existing_user = undef;my $existing_group = undef;my $new_name = undef;my $make_group_also = 0;my $home_dir = undef;my $undohome = undef;my $undouser = undef;my $undogroup = undef;my $shell = undef;my $first_uid = undef;my $last_uid = undef;my $dir_mode = undef;my $perm = undef;our @names;# Parse options, sanity checksunless ( GetOptions ("quiet|q" => sub { $verbose = 0 }, "force-badname" => \$allow_badname, "help|h" => sub { &usage(); exit 0 }, "version|v" => sub { &version(); exit 0 }, "system" => \$found_sys_opt, "group" => \$found_group_opt, "ingroup=s" => \$ingroup_name, "home=s" => \$special_home, "gecos=s" => \$new_gecos, "shell=s" => \$special_shell, "disabled-password" => sub { $ask_passwd = 0 }, "disabled-login" => sub { $disabled_login = 1; $ask_passwd = 0 }, "uid=i" => \$new_uid, "firstuid=i" => \$new_firstuid, "lastuid=i" => \$new_lastuid, "gid=i" => \$new_gid, "conf=s" => \$configfile, "no-create-home" => \$no_create_home, "add_extra_groups" => \$add_extra_groups, "debug" => sub { $verbose = 2 } ) ) { &usage(); exit 1;}# everyone can issue "--help" and "--version", but only root can go ondief (gtx("Only root may add a user or group to the system.\n")) if ($> != 0);if( defined($configfile) ) { @defaults = ($configfile); }# detect the right modemy $action = $0 eq "addgroup" ? "addgroup" : "adduser";if (defined($found_sys_opt)) { $action = "addsysuser" if ($action eq "adduser"); $action = "addsysgroup" if ($action eq "addgroup");}############################# checks related to @names #############################while (defined(my $arg = shift(@ARGV))) { push (@names, $arg);}if ( (! defined $names[0]) || length($names[0]) == 0 || @names > 2) { dief (gtx("Only one or two names allowed.\n"));} if (@names == 2) { # must be addusertogroup dief (gtx("Specify only one name in this mode.\n")) if ($action eq "addsysuser" || $found_group_opt); $action = "addusertogroup"; $existing_user = shift (@names); $existing_group = shift (@names);}else { $new_name = shift (@names);}#################################### check for consistent parameters ####################################if ($action ne "addgroup" && defined($found_group_opt) +defined($ingroup_name) +defined($new_gid) > 1 ) { dief (gtx("The --group, --ingroup, and --gid options are mutually exclusive.\n"));}if ((defined($special_home)) && ($special_home !~ m+^/+ )) { dief (gtx("The home dir must be an absolute path.\n"));} if (defined($special_home) && $verbose) { print gtx("Warning: The home dir you specified already exists.\n") if (!defined($no_create_home) && -d $special_home); print gtx("Warning: The home dir you specified does not exist.\n") if (defined($no_create_home) && ! -d $special_home);}if ($found_group_opt) { if ($action eq "addsysuser") { $make_group_also = 1; } elsif ($found_sys_opt) { $action = "addsysgroup"; } else { $action = "addgroup"; }}$ENV{"VERBOSE"} = $verbose;$ENV{"DEBUG"} = $verbose;# preseed configuration data and then read the config filepreseed_config(\@defaults,\%config);&checkname($new_name) if defined $new_name;$SIG{'INT'} = $SIG{'QUIT'} = $SIG{'HUP'} = 'handler';###### OK, we've processed the arguments. $action equals one of the following,# and the appropriate variables have been set:## $action = "adduser"# $new_name - the name of the new user.# $ingroup_name | $new_gid - the group to add the user to# $special_home, $new_uid, $new_gecos - optional overrides# $action = "addgroup"# $new_name - the name of the new group# $new_gid - optional override# $action = "addsysgroup"# $new_name - the name of the new group# $new_gid - optional override# $action = "addsysuser"# $new_name - the name of the new user# $make_group_also | $ingroup_name | $new_gid | 0 - which group# $special_home, $new_uid, $new_gecos - optional overrides# $action = "addusertogroup"# $existing_user - the user to be added# $existing_group - the group to add her to######################## addsysgroup ###################if ($action eq "addsysgroup") { # Check if requested group already exists and we can exit safely my $ret = existing_group_ok($new_name, $new_gid); if ($ret == 3) { print STDERR "$0: "; printf STDERR (gtx("The group `%s' already exists as a system group. Exiting.\n"), $new_name) if $verbose; exit 0; } if ($ret == 1) { print STDERR "$0: "; printf STDERR (gtx("The group `%s' already exists and is not a system group. Exiting.\n"), $new_name) if $verbose; exit 1; } if ($ret == 2) { print STDERR "$0: "; printf STDERR (gtx("The group `%s' already exists, but has a different GID. Exiting.\n"), $new_name) if $verbose; exit 1; } dief (gtx("The group `%s' already exists and is not a system group.\n"),$new_name) if (defined getgrnam($new_name)); dief (gtx("The GID `%s' is already in use.\n"),$new_gid) if (defined($new_gid) && defined(getgrgid($new_gid))); if (!defined($new_gid)) { $new_gid = &first_avail_gid($config{"first_system_gid"}, $config{"last_system_gid"}); 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"}; dief (gtx("The group `%s' was not created.\n"),$new_name); } } printf (gtx("Adding group `%s' (GID %d) ...\n"),$new_name,$new_gid) if $verbose; &invalidate_nscd("group"); my $groupadd = &which('groupadd'); &systemcall($groupadd, '-g', $new_gid, $new_name); &invalidate_nscd("group"); print (gtx("Done.\n")) if $verbose; exit 0;}################ addgroup ################if ($action eq "addgroup") { dief (gtx("The group `%s' already exists.\n"),$new_name) if (defined getgrnam($new_name)); dief (gtx("The GID `%s' is already in use.\n"),$new_gid) if (defined($new_gid) && defined(getgrgid($new_gid))); if (!defined($new_gid)) { $new_gid = &first_avail_gid($config{"first_gid"}, $config{"last_gid"}); if ($new_gid == -1) { print STDERR "$0: "; printf STDERR gtx("No GID is available in the range %d-%d (FIRST_GID - LAST_GID).\n"),$config{"first_gid"},$config{"last_gid"}; dief (gtx("The group `%s' was not created.\n"),$new_name); } } printf (gtx("Adding group `%s' (GID %d) ...\n"),$new_name,$new_gid) if $verbose; &invalidate_nscd("group"); my $groupadd = &which('groupadd'); &systemcall($groupadd, '-g', $new_gid, $new_name); &invalidate_nscd("group"); print (gtx("Done.\n")) if $verbose; exit 0;}###################### addusertogroup ######################if ($action eq "addusertogroup") { dief (gtx("The user `%s' does not exist.\n"),$existing_user) if (!defined getpwnam($existing_user)); dief (gtx("The group `%s' does not exist.\n"),$existing_group) if (!defined getgrnam($existing_group)); if (&user_is_member($existing_user, $existing_group)) { printf gtx("The user `%s' is already a member of `%s'.\n"), $existing_user,$existing_group if $verbose; exit 0; # not really an error } printf gtx("Adding user `%s' to group `%s' ...\n"),$existing_user,$existing_group if $verbose; &invalidate_nscd(); # FIXME - the next line has a race condition. #&systemcall('usermod', '-G', #join(",", get_users_groups($existing_user), $existing_group), #$existing_user); my $gpasswd = &which('gpasswd'); &systemcall($gpasswd, '-M', join(',', get_group_members($existing_group), $existing_user), $existing_group); #&systemcall('gpasswd', '-a',$existing_user,$existing_group); &invalidate_nscd(); print (gtx("Done.\n")) if $verbose; exit 0;}################## addsysuser ##################if ($action eq "addsysuser") { if (existing_user_ok($new_name, $new_uid) == 1) { printf (gtx("The user `%s' already exists as a system user. Exiting.\n"), $new_name) if $verbose; exit 0; } if (existing_user_ok($new_name, $new_uid) == 2) { printf (gtx("The user `%s' already exists with a different UID. Exiting.\n"), $new_name) if $verbose; exit 1; } if (!$ingroup_name && !defined($new_gid) && !$make_group_also) { $new_gid = $nogroup_id; } check_user_group(1); if (!defined($new_uid) && $make_group_also) { $new_uid = &first_avail_uid($config{"first_system_uid"}, $config{"last_system_uid"}); 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"}); $ingroup_name = $new_name; } elsif (!defined($new_uid) && !$make_group_also) { $new_uid = &first_avail_uid($config{"first_system_uid"}, $config{"last_system_uid"}); 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"}; dief (gtx("The user `%s' was not created.\n"),$new_name); } if (defined($new_gid)) { $ingroup_name = getgrgid($new_gid); } elsif ($ingroup_name) { $new_gid = getgrnam($ingroup_name); } else { dief (gtx("Internal error")); } } else { if (defined($new_gid)) { $ingroup_name = getgrgid($new_gid); } elsif ($ingroup_name) { $new_gid = getgrnam($ingroup_name); } elsif ($make_group_also){ $new_gid=$new_uid; $ingroup_name=$new_name; } else { dief (gtx("Internal error")); } } printf (gtx("Adding system user `%s' (UID %d) ...\n"),$new_name,$new_uid) if $verbose; &invalidate_nscd(); # if we reach this point, and the group does already exist, we can use it. if ($make_group_also && !getgrnam($new_name)) { printf (gtx("Adding new group `%s' (GID %d) ...\n"),$new_name,$new_gid) if $verbose; $undogroup = $new_name; my $groupadd = &which('groupadd'); &systemcall($groupadd, '-g', $new_gid, $new_name); &invalidate_nscd("group"); } printf gtx("Adding new user `%s' (UID %d) with group `%s' ...\n"),$new_name,$new_uid,$ingroup_name if $verbose; $home_dir = $special_home || &homedir($new_name, $ingroup_name); $shell = $special_shell || '/bin/false'; $undouser = $new_name; my $useradd = &which('useradd'); &systemcall($useradd, '-d', $home_dir, '-g', $ingroup_name, '-s', $shell, '-u', $new_uid, $new_name); my $chage = &which('chage'); print "$chage -M 99999 $new_name\n" if ($verbose > 1); # do _not_ use systemcall() here, since systemcall() dies on # non-zero exit code and we need to do special handling here! if (system($chage, '-M', '99999', $new_name)) { if( ($?>>8) ne 15 ) { &cleanup(sprintf((gtx("`%s' returned error code %d. Exiting.\n")), "$chage -M 99999 $new_name", $?>>8)) if ($?>>8); &cleanup(sprintf((gtx("`%s' exited from signal %d. Exiting.\n")), "$chage -M 99999 $new_name", $?&255)); } else { printf (gtx("%s failed with return code 15, shadow not enabled, password aging cannot be set. Continuing.\n"), $chage); } } &invalidate_nscd(); if(defined($new_gecos)) { &ch_gecos($new_gecos); } create_homedir (0); exit 0;}############### adduser ###############if ($action eq "adduser") { if (!$ingroup_name && !defined($new_gid)) { if ($config{"usergroups"} =~ /yes/i) { $make_group_also = 1; } else { $new_gid = $config{"users_gid"}; } } check_user_group(0); $first_uid = $new_firstuid || $config{"first_uid"}; $last_uid = $new_lastuid || $config{"last_uid"}; printf (gtx("Adding user `%s' ...\n"),$new_name) if $verbose; if (!defined($new_uid) && $make_group_also) { $new_uid = &first_avail_uid($first_uid, $last_uid); if ($new_uid == -1) { print STDERR "$0: "; printf STDERR gtx("No UID/GID pair is available in the range %d-%d (FIRST_UID - LAST_UID).\n"),$first_uid,$last_uid; dief (gtx("The user `%s' was not created.\n"),$new_name); } $new_gid = &first_avail_gid($config{"first_gid"}, $config{"last_gid"}); $ingroup_name = $new_name; } elsif (!defined($new_uid) && !$make_group_also) { $new_uid = &first_avail_uid($first_uid, $last_uid); 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"}; dief (gtx("The user `%s' was not created.\n"),$new_name); } if (defined($new_gid)) { $ingroup_name = getgrgid($new_gid); } elsif ($ingroup_name) { $new_gid = getgrnam($ingroup_name); } else { dief (gtx("Internal error")); } } else { if (defined($new_gid)) { $ingroup_name = getgrgid($new_gid); } elsif ($ingroup_name) { $new_gid = getgrnam($ingroup_name); } elsif ($make_group_also){ $new_gid=$new_uid; $ingroup_name=$new_name; } else { dief (gtx("Internal error")); } } &invalidate_nscd(); if ($make_group_also) { printf (gtx("Adding new group `%s' (%d) ...\n"),$new_name,$new_gid) if $verbose; $undogroup = $new_name; my $groupadd = &which('groupadd'); &systemcall($groupadd, '-g', $new_gid, $new_name); &invalidate_nscd(); } printf gtx("Adding new user `%s' (%d) with group `%s' ...\n"),$new_name,$new_uid,$ingroup_name if $verbose; $home_dir = $special_home || &homedir($new_name, $ingroup_name); $shell = $special_shell || $config{"dshell"}; $undouser = $new_name; my $useradd = &which('useradd'); &systemcall($useradd, '-d', $home_dir, '-g', $ingroup_name, '-s', $shell, '-u', $new_uid, $new_name); &invalidate_nscd(); create_homedir (1); # copy skeleton data # useradd without -p has left the account disabled (password string is '!') if ($ask_passwd) { for (;;) { my $passwd = &which('passwd'); # do _not_ use systemcall() here, since systemcall() dies on # non-zero exit code and we need to do special handling here! system($passwd, $new_name); my $ok = $?>>8; if ($ok != 0) { my $noexpr = langinfo(NOEXPR()); my $answer; # hm, error, should we break now? print (gtx("Permission denied\n")) if ($ok == 1); print (gtx("invalid combination of options\n")) if ($ok == 2); print (gtx("unexpected failure, nothing done\n")) if ($ok == 3); print (gtx("unexpected failure, passwd file missing\n")) if ($ok == 3); print (gtx("passwd file busy, try again\n")) if ($ok == 4); print (gtx("invalid argument to option\n")) if ($ok == 5); # Translators: [Y/n] has to be replaced by values defined in your # locale. You can see by running "locale noexpr" which regular # expression will be checked to find positive answer. print (gtx("Try again? [Y/n] ")); chop ($answer=<STDIN>); last if ($answer =~ m/$noexpr/o); } else { last; ## passwd ok } } } else { if(!$disabled_login) { my $usermod = &which('usermod'); &systemcall($usermod, '-p', '*', $new_name); } } if (defined($new_gecos)) { &ch_gecos($new_gecos); } else { my $yesexpr = langinfo(YESEXPR()); for (;;) { my $chfn = &which('chfn'); &systemcall($chfn, $new_name); # Translators: [y/N] has to be replaced by values defined in your # locale. You can see by running "locale yesexpr" which regular # expression will be checked to find positive answer. print (gtx("Is the information correct? [y/N] ")); chop (my $answer=<STDIN>); last if ($answer =~ m/$yesexpr/o); } } if ( ( $add_extra_groups || $config{"add_extra_groups"} ) && defined($config{"extra_groups"}) ) { printf (gtx("Adding new user `%s' to extra groups ...\n"), $new_name); foreach my $newgrp ( split ' ', $config{"extra_groups"} ) { if (!defined getgrnam($newgrp)) { warnf (gtx("The group `%s' does not exist.\n"),$newgrp); next; } if (&user_is_member($new_name, $newgrp)) { printf gtx("The user `%s' is already a member of `%s'.\n"), $new_name,$newgrp if $verbose; next; } printf gtx("Adding user `%s' to group `%s' ...\n"),$new_name,$newgrp if $verbose; &invalidate_nscd(); my $gpasswd = &which('gpasswd'); &systemcall($gpasswd, '-M', join(',', get_group_members($newgrp), $new_name), $newgrp); &invalidate_nscd(); } } if ($config{"quotauser"}) { printf (gtx("Setting quota for user `%s' to values of user `%s' ...\n"), $new_name, $config{quotauser}); my $edquota = &which('edquota'); &systemcall($edquota, '-p', $config{quotauser}, $new_name); } &systemcall('/usr/local/sbin/adduser.local', $new_name, $new_uid, $new_gid, $home_dir) if (-x "/usr/local/sbin/adduser.local"); exit 0;}## we never go here## calculate home directorysub homedir { my $dir = $config{"dhome"}; $dir .= '/' . $_[1] if ($config{"grouphomes"} =~ /yes/i); $dir .= '/' . substr($_[0],0,1) if ($config{"letterhomes"} =~ /yes/i); $dir .= '/' . $_[0]; return $dir;}# create_homedir -- create the homedirectory# parameter 1: $copy_skeleton: # if 0 -> don't copy the skeleton data# if 1 -> copy the files in /etc/skel to the newly created home directorysub create_homedir { my ($copy_skeleton) = @_; if ($no_create_home) { printf gtx("Not creating home directory `%s'.\n"), $home_dir if $verbose; } elsif (-e $home_dir) { printf gtx("The home directory `%s' already exists. Not copying from `%s'.\n"), $home_dir,$config{skel} if $verbose && !$no_create_home; my @homedir_stat = stat($home_dir); my $home_uid = $homedir_stat[4]; my $home_gid = $homedir_stat[5]; if (($home_uid != $new_uid) || ($home_gid != $new_gid)) { # post-etch, see #397916 # warnf gtx("Warning: The home directory `%s' does not belong to the user you are currently creating.\n"), $home_dir; warnf gtx("Warning: that home directory does not belong to the user you are currently creating.\n"); } undef @homedir_stat; undef $home_uid; undef $home_gid; } else { printf gtx("Creating home directory `%s' ...\n"),$home_dir if $verbose; $undohome = $home_dir; &mktree($home_dir) || &cleanup(sprintf(gtx("Couldn't create home directory `%s': %s.\n"), $home_dir, $!)); chown($new_uid, $new_gid, $home_dir) || &cleanup("chown $new_uid:$new_gid $home_dir: $!\n"); $dir_mode = get_dir_mode($make_group_also); chmod ($dir_mode, $home_dir) || &cleanup("chmod $dir_mode $home_dir: $!\n"); if ($config{"skel"} && $copy_skeleton) { printf gtx("Copying files from `%s' ...\n"),$config{skel} if $verbose; open(FIND, "cd $config{skel}; find . -print |") || &cleanup(sprintf(gtx("fork for `find' failed: %s\n"), $!)); while (<FIND>) { chop; next if ($_ eq "."); next if ($_ =~ qr/$config{skel_ignore_regex}/ ); ©_to_dir($config{"skel"}, $_, $home_dir, $new_uid, $new_gid, ($config{"setgid_home"} =~ /yes/i)); } } }}# create a directory and all parent directories# we don't care about the rights and so onsub mktree { my($tree) = @_; my($done, @path); my $default_dir_mode = 0755; $tree =~ s:^/*(.*)/*$:$1:; # chop off leading & trailing slashes @path = split(/\//, $tree); $done = ""; while (@path) { $done .= '/' . shift(@path); -d $done || mkdir($done, $default_dir_mode) || return 0; } return 1;}# returns 0 if the the user doesn't exist or# returns 1 if the user already exists with the specified uid (or $new_uid wasn't specified)# returns 2 if the user already exists, but $new_uid doesn't matches its uidsub existing_user_ok { my($new_name,$new_uid) = @_; my ($dummy1,$dummy2,$uid); if (($dummy1,$dummy2,$uid) = getpwnam($new_name)) { if( defined($new_uid) && $uid == $new_uid ) { return 1; } if (! defined($new_uid)) { return 1; } if( $uid >= $config{"first_system_uid"} && $uid <= $config{"last_system_uid" } ) { return 2; } } else { return 0; }}# returns 0 if the group doesn't exist or# returns 1 if the group already exists with the specified gid (or $new_gid wasn't specified)# returns 2 if the group already exists, but $new_gid doesn't match its gid # returns 3 if the group already exists inside the system rangesub existing_group_ok { my($new_name,$new_gid) = @_; my ($dummy1,$dummy2,$gid); if (($dummy1,$dummy2,$gid) = getgrnam($new_name)) { if( $gid >= $config{"first_system_gid"} && $gid <= $config{"last_system_gid" } ) { return 3; } if (! defined($new_gid)) { return 1; } if ($gid == $new_gid) { return 1; } else { return 2; } } else { return 0; }}sub check_user_group { my ($system) = @_; if( !$system || !existing_user_ok($new_name, $new_uid) ) { if( defined getpwnam($new_name) ) { if( $system ) { dief (gtx("The user `%s' already exists, and is not a system user.\n"),$new_name); } else { dief (gtx("The user `%s' already exists.\n"),$new_name); } } dief (gtx("The UID %d is already in use.\n"),$new_uid) if (defined($new_uid) && getpwuid($new_uid)); } if ($make_group_also) { if( !$system || !existing_group_ok($new_name, $new_uid) ) { dief (gtx("The group `%s' already exists.\n"),$new_name) if (defined getgrnam($new_name)); dief (gtx("The GID %d is already in use.\n"),$new_uid) if (defined($new_uid) && defined(getgrgid($new_uid))); } } else { dief (gtx("The group `%s' does not exist.\n"),$ingroup_name) if ($ingroup_name && !defined(getgrnam($ingroup_name))); dief (gtx("The GID %d does not exist.\n"),$new_gid) if (defined($new_gid) && !defined(getgrgid($new_gid))); }}# copy files, directories, symlinks sub copy_to_dir { my($fromdir, $file, $todir, $newu, $newg, $sgiddir) = @_; if (-l "$fromdir/$file") { my $target=readlink("$fromdir/$file") or &cleanup("readlink: $!\n"); my $curgid="$)"; my $curuid="$>"; my $error=""; $)="$newg"; $>="$newu"; symlink("$target", "$todir/$file") or $error="$!"; $>="$curuid"; $)="$curgid"; if( "$error" ne "" ) { &cleanup("symlink: $!\n"); } return; } elsif (-f "$fromdir/$file") { open (FILE, "$fromdir/$file") || &cleanup("open $fromdir/$file: $!"); open (NEWFILE, ">$todir/$file") || &cleanup("open >$todir/$file: $!"); (print NEWFILE <FILE>) || &cleanup("print $todir/$file: $!"); close FILE; close(NEWFILE) || &cleanup("close $todir/$file "); } elsif (-d "$fromdir/$file") { mkdir("$todir/$file", 700) || &cleanup("mkdir: $!"); } else { &cleanup(sprintf((gtx("Cannot deal with %s.\nIt is not a dir, file, or symlink.\n")), "$fromdir/$file")); } chown($newu, $newg, "$todir/$file") || &cleanup("chown $newu:$newg $todir/$file: $!\n"); $perm = (stat("$fromdir/$file"))[2] & 07777; $perm |= 02000 if (-d "$fromdir/$file" && ($perm & 010) && $sgiddir); chmod($perm, "$todir/$file") || &cleanup("chmod $todir/$file: $!\n");} # check if the given name matches some sanity checkssub checkname { my ($name) = @_; if ($name !~ /^[_.A-Za-z0-9][-\@_.A-Za-z0-9]*\$?$/) { printf STDERR(gtx("%s: To avoid problems, the username should consist only ofletters, digits, underscores, periods, at signs and dashes, and not start witha dash (as defined by IEEE Std 1003.1-2001). For compatibility with Sambamachine accounts \$ is also supported at the end of the username\n"), $0); exit 1; } if ($name !~ qr/$config{"name_regex"}/) { if ($allow_badname) { print (gtx("Allowing use of questionable username.\n")) if ($verbose); } else { printf STDERR(gtx("%s: Please enter a username matching the regular expression configuredvia the NAME_REGEX configuration variable. Use the `--force-badname'option to relax this check or reconfigure NAME_REGEX.\n"), $0); exit 1; } }}# return the first available uid in given range# return -1 if no free uid is availablesub first_avail_uid { my ($min, $max) = @_; printf (gtx("Selecting UID from range %d to %d ...\n"),$min,$max) if ($verbose > 1); my $t = $min; while ($t <= $max) { return $t if (!defined(getpwuid($t))); $t++; } return -1; # nothing available}# return the first available gid in given range# return -1 if no free gid is availablesub first_avail_gid { my ($min, $max) = @_; printf (gtx("Selecting GID from range %d to %d ...\n"),$min,$max) if ($verbose > 1); my $t = $min; while ($t <= $max) { return $t if (!defined(getgrgid($t))); $t++; } return -1; # nothing available}sub ch_gecos { my $chfn = &which('chfn'); my $gecos = shift; if($gecos =~ /,/) { my($gecos_name,$gecos_room,$gecos_work,$gecos_home,$gecos_other) = split(/,/,$gecos); &systemcall($chfn, '-f', $gecos_name, '-r', $gecos_room, $new_name); &systemcall($chfn,'-w',$gecos_work,$new_name) if(defined($gecos_work)); &systemcall($chfn,'-h',$gecos_home,$new_name) if(defined($gecos_home)); &systemcall($chfn,'-o',$gecos_other,$new_name) if(defined($gecos_other)); } else { &systemcall($chfn, '-f', $gecos, $new_name); }}# user is member of group?sub user_is_member { my($user, $group) = @_; for (split(/ /, (getgrnam($group))[3])) { return 1 if ($user eq $_); } return 0;}sub cleanup { my ($msg) = @_; printf (gtx("Stopped: %s\n"),$msg); if ($undohome) { printf (gtx("Removing directory `%s' ...\n"),$undohome); &systemcall('rm', '-rf', $undohome); } if ($undouser) { printf (gtx("Removing user `%s' ...\n"),$undouser); &systemcall('userdel', $undouser); } if ($undogroup) { printf (gtx("Removing group `%s' ...\n"),$undogroup); &systemcall('groupdel', $undogroup); } # do we need to invalidate the nscd cache here, too? exit 1;}sub handler { my($sig) = @_; # Translators: the variable %s is INT, QUIT, or HUP. # Please do not insert a space character between SIG and %s. &cleanup(sprintf(gtx("Caught a SIG%s.\n"), $sig));} sub version { printf (gtx("adduser version %s\n\n"), $version); print gtx("Adds a user or group to the system. Copyright (C) 1997, 1998, 1999 Guy Maor <maor\@debian.org>Copyright (C) 1995 Ian Murdock <imurdock\@gnu.ai.mit.edu>, Ted Hajek <tedhajek\@boombox.micro.umn.edu>\n"); print gtx("This program is free software; you can redistribute it and/or modifyit under the terms of the GNU General Public License as published bythe Free Software Foundation; either version 2 of the License, or (atyour option) any later version.This program is distributed in the hope that it will be useful, butWITHOUT ANY WARRANTY; without even the implied warranty ofMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNUGeneral Public License, /usr/share/common-licenses/GPL, for more details.");}sub usage { printf gtx("adduser [--home DIR] [--shell SHELL] [--no-create-home] [--uid ID][--firstuid ID] [--lastuid ID] [--gecos GECOS] [--ingroup GROUP | --gid ID][--disabled-password] [--disabled-login] USER Add a normal useradduser --system [--home DIR] [--shell SHELL] [--no-create-home] [--uid ID][--gecos GECOS] [--group | --ingroup GROUP | --gid ID] [--disabled-password][--disabled-login] USER Add a system useradduser --group [--gid ID] GROUPaddgroup [--gid ID] GROUP Add a user groupaddgroup --system [--gid ID] GROUP Add a system groupadduser USER GROUP Add an existing user to an existing groupgeneral options: --quiet | -q don't give process information to stdout --force-badname allow usernames which do not match the NAME_REGEX configuration variable --help | -h usage message --version | -v version number and copyright --conf | -c FILE use FILE as configuration file\n\n");}sub get_dir_mode { my $setgid = shift; # no longer make home directories setgid per default (closes: #64806) $setgid = 0 unless $config{"setgid_home"} =~ /yes/i; my $dir_mode = $config{"dir_mode"}; if(!defined($dir_mode) || ! ($dir_mode =~ /[0-7]{3}/ || $dir_mode =~ /[0-7]{4}/)) { $dir_mode = $setgid ? 2755 : 0755; } else { $dir_mode = $config{"dir_mode"}; if($setgid && (length($dir_mode) == 3 || $dir_mode =~ /^[0-1|4-5][0-7]{3}$/)) { $dir_mode += 2000; } } return oct($dir_mode); }# Local Variables:# mode:cperl# cperl-indent-level:4# End:# vim:set ai et sts=4 sw=4 tw=0: