home *** CD-ROM | disk | FTP | other *** search
/ PC Welt 2006 November (DVD) / PCWELT_11_2006.ISO / casper / filesystem.squashfs / usr / sbin / deluser < prev    next >
Encoding:
Text File  |  2006-07-10  |  13.8 KB  |  480 lines

  1. #!/usr/bin/perl
  2.  
  3. # deluser -- a utility to remove users from the system
  4. # delgroup -- a utilty to remove groups from the system
  5. my $version = "3.92";
  6.  
  7. # Copyright (C) 2000 Roland Bauerschmidt <rb@debian.org>
  8. # Based on 'adduser' as pattern by
  9. #     Guy Maor <maor@debian.org>
  10. #     Ted Hajek <tedhajek@boombox.micro.umn.edu>
  11. #     Ian A. Murdock <imurdock@gnu.ai.mit.edu>
  12.  
  13. # This program is free software; you can redistribute it and/or modify
  14. # it under the terms of the GNU General Public License as published by
  15. # the Free Software Foundation; either version 2 of the License, or
  16. # (at your option) any later version.
  17. #
  18. # This program is distributed in the hope that it will be useful,
  19. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  20. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  21. # GNU General Public License for more details.
  22. #
  23. # You should have received a copy of the GNU General Public License
  24. # along with this program; if not, write to the Free Software
  25. # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  26.  
  27. ####################
  28. # See the usage subroutine for explanation about how the program can be called
  29. ####################
  30.  
  31. use warnings;
  32. use strict;
  33. use Getopt::Long;
  34. use Debian::AdduserCommon;
  35.  
  36. my $install_more_packages ;
  37.  
  38. BEGIN {
  39.     eval 'use File::Find';
  40.     if ($@) {
  41.       $install_more_packages = 1;
  42.     }
  43.     #no warnings "File::Find";
  44.     eval 'use File::Temp';
  45.     if ($@) {
  46.       $install_more_packages = 1;
  47.     }
  48. }
  49.  
  50.  
  51. BEGIN {
  52.     eval 'use Locale::gettext';
  53.     if ($@) {
  54.         *gettext = sub { shift };
  55.         *textdomain = sub { "" };
  56.         *LC_MESSAGES = sub { 5 };
  57.     }
  58.     eval {
  59.         require POSIX;
  60.         import POSIX qw(setlocale);
  61.     };
  62.     if ($@) {
  63.         *setlocale = sub { return 1 };
  64.     }
  65. }
  66.  
  67. setlocale(LC_MESSAGES, "");
  68. textdomain("adduser");
  69.  
  70. my $action = $0 =~ /delgroup$/ ? "delgroup" : "deluser";
  71. our $verbose = 1;
  72. my %pconfig = ();
  73. my %config = ();
  74. my $configfile;
  75. my @defaults;
  76.  
  77. GetOptions ("quiet|q" => sub {$verbose = 0; },
  78.             "debug" => sub {$verbose = 2; },
  79.         "version|v" => sub {version(); exit 0; },
  80.         "help|h" => sub { usage(); exit 0;},
  81.         "group" => sub { $action = "delgroup";},
  82.         "conf=s" => \$configfile,
  83.         "system" => \$pconfig{"system"},
  84.         "only-if-empty" => \$pconfig{"only_if_empty"},
  85.         "remove-home" => \$pconfig{"remove_home"},
  86.         "remove-all-files" => \$pconfig{"remove_all_files"},
  87.         "backup" => \$pconfig{"backup"},
  88.         "backup-to" => \$pconfig{"backup_to"}
  89.       );
  90.  
  91. die ("$0: ",gtx("Only root may remove a user or group from the system.\n")) if ($> != 0);
  92.  
  93. if (!defined($configfile)) { 
  94.     @defaults = ("/etc/adduser.conf", "/etc/deluser.conf");
  95. } else {
  96.     @defaults = ($configfile);
  97. }
  98.  
  99. my @names = ();
  100. my ($user,$group);
  101.  
  102. ######################
  103. # handling of @names #
  104. ######################
  105.  
  106. while (defined(my $arg = shift(@ARGV))) {
  107.   if (defined($names[0]) && $arg =~ /^--/) {
  108.       die ("$0: ",gtx("No options allowed after names.\n"));
  109.     } else {            # it's a username
  110.     push (@names, $arg);
  111.     }
  112. }
  113.  
  114. if(@names == 0) {
  115.     if($action eq "delgroup") {
  116.     print (gtx("Enter a group name to remove: "));
  117.     } else {
  118.     print (gtx("Enter a user name to remove: "));
  119.     }
  120.     chomp(my $answer=<STDIN>);
  121.     push(@names, $answer);
  122. }
  123.  
  124. if (length($names[0]) == 0 || @names > 2) {
  125.     die ("$0: ",gtx("Only one or two names allowed.\n"));
  126. }
  127.  
  128. if(@names == 2) {      # must be deluserfromgroup
  129.     $action = "deluserfromgroup";
  130.     $user = shift(@names);
  131.     $group = shift(@names);
  132. } else {
  133.     if($action eq "delgroup") {
  134.     $group = shift(@names);
  135.     } else {
  136.     $user = shift(@names);
  137.     }
  138. }
  139.  
  140. undef(@names);
  141.  
  142.  
  143. ##########################################################
  144. # (1) preseed the config
  145. # (2) read the default /etc/adduser.conf configuration.
  146. # (3) read the default /etc/deluser.conf configuration.
  147. # (4) process commmand line settings
  148. # last match wins
  149. ##########################################################
  150.  
  151. preseed_config (\@defaults,\%config);
  152.  
  153. foreach(keys(%pconfig)) {
  154.     $config{$_} = $pconfig{$_} if ($pconfig{$_});
  155. }
  156. undef (%pconfig);
  157.  
  158. if (($config{remove_home} || $config{remove_all_files} || $config{backup}) && ($install_more_packages)) {
  159.     die (gtx("In order to use the --remove-home, --remove-all-files, and --backup features,
  160. you need to install the `perl-modules' package. To accomplish that, run
  161. apt-get install perl-modules\n"));
  162. }
  163.  
  164.  
  165. my ($pw_uid, $pw_gid, $pw_homedir, $gr_gid, $maingroup);
  166.  
  167. if($user) {
  168.     #($pw_name,$pw_passwd,$pw_uid,$pw_gid,$pw_quota,$pw_comment,
  169.     # $pw_gecos,$pw_homedir,$pw_shell,$pw_expire) = getpwnam($user);
  170.     my @passwd = getpwnam($user);
  171.     $pw_uid = $passwd[2];
  172.     $pw_gid = $passwd[3];
  173.     $pw_homedir = $passwd[7];
  174.     
  175.     $maingroup = $pw_gid ? getgrgid($pw_gid) : "";
  176. }
  177. if($group) {
  178.     #($gr_name,$gr_passwd,$gr_gid,$gr_members) = getgrnam($group);
  179.     my @group = getgrnam($group);
  180.     $gr_gid = $group[2];
  181. }
  182.  
  183. # arguments are processed:
  184. #
  185. #  $action = "deluser"
  186. #     $user          name of the user to remove
  187. #
  188. #  $action = "delgroup"
  189. #     $group         name of the group to remove
  190. #
  191. #  $action = "deluserfromgroup"
  192. #     $user          the user to be remove
  193. #     $group         the group to remove him/her from
  194.  
  195.  
  196. if($action eq "deluser") {
  197.     &invalidate_nscd();
  198.     
  199.     my($dummy1,$dummy2,$uid);
  200.  
  201.     # Don't allow a non-system user to be deleted when --system is given
  202.     # Also, "user does not exist" is only a warning with --system, but an
  203.     # error without --system.
  204.     if( $config{"system"} ) {
  205.     if( ($dummy1,$dummy2,$uid) = getpwnam($user) ) {
  206.         if ( ($uid < $config{"first_system_uid"} ||
  207.         $uid > $config{"last_system_uid" } ) ) {
  208.         printf (gtx("The user `%s' is not a system account... Exiting.\n"), $user) if $verbose;
  209.         exit 1;
  210.         }
  211.         } else {
  212.         printf (gtx("The user `%s' does not exist, but --system was given... Exiting.\n"), $user) if $verbose;
  213.         exit 0;
  214.     }
  215.     }
  216.     
  217.     unless(exist_user($user)) {
  218.     fail (2,gtx("The user `%s' does not exist.\n"),$user);
  219.     }
  220.  
  221.  
  222.     if($config{"remove_home"} || $config{"remove_all_files"}) {
  223.       s_print (gtx("Looking for files to backup/remove...\n"));
  224.       my @mountpoints;
  225.       open(MOUNT, "mount |")
  226.           || fail (4 ,gtx("fork for parse mount points failed: %s\n", $!));
  227.       while (<MOUNT>) {
  228.           my @temparray = split;
  229.           my $fstype = $temparray[4];
  230.           my $exclude_fstypes = $config{"exclude_fstypes"};
  231.           if (defined($exclude_fstypes)) {
  232.               next if ($fstype =~ /$exclude_fstypes/);
  233.           }
  234.           push @mountpoints,$temparray[2];
  235.       }
  236.       close(MOUNT) or die (gtx("can't close mount pipe: %s\n",$!));
  237.       my(@files,@dirs);
  238.       if($config{"remove_home"} && ! $config{"remove_all_files"}) {
  239.  
  240.     sub home_match {
  241.       # according to the manpage
  242.       foreach my $mount (@mountpoints) {
  243.         if( $File::Find::name eq $mount ) {
  244.           s_printf (gtx("Not backing up/removing `%s', it is a mount point.\n"),$File::Find::name);
  245.           $File::Find::prune=1;
  246.           return;
  247.         }
  248.       }
  249.       foreach my $re ( split ' ', $config{"no_del_paths"} ) {
  250.         if( $File::Find::name =~ qr/$re/ ) {
  251.           s_printf (gtx("Not backing up/removing `%s', it matches %s.\n"),$File::Find::name,$re);
  252.           $File::Find::prune=1;
  253.           return;
  254.         }
  255.       }
  256.       push(@files, $File::Find::name) 
  257.         if(-f $File::Find::name || -l $File::Find::name);
  258.       push(@dirs, $File::Find::name)
  259.         if(-d $File::Find::name);
  260.     } # sub home_match
  261.     
  262.     File::Find::find({wanted => \&home_match, untaint => 1, no_chdir => 1}, $pw_homedir)
  263.       if(-d "$pw_homedir");
  264.     push(@files, "/var/mail/$user")
  265.       if(-e "/var/mail/$user");
  266.       } else {
  267.     
  268.     sub find_match {
  269.       my ($dev,$ino,$mode,$nlink,$uid,$gid);
  270.       (($dev,$ino,$mode,$nlink,$uid,$gid) = lstat($_)) &&
  271.         ($uid == $pw_uid) &&
  272.           (
  273.         ($File::Find::name =~ /^\/proc\// && ($File::Find::prune = 1)) ||
  274.         (-f $File::Find::name && push(@files, $File::Find::name)) ||
  275.         (-d $File::Find::name && push(@dirs, $File::Find::name))
  276.           );
  277.     } # sub find_match
  278.     
  279.     File::Find::find({wanted => \&find_match, untaint => 1, no_chdir => 1}, '/');
  280.       }
  281.  
  282.       if($config{"backup"}) {
  283.       s_printf (gtx("Backing up files to be removed to %s ...\n"),$config{"backup_to"});
  284.       my $filesfile = new File::Temp(TEMPLATE=>"deluser.XXXXX", DIR=>"/tmp");
  285.       my $filesfilename = $filesfile->filename;
  286.       my $backup_name = $config{"backup_to"} . "/$user.tar";
  287.       print "backup_name = $backup_name";
  288.       print $filesfile join("\n",@files);
  289.       $filesfile->close();
  290.          my $tar = &which('tar');
  291.       &systemcall($tar, "-cf", $backup_name, "--files-from", $filesfilename);
  292.       chmod 600, $backup_name;
  293.          my $rootid = 0;
  294.       chown $rootid, $rootid, $backup_name;
  295.       unlink($filesfilename);
  296.          my $bzip2 = &which('bzip2', 1);
  297.          my $gzip = &which('gzip', 1);
  298.       if($bzip2) {
  299.           systemcall($bzip2, $backup_name);
  300.       } elsif($gzip) {
  301.           systemcall($gzip, "--best", $backup_name);
  302.       }
  303.       }
  304.  
  305.       if(@files || @dirs) {
  306.       s_print (gtx("Removing files...\n"));
  307.       unlink(@files) if(@files);
  308.       foreach(reverse(sort(@dirs))) {
  309.           rmdir($_);
  310.       }
  311.       }
  312.     }
  313.  
  314.     if (system("crontab -l $user >/dev/null 2>&1") == 0) {
  315.       # crontab -l returns 1 if there is no crontab
  316.       my $crontab = &which('crontab');
  317.       &systemcall($crontab, "-r", $user);
  318.       s_print (gtx("Removing crontab\n"));
  319.     }
  320.  
  321.     s_printf (gtx("Removing user `%s'...\n"),$user);
  322.     my $userdel = &which('userdel');
  323.     &systemcall($userdel, $user);
  324.     &invalidate_nscd();
  325.  
  326.     systemcall('/usr/local/sbin/deluser.local', $user, $pw_uid,
  327.                 $pw_gid, $pw_homedir) if (-x "/usr/local/sbin/deluser.local");
  328.  
  329.     s_print (gtx("done.\n"));
  330.     exit 0;
  331. }
  332.  
  333.     
  334. if($action eq "delgroup") {
  335.     &invalidate_nscd();
  336.     unless(exist_group($group)) {
  337.     fail (3 ,gtx("The group `%s' does not exist.\n"),$group);
  338.     }
  339.     my($dummy,$gid,$members);
  340.     if( !(($dummy, $dummy, $gid, $members ) = getgrnam($group)) ) {
  341.     fail (4 ,gtx("getgrnam `%s' failed. This shouldn't happen.\n"), $group);
  342.     }
  343.     if( $config{"system"} && 
  344.     ($gid < $config{"first_system_gid"} ||
  345.      $gid > $config{"last_system_gid" } )) {
  346.         printf (gtx("The group `%s' is not a system group... Exiting.\n"), $group) if $verbose;
  347.     exit 3;
  348.     }
  349.     if( $config{"only_if_empty"} && $members ne "") {
  350.     fail (5, gtx("The group `%s' is not empty!\n"),$group);
  351.     }
  352.     
  353.     setpwent;
  354.     while ((my $acctname,my $primgrp) = (getpwent)[0,3]) {
  355.     if( $primgrp eq $gr_gid ) {
  356.         fail (7, gtx("`%s' still has `%s' as their primary group!\n"),$acctname,$group);
  357.     }
  358.     }
  359.     endpwent;
  360.  
  361.     s_printf (gtx("Removing group `%s'...\n"),$group);
  362.     my $groupdel = &which('groupdel');
  363.     &systemcall($groupdel,$group);
  364.     &invalidate_nscd();
  365.     s_print (gtx("done.\n"));
  366.     exit 0;
  367. }
  368.  
  369.  
  370. if($action eq "deluserfromgroup")
  371. {
  372.     &invalidate_nscd();
  373.     unless(exist_user($user)) {
  374.     fail (2, gtx("The user `%s' does not exist.\n"),$user);
  375.     }
  376.     unless(exist_group($group)) {
  377.     fail (3, gtx("The group `%s' does not exist.\n"),$group);
  378.     }
  379.     if($maingroup eq $group) {
  380.     fail (7, "$0: ",gtx("You may not remove the account from its primary group.\n"));
  381.     }
  382.  
  383.     my @members = get_group_members($group);
  384.     my $ismember = 0;
  385.  
  386.     for(my $i = 0; $i <= $#members; $i++) {
  387.     if($members[$i] eq $user) {
  388.         $ismember = 1;
  389.         splice(@members,$i,1);
  390.     }
  391.     }
  392.  
  393.     unless($ismember) {
  394.     fail (6, gtx("The user `%s' is not a member of group `%s'.\n"),$user,$group);
  395.     }
  396.  
  397.     s_printf (gtx("Removing user `%s' from group `%s'...\n"),$user,$group);
  398.     #systemcall("usermod","-G", join(",",@groups), $user );
  399.     my $gpasswd = &which('gpasswd');
  400.     &systemcall($gpasswd,'-M', join(',',@members), $group);
  401.     &invalidate_nscd();
  402.     s_print (gtx("done.\n"));
  403. }
  404.  
  405.  
  406. ######
  407.  
  408. sub fail {
  409.   my ($errorcode, $format, @args) = @_;
  410.   printf STDERR "$0: $format",@args;
  411.   exit $errorcode;
  412.  
  413. }
  414.  
  415. sub version {
  416.     printf ("deluser: (version: %s)\n\n", $version);
  417.     printf (gtx("removing user and groups from the system. "));
  418.  
  419.     printf gtx("Copyright (C) 2000 Roland Bauerschmidt <roland\@copyleft.de>\n\n");
  420.  
  421.     printf gtx("deluser is based on adduser by Guy Maor <maor\@debian.org>, Ian Murdock\n".
  422.       "<imurdock\@gnu.ai.mit.edu> and Ted Hajek <tedhajek\@boombox.micro.umn.edu>\n");
  423.  
  424.     printf gtx("\nThis program is free software; you can redistribute it and/or modify
  425. it under the terms of the GNU General Public License as published by
  426. the Free Software Foundation; either version 2 of the License, or (at
  427. your option) any later version.
  428.  
  429. This program is distributed in the hope that it will be useful, but
  430. WITHOUT ANY WARRANTY; without even the implied warranty of
  431. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  432. General Public License, /usr/share/common-licenses/GPL, for more details.\n");
  433. }
  434.  
  435. sub usage {
  436.     printf ("deluser: (version %s)\n\n", $version);
  437.     printf gtx("removing user and groups from the system. Version:");
  438.  
  439.     printf gtx("deluser user
  440.   remove a normal user from the system
  441.   example: deluser mike
  442.  
  443.   --remove-home             remove the users home directory and mail spool
  444.   --remove-all-files        remove all files owned by user
  445.   --backup            backup files before removing.
  446.   --backup-to <dir>         target directory for the backups.
  447.                             Default is the current directory.
  448.   --system                  only remove if system user
  449.  
  450. delgroup group
  451. deluser --group group
  452.   remove a group from the system
  453.   example: deluser --group students
  454.  
  455.   --system                  only remove if system group
  456.   --only-if-empty           only remove if no members left
  457.  
  458. deluser user group
  459.   remove the user from a group
  460.   example: deluser mike students
  461.  
  462. general options:
  463.   --quiet | -q      don't give process information to stdout
  464.   --help | -h       usage message
  465.   --version | -v    version number and copyright
  466.   --conf | -c FILE  use FILE as configuration file\n\n");
  467. }
  468.  
  469. sub exist_user {
  470.     my $exist_user = shift;
  471.     return(defined getpwnam($exist_user));
  472. }
  473.  
  474. sub exist_group {
  475.     my $exist_group = shift;
  476.     return(defined getgrnam($exist_group));
  477. }
  478.  
  479. # vim:set ai et sts=4 sw=4 tw=0:
  480.