#! /usr/bin/perl -w
#
# check_citrix_activeusers - nagios plugin 
#
# Copyright (C) 2009 Guenther Mair,
# Derived from check_ifoperstatus by Christoph Kron.
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
#
#
# Report bugs to:  guenther.mair@hoslo.ch
#
# $Id: check_citrix_activeusers 4 2009-05-24 11:51:09Z gunny $
#

use POSIX;
use strict;
use lib "/usr/local/nagios/libexec"  ;
use utils qw($TIMEOUT %ERRORS &print_revision &support);

use Net::SNMP;
use Getopt::Long;
&Getopt::Long::config('bundling');

my $PROGNAME = 'check_citrix_activeusers';
my $REVISION = '$Rev: 4 $';
sub print_help ();
sub usage ();
sub process_arguments ();
sub connect_snmp ();

my $DEBUG = 0;

my $timeout;
my $SNMP_TIMEOUT = 5;
my $SNMP_RETRIES = 2;
my $snmp_timeout;
my $snmp_retries;
my @hosts;
our $hostname;
my $session;
my $error;
my $response;
my $sub_response;
my $opt_h;
my $opt_V;
my $key;
my $lastc;
my $name;
my $status;
my $answer = "";
my $snmpkey = 0;
my $community = "public";
my $snmp_version = 1 ;
my $maxmsgsize = 1472 ; # Net::SNMP default is 1472
my ($seclevel, $authproto, $secname, $authpass, $privpass, $auth, $priv, $context);
my $port = 161;
my $warning;
my $critical;
my @tmp;
my $count = 0;
my $sum = 0;
my $currentOID = '';
my $state = 'OK';

my $WFActive = '1.3.6.1.4.1.9827.1.1.1.1';

## Validate Arguments

process_arguments();


## Just in case of problems, let's not hang Nagios

$SIG{'ALRM'} = sub {
     print ("ERROR: No snmp response from $hostname (alarm)\n");
     exit $ERRORS{"UNKNOWN"};
};

alarm($timeout);


print $PROGNAME . ":";
print "\n" if $DEBUG;

## Main function

foreach $hostname (@hosts) {

	connect_snmp();

	if (!defined ($response = $session->get_table($WFActive))) {
		$answer=$session->error;
		$session->close;
		$state = 'CRITICAL';
		printf ("$state: SNMP error with snmp version $snmp_version ($answer)\n");
		$session->close;
		exit $ERRORS{$state};
	}

	print " " if not $DEBUG;
        print $hostname;
	print ":\n" if $DEBUG;

	foreach $key ( keys %{$response}) {
		$count++;
		$sum += $response->{$key};

		$key =~ /.*\.(\d+)$/;
		$snmpkey = $1;
		print " " . $response->{$key} . " user(s)";
		print " (" . $key . ": " . $response->{$key} . ")\n" if $DEBUG;
	}

	print ";" if not $DEBUG;

	$session->close;
}

if ( $sum > $critical ) {
	$state = 'CRITICAL';
} elsif ( $sum > $warning ) {
	$state = 'WARNING';
} else {
	$state = 'OK';
}
printf(" total %.0f users (%s)|users=%.0f\n", $sum, $state, $sum);
exit $ERRORS{$state};


### subroutines

sub usage() {
  printf "\nMissing arguments!\n";
  printf "\n";
  printf "usage: \n";
  printf "check_citrix_activeusers -w <MAX> -c <MAX> -H <HOSTNAME>[,HOSTNAME,...] [-C <community>]\n";
  printf "Copyright (C) 2009 Guenther Mair\n";
  printf "\n\n";
  exit $ERRORS{"UNKNOWN"};
}

