--- /dev/null
+
+PLUGINDIR=plugins
+INSTALL=/usr/bin/install
+DSTPLUGINDIR=$(DESTDIR)/usr/lib/nagios/plugins
+
+all:
+
+install:
+ $(INSTALL) -d $(DSTPLUGINDIR)
+ $(INSTALL) -m 0755 $(PLUGINDIR)/check_cert $(DSTPLUGINDIR)
+ $(INSTALL) -m 0755 $(PLUGINDIR)/check_md_raid $(DSTPLUGINDIR)
--- /dev/null
+The Debian Package nagios-plugins-local
+----------------------------
+
+This package is a collection of scripts that are not in the standard Debian
+repository, but which are nonetheless useful.
+
+ -- Michael Howe <michael@michaelhowe.org> Sat, 06 Mar 2010 10:43:16 +0000
--- /dev/null
+nagios-plugins-local (0.1) unstable; urgency=low
+
+ * Initial Release.
+
+ -- Michael Howe <michael@michaelhowe.org> Sat, 06 Mar 2010 10:43:16 +0000
--- /dev/null
+Source: nagios-plugins-local
+Section: net
+Priority: extra
+Maintainer: Michael Howe <michael@michaelhowe.org>
+Build-Depends: debhelper (>= 7)
+Standards-Version: 3.8.4
+Homepage:
+
+Package: nagios-plugins-local
+Architecture: all
+Depends: ${misc:Depends}, perl, python
+Description: Local nagios plugins
+ Nagios plugins customized for use on michaelhowe.org hosts.
--- /dev/null
+This work was packaged for Debian by:
+
+ Michael Howe <michael@michaelhowe.org> on Sat, 06 Mar 2010 10:43:16 +0000
+
+Upstream Author(s):
+
+ Hari Sekhon
+ Mike Ryan
+
+Copyright:
+
+ check_md_raid: <Copyright (C) 2007 Hari Sekhon>
+ check_cert: <Copyright (C) 2006 Mike Ryan>
+
+License:
+
+ 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 3 of the License, or
+ (at your option) any later version.
+
+ This package 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/>.
+
+On Debian systems, the complete text of the GNU General
+Public License version 3 can be found in "/usr/share/common-licenses/GPL-3".
+
+The Debian packaging is:
+
+ Copyright (C) 2010 Michael Howe <michael@michaelhowe.org>
+and is licensed under the GPL version 3, see above.
--- /dev/null
+#!/usr/bin/make -f
+# -*- makefile -*-
+# Sample debian/rules that uses debhelper.
+# This file was originally written by Joey Hess and Craig Small.
+# As a special exception, when this file is copied by dh-make into a
+# dh-make output file, you may use that output file without restriction.
+# This special exception was added by Craig Small in version 0.37 of dh-make.
+
+# Uncomment this to turn on verbose mode.
+export DH_VERBOSE=1
+
+%:
+ dh $@
--- /dev/null
+3.0 (quilt)
--- /dev/null
+#!/usr/bin/perl
+###########################################################################
+##### #
+##### check_cert.pl -- check HTTPS, IMAPS, LDAPS or SMTP (with #
+##### STARTTLS) certificate expiration and, optionally, naming. #
+##### #
+############| mike ryan -- 02/03/06, 14:15 |#########
+
+#use 5.6.1;
+use strict;
+use warnings;
+no warnings qw(redefine);
+
+use Date::Parse qw(str2time);
+use English;
+use Getopt::Long;
+use URI;
+
+#use lib '/usr/local/nagios/libexec';
+use lib '/usr/lib/nagios/plugins';
+use utils qw(%ERRORS);
+
+sub usage {
+ my %params = @_;
+
+ if (defined($params{'message'})) {
+ my $message = $params{'message'};
+ $message =~ s/\n*$/\n/s;
+ print STDERR $message;
+ }
+
+ print STDERR <<EOF;
+Usage: $PROGRAM_NAME --warn=<days> --critical=<days> --host=<hostname> --protocol=<protocol> [<options>]
+ --critical=<days> number of days before certificate expiration
+ to return a critical status
+
+ --help display this message
+
+ --url=<url> URL to check. supported schemes: file,
+ https, imaps, ldaps, smtp, smtps.
+
+ --name=<name> expected name on certificate
+
+ --warning=<days> number of days before certificate expiration
+ to return a warning status
+EOF
+
+ if (!defined($params{'error'}) || $params{'error'}) {
+ print "UNKNOWN: bad usage\n";
+ exit($ERRORS{'UNKNOWN'});
+ }
+}
+
+###########################################################################
+##### #
+##### init. #
+##### #
+###########################################################################
+
+my %opt;
+GetOptions(\%opt,
+ 'critical=i',
+ 'help',
+ 'name=s',
+ 'url=s',
+ 'warning=i',
+) || usage();
+
+if (defined($opt{'help'})) {
+ usage();
+}
+
+# check for required options
+foreach my $option (qw{critical warning url}) {
+ if (!defined($opt{$option})) {
+ usage(message => "--$option required");
+ }
+}
+
+# check URL scheme type
+my $uri = URI->new($opt{'url'});
+my $scheme = lc($uri->scheme);
+if (!defined($scheme) || ($scheme eq '')) {
+ usage(message => "invalid URL");
+}
+
+###########################################################################
+##### #
+##### retrieve certificate #
+##### #
+###########################################################################
+
+my $certdata;
+
+my $host = $uri->opaque();
+$host =~ s/^\/+//;
+my $port = undef;
+if ($host =~ s/:(\d+)//) {
+ $port = $1;
+}
+$host ||= 'localhost';
+
+if ($scheme eq 'file') {
+ $certdata = read_file($uri->path());
+
+} elsif ($scheme eq 'https') {
+ $port ||= 443;
+
+ $certdata = s_client("", "-connect $host:$port");
+
+} elsif ($scheme eq 'imaps') {
+ $port ||= 993;
+
+ $certdata = s_client(". logout", "-connect $host:$port");
+
+} elsif ($scheme eq 'ldaps') {
+ $port ||= 636;
+
+ $certdata = s_client("", "-connect $host:$port");
+
+} elsif ($scheme eq 'smtp') {
+ $port ||= 25;
+
+ $certdata = s_client("quit", "-starttls smtp -connect $host:$port");
+
+} elsif ($scheme eq 'smtps') {
+ $port ||= 465;
+
+ $certdata = s_client("quit", "-connect $host:$port");
+
+} else {
+ usage(message => "unsupported scheme ($scheme)");
+}
+
+if (!defined($certdata)) {
+ print "UNKNOWN: failed to retrieve certificate data\n";
+ exit($ERRORS{'UNKNOWN'});
+}
+
+# make sure certificate validity isn't in the future.
+my $check_start_time = time;
+if (!defined($certdata->{'not_before'})) {
+ print "UNKNOWN: failed to parse Not Before validity\n";
+ exit($ERRORS{'UNKNOWN'});
+}
+if ($check_start_time < $certdata->{'not_before'}) {
+ printf("CRITICAL: certificate not valid until %s\n", scalar(localtime($certdata->{'not_before'})));
+ exit($ERRORS{'CRITICAL'});
+}
+
+# make sure certificate validity isn't in the past.
+if (!defined($certdata->{'not_after'})) {
+ print "UNKNOWN: failed to parse Not After validitiy\n";
+ exit($ERRORS{'UNKNOWN'});
+}
+if ($check_start_time > $certdata->{'not_after'}) {
+ printf("CRITICAL: certificate expired %s\n", scalar(localtime($certdata->{'not_after'})));
+ exit($ERRORS{'CRITICAL'});
+}
+
+# check for impending expiration.
+my $expires_in = int(($certdata->{'not_after'} - $check_start_time) / (24*60*60));
+if ($expires_in <= $opt{'critical'}) {
+ printf("CRITICAL: certificate expires in $expires_in days (%s)\n", scalar(localtime($certdata->{'not_after'})));
+ exit($ERRORS{'CRITICAL'});
+}
+if ($expires_in <= $opt{'warning'}) {
+ printf("WARNING: certificate expires in $expires_in days (%s)\n", scalar(localtime($certdata->{'not_after'})));
+ exit($ERRORS{'WARNING'});
+}
+
+# optionally check for name mismatch.
+if (defined($opt{'name'})) {
+ if (!defined($certdata->{'cn'})) {
+ print "UNKNOWN: failed to parse certificate name\n";
+ exit($ERRORS{'UNKNOWN'});
+ }
+ if (lc($opt{'name'}) ne lc($certdata->{'cn'})) {
+ printf("CRITICAL: certificate name mismatch (expected %s, got %s)\n", $opt{'name'}, $certdata->{'cn'});
+ exit($ERRORS{'CRITICAL'});
+ }
+}
+
+# note good certificate.
+printf("OK: certificate expires in %d days (%s)\n", $expires_in, scalar(localtime($certdata->{'not_after'})));
+exit($ERRORS{'OK'});
+
+###########################################################################
+##### #
+##### certificate retrieval functions. #
+##### #
+###########################################################################
+
+sub s_client {
+ my ($command, $arguments) = @_;
+
+ return(parse_certificate(scalar(`/bin/echo $command | /usr/bin/openssl s_client $arguments 2>/dev/null | /usr/bin/openssl x509 -text 2>/dev/null`)));
+}
+
+sub read_file {
+ my ($filename) = @_;
+
+ return(parse_certificate(scalar(`/usr/bin/openssl x509 -in $filename -text 2>/dev/null`)));
+}
+
+sub parse_certificate {
+ my ($text) = @_;
+
+ my %result;
+
+ foreach my $line (split(/[\r\n]+/, $text)) {
+ if ($line =~ /^\s+Not Before: (.*)$/ ){
+ $result{'not_before'} = str2time($1);
+ } elsif ($line =~ /^\s+Not After : (.*)$/ ){
+ $result{'not_after'} = str2time($1);
+ } elsif ($line =~ /^\s+Subject:.*, CN=(.*)$/ ){
+ $result{'cn'} = $1;
+ }
+ }
+
+ if (scalar(keys(%result)) == 0) {
+ print("CRITICAL: failed to retrieve certificate\n");
+ exit($ERRORS{'CRITICAL'});
+ }
+
+ return(\%result);
+}
+
--- /dev/null
+#!/usr/bin/env python
+#
+# Copyright Hari Sekhon 2007
+#
+# 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+#
+
+""" This plugin for Nagios uses the standard mdadm program to get the status
+ of all the linux md arrays on the local machine using the mdadm utility"""
+
+__version__ = "0.7.2"
+
+import os
+import re
+import sys
+from optparse import OptionParser
+
+# Standard Nagios return codes
+OK = 0
+WARNING = 1
+CRITICAL = 2
+UNKNOWN = 3
+
+# Full path to the mdadm utility check on the Raid state
+BIN = "/sbin/mdadm"
+
+def end(status, message):
+ """exits the plugin with first arg as the return code and the second
+ arg as the message to output"""
+
+ if status == OK:
+ print "RAID OK: %s" % message
+ sys.exit(OK)
+ elif status == WARNING:
+ print "RAID WARNING: %s" % message
+ sys.exit(WARNING)
+ elif status == CRITICAL:
+ print "RAID CRITICAL: %s" % message
+ sys.exit(CRITICAL)
+ else:
+ print "UNKNOWN: %s" % message
+ sys.exit(UNKNOWN)
+
+
+if os.geteuid() != 0:
+ end(UNKNOWN, "You must be root to run this plugin")
+
+if not os.path.exists(BIN):
+ end(UNKNOWN, "Raid utility '%s' cannot be found" % BIN)
+
+if not os.access(BIN, os.X_OK):
+ end(UNKNOWN, "Raid utility '%s' is not executable" % BIN)
+
+
+def find_arrays(verbosity):
+ """finds all MD arrays on local machine using mdadm and returns a list of
+ them, or exits UNKNOWN if no MD arrays are found"""
+
+ if verbosity >= 3:
+ print "finding all MD arrays via: %s --detail --scan" % BIN
+ devices_output = os.popen("%s --detail --scan" % BIN).readlines()
+ raid_devices = []
+ for line in devices_output:
+ if "ARRAY" in line:
+ raid_device = line.split()[1]
+ if verbosity >= 2:
+ print "found array %s" % raid_device
+ raid_devices.append(raid_device)
+
+ if len(raid_devices) == 0:
+ end(UNKNOWN, "no MD raid devices found on this machine")
+ else:
+ raid_devices.sort()
+ return raid_devices
+
+
+def test_raid(verbosity):
+ """checks all MD arrays on local machine, returns status code"""
+
+ raid_devices = find_arrays(verbosity)
+
+ status = OK
+ message = ""
+ arrays_not_ok = 0
+ number_arrays = len(raid_devices)
+ for array in raid_devices:
+ if verbosity >= 2:
+ print 'Now testing raid device "%s"' % array
+
+ detailed_output = os.popen("%s --detail %s" % (BIN, array) ).readlines()
+
+ if verbosity >= 3:
+ for line in detailed_output:
+ print line,
+
+ state = "unknown"
+ for line in detailed_output:
+ if "State :" in line:
+ state = line.split(":")[-1][1:-1]
+ re_clean = re.compile('^clean(, no-errors)?$')
+ if not re_clean.match(state) and state != "active":
+ arrays_not_ok += 1
+ raidlevel = detailed_output[3].split()[-1]
+ shortname = array.split("/")[-1].upper()
+ if state == "dirty":
+ # This happens when the array is under heavy usage but it's \
+ # normal and the array recovers within seconds
+ continue
+ elif "recovering" in state:
+ extra_info = None
+ for line in detailed_output:
+ if "Rebuild Status" in line:
+ extra_info = line
+ message += 'Array "%s" is in state ' % shortname
+ if extra_info:
+ message += '"%s" (%s) - %s' \
+ % (state, raidlevel, extra_info)
+ else:
+ message += '"%s" (%s)' % (state, raidlevel)
+ message += ", "
+ if status == OK:
+ status = WARNING
+ elif state == "unknown":
+ message += 'State of Raid Array "%s" is unknown, ' % shortname
+ if state == OK:
+ status = UNKNOWN
+ else:
+ message += 'Array %s is in state "%s" (%s), ' \
+ % (shortname, state, raidlevel)
+ status = CRITICAL
+
+ message = message.rstrip(", ")
+
+ if status == OK:
+ message += "All arrays OK"
+ else:
+ if arrays_not_ok == 1:
+ message = "1 array not ok - " + message
+ else:
+ message = "%s arrays not ok - " % arrays_not_ok + message
+
+ if number_arrays == 1:
+ message += " [1 array checked]"
+ else:
+ message += " [%s arrays checked]" % number_arrays
+
+ return status, message
+
+
+def main():
+ """parses args and calls func to test MD arrays"""
+
+ parser = OptionParser()
+
+ parser.add_option( "-v",
+ "--verbose",
+ action="count",
+ dest="verbosity",
+ help="Verbose mode. Good for testing plugin. By default\
+ only one result line is printed as per Nagios standards")
+
+ parser.add_option( "-V",
+ "--version",
+ action="store_true",
+ dest="version",
+ help="Print version number and exit")
+
+ (options, args) = parser.parse_args()
+
+ if args:
+ parser.print_help()
+ sys.exit(UNKNOWN)
+
+ verbosity = options.verbosity
+ version = options.version
+
+ if version:
+ print __version__
+ sys.exit(OK)
+
+ result, message = test_raid(verbosity)
+
+ end(result, message)
+
+
+if __name__ == "__main__":
+ main()