#!/usr/bin/perl
#WHMADDON:modsec:Mod Security
# cpanel - addon_modsec.cgi                  Copyright(c) 2004-2006 cPanel, Inc.
#                                                           All Rights Reserved.
# copyright@cpanel.net                                         http://cpanel.net
# This code is subject to the cPanel license. Unauthorized copying is prohibited

use lib '/usr/local/cpanel', '/usr/local/cpanel/whostmgr/docroot/cgi';
use strict;
use whmlib;
use SafeFile;
require "parseform.pl";

my $def_conf = '/usr/local/apache/conf/modsec.user.conf.default';
my $blank_conf = '/usr/local/apache/conf/modsec.user.conf.none';
my $installed_conf = '/usr/local/apache/conf/modsec.user.conf';


print "Content-type: text/html\n\n";

# ACL setup
my %ACL = %Whostmgr::ACLS::default; # all set to false

if ($ENV{'REMOTE_USER'} eq 'root') {
    $ACL{'all'} = 1;
} elsif ($ENV{'REMOTE_USER'}) {
    if (-r '/var/cpanel/resellers') {
        if (open my $resellers_fh,'<','/var/cpanel/resellers') {
            while (<$resellers_fh>) {
                if (m{ \A $ENV{'REMOTE_USER'} [:] (\S+) }xms) {
                    my $acls = $1;
                    my @ACLS = split(m{ [,] }xms, $acls);
                    foreach my $acl (@ACLS) {
                        $ACL{$acl} = 1;
                    }
                    last; # disallow multiple lines for one reseller
                }
            }
            close $resellers_fh;
        } else {
            warn "Unable to open /var/cpanel/resellers: $!";
        }
    }
}


defheader('Mod Security');

if ( !$ACL{'all'} ) {
    print <<'EOM';
<br />
<div align="center"><b>mod_security is installed and running!</b></div>
<br />
EOM
    exit 0;
}

my %FORM = parseform();

if ( $FORM{'cgiaction'} eq 'config' ) {
    if ( ! -e $installed_conf ) {
        system 'cp', '-f', $blank_conf, $installed_conf;
    }
    printConfig($installed_conf);
}
elsif ( $FORM{'cgiaction'} eq 'configedit' ) {
    editConfig( $FORM{'config'} );
}
elsif ( $FORM{'cgiaction'} eq 'configdefault' ) {
    defaultConfig();
}
elsif ( $FORM{'cgiaction'} eq 'confignone' ) {
    noneConfig();
}
else { # $FORM{'cgiaction'} eq 'logs' or not specified
    printLogs( $FORM{'table'}, $FORM{'search'}, $FORM{'order'}, $FORM{'lower'}, $FORM{'upper'}, $FORM{'sort'} );
}

sub printLogs {
    my ( $table, $search, $order, $lower, $upper ) = @_;
    my $statement = statementSql();
    my $display = displaySql( $FORM{'table'}, $FORM{'search'}, $FORM{'order'}, $FORM{'lower'}, $FORM{'upper'}, $FORM{'sort'} );
    
    print <<"EOM";
<div align="center">
<br />
<form action="addon_modsec.cgi" method="get">
    <input type="hidden" name="cgiaction" value="config">
    <input type="submit" value="Edit Config">
</form>
<br />
$statement
<br />
$display
<br />
</div>
EOM
}

sub displaySql {
    my ( $table, $search, $order, $lower, $upper, $sort ) = @_;
    my $return =<<'EOM';
<table class="sortable" id="modsectbl" width="95%">
    <tr class="tblheader">
        <th>Date</th>
        <th>Time</th>
        <th>IP</th>
        <th>GET</th>
        <th>Host</th>
        <th>Message</th>
        <th>Action</th>
    </tr>
EOM
    use DBI;
    my $dbhost     = '__MYSQLHOST__';
    my $dbuser     = 'modsec';
    my $dbpassword = '__DBPASSWORD__';
    my $dbname     = "modsec";
    my $tblname    = "modsec";
    my $lower      = "0";
    my $upper      = "30";
    my $dsn        = "DBI:mysql:${dbname}:${dbhost}";
    my $dbh        = DBI->connect( $dsn, $dbuser, $dbpassword );

    my $querystmnt;
    if ( $table && $search ) {
        $querystmnt = "$table LIKE '$search' ORDER BY '$sort' $order LIMIT $lower,$upper";
    }
    else { 
        $querystmnt = q{1 ORDER BY id DESC LIMIT 0,30}; 
    }

    my $query = $dbh->prepare("SELECT * FROM $tblname WHERE $querystmnt");
    $query->execute();
    my $line_count = 0;
    my $tclass;
    while ( my $row = $query->fetchrow_hashref() ) {
        my $ip = cleanfield( $row->{'ip'} );
        my $date = cleanfield( $row->{'date'} );
        my $time = cleanfield( $row->{'time'} );
        my $get = cleanfield( $row->{'get'} );
        my $host = cleanfield( $row->{'host'} );
        my $mod_security_message = cleanfield( $row->{'mod_security_message'} );
        my $mod_security_action = cleanfield( $row->{'mod_security_action'} );
        $line_count++;
        if (($line_count % 2) == 0) {
            $tclass = 'tdshade1';
        }
        else {
            $tclass = 'tdshade2';
        }
        
        $return .=<<"EOM";
    <tr class="$tclass">
        <td align="center">$date</td>
        <td align="center">$time</td>
        <td align="center">$ip</td>
        <td align="center">$get</td>
        <td align="center">$host</td>
        <td align="center">$mod_security_message</td>
        <td align="center">$mod_security_action</td>
    </tr>
EOM
    }
    $query->finish();
    $return .= '</table>';
    return $return;
}

