#!/bin/sh
#
# monitor-base -- remctl backend for standard Nagios probes.
#
# Copyright 2005, 2008, 2010, 2011, 2012, 2013, 2026
#     The Board of Trustees of the Leland Stanford Junior University
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to
# deal in the Software without restriction, including without limitation the
# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
# sell copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
# IN THE SOFTWARE.

PATH=/usr/lib/nagios/plugins:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
export PATH

# The 'disk-rw' check needs a default location and a file name. The check
# appends the PID to the file name and removes the file when it finishes,
# so it does not persist between runs.
TEST_DISK=/var/tmp
TEST_FILE=testfile-rw

cmd="$1"
shift
case $cmd in
    disk)
        # We need to exclude the tracefs file system as tracefs's permissions
        # prohibit user "nobody" from access.
        setuidgid nobody check_disk "$@" -x /usr/vice/cache -x /main3 -X tracefs
        ;;
    disk-rw)
        if [ "x${1}" != "x" ]; then
            TEST_DISK=$1
        fi
        if [ ! -d "$TEST_DISK" ]; then
            echo "DISK-RW CRITICAL - no such directory '$TEST_DISK'"
            exit 2
        fi

        # Use a unique, per-run file so a stale file from a crashed run or a
        # concurrent probe cannot mask a real failure.
        TEST_FILE="${TEST_DISK}/${TEST_FILE}.$$"

        # Always remove the test file, even if a step below fails or the
        # script is interrupted.
        trap 'rm -f "$TEST_FILE"' EXIT HUP INT TERM

        # Write, read back, and confirm the content survived the round trip.
        # A bare touch would not catch a full or subtly broken filesystem;
        # a real write plus read does.
        if ! echo "monitor-base disk-rw $$" > "$TEST_FILE" 2>/dev/null; then
            echo "DISK-RW CRITICAL - cannot write to '$TEST_DISK'"
            exit 2
        fi
        if ! read_back=$(cat "$TEST_FILE" 2>/dev/null); then
            echo "DISK-RW CRITICAL - cannot read back file in '$TEST_DISK'"
            exit 2
        fi
        if [ "x${read_back}" != "xmonitor-base disk-rw $$" ]; then
            echo "DISK-RW CRITICAL - read-back mismatch in '$TEST_DISK'"
            exit 2
        fi

        echo "DISK-RW OK - '$TEST_DISK' is writable"
        exit 0
        ;;
    file-age)
        check_file_age "$@"
        ;;
    filesystemstate)
        check_filesystem_state
        ;;
    hardware-health)
        check_hardware_health "$@"
        ;;
    ipmi)
        check_ipmi_sel "$@"
        ;;
    load)
        setuidgid nobody check_load "$@"
        ;;
    localcert)
        setuidgid nobody check_ssl_local "$@"
        ;;
    log)
        check_log "$@"
        ;;
    mysql)
        setuidgid nobody check_mysql "$@"
        ;;
    nic)
        interface="$1"
        if [ -z "$interface" ] ; then
            interface=eth0
        fi
        status=$(/sbin/mii-tool "$interface" 2>&1 | tr '\n' ' ')
        if echo "$status" | grep -E -q 'FD|full' ; then
            echo "NIC OK - $status"
            exit 0
        else
            echo "NIC CRITICAL - $status"
            exit 2
        fi
        ;;
    ntp)
        setuidgid nobody check_ntp_time -H localhost -4 "$@"
        ;;
    ossec-report)
        check_ossec_report "$@"
        ;;
    procs)
        setuidgid nobody check_procs "$@"
        ;;
    procs_perf)
        setuidgid nobody check_procs_perf "$@"
        ;;
    puppet)
        check_puppet -s "$@"
        ;;
    service)
        check_service "$@"
        ;;
    # Run as "nobody" (matching the "localcert" check) so the probe has the
    # same low privilege as a typical unprivileged cert consumer. This way a
    # cert mistakenly made readable only by root is reported as a failure
    # rather than silently passing because root can read it.
    ssl_cert_file)
        setuidgid nobody check_ssl_local "$@"
        ;;
    # sslcert_file is an alias for ssl_cert_file:
    sslcert_file)
        setuidgid nobody check_ssl_local "$@"
        ;;
    swap)
        setuidgid nobody check_swap "$@"
        ;;
    swaprate)
        setuidgid nobody check_swap_rate "$@"
        ;;
    tcp)
        setuidgid nobody check_tcp "$@"
        ;;
    uptime)
        setuidgid nobody check_uptime "$@"
        ;;
    help)
        echo "Monitoring remctl help:"
        echo "  monitor disk                    Check disk space"
        echo "  monitor disk-rw                 Check if root disk is writable"
        echo "  monitor file-age                Check the age of a file"
        echo "  monitor filesystemstate         Check the state of the filesystems"
        echo "  monitor hardware-health         Check health of system hardware"
        echo "  monitor ipmi                    Check for ipmi sel errors"
        echo "  monitor load                    Check cpu load"
        echo "  monitor localcert               Check a local SSL cert file"
        echo "  monitor log                     Check log for a certain pattern"
        echo "  monitor mysql                   Check mysql"
        echo "  monitor nic [<interface>]       Check NIC duplex"
        echo "  monitor ntp                     Check ntp"
        echo "  monitor ossec-report            Check the file size of the OSSEC Report"
        echo "  monitor procs                   Check specific process"
        echo "  monitor procs_perf              Check specific process with performance data"
        echo "  monitor puppet                  Check puppet client and runtime status"
        echo "  monitor service                 Check specific service status"
        echo "  monitor ssl_cert_file           Check the expiration of an SSL Certificate File"
        echo "  monitor sslcert_file            alias for ssl_cert_file"
        echo "  monitor swap                    Check swap usage"
        echo "  monitor swaprate                Check swap rate"
        echo "  monitor tcp -H <host> -p <port> Check to see if <port> at <host> is open"
        echo "  monitor uptime                  Check server uptime"
        ;;
    *)
        echo "monitor-base: unknown check parameters $cmd"
        exit 2
        ;;
