Database Logging Daemon for samba on SME Server
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

163 lines
4.7 KiB

#!/usr/bin/perl -w
use File::Tail;
use DBI;
use URI;
use Getopt::Long;
use strict;
our %opts = ();
# Set default options
$opts{log} = '/var/log/smb_audit.log';
$opts{debug} = 0;
$opts{dbhost} = 'localhost';
$opts{dbname} = 'samba_log';
$opts{dbuser} = 'samba';
$opts{dbpass} = 'samba';
# get command line arguments
GetOptions(
"debug=i" => \$opts{debug},
"log=s" => \$opts{squidlog},
"dbhost=s" => \$opts{dbhost},
"dbname=s" => \$opts{dbname},
"dbpass=s" => \$opts{dbpass}
);
# Disable output buffering
select(STDOUT);
$| = 1;
select(STDERR);
$| = 1;
open STDERR, '>&STDOUT';
# Set process name
$0 = 'samba-db-logd';
# Get hostname
our $host = `hostname`;
chomp($host);
### Subroutines
# Print messages on stderr
# for debuging purpose
sub printlog {
my $msg = shift;
print "$msg\n";
return;
}
# Connect to the database
sub db_connect {
my $dbh = DBI->connect("DBI:mysql:database=$opts{dbname};host=$opts{dbhost}",
$opts{dbuser}, $opts{dbpass}, {RaiseError => 1});
die "Couldn't connect to database\n" unless ($dbh);
return $dbh;
}
# escape chars for MySQL queries
sub mysql_escape {
my $string = shift;
$string =~ s|'|\\'|g;
return $string;
}
my $dbh = db_connect;
# Open log file
printlog("opening log file") if ($opts{debug} ge 1);
my $tail = File::Tail->new(name=>$opts{log}, maxinterval=>15);
while (defined(my $line=$tail->read)){
chomp($line);
my ($username, $client_ip, $client_name, $share,
$action, $status, $access_mode, $file_src, $file_dst) = undef;
# Oct 12 17:20:24 sme8 smbd[11176]: admin|192.168.7.50|pc10-45|intranet|mkdir|Nouveau dossier
if ($line =~ m/^\w+\s\d+\s\d+:\d+:\d+\s\w+\ssmbd\[\d+\]:\s+(\w+)\|(\d+\.\d+\.\d+\.\d+)\|(\w+)\|(\w+)\|(\w+)/){
$username = $1;
$client_ip = $2;
$client_name = $3;
$share = $4;
$action = $5;
}
else{
printlog("Couldn't parse this line: $line\n");
next;
}
my @other = split /\|/, $line;
if (($action eq 'opendir') || ($action eq 'rmdir') || ($action eq 'mkdir') || ($action eq 'unlink')){
# Oct 12 17:20:24 sme8 smbd[11176]: admin|192.168.7.50|pc10-45|intranet|opendir|ok|./
$status = $other[5];
$file_src = $other[6];
}
elsif ($action eq 'open'){
# Oct 12 17:20:28 sme8 smbd[11176]: admin|192.168.7.50|pc10-45|intranet|open|ok|r|Nouveau document
$status = $other[5];
$access_mode = $other[6];
$file_src = $other[7];
}
elsif ($action eq 'rename'){
# Oct 12 17:20:28 sme8 smbd[11176]: admin|192.168.7.50|pc10-45|intranet|rename|ok|./Nouveau document|Nouveau document 2
$status = $other[5];
$file_src = $other[6];
$file_dst = $other[7];
}
my ($sec,$min,$hour,$day,$mon,$year) = localtime;
$year += 1900;
$mon += 1;
my $date = $year.'-'.$mon.'-'.$day;
my $time = $hour.':'.$min.':'.$sec;
# MySQL escape
# Shouldn't be needed, but just in case logs contains junk
$username = mysql_escape($username);
$client_ip = mysql_escape($client_ip);
$client_name = mysql_escape($client_name);
$share = mysql_escape($share);
$action = mysql_escape($action);
$access_mode = mysql_escape($access_mode) if (defined $access_mode);
$status = mysql_escape($status);
$file_src = mysql_escape($file_src);
$file_dst = mysql_escape($file_dst) if (defined $file_dst);
# File names may appear with a space at the end in the logs
$file_src =~ s/\s+$//;
$file_dst =~ s/\s+$// if (defined $file_dst);
if ($opts{debug} ge 2){
my $msg = "New audit entry:\ndate: $date\nhour: $time\nusername: $username\n".
"client_ip: $client_ip\nclient_name: $client_name\nshare: $share\n".
"action: $action\nstatus: $status\nfile_src: $file_src";
$msg .= "\naccess_mode: $access_mode" if (defined $access_mode);
$msg .= "\nfile_dst: $file_dst" if (defined $file_dst);
$msg .= "\n";
printlog($msg);
}
my $q = "INSERT INTO audit ".
"(samba_host,date_day,date_time,username,client_ip,client_name,".
"action,";
$q .= "access_mode," if (defined $access_mode);
$q .= "status,share,file_src";
$q .= ",file_dst" if (defined $file_dst);
$q .= ") VALUES('$host','$date','$time','$username','$client_ip','$client_name',".
"'$action'";
$q .= ",'$access_mode'" if (defined $access_mode);
$q .= ",'$status','$share','$file_src'";
$q .= ",'$file_dst'" if (defined $file_dst);
$q .= ")";
printlog("Current query:\n$q\n") if ($opts{debug} ge 3);
my $qh = $dbh->prepare($q);
$qh->execute or exit(1);
}
exit(0);