Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Newer
Older
100755 675 lines (513 sloc) 17.318 kB
4e3ad0f Standardize on 'use warnings' instead of -w as -w spills into everyth…
Jeremy Mates authored
1 #!/usr/bin/perl
9f97362 Initial work on expiration date handling script.
Jeremy Mates authored
2 #
907f524 Documentation cleanups, other random fixes.
Jeremy Mates authored
3 # Expiration date checker and handler. Supports x509 certificates, and
4 # anything a wrapper script can be written for. Run perldoc(1) on this
5 # script for additional documentation.
9f97362 Initial work on expiration date handling script.
Jeremy Mates authored
6 #
7 # The author disclaims all copyrights and releases this script into the
8 # public domain.
9
10 use strict;
4e3ad0f Standardize on 'use warnings' instead of -w as -w spills into everyth…
Jeremy Mates authored
11 use warnings;
9f97362 Initial work on expiration date handling script.
Jeremy Mates authored
12
2900692 Add preferences file support and mostly complete handling for expired,
Jeremy Mates authored
13 use Config::General qw(ParseConfig);
9f97362 Initial work on expiration date handling script.
Jeremy Mates authored
14 use Date::Parse qw(str2time);
907f524 Documentation cleanups, other random fixes.
Jeremy Mates authored
15 use File::Basename qw(basename);
9f97362 Initial work on expiration date handling script.
Jeremy Mates authored
16 use File::Temp qw(tempfile);
907f524 Documentation cleanups, other random fixes.
Jeremy Mates authored
17 use Getopt::Std;
9f97362 Initial work on expiration date handling script.
Jeremy Mates authored
18
228b2c9 Check STDOUT at exit to catch errors (perldoc perlopentut).
Jeremy Mates authored
19 END {
20 # Report problems when writing to stdout (perldoc perlopentut)
21 unless ( close(STDOUT) ) {
b8966ec Standardize on sysexits.h codes for most things. Other tweaks.
Jeremy Mates authored
22 warn "error: problem closing STDOUT: $!\n";
23 exit 74;
228b2c9 Check STDOUT at exit to catch errors (perldoc perlopentut).
Jeremy Mates authored
24 }
25 }
26
8a3615a Better action handling, use table instead of symbol table mucking. Read
Jeremy Mates authored
27 my $basename = basename($0);
28
4021bc7 Use %lookup to hold parameters for template expansion, now
Jeremy Mates authored
29 my %program_param = ( name => $basename, argv => "@ARGV", pid => $$ );
9f97362 Initial work on expiration date handling script.
Jeremy Mates authored
30
4021bc7 Use %lookup to hold parameters for template expansion, now
Jeremy Mates authored
31 # list different modes of operation (subroutine that obtains expiration
32 # date and other metadata from an external command/code)
6c95e24 Make actions proper subroutines, and move below main code.
Jeremy Mates authored
33 my %actions = (
34 certificate => \&action_certificate,
35 openssl_x509 => \&action_openssl_x509,
36 );
8a3615a Better action handling, use table instead of symbol table mucking. Read
Jeremy Mates authored
37 my @actions = sort keys %actions;
9f97362 Initial work on expiration date handling script.
Jeremy Mates authored
38
39 my %opts;
2900692 Add preferences file support and mostly complete handling for expired,
Jeremy Mates authored
40 getopts 'h?l:c:f:', \%opts;
a1b4393 Added duration2second parsing routine, -e option to pass in a global
Jeremy Mates authored
41
8a3615a Better action handling, use table instead of symbol table mucking. Read
Jeremy Mates authored
42 if ( exists $opts{l} ) {
43 print "@actions\n";
84fad9e Use do_exit() to handle exit values, in event need to adjust the exit
Jeremy Mates authored
44 do_exit(0);
8a3615a Better action handling, use table instead of symbol table mucking. Read
Jeremy Mates authored
45 }
9f97362 Initial work on expiration date handling script.
Jeremy Mates authored
46
47 if ( exists $opts{h} or exists $opts{'?'} or not @ARGV ) {
48 print_help();
b8966ec Standardize on sysexits.h codes for most things. Other tweaks.
Jeremy Mates authored
49 do_exit(64);
9f97362 Initial work on expiration date handling script.
Jeremy Mates authored
50 }
51
2900692 Add preferences file support and mostly complete handling for expired,
Jeremy Mates authored
52 my %config = ParseConfig( -ConfigFile => $opts{f}, -LowerCaseNames => 1 );
1a8f8ce Revert to simpler version.
Jeremy Mates authored
53 if ( !defined $config{class} ) {
a331c16 Added parse_tokens to deal with quoted data for exec and pipe handlers:
Jeremy Mates authored
54 remark(
55 'error',
56 'no classes defined in configuration',
57 { file => $opts{f} }
58 );
b8966ec Standardize on sysexits.h codes for most things. Other tweaks.
Jeremy Mates authored
59 do_exit(78);
a331c16 Added parse_tokens to deal with quoted data for exec and pipe handlers:
Jeremy Mates authored
60 }
8a3615a Better action handling, use table instead of symbol table mucking. Read
Jeremy Mates authored
61
62 my $op_mode = shift || q{};
9f97362 Initial work on expiration date handling script.
Jeremy Mates authored
63 $op_mode =~ tr/-/_/;
64
8a3615a Better action handling, use table instead of symbol table mucking. Read
Jeremy Mates authored
65 if ( !exists $actions{$op_mode} ) {
66 remark( 'error', 'unknown mode',
67 { allowed => join( q{,}, @actions ), mode => $op_mode } );
68 print_help();
b8966ec Standardize on sysexits.h codes for most things. Other tweaks.
Jeremy Mates authored
69 do_exit(78);
8a3615a Better action handling, use table instead of symbol table mucking. Read
Jeremy Mates authored
70 }
71
2900692 Add preferences file support and mostly complete handling for expired,
Jeremy Mates authored
72 # where in the prefs to read expire, window handlers from
73 my $report_handler = exists $opts{c} ? $opts{c} : 'default';
8f2136b Additional File::AtomicWrite migration and better temp file handling.
Jeremy Mates authored
74 my $report_ref = $config{class}->{$report_handler};
2900692 Add preferences file support and mostly complete handling for expired,
Jeremy Mates authored
75
a331c16 Added parse_tokens to deal with quoted data for exec and pipe handlers:
Jeremy Mates authored
76 if ( !defined $report_ref ) {
77 remark(
78 'error',
79 'class preferences not found',
80 { class => $report_handler, file => $opts{f} }
81 );
b8966ec Standardize on sysexits.h codes for most things. Other tweaks.
Jeremy Mates authored
82 do_exit(78);
a331c16 Added parse_tokens to deal with quoted data for exec and pipe handlers:
Jeremy Mates authored
83 }
84
1a8f8ce Revert to simpler version.
Jeremy Mates authored
85 # lookup expiration date and other info via mode handler
86 my ( %time_param, %extra_param );
87 {
88 my ( $time_ref, $extra_ref ) = $actions{$op_mode}->(@ARGV);
89 if ( !defined $time_ref or !defined $time_ref->{expire_epoch} ) {
90 remark( 'error', 'no expire date found' );
b8966ec Standardize on sysexits.h codes for most things. Other tweaks.
Jeremy Mates authored
91 do_exit(78);
1a8f8ce Revert to simpler version.
Jeremy Mates authored
92 }
93 @time_param{ keys %$time_ref } = values %$time_ref;
94 @extra_param{ keys %$extra_ref } = values %$extra_ref;
95 }
96 $time_param{cur_epoch} = time;
97
98 my %lookup = (
99 time => \%time_param,
100 extra => \%extra_param,
101 program => \%program_param
102 );
103
104 # check whether expired, or if within a window
105 if ( $time_param{expire_epoch} <= $time_param{cur_epoch} ) {
106
107 # TODO fill out more parameters (humanized time? strftime, parameters
108 # about the certificate, and etc.? - see what need for reporting)
109 # seconds_ago => $cur_epoch - $expire_epoch,
110 handle_condition( $report_ref->{expired}, \%lookup );
111
112 die "error: expired handler did not exit script\n";
113 }
114
115 if ( exists $report_ref->{window} ) {
116 my @windows;
117
118 if ( ref $report_ref->{window} eq 'HASH' ) {
119 my %tmp = %{ $report_ref->{window} };
120 delete $report_ref->{window};
121 $report_ref->{window}->[0] = \%tmp;
122 } elsif ( ref $report_ref->{window} ne 'ARRAY' ) {
123 remark(
124 'error',
125 'unexpected reference type for window',
126 { ref => ref $report_ref->{window}, file => $opts{f} }
127 );
b8966ec Standardize on sysexits.h codes for most things. Other tweaks.
Jeremy Mates authored
128 do_exit(78);
1a8f8ce Revert to simpler version.
Jeremy Mates authored
129 }
130
131 # build Windows to look at (sanity checks, duration conversion)
132 # TODO include window timevalue in time_param hash
133 for my $window_ref ( @{ $report_ref->{window} } ) {
134 if ( !exists $window_ref->{inside} ) {
135 remark( 'error', 'skipping window without date setting' );
136 next;
137 }
138 $window_ref->{inside_sec} = duration2seconds( $window_ref->{inside} );
139 push @windows, $window_ref;
140 }
141
142 for
143 my $window_ref ( sort { $a->{inside_sec} <=> $b->{inside_sec} } @windows )
144 {
145
146 if ( $time_param{expire_epoch} <=
147 ( $time_param{cur_epoch} + $window_ref->{inside_sec} ) ) {
148
149 # TODO seconds_left => $expire_epoch - $cur_epoch,
150 handle_condition( $window_ref, \%lookup );
151
152 die "error: window handler did not exit script\n";
153 }
154 }
155 }
156
157 if ( exists $report_ref->{default} ) {
158 # TODO seconds_left => $expire_epoch - $cur_epoch,
159 handle_condition( $report_ref->{default}, \%lookup );
160
161 die "error: default handler did not exit script\n";
162 } else {
163 # if no default, exit, assuming an implicit default exit
164 do_exit(0);
165 }
2900692 Add preferences file support and mostly complete handling for expired,
Jeremy Mates authored
166
6c95e24 Make actions proper subroutines, and move below main code.
Jeremy Mates authored
167 # Mode to parse for expiration date using 'openssl x509' (certificate)
168 sub action_openssl_x509 {
169 my @x509_arguments = @_;
170
171 my @command =
172 ( qw{openssl x509 -noout -dates -subject -issuer}, @x509_arguments );
173
174 my $results = get_output(@command);
175 if ( !defined $results ) {
84fad9e Use do_exit() to handle exit values, in event need to adjust the exit
Jeremy Mates authored
176 remark( 'error', 'no output returned', { command => "@command" } );
b8966ec Standardize on sysexits.h codes for most things. Other tweaks.
Jeremy Mates authored
177 do_exit(70);
6c95e24 Make actions proper subroutines, and move below main code.
Jeremy Mates authored
178 }
179
180 my ( %time_param, %cert_param );
181 for my $line (@$results) {
182 if ( $line =~ m/^notAfter=(.+)/ ) {
183 $time_param{expire_epoch} = date_openssl2epoch($1)
184 if !exists $time_param{expire_epoch};
185 next;
186 }
187 if ( $line =~ m/^notBefore=(.+)/ ) {
188 $time_param{start_epoch} = date_openssl2epoch($1)
189 if !exists $time_param{start_epoch};
190 next;
191 }
192 if ( $line =~ m/^subject\s*=\s*(.+)/ ) {
193 $cert_param{subject} = $1 if !exists $cert_param{subject};
194 next;
195 }
196 if ( $line =~ m/^issuer\s*=\s*(.+)/ ) {
197 $cert_param{issuer} = $1 if !exists $cert_param{issuer};
198 next;
199 }
200 }
201
202 if ( !exists $time_param{expire_epoch} ) {
203 return;
204 }
205
206 return \%time_param, \%cert_param;
207 }
208
209 # runs a command that should return a certificate to stdout that
210 # 'openssl x509' can then parse for information
211 sub action_certificate {
212 my @command = @_;
213 my $results = get_output(@command);
214 if ( !defined $results ) {
84fad9e Use do_exit() to handle exit values, in event need to adjust the exit
Jeremy Mates authored
215 remark( 'error', 'no output returned', { command => "@command" } );
b8966ec Standardize on sysexits.h codes for most things. Other tweaks.
Jeremy Mates authored
216 do_exit(70);
6c95e24 Make actions proper subroutines, and move below main code.
Jeremy Mates authored
217 }
218
8f2136b Additional File::AtomicWrite migration and better temp file handling.
Jeremy Mates authored
219 my ( $tmp_fh, $filename );
220 eval { ( $tmp_fh, $filename ) = tempfile(); };
221
222 local $SIG{TERM} = sub { close $tmp_fh; unlink $filename };
223
224 if ( $@ or !defined $tmp_fh ) {
225 remark(
226 'error',
227 'no temporary file created',
228 ( $@ ? do { chomp $@; { errstr => $@ } } : {} )
229 );
b8966ec Standardize on sysexits.h codes for most things. Other tweaks.
Jeremy Mates authored
230 do_exit(73);
84fad9e Use do_exit() to handle exit values, in event need to adjust the exit
Jeremy Mates authored
231 }
8f2136b Additional File::AtomicWrite migration and better temp file handling.
Jeremy Mates authored
232
6c95e24 Make actions proper subroutines, and move below main code.
Jeremy Mates authored
233 for my $line (@$results) {
234 print $tmp_fh $line;
235 }
8f2136b Additional File::AtomicWrite migration and better temp file handling.
Jeremy Mates authored
236 close $tmp_fh;
6c95e24 Make actions proper subroutines, and move below main code.
Jeremy Mates authored
237
238 return $actions{openssl_x509}->( '-in', $filename );
239 }
240
2900692 Add preferences file support and mostly complete handling for expired,
Jeremy Mates authored
241 # parses handler prefs from under config, figures out what to do...
242 sub handle_condition {
243 my $handle_ref = shift;
4021bc7 Use %lookup to hold parameters for template expansion, now
Jeremy Mates authored
244 my $lookup_ref = shift;
2900692 Add preferences file support and mostly complete handling for expired,
Jeremy Mates authored
245
a331c16 Added parse_tokens to deal with quoted data for exec and pipe handlers:
Jeremy Mates authored
246 # handlers must exit, default to 0 if unset
afa4770 Catch missing handers with die(). Default to 0 for exit_value in
Jeremy Mates authored
247 if ( !exists $handle_ref->{exit_value} ) {
248 $handle_ref->{exit_value} = 0;
2900692 Add preferences file support and mostly complete handling for expired,
Jeremy Mates authored
249 }
250
afa4770 Catch missing handers with die(). Default to 0 for exit_value in
Jeremy Mates authored
251 my %handlers = (
a331c16 Added parse_tokens to deal with quoted data for exec and pipe handlers:
Jeremy Mates authored
252 # runs a command, such as logger(1)
afa4770 Catch missing handers with die(). Default to 0 for exit_value in
Jeremy Mates authored
253 exec => sub {
4021bc7 Use %lookup to hold parameters for template expansion, now
Jeremy Mates authored
254 my $cmd_str = shift;
255 my $lookup_ref = shift;
afa4770 Catch missing handers with die(). Default to 0 for exit_value in
Jeremy Mates authored
256
a331c16 Added parse_tokens to deal with quoted data for exec and pipe handlers:
Jeremy Mates authored
257 my @command = parse_tokens($cmd_str);
afa4770 Catch missing handers with die(). Default to 0 for exit_value in
Jeremy Mates authored
258 for my $part (@command) {
4021bc7 Use %lookup to hold parameters for template expansion, now
Jeremy Mates authored
259 $part =~
260 s/ (?<!\\) %{ ([^.]+) \. ([^}]+) } / $lookup_ref->{$1}->{$2} || '' /egx;
afa4770 Catch missing handers with die(). Default to 0 for exit_value in
Jeremy Mates authored
261 $part =~ s/(\\.)/qq("$1")/eeg;
262 }
263
264 my $status = system @command;
265 if ( $status != 0 ) {
266 remark(
267 'warning',
268 'command failed',
269 { command => "@command", errno => $? }
270 );
271 }
272
273 return;
274 },
a331c16 Added parse_tokens to deal with quoted data for exec and pipe handlers:
Jeremy Mates authored
275 # like exec, but takes first token as standard input to the program
276 # (to support sending data to things like mail(1))
afa4770 Catch missing handers with die(). Default to 0 for exit_value in
Jeremy Mates authored
277 pipe => sub {
4021bc7 Use %lookup to hold parameters for template expansion, now
Jeremy Mates authored
278 my $cmd_str = shift;
279 my $lookup_ref = shift;
afa4770 Catch missing handers with die(). Default to 0 for exit_value in
Jeremy Mates authored
280
1867cab Improved pipe support: no need to quote lines before the |.
Jeremy Mates authored
281 # standard input everything before first unbackwhacked |
282 my ( $stdin, $cmd_tmp ) = split /\s*(?<!\\)\|\s*/, $cmd_str, 2;
afa4770 Catch missing handers with die(). Default to 0 for exit_value in
Jeremy Mates authored
283
1218072 Apply template expansion to standard input to pipe.
Jeremy Mates authored
284 $stdin =~
285 s/ (?<!\\) %{ ([^.]+) \. ([^}]+) } / $lookup_ref->{$1}->{$2} || '' /egx;
d4f30a2 Another bugfix.
Jeremy Mates authored
286 $stdin =~ s/(\\.)/qq("$1")/eeg;
1218072 Apply template expansion to standard input to pipe.
Jeremy Mates authored
287
288 my @command;
1867cab Improved pipe support: no need to quote lines before the |.
Jeremy Mates authored
289 for my $part ( parse_tokens($cmd_tmp) ) {
4021bc7 Use %lookup to hold parameters for template expansion, now
Jeremy Mates authored
290 $part =~
291 s/ (?<!\\) %{ ([^.]+) \. ([^}]+) } / $lookup_ref->{$1}->{$2} || '' /egx;
afa4770 Catch missing handers with die(). Default to 0 for exit_value in
Jeremy Mates authored
292 $part =~ s/(\\.)/qq("$1")/eeg;
1867cab Improved pipe support: no need to quote lines before the |.
Jeremy Mates authored
293 push @command, $part;
4021bc7 Use %lookup to hold parameters for template expansion, now
Jeremy Mates authored
294 }
afa4770 Catch missing handers with die(). Default to 0 for exit_value in
Jeremy Mates authored
295
907f524 Documentation cleanups, other random fixes.
Jeremy Mates authored
296 my $cmd_fh;
297 open $cmd_fh, '|-' or exec @command or return;
298 print $cmd_fh $stdin;
299 close $cmd_fh;
afa4770 Catch missing handers with die(). Default to 0 for exit_value in
Jeremy Mates authored
300
301 return;
302 },
a331c16 Added parse_tokens to deal with quoted data for exec and pipe handlers:
Jeremy Mates authored
303 # print to standard output
afa4770 Catch missing handers with die(). Default to 0 for exit_value in
Jeremy Mates authored
304 stdout => sub {
305 my $output_str = shift;
4021bc7 Use %lookup to hold parameters for template expansion, now
Jeremy Mates authored
306 my $lookup_ref = shift;
afa4770 Catch missing handers with die(). Default to 0 for exit_value in
Jeremy Mates authored
307
4021bc7 Use %lookup to hold parameters for template expansion, now
Jeremy Mates authored
308 $output_str =~
309 s/ (?<!\\) %{ ([^.]+) \. ([^}]+) } / $lookup_ref->{$1}->{$2} || '' /egx;
afa4770 Catch missing handers with die(). Default to 0 for exit_value in
Jeremy Mates authored
310 $output_str =~ s/(\\.)/qq("$1")/eeg;
311 print "$output_str\n";
312
313 return;
314 }
315 );
316
f0ab617 Properly handle preferences file with single window instance. Perltidy.
Jeremy Mates authored
317 for my $handle ( sort keys %handlers ) {
afa4770 Catch missing handers with die(). Default to 0 for exit_value in
Jeremy Mates authored
318 if ( exists $handle_ref->{$handle} ) {
319 if ( ref $handle_ref->{$handle} eq 'ARRAY' ) {
320 for my $item ( @{ $handle_ref->{$handle} } ) {
4021bc7 Use %lookup to hold parameters for template expansion, now
Jeremy Mates authored
321 $handlers{$handle}->( $item, $lookup_ref );
afa4770 Catch missing handers with die(). Default to 0 for exit_value in
Jeremy Mates authored
322 }
323 } else {
4021bc7 Use %lookup to hold parameters for template expansion, now
Jeremy Mates authored
324 $handlers{$handle}->( $handle_ref->{$handle}, $lookup_ref );
afa4770 Catch missing handers with die(). Default to 0 for exit_value in
Jeremy Mates authored
325 }
326 }
2900692 Add preferences file support and mostly complete handling for expired,
Jeremy Mates authored
327 }
a1b4393 Added duration2second parsing routine, -e option to pass in a global
Jeremy Mates authored
328
1a8f8ce Revert to simpler version.
Jeremy Mates authored
329 do_exit( $handle_ref->{exit_value} );
afa4770 Catch missing handers with die(). Default to 0 for exit_value in
Jeremy Mates authored
330 }
9f97362 Initial work on expiration date handling script.
Jeremy Mates authored
331
a331c16 Added parse_tokens to deal with quoted data for exec and pipe handlers:
Jeremy Mates authored
332 # converts a string into a list of tokens
333 sub parse_tokens {
334 my $string = shift;
335 my @tokens;
336
337 UBLE: {
338 # non-quoted strings, backslashed quotes and whitespace allowed
339 push( @tokens, $1 ), redo UBLE if $string =~ m/ \G ( [^"'\s]+ ) \s* /cgx;
340
341 # double-quoted strings, backslashed quotes allowed
342 push( @tokens, $1 ), redo UBLE
343 if $string =~ m/ \G " ((?: \\.|[^\\"] )+) " \s* /cgx;
344
345 push( @tokens, $1 ), redo UBLE
346 if $string =~ m/ \G ' ((?: \\.|[^\\'] )+) ' \s* /cgx;
347
348 last UBLE if $string =~ / \G $ /gcx;
349
84fad9e Use do_exit() to handle exit values, in event need to adjust the exit
Jeremy Mates authored
350 remark( 'error', 'unparseable token in string', { data => $string } );
b8966ec Standardize on sysexits.h codes for most things. Other tweaks.
Jeremy Mates authored
351 do_exit(78);
a331c16 Added parse_tokens to deal with quoted data for exec and pipe handlers:
Jeremy Mates authored
352 }
353
354 return @tokens;
355 }
356
9f97362 Initial work on expiration date handling script.
Jeremy Mates authored
357 sub date_openssl2epoch {
358 my $date = shift;
359
360 my $time = str2time($date);
361 return $time;
362 }
363
8a3615a Better action handling, use table instead of symbol table mucking. Read
Jeremy Mates authored
364 # takes command to run (and optional leading hashref with parameters),
365 # returns filehandle (or undef on error) with STDOUT of program
9f97362 Initial work on expiration date handling script.
Jeremy Mates authored
366 sub get_output {
367 my $param = {};
368 if ( @_ and ref $_[0] eq 'HASH' ) {
369 $param = { %$param, %{ $_[0] } };
370 shift @_;
371 }
372
373 my @command = @_;
374 return unless @command;
375
376 #remark( 'debug', 'command run', { command => "@command" } );
377
378 my $timeout = $param->{timeout} || 60;
379
8a3615a Better action handling, use table instead of symbol table mucking. Read
Jeremy Mates authored
380 my @results;
9f97362 Initial work on expiration date handling script.
Jeremy Mates authored
381
382 eval {
383 local $SIG{ALRM} = sub { die "alarm\n" };
384
385 alarm $timeout;
386
907f524 Documentation cleanups, other random fixes.
Jeremy Mates authored
387 my $output_fh;
388 open $output_fh, '-|' or exec @command or die "exec error\n";
389 @results = <$output_fh>;
390 close $output_fh;
9f97362 Initial work on expiration date handling script.
Jeremy Mates authored
391
392 alarm 0;
393 };
394 if ($@) {
8a3615a Better action handling, use table instead of symbol table mucking. Read
Jeremy Mates authored
395 my $error_str =
396 $@ eq "alarm\n" ? 'command timed out'
397 : $@ eq "exec error\n" ? undef
8f2136b Additional File::AtomicWrite migration and better temp file handling.
Jeremy Mates authored
398 : 'unexpected command error';
8a3615a Better action handling, use table instead of symbol table mucking. Read
Jeremy Mates authored
399
400 if ( defined $error_str ) {
9f97362 Initial work on expiration date handling script.
Jeremy Mates authored
401 chomp $@;
8a3615a Better action handling, use table instead of symbol table mucking. Read
Jeremy Mates authored
402 remark( 'error', $error_str, { command => "@command", errno => $@ } );
9f97362 Initial work on expiration date handling script.
Jeremy Mates authored
403 }
404 }
405
8a3615a Better action handling, use table instead of symbol table mucking. Read
Jeremy Mates authored
406 return @results ? \@results : undef;
9f97362 Initial work on expiration date handling script.
Jeremy Mates authored
407 }
408
a1b4393 Added duration2second parsing routine, -e option to pass in a global
Jeremy Mates authored
409 sub duration2seconds {
410 my $tmpdur = shift;
411 my $seconds;
412
413 # how to convert short human durations into seconds
414 my %factor = (
8a3615a Better action handling, use table instead of symbol table mucking. Read
Jeremy Mates authored
415 y => 31536000,
a1b4393 Added duration2second parsing routine, -e option to pass in a global
Jeremy Mates authored
416 w => 604800,
417 d => 86400,
418 h => 3600,
419 m => 60,
420 s => 1,
421 );
422
423 # assume raw seconds for plain number
424 if ( $tmpdur =~ m/^\d+$/ ) {
425 $seconds = $tmpdur * 60;
426
8a3615a Better action handling, use table instead of symbol table mucking. Read
Jeremy Mates authored
427 } elsif ( $tmpdur =~ m/^[ywdhms\d\s]+$/ ) {
a1b4393 Added duration2second parsing routine, -e option to pass in a global
Jeremy Mates authored
428
429 # match "2m 5s" style input and convert to seconds
8a3615a Better action handling, use table instead of symbol table mucking. Read
Jeremy Mates authored
430 while ( $tmpdur =~ m/(\d+)\s*([ywdhms])/g ) {
a1b4393 Added duration2second parsing routine, -e option to pass in a global
Jeremy Mates authored
431 $seconds += $1 * $factor{$2};
432 }
433 } else {
84fad9e Use do_exit() to handle exit values, in event need to adjust the exit
Jeremy Mates authored
434 remark( 'error', 'unknown characters in duration', { data => $tmpdur } );
b8966ec Standardize on sysexits.h codes for most things. Other tweaks.
Jeremy Mates authored
435 do_exit(78);
a1b4393 Added duration2second parsing routine, -e option to pass in a global
Jeremy Mates authored
436 }
437
438 unless ( defined $seconds and $seconds =~ m/^\d+$/ ) {
84fad9e Use do_exit() to handle exit values, in event need to adjust the exit
Jeremy Mates authored
439 remark( 'error', 'unable to parse duration', { data => $tmpdur } );
b8966ec Standardize on sysexits.h codes for most things. Other tweaks.
Jeremy Mates authored
440 do_exit(78);
a1b4393 Added duration2second parsing routine, -e option to pass in a global
Jeremy Mates authored
441 }
442
443 return $seconds;
444 }
445
84fad9e Use do_exit() to handle exit values, in event need to adjust the exit
Jeremy Mates authored
446 # Wrapper for exit values, in case need to alter them under particular
447 # monitoring systems. Script uses 100+ for various error conditions.
448 sub do_exit {
449 my $exit_value = shift;
450
451 exit $exit_value;
452 }
453
9f97362 Initial work on expiration date handling script.
Jeremy Mates authored
454 sub remark {
455 my $priority = shift;
456 my $message = shift;
457 my $attributes = shift;
458
459 chomp $message;
460
461 my $attr_str;
462 if ($attributes) {
463 $attr_str = join ', ',
464 map { $attributes->{$_} ||= q{}; "$_=$attributes->{$_}" }
465 sort keys %$attributes;
466 }
467
468 print STDERR "$priority: $message"
469 . ( $attr_str ? ": $attr_str" : q{} ) . "\n";
470 return 1;
471 }
472
473 sub print_help {
474 print <<"END_USAGE";
e9a90b1 Added POD, updated print_help output, leading description.
Jeremy Mates authored
475 Usage: $basename -f prefs [options] mode [arguments]
9f97362 Initial work on expiration date handling script.
Jeremy Mates authored
476
477 Expiration date handler.
478
479 Options:
480 -h/-? Display this message.
e9a90b1 Added POD, updated print_help output, leading description.
Jeremy Mates authored
481
482 -f pp Read preferences file from pp.
483
484 -c cc Specify custom class to read from preferences file.
485
486 -l List supported modes and exit.
9f97362 Initial work on expiration date handling script.
Jeremy Mates authored
487
488 Run perldoc(1) on this script for additional documentation.
489
490 END_USAGE
491 return;
492 }
8a3615a Better action handling, use table instead of symbol table mucking. Read
Jeremy Mates authored
493
4021bc7 Use %lookup to hold parameters for template expansion, now
Jeremy Mates authored
494 __END__
e9a90b1 Added POD, updated print_help output, leading description.
Jeremy Mates authored
495
496 =head1 NAME
497
498 check-expire - expiration date checker and handler
499
500 =head1 SYNOPSIS
501
502 Check the certificate on C<www.example.org:443>, and handle the expired
503 or near-expired certificate via options in the C<prefs> configuration
504 file:
505
506 $ check-expire -f prefs certificate check-web www.example.org:443
507
508 Where the C<check-web> wrapper outputs the certificate via:
509
510 #!/bin/sh
511 echo GET / HTTP/1.0 | openssl s_client -connect "$1" 2>&1
512
00f1efe Added openssl-x509 usage example.
Jeremy Mates authored
513 Directly accessible certificate files can be checked via:
514
515 $ check-expire -f prefs openssl-x509 -in /path/to/some.cert
516
e9a90b1 Added POD, updated print_help output, leading description.
Jeremy Mates authored
517 =head1 DESCRIPTION
518
519 =head2 Overview
520
521 Checks expiration dates on data like x509 certificates. Uses preferences
522 to handle expired certificates, or configurable actions should the
523 expiration date be inside a particular time window. Requires wrapper
524 scripts to obtain the certificate or expiration date to parse.
525
526 =head2 Normal Usage
527
528 $ check-expire -f prefs mode [mode options]
529
530 See L<"OPTIONS"> for details on the command line switches supported.
531
532 =head1 OPTIONS
533
534 This script currently supports the following command line switches.
535 Arguments following the C<mode> will vary.
536
537 =over 4
538
539 =item B<-h>, B<-?>
540
541 Prints a brief usage note about the script.
542
543 =item B<-f> I<prefs>
544
545 Read handling preferences from the I<prefs> file. See L<"FILES"> for
546 configuration details.
547
548 =item B<-c> I<class>
549
550 Specify a custom handling class, otherwise set to C<default>. The class
551 is read from the preferences file, see L<"FILES"> for details.
552
553 =item B<-l>
554
555 List allowed modes to standard output and exit.
556
557 =back
558
559 =head1 FILES
560
4021bc7 Use %lookup to hold parameters for template expansion, now
Jeremy Mates authored
561 The preferences file specifies how to handle expiration dates. See below
562 for an example. At minimum, a named C<class> block should be created
563 with the name C<default>. This block should contain rules to handle
564 different conditions: C<expired> will be called if the data is expired,
565 followed by any C<window> blocks, ordered to process the shortest
566 durations first. If none match, a C<default> hander is called.
567
568 The first matching handler block will exit the script, with an
569 C<exit_value> of zero, unless a different C<exit_value> is set.
570
571 Blocks can include C<stdout> to print output, C<exec> to run named
572 commands, C<pipe> to send input to a named command, and C<exit_value> to
573 change the exit status of C<check-expire>. Aruguments to these options
574 can template information about the certificate and other data (see the
575 example below for the syntax, and the source for available parameters).
576
577 C<exec> and C<pipe> must be commands to run, not shell statements. If
578 shell code is needed, write a wrapper script, and execute that.
579
580 C<window> handlers must include a single C<inside> statement followed by
581 a duration in sections, or a shorthand duration such as C<7d>.
582
583 The following outputs values read by SiteScope. For expired or near-
584 expired data, errors are raised in SiteScope via the higher return
585 codes. Data expiring inside a month generates an e-mail, but no
586 SiteScope error.
e9a90b1 Added POD, updated print_help output, leading description.
Jeremy Mates authored
587
a331c16 Added parse_tokens to deal with quoted data for exec and pipe handlers:
Jeremy Mates authored
588 <class default>
589 # default handler used if nothing else matches
590 <default>
591 stdout "Return Code: 0"
592 </default>
e9a90b1 Added POD, updated print_help output, leading description.
Jeremy Mates authored
593
4021bc7 Use %lookup to hold parameters for template expansion, now
Jeremy Mates authored
594 # higher return code if expiring inside 7 days, e-mail warnings
a331c16 Added parse_tokens to deal with quoted data for exec and pipe handlers:
Jeremy Mates authored
595 <window>
596 inside 7d
e9a90b1 Added POD, updated print_help output, leading description.
Jeremy Mates authored
597
a331c16 Added parse_tokens to deal with quoted data for exec and pipe handlers:
Jeremy Mates authored
598 stdout "Return Code: 1"
599 exit_value 1
4021bc7 Use %lookup to hold parameters for template expansion, now
Jeremy Mates authored
600
1867cab Improved pipe support: no need to quote lines before the |.
Jeremy Mates authored
601 pipe expiring soon: %{extra.subject} | /bin/mail -s "cert warning" root
a331c16 Added parse_tokens to deal with quoted data for exec and pipe handlers:
Jeremy Mates authored
602 </window>
e9a90b1 Added POD, updated print_help output, leading description.
Jeremy Mates authored
603
4021bc7 Use %lookup to hold parameters for template expansion, now
Jeremy Mates authored
604 # just warn via e-mail if expiring inside 30 days
a331c16 Added parse_tokens to deal with quoted data for exec and pipe handlers:
Jeremy Mates authored
605 <window>
606 inside 30d
e9a90b1 Added POD, updated print_help output, leading description.
Jeremy Mates authored
607
a331c16 Added parse_tokens to deal with quoted data for exec and pipe handlers:
Jeremy Mates authored
608 stdout "Return Code: 0"
1867cab Improved pipe support: no need to quote lines before the |.
Jeremy Mates authored
609 pipe expiring soon: %{extra.subject} | /bin/mail -s "cert warning" root
a331c16 Added parse_tokens to deal with quoted data for exec and pipe handlers:
Jeremy Mates authored
610 </window>
4021bc7 Use %lookup to hold parameters for template expansion, now
Jeremy Mates authored
611
612 # handler for expired data (equal to or past expiration date)
613 <expired>
614 exec /usr/bin/logger expired certificate: subject=%{extra.subject}
615
616 pipe <<END_PIPE
1867cab Improved pipe support: no need to quote lines before the |.
Jeremy Mates authored
617 Expired certificate:
618 subject=%{extra.subject}
619 expired=%{time.expire_epoch}
9c2316a POD template bugfix.
Jeremy Mates authored
620 command=%{program.name} %{program.argv}
4021bc7 Use %lookup to hold parameters for template expansion, now
Jeremy Mates authored
621 | /bin/mail -s "expired cert" root
622 END_PIPE
623
624 stdout "Return Code: 2"
625 exit_value 2
626 </expired>
627
a331c16 Added parse_tokens to deal with quoted data for exec and pipe handlers:
Jeremy Mates authored
628 </class>
e9a90b1 Added POD, updated print_help output, leading description.
Jeremy Mates authored
629
630 See L<Config::General|Config::General> for details on the configuration
631 file format.
632
633 =head1 BUGS
634
635 =head2 Reporting Bugs
636
637 Newer versions of this script may be available from:
638
98564d5 Replace sial.org/code links with github links.
Jeremy Mates authored
639 http://github.com/thrig/sial.org-scripts/tree/master
e9a90b1 Added POD, updated print_help output, leading description.
Jeremy Mates authored
640
641 If the bug is in the latest version, send a report to the author.
642 Patches that fix problems or add new features are welcome.
643
644 =head2 Known Issues
645
646 No known issues.
647
4021bc7 Use %lookup to hold parameters for template expansion, now
Jeremy Mates authored
648 =head1 TODO
649
650 Mode handler for key=value output from a program, to facilitate
651 interface scripts to other arbitrary systems.
652
653 More metadata in %lookup (with modifying %lookup too much once doing
654 tests!), for humanized dates, time durations, and other details.
655
656 Document usage under Nagios or other interfaces.
657
658 Read things to check from preferences file and loop over, instead of
659 needing a different command run for each thing to check?
660
e9a90b1 Added POD, updated print_help output, leading description.
Jeremy Mates authored
661 =head1 SEE ALSO
662
663 perl(1), s_client(1), x509(1)
664
665 =head1 AUTHOR
666
3967523 Remove URL.
Jeremy Mates authored
667 Jeremy Mates
e9a90b1 Added POD, updated print_help output, leading description.
Jeremy Mates authored
668
669 =head1 COPYRIGHT
670
671 The author disclaims all copyrights and releases this script into the
672 public domain.
673
674 =cut
Something went wrong with that request. Please try again.