]> git.ipfire.org Git - thirdparty/ntp.git/commitdiff
[Bug 1003] ntpdc unconfig command doesn't prompt for keyid.
authorDave Hart <hart@ntp.org>
Wed, 11 Nov 2009 12:36:24 +0000 (12:36 +0000)
committerDave Hart <hart@ntp.org>
Wed, 11 Nov 2009 12:36:24 +0000 (12:36 +0000)
[Bug 1376] Enable authenticated ntpq and ntpdc using newly-available
  digest types.
ntp-keygen, Autokey OpenSSL build vs. run version mismatch is now a
  non-fatal warning.

bk: 4afaafc8TYNwbwA9mbO7Rxxd9jNAgg

13 files changed:
ChangeLog
include/ntp_request.h
include/ntp_stdlib.h
libntp/a_md5encrypt.c
libntp/authreadkeys.c
libntp/ssl_init.c
ntpd/keyword-gen.c
ntpd/ntp_intres.c
ntpd/ntp_request.c
ntpdc/ntpdc.c
ntpdc/ntpdc_ops.c
ntpq/ntpq-subs.c
ntpq/ntpq.c

index cc781463015c22e1c7232da1395d520e14147d1e..16c88538addaa8efeaad022540af36dd3033c580 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,8 @@
+* [Bug 1003] ntpdc unconfig command doesn't prompt for keyid.
+* [Bug 1376] Enable authenticated ntpq and ntpdc using newly-available
+  digest types.
+* ntp-keygen, Autokey OpenSSL build vs. run version mismatch is now a
+  non-fatal warning.
 (4.2.5p242-RC) 2009/11/10 Released by Harlan Stenn <stenn@ntp.org>
 * [Bug 1363] CID 92 clarify fallthrough case in clk_trimtsip.c
 * [Bug 1366] ioctl(TIOCSCTTY, 0) fails on NetBSD *[0-2].* > 3.99.7.
index 643904071629abc3b6678917699657c997e290b6..1d4e90ba4dfd205938f43ffd73ff69962e8f3f4a 100644 (file)
@@ -5,6 +5,7 @@
 #ifndef NTP_REQUEST_H
 #define NTP_REQUEST_H
 
+#include "stddef.h"
 #include "ntp_types.h"
 #include "recvbuff.h"
 
@@ -135,7 +136,7 @@ struct req_pkt {
                                        /* struct conf_peer must fit */
        l_fp tstamp;                    /* time stamp, for authentication */
        keyid_t keyid;                  /* (optional) encryption key */
-       char mac[MAX_MD5_LEN-sizeof(u_int32)]; /* (optional) auth code */
+       char mac[MAX_MD5_LEN-sizeof(keyid_t)]; /* (optional) auth code */
 };
 
 /*
@@ -145,22 +146,20 @@ struct req_pkt {
 struct req_pkt_tail {
        l_fp tstamp;                    /* time stamp, for authentication */
        keyid_t keyid;                  /* (optional) encryption key */
-       char mac[MAX_MD5_LEN-sizeof(u_int32)]; /* (optional) auth code */
+       char mac[MAX_MD5_LEN-sizeof(keyid_t)]; /* (optional) auth code */
 };
 
-/*
- * Input packet lengths.  One with the mac, one without.
- */
-#define        REQ_LEN_HDR     8       /* 4 * u_char + 2 * u_short */
-#define        REQ_LEN_MAC     (sizeof(struct req_pkt))
-#define        REQ_LEN_NOMAC   (sizeof(struct req_pkt) - MAX_MD5_LEN)
+/* MODE_PRIVATE request packet header length before optional items. */
+#define        REQ_LEN_HDR     (offsetof(struct req_pkt, data))
+/* MODE_PRIVATE request packet fixed length without MAC. */
+#define        REQ_LEN_NOMAC   (offsetof(struct req_pkt, keyid))
 
 /*
- * A response packet.  The length here is variable, this is a
- * maximally sized one.  Note that this implementation doesn't
+ * A MODE_PRIVATE response packet.  The length here is variable, this
+ * is a maximally sized one.  Note that this implementation doesn't
  * authenticate responses.
  */
