doc: Typo fix in a comment.
[gnupg.git] / g10 / keyserver.c
index 3aed54b..a8c222d 100644 (file)
@@ -16,7 +16,7 @@
  * GNU General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
- * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ * along with this program; if not, see <https://www.gnu.org/licenses/>.
  */
 
 #include <config.h>
 #include <stdio.h>
 #include <string.h>
 #include <stdlib.h>
-#include <assert.h>
 #include <errno.h>
 
 #include "gpg.h"
-#include "iobuf.h"
+#include "../common/iobuf.h"
 #include "filter.h"
 #include "keydb.h"
-#include "status.h"
+#include "../common/status.h"
 #include "exec.h"
 #include "main.h"
-#include "i18n.h"
-#include "ttyio.h"
+#include "../common/i18n.h"
+#include "../common/ttyio.h"
 #include "options.h"
 #include "packet.h"
 #include "trustdb.h"
 #include "keyserver-internal.h"
-#include "util.h"
-#include "dns-cert.h"
-#include "pka.h"
-#ifdef USE_DNS_SRV
-#include "srv.h"
-#endif
-#include "membuf.h"
+#include "../common/util.h"
+#include "../common/membuf.h"
+#include "../common/mbox-util.h"
 #include "call-dirmngr.h"
 
 #ifdef HAVE_W32_SYSTEM
@@ -92,11 +87,11 @@ static struct parse_options keyserver_opts[]=
     /* some of these options are not real - just for the help
        message */
     {"max-cert-size",0,NULL,NULL},  /* MUST be the first in this array! */
+    {"http-proxy", KEYSERVER_HTTP_PROXY, NULL, /* MUST be the second!  */
+     N_("override proxy options set for dirmngr")},
 
     {"include-revoked",0,NULL,N_("include revoked keys in search results")},
     {"include-subkeys",0,NULL,N_("include subkeys when searching by key ID")},
-    {"http-proxy", KEYSERVER_HTTP_PROXY, NULL,
-     N_("override proxy options set for dirmngr")},
     {"timeout", KEYSERVER_TIMEOUT, NULL,
      N_("override timeout options set for dirmngr")},
     {"refresh-add-fake-v3-keyids",KEYSERVER_ADD_FAKE_V3,NULL,
@@ -112,10 +107,10 @@ 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 *override_keyserver,
+                                  int quick,
                                   unsigned char **r_fpr, size_t *r_fprlen);
-static gpg_error_t keyserver_put (ctrl_t ctrl, strlist_t keyspecs,
-                                  struct keyserver_spec *keyserver);
+static gpg_error_t keyserver_put (ctrl_t ctrl, strlist_t keyspecs);
 
 
 /* Reasonable guess.  The commonly used test key simon.josefsson.org
@@ -124,8 +119,9 @@ static gpg_error_t keyserver_put (ctrl_t ctrl, strlist_t keyspecs,
 
 static size_t max_cert_size=DEFAULT_MAX_CERT_SIZE;
 
+
 static void
-warn_kshelper_option(char *option)
+warn_kshelper_option(char *option, int noisy)
 {
   char *p;
 
@@ -139,9 +135,12 @@ warn_kshelper_option(char *option)
   else if (!strcmp (option, "check-cert")
            || !strcmp (option, "broken-http-proxy"))
     log_info ("keyserver option '%s' is obsolete\n", option);
+  else if (noisy || opt.verbose)
+    log_info ("keyserver option '%s' is unknown\n", option);
 }
 
 
+/* Called from main to parse the args for --keyserver-options.  */
 int
 parse_keyserver_options(char *options)
 {
@@ -150,6 +149,7 @@ parse_keyserver_options(char *options)
   char *max_cert=NULL;
 
   keyserver_opts[0].value=&max_cert;
+  keyserver_opts[1].value=&opt.keyserver_options.http_proxy;
 
   while((tok=optsep(&options)))
     {
@@ -166,7 +166,7 @@ parse_keyserver_options(char *options)
        {
          /* All of the standard options have failed, so the option was
             destined for a keyserver plugin as used by GnuPG < 2.1 */
-         warn_kshelper_option (tok);
+         warn_kshelper_option (tok, 1);
        }
     }
 
@@ -242,13 +242,13 @@ parse_keyserver_uri (const char *string,int require_scheme)
   struct keyserver_spec *keyserver;
   const char *idx;
   int count;
-  char *uri,*options;
+  char *uri, *duped_uri, *options;
 
-  assert(string!=NULL);
+  log_assert (string);
 
   keyserver=xmalloc_clear(sizeof(struct keyserver_spec));
 
-  uri=xstrdup(string);
+  duped_uri = uri = xstrdup (string);
 
   options=strchr(uri,' ');
   if(options)
@@ -259,7 +259,7 @@ parse_keyserver_uri (const char *string,int require_scheme)
       options++;
 
       while((tok=optsep(&options)))
-       warn_kshelper_option (tok);
+       warn_kshelper_option (tok, 0);
     }
 
   /* Get the scheme */
