summaryrefslogtreecommitdiff
path: root/scripts
diff options
context:
space:
mode:
authorStephen Hemminger <stephen.hemminger@vyatta.com>2008-05-29 16:29:21 -0700
committerStephen Hemminger <stephen.hemminger@vyatta.com>2008-05-29 16:29:21 -0700
commit89fe48dea3fd1e3cbbacc0e78f58d277d72168b8 (patch)
treed0f3b226b1524ed5612f7b83eb2e1335ad879f63 /scripts
parent5439d0bb321b8121d0d25060c1b74086b7aa9be5 (diff)
downloadvyatta-cfg-system-89fe48dea3fd1e3cbbacc0e78f58d277d72168b8.tar.gz
vyatta-cfg-system-89fe48dea3fd1e3cbbacc0e78f58d277d72168b8.zip
Rework how user accounts are managed
Rewrite the scripts that manage user accounts to: 1) use Posix standard useradd, userdel scripts rather than modifying passwd/group files directly. 2) add home-directory field to account management 3) support adding accounts to additional groups Note: this code should now also work with NIS since it has no direct access to /etc/passwd.
Diffstat (limited to 'scripts')
-rwxr-xr-xscripts/system/vyatta_update_login.pl85
-rwxr-xr-xscripts/system/vyatta_update_login_user.pl241
2 files changed, 72 insertions, 254 deletions
diff --git a/scripts/system/vyatta_update_login.pl b/scripts/system/vyatta_update_login.pl
index a5d1fd2a..bf2b0c10 100755
--- a/scripts/system/vyatta_update_login.pl
+++ b/scripts/system/vyatta_update_login.pl
@@ -24,7 +24,7 @@ use VyattaConfig;
my $uconfig = new VyattaConfig;
$uconfig->setLevel("system login user");
-my %users = $uconfig->listNodeStatus();
+my %users = $uconfig->listNodeStatus();
my @user_keys = sort keys %users;
if ( ( scalar(@user_keys) <= 0 )
@@ -37,24 +37,83 @@ if ( ( scalar(@user_keys) <= 0 )
exit 1;
}
+# Exit codes form useradd.8 man page
+my %reasons = (
+ 0 => 'success',
+ 1 => 'can´t update password file',
+ 2 => 'invalid command syntax',
+ 3 => 'invalid argument to option',
+ 4 => 'UID already in use (and no -o)',
+ 6 => 'specified group doesn´t exist',
+ 9 => 'username already in use',
+ 10 => 'can´t update group file',
+ 12 => 'can´t create home directory',
+ 13 => 'can´t create mail spool',
+);
+
+# Map of level to additional groups
+my %level_map = (
+ 'admin' => [ 'quaggavty', 'vyattacfg', 'sudo', 'adm', ],
+ 'operator' => [ 'quaggavty', 'operator', 'adm', ],
+);
+
# we have some users
for my $user (@user_keys) {
if ( $users{$user} eq 'deleted' ) {
- system("sudo /opt/vyatta/sbin/vyatta_update_login_user.pl -d '$user'");
- exit 1 if ( $? >> 8 );
+ system("sudo userdel -r '$user'");
+ die "userdel failed\n" if ( $? >> 8 );
}
elsif ( $users{$user} eq 'added' || $users{$user} eq 'changed' ) {
- my $fname = $uconfig->returnValue("$user full-name");
- my $level = $uconfig->returnValue("$user level");
- my $p =
- $uconfig->returnValue("$user authentication encrypted-password");
- system( "sudo /opt/vyatta/sbin/vyatta_update_login_user.pl '$user' "
- . "'$fname' '$p' '$level'" );
- exit 1 if ( $? >> 8 );
- }
- else {
+ $uconfig->setLevel("system login user $user");
+
+ # See if this is a modification of existing account
+ my (undef, undef, $uid, undef, undef,
+ undef, undef, undef, $shell, undef) = getpwnam($user);
+
+ my $cmd;
+ # not found in existing passwd, must be new
+ if ( !defined $uid ) {
+ $cmd = 'useradd -s /bin/vbash -m';
+ }
+ # is it a vyatta user?
+ elsif ( $shell ne '/bin/vbash' ) {
+ die "$user: exists but is not a vyatta login user\n";
+ }
+ else {
+ $cmd = "usermod";
+ }
+
+ my $pwd = $uconfig->returnValue('authentication encrypted-password');
+ $pwd or die 'encrypted password not set';
+ $cmd .= " -p '$pwd'";
- # not changed. do nothing.
+ my $fname = $uconfig->returnValue('full-name');
+ $cmd .= " -c \"$fname\"" if ( defined $fname );
+
+ my $home = $uconfig->returnValue('home-directory');
+ $cmd .= " -d \"$home\"" if ( defined $home );
+
+ # map level to group membership
+ my $level = $uconfig->returnValue('level');
+ my $gref = $level_map{$level};
+ my @groups = @{$gref};
+
+ # add any additional groups from configuration
+ push( @groups, $uconfig->returnValues('group') );
+
+ $cmd .= ' -G ' . join( ',', @groups );
+
+ system("sudo $cmd $user");
+ if ( $? == -1 ) {
+ die "failed to exec $cmd";
+ }
+ elsif ( $? & 127 ) {
+ die "$cmd died with signal" . ( $? & 127 );
+ }
+ elsif ( $? != 0 ) {
+ my $reason = $reasons{ $? >> 8 };
+ die "$cmd failed: $reason\n";
+ }
}
}
diff --git a/scripts/system/vyatta_update_login_user.pl b/scripts/system/vyatta_update_login_user.pl
deleted file mode 100755
index 0eea2806..00000000
--- a/scripts/system/vyatta_update_login_user.pl
+++ /dev/null
@@ -1,241 +0,0 @@
-#!/usr/bin/perl
-
-use strict;
-use Fcntl;
-use POSIX qw(:unistd_h);
-
-# arg: login_name
-# returns the next available uid if login_name doesn't exist.
-# otherwise returns (undef, <passwd fields for login_name>).
-sub next_uid_if_not_exist {
- my $login = shift;
- my $min_uid = 1000;
- my $max_uid = 60000;
- if (open(LOGIN_DEF, "/etc/login.defs")) {
- while (<LOGIN_DEF>) {
- if (m/^\s*UID_MIN\s+(\d+)/) {
- $min_uid = $1;
- next;
- }
- if (m/^\s*UID_MAX\s+(\d+)/) {
- $max_uid = $1;
- next;
- }
- }
- close LOGIN_DEF;
- }
-
- open(PASSWD, "/etc/passwd") or exit 1;
- while (<PASSWD>) {
- chomp;
- my @passwd_fields = split /:/;
- if ($passwd_fields[0] eq $login) {
- close PASSWD;
- return (undef, @passwd_fields);
- }
- if ($min_uid <= $passwd_fields[2]) {
- next if ($passwd_fields[2] > $max_uid);
- $min_uid = $passwd_fields[2] + 1;
- next;
- }
- }
- close PASSWD;
- exit 2 if ($min_uid > $max_uid);
- return ($min_uid);
-}
-
-# arg: login_name
-# returns the corresponding line in shadow or undef if login_name doesn't
-# exist.
-sub get_shadow_line {
- my $login = shift;
- open(SHADOW, "/etc/shadow") or exit 3;
- while (<SHADOW>) {
- chomp;
- if (m/^$login:/) {
- close SHADOW;
- return $_;
- }
- }
- close SHADOW;
- return undef;
-}
-
-# arg: login name
-# removes the specified user from group/gshadow
-sub remove_user_from_group {
- my $user = shift;
- my $sed_cmd = 'sed -i \'/^[^:]\+:/{'
- . 's/:' . $user . '$/:/;'
- . 's/:' . $user . ',/:/;'
- . 's/,' . $user . ',/,/;'
- . 's/,' . $user . '$//;}\'';
- system("$sed_cmd /etc/group");
- exit 1 if ($? >> 8);
- system("$sed_cmd /etc/gshadow");
- exit 1 if ($? >> 8);
-}
-
-# arg: login name
-# adds the specified user to group/gshadow
-sub add_user_to_group {
- my $user = shift;
- my $group = shift;
- my $gcmd = 'grep -q -e \'^' . $group . ':.*[:,]' . $user . '\(,\|$\)\'';
- my $ret = system("$gcmd /etc/group");
- my $in_group = (($ret >> 8) == 0) ? 1 : 0;
- $ret = system("$gcmd /etc/gshadow");
- my $in_gshadow = (($ret >> 8) == 0) ? 1 : 0;
-
- my $sed_cmd = 'sed -i \'/^' . $group . ':/{'
- . 's/\([^:]\)$/\1,' . $user . '/;'
- . 's/:$/:' . $user . '/;}\'';
- if (!$in_group) {
- system("$sed_cmd /etc/group");
- exit 1 if ($? >> 8);
- }
- if (!$in_gshadow) {
- system("$sed_cmd /etc/gshadow");
- exit 1 if ($? >> 8);
- }
-}
-
-my $user = shift;
-my $full = shift;
-my $encrypted = shift;
-my $level = shift;
-
-# emulate lckpwdf(3).
-# difference: we only try to lock it once (non-blocking). lckpwdf will block
-# for up to 15 seconds waiting for the lock.
-# note that the lock is released when file is closed (e.g., exit), so no need
-# for explicit unlock.
-my $flock = pack "ssa20", F_WRLCK, SEEK_SET, "\0";
-sysopen(PWDLCK, "/etc/.pwd.lock", O_WRONLY | O_CREAT, 0600) or exit 3;
-fcntl(PWDLCK, F_SETLK, $flock) or exit 3;
-
-if ($user eq "-d") {
- $user = $full;
- exit 4 if (!defined($user));
-
- # check if user is using the system
- my @pslines = `ps -U $user -u $user u`;
- if ($#pslines != 0) {
- # user is using the system
- print STDERR "Delete failed: user \"$user\" is using the system\n";
- exit 4;
- }
-
- my $ret = system("sed -i '/^$user:/d' /etc/passwd");
- exit 5 if ($ret >> 8);
- $ret = system("sed -i '/^$user:/d' /etc/shadow");
- exit 6 if ($ret >> 8);
- $ret = system("rm -rf /home/$user");
- exit 7 if ($ret >> 8);
- remove_user_from_group($user);
- exit 0;
-}
-
-my %level_map = (
- 'admin' => [ 'users', 'quaggavty', 'vyattacfg', 'sudo', 'adm', ],
- 'operator' => [ 'users', 'quaggavty', 'operator', 'adm', ],
- );
-exit 4 if (!defined($user) || !defined($full) || !defined($encrypted)
- || !defined($level));
-exit 4 if (!defined($level_map{$level}));
-my $gref = $level_map{$level};
-my @groups = @{$gref};
-my $def_grp = $groups[0];
-if ($user eq 'root') {
- $def_grp = 'root';
-}
-
-# note that DEF_SHELL doesn't affect root since root is never "added"
-my $DEF_SHELL = "/bin/vbash";
-
-open(GRP, "/etc/group") or exit 5;
-my $def_gid = undef;
-while (<GRP>) {
- my @group_fields = split /:/;
- if ($group_fields[0] eq $def_grp) {
- $def_gid = $group_fields[2];
- last;
- }
-}
-exit 6 if (!defined($def_gid));
-
-my @vals = next_uid_if_not_exist($user);
-my ($new_user, $passwd_line, $shadow_line) = (0, "", "");
-if (defined($vals[0])) {
- # add new user
- $new_user = 1;
- $passwd_line = "$user:x:$vals[0]:${def_gid}:$full:/home/$user:$DEF_SHELL";
- my $sline = get_shadow_line($user);
- exit 7 if (defined($sline));
- my $seconds = `date +%s`;
- my $days = int($seconds / 3600 / 24);
- $shadow_line = "$user:$encrypted:$days:0:99999:7:::";
-} else {
- # modify existing user
- shift @vals;
- $vals[3] = $def_gid;
- $vals[4] = $full;
- $passwd_line = join(':', @vals);
- my $sline = get_shadow_line($user);
- exit 8 if (!defined($sline));
- @vals = split /:/, $sline;
- $vals[1] = $encrypted;
- for (my $padding = (9 - $#vals - 1); $padding > 0; $padding--) {
- push @vals, '';
- }
- $shadow_line = join(':', @vals);
-}
-
-my $ret = 0;
-if (!$new_user) {
- $ret = system("sed -i '/^$user:/d' /etc/passwd");
- exit 9 if ($ret >> 8);
- $ret = system("sed -i '/^$user:/d' /etc/shadow");
- exit 10 if ($ret >> 8);
- remove_user_from_group($user);
-}
-
-open(PASSWD, ">>/etc/passwd") or exit 11;
-print PASSWD "$passwd_line\n";
-close PASSWD;
-open(SHADOW, ">>/etc/shadow") or exit 12;
-print SHADOW "$shadow_line\n";
-close SHADOW;
-
-# root doesn't need to be added to group
-if ($user ne 'root') {
- foreach my $group (@groups) {
- add_user_to_group($user, $group);
- }
-}
-
-if (($new_user) && !(-e "/home/$user")) {
- if (-d "/etc/skel") {
- $ret = system("cp -a /etc/skel /home/$user");
- exit 13 if ($ret >> 8);
- $ret = system("chmod 755 /home/$user");
- exit 14 if ($ret >> 8);
- $ret = system("chown -R $user:$def_grp /home/$user");
- exit 15 if ($ret >> 8);
- } else {
- $ret = system("mkdir -p /home/$user");
- exit 16 if ($ret >> 8);
- $ret = system("chmod 755 /home/$user");
- exit 17 if ($ret >> 8);
- }
-}
-
-my $vtysh_conf = "/etc/vyatta/quagga/vtysh.conf";
-if (($new_user) && (-e $vtysh_conf)) {
- open(VTYSH_CONF, ">>$vtysh_conf") or exit 11;
- print VTYSH_CONF "username $user nopassword\n";
- close VTYSH_CONF;
-}
-
-exit 0;
-