1
0
mirror of git://git.gnupg.org/gnupg.git synced 2024-09-20 14:51:42 +02:00

Keyserver search and get basically works again.

This commit is contained in:
Werner Koch 2011-01-18 12:51:16 +01:00
parent c2c5d30db8
commit 357f8d5398
14 changed files with 1519 additions and 827 deletions

View File

@ -35,7 +35,7 @@ endif
if BUILD_GPG if BUILD_GPG
gpg = g10 gpg = g10
if !HAVE_W32CE_SYSTEM if !HAVE_W32CE_SYSTEM
keyserver = keyserver keyserver =
endif endif
else else
gpg = gpg =

View File

@ -79,6 +79,7 @@ ks_action_search (ctrl_t ctrl, strlist_t patterns, estream_t outfp)
{ {
err = copy_stream (infp, outfp); err = copy_stream (infp, outfp);
es_fclose (infp); es_fclose (infp);
break;
} }
} }
} }
@ -88,3 +89,62 @@ ks_action_search (ctrl_t ctrl, strlist_t patterns, estream_t outfp)
return err; return err;
} }
/* Get the requested keys (macthing 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)
{
gpg_error_t err = 0;
gpg_error_t first_err = 0;
int any = 0;
strlist_t sl;
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 keyserver. To fully
support multiple keyservers we need to track the result for each
pattern and use the next keyserver if one key was not found. The
keyservers might not all be fully synced thus it is not clear
whether the first keyserver has the freshest copy of the key.
Need to think about a better strategy. */
for (uri = ctrl->keyservers; !err && uri; uri = uri->next)
{
if (uri->parsed_uri->is_http)
{
any = 1;
for (sl = patterns; !err && sl; sl = sl->next)
{
err = ks_hkp_get (ctrl, uri->parsed_uri, sl->d, &infp);
if (err)
{
/* It is possible that a server does not carry a
key, thus we only save the error and continue
with the next pattern. FIXME: It is an open
question how to return such an error condition to
the caller. */
first_err = err;
err = 0;
}
else
{
err = copy_stream (infp, outfp);
/* Reading from the keyserver should nver fail, thus
return this error. */
es_fclose (infp);
infp = NULL;
}
}
}
}
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

@ -21,6 +21,7 @@
#define DIRMNGR_KS_ACTION_H 1 #define DIRMNGR_KS_ACTION_H 1
gpg_error_t ks_action_search (ctrl_t ctrl, strlist_t patterns, estream_t outfp); 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);
#endif /*DIRMNGR_KS_ACTION_H*/ #endif /*DIRMNGR_KS_ACTION_H*/

View File

