]> git.ipfire.org Git - thirdparty/ntp.git/commitdiff
Improve ntpd scalability for servers with many trusted keys.
authorDave Hart <hart@ntp.org>
Mon, 27 Feb 2012 23:05:11 +0000 (23:05 +0000)
committerDave Hart <hart@ntp.org>
Mon, 27 Feb 2012 23:05:11 +0000 (23:05 +0000)
bk: 4f4c0c27Ybd1h1v8hpbesZwd0ffCmw

ChangeLog
include/ntp_stdlib.h
libntp/a_md5encrypt.c
libntp/authkeys.c
ntpd/ntp_config.c
ntpdc/ntpdc.c
ntpq/ntpq.c
sntp/main.c
sntp/tests_main.cpp
tests/libntp/a_md5encrypt.cpp
tests/libntp/authkeys.cpp

index 1761ddc5b38545f36c2ca66ad3d0b03b49c85eec..2bf8e8f018b38b297b798299dbd7e4e8a75b30e7 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,4 @@
+* Improve ntpd scalability for servers with many trusted keys.
 (4.2.7p261) 2012/02/27 Released by Harlan Stenn <stenn@ntp.org>
 * [Bug 2048] add the clock variable timecode to SHM refclock.
 (4.2.7p260) 2012/02/24 Released by Harlan Stenn <stenn@ntp.org>
index a4638c81e8b97a066af6496e218ee3dbe31d5741..0640dae2decd19c89c0d3ec667161393a5d5e89a 100644 (file)
@@ -107,13 +107,14 @@ extern    int     ntp_getopt      (int, char **, const char *);
 extern void    init_auth       (void);
 extern void    init_lib        (void);
 extern struct savekey *auth_findkey (keyid_t);
-extern int     auth_moremem    (void);
+extern void    auth_moremem    (int);
+extern void    auth_prealloc_symkeys(int);
 extern int     ymd2yd          (int, int, int);
 
 /* a_md5encrypt.c */
 extern int     MD5authdecrypt  (int, u_char *, u_int32 *, int, int);
 extern int     MD5authencrypt  (int, u_char *, u_int32 *, int);
-extern void    MD5auth_setkey  (keyid_t, int, const u_char *, const int);
+extern void    MD5auth_setkey  (keyid_t, int, const u_char *, int);
 extern u_int32 addr2refid      (sockaddr_u *);
 
 /* emalloc.c */
@@ -204,9 +205,10 @@ extern int authnumfreekeys;
  * The key cache. We cache the last key we looked at here.
  */
 extern keyid_t cache_keyid;            /* key identifier */
-extern u_char *        cache_key;              /* key pointer */
 extern int     cache_type;             /* key type */
-extern u_int   cache_keylen;           /* key length */
+extern u_char *        cache_secret;           /* secret */
+extern u_short cache_secretsize;       /* secret octets */
+extern u_short cache_flags;            /* KEY_ bit flags */
 
 /* getopt.c */
 extern char *  ntp_optarg;             /* global argument pointer */