esac

# Some tests (for example disk-rw) exit on their own, so not every test
# reaches this point. This exit handles the tests that fall through.
exit $?

# Documentation.  Use a hack to hide this from the shell.  Because of the
# above exit line, this should never be executed.
DOCS=<<__END_OF_DOCS__

=for stopwords
Allbery Huaqing Zheng NIC Nagios backend remctl ipmi nic dir localcert
mii-tool oldlog procs disk-rw swaprate username eth0

=head1 NAME

monitor-base - remctl backend for standard Nagios probes

=head1 SYNOPSIS

B<monitor-base> disk B<-w> I<warn_limit> B<-c> I<crit_limit>

B<monitor-base> disk-rw [I<dir>]

B<monitor-base> hardware-health

B<monitor-base> ipmi

B<monitor-base> load B<-w> I<1m,5m,15m> B<-c> I<1m,5m,15m>

B<monitor-base> localcert B<-w> I<days> B<-c> I<days> B<-f> I<path-to-file>

B<monitor-base> log B<-F> I<logfile> B<-O> I<oldlog> B<-t> I<threshold>
    B<-q> I<pattern>

B<monitor-base> mysql B<-H> I<host> B<-P> I<port> B<-d> I<database>
    B<-u> I<username> B<-p> I<password>

B<monitor-base> nic [I<interface>]

B<monitor-base> ntp B<-w> I<warn_limit> B<-c> I<crit_limit>

B<monitor-base> procs -C command

B<monitor-base> procs_perf -C command

B<monitor-base> puppet

B<monitor-base> service

B<monitor-base> sslcert_file B<-w> I<warn_limit> B<-c> I<crit_limit> B<-f> I<sslcert filename>

B<monitor-base> swap B<-w> I<warn_limit%> B<-c> I<crit_limit%>

B<monitor-base> swaprate B<-w> I<warn_limit> B<-c> I<crit_limit>

B<monitor-base> uptime B<-w> I<warn_limit> B<-c> I<crit_limit>

B<monitor-base> help

=head1 DESCRIPTION

This is a shell script wrapper around a set of local Nagios plugins and a
few additional checks that are maintained as part of this script.  This
script takes the first argument as the type of check to perform.  Any
subsequent arguments is then passed to the plugin binary for those checks
that aren't implemented internally.

The NIC check is handled separately.  It runs B<mii-tool> and reports okay
if the interface is in full duplex or reports a critical error if the
interface is not.  It takes an optional interface or defaults to eth0.

The C<disk-rw> check touches (and does not remove!) the file
F<testfile-rw> in the directory I<dir> (defaults to F</var/tmp>) in order
to confirm that it's possible to do so.  If we can't write this file, it
probably means that the system has set its root disk to read-only, or
something similar.

=head1 AUTHOR

Huaqing Zheng <morpheus@stanford.edu>.  NIC check added by Russ Allbery
<rra@stanford.edu> based on work by Roger Silva.  NTP check added by LJ
Laubenheimer <ljlgeek@stanford.edu>

=head1 COPYRIGHT

Copyright 2005, 2008, 2010, 2011, 2012, 2019 The Board of Trustees of the
Leland Stanford Junior University.

=cut

__END_OF_DOCS__
