]> git.ipfire.org Git - thirdparty/ntp.git/commitdiff
[Bug 2776] Improve ntpq's 'help keytype'
authorHarlan Stenn <stenn@ntp.org>
Tue, 21 Apr 2015 09:48:05 +0000 (09:48 +0000)
committerHarlan Stenn <stenn@ntp.org>
Tue, 21 Apr 2015 09:48:05 +0000 (09:48 +0000)
bk: 55361cd5MsWVbB6QH2mrIFSKc7Kycw

ChangeLog
ntpq/ntpq.c

index de60ac5a8dc217a98d3ba0b6ada768685b79f97e..e965c762dd3b10dee4e784809d1091174d010979 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,6 @@
 ---
 
+* [Bug 2776] Improve ntpq's 'help keytype'.
 * [Bug 2794] Clean up kernel clock status reports.
 * [Bug 2804] install-local-data assumes GNU 'find' semantics.
 * [Bug 2808] GPSD_JSON driver enhancements, step 1.
index 90cae41b1ca3102effea6263b1ca8b86c54a169f..68c867b29f45f873b62c8a109b60c57c555c83d5 100644 (file)
 #ifdef OPENSSL
 #include "openssl/evp.h"
 #include "openssl/objects.h"
+#include "openssl/err.h"
 #endif
 #include <ssl_applink.c>
 
 #include "ntp_libopts.h"
 #include "ntpq-opts.h"
 
-
 #ifdef SYS_VXWORKS             /* vxWorks needs mode flag -casey*/
 # define open(name, flags)   open(name, flags, 0777)
 # define SERVER_PORT_NUM     123
@@ -218,6 +218,11 @@ static     int     assoccmp        (const void *, const void *);
 
 void   ntpq_custom_opt_handler (tOptions *, tOptDesc *);
 
+#ifdef OPENSSL
+static void list_md_fn(const EVP_MD *m, const char *from,
+                      const char *to, void *arg );
+#endif
+static char *list_digest_names(void);
 
 /*
  * Built-in commands we understand
@@ -275,8 +280,8 @@ struct xcmd builtins[] = {
          { "version number", "", "", "" },
          "set the NTP version number to use for requests" },
        { "keytype",    keytype,        { OPT|NTP_STR, NO, NO, NO },
-         { "key type (md5|des)", "", "", "" },
-         "set key type to use for authenticated requests (des|md5)" },
+         { "key type %s", "", "", "" },
+         NULL },
        { 0,            0,              { NO, NO, NO, NO },
          { "", "", "", "" }, "" }
 };
@@ -458,6 +463,31 @@ ntpqmain(
        if (!ipv6_works)
                ai_fam_default = AF_INET;
 
+       /* Fixup keytype's help based on available digest names */
+
+       {
+           char *list;
+           char *msg, *fmt;
+
+           list = list_digest_names();
+           for (icmd = 0; icmd < sizeof(builtins)/sizeof(builtins[0]); icmd++) {
+               if (strcmp("keytype", builtins[icmd].keyword) == 0)
+                   break;
+           }
+
+#ifdef OPENSSL
+           builtins[icmd].desc[0] = "digest-name";
+           fmt = "set key type to use for authenticated requests, one of:%s";
+#else
+           builtins[icmd].desc[0] = "md5";
+           fmt = "set key type to use for authenticated requests (%s)";
+#endif
+           msg = malloc(strlen(fmt) + strlen(list) - strlen("%s") +1);
+           sprintf(msg, fmt, list);
+           builtins[icmd].comment = msg;
+           free(list);
+       }
+
        progname = argv[0];
 
        {
@@ -2408,11 +2438,11 @@ keytype(
        key_type = keytype_from_text(digest_name, &digest_len);
 
        if (!key_type) {
-               fprintf(fp, "keytype must be 'md5'%s\n",
+               fprintf(fp, "keytype is not valid. "
 #ifdef OPENSSL
-                       " or a digest type provided by OpenSSL");
+                       "Type \"help keytype\" for the available digest types.\n");
 #else
-                       "");
+                       "Only \"md5\" is available.\n");
 #endif
                return;
        }
@@ -3424,3 +3454,97 @@ ntpq_custom_opt_handler(
                break;
        }
 }
+/*
+ * Obtain list of digest names
+ */
+
+#ifdef OPENSSL
+struct hstate {
+   char *list;
+   const char **seen;
+   int idx;
+};
+#define K_PER_LINE 8
+#define K_NL_PFX_STR "\n    "
+#define K_DELIM_STR ", "
+static void list_md_fn(const EVP_MD *m, const char *from, const char *to, void *arg )
+{
+    size_t len, n;
+    const char *name, *cp, **seen;
+    struct hstate *hstate = arg;
+    EVP_MD_CTX ctx;
+    u_int digest_len;
+    u_char digest[EVP_MAX_MD_SIZE];
+
+    if (!m)
+        return; /* Ignore aliases */
+
+    name = EVP_MD_name(m);
+
+    /* Lowercase names aren't accepted by keytype_from_text in ssl_init.c */
+
+    for( cp = name; *cp; cp++ ) {
+       if( islower(*cp) )
+           return;
+    }
+    len = (cp - name) + 1;
+
+    /* There are duplicates.  Discard if name has been seen. */
+
+    for (seen = hstate->seen; *seen; seen++)
+        if (!strcmp(*seen, name))
+           return;
+    n = (seen - hstate->seen) + 2;
+    hstate->seen = realloc(hstate->seen, n * sizeof(*seen));
+    hstate->seen[n-2] = name;
+    hstate->seen[n-1] = NULL;
+
+    /* Discard MACs that NTP won't accept.
+     * Keep this consistent with keytype_from_text() in ssl_init.c.
+     */
+
+    EVP_DigestInit(&ctx, EVP_get_digestbyname(name));
+    EVP_DigestFinal(&ctx, digest, &digest_len);
+    if (digest_len > (MAX_MAC_LEN - sizeof(keyid_t)))
+        return;
+
+    if (hstate->list != NULL)
+       len += strlen(hstate->list);
+    len += (hstate->idx >= K_PER_LINE)? strlen(K_NL_PFX_STR): strlen(K_DELIM_STR);
+
+    if (hstate->list == NULL) {
+       hstate->list = (char *)malloc(len);
+       hstate->list[0] = '\0';
+    } else
+       hstate->list = (char *)realloc(hstate->list, len);
+
+    sprintf(hstate->list + strlen(hstate->list), "%s%s",
+           ((hstate->idx >= K_PER_LINE)? K_NL_PFX_STR : K_DELIM_STR),
+           name);
+    if (hstate->idx >= K_PER_LINE)
+       hstate->idx = 1;
+    else
+       hstate->idx++;
+}
+#endif
+
+static char *list_digest_names(void)
+{
+    char *list = NULL;
+
+#ifdef OPENSSL
+    struct hstate hstate = { NULL, NULL, K_PER_LINE+1 };
+
+    hstate.seen = (const char **)calloc(1, sizeof( const char * ));
+
+    INIT_SSL();
+    EVP_MD_do_all_sorted(list_md_fn, &hstate);
+    list = hstate.list;
+    free(hstate.seen);
+#else
+    list = (char *)malloc(sizeof("md5"));
+    strcpy(list,"md5");
+#endif
+
+    return list;
+}