g10: Fix segfault on unsupported curve.
[gnupg.git] / g10 / keyserver.c
index e560d4b..e9ccb58 100644 (file)
@@ -1,6 +1,7 @@
 /* keyserver.c - generic keyserver code
  * Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
- *               2009, 2011 Free Software Foundation, Inc.
+ *               2009, 2011, 2012 Free Software Foundation, Inc.
+ * Copyright (C) 2014 Werner Koch
  *
  * This file is part of GnuPG.
  *
@@ -18,9 +19,6 @@
  * along with this program; if not, see <http://www.gnu.org/licenses/>.
  */
 
-/* !!! FIXME: Replace all printf by es_printf.  FIXME !!! */
-
-
 #include <config.h>
 #include <ctype.h>
 #include <stdio.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 "call-dirmngr.h"
 
@@ -93,13 +86,14 @@ static struct parse_options keyserver_opts[]=
   {
     /* some of these options are not real - just for the help
        message */
-    {"max-cert-size",0,NULL,NULL},
+    {"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")},
-    {"use-temp-files",0,NULL,
-     N_("use temporary files to pass data to keyserver helpers")},
-    {"keep-temp-files",KEYSERVER_KEEP_TEMP_FILES,NULL,
-     N_("do not delete temporary files after using them")},
+    {"timeout", KEYSERVER_TIMEOUT, NULL,
+     N_("override timeout options set for dirmngr")},
     {"refresh-add-fake-v3-keyids",KEYSERVER_ADD_FAKE_V3,NULL,
      NULL},
     {"auto-key-retrieve",KEYSERVER_AUTO_KEY_RETRIEVE,NULL,
@@ -111,41 +105,41 @@ static struct parse_options keyserver_opts[]=
     {NULL,0,NULL,NULL}
   };
 
-static int keyserver_work (ctrl_t ctrl, enum ks_action action,strlist_t list,
-                           KEYDB_SEARCH_DESC *desc,int count,
-                           unsigned char **fpr,size_t *fpr_len,
-                           struct keyserver_spec *keyserver);
 static gpg_error_t keyserver_get (ctrl_t ctrl,
                                   KEYDB_SEARCH_DESC *desc, int ndesc,
-                                  struct keyserver_spec *keyserver);
+                                  struct keyserver_spec *override_keyserver,
+                                  unsigned char **r_fpr, size_t *r_fprlen);
+static gpg_error_t keyserver_put (ctrl_t ctrl, strlist_t keyspecs);
 
 
-/* Reasonable guess */
-#define DEFAULT_MAX_CERT_SIZE 16384
+/* Reasonable guess.  The commonly used test key simon.josefsson.org
+   is larger than 32k, thus we need at least this value. */
+#define DEFAULT_MAX_CERT_SIZE 65536
 
 static size_t max_cert_size=DEFAULT_MAX_CERT_SIZE;
 
+
 static void
