summaryrefslogtreecommitdiffstats
path: root/share/examples
diff options
context:
space:
mode:
authorwosch <wosch@FreeBSD.org>1996-07-10 22:29:30 +0000
committerwosch <wosch@FreeBSD.org>1996-07-10 22:29:30 +0000
commitd8e4fc26f823d23548c55eab345ac121fcb3a1d3 (patch)
tree35ecf530a0906493bf9823cfbb9cc459eb008a07 /share/examples
downloadFreeBSD-src-d8e4fc26f823d23548c55eab345ac121fcb3a1d3.zip
FreeBSD-src-d8e4fc26f823d23548c55eab345ac121fcb3a1d3.tar.gz
import removeuser from Guy Helmer
see file TODO for known problems
Diffstat (limited to 'share/examples')
-rw-r--r--share/examples/removeuser/README.removeuser11
-rw-r--r--share/examples/removeuser/TODO31
-rw-r--r--share/examples/removeuser/removeuser.8105
-rw-r--r--share/examples/removeuser/removeuser.perl416
4 files changed, 563 insertions, 0 deletions
diff --git a/share/examples/removeuser/README.removeuser b/share/examples/removeuser/README.removeuser
new file mode 100644
index 0000000..28d354c
--- /dev/null
+++ b/share/examples/removeuser/README.removeuser
@@ -0,0 +1,11 @@
+# $Id$
+
+Here lies removeuser(8) for FreeBSD 2.x. It will remove a user's
+password entry, home directory, and incoming mail file from /var/mail.
+
+Install removeuser.perl into /usr/local/sbin, /usr/sbin, or where ever
+you like; install removeuser.8 into /usr/local/man/man8 or where ever.
+I suggest these commands to install it:
+
+install -c -o bin -g bin -m 555 removeuser.perl /usr/local/sbin/removeuser
+install -c -o bin -g bin -m 444 removeuser.8 /usr/local/man/man8/removeuser.8
diff --git a/share/examples/removeuser/TODO b/share/examples/removeuser/TODO
new file mode 100644
index 0000000..80b1071
--- /dev/null
+++ b/share/examples/removeuser/TODO
@@ -0,0 +1,31 @@
+# $Id: $
+
+Deleting a user is a complex task:
+
+DONE:
+- delete password entry
+- delete user from group database (/etc/group), may be delete groups
+- remove home dir
+- remove mailbox
+- delete crontab entries (/etc/crontab, /var/cron/allow,
+/var/cron/deny, /var/cron/tabs/user)
+- delete at(8) entries
+
+TODO:
+- delete ppp password (/etc/ppp/*)
+- delete slip entries (/etc/sliphome*)
+- delete user from /etc/ftpusers
+- check for other users with same uid (may be also for groups)
+- remove WWW files (/~user), which are not in HOME located
+- check other FS, $ find / -user user -print, delete suid/sgid bit,
+ remove files in /var/tmp
+- delete user from /etc/inetd.conf, remove files which owned by user
+- delete user from /etc/rc.local if the user start programs
+
+- delete mail aliases (/etc/aliases, may be /etc/sendmail.cf)
+- delete user phone numbers in /etc/phones
+- remove quota
+
+KNOWN BUGS:
+- removeuser does not remove the HOME directory if the HOME
+ directory is a symbolic link.
diff --git a/share/examples/removeuser/removeuser.8 b/share/examples/removeuser/removeuser.8
new file mode 100644
index 0000000..b17f557
--- /dev/null
+++ b/share/examples/removeuser/removeuser.8
@@ -0,0 +1,105 @@
+.\" Copyright 1995, 1996
+.\" Guy Helmer, Madison, South Dakota 57042. 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. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by Guy Helmer.
+.\" 4. 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.
+.\"
+.\" $Id$
+.\"
+.Dd June 28, 1996
+.Dt REMOVEUSER 8
+.Os
+.Sh NAME
+.Nm removeuser
+.Nd remove users from the system
+.Sh SYNOPSIS
+.Nm removeuser
+.Op Ar username
+.Sh DESCRIPTION
+The utility
+.Nm removeuser
+removes a user's
+.Xr crontab 1
+entry (if any) and any
+.Xr at 1
+jobs belonging to the user,
+then removes a user from the system's local password file, removes
+the user's home directory if it is owned by the user, and removes
+the user's incoming mail file if it exists. The username is removed
+from any groups to which it belongs in the file
+.Pa /etc/group .
+If a group becomes empty and the group name is the same as the username,
+the group is removed (this complements
+.Xr adduser 8 's
+per-user unique groups).
+.Pp
+.Nm removeuser
+politely refuses to remove users whose uid is 0 (typically root), since
+it seemed like a good idea at the time
+.Nm removeuser
+was written.
+.Pp
+.Nm removeuser
+shows the selected user's password file entry and asks for confirmation
+that you wish to remove the user. If the user's home directory is owned
+by the user (and not by any other user),
+.Nm removeuser
+asks whether you wish to remove the user's home directory and everything
+below.
+.Pp
+Available options:
+.Pp
+.Bl -tag -width username
+.It Ar \&username
+Identifies the user to be removed; if not present,
+.Nm removeuser
+interactively asks for the user to be removed.
+.Sh FILES
+.Bl -tag -width /etc/master.passwd -compact
+.It Pa /etc/master.passwd
+.It Pa /etc/passwd
+.It Pa /etc/group
+.It Pa /etc/spwd.db
+.It Pa /etc/pwd.db
+.El
+.Sh SEE ALSO
+.Xr at 1 ,
+.Xr chpass 1 ,
+.Xr crontab 1 ,
+.Xr finger 1 ,
+.Xr passwd 1 ,
+.Xr group 5 ,
+.Xr passwd 5 ,
+.Xr adduser 8 ,
+.Xr pwd_mkdb 8 ,
+.Xr vipw 8
+.Sh HISTORY
+The
+.Nm
+command appeared in FreeBSD 2.1.5
+
+.\" .Sh AUTHOR
+.\" Guy Helmer, Madison, South Dakota
diff --git a/share/examples/removeuser/removeuser.perl b/share/examples/removeuser/removeuser.perl
new file mode 100644
index 0000000..a0fd742
--- /dev/null
+++ b/share/examples/removeuser/removeuser.perl
@@ -0,0 +1,416 @@
+#!/usr/bin/perl
+# -*- perl -*-
+# Copyright 1995, 1996 Guy Helmer, Madison, South Dakota 57042.
+# 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.
+#
+# /usr/sbin/removeuser
+# Perl script to remove users
+#
+# Guy Helmer <ghelmer@alpha.dsu.edu>, 06/30/96
+#
+# $Id$
+
+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";
+$new_passwd_file = "${passwd_file}.new.$$";
+$group_file = "/etc/group";
+$new_group_file = "${group_file}.new.$$";
+$mail_dir = "/var/mail";
+$crontab_dir = "/var/cron/tabs";
+$atjob_dir = "/var/at/jobs";
+
+#$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 "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 > 0) {
+ print STDERR "usage: ${whoami} [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 {
+ # Get the user name from the user
+ $login_name = &get_login_name;
+}
+
+if (($pw_ent = &check_login_name($login_name)) eq '0') {
+ 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}: Sorry, I'd rather not remove a user with a uid of 0.\n";
+ &unlockpw;
+ exit 1;
+}
+
+print "Matching password entry:\n\n$pw_ent\n\n";
+
+$ans = &get_yn("Is this the entry you wish to remove? ");
+
+if ($ans eq 'N') {
+ print "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 (!(-d $home_dir)) {
+ print STDERR "${whoami}: Home ${home_dir} is not a directory, so it won't be removed\n";
+ $remove_directory = 0;
+} else {
+ $dir_owner = (stat($home_dir))[4]; # UID
+ if ($dir_owner != $uid) {
+ print STDERR "${whoami}: Home dir ${home_dir} is not owned by ${login_name} (uid ${dir_owner})\n";
+ $remove_directory = 0;
+ }
+}
+
+if ($remove_directory) {
+ $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, $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 the user's incoming mail file
+
+if (-e "$mail_dir/$login_name" || -l "$mail_dir/$login_name") {
+ print STDERR "Removing user's incoming mail file ($mail_dir/$login_name):";
+ unlink "$mail_dir/$login_name" ||
+ print STDERR "\n${whoami}: warning: unlink on $mail_dir/$login_name failed ($!) - continuing\n";
+ print STDERR " done.\n";
+}
+
+#
+# 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 = <>;
+ chop $login_name;
+ if (!($login_name =~ /[A-Za-z0-9_]/)) {
+ print STDERR "Sorry, login name must contain alphanumeric characters only.\n";
+ } elsif (length($login_name) > 8 || length($login_name) == 0) {
+ print STDERR "Sorry, login name must be eight characters or less.\n";
+ } else {
+ $done = 1;
+ }
+ }
+
+ print "User name is ${login_name}\n" if $debug;
+ 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'
+ 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, $i);
+
+ 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";
+ $skipped = 0;
+ while ($i = <MASTER_PW>) {
+ if ($i =~ /\n$/) {
+ chop $i;
+ }
+ if ($i ne $pw_ent) {
+ print NEW_PW "$i\n";
+ } else {
+ print STDERR "Dropped entry for $login_name\n" if $debug;
+ $skipped = 1;
+ }
+ }
+ 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($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";
+ &unlockpw;
+ exit 1;
+ }
+
+ #
+ # Run pwd_mkdb to install the updated password files and databases
+
+ print STDERR " updating databases,";
+ system('/usr/sbin/pwd_mkdb', '-p', ${new_passwd_file});
+ print STDERR " done.\n";
+
+ close(MASTER_PW); # Not useful anymore
+}
+
+sub update_group_file {
+ local($login_name) = @_;
+
+ local($i, $j, $grmember_list, $new_grent);
+ local($grname, $grpass, $grgid, $grmember_list, @grmembers);
+
+ 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 =~ /$login_name/)) {
+ # 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);
+ } elsif ($debug) {
+ print STDERR "Removing $login_name from group $grname\n";
+ }
+ }
+ 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\n";
+ } 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 " done.\n";
+}
+
+sub remove_dir {
+ # Recursively remove directories
+ local($dir) = @_;
+
+ if (!(-d $dir)) {
+ print STDERR "${whoami}: Error: $dir is not a directory\n";
+ return;
+ }
+ system('/bin/rm', '-rf', $dir);
+}
+
+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);
+ }
+ }
+ closedir(ATDIR);
+ if ($found) {
+ print STDERR " done.\n";
+ }
+}
OpenPOWER on IntegriCloud