sub print_help() {
	printf "check_citrix_activeusers plugin for Nagios\n";
	printf "\nUsage:\n";
	printf "   -H (--hostnames)  Hostnames to query (at least one required)\n";
	printf "   -C (--community)  SNMP read community (defaults to public,\n";
	printf "                     used with SNMP v1 and v2c\n";
	printf "   -v (--snmp_version)  1 for SNMP v1 (default)\n";
	printf "                        2 for SNMP v2c\n";
	printf "                        SNMP v2c will use get_bulk for less overhead\n";
	printf "                        if monitoring with -d\n";
	printf "   -L (--seclevel)   choice of \"noAuthNoPriv\", \"authNoPriv\", or	\"authPriv\"\n";
	printf "   -U (--secname)    username for SNMPv3 context\n";
	printf "   -w (--warning)    maximum amount of users\n";
	printf "   -c (--critical)   maximum amount of users\n";
	printf "   -r (--retries)    maximum retries for each snmp connection [default=2]\n";
	printf "   -s (--snmp-timout)   timeout in seconds for each snmp connection attempt [default=5]\n";
	printf "   -A (--authpass)   authentication password (cleartext ascii or localized key\n";
	printf "                     in hex with 0x prefix generated by using	\"snmpkey\" utility\n"; 
	printf "                     auth password and authEngineID\n";
	printf "   -a (--authproto)  Authentication protocol ( MD5 or SHA1)\n";
	printf "   -X (--privpass)   privacy password (cleartext ascii or localized key\n";
	printf "                     in hex with 0x prefix generated by using	\"snmpkey\" utility\n"; 
	printf "                     privacy password and authEngineID\n";
	printf "   -p (--port)       SNMP port (default 161)\n";
	printf "   -M (--maxmsgsize) Max message size - usefull only for v1 or v2c\n";
	printf "   -t (--timeout)    seconds before the plugin times out (default=$TIMEOUT)\n";
	printf "   -V (--version)    Plugin version\n";
	printf "   -h (--help)       usage help \n\n";
	printf " -c and -w must be specified\n\n";
	print_revision($PROGNAME, '$Revision: 4 $');
	
}

sub process_arguments() {
	$status = GetOptions(
		"V"   => \$opt_V,        "version"        => \$opt_V,
		"h"   => \$opt_h,        "help"           => \$opt_h,
		"v=i" => \$snmp_version, "snmp_version=i" => \$snmp_version,
		"C=s" => \$community,    "community=s"    => \$community,
		"L=s" => \$seclevel,     "seclevel=s"     => \$seclevel,
		"a=s" => \$authproto,    "authproto=s"    => \$authproto,
		"U=s" => \$secname,      "secname=s"      => \$secname,
		"A=s" => \$authpass,     "authpass=s"     => \$authpass,
		"X=s" => \$privpass,     "privpass=s"     => \$privpass,
		"c=s" => \$critical,     "critical=s"     => \$critical,
		"w=s" => \$warning,      "warning=s"      => \$warning,
		"p=i" => \$port,         "port=i"         => \$port,
		"H=s" => \$hostname,     "hostnames=s"    => \$hostname,
		"M=i" => \$maxmsgsize,   "maxmsgsize=i"   => \$maxmsgsize,
		"t=i" => \$timeout,      "timeout=i"      => \$timeout,
		"r=i" => \$snmp_retries, "retries=i"      => \$snmp_retries,
		"s=i" => \$snmp_timeout, "snmp-timeout=i" => \$snmp_timeout,
		);

	if ($status == 0){
		print_help();
		exit $ERRORS{'OK'};
	}
  
	if ($opt_V) {
		print_revision($PROGNAME,'$Revision: 4 $');
		exit $ERRORS{'OK'};
	}

	if ($opt_h) {
		print_help();
		exit $ERRORS{'OK'};
	}

	@hosts = split(/,/, $hostname);
	foreach $hostname (@hosts) {
		print "lookup: " . $hostname . "\n" if $DEBUG;
		if (! utils::is_hostname($hostname)){
			usage();
			exit $ERRORS{"UNKNOWN"};
		}
	}

	unless (defined $critical){
		printf "Maximum allowed Users (-c).\n";
		usage();
		exit $ERRORS{"UNKNOWN"};
	}

	unless (defined $warning){
		printf "Maximum allowed Users (-w).\n";
		usage();
		exit $ERRORS{"UNKNOWN"};
	}

	unless (defined $timeout) {
		$timeout = $TIMEOUT;
	}

	unless (defined $snmp_timeout) {
		$snmp_timeout = $SNMP_TIMEOUT;
	}

	unless (defined $snmp_retries) {
		$snmp_retries = $SNMP_RETRIES;
	}

	if ($snmp_version =~ /3/ ) {
		# Must define a security level even though default is noAuthNoPriv
		# v3 requires a security username
		if (defined $seclevel  && defined $secname) {
		
			# Must define a security level even though defualt is noAuthNoPriv
			unless ( grep /^$seclevel$/, qw(noAuthNoPriv authNoPriv authPriv) ) {
				usage();
				exit $ERRORS{"UNKNOWN"};
			}
			
			# Authentication wanted
			if ( $seclevel eq 'authNoPriv' || $seclevel eq 'authPriv' ) {
		
				unless ( $authproto eq 'MD5' || $authproto eq 'SHA1' ) {
					usage();
					exit $ERRORS{"UNKNOWN"};
				}

				if ( !defined $authpass) {
					usage();
					exit $ERRORS{"UNKNOWN"};
				}else{
					if ($authpass =~ /^0x/ ) {
						$auth = "-authkey => $authpass" ;
					}else{
						$auth = "-authpassword => $authpass";
					}
				}
					
			}
			
			# Privacy (DES encryption) wanted
			if ($seclevel eq  'authPriv' ) {
				if (! defined $privpass) {
					usage();
					exit $ERRORS{"UNKNOWN"};
				}else{
					if ($privpass =~ /^0x/){
						$priv = "-privkey => $privpass";
					}else{
						$priv = "-privpassword => $privpass";
					}
				}
			}

			# Context name defined or default

			unless ( defined $context) {
				$context = "";
			}
		}else {
			usage();
			exit $ERRORS{'UNKNOWN'}; ;
		}
	} # end snmpv3 parameter verifications
}

