rmuser.sh revision 109752
1107543Sscottl#!/bin/sh
2107543Sscottl#
3107543Sscottl# Copyright (c) 2002 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# 3. The name of the author may not be used to endorse or promote products
14107543Sscottl#    derived from this software without specific prior written permission.
15107543Sscottl#
16107543Sscottl# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17107543Sscottl# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18107543Sscottl# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19107543Sscottl# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20107543Sscottl# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21107543Sscottl# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22107543Sscottl# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23107543Sscottl# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24107543Sscottl# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25107543Sscottl# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26107543Sscottl#
27107543Sscottl#	Email: Mike Makonnen <mtm@identd.net>
28107543Sscottl#
29107543Sscottl# $FreeBSD: head/usr.sbin/adduser/rmuser.sh 109752 2003-01-23 20:18:21Z fjoe $
30107543Sscottl#
31107543Sscottl
32107543SscottlATJOBDIR="/var/at/jobs"
33107543SscottlCRONJOBDIR="/var/cron/tabs"
34107543SscottlMAILSPOOL="/var/mail"
35107543SscottlSIGKILL="-KILL"
36107694StjrTEMPDIRS="/tmp /var/tmp"
37107543SscottlTHISCMD=`/usr/bin/basename $0`
38107543Sscottl
39107543Sscottl# err msg
40107543Sscottl#	Display $msg on stderr.
41107543Sscottl#
42107543Sscottlerr() {
43107543Sscottl	echo 1>&2 ${THISCMD}: $*
44107543Sscottl}
45107543Sscottl
46107543Sscottl# rm_files login
47107543Sscottl#	Removes files or empty directories belonging to $login from various
48107543Sscottl#	temporary directories.
49107543Sscottl#
50107543Sscottlrm_files() {
51107543Sscottl	# The argument is required
52107543Sscottl	[ -n $1 ] && login=$1 || return
53107543Sscottl	
54107543Sscottl	for _dir in ${TEMPDIRS} ; do
55107543Sscottl		if [ ! -d $_dir ]; then
56107543Sscottl			err "$_dir is not a valid directory."
57107543Sscottl			continue
58107543Sscottl		fi
59107543Sscottl		echo -n "Removing files owned by ($login) in $_dir:"
60107694Stjr		filecount=`find 2>/dev/null "$_dir" -user "$login" -delete -print | \
61107694Stjr		    wc -l | sed 's/ *//'`
62107543Sscottl		echo " $filecount removed."
63107543Sscottl	done
64107543Sscottl}
65107543Sscottl
66107543Sscottl# rm_mail login
67107543Sscottl#	Removes unix mail and pop daemon files belonging to the user
68107543Sscottl#	specified in the $login argument.
69107543Sscottl#
70107543Sscottlrm_mail() {
71107543Sscottl	# The argument is required
72107543Sscottl	[ -n $1 ] && login=$1 || return
73107543Sscottl
74107543Sscottl	echo -n "Removing mail spool(s) for ($login):"
75107543Sscottl	if [ -f ${MAILSPOOL}/$login ]; then
76107543Sscottl		echo -n " ${MAILSPOOL}/$login"
77107543Sscottl		rm ${MAILSPOOL}/$login
78107543Sscottl	fi
79107543Sscottl	if [ -f ${MAILSPOOL}/${login}.pop ]; then
80107543Sscottl		echo -n " ${MAILSPOOL}/${login}.pop"
81107543Sscottl		rm ${MAILSPOOL}/${login}.pop
82107543Sscottl	fi
83107543Sscottl	echo '.'
84107543Sscottl}
85107543Sscottl
86107543Sscottl# kill_procs login
87107543Sscottl#	Send a SIGKILL to all processes owned by $login.
88107543Sscottl#
89107543Sscottlkill_procs() {
90107543Sscottl	# The argument is required
91107543Sscottl	[ -n $1 ] && login=$1 || return
92107543Sscottl
93107543Sscottl	echo -n "Terminating all processes owned by ($login):"
94107543Sscottl	killcount=0
95107543Sscottl	proclist=`ps 2>/dev/null -U $login | grep -v '^\ *PID' | awk '{print $1}'`
96107543Sscottl	for _pid in $proclist ; do
97107543Sscottl		kill 2>/dev/null ${SIGKILL} $_pid
98109752Sfjoe		killcount=$(($killcount + 1))
99107543Sscottl	done
100107543Sscottl	echo " ${SIGKILL} signal sent to $killcount processes."
101107543Sscottl}
102107543Sscottl
103107543Sscottl# rm_at_jobs login
104107543Sscottl#	Remove at (1) jobs belonging to $login.
105107543Sscottl#
106107543Sscottlrm_at_jobs() {
107107543Sscottl	# The argument is required
108107543Sscottl	[ -n $1 ] && login=$1 || return
109107543Sscottl
110107543Sscottl	atjoblist=`find 2>/dev/null ${ATJOBDIR} -maxdepth 1 -user $login -print`
111107543Sscottl	jobcount=0
112107543Sscottl	echo -n "Removing at(1) jobs owned by ($login):"
113107543Sscottl	for _atjob in $atjoblist ; do
114107543Sscottl		rm -f $_atjob
115109752Sfjoe		jobcount=$(($jobcount + 1))
116107543Sscottl	done
117107543Sscottl	echo " $jobcount removed."
118107543Sscottl}
119107543Sscottl
120107543Sscottl# rm_crontab login
121107543Sscottl#	Removes crontab file belonging to user $login.
122107543Sscottl#
123107543Sscottlrm_crontab() {
124107543Sscottl	# The argument is required
125107543Sscottl	[ -n $1 ] && login=$1 || return
126107543Sscottl
127107543Sscottl	echo -n "Removing crontab for ($login):"
128107543Sscottl	if [ -f ${CRONJOBDIR}/$login ]; then
129107543Sscottl		echo -n " ${CRONJOBDIR}/$login"
130107543Sscottl		rm -f ${CRONJOBDIR}/$login
131107543Sscottl	fi
132107543Sscottl	echo '.'
133107543Sscottl}
134107543Sscottl
135107543Sscottl# rm_user login
136107543Sscottl#	Remove user $login from the system. This subroutine makes use
137107543Sscottl#	of the pw(8) command to remove a user from the system. The pw(8)
138107543Sscottl#	command will remove the specified user from the user database
139107543Sscottl#	and group file and remove any crontabs. His home
140107543Sscottl#	directory will be removed if it is owned by him and contains no 
141107543Sscottl#	files or subdirectories owned by other users. Mail spool files will
142107543Sscottl#	also be removed.
143107543Sscottl#
144107543Sscottlrm_user() {
145107543Sscottl	# The argument is required
146107543Sscottl	[ -n $1 ] && login=$1 || return
147107543Sscottl
148107543Sscottl	echo -n "Removing user ($login)"
149107543Sscottl	[ -n "$pw_rswitch" ] && echo -n " (including home directory)"
150107543Sscottl	echo -n " from the system:"
151107543Sscottl	pw userdel -n $login $pw_rswitch
152107543Sscottl	echo ' Done.'
153107543Sscottl}
154107543Sscottl
155107543Sscottl# prompt_yesno msg
156107543Sscottl#	Prompts the user with a $msg. The answer is expected to be
157107543Sscottl#	yes, no, or some variation thereof. This subroutine returns 0
158107543Sscottl#	if the answer was yes, 1 if it was not.
159107543Sscottl#
160107543Sscottlprompt_yesno() {
161107543Sscottl	# The argument is required
162109750Sfjoe	[ -n "$1" ] && msg="$1" || return
163107543Sscottl
164107543Sscottl        while : ; do
165109750Sfjoe                echo -n "$msg"
166107543Sscottl                read _ans
167107543Sscottl                case $_ans in
168107543Sscottl                [Nn][Oo]|[Nn])
169107543Sscottl			return 1
170107543Sscottl                        ;;
171107543Sscottl                [Yy][Ee][Ss]|[Yy][Ee]|[Yy])
172107543Sscottl                        return 0
173107543Sscottl                        ;;
174107543Sscottl                *)
175107543Sscottl                        ;;
176107543Sscottl                esac
177107543Sscottl	done
178107543Sscottl}
179107543Sscottl
180107543Sscottl# show_usage
181107543Sscottl#	(no arguments)
182107543Sscottl#	Display usage message.
183107543Sscottl#
184107543Sscottlshow_usage() {
185107543Sscottl	echo "usage: ${THISCMD} [-y] [-f file] [user ...]"
186107543Sscottl	echo "       if the -y switch is used, either the -f switch or"
187107543Sscottl	echo "       one or more user names must be given"
188107543Sscottl}
189107543Sscottl
190107543Sscottl#### END SUBROUTINE DEFENITION ####
191107543Sscottl
192107543Sscottlffile=
193107543Sscottlfflag=
194107543Sscottlprocowner=
195107543Sscottlpw_rswitch=
196107543Sscottluserlist=
197107543Sscottlyflag=
198107543Sscottl
199107543Sscottlprocowner=`/usr/bin/id -u`
200107543Sscottlif [ "$procowner" != "0" ]; then
201107543Sscottl	err 'you must be root (0) to use this utility.'
202107543Sscottl	exit 1
203107543Sscottlfi
204107543Sscottl
205107543Sscottlargs=`getopt 2>/dev/null yf: $*`
206107543Sscottlif [ "$?" != "0" ]; then
207107543Sscottl	show_usage
208107543Sscottl	exit 1
209107543Sscottlfi
210107543Sscottlset -- $args
211107543Sscottlfor _switch ; do
212107543Sscottl	case $_switch in
213107543Sscottl	-y)
214107543Sscottl		yflag=1
215107543Sscottl		shift
216107543Sscottl		;;
217107543Sscottl	-f)
218107543Sscottl		fflag=1
219107543Sscottl		ffile="$2"
220107543Sscottl		shift; shift
221107543Sscottl		;;
222107543Sscottl	--)
223107543Sscottl		shift
224107543Sscottl		break
225107543Sscottl		;;
226107543Sscottl	esac
227107543Sscottldone
228107543Sscottl
229107543Sscottl# Get user names from a file if the -f switch was used. Otherwise,
230107543Sscottl# get them from the commandline arguments. If we're getting it
231107543Sscottl# from a file, the file must be owned by and writable only by root.
232107543Sscottl#
233107543Sscottlif [ $fflag ]; then
234107543Sscottl	_insecure=`find $ffile ! -user 0 -or -perm +0022`
235107543Sscottl	if [ -n "$_insecure" ]; then
236107543Sscottl		err "file ($ffile) must be owned by and writeable only by root."
237107543Sscottl		exit 1
238107543Sscottl	fi
239107543Sscottl	if [ -r "$ffile" ]; then
240107543Sscottl		userlist=`cat $ffile | while read _user _junk ; do
241107543Sscottl			case $_user in
242107543Sscottl			\#*|'')
243107543Sscottl				;;
244107543Sscottl			*)
245107543Sscottl				echo -n "$userlist $_user"
246107543Sscottl				;;
247107543Sscottl			esac
248107543Sscottl		done`
249107543Sscottl	fi
250107543Sscottlelse
251107543Sscottl	while [ $1 ] ; do
252107543Sscottl		userlist="$userlist $1"
253107543Sscottl		shift
254107543Sscottl	done
255107543Sscottlfi
256107543Sscottl
257107543Sscottl# If the -y or -f switch has been used and the list of users to remove
258107543Sscottl# is empty it is a fatal error. Otherwise, prompt the user for a list
259107543Sscottl# of one or more user names.
260107543Sscottl#
261107543Sscottlif [ ! "$userlist" ]; then
262107543Sscottl	if [ $fflag ]; then
263107543Sscottl		err "($ffile) does not exist or does not contain any user names."
264107543Sscottl		exit 1
265107543Sscottl	elif [ $yflag ]; then
266107543Sscottl		show_usage
267107543Sscottl		exit 1
268107543Sscottl	else
269107543Sscottl		echo -n "Please enter one or more user name's: "
270107543Sscottl		read userlist
271107543Sscottl	fi
272107543Sscottlfi
273107543Sscottl
274107543Sscottl_user=
275107543Sscottl_uid=
276107543Sscottlfor _user in $userlist ; do
277107543Sscottl	# Make sure the name exists in the passwd database and that it
278107543Sscottl	# does not have a uid of 0
279107543Sscottl	#
280107543Sscottl	userrec=`pw 2>/dev/null usershow -n $_user`
281107543Sscottl	if [ "$?" != "0" ]; then
282107543Sscottl		err "user ($_user) does not exist in the password database."
283107543Sscottl		continue
284107543Sscottl	fi
285107543Sscottl	_uid=`echo $userrec | awk -F: '{print $3}'`
286107543Sscottl	if [ "$_uid" = "0" ]; then
287107543Sscottl		err "user ($_user) has uid 0. You may not remove this user."
288107543Sscottl		continue
289107543Sscottl	fi
290107543Sscottl
291107543Sscottl	# If the -y switch was not used ask for confirmation to remove the
292107543Sscottl	# user and home directory.
293107543Sscottl	#
294107543Sscottl	if [ -z "$yflag" ]; then
295107543Sscottl		echo "Matching password entry:"
296107543Sscottl		echo
297107543Sscottl		echo $userrec
298107543Sscottl		echo
299107543Sscottl		if ! prompt_yesno "Is this the entry you wish to remove? " ; then
300107543Sscottl			continue
301107543Sscottl		fi
302107543Sscottl		_homedir=`echo $userrec | awk -F: '{print $9}'`
303109750Sfjoe		if prompt_yesno "Remove user's home directory ($_homedir)? "; then
304107543Sscottl			pw_rswitch="-r"
305107543Sscottl		fi
306107543Sscottl	else
307107543Sscottl		pw_rswitch="-r"
308107543Sscottl	fi
309107543Sscottl
310107543Sscottl	# Disable any further attempts to log into this account
311107543Sscottl	pw 2>/dev/null lock $_user
312107543Sscottl
313107543Sscottl	# Remove crontab, mail spool, etc. Then obliterate the user from
314107543Sscottl	# the passwd and group database.
315107543Sscottl	rm_crontab $_user
316107543Sscottl	rm_at_jobs $_user
317107543Sscottl	kill_procs $_user
318107543Sscottl	rm_mail $_user
319107543Sscottl	rm_files $_user
320107543Sscottl	rm_user $_user
321107543Sscottldone
322