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