summaryrefslogtreecommitdiffstats
path: root/adduser/rmuser.perl
diff options
context:
space:
mode:
Diffstat (limited to 'adduser/rmuser.perl')
-rw-r--r--adduser/rmuser.perl601
1 files changed, 0 insertions, 601 deletions
diff --git a/adduser/rmuser.perl b/adduser/rmuser.perl
deleted file mode 100644
index 1ffac08..0000000
--- a/adduser/rmuser.perl
+++ /dev/null
@@ -1,601 +0,0 @@
-#!/usr/bin/perl
-# -*- perl -*-
-# Copyright 1995, 1996, 1997 Guy Helmer, Ames, Iowa 50014.
-# All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions
-# are met:
-# 1. Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer as
-# the first lines of this file unmodified.
-# 2. Redistributions in binary form must reproduce the above copyright
-# notice, this list of conditions and the following disclaimer in the
-# documentation and/or other materials provided with the distribution.
-# 3. The name of the author may not be used to endorse or promote products
-# derived from this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY GUY HELMER ``AS IS'' AND ANY EXPRESS OR
-# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
-# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
-# IN NO EVENT SHALL GUY HELMER BE LIABLE FOR ANY DIRECT, INDIRECT,
-# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
-# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
-# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-#
-# rmuser - Perl script to remove users
-#
-# Guy Helmer <ghelmer@cs.iastate.edu>, 02/23/97
-#
-# $FreeBSD$
-
-use Fcntl;
-
-sub LOCK_SH {0x01;}
-sub LOCK_EX {0x02;}
-sub LOCK_NB {0x04;}
-sub LOCK_UN {0x08;}
-sub F_SETFD {2;}
-
-$ENV{"PATH"} = "/bin:/sbin:/usr/bin:/usr/sbin";
-umask(022);
-$whoami = $0;
-$passwd_file = "/etc/master.passwd";
-$passwd_tmp = "/etc/ptmp";
-$group_file = "/etc/group";
-$new_group_file = "${group_file}.new.$$";
-$mail_dir = "/var/mail";
-$crontab_dir = "/var/cron/tabs";
-$affirm = 0;
-
-#$debug = 1;
-
-sub cleanup {
- local($sig) = @_;
-
- print STDERR "Caught signal SIG$sig -- cleaning up.\n";
- &unlockpw;
- if (-e $new_passwd_file) {
- unlink $new_passwd_file;
- }
- exit(0);
-}
-
-sub lockpw {
- # Open the password file for reading
- if (!open(MASTER_PW, "$passwd_file")) {
- print STDERR "${whoami}: Error: Couldn't open ${passwd_file}: $!\n";
- exit(1);
- }
- # Set the close-on-exec flag just in case
- fcntl(MASTER_PW, &F_SETFD, 1);
- # Apply an advisory lock the password file
- if (!flock(MASTER_PW, &LOCK_EX|&LOCK_NB)) {
- print STDERR "${whoami}: Error: Couldn't lock ${passwd_file}: $!\n";
- exit(1);
- }
-}
-
-sub unlockpw {
- flock(MASTER_PW, &LOCK_UN);
-}
-
-$SIG{'INT'} = 'cleanup';
-$SIG{'QUIT'} = 'cleanup';
-$SIG{'HUP'} = 'cleanup';
-$SIG{'TERM'} = 'cleanup';
-
-if ($#ARGV == 1 && $ARGV[0] eq '-y') {
- shift @ARGV;
- $affirm = 1;
-}
-
-if ($#ARGV > 0) {
- print STDERR "usage: ${whoami} [-y] [username]\n";
- exit(1);
-}
-
-if ($< != 0) {
- print STDERR "${whoami}: Error: you must be root to use ${whoami}\n";
- exit(1);
-}
-
-&lockpw;
-
-if ($#ARGV == 0) {
- # Username was given as a parameter
- $login_name = pop(@ARGV);
-} else {
- if ($affirm) {
- print STDERR "${whoami}: Error: -y option given without username!\n";
- &unlockpw;
- exit 1;
- }
- # Get the user name from the user
- $login_name = &get_login_name;
-}
-
-($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;
-}
-
-if ($uid == 0) {
- print "${whoami}: Error: I'd rather not remove a user with a uid of 0.\n";
- &unlockpw;
- exit 1;
-}
-
-if (! $affirm) {
- 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? ");
-
- if ($ans eq 'N') {
- print "${whoami}: Informational: User ${login_name} not removed.\n";
- &unlockpw;
- exit 0;
- }
-}
-
-#
-# Get owner of user's home directory; don't remove home dir if not
-# owned by $login_name
-
-$remove_directory = 1;
-
-if (-l $home_dir) {
- $real_home_dir = &resolvelink($home_dir);
-} else {
- $real_home_dir = $home_dir;
-}
-
-#
-# If home_dir is a symlink and points to something that isn't a directory,
-# or if home_dir is not a symlink and is not a directory, don't remove
-# home_dir -- seems like a good thing to do, but probably isn't necessary...
-
-if (((-l $home_dir) && ((-e $real_home_dir) && !(-d $real_home_dir))) ||
- (!(-l $home_dir) && !(-d $home_dir))) {
- print STDERR "${whoami}: Informational: Home ${home_dir} is not a directory, so it won't be removed\n";
- $remove_directory = 0;
-}
-
-if (length($real_home_dir) && -d $real_home_dir) {
- $dir_owner = (stat($real_home_dir))[4]; # UID
- if ($dir_owner != $uid) {
- print STDERR "${whoami}: Informational: Home dir ${real_home_dir} is" .
- " not owned by ${login_name} (uid ${dir_owner})\n," .
- "\tso it won't be removed\n";
- $remove_directory = 0;
- }
-}
-
-if ($remove_directory && ! $affirm) {
- $ans = &get_yn("Remove user's home directory ($home_dir)? ");
- if ($ans eq 'N') {
- $remove_directory = 0;
- }
-}
-
-#exit 0 if $debug;
-
-#
-# Remove the user's crontab, if there is one
-# (probably needs to be done before password databases are updated)
-
-if (-e "$crontab_dir/$login_name") {
- print STDERR "Removing user's crontab:";
- system('/usr/bin/crontab', '-u', $login_name, '-r');
- print STDERR " done.\n";
-}
-
-#
-# Remove the user's at jobs, if any
-# (probably also needs to be done before password databases are updated)
-
-&remove_at_jobs($login_name);
-
-#
-# Kill all the user's processes
-
-&kill_users_processes($login_name, $uid);
-
-#
-# Copy master password file to new file less removed user's entry
-
-&update_passwd_file;
-
-#
-# Remove the user from all groups in /etc/group
-
-&update_group_file($login_name);
-
-#
-# Remove the user's home directory
-
-if ($remove_directory) {
- print STDERR "Removing user's home directory ($home_dir):";
- &remove_dir($home_dir);
- print STDERR " done.\n";
-}
-
-#
-# Remove files related to the user from the mail directory
-
-#&remove_files_from_dir($mail_dir, $login_name, $uid);
-$file = "$mail_dir/$login_name";
-if (-e $file || -l $file) {
- print STDERR "Removing user's incoming mail file ${file}:";
- unlink $file ||
- print STDERR "\n${whoami}: Warning: unlink on $file failed ($!) - continuing\n";
- print STDERR " done.\n";
-}
-
-#
-# Remove some pop daemon's leftover file
-
-$file = "$mail_dir/.${login_name}.pop";
-if (-e $file || -l $file) {
- print STDERR "Removing pop daemon's temporary mail file ${file}:";
- unlink $file ||
- print STDERR "\n${whoami}: Warning: unlink on $file failed ($!) - continuing\n";
- print STDERR " done.\n";
-}
-
-#
-# Remove files belonging to the user from the directories /tmp, /var/tmp,
-# and /var/tmp/vi.recover. Note that this doesn't take care of the
-# problem where a user may have directories or symbolic links in those
-# directories -- only regular files are removed.
-
-&remove_files_from_dir('/tmp', $login_name, $uid);
-&remove_files_from_dir('/var/tmp', $login_name, $uid);
-&remove_files_from_dir('/var/tmp/vi.recover', $login_name, $uid)
- if (-e '/var/tmp/vi.recover');
-
-#
-# All done!
-
-exit 0;
-
-sub get_login_name {
- #
- # Get new user's name
- local($done, $login_name);
-
- for ($done = 0; ! $done; ) {
- print "Enter login name for user to remove: ";
- $login_name = <>;
- chomp $login_name;
- if (not getpwnam("$login_name")) {
- print STDERR "Sorry, login name not in password database.\n";
- } else {
- $done = 1;
- }
- }
-
- print "User name is ${login_name}\n" if $debug;
- return($login_name);
-}
-
-sub get_yn {
- #
- # Get a yes or no answer; return 'Y' or 'N'
- local($prompt) = @_;
- local($done, $ans);
-
- for ($done = 0; ! $done; ) {
- print $prompt;
- $ans = <>;
- chop $ans;
- $ans =~ tr/a-z/A-Z/;
- if (!($ans =~ /^[YN]/)) {
- print STDERR "Please answer (y)es or (n)o.\n";
- } else {
- $done = 1;
- }
- }
-
- return(substr($ans, 0, 1));
-}
-
-sub update_passwd_file {
- local($skipped);
-
- print STDERR "Updating password file,";
- seek(MASTER_PW, 0, 0);
-
- 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 (<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);
- seek(MASTER_PW, 0, 0);
-
- if ($skipped == 0) {
- print STDERR "\n${whoami}: Whoops! Didn't find ${login_name}'s entry second time around!\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;
- }
-
- #
- # Run pwd_mkdb to install the updated password files and databases
-
- print STDERR " updating databases,";
- system('/usr/sbin/pwd_mkdb', '-p', ${passwd_tmp});
- print STDERR " done.\n";
-
- close(MASTER_PW); # Not useful anymore
-}
-
-sub update_group_file {
- local($login_name) = @_;
-
- local($i, $j, $grmember_list, $new_grent, $changes);
- local($grname, $grpass, $grgid, $grmember_list, @grmembers);
-
- $changes = 0;
- print STDERR "Updating group file:";
- open(GROUP, $group_file) ||
- die "\n${whoami}: Error: couldn't open ${group_file}: $!\n";
- if (!flock(GROUP, &LOCK_EX|&LOCK_NB)) {
- print STDERR "\n${whoami}: Error: couldn't lock ${group_file}: $!\n";
- exit 1;
- }
- local($group_perms, $group_uid, $group_gid) =
- (stat(GROUP))[2, 4, 5]; # File Mode, uid, gid
- open(NEW_GROUP, ">$new_group_file") ||
- die "\n${whoami}: Error: couldn't open ${new_group_file}: $!\n";
- chmod($group_perms, $new_group_file) ||
- printf STDERR "\n${whoami}: Warning: could not set permissions of new group file to %o ($!)\n\tContinuing, but please check permissions of $group_file!\n", $group_perms;
- 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 =~ /\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;
- } else {
- #
- # Remove the user from the group
- if ($i =~ /\n$/) {
- chop $i;
- }
- ($grname, $grpass, $grgid, $grmember_list) = split(/:/, $i);
- @grmembers = split(/,/, $grmember_list);
- undef @new_grmembers;
- local(@new_grmembers);
- foreach $j (@grmembers) {
- if ($j ne $login_name) {
- push(@new_grmembers, $j);
- } else {
- print STDERR " $grname";
- $changes = 1;
- }
- }
- if ($grname eq $login_name && $#new_grmembers == -1) {
- # Remove a user's personal group if empty
- print STDERR " (removing group $grname -- personal group is empty)";
- $changes = 1;
- } else {
- $grmember_list = join(',', @new_grmembers);
- $new_grent = join(':', $grname, $grpass, $grgid, $grmember_list);
- print NEW_GROUP "$new_grent\n";
- }
- }
- }
- close(NEW_GROUP);
- rename($new_group_file, $group_file) || # Replace old group file with new
- die "\n${whoami}: Error: couldn't rename $new_group_file to $group_file ($!)\n";
- close(GROUP); # File handle is worthless now
- print STDERR " (no changes)" if (! $changes);
- print STDERR " done.\n";
-}
-
-sub remove_dir {
- # Remove the user's home directory
- local($dir) = @_;
- local($linkdir);
-
- if (-l $dir) {
- $linkdir = &resolvelink($dir);
- # Remove the symbolic link
- unlink($dir) ||
- warn "${whoami}: Warning: could not unlink symlink $dir: $!\n";
- if (!(-e $linkdir)) {
- #
- # Dangling symlink - just return now
- return;
- }
- # Set dir to be the resolved pathname
- $dir = $linkdir;
- }
- if (!(-d $dir)) {
- print STDERR "${whoami}: Warning: $dir is not a directory\n";
- unlink($dir) || warn "${whoami}: Warning: could not unlink $dir: $!\n";
- return;
- }
- system('/bin/rm', '-rf', $dir);
-}
-
-sub remove_files_from_dir {
- local($dir, $login_name, $uid) = @_;
- local($path, $i, $owner);
-
- print STDERR "Removing files belonging to ${login_name} from ${dir}:";
-
- if (!opendir(DELDIR, $dir)) {
- print STDERR "\n${whoami}: Warning: couldn't open directory ${dir} ($!)\n";
- return;
- }
- while ($i = readdir(DELDIR)) {
- next if $i eq '.';
- next if $i eq '..';
-
- $owner = (stat("$dir/$i"))[4]; # UID
- if ($uid == $owner) {
- if (-f "$dir/$i") {
- print STDERR " $i";
- unlink "$dir/$i" ||
- print STDERR "\n${whoami}: Warning: unlink on ${dir}/${i} failed ($!) - continuing\n";
- } else {
- print STDERR " ($i not a regular file - skipped)";
- }
- }
- }
- closedir(DELDIR);
-
- printf STDERR " done.\n";
-}
-
-
-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);
- }
- }
- 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 {
- local($path) = @_;
- local($l);
-
- while (-l $path && -e $path) {
- if (!defined($l = readlink($path))) {
- die "${whoami}: readlink on $path failed (but it should have worked!): $!\n";
- }
- if ($l =~ /^\//) {
- # Absolute link
- $path = $l;
- } else {
- # Relative link
- $path =~ s/\/[^\/]+\/?$/\/$l/; # Replace last component of path
- }
- }
- return $path;
-}
-
-sub kill_users_processes {
- local($login_name, $uid) = @_;
- local($pid, $result);
-
- #
- # Do something a little complex: fork a child that changes its
- # real and effective UID to that of the removed user, then issues
- # a "kill(9, -1)" to kill all processes of the same uid as the sender
- # (see kill(2) for details).
- # The parent waits for the exit of the child and then returns.
-
- if ($pid = fork) {
- # Parent process
- waitpid($pid, 0);
- } elsif (defined $pid) {
- # Child process
- $< = $uid;
- $> = $uid;
- if ($< != $uid || $> != $uid) {
- print STDERR "${whoami}: Error (kill_users_processes):\n" .
- "\tCouldn't reset uid/euid to ${uid}: current uid/euid's are $< and $>\n";
- exit 1;
- }
- $result = kill(9, -1);
- print STDERR "Killed process(es) belonging to $login_name.\n"
- if $result;
- exit 0;
- } else {
- # Couldn't fork!
- print STDERR "${whoami}: Error: couldn't fork to kill ${login_name}'s processes - continuing\n";
- }
-}