xref: /freebsd/usr.sbin/adduser/rmuser.sh (revision d0b2dbfa0ecf2bbc9709efc5e20baf8e4b44bbbf)
17cdfce09SScott Long#!/bin/sh
27cdfce09SScott Long#
3*4d846d26SWarner Losh# SPDX-License-Identifier: BSD-2-Clause
41de7b4b8SPedro F. Giffuni#
5fc895860SMike Makonnen# Copyright (c) 2002, 2003 Michael Telahun Makonnen. All rights reserved.
67cdfce09SScott Long#
77cdfce09SScott Long# Redistribution and use in source and binary forms, with or without
87cdfce09SScott Long# modification, are permitted provided that the following conditions
97cdfce09SScott Long# are met:
107cdfce09SScott Long# 1. Redistributions of source code must retain the above copyright
117cdfce09SScott Long#    notice, this list of conditions and the following disclaimer.
127cdfce09SScott Long# 2. Redistributions in binary form must reproduce the above copyright
137cdfce09SScott Long#    notice, this list of conditions and the following disclaimer in the
147cdfce09SScott Long#    documentation and/or other materials provided with the distribution.
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#
2722884fddSMike Makonnen#	Email: Mike Makonnen <mtm@FreeBSD.Org>
287cdfce09SScott Long#
297cdfce09SScott Long#
307cdfce09SScott Long
317cdfce09SScott LongATJOBDIR="/var/at/jobs"
327cdfce09SScott LongCRONJOBDIR="/var/cron/tabs"
337cdfce09SScott LongMAILSPOOL="/var/mail"
347cdfce09SScott LongSIGKILL="-KILL"
35deca89c7STim J. RobbinsTEMPDIRS="/tmp /var/tmp"
367cdfce09SScott LongTHISCMD=`/usr/bin/basename $0`
37662c90c8SJohn BaldwinPWCMD="${PWCMD:-/usr/sbin/pw}"
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
466fcaf748SMike Makonnen# verbose
476fcaf748SMike Makonnen#	Returns 0 if verbose mode is set, 1 if it is not.
486fcaf748SMike Makonnen#
496fcaf748SMike Makonnenverbose() {
506fcaf748SMike Makonnen	[ -n "$vflag" ] && return 0 || return 1
516fcaf748SMike Makonnen}
526fcaf748SMike Makonnen
537cdfce09SScott Long# rm_files login
547cdfce09SScott Long#	Removes files or empty directories belonging to $login from various
557cdfce09SScott Long#	temporary directories.
567cdfce09SScott Long#
577cdfce09SScott Longrm_files() {
587cdfce09SScott Long	# The argument is required
597cdfce09SScott Long	[ -n $1 ] && login=$1 || return
607cdfce09SScott Long
616fcaf748SMike Makonnen	totalcount=0
627cdfce09SScott Long	for _dir in ${TEMPDIRS} ; do
636fcaf748SMike Makonnen		filecount=0
647cdfce09SScott Long		if [ ! -d $_dir ]; then
657cdfce09SScott Long			err "$_dir is not a valid directory."
667cdfce09SScott Long			continue
677cdfce09SScott Long		fi
686fcaf748SMike Makonnen		verbose && echo -n "Removing files owned by ($login) in $_dir:"
69d6bfbcc3SJens Schweikhardt		filecount=`find 2>/dev/null "$_dir" -user "$login" -delete -print |
70deca89c7STim J. Robbins		    wc -l | sed 's/ *//'`
716fcaf748SMike Makonnen		verbose && echo " $filecount removed."
726fcaf748SMike Makonnen		totalcount=$(($totalcount + $filecount))
737cdfce09SScott Long	done
746fcaf748SMike Makonnen	! verbose && [ $totalcount -ne 0 ] && echo -n " files($totalcount)"
757cdfce09SScott Long}
767cdfce09SScott Long
777cdfce09SScott Long# rm_mail login
787cdfce09SScott Long#	Removes unix mail and pop daemon files belonging to the user
797cdfce09SScott Long#	specified in the $login argument.
807cdfce09SScott Long#
817cdfce09SScott Longrm_mail() {
827cdfce09SScott Long	# The argument is required
837cdfce09SScott Long	[ -n $1 ] && login=$1 || return
847cdfce09SScott Long
856fcaf748SMike Makonnen	verbose && echo -n "Removing mail spool(s) for ($login):"
867cdfce09SScott Long	if [ -f ${MAILSPOOL}/$login ]; then
87d6bfbcc3SJens Schweikhardt		verbose && echo -n " ${MAILSPOOL}/$login" ||
886fcaf748SMike Makonnen		    echo -n " mailspool"
897cdfce09SScott Long		rm ${MAILSPOOL}/$login
907cdfce09SScott Long	fi
91017568b3SMike Makonnen	if [ -f ${MAILSPOOL}/.${login}.pop ]; then
92017568b3SMike Makonnen		verbose && echo -n " ${MAILSPOOL}/.${login}.pop" ||
936fcaf748SMike Makonnen		    echo -n " pop3"
94017568b3SMike Makonnen		rm ${MAILSPOOL}/.${login}.pop
957cdfce09SScott Long	fi
966fcaf748SMike Makonnen	verbose && echo '.'
977cdfce09SScott Long}
987cdfce09SScott Long
997cdfce09SScott Long# kill_procs login
1007cdfce09SScott Long#	Send a SIGKILL to all processes owned by $login.
1017cdfce09SScott Long#
1027cdfce09SScott Longkill_procs() {
1037cdfce09SScott Long	# The argument is required
1047cdfce09SScott Long	[ -n $1 ] && login=$1 || return
1057cdfce09SScott Long
1066fcaf748SMike Makonnen	verbose && echo -n "Terminating all processes owned by ($login):"
1077cdfce09SScott Long	killcount=0
1087cdfce09SScott Long	proclist=`ps 2>/dev/null -U $login | grep -v '^\ *PID' | awk '{print $1}'`
1097cdfce09SScott Long	for _pid in $proclist ; do
1107cdfce09SScott Long		kill 2>/dev/null ${SIGKILL} $_pid
111fd045cf5SMax Khon		killcount=$(($killcount + 1))
1127cdfce09SScott Long	done
1136fcaf748SMike Makonnen	verbose && echo " ${SIGKILL} signal sent to $killcount processes."
1146fcaf748SMike Makonnen	! verbose && [ $killcount -ne 0 ] && echo -n " processes(${killcount})"
1157cdfce09SScott Long}
1167cdfce09SScott Long
1177cdfce09SScott Long# rm_at_jobs login
1187cdfce09SScott Long#	Remove at (1) jobs belonging to $login.
1197cdfce09SScott Long#
1207cdfce09SScott Longrm_at_jobs() {
1217cdfce09SScott Long	# The argument is required
1227cdfce09SScott Long	[ -n $1 ] && login=$1 || return
1237cdfce09SScott Long
1247cdfce09SScott Long	atjoblist=`find 2>/dev/null ${ATJOBDIR} -maxdepth 1 -user $login -print`
1257cdfce09SScott Long	jobcount=0
1266fcaf748SMike Makonnen	verbose && echo -n "Removing at(1) jobs owned by ($login):"
1277cdfce09SScott Long	for _atjob in $atjoblist ; do
1287cdfce09SScott Long		rm -f $_atjob
129fd045cf5SMax Khon		jobcount=$(($jobcount + 1))
1307cdfce09SScott Long	done
1316fcaf748SMike Makonnen	verbose && echo " $jobcount removed."
1326fcaf748SMike Makonnen	! verbose && [ $jobcount -ne 0 ] && echo -n " at($jobcount)"
1337cdfce09SScott Long}
1347cdfce09SScott Long
1357cdfce09SScott Long# rm_crontab login
1367cdfce09SScott Long#	Removes crontab file belonging to user $login.
1377cdfce09SScott Long#
1387cdfce09SScott Longrm_crontab() {
1397cdfce09SScott Long	# The argument is required
1407cdfce09SScott Long	[ -n $1 ] && login=$1 || return
1417cdfce09SScott Long
1426fcaf748SMike Makonnen	verbose && echo -n "Removing crontab for ($login):"
1437cdfce09SScott Long	if [ -f ${CRONJOBDIR}/$login ]; then
1446fcaf748SMike Makonnen		verbose && echo -n " ${CRONJOBDIR}/$login" || echo -n " crontab"
1457cdfce09SScott Long		rm -f ${CRONJOBDIR}/$login
1467cdfce09SScott Long	fi
1476fcaf748SMike Makonnen	verbose && echo '.'
1487cdfce09SScott Long}
1497cdfce09SScott Long
150d6bfbcc3SJens Schweikhardt# rm_ipc login
151d6bfbcc3SJens Schweikhardt#	Remove all IPC mechanisms which are owned by $login.
152d6bfbcc3SJens Schweikhardt#
153d6bfbcc3SJens Schweikhardtrm_ipc() {
154d6bfbcc3SJens Schweikhardt	verbose && echo -n "Removing IPC mechanisms"
155d6bfbcc3SJens Schweikhardt	for i in s m q; do
156d6bfbcc3SJens Schweikhardt		ipcs -$i |
157d6bfbcc3SJens Schweikhardt		awk -v i=$i -v login=$1 '$1 == i && $5 == login { print $2 }' |
158d6bfbcc3SJens Schweikhardt		xargs -n 1 ipcrm -$i
159d6bfbcc3SJens Schweikhardt	done
160d6bfbcc3SJens Schweikhardt	verbose && echo '.'
161d6bfbcc3SJens Schweikhardt}
162d6bfbcc3SJens Schweikhardt
1637cdfce09SScott Long# rm_user login
1647cdfce09SScott Long#	Remove user $login from the system. This subroutine makes use
1657cdfce09SScott Long#	of the pw(8) command to remove a user from the system. The pw(8)
1667cdfce09SScott Long#	command will remove the specified user from the user database
1677cdfce09SScott Long#	and group file and remove any crontabs. His home
1687cdfce09SScott Long#	directory will be removed if it is owned by him and contains no
1697cdfce09SScott Long#	files or subdirectories owned by other users. Mail spool files will
1707cdfce09SScott Long#	also be removed.
1717cdfce09SScott Long#
1727cdfce09SScott Longrm_user() {
1737cdfce09SScott Long	# The argument is required
1747cdfce09SScott Long	[ -n $1 ] && login=$1 || return
1757cdfce09SScott Long
1766fcaf748SMike Makonnen	verbose && echo -n "Removing user ($login)"
1776fcaf748SMike Makonnen	[ -n "$pw_rswitch" ] && {
1786fcaf748SMike Makonnen		verbose && echo -n " (including home directory)"
1796fcaf748SMike Makonnen		! verbose && echo -n " home"
1806fcaf748SMike Makonnen	}
1816fcaf748SMike Makonnen	! verbose && echo -n " passwd"
1826fcaf748SMike Makonnen	verbose && echo -n " from the system:"
183662c90c8SJohn Baldwin	${PWCMD} userdel -n $login $pw_rswitch
1846fcaf748SMike Makonnen	verbose && echo ' Done.'
1857cdfce09SScott Long}
1867cdfce09SScott Long
1877cdfce09SScott Long# prompt_yesno msg
1887cdfce09SScott Long#	Prompts the user with a $msg. The answer is expected to be
1897cdfce09SScott Long#	yes, no, or some variation thereof. This subroutine returns 0
1907cdfce09SScott Long#	if the answer was yes, 1 if it was not.
1917cdfce09SScott Long#
1927cdfce09SScott Longprompt_yesno() {
1937cdfce09SScott Long	# The argument is required
194ce1794a8SMax Khon	[ -n "$1" ] && msg="$1" || return
1957cdfce09SScott Long
1967cdfce09SScott Long        while : ; do
197ce1794a8SMax Khon                echo -n "$msg"
1987cdfce09SScott Long                read _ans
1997cdfce09SScott Long                case $_ans in
2007cdfce09SScott Long                [Nn][Oo]|[Nn])
2017cdfce09SScott Long			return 1
2027cdfce09SScott Long                        ;;
2037cdfce09SScott Long                [Yy][Ee][Ss]|[Yy][Ee]|[Yy])
2047cdfce09SScott Long                        return 0
2057cdfce09SScott Long                        ;;
2067cdfce09SScott Long                *)
2077cdfce09SScott Long                        ;;
2087cdfce09SScott Long                esac
2097cdfce09SScott Long	done
2107cdfce09SScott Long}
2117cdfce09SScott Long
2127cdfce09SScott Long# show_usage
2137cdfce09SScott Long#	(no arguments)
2147cdfce09SScott Long#	Display usage message.
2157cdfce09SScott Long#
2167cdfce09SScott Longshow_usage() {
2176fcaf748SMike Makonnen	echo "usage: ${THISCMD} [-yv] [-f file] [user ...]"
2187cdfce09SScott Long	echo "       if the -y switch is used, either the -f switch or"
2197cdfce09SScott Long	echo "       one or more user names must be given"
2207cdfce09SScott Long}
2217cdfce09SScott Long
2227cdfce09SScott Long#### END SUBROUTINE DEFENITION ####
2237cdfce09SScott Long
2247cdfce09SScott Longffile=
2257cdfce09SScott Longfflag=
2267cdfce09SScott Longprocowner=
2277cdfce09SScott Longpw_rswitch=
2287cdfce09SScott Longuserlist=
2297cdfce09SScott Longyflag=
2306fcaf748SMike Makonnenvflag=
2317cdfce09SScott Long
2327cdfce09SScott Longprocowner=`/usr/bin/id -u`
2337cdfce09SScott Longif [ "$procowner" != "0" ]; then
2347cdfce09SScott Long	err 'you must be root (0) to use this utility.'
2357cdfce09SScott Long	exit 1
2367cdfce09SScott Longfi
2377cdfce09SScott Long
2386fcaf748SMike Makonnenargs=`getopt 2>/dev/null yvf: $*`
2397cdfce09SScott Longif [ "$?" != "0" ]; then
2407cdfce09SScott Long	show_usage
2417cdfce09SScott Long	exit 1
2427cdfce09SScott Longfi
2437cdfce09SScott Longset -- $args
2447cdfce09SScott Longfor _switch ; do
2457cdfce09SScott Long	case $_switch in
2467cdfce09SScott Long	-y)
2477cdfce09SScott Long		yflag=1
2487cdfce09SScott Long		shift
2497cdfce09SScott Long		;;
2506fcaf748SMike Makonnen	-v)
2516fcaf748SMike Makonnen		vflag=1
2526fcaf748SMike Makonnen		shift
2536fcaf748SMike Makonnen		;;
2547cdfce09SScott Long	-f)
2557cdfce09SScott Long		fflag=1
2567cdfce09SScott Long		ffile="$2"
2577cdfce09SScott Long		shift; shift
2587cdfce09SScott Long		;;
2597cdfce09SScott Long	--)
2607cdfce09SScott Long		shift
2617cdfce09SScott Long		break
2627cdfce09SScott Long		;;
2637cdfce09SScott Long	esac
2647cdfce09SScott Longdone
2657cdfce09SScott Long
2667cdfce09SScott Long# Get user names from a file if the -f switch was used. Otherwise,
2677cdfce09SScott Long# get them from the commandline arguments. If we're getting it
2687cdfce09SScott Long# from a file, the file must be owned by and writable only by root.
2697cdfce09SScott Long#
2707cdfce09SScott Longif [ $fflag ]; then
2717cdfce09SScott Long	_insecure=`find $ffile ! -user 0 -or -perm +0022`
2727cdfce09SScott Long	if [ -n "$_insecure" ]; then
2737cdfce09SScott Long		err "file ($ffile) must be owned by and writeable only by root."
2747cdfce09SScott Long		exit 1
2757cdfce09SScott Long	fi
2767cdfce09SScott Long	if [ -r "$ffile" ]; then
2777cdfce09SScott Long		userlist=`cat $ffile | while read _user _junk ; do
2787cdfce09SScott Long			case $_user in
2797cdfce09SScott Long			\#*|'')
2807cdfce09SScott Long				;;
2817cdfce09SScott Long			*)
2827cdfce09SScott Long				echo -n "$userlist $_user"
2837cdfce09SScott Long				;;
2847cdfce09SScott Long			esac
2857cdfce09SScott Long		done`
2867cdfce09SScott Long	fi
2877cdfce09SScott Longelse
2887cdfce09SScott Long	while [ $1 ] ; do
2897cdfce09SScott Long		userlist="$userlist $1"
2907cdfce09SScott Long		shift
2917cdfce09SScott Long	done
2927cdfce09SScott Longfi
2937cdfce09SScott Long
2947cdfce09SScott Long# If the -y or -f switch has been used and the list of users to remove
2957cdfce09SScott Long# is empty it is a fatal error. Otherwise, prompt the user for a list
2967cdfce09SScott Long# of one or more user names.
2977cdfce09SScott Long#
2987cdfce09SScott Longif [ ! "$userlist" ]; then
2997cdfce09SScott Long	if [ $fflag ]; then
3007cdfce09SScott Long		err "($ffile) does not exist or does not contain any user names."
3017cdfce09SScott Long		exit 1
3027cdfce09SScott Long	elif [ $yflag ]; then
3037cdfce09SScott Long		show_usage
3047cdfce09SScott Long		exit 1
3057cdfce09SScott Long	else
306d72fd3f9SAdam Weinberger		echo -n "Please enter one or more usernames: "
3077cdfce09SScott Long		read userlist
3087cdfce09SScott Long	fi
3097cdfce09SScott Longfi
3107cdfce09SScott Long
3117cdfce09SScott Long_user=
3127cdfce09SScott Long_uid=
3137cdfce09SScott Longfor _user in $userlist ; do
3147cdfce09SScott Long	# Make sure the name exists in the passwd database and that it
3157cdfce09SScott Long	# does not have a uid of 0
3167cdfce09SScott Long	#
3177cdfce09SScott Long	userrec=`pw 2>/dev/null usershow -n $_user`
3187cdfce09SScott Long	if [ "$?" != "0" ]; then
3197cdfce09SScott Long		err "user ($_user) does not exist in the password database."
3207cdfce09SScott Long		continue
3217cdfce09SScott Long	fi
3227cdfce09SScott Long	_uid=`echo $userrec | awk -F: '{print $3}'`
3237cdfce09SScott Long	if [ "$_uid" = "0" ]; then
3247cdfce09SScott Long		err "user ($_user) has uid 0. You may not remove this user."
3257cdfce09SScott Long		continue
3267cdfce09SScott Long	fi
3277cdfce09SScott Long
3287cdfce09SScott Long	# If the -y switch was not used ask for confirmation to remove the
3297cdfce09SScott Long	# user and home directory.
3307cdfce09SScott Long	#
3317cdfce09SScott Long	if [ -z "$yflag" ]; then
3327cdfce09SScott Long		echo "Matching password entry:"
3337cdfce09SScott Long		echo
3347cdfce09SScott Long		echo $userrec
3357cdfce09SScott Long		echo
3367cdfce09SScott Long		if ! prompt_yesno "Is this the entry you wish to remove? " ; then
3377cdfce09SScott Long			continue
3387cdfce09SScott Long		fi
3397cdfce09SScott Long		_homedir=`echo $userrec | awk -F: '{print $9}'`
340ce1794a8SMax Khon		if prompt_yesno "Remove user's home directory ($_homedir)? "; then
3417cdfce09SScott Long			pw_rswitch="-r"
3427cdfce09SScott Long		fi
3437cdfce09SScott Long	else
3447cdfce09SScott Long		pw_rswitch="-r"
3457cdfce09SScott Long	fi
3467cdfce09SScott Long
3477cdfce09SScott Long	# Disable any further attempts to log into this account
348662c90c8SJohn Baldwin	${PWCMD} 2>/dev/null lock $_user
3497cdfce09SScott Long
3507cdfce09SScott Long	# Remove crontab, mail spool, etc. Then obliterate the user from
3517cdfce09SScott Long	# the passwd and group database.
3526fcaf748SMike Makonnen	#
3536fcaf748SMike Makonnen	! verbose && echo -n "Removing user ($_user):"
3547cdfce09SScott Long	rm_crontab $_user
3557cdfce09SScott Long	rm_at_jobs $_user
356d6bfbcc3SJens Schweikhardt	rm_ipc $_user
3577cdfce09SScott Long	kill_procs $_user
3587cdfce09SScott Long	rm_files $_user
3596fcaf748SMike Makonnen	rm_mail $_user
3607cdfce09SScott Long	rm_user $_user
3616fcaf748SMike Makonnen	! verbose && echo "."
3627cdfce09SScott Longdone
363