xref: /freebsd/usr.sbin/adduser/rmuser.sh (revision d6bfbcc360facd6d9aaadd00bd7beedee0f18b21)
17cdfce09SScott Long#!/bin/sh
27cdfce09SScott Long#
3fc895860SMike Makonnen# Copyright (c) 2002, 2003 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#
147cdfce09SScott Long# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
157cdfce09SScott Long# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
167cdfce09SScott Long# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
177cdfce09SScott Long# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
187cdfce09SScott Long# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
197cdfce09SScott Long# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
207cdfce09SScott Long# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
217cdfce09SScott Long# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
227cdfce09SScott Long# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
237cdfce09SScott Long# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
247cdfce09SScott Long#
2522884fddSMike Makonnen#	Email: Mike Makonnen <mtm@FreeBSD.Org>
267cdfce09SScott Long#
277cdfce09SScott Long# $FreeBSD$
287cdfce09SScott Long#
297cdfce09SScott Long
307cdfce09SScott LongATJOBDIR="/var/at/jobs"
317cdfce09SScott LongCRONJOBDIR="/var/cron/tabs"
327cdfce09SScott LongMAILSPOOL="/var/mail"
337cdfce09SScott LongSIGKILL="-KILL"
34deca89c7STim J. RobbinsTEMPDIRS="/tmp /var/tmp"
357cdfce09SScott LongTHISCMD=`/usr/bin/basename $0`
367cdfce09SScott Long
377cdfce09SScott Long# err msg
387cdfce09SScott Long#	Display $msg on stderr.
397cdfce09SScott Long#
407cdfce09SScott Longerr() {
417cdfce09SScott Long	echo 1>&2 ${THISCMD}: $*
427cdfce09SScott Long}
437cdfce09SScott Long
446fcaf748SMike Makonnen# verbose
456fcaf748SMike Makonnen#	Returns 0 if verbose mode is set, 1 if it is not.
466fcaf748SMike Makonnen#
476fcaf748SMike Makonnenverbose() {
486fcaf748SMike Makonnen	[ -n "$vflag" ] && return 0 || return 1
496fcaf748SMike Makonnen}
506fcaf748SMike Makonnen
517cdfce09SScott Long# rm_files login
527cdfce09SScott Long#	Removes files or empty directories belonging to $login from various
537cdfce09SScott Long#	temporary directories.
547cdfce09SScott Long#
557cdfce09SScott Longrm_files() {
567cdfce09SScott Long	# The argument is required
577cdfce09SScott Long	[ -n $1 ] && login=$1 || return
587cdfce09SScott Long
596fcaf748SMike Makonnen	totalcount=0
607cdfce09SScott Long	for _dir in ${TEMPDIRS} ; do
616fcaf748SMike Makonnen		filecount=0
627cdfce09SScott Long		if [ ! -d $_dir ]; then
637cdfce09SScott Long			err "$_dir is not a valid directory."
647cdfce09SScott Long			continue
657cdfce09SScott Long		fi
666fcaf748SMike Makonnen		verbose && echo -n "Removing files owned by ($login) in $_dir:"
67d6bfbcc3SJens Schweikhardt		filecount=`find 2>/dev/null "$_dir" -user "$login" -delete -print |
68deca89c7STim J. Robbins		    wc -l | sed 's/ *//'`
696fcaf748SMike Makonnen		verbose && echo " $filecount removed."
706fcaf748SMike Makonnen		totalcount=$(($totalcount + $filecount))
717cdfce09SScott Long	done
726fcaf748SMike Makonnen	! verbose && [ $totalcount -ne 0 ] && echo -n " files($totalcount)"
737cdfce09SScott Long}
747cdfce09SScott Long
757cdfce09SScott Long# rm_mail login
767cdfce09SScott Long#	Removes unix mail and pop daemon files belonging to the user
777cdfce09SScott Long#	specified in the $login argument.
787cdfce09SScott Long#
797cdfce09SScott Longrm_mail() {
807cdfce09SScott Long	# The argument is required
817cdfce09SScott Long	[ -n $1 ] && login=$1 || return
827cdfce09SScott Long
836fcaf748SMike Makonnen	verbose && echo -n "Removing mail spool(s) for ($login):"
847cdfce09SScott Long	if [ -f ${MAILSPOOL}/$login ]; then
85d6bfbcc3SJens Schweikhardt		verbose && echo -n " ${MAILSPOOL}/$login" ||
866fcaf748SMike Makonnen		    echo -n " mailspool"
877cdfce09SScott Long		rm ${MAILSPOOL}/$login
887cdfce09SScott Long	fi
897cdfce09SScott Long	if [ -f ${MAILSPOOL}/${login}.pop ]; then
90d6bfbcc3SJens Schweikhardt		verbose && echo -n " ${MAILSPOOL}/${login}.pop" ||
916fcaf748SMike Makonnen		    echo -n " pop3"
927cdfce09SScott Long		rm ${MAILSPOOL}/${login}.pop
937cdfce09SScott Long	fi
946fcaf748SMike Makonnen	verbose && echo '.'
957cdfce09SScott Long}
967cdfce09SScott Long
977cdfce09SScott Long# kill_procs login
987cdfce09SScott Long#	Send a SIGKILL to all processes owned by $login.
997cdfce09SScott Long#
1007cdfce09SScott Longkill_procs() {
1017cdfce09SScott Long	# The argument is required
1027cdfce09SScott Long	[ -n $1 ] && login=$1 || return
1037cdfce09SScott Long
1046fcaf748SMike Makonnen	verbose && echo -n "Terminating all processes owned by ($login):"
1057cdfce09SScott Long	killcount=0
1067cdfce09SScott Long	proclist=`ps 2>/dev/null -U $login | grep -v '^\ *PID' | awk '{print $1}'`
1077cdfce09SScott Long	for _pid in $proclist ; do
1087cdfce09SScott Long		kill 2>/dev/null ${SIGKILL} $_pid
109fd045cf5SMax Khon		killcount=$(($killcount + 1))
1107cdfce09SScott Long	done
1116fcaf748SMike Makonnen	verbose && echo " ${SIGKILL} signal sent to $killcount processes."
1126fcaf748SMike Makonnen	! verbose && [ $killcount -ne 0 ] && echo -n " processes(${killcount})"
1137cdfce09SScott Long}
1147cdfce09SScott Long
1157cdfce09SScott Long# rm_at_jobs login
1167cdfce09SScott Long#	Remove at (1) jobs belonging to $login.
1177cdfce09SScott Long#
1187cdfce09SScott Longrm_at_jobs() {
1197cdfce09SScott Long	# The argument is required
1207cdfce09SScott Long	[ -n $1 ] && login=$1 || return
1217cdfce09SScott Long
1227cdfce09SScott Long	atjoblist=`find 2>/dev/null ${ATJOBDIR} -maxdepth 1 -user $login -print`
1237cdfce09SScott Long	jobcount=0
1246fcaf748SMike Makonnen	verbose && echo -n "Removing at(1) jobs owned by ($login):"
1257cdfce09SScott Long	for _atjob in $atjoblist ; do
1267cdfce09SScott Long		rm -f $_atjob
127fd045cf5SMax Khon		jobcount=$(($jobcount + 1))
1287cdfce09SScott Long	done
1296fcaf748SMike Makonnen	verbose && echo " $jobcount removed."
1306fcaf748SMike Makonnen	! verbose && [ $jobcount -ne 0 ] && echo -n " at($jobcount)"
1317cdfce09SScott Long}
1327cdfce09SScott Long
1337cdfce09SScott Long# rm_crontab login
1347cdfce09SScott Long#	Removes crontab file belonging to user $login.
1357cdfce09SScott Long#
1367cdfce09SScott Longrm_crontab() {
1377cdfce09SScott Long	# The argument is required
1387cdfce09SScott Long	[ -n $1 ] && login=$1 || return
1397cdfce09SScott Long
1406fcaf748SMike Makonnen	verbose && echo -n "Removing crontab for ($login):"
1417cdfce09SScott Long	if [ -f ${CRONJOBDIR}/$login ]; then
1426fcaf748SMike Makonnen		verbose && echo -n " ${CRONJOBDIR}/$login" || echo -n " crontab"
1437cdfce09SScott Long		rm -f ${CRONJOBDIR}/$login
1447cdfce09SScott Long	fi
1456fcaf748SMike Makonnen	verbose && echo '.'
1467cdfce09SScott Long}
1477cdfce09SScott Long
148d6bfbcc3SJens Schweikhardt# rm_ipc login
149d6bfbcc3SJens Schweikhardt#	Remove all IPC mechanisms which are owned by $login.
150d6bfbcc3SJens Schweikhardt#
151d6bfbcc3SJens Schweikhardtrm_ipc() {
152d6bfbcc3SJens Schweikhardt	verbose && echo -n "Removing IPC mechanisms"
153d6bfbcc3SJens Schweikhardt	for i in s m q; do
154d6bfbcc3SJens Schweikhardt		ipcs -$i |
155d6bfbcc3SJens Schweikhardt		awk -v i=$i -v login=$1 '$1 == i && $5 == login { print $2 }' |
156d6bfbcc3SJens Schweikhardt		xargs -n 1 ipcrm -$i
157d6bfbcc3SJens Schweikhardt	done
158d6bfbcc3SJens Schweikhardt	verbose && echo '.'
159d6bfbcc3SJens Schweikhardt}
160d6bfbcc3SJens Schweikhardt
1617cdfce09SScott Long# rm_user login
1627cdfce09SScott Long#	Remove user $login from the system. This subroutine makes use
1637cdfce09SScott Long#	of the pw(8) command to remove a user from the system. The pw(8)
1647cdfce09SScott Long#	command will remove the specified user from the user database
1657cdfce09SScott Long#	and group file and remove any crontabs. His home
1667cdfce09SScott Long#	directory will be removed if it is owned by him and contains no
1677cdfce09SScott Long#	files or subdirectories owned by other users. Mail spool files will
1687cdfce09SScott Long#	also be removed.
1697cdfce09SScott Long#
1707cdfce09SScott Longrm_user() {
1717cdfce09SScott Long	# The argument is required
1727cdfce09SScott Long	[ -n $1 ] && login=$1 || return
1737cdfce09SScott Long
1746fcaf748SMike Makonnen	verbose && echo -n "Removing user ($login)"
1756fcaf748SMike Makonnen	[ -n "$pw_rswitch" ] && {
1766fcaf748SMike Makonnen		verbose && echo -n " (including home directory)"
1776fcaf748SMike Makonnen		! verbose && echo -n " home"
1786fcaf748SMike Makonnen	}
1796fcaf748SMike Makonnen	! verbose && echo -n " passwd"
1806fcaf748SMike Makonnen	verbose && echo -n " from the system:"
1817cdfce09SScott Long	pw userdel -n $login $pw_rswitch
1826fcaf748SMike Makonnen	verbose && echo ' Done.'
1837cdfce09SScott Long}
1847cdfce09SScott Long
1857cdfce09SScott Long# prompt_yesno msg
1867cdfce09SScott Long#	Prompts the user with a $msg. The answer is expected to be
1877cdfce09SScott Long#	yes, no, or some variation thereof. This subroutine returns 0
1887cdfce09SScott Long#	if the answer was yes, 1 if it was not.
1897cdfce09SScott Long#
1907cdfce09SScott Longprompt_yesno() {
1917cdfce09SScott Long	# The argument is required
192ce1794a8SMax Khon	[ -n "$1" ] && msg="$1" || return
1937cdfce09SScott Long
1947cdfce09SScott Long        while : ; do
195ce1794a8SMax Khon                echo -n "$msg"
1967cdfce09SScott Long                read _ans
1977cdfce09SScott Long                case $_ans in
1987cdfce09SScott Long                [Nn][Oo]|[Nn])
1997cdfce09SScott Long			return 1
2007cdfce09SScott Long                        ;;
2017cdfce09SScott Long                [Yy][Ee][Ss]|[Yy][Ee]|[Yy])
2027cdfce09SScott Long                        return 0
2037cdfce09SScott Long                        ;;
2047cdfce09SScott Long                *)
2057cdfce09SScott Long                        ;;
2067cdfce09SScott Long                esac
2077cdfce09SScott Long	done
2087cdfce09SScott Long}
2097cdfce09SScott Long
2107cdfce09SScott Long# show_usage
2117cdfce09SScott Long#	(no arguments)
2127cdfce09SScott Long#	Display usage message.
2137cdfce09SScott Long#
2147cdfce09SScott Longshow_usage() {
2156fcaf748SMike Makonnen	echo "usage: ${THISCMD} [-yv] [-f file] [user ...]"
2167cdfce09SScott Long	echo "       if the -y switch is used, either the -f switch or"
2177cdfce09SScott Long	echo "       one or more user names must be given"
2187cdfce09SScott Long}
2197cdfce09SScott Long
2207cdfce09SScott Long#### END SUBROUTINE DEFENITION ####
2217cdfce09SScott Long
2227cdfce09SScott Longffile=
2237cdfce09SScott Longfflag=
2247cdfce09SScott Longprocowner=
2257cdfce09SScott Longpw_rswitch=
2267cdfce09SScott Longuserlist=
2277cdfce09SScott Longyflag=
2286fcaf748SMike Makonnenvflag=
2297cdfce09SScott Long
2307cdfce09SScott Longprocowner=`/usr/bin/id -u`
2317cdfce09SScott Longif [ "$procowner" != "0" ]; then
2327cdfce09SScott Long	err 'you must be root (0) to use this utility.'
2337cdfce09SScott Long	exit 1
2347cdfce09SScott Longfi
2357cdfce09SScott Long
2366fcaf748SMike Makonnenargs=`getopt 2>/dev/null yvf: $*`
2377cdfce09SScott Longif [ "$?" != "0" ]; then
2387cdfce09SScott Long	show_usage
2397cdfce09SScott Long	exit 1
2407cdfce09SScott Longfi
2417cdfce09SScott Longset -- $args
2427cdfce09SScott Longfor _switch ; do
2437cdfce09SScott Long	case $_switch in
2447cdfce09SScott Long	-y)
2457cdfce09SScott Long		yflag=1
2467cdfce09SScott Long		shift
2477cdfce09SScott Long		;;
2486fcaf748SMike Makonnen	-v)
2496fcaf748SMike Makonnen		vflag=1
2506fcaf748SMike Makonnen		shift
2516fcaf748SMike Makonnen		;;
2527cdfce09SScott Long	-f)
2537cdfce09SScott Long		fflag=1
2547cdfce09SScott Long		ffile="$2"
2557cdfce09SScott Long		shift; shift
2567cdfce09SScott Long		;;
2577cdfce09SScott Long	--)
2587cdfce09SScott Long		shift
2597cdfce09SScott Long		break
2607cdfce09SScott Long		;;
2617cdfce09SScott Long	esac
2627cdfce09SScott Longdone
2637cdfce09SScott Long
2647cdfce09SScott Long# Get user names from a file if the -f switch was used. Otherwise,
2657cdfce09SScott Long# get them from the commandline arguments. If we're getting it
2667cdfce09SScott Long# from a file, the file must be owned by and writable only by root.
2677cdfce09SScott Long#
2687cdfce09SScott Longif [ $fflag ]; then
2697cdfce09SScott Long	_insecure=`find $ffile ! -user 0 -or -perm +0022`
2707cdfce09SScott Long	if [ -n "$_insecure" ]; then
2717cdfce09SScott Long		err "file ($ffile) must be owned by and writeable only by root."
2727cdfce09SScott Long		exit 1
2737cdfce09SScott Long	fi
2747cdfce09SScott Long	if [ -r "$ffile" ]; then
2757cdfce09SScott Long		userlist=`cat $ffile | while read _user _junk ; do
2767cdfce09SScott Long			case $_user in
2777cdfce09SScott Long			\#*|'')
2787cdfce09SScott Long				;;
2797cdfce09SScott Long			*)
2807cdfce09SScott Long				echo -n "$userlist $_user"
2817cdfce09SScott Long				;;
2827cdfce09SScott Long			esac
2837cdfce09SScott Long		done`
2847cdfce09SScott Long	fi
2857cdfce09SScott Longelse
2867cdfce09SScott Long	while [ $1 ] ; do
2877cdfce09SScott Long		userlist="$userlist $1"
2887cdfce09SScott Long		shift
2897cdfce09SScott Long	done
2907cdfce09SScott Longfi
2917cdfce09SScott Long
2927cdfce09SScott Long# If the -y or -f switch has been used and the list of users to remove
2937cdfce09SScott Long# is empty it is a fatal error. Otherwise, prompt the user for a list
2947cdfce09SScott Long# of one or more user names.
2957cdfce09SScott Long#
2967cdfce09SScott Longif [ ! "$userlist" ]; then
2977cdfce09SScott Long	if [ $fflag ]; then
2987cdfce09SScott Long		err "($ffile) does not exist or does not contain any user names."
2997cdfce09SScott Long		exit 1
3007cdfce09SScott Long	elif [ $yflag ]; then
3017cdfce09SScott Long		show_usage
3027cdfce09SScott Long		exit 1
3037cdfce09SScott Long	else
3047cdfce09SScott Long		echo -n "Please enter one or more user name's: "
3057cdfce09SScott Long		read userlist
3067cdfce09SScott Long	fi
3077cdfce09SScott Longfi
3087cdfce09SScott Long
3097cdfce09SScott Long_user=
3107cdfce09SScott Long_uid=
3117cdfce09SScott Longfor _user in $userlist ; do
3127cdfce09SScott Long	# Make sure the name exists in the passwd database and that it
3137cdfce09SScott Long	# does not have a uid of 0
3147cdfce09SScott Long	#
3157cdfce09SScott Long	userrec=`pw 2>/dev/null usershow -n $_user`
3167cdfce09SScott Long	if [ "$?" != "0" ]; then
3177cdfce09SScott Long		err "user ($_user) does not exist in the password database."
3187cdfce09SScott Long		continue
3197cdfce09SScott Long	fi
3207cdfce09SScott Long	_uid=`echo $userrec | awk -F: '{print $3}'`
3217cdfce09SScott Long	if [ "$_uid" = "0" ]; then
3227cdfce09SScott Long		err "user ($_user) has uid 0. You may not remove this user."
3237cdfce09SScott Long		continue
3247cdfce09SScott Long	fi
3257cdfce09SScott Long
3267cdfce09SScott Long	# If the -y switch was not used ask for confirmation to remove the
3277cdfce09SScott Long	# user and home directory.
3287cdfce09SScott Long	#
3297cdfce09SScott Long	if [ -z "$yflag" ]; then
3307cdfce09SScott Long		echo "Matching password entry:"
3317cdfce09SScott Long		echo
3327cdfce09SScott Long		echo $userrec
3337cdfce09SScott Long		echo
3347cdfce09SScott Long		if ! prompt_yesno "Is this the entry you wish to remove? " ; then
3357cdfce09SScott Long			continue
3367cdfce09SScott Long		fi
3377cdfce09SScott Long		_homedir=`echo $userrec | awk -F: '{print $9}'`
338ce1794a8SMax Khon		if prompt_yesno "Remove user's home directory ($_homedir)? "; then
3397cdfce09SScott Long			pw_rswitch="-r"
3407cdfce09SScott Long		fi
3417cdfce09SScott Long	else
3427cdfce09SScott Long		pw_rswitch="-r"
3437cdfce09SScott Long	fi
3447cdfce09SScott Long
3457cdfce09SScott Long	# Disable any further attempts to log into this account
3467cdfce09SScott Long	pw 2>/dev/null lock $_user
3477cdfce09SScott Long
3487cdfce09SScott Long	# Remove crontab, mail spool, etc. Then obliterate the user from
3497cdfce09SScott Long	# the passwd and group database.
3506fcaf748SMike Makonnen	#
3516fcaf748SMike Makonnen	! verbose && echo -n "Removing user ($_user):"
3527cdfce09SScott Long	rm_crontab $_user
3537cdfce09SScott Long	rm_at_jobs $_user
354d6bfbcc3SJens Schweikhardt	rm_ipc $_user
3557cdfce09SScott Long	kill_procs $_user
3567cdfce09SScott Long	rm_files $_user
3576fcaf748SMike Makonnen	rm_mail $_user
3587cdfce09SScott Long	rm_user $_user
3596fcaf748SMike Makonnen	! verbose && echo "."
3607cdfce09SScott Longdone
361