@ -37,6 +37,117 @@
#define MAX_REDIRECTS 2 #define MAX_REDIRECTS 2
/* Send an HTTP request. On success returns an estream object at
R_FP. HOSTPORTSTR is only used for diagnostics. */
static gpg_error_t
send_request (ctrl_t ctrl, const char *request, const char *hostportstr,
estream_t *r_fp)
{
gpg_error_t err;
http_t http = NULL;
int redirects_left = MAX_REDIRECTS;
estream_t fp = NULL;
char *request_buffer = NULL;
*r_fp = NULL;
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"),
hostportstr, 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"),
hostportstr, gpg_strerror (err));
goto leave;
}
switch (http_get_status_code (http))
{
case 200:
err = 0;
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_buffer);
request_buffer = xtrystrdup (s);
if (request_buffer)
{
request = request_buffer;
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;
}
fp = http_get_read_ptr (http);
if (!fp)
{
err = gpg_error (GPG_ERR_BUG);
goto leave;
}
/* 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;
}
/* Search the keyserver identified by URI for keys matching PATTERN. /* Search the keyserver identified by URI for keys matching PATTERN.
On success R_FP has an open stream to read the data. */ On success R_FP has an open stream to read the data. */
gpg_error_t gpg_error_t
@ -48,10 +159,8 @@ ks_hkp_search (ctrl_t ctrl, parsed_uri_t uri, const char *pattern,
char fprbuf[2+40+1]; char fprbuf[2+40+1];
const char *scheme; const char *scheme;
char portstr[10]; char portstr[10];
http_t http = NULL;
char *hostport = NULL; char *hostport = NULL;
char *request = NULL; char *request = NULL;
int redirects_left = MAX_REDIRECTS;
estream_t fp = NULL; estream_t fp = NULL;
*r_fp = NULL; *r_fp = NULL;
@ -142,87 +251,11 @@ ks_hkp_search (ctrl_t ctrl, parsed_uri_t uri, const char *pattern,
} }
/* Send the request. */ /* Send the request. */
once_more: err = send_request (ctrl, request, hostport, &fp);
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) if (err)
{ goto leave;
/* 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. */ /* 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); int c = es_getc (fp);
if (c == -1) if (c == -1)
@ -241,15 +274,110 @@ ks_hkp_search (ctrl_t ctrl, parsed_uri_t uri, const char *pattern,
es_ungetc (c, fp); es_ungetc (c, fp);
} }
/* Return the read stream and close the HTTP context. */ /* Return the read stream. */
*r_fp = fp;
fp = NULL;
leave:
es_fclose (fp);
xfree (request);
xfree (hostport);
return err;
}
/* Get the key described key the KEYSPEC string from the keyserver
identified by URI. On success R_FP has an open stream to read the
data. */
gpg_error_t
ks_hkp_get (ctrl_t ctrl, parsed_uri_t uri, const char *keyspec, estream_t *r_fp)
{
gpg_error_t err;
KEYDB_SEARCH_DESC desc;
char kidbuf[8+1];
const char *scheme;
char portstr[10];
char *hostport = NULL;
char *request = NULL;
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 (keyspec, &desc);
if (err)
return err;
switch (desc.mode)
{
case KEYDB_SEARCH_MODE_SHORT_KID:
case KEYDB_SEARCH_MODE_LONG_KID:
snprintf (kidbuf, sizeof kidbuf, "%08lX", (ulong)desc.u.kid[1]);
break;
case KEYDB_SEARCH_MODE_FPR20:
case KEYDB_SEARCH_MODE_FPR:
/* This is a v4 fingerprint. Take the last 8 hex digits from
the fingerprint which is the expected short keyid. */
bin2hex (desc.u.fpr+16, 4, kidbuf);
break;
case KEYDB_SEARCH_MODE_FPR16:
log_error ("HKP keyserver do not support v3 fingerprints\n");
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. */
{
hostport = strconcat (scheme, "://",
*uri->host? uri->host: "localhost",
":", portstr, NULL);
if (!hostport)
{
err = gpg_error_from_syserror ();
goto leave;
}
request = strconcat (hostport,
"/pks/lookup?op=get&options=mr&search=0x",
kidbuf,
NULL);
if (!request)
{
err = gpg_error_from_syserror ();
goto leave;
}
}
/* Send the request. */
err = send_request (ctrl, request, hostport, &fp);
if (err)
goto leave;
/* Return the read stream and close the HTTP context. */
*r_fp = fp; *r_fp = fp;
fp = NULL; fp = NULL;
http_close (http, 1);
http = NULL;
leave: leave:
es_fclose (fp); es_fclose (fp);
http_close (http, 0);
xfree (request); xfree (request);
xfree (hostport); xfree (hostport);
return err; return err;

View File

@ -26,6 +26,8 @@
/*-- ks-engine-hkp.c --*/ /*-- ks-engine-hkp.c --*/
gpg_error_t ks_hkp_search (ctrl_t ctrl, parsed_uri_t uri, const char *pattern, gpg_error_t ks_hkp_search (ctrl_t ctrl, parsed_uri_t uri, const char *pattern,
estream_t *r_fp); estream_t *r_fp);
gpg_error_t ks_hkp_get (ctrl_t ctrl, parsed_uri_t uri,
const char *keyspec, estream_t *r_fp);

View File

@ -1475,6 +1475,66 @@ cmd_ks_search (assuan_context_t ctx, char *line)
} }
static const char hlp_ks_get[] =
"KS_GET {<pattern>}\n"
"\n"
"Get the keys matching PATTERN from the configured OpenPGP keyservers\n"
"(see command KEYSERVER). Each pattern should be a keyid or a fingerprint";
static gpg_error_t
cmd_ks_get (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 by
definition percent-plus escaped. However we only support keyids
and fingerprints and thus the client has no need to apply the
escaping. */
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 get. */
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_get (ctrl, list, outfp);
es_fclose (outfp);
}
leave:
return leave_cmd (ctx, err);
}
static const char hlp_getinfo[] = static const char hlp_getinfo[] =
@ -1611,6 +1671,7 @@ register_commands (assuan_context_t ctx)
{ "VALIDATE", cmd_validate, hlp_validate }, { "VALIDATE", cmd_validate, hlp_validate },
{ "KEYSERVER", cmd_keyserver, hlp_keyserver }, { "KEYSERVER", cmd_keyserver, hlp_keyserver },
{ "KS_SEARCH", cmd_ks_search, hlp_ks_search }, { "KS_SEARCH", cmd_ks_search, hlp_ks_search },
{ "KS_GET", cmd_ks_get, hlp_ks_get },
{ "GETINFO", cmd_getinfo, hlp_getinfo }, { "GETINFO", cmd_getinfo, hlp_getinfo },
{ "KILLDIRMNGR",cmd_killdirmngr,hlp_killdirmngr }, { "KILLDIRMNGR",cmd_killdirmngr,hlp_killdirmngr },
{ "RELOADDIRMNGR",cmd_reloaddirmngr,hlp_reloaddirmngr }, { "RELOADDIRMNGR",cmd_reloaddirmngr,hlp_reloaddirmngr },

