3 # Copyright (c) 2002, 2003 Michael Telahun Makonnen. All rights reserved.
5 # Redistribution and use in source and binary forms, with or without
6 # modification, are permitted provided that the following conditions
8 # 1. Redistributions of source code must retain the above copyright
9 # notice, this list of conditions and the following disclaimer.
10 # 2. Redistributions in binary form must reproduce the above copyright
11 # notice, this list of conditions and the following disclaimer in the
12 # documentation and/or other materials provided with the distribution.
14 # THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
15 # IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16 # OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17 # IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
18 # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
19 # NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20 # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23 # THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 # Email: Mike Makonnen <mtm@FreeBSD.Org>
30 ATJOBDIR
="/var/at/jobs"
31 CRONJOBDIR
="/var/cron/tabs"
34 TEMPDIRS
="/tmp /var/tmp"
35 THISCMD
=`/usr/bin/basename $0`
36 PWCMD
="${PWCMD:-/usr/sbin/pw}"
39 # Display $msg on stderr.
42 echo 1>&2 ${THISCMD}: $
*
46 # Returns 0 if verbose mode is set, 1 if it is not.
49 [ -n "$vflag" ] && return 0 ||
return 1
53 # Removes files or empty directories belonging to $login from various
54 # temporary directories.
57 # The argument is required
58 [ -n $1 ] && login
=$1 ||
return
61 for _dir
in ${TEMPDIRS} ; do
63 if [ ! -d $_dir ]; then
64 err
"$_dir is not a valid directory."
67 verbose
&& echo -n "Removing files owned by ($login) in $_dir:"
68 filecount
=`find 2>/dev/null "$_dir" -user "$login" -delete -print |
70 verbose
&& echo " $filecount removed."
71 totalcount
=$
(($totalcount + $filecount))
73 ! verbose
&& [ $totalcount -ne 0 ] && echo -n " files($totalcount)"
77 # Removes unix mail and pop daemon files belonging to the user
78 # specified in the $login argument.
81 # The argument is required
82 [ -n $1 ] && login
=$1 ||
return
84 verbose
&& echo -n "Removing mail spool(s) for ($login):"
85 if [ -f ${MAILSPOOL}/$login ]; then
86 verbose
&& echo -n " ${MAILSPOOL}/$login" ||
88 rm ${MAILSPOOL}/$login
90 if [ -f ${MAILSPOOL}/.
${login}.pop
]; then
91 verbose
&& echo -n " ${MAILSPOOL}/.${login}.pop" ||
93 rm ${MAILSPOOL}/.
${login}.pop
99 # Send a SIGKILL to all processes owned by $login.
102 # The argument is required
103 [ -n $1 ] && login
=$1 ||
return
105 verbose
&& echo -n "Terminating all processes owned by ($login):"
107 proclist
=`ps 2>/dev/null -U $login | grep -v '^\ *PID' | awk '{print $1}'`
108 for _pid
in $proclist ; do
109 kill 2>/dev
/null
${SIGKILL} $_pid
110 killcount
=$
(($killcount + 1))
112 verbose
&& echo " ${SIGKILL} signal sent to $killcount processes."
113 ! verbose
&& [ $killcount -ne 0 ] && echo -n " processes(${killcount})"
117 # Remove at (1) jobs belonging to $login.
120 # The argument is required
121 [ -n $1 ] && login
=$1 ||
return
123 atjoblist
=`find 2>/dev/null ${ATJOBDIR} -maxdepth 1 -user $login -print`
125 verbose
&& echo -n "Removing at(1) jobs owned by ($login):"
126 for _atjob
in $atjoblist ; do
128 jobcount
=$
(($jobcount + 1))
130 verbose
&& echo " $jobcount removed."
131 ! verbose
&& [ $jobcount -ne 0 ] && echo -n " at($jobcount)"
135 # Removes crontab file belonging to user $login.
138 # The argument is required
139 [ -n $1 ] && login
=$1 ||
return
141 verbose
&& echo -n "Removing crontab for ($login):"
142 if [ -f ${CRONJOBDIR}/$login ]; then
143 verbose
&& echo -n " ${CRONJOBDIR}/$login" ||
echo -n " crontab"
144 rm -f ${CRONJOBDIR}/$login
150 # Remove all IPC mechanisms which are owned by $login.
153 verbose
&& echo -n "Removing IPC mechanisms"
156 awk -v i
=$i -v login
=$1 '$1 == i && $5 == login { print $2 }' |
163 # Remove user $login from the system. This subroutine makes use
164 # of the pw(8) command to remove a user from the system. The pw(8)
165 # command will remove the specified user from the user database
166 # and group file and remove any crontabs. His home
167 # directory will be removed if it is owned by him and contains no
168 # files or subdirectories owned by other users. Mail spool files will
172 # The argument is required
173 [ -n $1 ] && login
=$1 ||
return
175 verbose
&& echo -n "Removing user ($login)"
176 [ -n "$pw_rswitch" ] && {
177 verbose
&& echo -n " (including home directory)"
178 ! verbose
&& echo -n " home"
180 ! verbose
&& echo -n " passwd"
181 verbose
&& echo -n " from the system:"
182 ${PWCMD} userdel
-n $login $pw_rswitch
183 verbose
&& echo ' Done.'
187 # Prompts the user with a $msg. The answer is expected to be
188 # yes, no, or some variation thereof. This subroutine returns 0
189 # if the answer was yes, 1 if it was not.
192 # The argument is required
193 [ -n "$1" ] && msg
="$1" ||
return
202 [Yy
][Ee
][Ss
]|
[Yy
][Ee
]|
[Yy
])
213 # Display usage message.
216 echo "usage: ${THISCMD} [-yv] [-f file] [user ...]"
217 echo " if the -y switch is used, either the -f switch or"
218 echo " one or more user names must be given"
221 #### END SUBROUTINE DEFENITION ####
231 procowner
=`/usr/bin/id -u`
232 if [ "$procowner" != "0" ]; then
233 err
'you must be root (0) to use this utility.'
237 args
=`getopt 2>/dev/null yvf: $*`
238 if [ "$?" != "0" ]; then
265 # Get user names from a file if the -f switch was used. Otherwise,
266 # get them from the commandline arguments. If we're getting it
267 # from a file, the file must be owned by and writable only by root.
270 _insecure
=`find $ffile ! -user 0 -or -perm +0022`
271 if [ -n "$_insecure" ]; then
272 err
"file ($ffile) must be owned by and writeable only by root."
275 if [ -r "$ffile" ]; then
276 userlist
=`cat $ffile | while read _user _junk ; do
281 echo -n "$userlist $_user"
288 userlist
="$userlist $1"
293 # If the -y or -f switch has been used and the list of users to remove
294 # is empty it is a fatal error. Otherwise, prompt the user for a list
295 # of one or more user names.
297 if [ ! "$userlist" ]; then
299 err
"($ffile) does not exist or does not contain any user names."
301 elif [ $yflag ]; then
305 echo -n "Please enter one or more usernames: "
312 for _user
in $userlist ; do
313 # Make sure the name exists in the passwd database and that it
314 # does not have a uid of 0
316 userrec
=`pw 2>/dev/null usershow -n $_user`
317 if [ "$?" != "0" ]; then
318 err
"user ($_user) does not exist in the password database."
321 _uid
=`echo $userrec | awk -F: '{print $3}'`
322 if [ "$_uid" = "0" ]; then
323 err
"user ($_user) has uid 0. You may not remove this user."
327 # If the -y switch was not used ask for confirmation to remove the
328 # user and home directory.
330 if [ -z "$yflag" ]; then
331 echo "Matching password entry:"
335 if ! prompt_yesno
"Is this the entry you wish to remove? " ; then
338 _homedir
=`echo $userrec | awk -F: '{print $9}'`
339 if prompt_yesno
"Remove user's home directory ($_homedir)? "; then
346 # Disable any further attempts to log into this account
347 ${PWCMD} 2>/dev
/null lock
$_user
349 # Remove crontab, mail spool, etc. Then obliterate the user from
350 # the passwd and group database.
352 ! verbose
&& echo -n "Removing user ($_user):"
360 ! verbose
&& echo "."