gpg: Make --auto-key-locate work again with keyservers.
authorWerner Koch <wk@gnupg.org>
Mon, 17 Mar 2014 14:39:33 +0000 (15:39 +0100)
committerWerner Koch <wk@gnupg.org>
Mon, 17 Mar 2014 14:39:33 +0000 (15:39 +0100)
* dirmngr/ks-engine-hkp.c (ks_hkp_get): Allow exact search mode.
* g10/keyserver.c (keyserver_import_name): Implement.
(keyserver_get): Use exact mode for name based import.
(keyserver_get): Add args R_FPR and R_FPRLEN.  Change all callers.

dirmngr/ks-engine-hkp.c
dirmngr/server.c
g10/keyserver.c

index 7b67302..e485e62 100644 (file)
@@ -1040,7 +1040,9 @@ ks_hkp_get (ctrl_t ctrl, parsed_uri_t uri, const char *keyspec, estream_t *r_fp)
 {
   gpg_error_t err;
   KEYDB_SEARCH_DESC desc;
-  char kidbuf[40+1];
+  char kidbuf[2+40+1];
+  const char *exactname = NULL;
+  char *searchkey = NULL;
   char *hostport = NULL;
   char *request = NULL;
   estream_t fp = NULL;
@@ -1060,16 +1062,22 @@ ks_hkp_get (ctrl_t ctrl, parsed_uri_t uri, const char *keyspec, estream_t *r_fp)
   switch (desc.mode)
     {
     case KEYDB_SEARCH_MODE_SHORT_KID:
-      snprintf (kidbuf, sizeof kidbuf, "%08lX", (ulong)desc.u.kid[1]);
+      snprintf (kidbuf, sizeof kidbuf, "0x%08lX", (ulong)desc.u.kid[1]);
       break;
     case KEYDB_SEARCH_MODE_LONG_KID:
-      snprintf (kidbuf, sizeof kidbuf, "%08lX%08lX",
+      snprintf (kidbuf, sizeof kidbuf, "0x%08lX%08lX",
                (ulong)desc.u.kid[0], (ulong)desc.u.kid[1]);
       break;
     case KEYDB_SEARCH_MODE_FPR20:
     case KEYDB_SEARCH_MODE_FPR:
       /* This is a v4 fingerprint. */
-      bin2hex (desc.u.fpr, 20, kidbuf);
+      kidbuf[0] = '0';
+      kidbuf[1] = 'x';
+      bin2hex (desc.u.fpr, 20, kidbuf+2);
+      break;
+
+    case KEYDB_SEARCH_MODE_EXACT:
+      exactname = desc.u.name;
       break;
 
     case KEYDB_SEARCH_MODE_FPR16:
@@ -1078,6 +1086,14 @@ ks_hkp_get (ctrl_t ctrl, parsed_uri_t uri, const char *keyspec, estream_t *r_fp)
       return gpg_error (GPG_ERR_INV_USER_ID);
     }
 
+  searchkey = http_escape_string (exactname? exactname : kidbuf,
+                                  EXTRA_ESCAPE_CHARS);
+  if (!searchkey)
+    {
+      err = gpg_error_from_syserror ();
+      goto leave;
+    }
+
   reselect = 0;
  again:
   /* Build the request string.  */
@@ -1092,8 +1108,9 @@ ks_hkp_get (ctrl_t ctrl, parsed_uri_t uri, const char *keyspec, estream_t *r_fp)
 
   xfree (request);
   request = strconcat (hostport,
-                       "/pks/lookup?op=get&options=mr&search=0x",
-                       kidbuf,
+                       "/pks/lookup?op=get&options=mr&search=",
+                       searchkey,
+                       exactname? "&exact=on":"",
                        NULL);
   if (!request)
     {
@@ -1123,6 +1140,7 @@ ks_hkp_get (ctrl_t ctrl, parsed_uri_t uri, const char *keyspec, estream_t *r_fp)
   es_fclose (fp);
   xfree (request);
   xfree (hostport);
+  xfree (searchkey);
   return err;
 }
 
index f1319ad..bdfb755 100644 (file)
@@ -1603,7 +1603,8 @@ static const char hlp_ks_get[] =
   "KS_GET {<pattern>}\n"
   "\n"
   "Get the keys matching PATTERN from the configured OpenPGP keyservers\n"
-  "(see command KEYSERVER).  Each pattern should be a keyid or a fingerprint";
+  "(see command KEYSERVER).  Each pattern should be a keyid, a fingerprint,\n"
+  "or an exact name indicastes by the '=' prefix.";
 static gpg_error_t
 cmd_ks_get (assuan_context_t ctx, char *line)
 {
index 3a3bc40..ac70da9 100644 (file)
@@ -1,6 +1,7 @@
 /* keyserver.c - generic keyserver code
  * Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
  *               2009, 2011, 2012 Free Software Foundation, Inc.
+ * Copyright (C) 2014 Werner Koch
  *
  * This file is part of GnuPG.
  *
@@ -110,7 +111,8 @@ static struct parse_options keyserver_opts[]=
 
 static gpg_error_t keyserver_get (ctrl_t ctrl,
                                   KEYDB_SEARCH_DESC *desc, int ndesc,
-                                  struct keyserver_spec *keyserver);
+                                  struct keyserver_spec *keyserver,
+                                  unsigned char **r_fpr, size_t *r_fprlen);
 static gpg_error_t keyserver_put (ctrl_t ctrl, strlist_t keyspecs,
                                   struct keyserver_spec *keyserver);
 
@@ -819,7 +821,7 @@ show_prompt (ctrl_t ctrl, KEYDB_SEARCH_DESC *desc, int numdesc,
           }
         for (idx = 0; idx < numidx; idx++)
           selarray[idx] = desc[numarray[idx]-1];
-        err = keyserver_get (ctrl, selarray, numidx, NULL);
+        err = keyserver_get (ctrl, selarray, numidx, NULL, NULL, NULL);
         xfree (selarray);
       }
     }
@@ -1039,6 +1041,7 @@ keyserver_export (ctrl_t ctrl, strlist_t users)
   return rc;
 }
 
+
 int
 keyserver_import (ctrl_t ctrl, strlist_t users)
 {
@@ -1071,13 +1074,31 @@ keyserver_import (ctrl_t ctrl, strlist_t users)
     }
 
   if(count>0)
-    rc=keyserver_get (ctrl, desc, count, NULL);
+    rc=keyserver_get (ctrl, desc, count, NULL, NULL, NULL);
 
   xfree(desc);
 
   return rc;
 }
 
+
+/* Import all keys that exactly match NAME */
+int
+keyserver_import_name (ctrl_t ctrl, const char *name,
+                       unsigned char **fpr, size_t *fprlen,
+                       struct keyserver_spec *keyserver)
+{
+  KEYDB_SEARCH_DESC desc;
+
+  memset (&desc, 0, sizeof desc);
+
+  desc.mode = KEYDB_SEARCH_MODE_EXACT;
+  desc.u.name = name;
+
+  return keyserver_get (ctrl, &desc, 1, keyserver, fpr, fprlen);
+}
+
+
 int
 keyserver_import_fprint (ctrl_t ctrl, const byte *fprint,size_t fprint_len,
                         struct keyserver_spec *keyserver)
@@ -1097,7 +1118,7 @@ keyserver_import_fprint (ctrl_t ctrl, const byte *fprint,size_t fprint_len,
 
   /* TODO: Warn here if the fingerprint we got doesn't match the one
      we asked for? */
-  return keyserver_get (ctrl, &desc, 1, keyserver);
+  return keyserver_get (ctrl, &desc, 1, keyserver, NULL, NULL);
 }
 
 int
@@ -1112,7 +1133,7 @@ keyserver_import_keyid (ctrl_t ctrl,
   desc.u.kid[0]=keyid[0];
   desc.u.kid[1]=keyid[1];
 
-  return keyserver_get (ctrl, &desc,1, keyserver);
+  return keyserver_get (ctrl, &desc,1, keyserver, NULL, NULL);
 }
 
 /* code mostly stolen from do_export_stream */
@@ -1316,7 +1337,7 @@ keyserver_refresh (ctrl_t ctrl, strlist_t users)
              /* We use the keyserver structure we parsed out before.
                 Note that a preferred keyserver without a scheme://
                 will be interpreted as hkp:// */
-             rc = keyserver_get (ctrl, &desc[i], 1, keyserver);
+             rc = keyserver_get (ctrl, &desc[i], 1, keyserver, NULL, NULL);
              if(rc)
                log_info(_("WARNING: unable to refresh key %s"
                           " via %s: %s\n"),keystr_from_desc(&desc[i]),
@@ -1346,7 +1367,7 @@ keyserver_refresh (ctrl_t ctrl, strlist_t users)
                     count,opt.keyserver->uri);
        }
 
-      rc=keyserver_get (ctrl, desc, numdesc, NULL);
+      rc=keyserver_get (ctrl, desc, numdesc, NULL, NULL, NULL);
     }
 
   xfree(desc);
@@ -1469,21 +1490,15 @@ keyserver_search (ctrl_t ctrl, strlist_t tokens)
 
 
 
-/* Called using:
-
-import_name:
-  rc = keyserver_work (ctrl, KS_GETNAME, list, NULL,
-                       0, fpr, fpr_len, keyserver);
-
-import_ldap:
-  rc = keyserver_work (ctrl, KS_GETNAME, list, NULL,
-                       0, fpr, fpr_len, keyserver);
-
- */
-
+/* Retrieve a key from a keyserver.  The search pattern are in
+   (DESC,NDESC).  Allowed search modes are keyid, fingerprint, and
+   exact searches.  KEYSERVER gives an optional override keyserver. If
+   (R_FPR,R_FPRLEN) are not NULL, the may retrun the fingerprint of
+   one imported key.  */
 static gpg_error_t
 keyserver_get (ctrl_t ctrl, KEYDB_SEARCH_DESC *desc, int ndesc,
-               struct keyserver_spec *keyserver)
+               struct keyserver_spec *keyserver,
+               unsigned char **r_fpr, size_t *r_fprlen)
 
 {
   gpg_error_t err = 0;
@@ -1536,10 +1551,12 @@ keyserver_get (ctrl_t ctrl, KEYDB_SEARCH_DESC *desc, int ndesc,
         }
       else if(desc[idx].mode == KEYDB_SEARCH_MODE_EXACT)
         {
-          /* FIXME: We don't need this.  It is used as a dummy by
-             keyserver_fetch which passes an entire URL.  Better use a
-             separate function here. */
-          pattern[npat] = xtrystrdup ("0x0000000000000000");
+          /* The Dirmngr uses also classify_user_id to detect the type
+             of the search string.  By adding the '=' prefix we force
+             Dirmngr's KS_GET to consider this an exact search string.
+             (In gpg 1.4 and gpg 2.0 the keyserver helpers used the
+             KS_GETNAME command to indicate this.)  */
+          pattern[npat] = strconcat ("=", desc[idx].u.name, NULL);
           if (!pattern[npat])
             err = gpg_error_from_syserror ();
           else
@@ -1578,7 +1595,7 @@ keyserver_get (ctrl_t ctrl, KEYDB_SEARCH_DESC *desc, int ndesc,
   for (idx=0; idx < npat; idx++)
     xfree (pattern[idx]);
   xfree (pattern);
-  if (opt.verbose)
+  if (opt.verbose && source)
     log_info ("data source: %s\n", source);
 
   if (!err)
@@ -1599,7 +1616,8 @@ keyserver_get (ctrl_t ctrl, KEYDB_SEARCH_DESC *desc, int ndesc,
          never accept or send them but we better protect against rogue
          keyservers. */
 
-      import_keys_es_stream (ctrl, datastream, stats_handle, NULL, NULL,
+      import_keys_es_stream (ctrl, datastream, stats_handle,
+                             r_fpr, r_fprlen,
                              (opt.keyserver_options.import_options
                               | IMPORT_NO_SECKEY));
       import_print_stats (stats_handle);
@@ -1824,31 +1842,18 @@ keyserver_import_pka (ctrl_t ctrl,
   return rc;
 }
 
-/* Import all keys that match name */
-int
-keyserver_import_name (ctrl_t ctrl, const char *name,
-                       unsigned char **fpr, size_t *fpr_len,
-                       struct keyserver_spec *keyserver)
-{
-  strlist_t list=NULL;
-  int rc;
-
-  append_to_strlist(&list,name);
-
-  rc = gpg_error (GPG_ERR_NOT_IMPLEMENTED);  /* FIXME */
-       /* keyserver_work (ctrl, KS_GETNAME, list, NULL, */
-       /*                 0, fpr, fpr_len, keyserver); */
-
-  free_strlist(list);
-
-  return rc;
-}
 
 /* Import a key by name using LDAP */
 int
 keyserver_import_ldap (ctrl_t ctrl,
-                       const char *name,unsigned char **fpr,size_t *fpr_len)
+                       const char *name, unsigned char **fpr, size_t *fprlen)
 {
+  (void)ctrl;
+  (void)name;
+  (void)fpr;
+  (void)fprlen;
+  return gpg_error (GPG_ERR_NOT_IMPLEMENTED); /*FIXME*/
+#if 0
   char *domain;
   struct keyserver_spec *keyserver;
   strlist_t list=NULL;
@@ -1919,4 +1924,5 @@ keyserver_import_ldap (ctrl_t ctrl,
   free_keyserver_spec(keyserver);
 
   return rc;
+#endif
 }