View File

@ -1,3 +1,11 @@
2011-01-18 Werner Koch <wk@g10code.com>
* 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> 2011-01-07 Werner Koch <wk@g10code.com>
* call-dirmngr.c, call-dirmngr.h: New. * call-dirmngr.c, call-dirmngr.h: New.

View File

@ -36,9 +36,29 @@
#include "options.h" #include "options.h"
#include "i18n.h" #include "i18n.h"
#include "asshelp.h" #include "asshelp.h"
#include "keyserver.h"
#include "call-dirmngr.h" #include "call-dirmngr.h"
/* Parameter structure used with the KS_SEARCH command. */
struct ks_search_parm_s
{
gpg_error_t lasterr; /* Last error code. */
membuf_t saveddata; /* Buffer to build complete lines. */
char *helpbuf; /* NULL or malloced buffer. */
size_t helpbufsize; /* Allocated size of HELPBUF. */
gpg_error_t (*data_cb)(void*, char*); /* Callback. */
void *data_cb_value; /* First argument for DATA_CB. */
};
/* Parameter structure used with the KS_GET command. */
struct ks_get_parm_s
{
estream_t memfp;
};
/* Data used to associate an session with dirmngr contexts. We can't /* Data used to associate an session with dirmngr contexts. We can't
use a simple one to one mapping because we sometimes need two use a simple one to one mapping because we sometimes need two
connection s to the dirmngr; for example while doing a listing and connection s to the dirmngr; for example while doing a listing and
@ -53,7 +73,7 @@ struct dirmngr_local_s
struct dirmngr_local_s *next; struct dirmngr_local_s *next;
/* The active Assuan context. */ /* The active Assuan context. */
static assuan_context_t ctx; assuan_context_t ctx;
/* Flag set to true while an operation is running on CTX. */ /* Flag set to true while an operation is running on CTX. */
int is_active; int is_active;
@ -106,12 +126,12 @@ create_context (ctrl_t ctrl, assuan_context_t *r_ctx)
/* Set all configured keyservers. We clear existing keyservers /* Set all configured keyservers. We clear existing keyservers
so that any keyserver configured in GPG overrides keyservers so that any keyserver configured in GPG overrides keyservers
possibly configured in Dirmngr. */ possibly configured in Dirmngr. */
if (ksi = opt.keyservers; !err && ksi; ksi = ksi->next) for (ksi = opt.keyserver; !err && ksi; ksi = ksi->next)
{ {
char *line; char *line;
line = xtryasprintf ("KEYSERVER%s %s", line = xtryasprintf ("KEYSERVER%s %s",
ksi == opt.keyservers? " --clear":"", ksi->uri); ksi == opt.keyserver? " --clear":"", ksi->uri);
if (!line) if (!line)
err = gpg_error_from_syserror (); err = gpg_error_from_syserror ();
else else
@ -156,7 +176,8 @@ open_context (ctrl_t ctrl, assuan_context_t *r_ctx)
/* Found an inactive local session - return that. */ /* Found an inactive local session - return that. */
assert (!dml->is_active); assert (!dml->is_active);
dml->is_active = 1; dml->is_active = 1;
return dml; *r_ctx = dml->ctx;
return 0;
} }
dml = xtrycalloc (1, sizeof *dml); dml = xtrycalloc (1, sizeof *dml);
@ -192,9 +213,9 @@ close_context (ctrl_t ctrl, assuan_context_t ctx)
{ {
if (dml->ctx == ctx) if (dml->ctx == ctx)
{ {
if (!ctx->is_active) if (!dml->is_active)
log_fatal ("closing inactive dirmngr context %p\n", ctx); log_fatal ("closing inactive dirmngr context %p\n", ctx);
ctx->is_active = 0; dml->is_active = 0;
return; return;
} }
} }
@ -203,54 +224,215 @@ close_context (ctrl_t ctrl, assuan_context_t ctx)
/* Data callback for the KS_SEARCH command. */
static gpg_error_t
ks_search_data_cb (void *opaque, const void *data, size_t datalen)
{
gpg_error_t err = 0;
struct ks_search_parm_s *parm = opaque;
const char *line, *s;
size_t rawlen, linelen;
char fixedbuf[256];
int if (parm->lasterr)
gpg_dirmngr_ks_search (ctrl_t ctrl, strlist_t names, return 0;
void (*cb)(void*, ksba_cert_t), void *cb_value)
if (!data)
return 0; /* Ignore END commands. */
put_membuf (&parm->saveddata, data, datalen);
again:
line = peek_membuf (&parm->saveddata, &rawlen);
if (!line)
{
parm->lasterr = gpg_error_from_syserror ();
return parm->lasterr; /* Tell the server about our problem. */
}
if ((s = memchr (line, '\n', rawlen)))
{
linelen = s - line; /* That is the length excluding the LF. */
if (linelen + 1 < sizeof fixedbuf)
{
/* We can use the static buffer. */
memcpy (fixedbuf, line, linelen);
fixedbuf[linelen] = 0;
if (linelen && fixedbuf[linelen-1] == '\r')
fixedbuf[linelen-1] = 0;
err = parm->data_cb (parm->data_cb_value, fixedbuf);
}
else
{
if (linelen + 1 >= parm->helpbufsize)
{
xfree (parm->helpbuf);
parm->helpbufsize = linelen + 1 + 1024;
parm->helpbuf = xtrymalloc (parm->helpbufsize);
if (!parm->helpbuf)
{
parm->lasterr = gpg_error_from_syserror ();
return parm->lasterr;
}
}
memcpy (parm->helpbuf, line, linelen);
parm->helpbuf[linelen] = 0;
if (linelen && parm->helpbuf[linelen-1] == '\r')
parm->helpbuf[linelen-1] = 0;
err = parm->data_cb (parm->data_cb_value, parm->helpbuf);
}
if (err)
parm->lasterr = err;
else
{
clear_membuf (&parm->saveddata, linelen+1);
goto again; /* There might be another complete line. */
}
}
return err;
}
/* Run the KS_SEARCH command using the search string SEARCHSTR. All
data lines are passed to the CB function. That function is called
with CB_VALUE as its first argument and the decoded data line as
second argument. The callback function may modify the data line
and it is guaranteed that this data line is a complete line with a
terminating 0 character but without the linefeed. NULL is passed
to the callback to indicate EOF. */
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 err; gpg_error_t err;
assuan_context_t ctx; assuan_context_t ctx;
char *pattern; struct ks_search_parm_s parm;
char line[ASSUAN_LINELENGTH]; char line[ASSUAN_LINELENGTH];
err = open_context (ctrl, &ctx); err = open_context (ctrl, &ctx);
if (err) if (err)
return err; return err;
pattern = pattern_from_strlist (names); {
if (!pattern) char *escsearchstr = percent_plus_escape (searchstr);
{ if (!escsearchstr)
if (ctx == dirmngr_ctx) {
release_dirmngr (ctrl); err = gpg_error_from_syserror ();
else close_context (ctrl, ctx);
release_dirmngr2 (ctrl); return err;
}
snprintf (line, sizeof line, "KS_SEARCH -- %s", escsearchstr);
xfree (escsearchstr);
}
return out_of_core (); memset (&parm, 0, sizeof parm);
} init_membuf (&parm.saveddata, 1024);
snprintf (line, DIM(line)-1, "LOOKUP%s %s", parm.data_cb = cb;
cache_only? " --cache-only":"", pattern); parm.data_cb_value = cb_value;
line[DIM(line)-1] = 0;
xfree (pattern);
parm.ctrl = ctrl; err = assuan_transact (ctx, line, ks_search_data_cb, &parm,
parm.ctx = ctx; NULL, NULL, NULL, NULL);
parm.cb = cb; if (!err)
parm.cb_value = cb_value; err = cb (cb_value, NULL); /* Send EOF. */
parm.error = 0;
init_membuf (&parm.data, 4096);
rc = assuan_transact (ctx, line, lookup_cb, &parm, xfree (get_membuf (&parm.saveddata, NULL));
NULL, NULL, lookup_status_cb, &parm); xfree (parm.helpbuf);
xfree (get_membuf (&parm.data, &len));
if (ctx == dirmngr_ctx)
release_dirmngr (ctrl);
else
release_dirmngr2 (ctrl);
if (rc)
return rc;
close_context (ctrl, ctx); close_context (ctrl, ctx);
return parm.error; return err;
}
/* Data callback for the KS_GET command. */
static gpg_error_t
ks_get_data_cb (void *opaque, const void *data, size_t datalen)
{
gpg_error_t err = 0;
struct ks_get_parm_s *parm = opaque;
size_t nwritten;
if (!data)
return 0; /* Ignore END commands. */
if (es_write (parm->memfp, data, datalen, &nwritten))
err = gpg_error_from_syserror ();
return err;
}
/* Run the KS_GET command using the patterns in the array PATTERN. On
success an estream object is returned to retrieve the keys. On
error an error code is returned and NULL stored at R_FP.
The pattern may only use search specification which a keyserver can
use to retriev keys. Because we know the format of the pattern we
don't need to escape the patterns before sending them to the
server.
If there are too many patterns the function returns an error. That
could be fixed by issuing several search commands or by
implementing a different interface. However with long keyids we
are able to ask for (1000-10-1)/(2+8+1) = 90 keys at once. */
gpg_error_t
gpg_dirmngr_ks_get (ctrl_t ctrl, char **pattern, estream_t *r_fp)
{
gpg_error_t err;
assuan_context_t ctx;
struct ks_get_parm_s parm;
char *line = NULL;
size_t linelen;
membuf_t mb;
int idx;
memset (&parm, 0, sizeof parm);
*r_fp = NULL;
err = open_context (ctrl, &ctx);
if (err)
return err;
/* Lump all patterns into one string. */
init_membuf (&mb, 1024);
put_membuf_str (&mb, "KS_GET --");
for (idx=0; pattern[idx]; idx++)
{
put_membuf (&mb, " ", 1); /* Append Delimiter. */
put_membuf_str (&mb, pattern[idx]);
}
put_membuf (&mb, "", 1); /* Append Nul. */
line = get_membuf (&mb, &linelen);
if (!line)
{
err = gpg_error_from_syserror ();
goto leave;
}
if (linelen + 2 >= ASSUAN_LINELENGTH)
{
err = gpg_error (GPG_ERR_TOO_MANY);
goto leave;
}
parm.memfp = es_fopenmem (0, "rwb");
if (!parm.memfp)
{
err = gpg_error_from_syserror ();
goto leave;
}
err = assuan_transact (ctx, line, ks_get_data_cb, &parm,
NULL, NULL, NULL, NULL);
if (err)
goto leave;
es_rewind (parm.memfp);
*r_fp = parm.memfp;
parm.memfp = NULL;
leave:
es_fclose (parm.memfp);
xfree (line);
close_context (ctrl, ctx);
return err;
} }

