aboutsummaryrefslogtreecommitdiff
path: root/libntp
diff options
context:
space:
mode:
Diffstat (limited to 'libntp')
-rw-r--r--libntp/Makefile.in1
-rw-r--r--libntp/a_md5encrypt.c248
-rw-r--r--libntp/adjtime.c4
-rw-r--r--libntp/authkeys.c126
-rw-r--r--libntp/authreadkeys.c52
-rw-r--r--libntp/libssl_compat.c5
-rw-r--r--libntp/ntp_calendar.c109
-rw-r--r--libntp/ssl_init.c114
-rw-r--r--libntp/statestr.c284
-rw-r--r--libntp/systime.c338
-rw-r--r--libntp/work_thread.c2
11 files changed, 914 insertions, 369 deletions
diff --git a/libntp/Makefile.in b/libntp/Makefile.in
index b59c01dd5a76..a3d8d1903b10 100644
--- a/libntp/Makefile.in
+++ b/libntp/Makefile.in
@@ -101,6 +101,7 @@ am__aclocal_m4_deps = $(top_srcdir)/sntp/libopts/m4/libopts.m4 \
$(top_srcdir)/sntp/m4/ltsugar.m4 \
$(top_srcdir)/sntp/m4/ltversion.m4 \
$(top_srcdir)/sntp/m4/lt~obsolete.m4 \
+ $(top_srcdir)/sntp/m4/ntp_af_unspec.m4 \
$(top_srcdir)/sntp/m4/ntp_cacheversion.m4 \
$(top_srcdir)/sntp/m4/ntp_compiler.m4 \
$(top_srcdir)/sntp/m4/ntp_crosscompile.m4 \
diff --git a/libntp/a_md5encrypt.c b/libntp/a_md5encrypt.c
index 7394d0d27b35..7dc7e7ecf40d 100644
--- a/libntp/a_md5encrypt.c
+++ b/libntp/a_md5encrypt.c
@@ -11,6 +11,177 @@
#include "ntp.h"
#include "ntp_md5.h" /* provides OpenSSL digest API */
#include "isc/string.h"
+
+#ifdef OPENSSL
+# include "openssl/cmac.h"
+# define CMAC "AES128CMAC"
+# define AES_128_KEY_SIZE 16
+#endif
+
+typedef struct {
+ const void * buf;
+ size_t len;
+} robuffT;
+
+typedef struct {
+ void * buf;
+ size_t len;
+} rwbuffT;
+
+#ifdef OPENSSL
+static size_t
+cmac_ctx_size(
+ CMAC_CTX * ctx)
+{
+ size_t mlen = 0;
+
+ if (ctx) {
+ EVP_CIPHER_CTX * cctx;
+ if (NULL != (cctx = CMAC_CTX_get0_cipher_ctx (ctx)))
+ mlen = EVP_CIPHER_CTX_block_size(cctx);
+ }
+ return mlen;
+}
+#endif /*OPENSSL*/
+
+static size_t
+make_mac(
+ const rwbuffT * digest,
+ int ktype,
+ const robuffT * key,
+ const robuffT * msg)
+{
+ /*
+ * Compute digest of key concatenated with packet. Note: the
+ * key type and digest type have been verified when the key
+ * was created.
+ */
+ size_t retlen = 0;
+
+#ifdef OPENSSL
+
+ INIT_SSL();
+
+ /* Check if CMAC key type specific code required */
+ if (ktype == NID_cmac) {
+ CMAC_CTX * ctx = NULL;
+ void const * keyptr = key->buf;
+ u_char keybuf[AES_128_KEY_SIZE];
+
+ /* adjust key size (zero padded buffer) if necessary */
+ if (AES_128_KEY_SIZE > key->len) {
+ memcpy(keybuf, keyptr, key->len);
+ memset((keybuf + key->len), 0,
+ (AES_128_KEY_SIZE - key->len));
+ keyptr = keybuf;
+ }
+
+ if (NULL == (ctx = CMAC_CTX_new())) {
+ msyslog(LOG_ERR, "MAC encrypt: CMAC %s CTX new failed.", CMAC);
+ goto cmac_fail;
+ }
+ if (!CMAC_Init(ctx, keyptr, AES_128_KEY_SIZE, EVP_aes_128_cbc(), NULL)) {
+ msyslog(LOG_ERR, "MAC encrypt: CMAC %s Init failed.", CMAC);
+ goto cmac_fail;
+ }
+ if (cmac_ctx_size(ctx) > digest->len) {
+ msyslog(LOG_ERR, "MAC encrypt: CMAC %s buf too small.", CMAC);
+ goto cmac_fail;
+ }
+ if (!CMAC_Update(ctx, msg->buf, msg->len)) {
+ msyslog(LOG_ERR, "MAC encrypt: CMAC %s Update failed.", CMAC);
+ goto cmac_fail;
+ }
+ if (!CMAC_Final(ctx, digest->buf, &retlen)) {
+ msyslog(LOG_ERR, "MAC encrypt: CMAC %s Final failed.", CMAC);
+ retlen = 0;
+ }
+ cmac_fail:
+ if (ctx)
+ CMAC_CTX_cleanup(ctx);
+ }
+ else { /* generic MAC handling */
+ EVP_MD_CTX * ctx = EVP_MD_CTX_new();
+ u_int uilen = 0;
+
+ if ( ! ctx) {
+ msyslog(LOG_ERR, "MAC encrypt: MAC %s Digest CTX new failed.",
+ OBJ_nid2sn(ktype));
+ goto mac_fail;
+ }
+
+ #ifdef EVP_MD_CTX_FLAG_NON_FIPS_ALLOW
+ /* make sure MD5 is allowd */
+ EVP_MD_CTX_set_flags(ctx, EVP_MD_CTX_FLAG_NON_FIPS_ALLOW);
+ #endif
+ /* [Bug 3457] DON'T use plain EVP_DigestInit! It would
+ * kill the flags! */
+ if (!EVP_DigestInit_ex(ctx, EVP_get_digestbynid(ktype), NULL)) {
+ msyslog(LOG_ERR, "MAC encrypt: MAC %s Digest Init failed.",
+ OBJ_nid2sn(ktype));
+ goto mac_fail;
+ }
+ if ((size_t)EVP_MD_CTX_size(ctx) > digest->len) {
+ msyslog(LOG_ERR, "MAC encrypt: MAC %s buf too small.",
+ OBJ_nid2sn(ktype));
+ goto mac_fail;
+ }
+ if (!EVP_DigestUpdate(ctx, key->buf, (u_int)key->len)) {
+ msyslog(LOG_ERR, "MAC encrypt: MAC %s Digest Update key failed.",
+ OBJ_nid2sn(ktype));
+ goto mac_fail;
+ }
+ if (!EVP_DigestUpdate(ctx, msg->buf, (u_int)msg->len)) {
+ msyslog(LOG_ERR, "MAC encrypt: MAC %s Digest Update data failed.",
+ OBJ_nid2sn(ktype));
+ goto mac_fail;
+ }
+ if (!EVP_DigestFinal(ctx, digest->buf, &uilen)) {
+ msyslog(LOG_ERR, "MAC encrypt: MAC %s Digest Final failed.",
+ OBJ_nid2sn(ktype));
+ uilen = 0;
+ }
+ mac_fail:
+ retlen = (size_t)uilen;
+
+ if (ctx)
+ EVP_MD_CTX_free(ctx);
+ }
+
+#else /* !OPENSSL follows */
+
+ if (ktype == NID_md5)
+ {
+ EVP_MD_CTX * ctx = EVP_MD_CTX_new();
+ uint uilen = 0;
+
+ if (digest->len < 16) {
+ msyslog(LOG_ERR, "%s", "MAC encrypt: MAC md5 buf too small.");
+ }
+ else if ( ! ctx) {
+ msyslog(LOG_ERR, "%s", "MAC encrypt: MAC md5 Digest CTX new failed.");
+ }
+ else {
+ EVP_DigestInit(ctx, EVP_get_digestbynid(ktype));
+ EVP_DigestUpdate(ctx, key->buf, key->len);
+ EVP_DigestUpdate(ctx, msg->buf, msg->len);
+ EVP_DigestFinal(ctx, digest->buf, &uilen);
+ }
+ if (ctx)
+ EVP_MD_CTX_free(ctx);
+ retlen = (size_t)uilen;
+ }
+ else
+ {
+ msyslog(LOG_ERR, "MAC encrypt: invalid key type %d" , ktype);
+ }
+
+#endif /* !OPENSSL */
+
+ return retlen;
+}
+
+
/*
* MD5authencrypt - generate message digest
*
@@ -20,36 +191,23 @@ size_t
MD5authencrypt(
int type, /* hash algorithm */
const u_char * key, /* key pointer */
+ size_t klen, /* key length */
u_int32 * pkt, /* packet pointer */
size_t length /* packet length */
)
{
u_char digest[EVP_MAX_MD_SIZE];
- u_int len;
- EVP_MD_CTX *ctx;
+ rwbuffT digb = { digest, sizeof(digest) };
+ robuffT keyb = { key, klen };
+ robuffT msgb = { pkt, length };
+ size_t dlen = 0;
- /*
- * Compute digest of key concatenated with packet. Note: the
- * key type and digest type have been verified when the key
- * was creaded.
- */
- INIT_SSL();
- ctx = EVP_MD_CTX_new();
- if (!(ctx && EVP_DigestInit(ctx, EVP_get_digestbynid(type)))) {
- msyslog(LOG_ERR,
- "MAC encrypt: digest init failed");
- EVP_MD_CTX_free(ctx);
- return (0);
- }
- EVP_DigestUpdate(ctx, key, cache_secretsize);
- EVP_DigestUpdate(ctx, (u_char *)pkt, length);
- EVP_DigestFinal(ctx, digest, &len);
- EVP_MD_CTX_free(ctx);
+ dlen = make_mac(&digb, type, &keyb, &msgb);
/* If the MAC is longer than the MAX then truncate it. */
- if (len > MAX_MAC_LEN - 4)
- len = MAX_MAC_LEN - 4;
- memmove((u_char *)pkt + length + 4, digest, len);
- return (len + 4);
+ if (dlen > MAX_MDG_LEN)
+ dlen = MAX_MDG_LEN;
+ memcpy((u_char *)pkt + length + KEY_MAC_LEN, digest, dlen);
+ return (dlen + KEY_MAC_LEN);
}
@@ -62,41 +220,30 @@ int
MD5authdecrypt(
int type, /* hash algorithm */
const u_char * key, /* key pointer */
+ size_t klen, /* key length */
u_int32 * pkt, /* packet pointer */
size_t length, /* packet length */
size_t size /* MAC size */
)
{
u_char digest[EVP_MAX_MD_SIZE];
- u_int len;
- EVP_MD_CTX *ctx;
+ rwbuffT digb = { digest, sizeof(digest) };
+ robuffT keyb = { key, klen };
+ robuffT msgb = { pkt, length };
+ size_t dlen = 0;
- /*
- * Compute digest of key concatenated with packet. Note: the
- * key type and digest type have been verified when the key
- * was created.
- */
- INIT_SSL();
- ctx = EVP_MD_CTX_new();
- if (!(ctx && EVP_DigestInit(ctx, EVP_get_digestbynid(type)))) {
- msyslog(LOG_ERR,
- "MAC decrypt: digest init failed");
- EVP_MD_CTX_free(ctx);
- return (0);
- }
- EVP_DigestUpdate(ctx, key, cache_secretsize);
- EVP_DigestUpdate(ctx, (u_char *)pkt, length);
- EVP_DigestFinal(ctx, digest, &len);
- EVP_MD_CTX_free(ctx);
+ dlen = make_mac(&digb, type, &keyb, &msgb);
+
/* If the MAC is longer than the MAX then truncate it. */
- if (len > MAX_MAC_LEN - 4)
- len = MAX_MAC_LEN - 4;
- if (size != (size_t)len + 4) {
+ if (dlen > MAX_MDG_LEN)
+ dlen = MAX_MDG_LEN;
+ if (size != (size_t)dlen + KEY_MAC_LEN) {
msyslog(LOG_ERR,
"MAC decrypt: MAC length error");
return (0);
}
- return !isc_tsmemcmp(digest, (u_char *)pkt + length + 4, len);
+ return !isc_tsmemcmp(digest,
+ (u_char *)pkt + length + KEY_MAC_LEN, dlen);
}
/*
@@ -108,7 +255,7 @@ MD5authdecrypt(
u_int32
addr2refid(sockaddr_u *addr)
{
- u_char digest[20];
+ u_char digest[EVP_MAX_MD_SIZE];
u_int32 addr_refid;
EVP_MD_CTX *ctx;
u_int len;
@@ -119,11 +266,12 @@ addr2refid(sockaddr_u *addr)
INIT_SSL();
ctx = EVP_MD_CTX_new();
- EVP_MD_CTX_init(ctx);
-#ifdef EVP_MD_CTX_FLAG_NON_FIPS_ALLOW
+# ifdef EVP_MD_CTX_FLAG_NON_FIPS_ALLOW
/* MD5 is not used as a crypto hash here. */
EVP_MD_CTX_set_flags(ctx, EVP_MD_CTX_FLAG_NON_FIPS_ALLOW);
-#endif
+# endif
+ /* [Bug 3457] DON'T use plain EVP_DigestInit! It would kill the
+ * flags! */
if (!EVP_DigestInit_ex(ctx, EVP_md5(), NULL)) {
msyslog(LOG_ERR,
"MD5 init failed");
diff --git a/libntp/adjtime.c b/libntp/adjtime.c
index a8e65808bf29..b536cc555d9a 100644
--- a/libntp/adjtime.c
+++ b/libntp/adjtime.c
@@ -314,7 +314,7 @@ adjtime (struct timeval *delta, struct timeval *olddelta)
/*
* Get the current clock period (nanoseconds)
*/
- if (ClockPeriod (CLOCK_REALTIME, 0, &period, 0) < 0)
+ if (ClockPeriod (CLOCK_REALTIME, 0, &period, 0) == -1)
return -1;
/*
@@ -354,7 +354,7 @@ adjtime (struct timeval *delta, struct timeval *olddelta)
adj.tick_count = 0;
}
- if (ClockAdjust (CLOCK_REALTIME, &adj, &oldadj) < 0)
+ if (ClockAdjust (CLOCK_REALTIME, &adj, &oldadj) == -1)
return -1;
/*
diff --git a/libntp/authkeys.c b/libntp/authkeys.c
index b2ff410cd476..7c1cbb0655ae 100644
--- a/libntp/authkeys.c
+++ b/libntp/authkeys.c
@@ -114,13 +114,16 @@ KeyAccT *cache_keyacclist; /* key access list */
KeyAccT*
keyacc_new_push(
KeyAccT * head,
- const sockaddr_u * addr
+ const sockaddr_u * addr,
+ unsigned int subnetbits
)
{
KeyAccT * node = emalloc(sizeof(KeyAccT));
memcpy(&node->addr, addr, sizeof(sockaddr_u));
+ node->subnetbits = subnetbits;
node->next = head;
+
return node;
}
@@ -165,7 +168,8 @@ keyacc_contains(
{
if (head) {
do {
- if (SOCK_EQ(&head->addr, addr))
+ if (keyacc_amatch(&head->addr, addr,
+ head->subnetbits))
return TRUE;
} while (NULL != (head = head->next));
return FALSE;
@@ -174,6 +178,98 @@ keyacc_contains(
}
}
+#if CHAR_BIT != 8
+# error "don't know how to handle bytes with that bit size"
+#endif
+
+/* ----------------------------------------------------------------- */
+/* check two addresses for a match, taking a prefix length into account
+ * when doing the compare.
+ *
+ * The ISC lib contains a similar function with not entirely specified
+ * semantics, so it seemed somewhat cleaner to do this from scratch.
+ *
+ * Note 1: It *is* assumed that the addresses are stored in network byte
+ * order, that is, most significant byte first!
+ *
+ * Note 2: "no address" compares unequal to all other addresses, even to
+ * itself. This has the same semantics as NaNs have for floats: *any*
+ * relational or equality operation involving a NaN returns FALSE, even
+ * equality with itself. "no address" is either a NULL pointer argument
+ * or an address of type AF_UNSPEC.
+ */
+int/*BOOL*/
+keyacc_amatch(
+ const sockaddr_u * a1,
+ const sockaddr_u * a2,
+ unsigned int mbits
+ )
+{
+ const uint8_t * pm1;
+ const uint8_t * pm2;
+ uint8_t msk;
+ unsigned int len;
+
+ /* 1st check: If any address is not an address, it's inequal. */
+ if ( !a1 || (AF_UNSPEC == AF(a1)) ||
+ !a2 || (AF_UNSPEC == AF(a2)) )
+ return FALSE;
+
+ /* We could check pointers for equality here and shortcut the
+ * other checks if we find object identity. But that use case is
+ * too rare to care for it.
+ */
+
+ /* 2nd check: Address families must be the same. */
+ if (AF(a1) != AF(a2))
+ return FALSE;
+
+ /* type check: address family determines buffer & size */
+ switch (AF(a1)) {
+ case AF_INET:
+ /* IPv4 is easy: clamp size, get byte pointers */
+ if (mbits > sizeof(NSRCADR(a1)) * 8)
+ mbits = sizeof(NSRCADR(a1)) * 8;
+ pm1 = (const void*)&NSRCADR(a1);
+ pm2 = (const void*)&NSRCADR(a2);
+ break;
+
+ case AF_INET6:
+ /* IPv6 is slightly different: Both scopes must match,
+ * too, before we even consider doing a match!
+ */
+ if ( ! SCOPE_EQ(a1, a2))
+ return FALSE;
+ if (mbits > sizeof(NSRCADR6(a1)) * 8)
+ mbits = sizeof(NSRCADR6(a1)) * 8;
+ pm1 = (const void*)&NSRCADR6(a1);
+ pm2 = (const void*)&NSRCADR6(a2);
+ break;
+
+ default:
+ /* don't know how to compare that!?! */
+ return FALSE;
+ }
+
+ /* Split bit length into byte length and partial byte mask.
+ * Note that the byte mask extends from the MSB of a byte down,
+ * and that zero shift (--> mbits % 8 == 0) results in an
+ * all-zero mask.
+ */
+ msk = 0xFFu ^ (0xFFu >> (mbits & 7));
+ len = mbits >> 3;
+
+ /* 3rd check: Do memcmp() over full bytes, if any */
+ if (len && memcmp(pm1, pm2, len))
+ return FALSE;
+
+ /* 4th check: compare last incomplete byte, if any */
+ if (msk && ((pm1[len] ^ pm2[len]) & msk))
+ return FALSE;
+
+ /* If none of the above failed, we're successfully through. */
+ return TRUE;
+}
/*
* init_auth - initialize internal data
@@ -316,6 +412,10 @@ auth_log2(size_t x)
return (u_short)r;
}
+int/*BOOL*/
+ipaddr_match_masked(const sockaddr_u *,const sockaddr_u *,
+ unsigned int mbits);
+
static void
authcache_flush_id(
keyid_t id
@@ -617,20 +717,19 @@ authistrusted(
{
symkey * sk;
- /* That specific key was already used to authenticate the
- * packet. Therefore, the key *must* exist... There's a chance
- * that is not trusted, though.
- */
if (keyno == cache_keyid) {
return (KEY_TRUSTED & cache_flags) &&
keyacc_contains(cache_keyacclist, sau, TRUE);
- } else {
+ }
+
+ if (NULL != (sk = auth_findkey(keyno))) {
authkeyuncached++;
- sk = auth_findkey(keyno);
- INSIST(NULL != sk);
return (KEY_TRUSTED & sk->flags) &&
keyacc_contains(sk->keyacclist, sau, TRUE);
}
+
+ authkeynotfound++;
+ return FALSE;
}
/* Note: There are two locations below where 'strncpy()' is used. While
@@ -795,7 +894,9 @@ authencrypt(
return 0;
}
- return MD5authencrypt(cache_type, cache_secret, pkt, length);
+ return MD5authencrypt(cache_type,
+ cache_secret, cache_secretsize,
+ pkt, length);
}
@@ -822,6 +923,7 @@ authdecrypt(
return FALSE;
}
- return MD5authdecrypt(cache_type, cache_secret, pkt, length,
- size);
+ return MD5authdecrypt(cache_type,
+ cache_secret, cache_secretsize,
+ pkt, length, size);
}
diff --git a/libntp/authreadkeys.c b/libntp/authreadkeys.c
index e9273ad61dbe..bd98ab21ab10 100644
--- a/libntp/authreadkeys.c
+++ b/libntp/authreadkeys.c
@@ -5,8 +5,8 @@
#include <stdio.h>
#include <ctype.h>
-#include "ntpd.h" /* Only for DPRINTF */
-#include "ntp_fp.h"
+//#include "ntpd.h" /* Only for DPRINTF */
+//#include "ntp_fp.h"
#include "ntp.h"
#include "ntp_syslog.h"
#include "ntp_stdlib.h"
@@ -148,6 +148,7 @@ authreadkeys(
u_int nerr;
KeyDataT *list = NULL;
KeyDataT *next = NULL;
+
/*
* Open file. Complain and return if it can't be opened.
*/
@@ -220,7 +221,8 @@ authreadkeys(
log_maybe(NULL,
"authreadkeys: invalid type for key %d",
keyno);
- } else if (EVP_get_digestbynid(keytype) == NULL) {
+ } else if (NID_cmac != keytype &&
+ EVP_get_digestbynid(keytype) == NULL) {
log_maybe(NULL,
"authreadkeys: no algorithm for key %d",
keyno);
@@ -295,28 +297,62 @@ authreadkeys(
}
token = nexttok(&line);
- DPRINTF(0, ("authreadkeys: full access list <%s>\n", (token) ? token : "NULL"));
if (token != NULL) { /* A comma-separated IP access list */
char *tp = token;
while (tp) {
char *i;
+ char *snp; /* subnet text pointer */
+ unsigned int snbits;
sockaddr_u addr;
i = strchr(tp, (int)',');
- if (i)
+ if (i) {
*i = '\0';
- DPRINTF(0, ("authreadkeys: access list: <%s>\n", tp));
+ }
+ snp = strchr(tp, (int)'/');
+ if (snp) {
+ char *sp;
+
+ *snp++ = '\0';
+ snbits = 0;
+ sp = snp;
+
+ while (*sp != '\0') {
+ if (!isdigit((unsigned char)*sp))
+ break;
+ if (snbits > 1000)
+ break; /* overflow */
+ snbits = 10 * snbits + (*sp++ - '0'); /* ascii dependent */
+ }
+ if (*sp != '\0') {
+ log_maybe(&nerr,
+ "authreadkeys: Invalid character in subnet specification for <%s/%s> in key %d",
+ sp, snp, keyno);
+ goto nextip;
+ }
+ } else {
+ snbits = UINT_MAX;
+ }
if (is_ip_address(tp, AF_UNSPEC, &addr)) {
- next->keyacclist = keyacc_new_push(
- next->keyacclist, &addr);
+ /* Make sure that snbits is valid for addr */
+ if ((snbits < UINT_MAX) &&
+ ( (IS_IPV4(&addr) && snbits > 32) ||
+ (IS_IPV6(&addr) && snbits > 128))) {
+ log_maybe(NULL,
+ "authreadkeys: excessive subnet mask <%s/%s> for key %d",
+ tp, snp, keyno);
+ }
+ next->keyacclist = keyacc_new_push(
+ next->keyacclist, &addr, snbits);
} else {
log_maybe(&nerr,
"authreadkeys: invalid IP address <%s> for key %d",
tp, keyno);
}
+ nextip:
if (i) {
tp = i + 1;
} else {
diff --git a/libntp/libssl_compat.c b/libntp/libssl_compat.c
index afe4d07a4b0a..5527682b34f9 100644
--- a/libntp/libssl_compat.c
+++ b/libntp/libssl_compat.c
@@ -74,7 +74,10 @@ sslshimBN_GENCB_free(
EVP_MD_CTX*
sslshim_EVP_MD_CTX_new(void)
{
- return calloc(1, sizeof(EVP_MD_CTX));
+ EVP_MD_CTX * ctx;
+ if (NULL != (ctx = calloc(1, sizeof(EVP_MD_CTX))))
+ EVP_MD_CTX_init(ctx);
+ return ctx;
}
void
diff --git a/libntp/ntp_calendar.c b/libntp/ntp_calendar.c
index 4bfb0e723c01..a550d5d3a2c7 100644
--- a/libntp/ntp_calendar.c
+++ b/libntp/ntp_calendar.c
@@ -1825,4 +1825,113 @@ isocal_date_to_ntp(
return isocal_date_to_ntp64(id).d_s.lo;
}
+/*
+ * ====================================================================
+ * 'basedate' support functions
+ * ====================================================================
+ */
+
+static int32_t s_baseday = NTP_TO_UNIX_DAYS;
+
+int32_t
+basedate_eval_buildstamp(void)
+{
+ struct calendar jd;
+ int32_t ed;
+
+ if (!ntpcal_get_build_date(&jd))
+ return NTP_TO_UNIX_DAYS;
+
+ /* The time zone of the build stamp is unspecified; we remove
+ * one day to provide a certain slack. And in case somebody
+ * fiddled with the system clock, we make sure we do not go
+ * before the UNIX epoch (1970-01-01). It's probably not possible
+ * to do this to the clock on most systems, but there are other
+ * ways to tweak the build stamp.
+ */
+ jd.monthday -= 1;
+ ed = ntpcal_date_to_rd(&jd) - DAY_NTP_STARTS;
+ return (ed < NTP_TO_UNIX_DAYS) ? NTP_TO_UNIX_DAYS : ed;
+}
+
+int32_t
+basedate_eval_string(
+ const char * str
+ )
+{
+ u_short y,m,d;
+ u_long ned;
+ int rc, nc;
+ size_t sl;
+
+ sl = strlen(str);
+ rc = sscanf(str, "%4hu-%2hu-%2hu%n", &y, &m, &d, &nc);
+ if (rc == 3 && (size_t)nc == sl) {
+ if (m >= 1 && m <= 12 && d >= 1 && d <= 31)
+ return ntpcal_edate_to_eradays(y-1, m-1, d)
+ - DAY_NTP_STARTS;
+ goto buildstamp;
+ }
+
+ rc = scanf(str, "%lu%n", &ned, &nc);
+ if (rc == 1 && (size_t)nc == sl) {
+ if (ned <= INT32_MAX)
+ return (int32_t)ned;
+ goto buildstamp;
+ }
+
+ buildstamp:
+ msyslog(LOG_WARNING,
+ "basedate string \"%s\" invalid, build date substituted!",
+ str);
+ return basedate_eval_buildstamp();
+}
+
+uint32_t
+basedate_get_day(void)
+{
+ return s_baseday;
+}
+
+int32_t
+basedate_set_day(
+ int32_t day
+ )
+{
+ struct calendar jd;
+ int32_t retv;
+
+ if (day < NTP_TO_UNIX_DAYS) {
+ msyslog(LOG_WARNING,
+ "baseday_set_day: invalid day (%lu), UNIX epoch substituted",
+ (unsigned long)day);
+ day = NTP_TO_UNIX_DAYS;
+ }
+ retv = s_baseday;
+ s_baseday = day;
+ ntpcal_rd_to_date(&jd, day + DAY_NTP_STARTS);
+ msyslog(LOG_INFO, "basedate set to %04hu-%02hu-%02hu",
+ jd.year, (u_short)jd.month, (u_short)jd.monthday);
+ return retv;
+}
+
+time_t
+basedate_get_eracenter(void)
+{
+ time_t retv;
+ retv = (time_t)(s_baseday - NTP_TO_UNIX_DAYS);
+ retv *= SECSPERDAY;
+ retv += (UINT32_C(1) << 31);
+ return retv;
+}
+
+time_t
+basedate_get_erabase(void)
+{
+ time_t retv;
+ retv = (time_t)(s_baseday - NTP_TO_UNIX_DAYS);
+ retv *= SECSPERDAY;
+ return retv;
+}
+
/* -*-EOF-*- */
diff --git a/libntp/ssl_init.c b/libntp/ssl_init.c
index bebf6e175531..96d9d0838bd7 100644
--- a/libntp/ssl_init.c
+++ b/libntp/ssl_init.c
@@ -5,7 +5,7 @@
* Moved from ntpd/ntp_crypto.c crypto_setup()
*/
#ifdef HAVE_CONFIG_H
-#include <config.h>
+# include <config.h>
#endif
#include <ctype.h>
#include <ntp.h>
@@ -13,11 +13,15 @@
#include <lib_strbuf.h>
#ifdef OPENSSL
-#include "openssl/crypto.h"
-#include "openssl/err.h"
-#include "openssl/evp.h"
-#include "openssl/opensslv.h"
-#include "libssl_compat.h"
+# include "openssl/cmac.h"
+# include "openssl/crypto.h"
+# include "openssl/err.h"
+# include "openssl/evp.h"
+# include "openssl/opensslv.h"
+# include "libssl_compat.h"
+
+# define CMAC_LENGTH 16
+# define CMAC "AES128CMAC"
int ssl_init_done;
@@ -26,8 +30,9 @@ int ssl_init_done;
static void
atexit_ssl_cleanup(void)
{
- if (!ssl_init_done)
+ if (!ssl_init_done) {
return;
+ }
ssl_init_done = FALSE;
EVP_cleanup();
@@ -63,7 +68,7 @@ void
ssl_check_version(void)
{
u_long v;
-
+
v = OpenSSL_version_num();
if ((v ^ OPENSSL_VERSION_NUMBER) & ~0xff0L) {
msyslog(LOG_WARNING,
@@ -77,6 +82,8 @@ ssl_check_version(void)
INIT_SSL();
}
+#else /* !OPENSSL */
+# define MD5_LENGTH 16
#endif /* OPENSSL */
@@ -88,61 +95,95 @@ ssl_check_version(void)
*/
int
keytype_from_text(
- const char *text,
- size_t *pdigest_len
+ const char * text,
+ size_t * pdigest_len
)
{
int key_type;
u_int digest_len;
-#ifdef OPENSSL
+#ifdef OPENSSL /* --*-- OpenSSL code --*-- */
const u_long max_digest_len = MAX_MAC_LEN - sizeof(keyid_t);
- u_char digest[EVP_MAX_MD_SIZE];
char * upcased;
char * pch;
+ EVP_MD const * md;
/*
* OpenSSL digest short names are capitalized, so uppercase the
* digest name before passing to OBJ_sn2nid(). If it is not
- * recognized but begins with 'M' use NID_md5 to be consistent
- * with past behavior.
+ * recognized but matches our CMAC string use NID_cmac, or if
+ * it begins with 'M' or 'm' use NID_md5 to be consistent with
+ * past behavior.
*/
INIT_SSL();
+
+ /* get name in uppercase */
LIB_GETBUF(upcased);
strlcpy(upcased, text, LIB_BUFLENGTH);
- for (pch = upcased; '\0' != *pch; pch++)
+
+ for (pch = upcased; '\0' != *pch; pch++) {
*pch = (char)toupper((unsigned char)*pch);
+ }
+
key_type = OBJ_sn2nid(upcased);
+
+ if (!key_type && !strncmp(CMAC, upcased, strlen(CMAC) + 1)) {
+ key_type = NID_cmac;
+
+ if (debug) {
+ fprintf(stderr, "%s:%d:%s():%s:key\n",
+ __FILE__, __LINE__, __func__, CMAC);
+ }
+ }
#else
+
key_type = 0;
#endif
- if (!key_type && 'm' == tolower((unsigned char)text[0]))
+ if (!key_type && 'm' == tolower((unsigned char)text[0])) {
key_type = NID_md5;
+ }
- if (!key_type)
+ if (!key_type) {
return 0;
+ }
if (NULL != pdigest_len) {
#ifdef OPENSSL
- EVP_MD_CTX *ctx;
+ md = EVP_get_digestbynid(key_type);
+ digest_len = (md) ? EVP_MD_size(md) : 0;
- ctx = EVP_MD_CTX_new();
- EVP_DigestInit(ctx, EVP_get_digestbynid(key_type));
- EVP_DigestFinal(ctx, digest, &digest_len);
- EVP_MD_CTX_free(ctx);
- if (digest_len > max_digest_len) {
+ if (!md || digest_len <= 0) {
+ if (key_type == NID_cmac) {
+ digest_len = CMAC_LENGTH;
+
+ if (debug) {
+ fprintf(stderr, "%s:%d:%s():%s:len\n",
+ __FILE__, __LINE__, __func__, CMAC);
+ }
+ } else {
fprintf(stderr,
- "key type %s %u octet digests are too big, max %lu\n",
- keytype_name(key_type), digest_len,
- max_digest_len);
+ "key type %s is not supported by OpenSSL\n",
+ keytype_name(key_type));
msyslog(LOG_ERR,
- "key type %s %u octet digests are too big, max %lu",
- keytype_name(key_type), digest_len,
- max_digest_len);
+ "key type %s is not supported by OpenSSL\n",
+ keytype_name(key_type));
return 0;
+ }
+ }
+
+ if (digest_len > max_digest_len) {
+ fprintf(stderr,
+ "key type %s %u octet digests are too big, max %lu\n",
+ keytype_name(key_type), digest_len,
+ max_digest_len);
+ msyslog(LOG_ERR,
+ "key type %s %u octet digests are too big, max %lu",
+ keytype_name(key_type), digest_len,
+ max_digest_len);
+ return 0;
}
#else
- digest_len = 16;
+ digest_len = MD5_LENGTH;
#endif
*pdigest_len = digest_len;
}
@@ -167,8 +208,18 @@ keytype_name(
#ifdef OPENSSL
INIT_SSL();
name = OBJ_nid2sn(nid);
- if (NULL == name)
+
+ if (NID_cmac == nid) {
+ name = CMAC;
+
+ if (debug) {
+ fprintf(stderr, "%s:%d:%s():%s:nid\n",
+ __FILE__, __LINE__, __func__, CMAC);
+ }
+ } else
+ if (NULL == name) {
name = unknown_type;
+ }
#else /* !OPENSSL follows */
if (NID_md5 == nid)
name = "MD5";
@@ -203,3 +254,4 @@ getpass_keytype(
return getpass(pass_prompt);
}
+
diff --git a/libntp/statestr.c b/libntp/statestr.c
index b8fa53ccb07f..d135222cf93d 100644
--- a/libntp/statestr.c
+++ b/libntp/statestr.c
@@ -22,64 +22,65 @@
*/
struct codestring {
int code;
- const char * const string;
+ const char * const string1;
+ const char * const string0;
};
/*
* Leap status (leap)
*/
static const struct codestring leap_codes[] = {
- { LEAP_NOWARNING, "leap_none" },
- { LEAP_ADDSECOND, "leap_add_sec" },
- { LEAP_DELSECOND, "leap_del_sec" },
- { LEAP_NOTINSYNC, "leap_alarm" },
- { -1, "leap" }
+ { LEAP_NOWARNING, "leap_none", 0 },
+ { LEAP_ADDSECOND, "leap_add_sec", 0 },
+ { LEAP_DELSECOND, "leap_del_sec", 0 },
+ { LEAP_NOTINSYNC, "leap_alarm", 0 },
+ { -1, "leap", 0 }
};
/*
* Clock source status (sync)
*/
static const struct codestring sync_codes[] = {
- { CTL_SST_TS_UNSPEC, "sync_unspec" },
- { CTL_SST_TS_ATOM, "sync_pps" },
- { CTL_SST_TS_LF, "sync_lf_radio" },
- { CTL_SST_TS_HF, "sync_hf_radio" },
- { CTL_SST_TS_UHF, "sync_uhf_radio" },
- { CTL_SST_TS_LOCAL, "sync_local" },
- { CTL_SST_TS_NTP, "sync_ntp" },
- { CTL_SST_TS_UDPTIME, "sync_other" },
- { CTL_SST_TS_WRSTWTCH, "sync_wristwatch" },
- { CTL_SST_TS_TELEPHONE, "sync_telephone" },
- { -1, "sync" }
+ { CTL_SST_TS_UNSPEC, "sync_unspec", 0 },
+ { CTL_SST_TS_ATOM, "sync_pps", 0 },
+ { CTL_SST_TS_LF, "sync_lf_radio", 0 },
+ { CTL_SST_TS_HF, "sync_hf_radio", 0 },
+ { CTL_SST_TS_UHF, "sync_uhf_radio", 0 },
+ { CTL_SST_TS_LOCAL, "sync_local", 0 },
+ { CTL_SST_TS_NTP, "sync_ntp", 0 },
+ { CTL_SST_TS_UDPTIME, "sync_other", 0 },
+ { CTL_SST_TS_WRSTWTCH, "sync_wristwatch", 0 },
+ { CTL_SST_TS_TELEPHONE, "sync_telephone", 0 },
+ { -1, "sync", 0 }
};
/*
* Peer selection status (sel)
*/
static const struct codestring select_codes[] = {
- { CTL_PST_SEL_REJECT, "sel_reject" },
- { CTL_PST_SEL_SANE, "sel_falsetick" },
- { CTL_PST_SEL_CORRECT, "sel_excess" },
- { CTL_PST_SEL_SELCAND, "sel_outlier" },
- { CTL_PST_SEL_SYNCCAND, "sel_candidate" },
- { CTL_PST_SEL_EXCESS, "sel_backup" },
- { CTL_PST_SEL_SYSPEER, "sel_sys.peer" },
- { CTL_PST_SEL_PPS, "sel_pps.peer" },
- { -1, "sel" }
+ { CTL_PST_SEL_REJECT, "sel_reject", 0 },
+ { CTL_PST_SEL_SANE, "sel_falsetick", 0 },
+ { CTL_PST_SEL_CORRECT, "sel_excess", 0 },
+ { CTL_PST_SEL_SELCAND, "sel_outlier", 0 },
+ { CTL_PST_SEL_SYNCCAND, "sel_candidate", 0 },
+ { CTL_PST_SEL_EXCESS, "sel_backup", 0 },
+ { CTL_PST_SEL_SYSPEER, "sel_sys.peer", 0 },
+ { CTL_PST_SEL_PPS, "sel_pps.peer", 0 },
+ { -1, "sel", 0 }
};
/*
* Clock status (clk)
*/
static const struct codestring clock_codes[] = {
- { CTL_CLK_OKAY, "clk_unspec" },
- { CTL_CLK_NOREPLY, "clk_no_reply" },
- { CTL_CLK_BADFORMAT, "clk_bad_format" },
- { CTL_CLK_FAULT, "clk_fault" },
- { CTL_CLK_PROPAGATION, "clk_bad_signal" },
- { CTL_CLK_BADDATE, "clk_bad_date" },
- { CTL_CLK_BADTIME, "clk_bad_time" },
- { -1, "clk" }
+ { CTL_CLK_OKAY, "clk_unspec", 0 },
+ { CTL_CLK_NOREPLY, "clk_no_reply", 0 },
+ { CTL_CLK_BADFORMAT, "clk_bad_format", 0 },
+ { CTL_CLK_FAULT, "clk_fault", 0 },
+ { CTL_CLK_PROPAGATION, "clk_bad_signal", 0 },
+ { CTL_CLK_BADDATE, "clk_bad_date", 0 },
+ { CTL_CLK_BADTIME, "clk_bad_time", 0 },
+ { -1, "clk", 0 }
};
@@ -88,20 +89,20 @@ static const struct codestring clock_codes[] = {
* Flash bits -- see ntpq.c tstflags & tstflagnames
*/
static const struct codestring flash_codes[] = {
- { TEST1, "pkt_dup" },
- { TEST2, "pkt_bogus" },
- { TEST3, "pkt_unsync" },
- { TEST4, "pkt_denied" },
- { TEST5, "pkt_auth" },
- { TEST6, "pkt_stratum" },
- { TEST7, "pkt_header" },
- { TEST8, "pkt_autokey" },
- { TEST9, "pkt_crypto" },
- { TEST10, "peer_stratum" },
- { TEST11, "peer_dist" },
- { TEST12, "peer_loop" },
- { TEST13, "peer_unreach" },
- { -1, "flash" }
+ { TEST1, "pkt_dup", 0 },
+ { TEST2, "pkt_bogus", 0 },
+ { TEST3, "pkt_unsync", 0 },
+ { TEST4, "pkt_denied", 0 },
+ { TEST5, "pkt_auth", 0 },
+ { TEST6, "pkt_stratum", 0 },
+ { TEST7, "pkt_header", 0 },
+ { TEST8, "pkt_autokey", 0 },
+ { TEST9, "pkt_crypto", 0 },
+ { TEST10, "peer_stratum", 0 },
+ { TEST11, "peer_dist", 0 },
+ { TEST12, "peer_loop", 0 },
+ { TEST13, "peer_unreach", 0 },
+ { -1, "flash", 0 }
};
#endif
@@ -110,56 +111,56 @@ static const struct codestring flash_codes[] = {
* System events (sys)
*/
static const struct codestring sys_codes[] = {
- { EVNT_UNSPEC, "unspecified" },
- { EVNT_NSET, "freq_not_set" },
- { EVNT_FSET, "freq_set" },
- { EVNT_SPIK, "spike_detect" },
- { EVNT_FREQ, "freq_mode" },
- { EVNT_SYNC, "clock_sync" },
- { EVNT_SYSRESTART, "restart" },
- { EVNT_SYSFAULT, "panic_stop" },
- { EVNT_NOPEER, "no_sys_peer" },
- { EVNT_ARMED, "leap_armed" },
- { EVNT_DISARMED, "leap_disarmed" },
- { EVNT_LEAP, "leap_event" },
- { EVNT_CLOCKRESET, "clock_step" },
- { EVNT_KERN, "kern" },
- { EVNT_TAI, "TAI" },
- { EVNT_LEAPVAL, "stale_leapsecond_values" },
- { -1, "" }
+ { EVNT_UNSPEC, "unspecified", 0 },
+ { EVNT_NSET, "freq_not_set", 0 },
+ { EVNT_FSET, "freq_set", 0 },
+ { EVNT_SPIK, "spike_detect", 0 },
+ { EVNT_FREQ, "freq_mode", 0 },
+ { EVNT_SYNC, "clock_sync", 0 },
+ { EVNT_SYSRESTART, "restart", 0 },
+ { EVNT_SYSFAULT, "panic_stop", 0 },
+ { EVNT_NOPEER, "no_sys_peer", 0 },
+ { EVNT_ARMED, "leap_armed", 0 },
+ { EVNT_DISARMED, "leap_disarmed", 0 },
+ { EVNT_LEAP, "leap_event", 0 },
+ { EVNT_CLOCKRESET, "clock_step", 0 },
+ { EVNT_KERN, "kern", 0 },
+ { EVNT_TAI, "TAI", 0 },
+ { EVNT_LEAPVAL, "stale_leapsecond_values", 0 },
+ { -1, "", 0 }
};
/*
* Peer events (peer)
*/
static const struct codestring peer_codes[] = {
- { PEVNT_MOBIL & ~PEER_EVENT, "mobilize" },
- { PEVNT_DEMOBIL & ~PEER_EVENT, "demobilize" },
- { PEVNT_UNREACH & ~PEER_EVENT, "unreachable" },
- { PEVNT_REACH & ~PEER_EVENT, "reachable" },
- { PEVNT_RESTART & ~PEER_EVENT, "restart" },
- { PEVNT_REPLY & ~PEER_EVENT, "no_reply" },
- { PEVNT_RATE & ~PEER_EVENT, "rate_exceeded" },
- { PEVNT_DENY & ~PEER_EVENT, "access_denied" },
- { PEVNT_ARMED & ~PEER_EVENT, "leap_armed" },
- { PEVNT_NEWPEER & ~PEER_EVENT, "sys_peer" },
- { PEVNT_CLOCK & ~PEER_EVENT, "clock_event" },
- { PEVNT_AUTH & ~PEER_EVENT, "bad_auth" },
- { PEVNT_POPCORN & ~PEER_EVENT, "popcorn" },
- { PEVNT_XLEAVE & ~PEER_EVENT, "interleave_mode" },
- { PEVNT_XERR & ~PEER_EVENT, "interleave_error" },
- { -1, "" }
+ { PEVNT_MOBIL & ~PEER_EVENT, "mobilize", 0 },
+ { PEVNT_DEMOBIL & ~PEER_EVENT, "demobilize", 0 },
+ { PEVNT_UNREACH & ~PEER_EVENT, "unreachable", 0 },
+ { PEVNT_REACH & ~PEER_EVENT, "reachable", 0 },
+ { PEVNT_RESTART & ~PEER_EVENT, "restart", 0 },
+ { PEVNT_REPLY & ~PEER_EVENT, "no_reply", 0 },
+ { PEVNT_RATE & ~PEER_EVENT, "rate_exceeded", 0 },
+ { PEVNT_DENY & ~PEER_EVENT, "access_denied", 0 },
+ { PEVNT_ARMED & ~PEER_EVENT, "leap_armed", 0 },
+ { PEVNT_NEWPEER & ~PEER_EVENT, "sys_peer", 0 },
+ { PEVNT_CLOCK & ~PEER_EVENT, "clock_event", 0 },
+ { PEVNT_AUTH & ~PEER_EVENT, "bad_auth", 0 },
+ { PEVNT_POPCORN & ~PEER_EVENT, "popcorn", 0 },
+ { PEVNT_XLEAVE & ~PEER_EVENT, "interleave_mode", 0 },
+ { PEVNT_XERR & ~PEER_EVENT, "interleave_error", 0 },
+ { -1, "", 0 }
};
/*
* Peer status bits
*/
static const struct codestring peer_st_bits[] = {
- { CTL_PST_CONFIG, "conf" },
- { CTL_PST_AUTHENABLE, "authenb" },
- { CTL_PST_AUTHENTIC, "auth" },
- { CTL_PST_REACH, "reach" },
- { CTL_PST_BCAST, "bcast" },
+ { CTL_PST_CONFIG, "conf", 0 },
+ { CTL_PST_AUTHENABLE, "authenb", 0 },
+ { CTL_PST_AUTHENTIC, "auth", 0 },
+ { CTL_PST_REACH, "reach", 0 },
+ { CTL_PST_BCAST, "bcast", 0 },
/* not used with getcode(), no terminating entry needed */
};
@@ -167,9 +168,9 @@ static const struct codestring peer_st_bits[] = {
* Restriction match bits
*/
static const struct codestring res_match_bits[] = {
- { RESM_NTPONLY, "ntpport" },
- { RESM_INTERFACE, "interface" },
- { RESM_SOURCE, "source" },
+ { RESM_NTPONLY, "ntpport", 0 },
+ { RESM_INTERFACE, "interface", 0 },
+ { RESM_SOURCE, "source", 0 },
/* not used with getcode(), no terminating entry needed */
};
@@ -177,18 +178,19 @@ static const struct codestring res_match_bits[] = {
* Restriction access bits
*/
static const struct codestring res_access_bits[] = {
- { RES_IGNORE, "ignore" },
- { RES_DONTSERVE, "noserve" },
- { RES_DONTTRUST, "notrust" },
- { RES_NOQUERY, "noquery" },
- { RES_NOMODIFY, "nomodify" },
- { RES_NOPEER, "nopeer" },
- { RES_NOTRAP, "notrap" },
- { RES_LPTRAP, "lptrap" },
- { RES_LIMITED, "limited" },
- { RES_VERSION, "version" },
- { RES_KOD, "kod" },
- { RES_FLAKE, "flake" },
+ { RES_IGNORE, "ignore", 0 },
+ { RES_DONTSERVE, "noserve", "serve" },
+ { RES_DONTTRUST, "notrust", "trust" },
+ { RES_NOQUERY, "noquery", "query" },
+ { RES_NOMODIFY, "nomodify", 0 },
+ { RES_NOPEER, "nopeer", "peer" },
+ { RES_NOEPEER, "noepeer", "epeer" },
+ { RES_NOTRAP, "notrap", "trap" },
+ { RES_LPTRAP, "lptrap", 0 },
+ { RES_LIMITED, "limited", 0 },
+ { RES_VERSION, "version", 0 },
+ { RES_KOD, "kod", 0 },
+ { RES_FLAKE, "flake", 0 },
/* not used with getcode(), no terminating entry needed */
};
@@ -197,23 +199,23 @@ static const struct codestring res_access_bits[] = {
* Crypto events (cryp)
*/
static const struct codestring crypto_codes[] = {
- { XEVNT_OK & ~CRPT_EVENT, "success" },
- { XEVNT_LEN & ~CRPT_EVENT, "bad_field_format_or_length" },
- { XEVNT_TSP & ~CRPT_EVENT, "bad_timestamp" },
- { XEVNT_FSP & ~CRPT_EVENT, "bad_filestamp" },
- { XEVNT_PUB & ~CRPT_EVENT, "bad_or_missing_public_key" },
- { XEVNT_MD & ~CRPT_EVENT, "unsupported_digest_type" },
- { XEVNT_KEY & ~CRPT_EVENT, "unsupported_identity_type" },
- { XEVNT_SGL & ~CRPT_EVENT, "bad_signature_length" },
- { XEVNT_SIG & ~CRPT_EVENT, "signature_not_verified" },
- { XEVNT_VFY & ~CRPT_EVENT, "certificate_not_verified" },
- { XEVNT_PER & ~CRPT_EVENT, "host_certificate_expired" },
- { XEVNT_CKY & ~CRPT_EVENT, "bad_or_missing_cookie" },
- { XEVNT_DAT & ~CRPT_EVENT, "bad_or_missing_leapseconds" },
- { XEVNT_CRT & ~CRPT_EVENT, "bad_or_missing_certificate" },
- { XEVNT_ID & ~CRPT_EVENT, "bad_or_missing_group key" },
- { XEVNT_ERR & ~CRPT_EVENT, "protocol_error" },
- { -1, "" }
+ { XEVNT_OK & ~CRPT_EVENT, "success", 0 },
+ { XEVNT_LEN & ~CRPT_EVENT, "bad_field_format_or_length", 0 },
+ { XEVNT_TSP & ~CRPT_EVENT, "bad_timestamp", 0 },
+ { XEVNT_FSP & ~CRPT_EVENT, "bad_filestamp", 0 },
+ { XEVNT_PUB & ~CRPT_EVENT, "bad_or_missing_public_key", 0 },
+ { XEVNT_MD & ~CRPT_EVENT, "unsupported_digest_type", 0 },
+ { XEVNT_KEY & ~CRPT_EVENT, "unsupported_identity_type", 0 },
+ { XEVNT_SGL & ~CRPT_EVENT, "bad_signature_length", 0 },
+ { XEVNT_SIG & ~CRPT_EVENT, "signature_not_verified", 0 },
+ { XEVNT_VFY & ~CRPT_EVENT, "certificate_not_verified", 0 },
+ { XEVNT_PER & ~CRPT_EVENT, "host_certificate_expired", 0 },
+ { XEVNT_CKY & ~CRPT_EVENT, "bad_or_missing_cookie", 0 },
+ { XEVNT_DAT & ~CRPT_EVENT, "bad_or_missing_leapseconds", 0 },
+ { XEVNT_CRT & ~CRPT_EVENT, "bad_or_missing_certificate", 0 },
+ { XEVNT_ID & ~CRPT_EVENT, "bad_or_missing_group key", 0 },
+ { XEVNT_ERR & ~CRPT_EVENT, "protocol_error", 0 },
+ { -1, "", 0 }
};
#endif /* AUTOKEY */
@@ -223,52 +225,52 @@ static const struct codestring crypto_codes[] = {
*/
static const struct codestring k_st_bits[] = {
# ifdef STA_PLL
- { STA_PLL, "pll" },
+ { STA_PLL, "pll", 0 },
# endif
# ifdef STA_PPSFREQ
- { STA_PPSFREQ, "ppsfreq" },
+ { STA_PPSFREQ, "ppsfreq", 0 },
# endif
# ifdef STA_PPSTIME
- { STA_PPSTIME, "ppstime" },
+ { STA_PPSTIME, "ppstime", 0 },
# endif
# ifdef STA_FLL
- { STA_FLL, "fll" },
+ { STA_FLL, "fll", 0 },
# endif
# ifdef STA_INS
- { STA_INS, "ins" },
+ { STA_INS, "ins", 0 },
# endif
# ifdef STA_DEL
- { STA_DEL, "del" },
+ { STA_DEL, "del", 0 },
# endif
# ifdef STA_UNSYNC
- { STA_UNSYNC, "unsync" },
+ { STA_UNSYNC, "unsync", 0 },
# endif
# ifdef STA_FREQHOLD
- { STA_FREQHOLD, "freqhold" },
+ { STA_FREQHOLD, "freqhold", 0 },
# endif
# ifdef STA_PPSSIGNAL
- { STA_PPSSIGNAL, "ppssignal" },
+ { STA_PPSSIGNAL, "ppssignal", 0 },
# endif
# ifdef STA_PPSJITTER
- { STA_PPSJITTER, "ppsjitter" },
+ { STA_PPSJITTER, "ppsjitter", 0 },
# endif
# ifdef STA_PPSWANDER
- { STA_PPSWANDER, "ppswander" },
+ { STA_PPSWANDER, "ppswander", 0 },
# endif
# ifdef STA_PPSERROR
- { STA_PPSERROR, "ppserror" },
+ { STA_PPSERROR, "ppserror", 0 },
# endif
# ifdef STA_CLOCKERR
- { STA_CLOCKERR, "clockerr" },
+ { STA_CLOCKERR, "clockerr", 0 },
# endif
# ifdef STA_NANO
- { STA_NANO, "nano" },
+ { STA_NANO, "nano", 0 },
# endif
# ifdef STA_MODE
- { STA_MODE, "mode=fll" },
+ { STA_MODE, "mode=fll", 0 },
# endif
# ifdef STA_CLK
- { STA_CLK, "src=B" },
+ { STA_CLK, "src=B", 0 },
# endif
/* not used with getcode(), no terminating entry needed */
};
@@ -292,12 +294,12 @@ getcode(
while (codetab->code != -1) {
if (codetab->code == code)
- return codetab->string;
+ return codetab->string1;
codetab++;
}
LIB_GETBUF(buf);
- snprintf(buf, LIB_BUFLENGTH, "%s_%d", codetab->string, code);
+ snprintf(buf, LIB_BUFLENGTH, "%s_%d", codetab->string1, code);
return buf;
}
@@ -354,10 +356,18 @@ decode_bitflags(
sep = "";
for (b = 0; b < tab_ct; b++) {
+ const char * flagstr;
+
if (tab[b].code & bits) {
+ flagstr = tab[b].string1;
+ } else {
+ flagstr = tab[b].string0;
+ }
+
+ if (flagstr) {
size_t avail = lim - pch;
rc = snprintf(pch, avail, "%s%s", sep,
- tab[b].string);
+ flagstr);
if ((size_t)rc >= avail)
goto toosmall;
pch += rc;
diff --git a/libntp/systime.c b/libntp/systime.c
index 29f1e86375e2..8e70897466cb 100644
--- a/libntp/systime.c
+++ b/libntp/systime.c
@@ -5,8 +5,10 @@
*
*/
#include <config.h>
+#include <math.h>
#include "ntp.h"
+#include "ntpd.h"
#include "ntp_syslog.h"
#include "ntp_stdlib.h"
#include "ntp_random.h"
@@ -14,6 +16,7 @@
#include "timevalops.h"
#include "timespecops.h"
#include "ntp_calendar.h"
+#include "lib_strbuf.h"
#ifdef HAVE_SYS_PARAM_H
# include <sys/param.h>
@@ -28,6 +31,9 @@
int allow_panic = FALSE; /* allow panic correction (-g) */
int enable_panic_check = TRUE; /* Can we check allow_panic's state? */
+u_long sys_lamport; /* Lamport violation */
+u_long sys_tsrounding; /* timestamp rounding errors */
+
#ifndef USE_COMPILETIME_PIVOT
# define USE_COMPILETIME_PIVOT 1
#endif
@@ -110,7 +116,10 @@ set_sys_fuzz(
sys_fuzz = fuzz_val;
INSIST(sys_fuzz >= 0);
INSIST(sys_fuzz <= 1.0);
- sys_fuzz_nsec = (long)(sys_fuzz * 1e9 + 0.5);
+ /* [Bug 3450] ensure nsec fuzz >= sys_fuzz to reduce chance of
+ * short-falling fuzz advance
+ */
+ sys_fuzz_nsec = (long)ceil(sys_fuzz * 1e9);
}
@@ -168,13 +177,10 @@ get_systime(
static struct timespec ts_last; /* last sampled os time */
static struct timespec ts_prev; /* prior os time */
static l_fp lfp_prev; /* prior result */
- static double dfuzz_prev; /* prior fuzz */
struct timespec ts; /* seconds and nanoseconds */
struct timespec ts_min; /* earliest permissible */
struct timespec ts_lam; /* lamport fictional increment */
- struct timespec ts_prev_log; /* for msyslog only */
double dfuzz;
- double ddelta;
l_fp result;
l_fp lfpfuzz;
l_fp lfpdelta;
@@ -191,8 +197,10 @@ get_systime(
* introduce small steps backward. It should not be an issue on
* systems where get_ostime() results in a true syscall.)
*/
- if (cmp_tspec(add_tspec_ns(ts, 50000000), ts_last) < 0)
+ if (cmp_tspec(add_tspec_ns(ts, 50000000), ts_last) < 0) {
lamport_violated = 1;
+ sys_lamport++;
+ }
ts_last = ts;
/*
@@ -216,21 +224,16 @@ get_systime(
if (!lamport_violated)
ts = ts_min;
}
- ts_prev_log = ts_prev;
ts_prev = ts;
- } else {
- /*
- * Quiet "ts_prev_log.tv_sec may be used uninitialized"
- * warning from x86 gcc 4.5.2.
- */
- ZERO(ts_prev_log);
}
/* convert from timespec to l_fp fixed-point */
result = tspec_stamp_to_lfp(ts);
/*
- * Add in the fuzz.
+ * Add in the fuzz. 'ntp_random()' returns [0..2**31-1] so we
+ * must scale up the result by 2.0 to cover the full fractional
+ * range.
*/
dfuzz = ntp_random() * 2. / FRAC * sys_fuzz;
DTOLFP(dfuzz, &lfpfuzz);
@@ -240,30 +243,34 @@ get_systime(
* Ensure result is strictly greater than prior result (ignoring
* sys_residual's effect for now) once sys_fuzz has been
* determined.
+ *
+ * [Bug 3450] Rounding errors and time slew can lead to a
+ * violation of the expected postcondition. This is bound to
+ * happen from time to time (depending on state of the random
+ * generator, the current slew and the closeness of system time
+ * stamps drawn) and does not warrant a syslog entry. Instead it
+ * makes much more sense to ensure the postcondition and hop
+ * along silently.
*/
if (!USING_SIGIO()) {
- if (!L_ISZERO(&lfp_prev) && !lamport_violated) {
- if (!L_ISGTU(&result, &lfp_prev) &&
- sys_fuzz > 0.) {
- msyslog(LOG_ERR, "ts_prev %s ts_min %s",
- tspectoa(ts_prev_log),
- tspectoa(ts_min));
- msyslog(LOG_ERR, "ts %s", tspectoa(ts));
- msyslog(LOG_ERR, "sys_fuzz %ld nsec, prior fuzz %.9f",
- sys_fuzz_nsec, dfuzz_prev);
- msyslog(LOG_ERR, "this fuzz %.9f",
- dfuzz);
- lfpdelta = lfp_prev;
- L_SUB(&lfpdelta, &result);
- LFPTOD(&lfpdelta, ddelta);
- msyslog(LOG_ERR,
- "prev get_systime 0x%x.%08x is %.9f later than 0x%x.%08x",
- lfp_prev.l_ui, lfp_prev.l_uf,
- ddelta, result.l_ui, result.l_uf);
+ if ( !L_ISZERO(&lfp_prev)
+ && !lamport_violated
+ && (sys_fuzz > 0.0)
+ ) {
+ lfpdelta = result;
+ L_SUB(&lfpdelta, &lfp_prev);
+ L_SUBUF(&lfpdelta, 1);
+ if (lfpdelta.l_i < 0)
+ {
+ L_NEG(&lfpdelta);
+ DPRINTF(1, ("get_systime: postcond failed by %s secs, fixed\n",
+ lfptoa(&lfpdelta, 9)));
+ result = lfp_prev;
+ L_ADDUF(&result, 1);
+ sys_tsrounding++;
}
}
lfp_prev = result;
- dfuzz_prev = dfuzz;
if (lamport_violated)
lamport_violated = FALSE;
}
@@ -362,105 +369,16 @@ adj_systime(
}
#endif
-
/*
- * step_systime - step the system clock.
+ * helper to keep utmp/wtmp up to date
*/
-
-int
-step_systime(
- double step
+static void
+update_uwtmp(
+ struct timeval timetv,
+ struct timeval tvlast
)
{
- time_t pivot; /* for ntp era unfolding */
- struct timeval timetv, tvlast, tvdiff;
- struct timespec timets;
- struct calendar jd;
- l_fp fp_ofs, fp_sys; /* offset and target system time in FP */
-
- /*
- * Get pivot time for NTP era unfolding. Since we don't step
- * very often, we can afford to do the whole calculation from
- * scratch. And we're not in the time-critical path yet.
- */
-#if SIZEOF_TIME_T > 4
- /*
- * This code makes sure the resulting time stamp for the new
- * system time is in the 2^32 seconds starting at 1970-01-01,
- * 00:00:00 UTC.
- */
- pivot = 0x80000000;
-#if USE_COMPILETIME_PIVOT
- /*
- * Add the compile time minus 10 years to get a possible target
- * area of (compile time - 10 years) to (compile time + 126
- * years). This should be sufficient for a given binary of
- * NTPD.
- */
- if (ntpcal_get_build_date(&jd)) {
- jd.year -= 10;
- pivot += ntpcal_date_to_time(&jd);
- } else {
- msyslog(LOG_ERR,
- "step-systime: assume 1970-01-01 as build date");
- }
-#else
- UNUSED_LOCAL(jd);
-#endif /* USE_COMPILETIME_PIVOT */
-#else
- UNUSED_LOCAL(jd);
- /* This makes sure the resulting time stamp is on or after
- * 1969-12-31/23:59:59 UTC and gives us additional two years,
- * from the change of NTP era in 2036 to the UNIX rollover in
- * 2038. (Minus one second, but that won't hurt.) We *really*
- * need a longer 'time_t' after that! Or a different baseline,
- * but that would cause other serious trouble, too.
- */
- pivot = 0x7FFFFFFF;
-#endif
-
- /* get the complete jump distance as l_fp */
- DTOLFP(sys_residual, &fp_sys);
- DTOLFP(step, &fp_ofs);
- L_ADD(&fp_ofs, &fp_sys);
-
- /* ---> time-critical path starts ---> */
-
- /* get the current time as l_fp (without fuzz) and as struct timeval */
- get_ostime(&timets);
- fp_sys = tspec_stamp_to_lfp(timets);
- tvlast.tv_sec = timets.tv_sec;
- tvlast.tv_usec = (timets.tv_nsec + 500) / 1000;
-
- /* get the target time as l_fp */
- L_ADD(&fp_sys, &fp_ofs);
-
- /* unfold the new system time */
- timetv = lfp_stamp_to_tval(fp_sys, &pivot);
-
- /* now set new system time */
- if (ntp_set_tod(&timetv, NULL) != 0) {
- msyslog(LOG_ERR, "step-systime: %m");
- if (enable_panic_check && allow_panic) {
- msyslog(LOG_ERR, "step_systime: allow_panic is TRUE!");
- }
- return FALSE;
- }
-
- /* <--- time-critical path ended with 'ntp_set_tod()' <--- */
-
- sys_residual = 0;
- lamport_violated = (step < 0);
- if (step_callback)
- (*step_callback)();
-
-#ifdef NEED_HPUX_ADJTIME
- /*
- * CHECKME: is this correct when called by ntpdate?????
- */
- _clear_adjtime();
-#endif
-
+ struct timeval tvdiff;
/*
* FreeBSD, for example, has:
* struct utmp {
@@ -589,6 +507,83 @@ step_systime(
#endif /* UPDATE_WTMPX */
}
+}
+
+/*
+ * step_systime - step the system clock.
+ */
+
+int
+step_systime(
+ double step
+ )
+{
+ time_t pivot; /* for ntp era unfolding */
+ struct timeval timetv, tvlast;
+ struct timespec timets;
+ l_fp fp_ofs, fp_sys; /* offset and target system time in FP */
+
+ /*
+ * Get pivot time for NTP era unfolding. Since we don't step
+ * very often, we can afford to do the whole calculation from
+ * scratch. And we're not in the time-critical path yet.
+ */
+#if SIZEOF_TIME_T > 4
+ pivot = basedate_get_eracenter();
+#else
+ /* This makes sure the resulting time stamp is on or after
+ * 1969-12-31/23:59:59 UTC and gives us additional two years,
+ * from the change of NTP era in 2036 to the UNIX rollover in
+ * 2038. (Minus one second, but that won't hurt.) We *really*
+ * need a longer 'time_t' after that! Or a different baseline,
+ * but that would cause other serious trouble, too.
+ */
+ pivot = 0x7FFFFFFF;
+#endif
+
+ /* get the complete jump distance as l_fp */
+ DTOLFP(sys_residual, &fp_sys);
+ DTOLFP(step, &fp_ofs);
+ L_ADD(&fp_ofs, &fp_sys);
+
+ /* ---> time-critical path starts ---> */
+
+ /* get the current time as l_fp (without fuzz) and as struct timeval */
+ get_ostime(&timets);
+ fp_sys = tspec_stamp_to_lfp(timets);
+ tvlast.tv_sec = timets.tv_sec;
+ tvlast.tv_usec = (timets.tv_nsec + 500) / 1000;
+
+ /* get the target time as l_fp */
+ L_ADD(&fp_sys, &fp_ofs);
+
+ /* unfold the new system time */
+ timetv = lfp_stamp_to_tval(fp_sys, &pivot);
+
+ /* now set new system time */
+ if (ntp_set_tod(&timetv, NULL) != 0) {
+ msyslog(LOG_ERR, "step-systime: %m");
+ if (enable_panic_check && allow_panic) {
+ msyslog(LOG_ERR, "step_systime: allow_panic is TRUE!");
+ }
+ return FALSE;
+ }
+
+ /* <--- time-critical path ended with 'ntp_set_tod()' <--- */
+
+ sys_residual = 0;
+ lamport_violated = (step < 0);
+ if (step_callback)
+ (*step_callback)();
+
+#ifdef NEED_HPUX_ADJTIME
+ /*
+ * CHECKME: is this correct when called by ntpdate?????
+ */
+ _clear_adjtime();
+#endif
+
+ update_uwtmp(timetv, tvlast);
if (enable_panic_check && allow_panic) {
msyslog(LOG_ERR, "step_systime: allow_panic is TRUE!");
INSIST(!allow_panic);
@@ -596,4 +591,93 @@ step_systime(
return TRUE;
}
+static const char *
+tv_fmt_libbuf(
+ const struct timeval * ptv
+ )
+{
+ char * retv;
+ vint64 secs;
+ ntpcal_split dds;
+ struct calendar jd;
+
+ secs = time_to_vint64(&ptv->tv_sec);
+ dds = ntpcal_daysplit(&secs);
+ ntpcal_daysplit_to_date(&jd, &dds, DAY_UNIX_STARTS);
+ LIB_GETBUF(retv);
+ snprintf(retv, LIB_BUFLENGTH,
+ "%04hu-%02hu-%02hu/%02hu:%02hu:%02hu.%06u",
+ jd.year, (u_short)jd.month, (u_short)jd.monthday,
+ (u_short)jd.hour, (u_short)jd.minute, (u_short)jd.second,
+ (u_int)ptv->tv_usec);
+ return retv;
+}
+
+
+int /*BOOL*/
+clamp_systime(void)
+{
+#if SIZEOF_TIME_T > 4
+
+ struct timeval timetv, tvlast;
+ struct timespec timets;
+ uint32_t tdiff;
+
+
+ timetv.tv_sec = basedate_get_erabase();
+
+ /* ---> time-critical path starts ---> */
+
+ /* get the current time as l_fp (without fuzz) and as struct timeval */
+ get_ostime(&timets);
+ tvlast.tv_sec = timets.tv_sec;
+ tvlast.tv_usec = (timets.tv_nsec + 500) / 1000;
+ if (tvlast.tv_usec >= 1000000) {
+ tvlast.tv_usec -= 1000000;
+ tvlast.tv_sec += 1;
+ }
+ timetv.tv_usec = tvlast.tv_usec;
+
+ tdiff = (uint32_t)(tvlast.tv_sec & UINT32_MAX) -
+ (uint32_t)(timetv.tv_sec & UINT32_MAX);
+ timetv.tv_sec += tdiff;
+ if (timetv.tv_sec != tvlast.tv_sec) {
+ /* now set new system time */
+ if (ntp_set_tod(&timetv, NULL) != 0) {
+ msyslog(LOG_ERR, "clamp-systime: %m");
+ return FALSE;
+ }
+ } else {
+ msyslog(LOG_INFO,
+ "clamp-systime: clock (%s) in allowed range",
+ tv_fmt_libbuf(&timetv));
+ return FALSE;
+ }
+
+ /* <--- time-critical path ended with 'ntp_set_tod()' <--- */
+
+ sys_residual = 0;
+ lamport_violated = (timetv.tv_sec < tvlast.tv_sec);
+ if (step_callback)
+ (*step_callback)();
+
+# ifdef NEED_HPUX_ADJTIME
+ /*
+ * CHECKME: is this correct when called by ntpdate?????
+ */
+ _clear_adjtime();
+# endif
+
+ update_uwtmp(timetv, tvlast);
+ msyslog(LOG_WARNING,
+ "clamp-systime: clock stepped from %s to %s!",
+ tv_fmt_libbuf(&tvlast), tv_fmt_libbuf(&timetv));
+ return TRUE;
+
+#else
+
+ return 0;
+#endif
+}
+
#endif /* !SIM */
diff --git a/libntp/work_thread.c b/libntp/work_thread.c
index 82f6064fb359..433290c4c9a7 100644
--- a/libntp/work_thread.c
+++ b/libntp/work_thread.c
@@ -27,7 +27,7 @@
#define CHILD_GONE_RESP CHILD_EXIT_REQ
/* Queue size increments:
* The request queue grows a bit faster than the response queue -- the
- * deamon can push requests and pull results faster on avarage than the
+ * daemon can push requests and pull results faster on avarage than the
* worker can process requests and push results... If this really pays
* off is debatable.
*/