sub statementSql {
    my $return =<<'EOM';
<table border="0">
    <tr>
        <td>
            Query Mod Security Database:<br />
            <i>Use SQL wildcards "%" to broaden search</i><br />
            <form name="sqlquery" action="addon_modsec.cgi">
                Field:&nbsp;
                <select name="table">
                    <option value="date">Date</option>
                    <option value="time">Time</option>
                    <option value="ip">IP</option>
                    <option value="get">GET</option>
                    <option value="host">Host</option>
                    <option value="mod_security_message">Message</option>
                    <option value="mod_security_action">Action</option>
                </select>
                Text:&nbsp;
                <input type="text" name="search" value="">
                <input type="hidden" name="cgiaction" value="logs">
                <br />
                Sort by:&nbsp;
                <input type="radio" name="sort" value="ip">IP&nbsp;</input>
                <input type="radio" name="sort" value="date" checked="checked">Date&nbsp;</input>
                <input type="radio" name="sort" value="time">Time&nbsp;</input>
                <input type="radio" name="sort" value="host">Host&nbsp;</input>
                <input type="radio" name="sort" value="mod_security_action">Action&nbsp;</input>
                <br />
                Order:&nbsp;
                <select name="order">
                    <option value="ASC">Ascending</option>
                    <option value="DESC">Descending</option>
                </select>
                <input type="submit" value="Search">
            </form>
        </td>
    </tr>
</table>
EOM
    return $return
}

sub printConfig {
    my $config_file = shift || $installed_conf;
    my $config;
    if ( open my $conf_fh, '<', $config_file ) {
        while ( my $line = readline $conf_fh ) {
            $config .= $line;
        }
        close $conf_fh;
    }
    print <<"EOM";
<br />
<div align="center">
<a href="addon_modsec.cgi"><b>Return To Logs</a>
<br /><br />
<table border="0">
    <tr>
        <td valign="top" align="center"><b>Reset configuration textarea to:</b>&nbsp;</td>
        <td><a href="addon_modsec.cgi?cgiaction=configdefault"><b>Default Configuration</b></a></td>
        <td>&nbsp;</td>
        <td><a href="addon_modsec.cgi?cgiaction=confignone"><b>No Configuration</b></a></td>
    </tr>
    <tr>
        <td colspan="4" align="center"><b>*</b><i>Changes must be saved</i></td>
    <tr>
</table>
<br />
<form action="addon_modsec.cgi" method="POST">
<textarea name="config" rows="50" cols="100">$config</textarea>
<br /><br />
<input type="hidden" name="cgiaction" value="configedit"><input type="submit" value="Save Configuration"></form>
</div>
EOM
}

sub defaultConfig {
    printConfig($def_conf);
}

sub noneConfig {
    printConfig($blank_conf);
}

sub editConfig {
    my $config = shift;
    
    if ( -z $installed_conf && !$config ) {
        printConfig($installed_conf);
        return;
    }
    my $conflock = SafeFile::safeopen( \*MSC, '>', $installed_conf );
    print MSC $config;
    SafeFile::safeclose( \*MSC, $conflock );
    restartApache();
    printConfig($installed_conf);
}

sub restartApache {
    if ( -x '/usr/local/cpanel/bin/safeapacherestart' ) {
        system '/usr/local/cpanel/bin/safeapacherestart';
    }
    else {
        if ( -x '/usr/bin/killall' ) {
            system '/usr/bin/killall', '-USR1', 'httpd';
        }
        elsif ( -x '/usr/sbin/killall' ) {
            system '/usr/sbin/killall', '-USR1', 'httpd';
        }
        elsif ( -x '/sbin/killall' ) {
            system '/sbin/killall', '-USR1', 'httpd';
        }
        elsif ( -x '/bin/killall' ) {
            system '/bin/killall', '-USR1', 'httpd';
        }
        elsif ( -x '/usr/local/bin/killall' ) {
            system '/usr/local/bin/killall', '-USR1', 'httpd';
        }
        elsif ( -x '/usr/local/sbin/killall' ) {
            system '/usr/local/sbin/killall', '-USR1', 'httpd';
        }
    }
}

sub cleanfield {
    my $value = shift;
    $value =~ s/</\&lt;/g;
    $value =~ s/>/\&gt;/g;
    $value =~ s/"/\&quot;/g;
    return $value;
}
