1 /* 2 * ntp_leapsec.c - leap second processing for NTPD 3 * 4 * Written by Juergen Perlinger (perlinger@ntp.org) for the NTP project. 5 * The contents of 'html/copyright.html' apply. 6 * ---------------------------------------------------------------------- 7 * This is an attempt to get the leap second handling into a dedicated 8 * module to make the somewhat convoluted logic testable. 9 */ 10 11 #include <config.h> 12 #include <sys/types.h> 13 #include <sys/stat.h> 14 #include <ctype.h> 15 16 #include "ntp.h" 17 #include "ntp_stdlib.h" 18 #include "ntp_calendar.h" 19 #include "ntp_leapsec.h" 20 #include "vint64ops.h" 21 22 #include "isc/sha1.h" 23 24 static const char * const logPrefix = "leapsecond file"; 25 26 /* --------------------------------------------------------------------- 27 * Our internal data structure 28 */ 29 #define MAX_HIST 10 /* history of leap seconds */ 30 31 struct leap_info { 32 vint64 ttime; /* transition time (after the step, ntp scale) */ 33 uint32_t stime; /* schedule limit (a month before transition) */ 34 int16_t taiof; /* TAI offset on and after the transition */ 35 uint8_t dynls; /* dynamic: inserted on peer/clock request */ 36 }; 37 typedef struct leap_info leap_info_t; 38 39 struct leap_head { 40 vint64 update; /* time of information update */ 41 vint64 expire; /* table expiration time */ 42 uint16_t size; /* number of infos in table */ 43 int16_t base_tai; /* total leaps before first entry */ 44 int16_t this_tai; /* current TAI offset */ 45 int16_t next_tai; /* TAI offset after 'when' */ 46 vint64 dtime; /* due time (current era end) */ 47 vint64 ttime; /* nominal transition time (next era start) */ 48 vint64 stime; /* schedule time (when we take notice) */ 49 vint64 ebase; /* base time of this leap era */ 50 uint8_t dynls; /* next leap is dynamic (by peer request) */ 51 }; 52 typedef struct leap_head leap_head_t; 53 54 struct leap_table { 55 leap_signature_t lsig; 56 leap_head_t head; 57 leap_info_t info[MAX_HIST]; 58 }; 59 60 /* Where we store our tables */ 61 static leap_table_t _ltab[2], *_lptr; 62 static int/*BOOL*/ _electric; 63 64 /* Forward decls of local helpers */ 65 static int add_range (leap_table_t *, const leap_info_t *); 66 static char * get_line (leapsec_reader, void *, char *, 67 size_t); 68 static inline char * skipws (char *ptr); 69 static int parsefail (const char *cp, const char *ep); 70 static void reload_limits (leap_table_t *, const vint64 *); 71 static void fetch_leap_era (leap_era_t *, const leap_table_t *, 72 const vint64 *); 73 static int betweenu32 (u_int32, u_int32, u_int32); 74 static void reset_times (leap_table_t *); 75 static int leapsec_add (leap_table_t *, const vint64 *, int); 76 static int leapsec_raw (leap_table_t *, const vint64 *, int, 77 int); 78 static const char * lstostr (const vint64 *ts); 79 80 /* ===================================================================== 81 * Get & Set the current leap table 82 */ 83 84 /* ------------------------------------------------------------------ */ 85 leap_table_t * 86 leapsec_get_table( 87 int alternate) 88 { 89 leap_table_t *p1, *p2; 90 91 p1 = _lptr; 92 if (p1 == &_ltab[0]) { 93 p2 = &_ltab[1]; 94 } else if (p1 == &_ltab[1]) { 95 p2 = &_ltab[0]; 96 } else { 97 p1 = &_ltab[0]; 98 p2 = &_ltab[1]; 99 reset_times(p1); 100 reset_times(p2); 101 _lptr = p1; 102 } 103 if (alternate) { 104 memcpy(p2, p1, sizeof(leap_table_t)); 105 p1 = p2; 106 } 107 108 return p1; 109 } 110 111 /* ------------------------------------------------------------------ */ 112 int/*BOOL*/ 113 leapsec_set_table( 114 leap_table_t * pt) 115 { 116 if (pt == &_ltab[0] || pt == &_ltab[1]) 117 _lptr = pt; 118 return _lptr == pt; 119 } 120 121 /* ------------------------------------------------------------------ */ 122 int/*BOOL*/ 123 leapsec_electric( 124 int/*BOOL*/ on) 125 { 126 int res = _electric; 127 if (on < 0) 128 return res; 129 130 _electric = (on != 0); 131 if (_electric == res) 132 return res; 133 134 if (_lptr == &_ltab[0] || _lptr == &_ltab[1]) 135 reset_times(_lptr); 136 137 return res; 138 } 139 140 /* ===================================================================== 141 * API functions that operate on tables 142 */ 143 144 /* --------------------------------------------------------------------- 145 * Clear all leap second data. Use it for init & cleanup 146 */ 147 void 148 leapsec_clear( 149 leap_table_t * pt) 150 { 151 memset(&pt->lsig, 0, sizeof(pt->lsig)); 152 memset(&pt->head, 0, sizeof(pt->head)); 153 reset_times(pt); 154 } 155 156 /* --------------------------------------------------------------------- 157 * Load a leap second file and check expiration on the go 158 */ 159 int/*BOOL*/ 160 leapsec_load( 161 leap_table_t * pt, 162 leapsec_reader func, 163 void * farg, 164 int use_build_limit 165 ) 166 { 167 char *cp, *ep, *endp, linebuf[50]; 168 vint64 ttime, limit; 169 long taiof; 170 struct calendar build; 171 172 leapsec_clear(pt); 173 if (use_build_limit && ntpcal_get_build_date(&build)) { 174 /* don't prune everything -- permit the last 10yrs 175 * before build. 176 */ 177 build.year -= 10; 178 limit = ntpcal_date_to_ntp64(&build); 179 } else { 180 memset(&limit, 0, sizeof(limit)); 181 } 182 183 while (get_line(func, farg, linebuf, sizeof(linebuf))) { 184 cp = linebuf; 185 if (*cp == '#') { 186 cp++; 187 if (*cp == '@') { 188 cp = skipws(cp+1); 189 pt->head.expire = strtouv64(cp, &ep, 10); 190 if (parsefail(cp, ep)) 191 goto fail_read; 192 pt->lsig.etime = pt->head.expire.D_s.lo; 193 } else if (*cp == '$') { 194 cp = skipws(cp+1); 195 pt->head.update = strtouv64(cp, &ep, 10); 196 if (parsefail(cp, ep)) 197 goto fail_read; 198 } 199 } else if (isdigit((u_char)*cp)) { 200 ttime = strtouv64(cp, &ep, 10); 201 if (parsefail(cp, ep)) 202 goto fail_read; 203 cp = skipws(ep); 204 taiof = strtol(cp, &endp, 10); 205 if ( parsefail(cp, endp) 206 || taiof > INT16_MAX || taiof < INT16_MIN) 207 goto fail_read; 208 if (ucmpv64(&ttime, &limit) >= 0) { 209 if (!leapsec_raw(pt, &ttime, 210 taiof, FALSE)) 211 goto fail_insn; 212 } else { 213 pt->head.base_tai = (int16_t)taiof; 214 } 215 pt->lsig.ttime = ttime.D_s.lo; 216 pt->lsig.taiof = (int16_t)taiof; 217 } 218 } 219 return TRUE; 220 221 fail_read: 222 errno = EILSEQ; 223 fail_insn: 224 leapsec_clear(pt); 225 return FALSE; 226 } 227 228 /* --------------------------------------------------------------------- 229 * Dump a table in human-readable format. Use 'fprintf' and a FILE 230 * pointer if you want to get it printed into a stream. 231 */ 232 void 233 leapsec_dump( 234 const leap_table_t * pt , 235 leapsec_dumper func, 236 void * farg) 237 { 238 int idx; 239 vint64 ts; 240 struct calendar atb, ttb; 241 242 ntpcal_ntp64_to_date(&ttb, &pt->head.expire); 243 (*func)(farg, "leap table (%u entries) expires at %04u-%02u-%02u:\n", 244 pt->head.size, 245 ttb.year, ttb.month, ttb.monthday); 246 idx = pt->head.size; 247 while (idx-- != 0) { 248 ts = pt->info[idx].ttime; 249 ntpcal_ntp64_to_date(&ttb, &ts); 250 ts = subv64u32(&ts, pt->info[idx].stime); 251 ntpcal_ntp64_to_date(&atb, &ts); 252 253 (*func)(farg, "%04u-%02u-%02u [%c] (%04u-%02u-%02u) - %d\n", 254 ttb.year, ttb.month, ttb.monthday, 255 "-*"[pt->info[idx].dynls != 0], 256 atb.year, atb.month, atb.monthday, 257 pt->info[idx].taiof); 258 } 259 } 260 261 /* ===================================================================== 262 * usecase driven API functions 263 */ 264 265 int/*BOOL*/ 266 leapsec_query( 267 leap_result_t * qr , 268 uint32_t ts32 , 269 const time_t * pivot) 270 { 271 leap_table_t * pt; 272 vint64 ts64, last, next; 273 uint32_t due32; 274 int fired; 275 276 /* preset things we use later on... */ 277 fired = FALSE; 278 ts64 = ntpcal_ntp_to_ntp(ts32, pivot); 279 pt = leapsec_get_table(FALSE); 280 memset(qr, 0, sizeof(leap_result_t)); 281 282 if (ucmpv64(&ts64, &pt->head.ebase) < 0) { 283 /* Most likely after leap frame reset. Could also be a 284 * backstep of the system clock. Anyway, get the new 285 * leap era frame. 286 */ 287 reload_limits(pt, &ts64); 288 } else if (ucmpv64(&ts64, &pt->head.dtime) >= 0) { 289 /* Boundary crossed in forward direction. This might 290 * indicate a leap transition, so we prepare for that 291 * case. 292 * 293 * Some operations below are actually NOPs in electric 294 * mode, but having only one code path that works for 295 * both modes is easier to maintain. 296 * 297 * There's another quirk we must keep looking out for: 298 * If we just stepped the clock, the step might have 299 * crossed a leap boundary. As with backward steps, we 300 * do not want to raise the 'fired' event in that case. 301 * So we raise the 'fired' event only if we're close to 302 * the transition and just reload the limits otherwise. 303 */ 304 last = addv64i32(&pt->head.dtime, 3); /* get boundary */ 305 if (ucmpv64(&ts64, &last) >= 0) { 306 /* that was likely a query after a step */ 307 reload_limits(pt, &ts64); 308 } else { 309 /* close enough for deeper examination */ 310 last = pt->head.ttime; 311 qr->warped = (int16_t)(last.D_s.lo - 312 pt->head.dtime.D_s.lo); 313 next = addv64i32(&ts64, qr->warped); 314 reload_limits(pt, &next); 315 fired = ucmpv64(&pt->head.ebase, &last) == 0; 316 if (fired) { 317 ts64 = next; 318 ts32 = next.D_s.lo; 319 } else { 320 qr->warped = 0; 321 } 322 } 323 } 324 325 qr->tai_offs = pt->head.this_tai; 326 qr->ebase = pt->head.ebase; 327 qr->ttime = pt->head.ttime; 328 329 /* If before the next scheduling alert, we're done. */ 330 if (ucmpv64(&ts64, &pt->head.stime) < 0) 331 return fired; 332 333 /* now start to collect the remaining data */ 334 due32 = pt->head.dtime.D_s.lo; 335 336 qr->tai_diff = pt->head.next_tai - pt->head.this_tai; 337 qr->ddist = due32 - ts32; 338 qr->dynamic = pt->head.dynls; 339 qr->proximity = LSPROX_SCHEDULE; 340 341 /* if not in the last day before transition, we're done. */ 342 if (!betweenu32(due32 - SECSPERDAY, ts32, due32)) 343 return fired; 344 345 qr->proximity = LSPROX_ANNOUNCE; 346 if (!betweenu32(due32 - 10, ts32, due32)) 347 return fired; 348 349 /* The last 10s before the transition. Prepare for action! */ 350 qr->proximity = LSPROX_ALERT; 351 return fired; 352 } 353 354 /* ------------------------------------------------------------------ */ 355 int/*BOOL*/ 356 leapsec_query_era( 357 leap_era_t * qr , 358 uint32_t ntpts, 359 const time_t * pivot) 360 { 361 const leap_table_t * pt; 362 vint64 ts64; 363 364 pt = leapsec_get_table(FALSE); 365 ts64 = ntpcal_ntp_to_ntp(ntpts, pivot); 366 fetch_leap_era(qr, pt, &ts64); 367 return TRUE; 368 } 369 370 /* ------------------------------------------------------------------ */ 371 int/*BOOL*/ 372 leapsec_frame( 373 leap_result_t *qr) 374 { 375 const leap_table_t * pt; 376 377 memset(qr, 0, sizeof(leap_result_t)); 378 pt = leapsec_get_table(FALSE); 379 380 qr->tai_offs = pt->head.this_tai; 381 qr->tai_diff = pt->head.next_tai - pt->head.this_tai; 382 qr->ebase = pt->head.ebase; 383 qr->ttime = pt->head.ttime; 384 qr->dynamic = pt->head.dynls; 385 386 return ucmpv64(&pt->head.ttime, &pt->head.stime) >= 0; 387 } 388 389 /* ------------------------------------------------------------------ */ 390 /* Reset the current leap frame */ 391 void 392 leapsec_reset_frame(void) 393 { 394 reset_times(leapsec_get_table(FALSE)); 395 } 396 397 /* ------------------------------------------------------------------ */ 398 /* load a file from a FILE pointer. Note: If vhash is true, load 399 * only after successful signature check. The stream must be seekable 400 * or this will fail. 401 */ 402 int/*BOOL*/ 403 leapsec_load_stream( 404 FILE * ifp , 405 const char * fname, 406 int/*BOOL*/ logall, 407 int/*BOOL*/ vhash) 408 { 409 leap_table_t *pt; 410 int rcheck; 411 412 if (NULL == fname) 413 fname = "<unknown>"; 414 415 if (vhash) { 416 rcheck = leapsec_validate((leapsec_reader)&getc, ifp); 417 if (logall) 418 switch (rcheck) 419 { 420 case LSVALID_GOODHASH: 421 msyslog(LOG_NOTICE, "%s ('%s'): good hash signature", 422 logPrefix, fname); 423 break; 424 425 case LSVALID_NOHASH: 426 msyslog(LOG_ERR, "%s ('%s'): no hash signature", 427 logPrefix, fname); 428 break; 429 case LSVALID_BADHASH: 430 msyslog(LOG_ERR, "%s ('%s'): signature mismatch", 431 logPrefix, fname); 432 break; 433 case LSVALID_BADFORMAT: 434 msyslog(LOG_ERR, "%s ('%s'): malformed hash signature", 435 logPrefix, fname); 436 break; 437 default: 438 msyslog(LOG_ERR, "%s ('%s'): unknown error code %d", 439 logPrefix, fname, rcheck); 440 break; 441 } 442 if (rcheck < 0) 443 return FALSE; 444 rewind(ifp); 445 } 446 pt = leapsec_get_table(TRUE); 447 if (!leapsec_load(pt, (leapsec_reader)getc, ifp, TRUE)) { 448 switch (errno) { 449 case EINVAL: 450 msyslog(LOG_ERR, "%s ('%s'): bad transition time", 451 logPrefix, fname); 452 break; 453 case ERANGE: 454 msyslog(LOG_ERR, "%s ('%s'): times not ascending", 455 logPrefix, fname); 456 break; 457 default: 458 msyslog(LOG_ERR, "%s ('%s'): parsing error", 459 logPrefix, fname); 460 break; 461 } 462 return FALSE; 463 } 464 465 if (pt->head.size) 466 msyslog(LOG_NOTICE, "%s ('%s'): loaded, expire=%s last=%s ofs=%d", 467 logPrefix, fname, lstostr(&pt->head.expire), 468 lstostr(&pt->info[0].ttime), pt->info[0].taiof); 469 else 470 msyslog(LOG_NOTICE, 471 "%s ('%s'): loaded, expire=%s ofs=%d (no entries after build date)", 472 logPrefix, fname, lstostr(&pt->head.expire), 473 pt->head.base_tai); 474 475 return leapsec_set_table(pt); 476 } 477 478 /* ------------------------------------------------------------------ */ 479 int/*BOOL*/ 480 leapsec_load_file( 481 const char * fname, 482 struct stat * sb_old, 483 int/*BOOL*/ force, 484 int/*BOOL*/ logall, 485 int/*BOOL*/ vhash) 486 { 487 FILE * fp; 488 struct stat sb_new; 489 int rc; 490 491 /* just do nothing if there is no leap file */ 492 if ( !(fname && *fname) ) 493 return FALSE; 494 495 /* try to stat the leapfile */ 496 if (0 != stat(fname, &sb_new)) { 497 if (logall) 498 msyslog(LOG_ERR, "%s ('%s'): stat failed: %m", 499 logPrefix, fname); 500 return FALSE; 501 } 502 503 /* silently skip to postcheck if no new file found */ 504 if (NULL != sb_old) { 505 if (!force 506 && sb_old->st_mtime == sb_new.st_mtime 507 && sb_old->st_ctime == sb_new.st_ctime 508 ) 509 return FALSE; 510 *sb_old = sb_new; 511 } 512 513 /* try to open the leap file, complain if that fails 514 * 515 * [perlinger@ntp.org] 516 * coverity raises a TOCTOU (time-of-check/time-of-use) issue 517 * here, which is not entirely helpful: While there is indeed a 518 * possible race condition between the 'stat()' call above and 519 * the 'fopen)' call below, I intentionally want to omit the 520 * overhead of opening the file and calling 'fstat()', because 521 * in most cases the file would have be to closed anyway without 522 * reading the contents. I chose to disable the coverity 523 * warning instead. 524 * 525 * So unless someone comes up with a reasonable argument why 526 * this could be a real issue, I'll just try to silence coverity 527 * on that topic. 528 */ 529 /* coverity[toctou] */ 530 if ((fp = fopen(fname, "r")) == NULL) { 531 if (logall) 532 msyslog(LOG_ERR, 533 "%s ('%s'): open failed: %m", 534 logPrefix, fname); 535 return FALSE; 536 } 537 538 rc = leapsec_load_stream(fp, fname, logall, vhash); 539 fclose(fp); 540 return rc; 541 } 542 543 /* ------------------------------------------------------------------ */ 544 void 545 leapsec_getsig( 546 leap_signature_t * psig) 547 { 548 const leap_table_t * pt; 549 550 pt = leapsec_get_table(FALSE); 551 memcpy(psig, &pt->lsig, sizeof(leap_signature_t)); 552 } 553 554 /* ------------------------------------------------------------------ */ 555 int/*BOOL*/ 556 leapsec_expired( 557 uint32_t when, 558 const time_t * tpiv) 559 { 560 const leap_table_t * pt; 561 vint64 limit; 562 563 pt = leapsec_get_table(FALSE); 564 limit = ntpcal_ntp_to_ntp(when, tpiv); 565 return ucmpv64(&limit, &pt->head.expire) >= 0; 566 } 567 568 /* ------------------------------------------------------------------ */ 569 int32_t 570 leapsec_daystolive( 571 uint32_t when, 572 const time_t * tpiv) 573 { 574 const leap_table_t * pt; 575 vint64 limit; 576 577 pt = leapsec_get_table(FALSE); 578 limit = ntpcal_ntp_to_ntp(when, tpiv); 579 limit = subv64(&pt->head.expire, &limit); 580 return ntpcal_daysplit(&limit).hi; 581 } 582 583 /* ------------------------------------------------------------------ */ 584 #if 0 /* currently unused -- possibly revived later */ 585 int/*BOOL*/ 586 leapsec_add_fix( 587 int total, 588 uint32_t ttime, 589 uint32_t etime, 590 const time_t * pivot) 591 { 592 time_t tpiv; 593 leap_table_t * pt; 594 vint64 tt64, et64; 595 596 if (pivot == NULL) { 597 time(&tpiv); 598 pivot = &tpiv; 599 } 600 601 et64 = ntpcal_ntp_to_ntp(etime, pivot); 602 tt64 = ntpcal_ntp_to_ntp(ttime, pivot); 603 pt = leapsec_get_table(TRUE); 604 605 if ( ucmpv64(&et64, &pt->head.expire) <= 0 606 || !leapsec_raw(pt, &tt64, total, FALSE) ) 607 return FALSE; 608 609 pt->lsig.etime = etime; 610 pt->lsig.ttime = ttime; 611 pt->lsig.taiof = (int16_t)total; 612 613 pt->head.expire = et64; 614 615 return leapsec_set_table(pt); 616 } 617 #endif 618 619 /* ------------------------------------------------------------------ */ 620 int/*BOOL*/ 621 leapsec_add_dyn( 622 int insert, 623 uint32_t ntpnow, 624 const time_t * pivot ) 625 { 626 leap_table_t * pt; 627 vint64 now64; 628 629 pt = leapsec_get_table(TRUE); 630 now64 = ntpcal_ntp_to_ntp(ntpnow, pivot); 631 return ( leapsec_add(pt, &now64, (insert != 0)) 632 && leapsec_set_table(pt)); 633 } 634 635 /* ------------------------------------------------------------------ */ 636 int/*BOOL*/ 637 leapsec_autokey_tai( 638 int tai_offset, 639 uint32_t ntpnow , 640 const time_t * pivot ) 641 { 642 leap_table_t * pt; 643 leap_era_t era; 644 vint64 now64; 645 int idx; 646 647 (void)tai_offset; 648 pt = leapsec_get_table(FALSE); 649 650 /* Bail out if the basic offset is not zero and the putative 651 * offset is bigger than 10s. That was in 1972 -- we don't want 652 * to go back that far! 653 */ 654 if (pt->head.base_tai != 0 || tai_offset < 10) 655 return FALSE; 656 657 /* If there's already data in the table, check if an update is 658 * possible. Update is impossible if there are static entries 659 * (since this indicates a valid leapsecond file) or if we're 660 * too close to a leapsecond transition: We do not know on what 661 * side the transition the sender might have been, so we use a 662 * dead zone around the transition. 663 */ 664 665 /* Check for static entries */ 666 for (idx = 0; idx != pt->head.size; idx++) 667 if ( ! pt->info[idx].dynls) 668 return FALSE; 669 670 /* get the fulll time stamp and leap era for it */ 671 now64 = ntpcal_ntp_to_ntp(ntpnow, pivot); 672 fetch_leap_era(&era, pt, &now64); 673 674 /* check the limits with 20s dead band */ 675 era.ebase = addv64i32(&era.ebase, 20); 676 if (ucmpv64(&now64, &era.ebase) < 0) 677 return FALSE; 678 679 era.ttime = addv64i32(&era.ttime, -20); 680 if (ucmpv64(&now64, &era.ttime) > 0) 681 return FALSE; 682 683 /* Here we can proceed. Calculate the delta update. */ 684 tai_offset -= era.taiof; 685 686 /* Shift the header info offsets. */ 687 pt->head.base_tai += tai_offset; 688 pt->head.this_tai += tai_offset; 689 pt->head.next_tai += tai_offset; 690 691 /* Shift table entry offsets (if any) */ 692 for (idx = 0; idx != pt->head.size; idx++) 693 pt->info[idx].taiof += tai_offset; 694 695 /* claim success... */ 696 return TRUE; 697 } 698 699 700 /* ===================================================================== 701 * internal helpers 702 */ 703 704 /* [internal] Reset / init the time window in the leap processor to 705 * force reload on next query. Since a leap transition cannot take place 706 * at an odd second, the value chosen avoids spurious leap transition 707 * triggers. Making all three times equal forces a reload. Using the 708 * maximum value for unsigned 64 bits makes finding the next leap frame 709 * a bit easier. 710 */ 711 static void 712 reset_times( 713 leap_table_t * pt) 714 { 715 memset(&pt->head.ebase, 0xFF, sizeof(vint64)); 716 pt->head.stime = pt->head.ebase; 717 pt->head.ttime = pt->head.ebase; 718 pt->head.dtime = pt->head.ebase; 719 } 720 721 /* [internal] Add raw data to the table, removing old entries on the 722 * fly. This cannot fail currently. 723 */ 724 static int/*BOOL*/ 725 add_range( 726 leap_table_t * pt, 727 const leap_info_t * pi) 728 { 729 /* If the table is full, make room by throwing out the oldest 730 * entry. But remember the accumulated leap seconds! 731 * 732 * Setting the first entry is a bit tricky, too: Simply assuming 733 * it is an insertion is wrong if the first entry is a dynamic 734 * leap second removal. So we decide on the sign -- if the first 735 * entry has a negative offset, we assume that it is a leap 736 * second removal. In both cases the table base offset is set 737 * accordingly to reflect the decision. 738 * 739 * In practice starting with a removal can only happen if the 740 * first entry is a dynamic request without having a leap file 741 * for the history proper. 742 */ 743 if (pt->head.size == 0) { 744 if (pi->taiof >= 0) 745 pt->head.base_tai = pi->taiof - 1; 746 else 747 pt->head.base_tai = pi->taiof + 1; 748 } else if (pt->head.size >= MAX_HIST) { 749 pt->head.size = MAX_HIST - 1; 750 pt->head.base_tai = pt->info[pt->head.size].taiof; 751 } 752 753 /* make room in lower end and insert item */ 754 memmove(pt->info+1, pt->info, pt->head.size*sizeof(*pt->info)); 755 pt->info[0] = *pi; 756 pt->head.size++; 757 758 /* invalidate the cached limit data -- we might have news ;-) 759 * 760 * This blocks a spurious transition detection. OTOH, if you add 761 * a value after the last query before a leap transition was 762 * expected to occur, this transition trigger is lost. But we 763 * can probably live with that. 764 */ 765 reset_times(pt); 766 return TRUE; 767 } 768 769 /* [internal] given a reader function, read characters into a buffer 770 * until either EOL or EOF is reached. Makes sure that the buffer is 771 * always NUL terminated, but silently truncates excessive data. The 772 * EOL-marker ('\n') is *not* stored in the buffer. 773 * 774 * Returns the pointer to the buffer, unless EOF was reached when trying 775 * to read the first character of a line. 776 */ 777 static char * 778 get_line( 779 leapsec_reader func, 780 void * farg, 781 char * buff, 782 size_t size) 783 { 784 int ch; 785 char *ptr; 786 787 /* if we cannot even store the delimiter, declare failure */ 788 if (buff == NULL || size == 0) 789 return NULL; 790 791 ptr = buff; 792 while (EOF != (ch = (*func)(farg)) && '\n' != ch) 793 if (size > 1) { 794 size--; 795 *ptr++ = (char)ch; 796 } 797 /* discard trailing whitespace */ 798 while (ptr != buff && isspace((u_char)ptr[-1])) 799 ptr--; 800 *ptr = '\0'; 801 return (ptr == buff && ch == EOF) ? NULL : buff; 802 } 803 804 /* [internal] skips whitespace characters from a character buffer. */ 805 static inline char * 806 skipws( 807 char * ptr 808 ) 809 { 810 while (isspace((u_char)*ptr)) { 811 ptr++; 812 } 813 return ptr; 814 } 815 816 /* [internal] check if a strtoXYZ ended at EOL or whitespace and 817 * converted something at all. Return TRUE if something went wrong. 818 */ 819 static int/*BOOL*/ 820 parsefail( 821 const char * cp, 822 const char * ep) 823 { 824 return (cp == ep) 825 || (*ep && *ep != '#' && !isspace((u_char)*ep)); 826 } 827 828 /* [internal] reload the table limits around the given time stamp. This 829 * is where the real work is done when it comes to table lookup and 830 * evaluation. Some care has been taken to have correct code for dealing 831 * with boundary conditions and empty tables. 832 * 833 * In electric mode, transition and trip time are the same. In dumb 834 * mode, the difference of the TAI offsets must be taken into account 835 * and trip time and transition time become different. The difference 836 * becomes the warping distance when the trip time is reached. 837 */ 838 static void 839 reload_limits( 840 leap_table_t * pt, 841 const vint64 * ts) 842 { 843 int idx; 844 845 /* Get full time and search the true lower bound. Use a 846 * simple loop here, since the number of entries does 847 * not warrant a binary search. This also works for an empty 848 * table, so there is no shortcut for that case. 849 */ 850 for (idx = 0; idx != pt->head.size; idx++) 851 if (ucmpv64(ts, &pt->info[idx].ttime) >= 0) 852 break; 853 854 /* get time limits with proper bound conditions. Note that the 855 * bounds of the table will be observed even if the table is 856 * empty -- no undefined condition must arise from this code. 857 */ 858 if (idx >= pt->head.size) { 859 memset(&pt->head.ebase, 0x00, sizeof(vint64)); 860 pt->head.this_tai = pt->head.base_tai; 861 } else { 862 pt->head.ebase = pt->info[idx].ttime; 863 pt->head.this_tai = pt->info[idx].taiof; 864 } 865 if (--idx >= 0) { 866 pt->head.next_tai = pt->info[idx].taiof; 867 pt->head.dynls = pt->info[idx].dynls; 868 pt->head.ttime = pt->info[idx].ttime; 869 870 if (_electric) 871 pt->head.dtime = pt->head.ttime; 872 else 873 pt->head.dtime = addv64i32( 874 &pt->head.ttime, 875 pt->head.next_tai - pt->head.this_tai); 876 877 pt->head.stime = subv64u32( 878 &pt->head.ttime, pt->info[idx].stime); 879 880 } else { 881 memset(&pt->head.ttime, 0xFF, sizeof(vint64)); 882 pt->head.stime = pt->head.ttime; 883 pt->head.dtime = pt->head.ttime; 884 pt->head.next_tai = pt->head.this_tai; 885 pt->head.dynls = 0; 886 } 887 } 888 889 /* [internal] fetch the leap era for a given time stamp. 890 * This is a cut-down version the algorithm used to reload the table 891 * limits, but it does not update any global state and provides just the 892 * era information for a given time stamp. 893 */ 894 static void 895 fetch_leap_era( 896 leap_era_t * into, 897 const leap_table_t * pt , 898 const vint64 * ts ) 899 { 900 int idx; 901 902 /* Simple search loop, also works with empty table. */ 903 for (idx = 0; idx != pt->head.size; idx++) 904 if (ucmpv64(ts, &pt->info[idx].ttime) >= 0) 905 break; 906 /* fetch era data, keeping an eye on boundary conditions */ 907 if (idx >= pt->head.size) { 908 memset(&into->ebase, 0x00, sizeof(vint64)); 909 into->taiof = pt->head.base_tai; 910 } else { 911 into->ebase = pt->info[idx].ttime; 912 into->taiof = pt->info[idx].taiof; 913 } 914 if (--idx >= 0) 915 into->ttime = pt->info[idx].ttime; 916 else 917 memset(&into->ttime, 0xFF, sizeof(vint64)); 918 } 919 920 /* [internal] Take a time stamp and create a leap second frame for 921 * it. This will schedule a leap second for the beginning of the next 922 * month, midnight UTC. The 'insert' argument tells if a leap second is 923 * added (!=0) or removed (==0). We do not handle multiple inserts 924 * (yet?) 925 * 926 * Returns 1 if the insert worked, 0 otherwise. (It's not possible to 927 * insert a leap second into the current history -- only appending 928 * towards the future is allowed!) 929 */ 930 static int/*BOOL*/ 931 leapsec_add( 932 leap_table_t* pt , 933 const vint64 * now64 , 934 int insert) 935 { 936 vint64 ttime, starttime; 937 struct calendar fts; 938 leap_info_t li; 939 940 /* Check against the table expiration and the latest available 941 * leap entry. Do not permit inserts, only appends, and only if 942 * the extend the table beyond the expiration! 943 */ 944 if ( ucmpv64(now64, &pt->head.expire) < 0 945 || (pt->head.size && ucmpv64(now64, &pt->info[0].ttime) <= 0)) { 946 errno = ERANGE; 947 return FALSE; 948 } 949 950 ntpcal_ntp64_to_date(&fts, now64); 951 /* To guard against dangling leap flags: do not accept leap 952 * second request on the 1st hour of the 1st day of the month. 953 */ 954 if (fts.monthday == 1 && fts.hour == 0) { 955 errno = EINVAL; 956 return FALSE; 957 } 958 959 /* Ok, do the remaining calculations */ 960 fts.monthday = 1; 961 fts.hour = 0; 962 fts.minute = 0; 963 fts.second = 0; 964 starttime = ntpcal_date_to_ntp64(&fts); 965 fts.month++; 966 ttime = ntpcal_date_to_ntp64(&fts); 967 968 li.ttime = ttime; 969 li.stime = ttime.D_s.lo - starttime.D_s.lo; 970 li.taiof = (pt->head.size ? pt->info[0].taiof : pt->head.base_tai) 971 + (insert ? 1 : -1); 972 li.dynls = 1; 973 return add_range(pt, &li); 974 } 975 976 /* [internal] Given a time stamp for a leap insertion (the exact begin 977 * of the new leap era), create new leap frame and put it into the 978 * table. This is the work horse for reading a leap file and getting a 979 * leap second update via authenticated network packet. 980 */ 981 int/*BOOL*/ 982 leapsec_raw( 983 leap_table_t * pt, 984 const vint64 * ttime, 985 int taiof, 986 int dynls) 987 { 988 vint64 starttime; 989 struct calendar fts; 990 leap_info_t li; 991 992 /* Check that we either extend the table or get a duplicate of 993 * the latest entry. The latter is a benevolent overwrite with 994 * identical data and could happen if we get an autokey message 995 * that extends the lifetime of the current leapsecond table. 996 * Otherwise paranoia rulez! 997 */ 998 if (pt->head.size) { 999 int cmp = ucmpv64(ttime, &pt->info[0].ttime); 1000 if (cmp == 0) 1001 cmp -= (taiof != pt->info[0].taiof); 1002 if (cmp < 0) { 1003 errno = ERANGE; 1004 return FALSE; 1005 } 1006 if (cmp == 0) 1007 return TRUE; 1008 } 1009 1010 ntpcal_ntp64_to_date(&fts, ttime); 1011 /* If this does not match the exact month start, bail out. */ 1012 if (fts.monthday != 1 || fts.hour || fts.minute || fts.second) { 1013 errno = EINVAL; 1014 return FALSE; 1015 } 1016 fts.month--; /* was in range 1..12, no overflow here! */ 1017 starttime = ntpcal_date_to_ntp64(&fts); 1018 li.ttime = *ttime; 1019 li.stime = ttime->D_s.lo - starttime.D_s.lo; 1020 li.taiof = (int16_t)taiof; 1021 li.dynls = (dynls != 0); 1022 return add_range(pt, &li); 1023 } 1024 1025 /* [internal] Do a wrap-around save range inclusion check. 1026 * Returns TRUE if x in [lo,hi[ (intervall open on right side) with full 1027 * handling of an overflow / wrap-around. 1028 */ 1029 static int/*BOOL*/ 1030 betweenu32( 1031 uint32_t lo, 1032 uint32_t x, 1033 uint32_t hi) 1034 { 1035 int rc; 1036 1037 if (lo <= hi) 1038 rc = (lo <= x) && (x < hi); 1039 else 1040 rc = (lo <= x) || (x < hi); 1041 return rc; 1042 } 1043 1044 /* ===================================================================== 1045 * validation stuff 1046 */ 1047 1048 typedef struct { 1049 unsigned char hv[ISC_SHA1_DIGESTLENGTH]; 1050 } sha1_digest; 1051 1052 /* [internal] parse a digest line to get the hash signature 1053 * The NIST code creating the hash writes them out as 5 hex integers 1054 * without leading zeros. This makes reading them back as hex-encoded 1055 * BLOB impossible, because there might be less than 40 hex digits. 1056 * 1057 * The solution is to read the values back as integers, and then do the 1058 * byte twiddle necessary to get it into an array of 20 chars. The 1059 * drawback is that it permits any acceptable number syntax provided by 1060 * 'scanf()' and 'strtoul()', including optional signs and '0x' 1061 * prefixes. 1062 */ 1063 static int/*BOOL*/ 1064 do_leap_hash( 1065 sha1_digest * mac, 1066 char const * cp ) 1067 { 1068 int wi, di, num, len; 1069 unsigned long tmp[5]; 1070 1071 memset(mac, 0, sizeof(*mac)); 1072 num = sscanf(cp, " %lx %lx %lx %lx %lx%n", 1073 &tmp[0], &tmp[1], &tmp[2], &tmp[3], &tmp[4], 1074 &len); 1075 if (num != 5 || cp[len] > ' ') 1076 return FALSE; 1077 1078 /* now do the byte twiddle */ 1079 for (wi=0; wi < 5; ++wi) 1080 for (di=3; di >= 0; --di) { 1081 mac->hv[wi*4 + di] = 1082 (unsigned char)(tmp[wi] & 0x0FF); 1083 tmp[wi] >>= 8; 1084 } 1085 return TRUE; 1086 } 1087 1088 /* [internal] add the digits of a data line to the hash, stopping at the 1089 * next hash ('#') character. 1090 */ 1091 static void 1092 do_hash_data( 1093 isc_sha1_t * mdctx, 1094 char const * cp ) 1095 { 1096 unsigned char text[32]; // must be power of two! 1097 unsigned int tlen = 0; 1098 unsigned char ch; 1099 1100 while ('\0' != (ch = *cp++) && '#' != ch) 1101 if (isdigit(ch)) { 1102 text[tlen++] = ch; 1103 tlen &= (sizeof(text)-1); 1104 if (0 == tlen) 1105 isc_sha1_update( 1106 mdctx, text, sizeof(text)); 1107 } 1108 1109 if (0 < tlen) 1110 isc_sha1_update(mdctx, text, tlen); 1111 } 1112 1113 /* given a reader and a reader arg, calculate and validate the the hash 1114 * signature of a NIST leap second file. 1115 */ 1116 int 1117 leapsec_validate( 1118 leapsec_reader func, 1119 void * farg) 1120 { 1121 isc_sha1_t mdctx; 1122 sha1_digest rdig, ldig; /* remote / local digests */ 1123 char line[50]; 1124 int hlseen = -1; 1125 1126 isc_sha1_init(&mdctx); 1127 while (get_line(func, farg, line, sizeof(line))) { 1128 if (!strncmp(line, "#h", 2)) 1129 hlseen = do_leap_hash(&rdig, line+2); 1130 else if (!strncmp(line, "#@", 2)) 1131 do_hash_data(&mdctx, line+2); 1132 else if (!strncmp(line, "#$", 2)) 1133 do_hash_data(&mdctx, line+2); 1134 else if (isdigit((unsigned char)line[0])) 1135 do_hash_data(&mdctx, line); 1136 } 1137 isc_sha1_final(&mdctx, ldig.hv); 1138 isc_sha1_invalidate(&mdctx); 1139 1140 if (0 > hlseen) 1141 return LSVALID_NOHASH; 1142 if (0 == hlseen) 1143 return LSVALID_BADFORMAT; 1144 if (0 != memcmp(&rdig, &ldig, sizeof(sha1_digest))) 1145 return LSVALID_BADHASH; 1146 return LSVALID_GOODHASH; 1147 } 1148 1149 /* 1150 * lstostr - prettyprint NTP seconds 1151 */ 1152 static const char * 1153 lstostr( 1154 const vint64 * ts) 1155 { 1156 char * buf; 1157 struct calendar tm; 1158 1159 LIB_GETBUF(buf); 1160 1161 if ( ! (ts->d_s.hi >= 0 && ntpcal_ntp64_to_date(&tm, ts) >= 0)) 1162 snprintf(buf, LIB_BUFLENGTH, "%s", "9999-12-31T23:59:59Z"); 1163 else 1164 snprintf(buf, LIB_BUFLENGTH, "%04d-%02d-%02dT%02d:%02d:%02dZ", 1165 tm.year, tm.month, tm.monthday, 1166 tm.hour, tm.minute, tm.second); 1167 1168 return buf; 1169 } 1170 1171 /* reset the global state for unit tests */ 1172 void 1173 leapsec_ut_pristine(void) 1174 { 1175 memset(_ltab, 0, sizeof(_ltab)); 1176 _lptr = NULL; 1177 _electric = 0; 1178 } 1179 1180 1181 1182 /* -*- that's all folks! -*- */ 1183