1#!/usr/bin/perl 2# 3# $OpenBSD: adduser.perl,v 1.53 2007/01/03 15:26:04 simon Exp $ 4# 5# Copyright (c) 1995-1996 Wolfram Schneider <wosch@FreeBSD.org>. Berlin. 6# All rights reserved. 7# 8# Redistribution and use in source and binary forms, with or without 9# modification, are permitted provided that the following conditions 10# are met: 11# 1. Redistributions of source code must retain the above copyright 12# notice, this list of conditions and the following disclaimer. 13# 2. Redistributions in binary form must reproduce the above copyright 14# notice, this list of conditions and the following disclaimer in the 15# documentation and/or other materials provided with the distribution. 16# 17# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27# SUCH DAMAGE. 28# 29# $From: adduser.perl,v 1.22 1996/12/07 21:25:12 ache Exp $ 30 31use IPC::Open2; 32use Fcntl qw(:DEFAULT :flock); 33 34################ 35# main 36# 37$test = 0; # test mode, only for development 38$check_only = 0; 39 40$SIG{'INT'} = 'cleanup'; 41$SIG{'QUIT'} = 'cleanup'; 42$SIG{'HUP'} = 'cleanup'; 43$SIG{'TERM'} = 'cleanup'; 44 45&check_root; # you must be root to run this script! 46&variables; # initialize variables 47&config_read(@ARGV); # read variables from config-file 48&parse_arguments(@ARGV); # parse arguments 49 50if (!$check_only && $#batch < 0) { 51 &hints; 52} 53 54# check 55$changes = 0; 56&variable_check; # check for valid variables 57&passwd_check; # check for valid passwdb 58&shells_read; # read /etc/shells 59&login_conf_read; # read /etc/login.conf 60&passwd_read; # read /etc/master.passwd 61&group_read; # read /etc/group 62&group_check; # check for incon* 63exit 0 if $check_only; # only check consistence and exit 64 65exit(!&batch(@batch)) if $#batch >= 0; # batch mode 66 67# Interactive: 68# main loop for creating new users 69&new_users; # add new users 70 71#end 72 73 74# Set adduser "default" variables internally before groking config file 75# Adduser.conf supersedes these 76sub variables { 77 $verbose = 1; # verbose = [0-2] 78 $defaultpasswd = "yes"; # use password for new users 79 $dotdir = "/etc/skel"; # copy dotfiles from this dir 80 $dotdir_bak = $dotdir; 81 $send_message = "no"; # send message to new user 82 $send_message_bak = '/etc/adduser.message'; 83 $config = "/etc/adduser.conf"; # config file for adduser 84 $config_read = 1; # read config file 85 $logfile = "/var/log/adduser"; # logfile 86 $home = "/home"; # default HOME 87 $etc_shells = "/etc/shells"; 88 $etc_passwd = "/etc/master.passwd"; 89 $etc_ptmp = "/etc/ptmp"; 90 $group = "/etc/group"; 91 $etc_login_conf = "/etc/login.conf"; 92 @pwd_mkdb = ("pwd_mkdb", "-p"); # program for building passwd database 93 $encryptionmethod = "auto"; 94 $rcsid = '$OpenBSD: adduser.perl,v 1.53 2007/01/03 15:26:04 simon Exp $'; 95 96 # List of directories where shells located 97 @path = ('/bin', '/usr/bin', '/usr/local/bin'); 98 # common shells, first element has higher priority 99 @shellpref = ('csh', 'sh', 'bash', 'tcsh', 'ksh'); 100 101 @encryption_methods = ('auto', 'blowfish', 'md5', 'des', 'old'); 102 103 $defaultshell = 'ksh'; # defaultshell if not empty 104 $group_uniq = 'USER'; 105 $defaultgroup = $group_uniq;# login groupname, $group_uniq means username 106 $defaultclass = 'default'; # default user login class 107 108 $uid_start = 1000; # new users get this uid 109 $uid_end = 2147483647; # max. uid 110 111 # global variables 112 # passwd 113 %username = (); # $username{username} = uid 114 %uid = (); # $uid{uid} = username 115 %pwgid = (); # $pwgid{pwgid} = username; gid from passwd db 116 117 $password = ''; # password for new users 118 119 # group 120 %groupname = (); # $groupname{groupname} = gid 121 %groupmembers = (); # $groupmembers{gid} = members of group/kommalist 122 %gid = (); # $gid{gid} = groupname; gid from group db 123 124 # shell 125 %shell = (); # $shell{`basename sh`} = sh 126 127 # only for me (=Wolfram) 128 if ($test) { 129 $home = "/home/w/tmp/adduser/home"; 130 $etc_shells = "./shells"; 131 $etc_passwd = "./master.passwd"; 132 $group = "./group"; 133 @pwd_mkdb = ("pwd_mkdb", "-p", "-d", "."); 134 $config = "adduser.conf"; 135 $send_message = "./adduser.message"; 136 $logfile = "./log.adduser"; 137 } 138 139 umask 022; # don't give login group write access 140 141 $ENV{'PATH'} = "/sbin:/bin:/usr/sbin:/usr/bin"; 142 @passwd_backup = (); 143 @group_backup = (); 144 @message_buffer = (); 145 @login_classes = (); 146 @user_variable_list = (); # user variables in /etc/adduser.conf 147 $do_not_delete = '## DO NOT DELETE THIS LINE!'; 148} 149 150sub login_conf_read { 151 foreach (`getcap -f $etc_login_conf -a -s localcipher`) { 152 chomp; 153 s/:.*//; 154 push(@login_classes, $_); 155 } 156} 157 158# read shell database, see also: shells(5) 159sub shells_read { 160 local($sh); 161 local($err) = 0; 162 163 print "Reading $etc_shells\n" if $verbose; 164 open(S, $etc_shells) || die "$etc_shells: $!\n"; 165 166 while(<S>) { 167 if (/^\s*\//) { 168 s/^\s*//; s/\s+.*//; # chop 169 $sh = $_; 170 if (-x $sh) { 171 $shell{&basename($sh)} = $sh; 172 } else { 173 warn "Shell: $sh not executable!\n"; 174 $err++; 175 } 176 } 177 } 178 close(S); 179 180 push(@list, "/sbin/nologin"); 181 &shell_pref_add("nologin"); 182 $shell{"nologin"} = "/sbin/nologin"; 183 184 return $err; 185} 186 187# add new shells if possible 188sub shells_add { 189 local($sh,$dir,@list); 190 191 return 1 unless $verbose; 192 193 foreach $sh (@shellpref) { 194 # all known shells 195 if (!$shell{$sh}) { 196 # shell $sh is not defined as login shell 197 foreach $dir (@path) { 198 if (-x "$dir/$sh") { 199 # found shell 200 if (&confirm_yn("Found shell: $dir/$sh. Add to $etc_shells?", "yes")) { 201 push(@list, "$dir/$sh"); 202 &shell_pref_add("$sh"); 203 $shell{&basename("$dir/$sh")} = "$dir/$sh"; 204 $changes++; 205 } 206 } 207 } 208 } 209 } 210 &append_file($etc_shells, @list) if $#list >= 0; 211} 212 213# add shell to preference list without duplication 214sub shell_pref_add { 215 local($new_shell) = @_; 216 local($shell); 217 218 foreach $shell (@shellpref) { 219 return if ($shell eq $new_shell); 220 } 221 push(@shellpref, $new_shell); 222} 223 224# choose your favourite shell and return the shell 225sub shell_default { 226 local($e,$i,$new_shell); 227 local($sh); 228 229 $sh = &shell_default_valid($defaultshell); 230 return $sh unless $verbose; 231 232 $new_shell = &confirm_list("Enter your default shell:", 0, 233 $sh, sort(keys %shell)); 234 print "Your default shell is: $new_shell -> $shell{$new_shell}\n"; 235 $changes++ if $new_shell ne $sh; 236 return $new_shell; 237} 238 239sub shell_default_valid { 240 local($sh) = @_; 241 local($s,$e); 242 243 return $sh if $shell{$sh}; 244 245 foreach $e (@shellpref) { 246 $s = $e; 247 last if defined($shell{$s}); 248 } 249 $s = "sh" unless $s; 250 warn "Shell ``$sh'' is undefined, use ``$s''\n"; 251 return $s; 252} 253 254# return default home partition (f.e. "/home") 255# create base directory if necessary 256sub home_partition { 257 local($home) = @_; 258 $home = &stripdir($home); 259 local($h) = $home; 260 261 return $h if !$verbose && $h eq &home_partition_valid($h); 262 263 while(1) { 264 $h = &confirm_list("Enter your default HOME partition:", 1, $home, ""); 265 $h = &stripdir($h); 266 last if $h eq &home_partition_valid($h); 267 } 268 269 $changes++ if $h ne $home; 270 return $h; 271} 272 273sub home_partition_valid { 274 local($h) = @_; 275 276 $h = &stripdir($h); 277 # all right (I hope) 278 return $h if $h =~ "^/" && -e $h && -w _ && (-d _ || -l $h); 279 280 # Errors or todo 281 if ($h !~ "^/") { 282 warn "Please use absolute path for home: ``$h''.\a\n"; 283 return 0; 284 } 285 286 if (-e $h) { 287 warn "$h exists, but is not a directory or symlink!\n" 288 unless -d $h || -l $h; 289 warn "$h is not writable!\n" 290 unless -w $h; 291 return 0; 292 } else { 293 # create home partition 294 return $h if &mkdir_home($h); 295 } 296 return 0; 297} 298 299# check for valid passwddb 300sub passwd_check { 301 system(@pwd_mkdb, "-c", $etc_passwd); 302 die "\nInvalid $etc_passwd - cannot add any users!\n" if $?; 303} 304 305# read /etc/passwd 306sub passwd_read { 307 local($p_username, $pw, $p_uid, $p_gid, $sh); 308 309 print "Check $etc_passwd\n" if $verbose; 310 open(P, "$etc_passwd") || die "$etc_passwd: $!\n"; 311 312 # we only use this to lock the password file 313 sysopen(PTMP, $etc_ptmp, O_RDWR|O_CREAT|O_EXCL, 0600) || 314 die "Password file busy\n"; 315 316 while(<P>) { 317 chop; 318 push(@passwd_backup, $_); 319 ($p_username, $pw, $p_uid, $p_gid, $sh) = (split(/:/, $_))[0..3,9]; 320 321 print "$p_username already exists with uid: $username{$p_username}!\n" 322 if $username{$p_username} && $verbose; 323 $username{$p_username} = $p_uid; 324 print "User $p_username: uid $p_uid exists twice: $uid{$p_uid}\n" 325 if $uid{$p_uid} && $verbose && $p_uid; # don't warn for uid 0 326 print "User $p_username: illegal shell: ``$sh''\n" 327 if ($verbose && $sh && 328 !$shell{&basename($sh)} && 329 $p_username !~ /^(news|xten|bin|nobody|uucp)$/ && 330 $sh !~ /\/(pppd|sliplogin)$/); 331 $uid{$p_uid} = $p_username; 332 $pwgid{$p_gid} = $p_username; 333 } 334 close P; 335} 336 337# read /etc/group 338sub group_read { 339 local($g_groupname,$pw,$g_gid, $memb); 340 341 print "Check $group\n" if $verbose; 342 open(G, "$group") || die "$group: $!\n"; 343 while(<G>) { 344 chop; 345 push(@group_backup, $_); 346 ($g_groupname, $pw, $g_gid, $memb) = (split(/:/, $_))[0..3]; 347 348 $groupmembers{$g_gid} = $memb; 349 warn "Groupname exists twice: $g_groupname:$g_gid -> $g_groupname:$groupname{$g_groupname}\n" 350 if $groupname{$g_groupname} && $verbose; 351 $groupname{$g_groupname} = $g_gid; 352 warn "Groupid exists twice: $g_groupname:$g_gid -> $gid{$g_gid}:$g_gid\n" 353 if $gid{$g_gid} && $verbose; 354 $gid{$g_gid} = $g_groupname; 355 } 356 close G; 357} 358 359# check gids /etc/passwd <-> /etc/group 360sub group_check { 361 local($c_gid, $c_username, @list); 362 363 foreach $c_gid (keys %pwgid) { 364 if (!$gid{$c_gid}) { 365 $c_username = $pwgid{$c_gid}; 366 warn "User ``$c_username'' has gid $c_gid but a group with this " . 367 "gid does not exist.\n" if $verbose; 368 } 369 } 370} 371 372# 373# main loop for creating new users 374# 375 376# return username 377sub new_users_name { 378 local($name); 379 380 while(1) { 381 $name = &confirm_list("Enter username", 1, "", ""); 382 if (length($name) > 31) { 383 warn "Username is longer than 31 characters\a\n"; 384 next; 385 } 386 last if (&new_users_name_valid($name) eq $name); 387 } 388 return $name; 389} 390 391sub new_users_name_valid { 392 local($name) = @_; 393 394 if ($name !~ /^[a-zA-Z0-9_\.][a-zA-Z0-9_\.\-]*\$?$/ || $name eq "") { 395 warn "Illegal username. " . 396 "Please see the restrictions section of the man page.\a\n"; 397 return 0; 398 } elsif ($username{$name}) { 399 warn "Username ``$name'' already exists!\a\n"; return 0; 400 } 401 return $name; 402} 403 404# return full name 405sub new_users_fullname { 406 local($name) = @_; 407 local($fullname); 408 409 while(1) { 410 $fullname = &confirm_list("Enter full name", 1, "", ""); 411 last if $fullname eq &new_users_fullname_valid($fullname); 412 } 413 $fullname = $name unless $fullname; 414 return $fullname; 415} 416 417sub new_users_fullname_valid { 418 local($fullname) = @_; 419 420 return $fullname if $fullname !~ /:/; 421 422 warn "``:'' is not allowed!\a\n"; 423 return 0; 424} 425 426# return shell (full path) for user 427sub new_users_shell { 428 local($sh); 429 430 $sh = &confirm_list("Enter shell", 0, $defaultshell, keys %shell); 431 return $shell{$sh}; 432} 433 434sub new_users_login_class { 435 local($log_cl); 436 437 $log_cl = &confirm_list("Login class", 0, $defaultclass, @login_classes); 438 return($log_cl); 439} 440 441# return free uid and gid 442sub new_users_id { 443 local($name) = @_; 444 local($u_id, $g_id) = &next_id($name); 445 local($u_id_tmp, $e); 446 447 while(1) { 448 $u_id_tmp = &confirm_list("Uid", 1, $u_id, ""); 449 last if $u_id_tmp =~ /^[0-9]+$/ && $u_id_tmp <= $uid_end && 450 ! $uid{$u_id_tmp}; 451 if ($uid{$u_id_tmp}) { 452 warn "Uid ``$u_id_tmp'' in use!\a\n"; 453 } else { 454 warn "Wrong uid.\a\n"; 455 } 456 } 457 # use calculated uid 458 return ($u_id_tmp, $g_id) if $u_id_tmp eq $u_id; 459 # recalculate gid 460 $uid_start = $u_id_tmp; 461 return &next_id($name); 462} 463 464# add user to group 465sub add_group { 466 local($gid, $name) = @_; 467 468 return 0 if 469 $groupmembers{$gid} =~ /^(.*,)?$name(,.*)?$/; 470 471 $groupmembers_bak{$gid} = $groupmembers{$gid}; 472 $groupmembers{$gid} .= "," if $groupmembers{$gid}; 473 $groupmembers{$gid} .= "$name"; 474 475 local(@l) = split(',', $groupmembers{$gid}); 476 # group(5): A group cannot have more than 200 members. 477 # The maximum line length of /etc/group is 1024 characters. 478 # Longer lines will be skipped. 479 if ($#l >= 200 || 480 length($groupmembers{$gid}) > 1024 - 50) { # 50 is for group name 481 warn "WARNING, group line ``$gid{$gid}'' is either too long or has\n" . 482 "too many users in the group, see group(5)\a\n"; 483 } 484 return $name; 485} 486 487 488# return login group 489sub new_users_grplogin { 490 local($name, $defaultgroup, $new_users_ok) = @_; 491 local($group_login, $group); 492 493 $group = $name; 494 $group = $defaultgroup if $defaultgroup ne $group_uniq; 495 496 if ($new_users_ok) { 497 # clean up backup 498 foreach $e (keys %groupmembers_bak) { delete $groupmembers_bak{$e}; } 499 } else { 500 # restore old groupmembers, user was not accept 501 foreach $e (keys %groupmembers_bak) { 502 $groupmembers{$e} = $groupmembers_bak{$e}; 503 } 504 } 505 506 while(1) { 507 $group_login = &confirm_list("Login group", 1, $group, 508 ($name, $group)); 509 last if $group_login eq $group; 510 last if $group_login eq $name; 511 last if defined $groupname{$group_login}; 512 if ($group_login eq $group_uniq) { 513 $group_login = $name; last; 514 } 515 516 if (defined $gid{$group_login}) { 517 # convert numeric groupname (gid) to groupname 518 $group_login = $gid{$group_login}; 519 last; 520 } 521 warn "Group does not exist!\a\n"; 522 } 523 524 #if (defined($groupname{$group_login})) { 525 # &add_group($groupname{$group_login}, $name); 526 #} 527 528 return ($group_login, $group_uniq) if $group_login eq $name; 529 return ($group_login, $group_login); 530} 531 532# return login group 533sub new_users_grplogin_batch { 534 local($name, $defaultgroup) = @_; 535 local($group_login, $group); 536 537 $group_login = $name; 538 $group_login = $defaultgroup if $defaultgroup ne $group_uniq; 539 540 if (defined $gid{$group_login}) { 541 # convert numeric groupname (gid) to groupname 542 $group_login = $gid{$group_login}; 543 } 544 545 # if (defined($groupname{$group_login})) { 546 # &add_group($groupname{$group_login}, $name); 547 # } 548 549 return $group_login 550 if defined($groupname{$group_login}) || $group_login eq $name; 551 warn "Group ``$group_login'' does not exist\a\n"; 552 return 0; 553} 554 555# return other groups (string) 556sub new_users_groups { 557 local($name, $other_groups) = @_; 558 local($string) = 559 "Login group is ``$group_login''. Invite $name into other groups:"; 560 local($e, $flag); 561 local($new_groups,$groups); 562 563 $other_groups = "no" unless $other_groups; 564 565 while(1) { 566 $groups = &confirm_list($string, 1, $other_groups, 567 ("no", $other_groups, "guest")); 568 # no other groups 569 return "" if $groups eq "no"; 570 571 ($flag, $new_groups) = &new_users_groups_valid($groups); 572 last unless $flag; 573 } 574 $new_groups =~ s/\s*$//; 575 return $new_groups; 576} 577 578sub new_users_groups_valid { 579 local($groups) = @_; 580 local($e, $new_groups); 581 local($flag) = 0; 582 583 foreach $e (split(/[,\s]+/, $groups)) { 584 # convert numbers to groupname 585 if ($e =~ /^[0-9]+$/ && $gid{$e}) { 586 $e = $gid{$e}; 587 } 588 if (defined($groupname{$e})) { 589 if ($e eq $group_login) { 590 # do not add user to a group if this group 591 # is also the login group. 592 } elsif (&add_group($groupname{$e}, $name)) { 593 $new_groups .= "$e "; 594 } else { 595 warn "$name is already member of group ``$e''\n"; 596 } 597 } else { 598 warn "Group ``$e'' does not exist\a\n"; $flag++; 599 } 600 } 601 return ($flag, $new_groups); 602} 603 604# your last change 605sub new_users_ok { 606 607 print <<EOF; 608 609Name: $name 610Password: **** 611Fullname: $fullname 612Uid: $u_id 613Gid: $g_id ($group_login) 614Groups: $group_login $new_groups 615Login Class: $log_cl 616HOME: $home/$name 617Shell: $sh 618EOF 619 620 return &confirm_yn("OK?", "yes"); 621} 622 623# make password database 624sub new_users_pwdmkdb { 625 local($last) = @_; 626 local($user); 627 628 $user = (split(/:/, $last))[0]; 629 system(@pwd_mkdb, "-u", $user, $etc_passwd); 630 if ($?) { 631 warn "$last\n"; 632 warn "``pwd_mkdb'' failed\n"; 633 exit($? >> 8); 634 } 635} 636 637# update group database 638sub new_users_group_update { 639 local($e, $n, $a, @a); 640 641 # Add *new* group 642 if (!defined($groupname{$group_login}) && !defined($gid{$g_id})) { 643 push(@group_backup, "$group_login:*:$g_id:"); 644 $groupname{$group_login} = $g_id; 645 $gid{$g_id} = $group_login; 646 # $groupmembers{$g_id} = $group_login; 647 } 648 649 if ($new_groups || defined($groupname{$group_login}) || 650 defined($gid{$groupname{$group_login}}) && 651 $gid{$groupname{$group_login}} ne "+") { 652 # new user is member of some groups 653 # new login group is already in name space 654 rename($group, "$group.bak"); 655 #warn "$group_login $groupname{$group_login} $groupmembers{$groupname{$group_login}}\n"; 656 foreach (@group_backup) { 657 ($n, $e) = (split(/:/, $_))[0,2]; 658 # special handling of YP entries 659 if (substr($n, 0, 1) eq "+") { 660 # remember and skip the empty group 661 if (length($n) == 1) { 662 $a = $_; 663 next; 664 } 665 # pass other groups 666 push(@a, $_); 667 } 668 # group membership might have changed 669 else { 670 push(@a, "$gid{$e}:*:$e:$groupmembers{$e}"); 671 } 672 } 673 # append empty YP group 674 if ($a) { 675 push(@a, $a); 676 } 677 &append_file($group, @a); 678 } else { 679 &append_file($group, "$group_login:*:$g_id:"); 680 } 681 682} 683 684sub new_users_passwd_update { 685 # update passwd/group variables 686 push(@passwd_backup, $new_entry); 687 $username{$name} = $u_id; 688 $uid{$u_id} = $name; 689 $pwgid{$g_id} = $name; 690} 691 692# send message to new user 693sub new_users_sendmessage { 694 return 1 if $send_message eq "no"; 695 696 local($cc) = 697 &confirm_list("Send message to ``$name'' and:", 698 1, "no", ("root", "second_mail_address", 699 "no carbon copy")); 700 local($e); 701 $cc = "" if $cc eq "no"; 702 703 @message_buffer = (); 704 message_read ($send_message); 705 706 foreach $e (@message_buffer) { 707 print eval "\"$e\""; 708 } 709 print "\n"; 710 711 local(@message_buffer_append) = (); 712 if (!&confirm_yn("Add anything to default message", "no")) { 713 print "Use ``.'' or ^D alone on a line to finish your message.\n"; 714 push(@message_buffer_append, "\n"); 715 while($read = <STDIN>) { 716 last if $read eq "\.\n"; 717 push(@message_buffer_append, $read); 718 } 719 } 720 721 &sendmessage("$name $cc", (@message_buffer, @message_buffer_append)) 722 if (&confirm_yn("Send message", "yes")); 723} 724 725sub sendmessage { 726 local($to, @message) = @_; 727 local($e); 728 729 if (!open(M, "| mail -s Welcome $to")) { 730 warn "Cannot send mail to: $to!\n"; 731 return 0; 732 } else { 733 foreach $e (@message) { 734 print M eval "\"$e\""; 735 } 736 close M; 737 } 738} 739 740 741sub new_users_password { 742 743 # empty password 744 return "" if $defaultpasswd ne "yes"; 745 746 local($password); 747 748 while(1) { 749 system("stty", "-echo"); 750 $password = &confirm_list("Enter password", 1, "", ""); 751 system("stty", "echo"); 752 print "\n"; 753 if ($password ne "") { 754 system("stty", "-echo"); 755 $newpass = &confirm_list("Enter password again", 1, "", ""); 756 system("stty", "echo"); 757 print "\n"; 758 last if $password eq $newpass; 759 print "They didn't match, please try again\n"; 760 } 761 elsif (!&confirm_yn("Set the password so that user cannot logon?", "no")) { 762 last; 763 } 764 } 765 766 return $password; 767} 768 769 770sub new_users { 771 772 print "\n" if $verbose; 773 print "Ok, let's go.\n" . 774 "Don't worry about mistakes. There will be a chance later to " . 775 "correct any input.\n" if $verbose; 776 777 # name: Username 778 # fullname: Full name 779 # sh: shell 780 # u_id: user id 781 # g_id: group id 782 # group_login: groupname of g_id 783 # new_groups: some other groups 784 # log_cl: login class 785 local($name, $group_login, $fullname, $sh, $u_id, $g_id, $new_groups, 786 $log_cl); 787 local($groupmembers_bak, $cryptpwd); 788 local($new_users_ok) = 1; 789 790 791 $new_groups = "no" unless $groupname{$new_groups}; 792 793 while(1) { 794 $name = &new_users_name; 795 $fullname = &new_users_fullname($name); 796 $sh = &new_users_shell; 797 ($u_id, $g_id) = &new_users_id($name); 798 ($group_login, $defaultgroup) = 799 &new_users_grplogin($name, $defaultgroup, $new_users_ok); 800 # do not use uniq username and login group 801 $g_id = $groupname{$group_login} if (defined($groupname{$group_login})); 802 803 $new_groups = &new_users_groups($name, $new_groups); 804 $log_cl = &new_users_login_class; 805 $password = &new_users_password; 806 807 808 if (&new_users_ok) { 809 $new_users_ok = 1; 810 811 $cryptpwd = "*"; # Locked by default 812 $cryptpwd = encrypt($password, &salt) if ($password ne ""); 813 $log_cl = "" if ($log_cl eq "default"); 814 815 # obscure perl bug 816 $new_entry = "$name\:" . "$cryptpwd" . 817 "\:$u_id\:$g_id\:$log_cl:0:0:$fullname:$home/$name:$sh"; 818 &append_file($etc_passwd, "$new_entry"); 819 &new_users_pwdmkdb("$new_entry"); 820 &new_users_group_update; 821 &new_users_passwd_update; print "Added user ``$name''\n"; 822 &adduser_log("$name:*:$u_id:$g_id($group_login):$fullname"); 823 &home_create($name, $group_login); 824 &new_users_sendmessage; 825 } else { 826 $new_users_ok = 0; 827 } 828 if (!&confirm_yn("Add another user?", "yes")) { 829 print "Goodbye!\n" if $verbose; 830 last; 831 } 832 print "\n" if !$verbose; 833 } 834} 835 836sub batch { 837 local($name, $groups, $fullname, $password) = @_; 838 local($sh); 839 840 $defaultshell = &shell_default_valid($defaultshell); 841 return 0 unless $home = &home_partition_valid($home); 842 return 0 if $dotdir ne &dotdir_default_valid($dotdir); 843 $send_message = &message_default; 844 845 return 0 if $name ne &new_users_name_valid($name); 846 $sh = $shell{$defaultshell}; 847 ($u_id, $g_id) = &next_id($name); 848 $group_login = &new_users_grplogin_batch($name, $defaultgroup); 849 return 0 unless $group_login; 850 $g_id = $groupname{$group_login} if (defined($groupname{$group_login})); 851 ($flag, $new_groups) = &new_users_groups_valid($groups); 852 return 0 if $flag; 853 $log_cl = ($defaultclass eq "default") ? "" : $defaultclass; 854 855 $cryptpwd = "*"; # Locked by default 856 if ($password ne "" && $password ne "*") { 857 if($unencrypted) { $cryptpwd = encrypt($password, &salt) } 858 else { $cryptpwd = $password } 859 } 860 # obscure perl bug 861 $new_entry = "$name\:" . "$cryptpwd" . 862 "\:$u_id\:$g_id\:$log_cl:0:0:$fullname:$home/$name:$sh"; 863 &append_file($etc_passwd, "$new_entry"); 864 &new_users_pwdmkdb("$new_entry"); 865 &new_users_group_update; 866 &new_users_passwd_update; print "Added user ``$name''\n"; 867 &sendmessage($name, @message_buffer) if $send_message ne "no"; 868 &adduser_log("$name:*:$u_id:$g_id($group_login):$fullname"); 869 &home_create($name, $group_login); 870} 871 872# ask for password usage 873sub password_default { 874 local($p) = $defaultpasswd; 875 if ($verbose) { 876 $p = &confirm_yn("Prompt for passwords by default", $defaultpasswd); 877 $changes++ unless $p; 878 } 879 return "yes" if (($defaultpasswd eq "yes" && $p) || 880 ($defaultpasswd eq "no" && !$p)); 881 return "no"; # otherwise 882} 883 884# get default encryption method 885sub encryption_default { 886 local($m) = ""; 887 if ($verbose) { 888 while (&encryption_check($m) == 0) { 889 $m = &confirm_list("Default encryption method for passwords:", 1, 890 $encryption_methods[0], @encryption_methods); 891 } 892 } 893 return($m); 894} 895 896sub class_default { 897 local($c) = $defaultclass; 898 899 if ($verbose) { 900 $c = &confirm_list("Default login class:", 0, 901 $defaultclass, @login_classes); 902 $changes++ if $c ne $defaultclass; 903 } 904 return($c); 905} 906 907# Confirm that we have a valid encryption method 908sub encryption_check { 909 local($m) = $_[0]; 910 911 foreach $i (@encryption_methods) { 912 if ($m eq $i) { return 1; } 913 } 914 915 if ($m =~ /^blowfish,(\d+)$/) { return 1; } 916 return 0; 917} 918 919# misc 920sub check_root { 921 die "You are not root!\n" if $< && !$test; 922} 923 924sub usage { 925 warn <<USAGE; 926usage: adduser 927 [-batch username [group[,group]...] [fullname] [password]] 928 [-check_only] 929 [-config_create] 930 [-dotdir dotdir] 931 [-e|-encryption method] 932 [-group login_group] 933 [-class login_class] 934 [-h|-help] 935 [-home home] 936 [-message message_file] 937 [-noconfig] 938 [-shell shell] 939 [-s|-silent|-q|-quiet] 940 [-uid_start uid_start] 941 [-uid_end uid_end] 942 [-unencrypted] 943 [-v|-verbose] 944 945home=$home shell=$defaultshell dotdir=$dotdir login_group=$defaultgroup 946login_class=$defaultclass message_file=$send_message uid_start=$uid_start 947uid_end=$uid_end 948USAGE 949 exit 1; 950} 951 952# uniq(1) 953sub uniq { 954 local(@list) = @_; 955 local($e, $last = "", @array); 956 957 foreach $e (sort @list) { 958 push(@array, $e) unless $e eq $last; 959 $last = $e; 960 } 961 return @array; 962} 963 964# Generate an appropriate argument to encrypt() 965# That may be a DES salt or a blowfish rotation count 966sub salt { 967 local($salt); # initialization 968 if ($encryptionmethod eq "des" || $encryptionmethod eq "old") { 969 local($i, $rand); 970 local(@itoa64) = ( '0' .. '9', 'a' .. 'z', 'A' .. 'Z' ); # 0 .. 63 971 972 warn "calculate salt\n" if $verbose > 1; 973 974 for ($i = 0; $i < 8; $i++) { 975 srand(time + $rand + $$); 976 $rand = rand(25*29*17 + $rand); 977 $salt .= $itoa64[$rand & $#itoa64]; 978 } 979 } elsif ($encryptionmethod eq "md5" || $encryptionmethod eq "auto") { 980 $salt = ""; 981 } elsif ($encryptionmethod =~ /^blowfish/ ) { 982 ($encryptionmethod, $salt) = split(/\,/, $encryptionmethod); 983 $salt = 7 unless $salt; # default rounds if unspecified 984 } else { 985 warn "$encryptionmethod encryption method invalid\n" if ($verbose > 0); 986 warn "Falling back to blowfish,7...\n" if ($verbose > 0); 987 $encryptionmethod = "blowfish"; 988 $salt = 7; 989 } 990 991 warn "Salt is: $salt\n" if $verbose > 1; 992 993 return $salt; 994} 995 996# Encrypt a password using the selected method 997sub encrypt { 998 local($pass, $salt) = ($_[0], $_[1]); 999 local(@args, $crypt); 1000 1001 if ($encryptionmethod eq "des" || $encryptionmethod eq "old") { 1002 @args = ("-s", $salt); 1003 } elsif ($encryptionmethod eq "md5") { 1004 @args = ("-m"); 1005 } elsif ($encryptionmethod eq "blowfish") { 1006 @args = ("-b", $salt); 1007 } elsif ($encryptionmethod eq "auto") { 1008 @args = ("-c", $log_cl); 1009 } 1010 1011 open2(\*ENCRD, \*ENCWR, "/usr/bin/encrypt", @args); 1012 print ENCWR "$pass\n"; 1013 close ENCWR; 1014 $crypt = <ENCRD>; 1015 close ENCRD; 1016 chomp $crypt; 1017 die "encrypt failed" if (wait == -1 || $? != 0); 1018 return($crypt); 1019} 1020 1021# hints 1022sub hints { 1023 if ($verbose) { 1024 print "Use option ``-silent'' if you don't want to see " . 1025 "all warnings and questions.\n\n"; 1026 } 1027} 1028 1029# 1030sub parse_arguments { 1031 local(@argv) = @_; 1032 1033 while ($_ = $argv[0], /^-/) { 1034 shift @argv; 1035 last if /^--$/; 1036 if (/^--?(v|verbose)$/) { $verbose = 1 } 1037 elsif (/^--?(s|silent|q|quiet)$/) { $verbose = 0 } 1038 elsif (/^--?(debug)$/) { $verbose = 2 } 1039 elsif (/^--?(h|help|\?)$/) { &usage } 1040 elsif (/^--?(home)$/) { $home = $argv[0]; shift @argv } 1041 elsif (/^--?(shell)$/) { $defaultshell = $argv[0]; shift @argv } 1042 elsif (/^--?(class)$/) { $defaultclass = $argv[0]; shift @argv } 1043 elsif (/^--?(dotdir)$/) { $dotdir = $argv[0]; shift @argv } 1044 elsif (/^--?(uid_start)$/) { $uid_start = $argv[0]; shift @argv } 1045 elsif (/^--?(uid_end)$/) { $uid_end = $argv[0]; shift @argv } 1046 elsif (/^--?(group)$/) { $defaultgroup = $argv[0]; shift @argv } 1047 elsif (/^--?(check_only)$/) { $check_only = 1 } 1048 elsif (/^--?(message)$/) { $send_message = $argv[0]; shift @argv; 1049 $sendmessage = 1; } 1050 elsif (/^--?(unencrypted)$/) { $unencrypted = 1 } 1051 elsif (/^--?(batch)$/) { 1052 @batch = splice(@argv, 0, 4); $verbose = 0; 1053 die "batch: too few arguments\n" if $#batch < 0; 1054 } 1055 # see &config_read 1056 elsif (/^--?(config_create)$/) { &hints; &create_conf; exit(0); } 1057 elsif (/^--?(noconfig)$/) { $config_read = 0; } 1058 elsif (/^--?(e|encryption)$/) { 1059 $encryptionmethod = $argv[0]; 1060 shift @argv; 1061 } 1062 else { &usage } 1063 } 1064 #&usage if $#argv < 0; 1065} 1066 1067sub basename { 1068 local($name) = @_; 1069 $name =~ s|/+$||; 1070 $name =~ s|.*/+||; 1071 return $name; 1072} 1073 1074sub dirname { 1075 local($name) = @_; 1076 $name = &stripdir($name); 1077 $name =~ s|/+[^/]+$||; 1078 $name = "/" unless $name; # dirname of / is / 1079 return $name; 1080} 1081 1082# return 1 if $file is a readable file or link 1083sub filetest { 1084 local($file, $verbose) = @_; 1085 1086 if (-e $file) { 1087 if (-f $file || -l $file) { 1088 return 1 if -r _; 1089 warn "$file unreadable\n" if $verbose; 1090 } else { 1091 warn "$file is not a plain file or link\n" if $verbose; 1092 } 1093 } 1094 return 0; 1095} 1096 1097# create or recreate configuration file prompting for values 1098sub create_conf { 1099 $create_conf = 1; 1100 1101 &shells_read; # Pull in /etc/shells info 1102 &shells_add; # maybe add some new shells 1103 $defaultshell = &shell_default; # enter default shell 1104 &login_conf_read; # read /etc/login.conf 1105 $defaultclass = &class_default; # default login.conf class 1106 $home = &home_partition($home); # find HOME partition 1107 $dotdir = &dotdir_default; # check $dotdir 1108 $send_message = &message_default; # send message to new user 1109 $defaultpasswd = &password_default; # maybe use password 1110 $defaultencryption = &encryption_default; # Encryption method 1111 1112 if ($send_message ne 'no') { 1113 &message_create($send_message); 1114 } else { 1115 &message_create($send_message_bak); 1116 } 1117 &config_write(1); 1118} 1119 1120# log for new user in /var/log/adduser 1121sub adduser_log { 1122 local($string) = @_; 1123 local($e); 1124 1125 return 1 if $logfile eq "no"; 1126 1127 local($sec, $min, $hour, $mday, $mon, $year) = localtime; 1128 $year += 1900; 1129 $mon++; 1130 1131 foreach $e ('sec', 'min', 'hour', 'mday', 'mon') { 1132 # '7' -> '07' 1133 eval "\$$e = 0 . \$$e" if (eval "\$$e" < 10); 1134 } 1135 1136 &append_file($logfile, "$year/$mon/$mday $hour:$min:$sec $string"); 1137} 1138 1139# create HOME directory, copy dotfiles from $dotdir to $HOME 1140sub home_create { 1141 local($name, $group) = @_; 1142 local($homedir) = "$home/$name"; 1143 1144 if (-e "$homedir") { 1145 warn "HOME Directory ``$homedir'' already exists\a\n"; 1146 return 0; 1147 } 1148 1149 if ($dotdir eq 'no') { 1150 if (!mkdir("$homedir", 0755)) { 1151 warn "mkdir $homedir: $!\n"; return 0; 1152 } 1153 system 'chown', "$name:$group", $homedir; 1154 return !$?; 1155 } 1156 1157 # copy files from $dotdir to $homedir 1158 # rename 'dot.foo' files to '.foo' 1159 print "Copy files from $dotdir to $homedir\n" if $verbose; 1160 system("cp", "-R", $dotdir, $homedir); 1161 system("chmod", "-R", "u+wrX,go-w", $homedir); 1162 system("chown", "-R", "$name:$group", $homedir); 1163 1164 # security 1165 opendir(D, $homedir); 1166 foreach $file (readdir(D)) { 1167 if ($file =~ /^dot\./ && -f "$homedir/$file") { 1168 $file =~ s/^dot\././; 1169 rename("$homedir/dot$file", "$homedir/$file"); 1170 } 1171 chmod(0600, "$homedir/$file") 1172 if ($file =~ /^\.(rhosts|Xauthority|kermrc|netrc)$/); 1173 chmod(0700, "$homedir/$file") 1174 if ($file =~ /^(Mail|prv|\.(iscreen|term))$/); 1175 } 1176 closedir D; 1177 return 1; 1178} 1179 1180# makes a directory hierarchy 1181sub mkdir_home { 1182 local($dir) = @_; 1183 $dir = &stripdir($dir); 1184 local($user_partition) = "/usr"; 1185 local($dirname) = &dirname($dir); 1186 1187 1188 -e $dirname || &mkdirhier($dirname); 1189 1190 if (((stat($dirname))[0]) == ((stat("/"))[0])){ 1191 # home partition is on root partition 1192 # create home partition on $user_partition and make 1193 # a symlink from $dir to $user_partition/`basename $dir` 1194 # For instance: /home -> /usr/home 1195 1196 local($basename) = &basename($dir); 1197 local($d) = "$user_partition/$basename"; 1198 1199 1200 if (-d $d) { 1201 warn "Oops, $d already exists\n" if $verbose; 1202 } else { 1203 print "Create $d\n" if $verbose; 1204 if (!mkdir("$d", 0755)) { 1205 warn "$d: $!\a\n"; return 0; 1206 } 1207 } 1208 1209 unlink($dir); # symlink to nonexist file 1210 print "Create symlink: $dir -> $d\n" if $verbose; 1211 if (!symlink("$d", $dir)) { 1212 warn "Symlink $d: $!\a\n"; return 0; 1213 } 1214 } else { 1215 print "Create $dir\n" if $verbose; 1216 if (!mkdir("$dir", 0755)) { 1217 warn "Directory ``$dir'': $!\a\n"; return 0; 1218 } 1219 } 1220 return 1; 1221} 1222 1223sub mkdirhier { 1224 local($dir) = @_; 1225 local($d,$p); 1226 1227 $dir = &stripdir($dir); 1228 1229 foreach $d (split('/', $dir)) { 1230 $dir = "$p/$d"; 1231 $dir =~ s|^//|/|; 1232 if (! -e "$dir") { 1233 print "Create $dir\n" if $verbose; 1234 if (!mkdir("$dir", 0755)) { 1235 warn "$dir: $!\n"; return 0; 1236 } 1237 } 1238 $p .= "/$d"; 1239 } 1240 return 1; 1241} 1242 1243# stript unused '/' 1244# F.i.: //usr///home// -> /usr/home 1245sub stripdir { 1246 local($dir) = @_; 1247 1248 $dir =~ s|/+|/|g; # delete double '/' 1249 $dir =~ s|/$||; # delete '/' at end 1250 return $dir if $dir ne ""; 1251 return '/'; 1252} 1253 1254# Read one of the elements from @list. $confirm is default. 1255# If !$allow accept only elements from @list. 1256sub confirm_list { 1257 local($message, $allow, $confirm, @list) = @_; 1258 local($read, $c, $print); 1259 1260 $print = "$message" if $message; 1261 $print .= " " unless $message =~ /\n$/ || $#list == 0; 1262 1263 $print .= join($", &uniq(@list)); #" 1264 $print .= " " unless $message =~ /\n$/ && $#list == 0; 1265 print "$print"; 1266 print "\n" if (length($print) + length($confirm)) > 60; 1267 print "[$confirm]: "; 1268 1269 chop($read = <STDIN>); 1270 $read =~ s/^\s*//; 1271 $read =~ s/\s*$//; 1272 return $confirm if $read eq ""; 1273 return "$read" if $allow; 1274 1275 foreach $c (@list) { 1276 return $read if $c eq $read; 1277 } 1278 warn "$read: is not allowed!\a\n"; 1279 return &confirm_list($message, $allow, $confirm, @list); 1280} 1281 1282# YES or NO question 1283# return 1 if &confirm("message", "yes") and answer is yes 1284# or if &confirm("message", "no") an answer is no 1285# otherwise 0 1286sub confirm_yn { 1287 local($message, $confirm) = @_; 1288 local($yes) = '^(yes|YES|y|Y)$'; 1289 local($no) = '^(no|NO|n|N)$'; 1290 local($read, $c); 1291 1292 if ($confirm && ($confirm =~ "$yes" || $confirm == 1)) { 1293 $confirm = "y"; 1294 } else { 1295 $confirm = "n"; 1296 } 1297 print "$message (y/n) [$confirm]: "; 1298 chop($read = <STDIN>); 1299 $read =~ s/^\s*//; 1300 $read =~ s/\s*$//; 1301 return 1 unless $read; 1302 1303 if (($confirm eq "y" && $read =~ "$yes") || 1304 ($confirm eq "n" && $read =~ "$no")) { 1305 return 1; 1306 } 1307 1308 if ($read !~ "$yes" && $read !~ "$no") { 1309 warn "Wrong value. Enter again!\a\n"; 1310 return &confirm_yn($message, $confirm); 1311 } 1312 return 0; 1313} 1314 1315# test if $dotdir exist 1316# return "no" if $dotdir not exist or dotfiles should not copied 1317sub dotdir_default { 1318 local($dir) = $dotdir; 1319 1320 return &dotdir_default_valid($dir) unless $verbose; 1321 while($verbose) { 1322 $dir = &confirm_list("Copy dotfiles from:", 1, 1323 $dir, ("no", $dotdir_bak, $dir)); 1324 last if $dir eq &dotdir_default_valid($dir); 1325 } 1326 warn "Do not copy dotfiles.\n" if $verbose && $dir eq "no"; 1327 1328 $changes++ if $dir ne $dotdir; 1329 return $dir; 1330} 1331 1332sub dotdir_default_valid { 1333 local($dir) = @_; 1334 1335 return $dir if (-e $dir && -r _ && (-d _ || -l $dir) && $dir =~ "^/"); 1336 return $dir if $dir eq "no"; 1337 warn "Dotdir ``$dir'' is not a directory\a\n"; 1338 return "no"; 1339} 1340 1341# ask for messages to new users 1342sub message_default { 1343 local($file) = $send_message; 1344 local(@d) = ($file, $send_message_bak, "no"); 1345 1346 while($verbose) { 1347 $file = &confirm_list("Send message from file:", 1, $file, @d); 1348 last if $file eq "no"; 1349 last if &filetest($file, 1); 1350 1351 # maybe create message file 1352 &message_create($file) if &confirm_yn("Create ``$file''?", "yes"); 1353 last if &filetest($file, 0); 1354 last if !&confirm_yn("File ``$file'' does not exist, try again?", 1355 "yes"); 1356 } 1357 1358 if ($file eq "no" || !&filetest($file, 0)) { 1359 warn "Do not send message\n" if $verbose; 1360 $file = "no"; 1361 } else { 1362 &message_read($file); 1363 } 1364 1365 $changes++ if $file ne $send_message && $verbose; 1366 return $file; 1367} 1368 1369# create message file 1370sub message_create { 1371 local($file) = @_; 1372 1373 rename($file, "$file.bak"); 1374 if (!open(M, "> $file")) { 1375 warn "Messagefile ``$file'': $!\n"; return 0; 1376 } 1377 print M <<EOF; 1378# 1379# Message file for adduser(8) 1380# comment: ``#'' 1381# default variables: \$name, \$fullname, \$password 1382# other variables: see /etc/adduser.conf after 1383# line ``$do_not_delete'' 1384# 1385 1386\$fullname, 1387 1388your account ``\$name'' was created. 1389Have fun! 1390 1391See also chpass(1), finger(1), passwd(1) 1392EOF 1393 close M; 1394 return 1; 1395} 1396 1397# read message file into buffer 1398sub message_read { 1399 local($file) = @_; 1400 @message_buffer = (); 1401 1402 if (!open(R, "$file")) { 1403 warn "File ``$file'':$!\n"; return 0; 1404 } 1405 while(<R>) { 1406 push(@message_buffer, $_) unless /^\s*#/; 1407 } 1408 close R; 1409} 1410 1411# write @list to $file with file-locking 1412sub append_file { 1413 local($file,@list) = @_; 1414 local($e); 1415 1416 open(F, ">> $file") || die "$file: $!\n"; 1417 print "Lock $file.\n" if $verbose > 1; 1418 while(!flock(F, LOCK_EX | LOCK_NB)) { 1419 warn "Cannot lock file: $file\a\n"; 1420 die "Sorry, gave up\n" 1421 unless &confirm_yn("Try again?", "yes"); 1422 } 1423 print F join("\n", @list) . "\n"; 1424 print "Unlock $file.\n" if $verbose > 1; 1425 flock(F, LOCK_UN); 1426 close F; 1427} 1428 1429# return free uid+gid 1430# uid == gid if possible 1431sub next_id { 1432 local($group) = @_; 1433 1434 $uid_start = 1000 if ($uid_start <= 0 || $uid_start >= $uid_end); 1435 # looking for next free uid 1436 while($uid{$uid_start}) { 1437 $uid_start++; 1438 $uid_start = 1000 if $uid_start >= $uid_end; 1439 print "$uid_start\n" if $verbose > 1; 1440 } 1441 1442 local($gid_start) = $uid_start; 1443 # group for user (username==groupname) already exist 1444 if ($groupname{$group}) { 1445 $gid_start = $groupname{$group}; 1446 } 1447 # gid is in use, looking for another gid. 1448 # Note: uid and gid are not equal 1449 elsif ($gid{$uid_start}) { 1450 while($gid{$gid_start} || $uid{$gid_start}) { 1451 $gid_start--; 1452 $gid_start = $uid_end if $gid_start < 100; 1453 } 1454 } 1455 return ($uid_start, $gid_start); 1456} 1457 1458# read config file - typically /etc/adduser.conf 1459sub config_read { 1460 local($opt) = join " ", @_; 1461 local($user_flag) = 0; 1462 1463 # don't read config file 1464 return 1 if $opt =~ /-(noconfig|config_create)/ || !$config_read; 1465 1466 if (!-f $config) { 1467 warn("Couldn't find $config: creating a new adduser configuration file\n"); 1468 &create_conf; 1469 } 1470 1471 if (!open(C, "$config")) { 1472 warn "$config: $!\n"; return 0; 1473 } 1474 1475 while(<C>) { 1476 # user defined variables 1477 /^$do_not_delete/ && $user_flag++; 1478 # found @array or $variable 1479 if (s/^(\w+\s*=\s*\()/\@$1/ || s/^(\w+\s*=)/\$$1/) { 1480 eval $_; 1481 #warn "$_"; 1482 } 1483 next if /^$/; 1484 # lines with '^##' are not saved 1485 push(@user_variable_list, $_) 1486 if $user_flag && !/^##/ && (s/^[\$\@]// || /^[#\s]/); 1487 } 1488 #warn "X @user_variable_list X\n"; 1489 close C; 1490} 1491 1492 1493# write config file 1494sub config_write { 1495 local($silent) = @_; 1496 1497 # nothing to do 1498 return 1 unless ($changes || ! -e $config || !$config_read || $silent); 1499 1500 if (!$silent) { 1501 if (-e $config) { 1502 return 1 if &confirm_yn("\nWrite your changes to $config?", "no"); 1503 } else { 1504 return 1 unless 1505 &confirm_yn("\nWrite your configuration to $config?", "yes"); 1506 } 1507 } 1508 1509 rename($config, "$config.bak"); 1510 open(C, "> $config") || die "$config: $!\n"; 1511 1512 # prepare some variables 1513 $send_message = "no" unless $send_message; 1514 $defaultpasswd = "no" unless $defaultpasswd; 1515 local($shpref) = "'" . join("', '", @shellpref) . "'"; 1516 local($shpath) = "'" . join("', '", @path) . "'"; 1517 local($user_var) = join('', @user_variable_list); 1518 local($def_lc) = "'" . join("', '", @login_classes) . "'"; 1519 1520 print C <<EOF; 1521# 1522# $rcsid 1523# $config - automatic generated by adduser(8) 1524# 1525# Note: adduser reads *and* writes this file. 1526# You may change values, but don't add new things before the 1527# line ``$do_not_delete'' 1528# 1529 1530# verbose = [0-2] 1531verbose = $verbose 1532 1533# Get new password for new users 1534# defaultpasswd = yes | no 1535defaultpasswd = $defaultpasswd 1536 1537# Default encryption method for user passwords 1538# Methods are all those listed in login.conf(5) 1539encryptionmethod = "$defaultencryption" 1540 1541# copy dotfiles from this dir ("/etc/skel" or "no") 1542dotdir = "$dotdir" 1543 1544# send this file to new user ("/etc/adduser.message" or "no") 1545send_message = "$send_message" 1546 1547# config file for adduser ("/etc/adduser.conf") 1548config = "$config" 1549 1550# logfile ("/var/log/adduser" or "no") 1551logfile = "$logfile" 1552 1553# default HOME directory ("/home") 1554home = "$home" 1555 1556# List of directories where shells located 1557# path = ('/bin', '/usr/bin', '/usr/local/bin') 1558path = ($shpath) 1559 1560# common shell list, first element has higher priority 1561# shellpref = ('bash', 'tcsh', 'ksh', 'csh', 'sh') 1562shellpref = ($shpref) 1563 1564# defaultshell if not empty ("bash") 1565defaultshell = "$defaultshell" 1566 1567# defaultgroup ('USER' for same as username or any other valid group) 1568defaultgroup = $defaultgroup 1569 1570# new users get this uid 1571uid_start = $uid_start 1572uid_end = $uid_end 1573 1574# default login.conf(5) login class 1575defaultclass = $defaultclass 1576 1577# login classes available from login.conf(5) 1578# login_classes = ('default', 'daemon', 'staff') 1579login_classes = ($def_lc) 1580 1581$do_not_delete 1582## your own variables, see /etc/adduser.message 1583EOF 1584 print C "$user_var\n" if ($user_var ne ''); 1585 print C "\n## end\n"; 1586 close C; 1587} 1588 1589# check for sane variables 1590sub variable_check { 1591 # Check uid_start & uid_end 1592 warn "WARNING: uid_start < 1000!\n" if($uid_start < 1000); 1593 die "ERROR: uid_start >= uid_end!\n" if($uid_start >= $uid_end); 1594 # unencrypted really only usable in batch mode 1595 warn "WARNING: unencrypted only effective in batch mode\n" 1596 if($#batch < 0 && $unencrypted); 1597} 1598 1599sub cleanup { 1600 local($sig) = @_; 1601 1602 print STDERR "Caught signal SIG$sig -- cleaning up.\n"; 1603 system("stty", "echo"); 1604 exit(0); 1605} 1606 1607END { 1608 if (-e $etc_ptmp && defined(fileno(PTMP))) { 1609 close PTMP; 1610 unlink($etc_ptmp) || warn "Error: unable to remove $etc_ptmp: $!\nPlease verify that $etc_ptmp no longer exists!\n"; 1611 } 1612} 1613