From 89fe48dea3fd1e3cbbacc0e78f58d277d72168b8 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Thu, 29 May 2008 16:29:21 -0700 Subject: 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. --- scripts/system/vyatta_update_login_user.pl | 241 ----------------------------- 1 file changed, 241 deletions(-) delete mode 100755 scripts/system/vyatta_update_login_user.pl (limited to 'scripts/system/vyatta_update_login_user.pl') 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, ). -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 () { - 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 () { - 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 () { - 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 () { - 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; - -- cgit v1.2.3