From d7ab7c04d4d43c06ce16c5a3c1eb5a12085fee52 Mon Sep 17 00:00:00 2001 From: downsj Date: Sun, 8 Dec 1996 13:57:06 +0000 Subject: [PATCH] sync with FreeBSD, except for the damned tcl script. --- usr.sbin/adduser/Makefile | 12 +- usr.sbin/adduser/adduser.perl | 12 +- usr.sbin/adduser/rmgroup.8 | 53 ++++ usr.sbin/adduser/rmgroup.sh | 31 +++ usr.sbin/adduser/rmuser.8 | 106 ++++++++ usr.sbin/adduser/rmuser.perl | 465 ++++++++++++++++++++++++++++++++++ 6 files changed, 669 insertions(+), 10 deletions(-) create mode 100644 usr.sbin/adduser/rmgroup.8 create mode 100644 usr.sbin/adduser/rmgroup.sh create mode 100644 usr.sbin/adduser/rmuser.8 create mode 100644 usr.sbin/adduser/rmuser.perl diff --git a/usr.sbin/adduser/Makefile b/usr.sbin/adduser/Makefile index bd7175c9ce8..22f7b88d129 100644 --- a/usr.sbin/adduser/Makefile +++ b/usr.sbin/adduser/Makefile @@ -1,9 +1,13 @@ -# $OpenBSD: Makefile,v 1.1 1996/09/28 05:58:34 downsj Exp $ +# $OpenBSD: Makefile,v 1.2 1996/12/08 13:57:06 downsj Exp $ +# $From: Makefile,v 1.9 1996/11/17 03:51:26 wosch Exp $ -MAN= adduser.8 adduser_proc.8 +SCRIPTS= adduser.perl rmuser.perl rmgroup.sh +MAN= adduser.8 adduser_proc.8 rmuser.8 rmgroup.8 beforeinstall: - install ${COPY} -o ${BINOWN} -g ${BINGRP} -m ${BINMODE} \ - ${.CURDIR}/adduser.perl ${DESTDIR}${BINDIR}/adduser +.for script in ${SCRIPTS} + ${INSTALL} -c -o ${BINOWN} -g ${BINGRP} -m ${BINMODE} \ + ${.CURDIR}/${script} ${DESTDIR}${BINDIR}/${script:R} +.endfor .include diff --git a/usr.sbin/adduser/adduser.perl b/usr.sbin/adduser/adduser.perl index fe0152b7bc5..5f5c9196463 100644 --- a/usr.sbin/adduser/adduser.perl +++ b/usr.sbin/adduser/adduser.perl @@ -1,6 +1,6 @@ #!/usr/bin/perl # -# $OpenBSD: adduser.perl,v 1.1 1996/09/28 05:58:35 downsj Exp $ +# $OpenBSD: adduser.perl,v 1.2 1996/12/08 13:57:07 downsj Exp $ # # Copyright (c) 1995-1996 Wolfram Schneider . Berlin. # All rights reserved. @@ -26,7 +26,7 @@ # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF # SUCH DAMAGE. # -# $From: adduser.perl,v 1.19 1996/09/17 19:34:56 wosch Exp $ +# $From: adduser.perl,v 1.22 1996/12/07 21:25:12 ache Exp $ # read variables @@ -257,7 +257,7 @@ sub passwd_read { print "User $p_username: illegal shell: ``$sh''\n" if ($verbose && $sh && !$shell{&basename($sh)} && - $p_username !~ /^(bin|uucp|falcon|nobody)$/ && + $p_username !~ /^(news|xten|bin|nobody|uucp)$/ && $sh !~ /\/(pppd|sliplogin)$/); $uid{$p_uid} = $p_username; $pwgid{$p_gid} = $p_username; @@ -309,7 +309,7 @@ sub new_users_name { local($name); while(1) { - $name = &confirm_list("Enter username", 1, "a-z0-9", ""); + $name = &confirm_list("Enter username", 1, "A-Za-z0-9_", ""); if (length($name) > 8) { warn "Username is longer than 8 chars\a\n"; next; @@ -1188,8 +1188,8 @@ sub message_create { \$fullname, -your account ``\$name'' was created. Your password is ``\$password''. -Please expire your password. Have fun! +your account ``\$name'' was created. +Have fun! See also chpass(1), finger(1), passwd(1) EOF diff --git a/usr.sbin/adduser/rmgroup.8 b/usr.sbin/adduser/rmgroup.8 new file mode 100644 index 00000000000..787987fbb37 --- /dev/null +++ b/usr.sbin/adduser/rmgroup.8 @@ -0,0 +1,53 @@ +.\" $OpenBSD: rmgroup.8,v 1.1 1996/12/08 13:57:08 downsj Exp $ +.\" +.\" Copyright (c) 1996 Wolfram Schneider . Berlin. +.\" 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. +.\" 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. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 THE AUTHOR OR CONTRIBUTORS 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. +.\" +.\" $From: rmgroup.8,v 1.1 1996/11/04 17:21:11 wosch Exp $ + +.Dd Oct, 30, 1996 +.Dt RMGROUP 8 +.Os +.Sh NAME +.Nm rmgroup +.Nd delete a Unix group +.Sh SYNOPSIS +.Nm +.Ar group +.Sh DESCRIPTION +.Nm +delete a Unix group from group database. +.Nm +do not delete the system groups wheel, daemon, kmem, sys, tty, +operator, bin, nogroup, nobody, +and not groups with gid 0. +.Sh SEE ALSO +.Xr group 5 , +.Xr adduser 8 , +.Xr addgroup 8 , +.Xr rmuser 8 +.Sh HISTORY +The +.Nm +command appeared in FreeBSD 2.2. diff --git a/usr.sbin/adduser/rmgroup.sh b/usr.sbin/adduser/rmgroup.sh new file mode 100644 index 00000000000..b9018b9eab9 --- /dev/null +++ b/usr.sbin/adduser/rmgroup.sh @@ -0,0 +1,31 @@ +#!/bin/sh +# $OpenBSD: rmgroup.sh,v 1.1 1996/12/08 13:57:08 downsj Exp $ +# +# Copyright (c) 1996 Wolfram Schneider . Berlin. +# All rights reserved. +# +# rmgroup - delete a Unix group +# +# $From: rmgroup.sh,v 1.1 1996/10/30 20:58:47 wosch Exp $ + +PATH=/bin:/usr/bin; export PATH +db=/etc/group + +case "$1" in + ""|-*) echo "usage: rmgroup group"; exit 1;; + wheel|daemon|kmem|sys|tty|operator|bin|nogroup|nobody) + echo "Do not remove system group: $1"; exit 2;; + *) group="$1";; +esac + +if egrep -q -- "^$group:" $db; then + if egrep -q -- "^$group:\*:0:" $db; then + echo "Do not remove group with gid 0: $group" + exit 2 + fi + egrep -v -- "^$group:" $db > $db.new && + cp -pf $db $db.bak && + mv -f $db.new $db +else + echo "Group \"$group\" does not exists in $db."; exit 1 +fi diff --git a/usr.sbin/adduser/rmuser.8 b/usr.sbin/adduser/rmuser.8 new file mode 100644 index 00000000000..2632602bf35 --- /dev/null +++ b/usr.sbin/adduser/rmuser.8 @@ -0,0 +1,106 @@ +.\" $OpenBSD: rmuser.8,v 1.1 1996/12/08 13:57:09 downsj Exp $ +.\" +.\" 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. +.\" +.\" $From: rmuser.8,v 1.1 1996/11/17 03:51:31 wosch Exp $ +.\" +.Dd July 16, 1996 +.Dt RMUSER 8 +.Os +.Sh NAME +.Nm rmuser +.Nd remove users from the system +.Sh SYNOPSIS +.Nm rmuser +.Op Ar username +.Sh DESCRIPTION +The utility +.Nm rmuser +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 rmuser +politely refuses to remove users whose uid is 0 (typically root), since +it seemed like a good idea at the time +.Nm rmuser +was written. +.Pp +.Nm rmuser +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 rmuser +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 rmuser +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 addgroup 8 , +.Xr pwd_mkdb 8 , +.Xr rmgroup 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/usr.sbin/adduser/rmuser.perl b/usr.sbin/adduser/rmuser.perl new file mode 100644 index 00000000000..d19add58a83 --- /dev/null +++ b/usr.sbin/adduser/rmuser.perl @@ -0,0 +1,465 @@ +#!/usr/bin/perl +# -*- perl -*- +# +# $OpenBSD: rmuser.perl,v 1.1 1996/12/08 13:57:09 downsj Exp $ +# +# 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. +# +# rmuser - Perl script to remove users +# +# Guy Helmer , 07/17/96 +# +# $From: rmuser.perl,v 1.2 1996/12/07 21:25:12 ache Exp $ + +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 (-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}: 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}: Home dir ${real_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) > 16 || length($login_name) == 0) { + print STDERR "Sorry, login name must be 16 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 = ) { + 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 = ) { + 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 = ) { + 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 { + # 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_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"; + } +} + +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; +} -- 2.20.1