diff options
Diffstat (limited to 'g10/call-dirmngr.c')
-rw-r--r-- | g10/call-dirmngr.c | 262 |
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; } |