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 )

View File

@ -1,6 +1,6 @@
/* keyserver.c - generic keyserver code /* keyserver.c - generic keyserver code
* Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, * Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
* 2009 Free Software Foundation, Inc. * 2009, 2011 Free Software Foundation, Inc.
* *
* This file is part of GnuPG. * This file is part of GnuPG.
* *
@ -18,6 +18,9 @@
* along with this program; if not, see <http://www.gnu.org/licenses/>. * along with this program; if not, see <http://www.gnu.org/licenses/>.
*/ */
/* !!! FIXME: Replace all printf by es_printf. FIXME !!! */
#include <config.h> #include <config.h>
#include <ctype.h> #include <ctype.h>
#include <stdio.h> #include <stdio.h>
@ -46,7 +49,7 @@
#include "srv.h" #include "srv.h"
#endif #endif
#include "membuf.h" #include "membuf.h"
#include "call-dirmngr.h"
#ifdef HAVE_W32_SYSTEM #ifdef HAVE_W32_SYSTEM
/* It seems Vista doesn't grok X_OK and so fails access() tests. /* It seems Vista doesn't grok X_OK and so fails access() tests.
@ -66,6 +69,24 @@ struct keyrec
unsigned int lines; unsigned int lines;
}; };
/* Parameters for the search line handler. */
struct search_line_handler_parm_s
{
ctrl_t ctrl; /* The session control structure. */
char *searchstr_disp; /* Native encoded search string or NULL. */
KEYDB_SEARCH_DESC *desc; /* Array with search descriptions. */
int count; /* Number of keys we are currently prepared to
handle. This is the size of the DESC array. If
it is too small, it will grow safely. */
int validcount; /* Enable the "Key x-y of z" messages. */
int nkeys; /* Number of processed records. */
int any_lines; /* At least one line has been processed. */
unsigned int numlines; /* Counter for displayed lines. */
int eof_seen; /* EOF encountered. */
int not_found; /* Set if no keys have been found. */
};
enum ks_action {KS_UNKNOWN=0,KS_GET,KS_GETNAME,KS_SEND,KS_SEARCH}; enum ks_action {KS_UNKNOWN=0,KS_GET,KS_GETNAME,KS_SEND,KS_SEARCH};
static struct parse_options keyserver_opts[]= static struct parse_options keyserver_opts[]=
@ -94,6 +115,10 @@ static int keyserver_work (ctrl_t ctrl, enum ks_action action,strlist_t list,
KEYDB_SEARCH_DESC *desc,int count, KEYDB_SEARCH_DESC *desc,int count,
unsigned char **fpr,size_t *fpr_len, unsigned char **fpr,size_t *fpr_len,
struct keyserver_spec *keyserver); struct keyserver_spec *keyserver);
static gpg_error_t keyserver_get (ctrl_t ctrl,
KEYDB_SEARCH_DESC *desc, int ndesc,
struct keyserver_spec *keyserver);
/* Reasonable guess */ /* Reasonable guess */
#define DEFAULT_MAX_CERT_SIZE 16384 #define DEFAULT_MAX_CERT_SIZE 16384
@ -556,6 +581,8 @@ print_keyrec(int number,struct keyrec *keyrec)
static struct keyrec * static struct keyrec *
parse_keyrec(char *keystring) parse_keyrec(char *keystring)
{ {
/* FIXME: Remove the static and put the data into the parms we use
for the caller anyway. */
static struct keyrec *work=NULL; static struct keyrec *work=NULL;
struct keyrec *ret=NULL; struct keyrec *ret=NULL;
char *record; char *record;
@ -584,12 +611,7 @@ parse_keyrec(char *keystring)
work->uidbuf=iobuf_temp(); work->uidbuf=iobuf_temp();
} }
/* Remove trailing whitespace */ trim_trailing_ws (keystring, strlen (keystring));
for(i=strlen(keystring);i>0;i--)
if(ascii_isspace(keystring[i-1]))
keystring[i-1]='\0';
else
break;
if((record=strsep(&keystring,":"))==NULL) if((record=strsep(&keystring,":"))==NULL)
return ret; return ret;
@ -728,220 +750,244 @@ parse_keyrec(char *keystring)
return ret; return ret;
} }
/* TODO: do this as a list sent to keyserver_work rather than calling /* Show a prompt and allow the user to select keys for retrieval. */
it once for each key to get the correct counts after the import static gpg_error_t
(cosmetics, really) and to better take advantage of the keyservers show_prompt (ctrl_t ctrl, KEYDB_SEARCH_DESC *desc, int numdesc,
that can do multiple fetches in one go (LDAP). */ int count, const char *search)
static int
show_prompt (ctrl_t ctrl,
KEYDB_SEARCH_DESC *desc,int numdesc,int count,const char *search)
{ {
char *answer; gpg_error_t err;
char *answer = NULL;
fflush (stdout); fflush (stdout);
if(count && opt.command_fd==-1) if (count && opt.command_fd == -1)
{ {
static int from=1; static int from = 1;
tty_printf("Keys %d-%d of %d for \"%s\". ",from,numdesc,count,search); tty_printf ("Keys %d-%d of %d for \"%s\". ",
from=numdesc+1; from, numdesc, count, search);
from = numdesc + 1;
} }
answer=cpr_get_no_help("keysearch.prompt", again:
_("Enter number(s), N)ext, or Q)uit > ")); err = 0;
xfree (answer);
answer = cpr_get_no_help ("keysearch.prompt",
_("Enter number(s), N)ext, or Q)uit > "));
/* control-d */ /* control-d */
if(answer[0]=='\x04') if (answer[0]=='\x04')
{ {
printf("Q\n"); tty_printf ("Q\n");
answer[0]='q'; answer[0] = 'q';
} }
if(answer[0]=='q' || answer[0]=='Q') if (answer[0]=='q' || answer[0]=='Q')
err = gpg_error (GPG_ERR_CANCELED);
else if (atoi (answer) >= 1 && atoi (answer) <= numdesc)
{ {
xfree(answer); char *split = answer;
return 1; char *num;
int numarray[50];
int numidx = 0;
int idx;
while ((num = strsep (&split, " ,")))
if (atoi (num) >= 1 && atoi (num) <= numdesc)
{
if (numidx >= DIM (numarray))
{
tty_printf ("Too many keys selected\n");
goto again;
}
numarray[numidx++] = atoi (num);
}
if (!numidx)
goto again;
{
KEYDB_SEARCH_DESC *selarray;
selarray = xtrymalloc (numidx * sizeof *selarray);
if (!selarray)
{
err = gpg_error_from_syserror ();
goto leave;
}
for (idx = 0; idx < numidx; idx++)
selarray[idx] = desc[numarray[idx]-1];
err = keyserver_get (ctrl, selarray, numidx, NULL);
xfree (selarray);
}
} }
else if(atoi(answer)>=1 && atoi(answer)<=numdesc)
leave:
xfree (answer);
return err;
}
/* This is a callback used by call-dirmngr.c to process the result of
KS_SEARCH command. LINE is the actual data line received with all
escaping removed and guaranteed to be exactly one line with
stripped LF; an EOF is indicated by LINE passed as NULL. LINE may
be modified after return. */
static gpg_error_t
search_line_handler (void *opaque, char *line)
{
struct search_line_handler_parm_s *parm = opaque;
gpg_error_t err = 0;
struct keyrec *keyrec;
if (parm->eof_seen && line)
{ {
char *split=answer,*num; log_debug ("ooops: unexpected data after EOF\n");
line = NULL;
}
while((num=strsep(&split," ,"))!=NULL) /* Print the received line. */
if(atoi(num)>=1 && atoi(num)<=numdesc) if (opt.with_colons && line)
keyserver_work (ctrl, KS_GET,NULL,&desc[atoi(num)-1],1, {
NULL,NULL,opt.keyserver); log_debug ("%s\n",line);
}
xfree(answer); /* Look for an info: line. The only current info: values defined
return 1; are the version and key count. */
if (line && !parm->any_lines && !ascii_strncasecmp ("info:", line, 5))
{
char *str = line + 5;
char *tok;
if ((tok = strsep (&str, ":")))
{
int version;
if (sscanf (tok, "%d", &version) !=1 )
version = 1;
if (version !=1 )
{
log_error (_("invalid keyserver protocol "
"(us %d!=handler %d)\n"), 1, version);
return gpg_error (GPG_ERR_UNSUPPORTED_PROTOCOL);
}
}
if ((tok = strsep (&str, ":"))
&& sscanf (tok, "%d", &parm->count) == 1)
{
if (!parm->count)
parm->not_found = 1;/* Server indicated that no items follow. */
else if (parm->count < 0)
parm->count = 10; /* Bad value - assume something reasonable. */
else
parm->validcount = 1; /* COUNT seems to be okay. */
}
parm->any_lines = 1;
return 0; /* Line processing finished. */
}
again:
if (line)
keyrec = parse_keyrec (line);
else
{
/* Received EOF - flush data */
parm->eof_seen = 1;
keyrec = parse_keyrec (NULL);
if (!keyrec)
{
if (!parm->nkeys)
parm->not_found = 1; /* No keys at all. */
else
{
if (parm->nkeys != parm->count)
parm->validcount = 0;
if (!(opt.with_colons && opt.batch))
{
err = show_prompt (parm->ctrl, parm->desc, parm->nkeys,
parm->validcount? parm->count : 0,
parm->searchstr_disp);
return err;
}
}
}
}
/* Save the key in the key array. */
if (keyrec)
{
/* Allocate or enlarge the key array if needed. */
if (!parm->desc)
{
if (parm->count < 1)
{
parm->count = 10;
parm->validcount = 0;
}
parm->desc = xtrymalloc (parm->count * sizeof *parm->desc);
if (!parm->desc)
{
err = gpg_error_from_syserror ();
iobuf_close (keyrec->uidbuf);
xfree (keyrec);
return err;
}
}
else if (parm->nkeys == parm->count)
{
/* Keyserver sent more keys than claimed in the info: line. */
KEYDB_SEARCH_DESC *tmp;
int newcount = parm->count + 10;
tmp = xtryrealloc (parm->desc, newcount * sizeof *parm->desc);
if (!tmp)
{
err = gpg_error_from_syserror ();
iobuf_close (keyrec->uidbuf);
xfree (keyrec);
return err;
}
parm->count = newcount;
parm->desc = tmp;
parm->validcount = 0;
}
parm->desc[parm->nkeys] = keyrec->desc;
if (!opt.with_colons)
{
/* SCREEN_LINES - 1 for the prompt. */
if (parm->numlines + keyrec->lines > opt.screen_lines - 1)
{
err = show_prompt (parm->ctrl, parm->desc, parm->nkeys,
parm->validcount ? parm->count:0,
parm->searchstr_disp);
if (err)
return err;
parm->numlines = 0;
}
print_keyrec (parm->nkeys+1, keyrec);
}
parm->numlines += keyrec->lines;
iobuf_close (keyrec->uidbuf);
xfree (keyrec);
parm->any_lines = 1;
parm->nkeys++;
/* If we are here due to a flush after the EOF, run again for
the last prompt. Fixme: Make this code better readable. */
if (parm->eof_seen)
goto again;
} }
return 0; return 0;
} }
/* Count and searchstr are just for cosmetics. If the count is too
small, it will grow safely. If negative it disables the "Key x-y
of z" messages. searchstr should be UTF-8 (rather than native). */
static void
keyserver_search_prompt (ctrl_t ctrl, IOBUF buffer,const char *searchstr)
{
int i=0,validcount=0,started=0,header=0,count=1;
unsigned int maxlen,buflen,numlines=0;
KEYDB_SEARCH_DESC *desc;
byte *line=NULL;
char *localstr=NULL;
if(searchstr)
localstr=utf8_to_native(searchstr,strlen(searchstr),0);
desc=xmalloc(count*sizeof(KEYDB_SEARCH_DESC));
for(;;)
{
struct keyrec *keyrec;
int rl;
maxlen=1024;
rl=iobuf_read_line(buffer,&line,&buflen,&maxlen);
if(opt.with_colons)
{
if(!header && ascii_strncasecmp("SEARCH ",line,7)==0
&& ascii_strncasecmp(" BEGIN",&line[strlen(line)-7],6)==0)
{
header=1;
continue;
}
else if(ascii_strncasecmp("SEARCH ",line,7)==0
&& ascii_strncasecmp(" END",&line[strlen(line)-5],4)==0)
continue;
printf("%s",line);
}
/* Look for an info: line. The only current info: values
defined are the version and key count. */
if(!started && rl>0 && ascii_strncasecmp("info:",line,5)==0)
{
char *tok,*str=&line[5];
if((tok=strsep(&str,":"))!=NULL)
{
int version;
if(sscanf(tok,"%d",&version)!=1)
version=1;
if(version!=1)
{
log_error(_("invalid keyserver protocol "
"(us %d!=handler %d)\n"),1,version);
break;
}
}
if((tok=strsep(&str,":"))!=NULL && sscanf(tok,"%d",&count)==1)
{
if(count==0)
goto notfound;
else if(count<0)
count=10;
else
validcount=1;
desc=xrealloc(desc,count*sizeof(KEYDB_SEARCH_DESC));
}
started=1;
continue;
}
if(rl==0)
{
keyrec=parse_keyrec(NULL);
if(keyrec==NULL)
{
if(i==0)
{
count=0;
break;
}
if(i!=count)
validcount=0;
if (opt.with_colons && opt.batch)
break;
for(;;)
{
if (show_prompt (ctrl, desc, i, validcount?count:0, localstr))
break;
validcount=0;
}
break;
}
}
else
keyrec=parse_keyrec(line);
if(i==count)
{
/* keyserver helper sent more keys than they claimed in the
info: line. */
count+=10;
desc=xrealloc(desc,count*sizeof(KEYDB_SEARCH_DESC));
validcount=0;
}
if(keyrec)
{
desc[i]=keyrec->desc;
if(!opt.with_colons)
{
/* screen_lines - 1 for the prompt. */
if(numlines+keyrec->lines>opt.screen_lines-1)
{
if (show_prompt (ctrl, desc, i, validcount?count:0, localstr))
break;
else
numlines=0;
}
print_keyrec(i+1,keyrec);
}
numlines+=keyrec->lines;
iobuf_close(keyrec->uidbuf);
xfree(keyrec);
started=1;
i++;
}
}
notfound:
/* Leave this commented out or now, and perhaps for a very long
time. All HKPish servers return HTML error messages for
no-key-found. */
/*
if(!started)
log_info(_("keyserver does not support searching\n"));
else
*/
if(count==0)
{
if(localstr)
log_info(_("key \"%s\" not found on keyserver\n"),localstr);
else
log_info(_("key not found on keyserver\n"));
}
xfree(localstr);
xfree(desc);
xfree(line);
}
/* We sometimes want to use a different gpgkeys_xxx for a given /* We sometimes want to use a different gpgkeys_xxx for a given
protocol (for example, ldaps is handled by gpgkeys_ldap). Map protocol (for example, ldaps is handled by gpgkeys_ldap). Map
@ -1513,7 +1559,7 @@ keyserver_spawn (ctrl_t ctrl,
break; break;
case KS_SEARCH: case KS_SEARCH:
keyserver_search_prompt (ctrl, spawn->fromchild,searchstr); //keyserver_search_prompt (ctrl, spawn->fromchild,searchstr);
break; break;
default: default:
@ -1532,6 +1578,8 @@ keyserver_spawn (ctrl_t ctrl,
} }
static int static int
keyserver_work (ctrl_t ctrl, keyserver_work (ctrl_t ctrl,
enum ks_action action,strlist_t list,KEYDB_SEARCH_DESC *desc, enum ks_action action,strlist_t list,KEYDB_SEARCH_DESC *desc,
@ -1596,6 +1644,10 @@ keyserver_work (ctrl_t ctrl,
return 0; return 0;
} }
int int
keyserver_export (ctrl_t ctrl, strlist_t users) keyserver_export (ctrl_t ctrl, strlist_t users)
{ {
@ -1661,8 +1713,7 @@ keyserver_import (ctrl_t ctrl, strlist_t users)
} }
if(count>0) if(count>0)
rc=keyserver_work (ctrl, KS_GET, NULL, desc, count, rc=keyserver_get (ctrl, desc, count, NULL);
NULL, NULL, opt.keyserver);
xfree(desc); xfree(desc);
@ -1688,7 +1739,7 @@ keyserver_import_fprint (ctrl_t ctrl, const byte *fprint,size_t fprint_len,
/* TODO: Warn here if the fingerprint we got doesn't match the one /* TODO: Warn here if the fingerprint we got doesn't match the one
we asked for? */ we asked for? */
return keyserver_work (ctrl, KS_GET, NULL, &desc, 1, NULL, NULL, keyserver); return keyserver_get (ctrl, &desc, 1, keyserver);
} }
int int
@ -1703,7 +1754,7 @@ keyserver_import_keyid (ctrl_t ctrl,
desc.u.kid[0]=keyid[0]; desc.u.kid[0]=keyid[0];
desc.u.kid[1]=keyid[1]; desc.u.kid[1]=keyid[1];
return keyserver_work (ctrl, KS_GET,NULL,&desc,1,NULL,NULL,keyserver); return keyserver_get (ctrl, &desc,1, keyserver);
} }
/* code mostly stolen from do_export_stream */ /* code mostly stolen from do_export_stream */
@ -1907,9 +1958,7 @@ keyserver_refresh (ctrl_t ctrl, strlist_t users)
/* We use the keyserver structure we parsed out before. /* We use the keyserver structure we parsed out before.
Note that a preferred keyserver without a scheme:// Note that a preferred keyserver without a scheme://
will be interpreted as hkp:// */ will be interpreted as hkp:// */
rc = keyserver_get (ctrl, &desc[i], 1, keyserver);
rc = keyserver_work (ctrl, KS_GET, NULL, &desc[i], 1,
NULL, NULL, keyserver);
if(rc) if(rc)
log_info(_("WARNING: unable to refresh key %s" log_info(_("WARNING: unable to refresh key %s"
" via %s: %s\n"),keystr_from_desc(&desc[i]), " via %s: %s\n"),keystr_from_desc(&desc[i]),
@ -1939,8 +1988,7 @@ keyserver_refresh (ctrl_t ctrl, strlist_t users)
count,opt.keyserver->uri); count,opt.keyserver->uri);
} }
rc=keyserver_work (ctrl, KS_GET, NULL, desc, numdesc, rc=keyserver_get (ctrl, desc, numdesc, NULL);
NULL, NULL, opt.keyserver);
} }
xfree(desc); xfree(desc);
@ -1955,16 +2003,18 @@ keyserver_refresh (ctrl_t ctrl, strlist_t users)
return rc; return rc;
} }
/* Search for keys on the keyservers. The patterns are given in the /* Search for keys on the keyservers. The patterns are given in the
string list TOKENS. */ string list TOKENS. */
gpg_error_t gpg_error_t
keyserver_search (ctrl_t ctrl, strlist_t tokens) keyserver_search (ctrl_t ctrl, strlist_t tokens)
{ {
gpg_error_t err; gpg_error_t err;
int rc=0,ret=0;
char *searchstr; char *searchstr;
struct search_line_handler_parm_s parm;
memset (&parm, 0, sizeof parm);
/* FIXME: WORK IN PROGRESS */
if (!tokens) if (!tokens)
return 0; /* Return success if no patterns are given. */ return 0; /* Return success if no patterns are given. */
@ -1974,31 +2024,6 @@ keyserver_search (ctrl_t ctrl, strlist_t tokens)
return gpg_error (GPG_ERR_NO_KEYSERVER); return gpg_error (GPG_ERR_NO_KEYSERVER);
} }
/* switch(ret) */
/* { */
/* case KEYSERVER_SCHEME_NOT_FOUND: */
/* log_error(_("no handler for keyserver scheme `%s'\n"), */
/* opt.keyserver->scheme); */
/* break; */
/* case KEYSERVER_NOT_SUPPORTED: */
/* log_error(_("action `%s' not supported with keyserver " */
/* "scheme `%s'\n"), "search", opt.keyserver->scheme); */
/* break; */
/* case KEYSERVER_TIMEOUT: */
/* log_error(_("keyserver timed out\n")); */
/* break; */
/* case KEYSERVER_INTERNAL_ERROR: */
/* default: */
/* log_error(_("keyserver internal error\n")); */
/* break; */
/* } */
/* return gpg_error (GPG_ERR_KEYSERVER); */
/* Write global options */ /* Write global options */
/* for(temp=opt.keyserver_options.other;temp;temp=temp->next) */ /* for(temp=opt.keyserver_options.other;temp;temp=temp->next) */
@ -2009,8 +2034,6 @@ keyserver_search (ctrl_t ctrl, strlist_t tokens)
/* for(temp=keyserver->options;temp;temp=temp->next) */ /* for(temp=keyserver->options;temp;temp=temp->next) */
/* fprintf(spawn->tochild,"OPTION %s\n",temp->d); */ /* fprintf(spawn->tochild,"OPTION %s\n",temp->d); */
/* Which keys do we want? Remember that the gpgkeys_ program
is going to lump these together into a search string. */
{ {
membuf_t mb; membuf_t mb;
strlist_t item; strlist_t item;
@ -2027,28 +2050,226 @@ keyserver_search (ctrl_t ctrl, strlist_t tokens)
if (!searchstr) if (!searchstr)
{ {
err = gpg_error_from_syserror (); err = gpg_error_from_syserror ();
goto leave;
} }
} }
log_info (_("searching for \"%s\" from %s\n"), searchstr, keyserver->uri); /* FIXME: Enable the next line */
/* log_info (_("searching for \"%s\" from %s\n"), searchstr, keyserver->uri); */
{ parm.ctrl = ctrl;
estream_t fp; if (searchstr)
err = gpg_dirmngr_ks_search (ctrl, searchstr, &fp); parm.searchstr_disp = utf8_to_native (searchstr, strlen (searchstr), 0);
err = gpg_dirmngr_ks_search (ctrl, searchstr, search_line_handler, &parm);
if (parm.not_found)
{
if (parm.searchstr_disp)
log_info (_("key \"%s\" not found on keyserver\n"),
parm.searchstr_disp);
else
log_info (_("key not found on keyserver\n"));
}
if (gpg_err_code (err) == GPG_ERR_NO_KEYSERVER)
log_error (_("no keyserver known (use option --keyserver)\n"));
else if (err)
log_error ("error searching keyserver: %s\n", gpg_strerror (err));
/* switch(ret) */
/* { */
/* case KEYSERVER_SCHEME_NOT_FOUND: */
/* log_error(_("no handler for keyserver scheme `%s'\n"), */
/* opt.keyserver->scheme); */
/* break; */
/* case KEYSERVER_NOT_SUPPORTED: */
/* log_error(_("action `%s' not supported with keyserver " */
/* "scheme `%s'\n"), "search", opt.keyserver->scheme); */
/* break; */
/* case KEYSERVER_TIMEOUT: */
/* log_error(_("keyserver timed out\n")); */
/* break; */
/* case KEYSERVER_INTERNAL_ERROR: */
/* default: */
/* log_error(_("keyserver internal error\n")); */
/* break; */
/* } */
/* return gpg_error (GPG_ERR_KEYSERVER); */
keyserver_search_prompt (ctrl, fp,searchstr);
}
leave: leave:
xfree(line); xfree (parm.desc);
xfree (parm.searchstr_disp);
xfree(searchstr); xfree(searchstr);
return err;
*prog=exec_finish(spawn);
return ret;
} }
/* 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);
import_ldap:
rc = keyserver_work (ctrl, KS_GETNAME, list, NULL,
0, fpr, fpr_len, keyserver);
*/
static gpg_error_t
keyserver_get (ctrl_t ctrl, KEYDB_SEARCH_DESC *desc, int ndesc,
struct keyserver_spec *keyserver)
{
gpg_error_t err = 0;
char **pattern;
int idx, npat;
estream_t datastream;
/* Create an array filled with a search pattern for each key. The
array is delimited by a NULL entry. */
pattern = xtrycalloc (ndesc+1, sizeof *pattern);
if (!pattern)
return gpg_error_from_syserror ();
for (npat=idx=0; idx < ndesc; idx++)
{
int quiet = 0;
if (desc[idx].mode == KEYDB_SEARCH_MODE_FPR20
|| desc[idx].mode == KEYDB_SEARCH_MODE_FPR16)
{
pattern[npat] = xtrymalloc (2+2*20+1);
if (!pattern[npat])
err = gpg_error_from_syserror ();
else
{
strcpy (pattern[npat], "0x");
bin2hex (desc[idx].u.fpr,
desc[idx].mode == KEYDB_SEARCH_MODE_FPR20? 20 : 16,
pattern[npat]+2);
npat++;
}
}
else if(desc[idx].mode == KEYDB_SEARCH_MODE_LONG_KID)
{
pattern[npat] = xtryasprintf ("0x%08lX%08lX",
(ulong)desc[idx].u.kid[0],
(ulong)desc[idx].u.kid[1]);
if (!pattern[npat])
err = gpg_error_from_syserror ();
else
npat++;
}
else if(desc[idx].mode == KEYDB_SEARCH_MODE_SHORT_KID)
{
pattern[npat] = xtryasprintf ("0x%08lX", (ulong)desc[idx].u.kid[1]);
if (!pattern[npat])
err = gpg_error_from_syserror ();
else
npat++;
}
else if(desc[idx].mode == KEYDB_SEARCH_MODE_EXACT)
{
/* FIXME: We don't need this. It is used as a dummy by
keyserver_fetch which passes an entire URL. Better use a
separate function here. */
pattern[npat] = xtrystrdup ("0x0000000000000000");
if (!pattern[npat])
err = gpg_error_from_syserror ();
else
{
npat++;
quiet = 1;
}
}
else if (desc[idx].mode == KEYDB_SEARCH_MODE_NONE)
continue;
else
BUG();
if (err)
{
for (idx=0; idx < npat; idx++)
xfree (pattern[idx]);
xfree (pattern);
return err;
}
if (!quiet && keyserver)
{
if (keyserver->host)
log_info (_("requesting key %s from %s server %s\n"),
keystr_from_desc (&desc[idx]),
keyserver->scheme, keyserver->host);
else
log_info (_("requesting key %s from %s\n"),
keystr_from_desc (&desc[idx]), keyserver->uri);
}
}
err = gpg_dirmngr_ks_get (ctrl, pattern, &datastream);
for (idx=0; idx < npat; idx++)
xfree (pattern[idx]);
xfree (pattern);
if (!err)
{
void *stats_handle;
stats_handle = import_new_stats_handle();
/* FIXME: Check whether this comment should be moved to dirmngr.
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. */
import_keys_es_stream (ctrl, datastream, stats_handle, NULL, NULL,
opt.keyserver_options.import_options);
import_print_stats (stats_handle);
import_release_stats_handle (stats_handle);
}
es_fclose (datastream);
return err;
}
int int
keyserver_fetch (ctrl_t ctrl, strlist_t urilist) keyserver_fetch (ctrl_t ctrl, strlist_t urilist)
{ {
@ -2075,7 +2296,7 @@ keyserver_fetch (ctrl_t ctrl, strlist_t urilist)
{ {
int rc; int rc;
rc = keyserver_work (ctrl, KS_GET, NULL, &desc, 1, NULL, NULL, spec); rc = keyserver_get (ctrl, &desc, 1, spec);
if(rc) if(rc)
log_info (_("WARNING: unable to fetch URI %s: %s\n"), log_info (_("WARNING: unable to fetch URI %s: %s\n"),
sl->d,g10_errstr(rc)); sl->d,g10_errstr(rc));

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