diff --git a/common/stringhelp.c b/common/stringhelp.c index 2d2b412dc..7cbf82ccc 100644 --- a/common/stringhelp.c +++ b/common/stringhelp.c @@ -77,7 +77,7 @@ change_slashes (char *name) /* - * Check whether STRINGS starts with KEYWORD. The keyword is + * Check whether STRING starts with KEYWORD. The keyword is * delimited by end of string, a space or a tab. Returns NULL if not * found or a pointer into STRING to the next non-space character * after the KEYWORD (which may be end of string). diff --git a/dirmngr/ks-engine-hkp.c b/dirmngr/ks-engine-hkp.c index 28b05e919..5c4543575 100644 --- a/dirmngr/ks-engine-hkp.c +++ b/dirmngr/ks-engine-hkp.c @@ -454,8 +454,7 @@ mark_host_dead (const char *name) /* Mark a host in the hosttable as dead or - if ALIVE is true - as - alive. If the host NAME does not exist a warning status message is - printed. */ + alive. */ gpg_error_t ks_hkp_mark_host (ctrl_t ctrl, const char *name, int alive) { @@ -974,6 +973,10 @@ ks_hkp_search (ctrl_t ctrl, parsed_uri_t uri, const char *pattern, if (err) goto leave; + err = dirmngr_status (ctrl, "SOURCE", hostport, NULL); + if (err) + goto leave; + /* Peek at the response. */ { int c = es_getc (fp); @@ -1082,6 +1085,10 @@ ks_hkp_get (ctrl_t ctrl, parsed_uri_t uri, const char *keyspec, estream_t *r_fp) if (err) goto leave; + err = dirmngr_status (ctrl, "SOURCE", hostport, NULL); + if (err) + goto leave; + /* Return the read stream and close the HTTP context. */ *r_fp = fp; fp = NULL; diff --git a/g10/call-dirmngr.c b/g10/call-dirmngr.c index 993533377..73f829ef2 100644 --- a/g10/call-dirmngr.c +++ b/g10/call-dirmngr.c @@ -40,6 +40,13 @@ #include "call-dirmngr.h" +/* Parameter structure used to gather status info. */ +struct ks_status_parm_s +{ + char *source; +}; + + /* Parameter structure used with the KS_SEARCH command. */ struct ks_search_parm_s { @@ -47,8 +54,9 @@ struct ks_search_parm_s 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. */ + gpg_error_t (*data_cb)(void*, int, char*); /* Callback. */ void *data_cb_value; /* First argument for DATA_CB. */ + struct ks_status_parm_s *stparm; /* Link to the status parameter. */ }; @@ -234,6 +242,29 @@ close_context (ctrl_t ctrl, assuan_context_t ctx) } + +/* Status callback for ks_get and ks_search. */ +static gpg_error_t +ks_status_cb (void *opaque, const char *line) +{ + struct ks_status_parm_s *parm = opaque; + gpg_error_t err = 0; + const char *s; + + if ((s = has_leading_keyword (line, "SOURCE"))) + { + if (!parm->source) + { + parm->source = xtrystrdup (s); + if (!parm->source) + err = gpg_error_from_syserror (); + } + } + + return err; +} + + /* Data callback for the KS_SEARCH command. */ static gpg_error_t @@ -248,6 +279,22 @@ ks_search_data_cb (void *opaque, const void *data, size_t datalen) if (parm->lasterr) return 0; + if (parm->stparm->source) + { + err = parm->data_cb (parm->data_cb_value, 1, parm->stparm->source); + if (err) + { + parm->lasterr = err; + return err; + } + /* Clear it so that we won't get back here unless the server + accidentally sends a second source status line. Note that + will not see all accidentally sent source lines because it + depends on whether data lines have been send in between. */ + xfree (parm->stparm->source); + parm->stparm->source = NULL; + } + if (!data) return 0; /* Ignore END commands. */ @@ -270,7 +317,7 @@ ks_search_data_cb (void *opaque, const void *data, size_t datalen) fixedbuf[linelen] = 0; if (linelen && fixedbuf[linelen-1] == '\r') fixedbuf[linelen-1] = 0; - err = parm->data_cb (parm->data_cb_value, fixedbuf); + err = parm->data_cb (parm->data_cb_value, 0, fixedbuf); } else { @@ -289,7 +336,7 @@ ks_search_data_cb (void *opaque, const void *data, size_t datalen) 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); + err = parm->data_cb (parm->data_cb_value, 0, parm->helpbuf); } if (err) parm->lasterr = err; @@ -306,17 +353,18 @@ ks_search_data_cb (void *opaque, const void *data, size_t datalen) /* 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. */ + with CB_VALUE as its first argument, a 0 as second argument, and + the decoded data line as third 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 (*cb)(void*, int, char *), void *cb_value) { gpg_error_t err; assuan_context_t ctx; + struct ks_status_parm_s stparm; struct ks_search_parm_s parm; char line[ASSUAN_LINELENGTH]; @@ -336,18 +384,21 @@ gpg_dirmngr_ks_search (ctrl_t ctrl, const char *searchstr, xfree (escsearchstr); } + memset (&stparm, 0, sizeof stparm); memset (&parm, 0, sizeof parm); init_membuf (&parm.saveddata, 1024); parm.data_cb = cb; parm.data_cb_value = cb_value; + parm.stparm = &stparm; err = assuan_transact (ctx, line, ks_search_data_cb, &parm, - NULL, NULL, NULL, NULL); + NULL, NULL, ks_status_cb, &stparm); if (!err) - err = cb (cb_value, NULL); /* Send EOF. */ + err = cb (cb_value, 0, NULL); /* Send EOF. */ xfree (get_membuf (&parm.saveddata, NULL)); xfree (parm.helpbuf); + xfree (stparm.source); close_context (ctrl, ctx); return err; @@ -382,24 +433,32 @@ ks_get_data_cb (void *opaque, const void *data, size_t datalen) don't need to escape the patterns before sending them to the server. + If R_SOURCE is not NULL the source of the data is stored as a + malloced string there. If a source is not known NULL is stored. + 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_dirmngr_ks_get (ctrl_t ctrl, char **pattern, + estream_t *r_fp, char **r_source) { gpg_error_t err; assuan_context_t ctx; + struct ks_status_parm_s stparm; struct ks_get_parm_s parm; char *line = NULL; size_t linelen; membuf_t mb; int idx; + memset (&stparm, 0, sizeof stparm); memset (&parm, 0, sizeof parm); *r_fp = NULL; + if (r_source) + *r_source = NULL; err = open_context (ctrl, &ctx); if (err) @@ -433,7 +492,7 @@ gpg_dirmngr_ks_get (ctrl_t ctrl, char **pattern, estream_t *r_fp) goto leave; } err = assuan_transact (ctx, line, ks_get_data_cb, &parm, - NULL, NULL, NULL, NULL); + NULL, NULL, ks_status_cb, &stparm); if (err) goto leave; @@ -441,8 +500,15 @@ gpg_dirmngr_ks_get (ctrl_t ctrl, char **pattern, estream_t *r_fp) *r_fp = parm.memfp; parm.memfp = NULL; + if (r_source) + { + *r_source = stparm.source; + stparm.source = NULL; + } + leave: es_fclose (parm.memfp); + xfree (stparm.source); xfree (line); close_context (ctrl, ctx); return err; diff --git a/g10/call-dirmngr.h b/g10/call-dirmngr.h index 933303dbf..481b948d9 100644 --- a/g10/call-dirmngr.h +++ b/g10/call-dirmngr.h @@ -22,9 +22,10 @@ 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 *), + gpg_error_t (*cb)(void*, int, 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_get (ctrl_t ctrl, char *pattern[], + estream_t *r_fp, char **r_source); gpg_error_t gpg_dirmngr_ks_fetch (ctrl_t ctrl, const char *url, estream_t *r_fp); gpg_error_t gpg_dirmngr_ks_put (ctrl_t ctrl, void *data, size_t datalen, diff --git a/g10/keyserver.c b/g10/keyserver.c index b8ab81e46..3a3bc40e7 100644 --- a/g10/keyserver.c +++ b/g10/keyserver.c @@ -831,17 +831,29 @@ show_prompt (ctrl_t ctrl, KEYDB_SEARCH_DESC *desc, int numdesc, /* 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. */ + KS_SEARCH command. If SPECIAL is 0, 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. + If special is 1, the line conatins the source of the information + (usually an URL). LINE may be modified after return. */ static gpg_error_t -search_line_handler (void *opaque, char *line) +search_line_handler (void *opaque, int special, char *line) { struct search_line_handler_parm_s *parm = opaque; gpg_error_t err = 0; struct keyrec *keyrec; + if (special == 1) + { + log_info ("data source: %s\n", line); + return 0; + } + else if (special) + { + log_debug ("unknown value %d for special search callback", special); + return 0; + } + if (parm->eof_seen && line) { log_debug ("ooops: unexpected data after EOF\n"); @@ -1478,6 +1490,7 @@ keyserver_get (ctrl_t ctrl, KEYDB_SEARCH_DESC *desc, int ndesc, char **pattern; int idx, npat; estream_t datastream; + char *source = NULL; /* Create an array filled with a search pattern for each key. The array is delimited by a NULL entry. */ @@ -1561,10 +1574,13 @@ keyserver_get (ctrl_t ctrl, KEYDB_SEARCH_DESC *desc, int ndesc, } - err = gpg_dirmngr_ks_get (ctrl, pattern, &datastream); + err = gpg_dirmngr_ks_get (ctrl, pattern, &datastream, &source); for (idx=0; idx < npat; idx++) xfree (pattern[idx]); xfree (pattern); + if (opt.verbose) + log_info ("data source: %s\n", source); + if (!err) { void *stats_handle; @@ -1590,7 +1606,7 @@ keyserver_get (ctrl_t ctrl, KEYDB_SEARCH_DESC *desc, int ndesc, import_release_stats_handle (stats_handle); } es_fclose (datastream); - + xfree (source); return err; }