]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - usr.sbin/adduser/rmuser.sh
This commit was generated by cvs2svn to compensate for changes in r179191,
[FreeBSD/FreeBSD.git] / usr.sbin / 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_ipc login
149 #       Remove all IPC mechanisms which are owned by $login.
150 #
151 rm_ipc() {
152         verbose && echo -n "Removing IPC mechanisms"
153         for i in s m q; do
154                 ipcs -$i |
155                 awk -v i=$i -v login=$1 '$1 == i && $5 == login { print $2 }' |
156                 xargs -n 1 ipcrm -$i
157         done
158         verbose && echo '.'
159 }
160
161 # rm_user login
162 #       Remove user $login from the system. This subroutine makes use
163 #       of the pw(8) command to remove a user from the system. The pw(8)
164 #       command will remove the specified user from the user database
165 #       and group file and remove any crontabs. His home
166 #       directory will be removed if it is owned by him and contains no 
167 #       files or subdirectories owned by other users. Mail spool files will
168 #       also be removed.
169 #
170 rm_user() {
171         # The argument is required
172         [ -n $1 ] && login=$1 || return
173
174         verbose && echo -n "Removing user ($login)"
175         [ -n "$pw_rswitch" ] && {
176                 verbose && echo -n " (including home directory)"
177                 ! verbose && echo -n " home"
178         }
179         ! verbose && echo -n " passwd"
180         verbose && echo -n " from the system:"
181         pw userdel -n $login $pw_rswitch
182         verbose && echo ' Done.'
183 }
184
185 # prompt_yesno msg
186 #       Prompts the user with a $msg. The answer is expected to be
187 #       yes, no, or some variation thereof. This subroutine returns 0
188 #       if the answer was yes, 1 if it was not.
189 #
190 prompt_yesno() {
191         # The argument is required
192         [ -n "$1" ] && msg="$1" || return
193
194         while : ; do
195                 echo -n "$msg"
196                 read _ans
197                 case $_ans in
198                 [Nn][Oo]|[Nn])
199                         return 1
200                         ;;
201                 [Yy][Ee][Ss]|[Yy][Ee]|[Yy])
202                         return 0
203                         ;;
204                 *)
205                         ;;
206                 esac
207         done
208 }
209
210 # show_usage
211 #       (no arguments)
212 #       Display usage message.
213 #
214 show_usage() {
215         echo "usage: ${THISCMD} [-yv] [-f file] [user ...]"
216         echo "       if the -y switch is used, either the -f switch or"
217         echo "       one or more user names must be given"
218 }
219
220 #### END SUBROUTINE DEFENITION ####
221
222 ffile=
223 fflag=
224 procowner=
225 pw_rswitch=
226 userlist=
227 yflag=
228 vflag=
229
230 procowner=`/usr/bin/id -u`
231 if [ "$procowner" != "0" ]; then
232         err 'you must be root (0) to use this utility.'
233         exit 1
234 fi
235
236 args=`getopt 2>/dev/null yvf: $*`
237 if [ "$?" != "0" ]; then
238         show_usage
239         exit 1
240 fi
241 set -- $args
242 for _switch ; do
243         case $_switch in
244         -y)
245                 yflag=1
246                 shift
247                 ;;
248         -v)
249                 vflag=1
250                 shift
251                 ;;
252         -f)
253                 fflag=1
254                 ffile="$2"
255                 shift; shift
256                 ;;
257         --)
258                 shift
259                 break
260                 ;;
261         esac
262 done
263
264 # Get user names from a file if the -f switch was used. Otherwise,
265 # get them from the commandline arguments. If we're getting it
266 # from a file, the file must be owned by and writable only by root.
267 #
268 if [ $fflag ]; then
269         _insecure=`find $ffile ! -user 0 -or -perm +0022`
270         if [ -n "$_insecure" ]; then
271                 err "file ($ffile) must be owned by and writeable only by root."
272                 exit 1
273         fi
274         if [ -r "$ffile" ]; then
275                 userlist=`cat $ffile | while read _user _junk ; do
276                         case $_user in
277                         \#*|'')
278                                 ;;
279                         *)
280                                 echo -n "$userlist $_user"
281                                 ;;
282                         esac
283                 done`
284         fi
285 else
286         while [ $1 ] ; do
287                 userlist="$userlist $1"
288                 shift
289         done
290 fi
291
292 # If the -y or -f switch has been used and the list of users to remove
293 # is empty it is a fatal error. Otherwise, prompt the user for a list
294 # of one or more user names.
295 #
296 if [ ! "$userlist" ]; then
297         if [ $fflag ]; then
298                 err "($ffile) does not exist or does not contain any user names."
299                 exit 1
300         elif [ $yflag ]; then
301                 show_usage
302                 exit 1
303         else
304                 echo -n "Please enter one or more usernames: "
305                 read userlist
306         fi
307 fi
308
309 _user=
310 _uid=
311 for _user in $userlist ; do
312         # Make sure the name exists in the passwd database and that it
313         # does not have a uid of 0
314         #
315         userrec=`pw 2>/dev/null usershow -n $_user`
316         if [ "$?" != "0" ]; then
317                 err "user ($_user) does not exist in the password database."
318                 continue
319         fi
320         _uid=`echo $userrec | awk -F: '{print $3}'`
321         if [ "$_uid" = "0" ]; then
322                 err "user ($_user) has uid 0. You may not remove this user."
323                 continue
324         fi
325
326         # If the -y switch was not used ask for confirmation to remove the
327         # user and home directory.
328         #
329         if [ -z "$yflag" ]; then
330                 echo "Matching password entry:"
331                 echo
332                 echo $userrec
333                 echo
334                 if ! prompt_yesno "Is this the entry you wish to remove? " ; then
335                         continue
336                 fi
337                 _homedir=`echo $userrec | awk -F: '{print $9}'`
338                 if prompt_yesno "Remove user's home directory ($_homedir)? "; then
339                         pw_rswitch="-r"
340                 fi
341         else
342                 pw_rswitch="-r"
343         fi
344
345         # Disable any further attempts to log into this account
346         pw 2>/dev/null lock $_user
347
348         # Remove crontab, mail spool, etc. Then obliterate the user from
349         # the passwd and group database.
350         #
351         ! verbose && echo -n "Removing user ($_user):"
352         rm_crontab $_user
353         rm_at_jobs $_user
354         rm_ipc $_user
355         kill_procs $_user
356         rm_files $_user
357         rm_mail $_user
358         rm_user $_user
359         ! verbose && echo "."
360 done