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