Initial code checking for backup - not yet working.
authorWerner Koch <wk@gnupg.org>
Mon, 10 Jan 2011 13:30:17 +0000 (14:30 +0100)
committerWerner Koch <wk@gnupg.org>
Mon, 10 Jan 2011 13:30:17 +0000 (14:30 +0100)
25 files changed:
.gitignore [new file with mode: 0644]
common/ChangeLog
common/http.c
common/http.h
common/keyserver.h
common/util.h
dirmngr/ChangeLog
dirmngr/Makefile.am
dirmngr/crlfetch.c
dirmngr/dirmngr.h
dirmngr/ks-action.c [new file with mode: 0644]
dirmngr/ks-action.h [new file with mode: 0644]
dirmngr/ks-engine-hkp.c [new file with mode: 0644]
dirmngr/ks-engine.h [new file with mode: 0644]
dirmngr/server.c
g10/ChangeLog
g10/Makefile.am
g10/call-dirmngr.c [new file with mode: 0644]
g10/call-dirmngr.h [new file with mode: 0644]
g10/gpg.c
g10/gpg.h
g10/keyserver-internal.h
g10/keyserver.c
g10/options.h
keyserver/gpgkeys_hkp.c

diff --git a/.gitignore b/.gitignore
new file mode 100644 (file)
index 0000000..9bd59ab
--- /dev/null
@@ -0,0 +1,8 @@
+Makefile.in
+aclocal.m4
+autom4te.cache/
+configure
+config.h.in
+config.h
+common/audit-events.h
+common/status-codes.h
index de96b8d..1484ae0 100644 (file)
@@ -1,3 +1,15 @@
+2011-01-07  Werner Koch  <wk@g10code.com>
+
+       * util.h (GPG_ERR_NO_KEYSERVER): New.
+
+       * keyserver.h (keyserver_spec): Move from ../g10/options.h to here.
+
+       * http.c (do_parse_uri): Add arg NO_SCHEME_CHECK.  Change all
+       callers.  Support HKP and HKPS.
+       (_http_parse_uri): Do proper error management.
+       * http.h (parsed_uri_s): Add field IS_HTTP.
+       (http_parse_uri): Support NO_SCHEME_CHECK arg.
+
 2010-12-17  Werner Koch  <wk@g10code.com>
 
        * asshelp.c (lock_spawning): Add arg VERBOSE.  Improve timeout
 
 
  Copyright 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
-          2009, 2010 Free Software Foundation, Inc.
+          2009, 2010, 2011 Free Software Foundation, Inc.
 
  This file is free software; as a special exception the author gives
  unlimited permission to copy and/or distribute it, with or without
index 1d84051..3d7c463 100644 (file)
@@ -138,7 +138,8 @@ typedef unsigned long longcounter_t;
 typedef void * gnutls_session_t;
 #endif
 
-static gpg_err_code_t do_parse_uri (parsed_uri_t uri, int only_local_part);
+static gpg_err_code_t do_parse_uri (parsed_uri_t uri, int only_local_part,
+                                    int no_scheme_check);
 static int remove_escapes (char *string);
 static int insert_escapes (char *buffer, const char *string,
                            const char *special);
