|
1 #!/usr/bin/perl -w |
|
2 |
|
3 use strict; |
|
4 use warnings; |
|
5 use File::Basename; |
|
6 use Getopt::Long; |
|
7 use Date::Manip; |
|
8 use IPC::Open2; |
|
9 use lib "/usr/lib/nagios/plugins"; |
|
10 use utils qw (%ERRORS &print_revision &support); |
|
11 |
|
12 sub print_help(); |
|
13 sub print_usage(); |
|
14 |
|
15 my $ME = basename $0; |
|
16 my ( $opt_w, $opt_c, $opt_V, $opt_h, $opt_b, $opt_s, @opt_certfiles ); |
|
17 my ( $w_time, $c_time, $result, $message, %certs ); |
|
18 my ( @critical, @warning, @ok ); |
|
19 |
|
20 $opt_w = "1month"; |
|
21 $opt_c = "1week"; |
|
22 $opt_b = "/usr/bin/openssl"; |
|
23 $opt_s = "md5WithRSAEncryption"; |
|
24 |
|
25 Getopt::Long::Configure('bundling'); |
|
26 GetOptions( |
|
27 "V" => \$opt_V, |
|
28 "version" => \$opt_V, |
|
29 "h" => \$opt_h, |
|
30 "help" => \$opt_h, |
|
31 "b=s" => \$opt_b, |
|
32 "binary" => \$opt_b, |
|
33 "w=s" => \$opt_w, |
|
34 "warning=s" => \$opt_w, |
|
35 "c=s" => \$opt_c, |
|
36 "critical=s" => \$opt_c, |
|
37 "s=s" => \$opt_s, |
|
38 "signature=s" => \$opt_s, |
|
39 "f=s" => \@opt_certfiles, |
|
40 "certfile=s" => \@opt_certfiles |
|
41 ); |
|
42 |
|
43 if ($opt_V) { |
|
44 print_revision( $ME, "1.2" ); |
|
45 exit $ERRORS{"OK"}; |
|
46 } |
|
47 |
|
48 if ($opt_h) { |
|
49 print_help(); |
|
50 exit $ERRORS{"OK"}; |
|
51 } |
|
52 |
|
53 # check openssl binary |
|
54 unless ( -x $opt_b ) { |
|
55 print "CERT CRITICAL: OpenSSL not found or not executable - $opt_b\n"; |
|
56 exit $ERRORS{"CRITICAL"}; |
|
57 } |
|
58 |
|
59 unless (@opt_certfiles) { |
|
60 print "CERT WARNING: Not defined any certificate files\n"; |
|
61 exit $ERRORS{"WARNING"}; |
|
62 } |
|
63 |
|
64 @opt_certfiles = split( /,/, join( ',', @opt_certfiles ) ); |
|
65 |
|
66 # extract certificate data |
|
67 foreach my $file (@opt_certfiles) { |
|
68 unless ( -r $file ) { |
|
69 print |
|
70 "CERT CRITICAL: $file - not exists or not read permission is granted\n"; |
|
71 exit $ERRORS{"CRITICAL"}; |
|
72 } |
|
73 my $no_print = |
|
74 "no_header,no_version,no_serial,no_validity,no_subject,no_issuer,no_pubkey,no_sigdump,no_extensions"; |
|
75 my @cmd_x509 = ( |
|
76 $opt_b, "x509", "-in", $file, |
|
77 "-noout", "-text", "-certopt", $no_print, |
|
78 "-subject", "-enddate", "-purpose" |
|
79 ); |
|
80 my @cmd_pkcs12 = ( |
|
81 $opt_b, "pkcs12", "-in", $file, |
|
82 "-clcerts", "-nokeys", "-nomacver", "-passin", |
|
83 "pass:" |
|
84 ); |
|
85 my @cmd_pipe = ( |
|
86 $opt_b, "x509", "-noout", "-text", |
|
87 "-certopt", $no_print, "-subject", "-enddate", |
|
88 "-purpose" |
|
89 ); |
|
90 my ( $temp, $sig, $cn, $enddate, $rc, $cert_type ); |
|
91 open( CERT, "-|" ) or do { |
|
92 open( STDERR, ">&STDOUT" ); |
|
93 exec(@cmd_x509); |
|
94 }; |
|
95 |
|
96 # check x509 certificates |
|
97 while (<CERT>) { |
|
98 /unable to load certificate/ and $rc = 1 and last; |
|
99 /Signature\sAlgorithm:\s($opt_s)\s+$/ and $sig = $1; |
|
100 /^subject=\s.*CN=(.*)\s+$/ and $cn = $1; |
|
101 /^notAfter=(.*)\s+$/ and $enddate = $1; |
|
102 /^(SSL\sclient)\s:\sYes$/ and $cert_type = $1; |
|
103 /^(SSL\sserver)\s:\sYes$/ and $cert_type = $1; |
|
104 } |
|
105 close(CERT); |
|
106 |
|
107 # check pkcs12 certificates |
|
108 if ($rc) { |
|
109 open( PKCS12, "@cmd_pkcs12 |" ); |
|
110 |
|
111 while (<PKCS12>) { |
|
112 $temp .= $_; |
|
113 } |
|
114 close(PKCS12); |
|
115 |
|
116 local ( *READ, *WRITE ); |
|
117 open2( \*READ, \*WRITE, @cmd_pipe ) or die "Can't fork: $!\n"; |
|
118 print WRITE $temp; |
|
119 close(WRITE); |
|
120 |
|
121 while (<READ>) { |
|
122 /unable to load certificate/ |
|
123 and print "CERT CRITICAL: unable to load certificate\n" |
|
124 and exit $ERRORS{"CRITICAL"}; |
|
125 /Signature\sAlgorithm:\s($opt_s)\s+$/ and $sig = $1; |
|
126 /^subject=\s.*CN=(.*)\s+$/ and $cn = $1; |
|
127 /^notAfter=(.*)\s+$/ and $enddate = $1; |
|
128 /^(SSL\sclient)\s:\sYes$/ and $cert_type = $1; |
|
129 /^(SSL\sserver)\s:\sYes$/ and $cert_type = $1; |
|
130 } |
|
131 close(READ); |
|
132 } |
|
133 |
|
134 # fill the hash |
|
135 push( @{ $certs{$file} }, ( $cn, $enddate, $sig, $cert_type ) ); |
|
136 } |
|
137 |
|
138 # calculate the time |
|
139 $w_time = DateCalc( "today", "+ $opt_w" ); |
|
140 $c_time = DateCalc( "today", "+ $opt_c" ); |
|
141 |
|
142 # check expire date |
|
143 foreach ( sort keys %certs ) { |
|
144 my $enddate; |
|
145 if ( @{ $certs{$_} }[1] =~ /(\w+\s+\d+\s+\d+:\d+:\d+\s+\d+)/ ) { |
|
146 $enddate = $1; |
|
147 } |
|
148 $enddate = ParseDate($enddate); |
|
149 unless ($enddate) { |
|
150 print "CERT CRITICAL: Can't parse enddate\n"; |
|
151 exit $ERRORS{"CRITICAL"}; |
|
152 } |
|
153 |
|
154 &Date_Cmp( $enddate, $w_time ) > 0 and push( @{ $certs{$_} }, "OK" ), next; |
|
155 &Date_Cmp( $enddate, $c_time ) > 0 |
|
156 and push( @{ $certs{$_} }, "WARNING" ), next; |
|
157 push( @{ $certs{$_} }, "CRITICAL" ); |
|
158 } |
|
159 |
|
160 # looking for stats |
|
161 foreach ( sort keys %certs ) { |
|
162 if ( @{ $certs{$_} }[2] ) { |
|
163 if ( @{ $certs{$_} }[2] eq "$opt_s" ) { |
|
164 push( @warning, |
|
165 "file: $_, CN=@{$certs{$_}}[0] Signature Algorithm: @{$certs{$_}}[2]" |
|
166 ); |
|
167 } |
|
168 } |
|
169 |
|
170 if ( @{ $certs{$_} }[4] eq "WARNING" ) { |
|
171 push( @warning, |
|
172 "file: $_, CN=@{$certs{$_}}[0] expires @{$certs{$_}}[1] type: @{$certs{$_}}[3]" |
|
173 ); |
|
174 } |
|
175 elsif ( @{ $certs{$_} }[4] eq "CRITICAL" ) { |
|
176 push( @critical, |
|
177 "file: $_, CN=@{$certs{$_}}[0] expires @{$certs{$_}}[1] type: @{$certs{$_}}[3]" |
|
178 ); |
|
179 } |
|
180 else { |
|
181 push( @ok, |
|
182 "file: $_, CN=@{$certs{$_}}[0] expires @{$certs{$_}}[1] type: @{$certs{$_}}[3]" |
|
183 ); |
|
184 } |
|
185 } |
|
186 |
|
187 # return the state |
|
188 if (@critical) { |
|
189 print "CERT CRITICAL: @critical\n"; |
|
190 exit $ERRORS{"CRITICAL"}; |
|
191 } |
|
192 elsif (@warning) { |
|
193 print "CERT WARNING: @warning\n"; |
|
194 exit $ERRORS{"WARNING"}; |
|
195 } |
|
196 else { |
|
197 print "CERT OK: @ok\n"; |
|
198 exit $ERRORS{"OK"}; |
|
199 } |
|
200 |
|
201 sub print_usage() { |
|
202 print "Usage:\n"; |
|
203 print |
|
204 " $ME [-b <binary>] [-w <time>] [-c <time>] [-s <signature algorithm>] [-f <file,file,file,...>]\n"; |
|
205 print " $ME [-h | --help]\n"; |
|
206 print " $ME [-V | --version]\n"; |
|
207 } |
|
208 |
|
209 sub print_help() { |
|
210 print_revision( $ME, "1.2" ); |
|
211 print "Copyright (c) 2010 Christian Arnold\n\n"; |
|
212 print "This plugin checks the expire date for openssl certificates.\n\n"; |
|
213 print_usage(); |
|
214 print "\n"; |
|
215 print " -b, --binary <binary>\n"; |
|
216 print " Path of openssl binary (default: /usr/bin/openssl)\n"; |
|
217 print " -w, --warning <time>\n"; |
|
218 print |
|
219 " Certificat should not be more than this time older (default: 1month)\n"; |
|
220 print |
|
221 " For time can be used year, month, day, hour, minute, second and weeks.\n"; |
|
222 print " -c, --critical <time>\n"; |
|
223 print |
|
224 " Certificat should not be more than this time older (default: 1week)\n"; |
|
225 print |
|
226 " For time can be used year, month, day, hour, minute, second and weeks.\n"; |
|
227 print " -s, --signature <signature algorithm>\n"; |
|
228 print |
|
229 " Return WARNING status if <signature algorithm> is used (default: md5WithRSAEncryption).\n"; |
|
230 print " -f, --certfile <file,file,file, ...>\n"; |
|
231 print |
|
232 " Absolute path of x509 or pkcs12 openssl certificate files, use comma-separated lists for multiple files.\n"; |
|
233 print " -h, --help\n"; |
|
234 print " Print detailed help screen\n"; |
|
235 print " -V, --version\n"; |
|
236 print " Print version information\n"; |
|
237 print "\n"; |
|
238 support(); |
|
239 } |
|
240 |
|
241 exit; |
|
242 |
|
243 # vim:sts=4 sw=4 aw ai sm: |