#!/usr/bin/perl

# ------------------------------------------------------------------
#
#    Copyright (C) 2002-2005 Novell/SUSE
#
#    This program is free software; you can redistribute it and/or
#    modify it under the terms of version 2 of the GNU General Public 
#    License published by the Free Software Foundation.
#
# ------------------------------------------------------------------

################################################################################
# ag_logparse 
#
#  - Generates report of SubDomain events 
#
#  Requires:
#		- /usr/lib/immunix/SubDomain/perl/Immunix::Reports.pm
#		- /usr/lib/immunix/SubDomain/perl/Events.pm 
#
#  Input (Optional):
#		-Start Date|End Date (Month, Day, Year, Time)
#		-Program Name
#		-Profile Name
#		-PID
#		-Severity Level
#		-Denied Resources
#		-Mode
#		-SDMode
#
################################################################################
my $Version='1.03';

use strict;
use Locale::gettext;
use POSIX;
use ycp;

use Immunix::Reports;

setlocale(LC_MESSAGES, "");
textdomain("yast2-apparmor");

use constant DEBUGGING => 0;

my $numEvents = 1000;

# Should be deprecated
sub saveQuery {

	my $query = shift;
	my $qLog = '/var/log/apparmor/reports/reporting-query.tmp';

	if ( open(QLOG, ">$qLog") ) {

		print QLOG "$query";

		close QLOG;

	} else {
		my $error = gettext("Unable to open") . " $qLog " . gettext("Couldn't save query.");
		ycp::y2error($error);
	}
}

sub getSavedQuery {

    my $page = shift;
    my $query = undef;

    my $qLog = '/var/log/apparmor/reports/reporting-query.tmp';

    if ( open(QLOG, "<$qLog") ) {

        $query = <QLOG>;
        chomp($query);

        close QLOG;

    } else {
		my $error = gettext("Unable to open") . " $qLog " . gettext("Couldn't retrieve query.");
        ycp::y2error("Unable to open $qLog.  Couldn't retrieve query.");
    }

    # rewrite query for current page
    my $limStart = (( $page * $numEvents ) - $numEvents);

    my ($q1) = (split(/LIMIT/, $query))[0];
    my $q2 = " LIMIT $limStart,$numEvents";

    $query = $q1 . $q2;

    return $query;
}