-add_canonical_option(char *option,strlist_t *list)
+warn_kshelper_option(char *option, int noisy)
 {
-  char *arg=argsplit(option);
-
-  if(arg)
-    {
-      char *joined;
-
-      joined=xmalloc(strlen(option)+1+strlen(arg)+1);
-      /* Make a canonical name=value form with no spaces */
-      strcpy(joined,option);
-      strcat(joined,"=");
-      strcat(joined,arg);
-      append_to_strlist(list,joined);
-      xfree(joined);
-    }
-  else
-    append_to_strlist(list,option);
+  char *p;
+
+  if ((p=strchr (option, '=')))
+    *p = 0;
+
+  if (!strcmp (option, "ca-cert-file"))
+    log_info ("keyserver option '%s' is obsolete; please use "
+              "'%s' in dirmngr.conf\n",
+              "ca-cert-file", "hkp-cacert");
+  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)
 {
@@ -154,47 +148,24 @@ 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)))
     {
       if(tok[0]=='\0')
        continue;
 
-      /* For backwards compatibility.  1.2.x used honor-http-proxy and
-        there are a good number of documents published that recommend
-        it. */
-      if(ascii_strcasecmp(tok,"honor-http-proxy")==0)
-       tok="http-proxy";
-      else if(ascii_strcasecmp(tok,"no-honor-http-proxy")==0)
-       tok="no-http-proxy";
-
       /* We accept quite a few possible options here - some options to
         handle specially, the keyserver_options list, and import and
-        export options that pertain to keyserver operations.  Note
-        that you must use strncasecmp here as there might be an
-        =argument attached which will foil the use of strcasecmp. */
-
-#ifdef EXEC_TEMPFILE_ONLY
-      if(ascii_strncasecmp(tok,"use-temp-files",14)==0 ||
-             ascii_strncasecmp(tok,"no-use-temp-files",17)==0)
-       log_info(_("WARNING: keyserver option `%s' is not used"
-                  " on this platform\n"),tok);
-#else
-      if(ascii_strncasecmp(tok,"use-temp-files",14)==0)
-       opt.keyserver_options.options|=KEYSERVER_USE_TEMP_FILES;
-      else if(ascii_strncasecmp(tok,"no-use-temp-files",17)==0)
-       opt.keyserver_options.options&=~KEYSERVER_USE_TEMP_FILES;
-#endif
-      else if(!parse_options(tok,&opt.keyserver_options.options,
-                            keyserver_opts,0)
-        && !parse_import_options(tok,
-                                 &opt.keyserver_options.import_options,0)
-        && !parse_export_options(tok,
-                                 &opt.keyserver_options.export_options,0))
+        export options that pertain to keyserver operations.  */
+
+      if (!parse_options (tok,&opt.keyserver_options.options, keyserver_opts,0)
+          && !parse_import_options(tok,&opt.keyserver_options.import_options,0)
+          && !parse_export_options(tok,&opt.keyserver_options.export_options,0))
        {
-         /* All of the standard options have failed, so the option is
-            destined for a keyserver plugin. */
-         add_canonical_option(tok,&opt.keyserver_options.other);
+         /* 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, 1);
        }
     }
 
@@ -209,6 +180,7 @@ parse_keyserver_options(char *options)
   return ret;
 }
 
+
 void
 free_keyserver_spec(struct keyserver_spec *keyserver)
 {
@@ -263,8 +235,7 @@ keyserver_match(struct keyserver_spec *spec)
    keyserver/ksutil.c for limited use in gpgkeys_ldap or the like. */
 
 keyserver_spec_t
-parse_keyserver_uri (const char *string,int require_scheme,
-                    const char *configname,unsigned int configlineno)
+parse_keyserver_uri (const char *string,int require_scheme)
 {
   int assume_hkp=0;
   struct keyserver_spec *keyserver;
@@ -287,7 +258,7 @@ parse_keyserver_uri (const char *string,int require_scheme,
       options++;
 
       while((tok=optsep(&options)))
-       add_canonical_option(tok,&keyserver->options);
+       warn_kshelper_option (tok, 0);
     }
 
   /* Get the scheme */
@@ -346,11 +317,8 @@ parse_keyserver_uri (const char *string,int require_scheme,
 
   if(ascii_strcasecmp(keyserver->scheme,"x-broken-hkp")==0)
     {
-      deprecated_warning(configname,configlineno,"x-broken-hkp",
-                        "--keyserver-options ","broken-http-proxy");
-      xfree(keyserver->scheme);
-      keyserver->scheme=xstrdup("hkp");
-      append_to_strlist(&opt.keyserver_options.other,"broken-http-proxy");
+      log_info ("keyserver option '%s' is obsolete\n",
+                "x-broken-hkp");
     }
   else if(ascii_strcasecmp(keyserver->scheme,"x-hkp")==0)
     {
@@ -489,7 +457,7 @@ parse_preferred_keyserver(PKT_signature *sig)
 
       memcpy(dupe,p,plen);
       dupe[plen]='\0';
-      spec=parse_keyserver_uri(dupe,1,NULL,0);
+      spec = parse_keyserver_uri (dupe, 1);
       xfree(dupe);
     }
 
@@ -503,19 +471,21 @@ print_keyrec(int number,struct keyrec *keyrec)
 
   iobuf_writebyte(keyrec->uidbuf,0);
   iobuf_flush_temp(keyrec->uidbuf);
-  printf("(%d)\t%s  ",number,iobuf_get_temp_buffer(keyrec->uidbuf));
+  es_printf ("(%d)\t%s  ", number, iobuf_get_temp_buffer (keyrec->uidbuf));
 
-  if(keyrec->size>0)
-    printf("%d bit ",keyrec->size);
+  if (keyrec->size>0)
+    es_printf ("%d bit ", keyrec->size);
 
   if(keyrec->type)
     {
-      const char *str = gcry_pk_algo_name (keyrec->type);
+      const char *str;
+
+      str = openpgp_pk_algo_name (keyrec->type);
 
-      if(str)
-       printf("%s ",str);
+      if (str && strcmp (str, "?"))
+       es_printf ("%s ",str);
       else
-       printf("unknown ");
+       es_printf ("unknown ");
     }
 
   switch(keyrec->desc.mode)
@@ -524,28 +494,34 @@ print_keyrec(int number,struct keyrec *keyrec)
         choice but to use it.  Do check --keyid-format to add a 0x if
         needed. */
     case KEYDB_SEARCH_MODE_SHORT_KID:
-      printf("key %s%08lX",
-            (opt.keyid_format==KF_0xSHORT
-             || opt.keyid_format==KF_0xLONG)?"0x":"",
-            (ulong)keyrec->desc.u.kid[1]);
+      es_printf ("key %s%08lX",
+                 (opt.keyid_format==KF_0xSHORT
+                  || opt.keyid_format==KF_0xLONG)?"0x":"",
+                 (ulong)keyrec->desc.u.kid[1]);
       break;
 
       /* However, if it gave us a long keyid, we can honor
-        --keyid-format */
+        --keyid-format via keystr(). */
     case KEYDB_SEARCH_MODE_LONG_KID:
-      printf("key %s",keystr(keyrec->desc.u.kid));
+      es_printf ("key %s",keystr(keyrec->desc.u.kid));
       break;
 
+      /* If it gave us a PGP 2.x fingerprint, not much we can do
+        beyond displaying it. */
     case KEYDB_SEARCH_MODE_FPR16:
-      printf("key ");
+      es_printf ("key ");
       for(i=0;i<16;i++)
-       printf("%02X",keyrec->desc.u.fpr[i]);
+       es_printf ("%02X",keyrec->desc.u.fpr[i]);
       break;
 
+      /* If we get a modern fingerprint, we have the most
+        flexibility. */
     case KEYDB_SEARCH_MODE_FPR20:
-      printf("key ");
-      for(i=0;i<20;i++)
-       printf("%02X",keyrec->desc.u.fpr[i]);
+      {
+       u32 kid[2];
+       keyid_from_fingerprint(keyrec->desc.u.fpr,20,kid);
+       es_printf("key %s",keystr(kid));
+      }
       break;
 
     default:
@@ -555,24 +531,24 @@ print_keyrec(int number,struct keyrec *keyrec)
 
   if(keyrec->createtime>0)
     {
-      printf(", ");
-      printf(_("created: %s"),strtimestamp(keyrec->createtime));
+      es_printf (", ");
+      es_printf (_("created: %s"), strtimestamp(keyrec->createtime));
     }
 
   if(keyrec->expiretime>0)
     {
-      printf(", ");
-      printf(_("expires: %s"),strtimestamp(keyrec->expiretime));
+      es_printf (", ");
+      es_printf (_("expires: %s"), strtimestamp(keyrec->expiretime));
     }
 
-  if(keyrec->flags&1)
-    printf(" (%s)",_("revoked"));
+  if (keyrec->flags&1)
+    es_printf (" (%s)", _("revoked"));
   if(keyrec->flags&2)
-    printf(" (%s)",_("disabled"));
+    es_printf (" (%s)", _("disabled"));
   if(keyrec->flags&4)
-    printf(" (%s)",_("expired"));
+    es_printf (" (%s)", _("expired"));
 
-  printf("\n");
+  es_printf ("\n");
 }
 
 /* Returns a keyrec (which must be freed) once a key is complete, and
@@ -631,7 +607,7 @@ parse_keyrec(char *keystring)
       if((tok=strsep(&keystring,":"))==NULL)
        return ret;
 
-      err = classify_user_id (tok, &work->desc);
+      err = classify_user_id (tok, &work->desc, 1);
       if (err || (work->desc.mode    != KEYDB_SEARCH_MODE_SHORT_KID
                   && work->desc.mode != KEYDB_SEARCH_MODE_LONG_KID
                   && work->desc.mode != KEYDB_SEARCH_MODE_FPR16
@@ -758,7 +734,7 @@ show_prompt (ctrl_t ctrl, KEYDB_SEARCH_DESC *desc, int numdesc,
   gpg_error_t err;
   char *answer = NULL;
 
-  fflush (stdout);
+  es_fflush (es_stdout);
 
   if (count && opt.command_fd == -1)
     {
@@ -815,7 +791,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);
       }
     }
@@ -827,17 +803,29 @@ show_prompt (ctrl_t ctrl, KEYDB_SEARCH_DESC *desc, int numdesc,
 
 
 /* This is a callback used by call-dirmngr.c to process the result of
-   KS_SEARCH command.  LINE is the actual data line received with all
-   escaping removed and guaranteed to be exactly one line with
-   stripped LF; an EOF is indicated by LINE passed as NULL.  LINE may
-   be modified after return.  */
+   KS_SEARCH command.  If SPECIAL is 0, LINE is the actual data line
+   received with all escaping removed and guaranteed to be exactly one
+   line with stripped LF; an EOF is indicated by LINE passed as NULL.
+   If special is 1, the line contains the source of the information
+   (usually an URL).  LINE may be modified after return.  */
 static gpg_error_t
-search_line_handler (void *opaque, char *line)
+search_line_handler (void *opaque, int special, char *line)
 {
   struct search_line_handler_parm_s *parm = opaque;
   gpg_error_t err = 0;
   struct keyrec *keyrec;
 
+  if (special == 1)
+    {
+      log_info ("data source: %s\n", line);
+      return 0;
+    }
+  else if (special)
+    {
+      log_debug ("unknown value %d for special search callback", special);
+      return 0;
+    }
+
   if (parm->eof_seen && line)
     {
       log_debug ("ooops: unexpected data after EOF\n");
@@ -847,7 +835,7 @@ search_line_handler (void *opaque, char *line)
   /* Print the received line.  */
   if (opt.with_colons && line)
     {
-      log_debug ("%s\n",line);
+      es_printf ("%s\n", line);
     }
 
   /* Look for an info: line.  The only current info: values defined
@@ -989,664 +977,6 @@ search_line_handler (void *opaque, char *line)
 }
 
 
-/* We sometimes want to use a different gpgkeys_xxx for a given
-   protocol (for example, ldaps is handled by gpgkeys_ldap).  Map
-   these here. */
-static const char *
-keyserver_typemap(const char *type)
-{
-  if(strcmp(type,"ldaps")==0)
-    return "ldap";
-  else if(strcmp(type,"hkps")==0)
-    return "hkp";
-  else
-    return type;
-}
-
-/* The PGP LDAP and the curl fetch-a-LDAP-object methodologies are
-   sufficiently different that we can't use curl to do LDAP. */
-static int
-direct_uri_map(const char *scheme,unsigned int is_direct)
-{
-  if(is_direct && strcmp(scheme,"ldap")==0)
-    return 1;
-
-  return 0;
-}
-
-#if GNUPG_MAJOR_VERSION == 2
-#define GPGKEYS_PREFIX "gpg2keys_"
-#else
-#define GPGKEYS_PREFIX "gpgkeys_"
-#endif
-#define GPGKEYS_CURL GPGKEYS_PREFIX "curl" EXEEXT
-#define GPGKEYS_PREFIX_LEN (strlen(GPGKEYS_CURL))
-#define KEYSERVER_ARGS_KEEP " -o \"%O\" \"%I\""
-#define KEYSERVER_ARGS_NOKEEP " -o \"%o\" \"%i\""
-
-static int
-keyserver_spawn (ctrl_t ctrl,
-                 enum ks_action action,strlist_t list,KEYDB_SEARCH_DESC *desc,
-                 int count,int *prog,unsigned char **fpr,size_t *fpr_len,
-                 struct keyserver_spec *keyserver)
-{
-  int ret=0,i,gotversion=0,outofband=0;
-  strlist_t temp;
-  unsigned int maxlen,buflen;
-  char *command,*end,*searchstr=NULL;
-  byte *line=NULL;
-  struct exec_info *spawn;
-  const char *scheme;
-  const char *libexecdir = gnupg_libexecdir ();
-
-  assert(keyserver);
-
-#ifdef EXEC_TEMPFILE_ONLY
-  opt.keyserver_options.options|=KEYSERVER_USE_TEMP_FILES;
-#endif
-
-  /* Build the filename for the helper to execute */
-  scheme=keyserver_typemap(keyserver->scheme);
-
-#ifdef DISABLE_KEYSERVER_PATH
-  /* Destroy any path we might have.  This is a little tricky,
-     portability-wise.  It's not correct to delete the PATH
-     environment variable, as that may fall back to a system built-in
-     PATH.  Similarly, it is not correct to set PATH to the null
-     string (PATH="") since this actually deletes the PATH environment
-     variable under MinGW.  The safest thing to do here is to force
-     PATH to be GNUPG_LIBEXECDIR.  All this is not that meaningful on
-     Unix-like systems (since we're going to give a full path to
-     gpgkeys_foo), but on W32 it prevents loading any DLLs from
-     directories in %PATH%.
-
-     After some more thinking about this we came to the conclusion
-     that it is better to load the helpers from the directory where
-     the program of this process lives.  Fortunately Windows provides
-     a way to retrieve this and our gnupg_libexecdir function has been
-     modified to return just this.  Setting the exec-path is not
-     anymore required.
-       set_exec_path(libexecdir);
- */
-#else
-  if(opt.exec_path_set)
-    {
-      /* If exec-path was set, and DISABLE_KEYSERVER_PATH is
-        undefined, then don't specify a full path to gpgkeys_foo, so
-        that the PATH can work. */
-      command=xmalloc(GPGKEYS_PREFIX_LEN+strlen(scheme)+3+strlen(EXEEXT)+1);
-      command[0]='\0';
-    }
-  else
-#endif
-    {
-      /* Specify a full path to gpgkeys_foo. */
-      command=xmalloc(strlen(libexecdir)+strlen(DIRSEP_S)+
-                     GPGKEYS_PREFIX_LEN+strlen(scheme)+3+strlen(EXEEXT)+1);
-      strcpy(command,libexecdir);
-      strcat(command,DIRSEP_S);
-    }
-
-  end=command+strlen(command);
-
-  /* Build a path for the keyserver helper.  If it is direct_uri
-     (i.e. an object fetch and not a keyserver), then add "_uri" to
-     the end to distinguish the keyserver helper from an object
-     fetcher that can speak that protocol (this is a problem for
-     LDAP). */
-
-  strcat(command,GPGKEYS_PREFIX);
-  strcat(command,scheme);
-
-  /* This "_uri" thing is in case we need to call a direct handler
-     instead of the keyserver handler.  This lets us use gpgkeys_curl
-     or gpgkeys_ldap_uri (we don't provide it, but a user might)
-     instead of gpgkeys_ldap to fetch things like
-     ldap://keyserver.pgp.com/o=PGP%20keys?pgpkey?sub?pgpkeyid=99242560 */
-
-  if(direct_uri_map(scheme,keyserver->flags.direct_uri))
-    strcat(command,"_uri");
-
-  strcat(command,EXEEXT);
-
-  /* Can we execute it?  If not, try curl as our catchall. */
-  if(path_access(command,X_OK)!=0)
-    strcpy(end,GPGKEYS_CURL);
-
-  if(opt.keyserver_options.options&KEYSERVER_USE_TEMP_FILES)
-    {
-      if(opt.keyserver_options.options&KEYSERVER_KEEP_TEMP_FILES)
-       {
-         command=xrealloc(command,strlen(command)+
-                           strlen(KEYSERVER_ARGS_KEEP)+1);
-         strcat(command,KEYSERVER_ARGS_KEEP);
-       }
-      else
-       {
-         command=xrealloc(command,strlen(command)+
-                           strlen(KEYSERVER_ARGS_NOKEEP)+1);
-         strcat(command,KEYSERVER_ARGS_NOKEEP);
-       }
-
-      ret=exec_write(&spawn,NULL,command,NULL,0,0);
-    }
-  else
-    ret=exec_write(&spawn,command,NULL,NULL,0,0);
-
-  xfree(command);
-
-  if(ret)
-    return ret;
-
-  fprintf(spawn->tochild,
-         "# This is a GnuPG %s keyserver communications file\n",VERSION);
-  fprintf(spawn->tochild,"VERSION %d\n",KEYSERVER_PROTO_VERSION);
-  fprintf(spawn->tochild,"PROGRAM %s\n",VERSION);
-  fprintf(spawn->tochild,"SCHEME %s\n",keyserver->scheme);
-
-  if(keyserver->opaque)
-    fprintf(spawn->tochild,"OPAQUE %s\n",keyserver->opaque);
-  else
-    {
-      if(keyserver->auth)
-       fprintf(spawn->tochild,"AUTH %s\n",keyserver->auth);
-
-      if(keyserver->host)
-       fprintf(spawn->tochild,"HOST %s\n",keyserver->host);
-
-      if(keyserver->port)
-       fprintf(spawn->tochild,"PORT %s\n",keyserver->port);
-
-      if(keyserver->path)
-       fprintf(spawn->tochild,"PATH %s\n",keyserver->path);
-    }
-
-  /* Write global options */
-
-  for(temp=opt.keyserver_options.other;temp;temp=temp->next)
-    fprintf(spawn->tochild,"OPTION %s\n",temp->d);
-
-  /* Write per-keyserver options */
-
-  for(temp=keyserver->options;temp;temp=temp->next)
-    fprintf(spawn->tochild,"OPTION %s\n",temp->d);
-
-  switch(action)
-    {
-    case KS_GET:
-      {
-       fprintf(spawn->tochild,"COMMAND GET\n\n");
-
-       /* Which keys do we want? */
-
-       for(i=0;i<count;i++)
-         {
-           int quiet=0;
-
-           if(desc[i].mode==KEYDB_SEARCH_MODE_FPR20)
-             {
-               int f;
-
-               fprintf(spawn->tochild,"0x");
-
-               for(f=0;f<MAX_FINGERPRINT_LEN;f++)
-                 fprintf(spawn->tochild,"%02X",desc[i].u.fpr[f]);
-
-               fprintf(spawn->tochild,"\n");
-             }
-           else if(desc[i].mode==KEYDB_SEARCH_MODE_FPR16)
-             {
-               int f;
-
-               fprintf(spawn->tochild,"0x");
-
-               for(f=0;f<16;f++)
-                 fprintf(spawn->tochild,"%02X",desc[i].u.fpr[f]);
-
-               fprintf(spawn->tochild,"\n");
-             }
-           else if(desc[i].mode==KEYDB_SEARCH_MODE_LONG_KID)
-             fprintf(spawn->tochild,"0x%08lX%08lX\n",
-                     (ulong)desc[i].u.kid[0],
-                     (ulong)desc[i].u.kid[1]);
-           else if(desc[i].mode==KEYDB_SEARCH_MODE_SHORT_KID)
-             fprintf(spawn->tochild,"0x%08lX\n",
-                     (ulong)desc[i].u.kid[1]);
-           else if(desc[i].mode==KEYDB_SEARCH_MODE_EXACT)
-             {
-               fprintf(spawn->tochild,"0x0000000000000000\n");
-               quiet=1;
-             }
-           else if(desc[i].mode==KEYDB_SEARCH_MODE_NONE)
-             continue;
-           else
-             BUG();
-
-           if(!quiet)
-             {
-               if(keyserver->host)
-                 log_info(_("requesting key %s from %s server %s\n"),
-                          keystr_from_desc(&desc[i]),
-                          keyserver->scheme,keyserver->host);
-               else
-                 log_info(_("requesting key %s from %s\n"),
-                          keystr_from_desc(&desc[i]),keyserver->uri);
-             }
-         }
-
-       fprintf(spawn->tochild,"\n");
-
-       break;
-      }
-
-    case KS_GETNAME:
-      {
-       strlist_t key;
-
-       fprintf(spawn->tochild,"COMMAND GETNAME\n\n");
-
-       /* Which names do we want? */
-
-       for(key=list;key!=NULL;key=key->next)
-         fprintf(spawn->tochild,"%s\n",key->d);
-
-       fprintf(spawn->tochild,"\n");
-
-       if(keyserver->host)
-         log_info(_("searching for names from %s server %s\n"),
-                  keyserver->scheme,keyserver->host);
-       else
-         log_info(_("searching for names from %s\n"),keyserver->uri);
-
-       break;
-      }
-
-    case KS_SEND:
-      {
-       strlist_t key;
-
-       /* Note the extra \n here to send an empty keylist block */
-       fprintf(spawn->tochild,"COMMAND SEND\n\n\n");
-
-       for(key=list;key!=NULL;key=key->next)
-         {
-           armor_filter_context_t *afx;
-           IOBUF buffer = iobuf_temp ();
-           KBNODE block;
-
-           temp=NULL;
-           add_to_strlist(&temp,key->d);
-
-           afx = new_armor_context ();
-           afx->what = 1;
-           /* Tell the armor filter to use Unix-style \n line
-              endings, since we're going to fprintf this to a file
-              that (on Win32) is open in text mode.  The win32 stdio
-              will transform the \n to \r\n and we'll end up with the
-              proper line endings on win32.  This is a no-op on
-              Unix. */
-           afx->eol[0] = '\n';
-           push_armor_filter (afx, buffer);
-            release_armor_context (afx);
-
-           /* TODO: Remove Comment: lines from keys exported this
-              way? */
-
-           if(export_pubkeys_stream (ctrl, buffer,temp,&block,
-                                      opt.keyserver_options.export_options)==-1)
-             iobuf_close(buffer);
-           else
-             {
-               KBNODE node;
-
-               iobuf_flush_temp(buffer);
-
-               merge_keys_and_selfsig(block);
-
-               fprintf(spawn->tochild,"INFO %08lX%08lX BEGIN\n",
-                       (ulong)block->pkt->pkt.public_key->keyid[0],
-                       (ulong)block->pkt->pkt.public_key->keyid[1]);
-
-               for(node=block;node;node=node->next)
-                 {
-                   switch(node->pkt->pkttype)
-                     {
-                     default:
-                       continue;
-
-                     case PKT_PUBLIC_KEY:
-                     case PKT_PUBLIC_SUBKEY:
-                       {
-                         PKT_public_key *pk=node->pkt->pkt.public_key;
-
-                         keyid_from_pk(pk,NULL);
-
-                         fprintf(spawn->tochild,"%sb:%08lX%08lX:%u:%u:%u:%u:",
-                                 node->pkt->pkttype==PKT_PUBLIC_KEY?"pu":"su",
-                                 (ulong)pk->keyid[0],(ulong)pk->keyid[1],
-                                 pk->pubkey_algo,
-                                 nbits_from_pk(pk),
-                                 pk->timestamp,
-                                 pk->expiredate);
-
-                         if(pk->flags.revoked)
-                           fprintf(spawn->tochild,"r");
-                         if(pk->has_expired)
-                           fprintf(spawn->tochild,"e");
-
-                         fprintf(spawn->tochild,"\n");
-                       }
-                       break;
-
-                     case PKT_USER_ID:
-                       {
-                         PKT_user_id *uid=node->pkt->pkt.user_id;
-                         int r;
-
-                         if(uid->attrib_data)
-                           continue;
-
-                         fprintf(spawn->tochild,"uid:");
-
-                         /* Quote ':', '%', and any 8-bit
-                            characters */
-                         for(r=0;r<uid->len;r++)
-                           {
-                             if(uid->name[r]==':' || uid->name[r]=='%'
-                                || uid->name[r]&0x80)
-                               fprintf(spawn->tochild,"%%%02X",
-                                       (byte)uid->name[r]);
-                             else
-                               fprintf(spawn->tochild,"%c",uid->name[r]);
-                           }
-
-                         fprintf(spawn->tochild,":%u:%u:",
-                                 uid->created,uid->expiredate);
-
-                         if(uid->is_revoked)
-                           fprintf(spawn->tochild,"r");
-                         if(uid->is_expired)
-                           fprintf(spawn->tochild,"e");
-
-                         fprintf(spawn->tochild,"\n");
-                       }
-                       break;
-
-                       /* This bit is really for the benefit of
-                          people who store their keys in LDAP
-                          servers.  It makes it easy to do queries
-                          for things like "all keys signed by
-                          Isabella". */
-                     case PKT_SIGNATURE:
-                       {
-                         PKT_signature *sig=node->pkt->pkt.signature;
-
-                         if(!IS_UID_SIG(sig))
-                           continue;
-
-                         fprintf(spawn->tochild,"sig:%08lX%08lX:%X:%u:%u\n",
-                                 (ulong)sig->keyid[0],(ulong)sig->keyid[1],
-                                 sig->sig_class,sig->timestamp,
-                                 sig->expiredate);
-                       }
-                       break;
-                     }
-                 }
-
-               fprintf(spawn->tochild,"INFO %08lX%08lX END\n",
-                       (ulong)block->pkt->pkt.public_key->keyid[0],
-                       (ulong)block->pkt->pkt.public_key->keyid[1]);
-
-               fprintf(spawn->tochild,"KEY %08lX%08lX BEGIN\n",
-                       (ulong)block->pkt->pkt.public_key->keyid[0],
-                       (ulong)block->pkt->pkt.public_key->keyid[1]);
-               fwrite(iobuf_get_temp_buffer(buffer),
-                      iobuf_get_temp_length(buffer),1,spawn->tochild);
-               fprintf(spawn->tochild,"KEY %08lX%08lX END\n",
-                       (ulong)block->pkt->pkt.public_key->keyid[0],
-                       (ulong)block->pkt->pkt.public_key->keyid[1]);
-
-               iobuf_close(buffer);
-
-               if(keyserver->host)
-                 log_info(_("sending key %s to %s server %s\n"),
-                          keystr(block->pkt->pkt.public_key->keyid),
-                          keyserver->scheme,keyserver->host);
-               else
-                 log_info(_("sending key %s to %s\n"),
-                          keystr(block->pkt->pkt.public_key->keyid),
-                          keyserver->uri);
-
-               release_kbnode(block);
-             }
-
-           free_strlist(temp);
-         }
-
-       break;
-      }
-
-    case KS_SEARCH:
-      {
-       strlist_t key;
-
-       fprintf(spawn->tochild,"COMMAND SEARCH\n\n");
-
-       /* Which keys do we want?  Remember that the gpgkeys_ program
-           is going to lump these together into a search string. */
-
-       for(key=list;key!=NULL;key=key->next)
-         {
-           fprintf(spawn->tochild,"%s\n",key->d);
-           if(key!=list)
-             {
-               searchstr=xrealloc(searchstr,
-                                   strlen(searchstr)+strlen(key->d)+2);
-               strcat(searchstr," ");
-             }
-           else
-             {
-               searchstr=xmalloc(strlen(key->d)+1);
-               searchstr[0]='\0';
-             }
-
-           strcat(searchstr,key->d);
-         }
-
-       fprintf(spawn->tochild,"\n");
-
-       if(keyserver->host)
-         log_info(_("searching for \"%s\" from %s server %s\n"),
-                  searchstr,keyserver->scheme,keyserver->host);
-       else
-         log_info(_("searching for \"%s\" from %s\n"),
-                  searchstr,keyserver->uri);
-
-       break;
-      }
-
-    default:
-      log_fatal(_("no keyserver action!\n"));
-      break;
-    }
-
-  /* Done sending, so start reading. */
-  ret=exec_read(spawn);
-  if(ret)
-    goto fail;
-
-  /* Now handle the response */
-
-  for(;;)
-    {
-      int plen;
-      char *ptr;
-
-      maxlen=1024;
-      if(iobuf_read_line(spawn->fromchild,&line,&buflen,&maxlen)==0)
-       {
-         ret = gpg_error_from_syserror ();
-         goto fail; /* i.e. EOF */
-       }
-
-      ptr=line;
-
-      /* remove trailing whitespace */
-      plen=strlen(ptr);
-      while(plen>0 && ascii_isspace(ptr[plen-1]))
-       plen--;
-      plen[ptr]='\0';
-
-      if(*ptr=='\0')
-       break;
-
-      if(ascii_strncasecmp(ptr,"VERSION ",8)==0)
-       {
-         gotversion=1;
-
-         if(atoi(&ptr[8])!=KEYSERVER_PROTO_VERSION)
-           {
-             log_error(_("invalid keyserver protocol (us %d!=handler %d)\n"),
-                       KEYSERVER_PROTO_VERSION,atoi(&ptr[8]));
-             goto fail;
-           }
-       }
-      else if(ascii_strncasecmp(ptr,"PROGRAM ",8)==0)
-       {
-         if(ascii_strncasecmp(&ptr[8],VERSION,strlen(VERSION))!=0)
-           log_info(_("WARNING: keyserver handler from a different"
-                      " version of GnuPG (%s)\n"),&ptr[8]);
-       }
-      else if(ascii_strncasecmp(ptr,"OPTION OUTOFBAND",16)==0)
-       outofband=1; /* Currently the only OPTION */
-    }
-
-  if(!gotversion)
-    {
-      log_error(_("keyserver did not send VERSION\n"));
-      goto fail;
-    }
-
-  if(!outofband)
-    switch(action)
-      {
-      case KS_GET:
-      case KS_GETNAME:
-       {
-         void *stats_handle;
-
-         stats_handle=import_new_stats_handle();
-
-         /* Slurp up all the key data.  In the future, it might be
-            nice to look for KEY foo OUTOFBAND and FAILED indicators.
-            It's harmless to ignore them, but ignoring them does make
-            gpg complain about "no valid OpenPGP data found".  One
-            way to do this could be to continue parsing this
-            line-by-line and make a temp iobuf for each key. */
-
-          /* FIXME: Pass CTRL.  */
-         import_keys_stream (NULL, spawn->fromchild,stats_handle,fpr,fpr_len,
-                             opt.keyserver_options.import_options);
-
-         import_print_stats(stats_handle);
-         import_release_stats_handle(stats_handle);
-
-         break;
-       }
-
-       /* Nothing to do here */
-      case KS_SEND:
-       break;
-
-      case KS_SEARCH:
-       //keyserver_search_prompt (ctrl, spawn->fromchild,searchstr);
-       break;
-
-      default:
-       log_fatal(_("no keyserver action!\n"));
-       break;
-      }
-
- fail:
-  xfree(line);
-  xfree(searchstr);
-
-
-  *prog=exec_finish(spawn);
-
-  return ret;
-}
-
-
-
-
-static int
-keyserver_work (ctrl_t ctrl,
-                enum ks_action action,strlist_t list,KEYDB_SEARCH_DESC *desc,
-                int count,unsigned char **fpr,size_t *fpr_len,
-                struct keyserver_spec *keyserver)
-{
-  int rc=0,ret=0;
-
-  if (!keyserver)
-    {
-      log_error (_("no keyserver known (use option --keyserver)\n"));
-      return gpg_error (GPG_ERR_BAD_URI);
-    }
-
-
-  rc = keyserver_spawn (ctrl, action, list, desc, count,
-                        &ret, fpr, fpr_len, keyserver);
-  if (ret)
-    {
-      switch(ret)
-       {
-       case KEYSERVER_SCHEME_NOT_FOUND:
-         log_error(_("no handler for keyserver scheme `%s'\n"),
-                   keyserver->scheme);
-         break;
-
-       case KEYSERVER_NOT_SUPPORTED:
-         log_error(_("action `%s' not supported with keyserver "
-                     "scheme `%s'\n"),
-                   action==KS_GET?"get":action==KS_SEND?"send":
-                   action==KS_SEARCH?"search":"unknown",
-                   keyserver->scheme);
-         break;
-
-       case KEYSERVER_VERSION_ERROR:
-         log_error(_(GPGKEYS_PREFIX "%s does not support"
-                     " handler version %d\n"),
-                   keyserver_typemap(keyserver->scheme),
-                   KEYSERVER_PROTO_VERSION);
-         break;
-
-       case KEYSERVER_TIMEOUT:
-         log_error(_("keyserver timed out\n"));
-         break;
-
-       case KEYSERVER_INTERNAL_ERROR:
-       default:
-         log_error(_("keyserver internal error\n"));
-         break;
-       }
-
-      return G10ERR_KEYSERVER;
-    }
-
-  if (rc)
-    {
-      log_error (_("keyserver communications error: %s\n"),g10_errstr(rc));
-
-      return rc;
-    }
-
-  return 0;
-}
-
-
-
-
 
 int
 keyserver_export (ctrl_t ctrl, strlist_t users)
@@ -1659,7 +989,7 @@ keyserver_export (ctrl_t ctrl, strlist_t users)
   /* Weed out descriptors that we don't support sending */
   for(;users;users=users->next)
     {
-      err = classify_user_id (users->d, &desc);
+      err = classify_user_id (users->d, &desc, 1);
       if (err || (desc.mode    != KEYDB_SEARCH_MODE_SHORT_KID
                   && desc.mode != KEYDB_SEARCH_MODE_LONG_KID
                   && desc.mode != KEYDB_SEARCH_MODE_FPR16
@@ -1674,13 +1004,93 @@ keyserver_export (ctrl_t ctrl, strlist_t users)
 
   if(sl)
     {
-      rc = keyserver_work (ctrl, KS_SEND,sl,NULL,0,NULL,NULL,opt.keyserver);
+      rc = keyserver_put (ctrl, sl);
       free_strlist(sl);
     }
 
   return rc;
 }
 
+
+/* Structure to convey the arg to keyserver_retrieval_screener.  */
+struct ks_retrieval_screener_arg_s
+{
+  KEYDB_SEARCH_DESC *desc;
+  int ndesc;
+};
+
+
+/* Check whether a key matches the search description.  The function
+   returns 0 if the key shall be imported.  */
+static gpg_error_t
+keyserver_retrieval_screener (kbnode_t keyblock, void *opaque)
+{
+  struct ks_retrieval_screener_arg_s *arg = opaque;
+  KEYDB_SEARCH_DESC *desc = arg->desc;
+  int ndesc = arg->ndesc;
+  kbnode_t node;
+  PKT_public_key *pk;
+  int n;
+  u32 keyid[2];
+  byte fpr[MAX_FINGERPRINT_LEN];
+  size_t fpr_len = 0;
+
+  /* Secret keys are not expected from a keyserver.  We do not
+     care about secret subkeys because the import code takes care
+     of skipping them.  Not allowing an import of a public key
+     with a secret subkey would make it too easy to inhibit the
+     downloading of a public key.  Recall that keyservers do only
+     limited checks.  */
+  node = find_kbnode (keyblock, PKT_SECRET_KEY);
+  if (node)
+    return gpg_error (GPG_ERR_GENERAL);   /* Do not import. */
+
+  if (!ndesc)
+    return 0; /* Okay if no description given.  */
+
+  /* Loop over all key packets.  */
+  for (node = keyblock; node; node = node->next)
+    {
+      if (node->pkt->pkttype != PKT_PUBLIC_KEY
+          && node->pkt->pkttype != PKT_PUBLIC_SUBKEY)
+        continue;
+
+      pk = node->pkt->pkt.public_key;
+      fingerprint_from_pk (pk, fpr, &fpr_len);
+      keyid_from_pk (pk, keyid);
+
+      /* Compare requested and returned fingerprints if available. */
+      for (n = 0; n < ndesc; n++)
+        {
+          if (desc[n].mode == KEYDB_SEARCH_MODE_FPR20)
+            {
+              if (fpr_len == 20 && !memcmp (fpr, desc[n].u.fpr, 20))
+                return 0;
+            }
+          else if (desc[n].mode == KEYDB_SEARCH_MODE_FPR16)
+            {
+              if (fpr_len == 16 && !memcmp (fpr, desc[n].u.fpr, 16))
+                return 0;
+            }
+          else if (desc[n].mode == KEYDB_SEARCH_MODE_LONG_KID)
+            {
+              if (keyid[0] == desc[n].u.kid[0] && keyid[1] == desc[n].u.kid[1])
+                return 0;
+            }
+          else if (desc[n].mode == KEYDB_SEARCH_MODE_SHORT_KID)
+            {
+              if (keyid[1] == desc[n].u.kid[1])
+                return 0;
+            }
+          else /* No keyid or fingerprint - can't check.  */
+            return 0; /* allow import.  */
+        }
+    }
+
+  return gpg_error (GPG_ERR_GENERAL);
+}
+
+
 int
 keyserver_import (ctrl_t ctrl, strlist_t users)
 {
@@ -1694,7 +1104,7 @@ keyserver_import (ctrl_t ctrl, strlist_t users)
 
   for(;users;users=users->next)
     {
-      err = classify_user_id (users->d, &desc[count]);
+      err = classify_user_id (users->d, &desc[count], 1);
       if (err || (desc[count].mode    != KEYDB_SEARCH_MODE_SHORT_KID
                   && desc[count].mode != KEYDB_SEARCH_MODE_LONG_KID
                   && desc[count].mode != KEYDB_SEARCH_MODE_FPR16
@@ -1713,13 +1123,39 @@ 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;
 }
 
+
+/* 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,
+                       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)
@@ -1739,7 +1175,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
@@ -1754,24 +1190,33 @@ 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 */
 static int
 keyidlist(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;
 
   *klist=xmalloc(sizeof(KEYDB_SEARCH_DESC)*num);
 
-  kdbhd=keydb_new ();
+  kdbhd = keydb_new ();
+  if (!kdbhd)
+    {
+      rc = gpg_error_from_syserror ();
+      goto leave;
+    }
+  keydb_disable_caching (kdbhd);  /* We are looping the search.  */
 
   if(!users)
     {
@@ -1788,7 +1233,7 @@ keyidlist(strlist_t users,KEYDB_SEARCH_DESC **klist,int *count,int fakev3)
       for (ndesc=0, sl=users; sl; sl = sl->next)
        {
           gpg_error_t err;
-         if (!(err = classify_user_id (sl->d, desc+ndesc)))
+         if (!(err = classify_user_id (sl->d, desc+ndesc, 1)))
            ndesc++;
          else
            log_error (_("key \"%s\" not found: %s\n"),
@@ -1796,8 +1241,12 @@ keyidlist(strlist_t users,KEYDB_SEARCH_DESC **klist,int *count,int fakev3)
        }
     }
 
-  while (!(rc = keydb_search (kdbhd, desc, ndesc)))
+  for (;;)
     {
+      rc = keydb_search (kdbhd, desc, ndesc, NULL);
+      if (rc)
+        break;  /* ready.  */
+
       if (!users)
        desc[0].mode = KEYDB_SEARCH_MODE_NEXT;
 
@@ -1805,7 +1254,7 @@ keyidlist(strlist_t users,KEYDB_SEARCH_DESC **klist,int *count,int fakev3)
       rc = keydb_get_keyblock (kdbhd, &keyblock );
       if( rc )
        {
-         log_error (_("error reading keyblock: %s\n"), g10_errstr(rc) );
+          log_error (_("error reading keyblock: %s\n"), gpg_strerror (rc) );
          goto leave;
        }
 
@@ -1899,12 +1348,15 @@ keyidlist(strlist_t users,KEYDB_SEARCH_DESC **klist,int *count,int fakev3)
        }
     }
 
-  if(rc==-1)
-    rc=0;
+  if (gpg_err_code (rc) == GPG_ERR_NOT_FOUND)
+    rc = 0;
 
  leave:
   if(rc)
-    xfree(*klist);
+    {
+      xfree(*klist);
+      *klist = NULL;
+    }
   xfree(desc);
   keydb_release(kdbhd);
   release_kbnode(keyblock);
@@ -1915,10 +1367,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;
 
@@ -1933,15 +1387,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 (users, &desc, &numdesc, fakev3);
+  if (err)
+    return err;
 
   count=numdesc;
   if(count>0)
@@ -1955,14 +1414,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);
-             if(rc)
+             err = keyserver_get (ctrl, &desc[i], 1, keyserver, NULL, NULL);
+             if (err)
                log_info(_("WARNING: unable to refresh key %s"
                           " via %s: %s\n"),keystr_from_desc(&desc[i]),
-                        keyserver->uri,g10_errstr(rc));
+                        keyserver->uri,gpg_strerror (err));
              else
                {
                  /* We got it, so mark it as NONE so we don't try and
@@ -1979,16 +1441,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);
+          err = keyserver_get (ctrl, desc, numdesc, NULL, NULL, NULL);
+        }
     }
 
   xfree(desc);
@@ -1998,9 +1465,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))
-    trustdb_check_or_update();
+    check_or_update_trustdb ();
 
-  return rc;
+  return err;
 }
 
 
@@ -2018,21 +1485,15 @@ 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) */
-  /*   fprintf(spawn->tochild,"OPTION %s\n",temp->d); */
+  /*   es_fprintf(spawn->tochild,"OPTION %s\n",temp->d); */
 
   /* Write per-keyserver options */
 
   /* for(temp=keyserver->options;temp;temp=temp->next) */
-  /*   fprintf(spawn->tochild,"OPTION %s\n",temp->d); */
+  /*   es_fprintf(spawn->tochild,"OPTION %s\n",temp->d); */
 
   {
     membuf_t mb;
@@ -2079,13 +1540,13 @@ keyserver_search (ctrl_t ctrl, strlist_t tokens)
   /* switch(ret) */
   /*   { */
   /*   case KEYSERVER_SCHEME_NOT_FOUND: */
-  /*     log_error(_("no handler for keyserver scheme `%s'\n"), */
+  /*     log_error(_("no handler for keyserver scheme '%s'\n"), */
   /*               opt.keyserver->scheme); */
   /*     break; */
 
   /*   case KEYSERVER_NOT_SUPPORTED: */
-  /*     log_error(_("action `%s' not supported with keyserver " */
-  /*                 "scheme `%s'\n"), "search", opt.keyserver->scheme); */
+  /*     log_error(_("action '%s' not supported with keyserver " */
+  /*                 "scheme '%s'\n"), "search", opt.keyserver->scheme); */
   /*     break; */
 
   /*   case KEYSERVER_TIMEOUT: */
@@ -2109,55 +1570,43 @@ keyserver_search (ctrl_t ctrl, strlist_t tokens)
   return err;
 }
 
-
-
-/* Called using:
-
-show_prompt:
-import:
-import_foo:
-refresh:
-    rc=keyserver_work (ctrl, KS_GET, NULL, desc, count,
-                       NULL, NULL, opt.keyserver);
-
-
-fetch:
-         rc = keyserver_work (ctrl, KS_GET, NULL, &desc, 1, NULL, NULL, spec);
-         if(rc)
-           log_info (_("WARNING: unable to fetch URI %s: %s\n"),
-                    sl->d,g10_errstr(rc));
-
-
-export:
-      rc = keyserver_work (ctrl, KS_SEND,sl,NULL,0,NULL,NULL,opt.keyserver);
-
-
-
-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);
-
- */
-
+/* Helper for keyserver_get.  Here we only receive a chunk of the
+   description to be processed in one batch.  This is required due to
+   the limited number of patterns the dirmngr interface (KS_GET) can
+   grok and to limit the amount of temporary required memory.  */
 static gpg_error_t
-keyserver_get (ctrl_t ctrl, KEYDB_SEARCH_DESC *desc, int ndesc,
-               struct keyserver_spec *keyserver)
+keyserver_get_chunk (ctrl_t ctrl, KEYDB_SEARCH_DESC *desc, int ndesc,
+                     int *r_ndesc_used,
+                     import_stats_t stats_handle,
+                     struct keyserver_spec *override_keyserver,
+                     unsigned char **r_fpr, size_t *r_fprlen)
 
 {
   gpg_error_t err = 0;
   char **pattern;
   int idx, npat;
   estream_t datastream;
+  char *source = NULL;
+  size_t linelen;  /* Estimated linelen for KS_GET.  */
+  size_t n;
+
+#define MAX_KS_GET_LINELEN 950  /* Somewhat lower than the real limit.  */
+
+  *r_ndesc_used = 0;
 
   /* Create an array filled with a search pattern for each key.  The
      array is delimited by a NULL entry.  */
   pattern = xtrycalloc (ndesc+1, sizeof *pattern);
   if (!pattern)
     return gpg_error_from_syserror ();
+
+  /* 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
+     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++)
     {
       int quiet = 0;
@@ -2165,7 +1614,12 @@ keyserver_get (ctrl_t ctrl, KEYDB_SEARCH_DESC *desc, int ndesc,
       if (desc[idx].mode == KEYDB_SEARCH_MODE_FPR20
           || desc[idx].mode == KEYDB_SEARCH_MODE_FPR16)
         {
-          pattern[npat] = xtrymalloc (2+2*20+1);
+          n = 1+2+2*20;
+          if (idx && linelen + n > MAX_KS_GET_LINELEN)
+            break; /* Declare end of this chunk.  */
+          linelen += n;
+
+          pattern[npat] = xtrymalloc (n);
           if (!pattern[npat])
             err = gpg_error_from_syserror ();
           else
@@ -2179,6 +1633,11 @@ keyserver_get (ctrl_t ctrl, KEYDB_SEARCH_DESC *desc, int ndesc,
         }
       else if(desc[idx].mode == KEYDB_SEARCH_MODE_LONG_KID)
         {
+          n = 1+2+16;
+          if (idx && linelen + n > MAX_KS_GET_LINELEN)
+            break; /* Declare end of this chunk.  */
+          linelen += n;
+
           pattern[npat] = xtryasprintf ("0x%08lX%08lX",
                                         (ulong)desc[idx].u.kid[0],
                                         (ulong)desc[idx].u.kid[1]);
@@ -2189,6 +1648,11 @@ keyserver_get (ctrl_t ctrl, KEYDB_SEARCH_DESC *desc, int ndesc,
         }
       else if(desc[idx].mode == KEYDB_SEARCH_MODE_SHORT_KID)
         {
+          n = 1+2+8;
+          if (idx && linelen + n > MAX_KS_GET_LINELEN)
+            break; /* Declare end of this chunk.  */
+          linelen += n;
+
           pattern[npat] = xtryasprintf ("0x%08lX", (ulong)desc[idx].u.kid[1]);
           if (!pattern[npat])
             err = gpg_error_from_syserror ();
@@ -2197,10 +1661,18 @@ 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 also uses 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.)  */
+
+          n = 1+1+strlen (desc[idx].u.name);
+          if (idx && linelen + n > MAX_KS_GET_LINELEN)
+            break; /* Declare end of this chunk.  */
+          linelen += n;
+
+          pattern[npat] = strconcat ("=", desc[idx].u.name, NULL);
           if (!pattern[npat])
             err = gpg_error_from_syserror ();
           else
@@ -2222,28 +1694,33 @@ keyserver_get (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);
         }
     }
 
+  /* Remember now many of search items were considered.  Note that
+     this is different from NPAT.  */
+  *r_ndesc_used = idx;
 
-  err = gpg_dirmngr_ks_get (ctrl, pattern, &datastream);
+  err = gpg_dirmngr_ks_get (ctrl, pattern, override_keyserver,
+                            &datastream, &source);
   for (idx=0; idx < npat; idx++)
     xfree (pattern[idx]);
   xfree (pattern);
+  if (opt.verbose && source)
+    log_info ("data source: %s\n", source);
+
   if (!err)
     {
-      void *stats_handle;
-
-      stats_handle = import_new_stats_handle();
+      struct ks_retrieval_screener_arg_s screenerarg;
 
       /* FIXME: Check whether this comment should be moved to dirmngr.
 
@@ -2252,110 +1729,210 @@ keyserver_get (ctrl_t ctrl, KEYDB_SEARCH_DESC *desc, int ndesc,
          harmless to ignore them, but ignoring them does make gpg
          complain about "no valid OpenPGP data found".  One way to do
          this could be to continue parsing this line-by-line and make
-         a temp iobuf for each key. */
+         a temp iobuf for each key.  Note that we don't allow the
+         import of secret keys from a keyserver.  Keyservers should
+         never accept or send them but we better protect against rogue
+         keyservers. */
+
+      screenerarg.desc = desc;
+      screenerarg.ndesc = *r_ndesc_used;
+      import_keys_es_stream (ctrl, datastream, stats_handle,
+                             r_fpr, r_fprlen,
+                             (opt.keyserver_options.import_options
+                              | IMPORT_NO_SECKEY),
+                             keyserver_retrieval_screener, &screenerarg);
+    }
+  es_fclose (datastream);
+  xfree (source);
+
+  return err;
+}
+
+
+/* Retrieve a key from a keyserver.  The search pattern are in
+   (DESC,NDESC).  Allowed search modes are keyid, fingerprint, and
+   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.  */
+static gpg_error_t
+keyserver_get (ctrl_t ctrl, KEYDB_SEARCH_DESC *desc, int ndesc,
+               struct keyserver_spec *override_keyserver,
+               unsigned char **r_fpr, size_t *r_fprlen)
+{
+  gpg_error_t err;
+  import_stats_t stats_handle;
+  int ndesc_used;
+  int any_good = 0;
 
-      import_keys_es_stream (ctrl, datastream, stats_handle, NULL, NULL,
-                             opt.keyserver_options.import_options);
+  stats_handle = import_new_stats_handle();
 
-      import_print_stats (stats_handle);
-      import_release_stats_handle (stats_handle);
+  for (;;)
+    {
+      err = keyserver_get_chunk (ctrl, desc, ndesc, &ndesc_used, stats_handle,
+                                 override_keyserver, r_fpr, r_fprlen);
+      if (!err)
+        any_good = 1;
+      if (err || ndesc_used >= ndesc)
+        break; /* Error or all processed.  */
+      /* Prepare for the next chunk.  */
+      desc += ndesc_used;
+      ndesc -= ndesc_used;
     }
-  es_fclose (datastream);
 
+  if (any_good)
+    import_print_stats (stats_handle);
 
+  import_release_stats_handle (stats_handle);
   return err;
 }
 
 
+/* Send all keys specified by KEYSPECS to the configured keyserver.  */
+static gpg_error_t
+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 (gpg_dirmngr_ks_list (ctrl, &ksurl))
+    {
+      log_error (_("no keyserver known\n"));
+      return gpg_error (GPG_ERR_NO_KEYSERVER);
+    }
+
+  for (kspec = keyspecs; kspec; kspec = kspec->next)
+    {
+      void *data;
+      size_t datalen;
+      kbnode_t keyblock;
+
+      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
+        {
+          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);
+          xfree (data);
+          if (err)
+            {
+              write_status_error ("keyserver_send", err);
+              log_error (_("keyserver send failed: %s\n"), gpg_strerror (err));
+            }
+        }
+    }
 
+  xfree (ksurl);
 
+  return err;
+
+}
+
+
+/* Loop over all URLs in STRLIST and fetch the key at that URL.  Note
+   that the fetch operation ignores the configured key servers and
+   instead directly retrieves the keys.  */
 int
 keyserver_fetch (ctrl_t ctrl, strlist_t urilist)
 {
-  KEYDB_SEARCH_DESC desc;
+  gpg_error_t err;
   strlist_t sl;
-  unsigned int options=opt.keyserver_options.import_options;
+  estream_t datastream;
+  unsigned int save_options = opt.keyserver_options.import_options;
 
   /* Switch on fast-import, since fetch can handle more than one
      import and we don't want each set to rebuild the trustdb.
      Instead we do it once at the end. */
-  opt.keyserver_options.import_options|=IMPORT_FAST;
-
-  /* A dummy desc since we're not actually fetching a particular key
-     ID */
-  memset(&desc,0,sizeof(desc));
-  desc.mode=KEYDB_SEARCH_MODE_EXACT;
+  opt.keyserver_options.import_options |= IMPORT_FAST;
 
-  for(sl=urilist;sl;sl=sl->next)
+  for (sl=urilist; sl; sl=sl->next)
     {
-      struct keyserver_spec *spec;
+      if (!opt.quiet)
+        log_info (_("requesting key from '%s'\n"), sl->d);
 
-      spec=parse_keyserver_uri(sl->d,1,NULL,0);
-      if(spec)
-       {
-         int rc;
+      err = gpg_dirmngr_ks_fetch (ctrl, sl->d, &datastream);
+      if (!err)
+        {
+          import_stats_t stats_handle;
 
-         rc = keyserver_get (ctrl, &desc, 1, spec);
-         if(rc)
-           log_info (_("WARNING: unable to fetch URI %s: %s\n"),
-                    sl->d,g10_errstr(rc));
+          stats_handle = import_new_stats_handle();
+          import_keys_es_stream (ctrl, datastream, stats_handle, NULL, NULL,
+                                 opt.keyserver_options.import_options,
+                                 NULL, NULL);
 
-         free_keyserver_spec(spec);
-       }
+          import_print_stats (stats_handle);
+          import_release_stats_handle (stats_handle);
+        }
       else
-       log_info (_("WARNING: unable to parse URI %s\n"),sl->d);
+        log_info (_("WARNING: unable to fetch URI %s: %s\n"),
+                  sl->d, gpg_strerror (err));
+      es_fclose (datastream);
     }
 
-  opt.keyserver_options.import_options=options;
+  opt.keyserver_options.import_options = save_options;
 
   /* If the original options didn't have fast import, and the trustdb
      is dirty, rebuild. */
-  if(!(opt.keyserver_options.import_options&IMPORT_FAST))
-    trustdb_check_or_update();
+  if (!(opt.keyserver_options.import_options&IMPORT_FAST))
+    check_or_update_trustdb ();
 
   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)
 {
-  char *domain,*look,*url;
-  IOBUF key;
-  int type,rc=G10ERR_GENERAL;
-
-  look=xstrdup(name);
+  gpg_error_t err;
+  char *look,*url;
+  estream_t key;
 
-  domain=strrchr(look,'@');
-  if(domain)
-    *domain='.';
+  look = xstrdup(name);
 
-  type=get_dns_cert(look,max_cert_size,&key,fpr,fpr_len,&url);
-  if (!type || type == -1)
+  if (!dane_mode)
     {
-      /* There might be an error in res_query which leads to an error
-         return (-1) in the case that nothing was found.  Thus we take
-         all errors as key not found.  */
-      rc = G10ERR_NO_PUBKEY;
+      char *domain = strrchr (look,'@');
+      if (domain)
+        *domain='.';
     }
-  else if (type==1)
+
+  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;
 
-      /* CERTs are always in binary format */
+      /* CERTs and DANE records are always in binary format */
       opt.no_armor=1;
 
-      /* FIXME: Pass CTRL.  */
-      rc = import_keys_stream (NULL, key, NULL, fpr, fpr_len,
-                               opt.keyserver_options.import_options);
+      err = import_keys_es_stream (ctrl, key, NULL, fpr, fpr_len,
+                                   (opt.keyserver_options.import_options
+                                    | IMPORT_NO_SECKEY),
+                                   NULL, NULL);
 
       opt.no_armor=armor_status;
 
-      iobuf_close(key);
+      es_fclose (key);
+      key = NULL;
     }
-  else if(type==2 && *fpr)
+  else if (*fpr)
     {
       /* We only consider the IPGP type if a fingerprint was provided.
         This lets us select the right key regardless of what a URL
@@ -2364,94 +1941,80 @@ keyserver_import_cert (ctrl_t ctrl,
        {
          struct keyserver_spec *spec;
 
-         spec=parse_keyserver_uri(url,1,NULL,0);
+         spec = parse_keyserver_uri (url, 1);
          if(spec)
            {
-             rc = keyserver_import_fprint (ctrl, *fpr,*fpr_len,spec);
+             err = keyserver_import_fprint (ctrl, *fpr,*fpr_len,spec);
              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. */
 
-         rc = keyserver_import_fprint (ctrl, *fpr,*fpr_len,opt.keyserver);
+         err = keyserver_import_fprint (ctrl, *fpr,*fpr_len,opt.keyserver);
        }
       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
         --keyserver)\n" ? */
 
-      xfree(url);
     }
 
+  xfree(url);
   xfree(look);
 
-  return rc;
+  return err;
 }
 
 /* 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 = G10ERR_NO_PUBKEY;
-
-  *fpr = xmalloc (20);
-  *fpr_len = 20;
+  gpg_error_t err;
+  char *url;
 
-  uri = get_pka_info (name, *fpr);
-  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, NULL, 0);
+      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);
          free_keyserver_spec (spec);
        }
-      xfree (uri);
     }
+  xfree (url);
 
-  if (rc)
+  if (err)
     {
       xfree(*fpr);
       *fpr = NULL;
+      *fpr_len = 0;
     }
 
-  return rc;
+  return err;
 }
 
-/* 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 = 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;
@@ -2465,7 +2028,7 @@ keyserver_import_ldap (ctrl_t ctrl,
   /* Parse out the domain */
   domain=strrchr(name,'@');
   if(!domain)
-    return G10ERR_GENERAL;
+    return GPG_ERR_GENERAL;
 
   domain++;
 
@@ -2477,6 +2040,7 @@ keyserver_import_ldap (ctrl_t ctrl,
 #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++)
@@ -2513,12 +2077,14 @@ keyserver_import_ldap (ctrl_t ctrl,
 
   append_to_strlist(&list,name);
 
-  rc = keyserver_work (ctrl, KS_GETNAME, list, NULL,
-                       0, fpr, fpr_len, keyserver);
+  rc = gpg_error (GPG_ERR_NOT_IMPLEMENTED); /*FIXME*/
+       /* keyserver_work (ctrl, KS_GETNAME, list, NULL, */
+       /*                 0, fpr, fpr_len, keyserver); */
 
   free_strlist(list);
 
   free_keyserver_spec(keyserver);
 
   return rc;
+#endif
 }