8 use DB_File; |
8 use DB_File; |
9 use Getopt::Long; |
9 use Getopt::Long; |
10 use IPC::Open2; |
10 use IPC::Open2; |
11 use Date::Manip; |
11 use Date::Manip; |
12 use POSIX ":sys_wait_h"; |
12 use POSIX ":sys_wait_h"; |
|
13 use feature qw(:5.10); |
13 use lib "/usr/lib/nagios/plugins"; |
14 use lib "/usr/lib/nagios/plugins"; |
14 use utils qw (%ERRORS &print_revision &support); |
15 use utils qw (%ERRORS &print_revision &support); |
15 |
16 |
16 my $ME = basename $0; |
17 my $ME = basename $0; |
|
18 my $USAGE = <<EOF; |
|
19 Usage: $ME [-b <binary>] [-i init] [-d <path>] [-w <time>] [-c <time>] [-s <signature algorithm>] [-e <file,file,file,...>] |
|
20 $ME [-h | --help] |
|
21 $ME [-V | --version] |
|
22 EOF |
17 my $VERSION = "0.4"; |
23 my $VERSION = "0.4"; |
18 my $hash_file = "/var/tmp/" . basename($0) . ".known.db"; |
24 my $hash_file = "/var/tmp/" . basename($0) . ".known.db"; |
19 my %known; |
25 my (%known, %excluded); |
20 my %certs = (); |
26 my %certs = (); |
21 my $no_print = |
27 my $no_print = |
22 "no_header,no_version,no_serial,no_validity,no_subject,no_issuer,no_pubkey,no_sigdump,no_extensions"; |
28 "no_header,no_version,no_serial,no_validity,no_subject,no_issuer,no_pubkey,no_sigdump,no_extensions"; |
23 my @cmd_x509 = ( |
29 my @cmd_x509 = ( |
24 "openssl", "x509", "-noout", "-text", |
30 "openssl", "x509", "-noout", "-text", |
25 "-certopt", "$no_print", "-subject", "-enddate" |
31 "-certopt", "$no_print", "-subject", "-enddate" |
26 ); |
32 ); |
27 my @cmd_pkcs12 = |
33 my @cmd_pkcs12 = qw(openssl pkcs12 -clcerts -nokeys -nomacver -passin pass:); |
28 ("openssl", "pkcs12", "-clcerts", "-nokeys", "-nomacver", "-passin", "pass:"); |
|
29 my @cmd_pipe = ( |
34 my @cmd_pipe = ( |
30 "openssl", "x509", "-noout", "-text", |
35 "openssl", "x509", "-noout", "-text", |
31 "-certopt", $no_print, "-subject", "-enddate" |
36 "-certopt", $no_print, "-subject", "-enddate" |
32 ); |
37 ); |
33 |
38 |
72 tie(%known, DB_File => $hash_file, O_RDWR | O_CREAT, 0600) |
78 tie(%known, DB_File => $hash_file, O_RDWR | O_CREAT, 0600) |
73 or die "Couldn't tie hash to file $hash_file: $!; aborting"; |
79 or die "Couldn't tie hash to file $hash_file: $!; aborting"; |
74 |
80 |
75 # initiate file-data hash |
81 # initiate file-data hash |
76 %known = () if $opt_init; |
82 %known = () if $opt_init; |
|
83 @excluded{@opt_exclude} = (); |
77 |
84 |
78 find({ wanted => \&process_file }, $opt_directory); |
85 find({ wanted => \&process_file }, $opt_directory); |
79 |
86 |
|
87 exit; |
|
88 |
80 # calculate the time |
89 # calculate the time |
|
90 # $w_time = time() + 4 * 7 * 86400; |
81 $w_time = DateCalc("today", "+ $opt_warning"); |
91 $w_time = DateCalc("today", "+ $opt_warning"); |
82 $c_time = DateCalc("today", "+ $opt_critical"); |
92 $c_time = DateCalc("today", "+ $opt_critical"); |
83 |
93 |
84 # check expire date |
94 # check expire date |
85 foreach (sort keys %certs) { |
95 foreach (sort keys %certs) { |
136 untie %known; |
146 untie %known; |
137 |
147 |
138 exit; |
148 exit; |
139 } |
149 } |
140 |
150 |
|
151 sub get_id(;$) { return join " ", (@_ ? stat($_[0]) : stat(_))[7, 9] } |
|
152 |
141 sub process_file() { |
153 sub process_file() { |
|
154 |
|
155 return if exists $excluded{$File::Find::name}; |
142 return if not -f; |
156 return if not -f; |
143 |
157 |
144 my $id = join " ", (stat)[7, 9]; |
158 my $id = get_id(); |
145 my $is_certificate = 0; |
159 my $is_certificate = 0; |
146 my $in_cert = 0; |
160 my $in_cert = 0; |
147 my @cert = (); |
161 my @cert = (); |
148 my ($rc, $temp, $signature, $subject, $enddate); |
162 my ($rc, $temp, $signature, $subject, $enddate); |
149 |
163 |
150 # excluded files |
164 # excluded files |
151 @opt_exclude = split(/,/, join(',', @opt_exclude)) if @opt_exclude; |
165 # @opt_exclude = split(/,/, join(',', @opt_exclude)) if @opt_exclude; |
152 foreach my $exclude_file (@opt_exclude) { |
|
153 if ($exclude_file eq $File::Find::name) { |
|
154 $known{$File::Find::name} = $id; |
|
155 return; |
|
156 } |
|
157 } |
|
158 |
166 |
159 return |
167 return |
160 if exists $known{$File::Find::name} |
168 if exists $known{$File::Find::name} |
161 and $known{$File::Find::name} eq $id; |
169 and $known{$File::Find::name} eq $id; |
162 |
170 |
|
171 #say $File::Find::name; |
163 # checking for pkcs12 certificates |
172 # checking for pkcs12 certificates |
|
173 |
|
174 if (0) { |
164 my @cmd_pkcs12_current = @cmd_pkcs12; |
175 my @cmd_pkcs12_current = @cmd_pkcs12; |
165 push @cmd_pkcs12_current, "-in", $File::Find::name, "2>/dev/null"; |
176 push @cmd_pkcs12_current, "-in", $File::Find::name, "2>/dev/null"; |
166 |
|
167 my $cid = open(FILE, "@cmd_pkcs12_current |") || die "Can't fork: $!"; |
177 my $cid = open(FILE, "@cmd_pkcs12_current |") || die "Can't fork: $!"; |
168 |
178 |
169 while (<FILE>) { |
179 while (<FILE>) { |
170 /^$cid:error:.*/ and last; |
180 /^$cid:error:.*/ and last; |
171 $temp .= $_; |
181 $temp .= $_; |
194 push(@{ $certs{$File::Find::name} }, ($subject, $enddate, $signature)); |
204 push(@{ $certs{$File::Find::name} }, ($subject, $enddate, $signature)); |
195 |
205 |
196 $known{$File::Find::name} = $id if not($is_certificate); |
206 $known{$File::Find::name} = $id if not($is_certificate); |
197 return; |
207 return; |
198 } |
208 } |
199 |
209 } |
200 open(FILE, $File::Find::name) or die "can't open $_: $!"; |
210 |
201 |
211 open(FILE, $_) or die "can't open $File::Find::name: $!"; |
202 while (<FILE>) { |
212 my $file = join "", <FILE>; |
203 |
213 close(FILE); |
204 # cheking for x509 certificates |
214 |
205 if ($in_cert) { |
215 while ($file =~ /^(-+BEGIN CERTIFICATE.*?-+END CERTIFICATE-+)$/msg) { |
206 push @cert, $_; |
216 |
207 if (/^-----END CERTIFICATE-----$/) { |
217 # open filehandles (for read and write) |
208 $in_cert = 0; |
218 local (*READ, *WRITE); |
209 |
219 my $cid = open2(\*READ, \*WRITE, @cmd_x509) |
210 # open filehandles (for read and write) |
220 or die "Can' fork: $!\n"; |
211 local (*READ, *WRITE); |
221 print WRITE $1; |
212 my $cid = open2(\*READ, \*WRITE, @cmd_x509) |
222 close(WRITE); |
213 or die "Can' fork: $!\n"; |
223 |
214 print WRITE @cert; |
224 while (<READ>) { |
215 close(WRITE); |
225 /Signature\sAlgorithm:\s(.*)\s+$/ and $signature = $1; |
216 @cert = (); |
226 /^subject=\s+(.*)$/ and $subject = $1; |
217 |
227 /^notAfter=(.*)\s+$/ and $enddate = $1; |
218 while (<READ>) { |
228 } |
219 /Signature\sAlgorithm:\s(.*)\s+$/ and $signature = $1; |
229 close(READ); |
220 /^subject=\s+(.*)$/ and $subject = $1; |
230 |
221 /^notAfter=(.*)\s+$/ and $enddate = $1; |
231 waitpid($cid, 0) < 0 and die "no child with pid $cid\n"; |
222 } |
|
223 close(READ); |
|
224 |
|
225 # waiting for child processes |
|
226 do { |
|
227 $cid = waitpid(-1, WNOHANG); |
|
228 } while $cid > 0; |
|
229 |
232 |
230 if ($opt_debug) { |
233 if ($opt_debug) { |
231 print "-----\n"; |
234 print "-----\n"; |
232 print "$File::Find::name\n"; |
235 print "$File::Find::name\n"; |
233 print "Signature Algorithm: $signature\n" if ($signature); |
236 print "Signature Algorithm: $signature\n" if ($signature); |
237 |
240 |
238 push( |
241 push( |
239 @{ $certs{$File::Find::name} }, |
242 @{ $certs{$File::Find::name} }, |
240 ($subject, $enddate, $signature) |
243 ($subject, $enddate, $signature) |
241 ); |
244 ); |
242 $is_certificate = 1; |
245 |
243 next; |
246 $is_certificate = 1; |
244 } |
247 } |
245 } |
|
246 |
|
247 if (/^-----BEGIN CERTIFICATE-----$/) { |
|
248 $in_cert = 1; |
|
249 push @cert, $_; |
|
250 next; |
|
251 } |
|
252 } |
|
253 |
248 |
254 $known{$File::Find::name} = $id if not($is_certificate); |
249 $known{$File::Find::name} = $id if not($is_certificate); |
255 close(FILE); |
250 } |
256 } |
251 |
257 |
252 |
258 sub print_usage() { |
253 sub print_usage() { print $USAGE }; |
259 print "Usage:\n"; |
|
260 print |
|
261 " $ME [-b <binary>] [-i init] [-d <path>] [-w <time>] [-c <time>] [-s <signature algorithm>] [-e <file,file,file,...>]\n"; |
|
262 print " $ME [-h | --help]\n"; |
|
263 print " $ME [-V | --version]\n"; |
|
264 } |
|
265 |
254 |
266 sub print_help() { |
255 sub print_help() { |
267 print_revision($ME, $VERSION); |
256 print_revision($ME, $VERSION); |
268 print "Copyright (c) 2009 Christian Arnold\n\n"; |
257 print <<EOF; |
269 print "This plugin checks the expire date for openssl certificates.\n\n"; |
258 Copyright (c) 2009 Christian Arnold |
270 print_usage(); |
259 |
271 print "\n"; |
260 This plugin checks the expire date for openssl certificates. |
272 print " -b, --binary <binary>\n"; |
261 |
273 print " Path of openssl binary (default: /usr/bin/openssl)\n"; |
262 $USAGE |
274 print " -d, --directory <path>\n"; |
263 -b, --binary <binary> |
275 print |
264 Path of openssl binary (default: /usr/bin/openssl) |
276 " Absolute directory path in which will be recursively search for certificate files (default: /etc).\n"; |
265 -d, --directory <path> |
|
266 EOF |
|
267 |
|
268 print "Absolute directory path in which will be recursively search for certificate files (default: /etc).\n"; |
277 print " -w, --warning <time>\n"; |
269 print " -w, --warning <time>\n"; |
278 print |
270 print |
279 " Certificat should not be more than this time older (default: 1month).\n"; |
271 " Certificat should not be more than this time older (default: 1month).\n"; |
280 print |
272 print |
281 " For time can be used year, month, day, hour, minute, second and weeks.\n"; |
273 " For time can be used year, month, day, hour, minute, second and weeks.\n"; |