]> git.ipfire.org Git - thirdparty/ntp.git/commitdiff
[Bug 1531] Require nonce with mrulist requests.
authorDave Hart <hart@ntp.org>
Thu, 22 Apr 2010 10:06:01 +0000 (10:06 +0000)
committerDave Hart <hart@ntp.org>
Thu, 22 Apr 2010 10:06:01 +0000 (10:06 +0000)
[Bug 1532] Remove ntpd support for ntpdc's monlist in favor of ntpq's
  mrulist.

bk: 4bd01f892ejm36_aylOSZXisaW9PYw

ChangeLog
include/ntp_control.h
include/ntp_md5.h
include/ntpd.h
libntp/a_md5encrypt.c
ntpd/ntp_control.c
ntpd/ntp_request.c
ntpd/ntp_scanner.c
ntpq/ntpq-subs.c

index 793e83a0c2214e44ae1a4a69c5e02da602c6b71f..d769c8c745e4c601b06d67ae1646822ac5c35052 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,6 @@
+* [Bug 1531] Require nonce with mrulist requests.
+* [Bug 1532] Remove ntpd support for ntpdc's monlist in favor of ntpq's
+  mrulist.
 * Include (4.2.6p2-RC1) - [Bug 1503] [Bug 1504] [Bug 1518] [Bug 1522],
   all of which were fixed in 4.2.7 previously. 
 (4.2.7p24) 2010/04/13 Released by Harlan Stenn <stenn@ntp.org>
