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