/[adduser]/trunk/adduser
ViewVC logotype

Contents of /trunk/adduser

Parent Directory Parent Directory | Revision Log Revision Log


Revision 720 - (show annotations) (download)
Sat Feb 24 18:35:22 2007 UTC (6 years, 3 months ago) by joerghoh-guest
File size: 33658 byte(s)
be more verbose; breaks i18n templatessvn diff
1 #!/usr/bin/perl
2
3 # adduser: a utility to add users to the system
4 # addgroup: a utility to add groups to the system
5 my $version = "VERSION";
6
7 # Copyright (C) 1997, 1998, 1999 Guy Maor <maor@debian.org>
8 # Copyright (C) 1995 Ted Hajek <tedhajek@boombox.micro.umn.edu>
9 # Ian A. Murdock <imurdock@gnu.ai.mit.edu>
10 # Bugfixes and other improvements Roland Bauerschmidt <rb@debian.org>
11 # General scheme of the program adapted by the original debian 'adduser'
12 # program by Ian A. Murdock <imurdock@gnu.ai.mit.edu>.
13 #
14 # This program is free software; you can redistribute it and/or modify
15 # it under the terms of the GNU General Public License as published by
16 # the Free Software Foundation; either version 2 of the License, or
17 # (at your option) any later version.
18 #
19 # This program is distributed in the hope that it will be useful,
20 # but WITHOUT ANY WARRANTY; without even the implied warranty of
21 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 # GNU General Public License for more details.
23 #
24 # You should have received a copy of the GNU General Public License
25 # along with this program; if not, write to the Free Software
26 # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
27 #
28 #
29 ####################
30 # See the usage subroutine for explanation about how the program can be called
31 ####################
32
33 use warnings;
34 use strict;
35 use Debian::AdduserCommon;
36 use Getopt::Long;
37
38 BEGIN {
39 eval 'use Locale::gettext';
40 if ($@) {
41 *gettext = sub { shift };
42 *textdomain = sub { "" };
43 *LC_MESSAGES = sub { 5 };
44 }
45 eval {
46 require POSIX;
47 import POSIX qw(setlocale);
48 };
49 if ($@) {
50 *setlocale = sub { return 1 };
51 }
52 eval {
53 require I18N::Langinfo;
54 import I18N::Langinfo qw(langinfo YESEXPR NOEXPR);
55 };
56 if ($@) {
57 *langinfo = sub { return shift; };
58 *YESEXPR = sub { "^[yY]" };
59 *NOEXPR = sub { "^[nN]" };
60 }
61 }
62
63 setlocale(LC_MESSAGES, "");
64 textdomain("adduser");
65 my $yesexpr = langinfo(YESEXPR());
66
67 my %config; # configuration hash
68
69 my @defaults = ("/etc/adduser.conf");
70 my $nogroup_id = getgrnam("nogroup") || 65534;
71 $0 =~ s+.*/++;
72
73 our $verbose = 1; # should we be verbose?
74 my $allow_badname = 0; # should we allow bad names?
75 my $ask_passwd = 1; # ask for a passwd?
76 my $disabled_login = 0; # leave the new account disabled?
77
78 our $configfile = undef;
79 our $found_group_opt = undef;
80 our $found_sys_opt = undef;
81 our $ingroup_name = undef;
82 our $new_firstuid = undef;
83 our $new_gecos = undef;
84 our $new_gid = undef;
85 our $new_lastuid = undef;
86 our $new_uid = undef;
87 our $no_create_home = undef;
88 our $special_home = undef;
89 our $special_shell = undef;
90 our $add_extra_groups = 0;
91
92 # Global variables we need later
93 my $existing_user = undef;
94 my $existing_group = undef;
95 my $new_name = undef;
96 my $make_group_also = 0;
97 my $home_dir = undef;
98 my $undohome = undef;
99 my $undouser = undef;
100 my $undogroup = undef;
101 my $shell = undef;
102 my $first_uid = undef;
103 my $last_uid = undef;
104 my $dir_mode = undef;
105 my $perm = undef;
106
107 our @names;
108
109 # Parse options, sanity checks
110 unless ( GetOptions ("quiet|q" => sub { $verbose = 0 },
111 "force-badname" => \$allow_badname,
112 "help|h" => sub { &usage(); exit 1 },
113 "version|v" => sub { &version(); exit 1 },
114 "system" => \$found_sys_opt,
115 "group" => \$found_group_opt,
116 "ingroup=s" => \$ingroup_name,
117 "home=s" => \$special_home,
118 "gecos=s" => \$new_gecos,
119 "shell=s" => \$special_shell,
120 "disabled-password" => sub { $ask_passwd = 0 },
121 "disabled-login" => sub { $disabled_login = 1; $ask_passwd = 0 },
122 "uid=i" => \$new_uid,
123 "firstuid=i" => \$new_firstuid,
124 "lastuid=i" => \$new_lastuid,
125 "gid=i" => \$new_gid,
126 "conf=s" => \$configfile,
127 "no-create-home" => \$no_create_home,
128 "add_extra_groups" => \$add_extra_groups,
129 "debug" => sub { $verbose = 2 } ) ) {
130 &usage();
131 exit 1;
132 }
133
134 # everyone can issue "--help" and "--version", but only root can go on
135 dief (gtx("Only root may add a user or group to the system.\n")) if ($> != 0);
136
137 if( defined($configfile) ) { @defaults = ($configfile); }
138
139 # detect the right mode
140 my $action = $0 eq "addgroup" ? "addgroup" : "adduser";
141 if (defined($found_sys_opt)) {
142 $action = "addsysuser" if ($action eq "adduser");
143 $action = "addsysgroup" if ($action eq "addgroup");
144 }
145
146
147
148 ############################
149 # checks related to @names #
150 ############################
151
152
153 while (defined(my $arg = shift(@ARGV))) {
154 push (@names, $arg);
155 }
156
157 if ( (! defined $names[0]) || length($names[0]) == 0 || @names > 2) {
158 dief (gtx("Only one or two names allowed.\n"));
159 }
160
161
162 if (@names == 2) { # must be addusertogroup
163 dief (gtx("Specify only one name in this mode.\n"))
164 if ($action eq "addsysuser" || $found_group_opt);
165 $action = "addusertogroup";
166 $existing_user = shift (@names);
167 $existing_group = shift (@names);
168 }
169 else {
170 $new_name = shift (@names);
171 }
172
173 ###################################
174 # check for consistent parameters #
175 ###################################
176
177 if ($action ne "addgroup" &&
178 defined($found_group_opt) +defined($ingroup_name) +defined($new_gid) > 1 ) {
179 dief (gtx("The --group, --ingroup, and --gid options are mutually exclusive.\n"));
180 }
181
182
183 if ((defined($special_home)) && ($special_home !~ m+^/+ )) {
184 dief (gtx("The home dir must be an absolute path.\n"));
185 }
186
187 if (defined($special_home) && $verbose) {
188 print gtx("Warning: The home dir you specified already exists.\n")
189 if (!defined($no_create_home) && -d $special_home);
190 # post etch: see 399992
191 #print gtx("Warning: The home dir you specified can't be accessed: $!\n")
192 print gtx("Warning: The home dir you specified does not exist.\n")
193 if (defined($no_create_home) && ! -d $special_home);
194 }
195
196
197 if ($found_group_opt) {
198 if ($action eq "addsysuser") {
199 $make_group_also = 1;
200 }
201 elsif ($found_sys_opt) {
202 $action = "addsysgroup";
203 }
204 else {
205 $action = "addgroup";
206 }
207 }
208
209
210 $ENV{"VERBOSE"} = $verbose;
211 $ENV{"DEBUG"} = $verbose;
212
213
214 # preseed configuration data and then read the config file
215 preseed_config(\@defaults,\%config);
216
217 &checkname($new_name) if defined $new_name;
218 $SIG{'INT'} = $SIG{'QUIT'} = $SIG{'HUP'} = 'handler';
219
220 #####
221 # OK, we've processed the arguments. $action equals one of the following,
222 # and the appropriate variables have been set:
223 #
224 # $action = "adduser"
225 # $new_name - the name of the new user.
226 # $ingroup_name | $new_gid - the group to add the user to
227 # $special_home, $new_uid, $new_gecos - optional overrides
228 # $action = "addgroup"
229 # $new_name - the name of the new group
230 # $new_gid - optional override
231 # $action = "addsysgroup"
232 # $new_name - the name of the new group
233 # $new_gid - optional override
234 # $action = "addsysuser"
235 # $new_name - the name of the new user
236 # $make_group_also | $ingroup_name | $new_gid | 0 - which group
237 # $special_home, $new_uid, $new_gecos - optional overrides
238 # $action = "addusertogroup"
239 # $existing_user - the user to be added
240 # $existing_group - the group to add her to
241 #####
242
243
244 #################
245 ## addsysgroup ##
246 #################
247 if ($action eq "addsysgroup") {
248
249 # Check if requested group already exists and we can exit safely
250 my $ret = existing_group_ok($new_name, $new_gid);
251
252 if ($ret == 3) {
253 print STDERR "$0: " if $verbose;
254 printf STDERR (gtx("The group `%s' already exists as a system group. Exiting.\n"), $new_name) if $verbose;
255 exit 0;
256 }
257
258 if ($ret == 1) {
259 print STDERR "$0: " if $verbose;
260 printf STDERR (gtx("The group `%s' already exists and is not a system group. Exiting.\n"), $new_name) if $verbose;
261 exit 1;
262 }
263
264 if ($ret == 2) {
265 print STDERR "$0: " if $verbose;
266 printf STDERR (gtx("The group `%s' already exists, but has a different GID. Exiting.\n"), $new_name) if $verbose;
267 exit 1;
268 }
269
270 dief (gtx("The group `%s' already exists and is not a system group.\n"),$new_name)
271 if (defined getgrnam($new_name));
272 dief (gtx("The GID `%s' is already in use.\n"),$new_gid)
273 if (defined($new_gid) && defined(getgrgid($new_gid)));
274
275 if (!defined($new_gid)) {
276 $new_gid = &first_avail_gid($config{"first_system_gid"},
277 $config{"last_system_gid"});
278 if ($new_gid == -1) {
279 print STDERR "$0: ";
280 printf STDERR gtx("No GID is available in the range %d-%d (FIRST_SYS_GID - LAST_SYS_GID).\n"),$config{"first_system_gid"},$config{"last_system_gid"};
281 dief (gtx("The group `%s' was not created.\n"),$new_name);
282 }
283 }
284
285
286 printf (gtx("Adding group `%s' (GID %d) ...\n"),$new_name,$new_gid) if $verbose;
287 &invalidate_nscd("group");
288 my $groupadd = &which('groupadd');
289 &systemcall($groupadd, '-g', $new_gid, $new_name);
290 &invalidate_nscd("group");
291 print (gtx("Done.\n")) if $verbose;
292 exit 0;
293 }
294
295
296 ##############
297 ## addgroup ##
298 ##############
299 if ($action eq "addgroup") {
300 dief (gtx("The group `%s' already exists.\n"),$new_name)
301 if (defined getgrnam($new_name));
302 dief (gtx("The GID `%s' is already in use.\n"),$new_gid)
303 if (defined($new_gid) && defined(getgrgid($new_gid)));
304 if (!defined($new_gid)) {
305 $new_gid = &first_avail_gid($config{"first_gid"},
306 $config{"last_gid"});
307
308 if ($new_gid == -1) {
309 print STDERR "$0: ";
310 printf STDERR gtx("No GID is available in the range %d-%d (FIRST_GID - LAST_GID).\n"),$config{"first_gid"},$config{"last_gid"};
311 dief (gtx("The group `%s' was not created.\n"),$new_name);
312 }
313 }
314
315 printf (gtx("Adding group `%s' (GID %d) ...\n"),$new_name,$new_gid) if $verbose;
316 &invalidate_nscd("group");
317 my $groupadd = &which('groupadd');
318 &systemcall($groupadd, '-g', $new_gid, $new_name);
319 &invalidate_nscd("group");
320 print (gtx("Done.\n")) if $verbose;
321 exit 0;
322 }
323
324
325 ####################
326 ## addusertogroup ##
327 ####################
328 if ($action eq "addusertogroup") {
329 dief (gtx("The user `%s' does not exist.\n"),$existing_user)
330 if (!defined getpwnam($existing_user));
331 dief (gtx("The group `%s' does not exist.\n"),$existing_group)
332 if (!defined getgrnam($existing_group));
333 if (&user_is_member($existing_user, $existing_group)) {
334 printf gtx("The user `%s' is already a member of `%s'.\n"),
335 $existing_user,$existing_group if $verbose;
336 exit 0; # not really an error
337 }
338
339 printf gtx("Adding user `%s' to group `%s' ...\n"),$existing_user,$existing_group
340 if $verbose;
341 &invalidate_nscd();
342 # FIXME - the next line has a race condition.
343 #&systemcall('usermod', '-G',
344 #join(",", get_users_groups($existing_user), $existing_group),
345 #$existing_user);
346 my $gpasswd = &which('gpasswd');
347 &systemcall($gpasswd, '-M',
348 join(',', get_group_members($existing_group), $existing_user),
349 $existing_group);
350 #&systemcall('gpasswd', '-a',$existing_user,$existing_group);
351 &invalidate_nscd();
352 print (gtx("Done.\n")) if $verbose;
353 exit 0;
354 }
355
356
357 ################
358 ## addsysuser ##
359 ################
360 if ($action eq "addsysuser") {
361 if (existing_user_ok($new_name, $new_uid) == 1) {
362 printf (gtx("The user `%s' already exists as a system user. Exiting.\n"), $new_name) if $verbose;
363 exit 0;
364 }
365 if (existing_user_ok($new_name, $new_uid) == 2) {
366 printf (gtx("The user `%s' already exists with a different UID. Exiting.\n"), $new_name) if $verbose;
367 exit 1;
368 }
369
370 if (!$ingroup_name && !defined($new_gid) && !$make_group_also) {
371 $new_gid = $nogroup_id;
372 }
373 check_user_group(1);
374
375 if (!defined($new_uid) && $make_group_also) {
376 $new_uid = &first_avail_uid($config{"first_system_uid"},
377 $config{"last_system_uid"});
378 if ($new_uid == -1) {
379 print STDERR "$0: ";
380 printf STDERR gtx("No UID/GID pair is available in the range %d-%d (FIRST_SYS_UID - LAST_SYS_UID).\n"),$config{"first_system_uid"},$config{"last_system_uid"};
381 dief (gtx("The user `%s' was not created.\n"),$new_name);
382 }
383 $new_gid = &first_avail_gid($config{"first_system_gid"},
384 $config{"last_system_gid"});
385 $ingroup_name = $new_name;
386 }
387 elsif (!defined($new_uid) && !$make_group_also) {
388 $new_uid = &first_avail_uid($config{"first_system_uid"},
389 $config{"last_system_uid"});
390 if ($new_uid == -1) {
391 print STDERR "$0: ";
392 printf STDERR gtx("No UID is available in the range %d-%d (FIRST_SYS_UID - LAST_SYS_UID).\n"),$config{"first_system_uid"},$config{"last_system_uid"};
393 dief (gtx("The user `%s' was not created.\n"),$new_name);
394 }
395 if (defined($new_gid)) { $ingroup_name = getgrgid($new_gid); }
396 elsif ($ingroup_name) { $new_gid = getgrnam($ingroup_name); }
397 else { dief (gtx("Internal error")); }
398 }
399 else {
400 if (defined($new_gid)) { $ingroup_name = getgrgid($new_gid); }
401 elsif ($ingroup_name) { $new_gid = getgrnam($ingroup_name); }
402 elsif ($make_group_also){ $new_gid=$new_uid; $ingroup_name=$new_name; }
403 else { dief (gtx("Internal error")); }
404 }
405 printf (gtx("Adding system user `%s' (UID %d) ...\n"),$new_name,$new_uid) if $verbose;
406
407 &invalidate_nscd();
408 # if we reach this point, and the group does already exist, we can use it.
409 if ($make_group_also && !getgrnam($new_name)) {
410 printf (gtx("Adding new group `%s' (GID %d) ...\n"),$new_name,$new_gid) if $verbose;
411 $undogroup = $new_name;
412 my $groupadd = &which('groupadd');
413 &systemcall($groupadd, '-g', $new_gid, $new_name);
414 &invalidate_nscd("group");
415 }
416
417 printf gtx("Adding new user `%s' (UID %d) with group `%s' ...\n"),$new_name,$new_uid,$ingroup_name
418 if $verbose;
419 $home_dir = $special_home || &homedir($new_name, $ingroup_name);
420 $shell = $special_shell || '/bin/false';
421 $undouser = $new_name;
422 my $useradd = &which('useradd');
423 &systemcall($useradd, '-d', $home_dir, '-g', $ingroup_name, '-s',
424 $shell, '-u', $new_uid, $new_name);
425 my $chage = &which('chage');
426 print "$chage -M 99999 $new_name\n" if ($verbose > 1);
427 # do _not_ use systemcall() here, since systemcall() dies on
428 # non-zero exit code and we need to do special handling here!
429 if (system($chage, '-M', '99999', $new_name)) {
430 if( ($?>>8) ne 15 ) {
431 &cleanup(sprintf((gtx("`%s' returned error code %d. Exiting.\n")), "$chage -M 99999 $new_name", $?>>8))
432 if ($?>>8);
433 &cleanup(sprintf((gtx("`%s' exited from signal %d. Exiting.\n")), "$chage -M 99999 $new_name", $?&255));
434 } else {
435 printf (gtx("%s failed with return code 15, shadow not enabled, password aging cannot be set. Continuing.\n"), $chage);
436 }
437 }
438 &invalidate_nscd();
439
440 if(defined($new_gecos)) {
441 &ch_gecos($new_gecos);
442 }
443
444 create_homedir (0);
445
446 exit 0;
447 }
448
449
450 #############
451 ## adduser ##
452 #############
453 if ($action eq "adduser") {
454 if (!$ingroup_name && !defined($new_gid)) {
455 if ($config{"usergroups"} =~ /yes/i) { $make_group_also = 1; }
456 else { $new_gid = $config{"users_gid"}; }
457 }
458 check_user_group(0);
459 $first_uid = $new_firstuid || $config{"first_uid"};
460 $last_uid = $new_lastuid || $config{"last_uid"};
461 printf (gtx("Adding user `%s' ...\n"),$new_name) if $verbose;
462
463 if (!defined($new_uid) && $make_group_also) {
464 $new_uid = &first_avail_uid($first_uid,
465 $last_uid);
466
467 if ($new_uid == -1) {
468 print STDERR "$0: ";
469 printf STDERR gtx("No UID/GID pair is available in the range %d-%d (FIRST_UID - LAST_UID).\n"),$first_uid,$last_uid;
470 dief (gtx("The user `%s' was not created.\n"),$new_name);
471 }
472 $new_gid = &first_avail_gid($config{"first_gid"},
473 $config{"last_gid"});
474 $ingroup_name = $new_name;
475 }
476 elsif (!defined($new_uid) && !$make_group_also) {
477 $new_uid = &first_avail_uid($first_uid,
478 $last_uid);
479 if ($new_uid == -1) {
480 print STDERR "$0: ";
481 printf STDERR gtx("No UID is available in the range %d-%d (FIRST_UID - LAST_UID).\n"),$config{"first_uid"},$config{"last_uid"};
482 dief (gtx("The user `%s' was not created.\n"),$new_name);
483 }
484 if (defined($new_gid)) { $ingroup_name = getgrgid($new_gid); }
485 elsif ($ingroup_name) { $new_gid = getgrnam($ingroup_name); }
486 else { dief (gtx("Internal error")); }
487 }
488 else {
489 if (defined($new_gid)) { $ingroup_name = getgrgid($new_gid); }
490 elsif ($ingroup_name) { $new_gid = getgrnam($ingroup_name); }
491 elsif ($make_group_also){ $new_gid=$new_uid; $ingroup_name=$new_name; }
492 else { dief (gtx("Internal error")); }
493 }
494
495 &invalidate_nscd();
496 if ($make_group_also) {
497 printf (gtx("Adding new group `%s' (%d) ...\n"),$new_name,$new_gid) if $verbose;
498 $undogroup = $new_name;
499 my $groupadd = &which('groupadd');
500 &systemcall($groupadd, '-g', $new_gid, $new_name);
501 &invalidate_nscd();
502 }
503
504 printf gtx("Adding new user `%s' (%d) with group `%s' ...\n"),$new_name,$new_uid,$ingroup_name
505 if $verbose;
506 $home_dir = $special_home || &homedir($new_name, $ingroup_name);
507 $shell = $special_shell || $config{"dshell"};
508 $undouser = $new_name;
509 my $useradd = &which('useradd');
510 &systemcall($useradd, '-d', $home_dir, '-g', $ingroup_name, '-s',
511 $shell, '-u', $new_uid, $new_name);
512 &invalidate_nscd();
513
514 create_homedir (1); # copy skeleton data
515
516 # useradd without -p has left the account disabled (password string is '!')
517 if ($ask_passwd) {
518 for (;;) {
519 my $passwd = &which('passwd');
520 # do _not_ use systemcall() here, since systemcall() dies on
521 # non-zero exit code and we need to do special handling here!
522 system($passwd, $new_name);
523 my $ok = $?>>8;
524 if ($ok != 0) {
525 my $noexpr = langinfo(NOEXPR());
526 my $answer;
527 # hm, error, should we break now?
528 print (gtx("Permission denied\n")) if ($ok == 1);
529 print (gtx("invalid combination of options\n")) if ($ok == 2);
530 print (gtx("unexpected failure, nothing done\n")) if ($ok == 3);
531 print (gtx("unexpected failure, passwd file missing\n")) if ($ok == 3);
532 print (gtx("passwd file busy, try again\n")) if ($ok == 4);
533 print (gtx("invalid argument to option\n")) if ($ok == 5);
534
535 # Translators: [Y/n] has to be replaced by values defined in your
536 # locale. You can see by running "locale noexpr" which regular
537 # expression will be checked to find positive answer.
538 print (gtx("Try again? [Y/n] "));
539 chop ($answer=<STDIN>);
540 last if ($answer =~ m/$noexpr/o);
541 }
542 else {
543 last; ## passwd ok
544 }
545 }
546 } else {
547 if(!$disabled_login) {
548 my $usermod = &which('usermod');
549 &systemcall($usermod, '-p', '*', $new_name);
550 }
551 }
552
553 if (defined($new_gecos)) {
554 &ch_gecos($new_gecos);
555 }
556 else {
557 my $yesexpr = langinfo(YESEXPR());
558 for (;;) {
559 my $chfn = &which('chfn');
560 &systemcall($chfn, $new_name);
561 # Translators: [y/N] has to be replaced by values defined in your
562 # locale. You can see by running "locale yesexpr" which regular
563 # expression will be checked to find positive answer.
564 print (gtx("Is the information correct? [y/N] "));
565 chop (my $answer=<STDIN>);
566 last if ($answer =~ m/$yesexpr/o);
567 }
568 }
569
570 if ( ( $add_extra_groups || $config{"add_extra_groups"} ) && defined($config{"extra_groups"}) ) {
571 printf (gtx("Adding new user `%s' to extra groups ...\n"), $new_name);
572 foreach my $newgrp ( split ' ', $config{"extra_groups"} ) {
573 if (!defined getgrnam($newgrp)) {
574 warnf (gtx("The group `%s' does not exist.\n"),$newgrp);
575 next;
576 }
577 if (&user_is_member($new_name, $newgrp)) {
578 printf gtx("The user `%s' is already a member of `%s'.\n"),
579 $new_name,$newgrp if $verbose;
580 next;
581
582 }
583
584 printf gtx("Adding user `%s' to group `%s' ...\n"),$new_name,$newgrp
585 if $verbose;
586 &invalidate_nscd();
587 my $gpasswd = &which('gpasswd');
588 &systemcall($gpasswd, '-M',
589 join(',', get_group_members($newgrp), $new_name),
590 $newgrp);
591 &invalidate_nscd();
592 }
593 }
594
595
596 if ($config{"quotauser"}) {
597 printf (gtx("Setting quota for user `%s' to values of user `%s' ...\n"), $new_name, $config{quotauser});
598 my $edquota = &which('edquota');
599 &systemcall($edquota, '-p', $config{quotauser}, $new_name);
600 }
601
602 &systemcall('/usr/local/sbin/adduser.local', $new_name, $new_uid,
603 $new_gid, $home_dir) if (-x "/usr/local/sbin/adduser.local");
604
605 exit 0;
606 }
607
608 #
609 # we never go here
610 #
611
612
613 # calculate home directory
614 sub homedir {
615 my $dir = $config{"dhome"};
616 $dir .= '/' . $_[1] if ($config{"grouphomes"} =~ /yes/i);
617 $dir .= '/' . substr($_[0],0,1) if ($config{"letterhomes"} =~ /yes/i);
618 $dir .= '/' . $_[0];
619 return $dir;
620 }
621
622
623 # create_homedir -- create the homedirectory
624 # parameter
625 # 1: $copy_skeleton:
626 # if 0 -> don't copy the skeleton data
627 # if 1 -> copy the files in /etc/skel to the newly created home directory
628 # return values:
629 # none
630 sub create_homedir {
631 my ($copy_skeleton) = @_;
632
633 if ($no_create_home) {
634 printf gtx("Not creating home directory `%s'.\n"), $home_dir if $verbose;
635 }
636 elsif (-e $home_dir) {
637 printf gtx("The home directory `%s' already exists. Not copying from `%s'.\n"),
638 $home_dir,$config{skel} if $verbose && !$no_create_home;
639 my @homedir_stat = stat($home_dir);
640 my $home_uid = $homedir_stat[4];
641 my $home_gid = $homedir_stat[5];
642 if (($home_uid != $new_uid) || ($home_gid != $new_gid)) {
643 # post-etch, see #397916
644 # warnf gtx("Warning: The home directory `%s' does not belong to the user you are currently creating.\n"), $home_dir;
645 warnf (gtx("Warning: that home %s directory does not belong to the user you are currently creating.\n"),%home_dir);
646 }
647 undef @homedir_stat; undef $home_uid; undef $home_gid;
648 }
649 else {
650 printf gtx("Creating home directory `%s' ...\n"),$home_dir if $verbose;
651 $undohome = $home_dir;
652 &mktree($home_dir) || &cleanup(sprintf(gtx("Couldn't create home directory `%s': %s.\n"), $home_dir, $!));
653 chown($new_uid, $new_gid, $home_dir)
654 || &cleanup("chown $new_uid:$new_gid $home_dir: $!\n");
655 $dir_mode = get_dir_mode($make_group_also);
656 chmod ($dir_mode, $home_dir) ||
657 &cleanup("chmod $dir_mode $home_dir: $!\n");
658
659 if ($config{"skel"} && $copy_skeleton) {
660 printf gtx("Copying files from `%s' ...\n"),$config{skel} if $verbose;
661 open(FIND, "cd $config{skel}; find . -print |")
662 || &cleanup(sprintf(gtx("fork for `find' failed: %s\n"), $!));
663 while (<FIND>) {
664 chop;
665 next if ($_ eq ".");
666 next if ($_ =~ qr/$config{skel_ignore_regex}/ );
667 &copy_to_dir($config{"skel"}, $_, $home_dir, $new_uid,
668 $new_gid, ($config{"setgid_home"} =~ /yes/i));
669 }
670 }
671 }
672 }
673
674 # mktree: create a directory and all parent directories, we don't care about the rights and so on
675 # parameters:
676 # tree: the path
677 # return values:
678 # none
679 sub mktree {
680 my($tree) = @_;
681 my($done, @path);
682 my $default_dir_mode = 0755;
683
684 $tree =~ s:^/*(.*)/*$:$1:; # chop off leading & trailing slashes
685 @path = split(/\//, $tree);
686
687 $done = "";
688 while (@path) {
689 $done .= '/' . shift(@path);
690 -d $done || mkdir($done, $default_dir_mode) || return 0;
691 }
692 return 1;
693 }
694
695 # existing_user_ok: check if there's already a user present on the system which satisfies the requirements
696 # parameter:
697 # new_name: the name of the user to check
698 # new_uid : the UID of the user
699 # return values:
700 # 0 if the the user doesn't exist
701 # 1 if the user already exists with the specified uid (or $new_uid wasn't specified)
702 # 2 if the user already exists, but $new_uid doesn't matches its uid
703 sub existing_user_ok {
704 my($new_name,$new_uid) = @_;
705 my ($dummy1,$dummy2,$uid);
706 if (($dummy1,$dummy2,$uid) = getpwnam($new_name)) {
707 if( defined($new_uid) && $uid == $new_uid ) {
708 return 1;
709 }
710 if (! defined($new_uid)) {
711 return 1;
712 }
713 # TODO: do we really need this code? Range check shouldn't performed here
714 if( $uid >= $config{"first_system_uid"} &&
715 $uid <= $config{"last_system_uid" } ) {
716 return 2;
717 }
718 } else {
719 return 0;
720 }
721 }
722
723 # existing_group_ok: check if there's already a group which satiesfies the requirements
724 # parameter:
725 # new_name: the name of the group
726 # new_gid : the UID of the group
727 # return values:
728 # 0 if the group doesn't exist
729 # 1 if the group already exists with the specified gid (or $new_gid wasn't specified)
730 # 2 if the group already exists, but $new_gid doesn't match its gid
731 # 3 if the group already exists inside the system range
732 sub existing_group_ok {
733 my($new_name,$new_gid) = @_;
734 my ($dummy1,$dummy2,$gid);
735 if (($dummy1,$dummy2,$gid) = getgrnam($new_name)) {
736
737 # TODO: is this check required? There shouldn't be any gid outside of our allowed range anyways ...
738 if( $gid >= $config{"first_system_gid"} &&
739 $gid <= $config{"last_system_gid" } ) {
740 return 3;
741 }
742 if (! defined($new_gid)) {
743 return 1;
744 }
745 if ($gid == $new_gid) {
746 return 1;
747 } else {
748 return 2;
749 }
750 } else {
751 return 0;
752 }
753 }
754
755
756
757 # check_user_group: ???
758 # parameters:
759 # system: 0 if the user isn't a system user, 1 otherwise
760 # return values:
761 #
762 sub check_user_group {
763 my ($system) = @_;
764 if( !$system || !existing_user_ok($new_name, $new_uid) ) {
765 if( defined getpwnam($new_name) ) {
766 if( $system ) {
767 dief (gtx("The user `%s' already exists, and is not a system user.\n"),$new_name);
768 } else {
769 dief (gtx("The user `%s' already exists.\n"),$new_name);
770 }
771 }
772 dief (gtx("The UID %d is already in use.\n"),$new_uid)
773 if (defined($new_uid) && getpwuid($new_uid));
774 }
775 if ($make_group_also) {
776 if( !$system || !existing_group_ok($new_name, $new_uid) ) {
777 dief (gtx("The group `%s' already exists.\n"),$new_name)
778 if (defined getgrnam($new_name));
779 dief (gtx("The GID %d is already in use.\n"),$new_uid)
780 if (defined($new_uid) && defined(getgrgid($new_uid)));
781 }
782 }
783 else {
784 dief (gtx("The group `%s' does not exist.\n"),$ingroup_name)
785 if ($ingroup_name && !defined(getgrnam($ingroup_name)));
786 dief (gtx("The GID %d does not exist.\n"),$new_gid)
787 if (defined($new_gid) && !defined(getgrgid($new_gid)));
788 }
789 }
790
791
792 # copy_to_dir :
793 # parameters:
794 # fromdir
795 # file
796 # todir
797 # newi
798 # newg
799 # sgiddir
800 # return values:
801 # none
802 sub copy_to_dir {
803 my($fromdir, $file, $todir, $newu, $newg, $sgiddir) = @_;
804
805 if (-l "$fromdir/$file") {
806 my $target=readlink("$fromdir/$file") or &cleanup("readlink: $!\n");
807 my $curgid="$)";
808 my $curuid="$>";
809 my $error="";
810 $)="$newg";
811 $>="$newu";
812 symlink("$target", "$todir/$file") or $error="$!";
813 $>="$curuid";
814 $)="$curgid";
815 if( "$error" ne "" ) {
816 &cleanup("symlink: $!\n");
817 }
818 return;
819 }
820 elsif (-f "$fromdir/$file") {
821 open (FILE, "$fromdir/$file") || &cleanup("open $fromdir/$file: $!");
822 open (NEWFILE, ">$todir/$file") || &cleanup("open >$todir/$file: $!");
823
824 (print NEWFILE <FILE>) || &cleanup("print $todir/$file: $!");
825 close FILE;
826 close(NEWFILE) || &cleanup("close $todir/$file ");
827
828 }
829 elsif (-d "$fromdir/$file") {
830 mkdir("$todir/$file", 700) || &cleanup("mkdir: $!");
831 }
832 else {
833 &cleanup(sprintf((gtx("Cannot deal with %s.\nIt is not a dir, file, or symlink.\n")), "$fromdir/$file"));
834 }
835
836 chown($newu, $newg, "$todir/$file")
837 || &cleanup("chown $newu:$newg $todir/$file: $!\n");
838 $perm = (stat("$fromdir/$file"))[2] & 07777;
839 $perm |= 02000 if (-d "$fromdir/$file" && ($perm & 010) && $sgiddir);
840 chmod($perm, "$todir/$file") || &cleanup("chmod $todir/$file: $!\n");
841 }
842
843
844 # checkname: perform some sanity checks
845 # parameters:
846 # none
847 # return values:
848 # none (exits on error)
849 sub checkname {
850 my ($name) = @_;
851 if ($name !~ /^[_.A-Za-z0-9][-\@_.A-Za-z0-9]*\$?$/) {
852 printf STDERR
853 (gtx("%s: To avoid problems, the username should consist only of
854 letters, digits, underscores, periods, at signs and dashes, and not start with
855 a dash (as defined by IEEE Std 1003.1-2001). For compatibility with Samba
856 machine accounts \$ is also supported at the end of the username\n"), $0);
857 exit 1;
858 }
859 if ($name !~ qr/$config{"name_regex"}/) {
860 if ($allow_badname) {
861 print (gtx("Allowing use of questionable username.\n")) if ($verbose);
862 }
863 else {
864 printf STDERR
865 (gtx("%s: Please enter a username matching the regular expression configured
866 via the NAME_REGEX configuration variable. Use the `--force-badname'
867 option to relax this check or reconfigure NAME_REGEX.\n"), $0);
868 exit 1;
869 }
870 }
871 }
872
873 # first_avail_uid: return the first available uid in given range
874 # parameters:
875 # min, max: the range
876 # return values:
877 # -1 if no free uid is available
878 # otherwise the choosen uid
879 sub first_avail_uid {
880 my ($min, $max) = @_;
881 printf (gtx("Selecting UID from range %d to %d ...\n"),$min,$max) if ($verbose > 1);
882
883 my $t = $min;
884 while ($t <= $max) {
885 return $t if (!defined(getpwuid($t)));
886 $t++;
887 }
888 return -1; # nothing available
889 }
890
891 # first_avail_gid: return the first available gid in given range
892 # parameters:
893 # min, max: the range
894 # return values:
895 # -1 if no free gid is available
896 # otherwise the choosen gid
897 sub first_avail_gid {
898 my ($min, $max) = @_;
899 printf (gtx("Selecting GID from range %d to %d ...\n"),$min,$max) if ($verbose > 1);
900
901 my $t = $min;
902 while ($t <= $max) {
903 return $t if (!defined(getgrgid($t)));
904 $t++;
905 }
906 return -1; # nothing available
907 }
908
909 sub ch_gecos {
910 my $chfn = &which('chfn');
911 my $gecos = shift;
912 if($gecos =~ /,/)
913 {
914 my($gecos_name,$gecos_room,$gecos_work,$gecos_home,$gecos_other)
915 = split(/,/,$gecos);
916
917 &systemcall($chfn, '-f', $gecos_name, '-r', $gecos_room, $new_name);
918 &systemcall($chfn,'-w',$gecos_work,$new_name)
919 if(defined($gecos_work));
920 &systemcall($chfn,'-h',$gecos_home,$new_name)
921 if(defined($gecos_home));
922 &systemcall($chfn,'-o',$gecos_other,$new_name)
923 if(defined($gecos_other));
924 }
925 else
926 {
927 &systemcall($chfn, '-f', $gecos, $new_name);
928 }
929 }
930
931 # user is member of group?
932 sub user_is_member {
933 my($user, $group) = @_;
934 for (split(/ /, (getgrnam($group))[3])) {
935 return 1 if ($user eq $_);
936 }
937 return 0;
938 }
939
940
941 sub cleanup {
942 my ($msg) = @_;
943 printf (gtx("Stopped: %s\n"),$msg);
944 if ($undohome) {
945 printf (gtx("Removing directory `%s' ...\n"),$undohome);
946 &systemcall('rm', '-rf', $undohome);
947 }
948 if ($undouser) {
949 printf (gtx("Removing user `%s' ...\n"),$undouser);
950 &systemcall('userdel', $undouser);
951 }
952 if ($undogroup) {
953 printf (gtx("Removing group `%s' ...\n"),$undogroup);
954 &systemcall('groupdel', $undogroup);
955 }
956 # do we need to invalidate the nscd cache here, too?
957 exit 1;
958 }
959
960 sub handler {
961 my($sig) = @_;
962 # Translators: the variable %s is INT, QUIT, or HUP.
963 # Please do not insert a space character between SIG and %s.
964 &cleanup(sprintf(gtx("Caught a SIG%s.\n"), $sig));
965 }
966
967
968 sub version {
969 printf (gtx("adduser version %s\n\n"), $version);
970 print gtx("Adds a user or group to the system.
971
972 Copyright (C) 1997, 1998, 1999 Guy Maor <maor\@debian.org>
973 Copyright (C) 1995 Ian Murdock <imurdock\@gnu.ai.mit.edu>,
974 Ted Hajek <tedhajek\@boombox.micro.umn.edu>
975 \n");
976 print gtx(
977 "This program is free software; you can redistribute it and/or modify
978 it under the terms of the GNU General Public License as published by
979 the Free Software Foundation; either version 2 of the License, or (at
980 your option) any later version.
981
982 This program is distributed in the hope that it will be useful, but
983 WITHOUT ANY WARRANTY; without even the implied warranty of
984 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
985 General Public License, /usr/share/common-licenses/GPL, for more details.
986 ");
987 }
988
989 sub usage {
990 printf gtx(
991 "adduser [--home DIR] [--shell SHELL] [--no-create-home] [--uid ID]
992 [--firstuid ID] [--lastuid ID] [--gecos GECOS] [--ingroup GROUP | --gid ID]
993 [--disabled-password] [--disabled-login] USER
994 Add a normal user
995
996 adduser --system [--home DIR] [--shell SHELL] [--no-create-home] [--uid ID]
997 [--gecos GECOS] [--group | --ingroup GROUP | --gid ID] [--disabled-password]
998 [--disabled-login] USER
999 Add a system user
1000
1001 addgroup [--gid ID] GROUP
1002 Add a user group
1003
1004 addgroup --system [--gid ID] GROUP
1005 Add a system group
1006
1007 adduser USER GROUP
1008 Add an existing user to an existing group
1009
1010 general options:
1011 --quiet | -q don't give process information to stdout
1012 --force-badname allow usernames which do not match the
1013 NAME_REGEX configuration variable
1014 --help | -h usage message
1015 --version | -v version number and copyright
1016 --conf | -c FILE use FILE as configuration file\n\n");
1017 }
1018
1019 sub get_dir_mode
1020 {
1021 my $setgid = shift;
1022 # no longer make home directories setgid per default (closes: #64806)
1023 $setgid = 0 unless $config{"setgid_home"} =~ /yes/i;
1024
1025 my $dir_mode = $config{"dir_mode"};
1026 if(!defined($dir_mode) || ! ($dir_mode =~ /[0-7]{3}/ ||
1027 $dir_mode =~ /[0-7]{4}/))
1028 {
1029 $dir_mode = $setgid ? 2755 : 0755;
1030 }
1031 else
1032 {
1033 $dir_mode = $config{"dir_mode"};
1034 if($setgid && (length($dir_mode) == 3 || $dir_mode =~ /^[0-1|4-5][0-7]{3}$/))
1035 {
1036 $dir_mode += 2000;
1037 }
1038 }
1039 return oct($dir_mode);
1040 }
1041
1042 # Local Variables:
1043 # mode:cperl
1044 # cperl-indent-level:4
1045 # End:
1046
1047 # vim:set ai et sts=4 sw=4 tw=0:

Properties

Name Value
svn:executable

  ViewVC Help
Powered by ViewVC 1.1.5