17cdfce09SScott Long#!/bin/sh 27cdfce09SScott Long# 3fc895860SMike Makonnen# Copyright (c) 2002, 2003 Michael Telahun Makonnen. All rights reserved. 47cdfce09SScott Long# 57cdfce09SScott Long# Redistribution and use in source and binary forms, with or without 67cdfce09SScott Long# modification, are permitted provided that the following conditions 77cdfce09SScott Long# are met: 87cdfce09SScott Long# 1. Redistributions of source code must retain the above copyright 97cdfce09SScott Long# notice, this list of conditions and the following disclaimer. 107cdfce09SScott Long# 2. Redistributions in binary form must reproduce the above copyright 117cdfce09SScott Long# notice, this list of conditions and the following disclaimer in the 127cdfce09SScott Long# documentation and/or other materials provided with the distribution. 137cdfce09SScott Long# 147cdfce09SScott Long# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 157cdfce09SScott Long# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 167cdfce09SScott Long# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 177cdfce09SScott Long# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 187cdfce09SScott Long# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 197cdfce09SScott Long# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 207cdfce09SScott Long# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 217cdfce09SScott Long# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 227cdfce09SScott Long# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 237cdfce09SScott Long# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 247cdfce09SScott Long# 2522884fddSMike Makonnen# Email: Mike Makonnen <mtm@FreeBSD.Org> 267cdfce09SScott Long# 277cdfce09SScott Long# $FreeBSD$ 287cdfce09SScott Long# 297cdfce09SScott Long 307cdfce09SScott LongATJOBDIR="/var/at/jobs" 317cdfce09SScott LongCRONJOBDIR="/var/cron/tabs" 327cdfce09SScott LongMAILSPOOL="/var/mail" 337cdfce09SScott LongSIGKILL="-KILL" 34deca89c7STim J. RobbinsTEMPDIRS="/tmp /var/tmp" 357cdfce09SScott LongTHISCMD=`/usr/bin/basename $0` 367cdfce09SScott Long 377cdfce09SScott Long# err msg 387cdfce09SScott Long# Display $msg on stderr. 397cdfce09SScott Long# 407cdfce09SScott Longerr() { 417cdfce09SScott Long echo 1>&2 ${THISCMD}: $* 427cdfce09SScott Long} 437cdfce09SScott Long 446fcaf748SMike Makonnen# verbose 456fcaf748SMike Makonnen# Returns 0 if verbose mode is set, 1 if it is not. 466fcaf748SMike Makonnen# 476fcaf748SMike Makonnenverbose() { 486fcaf748SMike Makonnen [ -n "$vflag" ] && return 0 || return 1 496fcaf748SMike Makonnen} 506fcaf748SMike Makonnen 517cdfce09SScott Long# rm_files login 527cdfce09SScott Long# Removes files or empty directories belonging to $login from various 537cdfce09SScott Long# temporary directories. 547cdfce09SScott Long# 557cdfce09SScott Longrm_files() { 567cdfce09SScott Long # The argument is required 577cdfce09SScott Long [ -n $1 ] && login=$1 || return 587cdfce09SScott Long 596fcaf748SMike Makonnen totalcount=0 607cdfce09SScott Long for _dir in ${TEMPDIRS} ; do 616fcaf748SMike Makonnen filecount=0 627cdfce09SScott Long if [ ! -d $_dir ]; then 637cdfce09SScott Long err "$_dir is not a valid directory." 647cdfce09SScott Long continue 657cdfce09SScott Long fi 666fcaf748SMike Makonnen verbose && echo -n "Removing files owned by ($login) in $_dir:" 67d6bfbcc3SJens Schweikhardt filecount=`find 2>/dev/null "$_dir" -user "$login" -delete -print | 68deca89c7STim J. Robbins wc -l | sed 's/ *//'` 696fcaf748SMike Makonnen verbose && echo " $filecount removed." 706fcaf748SMike Makonnen totalcount=$(($totalcount + $filecount)) 717cdfce09SScott Long done 726fcaf748SMike Makonnen ! verbose && [ $totalcount -ne 0 ] && echo -n " files($totalcount)" 737cdfce09SScott Long} 747cdfce09SScott Long 757cdfce09SScott Long# rm_mail login 767cdfce09SScott Long# Removes unix mail and pop daemon files belonging to the user 777cdfce09SScott Long# specified in the $login argument. 787cdfce09SScott Long# 797cdfce09SScott Longrm_mail() { 807cdfce09SScott Long # The argument is required 817cdfce09SScott Long [ -n $1 ] && login=$1 || return 827cdfce09SScott Long 836fcaf748SMike Makonnen verbose && echo -n "Removing mail spool(s) for ($login):" 847cdfce09SScott Long if [ -f ${MAILSPOOL}/$login ]; then 85d6bfbcc3SJens Schweikhardt verbose && echo -n " ${MAILSPOOL}/$login" || 866fcaf748SMike Makonnen echo -n " mailspool" 877cdfce09SScott Long rm ${MAILSPOOL}/$login 887cdfce09SScott Long fi 897cdfce09SScott Long if [ -f ${MAILSPOOL}/${login}.pop ]; then 90d6bfbcc3SJens Schweikhardt verbose && echo -n " ${MAILSPOOL}/${login}.pop" || 916fcaf748SMike Makonnen echo -n " pop3" 927cdfce09SScott Long rm ${MAILSPOOL}/${login}.pop 937cdfce09SScott Long fi 946fcaf748SMike Makonnen verbose && echo '.' 957cdfce09SScott Long} 967cdfce09SScott Long 977cdfce09SScott Long# kill_procs login 987cdfce09SScott Long# Send a SIGKILL to all processes owned by $login. 997cdfce09SScott Long# 1007cdfce09SScott Longkill_procs() { 1017cdfce09SScott Long # The argument is required 1027cdfce09SScott Long [ -n $1 ] && login=$1 || return 1037cdfce09SScott Long 1046fcaf748SMike Makonnen verbose && echo -n "Terminating all processes owned by ($login):" 1057cdfce09SScott Long killcount=0 1067cdfce09SScott Long proclist=`ps 2>/dev/null -U $login | grep -v '^\ *PID' | awk '{print $1}'` 1077cdfce09SScott Long for _pid in $proclist ; do 1087cdfce09SScott Long kill 2>/dev/null ${SIGKILL} $_pid 109fd045cf5SMax Khon killcount=$(($killcount + 1)) 1107cdfce09SScott Long done 1116fcaf748SMike Makonnen verbose && echo " ${SIGKILL} signal sent to $killcount processes." 1126fcaf748SMike Makonnen ! verbose && [ $killcount -ne 0 ] && echo -n " processes(${killcount})" 1137cdfce09SScott Long} 1147cdfce09SScott Long 1157cdfce09SScott Long# rm_at_jobs login 1167cdfce09SScott Long# Remove at (1) jobs belonging to $login. 1177cdfce09SScott Long# 1187cdfce09SScott Longrm_at_jobs() { 1197cdfce09SScott Long # The argument is required 1207cdfce09SScott Long [ -n $1 ] && login=$1 || return 1217cdfce09SScott Long 1227cdfce09SScott Long atjoblist=`find 2>/dev/null ${ATJOBDIR} -maxdepth 1 -user $login -print` 1237cdfce09SScott Long jobcount=0 1246fcaf748SMike Makonnen verbose && echo -n "Removing at(1) jobs owned by ($login):" 1257cdfce09SScott Long for _atjob in $atjoblist ; do 1267cdfce09SScott Long rm -f $_atjob 127fd045cf5SMax Khon jobcount=$(($jobcount + 1)) 1287cdfce09SScott Long done 1296fcaf748SMike Makonnen verbose && echo " $jobcount removed." 1306fcaf748SMike Makonnen ! verbose && [ $jobcount -ne 0 ] && echo -n " at($jobcount)" 1317cdfce09SScott Long} 1327cdfce09SScott Long 1337cdfce09SScott Long# rm_crontab login 1347cdfce09SScott Long# Removes crontab file belonging to user $login. 1357cdfce09SScott Long# 1367cdfce09SScott Longrm_crontab() { 1377cdfce09SScott Long # The argument is required 1387cdfce09SScott Long [ -n $1 ] && login=$1 || return 1397cdfce09SScott Long 1406fcaf748SMike Makonnen verbose && echo -n "Removing crontab for ($login):" 1417cdfce09SScott Long if [ -f ${CRONJOBDIR}/$login ]; then 1426fcaf748SMike Makonnen verbose && echo -n " ${CRONJOBDIR}/$login" || echo -n " crontab" 1437cdfce09SScott Long rm -f ${CRONJOBDIR}/$login 1447cdfce09SScott Long fi 1456fcaf748SMike Makonnen verbose && echo '.' 1467cdfce09SScott Long} 1477cdfce09SScott Long 148d6bfbcc3SJens Schweikhardt# rm_ipc login 149d6bfbcc3SJens Schweikhardt# Remove all IPC mechanisms which are owned by $login. 150d6bfbcc3SJens Schweikhardt# 151d6bfbcc3SJens Schweikhardtrm_ipc() { 152d6bfbcc3SJens Schweikhardt verbose && echo -n "Removing IPC mechanisms" 153d6bfbcc3SJens Schweikhardt for i in s m q; do 154d6bfbcc3SJens Schweikhardt ipcs -$i | 155d6bfbcc3SJens Schweikhardt awk -v i=$i -v login=$1 '$1 == i && $5 == login { print $2 }' | 156d6bfbcc3SJens Schweikhardt xargs -n 1 ipcrm -$i 157d6bfbcc3SJens Schweikhardt done 158d6bfbcc3SJens Schweikhardt verbose && echo '.' 159d6bfbcc3SJens Schweikhardt} 160d6bfbcc3SJens Schweikhardt 1617cdfce09SScott Long# rm_user login 1627cdfce09SScott Long# Remove user $login from the system. This subroutine makes use 1637cdfce09SScott Long# of the pw(8) command to remove a user from the system. The pw(8) 1647cdfce09SScott Long# command will remove the specified user from the user database 1657cdfce09SScott Long# and group file and remove any crontabs. His home 1667cdfce09SScott Long# directory will be removed if it is owned by him and contains no 1677cdfce09SScott Long# files or subdirectories owned by other users. Mail spool files will 1687cdfce09SScott Long# also be removed. 1697cdfce09SScott Long# 1707cdfce09SScott Longrm_user() { 1717cdfce09SScott Long # The argument is required 1727cdfce09SScott Long [ -n $1 ] && login=$1 || return 1737cdfce09SScott Long 1746fcaf748SMike Makonnen verbose && echo -n "Removing user ($login)" 1756fcaf748SMike Makonnen [ -n "$pw_rswitch" ] && { 1766fcaf748SMike Makonnen verbose && echo -n " (including home directory)" 1776fcaf748SMike Makonnen ! verbose && echo -n " home" 1786fcaf748SMike Makonnen } 1796fcaf748SMike Makonnen ! verbose && echo -n " passwd" 1806fcaf748SMike Makonnen verbose && echo -n " from the system:" 1817cdfce09SScott Long pw userdel -n $login $pw_rswitch 1826fcaf748SMike Makonnen verbose && echo ' Done.' 1837cdfce09SScott Long} 1847cdfce09SScott Long 1857cdfce09SScott Long# prompt_yesno msg 1867cdfce09SScott Long# Prompts the user with a $msg. The answer is expected to be 1877cdfce09SScott Long# yes, no, or some variation thereof. This subroutine returns 0 1887cdfce09SScott Long# if the answer was yes, 1 if it was not. 1897cdfce09SScott Long# 1907cdfce09SScott Longprompt_yesno() { 1917cdfce09SScott Long # The argument is required 192ce1794a8SMax Khon [ -n "$1" ] && msg="$1" || return 1937cdfce09SScott Long 1947cdfce09SScott Long while : ; do 195ce1794a8SMax Khon echo -n "$msg" 1967cdfce09SScott Long read _ans 1977cdfce09SScott Long case $_ans in 1987cdfce09SScott Long [Nn][Oo]|[Nn]) 1997cdfce09SScott Long return 1 2007cdfce09SScott Long ;; 2017cdfce09SScott Long [Yy][Ee][Ss]|[Yy][Ee]|[Yy]) 2027cdfce09SScott Long return 0 2037cdfce09SScott Long ;; 2047cdfce09SScott Long *) 2057cdfce09SScott Long ;; 2067cdfce09SScott Long esac 2077cdfce09SScott Long done 2087cdfce09SScott Long} 2097cdfce09SScott Long 2107cdfce09SScott Long# show_usage 2117cdfce09SScott Long# (no arguments) 2127cdfce09SScott Long# Display usage message. 2137cdfce09SScott Long# 2147cdfce09SScott Longshow_usage() { 2156fcaf748SMike Makonnen echo "usage: ${THISCMD} [-yv] [-f file] [user ...]" 2167cdfce09SScott Long echo " if the -y switch is used, either the -f switch or" 2177cdfce09SScott Long echo " one or more user names must be given" 2187cdfce09SScott Long} 2197cdfce09SScott Long 2207cdfce09SScott Long#### END SUBROUTINE DEFENITION #### 2217cdfce09SScott Long 2227cdfce09SScott Longffile= 2237cdfce09SScott Longfflag= 2247cdfce09SScott Longprocowner= 2257cdfce09SScott Longpw_rswitch= 2267cdfce09SScott Longuserlist= 2277cdfce09SScott Longyflag= 2286fcaf748SMike Makonnenvflag= 2297cdfce09SScott Long 2307cdfce09SScott Longprocowner=`/usr/bin/id -u` 2317cdfce09SScott Longif [ "$procowner" != "0" ]; then 2327cdfce09SScott Long err 'you must be root (0) to use this utility.' 2337cdfce09SScott Long exit 1 2347cdfce09SScott Longfi 2357cdfce09SScott Long 2366fcaf748SMike Makonnenargs=`getopt 2>/dev/null yvf: $*` 2377cdfce09SScott Longif [ "$?" != "0" ]; then 2387cdfce09SScott Long show_usage 2397cdfce09SScott Long exit 1 2407cdfce09SScott Longfi 2417cdfce09SScott Longset -- $args 2427cdfce09SScott Longfor _switch ; do 2437cdfce09SScott Long case $_switch in 2447cdfce09SScott Long -y) 2457cdfce09SScott Long yflag=1 2467cdfce09SScott Long shift 2477cdfce09SScott Long ;; 2486fcaf748SMike Makonnen -v) 2496fcaf748SMike Makonnen vflag=1 2506fcaf748SMike Makonnen shift 2516fcaf748SMike Makonnen ;; 2527cdfce09SScott Long -f) 2537cdfce09SScott Long fflag=1 2547cdfce09SScott Long ffile="$2" 2557cdfce09SScott Long shift; shift 2567cdfce09SScott Long ;; 2577cdfce09SScott Long --) 2587cdfce09SScott Long shift 2597cdfce09SScott Long break 2607cdfce09SScott Long ;; 2617cdfce09SScott Long esac 2627cdfce09SScott Longdone 2637cdfce09SScott Long 2647cdfce09SScott Long# Get user names from a file if the -f switch was used. Otherwise, 2657cdfce09SScott Long# get them from the commandline arguments. If we're getting it 2667cdfce09SScott Long# from a file, the file must be owned by and writable only by root. 2677cdfce09SScott Long# 2687cdfce09SScott Longif [ $fflag ]; then 2697cdfce09SScott Long _insecure=`find $ffile ! -user 0 -or -perm +0022` 2707cdfce09SScott Long if [ -n "$_insecure" ]; then 2717cdfce09SScott Long err "file ($ffile) must be owned by and writeable only by root." 2727cdfce09SScott Long exit 1 2737cdfce09SScott Long fi 2747cdfce09SScott Long if [ -r "$ffile" ]; then 2757cdfce09SScott Long userlist=`cat $ffile | while read _user _junk ; do 2767cdfce09SScott Long case $_user in 2777cdfce09SScott Long \#*|'') 2787cdfce09SScott Long ;; 2797cdfce09SScott Long *) 2807cdfce09SScott Long echo -n "$userlist $_user" 2817cdfce09SScott Long ;; 2827cdfce09SScott Long esac 2837cdfce09SScott Long done` 2847cdfce09SScott Long fi 2857cdfce09SScott Longelse 2867cdfce09SScott Long while [ $1 ] ; do 2877cdfce09SScott Long userlist="$userlist $1" 2887cdfce09SScott Long shift 2897cdfce09SScott Long done 2907cdfce09SScott Longfi 2917cdfce09SScott Long 2927cdfce09SScott Long# If the -y or -f switch has been used and the list of users to remove 2937cdfce09SScott Long# is empty it is a fatal error. Otherwise, prompt the user for a list 2947cdfce09SScott Long# of one or more user names. 2957cdfce09SScott Long# 2967cdfce09SScott Longif [ ! "$userlist" ]; then 2977cdfce09SScott Long if [ $fflag ]; then 2987cdfce09SScott Long err "($ffile) does not exist or does not contain any user names." 2997cdfce09SScott Long exit 1 3007cdfce09SScott Long elif [ $yflag ]; then 3017cdfce09SScott Long show_usage 3027cdfce09SScott Long exit 1 3037cdfce09SScott Long else 3047cdfce09SScott Long echo -n "Please enter one or more user name's: " 3057cdfce09SScott Long read userlist 3067cdfce09SScott Long fi 3077cdfce09SScott Longfi 3087cdfce09SScott Long 3097cdfce09SScott Long_user= 3107cdfce09SScott Long_uid= 3117cdfce09SScott Longfor _user in $userlist ; do 3127cdfce09SScott Long # Make sure the name exists in the passwd database and that it 3137cdfce09SScott Long # does not have a uid of 0 3147cdfce09SScott Long # 3157cdfce09SScott Long userrec=`pw 2>/dev/null usershow -n $_user` 3167cdfce09SScott Long if [ "$?" != "0" ]; then 3177cdfce09SScott Long err "user ($_user) does not exist in the password database." 3187cdfce09SScott Long continue 3197cdfce09SScott Long fi 3207cdfce09SScott Long _uid=`echo $userrec | awk -F: '{print $3}'` 3217cdfce09SScott Long if [ "$_uid" = "0" ]; then 3227cdfce09SScott Long err "user ($_user) has uid 0. You may not remove this user." 3237cdfce09SScott Long continue 3247cdfce09SScott Long fi 3257cdfce09SScott Long 3267cdfce09SScott Long # If the -y switch was not used ask for confirmation to remove the 3277cdfce09SScott Long # user and home directory. 3287cdfce09SScott Long # 3297cdfce09SScott Long if [ -z "$yflag" ]; then 3307cdfce09SScott Long echo "Matching password entry:" 3317cdfce09SScott Long echo 3327cdfce09SScott Long echo $userrec 3337cdfce09SScott Long echo 3347cdfce09SScott Long if ! prompt_yesno "Is this the entry you wish to remove? " ; then 3357cdfce09SScott Long continue 3367cdfce09SScott Long fi 3377cdfce09SScott Long _homedir=`echo $userrec | awk -F: '{print $9}'` 338ce1794a8SMax Khon if prompt_yesno "Remove user's home directory ($_homedir)? "; then 3397cdfce09SScott Long pw_rswitch="-r" 3407cdfce09SScott Long fi 3417cdfce09SScott Long else 3427cdfce09SScott Long pw_rswitch="-r" 3437cdfce09SScott Long fi 3447cdfce09SScott Long 3457cdfce09SScott Long # Disable any further attempts to log into this account 3467cdfce09SScott Long pw 2>/dev/null lock $_user 3477cdfce09SScott Long 3487cdfce09SScott Long # Remove crontab, mail spool, etc. Then obliterate the user from 3497cdfce09SScott Long # the passwd and group database. 3506fcaf748SMike Makonnen # 3516fcaf748SMike Makonnen ! verbose && echo -n "Removing user ($_user):" 3527cdfce09SScott Long rm_crontab $_user 3537cdfce09SScott Long rm_at_jobs $_user 354d6bfbcc3SJens Schweikhardt rm_ipc $_user 3557cdfce09SScott Long kill_procs $_user 3567cdfce09SScott Long rm_files $_user 3576fcaf748SMike Makonnen rm_mail $_user 3587cdfce09SScott Long rm_user $_user 3596fcaf748SMike Makonnen ! verbose && echo "." 3607cdfce09SScott Longdone 361