sub connect_snmp() {
	if ( $snmp_version =~ /[12]/ ) {
  		($session, $error) = Net::SNMP->session(
			-hostname   => $hostname,
			-community  => $community,
			-port       => $port,
			-version    => $snmp_version,
			-timeout    => $snmp_timeout,
			-retries    => $snmp_retries,
			-maxmsgsize => $maxmsgsize
		);

		if (!defined($session)) {
			$state='UNKNOWN';
			$answer=$error;
			print ("$state: $answer");
			exit $ERRORS{$state};
		}
	
	}elsif ( $snmp_version =~ /3/ ) {

		if ($seclevel eq 'noAuthNoPriv') {
			($session, $error) = Net::SNMP->session(
				-hostname => $hostname,
				-port     => $port,
				-version  => $snmp_version,
				-timeout  => $snmp_timeout,
				-retries  => $snmp_retries,
				-username => $secname,
			);
		}elsif ( $seclevel eq 'authNoPriv' ) {
			($session, $error) = Net::SNMP->session(
				-hostname     => $hostname,
				-port         => $port,
				-version      => $snmp_version,
				-timeout      => $snmp_timeout,
				-retries      => $snmp_retries,
				-username     => $secname,
				$auth,
				-authprotocol => $authproto,
			);	
		}elsif ($seclevel eq 'authPriv' ) {
			($session, $error) = Net::SNMP->session(
				-hostname     => $hostname,
				-port         => $port,
				-version      => $snmp_version,
				-timeout      => $snmp_timeout,
				-retries      => $snmp_retries,
				-username     => $secname,
				$auth,
				-authprotocol => $authproto,
				$priv
			);
		}
					
		if (!defined($session)) {
			$state='UNKNOWN';
			$answer=$error;
			print ("$state: $answer");
			exit $ERRORS{$state};
		}

	}else{
		$state='UNKNOWN';
		print ("$state: No support for SNMP v$snmp_version yet\n");
		exit $ERRORS{$state};
	}
}
## End validation
