From ad6abe791319e730f446f546d4d3552412fa5b9c Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Tue, 21 May 2002 19:20:40 +0000 Subject: [PATCH] * keylist.c (list_internal_keys): Renamed from gpgsm_list_keys. (list_external_keys): New. (gpgsm_list_keys): Dispatcher for above. * call-dirmngr.c (lookup_cb,pattern_from_strlist) (gpgsm_dirmngr_lookup): New. * server.c (option_handler): Handle new option --list-mode. (do_listkeys): Handle options and actually use the mode argument. (get_status_string): New code TRUNCATED. --- common/errors.h | 4 +- sm/ChangeLog | 9 ++ sm/call-dirmngr.c | 233 ++++++++++++++++++++++++++++++++++++++++++++-- sm/gpgsm.c | 4 +- sm/gpgsm.h | 3 +- sm/keylist.c | 77 +++++++++++++-- sm/server.c | 41 ++++++-- 7 files changed, 345 insertions(+), 26 deletions(-) diff --git a/common/errors.h b/common/errors.h index 71a7e4b5d..246a2c0ce 100644 --- a/common/errors.h +++ b/common/errors.h @@ -176,7 +176,9 @@ enum { STATUS_ALREADY_SIGNED, STATUS_EXPSIG, - STATUS_EXPKEYSIG + STATUS_EXPKEYSIG, + + STATUS_TRUNCATED }; diff --git a/sm/ChangeLog b/sm/ChangeLog index 941d66a22..ea4aac590 100644 --- a/sm/ChangeLog +++ b/sm/ChangeLog @@ -1,5 +1,14 @@ 2002-05-21 Werner Koch + * keylist.c (list_internal_keys): Renamed from gpgsm_list_keys. + (list_external_keys): New. + (gpgsm_list_keys): Dispatcher for above. + * call-dirmngr.c (lookup_cb,pattern_from_strlist) + (gpgsm_dirmngr_lookup): New. + * server.c (option_handler): Handle new option --list-mode. + (do_listkeys): Handle options and actually use the mode argument. + (get_status_string): New code TRUNCATED. + * import.c (gpgsm_import): Try to identify the type of input and handle certs-only messages. diff --git a/sm/call-dirmngr.c b/sm/call-dirmngr.c index 29f7a1d8e..7e6a35912 100644 --- a/sm/call-dirmngr.c +++ b/sm/call-dirmngr.c @@ -33,6 +33,15 @@ #include "../assuan/assuan.h" #include "i18n.h" +struct membuf { + size_t len; + size_t size; + char *buf; + int out_of_core; +}; + + + static ASSUAN_CONTEXT dirmngr_ctx = NULL; static int force_pipe_server = 0; @@ -41,15 +50,79 @@ struct inq_certificate_parm_s { KsbaCert cert; }; - -struct membuf { - size_t len; - size_t size; - char *buf; - int out_of_core; +struct lookup_parm_s { + ASSUAN_CONTEXT ctx; + void (*cb)(void *, KsbaCert); + void *cb_value; + struct membuf data; + int error; }; + + +/* A simple implementation of a dynamic buffer. Use init_membuf() to + create a buffer, put_membuf to append bytes and get_membuf to + release and return the buffer. Allocation errors are detected but + only returned at the final get_membuf(), this helps not to clutter + the code with out of core checks. */ + +static void +init_membuf (struct membuf *mb, int initiallen) +{ + mb->len = 0; + mb->size = initiallen; + mb->out_of_core = 0; + mb->buf = xtrymalloc (initiallen); + if (!mb->buf) + mb->out_of_core = 1; +} + +static void +put_membuf (struct membuf *mb, const void *buf, size_t len) +{ + if (mb->out_of_core) + return; + + if (mb->len + len >= mb->size) + { + char *p; + + mb->size += len + 1024; + p = xtryrealloc (mb->buf, mb->size); + if (!p) + { + mb->out_of_core = 1; + return; + } + mb->buf = p; + } + memcpy (mb->buf + mb->len, buf, len); + mb->len += len; +} + +static void * +get_membuf (struct membuf *mb, size_t *len) +{ + char *p; + + if (mb->out_of_core) + { + xfree (mb->buf); + mb->buf = NULL; + return NULL; + } + + p = mb->buf; + *len = mb->len; + mb->buf = NULL; + mb->out_of_core = 1; /* don't allow a reuse */ + return p; +} + + + + /* Try to connect to the agent via socket or fork it off and work by pipes. Handle the server's initial greeting */ @@ -234,3 +307,151 @@ gpgsm_dirmngr_isvalid (KsbaCert cert) } + +/* Lookup helpers*/ +static AssuanError +lookup_cb (void *opaque, const void *buffer, size_t length) +{ + struct lookup_parm_s *parm = opaque; + size_t len; + char *buf; + KsbaCert cert; + int rc; + + if (parm->error) + return 0; + + if (buffer) + { + put_membuf (&parm->data, buffer, length); + return 0; + } + /* END encountered - process what we have */ + buf = get_membuf (&parm->data, &len); + if (!buf) + { + parm->error = GNUPG_Out_Of_Core; + return 0; + } + + cert = ksba_cert_new (); + if (!cert) + { + parm->error = GNUPG_Out_Of_Core; + return 0; + } + rc = ksba_cert_init_from_mem (cert, buf, len); + if (rc) + { + log_error ("failed to parse a certificate: %s\n", ksba_strerror (rc)); + } + else + { + parm->cb (parm->cb_value, cert); + } + + ksba_cert_release (cert); + init_membuf (&parm->data, 4096); + return 0; +} + +/* Return a properly escaped pattern from NAMES. The only error + return is NULL to indicate a malloc failure. */ +static char * +pattern_from_strlist (STRLIST names) +{ + STRLIST sl; + int n; + const char *s; + char *pattern, *p; + + for (n=0, sl=names; sl; sl = sl->next) + { + for (s=sl->d; *s; s++, n++) + { + if (*s == '%' || *s == ' ' || *s == '+') + n += 2; + } + n++; + } + + p = pattern = xtrymalloc (n+1); + if (!pattern) + return NULL; + + for (n=0, sl=names; sl; sl = sl->next) + { + for (s=sl->d; *s; s++) + { + switch (*s) + { + case '%': + *p++ = '%'; + *p++ = '2'; + *p++ = '5'; + break; + case ' ': + *p++ = '%'; + *p++ = '2'; + *p++ = '0'; + break; + case '+': + *p++ = '%'; + *p++ = '2'; + *p++ = 'B'; + break; + default: + *p++ = *s; + break; + } + } + *p++ = ' '; + } + if (p == pattern) + *pattern = 0; /* is empty */ + else + p[-1] = '\0'; /* remove trailing blank */ + + return pattern; +} + + +/* Run the Directroy Managers lookup command using the apptern + compiled from the strings given in NAMES. The caller must provide + the callback CB which will be passed cert by cert. */ +int +gpgsm_dirmngr_lookup (STRLIST names, + void (*cb)(void*, KsbaCert), void *cb_value) +{ + int rc; + char *pattern; + char line[ASSUAN_LINELENGTH]; + struct lookup_parm_s parm; + size_t len; + + /* FIXME: Set an status handler so that we can get the TRUNCATED code */ + + rc = start_dirmngr (); + if (rc) + return rc; + + pattern = pattern_from_strlist (names); + if (!pattern) + return GNUPG_Out_Of_Core; + snprintf (line, DIM(line)-1, "LOOKUP %s", pattern); + line[DIM(line)-1] = 0; + xfree (pattern); + + parm.ctx = dirmngr_ctx; + parm.cb = cb; + parm.cb_value = cb_value; + parm.error = 0; + init_membuf (&parm.data, 4096); + + rc = assuan_transact (dirmngr_ctx, line, lookup_cb, &parm, + NULL, NULL, NULL, NULL); + xfree (get_membuf (&parm.data, &len)); + if (rc) + return map_assuan_err (rc); + return parm.error; +} diff --git a/sm/gpgsm.c b/sm/gpgsm.c index b5b144afe..83de50edb 100644 --- a/sm/gpgsm.c +++ b/sm/gpgsm.c @@ -1182,14 +1182,14 @@ main ( int argc, char **argv) case aListKeys: for (sl=NULL; argc; argc--, argv++) add_to_strlist (&sl, *argv); - gpgsm_list_keys (&ctrl, sl, stdout, 0); + gpgsm_list_keys (&ctrl, sl, stdout, (0 | (1<<6))); free_strlist(sl); break; case aListSecretKeys: for (sl=NULL; argc; argc--, argv++) add_to_strlist (&sl, *argv); - gpgsm_list_keys (&ctrl, sl, stdout, 2); + gpgsm_list_keys (&ctrl, sl, stdout, (2 | (1<<6))); free_strlist(sl); break; diff --git a/sm/gpgsm.h b/sm/gpgsm.h index a9d48c8bf..b1969112c 100644 --- a/sm/gpgsm.h +++ b/sm/gpgsm.h @@ -120,7 +120,6 @@ struct server_control_s { along with a signature or the number of certificates up the chain (0 = none, 1 = only signer) */ - }; typedef struct server_control_s *CTRL; @@ -234,6 +233,8 @@ int gpgsm_agent_learn (void); /*-- call-dirmngr.c --*/ int gpgsm_dirmngr_isvalid (KsbaCert cert); +int gpgsm_dirmngr_lookup (STRLIST names, + void (*cb)(void*, KsbaCert), void *cb_value); diff --git a/sm/keylist.c b/sm/keylist.c index 18d570ec8..b53b10f16 100644 --- a/sm/keylist.c +++ b/sm/keylist.c @@ -34,6 +34,12 @@ #include "keydb.h" #include "i18n.h" +struct list_external_parm_s { + FILE *fp; + int print_header; + int with_colons; +}; + static void @@ -265,15 +271,10 @@ list_cert_colon (KsbaCert cert, FILE *fp, int have_secret) -/* List all keys or just the key given as NAMES. - MODE controls the operation mode: - 0 = list all public keys but don't flag secret ones - 1 = list only public keys - 2 = list only secret keys - 3 = list secret and public keys +/* List all internal keys or just the key given as NAMES. */ -void -gpgsm_list_keys (CTRL ctrl, STRLIST names, FILE *fp, unsigned int mode) +static void +list_internal_keys (CTRL ctrl, STRLIST names, FILE *fp, unsigned int mode) { KEYDB_HANDLE hd; KEYDB_SEARCH_DESC *desc = NULL; @@ -396,3 +397,63 @@ gpgsm_list_keys (CTRL ctrl, STRLIST names, FILE *fp, unsigned int mode) +static void +list_external_cb (void *cb_value, KsbaCert cert) +{ + struct list_external_parm_s *parm = cb_value; + + if (parm->print_header) + { + const char *resname = "[external keys]"; + int i; + + fprintf (parm->fp, "%s\n", resname ); + for (i=strlen(resname); i; i-- ) + putchar('-'); + putc ('\n', parm->fp); + parm->print_header = 0; + } + + if (parm->with_colons) + list_cert_colon (cert, parm->fp, 0); + else + list_cert_colon (cert, parm->fp, 0); +} + + +/* List external keys similar to internal one. Note: mode does not + make sense here because it would be unwise to list external secret + keys */ +static void +list_external_keys (CTRL ctrl, STRLIST names, FILE *fp) +{ + int rc; + struct list_external_parm_s parm; + + parm.fp = fp; + parm.print_header = ctrl->no_server; + parm.with_colons = ctrl->with_colons; + + rc = gpgsm_dirmngr_lookup (names, list_external_cb, &parm); + if (rc) + log_error ("listing external keys failed: %s\n", gnupg_strerror (rc)); +} + +/* List all keys or just the key given as NAMES. + MODE controls the operation mode: + Bit 0-2: + 0 = list all public keys but don't flag secret ones + 1 = list only public keys + 2 = list only secret keys + 3 = list secret and public keys + Bit 6: list internal keys + Bit 7: list external keys + */ +void +gpgsm_list_keys (CTRL ctrl, STRLIST names, FILE *fp, unsigned int mode) +{ + if ((mode & (1<<6))) + list_internal_keys (ctrl, names, fp, (mode & 3)); + if ((mode & (1<<7))) + list_external_keys (ctrl, names, fp); +} diff --git a/sm/server.c b/sm/server.c index beaea803a..763084c73 100644 --- a/sm/server.c +++ b/sm/server.c @@ -40,6 +40,8 @@ static FILE *statusfp; struct server_local_s { ASSUAN_CONTEXT assuan_ctx; int message_fd; + int list_internal; + int list_external; CERTLIST recplist; }; @@ -144,6 +146,27 @@ option_handler (ASSUAN_CONTEXT ctx, const char *key, const char *value) if (!opt.lc_messages) return ASSUAN_Out_Of_Core; } + else if (!strcmp (key, "list-mode")) + { + int i = *value? atoi (value) : 0; + if (!i || i == 1) /* default and mode 1 */ + { + ctrl->server_local->list_internal = 1; + ctrl->server_local->list_external = 0; + } + else if (i == 2) + { + ctrl->server_local->list_internal = 0; + ctrl->server_local->list_external = 1; + } + else if (i == 3) + { + ctrl->server_local->list_internal = 1; + ctrl->server_local->list_external = 1; + } + else + return ASSUAN_Parameter_Error; + } else return ASSUAN_Invalid_Option; @@ -491,6 +514,7 @@ do_listkeys (ASSUAN_CONTEXT ctx, char *line, int mode) FILE *fp = assuan_get_data_fp (ctx); char *p; STRLIST list, sl; + unsigned int listmode; if (!fp) return set_error (General_Error, "no data stream"); @@ -519,7 +543,12 @@ do_listkeys (ASSUAN_CONTEXT ctx, char *line, int mode) } ctrl->with_colons = 1; - gpgsm_list_keys (assuan_get_pointer (ctx), list, fp, 3); + listmode = mode; + if (ctrl->server_local->list_internal) + listmode |= (1<<6); + if (ctrl->server_local->list_external) + listmode |= (1<<7); + gpgsm_list_keys (assuan_get_pointer (ctx), list, fp, listmode); free_strlist (list); return 0; } @@ -654,6 +683,8 @@ gpgsm_server (void) ctrl.server_local = xcalloc (1, sizeof *ctrl.server_local); ctrl.server_local->assuan_ctx = ctx; ctrl.server_local->message_fd = -1; + ctrl.server_local->list_internal = 1; + ctrl.server_local->list_external = 0; if (DBG_ASSUAN) assuan_set_log_stream (ctx, log_get_stream ()); @@ -757,6 +788,7 @@ get_status_string ( int no ) case STATUS_ALREADY_SIGNED : s = "ALREADY_SIGNED"; break; case STATUS_EXPSIG : s = "EXPSIG"; break; case STATUS_EXPKEYSIG : s = "EXPKEYSIG"; break; + case STATUS_TRUNCATED : s = "TRUNCATED"; break; default: s = "?"; break; } return s; @@ -902,10 +934,3 @@ write_status_text_and_buffer ( int no, const char *string, fflush (statusfp); } #endif - - - - - - -