1 1.1 christos #! @PATH_PERL@ -w 2 1.1.1.4 christos # @configure_input 3 1.1 christos 4 1.1.1.3 christos # Copyright (C) 2015, 2017 Network Time Foundation 5 1.1 christos # Author: Harlan Stenn 6 1.1.1.3 christos # 7 1.1.1.3 christos # General cleanup and https support: Paul McMath 8 1.1.1.3 christos # 9 1.1 christos # Original shell version: 10 1.1 christos # Copyright (C) 2014 Timothe Litt litt at acm dot org 11 1.1.1.3 christos # 12 1.1 christos # This script may be freely copied, used and modified providing that 13 1.1 christos # this notice and the copyright statement are included in all copies 14 1.1 christos # and derivative works. No warranty is offered, and use is entirely at 15 1.1 christos # your own risk. Bugfixes and improvements would be appreciated by the 16 1.1 christos # author. 17 1.1 christos 18 1.1.1.3 christos ######## BEGIN ######### 19 1.1 christos use strict; 20 1.1 christos 21 1.1.1.3 christos # Core modules 22 1.1 christos use Digest::SHA qw(sha1_hex); 23 1.1.1.3 christos use File::Basename; 24 1.1 christos use File::Copy qw(move); 25 1.1.1.3 christos use File::Temp qw(tempfile); 26 1.1 christos use Getopt::Long qw(:config auto_help no_ignore_case bundling); 27 1.1.1.3 christos use Sys::Syslog qw(:standard :macros); 28 1.1 christos 29 1.1.1.3 christos # External modules 30 1.1.1.3 christos use HTTP::Tiny 0.056; 31 1.1.1.3 christos use Net::SSLeay 1.49; 32 1.1.1.3 christos use IO::Socket::SSL 1.56; 33 1.1.1.3 christos 34 1.1.1.3 christos my $VERSION = '1.004'; 35 1.1.1.3 christos 36 1.1.1.3 christos my $RUN_DIR = '/tmp'; 37 1.1.1.3 christos my $RUN_UID = 0; 38 1.1.1.3 christos my $TMP_FILE; 39 1.1.1.3 christos my $TMP_FH; 40 1.1.1.3 christos my $FILE_MODE = 0644; 41 1.1.1.3 christos 42 1.1.1.3 christos ######## DEFAULT CONFIGURATION ########## 43 1.1.1.3 christos # LEAP FILE SRC URIS 44 1.1.1.3 christos # HTTPS - (default) 45 1.1.1.3 christos # https://www.ietf.org/timezones/data/leap-seconds 46 1.1.1.3 christos # HTTP - No TLS/SSL - (not recommended) 47 1.1.1.3 christos # http://www.ietf.org/timezones/data/leap-seconds.list 48 1.1 christos 49 1.1.1.3 christos my $LEAPSRC = 'https://www.ietf.org/timezones/data/leap-seconds.list'; 50 1.1 christos my $LEAPFILE; 51 1.1 christos 52 1.1 christos # How many times to try to download new file 53 1.1.1.3 christos my $MAXTRIES = 6; 54 1.1.1.3 christos my $INTERVAL = 10; 55 1.1 christos 56 1.1.1.3 christos my $NTPCONF='/etc/ntp.conf'; 57 1.1 christos 58 1.1 christos # How long (in days) before expiration to get updated file 59 1.1.1.3 christos my $PREFETCH = 60; 60 1.1.1.3 christos my $EXPIRES; 61 1.1.1.3 christos my $FORCE; 62 1.1 christos 63 1.1.1.3 christos # Output Flags 64 1.1.1.3 christos my $QUIET; 65 1.1.1.3 christos my $DEBUG; 66 1.1.1.3 christos my $SYSLOG; 67 1.1.1.3 christos my $TOTERM; 68 1.1.1.3 christos my $LOGFAC = 'LOG_USER'; 69 1.1.1.3 christos 70 1.1.1.3 christos ######### PARSE/SET OPTIONS ######### 71 1.1.1.3 christos my %SSL_OPTS; 72 1.1.1.3 christos my %SSL_ATTRS = ( 73 1.1.1.3 christos verify_SSL => 1, 74 1.1.1.3 christos SSL_options => \%SSL_OPTS, 75 1.1.1.3 christos ); 76 1.1 christos 77 1.1.1.3 christos our(%opt); 78 1.1 christos 79 1.1.1.3 christos GetOptions(\%opt, 80 1.1.1.3 christos 'C=s', 81 1.1.1.3 christos 'D=s', 82 1.1.1.3 christos 'e:60', 83 1.1.1.3 christos 'F', 84 1.1.1.3 christos 'f=s', 85 1.1.1.3 christos 'h|help', 86 1.1.1.3 christos 'i:10', 87 1.1.1.3 christos 'L=s', 88 1.1.1.3 christos 'l=s', 89 1.1.1.3 christos 'q', 90 1.1.1.3 christos 'r:6', 91 1.1.1.3 christos 's', 92 1.1.1.3 christos 't', 93 1.1.1.3 christos 'u=s', 94 1.1.1.3 christos 'v', 95 1.1.1.3 christos ); 96 1.1 christos 97 1.1.1.3 christos $LOGFAC = $opt{l} if defined $opt{l}; 98 1.1.1.3 christos $LEAPSRC = $opt{u} if defined $opt{u}; 99 1.1.1.3 christos $LEAPFILE = $opt{L} if defined $opt{L}; 100 1.1.1.3 christos $PREFETCH = $opt{e} if defined $opt{e}; 101 1.1.1.3 christos $NTPCONF = $opt{f} if defined $opt{f}; 102 1.1.1.3 christos $MAXTRIES = $opt{r} if defined $opt{r}; 103 1.1.1.3 christos $INTERVAL = $opt{i} if defined $opt{i}; 104 1.1.1.3 christos 105 1.1.1.3 christos $FORCE = 1 if defined $opt{F}; 106 1.1.1.3 christos $DEBUG = 1 if defined $opt{v}; 107 1.1.1.3 christos $QUIET = 1 if defined $opt{q}; 108 1.1.1.3 christos $SYSLOG = 1 if defined $opt{s}; 109 1.1.1.3 christos $TOTERM = 1 if defined $opt{t}; 110 1.1.1.3 christos 111 1.1.1.3 christos $SSL_OPTS{SSL_ca_file} = $opt{C} if (defined($opt{C})); 112 1.1.1.3 christos $SSL_OPTS{SSL_ca_path} = $opt{D} if (defined($opt{D})); 113 1.1.1.3 christos 114 1.1.1.3 christos ############### 115 1.1.1.3 christos ## START MAIN 116 1.1.1.3 christos ############### 117 1.1.1.3 christos my $PROG = basename($0); 118 1.1.1.3 christos 119 1.1.1.3 christos # Logging - Default is to use syslog(3) if STDOUT isn't 120 1.1.1.3 christos # connected to a tty. 121 1.1.1.3 christos if ($SYSLOG || !-t STDOUT) { 122 1.1.1.3 christos $SYSLOG = 1; 123 1.1.1.3 christos openlog($PROG, 'pid', $LOGFAC); 124 1.1.1.3 christos } 125 1.1.1.3 christos else { 126 1.1.1.3 christos $TOTERM = 1; 127 1.1.1.3 christos } 128 1.1 christos 129 1.1.1.3 christos if (defined $opt{q} && defined $opt{v}) { 130 1.1.1.3 christos log_fatal(LOG_ERR, '-q and -v options mutually exclusive'); 131 1.1.1.3 christos } 132 1.1 christos 133 1.1.1.3 christos if (defined $opt{L} && defined $opt{f}) { 134 1.1.1.3 christos log_fatal(LOG_ERR, '-L and -f options mutually exclusive'); 135 1.1.1.3 christos } 136 1.1 christos 137 1.1.1.3 christos $SIG{INT} = \&signal_catcher; 138 1.1.1.3 christos $SIG{TERM} = \&signal_catcher; 139 1.1.1.3 christos $SIG{QUIT} = \&signal_catcher; 140 1.1.1.3 christos 141 1.1.1.3 christos # Take some security precautions 142 1.1.1.3 christos close STDIN; 143 1.1.1.3 christos 144 1.1.1.3 christos # Show help 145 1.1.1.3 christos if (defined $opt{h}) { 146 1.1.1.3 christos show_help(); 147 1.1.1.3 christos exit 0; 148 1.1.1.3 christos } 149 1.1 christos 150 1.1.1.3 christos if ($< != $RUN_UID) { 151 1.1.1.3 christos log_fatal(LOG_ERR, 'User ' . getpwuid($<) . " (UID $<) tried to run $PROG"); 152 1.1.1.3 christos } 153 1.1 christos 154 1.1.1.3 christos chdir $RUN_DIR || log_fatal("Failed to change dir to $RUN_DIR"); 155 1.1 christos 156 1.1.1.3 christos # Parse ntp.conf for path to leapfile if not set by user 157 1.1.1.3 christos if (! $LEAPFILE) { 158 1.1 christos 159 1.1.1.3 christos open my $LF, '<', $NTPCONF || log_fatal(LOG_ERR, "Can't open <$NTPCONF>: $!"); 160 1.1 christos 161 1.1.1.3 christos while (<$LF>) { 162 1.1.1.3 christos chomp; 163 1.1.1.3 christos $LEAPFILE = $1 if /^ *leapfile\s+"(\S+)"/; 164 1.1.1.3 christos } 165 1.1.1.3 christos close $LF; 166 1.1 christos 167 1.1.1.3 christos if (! $LEAPFILE) { 168 1.1.1.3 christos log_fatal(LOG_ERR, "No leapfile directive in $NTPCONF; leapfile location not known"); 169 1.1.1.3 christos } 170 1.1.1.3 christos } 171 1.1 christos 172 1.1.1.3 christos -s $LEAPFILE || logger(LOG_DEBUG, "Leapfile $LEAPFILE is empty"); 173 1.1 christos 174 1.1.1.3 christos # Download new file if: 175 1.1.1.3 christos # 1. file doesn't exist 176 1.1.1.3 christos # 2. invoked w/ force flag (-F) 177 1.1.1.3 christos # 3. current file isn't valid 178 1.1.1.3 christos # 4. current file expired or expires soon 179 1.1 christos 180 1.1.1.3 christos if ( !-e $LEAPFILE || $FORCE || ! verifySHA($LEAPFILE) || 181 1.1.1.3 christos ( $EXPIRES lt ( $PREFETCH * 86400 + time() ) )) { 182 1.1 christos 183 1.1.1.3 christos for (my $try = 1; $try <= $MAXTRIES; $try++) { 184 1.1.1.3 christos logger(LOG_DEBUG, "Attempting download from $LEAPSRC, try $try.."); 185 1.1 christos 186 1.1.1.3 christos ($TMP_FH, $TMP_FILE) = tempfile(UNLINK => 1, SUFFIX => '.list'); 187 1.1 christos 188 1.1.1.3 christos if (retrieve_file($TMP_FH)) { 189 1.1 christos 190 1.1.1.3 christos if ( verifySHA($TMP_FILE) ) { 191 1.1.1.3 christos move_file($TMP_FILE, $LEAPFILE); 192 1.1.1.3 christos chmod $FILE_MODE, $LEAPFILE; 193 1.1.1.3 christos logger(LOG_INFO, "Installed new $LEAPFILE from $LEAPSRC"); 194 1.1.1.3 christos } 195 1.1.1.3 christos else { 196 1.1.1.3 christos logger(LOG_ERR, "Downloaded file $TMP_FILE rejected -- saved for diagnosis"); 197 1.1.1.3 christos move_file($TMP_FILE, 'leap-seconds.list_corrupt'); 198 1.1.1.3 christos exit 1; 199 1.1.1.3 christos } 200 1.1.1.3 christos # Fall through 201 1.1.1.3 christos exit 0; 202 1.1.1.3 christos } 203 1.1.1.3 christos 204 1.1.1.3 christos # Failure 205 1.1.1.3 christos unlink $TMP_FILE; 206 1.1.1.3 christos logger(LOG_INFO, "Download failed. Waiting $INTERVAL minutes before retrying..."); 207 1.1.1.3 christos sleep $INTERVAL * 60 ; 208 1.1.1.3 christos } 209 1.1.1.3 christos 210 1.1.1.3 christos # Failed and out of retries 211 1.1.1.3 christos log_fatal(LOG_ERR, "Download from $LEAPSRC failed after $MAXTRIES attempts"); 212 1.1.1.3 christos } 213 1.1 christos 214 1.1.1.3 christos logger(LOG_INFO, "Not time to replace $LEAPFILE"); 215 1.1 christos 216 1.1.1.3 christos exit 0; 217 1.1 christos 218 1.1.1.3 christos ######## SUB ROUTINES ######### 219 1.1.1.3 christos sub move_file { 220 1.1 christos 221 1.1.1.3 christos (my $src, my $dst) = @_; 222 1.1.1.3 christos 223 1.1.1.3 christos if ( move($src, $dst) ) { 224 1.1.1.3 christos logger(LOG_DEBUG, "Moved $src to $dst"); 225 1.1.1.3 christos } 226 1.1.1.3 christos else { 227 1.1.1.3 christos log_fatal(LOG_ERR, "Moving $src to $dst failed: $!"); 228 1.1.1.3 christos } 229 1.1.1.3 christos } 230 1.1.1.3 christos 231 1.1.1.3 christos # Removes temp file if terminating signal recv'd 232 1.1.1.3 christos sub signal_catcher { 233 1.1.1.3 christos my $signame = shift; 234 1.1.1.3 christos 235 1.1.1.3 christos close $TMP_FH; 236 1.1.1.3 christos unlink $TMP_FILE; 237 1.1.1.3 christos log_fatal(LOG_INFO, "Recv'd SIG${signame}. Terminating."); 238 1.1.1.3 christos } 239 1.1.1.3 christos 240 1.1.1.3 christos sub log_fatal { 241 1.1.1.3 christos my ($p, $msg) = @_; 242 1.1.1.3 christos logger($p, $msg); 243 1.1.1.3 christos exit 1; 244 1.1.1.3 christos } 245 1.1 christos 246 1.1 christos sub logger { 247 1.1.1.3 christos my ($p, $msg) = @_; 248 1.1.1.3 christos 249 1.1.1.3 christos # Suppress LOG_DEBUG msgs unless $DEBUG set 250 1.1.1.3 christos return if (!$DEBUG && $p eq LOG_DEBUG); 251 1.1.1.3 christos 252 1.1.1.3 christos # Suppress all but LOG_ERR msgs if $QUIET set 253 1.1.1.3 christos return if ($QUIET && $p ne LOG_ERR); 254 1.1 christos 255 1.1.1.3 christos if ($TOTERM) { 256 1.1.1.3 christos if ($p eq LOG_ERR) { # errors should go to STDERR 257 1.1.1.3 christos print STDERR "$msg\n"; 258 1.1.1.3 christos } 259 1.1.1.3 christos else { 260 1.1.1.3 christos print STDOUT "$msg\n"; 261 1.1 christos } 262 1.1 christos } 263 1.1 christos 264 1.1.1.3 christos if ($SYSLOG) { 265 1.1.1.3 christos syslog($p, $msg) 266 1.1 christos } 267 1.1 christos } 268 1.1 christos 269 1.1.1.3 christos ################################# 270 1.1.1.3 christos # Connect to server and retrieve file 271 1.1.1.3 christos # 272 1.1.1.3 christos # Since we make as many as $MAXTRIES attempts to connect to the remote 273 1.1.1.3 christos # server to download the file, the network socket should be closed after 274 1.1.1.3 christos # each attempt, rather than let it be reused (because it may be in some 275 1.1.1.3 christos # unknown state). 276 1.1.1.3 christos # 277 1.1.1.3 christos # HTTP::Tiny doesn't export a method to explicitly close a connected 278 1.1.1.3 christos # socket, therefore, we instantiate the lexically scoped $http object in 279 1.1.1.3 christos # a function; when the function returns, the object goes out of scope 280 1.1.1.3 christos # and is destroyed, closing the socket. 281 1.1.1.3 christos sub retrieve_file { 282 1.1.1.3 christos 283 1.1.1.3 christos my $fh = shift; 284 1.1.1.3 christos my $http; 285 1.1.1.3 christos 286 1.1.1.3 christos if ($LEAPSRC =~ /^https\S+/) { 287 1.1.1.3 christos $http = HTTP::Tiny->new(%SSL_ATTRS); 288 1.1.1.3 christos (my $ok, my $why) = $http->can_ssl; 289 1.1.1.3 christos log_fatal(LOG_ERR, "TLS/SSL config error: $why") if ! $ok; 290 1.1.1.3 christos } 291 1.1.1.3 christos else { 292 1.1.1.3 christos $http = HTTP::Tiny->new(); 293 1.1.1.3 christos } 294 1.1.1.3 christos 295 1.1.1.3 christos my $reply = $http->get($LEAPSRC); 296 1.1.1.3 christos 297 1.1.1.3 christos if ($reply->{success}) { 298 1.1.1.3 christos logger(LOG_DEBUG, "Download of $LEAPSRC succeeded"); 299 1.1.1.3 christos print $fh $reply->{content} || 300 1.1.1.3 christos log_fatal(LOG_ERR, "Couldn't write new file contents to temp file: $!"); 301 1.1.1.3 christos close $fh; 302 1.1.1.3 christos return 1; 303 1.1.1.3 christos } 304 1.1.1.3 christos else { 305 1.1.1.3 christos close $fh; 306 1.1.1.3 christos return 0; 307 1.1.1.3 christos } 308 1.1.1.3 christos } 309 1.1 christos 310 1.1.1.3 christos ######################## 311 1.1 christos # Validate a leap-seconds file checksum 312 1.1 christos # 313 1.1.1.3 christos # File format: (full description in file) 314 1.1.1.3 christos # Pound sign (#) marks comments, EXCEPT: 315 1.1.1.3 christos # #$ number : the NTP date of the last update 316 1.1.1.3 christos # #@ number : the NTP date that the file expires 317 1.1.1.3 christos # #h hex hex hex hex hex : the SHA-1 checksum of the data & dates, 318 1.1.1.3 christos # excluding whitespace w/o leading zeroes 319 1.1.1.3 christos # 320 1.1.1.3 christos # Date (seconds since 1900) leaps : leaps is the # of seconds to add 321 1.1.1.3 christos # for times >= Date 322 1.1 christos # Date lines have comments. 323 1.1 christos # 324 1.1 christos # Returns: 325 1.1.1.3 christos # 0 Invalid Checksum/Expired 326 1.1.1.3 christos # 1 File is valid 327 1.1 christos 328 1.1 christos sub verifySHA { 329 1.1 christos 330 1.1.1.3 christos my $file = shift; 331 1.1.1.3 christos my $fh; 332 1.1.1.3 christos my $data; 333 1.1 christos my $FSHA; 334 1.1 christos 335 1.1.1.3 christos open $fh, '<', $file || log_fatal(LOG_ERR, "Can't open $file: $!"); 336 1.1.1.3 christos 337 1.1 christos # Remove comments, except those that are markers for last update, 338 1.1 christos # expires and hash 339 1.1.1.3 christos while (<$fh>) { 340 1.1 christos if (/^#\$/) { 341 1.1.1.3 christos s/^..//; 342 1.1.1.3 christos $data .= $_; 343 1.1 christos } 344 1.1 christos elsif (/^#\@/) { 345 1.1.1.3 christos s/^..//; 346 1.1.1.3 christos $data .= $_; 347 1.1.1.3 christos s/\s+//g; 348 1.1.1.3 christos $EXPIRES = $_ - 2208988800; 349 1.1 christos } 350 1.1 christos elsif (/^#h\s+([[:xdigit:]]+)\s+([[:xdigit:]]+)\s+([[:xdigit:]]+)\s+([[:xdigit:]]+)\s+([[:xdigit:]]+)/) { 351 1.1.1.3 christos chomp; 352 1.1.1.3 christos $FSHA = sprintf("%08s%08s%08s%08s%08s", $1, $2, $3, $4, $5); 353 1.1 christos } 354 1.1 christos elsif (/^#/) { 355 1.1.1.3 christos # ignore it 356 1.1 christos } 357 1.1 christos elsif (/^\d/) { 358 1.1.1.3 christos s/#.*$//; 359 1.1.1.3 christos $data .= $_; 360 1.1.1.3 christos } 361 1.1.1.3 christos else { 362 1.1.1.3 christos chomp; 363 1.1.1.3 christos print "Unexpected line: <$_>\n"; 364 1.1 christos } 365 1.1 christos } 366 1.1.1.3 christos close $fh; 367 1.1 christos 368 1.1 christos if ( $EXPIRES < time() ) { 369 1.1.1.3 christos logger(LOG_DEBUG, 'File expired on ' . gmtime($EXPIRES)); 370 1.1.1.3 christos return 0; 371 1.1 christos } 372 1.1 christos 373 1.1.1.3 christos if (! $FSHA) { 374 1.1.1.3 christos logger(LOG_NOTICE, "no checksum record found in file"); 375 1.1.1.3 christos return 0; 376 1.1 christos } 377 1.1 christos 378 1.1.1.3 christos # Remove all white space 379 1.1.1.3 christos $data =~ s/\s//g; 380 1.1 christos 381 1.1.1.3 christos # Compute the SHA hash of the data, removing the marker and filename 382 1.1.1.3 christos # Computed in binary mode, which shouldn't matter since whitespace has been removed 383 1.1.1.3 christos my $DSHA = sha1_hex($data); 384 1.1 christos 385 1.1.1.3 christos if ($FSHA eq $DSHA) { 386 1.1.1.3 christos logger(LOG_DEBUG, "Checksum of $file validated"); 387 1.1.1.3 christos return 1; 388 1.1.1.3 christos } 389 1.1.1.3 christos else { 390 1.1.1.3 christos logger(LOG_NOTICE, "Checksum of $file is invalid EXPECTED: $FSHA COMPUTED: $DSHA"); 391 1.1.1.3 christos return 0; 392 1.1 christos } 393 1.1 christos } 394 1.1 christos 395 1.1.1.3 christos sub show_help { 396 1.1.1.3 christos print <<EOF 397 1.1 christos 398 1.1.1.3 christos Usage: $PROG [options] 399 1.1 christos 400 1.1.1.3 christos Verifies and if necessary, updates leap-second definition file 401 1.1 christos 402 1.1.1.3 christos All arguments are optional: Default (or current value) shown: 403 1.1.1.3 christos -C Absolute path to CA Cert (see SSL/TLS Considerations) 404 1.1.1.3 christos -D Path to a CAdir (see SSL/TLS Considerations) 405 1.1.1.3 christos -e Specify how long (in days) before expiration the file is to be 406 1.1.1.3 christos refreshed. Note that larger values imply more frequent refreshes. 407 1.1.1.3 christos $PREFETCH 408 1.1.1.3 christos -F Force update even if current file is OK and not close to expiring. 409 1.1.1.3 christos -f Absolute path ntp.conf file (default /etc/ntp.conf) 410 1.1.1.3 christos $NTPCONF 411 1.1.1.3 christos -h show help 412 1.1.1.3 christos -i Specify number of minutes between retries 413 1.1.1.3 christos $INTERVAL 414 1.1.1.3 christos -L Absolute path to leapfile on the local system 415 1.1.1.3 christos (overrides value in ntp.conf) 416 1.1.1.3 christos -l Specify the syslog(3) facility for logging 417 1.1.1.3 christos $LOGFAC 418 1.1.1.3 christos -q Only report errors (cannot be used with -v) 419 1.1.1.3 christos -r Specify number of attempts to retrieve file 420 1.1.1.3 christos $MAXTRIES 421 1.1.1.3 christos -s Send output to syslog(3) - implied if STDOUT has no tty or redirected 422 1.1.1.3 christos -t Send output to terminal - implied if STDOUT attached to terminal 423 1.1.1.3 christos -u Specify the URL of the master copy to download 424 1.1.1.3 christos $LEAPSRC 425 1.1.1.3 christos -v Verbose - show debug messages (cannot be used with -q) 426 1.1 christos 427 1.1.1.3 christos The following options are not (yet) implemented in the perl version: 428 1.1.1.3 christos -4 Use only IPv4 429 1.1.1.3 christos -6 Use only IPv6 430 1.1.1.3 christos -c Command to restart NTP after installing a new file 431 1.1.1.3 christos <none> - ntpd checks file daily 432 1.1.1.3 christos -p 4|6 433 1.1.1.3 christos Prefer IPv4 or IPv6 (as specified) addresses, but use either 434 1.1 christos 435 1.1.1.3 christos $PROG will validate the file currently on the local system. 436 1.1 christos 437 1.1.1.3 christos Ordinarily, the leapfile is found using the 'leapfile' directive in 438 1.1.1.3 christos $NTPCONF. However, an alternate location can be specified on the 439 1.1.1.3 christos command line with the -L flag. 440 1.1.1.3 christos 441 1.1.1.3 christos If the leapfile does not exist, is not valid, has expired, or is 442 1.1.1.3 christos expiring soon, a new copy will be downloaded. If the new copy is 443 1.1.1.3 christos valid, it is installed. 444 1.1 christos 445 1.1.1.3 christos If the current file is acceptable, no download or restart occurs. 446 1.1 christos 447 1.1.1.3 christos This can be run as a cron job. As the file is rarely updated, and 448 1.1.1.3 christos leap seconds are announced at least one month in advance (usually 449 1.1.1.3 christos longer), it need not be run more frequently than about once every 450 1.1.1.3 christos three weeks. 451 1.1.1.3 christos 452 1.1.1.3 christos SSL/TLS Considerations 453 1.1.1.3 christos ----------------------- 454 1.1.1.3 christos The perl modules can usually locate the CA certificate used to verify 455 1.1.1.3 christos the peer's identity. 456 1.1.1.3 christos 457 1.1.1.3 christos On BSDs, the default is typically the file /etc/ssl/certs.pem. On 458 1.1.1.3 christos Linux, the location is typically a path to a CAdir - a directory of 459 1.1.1.3 christos symlinks named according to a hash of the certificates' subject names. 460 1.1.1.3 christos 461 1.1.1.3 christos The -C or -D options are available to pass in a location if no CA cert 462 1.1.1.3 christos is found in the default location. 463 1.1.1.3 christos 464 1.1.1.3 christos External Dependencies 465 1.1.1.3 christos --------------------- 466 1.1.1.3 christos The following perl modules are required: 467 1.1.1.3 christos HTTP::Tiny - version >= 0.056 468 1.1.1.3 christos IO::Socket::SSL - version >= 1.56 469 1.1.1.3 christos NET::SSLeay - version >= 1.49 470 1.1 christos 471 1.1.1.3 christos Version: $VERSION 472 1.1 christos 473 1.1.1.3 christos EOF 474 1.1 christos } 475 1.1 christos 476