@@ -436,11 +436,13 @@ parse_keyserver_uri (const char *string,int require_scheme)
       goto fail;
     }
 
+  xfree (duped_uri);
   return keyserver;
 
  fail:
   free_keyserver_spec(keyserver);
 
+  xfree (duped_uri);
   return NULL;
 }
 
@@ -466,7 +468,7 @@ parse_preferred_keyserver(PKT_signature *sig)
 }
 
 static void
-print_keyrec(int number,struct keyrec *keyrec)
+print_keyrec (ctrl_t ctrl, int number,struct keyrec *keyrec)
 {
   int i;
 
@@ -520,7 +522,7 @@ print_keyrec(int number,struct keyrec *keyrec)
     case KEYDB_SEARCH_MODE_FPR20:
       {
        u32 kid[2];
-       keyid_from_fingerprint(keyrec->desc.u.fpr,20,kid);
+       keyid_from_fingerprint (ctrl, keyrec->desc.u.fpr,20,kid);
        es_printf("key %s",keystr(kid));
       }
       break;
@@ -792,7 +794,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, NULL, NULL);
+        err = keyserver_get (ctrl, selarray, numidx, NULL, 0, NULL, NULL);
         xfree (selarray);
       }
     }
@@ -958,7 +960,7 @@ search_line_handler (void *opaque, int special, char *line)
               parm->numlines = 0;
             }
 
-          print_keyrec (parm->nkeys+1, keyrec);
+          print_keyrec (parm->ctrl, parm->nkeys+1, keyrec);
         }
 
       parm->numlines += keyrec->lines;
@@ -1005,7 +1007,7 @@ keyserver_export (ctrl_t ctrl, strlist_t users)
 
   if(sl)
     {
-      rc = keyserver_put (ctrl, sl, opt.keyserver);
+      rc = keyserver_put (ctrl, sl);
       free_strlist(sl);
     }
 
@@ -1124,7 +1126,7 @@ keyserver_import (ctrl_t ctrl, strlist_t users)
     }
 
   if(count>0)
-    rc=keyserver_get (ctrl, desc, count, NULL, NULL, NULL);
+    rc = keyserver_get (ctrl, desc, count, NULL, 0, NULL, NULL);
 
   xfree(desc);
 
@@ -1132,6 +1134,14 @@ keyserver_import (ctrl_t ctrl, strlist_t users)
 }
 
 
+/* Return true if any keyserver has been configured. */
+int
+keyserver_any_configured (ctrl_t ctrl)
+{
+  return !gpg_dirmngr_ks_list (ctrl, NULL);
+}
+
+
 /* Import all keys that exactly match NAME */
 int
 keyserver_import_name (ctrl_t ctrl, const char *name,
@@ -1145,13 +1155,13 @@ keyserver_import_name (ctrl_t ctrl, const char *name,
   desc.mode = KEYDB_SEARCH_MODE_EXACT;
   desc.u.name = name;
 
-  return keyserver_get (ctrl, &desc, 1, keyserver, fpr, fprlen);
+  return keyserver_get (ctrl, &desc, 1, keyserver, 0, fpr, fprlen);
 }
 
 
 int
 keyserver_import_fprint (ctrl_t ctrl, const byte *fprint,size_t fprint_len,
-                        struct keyserver_spec *keyserver)
+                        struct keyserver_spec *keyserver, int quick)
 {
   KEYDB_SEARCH_DESC desc;
 
@@ -1168,12 +1178,12 @@ 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, NULL, NULL);
+  return keyserver_get (ctrl, &desc, 1, keyserver, quick, NULL, NULL);
 }
 
 int
 keyserver_import_keyid (ctrl_t ctrl,
-                        u32 *keyid,struct keyserver_spec *keyserver)
+                        u32 *keyid,struct keyserver_spec *keyserver, int quick)
 {
   KEYDB_SEARCH_DESC desc;
 
@@ -1183,17 +1193,22 @@ 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, NULL, NULL);
+  return keyserver_get (ctrl, &desc, 1, keyserver, quick, NULL, NULL);
 }
 
