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