xref: /freebsd/usr.sbin/adduser/rmuser.sh (revision fd045cf5661a9a5b37ab87b07c593b4d84fa7aee)
17cdfce09SScott Long#!/bin/sh
27cdfce09SScott Long#
37cdfce09SScott Long# Copyright (c) 2002 Michael Telahun Makonnen. All rights reserved.
47cdfce09SScott Long#
57cdfce09SScott Long# Redistribution and use in source and binary forms, with or without
67cdfce09SScott Long# modification, are permitted provided that the following conditions
77cdfce09SScott Long# are met:
87cdfce09SScott Long# 1. Redistributions of source code must retain the above copyright
97cdfce09SScott Long#    notice, this list of conditions and the following disclaimer.
107cdfce09SScott Long# 2. Redistributions in binary form must reproduce the above copyright
117cdfce09SScott Long#    notice, this list of conditions and the following disclaimer in the
127cdfce09SScott Long#    documentation and/or other materials provided with the distribution.
137cdfce09SScott Long# 3. The name of the author may not be used to endorse or promote products
147cdfce09SScott Long#    derived from this software without specific prior written permission.
157cdfce09SScott Long#
167cdfce09SScott Long# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
177cdfce09SScott Long# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
187cdfce09SScott Long# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
197cdfce09SScott Long# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
207cdfce09SScott Long# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
217cdfce09SScott Long# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
227cdfce09SScott Long# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
237cdfce09SScott Long# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
247cdfce09SScott Long# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
257cdfce09SScott Long# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
267cdfce09SScott Long#
277cdfce09SScott Long#	Email: Mike Makonnen <mtm@identd.net>
287cdfce09SScott Long#
297cdfce09SScott Long# $FreeBSD$
307cdfce09SScott Long#
317cdfce09SScott Long
327cdfce09SScott LongATJOBDIR="/var/at/jobs"
337cdfce09SScott LongCRONJOBDIR="/var/cron/tabs"
347cdfce09SScott LongMAILSPOOL="/var/mail"
357cdfce09SScott LongSIGKILL="-KILL"
36deca89c7STim J. RobbinsTEMPDIRS="/tmp /var/tmp"
377cdfce09SScott LongTHISCMD=`/usr/bin/basename $0`
387cdfce09SScott Long
397cdfce09SScott Long# err msg
407cdfce09SScott Long#	Display $msg on stderr.
417cdfce09SScott Long#
427cdfce09SScott Longerr() {
437cdfce09SScott Long	echo 1>&2 ${THISCMD}: $*
447cdfce09SScott Long}
457cdfce09SScott Long
467cdfce09SScott Long# rm_files login
477cdfce09SScott Long#	Removes files or empty directories belonging to $login from various
487cdfce09SScott Long#	temporary directories.
497cdfce09SScott Long#
507cdfce09SScott Longrm_files() {
517cdfce09SScott Long	# The argument is required
527cdfce09SScott Long	[ -n $1 ] && login=$1 || return
537cdfce09SScott Long
547cdfce09SScott Long	for _dir in ${TEMPDIRS} ; do
557cdfce09SScott Long		if [ ! -d $_dir ]; then
567cdfce09SScott Long			err "$_dir is not a valid directory."
577cdfce09SScott Long			continue
587cdfce09SScott Long		fi
597cdfce09SScott Long		echo -n "Removing files owned by ($login) in $_dir:"
60deca89c7STim J. Robbins		filecount=`find 2>/dev/null "$_dir" -user "$login" -delete -print | \
61deca89c7STim J. Robbins		    wc -l | sed 's/ *//'`
627cdfce09SScott Long		echo " $filecount removed."
637cdfce09SScott Long	done
647cdfce09SScott Long}
657cdfce09SScott Long
667cdfce09SScott Long# rm_mail login
677cdfce09SScott Long#	Removes unix mail and pop daemon files belonging to the user
687cdfce09SScott Long#	specified in the $login argument.
697cdfce09SScott Long#
707cdfce09SScott Longrm_mail() {
717cdfce09SScott Long	# The argument is required
727cdfce09SScott Long	[ -n $1 ] && login=$1 || return
737cdfce09SScott Long
747cdfce09SScott Long	echo -n "Removing mail spool(s) for ($login):"
757cdfce09SScott Long	if [ -f ${MAILSPOOL}/$login ]; then
767cdfce09SScott Long		echo -n " ${MAILSPOOL}/$login"
777cdfce09SScott Long		rm ${MAILSPOOL}/$login
787cdfce09SScott Long	fi
797cdfce09SScott Long	if [ -f ${MAILSPOOL}/${login}.pop ]; then
807cdfce09SScott Long		echo -n " ${MAILSPOOL}/${login}.pop"
817cdfce09SScott Long		rm ${MAILSPOOL}/${login}.pop
827cdfce09SScott Long	fi
837cdfce09SScott Long	echo '.'
847cdfce09SScott Long}
857cdfce09SScott Long
867cdfce09SScott Long# kill_procs login
877cdfce09SScott Long#	Send a SIGKILL to all processes owned by $login.
887cdfce09SScott Long#
897cdfce09SScott Longkill_procs() {
907cdfce09SScott Long	# The argument is required
917cdfce09SScott Long	[ -n $1 ] && login=$1 || return
927cdfce09SScott Long
937cdfce09SScott Long	echo -n "Terminating all processes owned by ($login):"
947cdfce09SScott Long	killcount=0
957cdfce09SScott Long	proclist=`ps 2>/dev/null -U $login | grep -v '^\ *PID' | awk '{print $1}'`
967cdfce09SScott Long	for _pid in $proclist ; do
977cdfce09SScott Long		kill 2>/dev/null ${SIGKILL} $_pid
98fd045cf5SMax Khon		killcount=$(($killcount + 1))
997cdfce09SScott Long	done
1007cdfce09SScott Long	echo " ${SIGKILL} signal sent to $killcount processes."
1017cdfce09SScott Long}
1027cdfce09SScott Long
1037cdfce09SScott Long# rm_at_jobs login
1047cdfce09SScott Long#	Remove at (1) jobs belonging to $login.
1057cdfce09SScott Long#
1067cdfce09SScott Longrm_at_jobs() {
1077cdfce09SScott Long	# The argument is required
1087cdfce09SScott Long	[ -n $1 ] && login=$1 || return
1097cdfce09SScott Long
1107cdfce09SScott Long	atjoblist=`find 2>/dev/null ${ATJOBDIR} -maxdepth 1 -user $login -print`
1117cdfce09SScott Long	jobcount=0
1127cdfce09SScott Long	echo -n "Removing at(1) jobs owned by ($login):"
1137cdfce09SScott Long	for _atjob in $atjoblist ; do
1147cdfce09SScott Long		rm -f $_atjob
115fd045cf5SMax Khon		jobcount=$(($jobcount + 1))
1167cdfce09SScott Long	done
1177cdfce09SScott Long	echo " $jobcount removed."
1187cdfce09SScott Long}
1197cdfce09SScott Long
1207cdfce09SScott Long# rm_crontab login
1217cdfce09SScott Long#	Removes crontab file belonging to user $login.
1227cdfce09SScott Long#
1237cdfce09SScott Longrm_crontab() {
1247cdfce09SScott Long	# The argument is required
1257cdfce09SScott Long	[ -n $1 ] && login=$1 || return
1267cdfce09SScott Long
1277cdfce09SScott Long	echo -n "Removing crontab for ($login):"
1287cdfce09SScott Long	if [ -f ${CRONJOBDIR}/$login ]; then
1297cdfce09SScott Long		echo -n " ${CRONJOBDIR}/$login"
1307cdfce09SScott Long		rm -f ${CRONJOBDIR}/$login
1317cdfce09SScott Long	fi
1327cdfce09SScott Long	echo '.'
1337cdfce09SScott Long}
1347cdfce09SScott Long
1357cdfce09SScott Long# rm_user login
1367cdfce09SScott Long#	Remove user $login from the system. This subroutine makes use
1377cdfce09SScott Long#	of the pw(8) command to remove a user from the system. The pw(8)
1387cdfce09SScott Long#	command will remove the specified user from the user database
1397cdfce09SScott Long#	and group file and remove any crontabs. His home
1407cdfce09SScott Long#	directory will be removed if it is owned by him and contains no
1417cdfce09SScott Long#	files or subdirectories owned by other users. Mail spool files will
1427cdfce09SScott Long#	also be removed.
1437cdfce09SScott Long#
1447cdfce09SScott Longrm_user() {
1457cdfce09SScott Long	# The argument is required
1467cdfce09SScott Long	[ -n $1 ] && login=$1 || return
1477cdfce09SScott Long
1487cdfce09SScott Long	echo -n "Removing user ($login)"
1497cdfce09SScott Long	[ -n "$pw_rswitch" ] && echo -n " (including home directory)"
1507cdfce09SScott Long	echo -n " from the system:"
1517cdfce09SScott Long	pw userdel -n $login $pw_rswitch
1527cdfce09SScott Long	echo ' Done.'
1537cdfce09SScott Long}
1547cdfce09SScott Long
1557cdfce09SScott Long# prompt_yesno msg
1567cdfce09SScott Long#	Prompts the user with a $msg. The answer is expected to be
1577cdfce09SScott Long#	yes, no, or some variation thereof. This subroutine returns 0
1587cdfce09SScott Long#	if the answer was yes, 1 if it was not.
1597cdfce09SScott Long#
1607cdfce09SScott Longprompt_yesno() {
1617cdfce09SScott Long	# The argument is required
162ce1794a8SMax Khon	[ -n "$1" ] && msg="$1" || return
1637cdfce09SScott Long
1647cdfce09SScott Long        while : ; do
165ce1794a8SMax Khon                echo -n "$msg"
1667cdfce09SScott Long                read _ans
1677cdfce09SScott Long                case $_ans in
1687cdfce09SScott Long                [Nn][Oo]|[Nn])
1697cdfce09SScott Long			return 1
1707cdfce09SScott Long                        ;;
1717cdfce09SScott Long                [Yy][Ee][Ss]|[Yy][Ee]|[Yy])
1727cdfce09SScott Long                        return 0
1737cdfce09SScott Long                        ;;
1747cdfce09SScott Long                *)
1757cdfce09SScott Long                        ;;
1767cdfce09SScott Long                esac
1777cdfce09SScott Long	done
1787cdfce09SScott Long}
1797cdfce09SScott Long
1807cdfce09SScott Long# show_usage
1817cdfce09SScott Long#	(no arguments)
1827cdfce09SScott Long#	Display usage message.
1837cdfce09SScott Long#
1847cdfce09SScott Longshow_usage() {
1857cdfce09SScott Long	echo "usage: ${THISCMD} [-y] [-f file] [user ...]"
1867cdfce09SScott Long	echo "       if the -y switch is used, either the -f switch or"
1877cdfce09SScott Long	echo "       one or more user names must be given"
1887cdfce09SScott Long}
1897cdfce09SScott Long
1907cdfce09SScott Long#### END SUBROUTINE DEFENITION ####
1917cdfce09SScott Long
1927cdfce09SScott Longffile=
1937cdfce09SScott Longfflag=
1947cdfce09SScott Longprocowner=
1957cdfce09SScott Longpw_rswitch=
1967cdfce09SScott Longuserlist=
1977cdfce09SScott Longyflag=
1987cdfce09SScott Long
1997cdfce09SScott Longprocowner=`/usr/bin/id -u`
2007cdfce09SScott Longif [ "$procowner" != "0" ]; then
2017cdfce09SScott Long	err 'you must be root (0) to use this utility.'
2027cdfce09SScott Long	exit 1
2037cdfce09SScott Longfi
2047cdfce09SScott Long
2057cdfce09SScott Longargs=`getopt 2>/dev/null yf: $*`
2067cdfce09SScott Longif [ "$?" != "0" ]; then
2077cdfce09SScott Long	show_usage
2087cdfce09SScott Long	exit 1
2097cdfce09SScott Longfi
2107cdfce09SScott Longset -- $args
2117cdfce09SScott Longfor _switch ; do
2127cdfce09SScott Long	case $_switch in
2137cdfce09SScott Long	-y)
2147cdfce09SScott Long		yflag=1
2157cdfce09SScott Long		shift
2167cdfce09SScott Long		;;
2177cdfce09SScott Long	-f)
2187cdfce09SScott Long		fflag=1
2197cdfce09SScott Long		ffile="$2"
2207cdfce09SScott Long		shift; shift
2217cdfce09SScott Long		;;
2227cdfce09SScott Long	--)
2237cdfce09SScott Long		shift
2247cdfce09SScott Long		break
2257cdfce09SScott Long		;;
2267cdfce09SScott Long	esac
2277cdfce09SScott Longdone
2287cdfce09SScott Long
2297cdfce09SScott Long# Get user names from a file if the -f switch was used. Otherwise,
2307cdfce09SScott Long# get them from the commandline arguments. If we're getting it
2317cdfce09SScott Long# from a file, the file must be owned by and writable only by root.
2327cdfce09SScott Long#
2337cdfce09SScott Longif [ $fflag ]; then
2347cdfce09SScott Long	_insecure=`find $ffile ! -user 0 -or -perm +0022`
2357cdfce09SScott Long	if [ -n "$_insecure" ]; then
2367cdfce09SScott Long		err "file ($ffile) must be owned by and writeable only by root."
2377cdfce09SScott Long		exit 1
2387cdfce09SScott Long	fi
2397cdfce09SScott Long	if [ -r "$ffile" ]; then
2407cdfce09SScott Long		userlist=`cat $ffile | while read _user _junk ; do
2417cdfce09SScott Long			case $_user in
2427cdfce09SScott Long			\#*|'')
2437cdfce09SScott Long				;;
2447cdfce09SScott Long			*)
2457cdfce09SScott Long				echo -n "$userlist $_user"
2467cdfce09SScott Long				;;
2477cdfce09SScott Long			esac
2487cdfce09SScott Long		done`
2497cdfce09SScott Long	fi
2507cdfce09SScott Longelse
2517cdfce09SScott Long	while [ $1 ] ; do
2527cdfce09SScott Long		userlist="$userlist $1"
2537cdfce09SScott Long		shift
2547cdfce09SScott Long	done
2557cdfce09SScott Longfi
2567cdfce09SScott Long
2577cdfce09SScott Long# If the -y or -f switch has been used and the list of users to remove
2587cdfce09SScott Long# is empty it is a fatal error. Otherwise, prompt the user for a list
2597cdfce09SScott Long# of one or more user names.
2607cdfce09SScott Long#
2617cdfce09SScott Longif [ ! "$userlist" ]; then
2627cdfce09SScott Long	if [ $fflag ]; then
2637cdfce09SScott Long		err "($ffile) does not exist or does not contain any user names."
2647cdfce09SScott Long		exit 1
2657cdfce09SScott Long	elif [ $yflag ]; then
2667cdfce09SScott Long		show_usage
2677cdfce09SScott Long		exit 1
2687cdfce09SScott Long	else
2697cdfce09SScott Long		echo -n "Please enter one or more user name's: "
2707cdfce09SScott Long		read userlist
2717cdfce09SScott Long	fi
2727cdfce09SScott Longfi
2737cdfce09SScott Long
2747cdfce09SScott Long_user=
2757cdfce09SScott Long_uid=
2767cdfce09SScott Longfor _user in $userlist ; do
2777cdfce09SScott Long	# Make sure the name exists in the passwd database and that it
2787cdfce09SScott Long	# does not have a uid of 0
2797cdfce09SScott Long	#
2807cdfce09SScott Long	userrec=`pw 2>/dev/null usershow -n $_user`
2817cdfce09SScott Long	if [ "$?" != "0" ]; then
2827cdfce09SScott Long		err "user ($_user) does not exist in the password database."
2837cdfce09SScott Long		continue
2847cdfce09SScott Long	fi
2857cdfce09SScott Long	_uid=`echo $userrec | awk -F: '{print $3}'`
2867cdfce09SScott Long	if [ "$_uid" = "0" ]; then
2877cdfce09SScott Long		err "user ($_user) has uid 0. You may not remove this user."
2887cdfce09SScott Long		continue
2897cdfce09SScott Long	fi
2907cdfce09SScott Long
2917cdfce09SScott Long	# If the -y switch was not used ask for confirmation to remove the
2927cdfce09SScott Long	# user and home directory.
2937cdfce09SScott Long	#
2947cdfce09SScott Long	if [ -z "$yflag" ]; then
2957cdfce09SScott Long		echo "Matching password entry:"
2967cdfce09SScott Long		echo
2977cdfce09SScott Long		echo $userrec
2987cdfce09SScott Long		echo
2997cdfce09SScott Long		if ! prompt_yesno "Is this the entry you wish to remove? " ; then
3007cdfce09SScott Long			continue
3017cdfce09SScott Long		fi
3027cdfce09SScott Long		_homedir=`echo $userrec | awk -F: '{print $9}'`
303ce1794a8SMax Khon		if prompt_yesno "Remove user's home directory ($_homedir)? "; then
3047cdfce09SScott Long			pw_rswitch="-r"
3057cdfce09SScott Long		fi
3067cdfce09SScott Long	else
3077cdfce09SScott Long		pw_rswitch="-r"
3087cdfce09SScott Long	fi
3097cdfce09SScott Long
3107cdfce09SScott Long	# Disable any further attempts to log into this account
3117cdfce09SScott Long	pw 2>/dev/null lock $_user
3127cdfce09SScott Long
3137cdfce09SScott Long	# Remove crontab, mail spool, etc. Then obliterate the user from
3147cdfce09SScott Long	# the passwd and group database.
3157cdfce09SScott Long	rm_crontab $_user
3167cdfce09SScott Long	rm_at_jobs $_user
3177cdfce09SScott Long	kill_procs $_user
3187cdfce09SScott Long	rm_mail $_user
3197cdfce09SScott Long	rm_files $_user
3207cdfce09SScott Long	rm_user $_user
3217cdfce09SScott Longdone
322