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