#!/usr/bin/perl -w ############################## check_inactive ############################################################################### # # Name : check_inactive # Version : 1.2 # Date : Feb 5, 2018 # Author : Anton Hofland # Company : 2024Sight (www.2024sight.com) # Licence : GPL - http://www.fsf.org/licenses/gpl.txt # # This plugin was developed to monitor inactive users. Inactive users typically arise when system administrators log in # while in the process of checking things or tracking down a problem. Remaining logged in presents a security issue, # especially when the system administrator logs in via the console and leaves it accidentally logged in with elevated # access. This plugin monitors inactive users and raises a warning or a critical error. The default is a warning # after one hour and a critical error after two hours. # # This plugin requires the User-Utmp-1.8 or later CPAN module to be installed. It can be downloaded from www.cpan.org if it # is not already installed on your system # # 5/2/2018 Added debug option # 5/2/2018 Removed ordering dependency in the UTMP record processing code # 5/2/2018 Removed spurious definitions # 5/2/2018 Added code to check that UTMP or UTMPX is installed # 5/2/2018 Slimmed down the code to just look for user processes # ############################################################################################################################# use strict; use Getopt::Long; use User::Utmp qw(:constants); use File::stat; use Time::localtime; use Time::Local; my $Version = '1.2'; my %Errors = ( 'OK' => 0, 'WARNING' => 1, 'CRITICAL' => 2, 'UNKNOWN' => 3, 'DEPENDENT' => 4 ); my @Utmp; my $O_Help = undef; # Print the help message my $O_Print = undef; # Print the list of logged in users and the inactive times in seconds my $O_Version = undef; # Print version my $O_Debug = undef; # Print debug information my $O_Warning_Timeout = 3600; # Change the default warning timeout of one hour my $O_Critical_Timeout = 7200; # Change the default critical error timeout of two hours my $O_Utmpx = undef; # Use UTMPX instead of UTMP my $Warning_Timeout = 3600; # Default warning timeout of 3600 seconds (one hour) my $Critical_Timeout = 7200; # Default critical error timeout of 7200 seconds (two hours) my $Line = undef; # Line the user is logged in on my $Device = undef; # Device the user is logged in on (/dev/$Line) my $Stats = undef; # Statistics of the device my $Inactive_Users = 0; # Number of inactive users my $Error = "WARNING"; # Default return code. my %User; # User names of the logged in users my %Inactivity_Time; # Time in seconds since the last activity my %Log_Time; # Time at which the log entry has been created my $Utmp_Entry = undef; # Individual Utmp Record my $Current_Local_Time = localtime(); my $Seconds_Since_The_Epoch = timelocal( $Current_Local_Time -> sec, $Current_Local_Time -> min, $Current_Local_Time -> hour, $Current_Local_Time -> mday, $Current_Local_Time -> mon, $Current_Local_Time -> year ); ############################################################################################################################# sub print_version { print "check_inactive version : $Version\n"; } ############################################################################################################################# sub print_usage { print "Usage: check_inactive --help\n"; print " check_inactive --version\n"; print " check_inactive [--utmpx] [--debug] [--warning ] [--critical ]\n"; } ############################################################################################################################# sub print_help { print "\n"; print "Nagios Plugin to check if there is a user inactive for longer than seconds\n"; print "\n"; print_usage(); print "\n"; print " --help print help message\n"; print " --version print version\n"; print " --debug print debug information\n"; print " --print print users and their inactivity times in seconds\n"; print " --utmpx use utmpx\n"; print " --warning set warning inactivity timeout to \n"; print " --critical set critical error inactivity timeout to \n"; print "\n"; print " Critical error time out should be greater than the warning time out\n"; print "\n\n"; print "The Nagios check_inactive plugin has been developed by 2024Sight (www.2024sight.com)\n"; print "\n"; } ############################################################################################################################# sub check_options { Getopt::Long::Configure("bundling"); GetOptions( 'h' => \$O_Help, 'help' => \$O_Help, 'p' => \$O_Print, 'print' => \$O_Print, 'v' => \$O_Version, 'version' => \$O_Version, 'd' => \$O_Debug, 'debug' => \$O_Debug, 'w=s' => \$O_Warning_Timeout, 'warning=s' => \$O_Warning_Timeout, 'c=s' => \$O_Critical_Timeout, 'critical=s' => \$O_Critical_Timeout, 'x' => \$O_Utmpx, 'utmpx' => \$O_Utmpx ); if ( defined( $O_Help )) { print_help(); exit $Errors{ "UNKNOWN" }; }; if ( defined( $O_Version )) { print_version(); exit $Errors{ "UNKNOWN" }; }; if ( $O_Warning_Timeout >= $O_Critical_Timeout ) { print STDERR "check_inactive: warning timeout should be smaller than $O_Critical_Timeout seconds\n"; exit $Errors{ "UNKNOWN" }; } $Warning_Timeout = $O_Warning_Timeout; $Critical_Timeout = $O_Critical_Timeout; } ################################### MAIN #################################################################################### # # The main program starts here. It processes the command line options. This is then followed by loading the the utmp # or utmpx file into an associative array. Finally, we will get the locatime, convert it into seconds since the epoch, # and then read for every logged in user the last access time of the terminal the user is on. If ( last access time - # seconds since the epoch ), which is the inactive time, exceeds the timeout value, an error gets raised in accordance # with the Nagios protocol. By using the -p option, all users and their inactive time in seconds get printed. # ############################################################################################################################# check_options(); if ( defined ( $O_Utmpx )) { if ( User::Utmp::HAS_UTMPX()) { if ( defined( $O_Debug )) { print STDERR "check_inactive: Using UTMPX\n"; } if ( ! ( @Utmp = User::Utmp::getutx())) { print STDERR "check_inactive: failed to load utmp data\n"; exit $Errors{ "UNKNOWN" }; } } else { print STDERR "check_inactive: utmpx is not available on your system\n"; exit $Errors{ "UNKNOWN" }; } } else { if ( ! ( @Utmp = User::Utmp::getut())) { print STDERR "check_inactive: failed to load utmp data\n"; exit $Errors{ "UNKNOWN" }; } if ( defined( $O_Debug )) { print STDERR "check_inactive: Using UTMP\n"; } } if ( defined( $O_Print )) { print " USER\t TERM\tINACTIVITY\n"; } foreach $Utmp_Entry ( @Utmp ) { if ( $Utmp_Entry -> { "ut_type" } == USER_PROCESS ) { if ( defined( $O_Debug )) { print STDERR "check_inactive: ut_type\t= ", $Utmp_Entry -> { "ut_type" }, "\n"; } if ( defined( $Utmp_Entry -> { "ut_line" } )) { $Line = $Utmp_Entry -> { "ut_line" }; $Device = "/dev/" . $Line; if ( defined( $O_Debug )) { print STDERR "check_inactive: ut_line\t= ", $Utmp_Entry -> { "ut_line" }, "\n"; } if ( defined( $Utmp_Entry -> { "ut_user" } )) { if ( defined( $O_Debug )) { print STDERR "check_inactive: ut_user\t= ", $Utmp_Entry -> { "ut_user" }, "\n"; } if ( ! ( defined ( $User{ $Line } ))) { $User{ $Line } = $Utmp_Entry -> { "ut_user" }; } if ( defined( $Utmp_Entry -> { "ut_time" } )) { if ( defined( $O_Debug )) { print STDERR "check_inactive: ut_time\t= ", $Utmp_Entry -> { "ut_user" }, "\n"; } if (( ! defined ( $Log_Time{ $Line } )) || ( $Log_Time{ $Line } < $Utmp_Entry -> { "ut_time" } )) { $Log_Time{ $Line } = $Utmp_Entry -> { "ut_time" }; if ( -e "$Device" ) { $Stats = stat( "$Device" ); $Inactivity_Time{ $Line } = $Seconds_Since_The_Epoch - ( $Stats -> atime ); } else { print "check_inactive: $Device not found\n"; exit $Errors{ "UNKNOWN" }; } } } } } if ( defined( $O_Debug )) { print STDERR "\n"; } } } foreach $Line ( keys %User ) { if ( $Inactivity_Time{ $Line } > $Warning_Timeout ) { if ( defined( $O_Debug )) { print STDERR "check_inactive: WARNING - Found inactive user ", $User{ $Line }, " on $Line\n"; } $Inactive_Users += 1; if ( $Inactivity_Time{ $Line } > $Critical_Timeout ) { if ( defined( $O_Debug )) { print STDERR "check_inactive: CRITICAL - Found inactive user ", $User{ $Line }, " on $Line\n"; } $Error = "CRITICAL"; } } if ( defined( $O_Print )) { printf( "%10.10s\t%10.10s\t%10d\n", $User{ $Line }, $Line, $Inactivity_Time{ $Line } ); } } if ( defined( $O_Print )) { print "\n"; } if ( $Inactive_Users > 0 ) { print "Inactive Users: $Inactive_Users\n"; exit $Errors{ $Error }; } print "There are no inactive users\n"; exit $Errors{ "OK" }; #############################################################################################################################