1#!/bin/sh 2# 3# Copyright (c) 2002-2004 Michael Telahun Makonnen. All rights reserved. 4# 5# Redistribution and use in source and binary forms, with or without 6# modification, are permitted provided that the following conditions 7# are met: 8# 1. Redistributions of source code must retain the above copyright 9# notice, this list of conditions and the following disclaimer. 10# 2. Redistributions in binary form must reproduce the above copyright 11# notice, this list of conditions and the following disclaimer in the 12# documentation and/or other materials provided with the distribution. 13# 14# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 15# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 16# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 17# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 18# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 19# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 20# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 21# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 23# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24# 25# Email: Mike Makonnen <mtm@FreeBSD.Org> 26# 27# $FreeBSD$ 28# 29 30# err msg 31# Display $msg on stderr, unless we're being quiet. 32# 33err() { 34 if [ -z "$quietflag" ]; then 35 echo 1>&2 ${THISCMD}: ERROR: $* 36 fi 37} 38 39# info msg 40# Display $msg on stdout, unless we're being quiet. 41# 42info() { 43 if [ -z "$quietflag" ]; then 44 echo ${THISCMD}: INFO: $* 45 fi 46} 47 48# get_nextuid 49# Output the value of $_uid if it is available for use. If it 50# is not, output the value of the next higher uid that is available. 51# If a uid is not specified, output the first available uid, as indicated 52# by pw(8). 53# 54get_nextuid () { 55 _uid=$1 56 _nextuid= 57 58 if [ -z "$_uid" ]; then 59 _nextuid="`${PWCMD} usernext | cut -f1 -d:`" 60 else 61 while : ; do 62 ${PWCMD} usershow $_uid > /dev/null 2>&1 63 if [ ! "$?" -eq 0 ]; then 64 _nextuid=$_uid 65 break 66 fi 67 _uid=$(($_uid + 1)) 68 done 69 fi 70 echo $_nextuid 71} 72 73# show_usage 74# Display usage information for this utility. 75# 76show_usage() { 77 echo "usage: ${THISCMD} [options]" 78 echo " options may include:" 79 echo " -C save to the configuration file only" 80 echo " -D do not attempt to create the home directory" 81 echo " -E disable this account after creation" 82 echo " -G additional groups to add accounts to" 83 echo " -L login class of the user" 84 echo " -M file permission for home directory" 85 echo " -N do not read configuration file" 86 echo " -S a nonexistent shell is not an error" 87 echo " -d home directory" 88 echo " -f file from which input will be received" 89 echo " -g default login group" 90 echo " -h display this usage message" 91 echo " -k path to skeleton home directory" 92 echo " -m user welcome message file" 93 echo " -q absolute minimal user feedback" 94 echo " -s shell" 95 echo " -u uid to start at" 96 echo " -w password type: no, none, yes or random" 97} 98 99# valid_shells 100# Outputs a list of valid shells from /etc/shells. Only the 101# basename of the shell is output. 102# 103valid_shells() { 104 _prefix= 105 cat ${ETCSHELLS} | 106 while read _path _junk ; do 107 case $_path in 108 \#*|'') 109 ;; 110 *) 111 echo -n "${_prefix}`basename $_path`" 112 _prefix=' ' 113 ;; 114 esac 115 done 116 117 # /usr/sbin/nologin is a special case 118 [ -x "${NOLOGIN_PATH}" ] && echo -n " ${NOLOGIN}" 119} 120 121# fullpath_from_shell shell 122# Given $shell, which is either the full path to a shell or 123# the basename component of a valid shell, get the 124# full path to the shell from the /etc/shells file. 125# 126fullpath_from_shell() { 127 _shell=$1 128 [ -z "$_shell" ] && return 1 129 130 # /usr/sbin/nologin is a special case; it needs to be handled 131 # before the cat | while loop, since a 'return' from within 132 # a subshell will not terminate the function's execution, and 133 # the path to the nologin shell might be printed out twice. 134 # 135 if [ "$_shell" = "${NOLOGIN}" -o \ 136 "$_shell" = "${NOLOGIN_PATH}" ]; then 137 echo ${NOLOGIN_PATH} 138 return 0; 139 fi 140 141 cat ${ETCSHELLS} | 142 while read _path _junk ; do 143 case "$_path" in 144 \#*|'') 145 ;; 146 *) 147 if [ "$_path" = "$_shell" -o \ 148 "`basename $_path`" = "$_shell" ]; then 149 echo $_path 150 return 0 151 fi 152 ;; 153 esac 154 done 155 156 return 1 157} 158 159# shell_exists shell 160# If the given shell is listed in ${ETCSHELLS} or it is 161# the nologin shell this function will return 0. 162# Otherwise, it will return 1. If shell is valid but 163# the path is invalid or it is not executable it 164# will emit an informational message saying so. 165# 166shell_exists() 167{ 168 _sh="$1" 169 _shellchk="${GREPCMD} '^$_sh$' ${ETCSHELLS} > /dev/null 2>&1" 170 171 if ! eval $_shellchk; then 172 # The nologin shell is not listed in /etc/shells. 173 if [ "$_sh" != "${NOLOGIN_PATH}" ]; then 174 err "Invalid shell ($_sh) for user $username." 175 return 1 176 fi 177 fi 178 ! [ -x "$_sh" ] && 179 info "The shell ($_sh) does not exist or is not executable." 180 181 return 0 182} 183 184# save_config 185# Save some variables to a configuration file. 186# Note: not all script variables are saved, only those that 187# it makes sense to save. 188# 189save_config() { 190 echo "# Configuration file for adduser(8)." > ${ADDUSERCONF} 191 echo "# NOTE: only *some* variables are saved." >> ${ADDUSERCONF} 192 echo "# Last Modified on `${DATECMD}`." >> ${ADDUSERCONF} 193 echo '' >> ${ADDUSERCONF} 194 echo "defaultHomePerm=$uhomeperm" >> ${ADDUSERCONF} 195 echo "defaultLgroup=$ulogingroup" >> ${ADDUSERCONF} 196 echo "defaultclass=$uclass" >> ${ADDUSERCONF} 197 echo "defaultgroups=$ugroups" >> ${ADDUSERCONF} 198 echo "passwdtype=$passwdtype" >> ${ADDUSERCONF} 199 echo "homeprefix=$homeprefix" >> ${ADDUSERCONF} 200 echo "defaultshell=$ushell" >> ${ADDUSERCONF} 201 echo "udotdir=$udotdir" >> ${ADDUSERCONF} 202 echo "msgfile=$msgfile" >> ${ADDUSERCONF} 203 echo "disableflag=$disableflag" >> ${ADDUSERCONF} 204 echo "uidstart=$uidstart" >> ${ADDUSERCONF} 205} 206 207# add_user 208# Add a user to the user database. If the user chose to send a welcome 209# message or lock the account, do so. 210# 211add_user() { 212 213 # Is this a configuration run? If so, don't modify user database. 214 # 215 if [ -n "$configflag" ]; then 216 save_config 217 return 218 fi 219 220 _uid= 221 _name= 222 _comment= 223 _gecos= 224 _home= 225 _group= 226 _grouplist= 227 _shell= 228 _class= 229 _dotdir= 230 _expire= 231 _pwexpire= 232 _passwd= 233 _upasswd= 234 _passwdmethod= 235 236 _name="-n '$username'" 237 [ -n "$uuid" ] && _uid='-u "$uuid"' 238 [ -n "$ulogingroup" ] && _group='-g "$ulogingroup"' 239 [ -n "$ugroups" ] && _grouplist='-G "$ugroups"' 240 [ -n "$ushell" ] && _shell='-s "$ushell"' 241 [ -n "$uclass" ] && _class='-L "$uclass"' 242 [ -n "$ugecos" ] && _comment='-c "$ugecos"' 243 [ -n "$udotdir" ] && _dotdir='-k "$udotdir"' 244 [ -n "$uexpire" ] && _expire='-e "$uexpire"' 245 [ -n "$upwexpire" ] && _pwexpire='-p "$upwexpire"' 246 if [ -z "$Dflag" -a -n "$uhome" ]; then 247 # The /nonexistent home directory is special. It 248 # means the user has no home directory. 249 if [ "$uhome" = "$NOHOME" ]; then 250 _home='-d "$uhome"' 251 else 252 # Use home directory permissions if specified 253 if [ -n "$uhomeperm" ]; then 254 _home='-m -d "$uhome" -M "$uhomeperm"' 255 else 256 _home='-m -d "$uhome"' 257 fi 258 fi 259 elif [ -n "$Dflag" -a -n "$uhome" ]; then 260 _home='-d "$uhome"' 261 fi 262 case $passwdtype in 263 no) 264 _passwdmethod="-w no" 265 _passwd="-h -" 266 ;; 267 yes) 268 # Note on processing the password: The outer double quotes 269 # make literal everything except ` and \ and $. 270 # The outer single quotes make literal ` and $. 271 # We can ensure the \ isn't treated specially by specifying 272 # the -r switch to the read command used to obtain the input. 273 # 274 _passwdmethod="-w yes" 275 _passwd="-h 0" 276 _upasswd='echo "$upass" |' 277 ;; 278 none) 279 _passwdmethod="-w none" 280 ;; 281 random) 282 _passwdmethod="-w random" 283 ;; 284 esac 285 286 _pwcmd="$_upasswd ${PWCMD} useradd $_uid $_name $_group $_grouplist $_comment" 287 _pwcmd="$_pwcmd $_shell $_class $_home $_dotdir $_passwdmethod $_passwd" 288 _pwcmd="$_pwcmd $_expire $_pwexpire" 289 290 if ! _output=`eval $_pwcmd` ; then 291 err "There was an error adding user ($username)." 292 return 1 293 else 294 info "Successfully added ($username) to the user database." 295 if [ "random" = "$passwdtype" ]; then 296 randompass="$_output" 297 info "Password for ($username) is: $randompass" 298 fi 299 fi 300 301 if [ -n "$disableflag" ]; then 302 if ${PWCMD} lock $username ; then 303 info "Account ($username) is locked." 304 else 305 info "Account ($username) could NOT be locked." 306 fi 307 fi 308 309 _line= 310 _owner= 311 _perms= 312 if [ -n "$msgflag" ]; then 313 [ -r "$msgfile" ] && { 314 # We're evaluating the contents of an external file. 315 # Let's not open ourselves up for attack. _perms will 316 # be empty if it's writeable only by the owner. _owner 317 # will *NOT* be empty if the file is owned by root. 318 # 319 _dir="`dirname $msgfile`" 320 _file="`basename $msgfile`" 321 _perms=`/usr/bin/find $_dir -name $_file -perm +07022 -prune` 322 _owner=`/usr/bin/find $_dir -name $_file -user 0 -prune` 323 if [ -z "$_owner" -o -n "$_perms" ]; then 324 err "The message file ($msgfile) may be writeable only by root." 325 return 1 326 fi 327 cat "$msgfile" | 328 while read _line ; do 329 eval echo "$_line" 330 done | ${MAILCMD} -s"Welcome" ${username} 331 info "Sent welcome message to ($username)." 332 } 333 fi 334} 335 336# get_user 337# Reads username of the account from standard input or from a global 338# variable containing an account line from a file. The username is 339# required. If this is an interactive session it will prompt in 340# a loop until a username is entered. If it is batch processing from 341# a file it will output an error message and return to the caller. 342# 343get_user() { 344 _input= 345 346 # No need to take down user names if this is a configuration saving run. 347 [ -n "$configflag" ] && return 348 349 while : ; do 350 if [ -z "$fflag" ]; then 351 echo -n "Username: " 352 read _input 353 else 354 _input="`echo "$fileline" | cut -f1 -d:`" 355 fi 356 357 # There *must* be a username, and it must not exist. If 358 # this is an interactive session give the user an 359 # opportunity to retry. 360 # 361 if [ -z "$_input" ]; then 362 err "You must enter a username!" 363 [ -z "$fflag" ] && continue 364 fi 365 ${PWCMD} usershow $_input > /dev/null 2>&1 366 if [ "$?" -eq 0 ]; then 367 err "User exists!" 368 [ -z "$fflag" ] && continue 369 fi 370 break 371 done 372 username="$_input" 373} 374 375# get_gecos 376# Reads extra information about the user. Can be used both in interactive 377# and batch (from file) mode. 378# 379get_gecos() { 380 _input= 381 382 # No need to take down additional user information for a configuration run. 383 [ -n "$configflag" ] && return 384 385 if [ -z "$fflag" ]; then 386 echo -n "Full name: " 387 read _input 388 else 389 _input="`echo "$fileline" | cut -f7 -d:`" 390 fi 391 ugecos="$_input" 392} 393 394# get_shell 395# Get the account's shell. Works in interactive and batch mode. It 396# accepts either the base name of the shell or the full path. 397# If an invalid shell is entered it will simply use the default shell. 398# 399get_shell() { 400 _input= 401 _fullpath= 402 ushell="$defaultshell" 403 404 # Make sure the current value of the shell is a valid one 405 if [ -z "$Sflag" ]; then 406 if ! shell_exists $ushell ; then 407 info "Using default shell ${defaultshell}." 408 ushell="$defaultshell" 409 fi 410 fi 411 412 if [ -z "$fflag" ]; then 413 echo -n "Shell ($shells) [`basename $ushell`]: " 414 read _input 415 else 416 _input="`echo "$fileline" | cut -f9 -d:`" 417 fi 418 if [ -n "$_input" ]; then 419 if [ -n "$Sflag" ]; then 420 ushell="$_input" 421 else 422 _fullpath=`fullpath_from_shell $_input` 423 if [ -n "$_fullpath" ]; then 424 ushell="$_fullpath" 425 else 426 err "Invalid shell ($_input) for user $username." 427 info "Using default shell ${defaultshell}." 428 ushell="$defaultshell" 429 fi 430 fi 431 fi 432} 433 434# get_homedir 435# Reads the account's home directory. Used both with interactive input 436# and batch input. 437# 438get_homedir() { 439 _input= 440 if [ -z "$fflag" ]; then 441 echo -n "Home directory [${homeprefix}/${username}]: " 442 read _input 443 else 444 _input="`echo "$fileline" | cut -f8 -d:`" 445 fi 446 447 if [ -n "$_input" ]; then 448 uhome="$_input" 449 # if this is a configuration run, then user input is the home 450 # directory prefix. Otherwise it is understood to 451 # be $prefix/$user 452 # 453 [ -z "$configflag" ] && homeprefix="`dirname $uhome`" || homeprefix="$uhome" 454 else 455 uhome="${homeprefix}/${username}" 456 fi 457} 458 459# get_homeperm 460# Reads the account's home directory permissions. 461# 462get_homeperm() { 463 uhomeperm=$defaultHomePerm 464 _input= 465 _prompt= 466 467 if [ -n "$uhomeperm" ]; then 468 _prompt="Home directory permissions [${uhomeperm}]: " 469 else 470 _prompt="Home directory permissions (Leave empty for default): " 471 fi 472 if [ -z "$fflag" ]; then 473 echo -n "$_prompt" 474 read _input 475 fi 476 477 if [ -n "$_input" ]; then 478 uhomeperm="$_input" 479 fi 480} 481 482# get_uid 483# Reads a numeric userid in an interactive or batch session. Automatically 484# allocates one if it is not specified. 485# 486get_uid() { 487 uuid=${uidstart} 488 _input= 489 _prompt= 490 491 if [ -n "$uuid" ]; then 492 _prompt="Uid [$uuid]: " 493 else 494 _prompt="Uid (Leave empty for default): " 495 fi 496 if [ -z "$fflag" ]; then 497 echo -n "$_prompt" 498 read _input 499 else 500 _input="`echo "$fileline" | cut -f2 -d:`" 501 fi 502 503 [ -n "$_input" ] && uuid=$_input 504 uuid=`get_nextuid $uuid` 505 uidstart=$uuid 506} 507 508# get_class 509# Reads login class of account. Can be used in interactive or batch mode. 510# 511get_class() { 512 uclass="$defaultclass" 513 _input= 514 _class=${uclass:-"default"} 515 516 if [ -z "$fflag" ]; then 517 echo -n "Login class [$_class]: " 518 read _input 519 else 520 _input="`echo "$fileline" | cut -f4 -d:`" 521 fi 522 523 [ -n "$_input" ] && uclass="$_input" 524} 525 526# get_logingroup 527# Reads user's login group. Can be used in both interactive and batch 528# modes. The specified value can be a group name or its numeric id. 529# This routine leaves the field blank if nothing is provided and 530# a default login group has not been set. The pw(8) command 531# will then provide a login group with the same name as the username. 532# 533get_logingroup() { 534 ulogingroup="$defaultLgroup" 535 _input= 536 537 if [ -z "$fflag" ]; then 538 echo -n "Login group [${ulogingroup:-$username}]: " 539 read _input 540 else 541 _input="`echo "$fileline" | cut -f3 -d:`" 542 fi 543 544 # Pw(8) will use the username as login group if it's left empty 545 [ -n "$_input" ] && ulogingroup="$_input" 546} 547 548# get_groups 549# Read additional groups for the user. It can be used in both interactive 550# and batch modes. 551# 552get_groups() { 553 ugroups="$defaultgroups" 554 _input= 555 _group=${ulogingroup:-"${username}"} 556 557 if [ -z "$configflag" ]; then 558 [ -z "$fflag" ] && echo -n "Login group is $_group. Invite $username" 559 [ -z "$fflag" ] && echo -n " into other groups? [$ugroups]: " 560 else 561 [ -z "$fflag" ] && echo -n "Enter additional groups [$ugroups]: " 562 fi 563 read _input 564 565 [ -n "$_input" ] && ugroups="$_input" 566} 567 568# get_expire_dates 569# Read expiry information for the account and also for the password. This 570# routine is used only from batch processing mode. 571# 572get_expire_dates() { 573 upwexpire="`echo "$fileline" | cut -f5 -d:`" 574 uexpire="`echo "$fileline" | cut -f6 -d:`" 575} 576 577# get_password 578# Read the password in batch processing mode. The password field matters 579# only when the password type is "yes" or "random". If the field is empty and the 580# password type is "yes", then it assumes the account has an empty passsword 581# and changes the password type accordingly. If the password type is "random" 582# and the password field is NOT empty, then it assumes the account will NOT 583# have a random password and set passwdtype to "yes." 584# 585get_password() { 586 # We may temporarily change a password type. Make sure it's changed 587 # back to whatever it was before we process the next account. 588 # 589 [ -n "$savedpwtype" ] && { 590 passwdtype=$savedpwtype 591 savedpwtype= 592 } 593 594 # There may be a ':' in the password 595 upass=${fileline#*:*:*:*:*:*:*:*:*:} 596 597 if [ -z "$upass" ]; then 598 case $passwdtype in 599 yes) 600 # if it's empty, assume an empty password 601 passwdtype=none 602 savedpwtype=yes 603 ;; 604 esac 605 else 606 case $passwdtype in 607 random) 608 passwdtype=yes 609 savedpwtype=random 610 ;; 611 esac 612 fi 613} 614 615# input_from_file 616# Reads a line of account information from standard input and 617# adds it to the user database. 618# 619input_from_file() { 620 _field= 621 622 while read -r fileline ; do 623 case "$fileline" in 624 \#*|'') 625 ;; 626 *) 627 get_user || continue 628 get_gecos 629 get_uid 630 get_logingroup 631 get_class 632 get_shell 633 get_homedir 634 get_homeperm 635 get_password 636 get_expire_dates 637 ugroups="$defaultgroups" 638 639 add_user 640 ;; 641 esac 642 done 643} 644 645# input_interactive 646# Prompts for user information interactively, and commits to 647# the user database. 648# 649input_interactive() { 650 651 _disable= 652 _pass= 653 _passconfirm= 654 _random="no" 655 _emptypass="no" 656 _usepass="yes" 657 _logingroup_ok="no" 658 _groups_ok="no" 659 case $passwdtype in 660 none) 661 _emptypass="yes" 662 _usepass="yes" 663 ;; 664 no) 665 _usepass="no" 666 ;; 667 random) 668 _random="yes" 669 ;; 670 esac 671 672 get_user 673 get_gecos 674 get_uid 675 676 # The case where group = user is handled elsewhere, so 677 # validate any other groups the user is invited to. 678 until [ "$_logingroup_ok" = yes ]; do 679 get_logingroup 680 _logingroup_ok=yes 681 if [ -n "$ulogingroup" -a "$username" != "$ulogingroup" ]; then 682 if ! ${PWCMD} show group $ulogingroup > /dev/null 2>&1; then 683 echo "Group $ulogingroup does not exist!" 684 _logingroup_ok=no 685 fi 686 fi 687 done 688 until [ "$_groups_ok" = yes ]; do 689 get_groups 690 _groups_ok=yes 691 for i in $ugroups; do 692 if [ "$username" != "$i" ]; then 693 if ! ${PWCMD} show group $i > /dev/null 2>&1; then 694 echo "Group $i does not exist!" 695 _groups_ok=no 696 fi 697 fi 698 done 699 done 700 701 get_class 702 get_shell 703 get_homedir 704 get_homeperm 705 706 while : ; do 707 echo -n "Use password-based authentication? [$_usepass]: " 708 read _input 709 [ -z "$_input" ] && _input=$_usepass 710 case $_input in 711 [Nn][Oo]|[Nn]) 712 passwdtype="no" 713 ;; 714 [Yy][Ee][Ss]|[Yy][Ee]|[Yy]) 715 while : ; do 716 echo -n "Use an empty password? (yes/no) [$_emptypass]: " 717 read _input 718 [ -n "$_input" ] && _emptypass=$_input 719 case $_emptypass in 720 [Nn][Oo]|[Nn]) 721 echo -n "Use a random password? (yes/no) [$_random]: " 722 read _input 723 [ -n "$_input" ] && _random="$_input" 724 case $_random in 725 [Yy][Ee][Ss]|[Yy][Ee]|[Yy]) 726 passwdtype="random" 727 break 728 ;; 729 esac 730 passwdtype="yes" 731 [ -n "$configflag" ] && break 732 trap 'stty echo; exit' 0 1 2 3 15 733 stty -echo 734 echo -n "Enter password: " 735 read -r upass 736 echo'' 737 echo -n "Enter password again: " 738 read -r _passconfirm 739 echo '' 740 stty echo 741 # if user entered a blank password 742 # explicitly ask again. 743 [ -z "$upass" -a -z "$_passconfirm" ] \ 744 && continue 745 ;; 746 [Yy][Ee][Ss]|[Yy][Ee]|[Yy]) 747 passwdtype="none" 748 break; 749 ;; 750 *) 751 # invalid answer; repeat the loop 752 continue 753 ;; 754 esac 755 if [ "$upass" != "$_passconfirm" ]; then 756 echo "Passwords did not match!" 757 continue 758 fi 759 break 760 done 761 ;; 762 *) 763 # invalid answer; repeat loop 764 continue 765 ;; 766 esac 767 break; 768 done 769 _disable=${disableflag:-"no"} 770 while : ; do 771 echo -n "Lock out the account after creation? [$_disable]: " 772 read _input 773 [ -z "$_input" ] && _input=$_disable 774 case $_input in 775 [Nn][Oo]|[Nn]) 776 disableflag= 777 ;; 778 [Yy][Ee][Ss]|[Yy][Ee]|[Yy]) 779 disableflag=yes 780 ;; 781 *) 782 # invalid answer; repeat loop 783 continue 784 ;; 785 esac 786 break 787 done 788 789 # Display the information we have so far and prompt to 790 # commit it. 791 # 792 _disable=${disableflag:-"no"} 793 [ -z "$configflag" ] && printf "%-10s : %s\n" Username $username 794 case $passwdtype in 795 yes) 796 _pass='*****' 797 ;; 798 no) 799 _pass='<disabled>' 800 ;; 801 none) 802 _pass='<blank>' 803 ;; 804 random) 805 _pass='<random>' 806 ;; 807 esac 808 [ -z "$configflag" ] && printf "%-10s : %s\n" "Password" "$_pass" 809 [ -n "$configflag" ] && printf "%-10s : %s\n" "Pass Type" "$passwdtype" 810 [ -z "$configflag" ] && printf "%-10s : %s\n" "Full Name" "$ugecos" 811 [ -z "$configflag" ] && printf "%-10s : %s\n" "Uid" "$uuid" 812 printf "%-10s : %s\n" "Class" "$uclass" 813 printf "%-10s : %s %s\n" "Groups" "${ulogingroup:-$username}" "$ugroups" 814 printf "%-10s : %s\n" "Home" "$uhome" 815 printf "%-10s : %s\n" "Home Mode" "$uhomeperm" 816 printf "%-10s : %s\n" "Shell" "$ushell" 817 printf "%-10s : %s\n" "Locked" "$_disable" 818 while : ; do 819 echo -n "OK? (yes/no): " 820 read _input 821 case $_input in 822 [Nn][Oo]|[Nn]) 823 return 1 824 ;; 825 [Yy][Ee][Ss]|[Yy][Ee]|[Yy]) 826 add_user 827 ;; 828 *) 829 continue 830 ;; 831 esac 832 break 833 done 834 return 0 835} 836 837#### END SUBROUTINE DEFINITION #### 838 839THISCMD=`/usr/bin/basename $0` 840DEFAULTSHELL=/bin/sh 841ADDUSERCONF="${ADDUSERCONF:-/etc/adduser.conf}" 842PWCMD="${PWCMD:-/usr/sbin/pw}" 843MAILCMD="${MAILCMD:-mail}" 844ETCSHELLS="${ETCSHELLS:-/etc/shells}" 845NOHOME="/nonexistent" 846NOLOGIN="nologin" 847NOLOGIN_PATH="/usr/sbin/nologin" 848GREPCMD="/usr/bin/grep" 849DATECMD="/bin/date" 850 851# Set default values 852# 853username= 854uuid= 855uidstart= 856ugecos= 857ulogingroup= 858uclass= 859uhome= 860uhomeperm= 861upass= 862ushell= 863udotdir=/usr/share/skel 864ugroups= 865uexpire= 866upwexpire= 867shells="`valid_shells`" 868passwdtype="yes" 869msgfile=/etc/adduser.msg 870msgflag= 871quietflag= 872configflag= 873fflag= 874infile= 875disableflag= 876Dflag= 877Sflag= 878readconfig="yes" 879homeprefix="/home" 880randompass= 881fileline= 882savedpwtype= 883defaultclass= 884defaultLgroup= 885defaultgroups= 886defaultshell="${DEFAULTSHELL}" 887defaultHomePerm= 888 889# Make sure the user running this program is root. This isn't a security 890# measure as much as it is a usefull method of reminding the user to 891# 'su -' before he/she wastes time entering data that won't be saved. 892# 893procowner=${procowner:-`/usr/bin/id -u`} 894if [ "$procowner" != "0" ]; then 895 err 'you must be the super-user (uid 0) to use this utility.' 896 exit 1 897fi 898 899# Overide from our conf file 900# Quickly go through the commandline line to see if we should read 901# from our configuration file. The actual parsing of the commandline 902# arguments happens after we read in our configuration file (commandline 903# should override configuration file). 904# 905for _i in $* ; do 906 if [ "$_i" = "-N" ]; then 907 readconfig= 908 break; 909 fi 910done 911if [ -n "$readconfig" ]; then 912 # On a long-lived system, the first time this script is run it 913 # will barf upon reading the configuration file for its perl predecessor. 914 if ( . ${ADDUSERCONF} > /dev/null 2>&1 ); then 915 [ -r ${ADDUSERCONF} ] && . ${ADDUSERCONF} > /dev/null 2>&1 916 fi 917fi 918 919# Proccess command-line options 920# 921for _switch ; do 922 case $_switch in 923 -L) 924 defaultclass="$2" 925 shift; shift 926 ;; 927 -C) 928 configflag=yes 929 shift 930 ;; 931 -D) 932 Dflag=yes 933 shift 934 ;; 935 -E) 936 disableflag=yes 937 shift 938 ;; 939 -k) 940 udotdir="$2" 941 shift; shift 942 ;; 943 -f) 944 [ "$2" != "-" ] && infile="$2" 945 fflag=yes 946 shift; shift 947 ;; 948 -g) 949 defaultLgroup="$2" 950 shift; shift 951 ;; 952 -G) 953 defaultgroups="$2" 954 shift; shift 955 ;; 956 -h) 957 show_usage 958 exit 0 959 ;; 960 -d) 961 homeprefix="$2" 962 shift; shift 963 ;; 964 -m) 965 case "$2" in 966 [Nn][Oo]) 967 msgflag= 968 ;; 969 *) 970 msgflag=yes 971 msgfile="$2" 972 ;; 973 esac 974 shift; shift 975 ;; 976 -M) 977 defaultHomePerm=$2 978 shift; shift 979 ;; 980 -N) 981 readconfig= 982 shift 983 ;; 984 -w) 985 case "$2" in 986 no|none|random|yes) 987 passwdtype=$2 988 ;; 989 *) 990 show_usage 991 exit 1 992 ;; 993 esac 994 shift; shift 995 ;; 996 -q) 997 quietflag=yes 998 shift 999 ;; 1000 -s) 1001 defaultshell="`fullpath_from_shell $2`" 1002 shift; shift 1003 ;; 1004 -S) 1005 Sflag=yes 1006 shift 1007 ;; 1008 -u) 1009 uidstart=$2 1010 shift; shift 1011 ;; 1012 esac 1013done 1014 1015# If the -f switch was used, get input from a file. Otherwise, 1016# this is an interactive session. 1017# 1018if [ -n "$fflag" ]; then 1019 if [ -z "$infile" ]; then 1020 input_from_file 1021 elif [ -n "$infile" ]; then 1022 if [ -r "$infile" ]; then 1023 input_from_file < $infile 1024 else 1025 err "File ($infile) is unreadable or does not exist." 1026 fi 1027 fi 1028else 1029 input_interactive 1030 while : ; do 1031 if [ -z "$configflag" ]; then 1032 echo -n "Add another user? (yes/no): " 1033 else 1034 echo -n "Re-edit the default configuration? (yes/no): " 1035 fi 1036 read _input 1037 case $_input in 1038 [Yy][Ee][Ss]|[Yy][Ee]|[Yy]) 1039 uidstart=`get_nextuid $uidstart` 1040 input_interactive 1041 continue 1042 ;; 1043 [Nn][Oo]|[Nn]) 1044 echo "Goodbye!" 1045 ;; 1046 *) 1047 continue 1048 ;; 1049 esac 1050 break 1051 done 1052fi 1053