All standard keyserver commands are now using dirmngr.

This commit is contained in:
Werner Koch 2011-01-20 14:12:53 +01:00
parent 357f8d5398
commit 7f32d88ed1
20 changed files with 689 additions and 735 deletions

View File

@ -1,3 +1,14 @@
2011-01-20 Werner Koch <wk@g10code.com>
* 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 <wk@g10code.com>
* iobuf.c (file_es_filter_ctx_t): New.

View File

@ -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;

View File

@ -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;
}

View File

@ -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

View File

@ -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*/

View File

@ -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);

View File

@ -1,13 +1,9 @@
2011-01-06 Werner Koch <wk@g10code.com>
2011-01-20 Werner Koch <wk@g10code.com>
* 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 <wk@g10code.com>
* ks-engine-hkp.c: New.
* ks-engine.h: New.
* ks-action.c, ks-action.h: New.

View File

@ -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;
}

View File

@ -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*/

View File

@ -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;
}

View File

@ -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);

View File

@ -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 },

View File

@ -1,13 +1,12 @@
2011-01-18 Werner Koch <wk@g10code.com>
2011-01-20 Werner Koch <wk@g10code.com>
* keyserver.c: Rewrite most stuff for use with dirmngr. Get rid
of all spawn code. Work work pending.
* export.c (export_pubkeys_buffer): New.
* import.c (import_keys_es_stream): New.
2011-01-14 Werner Koch <wk@g10code.com>
* keyserver.c (parse_keyrec): Use trim_trailing_ws.
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.
@ -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

View File

@ -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;
}

View File

@ -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*/

View File

@ -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 )
{

View File

@ -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);

View File

@ -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);

View File

@ -1,3 +1,9 @@
2011-01-20 Werner Koch <wk@g10code.com>
* 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 <wk@g10code.com>
* gpgkeys_hkp.c: Include util.h.

View File

@ -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)
{