sub getReportName {

    my $dir = shift;
    my @dirList = ();

    my $newName = undef;
    my $plainName = "Security.Incident.Report"; 

    # Append date info to help id reports
    my ($sec,$min,$hour,$mday,$month,$year,@junk) = localtime;

    $year += 1900;
    $month += 1;

    $month = sprintf("%02d", $month);
    $mday  = sprintf("%02d", $mday);
    $hour  = sprintf("%02d", $hour);
    $min   = sprintf("%02d", $min);
    $sec   = sprintf("%02d", $sec);
    $mday  = sprintf("%02d", $mday);

    my $suffix = "-$year-$month-$mday\_$hour.$min.$sec";
    $plainName = $plainName . $suffix;

    if (opendir (DIR, $dir)) {
        @dirList = grep(/\"$plainName\"/, readdir(DIR) );
        close DIR;
    }

    my $numReps = scalar(@dirList) + 1;
    $numReps = sprintf("%03d", $numReps);

    $newName = "$dir/$plainName.$numReps";

    return $newName;
}


sub getHeader {

	my ($args,$filts) = @_;

    my $date = localtime;
    my $start = "Jan 1, 2005"; 
	my $header = undef;

    my $count = 0;

    if ( $filts ) {
        # We don't want startdate/enddate to be listed as filters
        $count = keys(%$filts);
        if ($filts->{'startdate'}) {
            $filts->{'startdate'} = localtime($filts->{'startdate'});
			$start = $filts->{'startdate'};
            $count--;
        }
        if ($filts->{'enddate'}) {
            $filts->{'enddate'} = localtime($filts->{'enddate'});
            $count--;
        }
    }

    # Write SIR Header in csv format
    $header->{'csv'} =  gettext("# Security Incident Report - Generated by AppArmor\n");
    $header->{'csv'} .= sprintf(gettext("# Period: %s - %s\n"), $start, $date);


    if ( $count > 0 ) {
        $header->{'csv'} .= gettext("# The following filters were used for report generation:\n");
        for (sort keys(%$filts)) {
            unless ( $filts->{'startdate'} || $filts->{'enddate'} ) {
                $header->{'csv'} .= sprintf(gettext("# Filter: %s, Value: %s\n\n"), $_, $filts->{$_});
            }
        }
    } else {
        $header->{'csv'} .= gettext("# No filters were used for report generation:\n\n\n");
    }

    # Write SIR Header in html format
    $header->{'html'} =  gettext("<h3>Security Incident Report - Generated by AppArmor</h3>\n");
    $header->{'html'} .= sprintf(gettext("<h4>Period: %s - %s</h4>\n"), $start, $date);

	return $header;
}

sub exportReports {

	my ($args,$db,$filts) = @_;

    # Export results to file if requested
    if ( $args->{'exporttext'} || $args->{'exporthtml'} ) {

        my $expLog = undef;
		my $rawLog = undef; 
		my $expDir = '/var/log/apparmor/reports-exported/';

		if ( $args->{'exportPath'} && -e $args->{'exportPath'} ) {
			$expDir = $args->{'exportPath'};
		}

		my $repName = getReportName($expDir);
		my $header = getHeader($args,$filts);

        if ( $args->{'exporttext'} && $args->{'exporttext'} eq '1') {
            $expLog = "$repName.csv";
            Immunix::Reports::exportLog($expLog,$db,$header->{'csv'});
        }

        if ( $args->{'exporthtml'} && $args->{'exporthtml'} eq '1') {
            $expLog = "$repName.html";
            Immunix::Reports::exportLog($expLog,$db,$header->{'html'});
        }
    }

	return 0;
}

# Main
################################################################################

while ( <STDIN> ) {

    my ($command, $path, $args) = ycp::ParseCommand ($_);

	my $db = undef;
	my $error = undef;
	my $page = 1;
	my $numEvents = '1000';		# Number of event records to return

    if ( $command && $path && $args ) {
		# Arbitrary workaround until all the new code becomes active
		if ( $args->{'mode'} ) {
			$args->{'mode_req'} = $args->{'mode'};
			delete($args->{'mode'});
		}

		# yast slows down horribly when passing large number of records
		if ( $args->{'numEvents'} && $args->{'numEvents'} > 0 && $args->{'numEvents'} < 10001 ) {
			$numEvents = $args->{'numEvents'};
		}

		if ($args->{'starttime'}) {
			my ($hrs,$mins) = split(/\:/, $args->{'starttime'});
			$hrs = sprintf("%02d", $hrs);
			$mins = sprintf("%02d", $mins);
			$args->{'starttime'} = "$hrs:$mins"; 
		}
		if ($args->{'endtime'}) {
			my ($hrs,$mins) = split(/\:/, $args->{'endtime'});
			$hrs = sprintf("%02d", $hrs);
			$mins = sprintf("%02d", $mins);
			$args->{'endtime'} = "$hrs:$mins"; 
		}

		if ( $args->{'startmonth'} && $args->{'startday'} ) {
			$args->{'startdate'} = "$args->{'startmonth'} $args->{'startday'} $args->{'starttime'} $args->{'startyear'}";
		}

		if ( $args->{'endmonth'} && $args->{'endday'} ) {
			$args->{'enddate'} = "$args->{'endmonth'} $args->{'endday'} $args->{'endtime'} $args->{'endyear'}";
		}

		my $archRep   = 0;
		my $onDemand  = 0;
		my $turnPage  = 0;

		if ( $args->{'turnPage'} && ($args->{'turnPage'} == 1) ) { 
			$turnPage = $args->{'turnPage'};
		} 

		if ( $args->{'type'} ) { 
			if ( $args->{'type'} eq "onDemand" ) { 
				$onDemand = 1; 
				$args->{'logFile'} = '/var/log/apparmor/reports/events.rpt';
			} elsif ( $args->{'type'} eq "archRep" ) { 
				$archRep = 1; 
				unless ($args->{'logFile'}) { 
					$args->{'logFile'} = '/var/log/apparmor/reports/all-reports.rpt';
				}
			}
		}

        # Parse sdmode & mode labels
        if ( $args->{'sdmode'} ) {
			if ($args->{'sdmode'} eq "All") { 
				$args->{'sdmode'} = "-"; 		# Translate from GUI 
			} else {
	            $args->{'sdmode'} =~ s/\&//g;
	            $args->{'sdmode'} =~ s/\://g;
	            $args->{'sdmode'} =~ s/\s//g;
	            $args->{'sdmode'} =~ s/AccessType//g;
			}
        }

		# Only mode_req is used now
		for ('mode_req', 'mode_deny' ) {
	        if ( $args->{$_} && $args->{$_} eq "All" ) { 
				$args->{$_} = "-"; 
			} else {
	            $args->{$_} =~ s/\&//g;
	            $args->{$_} =~ s/Mode\://g;
	            $args->{$_} =~ s/\s//g;
			}
        }

		if ( $args->{'page'} && $args->{'page'} =~ /\d+/ && $args->{'page'} > 0 ) {
			$page = $args->{'page'};
		}

		my $sortKey = 'time';
		if ( $args->{'sortKey'} ) { $sortKey = $args->{'sortKey'}; }

		if ( $args->{'sort'} && $args->{'sort'} == 1 ) {

			my $filts = Immunix::Reports::setFormFilters($args);
			$filts = Immunix::Reports::rewriteFilters($filts);
            my $query = Immunix::Reports::getQuery($filts,$page,$sortKey,$numEvents);
            $db = Immunix::Reports::getEvents($query);

		} elsif ( $turnPage == 1 ) {

			if ( $args->{'turnArch'} && $args->{'turnArch'} == 1 ) {

	            $db = Immunix::Reports::getArchReport($args);
	            $turnPage = 1;

			} else {

				my $filts = Immunix::Reports::setFormFilters($args);
				$filts = Immunix::Reports::rewriteFilters($filts);
	            my $query = Immunix::Reports::getQuery($filts,$page,$sortKey,$numEvents);
	            $db = Immunix::Reports::getEvents($query);

			}

		} elsif ( $archRep == 1 ) {

			# Parse Logs (Probably Archived Immunix::Reports)
			##################################################
			if ($args->{'single'} && $args->{'single'} eq "1" ) {
				$error = Immunix::Reports::prepSingleLog($args);
				$args->{'logFile'} = '/var/log/apparmor/reports/all-reports.rpt';
			} else {
				$error = Immunix::Reports::prepArchivedLogs($args);
			}

			if ( ! $error || ($error && ($error eq '0')) ) {
				$error = Immunix::Reports::parseLog($args);
				delete($args->{'logFile'}); 

			} else {
		        ycp::y2error("ag_logparse - Unable to run archived reports: $error");
			}

		} elsif ($onDemand == 1) {

            # Parse Events (On-Demand report from events db)
            ##################################################
			my $filts = Immunix::Reports::setFormFilters($args);
			$filts = Immunix::Reports::rewriteFilters($filts);
            my $query = Immunix::Reports::getQuery($filts,$page,$sortKey,$numEvents);
            $db = Immunix::Reports::getEvents($query);

			exportReports($args,$db,$filts);

        } elsif ($args->{'getSirFilters'} && $args->{'getSirFilters'} == 1) {

			if ( ref($args) && $args->{'name'} ) { 
				$db = Immunix::Reports::getSirFilters($args);
			} else {
				$db = Immunix::Reports::getSirFilters();
			}
		}

		if ( ! $error || ($error eq "0") ) {
	        ycp::Return( $db );
		} elsif ( $error ne "0" ) {
		    ycp::y2error("ag_logparse: $error");
		    ycp::Return( $error );
			exit 1;
		} else {
		    ycp::Return( $error );
		}

    } else {
        my $error = "ag_logparse: Missing instruction or argument!";
		ycp::y2error($error);
        ycp::Return($error);
		exit 1;
    }

}

exit 0;

