1#!/bin/sh 2# 3# Copyright (c) 2002 Michael Telahun Makonnen. All rights reserved. 4# 5# Redistribution and use in source and binary forms, with or without 6# modification, are permitted provided that the following conditions 7# are met: 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. 13# 3. The name of the author may not be used to endorse or promote products 14# derived from this software without specific prior written permission. 15# 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. 26# 27# Email: Mike Makonnen <mtm@identd.net> 28# 29# $FreeBSD$ 30# 31 32ATJOBDIR="/var/at/jobs" 33CRONJOBDIR="/var/cron/tabs" 34MAILSPOOL="/var/mail" 35SIGKILL="-KILL" 36TEMPDIRS="/tmp /var/tmp" 37THISCMD=`/usr/bin/basename $0` 38 39# err msg 40# Display $msg on stderr. 41# 42err() { 43 echo 1>&2 ${THISCMD}: $* 44} 45 46# rm_files login 47# Removes files or empty directories belonging to $login from various 48# temporary directories. 49# 50rm_files() { 51 # The argument is required 52 [ -n $1 ] && login=$1 || return 53 54 for _dir in ${TEMPDIRS} ; do 55 if [ ! -d $_dir ]; then 56 err "$_dir is not a valid directory." 57 continue 58 fi 59 echo -n "Removing files owned by ($login) in $_dir:" 60 filecount=`find 2>/dev/null "$_dir" -user "$login" -delete -print | \ 61 wc -l | sed 's/ *//'` 62 echo " $filecount removed." 63 done 64} 65 66# rm_mail login 67# Removes unix mail and pop daemon files belonging to the user 68# specified in the $login argument. 69# 70rm_mail() { 71 # The argument is required 72 [ -n $1 ] && login=$1 || return 73 74 echo -n "Removing mail spool(s) for ($login):" 75 if [ -f ${MAILSPOOL}/$login ]; then 76 echo -n " ${MAILSPOOL}/$login" 77 rm ${MAILSPOOL}/$login 78 fi 79 if [ -f ${MAILSPOOL}/${login}.pop ]; then 80 echo -n " ${MAILSPOOL}/${login}.pop" 81 rm ${MAILSPOOL}/${login}.pop 82 fi 83 echo '.' 84} 85 86# kill_procs login 87# Send a SIGKILL to all processes owned by $login. 88# 89kill_procs() { 90 # The argument is required 91 [ -n $1 ] && login=$1 || return 92 93 echo -n "Terminating all processes owned by ($login):" 94 killcount=0 95 proclist=`ps 2>/dev/null -U $login | grep -v '^\ *PID' | awk '{print $1}'` 96 for _pid in $proclist ; do 97 kill 2>/dev/null ${SIGKILL} $_pid 98 killcount=`expr $killcount + 1` 99 done 100 echo " ${SIGKILL} signal sent to $killcount processes." 101} 102 103# rm_at_jobs login 104# Remove at (1) jobs belonging to $login. 105# 106rm_at_jobs() { 107 # The argument is required 108 [ -n $1 ] && login=$1 || return 109 110 atjoblist=`find 2>/dev/null ${ATJOBDIR} -maxdepth 1 -user $login -print` 111 jobcount=0 112 echo -n "Removing at(1) jobs owned by ($login):" 113 for _atjob in $atjoblist ; do 114 rm -f $_atjob 115 jobcount=`expr $jobcount + 1` 116 done 117 echo " $jobcount removed." 118} 119 120# rm_crontab login 121# Removes crontab file belonging to user $login. 122# 123rm_crontab() { 124 # The argument is required 125 [ -n $1 ] && login=$1 || return 126 127 echo -n "Removing crontab for ($login):" 128 if [ -f ${CRONJOBDIR}/$login ]; then 129 echo -n " ${CRONJOBDIR}/$login" 130 rm -f ${CRONJOBDIR}/$login 131 fi 132 echo '.' 133} 134 135# rm_user login 136# Remove user $login from the system. This subroutine makes use 137# of the pw(8) command to remove a user from the system. The pw(8) 138# command will remove the specified user from the user database 139# and group file and remove any crontabs. His home 140# directory will be removed if it is owned by him and contains no 141# files or subdirectories owned by other users. Mail spool files will 142# also be removed. 143# 144rm_user() { 145 # The argument is required 146 [ -n $1 ] && login=$1 || return 147 148 echo -n "Removing user ($login)" 149 [ -n "$pw_rswitch" ] && echo -n " (including home directory)" 150 echo -n " from the system:" 151 pw userdel -n $login $pw_rswitch 152 echo ' Done.' 153} 154 155# prompt_yesno msg 156# Prompts the user with a $msg. The answer is expected to be 157# yes, no, or some variation thereof. This subroutine returns 0 158# if the answer was yes, 1 if it was not. 159# 160prompt_yesno() { 161 # The argument is required 162 [ -n "$1" ] && msg="$1" || return 163 164 while : ; do 165 echo -n "$msg" 166 read _ans 167 case $_ans in 168 [Nn][Oo]|[Nn]) 169 return 1 170 ;; 171 [Yy][Ee][Ss]|[Yy][Ee]|[Yy]) 172 return 0 173 ;; 174 *) 175 ;; 176 esac 177 done 178} 179 180# show_usage 181# (no arguments) 182# Display usage message. 183# 184show_usage() { 185 echo "usage: ${THISCMD} [-y] [-f file] [user ...]" 186 echo " if the -y switch is used, either the -f switch or" 187 echo " one or more user names must be given" 188} 189 190#### END SUBROUTINE DEFENITION #### 191 192ffile= 193fflag= 194procowner= 195pw_rswitch= 196userlist= 197yflag= 198 199procowner=`/usr/bin/id -u` 200if [ "$procowner" != "0" ]; then 201 err 'you must be root (0) to use this utility.' 202 exit 1 203fi 204 205args=`getopt 2>/dev/null yf: $*` 206if [ "$?" != "0" ]; then 207 show_usage 208 exit 1 209fi 210set -- $args 211for _switch ; do 212 case $_switch in 213 -y) 214 yflag=1 215 shift 216 ;; 217 -f) 218 fflag=1 219 ffile="$2" 220 shift; shift 221 ;; 222 --) 223 shift 224 break 225 ;; 226 esac 227done 228 229# Get user names from a file if the -f switch was used. Otherwise, 230# get them from the commandline arguments. If we're getting it 231# from a file, the file must be owned by and writable only by root. 232# 233if [ $fflag ]; then 234 _insecure=`find $ffile ! -user 0 -or -perm +0022` 235 if [ -n "$_insecure" ]; then 236 err "file ($ffile) must be owned by and writeable only by root." 237 exit 1 238 fi 239 if [ -r "$ffile" ]; then 240 userlist=`cat $ffile | while read _user _junk ; do 241 case $_user in 242 \#*|'') 243 ;; 244 *) 245 echo -n "$userlist $_user" 246 ;; 247 esac 248 done` 249 fi 250else 251 while [ $1 ] ; do 252 userlist="$userlist $1" 253 shift 254 done 255fi 256 257# If the -y or -f switch has been used and the list of users to remove 258# is empty it is a fatal error. Otherwise, prompt the user for a list 259# of one or more user names. 260# 261if [ ! "$userlist" ]; then 262 if [ $fflag ]; then 263 err "($ffile) does not exist or does not contain any user names." 264 exit 1 265 elif [ $yflag ]; then 266 show_usage 267 exit 1 268 else 269 echo -n "Please enter one or more user name's: " 270 read userlist 271 fi 272fi 273 274_user= 275_uid= 276for _user in $userlist ; do 277 # Make sure the name exists in the passwd database and that it 278 # does not have a uid of 0 279 # 280 userrec=`pw 2>/dev/null usershow -n $_user` 281 if [ "$?" != "0" ]; then 282 err "user ($_user) does not exist in the password database." 283 continue 284 fi 285 _uid=`echo $userrec | awk -F: '{print $3}'` 286 if [ "$_uid" = "0" ]; then 287 err "user ($_user) has uid 0. You may not remove this user." 288 continue 289 fi 290 291 # If the -y switch was not used ask for confirmation to remove the 292 # user and home directory. 293 # 294 if [ -z "$yflag" ]; then 295 echo "Matching password entry:" 296 echo 297 echo $userrec 298 echo 299 if ! prompt_yesno "Is this the entry you wish to remove? " ; then 300 continue 301 fi 302 _homedir=`echo $userrec | awk -F: '{print $9}'` 303 if prompt_yesno "Remove user's home directory ($_homedir)? "; then 304 pw_rswitch="-r" 305 fi 306 else 307 pw_rswitch="-r" 308 fi 309 310 # Disable any further attempts to log into this account 311 pw 2>/dev/null lock $_user 312 313 # Remove crontab, mail spool, etc. Then obliterate the user from 314 # the passwd and group database. 315 rm_crontab $_user 316 rm_at_jobs $_user 317 kill_procs $_user 318 rm_mail $_user 319 rm_files $_user 320 rm_user $_user 321done 322