#!/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/^(?(?(?:\\[0-9A-Fa-f]{2}|\\\[^=\,\\]|[^=\,\\]+)+)\=(?(?:\\[0-9A-Fa-f]{2}|\\\[^=\,\\]|[^=\,\\]+)+))(?:\s*\,\s*(?(?(?:\\[0-9A-Fa-f]{2}|\\\[^=\,\\]|[^=\,\\]+)+)\=(?(?:\\[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 });