Subversion Repositories vnag

Rev

Rev 4 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
4 daniel-mar 1
<?php /* <ViaThinkSoftSignature>
52 daniel-mar 2
boKKZRVCLt6Pij9GtZwVtVRcuFrDhyTKij4SbspGGs+24F0eeo10iC1wBP05mJ7tL
3
WS8JfFSlv7vQDBcdd6sMF+vYQNldSznrK47dbZzQXFxuq26jd6BuuH41aP2pWHv57
4
XVCpYf5EPR0gFkyXzrtN/iFSr0kJKWk5iSz/iniucplPitxmXR0EN1qkKmcZgTon7
5
hKIjq3kb8RY6U4BFcXujRq7M/SlRvub2erQiWxPv3wKi+CQPRcCvq33/g7bPOTSpY
6
1WFCt+3zkCfQUomU27Y7/GSW1V+7T8DjAWUhR4rxO5nXyTx3vxqmv9UjfkKpTUVc/
7
TjhyS0mZ78rYX2HYW3+NBQQMMWfGlLKvuhHdJFU2dB9+YvW4Krm/N7xTcwKos3Aho
8
vSlnVHDf48KSXN/gPMKC7U3mOH8RB2oyiLJBX42CE+N30Ui+3TyxAj2/YMAjzDPYP
9
8b+yRhntXzvGX3wayFPcjBHBBWrchJ6JnERCewVW+/3vDKgjwHhnul4Y/lme79jNA
10
1Oj0ZX6rCGow+7z3he7/0ec92Rr8NOE8p7mrQn9iofTZcfFo2i5RDy+6raUvSi/Fp
11
2DP2HqwOGp2uHrFemzo9NepjH2DgnK5zMMRR1Q2hMksAsviWMWTUv0fkYZZSsi1LA
12
aROWE4CRaEhBuvt0bRIrJGZUbBWvxOE67CVYXHF20YvyKoI5IUN/ZOI2iCLMr+ss2
13
wrB5tW4ovYwsjV5nDAK1bg1hsdOKx5xv7PchfhUkAn1J3DoekDl9qECt3LKdKG2hl
14
ZwB/HrnuByxgab30wLUFsELT9v/pKJW6/2TFkWEfYw43MQzpsmKs/h0qTKW691GkW
15
htPhMbMpSCxgDGloU4z7EcMdnvTEM4ol1GyDn7NZlYhgEHfw+X/5CZNTYH5DJvt8J
16
K+aQaZFiZDHa8GaI7NyGERRk34C90lL7pgFEhaNGCFl+Z+YGegxwMjKbFo1xH0YNk
17
CMPYX9GGZIEMTTNEySCyuZsDvXpXK5CbQ8ywuZ9/B0avnUWrBBPLh9RchB07S6kA/
18
EcH71AxGafK8wDMrPzymdFVsHpwNp6FEvP/EpBHGv0x4/gYpPomUOxmy7uEE1dzdB
19
talRGPLAt8a/RXXG3ECsjgo3zDzmc8VYx6m4BPXvLsDX1b9NjN34AtBObE+iLLC3A
20
wMd4oQSnOwfDDYNdKg08s43j5m+SQ+HRGQqgGb9A6IcwxuHR9bTidXBgNORbbdjXf
21
9I1QW1Za0l5khdpDF/smNPMIwidcg2xBi7faHY/aOpzWTcTviox1ujPJmwaLr0I0l
22
DYFlTNaQ0wM+UBE501Lwss8gscs4duuSlBHQLA+ddOKWSd92/KK/JW3uf67rOaqfy
23
A==
4 daniel-mar 24
</ViaThinkSoftSignature> */ ?>
2 daniel-mar 25
<?php
26
 
27
/*
28
 * VNag - Nagios Framework for PHP
29
 * Developed by Daniel Marschall, ViaThinkSoft <www.viathinksoft.com>
30
 * Licensed under the terms of the Apache 2.0 license
31
 *
32
 * Revision 2018-07-16
33
 */
34
 
35
declare(ticks=1);
36
 
