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