#!/usr/bin/perl -w

# Purpose: kmsgsd separates ipchains/iptables messages from all other kernel 
# messages.
#
# Strategy: read message from the /var/log/psadfifo named pipe and 
# print any firewall related dop/reject/deny messages to the psad 
# data file "/var/log/psad/fwdata".
# 
# Copyright (C) 1999-2001 Michael B. Rash (mbr@cipherdyne.com)
#
#    This program is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#    GNU General Public License for more details.
#
#    You should have received a copy of the GNU General Public License
#    along with this program; if not, write to the Free Software
#    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
#    USA

use Psad;
use POSIX "setsid";
use strict;

#==================== config ======================= ## do not remove this line (used by install.pl to preserve configs) ##
my $psad_fw_data = "/var/log/psad/fwdata";

### The following variable can be modified to look for logging messages
### that are specific to iptables firewalls (specified by the "--log-prefix"
### option).  For example, if your firewall uses the string "Audit" for
### packets that have been blocked, then you could set $IPTABLES_MSG_SEARCH = "Audit";
my $IPTABLES_MSG_SEARCH = "DROP|REJECT|DENY";
#================== end config ===================== ## do not remove this line (used by install.pl to preserve configs) ##
#====================== main =======================

&Psad::unique_pid("/var/run/kmsgsd.pid");

my $pid = fork;
exit if $pid;
die "@@@@@  $0: Couldn't fork: $!" unless defined($pid);
POSIX::setsid() or die "@@@@@  $0: Can't start a new session: $!\n";

### write the pid to the pid file
&Psad::writepid("/var/run/kmsgsd.pid");

my $append_other = &check_facility();
if ($append_other) {
	open MESSAGES, ">> /var/log/messages" or die "Could not open /var/log/messages: $!\n";
}
open LOG, ">> $psad_fw_data" or die "Could not open $psad_fw_data: $!\n";

### main loop
for (;;) {
	open FIFO, "< /var/log/psadfifo" or die "Can't open file : $!\n";
	my $service = <FIFO>;  # for performance reasons, don't chomp 
	if (($service =~ /Packet\slog/ || $service =~ /IN.+?OUT.+?MAC/) && $service =~ /$IPTABLES_MSG_SEARCH/) {
		# log to the fwdata file
		my $old_fh = select LOG;
		$| = 1;
		print "$service";
		select $old_fh;
	} elsif ($append_other) {  # it was not a message (packet or otherwise) that we were interested in so write it to /var/log/messages
		my $old_fh2 = select MESSAGES;
		$| = 1;
		print "$service";
		select $old_fh2;
        }

}

# These statements don't get executed, but for completeness...
close LOG;
close MESSAGES if ($append_other);
close FIFO;
exit 0;
#==================== end main =====================
sub check_facility() {
	my $syslog = "/etc/syslog.conf";
	open SYS, "< $syslog";
	while(<SYS>) {
		next if (/^#/);
		# this next line should also include a test for $_ =~ /\*.info/...
		return 0 if ($_ =~ /kern.info/ && $_ =~ /psadfifo/);  # syslog is logging kern.info to an additional place instead of just to psadfifo
	}
	close SYS;
	return 1;
}
