adduser.sh revision 109720
1107543Sscottl#!/bin/sh 2107543Sscottl# 3107543Sscottl# Copyright (c) 2002 Michael Telahun Makonnen. All rights reserved. 4107543Sscottl# 5107543Sscottl# Redistribution and use in source and binary forms, with or without 6107543Sscottl# modification, are permitted provided that the following conditions 7107543Sscottl# are met: 8107543Sscottl# 1. Redistributions of source code must retain the above copyright 9107543Sscottl# notice, this list of conditions and the following disclaimer. 10107543Sscottl# 2. Redistributions in binary form must reproduce the above copyright 11107543Sscottl# notice, this list of conditions and the following disclaimer in the 12107543Sscottl# documentation and/or other materials provided with the distribution. 13107543Sscottl# 3. The name of the author may not be used to endorse or promote products 14107543Sscottl# derived from this software without specific prior written permission. 15107543Sscottl# 16107543Sscottl# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 17107543Sscottl# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18107543Sscottl# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 19107543Sscottl# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 20107543Sscottl# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 21107543Sscottl# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 22107543Sscottl# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 23107543Sscottl# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24107543Sscottl# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 25107543Sscottl# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26107543Sscottl# 27107543Sscottl# Email: Mike Makonnen <mtm@identd.net> 28107543Sscottl# 29107543Sscottl# $FreeBSD: head/usr.sbin/adduser/adduser.sh 109720 2003-01-23 01:57:30Z mtm $ 30107543Sscottl# 31107543Sscottl 32107543Sscottl# err msg 33107543Sscottl# Display $msg on stderr, unless we're being quiet. 34107543Sscottl# 35107543Sscottlerr() { 36107543Sscottl if [ -z "$quietflag" ]; then 37107543Sscottl echo 1>&2 ${THISCMD}: ERROR: $* 38107543Sscottl fi 39107543Sscottl} 40107543Sscottl 41107543Sscottl# info msg 42107543Sscottl# Display $msg on stdout, unless we're being quiet. 43107543Sscottl# 44107543Sscottlinfo() { 45107543Sscottl if [ -z "$quietflag" ]; then 46107543Sscottl echo ${THISCMD}: INFO: $* 47107543Sscottl fi 48107543Sscottl} 49107543Sscottl 50107543Sscottl# get_nextuid 51107543Sscottl# Output the value of $_uid if it is available for use. If it 52107543Sscottl# is not, output the value of the next higher uid that is available. 53107543Sscottl# If a uid is not specified, output the first available uid, as indicated 54107543Sscottl# by pw(8). 55107543Sscottl# 56107543Sscottlget_nextuid () { 57107543Sscottl _uid=$1 58107543Sscottl _nextuid= 59107543Sscottl 60107543Sscottl if [ -z "$_uid" ]; then 61107543Sscottl _nextuid="`${PWCMD} usernext | cut -f1 -d:`" 62107543Sscottl else 63107543Sscottl while : ; do 64107543Sscottl ${PWCMD} usershow $_uid > /dev/null 2>&1 65107543Sscottl if [ ! "$?" -eq 0 ]; then 66107543Sscottl _nextuid=$_uid 67107543Sscottl break 68107543Sscottl fi 69107543Sscottl _uid=$(($_uid + 1)) 70107543Sscottl done 71107543Sscottl fi 72107543Sscottl echo $_nextuid 73107543Sscottl} 74107543Sscottl 75107543Sscottl# show_usage 76107543Sscottl# Display usage information for this utility. 77107543Sscottl# 78107543Sscottlshow_usage() { 79107543Sscottl echo "usage: ${THISCMD} [options]" 80107543Sscottl echo " options may include:" 81107543Sscottl echo " -C save to the configuration file only" 82107543Sscottl echo " -E disable this account after creation" 83107543Sscottl echo " -G additional groups to add accounts to" 84107543Sscottl echo " -L login class of the user" 85107543Sscottl echo " -N do not read configuration file" 86107543Sscottl echo " -d home directory" 87107543Sscottl echo " -f file from which input will be received" 88107543Sscottl echo " -h display this usage message" 89107543Sscottl echo " -k path to skeleton home directory" 90107543Sscottl echo " -m user welcome message file" 91107543Sscottl echo " -q absolute minimal user feedback" 92107543Sscottl echo " -s shell" 93107543Sscottl echo " -u uid to start at" 94107543Sscottl echo " -w password type: no, none, yes or random" 95107543Sscottl} 96107543Sscottl 97107543Sscottl# valid_shells 98107543Sscottl# Outputs a list of valid shells from /etc/shells. Only the 99107543Sscottl# basename of the shell is output. 100107543Sscottl# 101107543Sscottlvalid_shells() { 102107543Sscottl _prefix= 103107543Sscottl cat ${ETCSHELLS} | 104107543Sscottl while read _path _junk ; do 105107543Sscottl case $_path in 106107543Sscottl \#*|'') 107107543Sscottl ;; 108107543Sscottl *) 109107543Sscottl echo -n "${_prefix}`basename $_path`" 110107543Sscottl _prefix=' ' 111107543Sscottl ;; 112107543Sscottl esac 113107543Sscottl done 114107543Sscottl} 115107543Sscottl 116107543Sscottl# fullpath_from_shell shell 117107543Sscottl# Given $shell, the basename component of a valid shell, get the 118107543Sscottl# full path to the shell from the /etc/shells file. 119107543Sscottl# 120107543Sscottlfullpath_from_shell() { 121107543Sscottl _shell=$1 122107543Sscottl [ -z "$_shell" ] && return 1 123107543Sscottl 124107543Sscottl cat ${ETCSHELLS} | 125107543Sscottl while read _path _junk ; do 126107543Sscottl case "$_path" in 127107543Sscottl \#*|'') 128107543Sscottl ;; 129107543Sscottl *) 130107543Sscottl if [ "`basename $_path`" = "$_shell" ]; then 131107543Sscottl echo $_path 132107543Sscottl return 0 133107543Sscottl fi 134107543Sscottl ;; 135107543Sscottl esac 136107543Sscottl done 137107543Sscottl return 1 138107543Sscottl} 139107543Sscottl 140107543Sscottl# save_config 141107543Sscottl# Save some variables to a configuration file. 142107543Sscottl# Note: not all script variables are saved, only those that 143107543Sscottl# it makes sense to save. 144107543Sscottl# 145107543Sscottlsave_config() { 146107543Sscottl echo "# Configuration file for adduser(8)." > ${ADDUSERCONF} 147107543Sscottl echo "# NOTE: only *some* variables are saved." >> ${ADDUSERCONF} 148107543Sscottl echo "# Last Modified on `date`." >> ${ADDUSERCONF} 149107543Sscottl echo '' >> ${ADDUSERCONF} 150107543Sscottl echo "defaultclass=$uclass" >> ${ADDUSERCONF} 151107543Sscottl echo "defaultgroups=$ugroups" >> ${ADDUSERCONF} 152107543Sscottl echo "passwdtype=$passwdtype" >> ${ADDUSERCONF} 153107543Sscottl echo "homeprefix=$homeprefix" >> ${ADDUSERCONF} 154107543Sscottl echo "defaultshell=$ushell" >> ${ADDUSERCONF} 155107543Sscottl echo "udotdir=$udotdir" >> ${ADDUSERCONF} 156107543Sscottl echo "msgfile=$msgfile" >> ${ADDUSERCONF} 157107543Sscottl echo "disableflag=$disableflag" >> ${ADDUSERCONF} 158107543Sscottl} 159107543Sscottl 160107543Sscottl# add_user 161107543Sscottl# Add a user to the user database. If the user chose to send a welcome 162107543Sscottl# message or lock the account, do so. 163107543Sscottl# 164107543Sscottladd_user() { 165107543Sscottl 166107543Sscottl # Is this a configuration run? If so, don't modify user database. 167107543Sscottl # 168107543Sscottl if [ -n "$configflag" ]; then 169107543Sscottl save_config 170107543Sscottl return 171107543Sscottl fi 172107543Sscottl 173107543Sscottl _uid= 174107543Sscottl _name= 175107543Sscottl _comment= 176107543Sscottl _gecos= 177107543Sscottl _home= 178107543Sscottl _group= 179107543Sscottl _grouplist= 180107543Sscottl _shell= 181107543Sscottl _class= 182107543Sscottl _dotdir= 183107543Sscottl _expire= 184107543Sscottl _pwexpire= 185107543Sscottl _passwd= 186107543Sscottl _upasswd= 187107543Sscottl _passwdmethod= 188107543Sscottl 189109720Smtm _name="-n '$username'" 190109720Smtm [ -n "$uuid" ] && _uid="-u '$uuid'" 191109720Smtm [ -n "$ulogingroup" ] && _group="-g '$ulogingroup'" 192109720Smtm [ -n "$ugroups" ] && _grouplist="-G '$ugroups'" 193109720Smtm [ -n "$ushell" ] && _shell="-s '$ushell'" 194109720Smtm [ -n "$uhome" ] && _home="-m -d '$uhome'" 195109720Smtm [ -n "$uclass" ] && _class="-L '$uclass'" 196107543Sscottl [ -n "$ugecos" ] && _comment="-c '$ugecos'" 197109720Smtm [ -n "$udotdir" ] && _dotdir="-k '$udotdir'" 198107543Sscottl [ -n "$uexpire" ] && _expire="-e '$uexpire'" 199107543Sscottl [ -n "$upwexpire" ] && _pwexpire="-p '$upwexpire'" 200107543Sscottl case $passwdtype in 201107543Sscottl no) 202107543Sscottl _passwdmethod="-w no" 203107543Sscottl _passwd="-h -" 204107543Sscottl ;; 205107543Sscottl yes) 206107543Sscottl _passwdmethod="-w yes" 207107543Sscottl _passwd="-h 0" 208109635Smtm _upasswd="echo '$upass' |" 209107543Sscottl ;; 210107543Sscottl none) 211107543Sscottl _passwdmethod="-w none" 212107543Sscottl ;; 213107543Sscottl random) 214107543Sscottl _passwdmethod="-w random" 215107543Sscottl ;; 216107543Sscottl esac 217107543Sscottl 218107543Sscottl _pwcmd="$_upasswd ${PWCMD} useradd $_uid $_name $_group $_grouplist $_comment" 219107543Sscottl _pwcmd="$_pwcmd $_shell $_class $_home $_dotdir $_passwdmethod $_passwd" 220107543Sscottl _pwcmd="$_pwcmd $_expire $_pwexpire" 221107543Sscottl 222107543Sscottl if ! _output=`eval $_pwcmd` ; then 223107543Sscottl err "There was an error adding user ($username)." 224107543Sscottl return 1 225107543Sscottl else 226107543Sscottl info "Successfully added ($username) to the user database." 227107543Sscottl if [ "random" = "$passwdtype" ]; then 228107543Sscottl randompass="$_output" 229107543Sscottl info "Password for ($username) is: $randompass" 230107543Sscottl fi 231107543Sscottl fi 232107543Sscottl 233107543Sscottl if [ -n "$disableflag" ]; then 234107543Sscottl if ${PWCMD} lock $username ; then 235107543Sscottl info "Account ($username) is locked." 236107543Sscottl else 237107543Sscottl info "Account ($username) could NOT be locked." 238107543Sscottl fi 239107543Sscottl fi 240107543Sscottl 241107543Sscottl _line= 242107543Sscottl _owner= 243107543Sscottl _perms= 244107543Sscottl if [ -n "$msgflag" ]; then 245107543Sscottl [ -r "$msgfile" ] && { 246107543Sscottl # We're evaluating the contents of an external file. 247107543Sscottl # Let's not open ourselves up for attack. _perms will 248107543Sscottl # be empty if it's writeable only by the owner. _owner 249107543Sscottl # will *NOT* be empty if the file is owned by root. 250107543Sscottl # 251107543Sscottl _dir="`dirname $msgfile`" 252107543Sscottl _file="`basename $msgfile`" 253107543Sscottl _perms=`/usr/bin/find $_dir -name $_file -perm +07022 -prune` 254107543Sscottl _owner=`/usr/bin/find $_dir -name $_file -user 0 -prune` 255107543Sscottl if [ -z "$_owner" -o -n "$_perms" ]; then 256107543Sscottl err "The message file ($msgfile) may be writeable only by root." 257107543Sscottl return 1 258107543Sscottl fi 259107543Sscottl cat "$msgfile" | 260107543Sscottl while read _line ; do 261107543Sscottl eval echo "$_line" 262107543Sscottl done | ${MAILCMD} -s"Welcome" ${username} 263107543Sscottl info "Sent welcome message to ($username)." 264107543Sscottl } 265107543Sscottl fi 266107543Sscottl} 267107543Sscottl 268107543Sscottl# get_user 269107543Sscottl# Reads username of the account from standard input or from a global 270107543Sscottl# variable containing an account line from a file. The username is 271107543Sscottl# required. If this is an interactive session it will prompt in 272107543Sscottl# a loop until a username is entered. If it is batch processing from 273107543Sscottl# a file it will output an error message and return to the caller. 274107543Sscottl# 275107543Sscottlget_user() { 276107543Sscottl _input= 277107543Sscottl 278107543Sscottl # No need to take down user names if this is a configuration saving run. 279107543Sscottl [ -n "$configflag" ] && return 280107543Sscottl 281107543Sscottl while : ; do 282107543Sscottl if [ -z "$fflag" ]; then 283107543Sscottl echo -n "Username: " 284107543Sscottl read _input 285107543Sscottl else 286107543Sscottl _input="`echo "$fileline" | cut -f1 -d:`" 287107543Sscottl fi 288107543Sscottl 289107543Sscottl # There *must* be a username. If this is an interactive 290107543Sscottl # session give the user an opportunity to retry. 291107543Sscottl # 292107543Sscottl if [ -z "$_input" ]; then 293107543Sscottl err "You must enter a username!" 294107543Sscottl [ -z "$fflag" ] && continue 295107543Sscottl fi 296107543Sscottl break 297107543Sscottl done 298107543Sscottl username="$_input" 299107543Sscottl} 300107543Sscottl 301107543Sscottl# get_gecos 302107543Sscottl# Reads extra information about the user. Can be used both in interactive 303107543Sscottl# and batch (from file) mode. 304107543Sscottl# 305107543Sscottlget_gecos() { 306107543Sscottl _input= 307107543Sscottl 308107543Sscottl # No need to take down additional user information for a configuration run. 309107543Sscottl [ -n "$configflag" ] && return 310107543Sscottl 311107543Sscottl if [ -z "$fflag" ]; then 312107543Sscottl echo -n "Full name: " 313107543Sscottl read _input 314107543Sscottl else 315107543Sscottl _input="`echo "$fileline" | cut -f7 -d:`" 316107543Sscottl fi 317107543Sscottl ugecos="$_input" 318107543Sscottl} 319107543Sscottl 320107543Sscottl# get_shell 321107543Sscottl# Get the account's shell. Works in interactive and batch mode. It 322107543Sscottl# accepts only the base name of the shell, NOT the full path. 323107543Sscottl# If an invalid shell is entered it will simply use the default shell. 324107543Sscottl# 325107543Sscottlget_shell() { 326107543Sscottl _input= 327107543Sscottl _fullpath= 328107543Sscottl ushell="$defaultshell" 329107543Sscottl 330107543Sscottl # Make sure the current value of the shell is a valid one 331107543Sscottl _shellchk="grep '^$ushell$' ${ETCSHELLS} > /dev/null 2>&1" 332107543Sscottl eval $_shellchk || { 333107543Sscottl err "Invalid shell ($ushell). Using default shell ${defaultshell}." 334107543Sscottl ushell="$defaultshell" 335107543Sscottl } 336107543Sscottl 337107543Sscottl if [ -z "$fflag" ]; then 338107543Sscottl echo -n "Shell ($shells) [`basename $ushell`]: " 339107543Sscottl read _input 340107543Sscottl else 341107543Sscottl _input="`echo "$fileline" | cut -f9 -d:`" 342107543Sscottl fi 343107543Sscottl if [ -n "$_input" ]; then 344107543Sscottl _fullpath=`fullpath_from_shell $_input` 345107543Sscottl if [ -n "$_fullpath" ]; then 346107543Sscottl ushell="$_fullpath" 347107543Sscottl else 348107543Sscottl err "Invalid shell selection. Using default shell ${defaultshell}." 349107543Sscottl ushell="$defaultshell" 350107543Sscottl fi 351107543Sscottl fi 352107543Sscottl} 353107543Sscottl 354107543Sscottl# get_homedir 355107543Sscottl# Reads the account's home directory. Used both with interactive input 356107543Sscottl# and batch input. 357107543Sscottl# 358107543Sscottlget_homedir() { 359107543Sscottl _input= 360107543Sscottl if [ -z "$fflag" ]; then 361107543Sscottl echo -n "Home directory [${homeprefix}/${username}]: " 362107543Sscottl read _input 363107543Sscottl else 364107543Sscottl _input="`echo "$fileline" | cut -f8 -d:`" 365107543Sscottl fi 366107543Sscottl 367107543Sscottl if [ -n "$_input" ]; then 368107543Sscottl uhome="$_input" 369107543Sscottl # if this is a configuration run, then user input is the home 370107543Sscottl # directory prefix. Otherwise it is understood to 371107543Sscottl # be $prefix/$user 372107543Sscottl # 373107543Sscottl [ -z "$configflag" ] && homeprefix="`dirname $uhome`" || homeprefix="$uhome" 374107543Sscottl else 375107543Sscottl uhome="${homeprefix}/${username}" 376107543Sscottl fi 377107543Sscottl} 378107543Sscottl 379107543Sscottl# get_uid 380107543Sscottl# Reads a numeric userid in an interactive or batch session. Automatically 381107543Sscottl# allocates one if it is not specified. 382107543Sscottl# 383107543Sscottlget_uid() { 384107543Sscottl uuid=${uidstart} 385107543Sscottl _input= 386107543Sscottl _prompt= 387107543Sscottl 388107543Sscottl # No need to take down uids for a configuration saving run. 389107543Sscottl [ -n "$configflag" ] && return 390107543Sscottl 391107543Sscottl if [ -n "$uuid" ]; then 392107543Sscottl _prompt="Uid [$uuid]: " 393107543Sscottl else 394107543Sscottl _prompt="Uid (Leave empty for default): " 395107543Sscottl fi 396107543Sscottl if [ -z "$fflag" ]; then 397109573Sfjoe echo -n "$_prompt" 398107543Sscottl read _input 399107543Sscottl else 400107543Sscottl _input="`echo "$fileline" | cut -f2 -d:`" 401107543Sscottl fi 402107543Sscottl 403107543Sscottl [ -n "$_input" ] && uuid=$_input 404107543Sscottl uuid=`get_nextuid $uuid` 405107543Sscottl uidstart=$uuid 406107543Sscottl} 407107543Sscottl 408107543Sscottl# get_class 409107543Sscottl# Reads login class of account. Can be used in interactive or batch mode. 410107543Sscottl# 411107543Sscottlget_class() { 412107543Sscottl uclass="$defaultclass" 413107543Sscottl _input= 414107543Sscottl _class=${uclass:-"default"} 415107543Sscottl 416107543Sscottl if [ -z "$fflag" ]; then 417107543Sscottl echo -n "Login class [$_class]: " 418107543Sscottl read _input 419107543Sscottl else 420107543Sscottl _input="`echo "$fileline" | cut -f4 -d:`" 421107543Sscottl fi 422107543Sscottl 423107543Sscottl [ -n "$_input" ] && uclass="$_input" 424107543Sscottl} 425107543Sscottl 426107543Sscottl# get_logingroup 427107543Sscottl# Reads user's login group. Can be used in both interactive and batch 428107543Sscottl# modes. The specified value can be a group name or its numeric id. 429107543Sscottl# This routine leaves the field blank if nothing is provided. The pw(8) 430107543Sscottl# command will then provide a login group with the same name as the username. 431107543Sscottl# 432107543Sscottlget_logingroup() { 433107543Sscottl ulogingroup= 434107543Sscottl _input= 435107543Sscottl 436107543Sscottl # No need to take down a login group for a configuration saving run. 437107543Sscottl [ -n "$configflag" ] && return 438107543Sscottl 439107543Sscottl if [ -z "$fflag" ]; then 440107543Sscottl echo -n "Login group [$username]: " 441107543Sscottl read _input 442107543Sscottl else 443107543Sscottl _input="`echo "$fileline" | cut -f3 -d:`" 444107543Sscottl fi 445107543Sscottl 446107543Sscottl # Pw(8) will use the username as login group if it's left empty 447107543Sscottl [ -n "$_input" ] && ulogingroup="$_input" || ulogingroup= 448107543Sscottl} 449107543Sscottl 450107543Sscottl# get_groups 451107543Sscottl# Read additional groups for the user. It can be used in both interactive 452107543Sscottl# and batch modes. 453107543Sscottl# 454107543Sscottlget_groups() { 455107543Sscottl ugroups="$defaultgroups" 456107543Sscottl _input= 457107543Sscottl _group=${ulogingroup:-"${username}"} 458107543Sscottl 459107543Sscottl if [ -z "$configflag" ]; then 460107543Sscottl [ -z "$fflag" ] && echo -n "Login group is $_group. Invite $username" 461107543Sscottl [ -z "$fflag" ] && echo -n " into other groups? [$ugroups]: " 462107543Sscottl else 463107543Sscottl [ -z "$fflag" ] && echo -n "Enter additional groups [$ugroups]: " 464107543Sscottl fi 465107543Sscottl read _input 466107543Sscottl 467107543Sscottl [ -n "$_input" ] && ugroups="$_input" 468107543Sscottl} 469107543Sscottl 470107543Sscottl# get_expire_dates 471107543Sscottl# Read expiry information for the account and also for the password. This 472107543Sscottl# routine is used only from batch processing mode. 473107543Sscottl# 474107543Sscottlget_expire_dates() { 475107543Sscottl upwexpire="`echo "$fileline" | cut -f5 -d:`" 476107543Sscottl uexpire="`echo "$fileline" | cut -f6 -d:`" 477107543Sscottl} 478107543Sscottl 479107543Sscottl# get_password 480107543Sscottl# Read the password in batch processing mode. The password field matters 481107543Sscottl# only when the password type is "yes" or "random". If the field is empty and the 482107543Sscottl# password type is "yes", then it assumes the account has an empty passsword 483107543Sscottl# and changes the password type accordingly. If the password type is "random" 484107543Sscottl# and the password field is NOT empty, then it assumes the account will NOT 485107543Sscottl# have a random password and set passwdtype to "yes." 486107543Sscottl# 487107543Sscottlget_password() { 488107543Sscottl # We may temporarily change a password type. Make sure it's changed 489107543Sscottl # back to whatever it was before we process the next account. 490107543Sscottl # 491107543Sscottl [ -n "$savedpwtype" ] && { 492107543Sscottl passwdtype=$savedpwtype 493107543Sscottl savedpwtype= 494107543Sscottl } 495107543Sscottl 496107543Sscottl # There may be a ':' in the password 497107543Sscottl upass=${fileline#*:*:*:*:*:*:*:*:*:} 498107543Sscottl 499107543Sscottl if [ -z "$upass" ]; then 500107543Sscottl case $passwdtype in 501107543Sscottl yes) 502107543Sscottl # if it's empty, assume an empty password 503107543Sscottl passwdtype=none 504107543Sscottl savedpwtype=yes 505107543Sscottl ;; 506107543Sscottl esac 507107543Sscottl else 508107543Sscottl case $passwdtype in 509107543Sscottl random) 510107543Sscottl passwdtype=yes 511107543Sscottl savedpwtype=random 512107543Sscottl ;; 513107543Sscottl esac 514107543Sscottl fi 515107543Sscottl} 516107543Sscottl 517107543Sscottl# input_from_file 518107543Sscottl# Reads a line of account information from standard input and 519107543Sscottl# adds it to the user database. 520107543Sscottl# 521107543Sscottlinput_from_file() { 522107543Sscottl _field= 523107543Sscottl 524107543Sscottl while read fileline ; do 525107543Sscottl case "$fileline" in 526107543Sscottl \#*|'') 527107543Sscottl return 0 528107543Sscottl ;; 529107543Sscottl esac 530107543Sscottl 531107543Sscottl get_user || continue 532107543Sscottl get_gecos 533107543Sscottl get_uid 534107543Sscottl get_logingroup 535107543Sscottl get_class 536107543Sscottl get_shell 537107543Sscottl get_homedir 538107543Sscottl get_password 539107543Sscottl get_expire_dates 540107543Sscottl 541107543Sscottl add_user 542107543Sscottl done 543107543Sscottl} 544107543Sscottl 545107543Sscottl# input_interactive 546107543Sscottl# Prompts for user information interactively, and commits to 547107543Sscottl# the user database. 548107543Sscottl# 549107543Sscottlinput_interactive() { 550107543Sscottl 551107543Sscottl _disable= 552107543Sscottl _pass= 553107543Sscottl _passconfirm= 554107543Sscottl _random="no" 555107543Sscottl _emptypass="no" 556107543Sscottl _usepass="yes" 557107543Sscottl case $passwdtype in 558107543Sscottl none) 559107543Sscottl _emptypass="yes" 560107543Sscottl _usepass="yes" 561107543Sscottl ;; 562107543Sscottl no) 563107543Sscottl _usepass="no" 564107543Sscottl ;; 565107543Sscottl random) 566107543Sscottl _random="yes" 567107543Sscottl ;; 568107543Sscottl esac 569107543Sscottl 570107543Sscottl get_user 571107543Sscottl get_gecos 572107543Sscottl get_uid 573107543Sscottl get_logingroup 574107543Sscottl get_groups 575107543Sscottl get_class 576107543Sscottl get_shell 577107543Sscottl get_homedir 578107543Sscottl 579107543Sscottl while : ; do 580107543Sscottl echo -n "Use password-based authentication? [$_usepass]: " 581107543Sscottl read _input 582107543Sscottl [ -z "$_input" ] && _input=$_usepass 583107543Sscottl case $_input in 584107543Sscottl [Nn][Oo]|[Nn]) 585107543Sscottl passwdtype="no" 586107543Sscottl ;; 587107543Sscottl [Yy][Ee][Ss]|[Yy][Ee]|[Yy]) 588107543Sscottl while : ; do 589107543Sscottl echo -n "Use an empty password? (yes/no) [$_emptypass]: " 590107543Sscottl read _input 591107543Sscottl [ -n "$_input" ] && _emptypass=$_input 592107543Sscottl case $_emptypass in 593107543Sscottl [Nn][Oo]|[Nn]) 594107543Sscottl echo -n "Use a random password? (yes/no) [$_random]: " 595107543Sscottl read _input 596107543Sscottl [ -n "$_input" ] && _random="$_input" 597107543Sscottl case $_random in 598107543Sscottl [Yy][Ee][Ss]|[Yy][Ee]|[Yy]) 599107543Sscottl passwdtype="random" 600107543Sscottl break 601107543Sscottl ;; 602107543Sscottl esac 603107543Sscottl passwdtype="yes" 604107543Sscottl trap 'stty echo; exit' 0 1 2 3 15 605107543Sscottl stty -echo 606107543Sscottl echo -n "Enter password: " 607107543Sscottl read upass 608107543Sscottl echo'' 609107543Sscottl echo -n "Enter password again: " 610107543Sscottl read _passconfirm 611107543Sscottl echo '' 612107543Sscottl stty echo 613107543Sscottl # if user entered a blank password 614107543Sscottl # explicitly ask again. 615107543Sscottl [ -z "$upass" -a -z "$_passconfirm" ] \ 616107543Sscottl && continue 617107543Sscottl ;; 618107543Sscottl [Yy][Ee][Ss]|[Yy][Ee]|[Yy]) 619107543Sscottl passwdtype="none" 620107543Sscottl break; 621107543Sscottl ;; 622107543Sscottl *) 623107543Sscottl # invalid answer; repeat the loop 624107543Sscottl continue 625107543Sscottl ;; 626107543Sscottl esac 627107543Sscottl if [ "$upass" != "$_passconfirm" ]; then 628107543Sscottl echo "Passwords did not match!" 629107543Sscottl continue 630107543Sscottl fi 631107543Sscottl break 632107543Sscottl done 633107543Sscottl ;; 634107543Sscottl *) 635107543Sscottl # invalid answer; repeat loop 636107543Sscottl continue 637107543Sscottl ;; 638107543Sscottl esac 639107543Sscottl break; 640107543Sscottl done 641107543Sscottl _disable=${disableflag:-"no"} 642107543Sscottl while : ; do 643107543Sscottl echo -n "Lock out the account after creation? [$_disable]: " 644107543Sscottl read _input 645107543Sscottl [ -z "$_input" ] && _input=$_disable 646107543Sscottl case $_input in 647107543Sscottl [Nn][Oo]|[Nn]) 648107543Sscottl disableflag= 649107543Sscottl ;; 650107543Sscottl [Yy][Ee][Ss]|[Yy][Ee]|[Yy]) 651107543Sscottl disableflag=yes 652107543Sscottl ;; 653107543Sscottl *) 654107543Sscottl # invalid answer; repeat loop 655107543Sscottl continue 656107543Sscottl ;; 657107543Sscottl esac 658107543Sscottl break 659107543Sscottl done 660107543Sscottl 661107543Sscottl # Display the information we have so far and prompt to 662107543Sscottl # commit it. 663107543Sscottl # 664107543Sscottl _disable=${disableflag:-"no"} 665107543Sscottl [ -z "$configflag" ] && printf "%-10s : %s\n" Username $username 666107543Sscottl case $passwdtype in 667107543Sscottl yes) 668107543Sscottl _pass='*****' 669107543Sscottl ;; 670107543Sscottl no) 671107543Sscottl _pass='<disabled>' 672107543Sscottl ;; 673107543Sscottl none) 674107543Sscottl _pass='<blank>' 675107543Sscottl ;; 676107543Sscottl random) 677107543Sscottl _pass='<random>' 678107543Sscottl ;; 679107543Sscottl esac 680107543Sscottl printf "%-10s : %s\n" "Password" "$_pass" 681107543Sscottl [ -z "$configflag" ] && printf "%-10s : %s\n" "Full Name" "$ugecos" 682107543Sscottl [ -z "$configflag" ] && printf "%-10s : %s\n" "Uid" "$uuid" 683107543Sscottl printf "%-10s : %s\n" "Class" "$uclass" 684107543Sscottl [ -z "$configflag" ] && printf "%-10s : %s %s\n" "Groups" "${ulogingroup:-$username}" "$ugroups" 685107543Sscottl printf "%-10s : %s\n" "Home" "$uhome" 686107543Sscottl printf "%-10s : %s\n" "Shell" "$ushell" 687107543Sscottl printf "%-10s : %s\n" "Locked" "$_disable" 688107543Sscottl while : ; do 689107543Sscottl echo -n "OK? (yes/no): " 690107543Sscottl read _input 691107543Sscottl case $_input in 692107543Sscottl [Nn][Oo]|[Nn]) 693107543Sscottl return 1 694107543Sscottl ;; 695107543Sscottl [Yy][Ee][Ss]|[Yy][Ee]|[Yy]) 696107543Sscottl add_user 697107543Sscottl ;; 698107543Sscottl *) 699107543Sscottl continue 700107543Sscottl ;; 701107543Sscottl esac 702107543Sscottl break 703107543Sscottl done 704107543Sscottl return 0 705107543Sscottl} 706107543Sscottl 707107543Sscottl#### END SUBROUTINE DEFENITION #### 708107543Sscottl 709107543SscottlTHISCMD=`/usr/bin/basename $0` 710107543SscottlDEFAULTSHELL=/bin/sh 711107543SscottlADDUSERCONF="${ADDUSERCONF:-/etc/adduser.conf}" 712107543SscottlPWCMD="${PWCMD:-/usr/sbin/pw}" 713107543SscottlMAILCMD="${MAILCMD:-mail}" 714107543SscottlETCSHELLS="${ETCSHELLS:-/etc/shells}" 715107543Sscottl 716107543Sscottl# Set default values 717107543Sscottl# 718107543Sscottlusername= 719107543Sscottluuid= 720107543Sscottluidstart= 721107543Sscottlugecos= 722107543Sscottlulogingroup= 723107543Sscottluclass= 724107543Sscottluhome= 725107543Sscottlupass= 726107543Sscottlushell= 727107543Sscottludotdir=/usr/share/skel 728107543Sscottlugroups= 729107543Sscottluexpire= 730107543Sscottlupwexpire= 731107543Sscottlshells="`valid_shells`" 732107543Sscottlpasswdtype="yes" 733107543Sscottlmsgfile=/etc/adduser.msg 734107543Sscottlmsgflag= 735107543Sscottlquietflag= 736107543Sscottlconfigflag= 737107543Sscottlfflag= 738107543Sscottlinfile= 739107543Sscottldisableflag= 740107543Sscottlreadconfig="yes" 741107543Sscottlhomeprefix="/home" 742107543Sscottlrandompass= 743107543Sscottlfileline= 744107543Sscottlsavedpwtype= 745107543Sscottldefaultclass= 746107543Sscottldefaultgoups= 747107543Sscottldefaultshell="${DEFAULTSHELL}" 748107543Sscottl 749107543Sscottl# Make sure the user running this program is root. This isn't a security 750107543Sscottl# measure as much as it is a usefull method of reminding the user to 751107543Sscottl# 'su -' before he/she wastes time entering data that won't be saved. 752107543Sscottl# 753107543Sscottlprocowner=${procowner:-`/usr/bin/id -u`} 754107543Sscottlif [ "$procowner" != "0" ]; then 755107543Sscottl err 'you must be the super-user (uid 0) to use this utility.' 756107543Sscottl exit 1 757107543Sscottlfi 758107543Sscottl 759107543Sscottl# Overide from our conf file 760107543Sscottl# Quickly go through the commandline line to see if we should read 761107543Sscottl# from our configuration file. The actual parsing of the commandline 762107543Sscottl# arguments happens after we read in our configuration file (commandline 763107543Sscottl# should override configuration file). 764107543Sscottl# 765107543Sscottlfor _i in $* ; do 766107543Sscottl if [ "$_i" = "-N" ]; then 767107543Sscottl readconfig= 768107543Sscottl break; 769107543Sscottl fi 770107543Sscottldone 771107543Sscottlif [ -n "$readconfig" ]; then 772107543Sscottl # On a long-lived system, the first time this script is run it 773107543Sscottl # will barf upon reading the configuration file for its perl predecessor. 774107543Sscottl if ( . ${ADDUSERCONF} > /dev/null 2>&1 ); then 775107543Sscottl [ -r ${ADDUSERCONF} ] && . ${ADDUSERCONF} > /dev/null 2>&1 776107543Sscottl fi 777107543Sscottlfi 778107543Sscottl 779107543Sscottl# Proccess command-line options 780107543Sscottl# 781107543Sscottlfor _switch ; do 782107543Sscottl case $_switch in 783107543Sscottl -L) 784107543Sscottl defaultclass="$2" 785107543Sscottl shift; shift 786107543Sscottl ;; 787107543Sscottl -C) 788107543Sscottl configflag=yes 789107543Sscottl shift 790107543Sscottl ;; 791107543Sscottl -E) 792107543Sscottl disableflag=yes 793107543Sscottl shift 794107543Sscottl ;; 795107543Sscottl -k) 796107543Sscottl udotdir="$2" 797107543Sscottl shift; shift 798107543Sscottl ;; 799107543Sscottl -f) 800107543Sscottl [ "$2" != "-" ] && infile="$2" 801107543Sscottl fflag=yes 802107543Sscottl shift; shift 803107543Sscottl ;; 804107543Sscottl -G) 805107543Sscottl defaultgroups="$2" 806107543Sscottl shift; shift 807107543Sscottl ;; 808107543Sscottl -h) 809107543Sscottl show_usage 810107543Sscottl exit 0 811107543Sscottl ;; 812107543Sscottl -d) 813107543Sscottl homeprefix="$2" 814107543Sscottl shift; shift 815107543Sscottl ;; 816107543Sscottl -m) 817107543Sscottl case "$2" in 818107543Sscottl [Nn][Oo]) 819107543Sscottl msgflag= 820107543Sscottl ;; 821107543Sscottl *) 822107543Sscottl msgflag=yes 823107543Sscottl msgfile="$2" 824107543Sscottl ;; 825107543Sscottl esac 826107543Sscottl shift; shift 827107543Sscottl ;; 828107543Sscottl -N) 829107543Sscottl readconfig= 830107543Sscottl shift 831107543Sscottl ;; 832107543Sscottl -w) 833107543Sscottl case "$2" in 834107543Sscottl no|none|random|yes) 835107543Sscottl passwdtype=$2 836107543Sscottl ;; 837107543Sscottl *) 838107543Sscottl show_usage 839107543Sscottl exit 1 840107543Sscottl ;; 841107543Sscottl esac 842107543Sscottl shift; shift 843107543Sscottl ;; 844107543Sscottl -q) 845107543Sscottl quietflag=yes 846107543Sscottl shift 847107543Sscottl ;; 848107543Sscottl -s) 849107543Sscottl defaultshell="`fullpath_from_shell $2`" 850107543Sscottl shift; shift 851107543Sscottl ;; 852107543Sscottl -u) 853107543Sscottl uidstart=$2 854107543Sscottl shift; shift 855107543Sscottl ;; 856107543Sscottl esac 857107543Sscottldone 858107543Sscottl 859107543Sscottl# If the -f switch was used, get input from a file. Otherwise, 860107543Sscottl# this is an interactive session. 861107543Sscottl# 862107543Sscottlif [ -n "$fflag" ]; then 863107543Sscottl if [ -z "$infile" ]; then 864107543Sscottl input_from_file 865107543Sscottl elif [ -n "$infile" ]; then 866107543Sscottl if [ -r "$infile" ]; then 867107543Sscottl input_from_file < $infile 868107543Sscottl else 869107543Sscottl err "File ($infile) is unreadable or does not exist." 870107543Sscottl fi 871107543Sscottl fi 872107543Sscottlelse 873107543Sscottl input_interactive 874107543Sscottlfi 875