]>
git.cameronkatri.com Git - pw-darwin.git/blob - adduser/rmuser.perl
3 # Copyright 1995, 1996 Guy Helmer, Madison, South Dakota 57042.
6 # Redistribution and use in source and binary forms, with or without
7 # modification, are permitted provided that the following conditions
9 # 1. Redistributions of source code must retain the above copyright
10 # notice, this list of conditions and the following disclaimer as
11 # the first lines of this file unmodified.
12 # 2. Redistributions in binary form must reproduce the above copyright
13 # notice, this list of conditions and the following disclaimer in the
14 # documentation and/or other materials provided with the distribution.
15 # 3. The name of the author may not be used to endorse or promote products
16 # derived from this software without specific prior written permission.
18 # THIS SOFTWARE IS PROVIDED BY GUY HELMER ``AS IS'' AND ANY EXPRESS OR
19 # IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 # OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 # IN NO EVENT SHALL GUY HELMER BE LIABLE FOR ANY DIRECT, INDIRECT,
22 # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23 # NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 # THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 # rmuser - Perl script to remove users
31 # Guy Helmer <ghelmer@alpha.dsu.edu>, 07/17/96
33 # $Id: removeuser.perl,v 1.2 1996/08/11 13:03:25 wosch Exp $
41 $ENV { "PATH" } = "/bin:/sbin:/usr/bin:/usr/sbin" ;
44 $passwd_file = "/etc/master.passwd" ;
45 $new_passwd_file = "${passwd_file}.new. $$ " ;
46 $group_file = "/etc/group" ;
47 $new_group_file = "${group_file}.new. $$ " ;
48 $mail_dir = "/var/mail" ;
49 $crontab_dir = "/var/cron/tabs" ;
50 $atjob_dir = "/var/at/jobs" ;
57 print STDERR
"Caught signal SIG $sig -- cleaning up. \n " ;
59 if (- e
$new_passwd_file ) {
60 unlink $new_passwd_file ;
66 # Open the password file for reading
67 if (! open ( MASTER_PW
, " $passwd_file " )) {
68 print STDERR
"${whoami}: Error: Couldn't open ${passwd_file}: $! \n " ;
71 # Set the close-on-exec flag just in case
72 fcntl ( MASTER_PW
, & F_SETFD
, 1 );
73 # Apply an advisory lock the password file
74 if (! flock ( MASTER_PW
, & LOCK_EX
|& LOCK_NB
)) {
75 print STDERR
"Couldn't lock ${passwd_file}: $! \n " ;
81 flock ( MASTER_PW
, & LOCK_UN
);
84 $SIG { 'INT' } = 'cleanup' ;
85 $SIG { 'QUIT' } = 'cleanup' ;
86 $SIG { 'HUP' } = 'cleanup' ;
87 $SIG { 'TERM' } = 'cleanup' ;
90 print STDERR
"usage: ${whoami} [username] \n " ;
95 print STDERR
"${whoami}: Error: you must be root to use ${whoami} \n " ;
102 # Username was given as a parameter
103 $login_name = pop ( @ARGV );
105 # Get the user name from the user
106 $login_name = & get_login_name
;
109 if (( $pw_ent = & check_login_name
( $login_name )) eq '0' ) {
110 print STDERR
"${whoami}: Error: User ${login_name} not in password database \n " ;
115 ( $name , $password , $uid , $gid , $class , $change , $expire , $gecos , $home_dir ,
116 $shell ) = split ( /:/ , $pw_ent );
119 print "${whoami}: Sorry, I'd rather not remove a user with a uid of 0. \n " ;
124 print "Matching password entry: \n\n $pw_ent \n\n " ;
126 $ans = & get_yn
( "Is this the entry you wish to remove? " );
129 print "User ${login_name} not removed. \n " ;
135 # Get owner of user's home directory; don't remove home dir if not
136 # owned by $login_name
138 $remove_directory = 1 ;
141 $real_home_dir = & resolvelink
( $home_dir );
143 $real_home_dir = $home_dir ;
147 # If home_dir is a symlink and points to something that isn't a directory,
148 # or if home_dir is not a symlink and is not a directory, don't remove
149 # home_dir -- seems like a good thing to do, but probably isn't necessary...
150 if (((- l
$home_dir ) && ((- e
$real_home_dir ) && !(- d
$real_home_dir ))) ||
151 (!(- l
$home_dir ) && !(- d
$home_dir ))) {
152 print STDERR
"${whoami}: Home ${home_dir} is not a directory, so it won't be removed \n " ;
153 $remove_directory = 0 ;
156 if ( length ( $real_home_dir ) && - d
$real_home_dir ) {
157 $dir_owner = ( stat ( $real_home_dir ))[ 4 ]; # UID
158 if ( $dir_owner != $uid ) {
159 print STDERR
"${whoami}: Home dir ${real_home_dir} is not owned by ${login_name} (uid ${dir_owner}) \n " ;
160 $remove_directory = 0 ;
164 if ( $remove_directory ) {
165 $ans = & get_yn
( "Remove user's home directory ( $home_dir )? " );
167 $remove_directory = 0 ;
174 # Remove the user's crontab, if there is one
175 # (probably needs to be done before password databases are updated)
177 if (- e
" $crontab_dir/$login_name " ) {
178 print STDERR
"Removing user's crontab:" ;
179 system ( '/usr/bin/crontab' , '-u' , $login_name , '-r' );
180 print STDERR
" done. \n " ;
184 # Remove the user's at jobs, if any
185 # (probably also needs to be done before password databases are updated)
187 & remove_at_jobs
( $login_name , $uid );
190 # Copy master password file to new file less removed user's entry
195 # Remove the user from all groups in /etc/group
197 & update_group_file
( $login_name );
200 # Remove the user's home directory
202 if ( $remove_directory ) {
203 print STDERR
"Removing user's home directory ( $home_dir ):" ;
204 & remove_dir
( $home_dir );
205 print STDERR
" done. \n " ;
209 # Remove the user's incoming mail file
211 if (- e
" $mail_dir/$login_name " || - l
" $mail_dir/$login_name " ) {
212 print STDERR
"Removing user's incoming mail file ( $mail_dir/$login_name ):" ;
213 unlink " $mail_dir/$login_name " ||
214 print STDERR
" \n ${whoami}: warning: unlink on $mail_dir/$login_name failed ( $! ) - continuing \n " ;
215 print STDERR
" done. \n " ;
225 # Get new user's name
226 local ( $done , $login_name );
228 for ( $done = 0 ; ! $done ; ) {
229 print "Enter login name for user to remove: " ;
232 if (!( $login_name =~ /[A-Za-z0-9_]/ )) {
233 print STDERR
"Sorry, login name must contain alphanumeric characters only. \n " ;
234 } elsif ( length ( $login_name ) > 8 || length ( $login_name ) == 0 ) {
235 print STDERR
"Sorry, login name must be eight characters or less. \n " ;
241 print "User name is ${login_name} \n " if $debug ;
245 sub check_login_name
{
247 # Check to see whether login name is in password file
248 local ( $login_name ) = @_ ;
249 local ( $Mname , $Mpassword , $Muid , $Mgid , $Mclass , $Mchange , $Mexpire ,
250 $Mgecos , $Mhome_dir , $Mshell );
253 seek ( MASTER_PW
, 0 , 0 );
254 while ( $i = < MASTER_PW
>) {
256 ( $Mname , $Mpassword , $Muid , $Mgid , $Mclass , $Mchange , $Mexpire ,
257 $Mgecos , $Mhome_dir , $Mshell ) = split ( /:/ , $i );
258 if ( $Mname eq $login_name ) {
259 seek ( MASTER_PW
, 0 , 0 );
260 return ( $i ); # User is in password database
263 seek ( MASTER_PW
, 0 , 0 );
265 return '0' ; # User wasn't found
270 # Get a yes or no answer; return 'Y' or 'N'
274 for ( $done = 0 ; ! $done ; ) {
279 if (!( $ans =~ /^[YN]/ )) {
280 print STDERR
"Please answer (y)es or (n)o. \n " ;
286 return ( substr ( $ans , 0 , 1 ));
289 sub update_passwd_file
{
292 print STDERR
"Updating password file," ;
293 seek ( MASTER_PW
, 0 , 0 );
294 open ( NEW_PW
, "> $new_passwd_file " ) ||
295 die " \n ${whoami}: Error: Couldn't open file ${new_passwd_file}: \n $! \n " ;
296 chmod ( 0600 , $new_passwd_file ) ||
297 print STDERR
" \n ${whoami}: warning: couldn't set mode of $new_passwd_file to 0600 ( $! ) \n\t continuing, but please check mode of /etc/master.passwd! \n " ;
299 while ( $i = < MASTER_PW
>) {
306 print STDERR
"Dropped entry for $login_name \n " if $debug ;
311 seek ( MASTER_PW
, 0 , 0 );
314 print STDERR
" \n ${whoami}: Whoops! Didn't find ${login_name}'s entry second time around! \n " ;
315 unlink ( $new_passwd_file ) ||
316 print STDERR
" \n ${whoami}: warning: couldn't unlink $new_passwd_file ( $! ) \n\t Please investigate, as this file should not be left in the filesystem \n " ;
322 # Run pwd_mkdb to install the updated password files and databases
324 print STDERR
" updating databases," ;
325 system ( '/usr/sbin/pwd_mkdb' , '-p' , ${ new_passwd_file
});
326 print STDERR
" done. \n " ;
328 close ( MASTER_PW
); # Not useful anymore
331 sub update_group_file
{
332 local ( $login_name ) = @_ ;
334 local ( $i , $j , $grmember_list , $new_grent );
335 local ( $grname , $grpass , $grgid , $grmember_list , @grmembers );
337 print STDERR
"Updating group file:" ;
338 open ( GROUP
, $group_file ) ||
339 die " \n ${whoami}: Error: couldn't open ${group_file}: $! \n " ;
340 if (! flock ( GROUP
, & LOCK_EX
|& LOCK_NB
)) {
341 print STDERR
" \n ${whoami}: Error: couldn't lock ${group_file}: $! \n " ;
344 local ( $group_perms , $group_uid , $group_gid ) =
345 ( stat ( GROUP
))[ 2 , 4 , 5 ]; # File Mode, uid, gid
346 open ( NEW_GROUP
, "> $new_group_file " ) ||
347 die " \n ${whoami}: Error: couldn't open ${new_group_file}: $! \n " ;
348 chmod ( $group_perms , $new_group_file ) ||
349 printf STDERR
" \n ${whoami}: warning: could not set permissions of new group file to %o ( $! ) \n\t Continuing, but please check permissions of $group_file! \n " , $group_perms ;
350 chown ( $group_uid , $group_gid , $new_group_file ) ||
351 print STDERR
" \n ${whoami}: warning: could not set owner/group of new group file to ${group_uid}/${group_gid} ( $! ) \n\r Continuing, but please check ownership of $group_file! \n " ;
352 while ( $i = < GROUP
>) {
353 if (!( $i =~ /$login_name/ )) {
354 # Line doesn't contain any references to the user, so just add it
359 # Remove the user from the group
363 ( $grname , $grpass , $grgid , $grmember_list ) = split ( /:/ , $i );
364 @grmembers = split ( /,/ , $grmember_list );
365 undef @new_grmembers ;
366 local ( @new_grmembers );
367 foreach $j ( @grmembers ) {
368 if ( $j ne $login_name ) {
369 push ( new_grmembers
, $j );
371 print STDERR
"Removing $login_name from group $grname \n " ;
374 if ( $grname eq $login_name && $#new_grmembers == - 1 ) {
375 # Remove a user's personal group if empty
376 print STDERR
"Removing group $grname -- personal group is empty \n " ;
378 $grmember_list = join ( ',' , @new_grmembers );
379 $new_grent = join ( ':' , $grname , $grpass , $grgid , $grmember_list );
380 print NEW_GROUP
" $new_grent \n " ;
385 rename ( $new_group_file , $group_file ) || # Replace old group file with new
386 die " \n ${whoami}: error: couldn't rename $new_group_file to $group_file ( $! ) \n " ;
387 close ( GROUP
); # File handle is worthless now
388 print STDERR
" done. \n " ;
392 # Remove the user's home directory
397 $linkdir = & resolvelink
( $dir );
398 # Remove the symbolic link
400 warn "${whoami}: Warning: could not unlink symlink $dir : $! \n " ;
401 if (!(- e
$linkdir )) {
403 # Dangling symlink - just return now
406 # Set dir to be the resolved pathname
410 print STDERR
"${whoami}: Warning: $dir is not a directory \n " ;
411 unlink ( $dir ) || warn "${whoami}: Warning: could not unlink $dir : $! \n " ;
414 system ( '/bin/rm' , '-rf' , $dir );
418 local ( $login_name , $uid ) = @_ ;
419 local ( $i , $owner , $found );
422 opendir ( ATDIR
, $atjob_dir ) || return ;
423 while ( $i = readdir ( ATDIR
)) {
426 next if $i eq '.lockfile' ;
428 $owner = ( stat ( " $atjob_dir/$i " ))[ 4 ]; # UID
429 if ( $uid == $owner ) {
431 print STDERR
"Removing user's at jobs:" ;
434 # Use atrm to remove the job
436 system ( '/usr/bin/atrm' , $i );
441 print STDERR
" done. \n " ;
449 while (- l
$path && - e
$path ) {
450 if (! defined ( $l = readlink ( $path ))) {
451 die "${whoami}: readlink on $path failed (but it should have worked!): $! \n " ;
458 $path =~ s/\/[^\/ ]+ \
/?$/ \
/$l/ ; # Replace last component of path