commit
7789ca862a
13 changed files with 413 additions and 0 deletions
@ -0,0 +1,15 @@ |
||||
#!/usr/bin/perl -w |
||||
|
||||
use esmith::Build::CreateLinks qw(:all); |
||||
|
||||
foreach my $event (qw/bootstrap-console-save workgroup-update/){ |
||||
templates2events("/etc/e-smith/sql/init/sambadblogd", $event); |
||||
} |
||||
safe_symlink("restart", "root/etc/e-smith/events/workgroup-update/services2adjust/squid-db-logd"); |
||||
safe_touch('root/var/service/samba-db-logd/down'); |
||||
safe_symlink("../daemontools" , 'root/etc/rc.d/init.d/supervise/samba-db-logd'); |
||||
safe_symlink("/var/service/samba-db-logd" , 'root/service/samba-db-logd'); |
||||
service_link_enhanced("samba-db-logd", "S98", "7"); |
||||
service_link_enhanced("samba-db-logd", "K15", "6"); |
||||
service_link_enhanced("samba-db-logd", "K35", "0"); |
||||
service_link_enhanced("samba-db-logd", "K35", "1"); |
@ -0,0 +1,53 @@ |
||||
#!/bin/bash |
||||
|
||||
DB_HOST=$(/sbin/e-smith/db configuration getprop samba-db-logd DbHost || echo localhost) |
||||
RETENTION=$(/sbin/e-smith/db configuration getprop samba-db-logd Retention || echo 365) |
||||
|
||||
SQL_DB=$(/sbin/e-smith/db configuration getprop samba-db-logd DbName) |
||||
TABNAME="audit" |
||||
SQLCMD="mysql ${SQL_DB} --batch"; |
||||
MONTH=$(date +%m) |
||||
YEAR=$(date +%Y) |
||||
|
||||
# We rotate on the first day of a new month |
||||
if [ "$MONTH" == "1" ]; then |
||||
MONTH=12 |
||||
else |
||||
MONTH=$(($MONTH-1)) |
||||
fi |
||||
|
||||
# Pad with 0 |
||||
MONTH=$(printf "%02d" $MONTH) |
||||
|
||||
DATE=$MONTH"_"$YEAR |
||||
|
||||
for T in ${TABNAME}; do |
||||
# create table 0 |
||||
echo "CREATE TABLE IF NOT EXISTS ${T}_0 LIKE ${T};" | $SQLCMD; |
||||
|
||||
# Rotate table |
||||
echo "FLUSH TABLES ${T}; RENAME TABLE ${T} TO ${T}_$DATE; RENAME TABLE ${T}_0 TO ${T}" | ${SQLCMD} >/dev/null 2>&1 |
||||
|
||||
# Drop _0 table if we rotate more than two times a month |
||||
if echo "DESCRIBE ${T}_0;" | ${SQLCMD} >/dev/null 2>&1; then |
||||
echo "DROP TABLE ${T}_0;" | $SQLCMD |
||||
fi |
||||
|
||||
#compress 2 |
||||
cd /var/lib/mysql/${SQL_DB}/ |
||||
echo "FLUSH TABLE ${T}_${DATE};" | $SQLCMD |
||||
myisampack -s "${T}_${DATE}.MYI" |
||||
myisamchk -s -rq --sort-index --analyze "${T}_${DATE}.MYI" |
||||
echo "FLUSH TABLE ${T}_${DATE}" | $SQLCMD |
||||
done |
||||
|
||||
# Now check existing table to drop olds ones |
||||
for T in $(echo "show tables" | $SQLCMD | grep -v -P "^Tables_in_"$SQL_DB | grep -v -P "^audit$"); do |
||||
TMONTH=$(echo $T | perl -pe 'm/^audit_(\d+)_(\d+)/; print $2;exit') |
||||
TYEAR=$(echo $T | perl -pe 'm/^audit_(\d+)_(\d+)/; print $3;exit') |
||||
# Drop table if older than configured retention |
||||
if [ "$(($(date -d "01/$MONTH/$YEAR" +%s)-$(date -d "01/$TMONTH/$TYEAR" +%s)))" -gt "$((24*3600*$RETENTION))" ]; then |
||||
echo "DROP TABLE $T;" | $SQLCMD |
||||
fi |
||||
done |
||||
|
@ -0,0 +1 @@ |
||||
samba_log |
@ -0,0 +1 @@ |
||||
samba |
@ -0,0 +1 @@ |
||||
enabled |
@ -0,0 +1 @@ |
||||
service |
@ -0,0 +1,27 @@ |
||||
{ |
||||
my $rec = $DB->get('samba-db-logd') |
||||
|| $DB->new_record('samba-db-logd', {type => 'service'}); |
||||
my $pw = $rec->prop('DbPassword'); |
||||
if (not $pw or length($pw) < 57){ |
||||
use MIME::Base64 qw(encode_base64); |
||||
|
||||
$pw = "not set due to error"; |
||||
if ( open( RANDOM, "/dev/urandom" ) ){ |
||||
my $buf; |
||||
# 57 bytes is a full line of Base64 coding, and contains |
||||
# 456 bits of randomness - given a perfectly random /dev/random |
||||
if ( read( RANDOM, $buf, 57 ) != 57 ){ |
||||
warn("Short read from /dev/random: $!"); |
||||
} |
||||
else{ |
||||
$pw = encode_base64($buf); |
||||
chomp $pw; |
||||
} |
||||
close RANDOM; |
||||
} |
||||
else{ |
||||
warn "Could not open /dev/urandom: $!"; |
||||
} |
||||
$rec->set_prop('DbPassword', $pw); |
||||
} |
||||
} |
@ -0,0 +1,46 @@ |
||||
{ |
||||
my $db = ${'samba-db-logd'}{'DbName'} || 'samba_log'; |
||||
my $user = ${'qpsmtpd'}{'DbUser'} || 'samba'; |
||||
my $pass = ${'qpsmtpd'}{'DbPassword'} || 'samba'; |
||||
|
||||
my $dbstruct = `rpm -qd smeserver-samba-db-logd | grep samba_log.sql`; |
||||
|
||||
$OUT .= <<"END"; |
||||
#! /bin/sh |
||||
if [ ! -d /var/lib/mysql/$db ]; then |
||||
/usr/bin/mysql -e 'create database $db' |
||||
/usr/bin/mysql $db < $dbstruct |
||||
fi |
||||
|
||||
/usr/bin/mysql <<EOF |
||||
USE mysql; |
||||
|
||||
REPLACE INTO user ( |
||||
host, |
||||
user, |
||||
password) |
||||
VALUES ( |
||||
'localhost', |
||||
'$user', |
||||
PASSWORD ('$pass')); |
||||
|
||||
|
||||
REPLACE INTO db ( |
||||
host, |
||||
db, |
||||
user, |
||||
select_priv, insert_priv, update_priv, delete_priv, |
||||
create_priv, alter_priv, index_priv, drop_priv, create_tmp_table_priv, |
||||
grant_priv, lock_tables_priv, references_priv) |
||||
VALUES ( |
||||
'localhost', |
||||
'$db', |
||||
'$user', |
||||
'Y', 'Y', 'Y', 'Y', |
||||
'Y', 'Y', 'Y', 'Y', 'Y', |
||||
'N', 'Y', 'Y'); |
||||
|
||||
FLUSH PRIVILEGES; |
||||
EOF |
||||
END |
||||
} |
@ -0,0 +1,163 @@ |
||||
#!/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); |
@ -0,0 +1,7 @@ |
||||
#!/bin/sh |
||||
|
||||
exec \ |
||||
/usr/local/bin/setuidgid smelog \ |
||||
/usr/local/bin/multilog t s5000000 \ |
||||
/var/log/samba-db-logd |
||||
|
@ -0,0 +1,25 @@ |
||||
#!/usr/bin/perl -w |
||||
|
||||
use esmith::ConfigDB; |
||||
my $c = esmith::ConfigDB->open_ro or die "Couldn't open ConfigDB\n"; |
||||
my $rec = $c->get('samba-db-logd'); |
||||
my $dbname = $rec->prop('DbName') || 'samba_log'; |
||||
my $dbuser = $rec->prop('DbUser') || 'samba'; |
||||
my $dbpass = $rec->prop('DbPassword') || 'samba'; |
||||
my $dbhost = $rec->prop('DbHost') || 'localhost'; |
||||
|
||||
my @args = ("--debug=1", "--dbname=$dbname", "--dbuser=$dbuser", "--dbpass=$dbpass"); |
||||
|
||||
push @args, "--dbhost=$dbhost" if ($dbhost ne 'localhost'); |
||||
|
||||
my $smbd = $c->get('smbd'); |
||||
|
||||
if ($smbd ne 'enabled'){ |
||||
exec("sv", "d", "/service/samba-db-logd"); |
||||
exit(0); |
||||
} |
||||
|
||||
exec("/usr/bin/squid-db-logd", @args) |
||||
or die "Cannot run the Samba Database Loggind Daemon"; |
||||
|
||||
exit(1); |
@ -0,0 +1,15 @@ |
||||
CREATE TABLE audit ( |
||||
id INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY, |
||||
samba_host VARCHAR(40) NOT NULL, |
||||
date_day DATE NOT NULL, |
||||
date_time TIME NOT NULL, |
||||
username VARCHAR(30) NOT NULL, |
||||
client_ip CHAR(15) NOT NULL, |
||||
client_name VARCHAR(50) NOT NULL, |
||||
action VARCHAR(15) NOT NULL, |
||||
access_mode VARCHAR(2) default NULL, |
||||
status VARCHAR(10) NOT NULL, |
||||
share VARCHAR(30) NOT NULL, |
||||
file_src VARCHAR(200) default NULL, |
||||
file_dst VARCHAR(200) default NULL |
||||
) ENGINE=MYISAM; |
@ -0,0 +1,58 @@ |
||||
%define version 0.0.1 |
||||
%define release 1.beta0 |
||||
%define name smeserver-samba-db-logd |
||||
|
||||
|
||||
Summary: samba MySQL logging module for SME Server |
||||
Name: %{name} |
||||
Version: %{version} |
||||
Release: %{release}%{?dist} |
||||
License: GPL |
||||
Group: Networking/Daemons |
||||
Source: %{name}-%{version}.tar.gz |
||||
|
||||
BuildRoot: /var/tmp/%{name}-%{version}-%{release}-buildroot |
||||
BuildArchitectures: noarch |
||||
BuildRequires: e-smith-devtools |
||||
|
||||
Requires: perl(File::Tail) |
||||
Requires: perl(Getopt::Long) |
||||
Requires: perl(DBI) |
||||
|
||||
%description |
||||
Log samba events in a MySQL database |
||||
|
||||
%changelog |
||||
* Fri Oct 12 2012 Daniel Berteaud <daniel@firewall-services.com> 0.2.0-1 |
||||
- Initial release |
||||
|
||||
%prep |
||||
%setup -q -n %{name}-%{version} |
||||
|
||||
%build |
||||
%{__mkdir_p} root/var/log/samba-db-logd |
||||
perl createlinks |
||||
|
||||
%install |
||||
/bin/rm -rf $RPM_BUILD_ROOT |
||||
(cd root ; /usr/bin/find . -depth -print | /bin/cpio -dump $RPM_BUILD_ROOT) |
||||
/bin/rm -f %{name}-%{version}-filelist |
||||
/sbin/e-smith/genfilelist $RPM_BUILD_ROOT \ |
||||
--dir /var/log/samba-db-logd 'attr(0770,smelog,smelog)' \ |
||||
--file /usr/bin/samba-db-logd 'attr(0755,root,root)' \ |
||||
--file /var/service/samba-db-logd/run 'attr(0755,root,root)' \ |
||||
--file /var/service/samba-db-logd/log/run 'attr(0755,root,root)' \ |
||||
--file /etc/cron.monthly/samba-log-rotate 'attr(0755,root,root)' \ |
||||
> %{name}-%{version}-filelist |
||||
|
||||
echo "%doc CHANGELOG.git" >> %{name}-%{version}-filelist |
||||
echo "%doc samba_log.sql" >> %{name}-%{version}-filelist |
||||
%files -f %{name}-%{version}-filelist |
||||
%defattr(-,root,root) |
||||
|
||||
%clean |
||||
rm -rf $RPM_BUILD_ROOT |
||||
|
||||
%post |
||||
%preun |
||||
|
Loading…
Reference in new issue