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.
184 lines
5.2 KiB
184 lines
5.2 KiB
#!/usr/bin/perl -w
|
|
|
|
use strict;
|
|
use warnings;
|
|
use JSON;
|
|
use Getopt::Long;
|
|
use File::Which;
|
|
use Date::Parse;
|
|
use File::ReadBackwards;
|
|
use Data::Dumper;
|
|
|
|
my $samba_tool = which('samba-tool');
|
|
my $pdbedit = which('pdbedit');
|
|
# Number of seconds in the past to count authentications
|
|
my $since = 300;
|
|
my $pretty = 0;
|
|
my $general = 1;
|
|
my $ou = undef;
|
|
|
|
# This log is expected to be in JSON format. For example, in smb.conf :
|
|
# log level = 1 auth_audit:3 auth_json_audit:4@/var/log/samba/audit_auth.log
|
|
my $audit_auth_log = '/var/log/samba/json/auth.log';
|
|
|
|
if (not defined $samba_tool or not defined $pdbedit){
|
|
print 'ZBX_NOTSUPPORTED';
|
|
exit 1;
|
|
}
|
|
|
|
GetOptions(
|
|
'pretty' => \$pretty,
|
|
'since=i' => \$since,
|
|
'audit-auth-log=s' => \$audit_auth_log,
|
|
'general' => \$general,
|
|
'ou=s' => \$ou
|
|
);
|
|
|
|
if ($since !~ m/^\d+$/){
|
|
die "Invalid value for since\n";
|
|
}
|
|
|
|
my $json = {};
|
|
|
|
if (defined $ou){
|
|
$json = {
|
|
objects => 0
|
|
};
|
|
if ($ou !~ m/^(?<RDN>(?<Key>(?:\\[0-9A-Fa-f]{2}|\\\[^=\,\\]|[^=\,\\]+)+)\=(?<Value>(?:\\[0-9A-Fa-f]{2}|\\\[^=\,\\]|[^=\,\\]+)+))(?:\s*\,\s*(?<RDN>(?<Key>(?:\\[0-9A-Fa-f]{2}|\\\[^=\,\\]|[^=\,\\]+)+)\=(?<Value>(?:\\[0-9A-Fa-f]{2}|\\\[^=\,\\]|[^=\,\\]+)+)))*$/){
|
|
die "Invalid OU\n";
|
|
}
|
|
foreach (qx($samba_tool ou listobjects '$ou' 2>/dev/null)){
|
|
die "Error while counting objects of OU $ou\n" if ($? != 0);
|
|
chomp;
|
|
$json->{objects}++;
|
|
}
|
|
} elsif ($general){
|
|
$json = {
|
|
accounts => {
|
|
users => 0,
|
|
inactive_users => 0,
|
|
active_users => 0,
|
|
groups => 0,
|
|
computers => 0
|
|
},
|
|
replication => 'UNKNWON',
|
|
processes => {
|
|
cldap_server => 0,
|
|
kccsrv => 0,
|
|
dreplsrv => 0,
|
|
ldap_server => 0,
|
|
kdc_server => 0,
|
|
dnsupdate => 0,
|
|
'notify-daemon' => 0,
|
|
rpc_server => 0,
|
|
winbind_server => 0,
|
|
nbt_server => 0,
|
|
dnssrv => 0,
|
|
samba => 0,
|
|
},
|
|
gpo => 0,
|
|
ou => 0,
|
|
activity => {
|
|
authentications => {
|
|
users => {
|
|
success => 0,
|
|
failure => 0
|
|
},
|
|
computers => {
|
|
success => 0,
|
|
failure => 0
|
|
}
|
|
},
|
|
authorizations => {
|
|
users => 0,
|
|
computers => 0
|
|
},
|
|
since => $since
|
|
}
|
|
};
|
|
|
|
# Get the numbers of users. pdbedit is prefered here because we can
|
|
# differentiate active and inactive users, which samba-tool can't do
|
|
# While at it, also get the computers
|
|
foreach (qx($pdbedit -L -v)){
|
|
next unless (m/^Account Flags:\s+\[(.*)\]/);
|
|
my $flags = $1;
|
|
if ($flags =~ m/U/){
|
|
$json->{accounts}->{users}++;
|
|
if ($flags =~ m/D/){
|
|
$json->{accounts}->{inactive_users}++;
|
|
} else {
|
|
$json->{accounts}->{active_users}++;
|
|
}
|
|
} elsif ($flags =~ m/W/){
|
|
$json->{accounts}->{computers}++;
|
|
}
|
|
}
|
|
|
|
# Now count groups
|
|
foreach (qx($samba_tool group list 2>/dev/null)){
|
|
$json->{accounts}->{groups}++;
|
|
}
|
|
|
|
# Get replication status
|
|
# We want just a quick summary, so only output the first line
|
|
# manual checks will be needed to get the details, but if this field doesn't contains [ALL GOOD],
|
|
# then something is probably wrong
|
|
$json->{replication} = (split(/\n/, qx($samba_tool drs showrepl --summary 2>/dev/null)))[0];
|
|
|
|
# Get the list of workers
|
|
foreach (qx($samba_tool processes 2>/dev/null)){
|
|
if (/^([^\(\s]+).+\d+$/){
|
|
$json->{processes}->{$1}++;
|
|
}
|
|
}
|
|
|
|
# Get the number of GPO
|
|
foreach (qx($samba_tool gpo listall 2>/dev/null)){
|
|
next unless (/^GPO/);
|
|
$json->{gpo}++;
|
|
}
|
|
|
|
# Get the number of OU
|
|
foreach (qx($samba_tool ou list 2>/dev/null)){
|
|
$json->{ou}++;
|
|
}
|
|
|
|
if (-e $audit_auth_log){
|
|
my $backward = File::ReadBackwards->new( $audit_auth_log ) or die "Couldn't open $audit_auth_log : $!\n";
|
|
while (defined (my $line = $backward->readline)){
|
|
my $event;
|
|
eval {
|
|
$event = from_json($line);
|
|
};
|
|
# Skip the log entry if we can't parse JSON
|
|
next if (not defined $event);
|
|
my $type = $event->{type};
|
|
# We're only interested in Authentication and Authorization messages
|
|
next if ($type ne 'Authentication' and $type ne 'Authorization');
|
|
# Parse the date in the timstamp field
|
|
my $timestamp = str2time($event->{timestamp});
|
|
|
|
# Skip if date couldn't be parsed
|
|
next if (not defined $timestamp);
|
|
# As we're reading in reverse order, if we reached an events prior to now - since, then we can stop, as all the other will be even earlier
|
|
last if (time() - $timestamp > $since);
|
|
|
|
my $subject;
|
|
if ($type eq 'Authentication'){
|
|
# Accounts ending with $ are for computers
|
|
$subject = (($event->{$type}->{mappedAccount} || $event->{$type}->{clientAccount} || '')=~ m/\$$/) ? 'computers' : 'users';
|
|
if ($event->{Authentication}->{status} eq 'NT_STATUS_OK'){
|
|
$json->{activity}->{authentications}->{$subject}->{success}++;
|
|
} else {
|
|
$json->{activity}->{authentications}->{$subject}->{failure}++;
|
|
}
|
|
} else {
|
|
$subject = ($event->{$type}->{account} =~ m/\$$/) ? 'computers' : 'users';
|
|
$json->{activity}->{authorizations}->{$subject}++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
print to_json($json, { pretty => $pretty });
|
|
|