freebsd-skq/usr.sbin/adduser/rmuser.sh
jhb 95fe9af01e The original adduser/rmuser scripts in Perl used to modify the PATH
setting.  When the scripts were converted to Bourne shell, this was
removed.  The adduser script was changed to use an explicit path for
the pw(8) command so that /usr/sbin did not have to be in the user's
PATH.  The rmuser script continued to assume that /usr/sbin was in the
user's path, however.  This fixes the rmuser script to use an explicit
path for pw(8) similar to adduser.

MFC after:	2 weeks
2008-07-30 18:37:21 +00:00

362 lines
8.9 KiB
Bash

#!/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