#!/bin/sh # # /usr/local/bin/localadduser # Copyright 2003-2006 Jonas Smedegaard # # $Id: localadduser,v 1.5 2006-08-31 22:51:54 jonas Exp $ # # Execute adduser noninteractively through sudo # # TODO: Check for bad arguments # TODO: Implement --help option # TODO: Support overriding options in /etc/local file # TODO: Check gecos field length # TODO: Check password strength of autogenerated password (and pick another if needed) # TODO: Deal with non-ASCII chars (transliterate or silence chfn warnings) # TODO: quiten output: only emit password line by default # TODO: support reading from file or stdin # TODO: Implement --update option: apply missing data to existing account # set -e PRG=$(basename "$0") TEMP="`getopt -s sh -o vqin -l verbose,quiet,interactive,noninteractive,dry-run -n "$PRG" -- "$@"`" if [ $? != 0 ] ; then echo >&2 "ERROR: Internal getopt error." ; exit 1 ; fi eval set -- "$TEMP" verbose=1 interactive=0 while true ; do case "$1" in -v|--verbose) verbose=1; shift ;; -q|--quiet) verbose=0; shift ;; -i|--interactive) interactive=1; shift ;; -n|--noninteractive) interactive=0; shift ;; --dry-run) simulate=true; shift ;; --) shift ; break ;; *) echo >&2 "ERROR: Internal error resolving options." ; exit 1 ;; esac done # echo something, but only if in verbose mode vecho() { test -n "$verbose" && echo "$@" >&2 } exit1() { response="${1:+Error: }${1:-Internal error!}" echo "$response" exit 1 } u=$1 shift for chunk in $@; do case $chunk in @*) groupchunks="${groupchunks:+$groupchunks }$chunk" ;; %*) officechunks="${officechunks:+$officechunks }$chunk" ;; *@*) other="${other:+$other }$chunk" ;; +*) phone_area="$chunk" ;; 0*|1*|2*|3*|4*|5*|6*|7*|8*|9*) if [ -z "$phone_area" ]; then exit1 "Phone number provided without leading area code!" fi if [ -n "$home_phone" ]; then exit1 "More than 2 phone numbers provided!" elif [ -n "$office_phone" ]; then office_phone="$phone_area $chunk" else home_phone="$phone_area $chunk" fi phone_area="" ;; *) fullname="${fullname:+$fullname }$chunk" ;; esac done if getent passwd "$u" | grep -q .; then exit1 "User \"$u\" already exists!" fi if getent group "$u" | grep -q .; then exit1 "Group \"$u\" already exists!" fi if [ -n "$phone_area" ]; then exit1 "Area code provided without trailing phonenumber!" fi for groupchunk in $groupchunks; do group="$(echo "$groupchunk" | perl -pe 's/^@//;')" if echo "$group" | perl -ne '/^[a-z][a-z0-9_-]*$/ and exit 1;'; then exit1 "Group \"$group\" contains illegal characters!" fi if ! members="$(getent group "$group")"; then exit1 "Group \"$group\" does not exist!" fi if echo "$members" | perl -pe 's/.*://; s/,/\n/g' | grep -Fxq "$u"; then exit1 "Group \"$group\" already contains user \"$u\"!" fi groups="${groups:+$groups }$group" done for officechunk in $officechunks; do office="${office:+$office }$(echo "$officechunk" | perl -pe 's/^%//;')" done if [ ! "$interactive" -gt 0 ]; then quiet="--quiet" fi sudo=sudo [ "$(id -u)" -ne 0 ] || sudo= # adduser is too pessimistic on --gecos size eval $simulate $sudo "/usr/sbin/adduser $quiet --disabled-login --gecos \"\" \"$u\"" eval $simulate $sudo "/usr/sbin/usermod -c \"$fullname,$office,$office_phone,$home_phone,$other\" \"$u\"" for group in $groups; do eval $simulate $sudo "/usr/sbin/adduser $quiet \"$u\" \"$group\"" done eval $simulate localresetpasswd "$u" #vecho "Account \"$u\" created succesfully! Password is $pass"