-#define        RESP_HEADER_SIZE        (8)
+#define        RESP_HEADER_SIZE        (offsetof(struct resp_pkt, data))
 #define        RESP_DATA_SIZE          (500)
 
 struct resp_pkt {
index 3685f686c9b1286721a803a97cf0fdab752a1dca..f2024fb16cf3500a90c7c9882e5a50fc0167f4c5 100644 (file)
@@ -37,11 +37,13 @@ extern      void    msyslog         (int, const char *, ...)
                                __attribute__((__format__(__printf__, 2, 3)));
 
 /*
- * When building without OpenSSL, use one constant #define, NID_md5,
- * for the keytype.  MD5 is the only digest supported without OpenSSL.
+ * When building without OpenSSL, use a few macros of theirs to
+ * minimize source differences in NTP.
  */
 #ifndef OPENSSL
 #define NID_md5        4       /* from openssl/objects.h */
+/* from openssl/evp.h */
+#define EVP_MAX_MD_SIZE        64      /* longest known is SHA512 */
 #endif
 
 extern void    auth_delkeys    (void);
@@ -169,6 +171,9 @@ extern      int     ssl_init_done;
 #else  /* !OPENSSL follows */
 #define        INIT_SSL()              do {} while (0)
 #endif
+extern int     keytype_from_text       (const char *,  size_t *);
+extern const char *keytype_name        (int);
+
 
 /* lib/isc/win32/strerror.c
  *
index 0b1264e1269d32a6652d7a70fdd256f04d69851d..bd30ba2c6c8f7f6e264c1aa92424e9ed2d5e2bf7 100644 (file)
@@ -28,7 +28,7 @@ MD5authencrypt(
        int     length          /* packet length */
        )
 {
-       u_char  digest[32];
+       u_char  digest[EVP_MAX_MD_SIZE];
        u_int   len;
 #ifdef OPENSSL
        EVP_MD_CTX ctx;
@@ -73,7 +73,7 @@ MD5authdecrypt(
        int     size            /* MAC size */
        )
 {
-       u_char  digest[32];
+       u_char  digest[EVP_MAX_MD_SIZE];
        u_int   len;
 #ifdef OPENSSL
        EVP_MD_CTX ctx;
index 38f25b2b681539f4548383d0fb80b1bd57d5fdc1..e757bd8599706d1cf881f828b56d1fcf0b7da264 100644 (file)
@@ -127,18 +127,13 @@ authreadkeys(
                        continue;
                }
 #ifdef OPENSSL
-
                /*
-                * If the key type is 'M' or 'm', it is replaced by 'MD5".
-                * In any case, it must be one of the algorithms supported
-                * by OpenSSL. The key type is the NID used by the message
-                * digest algorithm. Ther are a number of inconsistencies in
-                * the OpenSSL database. We attempt to discover them here
-                * and prevent use of inconsistent data.
+                * The key type is the NID used by the message digest 
+                * algorithm. There are a number of inconsistencies in
+                * the OpenSSL database. We attempt to discover them
+                * here and prevent use of inconsistent data.
                 */
-               if (strcmp(token, "M") == 0 || strcmp(token, "m") == 0)
-                       token  = "MD5";
-               keytype = OBJ_sn2nid(token);
+               keytype = keytype_from_text(token, NULL);
                if (keytype == 0 || keytype > 255) {
                        msyslog(LOG_ERR,
                            "authreadkeys: invalid type for key %d", keyno);
index 73c94a61aaaf5e6fca65ca0e6e38664f0a24114c..59ef8ff1a9d965a9338478ea1731e84136159e3f 100644 (file)
@@ -9,10 +9,9 @@
 #endif
 #include <ntp.h>
 #include <ntp_debug.h>
+#include <lib_strbuf.h>
 
-#ifndef OPENSSL
-int ssl_init__non_empty_compliation_unit;
-#else  /* OPENSSL follows */
+#ifdef OPENSSL
 #include "openssl/err.h"
 #include "openssl/rand.h"
 
@@ -36,15 +35,99 @@ void
 ssl_check_version(void)
 {
        if ((SSLeay() ^ OPENSSL_VERSION_NUMBER) & ~0xff0L) {
-               msyslog(LOG_ERR,
+               msyslog(LOG_WARNING,
                    "OpenSSL version mismatch. Built against %lx, you have %lx",
                    OPENSSL_VERSION_NUMBER, SSLeay());
                fprintf(stderr,
                    "OpenSSL version mismatch. Built against %lx, you have %lx\n",
                    OPENSSL_VERSION_NUMBER, SSLeay());
-               exit (-1);
        }
 
        INIT_SSL();
 }
 #endif /* OPENSSL */
+
+
+/*
+ * keytype_from_text   returns OpenSSL NID for digest by name, and
+ *                     optionally the associated digest length.
+ *
+ * Used by ntpd authreadkeys(), ntpq and ntpdc keytype()
+ */
+int
+keytype_from_text(
+       const char *keytype_name,
+       size_t *pdigest_len
+       )
+{
+       int             key_type;
+       u_int           digest_len;
+#ifdef OPENSSL
+       char            digest[EVP_MAX_MD_SIZE];
+       char *          upcased;
+       char *          pch;
+       EVP_MD_CTX      ctx;
+
+       /*
+        * 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.
+        */
+       INIT_SSL();
+       LIB_GETBUF(upcased);
+       strncpy(upcased, keytype_name, LIB_BUFLENGTH);
+       for (pch = upcased; '\0' != *pch; pch++)
+               *pch = (char)toupper(*pch);
+       key_type = OBJ_sn2nid(upcased);
+#else
+       key_type = 0;
+#endif
+
+       if (!key_type && 'm' == tolower(keytype_name[0]))
+               key_type = NID_md5;
+
+       if (!key_type)
+               return 0;
+
+       if (NULL != pdigest_len) {
+#ifdef OPENSSL
+               EVP_DigestInit(&ctx, EVP_get_digestbynid(key_type));
+               EVP_DigestFinal(&ctx, digest, &digest_len);
+#else
+               digest_len = 16;
+#endif
+               *pdigest_len = digest_len;
+       }
+
+       return key_type;
+}
+
+
+/*
+ * keytype_name                returns OpenSSL short name for digest by NID.
+ *
+ * Used by ntpq and ntpdc keytype()
+ */
+const char *
+keytype_name(
+       int nid
+       )
+{
+       static const char unknown_type[] = "(unknown key type)";
+       const char *name;
+
+#ifdef OPENSSL
+       INIT_SSL();
+       name = OBJ_nid2sn(nid);
+       if (NULL == name)
+               name = unknown_type;
+#else  /* !OPENSSL follows */
+       if (nid_MD5 == nid)
+               name = "MD5";
+       else
+               name = unknown_type;
+#endif
+       return name;
+}
+
index 76fb990a02fa3e1f733ee1280f0f3c73e9be62b7..6486d34eba3483799298938ffce17ac23a595435 100644 (file)
@@ -450,10 +450,10 @@ create_scan_states(
                        exit(2);
                }
        } else {
-               my_state = sst_highwater++;
-               while (my_state < COUNTOF(sst)
-                      && sst[my_state].finishes_token)
+               do
                        my_state = sst_highwater++;
+               while (my_state < COUNTOF(sst)
+                      && sst[my_state].finishes_token);
                if (my_state >= COUNTOF(sst)) {
                        fprintf(stderr,
                                "fatal, keyword scanner state array "
@@ -493,9 +493,9 @@ create_scan_states(
                        sst[token] = sst[my_state];
                        memset(&sst[my_state], 0,
                               sizeof(sst[my_state]));
-                       sst_highwater--;
-                       while (sst[sst_highwater].finishes_token)
+                       do
                                sst_highwater--;
+                       while (sst[sst_highwater].finishes_token);
                        my_state = token;
                        if (prev_char_s)
                                sst[prev_char_s].other_next_s = my_state;
index be8d24e21c44b33db4368331e841ef1d06a0c13a..3323b00b7b79ff7cdd023b7b7c25d0e19cbc04db 100644 (file)
@@ -723,7 +723,7 @@ request(
        FD_SET(sockfd, &fdset);
        while (select(sockfd + 1, &fdset, (fd_set *)0, (fd_set *)0, &tvout) >
               0) {
-               recv(sockfd, (char *)&reqpkt, REQ_LEN_MAC, 0);
+               recv(sockfd, (char *)&reqpkt, sizeof(reqpkt), 0);
                FD_ZERO(&fdset);
                FD_SET(sockfd, &fdset);
        }
index e9b0952cb142c49dd2646cd541547779075660b0..0fe81c3d5c4043c44f112c96c81ec754a94c6678 100644 (file)
@@ -62,7 +62,8 @@ static        struct req_proc univ_codes[] = {
 };
 
 static void    req_ack (sockaddr_u *, struct interface *, struct req_pkt *, int);
-static char *  prepare_pkt     (sockaddr_u *, struct interface *, struct req_pkt *, u_int);
+static char *  prepare_pkt     (sockaddr_u *, struct interface *,
+                                struct req_pkt *, size_t);
 static char *  more_pkt        (void);
 static void    flush_pkt       (void);
 static void    peer_list       (sockaddr_u *, struct interface *, struct req_pkt *);
@@ -278,13 +279,10 @@ prepare_pkt(
        sockaddr_u *srcadr,
        struct interface *inter,
        struct req_pkt *pkt,
-       u_int structsize
+       size_t structsize
        )
 {
-#ifdef DEBUG
-       if (debug > 3)
-           printf("request: preparing pkt\n");
-#endif
+       DPRINTF(4, ("request: preparing pkt\n"));
 
        /*
         * Fill in the implementation, request and itemsize fields
@@ -322,21 +320,18 @@ more_pkt(void)
         * If we were using the extra buffer, send the packet.
         */
        if (usingexbuf) {
-#ifdef DEBUG
-               if (debug > 2)
-                   printf("request: sending pkt\n");
-#endif
+               DPRINTF(3, ("request: sending pkt\n"));
                rpkt.rm_vn_mode = RM_VN_MODE(RESP_BIT, MORE_BIT, reqver);
                rpkt.auth_seq = AUTH_SEQ(0, seqno);
                rpkt.err_nitems = htons((u_short)nitems);
                sendpkt(toaddr, frominter, -1, (struct pkt *)&rpkt,
-                       RESP_HEADER_SIZE+databytes);
+                       RESP_HEADER_SIZE + databytes);
                numresppkts++;
 
                /*
                 * Copy data out of exbuf into the packet.
                 */
-               memmove(&rpkt.data[0], exbuf, (unsigned)itemsize);
+               memcpy(&rpkt.data[0], exbuf, (unsigned)itemsize);
                seqno++;
                databytes = 0;
                nitems = 0;
@@ -346,10 +341,7 @@ more_pkt(void)
        databytes += itemsize;
        nitems++;
        if (databytes + itemsize <= RESP_DATA_SIZE) {
-#ifdef DEBUG
-               if (debug > 3)
-                   printf("request: giving him more data\n");
-#endif
+               DPRINTF(4, ("request: giving him more data\n"));
                /*
                 * More room in packet.  Give him the
                 * next address.
@@ -360,12 +352,9 @@ more_pkt(void)
                 * No room in packet.  Give him the extra
                 * buffer unless this was the last in the sequence.
                 */
-#ifdef DEBUG
-               if (debug > 3)
-                   printf("request: into extra buffer\n");
-#endif
+               DPRINTF(4, ("request: into extra buffer\n"));
                if (seqno == MAXSEQ)
-                   return (char *)0;
+                       return NULL;
                else {
                        usingexbuf = 1;
                        return exbuf;
@@ -380,17 +369,14 @@ more_pkt(void)
 static void
 flush_pkt(void)
 {
-#ifdef DEBUG
-       if (debug > 2)
-           printf("request: flushing packet, %d items\n", nitems);
-#endif
+       DPRINTF(3, ("request: flushing packet, %d items\n", nitems));
        /*
         * Must send the last packet.  If nothing in here and nothing
         * has been sent, send an error saying no data to be found.
         */
        if (seqno == 0 && nitems == 0)
-           req_ack(toaddr, frominter, (struct req_pkt *)&rpkt,
-                   INFO_ERR_NODATA);
+               req_ack(toaddr, frominter, (struct req_pkt *)&rpkt,
+                       INFO_ERR_NODATA);
        else {
                rpkt.rm_vn_mode = RM_VN_MODE(RESP_BIT, 0, reqver);
                rpkt.auth_seq = AUTH_SEQ(0, seqno);
@@ -412,6 +398,8 @@ get_packet_mode(struct recvbuf *rbufp)
        struct req_pkt *inpkt = (struct req_pkt *)&rbufp->recv_pkt;
        return (INFO_MODE(inpkt->rm_vn_mode));
 }
+
+
 /*
  * process_private - process private mode (7) packets
  */
@@ -428,19 +416,22 @@ process_private(
        struct req_proc *proc;
        int ec;
        short temp_size;
+       l_fp ftmp;
+       double dtemp;
+       size_t recv_len;
+       size_t noslop_len;
+       size_t mac_len;
 
        /*
         * Initialize pointers, for convenience
         */
+       recv_len = rbufp->recv_length;
        inpkt = (struct req_pkt *)&rbufp->recv_pkt;
        srcadr = &rbufp->recv_srcadr;
        inter = rbufp->dstadr;
 
-#ifdef DEBUG
-       if (debug > 2)
-           printf("process_private: impl %d req %d\n",
-                  inpkt->implementation, inpkt->request);
-#endif
+       DPRINTF(3, ("process_private: impl %d req %d\n",
+                   inpkt->implementation, inpkt->request));
 
        /*
         * Do some sanity checks on the packet.  Return a format
@@ -467,10 +458,10 @@ process_private(
         * Get the appropriate procedure list to search.
         */
        if (inpkt->implementation == IMPL_UNIV)
-           proc = univ_codes;
+               proc = univ_codes;
        else if ((inpkt->implementation == IMPL_XNTPD) ||
                 (inpkt->implementation == IMPL_XNTPD_OLD))
-           proc = ntp_codes;
+               proc = ntp_codes;
        else {
                req_ack(srcadr, inter, inpkt, INFO_ERR_IMPL);
                return;
@@ -482,7 +473,7 @@ process_private(
         */
        while (proc->request_code != NO_REQUEST) {
                if (proc->request_code == (short) inpkt->request)
-                   break;
+                       break;
                proc++;
        }
        if (proc->request_code == NO_REQUEST) {
@@ -490,10 +481,7 @@ process_private(
                return;
        }
 
-#ifdef DEBUG
-       if (debug > 3)
-           printf("found request in tables\n");
-#endif
+       DPRINTF(4, ("found request in tables\n"));
 
        /*
         * If we need data, check to see if we have some.  If we
@@ -512,21 +500,15 @@ process_private(
            !(inpkt->implementation == IMPL_XNTPD &&
              inpkt->request == REQ_CONFIG &&
              temp_size == sizeof(struct old_conf_peer))) {
-#ifdef DEBUG
-               if (debug > 2)
-                       printf("process_private: wrong item size, received %d, should be %d or %d\n",
-                           temp_size, proc->sizeofitem, proc->v6_sizeofitem);
-#endif
+               DPRINTF(3, ("process_private: wrong item size, received %d, should be %d or %d\n",
+                           temp_size, proc->sizeofitem, proc->v6_sizeofitem));
                req_ack(srcadr, inter, inpkt, INFO_ERR_FMT);
                return;
        }
        if ((proc->sizeofitem != 0) &&
-           ((temp_size * INFO_NITEMS(inpkt->err_nitems)) >
-           (rbufp->recv_length - REQ_LEN_HDR))) {
-#ifdef DEBUG
-               if (debug > 2)
-                       printf("process_private: not enough data\n");
-#endif
+           ((size_t)(temp_size * INFO_NITEMS(inpkt->err_nitems)) >
+            (recv_len - REQ_LEN_HDR))) {
+               DPRINTF(3, ("process_private: not enough data\n"));
                req_ack(srcadr, inter, inpkt, INFO_ERR_FMT);
                return;
        }
@@ -552,55 +534,73 @@ process_private(
         * time stamp.
         */
        if (proc->needs_auth && sys_authenticate) {
-               l_fp ftmp;
-               double dtemp;
 
-               if (rbufp->recv_length < (REQ_LEN_HDR +
+               if (recv_len < (REQ_LEN_HDR +
                    (INFO_ITEMSIZE(inpkt->mbz_itemsize) *
                    INFO_NITEMS(inpkt->err_nitems)) +
                    sizeof(*tailinpkt))) {
                        req_ack(srcadr, inter, inpkt, INFO_ERR_FMT);
                        return;
-               } 
-               tailinpkt = (void *)((char *)&rbufp->recv_pkt +
-                   rbufp->recv_length - sizeof(*tailinpkt));
+               }
+
+               /*
+                * For 16-octet digests, regardless of itemsize and
+                * nitems, authenticated requests are a fixed size
+                * with the timestamp, key ID, and digest located
+                * at the end of the packet.  Because the key ID
+                * determining the digest size precedes the digest,
+                * for larger digests the fixed size request scheme
+                * is abandoned and the timestamp, key ID, and digest
+                * are located relative to the start of the packet,
+                * with the digest size determined by the packet size.
+                */
+               noslop_len = REQ_LEN_HDR
+                            + INFO_ITEMSIZE(inpkt->mbz_itemsize) *
+                              INFO_NITEMS(inpkt->err_nitems)
+                            + sizeof(inpkt->tstamp);
+               /* 32-bit alignment */
+               noslop_len = (noslop_len + 3) & ~3;
+               if (recv_len > (noslop_len + MAX_MAC_LEN))
+                       mac_len = 20;
+               else
+                       mac_len = recv_len - noslop_len;
+
+               tailinpkt = (void *)((char *)inpkt + recv_len -
+                           (mac_len + sizeof(inpkt->tstamp)));
 
                /*
-                * If this guy is restricted from doing this, don't let him
-                * If wrong key was used, or packet doesn't have mac, return.
+                * If this guy is restricted from doing this, don't let
+                * him.  If the wrong key was used, or packet doesn't
+                * have mac, return.
                 */
-               if (!INFO_IS_AUTH(inpkt->auth_seq) || info_auth_keyid == 0
+               if (!INFO_IS_AUTH(inpkt->auth_seq) || !info_auth_keyid
                    || ntohl(tailinpkt->keyid) != info_auth_keyid) {
+                       DPRINTF(5, ("failed auth %d info_auth_keyid %u pkt keyid %lu maclen %u\n",
+                                   INFO_IS_AUTH(inpkt->auth_seq),
+                                   info_auth_keyid,
+                                   ntohl(tailinpkt->keyid), mac_len));
 #ifdef DEBUG
-                       if (debug > 4)
-                           printf("failed auth %d info_auth_keyid %lu pkt keyid %lu\n",
-                                  INFO_IS_AUTH(inpkt->auth_seq),
-                                  (u_long)info_auth_keyid,
-                                  (u_long)ntohl(tailinpkt->keyid));
                        msyslog(LOG_DEBUG,
-                               "process_private: failed auth %d info_auth_keyid %lu pkt keyid %lu\n",
+                               "process_private: failed auth %d info_auth_keyid %u pkt keyid %lu maclen %u\n",
                                INFO_IS_AUTH(inpkt->auth_seq),
-                               (u_long)info_auth_keyid,
-                               (u_long)ntohl(tailinpkt->keyid));
+                               info_auth_keyid,
+                               ntohl(tailinpkt->keyid), mac_len);
 #endif
                        req_ack(srcadr, inter, inpkt, INFO_ERR_AUTH);
                        return;
                }
-               if (rbufp->recv_length > REQ_LEN_MAC) {
-#ifdef DEBUG
-                       if (debug > 4)
-                           printf("bad pkt length %d\n",
-                                  rbufp->recv_length);
-#endif
-                       msyslog(LOG_ERR, "process_private: bad pkt length %d",
-                               rbufp->recv_length);
+               if (recv_len > REQ_LEN_NOMAC + MAX_MAC_LEN) {
+                       DPRINTF(5, ("bad pkt length %d\n", recv_len));
+                       msyslog(LOG_ERR,
+                               "process_private: bad pkt length %d",
+                               recv_len);
                        req_ack(srcadr, inter, inpkt, INFO_ERR_FMT);
                        return;
                }
                if (!mod_okay || !authhavekey(info_auth_keyid)) {
+                       DPRINTF(5, ("failed auth mod_okay %d\n",
+                                   mod_okay));
 #ifdef DEBUG
-                       if (debug > 4)
-                           printf("failed auth mod_okay %d\n", mod_okay);
                        msyslog(LOG_DEBUG,
                                "process_private: failed auth mod_okay %d\n",
                                mod_okay);
@@ -630,22 +630,14 @@ process_private(
                 * So far so good.  See if decryption works out okay.
                 */
                if (!authdecrypt(info_auth_keyid, (u_int32 *)inpkt,
-                   rbufp->recv_length - sizeof(struct req_pkt_tail) +
-                   REQ_LEN_HDR, sizeof(struct req_pkt_tail) - REQ_LEN_HDR)) {
-#ifdef DEBUG
-                       if (debug > 4)
-                           printf("authdecrypt failed\n");
-#endif
+                                recv_len - mac_len, mac_len)) {
+                       DPRINTF(5, ("authdecrypt failed\n"));
                        req_ack(srcadr, inter, inpkt, INFO_ERR_AUTH);
                        return;
                }
        }
 
-#ifdef DEBUG
-       if (debug > 3)
-           printf("process_private: all okay, into handler\n");
-#endif
-
+       DPRINTF(3, ("process_private: all okay, into handler\n"));
        /*
         * Packet is okay.  Call the handler to send him data.
         */
index d789aa9bc4ff64cf0e85fa1fb264a0a77552070a..b84579d464fe6c8ad3cb6f023b7650c33afc0b4e 100644 (file)
@@ -3,7 +3,7 @@
  */
 
 #include <stdio.h>
-
+#include <stddef.h>
 #include <ctype.h>
 #include <signal.h>
 #include <setjmp.h>
@@ -50,7 +50,8 @@ static        const char *    prompt = "ntpdc> ";     /* prompt to ask him about */
 static u_long  info_auth_keyid;
 static int keyid_entered = 0;
 
-static int info_auth_keytype = NID_md5;        /* MD5 */
+static int     info_auth_keytype = NID_md5;    /* MD5 */
+static size_t  info_auth_hashlen = 16;         /* MD5 */
 u_long current_time;           /* needed by authkeys; not used */
 
 /*
@@ -71,10 +72,10 @@ int         ntpdcmain       (int,   char **);
  * Built in command handler declarations
  */
 static int     openhost        (const char *);
-static int     sendpkt         (char *, int);
+static int     sendpkt         (void *, size_t);
 static void    growpktdata     (void);
 static int     getresponse     (int, int, int *, int *, char **, int);
-static int     sendrequest     (int, int, int, int, int, char *);
+static int     sendrequest     (int, int, int, u_int, size_t, char *);
 static void    getcmds         (void);
 static RETSIGTYPE abortcmd     (int);
 static void    docmd           (const char *);
@@ -619,11 +620,11 @@ openhost(
  */
 static int
 sendpkt(
-       char *xdata,
-       int xdatalen
+       void *  xdata,
+       size_t  xdatalen
        )
 {
-       if (send(sockfd, xdata, (size_t)xdatalen, 0) == -1) {
+       if (send(sockfd, xdata, xdatalen, 0) == -1) {
                warning("write to %s failed", currenthost, "");
                return -1;
        }
@@ -639,11 +640,7 @@ static void
 growpktdata(void)
 {
        pktdatasize += INCDATASIZE;
-       pktdata = (char *)realloc(pktdata, (unsigned)pktdatasize);
-       if (pktdata == 0) {
-               (void) fprintf(stderr, "%s: realloc() failed!\n", progname);
-               exit(1);
-       }
+       pktdata = erealloc(pktdata, (size_t)pktdatasize);
 }
 
 
@@ -695,9 +692,9 @@ getresponse(
 
     again:
        if (firstpkt)
-           tvo = tvout;
+               tvo = tvout;
        else
-           tvo = tvsout;
+               tvo = tvsout;
        
        FD_SET(sockfd, &fds);
        n = select(sockfd+1, &fds, (fd_set *)0, (fd_set *)0, &tvo);
@@ -808,7 +805,8 @@ getresponse(
                pad = esize - size;
        else 
                pad = 0;
-       if ((datasize = items*size) > (n-RESP_HEADER_SIZE)) {
+       datasize = items * size;
+       if ((size_t)datasize > (n-RESP_HEADER_SIZE)) {
                if (debug)
                    printf(
                            "Received items %d, size %d (total %d), data in packet is %d\n",
@@ -854,7 +852,7 @@ getresponse(
        if ((datap + datasize + (pad * items)) > (pktdata + pktdatasize)) {
                int offset = datap - pktdata;
                growpktdata();
-               *rdata = pktdata; /* might have been realloced ! */
+               *rdata = pktdata; /* might have been realloced ! */
                datap = pktdata + offset;
        }
        /* 
@@ -862,9 +860,9 @@ getresponse(
         * items.  This is so we can play nice with older implementations
         */
 
-       tmp_data = (char *)rpkt.data;
-       for(i = 0; i <items; i++){
-               memmove(datap, tmp_data, (unsigned)size);
+       tmp_data = rpkt.data;
+       for (i = 0; i < items; i++) {
+               memcpy(datap, tmp_data, (unsigned)size);
                tmp_data += size;
                memset(datap + size, 0, pad);
                datap += size + pad;
@@ -882,36 +880,63 @@ getresponse(
         */
        ++numrecv;
        if (numrecv <= lastseq)
-           goto again;
+               goto again;
        return INFO_OKAY;
 }
 
 
 /*
  * sendrequest - format and send a request packet
+ *
+ * Historically, ntpdc has used a fixed-size request packet regardless
+ * of the actual payload size.  When authenticating, the timestamp, key
+ * ID, and digest have been placed just before the end of the packet.
+ * With the introduction in late 2009 of support for authenticated
+ * ntpdc requests using larger 20-octet digests (vs. 16 for MD5), we
+ * come up four bytes short.
+ *
+ * To maintain interop while allowing for larger digests, the behavior
+ * is unchanged when using 16-octet digests.  For larger digests, the
+ * timestamp, key ID, and digest are placed immediately following the
+ * request payload, with the overall packet size variable.  ntpd can
+ * distinguish 16-octet digests by the overall request size being
+ * REQ_LEN_NOMAC + 4 + 16 with the auth bit enabled.  When using a
+ * longer digest, that request size should be avoided.
+ *
+ * With the form used with 20-octet and larger digests, the timestamp,
+ * key ID, and digest are located by ntpd relative to the start of the
+ * packet, and the size of the digest is then implied by the packet
+ * size.
  */
 static int
 sendrequest(
        int implcode,
        int reqcode,
        int auth,
-       int qitems,
-       int qsize,
+       u_int qitems,
+       size_t qsize,
        char *qdata
        )
 {
        struct req_pkt qpkt;
-       int datasize;
+       size_t  datasize;
+       size_t  reqsize;
+       u_long  key_id;
+       l_fp    ts;
+       l_fp *  ptstamp;
+       int     maclen;
+       char    pass_prompt[32];
+       char *  pass;
 
-       memset((char *)&qpkt, 0, sizeof qpkt);
+       memset(&qpkt, 0, sizeof(qpkt));
 
        qpkt.rm_vn_mode = RM_VN_MODE(0, 0, 0);
        qpkt.implementation = (u_char)implcode;
        qpkt.request = (u_char)reqcode;
 
        datasize = qitems * qsize;
-       if (datasize != 0 && qdata != NULL) {
-               memmove((char *)qpkt.data, qdata, (unsigned)datasize);
+       if (datasize && qdata != NULL) {
+               memcpy(qpkt.data, qdata, datasize);
                qpkt.err_nitems = ERR_NITEMS(0, qitems);
                qpkt.mbz_itemsize = MBZ_ITEMSIZE(qsize);
        } else {
@@ -921,53 +946,64 @@ sendrequest(
 
        if (!auth || (keyid_entered && info_auth_keyid == 0)) {
                qpkt.auth_seq = AUTH_SEQ(0, 0);
-               return sendpkt((char *)&qpkt, req_pkt_size);
-       } else {
-               u_long  key_id;
-               l_fp    ts;
-               l_fp *  ptstamp;
-               int     maclen;
-               char *  pass;
+               return sendpkt(&qpkt, req_pkt_size);
+       }
 
-               if (info_auth_keyid == 0) {
-                       if (((struct conf_peer *)qpkt.data)->keyid > 0)
-                               info_auth_keyid = ((struct conf_peer *)qpkt.data)->keyid;
-                       else {
-                               key_id = getkeyid("Keyid: ");
-                               if (key_id == 0) {
-                                       (void) fprintf(stderr,
-                                           "Invalid key identifier\n");
-                                       return 1;
-                               }
-                               info_auth_keyid = key_id;
-                       }
-               }
-               if (!authistrusted(info_auth_keyid)) {
-                       pass = getpass("MD5 Password: ");
-                       if (*pass == '\0') {
-                               (void) fprintf(stderr,
-                                   "Invalid password\n");
-                               return (1);
-                       }
-                       authusekey(info_auth_keyid, info_auth_keytype,
-                                  (u_char *)pass);
-                       authtrust(info_auth_keyid, 1);
+       if (info_auth_keyid == 0) {
+               key_id = getkeyid("Keyid: ");
+               if (!key_id) {
+                       fprintf(stderr, "Invalid key identifier\n");
+                       return 1;
                }
-               qpkt.auth_seq = AUTH_SEQ(1, 0);
-               get_systime(&ts);
-               L_ADD(&ts, &delay_time);
-               ptstamp = (void *)((char *)&qpkt + req_pkt_size 
-                   - sizeof(qpkt.tstamp));
-               HTONL_FP(&ts, ptstamp);
-               maclen = authencrypt(info_auth_keyid, (u_int32 *)&qpkt,
-                   req_pkt_size);
-               if (maclen == 0) {  
-                       (void) fprintf(stderr, "Key not found\n");
-                       return (1);
+               info_auth_keyid = key_id;
+       }
+       if (!authistrusted(info_auth_keyid)) {
+               snprintf(pass_prompt, sizeof(pass_prompt),
+                        "%s Password: ",
+                        keytype_name(info_auth_keytype));
+               pass = getpass(pass_prompt);
+               if ('\0' == pass[0]) {
+                       fprintf(stderr, "Invalid password\n");
+                       return 1;
                }
-               return sendpkt((char *)&qpkt, (int)(req_pkt_size + maclen));
+               authusekey(info_auth_keyid, info_auth_keytype,
+                          (u_char *)pass);
+               authtrust(info_auth_keyid, 1);
        }
-       /*NOTREACHED*/
+       qpkt.auth_seq = AUTH_SEQ(1, 0);
+       if (info_auth_hashlen > 16) {
+               /*
+                * Only ntpd which expects REQ_LEN_NOMAC plus maclen
+                * octets in an authenticated request using a 16 octet
+                * digest (that is, a newer ntpd) will handle digests
+                * larger than 16 octets, so for longer digests, do
+                * not attempt to shorten the requests for downlevel
+                * ntpd compatibility.
+                */
+               if (REQ_LEN_NOMAC != req_pkt_size)
+                       return 1;
+               reqsize = REQ_LEN_HDR + datasize + sizeof(*ptstamp);
+               /* align to 32 bits */
+               reqsize = (reqsize + 3) & ~3;
+       } else
+               reqsize = req_pkt_size;
+       ptstamp = (void *)((char *)&qpkt + reqsize);
+       ptstamp--;
+       get_systime(&ts);
+       L_ADD(&ts, &delay_time);
+       HTONL_FP(&ts, ptstamp);
+       maclen = authencrypt(info_auth_keyid, (void *)&qpkt, reqsize);
+       if (!maclen) {  
+               fprintf(stderr, "Key not found\n");
+               return 1;
+       } else if (maclen != (info_auth_hashlen + sizeof(keyid_t))) {
+               fprintf(stderr,
+                       "%d octet MAC, %u expected with %u octet digest\n",
+                       maclen, (info_auth_hashlen + sizeof(keyid_t)),
+                       info_auth_hashlen);
+               return 1;
+       }
+       return sendpkt(&qpkt, reqsize + maclen);
 }
 
 
@@ -1026,7 +1062,7 @@ again:
         */
        res = sendrequest(implcode, reqcode, auth, qitems, qsize, qdata);
        if (res != 0)
-           return res;
+               return res;
        
        /*
         * Get the response.  If we got a standard error, print a message
@@ -1064,36 +1100,36 @@ again:
        /* log error message if not told to be quiet */
        if ((res > 0) && (((1 << res) & quiet_mask) == 0)) {
                switch(res) {
-                   case INFO_ERR_IMPL:
+               case INFO_ERR_IMPL:
                        /* Give us a chance to try the older implementation. */
                        if (implcode == IMPL_XNTPD)
                                break;
                        (void) fprintf(stderr,
                                       "***Server implementation incompatable with our own\n");
                        break;
-                   case INFO_ERR_REQ:
+               case INFO_ERR_REQ:
                        (void) fprintf(stderr,
                                       "***Server doesn't implement this request\n");
                        break;
-                   case INFO_ERR_FMT:
+               case INFO_ERR_FMT:
                        (void) fprintf(stderr,
                                       "***Server reports a format error in the received packet (shouldn't happen)\n");
                        break;
-                   case INFO_ERR_NODATA:
+               case INFO_ERR_NODATA:
                        (void) fprintf(stderr,
                                       "***Server reports data not found\n");
                        break;
-                   case INFO_ERR_AUTH:
+               case INFO_ERR_AUTH:
                        (void) fprintf(stderr, "***Permission denied\n");
                        break;
-                   case ERR_TIMEOUT:
+               case ERR_TIMEOUT:
                        (void) fprintf(stderr, "***Request timed out\n");
                        break;
-                   case ERR_INCOMPLETE:
+               case ERR_INCOMPLETE:
                        (void) fprintf(stderr,
                                       "***Response from server was incomplete\n");
                        break;
-                   default:
+               default:
                        (void) fprintf(stderr,
                                       "***Server returns unknown error code %d\n", res);
                        break;
@@ -1769,21 +1805,34 @@ keytype(
        FILE *fp
        )
 {
-       if (pcmd->nargs == 0)
-           fprintf(fp, "keytype is %s\n",
-                   (info_auth_keytype == NID_md5) ? "MD5" : "???");
-       else
-           switch (*(pcmd->argval[0].string)) {
-               case 'm':
-               case 'M':
-                   info_auth_keytype = NID_md5;
-                   break;
+       const char *    digest_name;
+       size_t          digest_len;
+       int             keytype;
+
+       if (!pcmd->nargs) {
+               fprintf(fp, "keytype is %s with %u octet digests\n",
+                       keytype_name(info_auth_keytype),
+                       info_auth_hashlen);
+               return;
+       }
 
-               default:
-                   fprintf(fp, "keytype must be 'md5'\n");
-           }
-}
+       digest_name = pcmd->argval[0].string;
+       digest_len = 0;
+       keytype = keytype_from_text(digest_name, &digest_len);
+
+       if (!keytype) {
+               fprintf(fp, "keytype must be 'md5'%s\n",
+#ifdef OPENSSL
+                       " or a digest type provided by OpenSSL");
+#else
+                       "");
+#endif
+               return;
+       }
 
+       info_auth_keytype = keytype;
+       info_auth_hashlen = digest_len;
+}
 
 
 /*
index 62b44ed71ebd3542e7e7990d0c33794a7a318ad6..0d26a65c4bbdbf9687a6a3f15ceb3cd7d09034b0 100644 (file)
@@ -1332,7 +1332,7 @@ doconfig(
        struct parse *pcmd,
        FILE *fp,
        int mode,
-        int refc
+       int refc
        )
 {
        struct conf_peer cpeer;
@@ -1359,7 +1359,7 @@ again:
        maxpoll = NTP_MAXDPOLL;
        numtyp = 1;
        if (refc)
-            numtyp = 5;
+               numtyp = 5;
 
        if (impl_ver == IMPL_XNTPD)
                sendsize = sizeof(struct conf_peer);
index b983e72d31936552fc3c79838cca4bfbd90025b6..3c1b3138426f872c64007d05022f1a8a52bec078 100644 (file)
@@ -1067,7 +1067,7 @@ printassoc(
                        break;
 
                case PEVNT_RATE:
-                       last_event = "raate_exceeded";
+                       last_event = "rate_exceeded";
                        break;
 
                case PEVNT_DENY:
index 15290a1f131f5b712f687222a181b3492e9811a3..33b1c920436f98abe447c469a52bcb1721ba697c 100644 (file)
@@ -18,6 +18,7 @@
 #include "ntp_stdlib.h"
 #include "ntp_assert.h"
 #include "ntp_lineedit.h"
+#include "ntp_debug.h"
 #include "isc/net.h"
 #include "isc/result.h"
 #include <ssl_applink.c>
@@ -67,7 +68,8 @@ s_char        sys_precision;          /* local clock precision (log2 s) */
  */
 u_long info_auth_keyid = 0;
 
-static int info_auth_keytype = NID_md5;        /* MD5 */
+static int     info_auth_keytype = NID_md5;    /* MD5 */
+static size_t  info_auth_hashlen = 16;         /* MD5 */
 u_long current_time;           /* needed by authkeys; not used */
 
 /*
@@ -249,7 +251,7 @@ int         ntpqmain        (int,   char **);
  */
 static int     openhost        (const char *);
 
-static int     sendpkt         (char *, int);
+static int     sendpkt         (void *, size_t);
 static int     getresponse     (int, int, u_short *, int *, char **, int);
 static int     sendrequest     (int, int, int, int, char *);
 static char *  tstflags        (u_long);
@@ -788,13 +790,11 @@ openhost(
  */
 static int
 sendpkt(
-       char *xdata,
-       int xdatalen
+       void *  xdata,
+       size_t  xdatalen
        )
 {
-       if (debug >= 3)
-           printf("Sending %d octets\n", xdatalen);
-
+       DPRINTF(3, ("Sending %u octets\n", xdatalen));
 
        if (send(sockfd, xdata, (size_t)xdatalen, 0) == -1) {
                warning("write to %s failed", currenthost, "");
@@ -803,13 +803,15 @@ sendpkt(
 
        if (debug >= 4) {
                int first = 8;
+               char *cdata = xdata;
+
                printf("Packet data:\n");
                while (xdatalen-- > 0) {
                        if (first-- == 0) {
                                printf("\n");
                                first = 7;
                        }
-                       printf(" %02x", *xdata++ & 0xff);
+                       printf(" %02x", *cdata++ & 0xff);
                }
                printf("\n");
        }
@@ -1216,15 +1218,19 @@ sendrequest(
        )
 {
        struct ntp_control qpkt;
-       int pktsize;
+       int     pktsize;
+       u_long  key_id;
+       char    pass_prompt[32];
+       char *  pass;
+       int     maclen;
 
        /*
         * Check to make sure the data will fit in one packet
         */
        if (qsize > CTL_MAX_DATA_LEN) {
-               (void) fprintf(stderr,
-                              "***Internal error!  qsize (%d) too large\n",
-                              qsize);
+               fprintf(stderr,
+                       "***Internal error!  qsize (%d) too large\n",
+                       qsize);
                return 1;
        }
 
@@ -1245,7 +1251,7 @@ sendrequest(
         * If we have data, copy and pad it out to a 32-bit boundary.
         */
        if (qsize > 0) {
-               memcpy(qpkt.data, qdata, (unsigned)qsize);
+               memcpy(qpkt.data, qdata, (size_t)qsize);
                pktsize += qsize;
                while (pktsize & (sizeof(u_int32) - 1)) {
                        qpkt.data[qsize++] = 0;
@@ -1258,55 +1264,60 @@ sendrequest(
         * we're going to have to think about it a little.
         */
        if (!auth && !always_auth) {
-               return sendpkt((char *)&qpkt, pktsize);
-       } else {
-               char *  pass = "\0";
-               int     maclen = 0;
+               return sendpkt(&qpkt, pktsize);
+       } 
 
-               /*
-                * Pad out packet to a multiple of 8 octets to be sure
-                * receiver can handle it.
-                */
-               while (pktsize & 7) {
-                       qpkt.data[qsize++] = 0;
-                       pktsize++;
-               }
+       /*
+        * Pad out packet to a multiple of 8 octets to be sure
+        * receiver can handle it.
+        */
+       while (pktsize & 7) {
+               qpkt.data[qsize++] = 0;
+               pktsize++;
+       }
 
-               /*
-                * Get the keyid and the password if we don't have one.
-                */
-               if (info_auth_keyid == 0) {
-                       int u_keyid = getkeyid("Keyid: ");
-                       if (u_keyid == 0 || u_keyid > NTP_MAXKEY) {
-                               (void) fprintf(stderr,
-                                  "Invalid key identifier\n");
-                               return 1;
-                       }
-                       info_auth_keyid = u_keyid;
+       /*
+        * Get the keyid and the password if we don't have one.
+        */
+       if (info_auth_keyid == 0) {
+               key_id = getkeyid("Keyid: ");
+               if (key_id == 0 || key_id > NTP_MAXKEY) {
+                       fprintf(stderr, 
+                               "Invalid key identifier\n");
+                       return 1;
                }
-               if (!authistrusted(info_auth_keyid)) {
-                       pass = getpass("MD5 Password: ");
-                       if (*pass == '\0') {
-                               (void) fprintf(stderr,
-                                 "Invalid password\n");
-                               return (1);
-                       }
-                       authusekey(info_auth_keyid, info_auth_keytype, (const u_char *)pass);
-                       authtrust(info_auth_keyid, 1);
+               info_auth_keyid = key_id;
+       }
+       if (!authistrusted(info_auth_keyid)) {
+               snprintf(pass_prompt, sizeof(pass_prompt),
+                        "%s Password: ",
+                        keytype_name(info_auth_keytype));
+               pass = getpass(pass_prompt);
+               if ('\0' == pass[0]) {
+                       fprintf(stderr, "Invalid password\n");
+                       return 1;
                }
+               authusekey(info_auth_keyid, info_auth_keytype,
+                          (u_char *)pass);
+               authtrust(info_auth_keyid, 1);
+       }
 
-               /*
-                * Do the encryption.
-                */
-               maclen = authencrypt(info_auth_keyid, (u_int32 *)&qpkt,
-                   pktsize);
-               if (maclen == 0) {
-                       (void) fprintf(stderr, "Key not found\n");
-                       return (1);
-               }
-               return sendpkt((char *)&qpkt, pktsize + maclen);
+       /*
+        * Do the encryption.
+        */
+       maclen = authencrypt(info_auth_keyid, (void *)&qpkt, pktsize);
+       if (!maclen) {  
+               fprintf(stderr, "Key not found\n");
+               return 1;
+       } else if ((size_t)maclen != (info_auth_hashlen + sizeof(keyid_t))) {
+               fprintf(stderr,
+                       "%d octet MAC, %u expected with %u octet digest\n",
+                       maclen, (info_auth_hashlen + sizeof(keyid_t)),
+                       info_auth_hashlen);
+               return 1;
        }
-       /*NOTREACHED*/
+       
+       return sendpkt((char *)&qpkt, pktsize + maclen);
 }
 
 
@@ -2376,21 +2387,34 @@ keytype(
        FILE *fp
        )
 {
-       if (pcmd->nargs == 0)
-           fprintf(fp, "keytype is %s\n",
-                   (info_auth_keytype == NID_md5) ? "MD5" : "???");
-       else
-           switch (*(pcmd->argval[0].string)) {
-               case 'm':
-               case 'M':
-                   info_auth_keytype = NID_md5;
-                   break;
+       const char *    digest_name;
+       size_t          digest_len;
+       int             key_type;
+
+       if (!pcmd->nargs) {
+               fprintf(fp, "keytype is %s with %u octet digests\n",
+                       keytype_name(info_auth_keytype),
+                       info_auth_hashlen);
+               return;
+       }
 
-               default:
-                   fprintf(fp, "keytype must be 'md5'\n");
-           }
-}
+       digest_name = pcmd->argval[0].string;
+       digest_len = 0;
+       key_type = keytype_from_text(digest_name, &digest_len);
 
+       if (!key_type) {
+               fprintf(fp, "keytype must be 'md5'%s\n",
+#ifdef OPENSSL
+                       " or a digest type provided by OpenSSL");
+#else
+                       "");
+#endif
+               return;
+       }
+
+       info_auth_keytype = key_type;
+       info_auth_hashlen = digest_len;
+}
 
 
 /*