index 3057f5d12598f5b046b821ffce68c33447331b60..a143e00a10da17925d056e6e7f232472a5d19411 100644 (file)
@@ -35,7 +35,7 @@ MD5authencrypt(
         */
        INIT_SSL();
        EVP_DigestInit(&ctx, EVP_get_digestbynid(type));
-       EVP_DigestUpdate(&ctx, key, (u_int)cache_keylen);
+       EVP_DigestUpdate(&ctx, key, cache_secretsize);
        EVP_DigestUpdate(&ctx, (u_char *)pkt, (u_int)length);
        EVP_DigestFinal(&ctx, digest, &len);
        memmove((u_char *)pkt + length + 4, digest, len);
@@ -68,7 +68,7 @@ MD5authdecrypt(
         */
        INIT_SSL();
        EVP_DigestInit(&ctx, EVP_get_digestbynid(type));
-       EVP_DigestUpdate(&ctx, key, (u_int)cache_keylen);
+       EVP_DigestUpdate(&ctx, key, cache_secretsize);
        EVP_DigestUpdate(&ctx, (u_char *)pkt, (u_int)length);
        EVP_DigestFinal(&ctx, digest, &len);
        if ((u_int)size != len + 4) {
@@ -76,7 +76,7 @@ MD5authdecrypt(
                    "MAC decrypt: MAC length error");
                return (0);
        }
-       return (!memcmp(digest, (char *)pkt + length + 4, len));
+       return !memcmp(digest, (char *)pkt + length + 4, len);
 }
 
 /*
index 3b65b41848b9ec244c702eb13fe441810a8a505a..d7f1fabae61e4a4eb26468f3f7dbb4056a7dad47 100644 (file)
@@ -5,12 +5,13 @@
 # include <config.h>
 #endif
 
+#include <math.h>
 #include <stdio.h>
 
-#include "ntp_types.h"
-#include "ntp_fp.h"
 #include "ntp.h"
+#include "ntp_fp.h"
 #include "ntpd.h"
+#include "ntp_lists.h"
 #include "ntp_string.h"
 #include "ntp_malloc.h"
 #include "ntp_stdlib.h"
 /*
  * Structure to store keys in in the hash table.
  */
+typedef struct savekey symkey;
+
 struct savekey {
-       struct savekey *next;
-       union {
-               u_char MD5_key[64];     /* for keys up to to 512 bits */
-       } k;
-       keyid_t keyid;          /* key identifier */
-       int     type;           /* key type */
-       u_short flags;          /* flags that wave */
-       u_long lifetime;        /* remaining lifetime */
-       int keylen;             /* key length */
+       symkey *        hlink;          /* next in hash bucket */
+       DECL_DLIST_LINK(symkey, llink); /* for overall & free lists */
+       u_char *        secret;         /* shared secret */
+       u_long          lifetime;       /* remaining lifetime */
+       keyid_t         keyid;          /* key identifier */
+       u_short         type;           /* OpenSSL digest NID */
+       u_short         secretsize;     /* secret octets */
+       u_short         flags;          /* KEY_ flags that wave */
 };
 
+/* define the payload region of symkey beyond the list pointers */
+#define symkey_payload secret
+
 #define        KEY_TRUSTED     0x001   /* this key is trusted */
 
+#ifdef DEBUG
+typedef struct symkey_alloc_tag symkey_alloc;
+
+struct symkey_alloc_tag {
+       symkey_alloc *  link;
+       void *          mem;            /* enable free() atexit */
+};
+
+symkey_alloc * authallocs;
+#endif /* DEBUG */
+
+static inline u_short  auth_log2(double x);
+static void            auth_resize_hashtable(void);
+static void            allocsymkey(symkey **, keyid_t, u_short,
+                                   u_short, u_long, u_short, u_char *);
+static void            freesymkey(symkey *, symkey **);
+#ifdef DEBUG
+static void            free_auth_mem(void);
+#endif
+
+symkey key_listhead;           /* list of all in-use keys */;
 /*
  * The hash table. This is indexed by the low order bits of the
  * keyid. We make this fairly big for potentially busy servers.
  */
-#define        HASHSIZE        64
-#define        HASHMASK        ((HASHSIZE)-1)
-#define        KEYHASH(keyid)  ((keyid) & HASHMASK)
+#define        DEF_AUTHHASHSIZE        64
+//#define      HASHMASK        ((HASHSIZE)-1)
+#define        KEYHASH(keyid)  ((keyid) & authhashmask)
 
-struct savekey *key_hash[HASHSIZE];
+int    authhashdisabled;
+u_short        authhashbuckets = DEF_AUTHHASHSIZE;
+u_short authhashmask = DEF_AUTHHASHSIZE - 1;
+symkey **key_hash;
 
 u_long authkeynotfound;                /* keys not found */
 u_long authkeylookups;         /* calls to lookup keys */
@@ -52,21 +81,21 @@ u_long authencryptions;             /* calls to encrypt */
 u_long authdecryptions;                /* calls to decrypt */
 
 /*
- * Storage for free key structures.  We malloc() such things but
+ * Storage for free symkey structures.  We malloc() such things but
  * never free them.
  */
-struct savekey *authfreekeys;
+symkey *authfreekeys;
 int authnumfreekeys;
 
-#define        MEMINC  12              /* number of new free ones to get */
+#define        MEMINC  16              /* number of new free ones to get */
 
 /*
  * The key cache. We cache the last key we looked at here.
  */
 keyid_t        cache_keyid;            /* key identifier */
-u_char *cache_key;             /* key pointer */
-u_int  cache_keylen;           /* key length */
-int    cache_type;             /* key type */
+u_char *cache_secret;          /* secret */
+u_short        cache_secretsize;       /* secret length */
+int    cache_type;             /* OpenSSL digest NID */
 u_short cache_flags;           /* flags that wave */
 
 
@@ -76,10 +105,213 @@ u_short cache_flags;              /* flags that wave */
 void
 init_auth(void)
 {
+       size_t newalloc;
+
        /*
         * Initialize hash table and free list
         */
-       ZERO(key_hash);
+       newalloc = authhashbuckets * sizeof(key_hash[0]);
+
+       key_hash = erealloc(key_hash, newalloc);
+       memset(key_hash, '\0', newalloc);
+
+       INIT_DLIST(key_listhead, llink);
+
+#ifdef DEBUG
+       atexit(&free_auth_mem);
+#endif
+}
+
+
+/*
+ * free_auth_mem - assist in leak detection by freeing all dynamic
+ *                allocations from this module.
+ */
+#ifdef DEBUG
+static void
+free_auth_mem(void)
+{
+       symkey *        sk;
+       symkey_alloc *  alloc;
+       symkey_alloc *  next_alloc;
+
+       while (NULL != (sk = HEAD_DLIST(key_listhead, llink))) {
+               freesymkey(sk, &key_hash[KEYHASH(sk->keyid)]);
+       }
+       free(key_hash);
+       key_hash = NULL;
+       cache_keyid = 0;
+       cache_flags = 0;
+       for (alloc = authallocs; alloc != NULL; alloc = next_alloc) {
+               next_alloc = alloc->link;
+               free(alloc->mem);       
+       }
+       authfreekeys = NULL;
+       authnumfreekeys = 0;
+}
+#endif /* DEBUG */
+
+
+/*
+ * auth_moremem - get some more free key structures
+ */
+void
+auth_moremem(
+       int     keycount
+       )
+{
+       symkey *        sk;
+       int             i;
+#ifdef DEBUG
+       void *          base;
+       symkey_alloc *  allocrec;
+# define MOREMEM_EXTRA_ALLOC   (sizeof(*allocrec))
+#else
+# define MOREMEM_EXTRA_ALLOC   (0)
+#endif
+
+       i = (keycount > 0)
+               ? keycount
+               : MEMINC;
+       sk = emalloc_zero(i * sizeof(*sk) + MOREMEM_EXTRA_ALLOC);
+#ifdef DEBUG
+       base = sk;
+#endif
+
+       for (; i > 0; i--, sk++) {
+               LINK_SLIST(authfreekeys, sk, llink.f);
+       }
+       authnumfreekeys += i;
+
+#ifdef DEBUG
+       allocrec = (void *)sk;
+       allocrec->mem = base;
+       LINK_SLIST(authallocs, allocrec, link);
+#endif
+}
+
+
+/*
+ * auth_prealloc_symkeys
+ */
+void
+auth_prealloc_symkeys(
+       int     keycount
+       )
+{
+       int     allocated;
+       int     additional;
+
+       allocated = authnumkeys + authnumfreekeys;
+       additional = keycount - allocated;
+       if (additional > 0)
+               auth_moremem(additional);
+       auth_resize_hashtable();
+}
+
+
+static inline u_short
+auth_log2(double x)
+{
+       return (u_short)(log10(x) / log10(2));
+}
+
+
+/*
+ * auth_resize_hashtable
+ *
+ * Size hash table to average 4 or fewer entries per bucket initially,
+ * within the bounds of at least 4 and no more than 15 bits for the hash
+ * table index.  Populate the hash table.
+ */
+static void
+auth_resize_hashtable(void)
+{
+       u_long          totalkeys;
+       u_short         hashbits;
+       u_short         hash;
+       size_t          newalloc;
+       symkey *        sk;
+
+       totalkeys = authnumkeys + authnumfreekeys;
+       hashbits = auth_log2(totalkeys / 4.0) + 1;
+       hashbits = max(4, hashbits);
+       hashbits = min(15, hashbits);
+
+       authhashbuckets = 1 << hashbits;
+       authhashmask = authhashbuckets - 1;
+       newalloc = authhashbuckets * sizeof(key_hash[0]);
+
+       key_hash = erealloc(key_hash, newalloc);
+       memset(key_hash, '\0', newalloc);
+
+       ITER_DLIST_BEGIN(key_listhead, sk, llink, symkey)
+               hash = KEYHASH(sk->keyid);
+               LINK_SLIST(key_hash[hash], sk, hlink);
+       ITER_DLIST_END()
+}
+
+
+/*
+ * allocsymkey - common code to allocate and link in symkey
+ *
+ * secret must be allocated with a free-compatible allocator.  It is
+ * owned by the referring symkey structure, and will be free()d by
+ * freesymkey().
+ */
+static void
+allocsymkey(
+       symkey **       bucket,
+       keyid_t         id,
+       u_short         flags,
+       u_short         type,
+       u_long          lifetime,
+       u_short         secretsize,
+       u_char *        secret
+       )
+{
+       symkey *        sk;
+
+       if (0 == authnumfreekeys)
+               auth_moremem(-1);
+       UNLINK_HEAD_SLIST(sk, authfreekeys, llink.f);
+       DEBUG_ENSURE(sk != NULL);
+       sk->keyid = id;
+       sk->flags = flags;
+       sk->type = type;
+       sk->secretsize = secretsize;
+       sk->secret = secret;
+       sk->lifetime = lifetime;
+       LINK_SLIST(*bucket, sk, hlink);
+       LINK_TAIL_DLIST(key_listhead, sk, llink);
+       authnumfreekeys--;
+       authnumkeys++;
+}
+
+
+/*
+ * freesymkey - common code to remove a symkey and recycle its entry.
+ */
+static void
+freesymkey(
+       symkey *        sk,
+       symkey **       bucket
+       )
+{
+       symkey *        unlinked;
+
+       if (sk->secret != NULL) {
+               memset(sk->secret, '\0', sk->secretsize);
+               free(sk->secret);
+       }
+       UNLINK_SLIST(unlinked, *bucket, sk, hlink, symkey);
+       DEBUG_ENSURE(sk == unlinked);
+       UNLINK_DLIST(sk, llink);
+       memset((char *)sk + offsetof(symkey, symkey_payload), '\0',
+              sizeof(*sk) - offsetof(symkey, symkey_payload));
+       LINK_SLIST(authfreekeys, sk, llink.f);
+       authnumkeys--;
+       authnumfreekeys++;
 }
 
 
@@ -88,59 +320,60 @@ init_auth(void)
  */
 struct savekey *
 auth_findkey(
-       keyid_t keyno
+       keyid_t         id
        )
 {
-       struct savekey *sk;
-
-       sk = key_hash[KEYHASH(keyno)];
-       while (sk != 0) {
-               if (keyno == sk->keyid)
-                       return (sk);
+       symkey *        sk;
 
-               sk = sk->next;
+       for (sk = key_hash[KEYHASH(id)]; sk != NULL; sk = sk->hlink) {
+               if (id == sk->keyid) {
+                       return sk;
+               }
        }
-       return (0);
+
+       return NULL;
 }
 
 
 /*
- * auth_havekey - return one if the key is known
+ * auth_havekey - return TRUE if the key id is zero or known
  */
 int
 auth_havekey(
-       keyid_t keyno
+       keyid_t         id
        )
 {
-       struct savekey *sk;
+       symkey *        sk;
 
-       if (keyno == 0 || (keyno == cache_keyid))
-               return (1);
-
-       sk = key_hash[KEYHASH(keyno)];
-       while (sk != 0) {
-               if (keyno == sk->keyid)
-                       return (1);
+       if (0 == id || cache_keyid == id) {
+               return TRUE;
+       }
 
-               sk = sk->next;
+       for (sk = key_hash[KEYHASH(id)]; sk != NULL; sk = sk->hlink) {
+               if (id == sk->keyid) {
+                       return TRUE;
+               }
        }
-       return (0);
+
+       return FALSE;
 }
 
 
 /*
- * authhavekey - return one and cache the key, if known and trusted.
+ * authhavekey - return TRUE and cache the key, if zero or both known
+ *              and trusted.
  */
 int
 authhavekey(
-       keyid_t keyno
+       keyid_t         id
        )
 {
-       struct savekey *sk;
+       symkey *        sk;
 
        authkeylookups++;
-       if (keyno == 0 || keyno == cache_keyid)
-               return (1);
+       if (0 == id || cache_keyid == id) {
+               return TRUE;
+       }
 
        /*
         * Seach the bin for the key. If found and the key type
@@ -148,30 +381,27 @@ authhavekey(
         * a key or key type. In this case consider the key missing.
         */
        authkeyuncached++;
-       sk = key_hash[KEYHASH(keyno)];
-       while (sk != NULL) {
-               if (keyno == sk->keyid) {
-                       if (sk->type == 0) {
+       for (sk = key_hash[KEYHASH(id)]; sk != NULL; sk = sk->hlink) {
+               if (id == sk->keyid) {
+                       if (0 == sk->type) {
                                authkeynotfound++;
-                               return (0);
+                               return FALSE;
                        }
                        break;
                }
-               sk = sk->next;
        }
 
        /*
         * If the key is not found, or if it is found but not trusted,
         * the key is not considered found.
         */
-       if (sk == NULL) {
+       if (NULL == sk) {
                authkeynotfound++;
-               return (0);
-
+               return FALSE;
        }
-       if (!(sk->flags & KEY_TRUSTED)) {
+       if (!(KEY_TRUSTED & sk->flags)) {
                authnokey++;
-               return (0);
+               return FALSE;
        }
 
        /*
@@ -180,31 +410,10 @@ authhavekey(
        cache_keyid = sk->keyid;
        cache_type = sk->type;
        cache_flags = sk->flags;
-       cache_key = sk->k.MD5_key;
-       cache_keylen = sk->keylen;
-       return (1);
-}
-
-
-/*
- * auth_moremem - get some more free key structures
- */
-int
-auth_moremem(void)
-{
-       struct savekey *sk;
-       int i;
+       cache_secret = sk->secret;
+       cache_secretsize = sk->secretsize;
 
-       sk = (struct savekey *)calloc(MEMINC, sizeof(struct savekey));
-       if (sk == 0)
-               return (0);
-       
-       for (i = MEMINC; i > 0; i--) {
-               sk->next = authfreekeys;
-               authfreekeys = sk++;
-       }
-       authnumfreekeys += MEMINC;
-       return (authnumfreekeys);
+       return TRUE;
 }
 
 
@@ -213,24 +422,24 @@ auth_moremem(void)
  */
 void
 authtrust(
-       keyid_t keyno,
-       u_long trust
+       keyid_t         id,
+       u_long          trust
        )
 {
-       struct savekey *sk;
+       symkey **       bucket;
+       symkey *        sk;
+       u_long          lifetime;
 
        /*
         * Search bin for key; if it does not exist and is untrusted,
         * forget it.
         */
-       sk = key_hash[KEYHASH(keyno)];
-       while (sk != 0) {
-               if (keyno == sk->keyid)
-                   break;
-
-               sk = sk->next;
+       bucket = &key_hash[KEYHASH(id)];
+       for (sk = *bucket; sk != NULL; sk = sk->hlink) {
+               if (id == sk->keyid)
+                       break;
        }
-       if (sk == 0 && !trust)
+       if (!trust && NULL == sk)
                return;
 
        /*
@@ -238,16 +447,15 @@ authtrust(
         * exist and is to be trusted or it does exist and is or is
         * not to be trusted.
         */     
-       if (sk != 0) {
-               if (cache_keyid == keyno) {
+       if (sk != NULL) {
+               if (cache_keyid == id) {
                        cache_flags = 0;
                        cache_keyid = 0;
                }
 
                /*
                 * Key exists. If it is to be trusted, say so and
-                * update its lifetime. If not, return it to the
-                * free list.
+                * update its lifetime. 
                 */
                if (trust > 0) {
                        sk->flags |= KEY_TRUSTED;
@@ -257,46 +465,22 @@ authtrust(
                                sk->lifetime = 0;
                        return;
                }
-               sk->flags &= ~KEY_TRUSTED; {
-                       struct savekey *skp;
-
-                       skp = key_hash[KEYHASH(keyno)];
-                       if (skp == sk) {
-                               key_hash[KEYHASH(keyno)] = sk->next;
-                       } else {
-                               while (skp->next != sk)
-                                   skp = skp->next;
-                               skp->next = sk->next;
-                       }
-                       authnumkeys--;
 
-                       sk->next = authfreekeys;
-                       authfreekeys = sk;
-                       authnumfreekeys++;
-               }
+               /* No longer trusted, return it to the free list. */
+               freesymkey(sk, bucket);
                return;
        }
 
        /*
-        * Here there is not key, but the key is to be trusted. There
-        * seems to be a disconnect here. Here we allocate a new key,
-        * but do not specify a key type, key or key length.
-        */ 
-       if (authnumfreekeys == 0)
-           if (auth_moremem() == 0)
-               return;
-
-       sk = authfreekeys;
-       authfreekeys = sk->next;
-       authnumfreekeys--;
-       sk->keyid = keyno;
-       sk->type = 0;
-       sk->keylen = 0;
-       sk->flags = KEY_TRUSTED;
-       sk->next = key_hash[KEYHASH(keyno)];
-       key_hash[KEYHASH(keyno)] = sk;
-       authnumkeys++;
-       return;
+        * keyid is not present, but the is to be trusted.  We allocate
+        * a new key, but do not specify a key type or secret.
+        */
+       if (trust > 1) {
+               lifetime = current_time + trust;
+       } else {
+               lifetime = 0;
+       }
+       allocsymkey(bucket, id, KEY_TRUSTED, 0, lifetime, 0, NULL);
 }
 
 
@@ -305,30 +489,26 @@ authtrust(
  */
 int
 authistrusted(
-       keyid_t keyno
+       keyid_t         keyno
        )
 {
-       struct savekey *sk;
+       symkey *        sk;
+       symkey **       bucket;
 
        if (keyno == cache_keyid)
-           return ((cache_flags & KEY_TRUSTED) != 0);
+               return !!(KEY_TRUSTED & cache_flags);
 
        authkeyuncached++;
-       sk = key_hash[KEYHASH(keyno)];
-       while (sk != 0) {
+       bucket = &key_hash[KEYHASH(keyno)];
+       for (sk = *bucket; sk != NULL; sk = sk->hlink) {
                if (keyno == sk->keyid)
-                   break;
-               sk = sk->next;
+                       break;
        }
-       if (sk == 0) {
+       if (NULL == sk || !(KEY_TRUSTED & sk->flags)) {
                authkeynotfound++;
-               return (0);
-
-       } else if (!(sk->flags & KEY_TRUSTED)) {
-               authkeynotfound++;
-               return (0);
+               return FALSE;
        }
-       return (1);
+       return TRUE;
 }
 
 
@@ -337,25 +517,32 @@ MD5auth_setkey(
        keyid_t keyno,
        int     keytype,
        const u_char *key,
-       const int len
+       int     len
        )
 {
-       struct savekey *sk;
+       symkey *        sk;
+       symkey **       bucket;
+       u_char *        secret;
+       size_t          secretsize;
        
+       DEBUG_ENSURE(keytype <= USHRT_MAX);
+       DEBUG_ENSURE(len < 4 * 1024);
+       len = max(0, len);
        /*
         * See if we already have the key.  If so just stick in the
         * new value.
         */
-       sk = key_hash[KEYHASH(keyno)];
-       while (sk != NULL) {
+       bucket = &key_hash[KEYHASH(keyno)];
+       for (sk = *bucket; sk != NULL; sk = sk->hlink) {
                if (keyno == sk->keyid) {
-                       sk->type = keytype;
-                       sk->keylen = min(len, sizeof(sk->k.MD5_key));
+                       sk->type = (u_short)keytype;
+                       secretsize = len;
+                       sk->secretsize = (u_short)secretsize;
 #ifndef DISABLE_BUG1243_FIX
-                       memcpy(sk->k.MD5_key, key, sk->keylen);
+                       memcpy(sk->secret, key, secretsize);
 #else
-                       strlcpy((char *)sk->k.MD5_key, (const char *)key,
-                           sizeof(sk->k.MD5_key));
+                       strlcpy((char *)sk->secret, (const char *)key,
+                               secretsize);
 #endif
                        if (cache_keyid == keyno) {
                                cache_flags = 0;
@@ -363,117 +550,85 @@ MD5auth_setkey(
                        }
                        return;
                }
-               sk = sk->next;
        }
 
        /*
         * Need to allocate new structure.  Do it.
         */
-       if (0 == authnumfreekeys && !auth_moremem())
-               return;
-
-       sk = authfreekeys;
-       authfreekeys = sk->next;
-       authnumfreekeys--;
-
-       sk->keyid = keyno;
-       sk->type = keytype;
-       sk->flags = 0;
-       sk->lifetime = 0;
-       sk->keylen = min(len, sizeof(sk->k.MD5_key));
+       secretsize = len;
+       secret = emalloc(secretsize);
 #ifndef DISABLE_BUG1243_FIX
-       memcpy(sk->k.MD5_key, key, sk->keylen);
+       memcpy(secret, key, secretsize);
 #else
-       strlcpy((char *)sk->k.MD5_key, (const char *)key,
-           sizeof(sk->k.MD5_key));
+       strlcpy((char *)secret, (const char *)key, secretsize);
 #endif
-       sk->next = key_hash[KEYHASH(keyno)];
-       key_hash[KEYHASH(keyno)] = sk;
+       allocsymkey(bucket, keyno, 0, (u_short)keytype, 0,
+                   (u_short)secretsize, secret);
 #ifdef DEBUG
-       if (debug > 1) {
-               char    hex[] = "0123456789abcdef";
-               int     j;
-
-               printf("auth_setkey: key %d type %d len %d ", sk->keyid,
-                   sk->type, sk->keylen);
-               for (j = 0; j < sk->keylen; j++)
-                               printf("%c%c", hex[key[j] >> 4],
-                                   hex[key[j] & 0xf]);
+       if (debug >= 4) {
+               size_t  j;
+
+               printf("auth_setkey: key %d type %d len %d ", (int)keyno,
+                   keytype, (int)secretsize);
+               for (j = 0; j < secretsize; j++)
+                       printf("%02x", secret[j]);
                printf("\n");
        }       
 #endif
-       authnumkeys++;
 }
 
 
 /*
- * auth_delkeys - delete all known keys, in preparation for rereading
- *               the keys file (presumably)
+ * auth_delkeys - delete non-autokey untrusted keys, and clear all info
+ *                except the trusted bit of non-autokey trusted keys, in
+ *               preparation for rereading the keys file.
  */
 void
 auth_delkeys(void)
 {
-       struct savekey *sk;
-       struct savekey **skp;
-       int i;
+       symkey *        sk;
+
+       ITER_DLIST_BEGIN(key_listhead, sk, llink, symkey)
+               if (sk->keyid > NTP_MAXKEY) {   /* autokey */
+                       continue;
+               }
 
-       for (i = 0; i < HASHSIZE; i++) {
-               skp = &(key_hash[i]);
-               sk = key_hash[i];
                /*
-                * Leave autokey keys alone.
+                * Don't lose info as to which keys are trusted.
                 */
-               while (sk != 0 && sk->keyid <= NTP_MAXKEY) {
-                       /*
-                        * Don't lose info as to which keys are trusted.
-                        */
-                       if (sk->flags & KEY_TRUSTED) {
-                               skp = &(sk->next);
-                               ZERO(sk->k);
-                               sk->lifetime = 0;
-                               sk->keylen = 0;
-                               sk = sk->next;
-                       } else {
-                               *skp = sk->next;
-                               authnumkeys--;
-                               sk->next = authfreekeys;
-                               authfreekeys = sk;
-                               authnumfreekeys++;
-                               sk = *skp;
+               if (KEY_TRUSTED & sk->flags) {
+                       if (sk->secret != NULL) {
+                               memset(sk->secret, '\0', sk->secretsize);
+                               free(sk->secret);
                        }
+                       sk->secretsize = 0;
+                       sk->lifetime = 0;
+               } else {
+                       freesymkey(sk, &key_hash[KEYHASH(sk->keyid)]);
                }
-       }
+       ITER_DLIST_END()
 }
 
+
 /*
  * auth_agekeys - delete keys whose lifetimes have expired
  */
 void
 auth_agekeys(void)
 {
-       struct savekey *sk;
-       struct savekey *skp;
-       int i;
-
-       for (i = 0; i < HASHSIZE; i++) {
-               sk = skp = key_hash[i];
-               while (sk != 0) {
-                       skp = sk->next;
-                       if (sk->lifetime > 0 && current_time >
-                           sk->lifetime) {
-                               authtrust(sk->keyid, 0);
-                               authkeyexpired++;
-                       }
-                       sk = skp;
+       symkey *        sk;
+
+       ITER_DLIST_BEGIN(key_listhead, sk, llink, symkey)
+               if (sk->lifetime > 0 && current_time > sk->lifetime) {
+                       freesymkey(sk, &key_hash[KEYHASH(sk->keyid)]);
+                       authkeyexpired++;
                }
-       }
-#ifdef DEBUG
-       if (debug)
-               printf("auth_agekeys: at %lu keys %lu expired %lu\n",
-                   current_time, authnumkeys, authkeyexpired);
-#endif
+       ITER_DLIST_END()
+       DPRINTF(1, ("auth_agekeys: at %lu keys %lu expired %lu\n",
+                   current_time, authnumkeys, authkeyexpired));
 }
 
+
 /*
  * authencrypt - generate message authenticator
  *
@@ -481,12 +636,11 @@ auth_agekeys(void)
  */
 int
 authencrypt(
-       keyid_t keyno,
-       u_int32 *pkt,
-       int length
+       keyid_t         keyno,
+       u_int32 *       pkt,
+       int             length
        )
-{
-
+{\
        /*
         * A zero key identifier means the sender has not verified
         * the last message was correctly authenticated. The MAC
@@ -494,41 +648,40 @@ authencrypt(
         */
        authencryptions++;
        pkt[length / 4] = htonl(keyno);
-       if (keyno == 0) {
-               return (4);
+       if (0 == keyno) {
+               return 4;
+       }
+       if (!authhavekey(keyno)) {
+               return 0;
        }
-       if (!authhavekey(keyno))
-               return (0);
 
-       return (MD5authencrypt(cache_type, cache_key, pkt, length));
+       return MD5authencrypt(cache_type, cache_secret, pkt, length);
 }
 
+
 /*
  * authdecrypt - verify message authenticator
  *
- * Returns one if authenticator valid, zero if invalid or key not found.
+ * Returns TRUE if authenticator valid, FALSE if invalid or not found.
  */
 int
 authdecrypt(
-       keyid_t keyno,
-       u_int32 *pkt,
-       int length,
-       int size
+       keyid_t         keyno,
+       u_int32 *       pkt,
+       int             length,
+       int             size
        )
 {
-
        /*
         * A zero key identifier means the sender has not verified
-        * the last message was correctly authenticated. Nevertheless,
-        * the authenticator itself is considered valid.
+        * the last message was correctly authenticated.  For our
+        * purpose this is an invalid authenticator.
         */
        authdecryptions++;
-       if (keyno == 0)
-               return (0);
-
-       if (!authhavekey(keyno) || size < 4)
-               return (0);
+       if (0 == keyno || !authhavekey(keyno) || size < 4) {
+               return FALSE;
+       }
 
-       return (MD5authdecrypt(cache_type, cache_key, pkt, length,
-          size));
+       return MD5authdecrypt(cache_type, cache_secret, pkt, length,
+                             size);
 }
index 4aaf0caa124f428c1f344e723ba768d35a355586..15555d1bb35b943a49c87ef3b929e9d58743d77a 100644 (file)
@@ -1820,6 +1820,7 @@ config_auth(
        int             first;
        int             last;
        int             i;
+       int             count;
 #ifdef AUTOKEY
        int             item;
 #endif
@@ -1881,6 +1882,29 @@ config_auth(
        }
 #endif /* AUTOKEY */
 
+       /*
+        * Count the number of trusted keys to preallocate storage and
+        * size the hash table.
+        */
+       count = 0;
+       my_val = HEAD_PFIFO(ptree->auth.trusted_key_list);
+       for (; my_val != NULL; my_val = my_val->link) {
+               if (T_Integer == my_val->type) {
+                       first = my_val->value.i;
+                       if (first > 1 && first <= NTP_MAXKEY)
+                               count++;
+               } else {
+                       REQUIRE(T_Intrange == my_val->type);
+                       first = my_val->value.r.first;
+                       last = my_val->value.r.last;
+                       if (!(first > last || first < 1 ||
+                           last > NTP_MAXKEY)) {
+                               count += 1 + last - first;
+                       }
+               }
+       }
+       auth_prealloc_symkeys(count);
+
        /* Keys Command */
        if (ptree->auth.keys)
                getauthkeys(ptree->auth.keys);
@@ -1899,18 +1923,28 @@ config_auth(
        /* Trusted Key Command */
        my_val = HEAD_PFIFO(ptree->auth.trusted_key_list);
        for (; my_val != NULL; my_val = my_val->link) {
-               if (T_Integer == my_val->type)
-                       authtrust(my_val->value.i, 1);
-               else if (T_Intrange == my_val->type) {
+               if (T_Integer == my_val->type) {
+                       first = my_val->value.i;
+                       if (first >= 1 && first <= NTP_MAXKEY) {
+                               authtrust(first, TRUE);
+                       } else {
+                               msyslog(LOG_NOTICE,
+                                       "Ignoring invalid trustedkey %d, min 1 max %d.",
+                                       first, NTP_MAXKEY);
+                       }
+               } else {
                        first = my_val->value.r.first;
                        last = my_val->value.r.last;
-                       if (first > last || first < 1 || last > 65534)
+                       if (first > last || first < 1 ||
+                           last > NTP_MAXKEY) {
                                msyslog(LOG_NOTICE,
-                                       "Ignoring invalid trustedkey range %d ... %d, min 1 max 65534.",
-                                       first, last);
-                       else
-                               for (i = first; i <= last; i++)
-                                       authtrust((keyid_t)i, 1);
+                                       "Ignoring invalid trustedkey range %d ... %d, min 1 max %d.",
+                                       first, last, NTP_MAXKEY);
+                       } else {
+                               for (i = first; i <= last; i++) {
+                                       authtrust(i, TRUE);
+                               }
+                       }
                }
        }
 
index 33f9c4627c4c5a94b3fb6dc668e15ab4d7e7da74..474754efbb5eb864bbf4bfb12d4c13ab1c0fa15b 100644 (file)
@@ -283,6 +283,7 @@ ntpdcmain(
 
        init_lib();     /* sets up ipv4_works, ipv6_works */
        ssl_applink();
+       init_auth();
 
        /* Check to see if we have IPv6. Otherwise default to IPv4 */
        if (!ipv6_works)
index a34dbe59697c243d8c2e833ccd58ec80424c4e08..71686664ced9b0648c140f7d336ba39345880316 100644 (file)
@@ -436,6 +436,7 @@ ntpqmain(
 
        init_lib();     /* sets up ipv4_works, ipv6_works */
        ssl_applink();
+       init_auth();
 
        /* Check to see if we have IPv6. Otherwise default to IPv4 */
        if (!ipv6_works)
index 6daee83911325925adbeb5988c6307ce3c0df85f..714c16b96719ca76fb3acbb58101929fbd19ef11 100644 (file)
@@ -92,6 +92,7 @@ static union {
 int droproot;                  /* intres imports these */
 int root_dropped;
 #endif
+u_long current_time;           /* libntp/authkeys.c */
 
 void open_sockets(void);
 void handle_lookup(const char *name, int flags);
@@ -140,6 +141,7 @@ sntp_main (
                exit(EX_SOFTWARE);
 
        init_lib();
+       init_auth();
 
        optct = ntpOptionProcess(&sntpOptions, argc, argv);
        argc -= optct;
index d9d6277b1c1b13aeda37c173c60849e20133239b..3d11bb1302effdc5fd97658a59f29610c5864848 100644 (file)
@@ -4,6 +4,7 @@ int main(int argc, char **argv) {
        ::testing::InitGoogleTest(&argc, argv);
 
        init_lib();
+       init_auth();
 
        // Some tests makes use of extra parameters passed to the tests
        // executable. Save these params as static members of the base class.
index 93170bcf49db2d87c53ce756f9164239600f0a05..f4cea7e54981979cbf362ee518dc71dc5b4334fc 100644 (file)
@@ -19,7 +19,7 @@ protected:
  */
 const int keytype = KEY_TYPE_MD5;
 const char *key = "abcdefgh";
-const int keyLength = 8;
+const u_short keyLength = 8;
 const char *packet = "ijklmnopqrstuvwx";
 const int packetLength = 16;
 const int keyIdLength = 4;
@@ -32,7 +32,7 @@ TEST_F(a_md5encryptTest, Encrypt) {
        memset(packetPtr+packetLength, 0, keyIdLength);
        memcpy(packetPtr, packet, packetLength);
 
-       cache_keylen = keyLength;
+       cache_secretsize = keyLength;
 
        int length =  MD5authencrypt(keytype, (u_char*)key, (u_int32*)packetPtr, packetLength);
 
@@ -45,13 +45,13 @@ TEST_F(a_md5encryptTest, Encrypt) {
 }
 
 TEST_F(a_md5encryptTest, DecryptValid) {
-       cache_keylen = keyLength;
+       cache_secretsize = keyLength;
 
        EXPECT_TRUE(MD5authdecrypt(keytype, (u_char*)key, (u_int32*)expectedPacket, packetLength, 20));
 }
 
 TEST_F(a_md5encryptTest, DecryptInvalid) {
-       cache_keylen = keyLength;
+       cache_secretsize = keyLength;
 
        const char *invalidPacket = "ijklmnopqrstuvwx\0\0\0\0\x0c\x0e\x84\xcf\x0b\xb7\xa8\x68\x8e\x52\x38\xdb\xbc\x1c\x39\x54";
        
index b361124b1055f0956e6207369b24fadb14dd4cc1..8dd33a9accfe2a6b1caad42f699a7eacb7089ee3 100644 (file)
@@ -12,19 +12,15 @@ extern "C" {
 #include "ntp_stdlib.h"
 };
 
-// This declaration does not exist in ntp_stdlib.h
-extern u_short cache_flags;
-
 class authkeysTest : public libntptest {
 protected:
        static const int KEYTYPE = KEY_TYPE_MD5;
 
        virtual void SetUp() {
-               init_auth();
-
                /*
-                * init_auth() does not initialize global variables like authnumkeys,
-                * so let's reset them to zero here.
+                * init_auth() is called by tests_main.cpp earlier.  It
+                * does not initialize global variables like
+                * authnumkeys, so let's reset them to zero here.
                 */
                authnumkeys = 0;
 
@@ -34,8 +30,8 @@ protected:
                cache_keyid = 0;
                cache_type = 0;
                cache_flags = 0;
-               cache_key = NULL;
-               cache_keylen = 0;
+               cache_secret = NULL;
+               cache_secretsize = 0;
        }
 
        void AddTrustedKey(keyid_t keyno) {
@@ -45,11 +41,11 @@ protected:
                 */
                MD5auth_setkey(keyno, KEYTYPE, NULL, 0);
 
-               authtrust(keyno, 1);
+               authtrust(keyno, TRUE);
        }
 
        void AddUntrustedKey(keyid_t keyno) {
-               authtrust(keyno, 0);
+               authtrust(keyno, FALSE);
        }
 };