aboutsummaryrefslogtreecommitdiffstats
path: root/dirmngr
diff options
context:
space:
mode:
Diffstat (limited to 'dirmngr')
-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
9 files changed, 590 insertions, 10 deletions
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 <[email protected]>
+
+ * 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 <[email protected]>
+
+ * 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 <[email protected]>
* 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)
{