summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.gitignore8
-rw-r--r--common/ChangeLog14
-rw-r--r--common/http.c49
-rw-r--r--common/http.h14
-rw-r--r--common/keyserver.h24
-rw-r--r--common/util.h3
-rw-r--r--dirmngr/ChangeLog20
-rw-r--r--dirmngr/Makefile.am3
-rw-r--r--dirmngr/crlfetch.c4
-rw-r--r--dirmngr/dirmngr.h14
-rw-r--r--dirmngr/ks-action.c90
-rw-r--r--dirmngr/ks-action.h26
-rw-r--r--dirmngr/ks-engine-hkp.c258
-rw-r--r--dirmngr/ks-engine.h32
-rw-r--r--dirmngr/server.c153
-rw-r--r--g10/ChangeLog15
-rw-r--r--g10/Makefile.am1
-rw-r--r--g10/call-dirmngr.c256
-rw-r--r--g10/call-dirmngr.h26
-rw-r--r--g10/gpg.c35
-rw-r--r--g10/gpg.h8
-rw-r--r--g10/keyserver-internal.h2
-rw-r--r--g10/keyserver.c123
-rw-r--r--g10/options.h28
-rw-r--r--keyserver/gpgkeys_hkp.c2
25 files changed, 1115 insertions, 93 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 000000000..9bd59abfa
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,8 @@
+Makefile.in
+aclocal.m4
+autom4te.cache/
+configure
+config.h.in
+config.h
+common/audit-events.h
+common/status-codes.h
diff --git a/common/ChangeLog b/common/ChangeLog
index de96b8dc8..1484ae0eb 100644
--- a/common/ChangeLog
+++ b/common/ChangeLog
@@ -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
@@ -2251,7 +2263,7 @@
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
diff --git a/common/http.c b/common/http.c
index 1d84051a2..3d7c463b5 100644
--- a/common/http.c
+++ b/common/http.c
@@ -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)
/*
* 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;
}
diff --git a/common/http.h b/common/http.h
index ac9cb1513..aaa2d3a13 100644
--- a/common/http.h
+++ b/common/http.h
@@ -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);
diff --git a/common/keyserver.h b/common/keyserver.h
index 6455e8c57..d286f7da7 100644
--- a/common/keyserver.h
+++ b/common/keyserver.h
@@ -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.
*
@@ -39,4 +39,26 @@
/* 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*/
diff --git a/common/util.h b/common/util.h
index 7c58b15c5..1f7964fc4 100644
--- a/common/util.h
+++ b/common/util.h
@@ -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
diff --git a/dirmngr/ChangeLog b/dirmngr/ChangeLog
index 2c208755d..f5b3dea12 100644
--- a/dirmngr/ChangeLog
+++ b/dirmngr/ChangeLog
@@ -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.
@@ -1488,7 +1505,8 @@
[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
diff --git a/dirmngr/Makefile.am b/dirmngr/Makefile.am
index 5b1fe30be..8c41c53b2 100644
--- a/dirmngr/Makefile.am
+++ b/dirmngr/Makefile.am
@@ -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
diff --git a/dirmngr/crlfetch.c b/dirmngr/crlfetch.c
index 83897a698..057742389 100644
--- a/dirmngr/crlfetch.c
+++ b/dirmngr/crlfetch.c
@@ -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)
{
diff --git a/dirmngr/dirmngr.h b/dirmngr/dirmngr.h
index 01478a64f..1ba90b8ed 100644
--- a/dirmngr/dirmngr.h
+++ b/dirmngr/dirmngr.h
@@ -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
index 000000000..5ad4b1810
--- /dev/null
+++ b/dirmngr/ks-action.c
@@ -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
index 000000000..57903398d
--- /dev/null
+++ b/dirmngr/ks-action.h
@@ -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
index 000000000..356f64348
--- /dev/null
+++ b/dirmngr/ks-engine-hkp.c
@@ -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
index 000000000..f68782f49
--- /dev/null
+++ b/dirmngr/ks-engine.h
@@ -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*/
diff --git a/dirmngr/server.c b/dirmngr/server.c
index 11ba1fb87..40e8dabd4 100644
--- a/dirmngr/server.c
+++ b/dirmngr/server.c
@@ -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);
}
+
+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);
+}
+
+
+
+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);
+}
+
+
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)
{
diff --git a/g10/ChangeLog b/g10/ChangeLog
index 0c8cbd418..1be035d39 100644
--- a/g10/ChangeLog
+++ b/g10/ChangeLog
@@ -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.
diff --git a/g10/Makefile.am b/g10/Makefile.am
index c8fc4821e..475529c4e 100644
--- a/g10/Makefile.am
+++ b/g10/Makefile.am
@@ -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
index 000000000..a18eb64b0
--- /dev/null
+++ b/g10/call-dirmngr.c
@@ -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;
+};
+
+
+
+/* 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);
+}
+
+
+
+
+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
index 000000000..fa579ad5c
--- /dev/null
+++ b/g10/call-dirmngr.h
@@ -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*/
diff --git a/g10/gpg.c b/g10/gpg.c
index 4a17b2905..1866c1cc8 100644
--- 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;
diff --git a/g10/gpg.h b/g10/gpg.h
index 1d645ea25..29db15a45 100644
--- a/g10/gpg.h
+++ b/g10/gpg.h
@@ -48,6 +48,10 @@
/* 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;
};
diff --git a/g10/keyserver-internal.h b/g10/keyserver-internal.h
index cbf3c04a8..2b1b64e35 100644
--- a/g10/keyserver-internal.h
+++ b/g10/keyserver-internal.h
@@ -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);
diff --git a/g10/keyserver.c b/g10/keyserver.c
index 422e62e78..60a117d2e 100644
--- a/g10/keyserver.c
+++ b/g10/keyserver.c
@@ -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)
{
diff --git a/g10/options.h b/g10/options.h
index 28a2805a9..cd0140651 100644
--- a/g10/options.h
+++ b/g10/options.h
@@ -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.
*
@@ -35,6 +35,13 @@
#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;
diff --git a/keyserver/gpgkeys_hkp.c b/keyserver/gpgkeys_hkp.c
index a44f09131..dd2129051 100644
--- a/keyserver/gpgkeys_hkp.c
+++ b/keyserver/gpgkeys_hkp.c
@@ -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";