Guest User

Untitled

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