rmuser.sh revision 111015
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# 25107543Sscottl# Email: Mike Makonnen <mtm@identd.net> 26107543Sscottl# 27107543Sscottl# $FreeBSD: head/usr.sbin/adduser/rmuser.sh 111015 2003-02-16 18:06:04Z mtm $ 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 58107543Sscottl 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:" 67107694Stjr 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 85111013Smtm verbose && echo -n " ${MAILSPOOL}/$login" || \ 86111013Smtm echo -n " mailspool" 87107543Sscottl rm ${MAILSPOOL}/$login 88107543Sscottl fi 89107543Sscottl if [ -f ${MAILSPOOL}/${login}.pop ]; then 90111013Smtm 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 148107543Sscottl# rm_user login 149107543Sscottl# Remove user $login from the system. This subroutine makes use 150107543Sscottl# of the pw(8) command to remove a user from the system. The pw(8) 151107543Sscottl# command will remove the specified user from the user database 152107543Sscottl# and group file and remove any crontabs. His home 153107543Sscottl# directory will be removed if it is owned by him and contains no 154107543Sscottl# files or subdirectories owned by other users. Mail spool files will 155107543Sscottl# also be removed. 156107543Sscottl# 157107543Sscottlrm_user() { 158107543Sscottl # The argument is required 159107543Sscottl [ -n $1 ] && login=$1 || return 160107543Sscottl 161111013Smtm verbose && echo -n "Removing user ($login)" 162111013Smtm [ -n "$pw_rswitch" ] && { 163111013Smtm verbose && echo -n " (including home directory)" 164111013Smtm ! verbose && echo -n " home" 165111013Smtm } 166111013Smtm ! verbose && echo -n " passwd" 167111013Smtm verbose && echo -n " from the system:" 168107543Sscottl pw userdel -n $login $pw_rswitch 169111013Smtm verbose && echo ' Done.' 170107543Sscottl} 171107543Sscottl 172107543Sscottl# prompt_yesno msg 173107543Sscottl# Prompts the user with a $msg. The answer is expected to be 174107543Sscottl# yes, no, or some variation thereof. This subroutine returns 0 175107543Sscottl# if the answer was yes, 1 if it was not. 176107543Sscottl# 177107543Sscottlprompt_yesno() { 178107543Sscottl # The argument is required 179109750Sfjoe [ -n "$1" ] && msg="$1" || return 180107543Sscottl 181107543Sscottl while : ; do 182109750Sfjoe echo -n "$msg" 183107543Sscottl read _ans 184107543Sscottl case $_ans in 185107543Sscottl [Nn][Oo]|[Nn]) 186107543Sscottl return 1 187107543Sscottl ;; 188107543Sscottl [Yy][Ee][Ss]|[Yy][Ee]|[Yy]) 189107543Sscottl return 0 190107543Sscottl ;; 191107543Sscottl *) 192107543Sscottl ;; 193107543Sscottl esac 194107543Sscottl done 195107543Sscottl} 196107543Sscottl 197107543Sscottl# show_usage 198107543Sscottl# (no arguments) 199107543Sscottl# Display usage message. 200107543Sscottl# 201107543Sscottlshow_usage() { 202111013Smtm echo "usage: ${THISCMD} [-yv] [-f file] [user ...]" 203107543Sscottl echo " if the -y switch is used, either the -f switch or" 204107543Sscottl echo " one or more user names must be given" 205107543Sscottl} 206107543Sscottl 207107543Sscottl#### END SUBROUTINE DEFENITION #### 208107543Sscottl 209107543Sscottlffile= 210107543Sscottlfflag= 211107543Sscottlprocowner= 212107543Sscottlpw_rswitch= 213107543Sscottluserlist= 214107543Sscottlyflag= 215111013Smtmvflag= 216107543Sscottl 217107543Sscottlprocowner=`/usr/bin/id -u` 218107543Sscottlif [ "$procowner" != "0" ]; then 219107543Sscottl err 'you must be root (0) to use this utility.' 220107543Sscottl exit 1 221107543Sscottlfi 222107543Sscottl 223111013Smtmargs=`getopt 2>/dev/null yvf: $*` 224107543Sscottlif [ "$?" != "0" ]; then 225107543Sscottl show_usage 226107543Sscottl exit 1 227107543Sscottlfi 228107543Sscottlset -- $args 229107543Sscottlfor _switch ; do 230107543Sscottl case $_switch in 231107543Sscottl -y) 232107543Sscottl yflag=1 233107543Sscottl shift 234107543Sscottl ;; 235111013Smtm -v) 236111013Smtm vflag=1 237111013Smtm shift 238111013Smtm ;; 239107543Sscottl -f) 240107543Sscottl fflag=1 241107543Sscottl ffile="$2" 242107543Sscottl shift; shift 243107543Sscottl ;; 244107543Sscottl --) 245107543Sscottl shift 246107543Sscottl break 247107543Sscottl ;; 248107543Sscottl esac 249107543Sscottldone 250107543Sscottl 251107543Sscottl# Get user names from a file if the -f switch was used. Otherwise, 252107543Sscottl# get them from the commandline arguments. If we're getting it 253107543Sscottl# from a file, the file must be owned by and writable only by root. 254107543Sscottl# 255107543Sscottlif [ $fflag ]; then 256107543Sscottl _insecure=`find $ffile ! -user 0 -or -perm +0022` 257107543Sscottl if [ -n "$_insecure" ]; then 258107543Sscottl err "file ($ffile) must be owned by and writeable only by root." 259107543Sscottl exit 1 260107543Sscottl fi 261107543Sscottl if [ -r "$ffile" ]; then 262107543Sscottl userlist=`cat $ffile | while read _user _junk ; do 263107543Sscottl case $_user in 264107543Sscottl \#*|'') 265107543Sscottl ;; 266107543Sscottl *) 267107543Sscottl echo -n "$userlist $_user" 268107543Sscottl ;; 269107543Sscottl esac 270107543Sscottl done` 271107543Sscottl fi 272107543Sscottlelse 273107543Sscottl while [ $1 ] ; do 274107543Sscottl userlist="$userlist $1" 275107543Sscottl shift 276107543Sscottl done 277107543Sscottlfi 278107543Sscottl 279107543Sscottl# If the -y or -f switch has been used and the list of users to remove 280107543Sscottl# is empty it is a fatal error. Otherwise, prompt the user for a list 281107543Sscottl# of one or more user names. 282107543Sscottl# 283107543Sscottlif [ ! "$userlist" ]; then 284107543Sscottl if [ $fflag ]; then 285107543Sscottl err "($ffile) does not exist or does not contain any user names." 286107543Sscottl exit 1 287107543Sscottl elif [ $yflag ]; then 288107543Sscottl show_usage 289107543Sscottl exit 1 290107543Sscottl else 291107543Sscottl echo -n "Please enter one or more user name's: " 292107543Sscottl read userlist 293107543Sscottl fi 294107543Sscottlfi 295107543Sscottl 296107543Sscottl_user= 297107543Sscottl_uid= 298107543Sscottlfor _user in $userlist ; do 299107543Sscottl # Make sure the name exists in the passwd database and that it 300107543Sscottl # does not have a uid of 0 301107543Sscottl # 302107543Sscottl userrec=`pw 2>/dev/null usershow -n $_user` 303107543Sscottl if [ "$?" != "0" ]; then 304107543Sscottl err "user ($_user) does not exist in the password database." 305107543Sscottl continue 306107543Sscottl fi 307107543Sscottl _uid=`echo $userrec | awk -F: '{print $3}'` 308107543Sscottl if [ "$_uid" = "0" ]; then 309107543Sscottl err "user ($_user) has uid 0. You may not remove this user." 310107543Sscottl continue 311107543Sscottl fi 312107543Sscottl 313107543Sscottl # If the -y switch was not used ask for confirmation to remove the 314107543Sscottl # user and home directory. 315107543Sscottl # 316107543Sscottl if [ -z "$yflag" ]; then 317107543Sscottl echo "Matching password entry:" 318107543Sscottl echo 319107543Sscottl echo $userrec 320107543Sscottl echo 321107543Sscottl if ! prompt_yesno "Is this the entry you wish to remove? " ; then 322107543Sscottl continue 323107543Sscottl fi 324107543Sscottl _homedir=`echo $userrec | awk -F: '{print $9}'` 325109750Sfjoe if prompt_yesno "Remove user's home directory ($_homedir)? "; then 326107543Sscottl pw_rswitch="-r" 327107543Sscottl fi 328107543Sscottl else 329107543Sscottl pw_rswitch="-r" 330107543Sscottl fi 331107543Sscottl 332107543Sscottl # Disable any further attempts to log into this account 333107543Sscottl pw 2>/dev/null lock $_user 334107543Sscottl 335107543Sscottl # Remove crontab, mail spool, etc. Then obliterate the user from 336107543Sscottl # the passwd and group database. 337111013Smtm # 338111013Smtm ! verbose && echo -n "Removing user ($_user):" 339107543Sscottl rm_crontab $_user 340107543Sscottl rm_at_jobs $_user 341107543Sscottl kill_procs $_user 342111013Smtm rm_files $_user 343107543Sscottl rm_mail $_user 344107543Sscottl rm_user $_user 345111013Smtm ! verbose && echo "." 346107543Sscottldone 347