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