index 065be7b9d23d844a0eb61492c8aa7e742d28ea69..3b0156b3026d64532081b9e05af46eec7bb1b95d 100644 (file)
@@ -57,6 +57,7 @@ struct ntp_control {
 #define CTL_OP_SAVECONFIG      9       /* save config to file */
 #define CTL_OP_READ_MRU                10      /* retrieve MRU (mrulist) */
 #define CTL_OP_READ_IFSTATS    11      /* interface stats (ifstats) */
+#define CTL_OP_REQ_NONCE       12      /* request a client nonce */
 #define        CTL_OP_UNSETTRAP        31      /* unset trap */
 
 /*
index 5e2206b008abcbf401ea06b8e3d1e098d6b74715..458962fdab6f5dc4d3c40891293254a025878a56 100644 (file)
@@ -1,13 +1,29 @@
 /*
  * ntp_md5.h: deal with md5.h headers
+ *
+ * Use the system MD5 if available, otherwise libisc's.
  */
-
 #if defined HAVE_MD5_H && defined HAVE_MD5INIT
 # include <md5.h>
 #else
 # include "isc/md5.h"
-# define MD5_CTX       isc_md5_t
-# define MD5Init       isc_md5_init
-# define MD5Update     isc_md5_update
-# define MD5Final(d,c) isc_md5_final(c,d)
+  typedef isc_md5_t            MD5_CTX;
+# define MD5Init(c)            isc_md5_init(c)
+# define MD5Update(c, p, s)    isc_md5_update(c, p, s)
+# define MD5Final(d, c)                isc_md5_final((c), (d)) /* swapped */
+#endif
+
+/*
+ * Provide OpenSSL-alike MD5 API if we're not using OpenSSL
+ */
+#ifndef OPENSSL
+  typedef MD5_CTX                      EVP_MD_CTX;
+# define EVP_get_digestbynid(t)                NULL
+# define EVP_DigestInit(c, dt)         MD5Init(c)
+# define EVP_DigestUpdate(c, p, s)     MD5Update(c, p, s)
+# define EVP_DigestFinal(c, d, pdl)    \
+       do {                            \
+               MD5Final((d), (c));     \
+               *(pdl) = 16;            \
+       } while (0)
 #endif
index ed5776d79a22cce180b0606dac8da2c53bb4895e..01a4178f659919a490d7b8becc37cefae8275a4f 100644 (file)
@@ -527,6 +527,9 @@ extern restrict_u * restrictlist6;  /* IPv6 restriction list */
 extern int             ntp_minpkt;
 extern u_char          ntp_minpoll;
 
+/* ntp_scanner.c */
+extern u_int32         conf_file_sum;  /* Simple sum of characters */
+
 /* ntp_signd.c */
 #ifdef HAVE_NTP_SIGND
 extern void send_via_ntp_signd(struct recvbuf, int, keyid_t, int, 
index bd30ba2c6c8f7f6e264c1aa92424e9ed2d5e2bf7..05c109a9ff175758335d1691639bc6fdd392a290 100644 (file)
 #include "ntp_stdlib.h"
 #include "ntp.h"
 #ifdef OPENSSL
-#include "openssl/evp.h"
+# include "openssl/evp.h"
 #else
-#include "ntp_md5.h"
-#endif /* OPENSSSL */
+# include "ntp_md5.h"  /* provides clone of OpenSSL MD5 API */
+#endif
 
 /*
  * MD5authencrypt - generate message digest
@@ -30,30 +30,18 @@ MD5authencrypt(
 {
        u_char  digest[EVP_MAX_MD_SIZE];
        u_int   len;
-#ifdef OPENSSL
        EVP_MD_CTX ctx;
-#else
-       MD5_CTX md5;
-#endif /* OPENSSL */
 
        /*
         * Compute digest of key concatenated with packet. Note: the
         * key type and digest type have been verified when the key
         * was creaded.
         */
-#ifdef OPENSSL
        INIT_SSL();
        EVP_DigestInit(&ctx, EVP_get_digestbynid(type));
        EVP_DigestUpdate(&ctx, key, (u_int)cache_keylen);
        EVP_DigestUpdate(&ctx, (u_char *)pkt, (u_int)length);
        EVP_DigestFinal(&ctx, digest, &len);
-#else /* OPENSSL */
-       MD5Init(&md5);
-       MD5Update(&md5, key, (u_int)cache_keylen);
-       MD5Update(&md5, (u_char *)pkt, (u_int)length);
-       MD5Final(digest, &md5);
-       len = 16;
-#endif /* OPENSSL */
        memmove((u_char *)pkt + length + 4, digest, len);
        return (len + 4);
 }
@@ -75,30 +63,18 @@ MD5authdecrypt(
 {
        u_char  digest[EVP_MAX_MD_SIZE];
        u_int   len;
-#ifdef OPENSSL
        EVP_MD_CTX ctx;
-#else
-       MD5_CTX md5;
-#endif /* OPENSSL */
 
        /*
         * Compute digest of key concatenated with packet. Note: the
         * key type and digest type have been verified when the key
         * was created.
         */
-#ifdef OPENSSL
        INIT_SSL();
        EVP_DigestInit(&ctx, EVP_get_digestbynid(type));
        EVP_DigestUpdate(&ctx, key, (u_int)cache_keylen);
        EVP_DigestUpdate(&ctx, (u_char *)pkt, (u_int)length);
        EVP_DigestFinal(&ctx, digest, &len);
-#else /* OPENSSL */
-       MD5Init(&md5);
-       MD5Update(&md5, key, (u_int)cache_keylen);
-       MD5Update(&md5, (u_char *)pkt, (u_int)length);
-       MD5Final(digest, &md5);
-       len = 16;
-#endif /* OPENSSL */
        if ((u_int)size != len + 4) {
                msyslog(LOG_ERR,
                    "MAC decrypt: MAC length error");
@@ -117,28 +93,17 @@ addr2refid(sockaddr_u *addr)
 {
        u_char          digest[20];
        u_int32         addr_refid;
-#ifdef OPENSSL
        EVP_MD_CTX      ctx;
        u_int           len;
-#else
-       MD5_CTX md5;
-#endif /* OPENSSL */
 
        if (IS_IPV4(addr))
                return (NSRCADR(addr));
 
-#ifdef OPENSSL
        INIT_SSL();
        EVP_DigestInit(&ctx, EVP_get_digestbynid(NID_md5));
        EVP_DigestUpdate(&ctx, (u_char *)PSOCK_ADDR6(addr),
            sizeof(struct in6_addr));
        EVP_DigestFinal(&ctx, digest, &len);
-#else
-       MD5Init(&md5);
-       MD5Update(&md5, (u_char *)PSOCK_ADDR6(addr),
-           sizeof(struct in6_addr));
-       MD5Final(digest, &md5);
-#endif /* OPENSSL */
        memcpy(&addr_refid, digest, 4);
        return (addr_refid);
 }
index 14baee287f374067ac8d9223f774d013c5089ded..fec962525aeec9ee4435d9c0956164e1d985fd96 100644 (file)
 #endif
 #include <arpa/inet.h>
 
+#ifdef OPENSSL
+# include "openssl/evp.h"
+#else
+# include "ntp_md5.h"  /* provides clone of OpenSSL MD5 API */
+#endif
+
+
 /*
  * Structure to hold request procedure information
  */
@@ -82,8 +89,12 @@ static       void    configure       (struct recvbuf *, int);
 static void    send_mru_entry  (mon_entry *, int);
 static void    send_random_tag_value(int);
 static void    read_mru_list   (struct recvbuf *, int);
-static void    send_ifstats_entry(struct interface *, u_int);
+static void    send_ifstats_entry(struct interface *, u_int);
 static void    read_ifstats    (struct recvbuf *, int);
+static u_int32 derive_nonce    (sockaddr_u *, u_int32, u_int32);
+static void    generate_nonce  (struct recvbuf *, char *, size_t);
+static int     validate_nonce  (const char *, struct recvbuf *);
+static void    req_nonce       (struct recvbuf *, int);
 static void    unset_trap      (struct recvbuf *, int);
 static struct ctl_trap *ctlfindtrap(sockaddr_u *,
                                     struct interface *);
@@ -100,6 +111,7 @@ static      struct ctl_proc control_codes[] = {
        { CTL_OP_CONFIGURE,     AUTH,   configure },
        { CTL_OP_READ_MRU,      NOAUTH, read_mru_list },
        { CTL_OP_READ_IFSTATS,  AUTH,   read_ifstats },
+       { CTL_OP_REQ_NONCE,     NOAUTH, req_nonce },
        { CTL_OP_UNSETTRAP,     NOAUTH, unset_trap },
        { NO_REQUEST,           0 }
 };
@@ -2676,6 +2688,96 @@ static void configure(
 }
 
 
+/*
+ * derive_nonce - generate client-address-specific nonce value
+ *               associated with a given timestamp.
+ */
+static u_int32 derive_nonce(
+       sockaddr_u *    addr,
+       u_int32         ts_i,
+       u_int32         ts_f
+       )
+{
+       static u_int32  salt[2];
+       union d_tag {
+               u_char  digest[EVP_MAX_MD_SIZE];
+               u_int32 extract;
+       }               d;
+       EVP_MD_CTX      ctx;
+       u_int           len;
+
+       while (!salt[0])
+               salt[0] = ntp_random();
+       salt[1] = conf_file_sum;
+
+       EVP_DigestInit(&ctx, EVP_get_digestbynid(NID_md5));
+       EVP_DigestUpdate(&ctx, salt, sizeof(salt));
+       EVP_DigestUpdate(&ctx, &ts_i, sizeof(ts_i));
+       EVP_DigestUpdate(&ctx, &ts_f, sizeof(ts_f));
+       if (IS_IPV4(addr))
+               EVP_DigestUpdate(&ctx, &SOCK_ADDR4(addr),
+                                sizeof(SOCK_ADDR4(addr)));
+       else
+               EVP_DigestUpdate(&ctx, &SOCK_ADDR6(addr),
+                                sizeof(SOCK_ADDR6(addr)));
+       EVP_DigestUpdate(&ctx, &NSRCPORT(addr), sizeof(NSRCPORT(addr)));
+       EVP_DigestUpdate(&ctx, salt, sizeof(salt));
+       EVP_DigestFinal(&ctx, d.digest, &len);
+
+       return d.extract;
+}
+
+
+/*
+ * generate_nonce - generate client-address-specific nonce string.
+ */
+static void generate_nonce(
+       struct recvbuf *        rbufp,
+       char *                  nonce,
+       size_t                  nonce_octets
+       )
+{
+       u_int32 derived;
+
+       derived = derive_nonce(&rbufp->recv_srcadr,
+                              rbufp->recv_time.l_ui,
+                              rbufp->recv_time.l_uf);
+       snprintf(nonce, nonce_octets, "%08x%08x%08x",
+                rbufp->recv_time.l_ui, rbufp->recv_time.l_uf, derived);
+}
+
+
+/*
+ * validate_nonce - validate client-address-specific nonce string.
+ *
+ * Returns TRUE if the local calculation of the nonce matches the
+ * client-provided value and the timestamp is recent enough.
+ */
+static int validate_nonce(
+       const char *            pnonce,
+       struct recvbuf *        rbufp
+       )
+{
+       u_int   ts_i;
+       u_int   ts_f;
+       l_fp    ts;
+       l_fp    now_delta;
+       u_int   supposed;
+       u_int   derived;
+
+       if (3 != sscanf(pnonce, "%08x%08x%08x", &ts_i, &ts_f, &supposed))
+               return FALSE;
+
+       ts.l_ui = (u_int32)ts_i;
+       ts.l_uf = (u_int32)ts_f;
+       derived = derive_nonce(&rbufp->recv_srcadr, ts.l_ui, ts.l_uf);
+       get_systime(&now_delta);
+       L_SUB(&now_delta, &ts);
+
+       return (supposed == derived && now_delta.l_ui < 16);
+}
+
+
 /*
  * Send a MRU list entry in response to a "ntpq -c mrulist" operation.
  *
@@ -2755,7 +2857,7 @@ send_mru_entry(
  *                        random integer value.
  *
  * To try to force clients to ignore unrecognized tags in mrulist
- * and iflist responses, the first and last rows are spiced with
+ * and ifstats responses, the first and last rows are spiced with
  * randomly-generated tag names with correct .# index.
  * Make it three characters knowing that none of the currently-used
  * tags have that length, avoiding the need to test for tag collision.
@@ -2813,6 +2915,9 @@ send_random_tag_value(
  * backing up all the way to the starting point.
  *
  * input parameters:
+ *     nonce=          Regurgitated nonce retrieved by the client
+ *                     previously using CTL_OP_REQ_NONCE, demonstrating
+ *                     ability to receive traffic sent to its address.
  *     limit=          Limit on MRU entries returned.  This is the sole
  *                     required input parameter.  [1...256]
  *                     limit=1 is a special case:  Instead of fetching
@@ -2842,12 +2947,13 @@ send_random_tag_value(
  * ntpq provides as many last/addr pairs as will fit in a single request
  * packet, except for the first request in a MRU fetch operation.
  *
- * The response begins with the next newer entry than referred to by
- * last.0 and addr.0, if the "0" entry has not been bumped to the front.
- * Otherwise, it will begin with the next entry newer than referred to
- * by last.1 and addr.1, and so on.  If none of the referenced entries
- * remain unchanged, the request fails and ntpq backs up to the next
- * earlier set of entries to resync.
+ * The response begins with a new nonce value to be used for any
+ * followup request.  Following the nonce is the next newer entry than
+ * referred to by last.0 and addr.0, if the "0" entry has not been
+ * bumped to the front.  If it has, the first entry returned will be the
+ * next entry newer than referred to by last.1 and addr.1, and so on.
+ * If none of the referenced entries remain unchanged, the request fails
+ * and ntpq backs up to the next earlier set of entries to resync.
  *
  * Except for the first response, the response begins with confirmation
  * of the entry that precedes the first additional entry provided:
@@ -2893,6 +2999,7 @@ static void read_mru_list(
        int restrict_mask
        )
 {
+       const char              nonce_text[] =          "nonce";
        const char              limit_text[] =          "limit";
        const char              mincount_text[] =       "mincount";
        const char              resall_text[] =         "resall";
@@ -2917,6 +3024,8 @@ static void read_mru_list(
        struct ctl_var *        v;
        char *                  val;
        char *                  pch;
+       char *                  pnonce;
+       int                     nonce_valid;
        int                     i;
        int                     priors;
        u_short                 hash;
@@ -2928,6 +3037,7 @@ static void read_mru_list(
         * fill in_parms var list with all possible input parameters.
         */
        in_parms = NULL;
+       set_var(&in_parms, nonce_text, sizeof(nonce_text), 0);
        set_var(&in_parms, limit_text, sizeof(limit_text), 0);
        set_var(&in_parms, mincount_text, sizeof(mincount_text), 0);
        set_var(&in_parms, resall_text, sizeof(resall_text), 0);
@@ -2942,6 +3052,7 @@ static void read_mru_list(
        }
 
        /* decode input parms */
+       pnonce = NULL;
        limit = 0;
        mincount = 0;
        resall = 0;
@@ -2955,7 +3066,9 @@ static void read_mru_list(
        while (NULL != (v = ctl_getitem(in_parms, &val)) &&
               !(EOV & v->flags)) {
 
-               if (!strcmp(limit_text, v->text))
+               if (!strcmp(nonce_text, v->text))
+                       pnonce = estrdup(val);
+               else if (!strcmp(limit_text, v->text))
                        sscanf(val, "%u", &limit);
                else if (!strcmp(mincount_text, v->text)) {
                        if (1 != sscanf(val, "%d", &mincount) ||
@@ -2989,6 +3102,16 @@ static void read_mru_list(
        }
        free_varlist(in_parms);
        in_parms = NULL;
+
+       /* return no responses until the nonce is validated */
+       if (NULL == pnonce)
+               return;
+
+       nonce_valid = validate_nonce(pnonce, rbufp);
+       free(pnonce);
+       if (!nonce_valid)
+               return;
+
        if (!(0 < limit && limit <= MRU_ROW_LIMIT)) {
                ctl_error(CERR_BADVALUE);
                return;
@@ -3036,6 +3159,8 @@ static void read_mru_list(
         * send up to limit= entries
         */
        get_systime(&now);
+       generate_nonce(rbufp, buf, sizeof(buf));
+       ctl_putunqstr("nonce", buf, strlen(buf));
        prior_mon = NULL;
        for (count = 0;
             count < limit && mon != NULL;
@@ -3229,6 +3354,22 @@ static void read_ifstats(
 }
 
 
+/*
+ * req_nonce - CTL_OP_REQ_NONCE for ntpq -c mrulist prerequisite.
+ */
+static void req_nonce(
+       struct recvbuf *        rbufp,
+       int                     restrict_mask
+       )
+{
+       char    buf[64];
+
+       generate_nonce(rbufp, buf, sizeof(buf));
+       ctl_putunqstr("nonce", buf, strlen(buf));
+       ctl_flushpkt(0);
+}
+
+
 /*
  * read_clockstatus - return clock radio status
  */
index 419d417e23ad140ec414a862748be5525218c46c..27a4c56cba56b8ad9b2a2133af9cc4ad3f842d8c 100644 (file)
@@ -88,8 +88,7 @@ static        void    do_resaddflags  (sockaddr_u *, struct interface *, struct req_pkt *);
 static void    do_ressubflags  (sockaddr_u *, struct interface *, struct req_pkt *);
 static void    do_unrestrict   (sockaddr_u *, struct interface *, struct req_pkt *);
 static void    do_restrict     (sockaddr_u *, struct interface *, struct req_pkt *, int);
-static void    mon_getlist_0   (sockaddr_u *, struct interface *, struct req_pkt *);
-static void    mon_getlist_1   (sockaddr_u *, struct interface *, struct req_pkt *);
+static void    mon_getlist     (sockaddr_u *, struct interface *, struct req_pkt *);
 static void    reset_stats     (sockaddr_u *, struct interface *, struct req_pkt *);
 static void    reset_peer      (sockaddr_u *, struct interface *, struct req_pkt *);
 static void    do_key_reread   (sockaddr_u *, struct interface *, struct req_pkt *);
@@ -149,8 +148,8 @@ static      struct req_proc ntp_codes[] = {
                                sizeof(struct conf_restrict), do_ressubflags },
        { REQ_UNRESTRICT, AUTH, v4sizeof(struct conf_restrict),
                                sizeof(struct conf_restrict), do_unrestrict },
-       { REQ_MON_GETLIST,      NOAUTH, 0, 0,   mon_getlist_0 },
-       { REQ_MON_GETLIST_1,    NOAUTH, 0, 0,   mon_getlist_1 },
+       { REQ_MON_GETLIST,      NOAUTH, 0, 0,   mon_getlist },
+       { REQ_MON_GETLIST_1,    NOAUTH, 0, 0,   mon_getlist },
        { REQ_RESET_STATS, AUTH, sizeof(struct reset_flags), 0, reset_stats },
        { REQ_RESET_PEER,  AUTH, v4sizeof(struct conf_unpeer),
                                sizeof(struct conf_unpeer), reset_peer },
@@ -1874,125 +1873,15 @@ do_restrict(
  * mon_getlist - return monitor data
  */
 static void
-mon_getlist_0(
+mon_getlist(
        sockaddr_u *srcadr,
        struct interface *inter,
        struct req_pkt *inpkt
        )
 {
-       register struct info_monitor *im;
-       register mon_entry *md;
-       l_fp    now;
-       l_fp    diff;
-       size_t  count;
-
-       DPRINTF(3, ("wants monitor 0 list\n"));
-
-       if (!mon_enabled) {
-               req_ack(srcadr, inter, inpkt, INFO_ERR_NODATA);
-               return;
-       }
-       get_systime(&now);
-       im = (struct info_monitor *)prepare_pkt(srcadr, inter, inpkt,
-           v6sizeof(struct info_monitor));
-       count = 0;
-
-       ITER_DLIST_BEGIN(mon_mru_list, md, mru, mon_entry)
-               diff = now;
-               L_SUB(&diff, &md->first);
-               im->avg_int = htonl((u_int32)(diff.l_ui / md->count));
-               diff = now;
-               L_SUB(&diff, &md->last);
-               im->last_int = htonl(diff.l_ui);
-               im->restr = htonl(md->flags);
-               im->count = htonl((u_int32)(md->count));
-               if (IS_IPV6(&md->rmtadr)) {
-                       if (!client_v6_capable)
-                               continue;
-                       im->addr6 = SOCK_ADDR6(&md->rmtadr);
-                       im->v6_flag = 1;
-               } else {
-                       im->addr = NSRCADR(&md->rmtadr);
-                       if (client_v6_capable)
-                               im->v6_flag = 0;
-               }
-               im->port = NSRCPORT(&md->rmtadr);
-               im->mode = PKT_MODE(md->vn_mode);
-               im->version = PKT_VERSION(md->vn_mode);
-               im = (struct info_monitor *)more_pkt();
-               count++;
-               if (NULL == im || count >= 600)
-                       break;
-       ITER_DLIST_END()
-
-       flush_pkt();
+       req_ack(srcadr, inter, inpkt, INFO_ERR_NODATA);
 }
 
-/*
- * mon_getlist - return monitor data
- */
-static void
-mon_getlist_1(
-       sockaddr_u *srcadr,
-       struct interface *inter,
-       struct req_pkt *inpkt
-       )
-{
-       register struct info_monitor_1 *im;
-       register mon_entry *md;
-       l_fp    now;
-       l_fp    diff;
-       size_t  count;
-
-       if (!mon_enabled) {
-               req_ack(srcadr, inter, inpkt, INFO_ERR_NODATA);
-               return;
-       }
-       get_systime(&now);
-       im = (struct info_monitor_1 *)prepare_pkt(srcadr, inter, inpkt,
-           v6sizeof(struct info_monitor_1));
-       count = 0;
-
-       ITER_DLIST_BEGIN(mon_mru_list, md, mru, mon_entry)
-               diff = now;
-               L_SUB(&diff, &md->first);
-               im->avg_int = htonl((u_int32)(diff.l_ui / md->count));
-               diff = now;
-               L_SUB(&diff, &md->last);
-               im->last_int = htonl(diff.l_ui);
-               im->restr = htonl((u_int32)md->flags);
-               im->count = htonl((u_int32)md->count);
-               if (IS_IPV6(&md->rmtadr)) {
-                       if (!client_v6_capable)
-                               continue;
-                       im->addr6 = SOCK_ADDR6(&md->rmtadr);
-                       im->v6_flag = 1;
-                       im->daddr6 = SOCK_ADDR6(&md->lcladr->sin);
-               } else {
-                       im->addr = NSRCADR(&md->rmtadr);
-                       if (client_v6_capable)
-                               im->v6_flag = 0;
-                       if (MDF_BCAST == md->cast_flags)
-                               im->daddr = NSRCADR(&md->lcladr->bcast);
-                       else if (md->cast_flags) {
-                               im->daddr = NSRCADR(&md->lcladr->sin);
-                               if (!im->daddr)
-                                       im->daddr = NSRCADR(&md->lcladr->bcast);
-                       } else
-                               im->daddr = 4;
-               }
-               im->flags = htonl(md->cast_flags);
-               im->port = NSRCPORT(&md->rmtadr);
-               im->mode = PKT_MODE(md->vn_mode);
-               im->version = PKT_VERSION(md->vn_mode);
-               im = (struct info_monitor_1 *)more_pkt();
-               count++;
-               if (NULL == im || count >= 600)
-                       break;
-       ITER_DLIST_END()
-
-       flush_pkt();
-}
 
 /*
  * Module entry points and the flags they correspond with
index 9f1752399a4371ef0df65f9eeb525d1afa0b771c..5a882788625e6cc91679bb9483e245bd6d626b45 100644 (file)
@@ -36,6 +36,7 @@
 
 #define MAX_LEXEME (1024 + 1)  /* The maximum size of a lexeme */
 char yytext[MAX_LEXEME];       /* Buffer for storing the input text/lexeme */
+u_int32 conf_file_sum;         /* Simple sum of characters read */
 extern int input_from_file;
 
 
@@ -127,6 +128,8 @@ FGETC(
        while (EOF != ch && (CHAR_MIN > ch || ch > CHAR_MAX));
 
        if (EOF != ch) {
+               if (input_from_file)
+                       conf_file_sum += (u_char)ch;
                ++stream->col_no;
                if (ch == '\n') {
                        stream->prev_line_col_no = stream->col_no;
@@ -148,6 +151,8 @@ UNGETC(
        struct FILE_INFO *stream
        )
 {
+       if (input_from_file)
+               conf_file_sum -= (u_char)ch;
        if (ch == '\n') {
                stream->col_no = stream->prev_line_col_no;
                stream->prev_line_col_no = -1;
index 2df0e4f94554ece556f4065f724cd1a37ffadb12..21876635f53eb7d6b10daf193c2779105d26338a 100644 (file)
@@ -2256,11 +2256,13 @@ collect_mru_list(
        int c_mru_l_rc;         /* this function's return code */
        u_char got;             /* MRU_GOT_* bits */
        const char ts_fmt[] = "0x%08x.%08x";
+       const char nonce_eq[] = "nonce=";
        size_t cb;
        mru *mon;
        mru *head;
        mru *recent;
        int list_complete;
+       char nonce[128];
        char buf[128];
        char req_buf[CTL_MAX_DATA_LEN];
        char *req;
@@ -2286,6 +2288,31 @@ collect_mru_list(
        u_short hash;
        mru *unlinked;
 
+       /*
+        * Retrieve a nonce specific to this client to demonstrate to
+        * ntpd that we're capable of receiving responses to our source
+        * IP address, and thereby unlikely to be forging the source.
+        */
+       qres = doquery(CTL_OP_REQ_NONCE, 0, 0, 0, NULL, &rstatus,
+                      &rsize, &rdata);
+       if (qres) {
+               fprintf(stderr, "nonce request failed\n");
+               return FALSE;
+       }
+
+       if (strncmp(rdata, nonce_eq, sizeof(nonce_eq) - 1)) {
+               fprintf(stderr, "unexpected nonce response format: %.*s\n",
+                       rsize, rdata);
+               return FALSE;
+       }
+       strncpy(nonce, rdata + sizeof(nonce_eq) - 1, sizeof(nonce));
+       chars = strlen(nonce);
+       while (chars > 0 &&
+              ('\r' == nonce[chars - 1] || '\n' == nonce[chars - 1])) {
+               chars--;
+               nonce[chars] = '\0';
+       }
+
        mru_count = 0;
        INIT_DLIST(mru_list, mlink);
        cb = NTP_HASH_SIZE * sizeof(*hash_table);
@@ -2304,11 +2331,12 @@ collect_mru_list(
        memset(&last_older, 0, sizeof(last_older));
 
        limit = min(3 * MAXFRAGS, ntpd_row_limit);
-       snprintf(req_buf, sizeof(req_buf), "limit=%d%s", limit, parms);
+       snprintf(req_buf, sizeof(req_buf), "nonce=%s, limit=%d%s",
+                nonce, limit, parms);
 
        while (TRUE) {
                if (debug)
-                       fprintf(stderr, "READ_MRU: %s\n", req_buf);
+                       fprintf(stderr, "READ_MRU parms: %s\n", req_buf);
                                
                qres = doqueryex(CTL_OP_READ_MRU, 0, 0, strlen(req_buf),
                                 req_buf, &rstatus, &rsize, &rdata, TRUE);
@@ -2334,7 +2362,7 @@ collect_mru_list(
                                NTP_INSIST(unlinked == recent);
                                free(recent);
                        }
-               } else if (CERR_BADVALUE == qres /* temp -> */ || CERR_BADFMT == qres /* <- temp */) {
+               } else if (CERR_BADVALUE == qres) {
                        /* ntpd has lower cap on row limit */
                        ntpd_row_limit--;
                        limit = min(limit, ntpd_row_limit);
@@ -2474,7 +2502,11 @@ collect_mru_list(
                                break;
 
                        case 'n':
-                               if (strcmp(tag, "now") ||
+                               if (!strcmp(tag, "nonce")) {
+                                       strncpy(nonce, val,
+                                               sizeof(nonce));
+                                       break; /* case */
+                               } else if (strcmp(tag, "now") ||
                                    2 != sscanf(val, ts_fmt,
                                                &pnow->l_ui,
                                                &pnow->l_uf))
@@ -2552,7 +2584,8 @@ collect_mru_list(
                req = req_buf;
                req_end = req_buf + sizeof(req_buf);
 #define REQ_ROOM       (req_end - req)
-               snprintf(req, REQ_ROOM, "limit=%d%s", limit, parms);
+               snprintf(req, REQ_ROOM, "nonce=%s, limit=%d%s", nonce,
+                        limit, parms);
                req += strlen(req);
 
                for (ri = 0, recent = HEAD_DLIST(mru_list, mlink);