From f0d4df2c60b04cdfd3053217c7fc164643ebdc92 Mon Sep 17 00:00:00 2001 From: Juergen Perlinger Date: Tue, 2 Jun 2015 09:11:10 +0200 Subject: [PATCH] Bug 2830 - ntpd doesn't always transfer the correct TAI offset via autokey fix a few bad ideas and missing links bk: 556d570eoecOta-7B3n2CIKE7LTJVA --- ntpd/ntp_crypto.c | 73 +++++++++++++++++++++------------------------- ntpd/ntp_leapsec.c | 41 ++++++++++++++++---------- 2 files changed, 59 insertions(+), 55 deletions(-) diff --git a/ntpd/ntp_crypto.c b/ntpd/ntp_crypto.c index 6e0e1eb4b..1084ef4c7 100644 --- a/ntpd/ntp_crypto.c +++ b/ntpd/ntp_crypto.c @@ -988,8 +988,9 @@ crypto_recv( * compare the value timestamps here, as they * can be updated by different servers. */ - if ((rval = crypto_verify(ep, NULL, peer)) != - XEVNT_OK) + rval = crypto_verify(ep, NULL, peer); + if ((rval != XEVNT_OK ) || + (vallen != 3*sizeof(uint32_t)) ) break; /* Check if we can update the basic TAI offset @@ -997,27 +998,9 @@ crypto_recv( * and ignores the time stamps in the autokey * message. */ - if (vallen == 0) { - /* NOP */ - } else if (vallen != 3*sizeof(uint32_t)) { -#ifdef DEBUG - if (debug) - printf("crypto_recv: CRYPTO_LEAP: bad value size %u\n", vallen); -#endif - } else if (sys_leap == LEAP_NOTINSYNC) { -#ifdef DEBUG - if (debug) - printf("crypto_recv: CRYPTO_LEAP: not in sync, TAI ignored\n"); -#endif - } else if ( ! leapsec_autokey_tai(ntohl(ep->pkt[0]), - rbufp->recv_time.l_ui, NULL)) - { -#ifdef DEBUG - if (debug) - printf("crypto_recv: CRYPTO_LEAP: TAI not updated\n"); -#endif - } - + if (sys_leap != LEAP_NOTINSYNC) + leapsec_autokey_tai(ntohl(ep->pkt[0]), + rbufp->recv_time.l_ui, NULL); tai_leap.tstamp = ep->tstamp; tai_leap.fstamp = ep->fstamp; crypto_update(); @@ -1915,27 +1898,38 @@ crypto_update(void) */ tai_leap.tstamp = hostval.tstamp; tai_leap.fstamp = hostval.fstamp; - if ( ! leapsec_frame(&leap_data)) - leap_data.tai_offs = 0; - - if (leap_data.tai_offs != 0) { /* might be better with > 10... */ - len = 3 * sizeof(u_int32); - if (tai_leap.ptr == NULL || ntohl(tai_leap.vallen) != len) { - free(tai_leap.ptr); - tai_leap.ptr = emalloc(len); - tai_leap.vallen = htonl(len); - } - ptr = (u_int32 *)tai_leap.ptr; + + /* Get the leap second era. We might need a full lookup early + * after start, when the cache is not yet loaded. + */ + leapsec_frame(&leap_data); + if ( ! memcmp(&leap_data.ebase, &leap_data.ttime, sizeof(vint64))) { + time_t now = time(NULL); + uint32_t nowntp = (uint32_t)now + JAN_1970; + leapsec_query(&leap_data, nowntp, &now); + } + + /* Create the data block. The protocol does not work without. */ + len = 3 * sizeof(u_int32); + if (tai_leap.ptr == NULL || ntohl(tai_leap.vallen) != len) { + free(tai_leap.ptr); + tai_leap.ptr = emalloc(len); + tai_leap.vallen = htonl(len); + } + ptr = (u_int32 *)tai_leap.ptr; + if (leap_data.tai_offs > 10) { + /* create a TAI / leap era block. The end time is a + * fake -- maybe we can do better. + */ ptr[0] = htonl(leap_data.tai_offs); ptr[1] = htonl(leap_data.ebase.d_s.lo); if (leap_data.ttime.d_s.hi >= 0) - ptr[2] = htonl(leap_data.ttime.D_s.lo - 7*86400); + ptr[2] = htonl(leap_data.ttime.D_s.lo + 7*86400); else ptr[2] = htonl(leap_data.ebase.D_s.lo + 25*86400); } else { - free(tai_leap.ptr); - tai_leap.ptr = NULL; - tai_leap.vallen = 0; + /* no leap era available */ + memset(ptr, 0, len); } if (tai_leap.sig == NULL) tai_leap.sig = emalloc(sign_siglen); @@ -1943,8 +1937,9 @@ crypto_update(void) EVP_SignUpdate(&ctx, (u_char *)&tai_leap, 12); EVP_SignUpdate(&ctx, tai_leap.ptr, len); if (EVP_SignFinal(&ctx, tai_leap.sig, &len, sign_pkey)) - tai_leap.siglen = htonl(sign_siglen); + tai_leap.siglen = htonl(len); crypto_flags |= CRYPTO_FLAG_TAI; + snprintf(statstr, sizeof(statstr), "signature update ts %u", ntohl(hostval.tstamp)); record_crypto_stats(NULL, statstr); diff --git a/ntpd/ntp_leapsec.c b/ntpd/ntp_leapsec.c index 90e053eb6..7f6df0a22 100644 --- a/ntpd/ntp_leapsec.c +++ b/ntpd/ntp_leapsec.c @@ -95,7 +95,7 @@ static int betweenu32(uint32_t, uint32_t, uint32_t); static void reset_times(leap_table_t*); static int leapsec_add(leap_table_t*, const vint64*, int); static int leapsec_raw(leap_table_t*, const vint64 *, int, int); -static char * lstostr(const vint64 * ts); +static const char * lstostr(const vint64 * ts); /* ===================================================================== * Get & Set the current leap table @@ -189,11 +189,16 @@ leapsec_load( struct calendar build; leapsec_clear(pt); - if (use_build_limit && ntpcal_get_build_date(&build)) + if (use_build_limit && ntpcal_get_build_date(&build)) { + /* don't prune everything -- permit the last 10yrs + * before build. + */ + build.year -= 10; limit = ntpcal_date_to_ntp64(&build); - else + } else { memset(&limit, 0, sizeof(limit)); - + } + while (get_line(func, farg, linebuf, sizeof(linebuf))) { cp = linebuf; if (*cp == '#') { @@ -390,8 +395,6 @@ leapsec_frame( memset(qr, 0, sizeof(leap_result_t)); pt = leapsec_get_table(FALSE); - if (ucmpv64(&pt->head.ttime, &pt->head.stime) <= 0) - return FALSE; qr->tai_offs = pt->head.this_tai; qr->tai_diff = pt->head.next_tai - pt->head.this_tai; @@ -399,7 +402,7 @@ leapsec_frame( qr->ttime = pt->head.ttime; qr->dynamic = pt->head.dynls; - return TRUE; + return ucmpv64(&pt->head.ttime, &pt->head.stime) >= 0; } /* ------------------------------------------------------------------ */ @@ -660,8 +663,11 @@ leapsec_autokey_tai( (void)tai_offset; pt = leapsec_get_table(FALSE); - /* Bail out if the basic offset is not zero */ - if (pt->head.base_tai != 0) + /* Bail out if the basic offset is not zero and the putative + * offset is bigger than 10s. That was in 1972 -- we don't want + * to go back that far! + */ + if (pt->head.base_tai != 0 || tai_offset < 10) return FALSE; /* If there's already data in the table, check if an update is @@ -1147,19 +1153,22 @@ leapsec_validate( /* * lstostr - prettyprint NTP seconds */ -static char * lstostr( +static const char * +lstostr( const vint64 * ts) { char * buf; struct calendar tm; + LIB_GETBUF(buf); + if ( ! (ts->d_s.hi >= 0 && ntpcal_ntp64_to_date(&tm, ts) >= 0)) - return "9999-12-31T23:59:59Z"; - - LIB_GETBUF(buf); - snprintf(buf, LIB_BUFLENGTH, "%04d-%02d-%02dT%02d:%02d:%02dZ", - tm.year, tm.month, tm.monthday, - tm.hour, tm.minute, tm.second); + snprintf(buf, LIB_BUFLENGTH, "%s", "9999-12-31T23:59:59Z"); + else + snprintf(buf, LIB_BUFLENGTH, "%04d-%02d-%02dT%02d:%02d:%02dZ", + tm.year, tm.month, tm.monthday, + tm.hour, tm.minute, tm.second); + return buf; } -- 2.47.3