aboutsummaryrefslogtreecommitdiffstats
path: root/g10
diff options
context:
space:
mode:
Diffstat (limited to 'g10')
-rw-r--r--g10/ChangeLog8
-rw-r--r--g10/call-dirmngr.c262
-rw-r--r--g10/call-dirmngr.h4
-rw-r--r--g10/gpg.c10
-rw-r--r--g10/import.c26
-rw-r--r--g10/keyserver.c741
-rw-r--r--g10/main.h3
7 files changed, 749 insertions, 305 deletions
diff --git a/g10/ChangeLog b/g10/ChangeLog
index 1be035d39..27f60fe24 100644
--- a/g10/ChangeLog
+++ b/g10/ChangeLog
@@ -1,3 +1,11 @@
+2011-01-18 Werner Koch <[email protected]>
+
+ * import.c (import_keys_es_stream): New.
+
+2011-01-14 Werner Koch <[email protected]>
+
+ * keyserver.c (parse_keyrec): Use trim_trailing_ws.
+
2011-01-07 Werner Koch <[email protected]>
* call-dirmngr.c, call-dirmngr.h: New.
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;
}
diff --git a/g10/call-dirmngr.h b/g10/call-dirmngr.h
index fa579ad5c..c848a2902 100644
--- a/g10/call-dirmngr.h
+++ b/g10/call-dirmngr.h
@@ -21,6 +21,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 *),
+ 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*/
diff --git a/g10/gpg.c b/g10/gpg.c
index 1866c1cc8..a0ec48341 100644
--- a/g10/gpg.c
+++ b/g10/gpg.c
@@ -3752,12 +3752,12 @@ main (int argc, char **argv)
case aSearchKeys:
sl = NULL;
- for( ; argc; argc--, argv++ )
- append_to_strlist2( &sl, *argv, utf8_strings );
+ for (; argc; argc--, argv++)
+ append_to_strlist2 (&sl, *argv, utf8_strings);
rc = keyserver_search (ctrl, sl);
- if(rc)
- log_error(_("keyserver search failed: %s\n"),g10_errstr(rc));
- free_strlist(sl);
+ if (rc)
+ log_error (_("keyserver search failed: %s\n"), gpg_strerror (rc));
+ free_strlist (sl);
break;
case aRefreshKeys:
diff --git a/g10/import.c b/g10/import.c
index 31160c33e..88abafd6a 100644
--- a/g10/import.c
+++ b/g10/import.c
@@ -243,6 +243,32 @@ import_keys_stream (ctrl_t ctrl, IOBUF inp, void *stats_handle,
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
import (ctrl_t ctrl, IOBUF inp, const char* fname,struct stats_s *stats,
unsigned char **fpr,size_t *fpr_len,unsigned int options )
diff --git a/g10/keyserver.c b/g10/keyserver.c
index 60a117d2e..e560d4bfa 100644
--- a/g10/keyserver.c
+++ b/g10/keyserver.c
@@ -1,6 +1,6 @@
/* keyserver.c - generic keyserver code
* 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.
*
@@ -18,6 +18,9 @@
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
+/* !!! FIXME: Replace all printf by es_printf. FIXME !!! */
+
+
#include <config.h>
#include <ctype.h>
#include <stdio.h>
@@ -46,7 +49,7 @@
#include "srv.h"
#endif
#include "membuf.h"
-
+#include "call-dirmngr.h"
#ifdef HAVE_W32_SYSTEM
/* It seems Vista doesn't grok X_OK and so fails access() tests.
@@ -66,6 +69,24 @@ struct keyrec
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};
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,
unsigned char **fpr,size_t *fpr_len,
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 */
#define DEFAULT_MAX_CERT_SIZE 16384
@@ -556,6 +581,8 @@ print_keyrec(int number,struct keyrec *keyrec)
static struct keyrec *
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;
struct keyrec *ret=NULL;
char *record;
@@ -584,12 +611,7 @@ parse_keyrec(char *keystring)
work->uidbuf=iobuf_temp();
}
- /* Remove trailing whitespace */
- for(i=strlen(keystring);i>0;i--)
- if(ascii_isspace(keystring[i-1]))
- keystring[i-1]='\0';
- else
- break;
+ trim_trailing_ws (keystring, strlen (keystring));
if((record=strsep(&keystring,":"))==NULL)
return ret;
@@ -665,7 +687,7 @@ parse_keyrec(char *keystring)
case 'R':
work->flags|=1;
break;
-
+
case 'd':
case 'D':
work->flags|=2;
@@ -728,221 +750,245 @@ parse_keyrec(char *keystring)
return ret;
}
-/* TODO: do this as a list sent to keyserver_work rather than calling
- it once for each key to get the correct counts after the import
- (cosmetics, really) and to better take advantage of the keyservers
- that can do multiple fetches in one go (LDAP). */
-static int
-show_prompt (ctrl_t ctrl,
- KEYDB_SEARCH_DESC *desc,int numdesc,int count,const char *search)
+/* Show a prompt and allow the user to select keys for retrieval. */
+static gpg_error_t
+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);
- if(count && opt.command_fd==-1)
+ if (count && opt.command_fd == -1)
{
- static int from=1;
- tty_printf("Keys %d-%d of %d for \"%s\". ",from,numdesc,count,search);
- from=numdesc+1;
+ static int from = 1;
+ tty_printf ("Keys %d-%d of %d for \"%s\". ",
+ from, numdesc, count, search);
+ from = numdesc + 1;
}
- answer=cpr_get_no_help("keysearch.prompt",
- _("Enter number(s), N)ext, or Q)uit > "));
+ again:
+ err = 0;
+ xfree (answer);
+ answer = cpr_get_no_help ("keysearch.prompt",
+ _("Enter number(s), N)ext, or Q)uit > "));
/* control-d */
- if(answer[0]=='\x04')
+ if (answer[0]=='\x04')
{
- printf("Q\n");
- answer[0]='q';
+ tty_printf ("Q\n");
+ 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);
- return 1;
- }
- else if(atoi(answer)>=1 && atoi(answer)<=numdesc)
- {
- char *split=answer,*num;
-
- while((num=strsep(&split," ,"))!=NULL)
- if(atoi(num)>=1 && atoi(num)<=numdesc)
- keyserver_work (ctrl, KS_GET,NULL,&desc[atoi(num)-1],1,
- NULL,NULL,opt.keyserver);
+ char *split = answer;
+ 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;
- xfree(answer);
- return 1;
+ {
+ 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);
+ }
}
- return 0;
+ leave:
+ xfree (answer);
+ return err;
}
-/* 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));
+/* 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;
- for(;;)
+ if (parm->eof_seen && line)
{
- 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;
+ log_debug ("ooops: unexpected data after EOF\n");
+ line = NULL;
+ }
- 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 the received line. */
+ if (opt.with_colons && line)
+ {
+ log_debug ("%s\n",line);
+ }
- print_keyrec(i+1,keyrec);
- }
+ /* Look for an info: line. The only current info: values defined
+ are the version and key count. */
+ if (line && !parm->any_lines && !ascii_strncasecmp ("info:", line, 5))
+ {
+ char *str = line + 5;
+ char *tok;
- numlines+=keyrec->lines;
- iobuf_close(keyrec->uidbuf);
- xfree(keyrec);
+ 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. */
+ }
- started=1;
- i++;
- }
+ 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;
+ }
+ }
+ }
}
- 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)
+ /* Save the key in the key array. */
+ if (keyrec)
{
- if(localstr)
- log_info(_("key \"%s\" not found on keyserver\n"),localstr);
- else
- log_info(_("key not found on keyserver\n"));
+ /* 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;
}
- xfree(localstr);
- xfree(desc);
- xfree(line);
+ return 0;
}
+
/* We sometimes want to use a different gpgkeys_xxx for a given
protocol (for example, ldaps is handled by gpgkeys_ldap). Map
these here. */
@@ -978,7 +1024,7 @@ direct_uri_map(const char *scheme,unsigned int is_direct)
#define KEYSERVER_ARGS_KEEP " -o \"%O\" \"%I\""
#define KEYSERVER_ARGS_NOKEEP " -o \"%o\" \"%i\""
-static int
+static int
keyserver_spawn (ctrl_t ctrl,
enum ks_action action,strlist_t list,KEYDB_SEARCH_DESC *desc,
int count,int *prog,unsigned char **fpr,size_t *fpr_len,
@@ -1019,7 +1065,7 @@ keyserver_spawn (ctrl_t ctrl,
the program of this process lives. Fortunately Windows provides
a way to retrieve this and our gnupg_libexecdir function has been
modified to return just this. Setting the exec-path is not
- anymore required.
+ anymore required.
set_exec_path(libexecdir);
*/
#else
@@ -1049,7 +1095,7 @@ keyserver_spawn (ctrl_t ctrl,
fetcher that can speak that protocol (this is a problem for
LDAP). */
- strcat(command,GPGKEYS_PREFIX);
+ strcat(command,GPGKEYS_PREFIX);
strcat(command,scheme);
/* This "_uri" thing is in case we need to call a direct handler
@@ -1079,7 +1125,7 @@ keyserver_spawn (ctrl_t ctrl,
{
command=xrealloc(command,strlen(command)+
strlen(KEYSERVER_ARGS_NOKEEP)+1);
- strcat(command,KEYSERVER_ARGS_NOKEEP);
+ strcat(command,KEYSERVER_ARGS_NOKEEP);
}
ret=exec_write(&spawn,NULL,command,NULL,0,0);
@@ -1497,7 +1543,7 @@ keyserver_spawn (ctrl_t ctrl,
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. */
-
+
/* FIXME: Pass CTRL. */
import_keys_stream (NULL, spawn->fromchild,stats_handle,fpr,fpr_len,
opt.keyserver_options.import_options);
@@ -1513,7 +1559,7 @@ keyserver_spawn (ctrl_t ctrl,
break;
case KS_SEARCH:
- keyserver_search_prompt (ctrl, spawn->fromchild,searchstr);
+ //keyserver_search_prompt (ctrl, spawn->fromchild,searchstr);
break;
default:
@@ -1532,7 +1578,9 @@ keyserver_spawn (ctrl_t ctrl,
}
-static int
+
+
+static int
keyserver_work (ctrl_t ctrl,
enum ks_action action,strlist_t list,KEYDB_SEARCH_DESC *desc,
int count,unsigned char **fpr,size_t *fpr_len,
@@ -1596,7 +1644,11 @@ keyserver_work (ctrl_t ctrl,
return 0;
}
-int
+
+
+
+
+int
keyserver_export (ctrl_t ctrl, strlist_t users)
{
gpg_error_t err;
@@ -1629,7 +1681,7 @@ keyserver_export (ctrl_t ctrl, strlist_t users)
return rc;
}
-int
+int
keyserver_import (ctrl_t ctrl, strlist_t users)
{
gpg_error_t err;
@@ -1661,8 +1713,7 @@ keyserver_import (ctrl_t ctrl, strlist_t users)
}
if(count>0)
- rc=keyserver_work (ctrl, KS_GET, NULL, desc, count,
- NULL, NULL, opt.keyserver);
+ rc=keyserver_get (ctrl, desc, count, NULL);
xfree(desc);
@@ -1688,10 +1739,10 @@ 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
we asked for? */
- return keyserver_work (ctrl, KS_GET, NULL, &desc, 1, NULL, NULL, keyserver);
+ return keyserver_get (ctrl, &desc, 1, keyserver);
}
-int
+int
keyserver_import_keyid (ctrl_t ctrl,
u32 *keyid,struct keyserver_spec *keyserver)
{
@@ -1703,11 +1754,11 @@ keyserver_import_keyid (ctrl_t ctrl,
desc.u.kid[0]=keyid[0];
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 */
-static int
+static int
keyidlist(strlist_t users,KEYDB_SEARCH_DESC **klist,int *count,int fakev3)
{
int rc=0,ndesc,num=100;
@@ -1730,13 +1781,13 @@ keyidlist(strlist_t users,KEYDB_SEARCH_DESC **klist,int *count,int fakev3)
}
else
{
- for (ndesc=0, sl=users; sl; sl = sl->next, ndesc++)
+ for (ndesc=0, sl=users; sl; sl = sl->next, ndesc++)
;
desc = xmalloc ( ndesc * sizeof *desc);
-
+
for (ndesc=0, sl=users; sl; sl = sl->next)
{
- gpg_error_t err;
+ gpg_error_t err;
if (!(err = classify_user_id (sl->d, desc+ndesc)))
ndesc++;
else
@@ -1747,7 +1798,7 @@ keyidlist(strlist_t users,KEYDB_SEARCH_DESC **klist,int *count,int fakev3)
while (!(rc = keydb_search (kdbhd, desc, ndesc)))
{
- if (!users)
+ if (!users)
desc[0].mode = KEYDB_SEARCH_MODE_NEXT;
/* read the keyblock */
@@ -1850,7 +1901,7 @@ keyidlist(strlist_t users,KEYDB_SEARCH_DESC **klist,int *count,int fakev3)
if(rc==-1)
rc=0;
-
+
leave:
if(rc)
xfree(*klist);
@@ -1907,9 +1958,7 @@ keyserver_refresh (ctrl_t ctrl, strlist_t users)
/* We use the keyserver structure we parsed out before.
Note that a preferred keyserver without a scheme://
will be interpreted as hkp:// */
-
- rc = keyserver_work (ctrl, KS_GET, NULL, &desc[i], 1,
- NULL, NULL, keyserver);
+ rc = keyserver_get (ctrl, &desc[i], 1, keyserver);
if(rc)
log_info(_("WARNING: unable to refresh key %s"
" 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);
}
- rc=keyserver_work (ctrl, KS_GET, NULL, desc, numdesc,
- NULL, NULL, opt.keyserver);
+ rc=keyserver_get (ctrl, desc, numdesc, NULL);
}
xfree(desc);
@@ -1955,16 +2003,18 @@ keyserver_refresh (ctrl_t ctrl, strlist_t users)
return rc;
}
+
/* Search for keys on the keyservers. The patterns are given in the
string list TOKENS. */
gpg_error_t
keyserver_search (ctrl_t ctrl, strlist_t tokens)
{
gpg_error_t err;
- int rc=0,ret=0;
char *searchstr;
+ struct search_line_handler_parm_s parm;
+
+ memset (&parm, 0, sizeof parm);
- /* FIXME: WORK IN PROGRESS */
if (!tokens)
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);
}
- /* 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 */
/* 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) */
/* 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;
strlist_t item;
@@ -2027,28 +2050,226 @@ keyserver_search (ctrl_t ctrl, strlist_t tokens)
if (!searchstr)
{
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;
+ if (searchstr)
+ 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); */
- {
- estream_t fp;
- err = gpg_dirmngr_ks_search (ctrl, searchstr, &fp);
-
- keyserver_search_prompt (ctrl, fp,searchstr);
- }
leave:
- xfree(line);
+ xfree (parm.desc);
+ xfree (parm.searchstr_disp);
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
keyserver_fetch (ctrl_t ctrl, strlist_t urilist)
{
@@ -2075,7 +2296,7 @@ keyserver_fetch (ctrl_t ctrl, strlist_t urilist)
{
int rc;
- rc = keyserver_work (ctrl, KS_GET, NULL, &desc, 1, NULL, NULL, spec);
+ rc = keyserver_get (ctrl, &desc, 1, spec);
if(rc)
log_info (_("WARNING: unable to fetch URI %s: %s\n"),
sl->d,g10_errstr(rc));
@@ -2275,7 +2496,7 @@ keyserver_import_ldap (ctrl_t ctrl,
snprintf(port,7,":%u",srvlist[i].port);
strcat(keyserver->host,port);
}
-
+
strcat(keyserver->host," ");
}
@@ -2291,7 +2512,7 @@ keyserver_import_ldap (ctrl_t ctrl,
strcat(keyserver->host,domain);
append_to_strlist(&list,name);
-
+
rc = keyserver_work (ctrl, KS_GETNAME, list, NULL,
0, fpr, fpr_len, keyserver);
diff --git a/g10/main.h b/g10/main.h
index b673cf559..2e760844a 100644
--- a/g10/main.h
+++ b/g10/main.h
@@ -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,
unsigned char **fpr,
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_release_stats_handle (void *p);
void import_print_stats (void *hd);