rmuser.sh revision 146556
1107543Sscottl#!/bin/sh
2107543Sscottl#
3111015Smtm# Copyright (c) 2002, 2003 Michael Telahun Makonnen. All rights reserved.
4107543Sscottl#
5107543Sscottl# Redistribution and use in source and binary forms, with or without
6107543Sscottl# modification, are permitted provided that the following conditions
7107543Sscottl# are met:
8107543Sscottl# 1. Redistributions of source code must retain the above copyright
9107543Sscottl#    notice, this list of conditions and the following disclaimer.
10107543Sscottl# 2. Redistributions in binary form must reproduce the above copyright
11107543Sscottl#    notice, this list of conditions and the following disclaimer in the
12107543Sscottl#    documentation and/or other materials provided with the distribution.
13107543Sscottl#
14107543Sscottl# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
15107543Sscottl# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16107543Sscottl# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17107543Sscottl# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
18107543Sscottl# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
19107543Sscottl# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20107543Sscottl# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21107543Sscottl# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22107543Sscottl# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23107543Sscottl# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24107543Sscottl#
25116624Smtm#	Email: Mike Makonnen <mtm@FreeBSD.Org>
26107543Sscottl#
27107543Sscottl# $FreeBSD: head/usr.sbin/adduser/rmuser.sh 146556 2005-05-24 04:50:07Z adamw $
28107543Sscottl#
29107543Sscottl
30107543SscottlATJOBDIR="/var/at/jobs"
31107543SscottlCRONJOBDIR="/var/cron/tabs"
32107543SscottlMAILSPOOL="/var/mail"
33107543SscottlSIGKILL="-KILL"
34107694StjrTEMPDIRS="/tmp /var/tmp"
35107543SscottlTHISCMD=`/usr/bin/basename $0`
36107543Sscottl
37107543Sscottl# err msg
38107543Sscottl#	Display $msg on stderr.
39107543Sscottl#
40107543Sscottlerr() {
41107543Sscottl	echo 1>&2 ${THISCMD}: $*
42107543Sscottl}
43107543Sscottl
44111013Smtm# verbose
45111013Smtm#	Returns 0 if verbose mode is set, 1 if it is not.
46111013Smtm#
47111013Smtmverbose() {
48111013Smtm	[ -n "$vflag" ] && return 0 || return 1
49111013Smtm}
50111013Smtm
51107543Sscottl# rm_files login
52107543Sscottl#	Removes files or empty directories belonging to $login from various
53107543Sscottl#	temporary directories.
54107543Sscottl#
55107543Sscottlrm_files() {
56107543Sscottl	# The argument is required
57107543Sscottl	[ -n $1 ] && login=$1 || return
58126398Sschweikh
59111013Smtm	totalcount=0
60107543Sscottl	for _dir in ${TEMPDIRS} ; do
61111013Smtm		filecount=0
62107543Sscottl		if [ ! -d $_dir ]; then
63107543Sscottl			err "$_dir is not a valid directory."
64107543Sscottl			continue
65107543Sscottl		fi
66111013Smtm		verbose && echo -n "Removing files owned by ($login) in $_dir:"
67126398Sschweikh		filecount=`find 2>/dev/null "$_dir" -user "$login" -delete -print |
68107694Stjr		    wc -l | sed 's/ *//'`
69111013Smtm		verbose && echo " $filecount removed."
70111013Smtm		totalcount=$(($totalcount + $filecount))
71107543Sscottl	done
72111013Smtm	! verbose && [ $totalcount -ne 0 ] && echo -n " files($totalcount)"
73107543Sscottl}
74107543Sscottl
75107543Sscottl# rm_mail login
76107543Sscottl#	Removes unix mail and pop daemon files belonging to the user
77107543Sscottl#	specified in the $login argument.
78107543Sscottl#
79107543Sscottlrm_mail() {
80107543Sscottl	# The argument is required
81107543Sscottl	[ -n $1 ] && login=$1 || return
82107543Sscottl
83111013Smtm	verbose && echo -n "Removing mail spool(s) for ($login):"
84107543Sscottl	if [ -f ${MAILSPOOL}/$login ]; then
85126398Sschweikh		verbose && echo -n " ${MAILSPOOL}/$login" ||
86111013Smtm		    echo -n " mailspool"
87107543Sscottl		rm ${MAILSPOOL}/$login
88107543Sscottl	fi
89107543Sscottl	if [ -f ${MAILSPOOL}/${login}.pop ]; then
90126398Sschweikh		verbose && echo -n " ${MAILSPOOL}/${login}.pop" ||
91111013Smtm		    echo -n " pop3"
92107543Sscottl		rm ${MAILSPOOL}/${login}.pop
93107543Sscottl	fi
94111013Smtm	verbose && echo '.'
95107543Sscottl}
96107543Sscottl
97107543Sscottl# kill_procs login
98107543Sscottl#	Send a SIGKILL to all processes owned by $login.
99107543Sscottl#
100107543Sscottlkill_procs() {
101107543Sscottl	# The argument is required
102107543Sscottl	[ -n $1 ] && login=$1 || return
103107543Sscottl
104111013Smtm	verbose && echo -n "Terminating all processes owned by ($login):"
105107543Sscottl	killcount=0
106107543Sscottl	proclist=`ps 2>/dev/null -U $login | grep -v '^\ *PID' | awk '{print $1}'`
107107543Sscottl	for _pid in $proclist ; do
108107543Sscottl		kill 2>/dev/null ${SIGKILL} $_pid
109109752Sfjoe		killcount=$(($killcount + 1))
110107543Sscottl	done
111111013Smtm	verbose && echo " ${SIGKILL} signal sent to $killcount processes."
112111013Smtm	! verbose && [ $killcount -ne 0 ] && echo -n " processes(${killcount})"
113107543Sscottl}
114107543Sscottl
115107543Sscottl# rm_at_jobs login
116107543Sscottl#	Remove at (1) jobs belonging to $login.
117107543Sscottl#
118107543Sscottlrm_at_jobs() {
119107543Sscottl	# The argument is required
120107543Sscottl	[ -n $1 ] && login=$1 || return
121107543Sscottl
122107543Sscottl	atjoblist=`find 2>/dev/null ${ATJOBDIR} -maxdepth 1 -user $login -print`
123107543Sscottl	jobcount=0
124111013Smtm	verbose && echo -n "Removing at(1) jobs owned by ($login):"
125107543Sscottl	for _atjob in $atjoblist ; do
126107543Sscottl		rm -f $_atjob
127109752Sfjoe		jobcount=$(($jobcount + 1))
128107543Sscottl	done
129111013Smtm	verbose && echo " $jobcount removed."
130111013Smtm	! verbose && [ $jobcount -ne 0 ] && echo -n " at($jobcount)"
131107543Sscottl}
132107543Sscottl
133107543Sscottl# rm_crontab login
134107543Sscottl#	Removes crontab file belonging to user $login.
135107543Sscottl#
136107543Sscottlrm_crontab() {
137107543Sscottl	# The argument is required
138107543Sscottl	[ -n $1 ] && login=$1 || return
139107543Sscottl
140111013Smtm	verbose && echo -n "Removing crontab for ($login):"
141107543Sscottl	if [ -f ${CRONJOBDIR}/$login ]; then
142111013Smtm		verbose && echo -n " ${CRONJOBDIR}/$login" || echo -n " crontab"
143107543Sscottl		rm -f ${CRONJOBDIR}/$login
144107543Sscottl	fi
145111013Smtm	verbose && echo '.'
146107543Sscottl}
147107543Sscottl
148126398Sschweikh# rm_ipc login
149126398Sschweikh#	Remove all IPC mechanisms which are owned by $login.
150126398Sschweikh#
151126398Sschweikhrm_ipc() {
152126398Sschweikh	verbose && echo -n "Removing IPC mechanisms"
153126398Sschweikh	for i in s m q; do
154126398Sschweikh		ipcs -$i |
155126398Sschweikh		awk -v i=$i -v login=$1 '$1 == i && $5 == login { print $2 }' |
156126398Sschweikh		xargs -n 1 ipcrm -$i
157126398Sschweikh	done
158126398Sschweikh	verbose && echo '.'
159126398Sschweikh}
160126398Sschweikh
161107543Sscottl# rm_user login
162107543Sscottl#	Remove user $login from the system. This subroutine makes use
163107543Sscottl#	of the pw(8) command to remove a user from the system. The pw(8)
164107543Sscottl#	command will remove the specified user from the user database
165107543Sscottl#	and group file and remove any crontabs. His home
166107543Sscottl#	directory will be removed if it is owned by him and contains no 
167107543Sscottl#	files or subdirectories owned by other users. Mail spool files will
168107543Sscottl#	also be removed.
169107543Sscottl#
170107543Sscottlrm_user() {
171107543Sscottl	# The argument is required
172107543Sscottl	[ -n $1 ] && login=$1 || return
173107543Sscottl
174111013Smtm	verbose && echo -n "Removing user ($login)"
175111013Smtm	[ -n "$pw_rswitch" ] && {
176111013Smtm		verbose && echo -n " (including home directory)"
177111013Smtm		! verbose && echo -n " home"
178111013Smtm	}
179111013Smtm	! verbose && echo -n " passwd"
180111013Smtm	verbose && echo -n " from the system:"
181107543Sscottl	pw userdel -n $login $pw_rswitch
182111013Smtm	verbose && echo ' Done.'
183107543Sscottl}
184107543Sscottl
185107543Sscottl# prompt_yesno msg
186107543Sscottl#	Prompts the user with a $msg. The answer is expected to be
187107543Sscottl#	yes, no, or some variation thereof. This subroutine returns 0
188107543Sscottl#	if the answer was yes, 1 if it was not.
189107543Sscottl#
190107543Sscottlprompt_yesno() {
191107543Sscottl	# The argument is required
192109750Sfjoe	[ -n "$1" ] && msg="$1" || return
193107543Sscottl
194107543Sscottl        while : ; do
195109750Sfjoe                echo -n "$msg"
196107543Sscottl                read _ans
197107543Sscottl                case $_ans in
198107543Sscottl                [Nn][Oo]|[Nn])
199107543Sscottl			return 1
200107543Sscottl                        ;;
201107543Sscottl                [Yy][Ee][Ss]|[Yy][Ee]|[Yy])
202107543Sscottl                        return 0
203107543Sscottl                        ;;
204107543Sscottl                *)
205107543Sscottl                        ;;
206107543Sscottl                esac
207107543Sscottl	done
208107543Sscottl}
209107543Sscottl
210107543Sscottl# show_usage
211107543Sscottl#	(no arguments)
212107543Sscottl#	Display usage message.
213107543Sscottl#
214107543Sscottlshow_usage() {
215111013Smtm	echo "usage: ${THISCMD} [-yv] [-f file] [user ...]"
216107543Sscottl	echo "       if the -y switch is used, either the -f switch or"
217107543Sscottl	echo "       one or more user names must be given"
218107543Sscottl}
219107543Sscottl
220107543Sscottl#### END SUBROUTINE DEFENITION ####
221107543Sscottl
222107543Sscottlffile=
223107543Sscottlfflag=
224107543Sscottlprocowner=
225107543Sscottlpw_rswitch=
226107543Sscottluserlist=
227107543Sscottlyflag=
228111013Smtmvflag=
229107543Sscottl
230107543Sscottlprocowner=`/usr/bin/id -u`
231107543Sscottlif [ "$procowner" != "0" ]; then
232107543Sscottl	err 'you must be root (0) to use this utility.'
233107543Sscottl	exit 1
234107543Sscottlfi
235107543Sscottl
236111013Smtmargs=`getopt 2>/dev/null yvf: $*`
237107543Sscottlif [ "$?" != "0" ]; then
238107543Sscottl	show_usage
239107543Sscottl	exit 1
240107543Sscottlfi
241107543Sscottlset -- $args
242107543Sscottlfor _switch ; do
243107543Sscottl	case $_switch in
244107543Sscottl	-y)
245107543Sscottl		yflag=1
246107543Sscottl		shift
247107543Sscottl		;;
248111013Smtm	-v)
249111013Smtm		vflag=1
250111013Smtm		shift
251111013Smtm		;;
252107543Sscottl	-f)
253107543Sscottl		fflag=1
254107543Sscottl		ffile="$2"
255107543Sscottl		shift; shift
256107543Sscottl		;;
257107543Sscottl	--)
258107543Sscottl		shift
259107543Sscottl		break
260107543Sscottl		;;
261107543Sscottl	esac
262107543Sscottldone
263107543Sscottl
264107543Sscottl# Get user names from a file if the -f switch was used. Otherwise,
265107543Sscottl# get them from the commandline arguments. If we're getting it
266107543Sscottl# from a file, the file must be owned by and writable only by root.
267107543Sscottl#
268107543Sscottlif [ $fflag ]; then
269107543Sscottl	_insecure=`find $ffile ! -user 0 -or -perm +0022`
270107543Sscottl	if [ -n "$_insecure" ]; then
271107543Sscottl		err "file ($ffile) must be owned by and writeable only by root."
272107543Sscottl		exit 1
273107543Sscottl	fi
274107543Sscottl	if [ -r "$ffile" ]; then
275107543Sscottl		userlist=`cat $ffile | while read _user _junk ; do
276107543Sscottl			case $_user in
277107543Sscottl			\#*|'')
278107543Sscottl				;;
279107543Sscottl			*)
280107543Sscottl				echo -n "$userlist $_user"
281107543Sscottl				;;
282107543Sscottl			esac
283107543Sscottl		done`
284107543Sscottl	fi
285107543Sscottlelse
286107543Sscottl	while [ $1 ] ; do
287107543Sscottl		userlist="$userlist $1"
288107543Sscottl		shift
289107543Sscottl	done
290107543Sscottlfi
291107543Sscottl
292107543Sscottl# If the -y or -f switch has been used and the list of users to remove
293107543Sscottl# is empty it is a fatal error. Otherwise, prompt the user for a list
294107543Sscottl# of one or more user names.
295107543Sscottl#
296107543Sscottlif [ ! "$userlist" ]; then
297107543Sscottl	if [ $fflag ]; then
298107543Sscottl		err "($ffile) does not exist or does not contain any user names."
299107543Sscottl		exit 1
300107543Sscottl	elif [ $yflag ]; then
301107543Sscottl		show_usage
302107543Sscottl		exit 1
303107543Sscottl	else
304146556Sadamw		echo -n "Please enter one or more usernames: "
305107543Sscottl		read userlist
306107543Sscottl	fi
307107543Sscottlfi
308107543Sscottl
309107543Sscottl_user=
310107543Sscottl_uid=
311107543Sscottlfor _user in $userlist ; do
312107543Sscottl	# Make sure the name exists in the passwd database and that it
313107543Sscottl	# does not have a uid of 0
314107543Sscottl	#
315107543Sscottl	userrec=`pw 2>/dev/null usershow -n $_user`
316107543Sscottl	if [ "$?" != "0" ]; then
317107543Sscottl		err "user ($_user) does not exist in the password database."
318107543Sscottl		continue
319107543Sscottl	fi
320107543Sscottl	_uid=`echo $userrec | awk -F: '{print $3}'`
321107543Sscottl	if [ "$_uid" = "0" ]; then
322107543Sscottl		err "user ($_user) has uid 0. You may not remove this user."
323107543Sscottl		continue
324107543Sscottl	fi
325107543Sscottl
326107543Sscottl	# If the -y switch was not used ask for confirmation to remove the
327107543Sscottl	# user and home directory.
328107543Sscottl	#
329107543Sscottl	if [ -z "$yflag" ]; then
330107543Sscottl		echo "Matching password entry:"
331107543Sscottl		echo
332107543Sscottl		echo $userrec
333107543Sscottl		echo
334107543Sscottl		if ! prompt_yesno "Is this the entry you wish to remove? " ; then
335107543Sscottl			continue
336107543Sscottl		fi
337107543Sscottl		_homedir=`echo $userrec | awk -F: '{print $9}'`
338109750Sfjoe		if prompt_yesno "Remove user's home directory ($_homedir)? "; then
339107543Sscottl			pw_rswitch="-r"
340107543Sscottl		fi
341107543Sscottl	else
342107543Sscottl		pw_rswitch="-r"
343107543Sscottl	fi
344107543Sscottl
345107543Sscottl	# Disable any further attempts to log into this account
346107543Sscottl	pw 2>/dev/null lock $_user
347107543Sscottl
348107543Sscottl	# Remove crontab, mail spool, etc. Then obliterate the user from
349107543Sscottl	# the passwd and group database.
350111013Smtm	#
351111013Smtm	! verbose && echo -n "Removing user ($_user):"
352107543Sscottl	rm_crontab $_user
353107543Sscottl	rm_at_jobs $_user
354126398Sschweikh	rm_ipc $_user
355107543Sscottl	kill_procs $_user
356111013Smtm	rm_files $_user
357107543Sscottl	rm_mail $_user
358107543Sscottl	rm_user $_user
359111013Smtm	! verbose && echo "."
360107543Sscottldone
361