#!/usr/bin/perl -w

# Copyright 2010, Tomas Edwardsson <tommi@opensource.is>

# check_cifs 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 3 of the License, or
# (at your option) any later version.
#
# check_cifs 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, see <http://www.gnu.org/licenses/>.


use strict;
use Nagios::Plugin;


# Create the Nagios plugin object
my $np = Nagios::Plugin->new(
        usage => "Usage: %s -H <hostname> -u <username> -p <password> -s <share>",
        version => "1.0",
);

# Add valid arguments
$np->add_arg(
        spec => 'hostname|H=s',
        help => '-H, --hostname=<hostname>',
        required => 1,
);

$np->add_arg(
        spec => 'username|u=s',
        help => '-u, --username=<username>',
        required => 1,
);

$np->add_arg(
        spec => 'password|p=s',
        help => '-p, --password=<password>',
        required => 1,
);

$np->add_arg(
        spec => 'share|s=s',
        help => '-s, --share=<password>',
        required => 1,
);

$np->add_arg(
        spec => 'kerberos|k',
        help => '-k, --kerberos',
        required => 0,
);

$np->add_arg(
        spec => 'writefile|w=s',
        help => '-w, --writefile=<filepath>',
        required => 0,
);

$np->add_arg(
        spec => 'writesize|W=i',
        help => '-W, --writesize=<megabytes>',
        required => 0,
	default => 10
);


my @tmpfiles = ();

sub createtmpfile($) {
	my $size = shift;

	$size = 10 if (!defined $size);

	$np->nagios_exit(UNKNOWN, "Size for param writesize not numeric") if ($size !~ /^\d+$/);
	
	my $tmpfile =  `mktemp check-cifs-XXXXXX -p /tmp`;
	my $rc = $? >> 8;
	chomp($tmpfile);

	push @tmpfiles, $tmpfile;
	if ($rc) {
		$np->nagios_exit(UNKNOWN, "Unable to run mktemp for temporary file");
	}

	open TMP, ">$tmpfile" or
		$np->nagios_exit(UNKNOWN, "Cannot open tempfile for writing: $!");

	for (1..$size) {
		print TMP "0"x(1024*1024);
	}
	close TMP;

	return $tmpfile;
}

sub testbin($) {
	my $program = shift;
	eval {
		system("$program &> /dev/null");
	};
	my $exit_value  = $? >> 8;
	if ($exit_value != 127) {
		return 0;
	} else {
		$np->nagios_exit(UNKNOWN, "Could not execute $program");
	}
}



# Check needed binaries
testbin("smbclient");
testbin("kinit");
testbin("kdestroy");


# Parse command line operations
$np->getopts;


# Initialize global for kerberos credentials cache
my $krb5cc = "";

# Login with kerberos
if ($np->opts->kerberos) {
	# Cache saved to temporary file too avoid clashed with 
	# other plugins
	$krb5cc = createtmpfile(0);

	# Execute kinit kerberised login
	my $kcmd = sprintf("echo '%s' | kinit -c %s '%s' 2>&1", $np->opts->password, $krb5cc, $np->opts->username);
	my $kinit = `$kcmd`;
	my $exit_value  = $? >> 8;

	# Check return code for failures
	if ($exit_value != 0) {
		chomp $kinit;
		$np->nagios_exit(CRITICAL, "Unable to log in with kerberos - $kinit");
	}
}

# Array of arguments for smbclient based on various circumstances
my @smbclient_opts;
my @smbclient_commands;

# Set servicename
push @smbclient_opts, sprintf("//%s/%s", $np->opts->hostname, $np->opts->share);

# Kerberised or NTLM ?
if ($np->opts->kerberos) {
	push @smbclient_opts, '-k'
} else {
	push @smbclient_opts, "'" . $np->opts->password . "'", '-U', "'" . $np->opts->username . "'", 
}


# We want to test writing a file to the remote share
if ($np->opts->writefile) {
	my $tmpfile = createtmpfile($np->opts->writesize);
	my $cmd = ($krb5cc ? "KRB5CCNAME=$krb5cc " : "") . "smbclient " . join(" ", @smbclient_opts) . " -c 'put $tmpfile " . $np->opts->writefile . "' 2>&1 |";
	open SMBCLIENT, $cmd or
		$np->nagios_exit(CRITICAL, "Unable to run CIFS connection: $!");

	# Toss header
	<SMBCLIENT>;

	my $return = <SMBCLIENT>;
	chomp($return);

	if ($return =~ /^putting file \S+? as \S+? \((\d+\.\d*) /) {
		close SMBCLIENT;
		$np->add_perfdata(
			label => "file_transfer",
			value => $1,
			uom => "KBps" );

		$np->nagios_exit(OK, "Connected and uploaded file at rate of $1" . ($np->opts->kerberos ? " (kerberised)" : ""));
	} else {
		close SMBCLIENT;
		$np->nagios_exit(CRITICAL, "Unable to upload file" . ($np->opts->kerberos ? " (kerberised)" : "") . ": $return");
	}
	
# Just a regular connection test
} else {
	my $cmd = ($krb5cc ? "KRB5CCNAME=$krb5cc " : "") . "smbclient " . join(" ", @smbclient_opts) . " -c '' 2>&1 |";
	open SMBCLIENT, $cmd or
		$np->nagios_exit(CRITICAL, "Unable to run CIFS connection: $!");

	# Toss header
	<SMBCLIENT>;
	my $nterror = <SMBCLIENT>;
	close SMBCLIENT;

	chomp($nterror) if ($nterror);
	if ($nterror) {
		$np->nagios_exit(CRITICAL, "Unable to connect to share" . ($np->opts->kerberos ? " (kerberised)" : "") . ": $nterror");
	}
	$np->nagios_exit(OK, "Connected successfully" . ($np->opts->kerberos ? " (kerberised)" : ""));
}




# Hack to remove the krb5 credentials file if we have exited
END {
	
	if (@tmpfiles) {
		foreach my $f (@tmpfiles) {
			if (-f $f) {
				unlink $f;
			}
		}
	}
};



