aboutsummaryrefslogtreecommitdiffstats
path: root/g10/call-dirmngr.c
diff options
context:
space:
mode:
Diffstat (limited to 'g10/call-dirmngr.c')
-rw-r--r--g10/call-dirmngr.c262
1 files changed, 222 insertions, 40 deletions
diff --git a/g10/call-dirmngr.c b/g10/call-dirmngr.c
index a18eb64b0..1816a72d3 100644
--- a/g10/call-dirmngr.c
+++ b/g10/call-dirmngr.c
@@ -36,9 +36,29 @@
#include "options.h"
#include "i18n.h"
#include "asshelp.h"
+#include "keyserver.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
use a simple one to one mapping because we sometimes need two
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;
/* The active Assuan context. */
- static assuan_context_t ctx;
+ assuan_context_t ctx;
/* Flag set to true while an operation is running on CTX. */
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
so that any keyserver configured in GPG overrides keyservers
possibly configured in Dirmngr. */
- if (ksi = opt.keyservers; !err && ksi; ksi = ksi->next)
+ for (ksi = opt.keyserver; !err && ksi; ksi = ksi->next)
{
char *line;
line = xtryasprintf ("KEYSERVER%s %s",
- ksi == opt.keyservers? " --clear":"", ksi->uri);
+ ksi == opt.keyserver? " --clear":"", ksi->uri);
if (!line)
err = gpg_error_from_syserror ();
else
@@ -156,7 +176,8 @@ open_context (ctrl_t ctrl, assuan_context_t *r_ctx)
/* Found an inactive local session - return that. */
assert (!dml->is_active);
dml->is_active = 1;
- return dml;
+ *r_ctx = dml->ctx;
+ return 0;
}
dml = xtrycalloc (1, sizeof *dml);
@@ -192,9 +213,9 @@ close_context (ctrl_t ctrl, assuan_context_t ctx)
{
if (dml->ctx == ctx)
{
- if (!ctx->is_active)
+ if (!dml->is_active)
log_fatal ("closing inactive dirmngr context %p\n", ctx);
- ctx->is_active = 0;
+ dml->is_active = 0;
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];
+
+ if (parm->lasterr)
+ return 0;
+
+ if (!data)
+ return 0; /* Ignore END commands. */
-int
-gpg_dirmngr_ks_search (ctrl_t ctrl, strlist_t names,
- void (*cb)(void*, ksba_cert_t), void *cb_value)
+ 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;
assuan_context_t ctx;
- char *pattern;
+ struct ks_search_parm_s parm;
char line[ASSUAN_LINELENGTH];
err = open_context (ctrl, &ctx);
if (err)
return err;
- pattern = pattern_from_strlist (names);
- if (!pattern)
+ {
+ char *escsearchstr = percent_plus_escape (searchstr);
+ if (!escsearchstr)
+ {
+ err = gpg_error_from_syserror ();
+ close_context (ctrl, ctx);
+ return err;
+ }
+ snprintf (line, sizeof line, "KS_SEARCH -- %s", escsearchstr);
+ xfree (escsearchstr);
+ }
+
+ memset (&parm, 0, sizeof parm);
+ init_membuf (&parm.saveddata, 1024);
+ parm.data_cb = cb;
+ parm.data_cb_value = cb_value;
+
+ err = assuan_transact (ctx, line, ks_search_data_cb, &parm,
+ NULL, NULL, NULL, NULL);
+ if (!err)
+ err = cb (cb_value, NULL); /* Send EOF. */
+
+ xfree (get_membuf (&parm.saveddata, NULL));
+ xfree (parm.helpbuf);
+
+ close_context (ctrl, ctx);
+ 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++)
{
- if (ctx == dirmngr_ctx)
- release_dirmngr (ctrl);
- else
- release_dirmngr2 (ctrl);
+ 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;
+ }
- return out_of_core ();
+ parm.memfp = es_fopenmem (0, "rwb");
+ if (!parm.memfp)
+ {
+ err = gpg_error_from_syserror ();
+ goto leave;
}
- snprintf (line, DIM(line)-1, "LOOKUP%s %s",
- cache_only? " --cache-only":"", pattern);
- line[DIM(line)-1] = 0;
- xfree (pattern);
-
- parm.ctrl = ctrl;
- parm.ctx = ctx;
- parm.cb = cb;
- parm.cb_value = cb_value;
- parm.error = 0;
- init_membuf (&parm.data, 4096);
-
- rc = assuan_transact (ctx, line, lookup_cb, &parm,
- NULL, NULL, lookup_status_cb, &parm);
- xfree (get_membuf (&parm.data, &len));
-
- if (ctx == dirmngr_ctx)
- release_dirmngr (ctrl);
- else
- release_dirmngr2 (ctrl);
+ err = assuan_transact (ctx, line, ks_get_data_cb, &parm,
+ NULL, NULL, NULL, NULL);
+ if (err)
+ goto leave;
- if (rc)
- return rc;
+ es_rewind (parm.memfp);
+ *r_fp = parm.memfp;
+ parm.memfp = NULL;
+ leave:
+ es_fclose (parm.memfp);
+ xfree (line);
close_context (ctrl, ctx);
- return parm.error;
+ return err;
}