#!/usr/bin/perl -w ### LAME BUG ALERT - program will barf if there ### are repeated elements in the conf file ### so be careful you don't "add" the same directory ### to a conf file that already has it in it use strict; use diagnostics; use File::Find (); use Getopt::Std; #use Sys::Syslog; use Config::General; die "Usage: permmy -[itcad] [directory] -f config-file\n" unless @ARGV >= 3; use vars qw/ $opt_t $opt_c $opt_d $opt_i $opt_f $opt_a/; getopts('tcdi:f:a:') or die "Usable options are -tcifa: $!\n"; my $dir_tree = $opt_i; my $add_tree = $opt_a; my $perms_config_file = $opt_f; use vars qw/ $conf %config/; if ($opt_t || $opt_d || $opt_c) { $conf = new Config::General( -ConfigFile => "$perms_config_file", -UseApacheInclude => "yes", -InterPolateVars => "yes" ); %config = $conf->getall; } sub return_mode { sprintf "%04o", (shift) & 07777; } ## checks for validity. Takes a type argument (m for mode, u for user ## and g for group) and the test value sub validator ($$) { my($type, $value) = @_; if ($type =~ /.*mode/) { die "$value is not a valid mode: $!\n" unless ((oct($value)) && (oct($value) <= 4095)); } elsif ($type =~ /.*owner/) { die "$value is not a valid user: $!\n" unless ((getpwnam($value)) || ($value eq "root")); } elsif ($type =~ /.*group/) { if (($value eq "root") && ($^O =~ /bsd|darwin/)) {print "There is no $value group on $^O, fix your config file!\n";} if (($value eq "wheel") && ($^O =~ /linux/)) {print "There is no $value group in $^O, fix your config file!\n";} if (($value eq "root") || ($value eq "wheel")) {$value = getgrgid(0);} die "$value is not a valid group: $!\n" unless ((getgrnam($value)) || (($value eq "root") || ($value eq "wheel"))); } else { die "Validator complaint: something wrong with type $type and/or value $value\n"; } } sub configurator ($$$$) { my($conf_type, $conf_file, $directory, $wanted_ref) = @_; if ($conf_type eq "i") { open CONFIG, ">$conf_file" or die "Could not open config file $conf_file for writing: $!\n"; } elsif ($conf_type eq "a") { open CONFIG, ">>$conf_file" or die "Could not open config file $conf_file for writing: $!\n"; } use vars qw/*name *dir *prune/; *name = *File::Find::name; *dir = *File::Find::dir; *prune = *File::Find::prune; # Traverse desired filesystems File::Find::find({wanted => $wanted_ref}, $directory); exit; close CONFIG or die "Could not close config file $conf_file: $!\n"; } sub configtest { foreach my $pri ( keys %config ) { die "$pri is not a valid descriptor: $!\n" unless (($pri eq "dir") || ($pri eq "file") || ($pri eq "link") || ($pri eq "area")); if ($pri eq "area") { foreach my $sec ( keys %{ $config{$pri} } ) { die "$sec does not exist: $!\n" unless (-e $sec); foreach my $ter (keys %{ $config{$pri}{$sec} } ) { die "$ter is not a valid type: $!\n" unless (($ter eq "dir-mode") || ($ter eq "dir-owner") || ($ter eq "dir-group") || ($ter eq "file-mode") || ($ter eq "file-owner") || ($ter eq "file-group") || ($ter eq "link-mode") || ($ter eq "link-owner") || ($ter eq "link-group")); &validator($ter, $config{$pri}{$sec}{$ter}); } } } else { foreach my $sec (keys %{ $config{$pri} } ) { die "$sec does not exist: $!\n" unless (-e $sec); foreach my $ter (keys %{ $config{$pri}{$sec} } ) { die "$ter is not a valid type: $!\n" unless (($ter eq "mode") || ($ter eq "owner") || ($ter eq "group")); &validator($ter, $config{$pri}{$sec}{$ter}); } } } } print "Syntax OK\n"; } sub wanted_ia { ((my $dev, my $ino, my $mode, my $nlink, my $uid, my $gid) = lstat($_)); my $pwuid = getpwuid $uid; my $grgid = getgrgid $gid; my $nice_mode = &return_mode($mode); if (-d $_) { print CONFIG "\n\tmode $nice_mode\n\towner $pwuid\n\tgroup $grgid\n\n"; } elsif (-f $_) { print CONFIG "\n\tmode $nice_mode\n\towner $pwuid\n\tgroup $grgid\n\n"; } elsif (-l $_) { print CONFIG "\n\tmode $nice_mode\n\towner $pwuid\n\tgroup $grgid\n\n"; } } sub change_mode ($$) { my($the_file, $change_value) = @_; ((my $dev, my $ino, my $mode, my $nlink, my $uid, my $gid) = lstat($the_file)); my $c_nice_mode = &return_mode($mode); if (($change_value) && (oct($change_value) != oct($c_nice_mode))) { my $o_mode = oct($change_value); chmod($o_mode, $the_file) or warn "Could not change mode of $the_file: $!\n"; print "Changed mode of $the_file from $c_nice_mode to $change_value\n"; } } sub change_owner ($$) { my($the_file, $change_value) = @_; ((my $dev, my $ino, my $mode, my $nlink, my $uid, my $gid) = lstat($the_file)); my $c_pwuid = getpwuid($uid); if (($change_value) && ($change_value ne $c_pwuid)) { my $num_uid = getpwnam($change_value); chown($num_uid, -1, $the_file) or warn "Could not change owner of $the_file: $!\n"; print "Changed owner of $the_file from $c_pwuid to $change_value\n"; } } sub change_group ($$) { my($the_file, $change_value) = @_; ((my $dev, my $ino, my $mode, my $nlink, my $uid, my $gid) = lstat($the_file)); my $c_grgid = getgrgid($gid); if (($change_value) && ($change_value ne $c_grgid)) { if (($change_value eq "root") || ($change_value eq "wheel")) {$change_value = getgrgid(0)} my $num_gid = getgrnam($change_value); chown(-1, $num_gid, $the_file) or warn "Could not change group of $the_file: $!\n"; print "Changed group of $the_file from $c_grgid to $change_value\n"; } } sub test_mode ($$) { my($the_file, $test_value) = @_; ((my $dev, my $ino, my $mode, my $nlink, my $uid, my $gid) = lstat($the_file)); my $c_nice_mode = return_mode($mode); print "The file $the_file has a mode of $c_nice_mode but should have a mode of $test_value\n" unless ($c_nice_mode eq $test_value); } sub test_owner ($$) { my($the_file, $test_value) = @_; ((my $dev, my $ino, my $mode, my $nlink, my $uid, my $gid) = lstat($the_file)); my $c_pwuid = getpwuid($uid); print "The file $the_file has an owner of $c_pwuid but should have an owner of $test_value\n" unless ($c_pwuid eq $test_value); } sub test_group ($$) { my($the_file, $test_value) = @_; ((my $dev, my $ino, my $mode, my $nlink, my $uid, my $gid) = lstat($the_file)); my $c_grgid = getgrgid($gid); print "The file $the_file has a group of $c_grgid but should have a group of $test_value\n" unless ($c_grgid eq $test_value); } if ($opt_d) { configtest(); } elsif ($opt_i) { configurator("i", $perms_config_file, $dir_tree, \&wanted_ia); } elsif ($opt_a) { configurator("a", $perms_config_file, $add_tree, \&wanted_ia); } elsif ($opt_t) { configtest(); foreach my $test ( keys %config ) { foreach my $tester ( keys %{ $config{$test} } ) { if (!-e $tester) { print "$tester does not seem to exist any more\n"; next; } foreach my $testy ( keys %{ $config{$test}{$tester} } ) { if ($testy eq "mode") { test_mode($tester, $config{$test}{$tester}{$testy}); } elsif ($testy eq "owner") { test_owner($tester, $config{$test}{$tester}{$testy}); } elsif ($testy eq "group") { test_group($tester, $config{$test}{$tester}{$testy}); } } } } } elsif ($opt_c) { configtest(); foreach my $test ( keys %config ) { if ($test eq "area") { foreach my $tester ( keys %{ $config{$test} } ) { if (!-e $tester) { print "$tester does not seem to exist any more\n"; next; } use vars qw/$d_mode $f_mode $l_mode $d_own $f_own $l_own $d_grp $f_grp $l_grp/; $d_mode=$f_mode=$l_mode=$d_own=$f_own=$l_own=$d_grp=$f_grp=$l_grp=0; foreach my $testy ( keys %{ $config{$test}{$tester} } ) { if ($testy eq "dir-mode") { $d_mode = $config{$test}{$tester}{$testy} } elsif ($testy eq "file-mode") { $f_mode = $config{$test}{$tester}{$testy} } elsif ($testy eq "link-mode") { $l_mode = $config{$test}{$tester}{$testy} } elsif ($testy eq "dir-owner") { $d_own = $config{$test}{$tester}{$testy} } elsif ($testy eq "file-owner") { $f_own = $config{$test}{$tester}{$testy} } elsif ($testy eq "link-owner") { $l_own = $config{$test}{$tester}{$testy} } elsif ($testy eq "dir-group") { $d_grp = $config{$test}{$tester}{$testy} } elsif ($testy eq "file-group") { $f_grp = $config{$test}{$te\ster}{$testy} } elsif ($testy eq "link-group") { $l_grp = $config{$test}{$tester}{$testy} } } use vars qw/*name *dir *prune/; *name = *File::Find::name; *dir = *File::Find::dir; *prune = *File::Find::prune; # Traverse desired filesystems File::Find::find({wanted => \&wanted_c}, $tester); exit; sub wanted_c { if ((-d $_) && ($d_mode)) { change_mode($_, $d_mode); } elsif ((-d $_) && ($d_own)) { change_owner($_, $d_own); } elsif ((-d $_) && ($d_grp)) { change_group($_, $d_grp); } elsif ((-f $_) && ($f_mode)) { change_mode($_, $f_mode); } elsif ((-f $_) && ($f_own)) { change_owner($_, $f_own); } elsif ((-f $_) && ($f_grp)) { change_group($_, $f_grp); } elsif ((-l $_) && ($l_mode)) { change_mode($_, $l_mode); } elsif ((-l $_) && ($l_own)) { change_owner($_, $l_own); } elsif ((-l $_) && ($l_grp)) { change_group($_, $l_grp); } } } } else { foreach my $tester ( keys %{ $config{$test} } ) { if (!-e $tester) { print "$tester does not seem to exist any more\n"; next; } foreach my $testy2 ( keys %{ $config{$test}{$tester} } ) elsif ((-l $_) && ($l_mode)) { change_mode($_, $l_mode); } elsif ((-l $_) && ($l_own)) { change_owner($_, $l_own); } elsif ((-l $_) && ($l_grp)) { change_group($_, $l_grp); } } } } else { foreach my $tester ( keys %{ $config{$test} } ) { if (!-e $tester) { print "$tester does not seem to exist any more\n"; next; } foreach my $testy2 ( keys %{ $config{$test}{$tester} } ) { if ($testy2 eq "mode") { change_mode($tester, $config{$test}{$tester}{$testy2}); } elsif ($testy2 eq "owner") { change_owner($tester, $config{$test}{$tester}{$testy2}); } elsif ($testy2 eq "group") { change_group($tester, $config{$test}{$tester}{$testy2}); } } } } } } #### dir-perms 0755 file-perms 0644 link-perms 0777 dir-owner root file-owner root link-owner root dir-group root file-group root link-group root perms 0700 owner shane group shane perms 0744 owner joe group baz perms 0777 owner follow group me