diff options
Diffstat (limited to 'usr.sbin/adduser/rmuser.sh')
-rw-r--r-- | usr.sbin/adduser/rmuser.sh | 361 |
1 files changed, 361 insertions, 0 deletions
diff --git a/usr.sbin/adduser/rmuser.sh b/usr.sbin/adduser/rmuser.sh new file mode 100644 index 0000000..6b09225 --- /dev/null +++ b/usr.sbin/adduser/rmuser.sh @@ -0,0 +1,361 @@ +#!/bin/sh +# +# Copyright (c) 2002, 2003 Michael Telahun Makonnen. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +# Email: Mike Makonnen <mtm@FreeBSD.Org> +# +# $FreeBSD$ +# + +ATJOBDIR="/var/at/jobs" +CRONJOBDIR="/var/cron/tabs" +MAILSPOOL="/var/mail" +SIGKILL="-KILL" +TEMPDIRS="/tmp /var/tmp" +THISCMD=`/usr/bin/basename $0` +PWCMD="${PWCMD:-/usr/sbin/pw}" + +# err msg +# Display $msg on stderr. +# +err() { + echo 1>&2 ${THISCMD}: $* +} + +# verbose +# Returns 0 if verbose mode is set, 1 if it is not. +# +verbose() { + [ -n "$vflag" ] && return 0 || return 1 +} + +# rm_files login +# Removes files or empty directories belonging to $login from various +# temporary directories. +# +rm_files() { + # The argument is required + [ -n $1 ] && login=$1 || return + + totalcount=0 + for _dir in ${TEMPDIRS} ; do + filecount=0 + if [ ! -d $_dir ]; then + err "$_dir is not a valid directory." + continue + fi + verbose && echo -n "Removing files owned by ($login) in $_dir:" + filecount=`find 2>/dev/null "$_dir" -user "$login" -delete -print | + wc -l | sed 's/ *//'` + verbose && echo " $filecount removed." + totalcount=$(($totalcount + $filecount)) + done + ! verbose && [ $totalcount -ne 0 ] && echo -n " files($totalcount)" +} + +# rm_mail login +# Removes unix mail and pop daemon files belonging to the user +# specified in the $login argument. +# +rm_mail() { + # The argument is required + [ -n $1 ] && login=$1 || return + + verbose && echo -n "Removing mail spool(s) for ($login):" + if [ -f ${MAILSPOOL}/$login ]; then + verbose && echo -n " ${MAILSPOOL}/$login" || + echo -n " mailspool" + rm ${MAILSPOOL}/$login + fi + if [ -f ${MAILSPOOL}/.${login}.pop ]; then + verbose && echo -n " ${MAILSPOOL}/.${login}.pop" || + echo -n " pop3" + rm ${MAILSPOOL}/.${login}.pop + fi + verbose && echo '.' +} + +# kill_procs login +# Send a SIGKILL to all processes owned by $login. +# +kill_procs() { + # The argument is required + [ -n $1 ] && login=$1 || return + + verbose && echo -n "Terminating all processes owned by ($login):" + killcount=0 + proclist=`ps 2>/dev/null -U $login | grep -v '^\ *PID' | awk '{print $1}'` + for _pid in $proclist ; do + kill 2>/dev/null ${SIGKILL} $_pid + killcount=$(($killcount + 1)) + done + verbose && echo " ${SIGKILL} signal sent to $killcount processes." + ! verbose && [ $killcount -ne 0 ] && echo -n " processes(${killcount})" +} + +# rm_at_jobs login +# Remove at (1) jobs belonging to $login. +# +rm_at_jobs() { + # The argument is required + [ -n $1 ] && login=$1 || return + + atjoblist=`find 2>/dev/null ${ATJOBDIR} -maxdepth 1 -user $login -print` + jobcount=0 + verbose && echo -n "Removing at(1) jobs owned by ($login):" + for _atjob in $atjoblist ; do + rm -f $_atjob + jobcount=$(($jobcount + 1)) + done + verbose && echo " $jobcount removed." + ! verbose && [ $jobcount -ne 0 ] && echo -n " at($jobcount)" +} + +# rm_crontab login +# Removes crontab file belonging to user $login. +# +rm_crontab() { + # The argument is required + [ -n $1 ] && login=$1 || return + + verbose && echo -n "Removing crontab for ($login):" + if [ -f ${CRONJOBDIR}/$login ]; then + verbose && echo -n " ${CRONJOBDIR}/$login" || echo -n " crontab" + rm -f ${CRONJOBDIR}/$login + fi + verbose && echo '.' +} + +# rm_ipc login +# Remove all IPC mechanisms which are owned by $login. +# +rm_ipc() { + verbose && echo -n "Removing IPC mechanisms" + for i in s m q; do + ipcs -$i | + awk -v i=$i -v login=$1 '$1 == i && $5 == login { print $2 }' | + xargs -n 1 ipcrm -$i + done + verbose && echo '.' +} + +# rm_user login +# Remove user $login from the system. This subroutine makes use +# of the pw(8) command to remove a user from the system. The pw(8) +# command will remove the specified user from the user database +# and group file and remove any crontabs. His home +# directory will be removed if it is owned by him and contains no +# files or subdirectories owned by other users. Mail spool files will +# also be removed. +# +rm_user() { + # The argument is required + [ -n $1 ] && login=$1 || return + + verbose && echo -n "Removing user ($login)" + [ -n "$pw_rswitch" ] && { + verbose && echo -n " (including home directory)" + ! verbose && echo -n " home" + } + ! verbose && echo -n " passwd" + verbose && echo -n " from the system:" + ${PWCMD} userdel -n $login $pw_rswitch + verbose && echo ' Done.' +} + +# prompt_yesno msg +# Prompts the user with a $msg. The answer is expected to be +# yes, no, or some variation thereof. This subroutine returns 0 +# if the answer was yes, 1 if it was not. +# +prompt_yesno() { + # The argument is required + [ -n "$1" ] && msg="$1" || return + + while : ; do + echo -n "$msg" + read _ans + case $_ans in + [Nn][Oo]|[Nn]) + return 1 + ;; + [Yy][Ee][Ss]|[Yy][Ee]|[Yy]) + return 0 + ;; + *) + ;; + esac + done +} + +# show_usage +# (no arguments) +# Display usage message. +# +show_usage() { + echo "usage: ${THISCMD} [-yv] [-f file] [user ...]" + echo " if the -y switch is used, either the -f switch or" + echo " one or more user names must be given" +} + +#### END SUBROUTINE DEFENITION #### + +ffile= +fflag= +procowner= +pw_rswitch= +userlist= +yflag= +vflag= + +procowner=`/usr/bin/id -u` +if [ "$procowner" != "0" ]; then + err 'you must be root (0) to use this utility.' + exit 1 +fi + +args=`getopt 2>/dev/null yvf: $*` +if [ "$?" != "0" ]; then + show_usage + exit 1 +fi +set -- $args +for _switch ; do + case $_switch in + -y) + yflag=1 + shift + ;; + -v) + vflag=1 + shift + ;; + -f) + fflag=1 + ffile="$2" + shift; shift + ;; + --) + shift + break + ;; + esac +done + +# Get user names from a file if the -f switch was used. Otherwise, +# get them from the commandline arguments. If we're getting it +# from a file, the file must be owned by and writable only by root. +# +if [ $fflag ]; then + _insecure=`find $ffile ! -user 0 -or -perm +0022` + if [ -n "$_insecure" ]; then + err "file ($ffile) must be owned by and writeable only by root." + exit 1 + fi + if [ -r "$ffile" ]; then + userlist=`cat $ffile | while read _user _junk ; do + case $_user in + \#*|'') + ;; + *) + echo -n "$userlist $_user" + ;; + esac + done` + fi +else + while [ $1 ] ; do + userlist="$userlist $1" + shift + done +fi + +# If the -y or -f switch has been used and the list of users to remove +# is empty it is a fatal error. Otherwise, prompt the user for a list +# of one or more user names. +# +if [ ! "$userlist" ]; then + if [ $fflag ]; then + err "($ffile) does not exist or does not contain any user names." + exit 1 + elif [ $yflag ]; then + show_usage + exit 1 + else + echo -n "Please enter one or more usernames: " + read userlist + fi +fi + +_user= +_uid= +for _user in $userlist ; do + # Make sure the name exists in the passwd database and that it + # does not have a uid of 0 + # + userrec=`pw 2>/dev/null usershow -n $_user` + if [ "$?" != "0" ]; then + err "user ($_user) does not exist in the password database." + continue + fi + _uid=`echo $userrec | awk -F: '{print $3}'` + if [ "$_uid" = "0" ]; then + err "user ($_user) has uid 0. You may not remove this user." + continue + fi + + # If the -y switch was not used ask for confirmation to remove the + # user and home directory. + # + if [ -z "$yflag" ]; then + echo "Matching password entry:" + echo + echo $userrec + echo + if ! prompt_yesno "Is this the entry you wish to remove? " ; then + continue + fi + _homedir=`echo $userrec | awk -F: '{print $9}'` + if prompt_yesno "Remove user's home directory ($_homedir)? "; then + pw_rswitch="-r" + fi + else + pw_rswitch="-r" + fi + + # Disable any further attempts to log into this account + ${PWCMD} 2>/dev/null lock $_user + + # Remove crontab, mail spool, etc. Then obliterate the user from + # the passwd and group database. + # + ! verbose && echo -n "Removing user ($_user):" + rm_crontab $_user + rm_at_jobs $_user + rm_ipc $_user + kill_procs $_user + rm_files $_user + rm_mail $_user + rm_user $_user + ! verbose && echo "." +done |