+
 /* code mostly stolen from do_export_stream */
 static int
-keyidlist(strlist_t users,KEYDB_SEARCH_DESC **klist,int *count,int fakev3)
+keyidlist (ctrl_t ctrl, strlist_t users, KEYDB_SEARCH_DESC **klist,
+           int *count, int fakev3)
 {
-  int rc=0,ndesc,num=100;
-  KBNODE keyblock=NULL,node;
+  int rc = 0;
+  int num = 100;
+  kbnode_t keyblock = NULL;
+  kbnode_t node;
   KEYDB_HANDLE kdbhd;
-  KEYDB_SEARCH_DESC *desc;
+  int ndesc;
+  KEYDB_SEARCH_DESC *desc = NULL;
   strlist_t sl;
 
   *count=0;
@@ -1201,6 +1216,11 @@ keyidlist(strlist_t users,KEYDB_SEARCH_DESC **klist,int *count,int fakev3)
   *klist=xmalloc(sizeof(KEYDB_SEARCH_DESC)*num);
 
   kdbhd = keydb_new ();
+  if (!kdbhd)
+    {
+      rc = gpg_error_from_syserror ();
+      goto leave;
+    }
   keydb_disable_caching (kdbhd);  /* We are looping the search.  */
 
   if(!users)
@@ -1229,21 +1249,16 @@ keyidlist(strlist_t users,KEYDB_SEARCH_DESC **klist,int *count,int fakev3)
   for (;;)
     {
       rc = keydb_search (kdbhd, desc, ndesc, NULL);
-      if (rc && gpg_err_code (rc) != GPG_ERR_LEGACY_KEY)
+      if (rc)
         break;  /* ready.  */
 
       if (!users)
        desc[0].mode = KEYDB_SEARCH_MODE_NEXT;
 
-      if (gpg_err_code (rc) == GPG_ERR_LEGACY_KEY)
-        continue;
-
       /* read the keyblock */
       rc = keydb_get_keyblock (kdbhd, &keyblock );
       if( rc )
        {
-          if (gpg_err_code (rc) == GPG_ERR_LEGACY_KEY)
-            continue;
           log_error (_("error reading keyblock: %s\n"), gpg_strerror (rc) );
          goto leave;
        }
@@ -1305,12 +1320,12 @@ keyidlist(strlist_t users,KEYDB_SEARCH_DESC **klist,int *count,int fakev3)
              PKT_user_id *uid=NULL;
              PKT_signature *sig=NULL;
 
-             merge_keys_and_selfsig(keyblock);
+             merge_keys_and_selfsig (ctrl, keyblock);
 
              for(node=node->next;node;node=node->next)
                {
                  if(node->pkt->pkttype==PKT_USER_ID
-                    && node->pkt->pkt.user_id->is_primary)
+                    && node->pkt->pkt.user_id->flags.primary)
                    uid=node->pkt->pkt.user_id;
                  else if(node->pkt->pkttype==PKT_SIGNATURE
                          && node->pkt->pkt.signature->
@@ -1343,7 +1358,10 @@ keyidlist(strlist_t users,KEYDB_SEARCH_DESC **klist,int *count,int fakev3)
 
  leave:
   if(rc)
-    xfree(*klist);
+    {
+      xfree(*klist);
+      *klist = NULL;
+    }
   xfree(desc);
   keydb_release(kdbhd);
   release_kbnode(keyblock);
@@ -1354,10 +1372,12 @@ keyidlist(strlist_t users,KEYDB_SEARCH_DESC **klist,int *count,int fakev3)
 /* Note this is different than the original HKP refresh.  It allows
    usernames to refresh only part of the keyring. */
 
-int
+gpg_error_t
 keyserver_refresh (ctrl_t ctrl, strlist_t users)
 {
-  int rc,count,numdesc,fakev3=0;
+  gpg_error_t err;
+  int count, numdesc;
+  int fakev3 = 0;
   KEYDB_SEARCH_DESC *desc;
   unsigned int options=opt.keyserver_options.import_options;
 
@@ -1372,15 +1392,20 @@ keyserver_refresh (ctrl_t ctrl, strlist_t users)
   opt.keyserver_options.import_options|=IMPORT_FAST;
 
   /* If refresh_add_fake_v3_keyids is on and it's a HKP or MAILTO
-     scheme, then enable fake v3 keyid generation. */
+     scheme, then enable fake v3 keyid generation.  Note that this
+     works only with a keyserver configured. gpg.conf
+     (i.e. opt.keyserver); however that method of configuring a
+     keyserver is deprecated and in any case it is questionable
+     whether we should keep on supporting these ancient and broken
+     keyservers.  */
   if((opt.keyserver_options.options&KEYSERVER_ADD_FAKE_V3) && opt.keyserver
      && (ascii_strcasecmp(opt.keyserver->scheme,"hkp")==0 ||
         ascii_strcasecmp(opt.keyserver->scheme,"mailto")==0))
     fakev3=1;
 
-  rc=keyidlist(users,&desc,&numdesc,fakev3);
-  if(rc)
-    return rc;
+  err = keyidlist (ctrl, users, &desc, &numdesc, fakev3);
+  if (err)
+    return err;
 
   count=numdesc;
   if(count>0)
@@ -1394,14 +1419,17 @@ keyserver_refresh (ctrl_t ctrl, strlist_t users)
            {
              struct keyserver_spec *keyserver=desc[i].skipfncvalue;
 
+              if (!opt.quiet)
+                log_info (_("refreshing %d key from %s\n"), 1, keyserver->uri);
+
              /* 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, NULL, NULL);
-             if(rc)
+             err = keyserver_get (ctrl, &desc[i], 1, keyserver, 0, NULL, NULL);
+             if (err)
                log_info(_("WARNING: unable to refresh key %s"
                           " via %s: %s\n"),keystr_from_desc(&desc[i]),
-                        keyserver->uri,gpg_strerror (rc));
+                        keyserver->uri,gpg_strerror (err));
              else
                {
                  /* We got it, so mark it as NONE so we don't try and
@@ -1418,16 +1446,21 @@ keyserver_refresh (ctrl_t ctrl, strlist_t users)
 
   if(count>0)
     {
-      if(opt.keyserver)
-       {
-         if(count==1)
-           log_info(_("refreshing 1 key from %s\n"),opt.keyserver->uri);
-         else
-           log_info(_("refreshing %d keys from %s\n"),
-                    count,opt.keyserver->uri);
-       }
+      char *tmpuri;
+
+      err = gpg_dirmngr_ks_list (ctrl, &tmpuri);
+      if (!err)
+        {
+          if (!opt.quiet)
+            {
+              log_info (ngettext("refreshing %d key from %s\n",
+                                 "refreshing %d keys from %s\n",
+                                 count), count, tmpuri);
+            }
+          xfree (tmpuri);
 
-      rc=keyserver_get (ctrl, desc, numdesc, NULL, NULL, NULL);
+          err = keyserver_get (ctrl, desc, numdesc, NULL, 0, NULL, NULL);
+        }
     }
 
   xfree(desc);
@@ -1437,9 +1470,9 @@ keyserver_refresh (ctrl_t ctrl, strlist_t users)
   /* If the original options didn't have fast import, and the trustdb
      is dirty, rebuild. */
   if(!(opt.keyserver_options.import_options&IMPORT_FAST))
-    check_or_update_trustdb ();
+    check_or_update_trustdb (ctrl);
 
-  return rc;
+  return err;
 }
 
 
@@ -1457,12 +1490,6 @@ keyserver_search (ctrl_t ctrl, strlist_t tokens)
   if (!tokens)
     return 0;  /* Return success if no patterns are given.  */
 
-  if (!opt.keyserver)
-    {
-      log_error (_("no keyserver known (use option --keyserver)\n"));
-      return gpg_error (GPG_ERR_NO_KEYSERVER);
-    }
-
   /* Write global options */
 
   /* for(temp=opt.keyserver_options.other;temp;temp=temp->next) */
@@ -1555,18 +1582,20 @@ keyserver_search (ctrl_t ctrl, strlist_t tokens)
 static gpg_error_t
 keyserver_get_chunk (ctrl_t ctrl, KEYDB_SEARCH_DESC *desc, int ndesc,
                      int *r_ndesc_used,
-                     void *stats_handle,
-                     struct keyserver_spec *keyserver,
+                     import_stats_t stats_handle,
+                     struct keyserver_spec *override_keyserver,
+                     int quick,
                      unsigned char **r_fpr, size_t *r_fprlen)
 
 {
   gpg_error_t err = 0;
   char **pattern;
-  int idx, npat;
+  int idx, npat, npat_fpr;
   estream_t datastream;
   char *source = NULL;
   size_t linelen;  /* Estimated linelen for KS_GET.  */
   size_t n;
+  int only_fprs;
 
 #define MAX_KS_GET_LINELEN 950  /* Somewhat lower than the real limit.  */
 
@@ -1580,12 +1609,12 @@ keyserver_get_chunk (ctrl_t ctrl, KEYDB_SEARCH_DESC *desc, int ndesc,
 
   /* Note that we break the loop as soon as our estimation of the to
      be used line length reaches the limit.  But we do this only if we
-     have processed at leas one search requests so that an overlong
+     have processed at least one search requests so that an overlong
      single request will be rejected only later by gpg_dirmngr_ks_get
      but we are sure that R_NDESC_USED has been updated.  This avoids
      a possible indefinite loop.  */
-  linelen = 9; /* "KS_GET --" */
-  for (npat=idx=0; idx < ndesc; idx++)
+  linelen = 17; /* "KS_GET --quick --" */
+  for (npat=npat_fpr=0, idx=0; idx < ndesc; idx++)
     {
       int quiet = 0;
 
@@ -1607,6 +1636,8 @@ keyserver_get_chunk (ctrl_t ctrl, KEYDB_SEARCH_DESC *desc, int ndesc,
                        desc[idx].mode == KEYDB_SEARCH_MODE_FPR20? 20 : 16,
                        pattern[npat]+2);
               npat++;
+              if (desc[idx].mode == KEYDB_SEARCH_MODE_FPR20)
+                npat_fpr++;
             }
         }
       else if(desc[idx].mode == KEYDB_SEARCH_MODE_LONG_KID)
@@ -1672,15 +1703,15 @@ keyserver_get_chunk (ctrl_t ctrl, KEYDB_SEARCH_DESC *desc, int ndesc,
           return err;
         }
 
-      if (!quiet && keyserver)
+      if (!quiet && override_keyserver)
         {
-          if (keyserver->host)
+          if (override_keyserver->host)
             log_info (_("requesting key %s from %s server %s\n"),
                       keystr_from_desc (&desc[idx]),
-                      keyserver->scheme, keyserver->host);
+                      override_keyserver->scheme, override_keyserver->host);
           else
             log_info (_("requesting key %s from %s\n"),
-                      keystr_from_desc (&desc[idx]), keyserver->uri);
+                      keystr_from_desc (&desc[idx]), override_keyserver->uri);
         }
     }
 
@@ -1688,7 +1719,10 @@ keyserver_get_chunk (ctrl_t ctrl, KEYDB_SEARCH_DESC *desc, int ndesc,
      this is different from NPAT.  */
   *r_ndesc_used = idx;
 
-  err = gpg_dirmngr_ks_get (ctrl, pattern, &datastream, &source);
+  only_fprs = (npat && npat == npat_fpr);
+
+  err = gpg_dirmngr_ks_get (ctrl, pattern, override_keyserver, quick,
+                            &datastream, &source);
   for (idx=0; idx < npat; idx++)
     xfree (pattern[idx]);
   xfree (pattern);
@@ -1717,7 +1751,9 @@ keyserver_get_chunk (ctrl_t ctrl, KEYDB_SEARCH_DESC *desc, int ndesc,
                              r_fpr, r_fprlen,
                              (opt.keyserver_options.import_options
                               | IMPORT_NO_SECKEY),
-                             keyserver_retrieval_screener, &screenerarg);
+                             keyserver_retrieval_screener, &screenerarg,
+                             only_fprs? KEYORG_KS : 0,
+                             source);
     }
   es_fclose (datastream);
   xfree (source);
@@ -1728,16 +1764,17 @@ keyserver_get_chunk (ctrl_t ctrl, KEYDB_SEARCH_DESC *desc, int ndesc,
 
 /* 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, they may return the fingerprint of a
-   single imported key.  */
+   exact searches.  OVERRIDE_KEYSERVER gives an optional override
+   keyserver. If (R_FPR,R_FPRLEN) are not NULL, they may return the
+   fingerprint of a single imported key.  If QUICK is set, dirmngr is
+   advised to use a shorter timeout. */
 static gpg_error_t
 keyserver_get (ctrl_t ctrl, KEYDB_SEARCH_DESC *desc, int ndesc,
-               struct keyserver_spec *keyserver,
+               struct keyserver_spec *override_keyserver, int quick,
                unsigned char **r_fpr, size_t *r_fprlen)
 {
   gpg_error_t err;
-  void *stats_handle;
+  import_stats_t stats_handle;
   int ndesc_used;
   int any_good = 0;
 
@@ -1746,7 +1783,7 @@ keyserver_get (ctrl_t ctrl, KEYDB_SEARCH_DESC *desc, int ndesc,
   for (;;)
     {
       err = keyserver_get_chunk (ctrl, desc, ndesc, &ndesc_used, stats_handle,
-                                 keyserver, r_fpr, r_fprlen);
+                                 override_keyserver, quick, r_fpr, r_fprlen);
       if (!err)
         any_good = 1;
       if (err || ndesc_used >= ndesc)
@@ -1764,21 +1801,21 @@ keyserver_get (ctrl_t ctrl, KEYDB_SEARCH_DESC *desc, int ndesc,
 }
 
 
-/* Send all keys specified by KEYSPECS to the KEYSERVERS.  */
+/* Send all keys specified by KEYSPECS to the configured keyserver.  */
 static gpg_error_t
-keyserver_put (ctrl_t ctrl, strlist_t keyspecs,
-               struct keyserver_spec *keyserver)
+keyserver_put (ctrl_t ctrl, strlist_t keyspecs)
 
 {
   gpg_error_t err;
   strlist_t kspec;
+  char *ksurl;
 
   if (!keyspecs)
     return 0;  /* Return success if the list is empty.  */
 
-  if (!opt.keyserver)
+  if (gpg_dirmngr_ks_list (ctrl, &ksurl))
     {
-      log_error (_("no keyserver known (use option --keyserver)\n"));
+      log_error (_("no keyserver known\n"));
       return gpg_error (GPG_ERR_NO_KEYSERVER);
     }
 
@@ -1790,19 +1827,15 @@ keyserver_put (ctrl_t ctrl, strlist_t keyspecs,
 
       err = export_pubkey_buffer (ctrl, kspec->d,
                                   opt.keyserver_options.export_options,
+                                  NULL,
                                   &keyblock, &data, &datalen);
       if (err)
         log_error (_("skipped \"%s\": %s\n"), kspec->d, gpg_strerror (err));
       else
         {
-          if (keyserver->host)
-            log_info (_("sending key %s to %s server %s\n"),
-                      keystr (keyblock->pkt->pkt.public_key->keyid),
-                      keyserver->scheme, keyserver->host);
-          else
-            log_info (_("sending key %s to %s\n"),
-                      keystr (keyblock->pkt->pkt.public_key->keyid),
-                      keyserver->uri);
+          log_info (_("sending key %s to %s\n"),
+                    keystr (keyblock->pkt->pkt.public_key->keyid),
+                    ksurl?ksurl:"[?]");
 
           err = gpg_dirmngr_ks_put (ctrl, data, datalen, keyblock);
           release_kbnode (keyblock);
@@ -1815,6 +1848,7 @@ keyserver_put (ctrl_t ctrl, strlist_t keyspecs,
         }
     }
 
+  xfree (ksurl);
 
   return err;
 
@@ -1822,10 +1856,10 @@ keyserver_put (ctrl_t ctrl, strlist_t keyspecs,
 
 
 /* Loop over all URLs in STRLIST and fetch the key at that URL.  Note
-   that the fetch operation ignores the configured key servers and
+   that the fetch operation ignores the configured keyservers and
    instead directly retrieves the keys.  */
 int
-keyserver_fetch (ctrl_t ctrl, strlist_t urilist)
+keyserver_fetch (ctrl_t ctrl, strlist_t urilist, int origin)
 {
   gpg_error_t err;
   strlist_t sl;
@@ -1845,12 +1879,12 @@ keyserver_fetch (ctrl_t ctrl, strlist_t urilist)
       err = gpg_dirmngr_ks_fetch (ctrl, sl->d, &datastream);
       if (!err)
         {
-          void *stats_handle;
+          import_stats_t stats_handle;
 
           stats_handle = import_new_stats_handle();
           import_keys_es_stream (ctrl, datastream, stats_handle, NULL, NULL,
                                  opt.keyserver_options.import_options,
-                                 NULL, NULL);
+                                 NULL, NULL, origin, sl->d);
 
           import_print_stats (stats_handle);
           import_release_stats_handle (stats_handle);
@@ -1866,42 +1900,68 @@ keyserver_fetch (ctrl_t ctrl, strlist_t urilist)
   /* If the original options didn't have fast import, and the trustdb
      is dirty, rebuild. */
   if (!(opt.keyserver_options.import_options&IMPORT_FAST))
-    check_or_update_trustdb ();
+    check_or_update_trustdb (ctrl);
 
   return 0;
 }
 
 
-/* Import key in a CERT or pointed to by a CERT */
+/* Import key in a CERT or pointed to by a CERT.  In DANE_MODE fetch
+   the certificate using the DANE method.  */
 int
-keyserver_import_cert (ctrl_t ctrl,
-                       const char *name,unsigned char **fpr,size_t *fpr_len)
+keyserver_import_cert (ctrl_t ctrl, const char *name, int dane_mode,
+                       unsigned char **fpr,size_t *fpr_len)
 {
   gpg_error_t err;
-  char *domain,*look,*url;
+  char *look,*url;
   estream_t key;
 
+  look = xstrdup(name);
 
-  look=xstrdup(name);
-
-  domain=strrchr(look,'@');
-  if(domain)
-    *domain='.';
+  if (!dane_mode)
+    {
+      char *domain = strrchr (look,'@');
+      if (domain)
+        *domain='.';
+    }
 
-  err = get_dns_cert (look, DNS_CERTTYPE_ANY, &key, fpr, fpr_len, &url);
+  err = gpg_dirmngr_dns_cert (ctrl, look, dane_mode? NULL : "*",
+                              &key, fpr, fpr_len, &url);
   if (err)
     ;
   else if (key)
     {
       int armor_status=opt.no_armor;
+      import_filter_t save_filt;
 
-      /* CERTs are always in binary format */
+      /* CERTs and DANE records are always in binary format */
       opt.no_armor=1;
-
-      err = import_keys_es_stream (ctrl, key, NULL, fpr, fpr_len,
-                                   (opt.keyserver_options.import_options
-                                    | IMPORT_NO_SECKEY),
-                                   NULL, NULL);
+      if (dane_mode)
+        {
+          save_filt = save_and_clear_import_filter ();
+          if (!save_filt)
+            err = gpg_error_from_syserror ();
+          else
+            {
+              char *filtstr = es_bsprintf ("keep-uid=mbox = %s", look);
+              err = filtstr? 0 : gpg_error_from_syserror ();
+              if (!err)
+                err = parse_and_set_import_filter (filtstr);
+              xfree (filtstr);
+              if (!err)
+                err = import_keys_es_stream (ctrl, key, NULL, fpr, fpr_len,
+                                             IMPORT_NO_SECKEY,
+                                             NULL, NULL, KEYORG_DANE, NULL);
+              restore_import_filter (save_filt);
+            }
+        }
+      else
+        {
+          err = import_keys_es_stream (ctrl, key, NULL, fpr, fpr_len,
+                                       (opt.keyserver_options.import_options
+                                        | IMPORT_NO_SECKEY),
+                                       NULL, NULL, 0, NULL);
+        }
 
       opt.no_armor=armor_status;
 
@@ -1920,19 +1980,20 @@ keyserver_import_cert (ctrl_t ctrl,
          spec = parse_keyserver_uri (url, 1);
          if(spec)
            {
-             err = keyserver_import_fprint (ctrl, *fpr,*fpr_len,spec);
+             err = keyserver_import_fprint (ctrl, *fpr, *fpr_len, spec, 0);
              free_keyserver_spec(spec);
            }
        }
-      else if(opt.keyserver)
+      else if (keyserver_any_configured (ctrl))
        {
          /* If only a fingerprint is provided, try and fetch it from
-            our --keyserver */
+            the configured keyserver. */
 
-         err = keyserver_import_fprint (ctrl, *fpr,*fpr_len,opt.keyserver);
+         err = keyserver_import_fprint (ctrl,
+                                         *fpr, *fpr_len, opt.keyserver, 0);
        }
       else
-       log_info(_("no keyserver known (use option --keyserver)\n"));
+       log_info(_("no keyserver known\n"));
 
       /* Give a better string here? "CERT fingerprint for \"%s\"
         found, but no keyserver" " known (use option
@@ -1948,37 +2009,96 @@ keyserver_import_cert (ctrl_t ctrl,
 
 /* Import key pointed to by a PKA record. Return the requested
    fingerprint in fpr. */
-int
-keyserver_import_pka (ctrl_t ctrl,
-                      const char *name,unsigned char **fpr,size_t *fpr_len)
+gpg_error_t
+keyserver_import_pka (ctrl_t ctrl, const char *name,
+                      unsigned char **fpr, size_t *fpr_len)
 {
-  char *uri;
-  int rc = GPG_ERR_NO_PUBKEY;
-
-  *fpr = xmalloc (20);
-  *fpr_len = 20;
+  gpg_error_t err;
+  char *url;
 
-  uri = get_pka_info (name, *fpr, 20);
-  if (uri && *uri)
+  err = gpg_dirmngr_get_pka (ctrl, name, fpr, fpr_len, &url);
+  if (url && *url && fpr && fpr_len)
     {
-      /* An URI is available.  Lookup the key. */
+      /* An URL is available.  Lookup the key. */
       struct keyserver_spec *spec;
-      spec = parse_keyserver_uri (uri, 1);
+      spec = parse_keyserver_uri (url, 1);
       if (spec)
        {
-         rc = keyserver_import_fprint (ctrl, *fpr, 20, spec);
+         err = keyserver_import_fprint (ctrl, *fpr, *fpr_len, spec, 0);
          free_keyserver_spec (spec);
        }
     }
-  xfree (uri);
+  xfree (url);
 
-  if (rc)
+  if (err)
     {
       xfree(*fpr);
       *fpr = NULL;
+      *fpr_len = 0;
     }
 
-  return rc;
+  return err;
+}
+
+
+/* Import a key using the Web Key Directory protocol.  */
+gpg_error_t
+keyserver_import_wkd (ctrl_t ctrl, const char *name, int quick,
+                      unsigned char **fpr, size_t *fpr_len)
+{
+  gpg_error_t err;
+  char *mbox;
+  estream_t key;
+  char *url = NULL;
+
+  /* We want to work on the mbox.  That is what dirmngr will do anyway
+   * and we need the mbox for the import filter anyway.  */
+  mbox = mailbox_from_userid (name);
+  if (!mbox)
+    {
+      err = gpg_error_from_syserror ();
+      if (gpg_err_code (err) == GPG_ERR_EINVAL)
+        err = gpg_error (GPG_ERR_INV_USER_ID);
+      return err;
+    }
+
+  err = gpg_dirmngr_wkd_get (ctrl, mbox, quick, &key, &url);
+  if (err)
+    ;
+  else if (key)
+    {
+      int armor_status = opt.no_armor;
+      import_filter_t save_filt;
+
+      /* Keys returned via WKD are in binary format. */
+      opt.no_armor = 1;
+      save_filt = save_and_clear_import_filter ();
+      if (!save_filt)
+        err = gpg_error_from_syserror ();
+      else
+        {
+          char *filtstr = es_bsprintf ("keep-uid=mbox = %s", mbox);
+          err = filtstr? 0 : gpg_error_from_syserror ();
+          if (!err)
+            err = parse_and_set_import_filter (filtstr);
+          xfree (filtstr);
+          if (!err)
+            err = import_keys_es_stream (ctrl, key, NULL, fpr, fpr_len,
+                                         IMPORT_NO_SECKEY,
+                                         NULL, NULL, KEYORG_WKD, url);
+
+        }
+
+      restore_import_filter (save_filt);
+      opt.no_armor = armor_status;
+
+      es_fclose (key);
+      key = NULL;
+    }
+
+  xfree (url);
+  xfree (mbox);
+  return err;
 }
 
 
@@ -1997,11 +2117,9 @@ keyserver_import_ldap (ctrl_t ctrl,
   struct keyserver_spec *keyserver;
   strlist_t list=NULL;
   int rc,hostlen=1;
-#ifdef USE_DNS_SRV
   struct srventry *srvlist=NULL;
   int srvcount,i;
   char srvname[MAXDNAME];
-#endif
 
   /* Parse out the domain */
   domain=strrchr(name,'@');
@@ -2015,9 +2133,9 @@ keyserver_import_ldap (ctrl_t ctrl,
   keyserver->host=xmalloc(1);
   keyserver->host[0]='\0';
 
-#ifdef USE_DNS_SRV
   snprintf(srvname,MAXDNAME,"_pgpkey-ldap._tcp.%s",domain);
 
+  FIXME("network related - move to dirmngr or drop the code");
   srvcount=getsrv(srvname,&srvlist);
 
   for(i=0;i<srvcount;i++)
@@ -2042,7 +2160,6 @@ keyserver_import_ldap (ctrl_t ctrl,
     }
 
   free(srvlist);
-#endif
 
   /* If all else fails, do the PGP Universal trick of
      ldap://keys.(domain) */