]> git.cameronkatri.com Git - pw-darwin.git/blobdiff - adduser/rmuser.perl
Fix conjugation of exists and add full stops to the messages I changed.
[pw-darwin.git] / adduser / rmuser.perl
index 8f6d56e260e9d4e6d35bdd0777d3c98aabb4f6b0..1ffac08750f6631c132ddbd1f504770d1f51ba68 100644 (file)
@@ -32,6 +32,8 @@
 #
 # $FreeBSD$
 
+use Fcntl;
+
 sub LOCK_SH {0x01;}
 sub LOCK_EX {0x02;}
 sub LOCK_NB {0x04;}
@@ -42,12 +44,11 @@ $ENV{"PATH"} = "/bin:/sbin:/usr/bin:/usr/sbin";
 umask(022);
 $whoami = $0;
 $passwd_file = "/etc/master.passwd";
-$new_passwd_file = "${passwd_file}.new.$$";
+$passwd_tmp = "/etc/ptmp";
 $group_file = "/etc/group";
 $new_group_file = "${group_file}.new.$$";
 $mail_dir = "/var/mail";
 $crontab_dir = "/var/cron/tabs";
-$atjob_dir = "/var/at/jobs";
 $affirm = 0;
 
 #$debug = 1;
@@ -107,8 +108,6 @@ if ($< != 0) {
 if ($#ARGV == 0) {
     # Username was given as a parameter
     $login_name = pop(@ARGV);
-    die "Sorry, login name must contain alphanumeric characters only.\n"
-       if ($login_name !~ /^[a-zA-Z0-9_]\w*$/);
 } else {
     if ($affirm) {
        print STDERR "${whoami}: Error: -y option given without username!\n";
@@ -119,15 +118,15 @@ if ($#ARGV == 0) {
     $login_name = &get_login_name;
 }
 
-if (($pw_ent = &check_login_name($login_name)) eq '0') {
+($name, $password, $uid, $gid, $change, $class, $gecos, $home_dir, $shell) =
+    (getpwnam("$login_name"));
+
+if (!defined $uid) {
     print STDERR "${whoami}: Error: User ${login_name} not in password database\n";
     &unlockpw;
     exit 1;
 }
 
-($name, $password, $uid, $gid, $class, $change, $expire, $gecos, $home_dir,
- $shell) = split(/:/, $pw_ent);
-
 if ($uid == 0) {
     print "${whoami}: Error: I'd rather not remove a user with a uid of 0.\n";
     &unlockpw;
@@ -135,7 +134,7 @@ if ($uid == 0) {
 }
 
 if (! $affirm) {
-    print "Matching password entry:\n\n$pw_ent\n\n";
+    print "Matching password entry:\n\n$name\:$password\:$uid\:$gid\:$class\:$change\:0\:$gecos\:$home_dir\:$shell\n\n";
 
     $ans = &get_yn("Is this the entry you wish to remove? ");
 
@@ -202,7 +201,7 @@ if (-e "$crontab_dir/$login_name") {
 # Remove the user's at jobs, if any
 # (probably also needs to be done before password databases are updated)
 
-&remove_at_jobs($login_name, $uid);
+&remove_at_jobs($login_name);
 
 #
 # Kill all the user's processes
@@ -275,11 +274,9 @@ sub get_login_name {
     for ($done = 0; ! $done; ) {
        print "Enter login name for user to remove: ";
        $login_name = <>;
-       chop $login_name;
-       if (!($login_name =~ /^[a-z0-9_][a-z0-9_\-]*$/)) {
-           print STDERR "Sorry, login name must contain alphanumeric characters only.\n";
-       } elsif (length($login_name) > 16 || length($login_name) == 0) {
-           print STDERR "Sorry, login name must be 16 characters or less.\n";
+       chomp $login_name;
+       if (not getpwnam("$login_name")) {
+           print STDERR "Sorry, login name not in password database.\n";
        } else {
            $done = 1;
        }
@@ -289,29 +286,6 @@ sub get_login_name {
     return($login_name);
 }
 
-sub check_login_name {
-    #
-    # Check to see whether login name is in password file
-    local($login_name) = @_;
-    local($Mname, $Mpassword, $Muid, $Mgid, $Mclass, $Mchange, $Mexpire,
-         $Mgecos, $Mhome_dir, $Mshell);
-    local($i);
-
-    seek(MASTER_PW, 0, 0);
-    while ($i = <MASTER_PW>) {
-       chop $i;
-       ($Mname, $Mpassword, $Muid, $Mgid, $Mclass, $Mchange, $Mexpire,
-        $Mgecos, $Mhome_dir, $Mshell) = split(/:/, $i);
-       if ($Mname eq $login_name) {
-           seek(MASTER_PW, 0, 0);
-           return($i);         # User is in password database
-       }
-    }
-    seek(MASTER_PW, 0, 0);
-
-    return '0';                        # User wasn't found
-}
-
 sub get_yn {
     #
     # Get a yes or no answer; return 'Y' or 'N'
@@ -334,24 +308,32 @@ sub get_yn {
 }
 
 sub update_passwd_file {
-    local($skipped, $i);
+    local($skipped);
 
     print STDERR "Updating password file,";
     seek(MASTER_PW, 0, 0);
-    open(NEW_PW, ">$new_passwd_file") ||
-       die "\n${whoami}: Error: Couldn't open file ${new_passwd_file}:\n $!\n";
-    chmod(0600, $new_passwd_file) ||
-       print STDERR "\n${whoami}: Warning: couldn't set mode of $new_passwd_file to 0600 ($!)\n\tcontinuing, but please check mode of /etc/master.passwd!\n";
+
+    sysopen(NEW_PW, $passwd_tmp, O_RDWR|O_CREAT|O_EXCL, 0600) ||
+       die "\n${whoami}: Error: Couldn't open file ${passwd_tmp}:\n $!\n";
+
     $skipped = 0;
-    while ($i = <MASTER_PW>) {
-       if ($i =~ /\n$/) {
-           chop $i;
-       }
-       if ($i ne $pw_ent) {
-           print NEW_PW "$i\n";
-       } else {
+    while (<MASTER_PW>) {
+       if (/^\Q$login_name:/o) {
            print STDERR "Dropped entry for $login_name\n" if $debug;
            $skipped = 1;
+       } else {
+           print NEW_PW;
+           # The other perl password tools assume all lowercase entries.
+           # Add a warning to help unsuspecting admins who might be
+           # using the wrong tool for the job, or might otherwise
+           # be unwittingly holding a loaded foot-shooting device.
+           if (/^\Q$login_name:/io) {
+               my $name = $_;
+               $name =~ s#\:.*\n##;
+               print STDERR "\n\n\tThere is also an entry for $name in your",
+                   "password file.\n\tThis can cause problems in some ",
+                   "situations.\n\n";
+           }
        }
     }
     close(NEW_PW);
@@ -359,8 +341,8 @@ sub update_passwd_file {
 
     if ($skipped == 0) {
        print STDERR "\n${whoami}: Whoops! Didn't find ${login_name}'s entry second time around!\n";
-       unlink($new_passwd_file) ||
-           print STDERR "\n${whoami}: Warning: couldn't unlink $new_passwd_file ($!)\n\tPlease investigate, as this file should not be left in the filesystem\n";
+       unlink($passwd_tmp) ||
+           print STDERR "\n${whoami}: Warning: couldn't unlink $passwd_tmp ($!)\n\tPlease investigate, as this file should not be left in the filesystem\n";
        &unlockpw;
        exit 1;
     }
@@ -369,7 +351,7 @@ sub update_passwd_file {
     # Run pwd_mkdb to install the updated password files and databases
 
     print STDERR " updating databases,";
-    system('/usr/sbin/pwd_mkdb', '-p', ${new_passwd_file});
+    system('/usr/sbin/pwd_mkdb', '-p', ${passwd_tmp});
     print STDERR " done.\n";
 
     close(MASTER_PW);          # Not useful anymore
@@ -398,7 +380,7 @@ sub update_group_file {
     chown($group_uid, $group_gid, $new_group_file) ||
        print STDERR "\n${whoami}: Warning: could not set owner/group of new group file to ${group_uid}/${group_gid} ($!)\n\rContinuing, but please check ownership of $group_file!\n";
     while ($i = <GROUP>) {
-       if (!($i =~ /$login_name/)) {
+       if (!($i =~ /\Q$login_name\E/)) {
            # Line doesn't contain any references to the user, so just add it
            # to the new file
            print NEW_GROUP $i;
@@ -495,32 +477,75 @@ sub remove_files_from_dir {
     printf STDERR " done.\n";
 }
 
-sub remove_at_jobs {
-    local($login_name, $uid) = @_;
-    local($i, $owner, $found);
 
-    $found = 0;
-    opendir(ATDIR, $atjob_dir) || return;
-    while ($i = readdir(ATDIR)) {
-       next if $i eq '.';
-       next if $i eq '..';
-       next if $i eq '.lockfile';
-
-       $owner = (stat("$atjob_dir/$i"))[4]; # UID
-       if ($uid == $owner) {
-           if (!$found) {
-               print STDERR "Removing user's at jobs:";
-               $found = 1;
-           }
-           # Use atrm to remove the job
-           print STDERR " $i";
-           system('/usr/bin/atrm', $i);
+sub invoke_atq {
+    local *ATQ;
+    my($user) = (shift || "");
+    my($path_atq) = "/usr/bin/atq";
+    my(@at) = ();
+    my($pid, $line);
+    
+    return @at if ($user eq "");
+    
+    if (!defined($pid = open(ATQ, "-|"))) {
+       die("creating pipe to atq: $!\n");
+    } elsif ($pid == 0) {
+       exec($path_atq, $user);
+       die("executing $path_atq: $!\n");
+    }
+    
+    while(defined($_ = <ATQ>)) {
+       chomp;
+       if (/^\d\d.\d\d.\d\d\s+\d\d.\d\d.\d\d\s+(\S+)\s+\S+\s+(\d+)$/) {
+           push(@at, $2) if ($1 eq $user);
        }
     }
-    closedir(ATDIR);
-    if ($found) {
-       print STDERR " done.\n";
+    close ATQ;
+    return @at;
+}
+
+sub invoke_atrm {
+    local *ATRM;
+    my($user) = (shift || "");
+    my($path_atrm) = "/usr/bin/atrm";
+    my(@jobs) = @_;
+    my($pid);
+    my($txt) = "";
+    
+    return "Invalid arguments" if (($user eq "") || ($#jobs == -1));
+    
+    if (!defined($pid = open(ATRM, "-|"))) {
+       die("creating pipe to atrm: $!\n");
+    } elsif ($pid == 0) {
+       exec($path_atrm, $user, @jobs);
+    }
+    
+    while(defined($_ = <ATRM>)) {
+       $txt .= $_;
+    }
+    close ATRM;
+    return $txt;
+}
+
+sub remove_at_jobs {
+    my($user) = (shift || "");
+    my(@at, $atrm);
+    
+    return 1 if ($user eq "");
+    
+    @at = invoke_atq($user);
+    return 0 if ($#at == -1);
+    
+    print STDERR "Removing user's at jobs:";
+    print STDERR " @at:";
+    $atrm = invoke_atrm($user, @at);
+    if ($atrm ne "") {
+       print STDERR " -- $atrm\n";
+       return 1;
     }
+    
+    print STDERR " done.\n";
+    return 0;
 }
 
 sub resolvelink {