rmuser.sh revision 107543
1107543Sscottl#!/bin/sh 2107543Sscottl# 3107543Sscottl# Copyright (c) 2002 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# 3. The name of the author may not be used to endorse or promote products 14107543Sscottl# derived from this software without specific prior written permission. 15107543Sscottl# 16107543Sscottl# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 17107543Sscottl# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18107543Sscottl# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 19107543Sscottl# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 20107543Sscottl# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 21107543Sscottl# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 22107543Sscottl# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 23107543Sscottl# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24107543Sscottl# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 25107543Sscottl# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26107543Sscottl# 27107543Sscottl# Email: Mike Makonnen <mtm@identd.net> 28107543Sscottl# 29107543Sscottl# $FreeBSD: head/usr.sbin/adduser/rmuser.sh 107543 2002-12-03 05:41:09Z scottl $ 30107543Sscottl# 31107543Sscottl 32107543SscottlATJOBDIR="/var/at/jobs" 33107543SscottlCRONJOBDIR="/var/cron/tabs" 34107543SscottlMAILSPOOL="/var/mail" 35107543SscottlSIGKILL="-KILL" 36107543SscottlTEMPDIRS="/tmp /var/tmp /var/tmp/vi.recover" 37107543SscottlTHISCMD=`/usr/bin/basename $0` 38107543Sscottl 39107543Sscottl# err msg 40107543Sscottl# Display $msg on stderr. 41107543Sscottl# 42107543Sscottlerr() { 43107543Sscottl echo 1>&2 ${THISCMD}: $* 44107543Sscottl} 45107543Sscottl 46107543Sscottl# rm_files login 47107543Sscottl# Removes files or empty directories belonging to $login from various 48107543Sscottl# temporary directories. 49107543Sscottl# 50107543Sscottlrm_files() { 51107543Sscottl # The argument is required 52107543Sscottl [ -n $1 ] && login=$1 || return 53107543Sscottl 54107543Sscottl for _dir in ${TEMPDIRS} ; do 55107543Sscottl if [ ! -d $_dir ]; then 56107543Sscottl err "$_dir is not a valid directory." 57107543Sscottl continue 58107543Sscottl fi 59107543Sscottl echo -n "Removing files owned by ($login) in $_dir:" 60107543Sscottl filecount=0 61107543Sscottl _ownedfiles=`find 2>/dev/null $_dir -maxdepth 1 -user $login -print` 62107543Sscottl for _file in $_ownedfiles ; do 63107543Sscottl rm -fd $_file 64107543Sscottl filecount=`expr $filecount + 1` 65107543Sscottl done 66107543Sscottl echo " $filecount removed." 67107543Sscottl done 68107543Sscottl} 69107543Sscottl 70107543Sscottl# rm_mail login 71107543Sscottl# Removes unix mail and pop daemon files belonging to the user 72107543Sscottl# specified in the $login argument. 73107543Sscottl# 74107543Sscottlrm_mail() { 75107543Sscottl # The argument is required 76107543Sscottl [ -n $1 ] && login=$1 || return 77107543Sscottl 78107543Sscottl echo -n "Removing mail spool(s) for ($login):" 79107543Sscottl if [ -f ${MAILSPOOL}/$login ]; then 80107543Sscottl echo -n " ${MAILSPOOL}/$login" 81107543Sscottl rm ${MAILSPOOL}/$login 82107543Sscottl fi 83107543Sscottl if [ -f ${MAILSPOOL}/${login}.pop ]; then 84107543Sscottl echo -n " ${MAILSPOOL}/${login}.pop" 85107543Sscottl rm ${MAILSPOOL}/${login}.pop 86107543Sscottl fi 87107543Sscottl echo '.' 88107543Sscottl} 89107543Sscottl 90107543Sscottl# kill_procs login 91107543Sscottl# Send a SIGKILL to all processes owned by $login. 92107543Sscottl# 93107543Sscottlkill_procs() { 94107543Sscottl # The argument is required 95107543Sscottl [ -n $1 ] && login=$1 || return 96107543Sscottl 97107543Sscottl echo -n "Terminating all processes owned by ($login):" 98107543Sscottl killcount=0 99107543Sscottl proclist=`ps 2>/dev/null -U $login | grep -v '^\ *PID' | awk '{print $1}'` 100107543Sscottl for _pid in $proclist ; do 101107543Sscottl kill 2>/dev/null ${SIGKILL} $_pid 102107543Sscottl killcount=`expr $killcount + 1` 103107543Sscottl done 104107543Sscottl echo " ${SIGKILL} signal sent to $killcount processes." 105107543Sscottl} 106107543Sscottl 107107543Sscottl# rm_at_jobs login 108107543Sscottl# Remove at (1) jobs belonging to $login. 109107543Sscottl# 110107543Sscottlrm_at_jobs() { 111107543Sscottl # The argument is required 112107543Sscottl [ -n $1 ] && login=$1 || return 113107543Sscottl 114107543Sscottl atjoblist=`find 2>/dev/null ${ATJOBDIR} -maxdepth 1 -user $login -print` 115107543Sscottl jobcount=0 116107543Sscottl echo -n "Removing at(1) jobs owned by ($login):" 117107543Sscottl for _atjob in $atjoblist ; do 118107543Sscottl rm -f $_atjob 119107543Sscottl jobcount=`expr $jobcount + 1` 120107543Sscottl done 121107543Sscottl echo " $jobcount removed." 122107543Sscottl} 123107543Sscottl 124107543Sscottl# rm_crontab login 125107543Sscottl# Removes crontab file belonging to user $login. 126107543Sscottl# 127107543Sscottlrm_crontab() { 128107543Sscottl # The argument is required 129107543Sscottl [ -n $1 ] && login=$1 || return 130107543Sscottl 131107543Sscottl echo -n "Removing crontab for ($login):" 132107543Sscottl if [ -f ${CRONJOBDIR}/$login ]; then 133107543Sscottl echo -n " ${CRONJOBDIR}/$login" 134107543Sscottl rm -f ${CRONJOBDIR}/$login 135107543Sscottl fi 136107543Sscottl echo '.' 137107543Sscottl} 138107543Sscottl 139107543Sscottl# rm_user login 140107543Sscottl# Remove user $login from the system. This subroutine makes use 141107543Sscottl# of the pw(8) command to remove a user from the system. The pw(8) 142107543Sscottl# command will remove the specified user from the user database 143107543Sscottl# and group file and remove any crontabs. His home 144107543Sscottl# directory will be removed if it is owned by him and contains no 145107543Sscottl# files or subdirectories owned by other users. Mail spool files will 146107543Sscottl# also be removed. 147107543Sscottl# 148107543Sscottlrm_user() { 149107543Sscottl # The argument is required 150107543Sscottl [ -n $1 ] && login=$1 || return 151107543Sscottl 152107543Sscottl echo -n "Removing user ($login)" 153107543Sscottl [ -n "$pw_rswitch" ] && echo -n " (including home directory)" 154107543Sscottl echo -n " from the system:" 155107543Sscottl pw userdel -n $login $pw_rswitch 156107543Sscottl echo ' Done.' 157107543Sscottl} 158107543Sscottl 159107543Sscottl# prompt_yesno msg 160107543Sscottl# Prompts the user with a $msg. The answer is expected to be 161107543Sscottl# yes, no, or some variation thereof. This subroutine returns 0 162107543Sscottl# if the answer was yes, 1 if it was not. 163107543Sscottl# 164107543Sscottlprompt_yesno() { 165107543Sscottl # The argument is required 166107543Sscottl [ -n "$1" ] && msg=$1 || return 167107543Sscottl 168107543Sscottl while : ; do 169107543Sscottl echo -n $msg 170107543Sscottl read _ans 171107543Sscottl case $_ans in 172107543Sscottl [Nn][Oo]|[Nn]) 173107543Sscottl return 1 174107543Sscottl ;; 175107543Sscottl [Yy][Ee][Ss]|[Yy][Ee]|[Yy]) 176107543Sscottl return 0 177107543Sscottl ;; 178107543Sscottl *) 179107543Sscottl ;; 180107543Sscottl esac 181107543Sscottl done 182107543Sscottl} 183107543Sscottl 184107543Sscottl# show_usage 185107543Sscottl# (no arguments) 186107543Sscottl# Display usage message. 187107543Sscottl# 188107543Sscottlshow_usage() { 189107543Sscottl echo "usage: ${THISCMD} [-y] [-f file] [user ...]" 190107543Sscottl echo " if the -y switch is used, either the -f switch or" 191107543Sscottl echo " one or more user names must be given" 192107543Sscottl} 193107543Sscottl 194107543Sscottl#### END SUBROUTINE DEFENITION #### 195107543Sscottl 196107543Sscottlffile= 197107543Sscottlfflag= 198107543Sscottlprocowner= 199107543Sscottlpw_rswitch= 200107543Sscottluserlist= 201107543Sscottlyflag= 202107543Sscottl 203107543Sscottlprocowner=`/usr/bin/id -u` 204107543Sscottlif [ "$procowner" != "0" ]; then 205107543Sscottl err 'you must be root (0) to use this utility.' 206107543Sscottl exit 1 207107543Sscottlfi 208107543Sscottl 209107543Sscottlargs=`getopt 2>/dev/null yf: $*` 210107543Sscottlif [ "$?" != "0" ]; then 211107543Sscottl show_usage 212107543Sscottl exit 1 213107543Sscottlfi 214107543Sscottlset -- $args 215107543Sscottlfor _switch ; do 216107543Sscottl case $_switch in 217107543Sscottl -y) 218107543Sscottl yflag=1 219107543Sscottl shift 220107543Sscottl ;; 221107543Sscottl -f) 222107543Sscottl fflag=1 223107543Sscottl ffile="$2" 224107543Sscottl shift; shift 225107543Sscottl ;; 226107543Sscottl --) 227107543Sscottl shift 228107543Sscottl break 229107543Sscottl ;; 230107543Sscottl esac 231107543Sscottldone 232107543Sscottl 233107543Sscottl# Get user names from a file if the -f switch was used. Otherwise, 234107543Sscottl# get them from the commandline arguments. If we're getting it 235107543Sscottl# from a file, the file must be owned by and writable only by root. 236107543Sscottl# 237107543Sscottlif [ $fflag ]; then 238107543Sscottl _insecure=`find $ffile ! -user 0 -or -perm +0022` 239107543Sscottl if [ -n "$_insecure" ]; then 240107543Sscottl err "file ($ffile) must be owned by and writeable only by root." 241107543Sscottl exit 1 242107543Sscottl fi 243107543Sscottl if [ -r "$ffile" ]; then 244107543Sscottl userlist=`cat $ffile | while read _user _junk ; do 245107543Sscottl case $_user in 246107543Sscottl \#*|'') 247107543Sscottl ;; 248107543Sscottl *) 249107543Sscottl echo -n "$userlist $_user" 250107543Sscottl ;; 251107543Sscottl esac 252107543Sscottl done` 253107543Sscottl fi 254107543Sscottlelse 255107543Sscottl while [ $1 ] ; do 256107543Sscottl userlist="$userlist $1" 257107543Sscottl shift 258107543Sscottl done 259107543Sscottlfi 260107543Sscottl 261107543Sscottl# If the -y or -f switch has been used and the list of users to remove 262107543Sscottl# is empty it is a fatal error. Otherwise, prompt the user for a list 263107543Sscottl# of one or more user names. 264107543Sscottl# 265107543Sscottlif [ ! "$userlist" ]; then 266107543Sscottl if [ $fflag ]; then 267107543Sscottl err "($ffile) does not exist or does not contain any user names." 268107543Sscottl exit 1 269107543Sscottl elif [ $yflag ]; then 270107543Sscottl show_usage 271107543Sscottl exit 1 272107543Sscottl else 273107543Sscottl echo -n "Please enter one or more user name's: " 274107543Sscottl read userlist 275107543Sscottl fi 276107543Sscottlfi 277107543Sscottl 278107543Sscottl_user= 279107543Sscottl_uid= 280107543Sscottlfor _user in $userlist ; do 281107543Sscottl # Make sure the name exists in the passwd database and that it 282107543Sscottl # does not have a uid of 0 283107543Sscottl # 284107543Sscottl userrec=`pw 2>/dev/null usershow -n $_user` 285107543Sscottl if [ "$?" != "0" ]; then 286107543Sscottl err "user ($_user) does not exist in the password database." 287107543Sscottl continue 288107543Sscottl fi 289107543Sscottl _uid=`echo $userrec | awk -F: '{print $3}'` 290107543Sscottl if [ "$_uid" = "0" ]; then 291107543Sscottl err "user ($_user) has uid 0. You may not remove this user." 292107543Sscottl continue 293107543Sscottl fi 294107543Sscottl 295107543Sscottl # If the -y switch was not used ask for confirmation to remove the 296107543Sscottl # user and home directory. 297107543Sscottl # 298107543Sscottl if [ -z "$yflag" ]; then 299107543Sscottl echo "Matching password entry:" 300107543Sscottl echo 301107543Sscottl echo $userrec 302107543Sscottl echo 303107543Sscottl if ! prompt_yesno "Is this the entry you wish to remove? " ; then 304107543Sscottl continue 305107543Sscottl fi 306107543Sscottl _homedir=`echo $userrec | awk -F: '{print $9}'` 307107543Sscottl if prompt_yesno "Remove user's home directory ($_homedir)?: "; then 308107543Sscottl pw_rswitch="-r" 309107543Sscottl fi 310107543Sscottl else 311107543Sscottl pw_rswitch="-r" 312107543Sscottl fi 313107543Sscottl 314107543Sscottl # Disable any further attempts to log into this account 315107543Sscottl pw 2>/dev/null lock $_user 316107543Sscottl 317107543Sscottl # Remove crontab, mail spool, etc. Then obliterate the user from 318107543Sscottl # the passwd and group database. 319107543Sscottl rm_crontab $_user 320107543Sscottl rm_at_jobs $_user 321107543Sscottl kill_procs $_user 322107543Sscottl rm_mail $_user 323107543Sscottl rm_files $_user 324107543Sscottl rm_user $_user 325107543Sscottldone 326