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