#!/usr/bin/perl -w
#
# $Id: PermsChk,v 1.4 2002/03/19 09:13:10 cvs Exp $
#
# ProcChk: Checks perms for critical files and dirs. If they are wrong, set 
# the correct perms.
#
# Miguel Armas <kuko@ulpgc.es>
#

#--------------------------------------------[ Initialization Section ]----

use strict;
use Getopt::Std;
use pifia;

#--------------------------------------------[ Configuration Section ]----- 
my $priority = "Critical";
my $alarm = "PermsChk";
my $remind = <#$remind#>;        # Seconds

#--------------------------------------------[ Code Section ]----

# proactive flag indicates if we should take proactive measures, that is, 
# install/upgrade packages or just notify. Default is 0 but the global 
# variable proactive takes precedence
my $proactive='<#$proactive#>';

# Set a safe PATH
$ENV{'PATH'} = "/bin:/sbin:/usr/bin:/usr/sbin:/root/bin";

# Option declaration
use vars qw($opt_v $opt_n $opt_p $opt_q);
getopts('vnpq');

# Verbosity level. If not verbose, we shouldn't write any output unless 
# there is a problem. If quiet is set, we won't write ANY output (even if 
# there where errors). verbose has precedence
my $quiet = 1 if ($opt_q);
my $verbose = 1 if ($opt_v);
$quiet = 0 if ($verbose);

# proactive flag handling (parameter has precedence over global variable)
$proactive=1 if ($opt_p);
$proactive=0 if ($opt_n);

# Flag to show that the situation was corrected (in the output)
my $corrected=($proactive ? "CORRECTED" : "");

use vars qw(%lastnotify);

perseval {
   # Read object files
   my @perms = readObjectFiles($alarm);
   
   foreach my $line (@perms) {
      my ($name,$perms,$owner,$group,$flags) = split(/\s+/,$line);
      $flags = "" if (!$flags);
      $perms = sprintf("%04d",$perms);
      my @stat = stat($name);
      if (!@stat) {
         # File doesn't exist
	 if (!$quiet && needNotify($name,$remind) && ($flags !~ /[-!]/)) {
	    print "$name doesn't exist \n";	    
	    $lastnotify{$name} = time();
	 }
      }
      else {
         # Should we delete it?
	 if ($flags =~ "!") {
	    unlink $name if ($proactive);
	    if (!$quiet && needNotify($name,$remind)) {
	       print "$name shouldn't exist. $corrected \n";
	       $lastnotify{$name} = time();
	    }
	    # skip to next file...
	    next;
	 }
	 # Treat directory recursively?
	 if ((-d $name) && $flags =~ "r") {
	    foreach my $file (<$name/*>) {
	       if (-d $file) {
	          my $dirperms=sprintf "%lo",oct($perms) | 00111;
		  push @perms,"$file $dirperms $owner $group $flags";
	       }
	       else {
	          push @perms,"$file $perms $owner $group $flags";
	       }
	    }
	    # For this directory we also add +x perms
	    $perms=sprintf "%0lo",oct($perms) | 00111;
	 };
	 my $fown = getpwuid($stat[4]);
         my $fgrp = getgrgid($stat[5]);
         my $fperms = $stat[2] & 07777;
         my $sperms = sprintf("%04o",$fperms);
         my $error = 0;
         # Make sure user and group exists in that host
         my $uid = getpwnam($owner);
         my $gid = getgrnam($group);
         if (!defined($uid) || !defined($gid)) {
            if (!$quiet && needNotify($name,$remind)) {
               print "Unknown user.group for $name ($owner.$group) \n";
               $lastnotify{$name} = time();
               next;
            }
         }
	 # Check owner/group
	 if (($fown ne $owner) || ($fgrp ne $group)) {
	    chown($uid,$gid,$name) if ($proactive);
	    $error = 1;
	 }
	 # Check perms 
	 if ($sperms != $perms) {
	    chmod(oct($perms),$name) if ($proactive);
	    $error = 1;
	 }

         if (!$quiet && $error && needNotify($name,$remind)) {
            print "$name was $sperms $fown.$fgrp. Needed $perms $owner.$group. $corrected \n";
            $lastnotify{$name} = time();
         }
      }
   }
} preserve '%lastnotify';
