#!/usr/pkg/bin/perl
#
# $Header: /home/vikas/src/nocol/perlnocol/RCS/smbmon,v 1.1 1999/10/31 17:46:51 vikas Exp $
#
#	smbmon - perl nocol SMB service monitor
#
# Programmer: Frank Crawford, frank@ansto.gov.au,  Jan 9, 1999
#
# Heavily based on novellmon by John Wobus, jmwobus@mailbox.syr.edu
#
# Command Format:
#
#  smbmon
#
#    Automatically kills old process and forks a new one, reading
#    the configuration file in the process.
#
# What it does:
#
#    smbmon queries a number of NBT servers using SAMBA and
#    checks for the appearance of the services listed in its own
#    configuration file and reports any that are missing.  Example:
#
#    Site        Address      Time   +-Variable-+ +-Value-+  Condition
#    DINAH/files 192.164.10.4 09:58    SMB server        0    Critical
#
#    This line states that a workstation service for DINAH is not available.
#
# Files used:
#
#   nmblookup                   Samba program query status.
#   nocol/data/smbmon-output    path to which to write nocol events.
#   smbmon-confg                configuration file.
#   smbmon.pid                  file holding smbmon's current process id.
#
# Nocol event elements used:
#   sender                     "smbmon"
#   mon, day, hour, min        time at which entity went up or down
#   severity                   up: 4; down: 3,2,1; test & down: 2;
#   nocop                      up, down, unknown
#   site
#    name                      the Server name and service.
#    addr                      IP address of the server.
#   var                       
#    name                      "SMB server"
#    value                     1 means up, 0 means down
#    threshold                 always 2
#    units                     always "entry"
#
# To install this:
#   (1) Choose where to put this file and the above 4 files and
#       assign the perl variables below appropriately.
#   (2) Create your smbmon-confg file in its chosen place.
#   (3) Put this file in its chosen place.
#   (4) Add appropriate code to rc.local to start this monitor.
#
# Configuration file format:
#    #<text>                                   Comment line.
#    <servername> <address> <servicetype>,<servicetype>
#						SMB service, name, address &
#                                               numerical type.
#
# Sample configuration file:
#    # smbmon configuration
#    DINAH   192.164.10.4	00,20/U
#    NTDOM   192.164.10.4	1c/G
#
##
# Sending queries to 192.164.10.4
# 192.164.10.4 dinah
# Looking up status of 192.164.10.4
# received 14 names
# 	DINAH           <00> -         M <ACTIVE> 
# 	DINAH           <20> -         M <ACTIVE> 
# 	NTDOM           <00> - <GROUP> M <ACTIVE> 
# 	NTDOM           <1c> - <GROUP> M <ACTIVE> 
# 	NTDOM           <1b> -         M <ACTIVE> 
# 	DINAH           <03> -         M <ACTIVE> 
# 	NTDOM           <1e> - <GROUP> M <ACTIVE> 
# 	NTDOM           <1d> -         M <ACTIVE> 
# 	..__MSBROWSE__. <01> - <GROUP> M <ACTIVE> 
# 	INet~Services   <1c> - <GROUP> M <ACTIVE> 
# 	DINAH           <43> -         M <ACTIVE> 
# 	IS~DINAH        <00> -         M <ACTIVE> 
# 	DINAH           <6a> -         M <ACTIVE> 
# 	DINAH           <be> -         M <ACTIVE> 
# num_good_sends=0 num_good_receives=0
## 
##
#
#
############################
## Variables customization #  overrides values in the nocollib.pl library
############################
$rprog="/usr/local/bin/nmblookup";		# Path for nmblookup.
				# Also check in &dotest for arguments
$varname="SMB_server";		# Registered SMB Server
$varunits="Entry" ;		# the var.units field in EVENT structure
$sleepint=60*5;			# Seconds to sleep between tries.
############################
$debug = 0;			# set to 1 for debugging output
$libdebug = 0;			# set to 1 for library debug output
$prognm = $0 ;

require  "nocollib.pl" ;

-x $rprog || die("Could not find executable $rprog, exiting");

$maxseverity = $E_ERROR ;	# max severity of events

# hash array of type numbers.
%tname=("00/u", "WksSvc",
	"00/g", "Domain",
	"03/u", "MsgSvc",
	"06/u", "RAS",
	"1b/u", "DomMBwsr",
	"1c/g", "DomCtrl",
	"1d/u", "MBwsr",
	"1f/u", "NetDDE",
	"20/u", "FileSvc",
	"23/u", "ExStore",
	"24/u", "ExDir",
	"87/u", "ExMTA",
	"6a/u", "ExIMC",
	);
%routers=();	# Keep track of the different machines to poll.

##
# Read the config file. Use '\t' as a separator.
#
sub readconf {
    open(CONFIG,"<$cfile")||die("Couldn't find $cfile, exiting");
    while(<CONFIG>){
	chop;
	if(/^\s*#/) {next;}   # skip comments
	if(/^\s*$/) {next;}   # skip blank lines
	elsif(/^\s*(\S+)\s+(\S+)\s+(\S+)(\s.*)?$/) {
	    local($name, $address, $type);
	    ($name = $1) =~ tr/a-z/A-Z/;
	    $address = $2;
	    foreach (split(',', $3)) {
		$_ = "0$_" unless /^[\da-f][\da-f]/i;
		$_ .= '/u' unless m:/:;
		tr/A-Z/a-z/;
		push(@items,"$name\t$address\t$_");
	    }
	    $routers{"$name\t$address"}++;
	}
    }
    close(CONFIG);
    if(0>$#items){die("Nothing to monitor in $cfile, exiting")};
}


## Check the current state of SMB servers
#
sub dotest {
    local($router, $address, $command);

    foreach(@items){$found{$_}=0;}

    foreach (keys(%routers)) {
	($router, $address) = split(/\t/);
	# You may want to read from a real config file
	$command="$rprog -s /dev/null -B $address -S $router";
	if ($debug) {print "(debug) dotest: running command $command\n" ;}
	open(ROUTER,"$command|");

	while(<ROUTER>){
	    if(/^\s+(\S+)\s+<(..)> - (<GROUP>)?\s*\S( <[^>]+>)* <ACTIVE>/) {
		local($name, $type, $item);
		($name = $1) =~ tr/a-z/A-Z/;
		$type = $2 . (($3) ? '/g' : '/u');
		$type =~ tr/A-Z/a-z/;
		$item="$name\t$address\t$type";
		$found{$item}=1 if defined($found{$item});
	    }
	}
	close(ROUTER);
    }
}


###
### Main program:
###

#Fork and get rid of old process.
&nocol_startup;

&readconf;

foreach $item (@items) {
    local($name,$address,$type)=split(/\t/,$item);
    if (defined($tname{$type})) {
	$name .= "/$tname{$type}";
    } else {
	$name .= "/$type";
    }
    &init_event("$name", $address, $item);
}


while (1)
{
    &dotest;
    foreach $item (@items)
    {
	if ($found{$item}) { &update_event($item, 1, 1, $maxseverity); }
	else { &update_event($item, 0, 0, $maxseverity); }
    }
    #Note: we want to write the file quickly.
    open(OEVENTS,">$datafile");
    foreach $item (@items)
    {
	&writeevent(OEVENTS, $item);
    }
    close(OEVENTS);
    sleep($sleepint);
}