View File

@ -21,6 +21,10 @@
void gpg_dirmngr_deinit_session_data (ctrl_t ctrl); void gpg_dirmngr_deinit_session_data (ctrl_t ctrl);
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);
#endif /*GNUPG_G10_CALL_DIRMNGR_H*/ #endif /*GNUPG_G10_CALL_DIRMNGR_H*/

View File

@ -3752,12 +3752,12 @@ main (int argc, char **argv)
case aSearchKeys: case aSearchKeys:
sl = NULL; sl = NULL;
for( ; argc; argc--, argv++ ) for (; argc; argc--, argv++)
append_to_strlist2( &sl, *argv, utf8_strings ); append_to_strlist2 (&sl, *argv, utf8_strings);
rc = keyserver_search (ctrl, sl); rc = keyserver_search (ctrl, sl);
if(rc) if (rc)
log_error(_("keyserver search failed: %s\n"),g10_errstr(rc)); log_error (_("keyserver search failed: %s\n"), gpg_strerror (rc));
free_strlist(sl); free_strlist (sl);
break; break;
case aRefreshKeys: case aRefreshKeys:

View File

@ -243,6 +243,32 @@ import_keys_stream (ctrl_t ctrl, IOBUF inp, void *stats_handle,
fpr, fpr_len, options); fpr, fpr_len, options);
} }
/* Variant of import_keys_stream reading from an estream_t. */
int
import_keys_es_stream (ctrl_t ctrl, estream_t fp, void *stats_handle,
unsigned char **fpr, size_t *fpr_len,
unsigned int options)
{
int rc;
iobuf_t inp;
inp = iobuf_esopen (fp, "r", 1);
if (!inp)
{
rc = gpg_error_from_syserror ();
log_error ("iobuf_esopen failed: %s\n", gpg_strerror (rc));
return rc;
}
rc = import_keys_internal (ctrl, inp, NULL, 0, stats_handle,
fpr, fpr_len, options);
iobuf_close (inp);
return rc;
}
static int static int
import (ctrl_t ctrl, IOBUF inp, const char* fname,struct stats_s *stats, import (ctrl_t ctrl, IOBUF inp, const char* fname,struct stats_s *stats,
unsigned char **fpr,size_t *fpr_len,unsigned int options ) unsigned char **fpr,size_t *fpr_len,unsigned int options )

File diff suppressed because it is too large Load Diff

View File

@ -272,6 +272,9 @@ void import_keys (ctrl_t ctrl, char **fnames, int nnames,
int import_keys_stream (ctrl_t ctrl, iobuf_t inp, void *stats_hd, int import_keys_stream (ctrl_t ctrl, iobuf_t inp, void *stats_hd,
unsigned char **fpr, unsigned char **fpr,
size_t *fpr_len, unsigned int options); size_t *fpr_len, unsigned int options);
int import_keys_es_stream (ctrl_t ctrl, estream_t fp, void *stats_handle,
unsigned char **fpr, size_t *fpr_len,
unsigned int options);
void *import_new_stats_handle (void); void *import_new_stats_handle (void);
void import_release_stats_handle (void *p); void import_release_stats_handle (void *p);
void import_print_stats (void *hd); void import_print_stats (void *hd);

846
po/de.po

File diff suppressed because it is too large Load Diff