37
class X509ExpireCheck extends VNag {
38
        protected $argFiles = null;
39
 
40
        public function __construct() {
41
                parent::__construct();
42
 
43
                $this->registerExpectedStandardArguments('Vhtwcv');
44
 
45
                $this->getHelpManager()->setPluginName('check_x509_expire');
46
                $this->getHelpManager()->setVersion('1.0');
47
                $this->getHelpManager()->setShortDescription('This plugin checks X.509 (PEM) files and warns if certificates are about to expire.');
48
                $this->getHelpManager()->setCopyright('Copyright (C) 2011-$CURYEAR$ Daniel Marschall, ViaThinkSoft.');
49
                $this->getHelpManager()->setSyntax('$SCRIPTNAME$ [-v] -w <warnSeconds>s -c <critSeconds>s -f "[#]<mask>" [-f "[#]<mask>" [...]]');
50
                $this->getHelpManager()->setFootNotes('If you encounter bugs, please contact ViaThinkSoft at www.viathinksoft.com');
51
 
52
                // Individual (non-standard) arguments:
53
                $this->addExpectedArgument($this->argFiles = new VNagArgument('f', 'file', VNagArgument::VALUE_REQUIRED, 'mask', 'The files to be checked. This argument can be used multiple times. Wilcards may be used but MUST be passed as string only (not resolved by the Shell). There are two possible checking modes: If you put a # in front of the file mask, only the oldest file of each group will be checked (use this mode e.g. if you have a directory which contains old backups of certificates beside the current working certificate). Otherwise, all files of the file group are checked.'));
54
 
52 daniel-mar 55
                // In this context, when the user writes "-w 60s" then they probably mean "-w @60s". Make sure that the user doesn't do it wrong
2 daniel-mar 56
                $this->warningSingleValueRangeBehaviors[0]  = self::SINGLEVALUE_RANGE_VAL_LT_X_BAD;
57
                $this->criticalSingleValueRangeBehaviors[0] = self::SINGLEVALUE_RANGE_VAL_LT_X_BAD;
58
        }
59
 
60
        private static function humanFriendlyTimeLeft($secs) {
61
                $out = array();
62
 
63
                if ($expired = $secs < 0) $secs *= -1;
64
 
65
                $years = floor($secs / 60 / 60 / 24 / 365);
66
                if ($years > 0) $out[] = $years == 1 ? "$years year" : "$years years";
67
 
68
                $days = floor($secs / 60 / 60 / 24) % 365;
69
                if ($days > 0) $out[] = $days == 1 ? "$days day" : "$days days";
70
 
71
                $hours = floor($secs / 60 / 60) % 24;
72
                if ($hours > 0) $out[] = $hours == 1 ? "$hours hour" : "$hours hours";
73
 
74
                $minutes = floor($secs / 60) % 60;
75
                if ($minutes > 0) $out[] = $minutes == 1 ? "$minutes minute" : "$minutes minutes";
76
 
77
                $seconds = $secs % 60;
78
                if ($seconds > 0) $out[] = $seconds == 1 ? "$seconds second" : "$seconds seconds";
79
 
80
                return ($expired ? 'EXPIRED SINCE ' : '').implode(", ", $out).($expired ? '' : ' left');
81
        }
82
 
83
        private static function timeLeft($pemFile) {
84
                $out = array();
85
 
86
                // TODO: Call PHP's openssl functions instead
87
                exec("openssl x509 -in ".escapeshellarg($pemFile)." -noout -text | grep \"Not After\" | cut -d ':' -f 2-", $out, $code); // TODO: check $code
88
                if ($code != 0) {
89
                        throw new VNagException("Error calling openssl!");
90
                }
91
 
92
                $tim = strtotime($out[0]);
93
                return $tim - time();
94
        }
95
 
96
        protected function cbRun($optional_args=array()) {
97
                $this->argFiles->require();
98
 
99
                $countFilesTotal = 0;
100
                $countFilesCrit = 0;
101
                $countFilesWarn = 0;
102
 
103
                $fileGroupMasks = $this->argFiles->getValue();
104
                if (!is_array($fileGroupMasks)) $fileGroupMasks = array($fileGroupMasks);
105
                foreach ($fileGroupMasks as $fileGroupMask) {
106
                        if (substr($fileGroupMask, 0, 1) === '#') {
107
                                $fileGroupMask = substr($fileGroupMask, 1); // remove #
108
 
109
                                // Mode 1: Only the youngest file of each group is checked.
110
                                // You can use this mode e.g. if you have a folder with downloaded files
111
                                // and you want to check if a downloading-script is still downloading
112
                                // new files regularly.
113
 
114
                                $files = glob($fileGroupMask);
115
                                if (count($files) == 0) continue;
116
 
117
                                $minTimeLeft = null;
118
                                foreach ($files as $file) {
119
                                        $minTimeLeft = is_null($minTimeLeft) ? filemtime($file) : min($minTimeLeft, self::timeLeft($file));
120
                                }
121
 
122
                                $countFilesTotal++;
123
                                if ($this->checkAgainstCriticalRange($minTimeLeft.'s', false, true)) {
124
                                        $countFilesCrit++;
125
                                        $this->addVerboseMessage("File group '$fileGroupMask' oldest file: ".self::humanFriendlyTimeLeft($minTimeLeft)." (Critical)\n", VNag::VERBOSITY_SUMMARY);
126
                                } else if ($this->checkAgainstWarningRange($minTimeLeft.'s', false, true)) {
127
                                        $countFilesWarn++;
128
                                        $this->addVerboseMessage("File group '$fileGroupMask' oldest file: ".self::humanFriendlyTimeLeft($minTimeLeft)." (Warning)\n", VNag::VERBOSITY_SUMMARY);
129
                                } else {
130
                                        if (($this->getArgumentHandler()->getArgumentObj('w')->available()) || ($this->getArgumentHandler()->getArgumentObj('c')->available())) {
131
                                                $this->addVerboseMessage("File group '$fileGroupMask' oldest file: ".self::humanFriendlyTimeLeft($minTimeLeft)." (OK)\n", VNag::VERBOSITY_ADDITIONAL_INFORMATION);
132
                                        } else {
133
                                                $this->addVerboseMessage("File group '$fileGroupMask' oldest file: ".self::humanFriendlyTimeLeft($minTimeLeft)."\n", VNag::VERBOSITY_ADDITIONAL_INFORMATION);
134
                                        }
135
                                }
136
                        } else {
137
                                // Mode 2: All files of each group are checked.
138
 
139
                                $files = glob($fileGroupMask);
140
                                if (count($files) == 0) continue;
141
 
142
                                foreach ($files as $file) {
143
                                        $timeLeft = self::timeLeft($file);
144
                                        $countFilesTotal++;
145
                                        if ($this->checkAgainstCriticalRange($timeLeft.'s', false, true)) {
146
                                                $countFilesCrit++;
147
                                                $this->addVerboseMessage("File $file: ".self::humanFriendlyTimeLeft($timeLeft)." (Critical)\n", VNag::VERBOSITY_SUMMARY);
148
                                        } else if ($this->checkAgainstWarningRange($timeLeft.'s', false, true)) {
149
                                                $countFilesWarn++;
150
                                                $this->addVerboseMessage("File $file: ".self::humanFriendlyTimeLeft($timeLeft)." (Warning)\n", VNag::VERBOSITY_SUMMARY);
151
                                        } else {
152
                                                if (($this->getArgumentHandler()->getArgumentObj('w')->available()) || ($this->getArgumentHandler()->getArgumentObj('c')->available())) {
153
                                                        $this->addVerboseMessage("File $file: ".self::humanFriendlyTimeLeft($timeLeft)." (OK)\n", VNag::VERBOSITY_ADDITIONAL_INFORMATION);
154
                                                } else {
155
                                                        $this->addVerboseMessage("File $file: ".self::humanFriendlyTimeLeft($timeLeft)."\n", VNag::VERBOSITY_ADDITIONAL_INFORMATION);
156
                                                }
157
                                        }
158
                                }
159
                        }
160
                }
161
 
162
                $msg = array();
163
                $msg[] = "Checked $countFilesTotal certificates";
164
                if ($this->getArgumentHandler()->getArgumentObj('w')->available()) $msg[] = "$countFilesWarn are in warning time range";
165
                if ($this->getArgumentHandler()->getArgumentObj('c')->available()) $msg[] = "$countFilesCrit are in critical time range";
166
                $msg = implode(", ", $msg);
167
 
168
                $this->setHeadLine($msg);
169
        }
170
}