1 | #!/bin/bash |
---|
2 | # |
---|
3 | # Copyright 1995 Hrvoje Dogan, Croatia. |
---|
4 | # Copyright 2002, 2003, 2004 Stuart Winter, West Midlands, England, UK. |
---|
5 | # Copyright 2004 Slackware Linux, Inc., Concord, CA, USA |
---|
6 | # All rights reserved. |
---|
7 | # |
---|
8 | # Redistribution and use of this script, with or without modification, is |
---|
9 | # permitted provided that the following conditions are met: |
---|
10 | # |
---|
11 | # 1. Redistributions of this script must retain the above copyright |
---|
12 | # notice, this list of conditions and the following disclaimer. |
---|
13 | # |
---|
14 | # THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED |
---|
15 | # WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF |
---|
16 | # MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO |
---|
17 | # EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
---|
18 | # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
---|
19 | # PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; |
---|
20 | # OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, |
---|
21 | # WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR |
---|
22 | # OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF |
---|
23 | # ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
---|
24 | # |
---|
25 | # |
---|
26 | ########################################################################## |
---|
27 | # Program: /usr/sbin/adduser |
---|
28 | # Purpose: Interactive front end to /usr/sbin/useradd for Slackware Linux |
---|
29 | # Author : Stuart Winter <stuart@polplex.co.uk> |
---|
30 | # Based on the original Slackware adduser by Hrvoje Dogan |
---|
31 | # with modifications by Patrick Volkerding |
---|
32 | # Version: 1.09 |
---|
33 | ########################################################################## |
---|
34 | # Usage..: adduser [<new_user_name>] |
---|
35 | ########################################################################## |
---|
36 | # History # |
---|
37 | ########### |
---|
38 | # v1.09 - 07/06/04 |
---|
39 | # * Added standard Slackware script licence to the head of this file. |
---|
40 | # v1.08 - 25/04/04 |
---|
41 | # * Disallow user names that begin with a numeric because useradd |
---|
42 | # (from shadow v4.03) does not allow them. <sw> |
---|
43 | # v1.07 - 07/03/03 |
---|
44 | # * When supplying a null string for the uid (meaning 'Choose next available'), |
---|
45 | # if there were file names in the range 'a-z' in the pwd then the |
---|
46 | # egrep command considered these files rather than the null string. |
---|
47 | # The egrep expression is now in quotes. |
---|
48 | # Reported & fixed by Vadim O. Ustiansky <sw> |
---|
49 | # v1.06 - 31/03/03 |
---|
50 | # * Ask to chown user.group the home directory if it already exists. |
---|
51 | # This helps reduce later confusion when adding users whose home dir |
---|
52 | # already exists (mounted partition for example) and is owned |
---|
53 | # by a user other than the user to which the directory is being |
---|
54 | # assigned as home. Default is not to chown. |
---|
55 | # Brought to my attention by mRgOBLIN. <sw> |
---|
56 | # v1.05 - 04/01/03 |
---|
57 | # * Advise & prevent users from creating logins with '.' characters |
---|
58 | # in the user name. <sw> |
---|
59 | # * Made pending account creation info look neater <sw> |
---|
60 | # v1.04 - 09/06/02 |
---|
61 | # * Catered for shadow-4.0.3's 'useradd' binary that no longer |
---|
62 | # will let you create a user that has any uppercase chars in it |
---|
63 | # This was reported on the userlocal.org forums |
---|
64 | # by 'xcp' - thanks. <sw,pjv> |
---|
65 | # v1.03 - 20/05/02 |
---|
66 | # * Support 'broken' (null lines in) /etc/passwd and |
---|
67 | # /etc/group files <sw> |
---|
68 | # * For recycling UIDs (default still 'off'), we now look in |
---|
69 | # /etc/login.defs for the UID_MIN value and use it |
---|
70 | # If not found then default to 1000 <sw> |
---|
71 | # v1.02 - 10/04/02 |
---|
72 | # * Fix user-specified UID bug. <pjv> |
---|
73 | # v1.01 - 23/03/02 |
---|
74 | # * Match Slackware indenting style, simplify. <pjv> |
---|
75 | # v1.00 - 22/03/02 |
---|
76 | # * Created |
---|
77 | ####################################################################### |
---|
78 | |
---|
79 | # Path to files |
---|
80 | pfile=/etc/passwd |
---|
81 | gfile=/etc/group |
---|
82 | sfile=/etc/shells |
---|
83 | |
---|
84 | # Paths to binaries |
---|
85 | useradd=/usr/sbin/useradd |
---|
86 | chfn=/usr/bin/chfn |
---|
87 | passwd=/usr/bin/passwd |
---|
88 | chmod=/bin/chmod |
---|
89 | |
---|
90 | # Defaults |
---|
91 | defhome=/home |
---|
92 | defshell=/bin/bash |
---|
93 | defchmod=711 # home dir permissions - may be preferable to use 701, however. |
---|
94 | defgroup=users |
---|
95 | |
---|
96 | # Determine what the minimum UID is (for UID recycling) |
---|
97 | # (we ignore it if it's not at the beginning of the line (i.e. commented out with #)) |
---|
98 | export recycleUIDMIN="$(grep ^UID_MIN /etc/login.defs | awk '{print $2}' 2>/dev/null)" |
---|
99 | # If we couldn't find it, set it to the default of 1000 |
---|
100 | if [ -z "$recycleUIDMIN" ]; then |
---|
101 | export recycleUIDMIN=1000 # this is the default from Slackware's /etc/login.defs |
---|
102 | fi |
---|
103 | |
---|
104 | |
---|
105 | # This setting enables the 'recycling' of older unused UIDs. |
---|
106 | # When you userdel a user, it removes it from passwd and shadow but it will |
---|
107 | # never get used again unless you specify it expliticly -- useradd (appears to) just |
---|
108 | # look at the last line in passwd and increment the uid. I like the idea of |
---|
109 | # recycling uids but you may have very good reasons not to (old forgotten |
---|
110 | # confidential files still on the system could then be owned by this new user). |
---|
111 | # We'll set this to no because this is what the original adduser shell script |
---|
112 | # did and it's what users expect. |
---|
113 | recycleuids=no |
---|
114 | |
---|
115 | # Function to read keyboard input. |
---|
116 | # bash1 is broken (even ash will take read -ep!), so we work around |
---|
117 | # it (even though bash1 is no longer supported on Slackware). |
---|
118 | function get_input() { |
---|
119 | local output |
---|
120 | if [ "`echo $BASH_VERSION | cut -b1`" = "1" ]; then |
---|
121 | echo -n "${1} " >&2 # fudge for use with bash v1 |
---|
122 | read output |
---|
123 | else # this should work with any other /bin/sh |
---|
124 | read -ep "${1} " output |
---|
125 | fi |
---|
126 | echo $output |
---|
127 | } |
---|
128 | |
---|
129 | # Function to display the account info |
---|
130 | function display () { |
---|
131 | local goose |
---|
132 | goose="$(echo $2 | cut -d ' ' -f 2-)" # lop off the prefixed argument useradd needs |
---|
133 | echo -n "$1 " |
---|
134 | # If it's null then display the 'other' information |
---|
135 | if [ -z "$goose" -a ! -z "$3" ]; then |
---|
136 | echo "$3" |
---|
137 | else |
---|
138 | echo "$goose" |
---|
139 | fi |
---|
140 | } |
---|
141 | |
---|
142 | # Function to check whether groups exist in the /etc/group file |
---|
143 | function check_group () { |
---|
144 | local got_error group |
---|
145 | if [ ! -z "$@" ]; then |
---|
146 | for group in $@ ; do |
---|
147 | local uid_not_named="" uid_not_num="" |
---|
148 | grep -v "$^" $gfile | awk -F: '{print $1}' | grep "^${group}$" >/dev/null 2>&1 || uid_not_named=yes |
---|
149 | grep -v "$^" $gfile | awk -F: '{print $3}' | grep "^${group}$" >/dev/null 2>&1 || uid_not_num=yes |
---|
150 | if [ ! -z "$uid_not_named" -a ! -z "$uid_not_num" ]; then |
---|
151 | echo "- Group '$group' does not exist" |
---|
152 | got_error=yes |
---|
153 | fi |
---|
154 | done |
---|
155 | fi |
---|
156 | # Return exit code of 1 if at least one of the groups didn't exist |
---|
157 | if [ ! -z "$got_error" ]; then |
---|
158 | return 1 |
---|
159 | fi |
---|
160 | } |
---|
161 | |
---|
162 | #: Read the login name for the new user :# |
---|
163 | # |
---|
164 | # Remember that most Mail Transfer Agents are case independant, so having |
---|
165 | # 'uSer' and 'user' may cause confusion/things to break. Because of this, |
---|
166 | # useradd from shadow-4.0.3 no longer accepts usernames containing uppercase, |
---|
167 | # and we must reject them, too. |
---|
168 | |
---|
169 | # Set the login variable to the command line param |
---|
170 | echo |
---|
171 | LOGIN="$1" |
---|
172 | needinput=yes |
---|
173 | while [ ! -z $needinput ]; do |
---|
174 | if [ -z "$LOGIN" ]; then |
---|
175 | while [ -z "$LOGIN" ]; do LOGIN="$(get_input "Login name for new user []:")" ; done |
---|
176 | fi |
---|
177 | grep "^${LOGIN}:" $pfile >/dev/null 2>&1 # ensure it's not already used |
---|
178 | if [ $? -eq 0 ]; then |
---|
179 | echo "- User '$LOGIN' already exists; please choose another" |
---|
180 | unset LOGIN |
---|
181 | elif [ ! -z "$( echo $LOGIN | grep "^[0-9]" )" ]; then |
---|
182 | echo "- User names cannot begin with a number; please choose another" |
---|
183 | unset LOGIN |
---|
184 | elif [ ! "$LOGIN" = "`echo $LOGIN | tr A-Z a-z`" ]; then # useradd does not allow uppercase |
---|
185 | echo "- User '$LOGIN' contains illegal characters (uppercase); please choose another" |
---|
186 | unset LOGIN |
---|
187 | elif [ ! -z "$( echo $LOGIN | grep '\.' )" ]; then |
---|
188 | echo "- User '$LOGIN' contains illegal characters (period/dot); please choose another" |
---|
189 | unset LOGIN |
---|
190 | else |
---|
191 | unset needinput |
---|
192 | fi |
---|
193 | done |
---|
194 | |
---|
195 | # Display the user name passed from the shell if it hasn't changed |
---|
196 | if [ "$1" = "$LOGIN" ]; then |
---|
197 | echo "Login name for new user: $LOGIN" |
---|
198 | fi |
---|
199 | |
---|
200 | #: Get the UID for the user & ensure it's not already in use :# |
---|
201 | # |
---|
202 | # Whilst we _can_ allow users with identical UIDs, it's not a 'good thing' because |
---|
203 | # when you change password for the uid, it finds the first match in /etc/passwd |
---|
204 | # which isn't necessarily the correct user |
---|
205 | # |
---|
206 | echo |
---|
207 | needinput=yes |
---|
208 | while [ ! -z "$needinput" ]; do |
---|
209 | _UID="$(get_input "User ID ('UID') [ defaults to next available ]:")" |
---|
210 | grep -v "^$" $pfile | awk -F: '{print $3}' | grep "^${_UID}$" >/dev/null 2>&1 |
---|
211 | if [ $? -eq 0 ]; then |
---|
212 | echo "- That UID is already in use; please choose another" |
---|
213 | elif [ ! -z "$(echo $_UID | egrep '[A-Za-z]')" ]; then |
---|
214 | echo "- UIDs are numerics only" |
---|
215 | else |
---|
216 | unset needinput |
---|
217 | fi |
---|
218 | done |
---|
219 | # If we were given a UID, then syntax up the variable to pass to useradd |
---|
220 | if [ ! -z "$_UID" ]; then |
---|
221 | U_ID="-u ${_UID}" |
---|
222 | else |
---|
223 | # Will we be recycling UIDs? |
---|
224 | if [ "$recycleuids" = "yes" ]; then |
---|
225 | U_ID="-u $(awk -F: '{uid[$3]=1} END { for (i=ENVIRON["recycleUIDMIN"];i in uid;i++);print i}' $pfile)" |
---|
226 | fi |
---|
227 | fi |
---|
228 | |
---|
229 | #: Get the initial group for the user & ensure it exists :# |
---|
230 | # |
---|
231 | # We check /etc/group for both the text version and the group ID number |
---|
232 | echo |
---|
233 | needinput=yes |
---|
234 | while [ ! -z "$needinput" ]; do |
---|
235 | GID="$(get_input "Initial group [ ${defgroup} ]:")" |
---|
236 | check_group "$GID" |
---|
237 | if [ $? -gt 0 ]; then |
---|
238 | echo "- Please choose another" |
---|
239 | else |
---|
240 | unset needinput |
---|
241 | fi |
---|
242 | done |
---|
243 | # Syntax the variable ready for useradd |
---|
244 | if [ -z "$GID" ]; then |
---|
245 | GID="-g ${defgroup}" |
---|
246 | else |
---|
247 | GID="-g ${GID}" |
---|
248 | fi |
---|
249 | |
---|
250 | #: Get additional groups for the user :# |
---|
251 | # |
---|
252 | echo |
---|
253 | needinput=yes |
---|
254 | while [ ! -z "$needinput" ]; do |
---|
255 | AGID="$(get_input "Additional groups (comma separated) []:")" |
---|
256 | AGID="$(echo "$AGID" | tr -d ' ' | tr , ' ')" # fix up for parsing |
---|
257 | if [ ! -z "$AGID" ]; then |
---|
258 | check_group "$AGID" # check all groups at once (treated as N # of params) |
---|
259 | if [ $? -gt 0 ]; then |
---|
260 | echo "- Please re-enter the group(s)" |
---|
261 | else |
---|
262 | unset needinput # we found all groups specified |
---|
263 | AGID="-G $(echo "$AGID" | tr ' ' ,)" |
---|
264 | fi |
---|
265 | else |
---|
266 | unset needinput # we don't *have* to have additional groups |
---|
267 | fi |
---|
268 | done |
---|
269 | |
---|
270 | #: Get the new user's home dir :# |
---|
271 | # |
---|
272 | echo |
---|
273 | needinput=yes |
---|
274 | while [ ! -z "$needinput" ]; do |
---|
275 | HME="$(get_input "Home directory [ ${defhome}/${LOGIN} ]")" |
---|
276 | if [ -z "$HME" ]; then |
---|
277 | HME="${defhome}/${LOGIN}" |
---|
278 | fi |
---|
279 | # Warn the user if the home dir already exists |
---|
280 | if [ -d "$HME" ]; then |
---|
281 | echo "- Warning: '$HME' already exists !" |
---|
282 | getyn="$(get_input " Do you wish to change the home directory path ? (Y/n) ")" |
---|
283 | if [ "$(echo $getyn | grep -i "n")" ]; then |
---|
284 | unset needinput |
---|
285 | # You're most likely going to only do this if you have the dir *mounted* for this user's $HOME |
---|
286 | getyn="$(get_input " Do you want to chown $LOGIN.$( echo $GID | awk '{print $2}') $HME ? (y/N) ")" |
---|
287 | if [ "$(echo $getyn | grep -i "y")" ]; then |
---|
288 | CHOWNHOMEDIR=$HME # set this to the home directory |
---|
289 | fi |
---|
290 | fi |
---|
291 | else |
---|
292 | unset needinput |
---|
293 | fi |
---|
294 | done |
---|
295 | HME="-d ${HME}" |
---|
296 | |
---|
297 | #: Get the new user's shell :# |
---|
298 | echo |
---|
299 | needinput=yes |
---|
300 | while [ ! -z "$needinput" ]; do |
---|
301 | unset got_error |
---|
302 | SHL="$(get_input "Shell [ ${defshell} ]")" |
---|
303 | if [ -z "$SHL" ]; then |
---|
304 | SHL="${defshell}" |
---|
305 | fi |
---|
306 | # Warn the user if the shell doesn't exist in /etc/shells or as a file |
---|
307 | if [ -z "$(grep "^${SHL}$" $sfile)" ]; then |
---|
308 | echo "- Warning: ${SHL} is not in ${sfile} (potential problem using FTP)" |
---|
309 | got_error=yes |
---|
310 | fi |
---|
311 | if [ ! -f "$SHL" ]; then |
---|
312 | echo "- Warning: ${SHL} does not exist as a file" |
---|
313 | got_error=yes |
---|
314 | fi |
---|
315 | if [ ! -z "$got_error" ]; then |
---|
316 | getyn="$(get_input " Do you wish to change the shell ? (Y/n) ")" |
---|
317 | if [ "$(echo $getyn | grep -i "n")" ]; then |
---|
318 | unset needinput |
---|
319 | fi |
---|
320 | else |
---|
321 | unset needinput |
---|
322 | fi |
---|
323 | done |
---|
324 | SHL="-s ${SHL}" |
---|
325 | |
---|
326 | #: Get the expiry date :# |
---|
327 | echo |
---|
328 | needinput=yes |
---|
329 | while [ ! -z "$needinput" ]; do |
---|
330 | EXP="$(get_input "Expiry date (YYYY-MM-DD) []:")" |
---|
331 | if [ ! -z "$EXP" ]; then |
---|
332 | # Check to see whether the expiry date is in the valid format |
---|
333 | if [ -z "$(echo "$EXP" | grep "^[[:digit:]]\{4\}[-]\?[[:digit:]]\{2\}[-]\?[[:digit:]]\{2\}$")" ]; then |
---|
334 | echo "- That is not a valid expiration date" |
---|
335 | else |
---|
336 | unset needinput |
---|
337 | EXP="-e ${EXP}" |
---|
338 | fi |
---|
339 | else |
---|
340 | unset needinput |
---|
341 | fi |
---|
342 | done |
---|
343 | |
---|
344 | # Display the info about the new impending account |
---|
345 | echo |
---|
346 | echo "New account will be created as follows:" |
---|
347 | echo |
---|
348 | echo "---------------------------------------" |
---|
349 | display "Login name.......: " "$LOGIN" |
---|
350 | display "UID..............: " "$_UID" "[ Next available ]" |
---|
351 | display "Initial group....: " "$GID" |
---|
352 | display "Additional groups: " "$AGID" "[ None ]" |
---|
353 | display "Home directory...: " "$HME" |
---|
354 | display "Shell............: " "$SHL" |
---|
355 | display "Expiry date......: " "$EXP" "[ Never ]" |
---|
356 | echo |
---|
357 | |
---|
358 | echo "This is it... if you want to bail out, hit Control-C. Otherwise, press" |
---|
359 | echo "ENTER to go ahead and make the account." |
---|
360 | read junk |
---|
361 | |
---|
362 | echo |
---|
363 | echo "Creating new account..." |
---|
364 | echo |
---|
365 | echo |
---|
366 | |
---|
367 | # Add the account to the system |
---|
368 | CMD="$useradd "$HME" -m "$EXP" "$U_ID" "$GID" "$AGID" "$SHL" "$LOGIN"" |
---|
369 | $CMD |
---|
370 | |
---|
371 | if [ $? -gt 0 ]; then |
---|
372 | echo "- Error running useradd command -- account not created!" |
---|
373 | echo "(cmd: $CMD)" |
---|
374 | exit 1 |
---|
375 | fi |
---|
376 | |
---|
377 | # chown the home dir ? We can only do this once the useradd has |
---|
378 | # completed otherwise the user name doesn't exist. |
---|
379 | if [ ! -z "${CHOWNHOMEDIR}" ]; then |
---|
380 | chown "$LOGIN"."$( echo $GID | awk '{print $2}')" "${CHOWNHOMEDIR}" |
---|
381 | fi |
---|
382 | |
---|
383 | # Set the finger information |
---|
384 | $chfn "$LOGIN" |
---|
385 | if [ $? -gt 0 ]; then |
---|
386 | echo "- Warning: an error occurred while setting finger information" |
---|
387 | fi |
---|
388 | |
---|
389 | # Set a password |
---|
390 | $passwd "$LOGIN" |
---|
391 | if [ $? -gt 0 ]; then |
---|
392 | echo "* WARNING: An error occured while setting the password for" |
---|
393 | echo " this account. Please manually investigate this *" |
---|
394 | exit 1 |
---|
395 | fi |
---|
396 | |
---|
397 | # If it was created (it should have been!), set the permissions for that user's dir |
---|
398 | HME="$(echo "$HME" | awk '{print $2}')" # We have to remove the -g prefix |
---|
399 | if [ -d "$HME" ]; then |
---|
400 | $chmod $defchmod "$HME" |
---|
401 | fi |
---|
402 | |
---|
403 | echo |
---|
404 | echo |
---|
405 | echo "Account setup complete." |
---|
406 | exit 0 |
---|
407 | |
---|