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