xref: /freebsd/usr.sbin/adduser/rmuser.sh (revision fc89586093fa5be0ff191e2de426fdace4c80dc2)
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#
257cdfce09SScott Long#	Email: Mike Makonnen <mtm@identd.net>
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:"
67deca89c7STim J. Robbins		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
856fcaf748SMike Makonnen		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
906fcaf748SMike Makonnen		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
1487cdfce09SScott Long# rm_user login
1497cdfce09SScott Long#	Remove user $login from the system. This subroutine makes use
1507cdfce09SScott Long#	of the pw(8) command to remove a user from the system. The pw(8)
1517cdfce09SScott Long#	command will remove the specified user from the user database
1527cdfce09SScott Long#	and group file and remove any crontabs. His home
1537cdfce09SScott Long#	directory will be removed if it is owned by him and contains no
1547cdfce09SScott Long#	files or subdirectories owned by other users. Mail spool files will
1557cdfce09SScott Long#	also be removed.
1567cdfce09SScott Long#
1577cdfce09SScott Longrm_user() {
1587cdfce09SScott Long	# The argument is required
1597cdfce09SScott Long	[ -n $1 ] && login=$1 || return
1607cdfce09SScott Long
1616fcaf748SMike Makonnen	verbose && echo -n "Removing user ($login)"
1626fcaf748SMike Makonnen	[ -n "$pw_rswitch" ] && {
1636fcaf748SMike Makonnen		verbose && echo -n " (including home directory)"
1646fcaf748SMike Makonnen		! verbose && echo -n " home"
1656fcaf748SMike Makonnen	}
1666fcaf748SMike Makonnen	! verbose && echo -n " passwd"
1676fcaf748SMike Makonnen	verbose && echo -n " from the system:"
1687cdfce09SScott Long	pw userdel -n $login $pw_rswitch
1696fcaf748SMike Makonnen	verbose && echo ' Done.'
1707cdfce09SScott Long}
1717cdfce09SScott Long
1727cdfce09SScott Long# prompt_yesno msg
1737cdfce09SScott Long#	Prompts the user with a $msg. The answer is expected to be
1747cdfce09SScott Long#	yes, no, or some variation thereof. This subroutine returns 0
1757cdfce09SScott Long#	if the answer was yes, 1 if it was not.
1767cdfce09SScott Long#
1777cdfce09SScott Longprompt_yesno() {
1787cdfce09SScott Long	# The argument is required
179ce1794a8SMax Khon	[ -n "$1" ] && msg="$1" || return
1807cdfce09SScott Long
1817cdfce09SScott Long        while : ; do
182ce1794a8SMax Khon                echo -n "$msg"
1837cdfce09SScott Long                read _ans
1847cdfce09SScott Long                case $_ans in
1857cdfce09SScott Long                [Nn][Oo]|[Nn])
1867cdfce09SScott Long			return 1
1877cdfce09SScott Long                        ;;
1887cdfce09SScott Long                [Yy][Ee][Ss]|[Yy][Ee]|[Yy])
1897cdfce09SScott Long                        return 0
1907cdfce09SScott Long                        ;;
1917cdfce09SScott Long                *)
1927cdfce09SScott Long                        ;;
1937cdfce09SScott Long                esac
1947cdfce09SScott Long	done
1957cdfce09SScott Long}
1967cdfce09SScott Long
1977cdfce09SScott Long# show_usage
1987cdfce09SScott Long#	(no arguments)
1997cdfce09SScott Long#	Display usage message.
2007cdfce09SScott Long#
2017cdfce09SScott Longshow_usage() {
2026fcaf748SMike Makonnen	echo "usage: ${THISCMD} [-yv] [-f file] [user ...]"
2037cdfce09SScott Long	echo "       if the -y switch is used, either the -f switch or"
2047cdfce09SScott Long	echo "       one or more user names must be given"
2057cdfce09SScott Long}
2067cdfce09SScott Long
2077cdfce09SScott Long#### END SUBROUTINE DEFENITION ####
2087cdfce09SScott Long
2097cdfce09SScott Longffile=
2107cdfce09SScott Longfflag=
2117cdfce09SScott Longprocowner=
2127cdfce09SScott Longpw_rswitch=
2137cdfce09SScott Longuserlist=
2147cdfce09SScott Longyflag=
2156fcaf748SMike Makonnenvflag=
2167cdfce09SScott Long
2177cdfce09SScott Longprocowner=`/usr/bin/id -u`
2187cdfce09SScott Longif [ "$procowner" != "0" ]; then
2197cdfce09SScott Long	err 'you must be root (0) to use this utility.'
2207cdfce09SScott Long	exit 1
2217cdfce09SScott Longfi
2227cdfce09SScott Long
2236fcaf748SMike Makonnenargs=`getopt 2>/dev/null yvf: $*`
2247cdfce09SScott Longif [ "$?" != "0" ]; then
2257cdfce09SScott Long	show_usage
2267cdfce09SScott Long	exit 1
2277cdfce09SScott Longfi
2287cdfce09SScott Longset -- $args
2297cdfce09SScott Longfor _switch ; do
2307cdfce09SScott Long	case $_switch in
2317cdfce09SScott Long	-y)
2327cdfce09SScott Long		yflag=1
2337cdfce09SScott Long		shift
2347cdfce09SScott Long		;;
2356fcaf748SMike Makonnen	-v)
2366fcaf748SMike Makonnen		vflag=1
2376fcaf748SMike Makonnen		shift
2386fcaf748SMike Makonnen		;;
2397cdfce09SScott Long	-f)
2407cdfce09SScott Long		fflag=1
2417cdfce09SScott Long		ffile="$2"
2427cdfce09SScott Long		shift; shift
2437cdfce09SScott Long		;;
2447cdfce09SScott Long	--)
2457cdfce09SScott Long		shift
2467cdfce09SScott Long		break
2477cdfce09SScott Long		;;
2487cdfce09SScott Long	esac
2497cdfce09SScott Longdone
2507cdfce09SScott Long
2517cdfce09SScott Long# Get user names from a file if the -f switch was used. Otherwise,
2527cdfce09SScott Long# get them from the commandline arguments. If we're getting it
2537cdfce09SScott Long# from a file, the file must be owned by and writable only by root.
2547cdfce09SScott Long#
2557cdfce09SScott Longif [ $fflag ]; then
2567cdfce09SScott Long	_insecure=`find $ffile ! -user 0 -or -perm +0022`
2577cdfce09SScott Long	if [ -n "$_insecure" ]; then
2587cdfce09SScott Long		err "file ($ffile) must be owned by and writeable only by root."
2597cdfce09SScott Long		exit 1
2607cdfce09SScott Long	fi
2617cdfce09SScott Long	if [ -r "$ffile" ]; then
2627cdfce09SScott Long		userlist=`cat $ffile | while read _user _junk ; do
2637cdfce09SScott Long			case $_user in
2647cdfce09SScott Long			\#*|'')
2657cdfce09SScott Long				;;
2667cdfce09SScott Long			*)
2677cdfce09SScott Long				echo -n "$userlist $_user"
2687cdfce09SScott Long				;;
2697cdfce09SScott Long			esac
2707cdfce09SScott Long		done`
2717cdfce09SScott Long	fi
2727cdfce09SScott Longelse
2737cdfce09SScott Long	while [ $1 ] ; do
2747cdfce09SScott Long		userlist="$userlist $1"
2757cdfce09SScott Long		shift
2767cdfce09SScott Long	done
2777cdfce09SScott Longfi
2787cdfce09SScott Long
2797cdfce09SScott Long# If the -y or -f switch has been used and the list of users to remove
2807cdfce09SScott Long# is empty it is a fatal error. Otherwise, prompt the user for a list
2817cdfce09SScott Long# of one or more user names.
2827cdfce09SScott Long#
2837cdfce09SScott Longif [ ! "$userlist" ]; then
2847cdfce09SScott Long	if [ $fflag ]; then
2857cdfce09SScott Long		err "($ffile) does not exist or does not contain any user names."
2867cdfce09SScott Long		exit 1
2877cdfce09SScott Long	elif [ $yflag ]; then
2887cdfce09SScott Long		show_usage
2897cdfce09SScott Long		exit 1
2907cdfce09SScott Long	else
2917cdfce09SScott Long		echo -n "Please enter one or more user name's: "
2927cdfce09SScott Long		read userlist
2937cdfce09SScott Long	fi
2947cdfce09SScott Longfi
2957cdfce09SScott Long
2967cdfce09SScott Long_user=
2977cdfce09SScott Long_uid=
2987cdfce09SScott Longfor _user in $userlist ; do
2997cdfce09SScott Long	# Make sure the name exists in the passwd database and that it
3007cdfce09SScott Long	# does not have a uid of 0
3017cdfce09SScott Long	#
3027cdfce09SScott Long	userrec=`pw 2>/dev/null usershow -n $_user`
3037cdfce09SScott Long	if [ "$?" != "0" ]; then
3047cdfce09SScott Long		err "user ($_user) does not exist in the password database."
3057cdfce09SScott Long		continue
3067cdfce09SScott Long	fi
3077cdfce09SScott Long	_uid=`echo $userrec | awk -F: '{print $3}'`
3087cdfce09SScott Long	if [ "$_uid" = "0" ]; then
3097cdfce09SScott Long		err "user ($_user) has uid 0. You may not remove this user."
3107cdfce09SScott Long		continue
3117cdfce09SScott Long	fi
3127cdfce09SScott Long
3137cdfce09SScott Long	# If the -y switch was not used ask for confirmation to remove the
3147cdfce09SScott Long	# user and home directory.
3157cdfce09SScott Long	#
3167cdfce09SScott Long	if [ -z "$yflag" ]; then
3177cdfce09SScott Long		echo "Matching password entry:"
3187cdfce09SScott Long		echo
3197cdfce09SScott Long		echo $userrec
3207cdfce09SScott Long		echo
3217cdfce09SScott Long		if ! prompt_yesno "Is this the entry you wish to remove? " ; then
3227cdfce09SScott Long			continue
3237cdfce09SScott Long		fi
3247cdfce09SScott Long		_homedir=`echo $userrec | awk -F: '{print $9}'`
325ce1794a8SMax Khon		if prompt_yesno "Remove user's home directory ($_homedir)? "; then
3267cdfce09SScott Long			pw_rswitch="-r"
3277cdfce09SScott Long		fi
3287cdfce09SScott Long	else
3297cdfce09SScott Long		pw_rswitch="-r"
3307cdfce09SScott Long	fi
3317cdfce09SScott Long
3327cdfce09SScott Long	# Disable any further attempts to log into this account
3337cdfce09SScott Long	pw 2>/dev/null lock $_user
3347cdfce09SScott Long
3357cdfce09SScott Long	# Remove crontab, mail spool, etc. Then obliterate the user from
3367cdfce09SScott Long	# the passwd and group database.
3376fcaf748SMike Makonnen	#
3386fcaf748SMike Makonnen	! verbose && echo -n "Removing user ($_user):"
3397cdfce09SScott Long	rm_crontab $_user
3407cdfce09SScott Long	rm_at_jobs $_user
3417cdfce09SScott Long	kill_procs $_user
3427cdfce09SScott Long	rm_files $_user
3436fcaf748SMike Makonnen	rm_mail $_user
3447cdfce09SScott Long	rm_user $_user
3456fcaf748SMike Makonnen	! verbose && echo "."
3467cdfce09SScott Longdone
347