adduser.sh revision 112433
1107543Sscottl#!/bin/sh 2107543Sscottl# 3127076Smtm# 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@identd.net> 26107543Sscottl# 27107543Sscottl# $FreeBSD: head/usr.sbin/adduser/adduser.sh 112433 2003-03-20 16:36:03Z 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" 80127076Smtm 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" 85127076Smtm echo " -f file from which input will be received" 86107543Sscottl echo " -h display this usage message" 87107543Sscottl echo " -k path to skeleton home directory" 88112519Smtm echo " -m user welcome message file" 89107543Sscottl echo " -q absolute minimal user feedback" 90107543Sscottl echo " -s shell" 91107543Sscottl echo " -u uid to start at" 92107543Sscottl echo " -w password type: no, none, yes or random" 93107543Sscottl} 94107543Sscottl 95107543Sscottl# valid_shells 96107543Sscottl# Outputs a list of valid shells from /etc/shells. Only the 97107543Sscottl# basename of the shell is output. 98107543Sscottl# 99107543Sscottlvalid_shells() { 100107543Sscottl _prefix= 101107543Sscottl cat ${ETCSHELLS} | 102107543Sscottl while read _path _junk ; do 103107543Sscottl case $_path in 104107543Sscottl \#*|'') 105107543Sscottl ;; 106107543Sscottl *) 107107543Sscottl echo -n "${_prefix}`basename $_path`" 108107543Sscottl _prefix=' ' 109107543Sscottl ;; 110107543Sscottl esac 111107543Sscottl done 112107543Sscottl} 113107543Sscottl 114107543Sscottl# fullpath_from_shell shell 115116627Smtm# Given $shell, the basename component of a valid shell, get the 116127635Scperciva# full path to the shell from the /etc/shells file. 117116627Smtm# 118107543Sscottlfullpath_from_shell() { 119107543Sscottl _shell=$1 120107543Sscottl [ -z "$_shell" ] && return 1 121130160Smtm 122130160Smtm cat ${ETCSHELLS} | 123107543Sscottl while read _path _junk ; do 124107543Sscottl case "$_path" in 125107543Sscottl \#*|'') 126107543Sscottl ;; 127107543Sscottl *) 128107543Sscottl if [ "`basename $_path`" = "$_shell" ]; then 129135616Sroam echo $_path 130135616Sroam return 0 131135616Sroam fi 132135616Sroam ;; 133135616Sroam esac 134135616Sroam done 135135616Sroam return 1 136135616Sroam} 137135616Sroam 138135616Sroam# save_config 139135616Sroam# Save some variables to a configuration file. 140107543Sscottl# Note: not all script variables are saved, only those that 141107543Sscottl# it makes sense to save. 142107543Sscottl# 143107543Sscottlsave_config() { 144107543Sscottl echo "# Configuration file for adduser(8)." > ${ADDUSERCONF} 145107543Sscottl echo "# NOTE: only *some* variables are saved." >> ${ADDUSERCONF} 146130160Smtm echo "# Last Modified on `${DATECMD}`." >> ${ADDUSERCONF} 147130160Smtm echo '' >> ${ADDUSERCONF} 148107543Sscottl echo "defaultLgroup=$ulogingroup" >> ${ADDUSERCONF} 149107543Sscottl echo "defaultclass=$uclass" >> ${ADDUSERCONF} 150107543Sscottl echo "defaultgroups=$ugroups" >> ${ADDUSERCONF} 151107543Sscottl echo "passwdtype=$passwdtype" >> ${ADDUSERCONF} 152107543Sscottl echo "homeprefix=$homeprefix" >> ${ADDUSERCONF} 153107543Sscottl echo "defaultshell=$ushell" >> ${ADDUSERCONF} 154116627Smtm echo "udotdir=$udotdir" >> ${ADDUSERCONF} 155107543Sscottl echo "msgfile=$msgfile" >> ${ADDUSERCONF} 156107543Sscottl echo "disableflag=$disableflag" >> ${ADDUSERCONF} 157107543Sscottl} 158116627Smtm 159116627Smtm# add_user 160116627Smtm# Add a user to the user database. If the user chose to send a welcome 161116627Smtm# message or lock the account, do so. 162116627Smtm# 163116627Smtmadd_user() { 164116627Smtm 165116627Smtm # Is this a configuration run? If so, don't modify user database. 166116627Smtm # 167116627Smtm if [ -n "$configflag" ]; then 168116627Smtm save_config 169116627Smtm return 170116627Smtm fi 171116627Smtm 172116627Smtm _uid= 173116627Smtm _name= 174116627Smtm _comment= 175116627Smtm _gecos= 176116627Smtm _home= 177116627Smtm _group= 178116628Smtm _grouplist= 179116627Smtm _shell= 180116627Smtm _class= 181116627Smtm _dotdir= 182116627Smtm _expire= 183107543Sscottl _pwexpire= 184107543Sscottl _passwd= 185107543Sscottl _upasswd= 186107543Sscottl _passwdmethod= 187107543Sscottl 188107543Sscottl _name="-n '$username'" 189107543Sscottl [ -n "$uuid" ] && _uid='-u "$uuid"' 190107543Sscottl [ -n "$ulogingroup" ] && _group='-g "$ulogingroup"' 191109751Sfjoe [ -n "$ugroups" ] && _grouplist='-G "$ugroups"' 192107543Sscottl [ -n "$ushell" ] && _shell='-s "$ushell"' 193112433Smtm [ -n "$uhome" ] && _home='-m -d "$uhome"' 194107543Sscottl [ -n "$uclass" ] && _class='-L "$uclass"' 195107543Sscottl [ -n "$ugecos" ] && _comment='-c "$ugecos"' 196107543Sscottl [ -n "$udotdir" ] && _dotdir='-k "$udotdir"' 197107543Sscottl [ -n "$uexpire" ] && _expire='-e "$uexpire"' 198107543Sscottl [ -n "$upwexpire" ] && _pwexpire='-p "$upwexpire"' 199107543Sscottl case $passwdtype in 200107543Sscottl no) 201107543Sscottl _passwdmethod="-w no" 202107543Sscottl _passwd="-h -" 203107543Sscottl ;; 204107543Sscottl yes) 205107543Sscottl # Note on processing the password: The outer double quotes 206107543Sscottl # make literal everything except ` and \ and $. 207107543Sscottl # The outer single quotes make literal ` and $. 208107543Sscottl # We can ensure the \ isn't treated specially by specifying 209107543Sscottl # the -r switch to the read command used to obtain the input. 210107543Sscottl # 211107543Sscottl _passwdmethod="-w yes" 212107543Sscottl _passwd="-h 0" 213107543Sscottl _upasswd='echo "$upass" |' 214107543Sscottl ;; 215107543Sscottl none) 216107543Sscottl _passwdmethod="-w none" 217107543Sscottl ;; 218107543Sscottl random) 219107543Sscottl _passwdmethod="-w random" 220107543Sscottl ;; 221107543Sscottl esac 222107543Sscottl 223107543Sscottl _pwcmd="$_upasswd ${PWCMD} useradd $_uid $_name $_group $_grouplist $_comment" 224107543Sscottl _pwcmd="$_pwcmd $_shell $_class $_home $_dotdir $_passwdmethod $_passwd" 225107543Sscottl _pwcmd="$_pwcmd $_expire $_pwexpire" 226107543Sscottl 227107543Sscottl if ! _output=`eval $_pwcmd` ; then 228107543Sscottl err "There was an error adding user ($username)." 229107543Sscottl return 1 230107543Sscottl else 231107543Sscottl info "Successfully added ($username) to the user database." 232107543Sscottl if [ "random" = "$passwdtype" ]; then 233109720Smtm randompass="$_output" 234110595Smtm info "Password for ($username) is: $randompass" 235110595Smtm fi 236110595Smtm fi 237110595Smtm 238110595Smtm if [ -n "$disableflag" ]; then 239110595Smtm if ${PWCMD} lock $username ; then 240110595Smtm info "Account ($username) is locked." 241110595Smtm else 242110595Smtm info "Account ($username) could NOT be locked." 243127076Smtm fi 244127076Smtm fi 245127076Smtm 246127076Smtm _line= 247127076Smtm _owner= 248127076Smtm _perms= 249127076Smtm if [ -n "$msgflag" ]; then 250127076Smtm [ -r "$msgfile" ] && { 251127076Smtm # We're evaluating the contents of an external file. 252127076Smtm # Let's not open ourselves up for attack. _perms will 253127076Smtm # be empty if it's writeable only by the owner. _owner 254107543Sscottl # will *NOT* be empty if the file is owned by root. 255107543Sscottl # 256107543Sscottl _dir="`dirname $msgfile`" 257107543Sscottl _file="`basename $msgfile`" 258107543Sscottl _perms=`/usr/bin/find $_dir -name $_file -perm +07022 -prune` 259107543Sscottl _owner=`/usr/bin/find $_dir -name $_file -user 0 -prune` 260110595Smtm if [ -z "$_owner" -o -n "$_perms" ]; then 261110595Smtm err "The message file ($msgfile) may be writeable only by root." 262110595Smtm return 1 263110595Smtm fi 264110595Smtm cat "$msgfile" | 265110595Smtm while read _line ; do 266107543Sscottl eval echo "$_line" 267107543Sscottl done | ${MAILCMD} -s"Welcome" ${username} 268110595Smtm info "Sent welcome message to ($username)." 269107543Sscottl } 270107543Sscottl fi 271107543Sscottl} 272107543Sscottl 273107543Sscottl# get_user 274107543Sscottl# Reads username of the account from standard input or from a global 275107543Sscottl# variable containing an account line from a file. The username is 276107543Sscottl# required. If this is an interactive session it will prompt in 277107543Sscottl# a loop until a username is entered. If it is batch processing from 278107543Sscottl# a file it will output an error message and return to the caller. 279107543Sscottl# 280107543Sscottlget_user() { 281107543Sscottl _input= 282107543Sscottl 283107543Sscottl # No need to take down user names if this is a configuration saving run. 284107543Sscottl [ -n "$configflag" ] && return 285107543Sscottl 286107543Sscottl while : ; do 287107543Sscottl if [ -z "$fflag" ]; then 288107543Sscottl echo -n "Username: " 289107543Sscottl read _input 290107543Sscottl else 291107543Sscottl _input="`echo "$fileline" | cut -f1 -d:`" 292107543Sscottl fi 293107543Sscottl 294107543Sscottl # There *must* be a username. If this is an interactive 295107543Sscottl # session give the user an opportunity to retry. 296107543Sscottl # 297107543Sscottl if [ -z "$_input" ]; then 298107543Sscottl err "You must enter a username!" 299107543Sscottl [ -z "$fflag" ] && continue 300107543Sscottl fi 301107543Sscottl break 302107543Sscottl done 303107543Sscottl username="$_input" 304107543Sscottl} 305107543Sscottl 306107543Sscottl# get_gecos 307107543Sscottl# Reads extra information about the user. Can be used both in interactive 308107543Sscottl# and batch (from file) mode. 309107543Sscottl# 310107543Sscottlget_gecos() { 311107543Sscottl _input= 312107543Sscottl 313107543Sscottl # No need to take down additional user information for a configuration run. 314107543Sscottl [ -n "$configflag" ] && return 315107543Sscottl 316107543Sscottl if [ -z "$fflag" ]; then 317107543Sscottl echo -n "Full name: " 318107543Sscottl read _input 319107543Sscottl else 320107543Sscottl _input="`echo "$fileline" | cut -f7 -d:`" 321107543Sscottl fi 322107543Sscottl ugecos="$_input" 323107543Sscottl} 324107543Sscottl 325107543Sscottl# get_shell 326107543Sscottl# Get the account's shell. Works in interactive and batch mode. It 327107543Sscottl# accepts only the base name of the shell, NOT the full path. 328107543Sscottl# If an invalid shell is entered it will simply use the default shell. 329107543Sscottl# 330107543Sscottlget_shell() { 331107543Sscottl _input= 332107543Sscottl _fullpath= 333107543Sscottl ushell="$defaultshell" 334107543Sscottl 335107543Sscottl # Make sure the current value of the shell is a valid one 336107543Sscottl _shellchk="${GREPCMD} '^$ushell$' ${ETCSHELLS} > /dev/null 2>&1" 337107543Sscottl eval $_shellchk || { 338107543Sscottl err "Invalid shell ($ushell). Using default shell ${defaultshell}." 339107543Sscottl ushell="$defaultshell" 340107543Sscottl } 341107543Sscottl 342107543Sscottl if [ -z "$fflag" ]; then 343107543Sscottl echo -n "Shell ($shells) [`basename $ushell`]: " 344107543Sscottl read _input 345107543Sscottl else 346107543Sscottl _input="`echo "$fileline" | cut -f9 -d:`" 347107543Sscottl fi 348107543Sscottl if [ -n "$_input" ]; then 349107543Sscottl _fullpath=`fullpath_from_shell $_input` 350107543Sscottl if [ -n "$_fullpath" ]; then 351107543Sscottl ushell="$_fullpath" 352107543Sscottl else 353107543Sscottl err "Invalid shell selection. Using default shell ${defaultshell}." 354107543Sscottl ushell="$defaultshell" 355107543Sscottl fi 356107543Sscottl fi 357107543Sscottl} 358107543Sscottl 359107543Sscottl# get_homedir 360107543Sscottl# Reads the account's home directory. Used both with interactive input 361107543Sscottl# and batch input. 362107543Sscottl# 363107543Sscottlget_homedir() { 364107543Sscottl _input= 365107543Sscottl if [ -z "$fflag" ]; then 366107543Sscottl echo -n "Home directory [${homeprefix}/${username}]: " 367107543Sscottl read _input 368107543Sscottl else 369107543Sscottl _input="`echo "$fileline" | cut -f8 -d:`" 370107543Sscottl fi 371107543Sscottl 372107543Sscottl if [ -n "$_input" ]; then 373107543Sscottl uhome="$_input" 374107543Sscottl # if this is a configuration run, then user input is the home 375107543Sscottl # directory prefix. Otherwise it is understood to 376107543Sscottl # be $prefix/$user 377107543Sscottl # 378107543Sscottl [ -z "$configflag" ] && homeprefix="`dirname $uhome`" || homeprefix="$uhome" 379107543Sscottl else 380107543Sscottl uhome="${homeprefix}/${username}" 381107543Sscottl fi 382130160Smtm} 383107543Sscottl 384107543Sscottl# get_uid 385107543Sscottl# Reads a numeric userid in an interactive or batch session. Automatically 386107543Sscottl# allocates one if it is not specified. 387107543Sscottl# 388107543Sscottlget_uid() { 389107543Sscottl uuid=${uidstart} 390107543Sscottl _input= 391127076Smtm _prompt= 392127076Smtm 393127076Smtm # No need to take down uids for a configuration saving run. 394127076Smtm [ -n "$configflag" ] && return 395127076Smtm 396116627Smtm if [ -n "$uuid" ]; then 397107543Sscottl _prompt="Uid [$uuid]: " 398107543Sscottl else 399107543Sscottl _prompt="Uid (Leave empty for default): " 400107543Sscottl fi 401107543Sscottl if [ -z "$fflag" ]; then 402107543Sscottl echo -n "$_prompt" 403107543Sscottl read _input 404107543Sscottl else 405127076Smtm _input="`echo "$fileline" | cut -f2 -d:`" 406127076Smtm fi 407107543Sscottl 408127076Smtm [ -n "$_input" ] && uuid=$_input 409127076Smtm uuid=`get_nextuid $uuid` 410127076Smtm uidstart=$uuid 411127076Smtm} 412127076Smtm 413127076Smtm# get_class 414127076Smtm# Reads login class of account. Can be used in interactive or batch mode. 415127076Smtm# 416107543Sscottlget_class() { 417107543Sscottl uclass="$defaultclass" 418107543Sscottl _input= 419107543Sscottl _class=${uclass:-"default"} 420107543Sscottl 421107543Sscottl if [ -z "$fflag" ]; then 422107543Sscottl echo -n "Login class [$_class]: " 423107543Sscottl read _input 424107543Sscottl else 425107543Sscottl _input="`echo "$fileline" | cut -f4 -d:`" 426107543Sscottl fi 427107543Sscottl 428107543Sscottl [ -n "$_input" ] && uclass="$_input" 429107543Sscottl} 430107543Sscottl 431107543Sscottl# get_logingroup 432107543Sscottl# Reads user's login group. Can be used in both interactive and batch 433107543Sscottl# modes. The specified value can be a group name or its numeric id. 434107543Sscottl# This routine leaves the field blank if nothing is provided and 435107543Sscottl# a default login group has not been set. The pw(8) command 436107543Sscottl# will then provide a login group with the same name as the username. 437107543Sscottl# 438107543Sscottlget_logingroup() { 439107543Sscottl ulogingroup="$defaultLgroup" 440107543Sscottl _input= 441107543Sscottl 442107543Sscottl if [ -z "$fflag" ]; then 443107543Sscottl echo -n "Login group [${ulogingroup:-$username}]: " 444107543Sscottl read _input 445107543Sscottl else 446107543Sscottl _input="`echo "$fileline" | cut -f3 -d:`" 447107543Sscottl fi 448107543Sscottl 449107543Sscottl # Pw(8) will use the username as login group if it's left empty 450107543Sscottl [ -n "$_input" ] && ulogingroup="$_input" 451107543Sscottl} 452107543Sscottl 453107543Sscottl# get_groups 454107543Sscottl# Read additional groups for the user. It can be used in both interactive 455107543Sscottl# and batch modes. 456107543Sscottl# 457107543Sscottlget_groups() { 458107543Sscottl ugroups="$defaultgroups" 459107543Sscottl _input= 460107543Sscottl _group=${ulogingroup:-"${username}"} 461107543Sscottl 462107543Sscottl if [ -z "$configflag" ]; then 463109573Sfjoe [ -z "$fflag" ] && echo -n "Login group is $_group. Invite $username" 464107543Sscottl [ -z "$fflag" ] && echo -n " into other groups? [$ugroups]: " 465107543Sscottl else 466107543Sscottl [ -z "$fflag" ] && echo -n "Enter additional groups [$ugroups]: " 467107543Sscottl fi 468107543Sscottl read _input 469107543Sscottl 470107543Sscottl [ -n "$_input" ] && ugroups="$_input" 471107543Sscottl} 472107543Sscottl 473107543Sscottl# get_expire_dates 474107543Sscottl# Read expiry information for the account and also for the password. This 475107543Sscottl# routine is used only from batch processing mode. 476107543Sscottl# 477107543Sscottlget_expire_dates() { 478107543Sscottl upwexpire="`echo "$fileline" | cut -f5 -d:`" 479107543Sscottl uexpire="`echo "$fileline" | cut -f6 -d:`" 480107543Sscottl} 481107543Sscottl 482107543Sscottl# get_password 483107543Sscottl# Read the password in batch processing mode. The password field matters 484107543Sscottl# only when the password type is "yes" or "random". If the field is empty and the 485107543Sscottl# password type is "yes", then it assumes the account has an empty passsword 486107543Sscottl# and changes the password type accordingly. If the password type is "random" 487107543Sscottl# and the password field is NOT empty, then it assumes the account will NOT 488107543Sscottl# have a random password and set passwdtype to "yes." 489107543Sscottl# 490107543Sscottlget_password() { 491107543Sscottl # We may temporarily change a password type. Make sure it's changed 492107543Sscottl # back to whatever it was before we process the next account. 493107543Sscottl # 494107543Sscottl [ -n "$savedpwtype" ] && { 495112433Smtm passwdtype=$savedpwtype 496112433Smtm savedpwtype= 497112433Smtm } 498107543Sscottl 499107543Sscottl # There may be a ':' in the password 500112433Smtm upass=${fileline#*:*:*:*:*:*:*:*:*:} 501107543Sscottl 502107543Sscottl if [ -z "$upass" ]; then 503107543Sscottl case $passwdtype in 504112433Smtm yes) 505107543Sscottl # if it's empty, assume an empty password 506107543Sscottl passwdtype=none 507107543Sscottl savedpwtype=yes 508107543Sscottl ;; 509107543Sscottl esac 510107543Sscottl else 511112433Smtm case $passwdtype in 512107543Sscottl random) 513107543Sscottl passwdtype=yes 514107543Sscottl savedpwtype=random 515107543Sscottl ;; 516107543Sscottl esac 517107543Sscottl fi 518107543Sscottl} 519107543Sscottl 520107543Sscottl# input_from_file 521107543Sscottl# Reads a line of account information from standard input and 522107543Sscottl# adds it to the user database. 523107543Sscottl# 524107543Sscottlinput_from_file() { 525107543Sscottl _field= 526107543Sscottl 527107543Sscottl while read -r fileline ; do 528107543Sscottl case "$fileline" in 529107543Sscottl \#*|'') 530107543Sscottl return 0 531107543Sscottl ;; 532107543Sscottl esac 533107543Sscottl 534107543Sscottl get_user || continue 535107543Sscottl get_gecos 536107543Sscottl get_uid 537107543Sscottl get_logingroup 538107543Sscottl get_class 539107543Sscottl get_shell 540107543Sscottl get_homedir 541107543Sscottl get_password 542107543Sscottl get_expire_dates 543107543Sscottl 544107543Sscottl add_user 545107543Sscottl done 546107543Sscottl} 547107543Sscottl 548107543Sscottl# input_interactive 549107543Sscottl# Prompts for user information interactively, and commits to 550107543Sscottl# the user database. 551107543Sscottl# 552107543Sscottlinput_interactive() { 553107543Sscottl 554107543Sscottl _disable= 555107543Sscottl _pass= 556107543Sscottl _passconfirm= 557107543Sscottl _random="no" 558107543Sscottl _emptypass="no" 559107543Sscottl _usepass="yes" 560107543Sscottl _logingroup_ok="no" 561107543Sscottl _groups_ok="no" 562107543Sscottl case $passwdtype in 563107543Sscottl none) 564107543Sscottl _emptypass="yes" 565107543Sscottl _usepass="yes" 566107543Sscottl ;; 567107543Sscottl no) 568107543Sscottl _usepass="no" 569107543Sscottl ;; 570107543Sscottl random) 571107543Sscottl _random="yes" 572107543Sscottl ;; 573107543Sscottl esac 574107543Sscottl 575107543Sscottl get_user 576107543Sscottl get_gecos 577107543Sscottl get_uid 578107543Sscottl 579107543Sscottl # The case where group = user is handled elsewhere, so 580107543Sscottl # validate any other groups the user is invited to. 581107543Sscottl until [ "$_logingroup_ok" = yes ]; do 582107543Sscottl get_logingroup 583107543Sscottl _logingroup_ok=yes 584107543Sscottl if [ -n "$ulogingroup" -a "$username" != "$ulogingroup" ]; then 585107543Sscottl if ! ${PWCMD} show group $ulogingroup > /dev/null 2>&1; then 586107543Sscottl echo "Group $ulogingroup does not exist!" 587107543Sscottl _logingroup_ok=no 588110595Smtm fi 589107543Sscottl fi 590107543Sscottl done 591107543Sscottl until [ "$_groups_ok" = yes ]; do 592107543Sscottl get_groups 593107543Sscottl _groups_ok=yes 594107543Sscottl for i in $ugroups; do 595107543Sscottl if [ "$username" != "$i" ]; then 596107543Sscottl if ! ${PWCMD} show group $i > /dev/null 2>&1; then 597107543Sscottl echo "Group $i does not exist!" 598107543Sscottl _groups_ok=no 599107543Sscottl fi 600107543Sscottl fi 601107543Sscottl done 602107543Sscottl done 603107543Sscottl 604107543Sscottl get_class 605107543Sscottl get_shell 606107543Sscottl get_homedir 607107543Sscottl 608107543Sscottl while : ; do 609107543Sscottl echo -n "Use password-based authentication? [$_usepass]: " 610107543Sscottl read _input 611107543Sscottl [ -z "$_input" ] && _input=$_usepass 612107543Sscottl case $_input in 613107543Sscottl [Nn][Oo]|[Nn]) 614107543Sscottl passwdtype="no" 615107543Sscottl ;; 616107543Sscottl [Yy][Ee][Ss]|[Yy][Ee]|[Yy]) 617107543Sscottl while : ; do 618107543Sscottl echo -n "Use an empty password? (yes/no) [$_emptypass]: " 619107543Sscottl read _input 620107543Sscottl [ -n "$_input" ] && _emptypass=$_input 621112401Smtm case $_emptypass in 622112401Smtm [Nn][Oo]|[Nn]) 623107543Sscottl echo -n "Use a random password? (yes/no) [$_random]: " 624107543Sscottl read _input 625107543Sscottl [ -n "$_input" ] && _random="$_input" 626107543Sscottl case $_random in 627107543Sscottl [Yy][Ee][Ss]|[Yy][Ee]|[Yy]) 628107543Sscottl passwdtype="random" 629107543Sscottl break 630107543Sscottl ;; 631107543Sscottl esac 632107543Sscottl passwdtype="yes" 633107543Sscottl [ -n "$configflag" ] && break 634107543Sscottl trap 'stty echo; exit' 0 1 2 3 15 635107543Sscottl stty -echo 636107543Sscottl echo -n "Enter password: " 637107543Sscottl read -r upass 638107543Sscottl echo'' 639110537Sadrian echo -n "Enter password again: " 640110537Sadrian read _passconfirm 641110537Sadrian echo '' 642110537Sadrian stty echo 643110537Sadrian # if user entered a blank password 644110537Sadrian # explicitly ask again. 645110537Sadrian [ -z "$upass" -a -z "$_passconfirm" ] \ 646110537Sadrian && continue 647110537Sadrian ;; 648110537Sadrian [Yy][Ee][Ss]|[Yy][Ee]|[Yy]) 649110537Sadrian passwdtype="none" 650110537Sadrian break; 651110537Sadrian ;; 652110537Sadrian *) 653110537Sadrian # invalid answer; repeat the loop 654110537Sadrian continue 655110537Sadrian ;; 656110537Sadrian esac 657110537Sadrian if [ "$upass" != "$_passconfirm" ]; then 658110537Sadrian echo "Passwords did not match!" 659110537Sadrian continue 660110537Sadrian fi 661110537Sadrian break 662110537Sadrian done 663110537Sadrian ;; 664110537Sadrian *) 665107543Sscottl # invalid answer; repeat loop 666107543Sscottl continue 667107543Sscottl ;; 668107543Sscottl esac 669107543Sscottl break; 670107543Sscottl done 671107543Sscottl _disable=${disableflag:-"no"} 672107543Sscottl while : ; do 673107543Sscottl echo -n "Lock out the account after creation? [$_disable]: " 674107543Sscottl read _input 675107543Sscottl [ -z "$_input" ] && _input=$_disable 676107543Sscottl case $_input in 677107543Sscottl [Nn][Oo]|[Nn]) 678107543Sscottl disableflag= 679107543Sscottl ;; 680107543Sscottl [Yy][Ee][Ss]|[Yy][Ee]|[Yy]) 681107543Sscottl disableflag=yes 682107543Sscottl ;; 683107543Sscottl *) 684107543Sscottl # invalid answer; repeat loop 685107543Sscottl continue 686107543Sscottl ;; 687107543Sscottl esac 688107543Sscottl break 689107543Sscottl done 690107543Sscottl 691107543Sscottl # Display the information we have so far and prompt to 692107543Sscottl # commit it. 693107543Sscottl # 694112401Smtm _disable=${disableflag:-"no"} 695107543Sscottl [ -z "$configflag" ] && printf "%-10s : %s\n" Username $username 696107543Sscottl case $passwdtype in 697107543Sscottl yes) 698110595Smtm _pass='*****' 699107543Sscottl ;; 700107543Sscottl no) 701116623Smtm _pass='<disabled>' 702107543Sscottl ;; 703107543Sscottl none) 704107543Sscottl _pass='<blank>' 705107543Sscottl ;; 706107543Sscottl random) 707107543Sscottl _pass='<random>' 708107543Sscottl ;; 709107543Sscottl esac 710107543Sscottl [ -z "$configflag" ] && printf "%-10s : %s\n" "Password" "$_pass" 711107543Sscottl [ -n "$configflag" ] && printf "%-10s : %s\n" "Pass Type" "$passwdtype" 712107543Sscottl [ -z "$configflag" ] && printf "%-10s : %s\n" "Full Name" "$ugecos" 713107543Sscottl [ -z "$configflag" ] && printf "%-10s : %s\n" "Uid" "$uuid" 714107543Sscottl printf "%-10s : %s\n" "Class" "$uclass" 715107543Sscottl printf "%-10s : %s %s\n" "Groups" "${ulogingroup:-$username}" "$ugroups" 716107543Sscottl printf "%-10s : %s\n" "Home" "$uhome" 717107543Sscottl printf "%-10s : %s\n" "Shell" "$ushell" 718107543Sscottl printf "%-10s : %s\n" "Locked" "$_disable" 719107543Sscottl while : ; do 720107543Sscottl echo -n "OK? (yes/no): " 721107543Sscottl read _input 722107543Sscottl case $_input in 723107543Sscottl [Nn][Oo]|[Nn]) 724107543Sscottl return 1 725107543Sscottl ;; 726107543Sscottl [Yy][Ee][Ss]|[Yy][Ee]|[Yy]) 727107543Sscottl add_user 728107543Sscottl ;; 729107543Sscottl *) 730107543Sscottl continue 731107543Sscottl ;; 732107543Sscottl esac 733107543Sscottl break 734107543Sscottl done 735107543Sscottl return 0 736107543Sscottl} 737107543Sscottl 738107543Sscottl#### END SUBROUTINE DEFENITION #### 739107543Sscottl 740107543SscottlTHISCMD=`/usr/bin/basename $0` 741107543SscottlDEFAULTSHELL=/bin/sh 742107543SscottlADDUSERCONF="${ADDUSERCONF:-/etc/adduser.conf}" 743107543SscottlPWCMD="${PWCMD:-/usr/sbin/pw}" 744107543SscottlMAILCMD="${MAILCMD:-mail}" 745107543SscottlETCSHELLS="${ETCSHELLS:-/etc/shells}" 746107543SscottlGREPCMD="/usr/bin/grep" 747107543SscottlDATECMD="/bin/date" 748107543Sscottl 749107543Sscottl# Set default values 750107543Sscottl# 751107543Sscottlusername= 752107543Sscottluuid= 753107543Sscottluidstart= 754107543Sscottlugecos= 755107543Sscottlulogingroup= 756107543Sscottluclass= 757107543Sscottluhome= 758107543Sscottlupass= 759107543Sscottlushell= 760107543Sscottludotdir=/usr/share/skel 761107543Sscottlugroups= 762107543Sscottluexpire= 763107543Sscottlupwexpire= 764107543Sscottlshells="`valid_shells`" 765107543Sscottlpasswdtype="yes" 766107543Sscottlmsgfile=/etc/adduser.msg 767107543Sscottlmsgflag= 768107543Sscottlquietflag= 769107543Sscottlconfigflag= 770107543Sscottlfflag= 771109751Sfjoeinfile= 772109751Sfjoedisableflag= 773107543Sscottlreadconfig="yes" 774107543Sscottlhomeprefix="/home" 775107543Sscottlrandompass= 776112433Smtmfileline= 777107543Sscottlsavedpwtype= 778107543Sscottldefaultclass= 779107543SscottldefaultLgroup= 780107543Sscottldefaultgoups= 781107543Sscottldefaultshell="${DEFAULTSHELL}" 782107543Sscottl 783107543Sscottl# Make sure the user running this program is root. This isn't a security 784107543Sscottl# measure as much as it is a usefull method of reminding the user to 785107543Sscottl# 'su -' before he/she wastes time entering data that won't be saved. 786107543Sscottl# 787107543Sscottlprocowner=${procowner:-`/usr/bin/id -u`} 788107543Sscottlif [ "$procowner" != "0" ]; then 789107543Sscottl err 'you must be the super-user (uid 0) to use this utility.' 790107543Sscottl exit 1 791107543Sscottlfi 792107543Sscottl 793107543Sscottl# Overide from our conf file 794107543Sscottl# Quickly go through the commandline line to see if we should read 795107543Sscottl# from our configuration file. The actual parsing of the commandline 796107543Sscottl# arguments happens after we read in our configuration file (commandline 797107543Sscottl# should override configuration file). 798107543Sscottl# 799107543Sscottlfor _i in $* ; do 800107543Sscottl if [ "$_i" = "-N" ]; then 801107543Sscottl readconfig= 802107543Sscottl break; 803107543Sscottl fi 804107543Sscottldone 805107543Sscottlif [ -n "$readconfig" ]; then 806107543Sscottl # On a long-lived system, the first time this script is run it 807127076Smtm # will barf upon reading the configuration file for its perl predecessor. 808116627Smtm if ( . ${ADDUSERCONF} > /dev/null 2>&1 ); then 809127635Scperciva [ -r ${ADDUSERCONF} ] && . ${ADDUSERCONF} > /dev/null 2>&1 810109751Sfjoe fi 811109751Sfjoefi 812107543Sscottl 813107543Sscottl# Proccess command-line options 814107543Sscottl# 815107543Sscottlfor _switch ; do 816107543Sscottl case $_switch in 817107543Sscottl -L) 818107543Sscottl defaultclass="$2" 819107543Sscottl shift; shift 820107543Sscottl ;; 821107543Sscottl -C) 822107543Sscottl configflag=yes 823107543Sscottl shift 824107543Sscottl ;; 825107543Sscottl -E) 826107543Sscottl disableflag=yes 827107543Sscottl shift 828107543Sscottl ;; 829107543Sscottl -k) 830107543Sscottl udotdir="$2" 831107543Sscottl shift; shift 832107543Sscottl ;; 833107543Sscottl -f) 834107543Sscottl [ "$2" != "-" ] && infile="$2" 835107543Sscottl fflag=yes 836107543Sscottl shift; shift 837127076Smtm ;; 838127076Smtm -g) 839107543Sscottl defaultLgroup="$2" 840107543Sscottl shift; shift 841107543Sscottl ;; 842107543Sscottl -G) 843107543Sscottl defaultgroups="$2" 844107543Sscottl shift; shift 845112433Smtm ;; 846116784Smtm -h) 847107543Sscottl show_usage 848107543Sscottl exit 0 849107543Sscottl ;; 850107543Sscottl -d) 851107543Sscottl homeprefix="$2" 852107543Sscottl shift; shift 853107543Sscottl ;; 854107543Sscottl -m) 855107543Sscottl case "$2" in 856107543Sscottl [Nn][Oo]) 857107543Sscottl msgflag= 858107543Sscottl ;; 859107543Sscottl *) 860107543Sscottl msgflag=yes 861107543Sscottl msgfile="$2" 862107543Sscottl ;; 863107543Sscottl esac 864107543Sscottl shift; shift 865107543Sscottl ;; 866107543Sscottl -N) 867107543Sscottl readconfig= 868107543Sscottl shift 869107543Sscottl ;; 870107543Sscottl -w) 871107543Sscottl case "$2" in 872107543Sscottl no|none|random|yes) 873107543Sscottl passwdtype=$2 874107543Sscottl ;; 875107543Sscottl *) 876107543Sscottl show_usage 877107543Sscottl exit 1 878107543Sscottl ;; 879107543Sscottl esac 880107543Sscottl shift; shift 881107543Sscottl ;; 882107543Sscottl -q) 883107543Sscottl quietflag=yes 884107543Sscottl shift 885107543Sscottl ;; 886107543Sscottl -s) 887107543Sscottl defaultshell="`fullpath_from_shell $2`" 888107543Sscottl shift; shift 889107543Sscottl ;; 890107543Sscottl -u) 891127076Smtm uidstart=$2 892127076Smtm shift; shift 893127076Smtm ;; 894127076Smtm esac 895107543Sscottldone 896107543Sscottl 897107543Sscottl# If the -f switch was used, get input from a file. Otherwise, 898107543Sscottl# this is an interactive session. 899107543Sscottl# 900107543Sscottlif [ -n "$fflag" ]; then 901107543Sscottl if [ -z "$infile" ]; then 902107543Sscottl input_from_file 903107543Sscottl elif [ -n "$infile" ]; then 904107543Sscottl if [ -r "$infile" ]; then 905107543Sscottl input_from_file < $infile 906107543Sscottl else 907107543Sscottl err "File ($infile) is unreadable or does not exist." 908112433Smtm fi 909112433Smtm fi 910112433Smtmelse 911112433Smtm input_interactive 912107543Sscottl while : ; do 913107543Sscottl if [ -z "$configflag" ]; then 914107543Sscottl echo -n "Add another user? (yes/no): " 915107543Sscottl else 916107543Sscottl echo -n "Re-edit the default configuration? (yes/no): " 917107543Sscottl fi 918107543Sscottl read _input 919107543Sscottl case $_input in 920107543Sscottl [Yy][Ee][Ss]|[Yy][Ee]|[Yy]) 921107543Sscottl uidstart=`get_nextuid $uidstart` 922107543Sscottl input_interactive 923107543Sscottl continue 924107543Sscottl ;; 925107543Sscottl [Nn][Oo]|[Nn]) 926107543Sscottl echo "Goodbye!" 927107543Sscottl ;; 928107543Sscottl *) 929107543Sscottl continue 930107543Sscottl ;; 931107543Sscottl esac 932107543Sscottl break 933107543Sscottl done 934107543Sscottlfi 935107543Sscottl