aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorWerner Koch <[email protected]>2011-01-20 13:12:53 +0000
committerWerner Koch <[email protected]>2011-01-20 13:12:53 +0000
commit7f32d88ed1b81719e0cda11710fc66745deee6e2 (patch)
tree569ba918414268e5cee2eebaa7de3e23b6bbe277
parentKeyserver search and get basically works again. (diff)
downloadgnupg-7f32d88ed1b81719e0cda11710fc66745deee6e2.tar.gz
gnupg-7f32d88ed1b81719e0cda11710fc66745deee6e2.zip
All standard keyserver commands are now using dirmngr.
Diffstat (limited to '')
-rw-r--r--common/ChangeLog11
-rw-r--r--common/b64dec.c32
-rw-r--r--common/b64enc.c22
-rw-r--r--common/http.c45
-rw-r--r--common/http.h1
-rw-r--r--common/util.h1
-rw-r--r--dirmngr/ChangeLog8
-rw-r--r--dirmngr/ks-action.c35
-rw-r--r--dirmngr/ks-action.h1
-rw-r--r--dirmngr/ks-engine-hkp.c190
-rw-r--r--dirmngr/ks-engine.h2
-rw-r--r--dirmngr/server.c71
-rw-r--r--g10/ChangeLog13
-rw-r--r--g10/call-dirmngr.c173
-rw-r--r--g10/call-dirmngr.h2
-rw-r--r--g10/export.c54
-rw-r--r--g10/keyserver.c748
-rw-r--r--g10/main.h4
-rw-r--r--keyserver/ChangeLog6
-rw-r--r--keyserver/gpgkeys_hkp.c3
20 files changed, 688 insertions, 734 deletions
diff --git a/common/ChangeLog b/common/ChangeLog
index 3ce80cb1a..3b7506492 100644
--- a/common/ChangeLog
+++ b/common/ChangeLog
@@ -1,3 +1,14 @@
+2011-01-20 Werner Koch <[email protected]>
+
+ * util.h (struct b64state): Add field LASTERR.
+ * b64enc.c (enc_start, b64enc_write, b64enc_finish): Handle
+ LASTERR. This is to make sure that we don't leak strduped data.
+ * b64dec.c (b64dec_start, b64dec_proc, b64dec_finish): Ditto.
+
+ * http.c (escape_data): New.
+ (insert_escapes): Implement using escape_data.
+ (http_escape_data): New.
+
2011-01-18 Werner Koch <[email protected]>
* iobuf.c (file_es_filter_ctx_t): New.
diff --git a/common/b64dec.c b/common/b64dec.c
index af223aef2..137dd7216 100644
--- a/common/b64dec.c
+++ b/common/b64dec.c
@@ -1,5 +1,5 @@
/* b64dec.c - Simple Base64 decoder.
- * Copyright (C) 2008 Free Software Foundation, Inc.
+ * Copyright (C) 2008, 2011 Free Software Foundation, Inc.
*
* This file is part of GnuPG.
*
@@ -72,16 +72,19 @@ b64dec_start (struct b64state *state, const char *title)
if (title)
{
if (!strncmp (title, "PGP", 3) && (!title[3] || title[3] == ' '))
- return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
-
- state->title = xtrystrdup (title);
- if (!state->title)
- return gpg_error_from_syserror ();
- state->idx = s_init;
+ state->lasterr = gpg_error (GPG_ERR_NOT_IMPLEMENTED);
+ else
+ {
+ state->title = xtrystrdup (title);
+ if (!state->title)
+ state->lasterr = gpg_error_from_syserror ();
+ else
+ state->idx = s_init;
+ }
}
else
state->idx = s_b64_0;
- return 0;
+ return state->lasterr;
}
@@ -96,12 +99,18 @@ b64dec_proc (struct b64state *state, void *buffer, size_t length,
int pos = state->quad_count;
char *d, *s;
+ if (state->lasterr)
+ return state->lasterr;
+
if (state->stop_seen)
{
*r_nbytes = 0;
- return gpg_error (GPG_ERR_EOF);
+ state->lasterr = gpg_error (GPG_ERR_EOF);
+ xfree (state->title);
+ state->title = NULL;
+ return state->lasterr;
}
-
+
for (s=d=buffer; length && !state->stop_seen; length--, s++)
{
switch (ds)
@@ -210,6 +219,9 @@ b64dec_proc (struct b64state *state, void *buffer, size_t length,
gpg_error_t
b64dec_finish (struct b64state *state)
{
+ if (state->lasterr)
+ return state->lasterr;
+
xfree (state->title);
state->title = NULL;
return state->invalid_encoding? gpg_error(GPG_ERR_BAD_DATA): 0;
diff --git a/common/b64enc.c b/common/b64enc.c
index 1e277f4cb..5d616198e 100644
--- a/common/b64enc.c
+++ b/common/b64enc.c
@@ -1,5 +1,6 @@
/* b64enc.c - Simple Base64 encoder.
- * Copyright (C) 2001, 2003, 2004, 2008, 2010 Free Software Foundation, Inc.
+ * Copyright (C) 2001, 2003, 2004, 2008, 2010,
+ * 2011 Free Software Foundation, Inc.
*
* This file is part of GnuPG.
*
@@ -143,6 +144,7 @@ enc_start (struct b64state *state, FILE *fp, estream_t stream,
memset (state, 0, sizeof *state);
state->fp = fp;
state->stream = stream;
+ state->lasterr = 0;
if (title && !*title)
state->flags |= B64ENC_NO_LINEFEEDS;
else if (title)
@@ -154,9 +156,9 @@ enc_start (struct b64state *state, FILE *fp, estream_t stream,
}
state->title = xtrystrdup (title);
if (!state->title)
- return gpg_error_from_syserror ();
+ state->lasterr = gpg_error_from_syserror ();
}
- return 0;
+ return state->lasterr;
}
@@ -203,6 +205,8 @@ b64enc_write (struct b64state *state, const void *buffer, size_t nbytes)
int idx, quad_count;
const unsigned char *p;
+ if (state->lasterr)
+ return state->lasterr;
if (!nbytes)
{
@@ -285,7 +289,13 @@ b64enc_write (struct b64state *state, const void *buffer, size_t nbytes)
return 0;
write_error:
- return gpg_error_from_syserror ();
+ state->lasterr = gpg_error_from_syserror ();
+ if (state->title)
+ {
+ xfree (state->title);
+ state->title = NULL;
+ }
+ return state->lasterr;
}
@@ -297,6 +307,9 @@ b64enc_finish (struct b64state *state)
int idx, quad_count;
char tmp[4];
+ if (state->lasterr)
+ return state->lasterr;
+
if (!(state->flags & B64ENC_DID_HEADER))
goto cleanup;
@@ -404,6 +417,7 @@ b64enc_finish (struct b64state *state)
}
state->fp = NULL;
state->stream = NULL;
+ state->lasterr = err;
return err;
}
diff --git a/common/http.c b/common/http.c
index 3d7c463b5..4d3536114 100644
--- a/common/http.c
+++ b/common/http.c
@@ -1,6 +1,6 @@
/* http.c - HTTP protocol handler
- * Copyright (C) 1999, 2001, 2002, 2003, 2004, 2006,
- * 2009, 2010 Free Software Foundation, Inc.
+ * Copyright (C) 1999, 2001, 2002, 2003, 2004, 2006, 2009, 2010,
+ * 2011 Free Software Foundation, Inc.
*
* This file is part of GnuPG.
*
@@ -742,14 +742,14 @@ remove_escapes (char *string)
}
-static int
-insert_escapes (char *buffer, const char *string,
- const char *special)
+static size_t
+escape_data (char *buffer, const void *data, size_t datalen,
+ const char *special)
{
- const unsigned char *s = (const unsigned char*)string;
- int n = 0;
+ const unsigned char *s;
+ size_t n = 0;
- for (; *s; s++)
+ for (s = data; datalen; s++, datalen--)
{
if (strchr (VALID_URI_CHARS, *s) && !strchr (special, *s))
{
@@ -771,6 +771,14 @@ insert_escapes (char *buffer, const char *string,
}
+static int
+insert_escapes (char *buffer, const char *string,
+ const char *special)
+{
+ return escape_data (buffer, string, strlen (string), special);
+}
+
+
/* Allocate a new string from STRING using standard HTTP escaping as
well as escaping of characters given in SPECIALS. A common pattern
for SPECIALS is "%;?&=". However it depends on the needs, for
@@ -792,6 +800,27 @@ http_escape_string (const char *string, const char *specials)
return buf;
}
+/* Allocate a new string from {DATA,DATALEN} using standard HTTP
+ escaping as well as escaping of characters given in SPECIALS. A
+ common pattern for SPECIALS is "%;?&=". However it depends on the
+ needs, for example "+" and "/: often needs to be escaped too.
+ Returns NULL on failure and sets ERRNO. */
+char *
+http_escape_data (const void *data, size_t datalen, const char *specials)
+{
+ int n;
+ char *buf;
+
+ n = escape_data (NULL, data, datalen, specials);
+ buf = xtrymalloc (n+1);
+ if (buf)
+ {
+ escape_data (buf, data, datalen, specials);
+ buf[n] = 0;
+ }
+ return buf;
+}
+
static uri_tuple_t
diff --git a/common/http.h b/common/http.h
index aaa2d3a13..7eecbc004 100644
--- a/common/http.h
+++ b/common/http.h
@@ -117,6 +117,7 @@ unsigned int http_get_status_code (http_t hd);
const char *http_get_header (http_t hd, const char *name);
char *http_escape_string (const char *string, const char *specials);
+char *http_escape_data (const void *data, size_t datalen, const char *specials);
#endif /*GNUPG_COMMON_HTTP_H*/
diff --git a/common/util.h b/common/util.h
index 1f7964fc4..f06701fc0 100644
--- a/common/util.h
+++ b/common/util.h
@@ -150,6 +150,7 @@ struct b64state
u32 crc;
int stop_seen:1;
int invalid_encoding:1;
+ gpg_error_t lasterr;
};
gpg_error_t b64enc_start (struct b64state *state, FILE *fp, const char *title);
diff --git a/dirmngr/ChangeLog b/dirmngr/ChangeLog
index f5b3dea12..47c7fe012 100644
--- a/dirmngr/ChangeLog
+++ b/dirmngr/ChangeLog
@@ -1,13 +1,9 @@
-2011-01-06 Werner Koch <[email protected]>
+2011-01-20 Werner Koch <[email protected]>
* server.c (release_ctrl_keyservers): New.
- (cmd_keyserver): New.
-
+ (cmd_keyserver, cmd_ks_seach, cmd_ks_get, cmd_ks_put): 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.
diff --git a/dirmngr/ks-action.c b/dirmngr/ks-action.c
index f376c27d1..fd2a2b568 100644
--- a/dirmngr/ks-action.c
+++ b/dirmngr/ks-action.c
@@ -90,7 +90,7 @@ ks_action_search (ctrl_t ctrl, strlist_t patterns, estream_t outfp)
}
-/* Get the requested keys (macthing PATTERNS) using all configured
+/* Get the requested keys (matching PATTERNS) using all configured
keyservers and write the result to the provided output stream. */
gpg_error_t
ks_action_get (ctrl_t ctrl, strlist_t patterns, estream_t outfp)
@@ -148,3 +148,36 @@ ks_action_get (ctrl_t ctrl, strlist_t patterns, estream_t outfp)
return err;
}
+
+
+/* Send an OpenPGP key to all keyservers. The key in {DATA,DATALEN}
+ is expected in OpenPGP binary transport format. */
+gpg_error_t
+ks_action_put (ctrl_t ctrl, const void *data, size_t datalen)
+{
+ gpg_error_t err = 0;
+ gpg_error_t first_err = 0;
+ int any = 0;
+ uri_item_t uri;
+
+ for (uri = ctrl->keyservers; !err && uri; uri = uri->next)
+ {
+ if (uri->parsed_uri->is_http)
+ {
+ any = 1;
+ err = ks_hkp_put (ctrl, uri->parsed_uri, data, datalen);
+ if (err)
+ {
+ first_err = err;
+ err = 0;
+ }
+ }
+ }
+
+ if (!any)
+ err = gpg_error (GPG_ERR_NO_KEYSERVER);
+ else if (!err && first_err)
+ err = first_err; /* fixme: Do we really want to do that? */
+ return err;
+}
+
diff --git a/dirmngr/ks-action.h b/dirmngr/ks-action.h
index 4a92ed1a4..b3bd3fc46 100644
--- a/dirmngr/ks-action.h
+++ b/dirmngr/ks-action.h
@@ -22,6 +22,7 @@
gpg_error_t ks_action_search (ctrl_t ctrl, strlist_t patterns, estream_t outfp);
gpg_error_t ks_action_get (ctrl_t ctrl, strlist_t patterns, estream_t outfp);
+gpg_error_t ks_action_put (ctrl_t ctrl, const void *data, size_t datalen);
#endif /*DIRMNGR_KS_ACTION_H*/
diff --git a/dirmngr/ks-engine-hkp.c b/dirmngr/ks-engine-hkp.c
index 662e9e4cb..e25900ae1 100644
--- a/dirmngr/ks-engine-hkp.c
+++ b/dirmngr/ks-engine-hkp.c
@@ -38,9 +38,12 @@
/* Send an HTTP request. On success returns an estream object at
- R_FP. HOSTPORTSTR is only used for diagnostics. */
+ R_FP. HOSTPORTSTR is only used for diagnostics. If POST_CB is not
+ NULL a post request is used and that callback is called to allow
+ writing the post data. */
static gpg_error_t
send_request (ctrl_t ctrl, const char *request, const char *hostportstr,
+ gpg_error_t (*post_cb)(void *, http_t), void *post_cb_value,
estream_t *r_fp)
{
gpg_error_t err;
@@ -51,7 +54,9 @@ send_request (ctrl_t ctrl, const char *request, const char *hostportstr,
*r_fp = NULL;
once_more:
- err = http_open (&http, HTTP_REQ_GET, request,
+ err = http_open (&http,
+ post_cb? HTTP_REQ_POST : HTTP_REQ_GET,
+ request,
/* fixme: AUTH */ NULL,
0,
/* fixme: proxy*/ NULL,
@@ -65,9 +70,14 @@ send_request (ctrl_t ctrl, const char *request, const char *hostportstr,
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 (post_cb)
+ err = post_cb (post_cb_value, http);
+ if (!err)
+ {
+ http_start_data (http);
+ if (es_ferror (fp))
+ err = gpg_error_from_syserror ();
+ }
}
if (err)
{
@@ -135,19 +145,76 @@ send_request (ctrl_t ctrl, const char *request, const char *hostportstr,
/* 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_buffer);
return err;
}
+static gpg_error_t
+armor_data (char **r_string, const void *data, size_t datalen)
+{
+ gpg_error_t err;
+ struct b64state b64state;
+ estream_t fp;
+ long length;
+ char *buffer;
+ size_t nread;
+
+ *r_string = NULL;
+
+ fp = es_fopenmem (0, "rw");
+ if (!fp)
+ return gpg_error_from_syserror ();
+ if ((err=b64enc_start_es (&b64state, fp, "PGP PUBLIC KEY BLOCK"))
+ || (err=b64enc_write (&b64state, data, datalen))
+ || (err = b64enc_finish (&b64state)))
+ {
+ es_fclose (fp);
+ return err;
+ }
+
+ /* FIXME: To avoid the extra buffer allocation estream should
+ provide a function to snatch the internal allocated memory from
+ such a memory stream. */
+ length = es_ftell (fp);
+ if (length < 0)
+ {
+ err = gpg_error_from_syserror ();
+ es_fclose (fp);
+ return err;
+ }
+
+ buffer = xtrymalloc (length+1);
+ if (!buffer)
+ {
+ err = gpg_error_from_syserror ();
+ es_fclose (fp);
+ return err;
+ }
+
+ es_rewind (fp);
+ if (es_read (fp, buffer, length, &nread))
+ {
+ err = gpg_error_from_syserror ();
+ es_fclose (fp);
+ return err;
+ }
+ buffer[nread] = 0;
+ es_fclose (fp);
+
+ *r_string = buffer;
+ return 0;
+}
+
+
+
+
/* 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
@@ -251,7 +318,7 @@ ks_hkp_search (ctrl_t ctrl, parsed_uri_t uri, const char *pattern,
}
/* Send the request. */
- err = send_request (ctrl, request, hostport, &fp);
+ err = send_request (ctrl, request, hostport, NULL, NULL, &fp);
if (err)
goto leave;
@@ -368,7 +435,7 @@ ks_hkp_get (ctrl_t ctrl, parsed_uri_t uri, const char *keyspec, estream_t *r_fp)
}
/* Send the request. */
- err = send_request (ctrl, request, hostport, &fp);
+ err = send_request (ctrl, request, hostport, NULL, NULL, &fp);
if (err)
goto leave;
@@ -384,3 +451,108 @@ ks_hkp_get (ctrl_t ctrl, parsed_uri_t uri, const char *keyspec, estream_t *r_fp)
}
+
+
+/* Callback parameters for put_post_cb. */
+struct put_post_parm_s
+{
+ char *datastring;
+};
+
+
+/* Helper for ks_hkp_put. */
+static gpg_error_t
+put_post_cb (void *opaque, http_t http)
+{
+ struct put_post_parm_s *parm = opaque;
+ gpg_error_t err = 0;
+ estream_t fp;
+ size_t len;
+
+ fp = http_get_write_ptr (http);
+ len = strlen (parm->datastring);
+
+ es_fprintf (fp,
+ "Content-Type: application/x-www-form-urlencoded\r\n"
+ "Content-Length: %zu\r\n", len+8 /* 8 is for "keytext" */);
+ http_start_data (http);
+ if (es_fputs ("keytext=", fp) || es_write (fp, parm->datastring, len, NULL))
+ err = gpg_error_from_syserror ();
+ return err;
+}
+
+
+/* Send the key in {DATA,DATALEN} to the keyserver identified by URI. */
+gpg_error_t
+ks_hkp_put (ctrl_t ctrl, parsed_uri_t uri, const void *data, size_t datalen)
+{
+ gpg_error_t err;
+ const char *scheme;
+ char portstr[10];
+ char *hostport = NULL;
+ char *request = NULL;
+ estream_t fp = NULL;
+ struct put_post_parm_s parm;
+ char *armored = NULL;
+
+ parm.datastring = NULL;
+
+ /* 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 ()*/
+
+ err = armor_data (&armored, data, datalen);
+ if (err)
+ goto leave;
+
+ parm.datastring = http_escape_string (armored, EXTRA_ESCAPE_CHARS);
+ if (!parm.datastring)
+ {
+ err = gpg_error_from_syserror ();
+ goto leave;
+ }
+ xfree (armored);
+ armored = NULL;
+
+ /* Build the request string. */
+ hostport = strconcat (scheme, "://",
+ *uri->host? uri->host: "localhost",
+ ":", portstr, NULL);
+ if (!hostport)
+ {
+ err = gpg_error_from_syserror ();
+ goto leave;
+ }
+
+ request = strconcat (hostport, "/pks/add", NULL);
+ if (!request)
+ {
+ err = gpg_error_from_syserror ();
+ goto leave;
+ }
+
+ /* Send the request. */
+ err = send_request (ctrl, request, hostport, put_post_cb, &parm, &fp);
+ if (err)
+ goto leave;
+
+ leave:
+ es_fclose (fp);
+ xfree (parm.datastring);
+ xfree (armored);
+ xfree (request);
+ xfree (hostport);
+ return err;
+}
diff --git a/dirmngr/ks-engine.h b/dirmngr/ks-engine.h
index 4b26662e8..304fc4d1a 100644
--- a/dirmngr/ks-engine.h
+++ b/dirmngr/ks-engine.h
@@ -28,6 +28,8 @@ gpg_error_t ks_hkp_search (ctrl_t ctrl, parsed_uri_t uri, const char *pattern,
estream_t *r_fp);
gpg_error_t ks_hkp_get (ctrl_t ctrl, parsed_uri_t uri,
const char *keyspec, estream_t *r_fp);
+gpg_error_t ks_hkp_put (ctrl_t ctrl, parsed_uri_t uri,
+ const void *data, size_t datalen);
diff --git a/dirmngr/server.c b/dirmngr/server.c
index 5d61da898..fc7b22989 100644
--- a/dirmngr/server.c
+++ b/dirmngr/server.c
@@ -47,6 +47,12 @@
something reasonable. */
#define MAX_CERT_LENGTH (8*1024)
+/* The same goes for OpenPGP keyblocks, but here we need to allow for
+ much longer blocks; a 200k keyblock is not too unusual for keys
+ with a lot of signatures (e.g. 0x5b0358a2). */
+#define MAX_KEYBLOCK_LENGTH (512*1024)
+
+
#define PARM_ERROR(t) assuan_set_error (ctx, \
gpg_error (GPG_ERR_ASS_PARAMETER), (t))
#define set_error(e,t) assuan_set_error (ctx, gpg_error (e), (t))
@@ -1535,6 +1541,70 @@ cmd_ks_get (assuan_context_t ctx, char *line)
}
+
+static const char hlp_ks_put[] =
+ "KS_PUT\n"
+ "\n"
+ "Send a key to the configured OpenPGP keyservers. The actual key material\n"
+ "is then requested by Dirmngr using\n"
+ "\n"
+ " INQUIRE KEYBLOCK\n"
+ "\n"
+ "The client shall respond with a binary version of the keyblock. For LDAP\n"
+ "keyservers Dirmngr may ask for meta information of the provided keyblock\n"
+ "using:\n"
+ "\n"
+ " INQUIRE KEYBLOCK_INFO\n"
+ "\n"
+ "The client shall respond with a colon delimited info lines";
+static gpg_error_t
+cmd_ks_put (assuan_context_t ctx, char *line)
+{
+ ctrl_t ctrl = assuan_get_pointer (ctx);
+ gpg_error_t err;
+ unsigned char *value = NULL;
+ size_t valuelen;
+ unsigned char *info = NULL;
+ size_t infolen;
+
+ /* No options for now. */
+ line = skip_options (line);
+
+ /* Ask for the key material. */
+ err = assuan_inquire (ctx, "KEYBLOCK",
+ &value, &valuelen, MAX_KEYBLOCK_LENGTH);
+ if (err)
+ {
+ log_error (_("assuan_inquire failed: %s\n"), gpg_strerror (err));
+ goto leave;
+ }
+
+ if (!valuelen) /* No data returned; return a comprehensible error. */
+ {
+ err = gpg_error (GPG_ERR_MISSING_CERT);
+ goto leave;
+ }
+
+ /* Ask for the key meta data. Not actually needed for HKP servers
+ but we do it anyway test the client implementaion. */
+ err = assuan_inquire (ctx, "KEYBLOCK_INFO",
+ &info, &infolen, MAX_KEYBLOCK_LENGTH);
+ if (err)
+ {
+ log_error (_("assuan_inquire failed: %s\n"), gpg_strerror (err));
+ goto leave;
+ }
+
+ /* Send the key. */
+ err = ks_action_put (ctrl, value, valuelen);
+
+ leave:
+ xfree (info);
+ xfree (value);
+ return leave_cmd (ctx, err);
+}
+
+
static const char hlp_getinfo[] =
@@ -1672,6 +1742,7 @@ register_commands (assuan_context_t ctx)
{ "KEYSERVER", cmd_keyserver, hlp_keyserver },
{ "KS_SEARCH", cmd_ks_search, hlp_ks_search },
{ "KS_GET", cmd_ks_get, hlp_ks_get },
+ { "KS_PUT", cmd_ks_put, hlp_ks_put },
{ "GETINFO", cmd_getinfo, hlp_getinfo },
{ "KILLDIRMNGR",cmd_killdirmngr,hlp_killdirmngr },
{ "RELOADDIRMNGR",cmd_reloaddirmngr,hlp_reloaddirmngr },
diff --git a/g10/ChangeLog b/g10/ChangeLog
index 27f60fe24..a60d5d581 100644
--- a/g10/ChangeLog
+++ b/g10/ChangeLog
@@ -1,12 +1,11 @@
-2011-01-18 Werner Koch <[email protected]>
+2011-01-20 Werner Koch <[email protected]>
- * import.c (import_keys_es_stream): New.
-
-2011-01-14 Werner Koch <[email protected]>
+ * keyserver.c: Rewrite most stuff for use with dirmngr. Get rid
+ of all spawn code. Work work pending.
- * keyserver.c (parse_keyrec): Use trim_trailing_ws.
+ * export.c (export_pubkeys_buffer): New.
-2011-01-07 Werner Koch <[email protected]>
+ * import.c (import_keys_es_stream): New.
* call-dirmngr.c, call-dirmngr.h: New.
* gpg.h (server_control_s): Add DIRMNGR_LOCAL.
@@ -11671,7 +11670,7 @@ Thu Feb 12 22:24:42 1998 Werner Koch (wk@frodo)
Copyright 1998,1999,2000,2001,2002,2003,2004,2005,
- 2006,2007,2008,2009,2010 Free Software Foundation, Inc.
+ 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/g10/call-dirmngr.c b/g10/call-dirmngr.c
index 1816a72d3..f34b94b60 100644
--- a/g10/call-dirmngr.c
+++ b/g10/call-dirmngr.c
@@ -59,6 +59,16 @@ struct ks_get_parm_s
};
+/* Parameter structure used with the KS_PUT command. */
+struct ks_put_parm_s
+{
+ assuan_context_t ctx;
+ kbnode_t keyblock; /* The optional keyblock. */
+ const void *data; /* The key in OpenPGP binary format. */
+ size_t datalen; /* The length of DATA. */
+};
+
+
/* 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
@@ -436,3 +446,166 @@ gpg_dirmngr_ks_get (ctrl_t ctrl, char **pattern, estream_t *r_fp)
close_context (ctrl, ctx);
return err;
}
+
+
+
+/* Handle the KS_PUT inquiries. */
+static gpg_error_t
+ks_put_inq_cb (void *opaque, const char *line)
+{
+ struct ks_put_parm_s *parm = opaque;
+ gpg_error_t err = 0;
+
+ if (!strncmp (line, "KEYBLOCK", 8) && (line[8] == ' ' || !line[8]))
+ {
+ if (parm->data)
+ err = assuan_send_data (parm->ctx, parm->data, parm->datalen);
+ }
+ else if (!strncmp (line, "KEYBLOCK_INFO", 13) && (line[13]==' ' || !line[13]))
+ {
+ kbnode_t node;
+ estream_t fp;
+
+ /* Parse the keyblock and send info lines back to the server. */
+ fp = es_fopenmem (0, "rw");
+ if (!fp)
+ err = gpg_error_from_syserror ();
+
+ for (node = parm->keyblock; !err && node; node=node->next)
+ {
+ switch(node->pkt->pkttype)
+ {
+ case PKT_PUBLIC_KEY:
+ case PKT_PUBLIC_SUBKEY:
+ {
+ PKT_public_key *pk = node->pkt->pkt.public_key;
+
+ keyid_from_pk (pk, NULL);
+
+ es_fprintf (fp, "%s:%08lX%08lX:%u:%u:%u:%u:%s%s:\n",
+ node->pkt->pkttype==PKT_PUBLIC_KEY? "pub" : "sub",
+ (ulong)pk->keyid[0], (ulong)pk->keyid[1],
+ pk->pubkey_algo,
+ nbits_from_pk (pk),
+ pk->timestamp,
+ pk->expiredate,
+ pk->flags.revoked? "r":"",
+ pk->has_expired? "e":"");
+ }
+ break;
+
+ case PKT_USER_ID:
+ {
+ PKT_user_id *uid = node->pkt->pkt.user_id;
+ int r;
+
+ if (!uid->attrib_data)
+ {
+ es_fprintf (fp, "uid:");
+
+ /* Quote ':', '%', and any 8-bit characters. */
+ for (r=0; r < uid->len; r++)
+ {
+ if (uid->name[r] == ':'
+ || uid->name[r]== '%'
+ || (uid->name[r]&0x80))
+ es_fprintf (fp, "%%%02X", (byte)uid->name[r]);
+ else
+ es_putc (uid->name[r], fp);
+ }
+
+ es_fprintf (fp, ":%u:%u:%s%s:\n",
+ uid->created,uid->expiredate,
+ uid->is_revoked? "r":"",
+ uid->is_expired? "e":"");
+ }
+ }
+ break;
+
+ /* This bit is really for the benefit of people who
+ store their keys in LDAP servers. It makes it easy
+ to do queries for things like "all keys signed by
+ Isabella". */
+ case PKT_SIGNATURE:
+ {
+ PKT_signature *sig = node->pkt->pkt.signature;
+
+ if (IS_UID_SIG (sig))
+ {
+ es_fprintf (fp, "sig:%08lX%08lX:%X:%u:%u:\n",
+ (ulong)sig->keyid[0],(ulong)sig->keyid[1],
+ sig->sig_class, sig->timestamp,
+ sig->expiredate);
+ }
+ }
+ break;
+
+ default:
+ continue;
+ }
+ /* Given that the last operation was an es_fprintf we should
+ get the correct ERRNO if ferror indicates an error. */
+ if (es_ferror (fp))
+ err = gpg_error_from_syserror ();
+ }
+
+ /* Without an error and if we have an keyblock at all, send the
+ data back. */
+ if (!err && parm->keyblock)
+ {
+ int rc;
+ char buffer[512];
+ size_t nread;
+
+ es_rewind (fp);
+ while (!(rc=es_read (fp, buffer, sizeof buffer, &nread)) && nread)
+ {
+ err = assuan_send_data (parm->ctx, buffer, nread);
+ if (err)
+ break;
+ }
+ if (!err && rc)
+ err = gpg_error_from_syserror ();
+ }
+ es_fclose (fp);
+ }
+ else
+ return gpg_error (GPG_ERR_ASS_UNKNOWN_INQUIRE);
+
+ return err;
+}
+
+
+/* Send a key to the configured server. {DATA,DATLEN} contains the
+ key in OpenPGP binary transport format. If KEYBLOCK is not NULL it
+ has the internal representaion of that key; this is for example
+ used to convey meta data to LDAP keyservers. */
+gpg_error_t
+gpg_dirmngr_ks_put (ctrl_t ctrl, void *data, size_t datalen, kbnode_t keyblock)
+{
+ gpg_error_t err;
+ assuan_context_t ctx;
+ struct ks_put_parm_s parm;
+
+ memset (&parm, 0, sizeof parm);
+
+ /* We are going to parse the keyblock, thus we better make sure the
+ all information is readily available. */
+ if (keyblock)
+ merge_keys_and_selfsig (keyblock);
+
+ err = open_context (ctrl, &ctx);
+ if (err)
+ return err;
+
+ parm.ctx = ctx;
+ parm.keyblock = keyblock;
+ parm.data = data;
+ parm.datalen = datalen;
+
+ err = assuan_transact (ctx, "KS_PUT", NULL, NULL,
+ ks_put_inq_cb, &parm, NULL, NULL);
+
+ close_context (ctrl, ctx);
+ return err;
+}
diff --git a/g10/call-dirmngr.h b/g10/call-dirmngr.h
index c848a2902..9523bf568 100644
--- a/g10/call-dirmngr.h
+++ b/g10/call-dirmngr.h
@@ -25,6 +25,8 @@ gpg_error_t gpg_dirmngr_ks_search (ctrl_t ctrl, const char *searchstr,
gpg_error_t (*cb)(void*, char *),
void *cb_value);
gpg_error_t gpg_dirmngr_ks_get (ctrl_t ctrl, char *pattern[], estream_t *r_fp);
+gpg_error_t gpg_dirmngr_ks_put (ctrl_t ctrl, void *data, size_t datalen,
+ kbnode_t keyblock);
#endif /*GNUPG_G10_CALL_DIRMNGR_H*/
diff --git a/g10/export.c b/g10/export.c
index 91c6a73d7..43856ffea 100644
--- a/g10/export.c
+++ b/g10/export.c
@@ -114,6 +114,60 @@ export_pubkeys_stream (ctrl_t ctrl, iobuf_t out, strlist_t users,
return rc;
}
+
+/*
+ * Export a single key into a memory buffer.
+ */
+gpg_error_t
+export_pubkey_buffer (ctrl_t ctrl, const char *keyspec, unsigned int options,
+ kbnode_t *r_keyblock, void **r_data, size_t *r_datalen)
+{
+ gpg_error_t err;
+ iobuf_t iobuf;
+ int any;
+ strlist_t helplist;
+
+ *r_keyblock = NULL;
+ *r_data = NULL;
+ *r_datalen = 0;
+
+ helplist = NULL;
+ if (!add_to_strlist_try (&helplist, keyspec))
+ return gpg_error_from_syserror ();
+
+ iobuf = iobuf_temp ();
+ err = do_export_stream (ctrl, iobuf, helplist, 0, r_keyblock, options, &any);
+ if (!err && !any)
+ err = gpg_error (GPG_ERR_NOT_FOUND);
+ if (!err)
+ {
+ const void *src;
+ size_t datalen;
+
+ iobuf_flush_temp (iobuf);
+ src = iobuf_get_temp_buffer (iobuf);
+ datalen = iobuf_get_temp_length (iobuf);
+ if (!datalen)
+ err = gpg_error (GPG_ERR_NO_PUBKEY);
+ else if (!(*r_data = xtrymalloc (datalen)))
+ err = gpg_error_from_syserror ();
+ else
+ {
+ memcpy (*r_data, src, datalen);
+ *r_datalen = datalen;
+ }
+ }
+ iobuf_close (iobuf);
+ free_strlist (helplist);
+ if (err && *r_keyblock)
+ {
+ release_kbnode (*r_keyblock);
+ *r_keyblock = NULL;
+ }
+ return err;
+}
+
+
int
export_seckeys (ctrl_t ctrl, strlist_t users )
{
diff --git a/g10/keyserver.c b/g10/keyserver.c
index e560d4bfa..2f055ada5 100644
--- a/g10/keyserver.c
+++ b/g10/keyserver.c
@@ -111,13 +111,11 @@ static struct parse_options keyserver_opts[]=
{NULL,0,NULL,NULL}
};
-static int keyserver_work (ctrl_t ctrl, enum ks_action action,strlist_t list,
- KEYDB_SEARCH_DESC *desc,int count,
- unsigned char **fpr,size_t *fpr_len,
- struct keyserver_spec *keyserver);
static gpg_error_t keyserver_get (ctrl_t ctrl,
KEYDB_SEARCH_DESC *desc, int ndesc,
struct keyserver_spec *keyserver);
+static gpg_error_t keyserver_put (ctrl_t ctrl, strlist_t keyspecs,
+ struct keyserver_spec *keyserver);
/* Reasonable guess */
@@ -989,664 +987,6 @@ search_line_handler (void *opaque, char *line)
}
-/* We sometimes want to use a different gpgkeys_xxx for a given
- protocol (for example, ldaps is handled by gpgkeys_ldap). Map
- these here. */
-static const char *
-keyserver_typemap(const char *type)
-{
- if(strcmp(type,"ldaps")==0)
- return "ldap";
- else if(strcmp(type,"hkps")==0)
- return "hkp";
- else
- return type;
-}
-
-/* The PGP LDAP and the curl fetch-a-LDAP-object methodologies are
- sufficiently different that we can't use curl to do LDAP. */
-static int
-direct_uri_map(const char *scheme,unsigned int is_direct)
-{
- if(is_direct && strcmp(scheme,"ldap")==0)
- return 1;
-
- return 0;
-}
-
-#if GNUPG_MAJOR_VERSION == 2
-#define GPGKEYS_PREFIX "gpg2keys_"
-#else
-#define GPGKEYS_PREFIX "gpgkeys_"
-#endif
-#define GPGKEYS_CURL GPGKEYS_PREFIX "curl" EXEEXT
-#define GPGKEYS_PREFIX_LEN (strlen(GPGKEYS_CURL))
-#define KEYSERVER_ARGS_KEEP " -o \"%O\" \"%I\""
-#define KEYSERVER_ARGS_NOKEEP " -o \"%o\" \"%i\""
-
-static int
-keyserver_spawn (ctrl_t ctrl,
- enum ks_action action,strlist_t list,KEYDB_SEARCH_DESC *desc,
- int count,int *prog,unsigned char **fpr,size_t *fpr_len,
- struct keyserver_spec *keyserver)
-{
- int ret=0,i,gotversion=0,outofband=0;
- strlist_t temp;
- unsigned int maxlen,buflen;
- char *command,*end,*searchstr=NULL;
- byte *line=NULL;
- struct exec_info *spawn;
- const char *scheme;
- const char *libexecdir = gnupg_libexecdir ();
-
- assert(keyserver);
-
-#ifdef EXEC_TEMPFILE_ONLY
- opt.keyserver_options.options|=KEYSERVER_USE_TEMP_FILES;
-#endif
-
- /* Build the filename for the helper to execute */
- scheme=keyserver_typemap(keyserver->scheme);
-
-#ifdef DISABLE_KEYSERVER_PATH
- /* Destroy any path we might have. This is a little tricky,
- portability-wise. It's not correct to delete the PATH
- environment variable, as that may fall back to a system built-in
- PATH. Similarly, it is not correct to set PATH to the null
- string (PATH="") since this actually deletes the PATH environment
- variable under MinGW. The safest thing to do here is to force
- PATH to be GNUPG_LIBEXECDIR. All this is not that meaningful on
- Unix-like systems (since we're going to give a full path to
- gpgkeys_foo), but on W32 it prevents loading any DLLs from
- directories in %PATH%.
-
- After some more thinking about this we came to the conclusion
- that it is better to load the helpers from the directory where
- the program of this process lives. Fortunately Windows provides
- a way to retrieve this and our gnupg_libexecdir function has been
- modified to return just this. Setting the exec-path is not
- anymore required.
- set_exec_path(libexecdir);
- */
-#else
- if(opt.exec_path_set)
- {
- /* If exec-path was set, and DISABLE_KEYSERVER_PATH is
- undefined, then don't specify a full path to gpgkeys_foo, so
- that the PATH can work. */
- command=xmalloc(GPGKEYS_PREFIX_LEN+strlen(scheme)+3+strlen(EXEEXT)+1);
- command[0]='\0';
- }
- else
-#endif
- {
- /* Specify a full path to gpgkeys_foo. */
- command=xmalloc(strlen(libexecdir)+strlen(DIRSEP_S)+
- GPGKEYS_PREFIX_LEN+strlen(scheme)+3+strlen(EXEEXT)+1);
- strcpy(command,libexecdir);
- strcat(command,DIRSEP_S);
- }
-
- end=command+strlen(command);
-
- /* Build a path for the keyserver helper. If it is direct_uri
- (i.e. an object fetch and not a keyserver), then add "_uri" to
- the end to distinguish the keyserver helper from an object
- fetcher that can speak that protocol (this is a problem for
- LDAP). */
-
- strcat(command,GPGKEYS_PREFIX);
- strcat(command,scheme);
-
- /* This "_uri" thing is in case we need to call a direct handler
- instead of the keyserver handler. This lets us use gpgkeys_curl
- or gpgkeys_ldap_uri (we don't provide it, but a user might)
- instead of gpgkeys_ldap to fetch things like
- ldap://keyserver.pgp.com/o=PGP%20keys?pgpkey?sub?pgpkeyid=99242560 */
-
- if(direct_uri_map(scheme,keyserver->flags.direct_uri))
- strcat(command,"_uri");
-
- strcat(command,EXEEXT);
-
- /* Can we execute it? If not, try curl as our catchall. */
- if(path_access(command,X_OK)!=0)
- strcpy(end,GPGKEYS_CURL);
-
- if(opt.keyserver_options.options&KEYSERVER_USE_TEMP_FILES)
- {
- if(opt.keyserver_options.options&KEYSERVER_KEEP_TEMP_FILES)
- {
- command=xrealloc(command,strlen(command)+
- strlen(KEYSERVER_ARGS_KEEP)+1);
- strcat(command,KEYSERVER_ARGS_KEEP);
- }
- else
- {
- command=xrealloc(command,strlen(command)+
- strlen(KEYSERVER_ARGS_NOKEEP)+1);
- strcat(command,KEYSERVER_ARGS_NOKEEP);
- }
-
- ret=exec_write(&spawn,NULL,command,NULL,0,0);
- }
- else
- ret=exec_write(&spawn,command,NULL,NULL,0,0);
-
- xfree(command);
-
- if(ret)
- return ret;
-
- fprintf(spawn->tochild,
- "# This is a GnuPG %s keyserver communications file\n",VERSION);
- fprintf(spawn->tochild,"VERSION %d\n",KEYSERVER_PROTO_VERSION);
- fprintf(spawn->tochild,"PROGRAM %s\n",VERSION);
- fprintf(spawn->tochild,"SCHEME %s\n",keyserver->scheme);
-
- if(keyserver->opaque)
- fprintf(spawn->tochild,"OPAQUE %s\n",keyserver->opaque);
- else
- {
- if(keyserver->auth)
- fprintf(spawn->tochild,"AUTH %s\n",keyserver->auth);
-
- if(keyserver->host)
- fprintf(spawn->tochild,"HOST %s\n",keyserver->host);
-
- if(keyserver->port)
- fprintf(spawn->tochild,"PORT %s\n",keyserver->port);
-
- if(keyserver->path)
- fprintf(spawn->tochild,"PATH %s\n",keyserver->path);
- }
-
- /* Write global options */
-
- for(temp=opt.keyserver_options.other;temp;temp=temp->next)
- fprintf(spawn->tochild,"OPTION %s\n",temp->d);
-
- /* Write per-keyserver options */
-
- for(temp=keyserver->options;temp;temp=temp->next)
- fprintf(spawn->tochild,"OPTION %s\n",temp->d);
-
- switch(action)
- {
- case KS_GET:
- {
- fprintf(spawn->tochild,"COMMAND GET\n\n");
-
- /* Which keys do we want? */
-
- for(i=0;i<count;i++)
- {
- int quiet=0;
-
- if(desc[i].mode==KEYDB_SEARCH_MODE_FPR20)
- {
- int f;
-
- fprintf(spawn->tochild,"0x");
-
- for(f=0;f<MAX_FINGERPRINT_LEN;f++)
- fprintf(spawn->tochild,"%02X",desc[i].u.fpr[f]);
-
- fprintf(spawn->tochild,"\n");
- }
- else if(desc[i].mode==KEYDB_SEARCH_MODE_FPR16)
- {
- int f;
-
- fprintf(spawn->tochild,"0x");
-
- for(f=0;f<16;f++)
- fprintf(spawn->tochild,"%02X",desc[i].u.fpr[f]);
-
- fprintf(spawn->tochild,"\n");
- }
- else if(desc[i].mode==KEYDB_SEARCH_MODE_LONG_KID)
- fprintf(spawn->tochild,"0x%08lX%08lX\n",
- (ulong)desc[i].u.kid[0],
- (ulong)desc[i].u.kid[1]);
- else if(desc[i].mode==KEYDB_SEARCH_MODE_SHORT_KID)
- fprintf(spawn->tochild,"0x%08lX\n",
- (ulong)desc[i].u.kid[1]);
- else if(desc[i].mode==KEYDB_SEARCH_MODE_EXACT)
- {
- fprintf(spawn->tochild,"0x0000000000000000\n");
- quiet=1;
- }
- else if(desc[i].mode==KEYDB_SEARCH_MODE_NONE)
- continue;
- else
- BUG();
-
- if(!quiet)
- {
- if(keyserver->host)
- log_info(_("requesting key %s from %s server %s\n"),
- keystr_from_desc(&desc[i]),
- keyserver->scheme,keyserver->host);
- else
- log_info(_("requesting key %s from %s\n"),
- keystr_from_desc(&desc[i]),keyserver->uri);
- }
- }
-
- fprintf(spawn->tochild,"\n");
-
- break;
- }
-
- case KS_GETNAME:
- {
- strlist_t key;
-
- fprintf(spawn->tochild,"COMMAND GETNAME\n\n");
-
- /* Which names do we want? */
-
- for(key=list;key!=NULL;key=key->next)
- fprintf(spawn->tochild,"%s\n",key->d);
-
- fprintf(spawn->tochild,"\n");
-
- if(keyserver->host)
- log_info(_("searching for names from %s server %s\n"),
- keyserver->scheme,keyserver->host);
- else
- log_info(_("searching for names from %s\n"),keyserver->uri);
-
- break;
- }
-
- case KS_SEND:
- {
- strlist_t key;
-
- /* Note the extra \n here to send an empty keylist block */
- fprintf(spawn->tochild,"COMMAND SEND\n\n\n");
-
- for(key=list;key!=NULL;key=key->next)
- {
- armor_filter_context_t *afx;
- IOBUF buffer = iobuf_temp ();
- KBNODE block;
-
- temp=NULL;
- add_to_strlist(&temp,key->d);
-
- afx = new_armor_context ();
- afx->what = 1;
- /* Tell the armor filter to use Unix-style \n line
- endings, since we're going to fprintf this to a file
- that (on Win32) is open in text mode. The win32 stdio
- will transform the \n to \r\n and we'll end up with the
- proper line endings on win32. This is a no-op on
- Unix. */
- afx->eol[0] = '\n';
- push_armor_filter (afx, buffer);
- release_armor_context (afx);
-
- /* TODO: Remove Comment: lines from keys exported this
- way? */
-
- if(export_pubkeys_stream (ctrl, buffer,temp,&block,
- opt.keyserver_options.export_options)==-1)
- iobuf_close(buffer);
- else
- {
- KBNODE node;
-
- iobuf_flush_temp(buffer);
-
- merge_keys_and_selfsig(block);
-
- fprintf(spawn->tochild,"INFO %08lX%08lX BEGIN\n",
- (ulong)block->pkt->pkt.public_key->keyid[0],
- (ulong)block->pkt->pkt.public_key->keyid[1]);
-
- for(node=block;node;node=node->next)
- {
- switch(node->pkt->pkttype)
- {
- default:
- continue;
-
- case PKT_PUBLIC_KEY:
- case PKT_PUBLIC_SUBKEY:
- {
- PKT_public_key *pk=node->pkt->pkt.public_key;
-
- keyid_from_pk(pk,NULL);
-
- fprintf(spawn->tochild,"%sb:%08lX%08lX:%u:%u:%u:%u:",
- node->pkt->pkttype==PKT_PUBLIC_KEY?"pu":"su",
- (ulong)pk->keyid[0],(ulong)pk->keyid[1],
- pk->pubkey_algo,
- nbits_from_pk(pk),
- pk->timestamp,
- pk->expiredate);
-
- if(pk->flags.revoked)
- fprintf(spawn->tochild,"r");
- if(pk->has_expired)
- fprintf(spawn->tochild,"e");
-
- fprintf(spawn->tochild,"\n");
- }
- break;
-
- case PKT_USER_ID:
- {
- PKT_user_id *uid=node->pkt->pkt.user_id;
- int r;
-
- if(uid->attrib_data)
- continue;
-
- fprintf(spawn->tochild,"uid:");
-
- /* Quote ':', '%', and any 8-bit
- characters */
- for(r=0;r<uid->len;r++)
- {
- if(uid->name[r]==':' || uid->name[r]=='%'
- || uid->name[r]&0x80)
- fprintf(spawn->tochild,"%%%02X",
- (byte)uid->name[r]);
- else
- fprintf(spawn->tochild,"%c",uid->name[r]);
- }
-
- fprintf(spawn->tochild,":%u:%u:",
- uid->created,uid->expiredate);
-
- if(uid->is_revoked)
- fprintf(spawn->tochild,"r");
- if(uid->is_expired)
- fprintf(spawn->tochild,"e");
-
- fprintf(spawn->tochild,"\n");
- }
- break;
-
- /* This bit is really for the benefit of
- people who store their keys in LDAP
- servers. It makes it easy to do queries
- for things like "all keys signed by
- Isabella". */
- case PKT_SIGNATURE:
- {
- PKT_signature *sig=node->pkt->pkt.signature;
-
- if(!IS_UID_SIG(sig))
- continue;
-
- fprintf(spawn->tochild,"sig:%08lX%08lX:%X:%u:%u\n",
- (ulong)sig->keyid[0],(ulong)sig->keyid[1],
- sig->sig_class,sig->timestamp,
- sig->expiredate);
- }
- break;
- }
- }
-
- fprintf(spawn->tochild,"INFO %08lX%08lX END\n",
- (ulong)block->pkt->pkt.public_key->keyid[0],
- (ulong)block->pkt->pkt.public_key->keyid[1]);
-
- fprintf(spawn->tochild,"KEY %08lX%08lX BEGIN\n",
- (ulong)block->pkt->pkt.public_key->keyid[0],
- (ulong)block->pkt->pkt.public_key->keyid[1]);
- fwrite(iobuf_get_temp_buffer(buffer),
- iobuf_get_temp_length(buffer),1,spawn->tochild);
- fprintf(spawn->tochild,"KEY %08lX%08lX END\n",
- (ulong)block->pkt->pkt.public_key->keyid[0],
- (ulong)block->pkt->pkt.public_key->keyid[1]);
-
- iobuf_close(buffer);
-
- if(keyserver->host)
- log_info(_("sending key %s to %s server %s\n"),
- keystr(block->pkt->pkt.public_key->keyid),
- keyserver->scheme,keyserver->host);
- else
- log_info(_("sending key %s to %s\n"),
- keystr(block->pkt->pkt.public_key->keyid),
- keyserver->uri);
-
- release_kbnode(block);
- }
-
- free_strlist(temp);
- }
-
- break;
- }
-
- case KS_SEARCH:
- {
- strlist_t key;
-
- fprintf(spawn->tochild,"COMMAND SEARCH\n\n");
-
- /* Which keys do we want? Remember that the gpgkeys_ program
- is going to lump these together into a search string. */
-
- for(key=list;key!=NULL;key=key->next)
- {
- fprintf(spawn->tochild,"%s\n",key->d);
- if(key!=list)
- {
- searchstr=xrealloc(searchstr,
- strlen(searchstr)+strlen(key->d)+2);
- strcat(searchstr," ");
- }
- else
- {
- searchstr=xmalloc(strlen(key->d)+1);
- searchstr[0]='\0';
- }
-
- strcat(searchstr,key->d);
- }
-
- fprintf(spawn->tochild,"\n");
-
- if(keyserver->host)
- log_info(_("searching for \"%s\" from %s server %s\n"),
- searchstr,keyserver->scheme,keyserver->host);
- else
- log_info(_("searching for \"%s\" from %s\n"),
- searchstr,keyserver->uri);
-
- break;
- }
-
- default:
- log_fatal(_("no keyserver action!\n"));
- break;
- }
-
- /* Done sending, so start reading. */
- ret=exec_read(spawn);
- if(ret)
- goto fail;
-
- /* Now handle the response */
-
- for(;;)
- {
- int plen;
- char *ptr;
-
- maxlen=1024;
- if(iobuf_read_line(spawn->fromchild,&line,&buflen,&maxlen)==0)
- {
- ret = gpg_error_from_syserror ();
- goto fail; /* i.e. EOF */
- }
-
- ptr=line;
-
- /* remove trailing whitespace */
- plen=strlen(ptr);
- while(plen>0 && ascii_isspace(ptr[plen-1]))
- plen--;
- plen[ptr]='\0';
-
- if(*ptr=='\0')
- break;
-
- if(ascii_strncasecmp(ptr,"VERSION ",8)==0)
- {
- gotversion=1;
-
- if(atoi(&ptr[8])!=KEYSERVER_PROTO_VERSION)
- {
- log_error(_("invalid keyserver protocol (us %d!=handler %d)\n"),
- KEYSERVER_PROTO_VERSION,atoi(&ptr[8]));
- goto fail;
- }
- }
- else if(ascii_strncasecmp(ptr,"PROGRAM ",8)==0)
- {
- if(ascii_strncasecmp(&ptr[8],VERSION,strlen(VERSION))!=0)
- log_info(_("WARNING: keyserver handler from a different"
- " version of GnuPG (%s)\n"),&ptr[8]);
- }
- else if(ascii_strncasecmp(ptr,"OPTION OUTOFBAND",16)==0)
- outofband=1; /* Currently the only OPTION */
- }
-
- if(!gotversion)
- {
- log_error(_("keyserver did not send VERSION\n"));
- goto fail;
- }
-
- if(!outofband)
- switch(action)
- {
- case KS_GET:
- case KS_GETNAME:
- {
- void *stats_handle;
-
- stats_handle=import_new_stats_handle();
-
- /* Slurp up all the key data. In the future, it might be
- nice to look for KEY foo OUTOFBAND and FAILED indicators.
- It's harmless to ignore them, but ignoring them does make
- gpg complain about "no valid OpenPGP data found". One
- way to do this could be to continue parsing this
- line-by-line and make a temp iobuf for each key. */
-
- /* FIXME: Pass CTRL. */
- import_keys_stream (NULL, spawn->fromchild,stats_handle,fpr,fpr_len,
- opt.keyserver_options.import_options);
-
- import_print_stats(stats_handle);
- import_release_stats_handle(stats_handle);
-
- break;
- }
-
- /* Nothing to do here */
- case KS_SEND:
- break;
-
- case KS_SEARCH:
- //keyserver_search_prompt (ctrl, spawn->fromchild,searchstr);
- break;
-
- default:
- log_fatal(_("no keyserver action!\n"));
- break;
- }
-
- fail:
- xfree(line);
- xfree(searchstr);
-
-
- *prog=exec_finish(spawn);
-
- return ret;
-}
-
-
-
-
-static int
-keyserver_work (ctrl_t ctrl,
- enum ks_action action,strlist_t list,KEYDB_SEARCH_DESC *desc,
- int count,unsigned char **fpr,size_t *fpr_len,
- struct keyserver_spec *keyserver)
-{
- int rc=0,ret=0;
-
- if (!keyserver)
- {
- log_error (_("no keyserver known (use option --keyserver)\n"));
- return gpg_error (GPG_ERR_BAD_URI);
- }
-
-
- rc = keyserver_spawn (ctrl, action, list, desc, count,
- &ret, fpr, fpr_len, keyserver);
- if (ret)
- {
- switch(ret)
- {
- case KEYSERVER_SCHEME_NOT_FOUND:
- log_error(_("no handler for keyserver scheme `%s'\n"),
- keyserver->scheme);
- break;
-
- case KEYSERVER_NOT_SUPPORTED:
- log_error(_("action `%s' not supported with keyserver "
- "scheme `%s'\n"),
- action==KS_GET?"get":action==KS_SEND?"send":
- action==KS_SEARCH?"search":"unknown",
- keyserver->scheme);
- break;
-
- case KEYSERVER_VERSION_ERROR:
- log_error(_(GPGKEYS_PREFIX "%s does not support"
- " handler version %d\n"),
- keyserver_typemap(keyserver->scheme),
- KEYSERVER_PROTO_VERSION);
- break;
-
- case KEYSERVER_TIMEOUT:
- log_error(_("keyserver timed out\n"));
- break;
-
- case KEYSERVER_INTERNAL_ERROR:
- default:
- log_error(_("keyserver internal error\n"));
- break;
- }
-
- return G10ERR_KEYSERVER;
- }
-
- if (rc)
- {
- log_error (_("keyserver communications error: %s\n"),g10_errstr(rc));
-
- return rc;
- }
-
- return 0;
-}
-
-
-
-
int
keyserver_export (ctrl_t ctrl, strlist_t users)
@@ -1674,7 +1014,7 @@ keyserver_export (ctrl_t ctrl, strlist_t users)
if(sl)
{
- rc = keyserver_work (ctrl, KS_SEND,sl,NULL,0,NULL,NULL,opt.keyserver);
+ rc = keyserver_put (ctrl, sl, opt.keyserver);
free_strlist(sl);
}
@@ -2113,26 +1453,6 @@ keyserver_search (ctrl_t ctrl, strlist_t tokens)
/* Called using:
-show_prompt:
-import:
-import_foo:
-refresh:
- rc=keyserver_work (ctrl, KS_GET, NULL, desc, count,
- NULL, NULL, opt.keyserver);
-
-
-fetch:
- rc = keyserver_work (ctrl, KS_GET, NULL, &desc, 1, NULL, NULL, spec);
- if(rc)
- log_info (_("WARNING: unable to fetch URI %s: %s\n"),
- sl->d,g10_errstr(rc));
-
-
-export:
- rc = keyserver_work (ctrl, KS_SEND,sl,NULL,0,NULL,NULL,opt.keyserver);
-
-
-
import_name:
rc = keyserver_work (ctrl, KS_GETNAME, list, NULL,
0, fpr, fpr_len, keyserver);
@@ -2267,6 +1587,58 @@ keyserver_get (ctrl_t ctrl, KEYDB_SEARCH_DESC *desc, int ndesc,
}
+/* Send all keys specified by KEYSPECS to the KEYSERVERS. */
+static gpg_error_t
+keyserver_put (ctrl_t ctrl, strlist_t keyspecs,
+ struct keyserver_spec *keyserver)
+
+{
+ gpg_error_t err;
+ strlist_t kspec;
+
+ if (!keyspecs)
+ return 0; /* Return success if the list is empty. */
+
+ if (!opt.keyserver)
+ {
+ log_error (_("no keyserver known (use option --keyserver)\n"));
+ return gpg_error (GPG_ERR_NO_KEYSERVER);
+ }
+
+ for (kspec = keyspecs; kspec; kspec = kspec->next)
+ {
+ void *data;
+ size_t datalen;
+ kbnode_t keyblock;
+
+ err = export_pubkey_buffer (ctrl, kspec->d,
+ opt.keyserver_options.export_options,
+ &keyblock, &data, &datalen);
+ if (err)
+ log_error (_("skipped \"%s\": %s\n"), kspec->d, gpg_strerror (err));
+ else
+ {
+ if (keyserver->host)
+ log_info (_("sending key %s to %s server %s\n"),
+ keystr (keyblock->pkt->pkt.public_key->keyid),
+ keyserver->scheme, keyserver->host);
+ else
+ log_info (_("sending key %s to %s\n"),
+ keystr (keyblock->pkt->pkt.public_key->keyid),
+ keyserver->uri);
+
+ err = gpg_dirmngr_ks_put (ctrl, data, datalen, keyblock);
+ release_kbnode (keyblock);
+ xfree (data);
+ if (err)
+ log_error (_("keyserver send failed: %s\n"), gpg_strerror (err));
+ }
+ }
+
+
+ return err;
+
+}
@@ -2439,8 +1811,9 @@ keyserver_import_name (ctrl_t ctrl, const char *name,
append_to_strlist(&list,name);
- rc = keyserver_work (ctrl, KS_GETNAME, list, NULL,
- 0, fpr, fpr_len, keyserver);
+ rc = gpg_error (GPG_ERR_NOT_IMPLEMENTED); /* FIXME */
+ /* keyserver_work (ctrl, KS_GETNAME, list, NULL, */
+ /* 0, fpr, fpr_len, keyserver); */
free_strlist(list);
@@ -2513,8 +1886,9 @@ keyserver_import_ldap (ctrl_t ctrl,
append_to_strlist(&list,name);
- rc = keyserver_work (ctrl, KS_GETNAME, list, NULL,
- 0, fpr, fpr_len, keyserver);
+ rc = gpg_error (GPG_ERR_NOT_IMPLEMENTED); /*FIXME*/
+ /* keyserver_work (ctrl, KS_GETNAME, list, NULL, */
+ /* 0, fpr, fpr_len, keyserver); */
free_strlist(list);
diff --git a/g10/main.h b/g10/main.h
index 2e760844a..427834023 100644
--- a/g10/main.h
+++ b/g10/main.h
@@ -287,6 +287,10 @@ int parse_export_options(char *str,unsigned int *options,int noisy);
int export_pubkeys (ctrl_t ctrl, strlist_t users, unsigned int options );
int export_pubkeys_stream (ctrl_t ctrl, iobuf_t out, strlist_t users,
kbnode_t *keyblock_out, unsigned int options );
+gpg_error_t export_pubkey_buffer (ctrl_t ctrl, const char *keyspec,
+ unsigned int options,
+ kbnode_t *r_keyblock,
+ void **r_data, size_t *r_datalen);
int export_seckeys (ctrl_t ctrl, strlist_t users);
int export_secsubkeys (ctrl_t ctrl, strlist_t users);
diff --git a/keyserver/ChangeLog b/keyserver/ChangeLog
index 14d5f6244..cc42a6426 100644
--- a/keyserver/ChangeLog
+++ b/keyserver/ChangeLog
@@ -1,3 +1,9 @@
+2011-01-20 Werner Koch <[email protected]>
+
+ * gpgkeys_hkp.c (get_name): Remove test for KS_GETNAME. It is
+ always true.
+ (search_key): Remove test for KS_GETNAME. It is always false.
+
2009-08-26 Werner Koch <[email protected]>
* gpgkeys_hkp.c: Include util.h.
diff --git a/keyserver/gpgkeys_hkp.c b/keyserver/gpgkeys_hkp.c
index dd2129051..d43a61ab5 100644
--- a/keyserver/gpgkeys_hkp.c
+++ b/keyserver/gpgkeys_hkp.c
@@ -340,7 +340,7 @@ get_name(const char *getkey)
opt->path,
appendable_path (opt->path,"/pks/lookup?op=get&options=mr&search="),
searchkey_encoded,
- opt->action == KS_GETNAME? "&exact=on":"",
+ "&exact=on",
NULL);
if(!request)
{
@@ -429,7 +429,6 @@ search_key(const char *searchkey)
appendable_path (opt->path, "/pks/lookup?op=index&options=mr&search="),
hexprefix,
searchkey_encoded,
- opt->action == KS_GETNAME? "&exact=on":"",
NULL);
if(!request)
{