3 # SPDX-License-Identifier: BSD-2-Clause
5 # Copyright (c) 2002, 2003 Michael Telahun Makonnen. All rights reserved.
7 # Redistribution and use in source and binary forms, with or without
8 # modification, are permitted provided that the following conditions
10 # 1. Redistributions of source code must retain the above copyright
11 # notice, this list of conditions and the following disclaimer.
12 # 2. Redistributions in binary form must reproduce the above copyright
13 # notice, this list of conditions and the following disclaimer in the
14 # documentation and/or other materials provided with the distribution.
16 # THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 # IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 # OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 # IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20 # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21 # NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25 # THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 # Email: Mike Makonnen <mtm@FreeBSD.Org>
31 ATJOBDIR="/var/at/jobs"
32 CRONJOBDIR="/var/cron/tabs"
35 TEMPDIRS="/tmp /var/tmp"
36 THISCMD=`/usr/bin/basename $0`
37 PWCMD="${PWCMD:-/usr/sbin/pw}"
40 # Display $msg on stderr.
43 echo 1>&2 ${THISCMD}: $*
47 # Returns 0 if verbose mode is set, 1 if it is not.
50 [ -n "$vflag" ] && return 0 || return 1
54 # Removes files or empty directories belonging to $login from various
55 # temporary directories.
58 # The argument is required
59 [ -n $1 ] && login=$1 || return
62 for _dir in ${TEMPDIRS} ; do
64 if [ ! -d $_dir ]; then
65 err "$_dir is not a valid directory."
68 verbose && echo -n "Removing files owned by ($login) in $_dir:"
69 filecount=`find 2>/dev/null "$_dir" -user "$login" -delete -print |
71 verbose && echo " $filecount removed."
72 totalcount=$(($totalcount + $filecount))
74 ! verbose && [ $totalcount -ne 0 ] && echo -n " files($totalcount)"
78 # Removes unix mail and pop daemon files belonging to the user
79 # specified in the $login argument.
82 # The argument is required
83 [ -n $1 ] && login=$1 || return
85 verbose && echo -n "Removing mail spool(s) for ($login):"
86 if [ -f ${MAILSPOOL}/$login ]; then
87 verbose && echo -n " ${MAILSPOOL}/$login" ||
89 rm ${MAILSPOOL}/$login
91 if [ -f ${MAILSPOOL}/.${login}.pop ]; then
92 verbose && echo -n " ${MAILSPOOL}/.${login}.pop" ||
94 rm ${MAILSPOOL}/.${login}.pop
100 # Send a SIGKILL to all processes owned by $login.
103 # The argument is required
104 [ -n $1 ] && login=$1 || return
106 verbose && echo -n "Terminating all processes owned by ($login):"
108 proclist=`ps 2>/dev/null -U $login | grep -v '^\ *PID' | awk '{print $1}'`
109 for _pid in $proclist ; do
110 kill 2>/dev/null ${SIGKILL} $_pid
111 killcount=$(($killcount + 1))
113 verbose && echo " ${SIGKILL} signal sent to $killcount processes."
114 ! verbose && [ $killcount -ne 0 ] && echo -n " processes(${killcount})"
118 # Remove at (1) jobs belonging to $login.
121 # The argument is required
122 [ -n $1 ] && login=$1 || return
124 atjoblist=`find 2>/dev/null ${ATJOBDIR} -maxdepth 1 -user $login -print`
126 verbose && echo -n "Removing at(1) jobs owned by ($login):"
127 for _atjob in $atjoblist ; do
129 jobcount=$(($jobcount + 1))
131 verbose && echo " $jobcount removed."
132 ! verbose && [ $jobcount -ne 0 ] && echo -n " at($jobcount)"
136 # Removes crontab file belonging to user $login.
139 # The argument is required
140 [ -n $1 ] && login=$1 || return
142 verbose && echo -n "Removing crontab for ($login):"
143 if [ -f ${CRONJOBDIR}/$login ]; then
144 verbose && echo -n " ${CRONJOBDIR}/$login" || echo -n " crontab"
145 rm -f ${CRONJOBDIR}/$login
151 # Remove all IPC mechanisms which are owned by $login.
154 verbose && echo -n "Removing IPC mechanisms"
157 awk -v i=$i -v login=$1 '$1 == i && $5 == login { print $2 }' |
164 # Remove user $login from the system. This subroutine makes use
165 # of the pw(8) command to remove a user from the system. The pw(8)
166 # command will remove the specified user from the user database
167 # and group file and remove any crontabs. His home
168 # directory will be removed if it is owned by him and contains no
169 # files or subdirectories owned by other users. Mail spool files will
173 # The argument is required
174 [ -n $1 ] && login=$1 || return
176 verbose && echo -n "Removing user ($login)"
177 [ -n "$pw_rswitch" ] && {
178 verbose && echo -n " (including home directory)"
179 ! verbose && echo -n " home"
181 ! verbose && echo -n " passwd"
182 verbose && echo -n " from the system:"
183 ${PWCMD} userdel -n $login $pw_rswitch
184 verbose && echo ' Done.'
188 # Prompts the user with a $msg. The answer is expected to be
189 # yes, no, or some variation thereof. This subroutine returns 0
190 # if the answer was yes, 1 if it was not.
193 # The argument is required
194 [ -n "$1" ] && msg="$1" || return
203 [Yy][Ee][Ss]|[Yy][Ee]|[Yy])
214 # Display usage message.
217 echo "usage: ${THISCMD} [-yv] [-f file] [user ...]"
218 echo " if the -y switch is used, either the -f switch or"
219 echo " one or more user names must be given"
222 #### END SUBROUTINE DEFENITION ####
232 procowner=`/usr/bin/id -u`
233 if [ "$procowner" != "0" ]; then
234 err 'you must be root (0) to use this utility.'
238 args=`getopt 2>/dev/null yvf: $*`
239 if [ "$?" != "0" ]; then
266 # Get user names from a file if the -f switch was used. Otherwise,
267 # get them from the commandline arguments. If we're getting it
268 # from a file, the file must be owned by and writable only by root.
271 _insecure=`find $ffile ! -user 0 -or -perm +0022`
272 if [ -n "$_insecure" ]; then
273 err "file ($ffile) must be owned by and writeable only by root."
276 if [ -r "$ffile" ]; then
277 userlist=`cat $ffile | while read _user _junk ; do
282 echo -n "$userlist $_user"
289 userlist="$userlist $1"
294 # If the -y or -f switch has been used and the list of users to remove
295 # is empty it is a fatal error. Otherwise, prompt the user for a list
296 # of one or more user names.
298 if [ ! "$userlist" ]; then
300 err "($ffile) does not exist or does not contain any user names."
302 elif [ $yflag ]; then
306 echo -n "Please enter one or more usernames: "
313 for _user in $userlist ; do
314 # Make sure the name exists in the passwd database and that it
315 # does not have a uid of 0
317 userrec=`pw 2>/dev/null usershow -n $_user`
318 if [ "$?" != "0" ]; then
319 err "user ($_user) does not exist in the password database."
322 _uid=`echo $userrec | awk -F: '{print $3}'`
323 if [ "$_uid" = "0" ]; then
324 err "user ($_user) has uid 0. You may not remove this user."
328 # If the -y switch was not used ask for confirmation to remove the
329 # user and home directory.
331 if [ -z "$yflag" ]; then
332 echo "Matching password entry:"
336 if ! prompt_yesno "Is this the entry you wish to remove? " ; then
339 _homedir=`echo $userrec | awk -F: '{print $9}'`
340 if prompt_yesno "Remove user's home directory ($_homedir)? "; then
347 # Disable any further attempts to log into this account
348 ${PWCMD} 2>/dev/null lock $_user
350 # Remove crontab, mail spool, etc. Then obliterate the user from
351 # the passwd and group database.
353 ! verbose && echo -n "Removing user ($_user):"
361 ! verbose && echo "."