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