]> git.cameronkatri.com Git - pw-darwin.git/blob - adduser/rmuser.sh
mdoc(7): Properly mark C headers.
[pw-darwin.git] / adduser / rmuser.sh
1 #!/bin/sh
2 #
3 # Copyright (c) 2002, 2003 Michael Telahun Makonnen. All rights reserved.
4 #
5 # Redistribution and use in source and binary forms, with or without
6 # modification, are permitted provided that the following conditions
7 # are met:
8 # 1. Redistributions of source code must retain the above copyright
9 # notice, this list of conditions and the following disclaimer.
10 # 2. Redistributions in binary form must reproduce the above copyright
11 # notice, this list of conditions and the following disclaimer in the
12 # documentation and/or other materials provided with the distribution.
13 #
14 # THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
15 # IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16 # OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17 # IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
18 # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
19 # NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20 # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23 # THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 #
25 # Email: Mike Makonnen <mtm@FreeBSD.Org>
26 #
27 # $FreeBSD$
28 #
29
30 ATJOBDIR="/var/at/jobs"
31 CRONJOBDIR="/var/cron/tabs"
32 MAILSPOOL="/var/mail"
33 SIGKILL="-KILL"
34 TEMPDIRS="/tmp /var/tmp"
35 THISCMD=`/usr/bin/basename $0`
36
37 # err msg
38 # Display $msg on stderr.
39 #
40 err() {
41 echo 1>&2 ${THISCMD}: $*
42 }
43
44 # verbose
45 # Returns 0 if verbose mode is set, 1 if it is not.
46 #
47 verbose() {
48 [ -n "$vflag" ] && return 0 || return 1
49 }
50
51 # rm_files login
52 # Removes files or empty directories belonging to $login from various
53 # temporary directories.
54 #
55 rm_files() {
56 # The argument is required
57 [ -n $1 ] && login=$1 || return
58
59 totalcount=0
60 for _dir in ${TEMPDIRS} ; do
61 filecount=0
62 if [ ! -d $_dir ]; then
63 err "$_dir is not a valid directory."
64 continue
65 fi
66 verbose && echo -n "Removing files owned by ($login) in $_dir:"
67 filecount=`find 2>/dev/null "$_dir" -user "$login" -delete -print | \
68 wc -l | sed 's/ *//'`
69 verbose && echo " $filecount removed."
70 totalcount=$(($totalcount + $filecount))
71 done
72 ! verbose && [ $totalcount -ne 0 ] && echo -n " files($totalcount)"
73 }
74
75 # rm_mail login
76 # Removes unix mail and pop daemon files belonging to the user
77 # specified in the $login argument.
78 #
79 rm_mail() {
80 # The argument is required
81 [ -n $1 ] && login=$1 || return
82
83 verbose && echo -n "Removing mail spool(s) for ($login):"
84 if [ -f ${MAILSPOOL}/$login ]; then
85 verbose && echo -n " ${MAILSPOOL}/$login" || \
86 echo -n " mailspool"
87 rm ${MAILSPOOL}/$login
88 fi
89 if [ -f ${MAILSPOOL}/${login}.pop ]; then
90 verbose && echo -n " ${MAILSPOOL}/${login}.pop" || \
91 echo -n " pop3"
92 rm ${MAILSPOOL}/${login}.pop
93 fi
94 verbose && echo '.'
95 }
96
97 # kill_procs login
98 # Send a SIGKILL to all processes owned by $login.
99 #
100 kill_procs() {
101 # The argument is required
102 [ -n $1 ] && login=$1 || return
103
104 verbose && echo -n "Terminating all processes owned by ($login):"
105 killcount=0
106 proclist=`ps 2>/dev/null -U $login | grep -v '^\ *PID' | awk '{print $1}'`
107 for _pid in $proclist ; do
108 kill 2>/dev/null ${SIGKILL} $_pid
109 killcount=$(($killcount + 1))
110 done
111 verbose && echo " ${SIGKILL} signal sent to $killcount processes."
112 ! verbose && [ $killcount -ne 0 ] && echo -n " processes(${killcount})"
113 }
114
115 # rm_at_jobs login
116 # Remove at (1) jobs belonging to $login.
117 #
118 rm_at_jobs() {
119 # The argument is required
120 [ -n $1 ] && login=$1 || return
121
122 atjoblist=`find 2>/dev/null ${ATJOBDIR} -maxdepth 1 -user $login -print`
123 jobcount=0
124 verbose && echo -n "Removing at(1) jobs owned by ($login):"
125 for _atjob in $atjoblist ; do
126 rm -f $_atjob
127 jobcount=$(($jobcount + 1))
128 done
129 verbose && echo " $jobcount removed."
130 ! verbose && [ $jobcount -ne 0 ] && echo -n " at($jobcount)"
131 }
132
133 # rm_crontab login
134 # Removes crontab file belonging to user $login.
135 #
136 rm_crontab() {
137 # The argument is required
138 [ -n $1 ] && login=$1 || return
139
140 verbose && echo -n "Removing crontab for ($login):"
141 if [ -f ${CRONJOBDIR}/$login ]; then
142 verbose && echo -n " ${CRONJOBDIR}/$login" || echo -n " crontab"
143 rm -f ${CRONJOBDIR}/$login
144 fi
145 verbose && echo '.'
146 }
147
148 # rm_user login
149 # Remove user $login from the system. This subroutine makes use
150 # of the pw(8) command to remove a user from the system. The pw(8)
151 # command will remove the specified user from the user database
152 # and group file and remove any crontabs. His home
153 # directory will be removed if it is owned by him and contains no
154 # files or subdirectories owned by other users. Mail spool files will
155 # also be removed.
156 #
157 rm_user() {
158 # The argument is required
159 [ -n $1 ] && login=$1 || return
160
161 verbose && echo -n "Removing user ($login)"
162 [ -n "$pw_rswitch" ] && {
163 verbose && echo -n " (including home directory)"
164 ! verbose && echo -n " home"
165 }
166 ! verbose && echo -n " passwd"
167 verbose && echo -n " from the system:"
168 pw userdel -n $login $pw_rswitch
169 verbose && echo ' Done.'
170 }
171
172 # prompt_yesno msg
173 # Prompts the user with a $msg. The answer is expected to be
174 # yes, no, or some variation thereof. This subroutine returns 0
175 # if the answer was yes, 1 if it was not.
176 #
177 prompt_yesno() {
178 # The argument is required
179 [ -n "$1" ] && msg="$1" || return
180
181 while : ; do
182 echo -n "$msg"
183 read _ans
184 case $_ans in
185 [Nn][Oo]|[Nn])
186 return 1
187 ;;
188 [Yy][Ee][Ss]|[Yy][Ee]|[Yy])
189 return 0
190 ;;
191 *)
192 ;;
193 esac
194 done
195 }
196
197 # show_usage
198 # (no arguments)
199 # Display usage message.
200 #
201 show_usage() {
202 echo "usage: ${THISCMD} [-yv] [-f file] [user ...]"
203 echo " if the -y switch is used, either the -f switch or"
204 echo " one or more user names must be given"
205 }
206
207 #### END SUBROUTINE DEFENITION ####
208
209 ffile=
210 fflag=
211 procowner=
212 pw_rswitch=
213 userlist=
214 yflag=
215 vflag=
216
217 procowner=`/usr/bin/id -u`
218 if [ "$procowner" != "0" ]; then
219 err 'you must be root (0) to use this utility.'
220 exit 1
221 fi
222
223 args=`getopt 2>/dev/null yvf: $*`
224 if [ "$?" != "0" ]; then
225 show_usage
226 exit 1
227 fi
228 set -- $args
229 for _switch ; do
230 case $_switch in
231 -y)
232 yflag=1
233 shift
234 ;;
235 -v)
236 vflag=1
237 shift
238 ;;
239 -f)
240 fflag=1
241 ffile="$2"
242 shift; shift
243 ;;
244 --)
245 shift
246 break
247 ;;
248 esac
249 done
250
251 # Get user names from a file if the -f switch was used. Otherwise,
252 # get them from the commandline arguments. If we're getting it
253 # from a file, the file must be owned by and writable only by root.
254 #
255 if [ $fflag ]; then
256 _insecure=`find $ffile ! -user 0 -or -perm +0022`
257 if [ -n "$_insecure" ]; then
258 err "file ($ffile) must be owned by and writeable only by root."
259 exit 1
260 fi
261 if [ -r "$ffile" ]; then
262 userlist=`cat $ffile | while read _user _junk ; do
263 case $_user in
264 \#*|'')
265 ;;
266 *)
267 echo -n "$userlist $_user"
268 ;;
269 esac
270 done`
271 fi
272 else
273 while [ $1 ] ; do
274 userlist="$userlist $1"
275 shift
276 done
277 fi
278
279 # If the -y or -f switch has been used and the list of users to remove
280 # is empty it is a fatal error. Otherwise, prompt the user for a list
281 # of one or more user names.
282 #
283 if [ ! "$userlist" ]; then
284 if [ $fflag ]; then
285 err "($ffile) does not exist or does not contain any user names."
286 exit 1
287 elif [ $yflag ]; then
288 show_usage
289 exit 1
290 else
291 echo -n "Please enter one or more user name's: "
292 read userlist
293 fi
294 fi
295
296 _user=
297 _uid=
298 for _user in $userlist ; do
299 # Make sure the name exists in the passwd database and that it
300 # does not have a uid of 0
301 #
302 userrec=`pw 2>/dev/null usershow -n $_user`
303 if [ "$?" != "0" ]; then
304 err "user ($_user) does not exist in the password database."
305 continue
306 fi
307 _uid=`echo $userrec | awk -F: '{print $3}'`
308 if [ "$_uid" = "0" ]; then
309 err "user ($_user) has uid 0. You may not remove this user."
310 continue
311 fi
312
313 # If the -y switch was not used ask for confirmation to remove the
314 # user and home directory.
315 #
316 if [ -z "$yflag" ]; then
317 echo "Matching password entry:"
318 echo
319 echo $userrec
320 echo
321 if ! prompt_yesno "Is this the entry you wish to remove? " ; then
322 continue
323 fi
324 _homedir=`echo $userrec | awk -F: '{print $9}'`
325 if prompt_yesno "Remove user's home directory ($_homedir)? "; then
326 pw_rswitch="-r"
327 fi
328 else
329 pw_rswitch="-r"
330 fi
331
332 # Disable any further attempts to log into this account
333 pw 2>/dev/null lock $_user
334
335 # Remove crontab, mail spool, etc. Then obliterate the user from
336 # the passwd and group database.
337 #
338 ! verbose && echo -n "Removing user ($_user):"
339 rm_crontab $_user
340 rm_at_jobs $_user
341 kill_procs $_user
342 rm_files $_user
343 rm_mail $_user
344 rm_user $_user
345 ! verbose && echo "."
346 done