@@ -356,7 +357,7 @@ _http_open (http_t *r_hd, http_req_t reqtype, const char *url,
   hd->flags = flags;
   hd->tls_context = tls_context;
 
-  err = _http_parse_uri (&hd->uri, url, errsource);
+  err = _http_parse_uri (&hd->uri, url, 0, errsource);
   if (!err)
     err = send_request (hd, auth, proxy, srvtag, headers, errsource);
   
@@ -368,7 +369,6 @@ _http_open (http_t *r_hd, http_req_t reqtype, const char *url,
         es_fclose (hd->fp_read);
       if (hd->fp_write)
         es_fclose (hd->fp_write);
-      http_release_parsed_uri (hd->uri);
       xfree (hd);
     }
   else
@@ -511,18 +511,27 @@ http_get_status_code (http_t hd)
 \f
 /*
  * Parse an URI and put the result into the newly allocated RET_URI.
- * The caller must always use release_parsed_uri() to releases the
- * resources (even on error).
+ * On success the caller must use release_parsed_uri() to releases the
+ * resources.  If NO_SCHEME_CHECK is set, the function tries to parse
+ * the URL in the same way it would do for an HTTP style URI.
  */
 gpg_error_t
-_http_parse_uri (parsed_uri_t * ret_uri, const char *uri,
-                 gpg_err_source_t errsource)
+_http_parse_uri (parsed_uri_t *ret_uri, const char *uri,
+                 int no_scheme_check, gpg_err_source_t errsource)
 {
+  gpg_err_code_t ec;
+
   *ret_uri = xtrycalloc (1, sizeof **ret_uri + strlen (uri));
   if (!*ret_uri)
     return gpg_err_make (errsource, gpg_err_code_from_syserror ());
   strcpy ((*ret_uri)->buffer, uri);
-  return gpg_err_make (errsource, do_parse_uri (*ret_uri, 0));
+  ec = do_parse_uri (*ret_uri, 0, no_scheme_check);
+  if (ec)
+    {
+      xfree (*ret_uri);
+      *ret_uri = NULL;
+    }
+  return gpg_err_make (errsource, ec);
 }
 
 void
@@ -543,7 +552,7 @@ http_release_parsed_uri (parsed_uri_t uri)
 
 
 static gpg_err_code_t
-do_parse_uri (parsed_uri_t uri, int only_local_part)
+do_parse_uri (parsed_uri_t uri, int only_local_part, int no_scheme_check)
 {
   uri_tuple_t *tail;
   char *p, *p2, *p3, *pp;
@@ -557,6 +566,7 @@ do_parse_uri (parsed_uri_t uri, int only_local_part)
   uri->port = 0;
   uri->params = uri->query = NULL;
   uri->use_tls = 0;
+  uri->is_http = 0;
 
   /* A quick validity check. */
   if (strspn (p, VALID_URI_CHARS) != n)
@@ -572,15 +582,24 @@ do_parse_uri (parsed_uri_t uri, int only_local_part)
        *pp = tolower (*(unsigned char*)pp);
       uri->scheme = p;
       if (!strcmp (uri->scheme, "http"))
-        uri->port = 80;
+        {
+          uri->port = 80;
+          uri->is_http = 1;
+        }
+      else if (!strcmp (uri->scheme, "hkp"))
+        {
+          uri->port = 11371;
+          uri->is_http = 1;
+        }
 #ifdef HTTP_USE_GNUTLS
-      else if (!strcmp (uri->scheme, "https"))
+      else if (!strcmp (uri->scheme, "https") || !strcmp (uri->scheme,"hkps"))
         {
           uri->port = 443;
+          uri->is_http = 1;
           uri->use_tls = 1;
         }
 #endif
-      else
+      else if (!no_scheme_check)
        return GPG_ERR_INV_URI; /* Unsupported scheme */
 
       p = p2;
@@ -852,12 +871,11 @@ send_request (http_t hd, const char *auth,
       if (proxy)
        http_proxy = proxy;
 
-      err = _http_parse_uri (&uri, http_proxy, errsource);
+      err = _http_parse_uri (&uri, http_proxy, 0, errsource);
       if (err)
        {
          log_error ("invalid HTTP proxy (%s): %s\n",
                     http_proxy, gpg_strerror (err));
-         http_release_parsed_uri (uri);
          return gpg_err_make (errsource, GPG_ERR_CONFIGURATION);
        }
 
@@ -1882,11 +1900,10 @@ main (int argc, char **argv)
   http_register_tls_callback (verify_callback);
 #endif /*HTTP_USE_GNUTLS*/
 
-  rc = http_parse_uri (&uri, *argv);
+  rc = http_parse_uri (&uri, *argv, 0);
   if (rc)
     {
       log_error ("`%s': %s\n", *argv, gpg_strerror (rc));
-      http_release_parsed_uri (uri);
       return 1;
     }
 
index ac9cb15..aaa2d3a 100644 (file)
@@ -23,7 +23,8 @@
 #include <gpg-error.h>
 #include "../common/estream.h"
 
-struct uri_tuple_s {
+struct uri_tuple_s 
+{
   struct uri_tuple_s *next;
   const char *name;    /* A pointer into name. */
   char  *value;         /* A pointer to value (a Nul is always appended). */
@@ -36,8 +37,9 @@ typedef struct uri_tuple_s *uri_tuple_t;
 struct parsed_uri_s 
 {
   /* All these pointers point into BUFFER; most stuff is not escaped. */
-  char *scheme;                /* Pointer to the scheme string (lowercase). */
-  int use_tls;          /* Whether TLS should be used. */
+  char *scheme;                /* Pointer to the scheme string (always lowercase). */
+  unsigned int is_http:1; /* This is a HTTP style URI.   */
+  unsigned int use_tls:1; /* Whether TLS should be used. */
   char *auth;           /* username/password for basic auth */
   char *host;          /* Host (converted to lowercase). */
   unsigned short port;  /* Port (always set if the host is set). */
@@ -71,9 +73,9 @@ typedef struct http_context_s *http_t;
 void http_register_tls_callback (gpg_error_t (*cb) (http_t, void *, int));
 
 gpg_error_t _http_parse_uri (parsed_uri_t *ret_uri, const char *uri,
-                             gpg_err_source_t errsource);
-#define http_parse_uri(a,b) \
-  _http_parse_uri ((a), (b), GPG_ERR_SOURCE_DEFAULT)
+                             int no_scheme_check, gpg_err_source_t errsource);
+#define http_parse_uri(a,b,c)                                    \
+  _http_parse_uri ((a), (b), (c), GPG_ERR_SOURCE_DEFAULT)
 
 void http_release_parsed_uri (parsed_uri_t uri);
 
index 6455e8c..d286f7d 100644 (file)
@@ -1,5 +1,5 @@
 /* keyserver.h - Public definitions for gpg keyserver helpers.
- * Copyright (C) 2001, 2002 Free Software Foundation, Inc.
+ * Copyright (C) 2001, 2002, 2011 Free Software Foundation, Inc.
  *
  * This file is part of GnuPG.
  *
 /* Must be 127 due to shell internal magic. */
 #define KEYSERVER_SCHEME_NOT_FOUND 127
 
+/* Object to hold information pertaining to a keyserver; it further
+   allows to build a list of keyservers.  Note that g10/options.h has
+   a typedef for this.  FIXME: We should make use of the
+   parse_uri_t. */
+struct keyserver_spec
+{
+  struct keyserver_spec *next;
+  char *uri;
+  char *scheme;
+  char *auth;
+  char *host;
+  char *port;
+  char *path;
+  char *opaque;
+  strlist_t options;
+  struct
+  {
+    unsigned int direct_uri:1;
+  } flags;
+};
+
+
 #endif /*GNUPG_COMMON_KEYSERVER_H*/
index 7c58b15..1f7964f 100644 (file)
@@ -36,6 +36,9 @@
 #ifndef GPG_ERR_MISSING_ISSUER_CERT
 #define GPG_ERR_MISSING_ISSUER_CERT 185
 #endif
+#ifndef GPG_ERR_NO_KEYSERVER
+#define GPG_ERR_NO_KEYSERVER 186
+#endif
 #ifndef GPG_ERR_FULLY_CANCELED
 #define GPG_ERR_FULLY_CANCELED 198
 #endif
index 2c20875..f5b3dea 100644 (file)
@@ -1,3 +1,20 @@
+2011-01-06  Werner Koch  <wk@g10code.com>
+
+       * server.c (release_ctrl_keyservers): New.
+       (cmd_keyserver): New.
+
+       * dirmngr.h (uri_item_t): New.
+       (struct server_control_s): Add field KEYSERVERS.
+
+2011-01-04  Werner Koch  <wk@g10code.com>
+
+       * ks-engine-hkp.c: New.
+       * ks-engine.h: New.
+       * ks-action.c, ks-action.h: New.
+       * server.c: Include ks-action.h.
+       (cmd_ks_search): New.
+       * Makefile.am (dirmngr_SOURCES): Add new files.
+
 2010-12-14  Werner Koch  <wk@g10code.com>
 
        * cdb.h (struct cdb) [W32]: Add field CDB_MAPPING.
        [Update after merge with GnuPG: see ./ChangeLog.1]
 
 
- Copyright 2004, 2005, 2006, 2007, 2008, 2009, 2010 g10 Code GmbH
+ Copyright 2004, 2005, 2006, 2007, 2008, 2009, 2010,
+          2011 Free Software Foundation, Inc.
 
  This file is free software; as a special exception the author gives
  unlimited permission to copy and/or distribute it, with or without
index 5b1fe30..8c41c53 100644 (file)
@@ -49,7 +49,8 @@ noinst_HEADERS = dirmngr.h crlcache.h crlfetch.h misc.h
 dirmngr_SOURCES = dirmngr.c dirmngr.h server.c crlcache.c crlfetch.c   \
        ldapserver.h ldapserver.c certcache.c certcache.h \
        cdb.h cdblib.c ldap.c misc.c dirmngr-err.h w32-ldap-help.h \
-       ocsp.c ocsp.h validate.c validate.h ldap-wrapper.h $(ldap_url)
+       ocsp.c ocsp.h validate.c validate.h ldap-wrapper.h $(ldap_url) \
+       ks-action.c ks-action.h ks-engine.h ks-engine-hkp.c
 
 if USE_LDAPWRAPPER
 dirmngr_SOURCES += ldap-wrapper.c 
index 83897a6..0577423 100644 (file)
@@ -160,7 +160,7 @@ crl_fetch (ctrl_t ctrl, const char *url, ksba_reader_t *reader)
   *reader = NULL;
 
  once_more:
-  err = http_parse_uri (&uri, url);
+  err = http_parse_uri (&uri, url, 0);
   http_release_parsed_uri (uri);
   if (err && url && !strncmp (url, "https:", 6))
     {
@@ -172,7 +172,7 @@ crl_fetch (ctrl_t ctrl, const char *url, ksba_reader_t *reader)
       if (free_this)
         {
           strcpy (stpcpy (free_this,"http:"), url+6);
-          err = http_parse_uri (&uri, free_this);
+          err = http_parse_uri (&uri, free_this, 0);
           http_release_parsed_uri (uri);
           if (!err)
             {
index 01478a6..1ba90b8 100644 (file)
@@ -32,7 +32,7 @@
 #include "../common/membuf.h"
 #include "../common/sysutils.h" /* (gnupg_fd_t) */
 #include "../common/i18n.h"
-
+#include "../common/http.h"     /* (parsed_uri_t) */
 
 /* This objects keeps information about a particular LDAP server and
    is used as item of a single linked list of servers. */
@@ -49,6 +49,17 @@ struct ldap_server_s
 typedef struct ldap_server_s *ldap_server_t;
 
 
+/* This objects is used to build a list of URI consisting of the
+   original and the parsed URI.  */
+struct uri_item_s
+{
+  struct uri_item_s *next;
+  parsed_uri_t parsed_uri;  /* The broken down URI.  */
+  char uri[1];              /* The original URI.  */
+};
+typedef struct uri_item_s *uri_item_t;
+
+
 /* A list of fingerprints.  */
 struct fingerprint_list_s;
 typedef struct fingerprint_list_s *fingerprint_list_t;
@@ -163,6 +174,7 @@ struct server_control_s
                             response. */
 
   int audit_events;  /* Send audit events to client.  */
+  uri_item_t keyservers; /* List of keyservers.  */
 };
 
 
diff --git a/dirmngr/ks-action.c b/dirmngr/ks-action.c
new file mode 100644 (file)
index 0000000..5ad4b18
--- /dev/null
@@ -0,0 +1,90 @@
+/* ks-action.c - OpenPGP keyserver actions
+ * Copyright (C) 2011 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GnuPG is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * 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/>.
+ */
+
+#include <config.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+
+#include "dirmngr.h"
+#include "misc.h"
+#include "ks-engine.h"
+#include "ks-action.h"
+
+
+/* Copy all data from IN to OUT.  */
+static gpg_error_t
+copy_stream (estream_t in, estream_t out)
+{
+  char buffer[512];
+  size_t nread;
+
+  while (!es_read (in, buffer, sizeof buffer, &nread))
+    {
+      if (!nread)
+        return 0; /* EOF */
+      if (es_write (out, buffer, nread, NULL))
+        break;
+
+    }
+  return gpg_error_from_syserror ();
+}
+
+
+
+/* Search all configured keyservers for keys matching PATTERNS and
+   write the result to the provided output stream.  */
+gpg_error_t
+ks_action_search (ctrl_t ctrl, strlist_t patterns, estream_t outfp)
+{
+  gpg_error_t err = 0;
+  int any = 0;
+  uri_item_t uri;
+  estream_t infp;
+
+  if (!patterns)
+    return gpg_error (GPG_ERR_NO_USER_ID);
+
+  /* FIXME: We only take care of the first pattern.  To fully support
+     multiple patterns we might either want to run several queries in
+     parallel and merge them.  We also need to decide what to do with
+     errors - it might not be the best idea to ignore an error from
+     one server and silently continue with another server.  For now we
+     stop at the first error. */
+  for (uri = ctrl->keyservers; !err && uri; uri = uri->next)
+    {
+      if (uri->parsed_uri->is_http)
+        {
+          any = 1;
+          err = ks_hkp_search (ctrl, uri->parsed_uri, patterns->d, &infp);
+          if (!err)
+            {
+              err = copy_stream (infp, outfp);
+              es_fclose (infp);
+            }
+        }
+    }
+
+  if (!any)
+    err = gpg_error (GPG_ERR_NO_KEYSERVER);
+  return err;
+}
+
diff --git a/dirmngr/ks-action.h b/dirmngr/ks-action.h
new file mode 100644 (file)
index 0000000..5790339
--- /dev/null
@@ -0,0 +1,26 @@
+/* ks-action.h - OpenPGP keyserver actions definitions
+ * Copyright (C) 2011 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GnuPG is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * 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/>.
+ */
+
+#ifndef DIRMNGR_KS_ACTION_H
+#define DIRMNGR_KS_ACTION_H 1
+
+gpg_error_t ks_action_search (ctrl_t ctrl, strlist_t patterns, estream_t outfp);
+
+
+#endif /*DIRMNGR_KS_ACTION_H*/
diff --git a/dirmngr/ks-engine-hkp.c b/dirmngr/ks-engine-hkp.c
new file mode 100644 (file)
index 0000000..356f643
--- /dev/null
@@ -0,0 +1,258 @@
+/* ks-engine-hkp.c - HKP keyserver engine
+ * Copyright (C) 2011 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GnuPG is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * 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/>.
+ */
+
+#include <config.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+
+#include "dirmngr.h"
+#include "misc.h"
+#include "userids.h"
+#include "ks-engine.h"
+
+/* To match the behaviour of our old gpgkeys helper code we escape
+   more characters than actually needed. */
+#define EXTRA_ESCAPE_CHARS "@!\"#$%&'()*+,-./:;<=>?[\\]^_{|}~"
+
+/* How many redirections do we allow.  */
+#define MAX_REDIRECTS 2
+
+
+/* Search the keyserver identified by URI for keys matching PATTERN.
+   On success R_FP has an open stream to read the data.  */
+gpg_error_t
+ks_hkp_search (ctrl_t ctrl, parsed_uri_t uri, const char *pattern,
+               estream_t *r_fp)
+{
+  gpg_error_t err;
+  KEYDB_SEARCH_DESC desc;
+  char fprbuf[2+40+1];
+  const char *scheme;
+  char portstr[10];
+  http_t http = NULL;
+  char *hostport = NULL;
+  char *request = NULL;
+  int redirects_left = MAX_REDIRECTS;
+  estream_t fp = NULL;
+
+  *r_fp = NULL;
+
+  /* Remove search type indicator and adjust PATTERN accordingly.
+     Note that HKP keyservers like the 0x to be present when searching
+     by keyid.  We need to re-format the fingerprint and keyids so to
+     remove the gpg specific force-use-of-this-key flag ("!").  */
+  err = classify_user_id (pattern, &desc);
+  if (err)
+    return err;
+  switch (desc.mode)
+    {
+    case KEYDB_SEARCH_MODE_EXACT:
+    case KEYDB_SEARCH_MODE_SUBSTR:
+    case KEYDB_SEARCH_MODE_MAIL:
+    case KEYDB_SEARCH_MODE_MAILSUB:
+      pattern = desc.u.name;
+      break;
+    case KEYDB_SEARCH_MODE_SHORT_KID:
+      snprintf (fprbuf, sizeof fprbuf, "0x%08lX", (ulong)desc.u.kid[1]);
+      pattern = fprbuf;
+      break;
+    case KEYDB_SEARCH_MODE_LONG_KID:
+      snprintf (fprbuf, sizeof fprbuf, "0x%08lX%08lX", 
+                (ulong)desc.u.kid[0], (ulong)desc.u.kid[1]);
+      pattern = fprbuf;
+      break;
+    case KEYDB_SEARCH_MODE_FPR16:
+      bin2hex (desc.u.fpr, 16, fprbuf);
+      pattern = fprbuf;
+      break;
+    case KEYDB_SEARCH_MODE_FPR20:
+    case KEYDB_SEARCH_MODE_FPR:
+      bin2hex (desc.u.fpr, 20, fprbuf);
+      pattern = fprbuf;
+      break;
+    default:
+      return gpg_error (GPG_ERR_INV_USER_ID);
+    }
+  
+  /* Map scheme and port.  */
+  if (!strcmp (uri->scheme,"hkps") || !strcmp (uri->scheme,"https"))
+    {
+      scheme = "https";
+      strcpy (portstr, "443");
+    }
+  else /* HKP or HTTP.  */
+    {
+      scheme = "http";
+      strcpy (portstr, "11371");
+    }
+  if (uri->port)
+    snprintf (portstr, sizeof portstr, "%hu", uri->port);
+  else
+    {} /*fixme_do_srv_lookup ()*/
+
+  /* Build the request string.  */
+  {
+    char *searchkey;
+
+    hostport = strconcat (scheme, "://", 
+                          *uri->host? uri->host: "localhost",
+                          ":", portstr, NULL);
+    if (!hostport)
+      {
+        err = gpg_error_from_syserror ();
+        goto leave;
+      }
+
+    searchkey = http_escape_string (pattern, EXTRA_ESCAPE_CHARS);
+    if (!searchkey)
+      {
+        err = gpg_error_from_syserror ();
+        goto leave;
+      }
+
+    request = strconcat (hostport,
+                         "/pks/lookup?op=index&options=mr&search=",
+                         searchkey,
+                         NULL);
+    xfree (searchkey);
+    if (!request)
+      {
+        err = gpg_error_from_syserror ();
+        goto leave;
+      }
+  }
+  
+  /* Send the request.  */
+ once_more:
+  err = http_open (&http, HTTP_REQ_GET, request,
+                   /* fixme: AUTH */ NULL,
+                   0,
+                   /* fixme: proxy*/ NULL,
+                   NULL, NULL,
+                   /*FIXME curl->srvtag*/NULL);
+  if (!err)
+    {
+      fp = http_get_write_ptr (http);
+      /* Avoid caches to get the most recent copy of the key.  We set
+         both the Pragma and Cache-Control versions of the header, so
+         we're good with both HTTP 1.0 and 1.1.  */
+      es_fputs ("Pragma: no-cache\r\n"
+                "Cache-Control: no-cache\r\n", fp);
+      http_start_data (http);
+      if (es_ferror (fp))
+        err = gpg_error_from_syserror ();
+    }
+  if (err)
+    {
+      /* Fixme: After a redirection we show the old host name.  */
+      log_error (_("error connecting to `%s': %s\n"),
+                 hostport, gpg_strerror (err));
+      goto leave;
+    }
+
+  /* Wait for the response.  */
+  dirmngr_tick (ctrl);
+  err = http_wait_response (http);
+  if (err)
+    {
+      log_error (_("error reading HTTP response for `%s': %s\n"),
+                 hostport, gpg_strerror (err));
+      goto leave;
+    }
+
+  switch (http_get_status_code (http))
+    {
+    case 200:
+      break; /* Success.  */
+
+    case 301:
+    case 302:
+      {
+        const char *s = http_get_header (http, "Location");
+        
+        log_info (_("URL `%s' redirected to `%s' (%u)\n"),
+                  request, s?s:"[none]", http_get_status_code (http));
+        if (s && *s && redirects_left-- )
+          {
+            xfree (request);
+            request = xtrystrdup (s);
+            if (request)
+              {
+                http_close (http, 0);
+                http = NULL;
+                goto once_more;
+              }
+            err = gpg_error_from_syserror ();
+          }
+        else
+          err = gpg_error (GPG_ERR_NO_DATA);
+        log_error (_("too many redirections\n"));
+      }
+      goto leave;
+
+    default:
+      log_error (_("error accessing `%s': http status %u\n"),
+                 request, http_get_status_code (http));
+      err = gpg_error (GPG_ERR_NO_DATA);
+      goto leave;
+    }
+
+  /* Start reading the response.  */
+  fp = http_get_read_ptr (http);
+  if (!fp)
+    {
+      err = gpg_error (GPG_ERR_BUG);
+      goto leave;
+    }
+  {
+    int c = es_getc (fp);
+    if (c == -1)
+      {
+        err = es_ferror (fp)?gpg_error_from_syserror ():gpg_error (GPG_ERR_EOF);
+        log_error ("error reading response: %s\n", gpg_strerror (err));
+        goto leave;
+      }
+    if (c == '<')
+      {
+        /* The document begins with a '<', assume it's a HTML
+           response, which we don't support.  */
+        err = gpg_error (GPG_ERR_UNSUPPORTED_ENCODING);
+        goto leave;
+      }
+    es_ungetc (c, fp);
+  }
+
+  /* Return the read stream and close the HTTP context.  */
+  *r_fp = fp;
+  fp = NULL;
+  http_close (http, 1);
+  http = NULL;
+
+ leave:
+  es_fclose (fp);
+  http_close (http, 0);
+  xfree (request);
+  xfree (hostport);
+  return err;
+}
+
+
diff --git a/dirmngr/ks-engine.h b/dirmngr/ks-engine.h
new file mode 100644 (file)
index 0000000..f68782f
--- /dev/null
@@ -0,0 +1,32 @@
+/* ks-engine.h - Keyserver engines definitions
+ * Copyright (C) 2011 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GnuPG is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * 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/>.
+ */
+
+#ifndef DIRMNGR_KS_ENGINE_H
+#define DIRMNGR_KS_ENGINE_H 1
+
+#include "../common/estream.h"
+#include "../common/http.h"
+
+/*-- ks-engine-hkp.c --*/
+gpg_error_t ks_hkp_search (ctrl_t ctrl, parsed_uri_t uri, const char *pattern,
+                           estream_t *r_fp);
+
+
+
+#endif /*DIRMNGR_KS_ENGINE_H*/
index 11ba1fb..40e8dab 100644 (file)
@@ -1,6 +1,6 @@
 /* dirmngr.c - LDAP access
  *     Copyright (C) 2002 Klarälvdalens Datakonsult AB
- *      Copyright (C) 2003, 2004, 2005, 2007, 2008, 2009 g10 Code GmbH
+ *      Copyright (C) 2003, 2004, 2005, 2007, 2008, 2009, 2011 g10 Code GmbH
  *
  * This file is part of DirMngr.
  *
@@ -41,6 +41,7 @@
 #include "validate.h"
 #include "misc.h"
 #include "ldap-wrapper.h"
+#include "ks-action.h"
 
 /* To avoid DoS attacks we limit the size of a certificate to
    something reasonable. */
@@ -58,7 +59,7 @@ struct server_local_s
   /* Data used to associate an Assuan context with local server data */
   assuan_context_t assuan_ctx;
 
-  /* Per-session LDAP serfver.  */
+  /* Per-session LDAP servers.  */
   ldap_server_t ldapservers;
 
   /* If this flag is set to true this dirmngr process will be
@@ -94,6 +95,21 @@ get_ldapservers_from_ctrl (ctrl_t ctrl)
 }
 
 
+/* Release all configured keyserver info from CTRL.  */
+void
+release_ctrl_keyservers (ctrl_t ctrl)
+{
+  while (ctrl->keyservers)
+    {
+      uri_item_t tmp = ctrl->keyservers->next;
+      http_release_parsed_uri (ctrl->keyservers->parsed_uri);
+      xfree (ctrl->keyservers);
+      ctrl->keyservers = tmp;
+    }
+}
+
+
+
 /* Helper to print a message while leaving a command.  */
 static gpg_error_t
 leave_cmd (assuan_context_t ctx, gpg_error_t err)
@@ -147,7 +163,7 @@ data_line_cookie_close (void *cookie)
 /* Copy the % and + escaped string S into the buffer D and replace the
    escape sequences.  Note, that it is sufficient to allocate the
    target string D as long as the source string S, i.e.: strlen(s)+1.
-   NOte further that If S contains an escaped binary nul the resulting
+   Note further that if S contains an escaped binary Nul the resulting
    string D will contain the 0 as well as all other characters but it
    will be impossible to know whether this is the original EOS or a
    copied Nul. */
@@ -1335,6 +1351,130 @@ cmd_validate (assuan_context_t ctx, char *line)
   return leave_cmd (ctx, err);
 }
 
+\f
+static const char hlp_keyserver[] =
+  "KEYSERVER [--clear] [<uri>]\n"
+  "\n"
+  "If called without arguments list all configured keyserver URLs.\n"
+  "If called with option \"--clear\" remove all configured keyservers\n"
+  "If called with an URI add this as keyserver.  Note that keyservers\n"
+  "are configured on a per-session base.  A default keyserver may already be\n"
+  "present, thus the \"--clear\" option must be used to get full control.\n"
+  "If \"--clear\" and an URI are used together the clear command is\n"
+  "obviously executed first.  A RESET command does not change the list\n"
+  "of configured keyservers.";
+static gpg_error_t
+cmd_keyserver (assuan_context_t ctx, char *line)
+{
+  ctrl_t ctrl = assuan_get_pointer (ctx);
+  gpg_error_t err;
+  int clear_flag, add_flag;
+  uri_item_t item = NULL; /* gcc 4.4.5 is not able to detect that it
+                             is always initialized.  */
+      
+  clear_flag = has_option (line, "--clear");
+  line = skip_options (line);
+  add_flag = !!*line;
+
+  if (add_flag)
+    {
+      item = xtrymalloc (sizeof *item + strlen (line));
+      if (!item)
+        {
+          err = gpg_error_from_syserror ();
+          goto leave;
+        }
+      item->next = NULL;
+      item->parsed_uri = NULL;
+      strcpy (item->uri, line);
+
+      err = http_parse_uri (&item->parsed_uri, line, 1);
+      if (err)
+        {
+          xfree (item);
+          goto leave;
+        }
+    }
+  if (clear_flag)
+    release_ctrl_keyservers (ctrl);
+  if (add_flag)
+    {
+      item->next = ctrl->keyservers;
+      ctrl->keyservers = item;
+    }
+  
+  if (!add_flag && !clear_flag) /* List  configured keyservers.  */
+    {
+      uri_item_t u;
+      
+      for (u=ctrl->keyservers; u; u = u->next)
+        dirmngr_status (ctrl, "KEYSERVER", u->uri, NULL);
+    }
+  err = 0;
+
+ leave:
+  return leave_cmd (ctx, err);
+}
+
+
+\f
+static const char hlp_ks_search[] =
+  "KS_SEARCH {<pattern>}\n"
+  "\n"
+  "Search the configured OpenPGP keyservers (see command KEYSERVER)\n"
+  "for keys matching PATTERN";
+static gpg_error_t
+cmd_ks_search (assuan_context_t ctx, char *line)
+{
+  ctrl_t ctrl = assuan_get_pointer (ctx);
+  gpg_error_t err;
+  strlist_t list, sl;
+  char *p;
+  estream_t outfp;
+
+  /* No options for now.  */
+  line = skip_options (line);
+
+  /* Break the line down into an strlist.  Each pattern is
+     percent-plus escaped. */
+  list = NULL;
+  for (p=line; *p; line = p)
+    {
+      while (*p && *p != ' ')
+        p++;
+      if (*p)
+        *p++ = 0;
+      if (*line)
+        {
+          sl = xtrymalloc (sizeof *sl + strlen (line));
+          if (!sl)
+            {
+              err = gpg_error_from_syserror ();
+              free_strlist (list);
+              goto leave;
+            }
+          sl->flags = 0;
+          strcpy_escaped_plus (sl->d, line);
+          sl->next = list;
+          list = sl;
+        }
+    }
+
+  /* Setup an output stream and perform the search.  */
+  outfp = es_fopencookie (ctx, "w", data_line_cookie_functions);
+  if (!outfp)
+    err = set_error (GPG_ERR_ASS_GENERAL, "error setting up a data stream");
+  else
+    {
+      err = ks_action_search (ctrl, list, outfp);
+      es_fclose (outfp);
+    }
+
+ leave:
+  return leave_cmd (ctx, err);
+}
+
+
 
 \f
 static const char hlp_getinfo[] = 
@@ -1469,6 +1609,8 @@ register_commands (assuan_context_t ctx)
     { "LISTCRLS",   cmd_listcrls,   hlp_listcrls },
     { "CACHECERT",  cmd_cachecert,  hlp_cachecert },
     { "VALIDATE",   cmd_validate,   hlp_validate },
+    { "KEYSERVER",  cmd_keyserver,  hlp_keyserver },
+    { "KS_SEARCH",  cmd_ks_search,  hlp_ks_search },
     { "GETINFO",    cmd_getinfo,    hlp_getinfo },
     { "KILLDIRMNGR",cmd_killdirmngr,hlp_killdirmngr },
     { "RELOADDIRMNGR",cmd_reloaddirmngr,hlp_reloaddirmngr },
@@ -1487,6 +1629,7 @@ register_commands (assuan_context_t ctx)
 }
 
 
+/* Note that we do not reset the list of configured keyservers.  */
 static gpg_error_t
 reset_notify (assuan_context_t ctx, char *line)
 {
@@ -1681,8 +1824,8 @@ dirmngr_status (ctrl_t ctrl, const char *keyword, ...)
 }
 
 
-/* Note, that we ignore CTRL for now but use the first connection to
-   send the progress info back. */
+/* Send a tick progress indicator back.  Fixme: This is only does for
+   the currently active channel.  */
 gpg_error_t
 dirmngr_tick (ctrl_t ctrl)
 {
index 0c8cbd4..1be035d 100644 (file)
@@ -1,3 +1,18 @@
+2011-01-07  Werner Koch  <wk@g10code.com>
+
+       * call-dirmngr.c, call-dirmngr.h: New.
+       * gpg.h (server_control_s): Add DIRMNGR_LOCAL.
+       * gpg.c: Include call-dirmngr.h.
+       (gpg_deinit_default_ctrl): Call gpg_dirmngr_deinit_session_data.
+
+2011-01-06  Werner Koch  <wk@g10code.com>
+
+       * gpg.c (main): Use keyserver_spec_t.
+
+       * options.h (struct opt): Factor definition of struct keyserver
+       out to ../common/keyserver.h.
+       (keyserver_spec_t): New.
+
 2010-12-09  Werner Koch  <wk@g10code.com>
 
        * tdbio.c (tdbio_set_dbname) [W32CE]: Take care of missing errno.
index c8fc482..475529c 100644 (file)
@@ -102,6 +102,7 @@ gpg2_SOURCES  = gpg.c               \
              helptext.c        \
              keyserver.c       \
              keyserver-internal.h \
+             call-dirmngr.c call-dirmngr.h \
              photoid.c photoid.h \
              call-agent.c call-agent.h \
              card-util.c \
diff --git a/g10/call-dirmngr.c b/g10/call-dirmngr.c
new file mode 100644 (file)
index 0000000..a18eb64
--- /dev/null
@@ -0,0 +1,256 @@
+/* call-dirmngr.c - GPG operations to the Dirmngr.
+ * Copyright (C) 2011 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GnuPG is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * 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/>.
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h> 
+#include <time.h>
+#include <assert.h>
+#ifdef HAVE_LOCALE_H
+# include <locale.h>
+#endif
+
+#include "gpg.h"
+#include <assuan.h>
+#include "util.h"
+#include "membuf.h"
+#include "options.h"
+#include "i18n.h"
+#include "asshelp.h"
+#include "call-dirmngr.h"
+
+
+/* Data used to associate an session with dirmngr contexts.  We can't
+   use a simple one to one mapping because we sometimes need two
+   connection s to the dirmngr; for example while doing a listing and
+   being in a data callback we may want to retrieve a key.  The local
+   dirmngr data takes care of this.  At the end of the session the
+   function dirmngr_deinit_session_data is called bu gpg.c to cleanup
+   these resources.  Note that gpg.h defines a typedef dirmngr_local_t
+   for this structure. */
+struct dirmngr_local_s 
+{
+  /* Link to other contexts which are used simultaneously.  */
+  struct dirmngr_local_s *next;
+
+  /* The active Assuan context. */
+  static assuan_context_t ctx;
+
+  /* Flag set to true while an operation is running on CTX.  */
+  int is_active;
+};
+
+
+\f
+/* Deinitialize all session data of dirmngr pertaining to CTRL.  */
+void
+gpg_dirmngr_deinit_session_data (ctrl_t ctrl)
+{
+  dirmngr_local_t dml;
+
+  while ((dml = ctrl->dirmngr_local))
+    {
+      ctrl->dirmngr_local = dml->next;
+      if (dml->is_active)
+        log_error ("oops: trying to cleanup an active dirmngr context\n");
+      else
+        assuan_release (dml->ctx);
+      xfree (dml);
+    }
+}
+
+
+/* Try to connect to the Dirmngr via a socket or fork it off if
+   possible.  Handle the server's initial greeting and set global
+   options.  */
+static gpg_error_t
+create_context (ctrl_t ctrl, assuan_context_t *r_ctx)
+{
+  gpg_error_t err;
+  assuan_context_t ctx;
+
+  *r_ctx = NULL;
+  err = start_new_dirmngr (&ctx,
+                           GPG_ERR_SOURCE_DEFAULT,
+                           opt.homedir,
+                           NULL,
+                           opt.verbose, DBG_ASSUAN,
+                           NULL /*gpg_status2*/, ctrl);
+  if (!err)
+    {
+      keyserver_spec_t ksi;
+
+      /* Tell the dirmngr that we want to collect audit event. */
+      /* err = assuan_transact (agent_ctx, "OPTION audit-events=1", */
+      /*                        NULL, NULL, NULL, NULL, NULL, NULL); */
+      
+      /* Set all configured keyservers.  We clear existing keyservers
+         so that any keyserver configured in GPG overrides keyservers
+         possibly configured in Dirmngr. */
+      if (ksi = opt.keyservers; !err && ksi; ksi = ksi->next)
+        {
+          char *line;
+          
+          line = xtryasprintf ("KEYSERVER%s %s",
+                               ksi == opt.keyservers? " --clear":"", ksi->uri);
+          if (!line)
+            err = gpg_error_from_syserror ();
+          else
+            {
+              err = assuan_transact (ctx, line,
+                                     NULL, NULL, NULL, NULL, NULL, NULL);
+              xfree (line);
+            }
+        }
+    }
+
+  if (err)
+    assuan_release (ctx);
+  else
+    {
+      /* audit_log_ok (ctrl->audit, AUDIT_DIRMNGR_READY, err); */
+      *r_ctx = ctx;
+    }
+  
+  return err;
+}
+
+
+/* Get a context for accessing dirmngr.  If no context is available a
+   new one is created and - if requred - dirmngr started.  On success
+   an assuan context is stored at R_CTX.  This Context may only be
+   released by means of close_context.  Note that NULL is stored at
+   R_CTX on error.  */
+static gpg_error_t
+open_context (ctrl_t ctrl, assuan_context_t *r_ctx)
+{
+  gpg_error_t err;
+  dirmngr_local_t dml;
+
+  *r_ctx = NULL;
+  for (;;)
+    {
+      for (dml = ctrl->dirmngr_local; dml && dml->is_active; dml = dml->next)
+        ;
+      if (dml)
+        {
+          /* Found an inactive local session - return that.  */
+          assert (!dml->is_active);
+          dml->is_active = 1;
+          return dml;
+        }
+      
+      dml = xtrycalloc (1, sizeof *dml);
+      if (!dml)
+        return gpg_error_from_syserror ();
+      err = create_context (ctrl, &dml->ctx);
+      if (err)
+        {
+          xfree (dml);
+          return err;
+        }
+      /* To be on the Pth thread safe site we need to add it to a
+         list; this is far easier than to have a lock for this
+         function.  It should not happen anyway but the code is free
+         because we need it for the is_active check above.  */
+      dml->next = ctrl->dirmngr_local;
+      ctrl->dirmngr_local = dml;
+    }
+}
+
+
+/* Close the assuan context CTX or return it to a pool of unused
+   contexts.  If CTX is NULL, the function does nothing.  */
+static void
+close_context (ctrl_t ctrl, assuan_context_t ctx)
+{
+  dirmngr_local_t dml;
+
+  if (!ctx)
+    return;
+
+  for (dml = ctrl->dirmngr_local; dml; dml = dml->next)
+    {
+      if (dml->ctx == ctx)
+        {
+          if (!ctx->is_active)
+            log_fatal ("closing inactive dirmngr context %p\n", ctx);
+          ctx->is_active = 0;
+          return;
+        }
+    }
+  log_fatal ("closing unknown dirmngr ctx %p\n", ctx);
+}
+
+
+\f
+
+int 
+gpg_dirmngr_ks_search (ctrl_t ctrl, strlist_t names,
+                       void (*cb)(void*, ksba_cert_t), void *cb_value)
+{ 
+  gpg_error_t err;
+  assuan_context_t ctx;
+  char *pattern;
+  char line[ASSUAN_LINELENGTH];
+
+  err = open_context (ctrl, &ctx);
+  if (err)
+    return err;
+
+  pattern = pattern_from_strlist (names);
+  if (!pattern)
+    {
+      if (ctx == dirmngr_ctx)
+       release_dirmngr (ctrl);
+      else
+       release_dirmngr2 (ctrl);
+
+      return out_of_core ();
+    }
+  snprintf (line, DIM(line)-1, "LOOKUP%s %s", 
+            cache_only? " --cache-only":"", pattern);
+  line[DIM(line)-1] = 0;
+  xfree (pattern);
+
+  parm.ctrl = ctrl;
+  parm.ctx = ctx;
+  parm.cb = cb;
+  parm.cb_value = cb_value;
+  parm.error = 0;
+  init_membuf (&parm.data, 4096);
+
+  rc = assuan_transact (ctx, line, lookup_cb, &parm,
+                        NULL, NULL, lookup_status_cb, &parm);
+  xfree (get_membuf (&parm.data, &len));
+
+  if (ctx == dirmngr_ctx)
+    release_dirmngr (ctrl);
+  else
+    release_dirmngr2 (ctrl);
+
+  if (rc)
+      return rc;
+
+  close_context (ctrl, ctx);
+  return parm.error;
+}
diff --git a/g10/call-dirmngr.h b/g10/call-dirmngr.h
new file mode 100644 (file)
index 0000000..fa579ad
--- /dev/null
@@ -0,0 +1,26 @@
+/* call-dirmngr.h - GPG operations to the Dirmngr
+ * Copyright (C) 2011 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GnuPG is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * 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/>.
+ */
+#ifndef GNUPG_G10_CALL_DIRMNGR_H
+#define GNUPG_G10_CALL_DIRMNGR_H 
+
+void gpg_dirmngr_deinit_session_data (ctrl_t ctrl);
+
+
+
+#endif /*GNUPG_G10_CALL_DIRMNGR_H*/
index 4a17b29..1866c1c 100644 (file)
--- a/g10/gpg.c
+++ b/g10/gpg.c
@@ -1,6 +1,6 @@
 /* gpg.c - The GnuPG utility (main for gpg)
- * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
- *               2006, 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
+ * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007
+ *               2008, 2009, 2010, 2011 Free Software Foundation, Inc.
  *
  * This file is part of GnuPG.
  *
@@ -54,6 +54,7 @@
 #include "exec.h"
 #include "gc-opt-flags.h"
 #include "asshelp.h"
+#include "call-dirmngr.h"
 
 #if defined(HAVE_DOSISH_SYSTEM) || defined(__CYGWIN__)
 #define MY_O_BINARY  O_BINARY
@@ -1822,7 +1823,7 @@ gpg_init_default_ctrl (ctrl_t ctrl)
 static void
 gpg_deinit_default_ctrl (ctrl_t ctrl)
 {
-  (void)ctrl;
+  gpg_dirmngr_deinit_session_data (ctrl);
 }
 
 
@@ -2658,15 +2659,15 @@ main (int argc, char **argv)
             break;
          case oKeyServer:
            {
-             struct keyserver_spec *keyserver;
-             keyserver=parse_keyserver_uri(pargs.r.ret_str,0,
-                                           configname,configlineno);
-             if(!keyserver)
-               log_error(_("could not parse keyserver URL\n"));
+             keyserver_spec_t keyserver;
+             keyserver = parse_keyserver_uri (pargs.r.ret_str,0,
+                                               configname,configlineno);
+             if (!keyserver)
+               log_error (_("could not parse keyserver URL\n"));
              else
                {
-                 keyserver->next=opt.keyserver;
-                 opt.keyserver=keyserver;
+                 keyserver->next = opt.keyserver;
+                 opt.keyserver = keyserver;
                }
            }
            break;
@@ -2853,14 +2854,14 @@ main (int argc, char **argv)
            break;
          case oDefaultKeyserverURL:
            {
-             struct keyserver_spec *keyserver;
-             keyserver=parse_keyserver_uri(pargs.r.ret_str,1,
-                                           configname,configlineno);
-             if(!keyserver)
-               log_error(_("could not parse keyserver URL\n"));
+             keyserver_spec_t keyserver;
+             keyserver = parse_keyserver_uri (pargs.r.ret_str,1,
+                                               configname,configlineno);
+             if (!keyserver)
+               log_error (_("could not parse keyserver URL\n"));
              else
-               free_keyserver_spec(keyserver);
-
+               free_keyserver_spec (keyserver);
+              
              opt.def_keyserver_url = pargs.r.ret_str;
            }
            break;
index 1d645ea..29db15a 100644 (file)
--- a/g10/gpg.h
+++ b/g10/gpg.h
 /* Object used to keep state locally to server.c . */
 struct server_local_s;
 
+/* Object used to keep state locally to call-dirmngr.c .  */
+struct dirmngr_local_s;
+typedef struct dirmngr_local_s *dirmngr_local_t;
+
 /* Object used to describe a keyblok node.  */
 typedef struct kbnode_struct *KBNODE;
 typedef struct kbnode_struct *kbnode_t;
@@ -58,7 +62,11 @@ typedef struct kbnode_struct *kbnode_t;
    gpg_init_default_ctrl(). */
 struct server_control_s
 {
+  /* Local data for server.c  */
   struct server_local_s *server_local;
+
+  /* Local data for call-dirmngr.c  */
+  dirmngr_local_t dirmngr_local;
 };
 
 
index cbf3c04..2b1b64e 100644 (file)
@@ -40,7 +40,7 @@ int keyserver_import_fprint (ctrl_t ctrl, const byte *fprint,size_t fprint_len,
 int keyserver_import_keyid (ctrl_t ctrl, u32 *keyid,
                             struct keyserver_spec *keyserver);
 int keyserver_refresh (ctrl_t ctrl, strlist_t users);
-int keyserver_search (ctrl_t ctrl, strlist_t tokens);
+gpg_error_t keyserver_search (ctrl_t ctrl, strlist_t tokens);
 int keyserver_fetch (ctrl_t ctrl, strlist_t urilist);
 int keyserver_import_cert (ctrl_t ctrl, const char *name,
                            unsigned char **fpr,size_t *fpr_len);
index 422e62e..60a117d 100644 (file)
@@ -45,6 +45,7 @@
 #ifdef USE_DNS_SRV
 #include "srv.h"
 #endif
+#include "membuf.h"
 
 
 #ifdef HAVE_W32_SYSTEM
@@ -236,9 +237,9 @@ keyserver_match(struct keyserver_spec *spec)
    parser any longer so it can be removed, or at least moved to
    keyserver/ksutil.c for limited use in gpgkeys_ldap or the like. */
 
-struct keyserver_spec *
-parse_keyserver_uri(const char *string,int require_scheme,
-                   const char *configname,unsigned int configlineno)
+keyserver_spec_t
+parse_keyserver_uri (const char *string,int require_scheme,
+                    const char *configname,unsigned int configlineno)
 {
   int assume_hkp=0;
   struct keyserver_spec *keyserver;
@@ -1530,6 +1531,7 @@ keyserver_spawn (ctrl_t ctrl,
   return ret;
 }
 
+
 static int 
 keyserver_work (ctrl_t ctrl,
                 enum ks_action action,strlist_t list,KEYDB_SEARCH_DESC *desc,
@@ -1538,23 +1540,16 @@ keyserver_work (ctrl_t ctrl,
 {
   int rc=0,ret=0;
 
-  if(!keyserver)
+  if (!keyserver)
     {
-      log_error(_("no keyserver known (use option --keyserver)\n"));
-      return G10ERR_BAD_URI;
+      log_error (_("no keyserver known (use option --keyserver)\n"));
+      return gpg_error (GPG_ERR_BAD_URI);
     }
 
-#ifdef DISABLE_KEYSERVER_HELPERS
-
-  log_error(_("external keyserver calls are not supported in this build\n"));
-  return G10ERR_KEYSERVER;
-
-#else
-  /* Spawn a handler */
 
   rc = keyserver_spawn (ctrl, action, list, desc, count,
                         &ret, fpr, fpr_len, keyserver);
-  if(ret)
+  if (ret)
     {
       switch(ret)
        {
@@ -1591,15 +1586,14 @@ keyserver_work (ctrl_t ctrl,
       return G10ERR_KEYSERVER;
     }
 
-  if(rc)
+  if (rc)
     {
-      log_error(_("keyserver communications error: %s\n"),g10_errstr(rc));
+      log_error (_("keyserver communications error: %s\n"),g10_errstr(rc));
 
       return rc;
     }
 
   return 0;
-#endif /* ! DISABLE_KEYSERVER_HELPERS*/
 }
 
 int 
@@ -1961,15 +1955,100 @@ keyserver_refresh (ctrl_t ctrl, strlist_t users)
   return rc;
 }
 
-int
+/* Search for keys on the keyservers.  The patterns are given in the
+   string list TOKENS.  */
+gpg_error_t
 keyserver_search (ctrl_t ctrl, strlist_t tokens)
 {
-  if (tokens)
-    return keyserver_work (ctrl, KS_SEARCH, tokens, NULL, 0,
-                           NULL, NULL, opt.keyserver);
-  return 0;
+  gpg_error_t err;
+  int rc=0,ret=0;
+  char *searchstr;
+
+  /* FIXME:  WORK IN PROGRESS */
+  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);
+    }
+
+      /* switch(ret) */
+      /*   { */
+      /*   case KEYSERVER_SCHEME_NOT_FOUND: */
+      /*     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); */
+      /*     break; */
+
+      /*   case KEYSERVER_TIMEOUT: */
+      /*     log_error(_("keyserver timed out\n")); */
+      /*     break; */
+
+      /*   case KEYSERVER_INTERNAL_ERROR: */
+      /*   default: */
+      /*     log_error(_("keyserver internal error\n")); */
+      /*     break; */
+      /*   } */
+
+      /* return gpg_error (GPG_ERR_KEYSERVER); */
+
+
+  /* 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); */
+
+  /* Which keys do we want?  Remember that the gpgkeys_ program
+     is going to lump these together into a search string. */
+  {
+    membuf_t mb;
+    strlist_t item;
+
+    init_membuf (&mb, 1024);
+    for (item = tokens; item; item = item->next)
+    {
+      if (item != tokens)
+        put_membuf (&mb, " ", 1);
+      put_membuf_str (&mb, item->d);
+    }
+    put_membuf (&mb, "", 1); /* Append Nul.  */
+    searchstr = get_membuf (&mb, NULL);
+    if (!searchstr)
+      {
+        err = gpg_error_from_syserror ();
+      }
+  }
+  log_info (_("searching for \"%s\" from %s\n"), searchstr, keyserver->uri);
+
+  {
+    estream_t fp;
+    err = gpg_dirmngr_ks_search (ctrl, searchstr, &fp);
+    
+    keyserver_search_prompt (ctrl, fp,searchstr);
+  }
+
+ leave:
+  xfree(line);
+  xfree(searchstr);
+
+
+  *prog=exec_finish(spawn);
+
+  return ret;
 }
 
+
 int
 keyserver_fetch (ctrl_t ctrl, strlist_t urilist)
 {
index 28a2805..cd01406 100644 (file)
@@ -1,6 +1,6 @@
 /* options.h
  * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006,
- *               2007, 2010 Free Software Foundation, Inc.
+ *               2007, 2010, 2011 Free Software Foundation, Inc.
  *
  * This file is part of GnuPG.
  *
 #endif
 #endif
 
+/* Declaration of a keyserver spec type.  The definition is found in
+   ../common/keyserver.h.  */
+struct keyserver_spec;
+typedef struct keyserver_spec *keyserver_spec_t;
+
+
+/* Global options for GPG.  */
 EXTERN_UNLESS_MAIN_MODULE
 struct
 {
@@ -130,22 +137,7 @@ struct
   int not_dash_escaped;
   int escape_from;
   int lock_once;
-  struct keyserver_spec
-  {
-    char *uri;
-    char *scheme;
-    char *auth;
-    char *host;
-    char *port;
-    char *path;
-    char *opaque;
-    strlist_t options;
-    struct
-    {
-      unsigned int direct_uri:1;
-    } flags;
-    struct keyserver_spec *next;
-  } *keyserver;
+  keyserver_spec_t keyserver;  /* The list of configured keyservers.  */
   struct
   {
     unsigned int options;
@@ -245,7 +237,7 @@ struct
       AKL_KEYSERVER,
       AKL_SPEC
     } type;
-    struct keyserver_spec *spec;
+    keyserver_spec_t spec;
     struct akl *next;
   } *auto_key_locate;
 
index a44f091..dd21290 100644 (file)
@@ -687,7 +687,7 @@ main(int argc,char *argv[])
       goto fail;
     }
 
-  if(ks_strcasecmp(opt->scheme,"hkps")==0)
+  if(ascii_strcasecmp(opt->scheme,"hkps")==0)
     {
       proto="https";
       port="443";