#!/bin/bash # # adduser Interactive user adding program. # # Copyright (C) 1996 Petri Mattila, Prihateam Networks # petri@prihateam.fi # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # # Changes: # 220496 v0.01 Initial version # 230496 v0.02 More checks, embolden summary # 240496 Even more checks # 250496 Help with ? # 040596 v0.03 Cleanups # 050596 v0.04 Bug fixes, expire date checks # 070596 v0.05 Iso-latin-1 names # ## Defaults # default groups def_group="users" def_other_groups="" # default home directory def_home_dir=/home/users # default shell def_shell=/bin/tcsh # Default expiration date (mm/dd/yy) def_expire="" # default dates def_pwd_min=0 def_pwd_max=90 def_pwd_warn=14 def_pwd_iact=14 # possible UIDs uid_low=1000 uid_high=64000 # skel directory skel=/etc/skel # default mode for home directory def_mode=711 # Regex, that the login name must meet, only ANSI characters login_regex='^[0-9a-zA-Z_-]*$' # Regex, that the user name must meet # ANSI version ##name_regex='^[0-9a-zA-Z_-\ ]*$' # ISO-LATIN-1 version name_regex='^[0-9a-zA-ZÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõöùúûüýþÿ_-\ ]*$' # set PATH export PATH="/bin:/sbin:/usr/bin:/usr/sbin" # Some special characters case "$TERM" in vt*|ansi*|con*|xterm*|linux*) S='' # start embolden E='' # end embolden ;; *) S='' E='' ;; esac ## Functions check_root() { if test "$EUID" -ne 0 then echo "You must be root to run this program." exit 1 fi } check_user() { local usr pwd uid gid name home sh cat /etc/passwd | ( while IFS=":" read usr pwd uid gid name home sh do if test "$1" = "${usr}" then return 1 fi done return 0 ) } check_group() { local read grp pwd gid members cat /etc/group | ( while IFS=":" read grp pwd gid members do if test "$1" = "${grp}" then return 1 fi done return 0 ) } check_other_groups() { local grp check IFS check="$1" IFS="," set ${check} for grp do if check_group "${grp}" then echo "Group ${grp} does not exist." return 1 fi done return 0 } check_uid() { local usr pwd uid gid name home sh cat /etc/passwd | ( while IFS=":" read usr pwd uid gid name home sh do if test "$1" = "${uid}" then return 1 fi done return 0 ) } read_yn() { local ans ynd ynd="$1" while : do read ans case "${ans}" in "") return ${ynd} ;; [nN]) return 1 ;; [yY]) return 0 ;; *) echo -n "Y or N, please ? " ;; esac done } read_login() { echo while : do echo -n "Login: ${def_login:+[${def_login}] }" read login if test "${login}" = '?' then less /etc/passwd echo continue fi if test -z "${login}" -a -n "${def_login}" then login="${def_login}" echo "Using ${login}" return fi if test "${#login}" -gt 8 then echo "Login must be at most 8 characters long" continue fi if test "${#login}" -lt 2 then echo "Login must be at least 2 characters long" continue fi if ! expr "${login}" : "${login_regex}" &> /dev/null then echo "Please use letters, numbers and special characters _-,." continue fi if ! check_user "${login}" then echo "Username ${login} is already in use" continue fi def_login="${login}" return done } read_name () { echo while : do echo -n "Real name: ${def_name:+[${def_name}] }" read name if test "${name}" = '?' then less /etc/passwd echo continue fi if test -z "${name}" -a -n "${def_name}" then name="${def_name}" echo "Using ${name}" fi if test "${#name}" -gt 32 then echo "Name should be at most 32 characters long" continue fi if ! expr "${name}" : "${name_regex}" &> /dev/null then echo "Please use letters, numbers, spaces and special characters ,._-" continue fi def_name="${name}" return done } read_home() { local x echo while : do echo -n "Home Directory: [${def_home_dir}/${login}] " read home if test -z "${home}" then home="${def_home_dir}/${login}" echo "Using ${home}" fi if ! expr "${home}" : '^[0-9a-zA-Z,._-\/]*$' &> /dev/null then echo "Please use letters, numbers, spaces and special characters ,._-/" continue fi x="$(basename ${home})" if test "${x}" != "${login}" then echo "Warning: you are about to use different login name and home directory." fi x="$(dirname ${home})" if ! test -d "${x}" then echo "Directory ${x} does not exist." echo "If you still want to use it, please make it manually." continue fi def_home_dir="${x}" return done } read_shell () { local x echo while : do echo -n "Shell: [${def_shell}] " read shell if test -z "${shell}" then shell="${def_shell}" echo "Using ${shell}" fi for x in $(cat /etc/shells) do if test "${x}" = "${shell}" then def_shell="${shell}" return fi done echo "Possible shells are:" cat /etc/shells done } read_group () { echo while : do echo -n "Group: [${def_group}] " read group if test -z "${group}" then group="${def_group}" echo "Using ${group}" fi if test "${group}" = '?' then less /etc/group echo continue fi if check_group "${group}" then echo "Group ${group} does not exist." continue fi def_group="${group}" return done } read_other_groups () { echo while : do echo -n "Other groups: [${def_og:-none}] " read other_groups if test "${other_groups}" = '?' then less /etc/group echo continue fi if test -z "${other_groups}" then if test -n "${def_og}" then other_groups="${def_og}" echo "Using ${other_groups}" else echo "No other groups" return fi fi if ! check_other_groups "${other_groups}" then continue fi def_og="${other_groups}" return done } read_uid () { echo while : do echo -n "uid: [first free] " read uid if test -z "${uid}" then echo "Using first free UID." return fi if test "${uid}" = '?' then less /etc/passwd echo continue fi if ! expr "${uid}" : '^[0-9]+$' &> /dev/null then echo "Please use numbers only." continue fi if test "${uid}" -lt "${uid_low}" then echo "UID must be greater than ${uid_low}" continue fi if test "${uid}" -gt "${uid_high}" then echo "UID must be smaller than ${uid_high}" continue fi if ! check_uid "${uid}" then echo "UID ${uid} is already in use" continue fi return done } read_max_valid_days() { echo while : do echo -en "Maximum days between password changes: [${def_pwd_max}] " read max_days if test -z "${max_days}" then max_days="${def_pwd_max}" echo "Using ${max_days}" return fi if ! expr "${max_days}" : '^[0-9]+$' &> /dev/null then echo "Please use numbers only." continue fi if test "${max_days}" -lt 7 then echo "Warning: you are using a value shorter than a week." fi def_pwd_max="${max_days}" return done } read_min_valid_days() { echo while : do echo -en "Minimum days between password changes: [${def_pwd_min}] " read min_days if test -z "${min_days}" then min_days="${def_pwd_min}" echo "Using ${min_days}" return fi if ! expr "${min_days}" : '^[0-9]+$' &> /dev/null then echo "Please use numbers only." continue fi if test "${min_days}" -gt 7 then echo "Warning: you are using a value longer than a week." fi def_pwd_min="${min_days}" return done } read_warning_days() { echo while : do echo -en "Number of warning days before password expires: [${def_pwd_warn}] " read warn_days if test -z "${warn_days}" then warn_days="${def_pwd_warn}" echo "Using ${warn_days}" fi if ! expr "${warn_days}" : '^[0-9]+$' &> /dev/null then echo "Please use numbers only." continue fi if test "${warn_days}" -gt 14 then echo "Warning: you are using a value longer than two week." fi def_pwd_warn="${warn_days}" return done } read_inactive_days() { echo while : do echo -en "Number of usable days after expiration: [${def_pwd_iact}] " read iact_days if test -z "${iact_days}" then iact_days="${def_pwd_iact}" echo "Using ${iact_days}" return fi if ! expr "${iact_days}" : '^[0-9]+$' &> /dev/null then echo "Please use numbers only." continue fi if test "${iact_days}" -gt 14 then echo "Warning: you are using a value that is more than two weeks." fi def_pwd_iact="${iact_days}" return done } read_expire_date() { local ans echo while : do echo -en "Expire date of this account (mm/dd/yy): [${def_expire:-never}] " read ans if test -z "${ans}" then if test -z "${def_expire}" then ans="never" else ans="${def_expire}" echo "Using ${def_expire}" fi fi if test "${ans}" = "never" then echo "Account will never expire." def_expire="" expire="" return fi if ! expr "${ans}" : '^[0-9][0-9]/[0-9][0-9]/[0-9][0-9]$' &> /dev/null then echo "Please use format mm/dd/yy" continue fi if ! expire_date="$(date -d ${ans} '+%A, %B %d %Y')" then continue fi def_expire="${expire}" return done } read_passwd_yn() { echo -en "\nDo you want to set password [Y/n] ? " if read_yn 0 then set_pwd="YES" else set_pwd="" fi } print_values() { clear cat << EOM Login: ${S}${login}${E} Group: ${S}${group}${E} Other groups: ${S}${other_groups:-[none]}${E} Real Name: ${S}${name}${E} uid: ${S}${uid:-[first free]}${E} home: ${S}${home}${E} shell: ${S}${shell}${E} Account expiration date: ${S}${expire_date:-never}${E} Minimum days between password changes: ${S}${min_days}${E} Maximum days between password changes: ${S}${max_days}${E} Number of usable days after expiration: ${S}${iact_days}${E} Number of warning days before expiration: ${S}${warn_days}${E} ${S}${set_pwd:+Set password for this account.}${E} EOM } set_user() { if ! useradd \ -c "${name}" \ -d "${home}" \ -g "${group}" \ -s "${shell}" \ ${expire:+-e ${expire}} \ ${uid:+-u ${uid}} \ ${other_groups:+-G ${other_groups}} \ ${login} then echo "Error ($?) in useradd...exiting..." exit 1 fi } set_aging() { if ! passwd \ -x ${max_days} \ -n ${min_days} \ -w ${warn_days} \ -i ${iact_days} \ ${login} then echo "Error ($?) in setting password aging...exiting..." exit 1 fi } set_password() { if test -n "${set_pwd}" then echo passwd ${login} echo fi } set_system() { if test -d "${home}" then echo "Directory ${home} already exists." echo "Skeleton files not copied." return fi echo -n "Copying skeleton files..." ( mkdir ${home} cd ${skel} && cp -af . ${home} chmod ${def_mode} ${home} chown -R ${login}:${group} ${home} ) echo "done." ## Add your own stuff here: echo -n "Setting up other files..." ( mailbox="/var/spool/mail/${login}" touch ${mailbox} chown "${login}:mail" ${mailbox} chmod 600 ${mailbox} ) echo "done." } read_values() { clear echo -e "\nPlease answer the following questions about the new user to be added." while : do read_login read_name read_group read_other_groups read_home read_shell read_uid read_expire_date read_max_valid_days read_min_valid_days read_warning_days read_inactive_days read_passwd_yn print_values echo -n "Is this correct [N/y] ? " read_yn 1 && return done } main() { check_root read_values set_user set_aging set_system set_password } ## Run it 8-) main # End.