X-Git-Url: https://git.cameronkatri.com/pw-darwin.git/blobdiff_plain/3aa16d3ca9fd4cb76b388bc6ea16f17d852ec723..ad3df1df7be99f6b798c6927e7b8917dbde5f497:/adduser/adduser.perl diff --git a/adduser/adduser.perl b/adduser/adduser.perl index efa6aaf..421cf02 100644 --- a/adduser/adduser.perl +++ b/adduser/adduser.perl @@ -24,13 +24,15 @@ # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF # SUCH DAMAGE. # -# $Id: adduser.perl,v 1.29 1997/05/01 22:55:58 ache Exp $ +# $FreeBSD$ # read variables sub variables { $verbose = 1; # verbose = [0-2] - $defaultpasswd = "yes"; # use password for new users + $defaultusepassword = "yes"; # use password authentication for new users + $defaultenableaccount = "yes"; # enable the account by default + $defaultemptypassword = "no"; # don't create an empty password $dotdir = "/usr/share/skel"; # copy dotfiles from this dir $dotdir_bak = $dotdir; $send_message = "/etc/adduser.message"; # send message to new user @@ -65,27 +67,19 @@ sub variables { $pwgid = ''; # $pwgid{pwgid} = username; gid from passwd db $password = ''; # password for new users + $usepassword = ''; # use password-based auth + $useemptypassword = ''; # use an empty password + $enableaccount = ''; # enable or disable account password at creation # group $groupname =''; # $groupname{groupname} = gid $groupmembers = ''; # $groupmembers{gid} = members of group/kommalist $gid = ''; # $gid{gid} = groupname; gid form group db + @group_comments; # Comments in the group file # shell $shell = ''; # $shell{`basename sh`} = sh - # only for me (=Wolfram) - if ($test) { - $home = "/home/w/tmp/adduser/home"; - $etc_shells = "./shells"; - $etc_passwd = "./master.passwd"; - $group = "./group"; - $pwd_mkdb = "pwd_mkdb -p -d ."; - $config = "adduser.conf"; - $send_message = "./adduser.message"; - $logfile = "./log.adduser"; - } - umask 022; # don't give login group write access $ENV{'PATH'} = "/sbin:/bin:/usr/sbin:/usr/bin"; @@ -117,13 +111,13 @@ sub shells_read { } } -# Allow /nonexistent and /bin/date as a valid shell for system utils + # Allow /nonexistent and /bin/date as a valid shell for system utils push(@list, "/nonexistent"); - push(@shellpref, "no"); + push(@shellpref, "no") if !grep(/^no$/, @shellpref); $shell{"no"} = "/nonexistent"; push(@list, "/bin/date"); - push(@shellpref, "date"); + push(@shellpref, "date") if !grep(/^date$/, @shellpref); $shell{"date"} = "/bin/date"; return $err; @@ -185,7 +179,7 @@ sub shell_default_valid { return $s; } -# return default home partition (f.e. "/home") +# return default home partition (e.g. "/home") # create base directory if nesseccary sub home_partition { local($home) = @_; @@ -232,7 +226,7 @@ sub home_partition_valid { # check for valid passwddb sub passwd_check { - system("$pwd_mkdb -c $etc_passwd"); + system("$pwd_mkdb -C $etc_passwd"); die "\nInvalid $etc_passwd - cannot add any users!\n" if $?; } @@ -241,7 +235,7 @@ sub passwd_read { local($p_username, $pw, $p_uid, $p_gid, $sh, %shlist); print "Check $etc_passwd\n" if $verbose; - open(P, "$etc_passwd") || die "$passwd: $!\n"; + open(P, "$etc_passwd") || die "$etc_passwd: $!\n"; while(

) { chop; @@ -261,7 +255,7 @@ sub passwd_read { if ($verbose && $sh && !$shell{&basename($sh)} && $p_username !~ /^(news|xten|bin|nobody|uucp)$/ && - $sh !~ /\/(pppd|sliplogin)$/); + $sh !~ /\/(pppd|sliplogin|nologin|nonexistent)$/); $uid{$p_uid} = $p_username; $pwgid{$p_gid} = $p_username; } @@ -277,9 +271,13 @@ sub group_read { while() { chop; push(@group_backup, $_); - # ignore comments + # Ignore empty lines next if /^\s*$/; - next if /^\s*#/; + # Save comments to restore later + if (/^\s*\#/) { + push(@group_comments, $_); + next; + } ($g_groupname, $pw, $g_gid, $memb) = (split(/:/, $_))[0..3]; @@ -321,7 +319,7 @@ sub new_users_name { warn "Username is longer than 16 chars\a\n"; next; } - last if (&new_users_name_valid($name) eq $name); + last if (&new_users_name_valid($name)); } return $name; } @@ -329,14 +327,14 @@ sub new_users_name { sub new_users_name_valid { local($name) = @_; - if ($name !~ /^[a-z0-9_][a-z0-9_\-]*$/) { + if ($name !~ /^[a-z0-9_][a-z0-9_\-]*$/ || $name eq "a-z0-9_-") { warn "Wrong username. " . "Please use only lowercase characters or digits\a\n"; return 0; } elsif ($username{$name}) { warn "Username ``$name'' already exists!\a\n"; return 0; } - return $name; + return 1; } # return full name @@ -369,6 +367,20 @@ sub new_users_shell { return $shell{$sh}; } +# return home (full path) for user +# Note that the home path defaults to $home/$name for batch +sub new_users_home { + local($name) = @_; + local($userhome); + + while(1) { + $userhome = &confirm_list("Enter home directory (full path)", 1, "$home/$name", ""); + last if $userhome =~ /^\//; + warn qq{Home directory "$userhome" is not a full path\a\n}; + } + return $userhome; +} + # return free uid and gid sub new_users_id { local($name) = @_; @@ -381,12 +393,15 @@ sub new_users_id { ! $uid{$u_id_tmp}; if ($uid{$u_id_tmp}) { warn "Uid ``$u_id_tmp'' in use!\a\n"; + $uid_start = $u_id_tmp; + ($u_id, $g_id) = &next_id($name); + next; } else { warn "Wrong uid.\a\n"; } } # use calculated uid - return ($u_id_tmp, $g_id) if $u_id_tmp eq $u_id; + # return ($u_id_tmp, $g_id) if $u_id_tmp eq $u_id; # recalculate gid $uid_start = $u_id_tmp; return &next_id($name); @@ -397,8 +412,8 @@ sub new_users_class { local($def) = @_; local($class); - $class = &confirm_list("Enter login class:", 1, $def, ($def, "no")); - $class = "" if $class eq "no"; + $class = &confirm_list("Enter login class:", 1, $def, ($def, "default")); + $class = "" if $class eq "default"; return $class; } @@ -461,29 +476,6 @@ sub new_users_grplogin { return ($group_login, $group_login); } -# return login group -sub new_users_grplogin_batch { - local($name, $defaultgroup) = @_; - local($group_login, $group); - - $group_login = $name; - $group_login = $defaultgroup if $defaultgroup ne $group_uniq; - - if (defined $gid{$group_login}) { - # convert numeric groupname (gid) to groupname - $group_login = $gid{$group_login}; - } - - # if (defined($groupname{$group_login})) { - # &add_group($groupname{$group_login}, $name); - # } - - return $group_login - if defined($groupname{$group_login}) || $group_login eq $name; - warn "Group ``$group_login'' does not exist\a\n"; - return 0; -} - # return other groups (string) sub new_users_groups { local($name, $other_groups) = @_; @@ -535,17 +527,30 @@ sub new_users_groups_valid { # your last change sub new_users_ok { + local ($newpasswd); + # Note that we either show "password disabled" or + # "****" .. we don't show "empty password" since + # the whole point of starring out the password in + # the first place is to stop people looking over your + # shoulder and seeing the password.. -- adrian + if ($usepassword eq "no") { + $newpasswd = "Password disabled"; + } elsif ($enableaccount eq "no") { + $newpasswd = "Password disabled"; + } else { + $newpasswd = "****"; + } print < $b} (keys %gid)) { push(@a, "$gid{$e}:*:$e:$groupmembers{$e}"); } @@ -649,9 +658,6 @@ sub sendmessage { sub new_users_password { - # empty password - return "" if $defaultpasswd ne "yes"; - local($password); while(1) { @@ -675,6 +681,29 @@ sub new_users_password { return $password; } +sub new_users_use_password { + local ($p) = $defaultusepassword; + $p = &confirm_yn("Use password-based authentication", $defaultusepassword); + return "yes" if (($defaultusepassword eq "yes" && $p) || + ($defaultusepassword eq "no" && !$p)); + return "no"; # otherwise +} + +sub new_users_enable_account { + local ($p) = $defaultenableaccount; + $p = &confirm_yn("Enable account password at creation", $defaultenableaccount); + return "yes" if (($defaultenableaccount eq "yes" && $p) || + ($defaultenableaccount eq "no" && !$p)); + return "no"; # otherwise +} + +sub new_users_empty_password { + local ($p) = $defaultemptypassword; + $p = &confirm_yn("Use an empty password", $defaultemptypassword); + return "yes" if (($defaultemptypassword eq "yes" && $p) || + ($defaultemptypassword eq "no" && !$p)); + return "no"; # otherwise +} sub new_users { @@ -686,12 +715,14 @@ sub new_users { # name: Username # fullname: Full name # sh: shell + # userhome: home path for user # u_id: user id # g_id: group id # class: login class # group_login: groupname of g_id # new_groups: some other groups local($name, $group_login, $fullname, $sh, $u_id, $g_id, $class, $new_groups); + local($userhome); local($groupmembers_bak, $cryptpwd); local($new_users_ok) = 1; @@ -703,6 +734,7 @@ sub new_users { $name = &new_users_name; $fullname = &new_users_fullname($name); $sh = &new_users_shell; + $userhome = &new_users_home($name); ($u_id, $g_id) = &new_users_id($name); $class = &new_users_class($defaultclass); ($group_login, $defaultgroup) = @@ -710,25 +742,64 @@ sub new_users { # do not use uniq username and login group $g_id = $groupname{$group_login} if (defined($groupname{$group_login})); + + # The tricky logic: + # If $usepasswd is 0, we use a * as a password + # If $usepasswd is 1, then + # if $enableaccount is 0, we prepend * as a password + # else if $enableaccount is 1 we don't prepend anything + # if $useemptypassword is 0 we ask for a password, + # else we use a blank one + # + # The logic is tasty, I'll give you that, but its flexible and + # it'll stop people shooting themselves in the foot. + $new_groups = &new_users_groups($name, $new_groups); - $password = &new_users_password; + $usepassword = &new_users_use_password; + if ($usepassword eq "no") { + # note that the assignments to enableaccount and + # useemptypassword functionally do the same as + # usepasswd == "no". Just for consistency. + $password = ""; # no password! + $enableaccount = "no"; # doesn't matter here + $useemptypassword = "yes"; # doesn't matter here + } else { + $useemptypassword = &new_users_empty_password; + if ($useemptypassword eq "no") { + $password = &new_users_password; + } + $enableaccount = &new_users_enable_account; + } if (&new_users_ok) { $new_users_ok = 1; $cryptpwd = ""; $cryptpwd = crypt($password, &salt) if $password ne ""; + + if ($usepassword eq "no") { + $cryptpwd = "*"; + } else { + # cryptpwd is valid before this if mess, so if + # blankpasswd is no we don't blank the cryptpwd + if ($useemptypassword eq "yes") { + $cryptpwd = ""; + } + if ($enableaccount eq "no") { + $cryptpwd = "*" . $cryptpwd; + } + } # obscure perl bug $new_entry = "$name\:" . "$cryptpwd" . - "\:$u_id\:$g_id\:$class\:0:0:$fullname:$home/$name:$sh"; + "\:$u_id\:$g_id\:$class\:0:0:$fullname:$userhome:$sh"; &append_file($etc_passwd, "$new_entry"); - &new_users_pwdmkdb("$new_entry"); + &new_users_pwdmkdb("$new_entry", $name); &new_users_group_update; &new_users_passwd_update; print "Added user ``$name''\n"; &new_users_sendmessage; &adduser_log("$name:*:$u_id:$g_id($group_login):$fullname"); - &home_create($name, $group_login); + &home_create($userhome, $name, $group_login); } else { $new_users_ok = 0; } @@ -740,51 +811,42 @@ sub new_users { } } -sub batch { - local($name, $groups, $class, $fullname, $password) = @_; - local($sh); - - $defaultshell = &shell_default_valid($defaultshell); - return 0 unless $home = &home_partition_valid($home); - return 0 if $dotdir ne &dotdir_default_valid($dotdir); - $send_message = &message_default; - - return 0 if $name ne &new_users_name_valid($name); - $sh = $shell{$defaultshell}; - ($u_id, $g_id) = &next_id($name); - $group_login = &new_users_grplogin_batch($name, $defaultgroup); - return 0 unless $group_login; - $g_id = $groupname{$group_login} if (defined($groupname{$group_login})); - ($flag, $new_groups) = &new_users_groups_valid($groups); - return 0 if $flag; - - $class = $defaultclass if $class eq ""; - $cryptpwd = ""; - $cryptpwd = crypt($password, &salt) if $password ne ""; - # obscure perl bug - $new_entry = "$name\:" . "$cryptpwd" . - "\:$u_id\:$g_id\:$class\:0:0:$fullname:$home/$name:$sh"; - &append_file($etc_passwd, "$new_entry"); - &new_users_pwdmkdb("$new_entry"); - &new_users_group_update; - &new_users_passwd_update; print "Added user ``$name''\n"; - &sendmessage($name, @message_buffer) if $send_message ne "no"; - &adduser_log("$name:*:$u_id:$g_id($group_login):$fullname"); - &home_create($name, $group_login); -} - # ask for password usage sub password_default { - local($p) = $defaultpasswd; + local($p) = $defaultusepassword; if ($verbose) { - $p = &confirm_yn("Use passwords", $defaultpasswd); + $p = &confirm_yn("Use password-based authentication", $defaultusepassword); $changes++ unless $p; } - return "yes" if (($defaultpasswd eq "yes" && $p) || - ($defaultpasswd eq "no" && !$p)); + return "yes" if (($defaultusepassword eq "yes" && $p) || + ($defaultusepassword eq "no" && !$p)); return "no"; # otherwise } +# ask for account enable usage +sub enable_account_default { + local ($p) = $defaultenableaccount; + if ($verbose) { + $p = &confirm_yn("Enable account password at creation", $defaultenableaccount); + $changes++ unless $p; + } + return "yes" if (($defaultenableaccount eq "yes" && $p) || + ($defaultenableaccount eq "no" && !$p)); + return "no"; # otherwise +} + +# ask for empty password +sub enable_empty_password { + local ($p) = $defaultemptypassword; + if ($verbose) { + $p = &confirm_yn("Use an empty password", $defaultemptypassword); + $changes++ unless $p; + } + return "yes" if (($defaultemptypassword eq "yes" && $p) || + ($defaultemptypassword eq "no" && !$p)); + return "no"; # otherwise +} + # misc sub check_root { die "You are not root!\n" if $< && !$test; @@ -793,7 +855,6 @@ sub check_root { sub usage { warn < 1; # to64 - for ($i = 0; $i < 8; $i++) { + for ($i = 0; $i < 27; $i++) { srand(time + $rand + $$); $rand = rand(25*29*17 + $rand); $salt .= $itoa64[$rand & $#itoa64]; @@ -853,10 +914,10 @@ sub copyright { # hints sub hints { if ($verbose) { - print "Use option ``-silent'' if you don't want see " . - "all warnings & questions.\n\n"; + print "Use option ``-silent'' if you don't want to see " . + "all warnings and questions.\n\n"; } else { - print "Use option ``-verbose'' if you want see more warnings & " . + print "Use option ``-verbose'' if you want to see more warnings and " . "questions \nor try to repair bugs.\n\n"; } } @@ -882,8 +943,9 @@ sub parse_arguments { elsif (/^--?(message)$/) { $send_message = $argv[0]; shift @argv; $sendmessage = 1; } elsif (/^--?(batch)$/) { - @batch = splice(@argv, 0, 5); $verbose = 0; - die "batch: too few arguments\n" if $#batch < 0; + warn "The -batch option is not supported anymore.\n", + "Please use the pw(8) command line tool!\n"; + exit(0); } # see &config_read elsif (/^--?(config_create)$/) { &create_conf; } @@ -943,6 +1005,7 @@ sub adduser_log { return 1 if $logfile eq "no"; local($sec, $min, $hour, $mday, $mon, $year) = localtime; + $year += 1900; $mon++; foreach $e ('sec', 'min', 'hour', 'mday', 'mon', 'year') { @@ -955,17 +1018,28 @@ sub adduser_log { # create HOME directory, copy dotfiles from $dotdir to $HOME sub home_create { - local($name, $group) = @_; - local($homedir) = "$home/$name"; + local($homedir, $name, $group) = @_; + local($rootdir); if (-e "$homedir") { warn "HOME Directory ``$homedir'' already exist\a\n"; return 0; } + # if the home directory prefix doesn't exist, create it + # First, split the directory into a list; then remove the user's dir + @dir = split('/', $homedir); pop(@dir); + # Put back together & strip to get directory prefix + $rootdir = &stripdir(join('/', @dir)); + + if (!&mkdirhier("$rootdir")) { + # warn already displayed + return 0; + } + if ($dotdir eq 'no') { - if (!mkdir("$homedir",0755)) { - warn "mkdir $homedir: $!\n"; return 0; + if (!mkdir("$homedir", 0755)) { + warn "$dir: $!\n"; return 0; } system 'chown', "$name:$group", $homedir; return !$?; @@ -974,7 +1048,7 @@ sub home_create { # copy files from $dotdir to $homedir # rename 'dot.foo' files to '.foo' print "Copy files from $dotdir to $homedir\n" if $verbose; - system("cp -r $dotdir $homedir"); + system("cp -R $dotdir $homedir"); system("chmod -R u+wrX,go-w $homedir"); system("chown -R $name:$group $homedir"); @@ -1001,7 +1075,6 @@ sub mkdir_home { local($user_partition) = "/usr"; local($dirname) = &dirname($dir); - -e $dirname || &mkdirhier($dirname); if (((stat($dirname))[0]) == ((stat("/"))[0])){ @@ -1325,7 +1398,9 @@ sub config_write { # prepare some variables $send_message = "no" unless $send_message; - $defaultpasswd = "no" unless $defaultpasswd; + $defaultusepassword = "no" unless $defaultusepassword; + $defaultenableaccount = "yes" unless $defaultenableaccount; + $defaultemptypassword = "no" unless $defaultemptypassword; local($shpref) = "'" . join("', '", @shellpref) . "'"; local($shpath) = "'" . join("', '", @path) . "'"; local($user_var) = join('', @user_variable_list); @@ -1335,16 +1410,25 @@ sub config_write { # $config - automatic generated by adduser(8) # # Note: adduser read *and* write this file. -# You may change values, but don't add new things befor the +# You may change values, but don't add new things before the # line ``$do_not_delete'' # # verbose = [0-2] verbose = $verbose -# use password for new users -# defaultpasswd = yes | no -defaultpasswd = $defaultpasswd +# use password-based authentication for new users +# defaultusepassword = "yes" | "no" +defaultusepassword = "$defaultusepassword" + +# enable account password at creation +# (the password will be prepended with a star if the account isn't enabled) +# defaultenableaccount = "yes" | "no" +defaultenableaccount = "$defaultenableaccount" + +# allow blank passwords +# defaultemptypassword = "yes" | "no" +defaultemptypassword = "$defaultemptypassword" # copy dotfiles from this dir ("/usr/share/skel" or "no") dotdir = "$dotdir" @@ -1379,7 +1463,7 @@ defaultgroup = $defaultgroup defaultclass = "$defaultclass" # new users get this uid (1000) -uid_start = 1000 +uid_start = "$uid_start" $do_not_delete ## your own variables, see /etc/adduser.message @@ -1401,7 +1485,7 @@ $check_only = 0; &config_read(@ARGV); # read variables form config-file &parse_arguments(@ARGV); # parse arguments -if (!$check_only && $#batch < 0) { +if (!$check_only) { ©right; &hints; } @@ -1414,7 +1498,6 @@ $changes = 0; &group_check; # check for incon* exit 0 if $check_only; # only check consistence and exit -exit(!&batch(@batch)) if $#batch >= 0; # batch mode # interactive # some questions @@ -1423,7 +1506,17 @@ $defaultshell = &shell_default; # enter default shell $home = &home_partition($home); # find HOME partition $dotdir = &dotdir_default; # check $dotdir $send_message = &message_default; # send message to new user -$defaultpasswd = &password_default; # maybe use password +$defaultusepassword = &password_default; # maybe use password +if ($defaultusepassword eq "no") { + if ($verbose) { + print "Creating accounts with a locked password.\n"; + } + $defaultenableaccount = "no"; + $defaultemptypassword = "yes"; +} else { + $defaultenableaccount = &enable_account_default; # enable or disable account + $defaultemptypassword = &enable_empty_password; # use empty password or not +} &config_write(!$verbose); # write variables in file # main loop for creating new users