From 332c9eaa2a3c7cae90b389cdaa2c149c5595fb4d Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Tue, 12 Sep 2017 18:05:00 +0200 Subject: wks: Add new policy flag protocol-version * tools/gpg-wks.h (policy_flags_s): Add field protocol_version. * tools/wks-util.c (wks_parse_policy): Add new policy flag. Signed-off-by: Werner Koch --- tools/wks-util.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) (limited to 'tools/wks-util.c') diff --git a/tools/wks-util.c b/tools/wks-util.c index 46ad5c27b..45237b2b4 100644 --- a/tools/wks-util.c +++ b/tools/wks-util.c @@ -316,7 +316,8 @@ wks_parse_policy (policy_flags_t flags, estream_t stream, int ignore_unknown) TOK_MAILBOX_ONLY, TOK_DANE_ONLY, TOK_AUTH_SUBMIT, - TOK_MAX_PENDING + TOK_MAX_PENDING, + TOK_PROTOCOL_VERSION }; static struct { const char *name; @@ -325,7 +326,8 @@ wks_parse_policy (policy_flags_t flags, estream_t stream, int ignore_unknown) { "mailbox-only", TOK_MAILBOX_ONLY }, { "dane-only", TOK_DANE_ONLY }, { "auth-submit", TOK_AUTH_SUBMIT }, - { "max-pending", TOK_MAX_PENDING } + { "max-pending", TOK_MAX_PENDING }, + { "protocol-version", TOK_PROTOCOL_VERSION } }; gpg_error_t err = 0; int lnr = 0; @@ -400,6 +402,14 @@ wks_parse_policy (policy_flags_t flags, estream_t stream, int ignore_unknown) * and decide whether to allow other units. */ flags->max_pending = atoi (value); break; + case TOK_PROTOCOL_VERSION: + if (!value) + { + err = gpg_error (GPG_ERR_SYNTAX); + goto leave; + } + flags->protocol_version = atoi (value); + break; } } -- cgit From 4e0696de897cac6a34d55a69d8889faf26f1a923 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Mon, 18 Sep 2017 11:16:07 +0200 Subject: wks: Use dedicated type to convey user ids. * tools/gpg-wks.h (uidinfo_list_s, uidinfo_list_t): New. * tools/wks-util.c (append_to_uidinfo_list): New. (free_uidinfo_list): New. (wks_list_key): Change arg r_mboxes to uidinfo_list_t. Use append_to_uidinfo_list. * tools/gpg-wks-server.c (sserver_ctx_s): Replace strlist_t by uidinfo_list_t. (process_new_key): Ditto. (check_and_publish): Ditto. (command_receive_cb): Replace free_strlist by free_uidinfo_list. * tools/gpg-wks-client.c (command_check): Replace strlist_t by uidinfo_list_t. Also print user id in verbose mode. Signed-off-by: Werner Koch --- tools/gpg-wks-client.c | 19 +++++++++++------- tools/gpg-wks-server.c | 36 ++++++++++++++++++--------------- tools/gpg-wks.h | 14 ++++++++++++- tools/wks-util.c | 54 ++++++++++++++++++++++++++++++++++++++++++-------- 4 files changed, 91 insertions(+), 32 deletions(-) (limited to 'tools/wks-util.c') diff --git a/tools/gpg-wks-client.c b/tools/gpg-wks-client.c index e703640e1..6b83de8c5 100644 --- a/tools/gpg-wks-client.c +++ b/tools/gpg-wks-client.c @@ -119,7 +119,7 @@ const char *fake_submission_addr; static void wrong_args (const char *text) GPGRT_ATTR_NORETURN; static gpg_error_t command_supported (char *userid); static gpg_error_t command_check (char *userid); -static gpg_error_t command_send (const char *fingerprint, char *userid); +static gpg_error_t command_send (const char *fingerprint, const char *userid); static gpg_error_t encrypt_response (estream_t *r_output, estream_t input, const char *addrspec, const char *fingerprint); @@ -597,8 +597,8 @@ command_check (char *userid) char *addrspec = NULL; estream_t key = NULL; char *fpr = NULL; - strlist_t mboxes = NULL; - strlist_t sl; + uidinfo_list_t mboxes = NULL; + uidinfo_list_t sl; int found = 0; addrspec = mailbox_from_userid (userid); @@ -657,10 +657,14 @@ command_check (char *userid) for (sl = mboxes; sl; sl = sl->next) { - if (!strcmp (sl->d, addrspec)) + if (sl->mbox && !strcmp (sl->mbox, addrspec)) found = 1; if (opt.verbose) - log_info (" addr-spec: %s\n", sl->d); + { + log_info (" user-id: %s\n", sl->uid); + if (sl->mbox) + log_info (" addr-spec: %s\n", sl->mbox); + } } if (!found) { @@ -671,7 +675,7 @@ command_check (char *userid) leave: xfree (fpr); - free_strlist (mboxes); + free_uidinfo_list (mboxes); es_fclose (key); xfree (addrspec); return err; @@ -682,7 +686,7 @@ command_check (char *userid) /* Locate the key by fingerprint and userid and send a publication * request. */ static gpg_error_t -command_send (const char *fingerprint, char *userid) +command_send (const char *fingerprint, const char *userid) { gpg_error_t err; KEYDB_SEARCH_DESC desc; @@ -706,6 +710,7 @@ command_send (const char *fingerprint, char *userid) err = gpg_error (GPG_ERR_INV_NAME); goto leave; } + addrspec = mailbox_from_userid (userid); if (!addrspec) { diff --git a/tools/gpg-wks-server.c b/tools/gpg-wks-server.c index 1633a2084..f7aadba3d 100644 --- a/tools/gpg-wks-server.c +++ b/tools/gpg-wks-server.c @@ -127,7 +127,7 @@ static struct debug_flags_s debug_flags [] = struct server_ctx_s { char *fpr; - strlist_t mboxes; /* List of addr-specs taken from the UIDs. */ + uidinfo_list_t mboxes; /* List with addr-specs taken from the UIDs. */ unsigned int draft_version_2:1; /* Client supports the draft 2. */ }; typedef struct server_ctx_s *server_ctx_t; @@ -1092,7 +1092,7 @@ static gpg_error_t process_new_key (server_ctx_t ctx, estream_t key) { gpg_error_t err; - strlist_t sl; + uidinfo_list_t sl; const char *s; char *dname = NULL; char *nonce = NULL; @@ -1101,7 +1101,7 @@ process_new_key (server_ctx_t ctx, estream_t key) /* First figure out the user id from the key. */ xfree (ctx->fpr); - free_strlist (ctx->mboxes); + free_uidinfo_list (ctx->mboxes); err = wks_list_key (key, &ctx->fpr, &ctx->mboxes); if (err) goto leave; @@ -1114,14 +1114,17 @@ process_new_key (server_ctx_t ctx, estream_t key) log_info ("fingerprint: %s\n", ctx->fpr); for (sl = ctx->mboxes; sl; sl = sl->next) { - log_info (" addr-spec: %s\n", sl->d); + if (sl->mbox) + log_info (" addr-spec: %s\n", sl->mbox); } /* Walk over all user ids and send confirmation requests for those * we support. */ for (sl = ctx->mboxes; sl; sl = sl->next) { - s = strchr (sl->d, '@'); + if (!sl->mbox) + continue; + s = strchr (sl->mbox, '@'); log_assert (s && s[1]); xfree (dname); dname = make_filename_try (opt.directory, s+1, NULL); @@ -1133,26 +1136,26 @@ process_new_key (server_ctx_t ctx, estream_t key) if (access (dname, W_OK)) { - log_info ("skipping address '%s': Domain not configured\n", sl->d); + log_info ("skipping address '%s': Domain not configured\n", sl->mbox); continue; } - if (get_policy_flags (&policybuf, sl->d)) + if (get_policy_flags (&policybuf, sl->mbox)) { - log_info ("skipping address '%s': Bad policy flags\n", sl->d); + log_info ("skipping address '%s': Bad policy flags\n", sl->mbox); continue; } if (policybuf.auth_submit) { /* Bypass the confirmation stuff and publish the key as is. */ - log_info ("publishing address '%s'\n", sl->d); + log_info ("publishing address '%s'\n", sl->mbox); /* FIXME: We need to make sure that we do this only for the * address in the mail. */ log_debug ("auth-submit not yet working!\n"); } else { - log_info ("storing address '%s'\n", sl->d); + log_info ("storing address '%s'\n", sl->mbox); xfree (nonce); xfree (fname); @@ -1160,7 +1163,7 @@ process_new_key (server_ctx_t ctx, estream_t key) if (err) goto leave; - err = send_confirmation_request (ctx, sl->d, nonce, fname); + err = send_confirmation_request (ctx, sl->mbox, nonce, fname); if (err) goto leave; } @@ -1313,7 +1316,7 @@ check_and_publish (server_ctx_t ctx, const char *address, const char *nonce) char *hash = NULL; const char *domain; const char *s; - strlist_t sl; + uidinfo_list_t sl; char shaxbuf[32]; /* Used for SHA-1 and SHA-256 */ /* FIXME: There is a bug in name-value.c which adds white space for @@ -1351,7 +1354,7 @@ check_and_publish (server_ctx_t ctx, const char *address, const char *nonce) /* We need to get the fingerprint from the key. */ xfree (ctx->fpr); - free_strlist (ctx->mboxes); + free_uidinfo_list (ctx->mboxes); err = wks_list_key (key, &ctx->fpr, &ctx->mboxes); if (err) goto leave; @@ -1363,13 +1366,14 @@ check_and_publish (server_ctx_t ctx, const char *address, const char *nonce) } log_info ("fingerprint: %s\n", ctx->fpr); for (sl = ctx->mboxes; sl; sl = sl->next) - log_info (" addr-spec: %s\n", sl->d); + if (sl->mbox) + log_info (" addr-spec: %s\n", sl->mbox); /* Check that the key has 'address' as a user id. We use * case-insensitive matching because the client is expected to * return the address verbatim. */ for (sl = ctx->mboxes; sl; sl = sl->next) - if (!strcmp (sl->d, address)) + if (sl->mbox && !strcmp (sl->mbox, address)) break; if (!sl) { @@ -1565,7 +1569,7 @@ command_receive_cb (void *opaque, const char *mediatype, } xfree (ctx.fpr); - free_strlist (ctx.mboxes); + free_uidinfo_list (ctx.mboxes); return err; } diff --git a/tools/gpg-wks.h b/tools/gpg-wks.h index caea98e2f..7fc8d9acd 100644 --- a/tools/gpg-wks.h +++ b/tools/gpg-wks.h @@ -69,11 +69,23 @@ struct policy_flags_s typedef struct policy_flags_s *policy_flags_t; +/* An object to convey user ids of a key. */ +struct uidinfo_list_s +{ + struct uidinfo_list_s *next; + char *mbox; /* NULL or the malloced mailbox from UID. */ + char uid[1]; +}; +typedef struct uidinfo_list_s *uidinfo_list_t; + + /*-- wks-util.c --*/ void wks_set_status_fd (int fd); void wks_write_status (int no, const char *format, ...) GPGRT_ATTR_PRINTF(2,3); -gpg_error_t wks_list_key (estream_t key, char **r_fpr, strlist_t *r_mboxes); +void free_uidinfo_list (uidinfo_list_t list); +gpg_error_t wks_list_key (estream_t key, char **r_fpr, + uidinfo_list_t *r_mboxes); gpg_error_t wks_send_mime (mime_maker_t mime); gpg_error_t wks_parse_policy (policy_flags_t flags, estream_t stream, int ignore_unknown); diff --git a/tools/wks-util.c b/tools/wks-util.c index 45237b2b4..bc076a7c0 100644 --- a/tools/wks-util.c +++ b/tools/wks-util.c @@ -89,6 +89,48 @@ wks_write_status (int no, const char *format, ...) } + + +/* Append UID to LIST and return the new item. On success LIST is + * updated. On error ERRNO is set and NULL returned. */ +static uidinfo_list_t +append_to_uidinfo_list (uidinfo_list_t *list, const char *uid) +{ + uidinfo_list_t r, sl; + + sl = xtrymalloc (sizeof *sl + strlen (uid)); + if (!sl) + return NULL; + + strcpy (sl->uid, uid); + sl->mbox = mailbox_from_userid (uid); + sl->next = NULL; + if (!*list) + *list = sl; + else + { + for (r = *list; r->next; r = r->next ) + ; + r->next = sl; + } + return sl; +} + + +/* Free the list of uid infos at LIST. */ +void +free_uidinfo_list (uidinfo_list_t list) +{ + while (list) + { + uidinfo_list_t tmp = list->next; + xfree (list->mbox); + xfree (list); + list = tmp; + } +} + + /* Helper for wks_list_key. */ static void @@ -105,7 +147,7 @@ list_key_status_cb (void *opaque, const char *keyword, char *args) * list of mailboxes at R_MBOXES. Returns 0 on success; on error NULL * is stored at R_FPR and R_MBOXES and an error code is returned. */ gpg_error_t -wks_list_key (estream_t key, char **r_fpr, strlist_t *r_mboxes) +wks_list_key (estream_t key, char **r_fpr, uidinfo_list_t *r_mboxes) { gpg_error_t err; ccparray_t ccp; @@ -118,9 +160,8 @@ wks_list_key (estream_t key, char **r_fpr, strlist_t *r_mboxes) char **fields = NULL; int nfields; int lnr; - char *mbox = NULL; char *fpr = NULL; - strlist_t mboxes = NULL; + uidinfo_list_t mboxes = NULL; *r_fpr = NULL; *r_mboxes = NULL; @@ -232,9 +273,7 @@ wks_list_key (estream_t key, char **r_fpr, strlist_t *r_mboxes) else if (!strcmp (fields[0], "uid") && nfields > 9) { /* Fixme: Unescape fields[9] */ - xfree (mbox); - mbox = mailbox_from_userid (fields[9]); - if (mbox && !append_to_strlist_try (&mboxes, mbox)) + if (!append_to_uidinfo_list (&mboxes, fields[9])) { err = gpg_error_from_syserror (); goto leave; @@ -255,8 +294,7 @@ wks_list_key (estream_t key, char **r_fpr, strlist_t *r_mboxes) leave: xfree (fpr); - xfree (mboxes); - xfree (mbox); + free_uidinfo_list (mboxes); xfree (fields); es_free (line); xfree (argv); -- cgit From a0035986a8615df056182bb9af775b8b7b22003d Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Mon, 18 Sep 2017 11:31:36 +0200 Subject: wks: Print the UID creation time with gpg-wks-client --check. * tools/gpg-wks.h (uidinfo_list_s): Add field 'created'. * tools/wks-util.c (append_to_uidinfo_list): Add arf 'created'. (wks_list_key): Pass timestamp to append_to_uidinfo_list. * tools/gpg-wks-client.c (command_check): Print UID creation time. Signed-off-by: Werner Koch --- tools/gpg-wks-client.c | 1 + tools/gpg-wks.h | 1 + tools/wks-util.c | 6 ++++-- 3 files changed, 6 insertions(+), 2 deletions(-) (limited to 'tools/wks-util.c') diff --git a/tools/gpg-wks-client.c b/tools/gpg-wks-client.c index 6b83de8c5..18a0edd72 100644 --- a/tools/gpg-wks-client.c +++ b/tools/gpg-wks-client.c @@ -662,6 +662,7 @@ command_check (char *userid) if (opt.verbose) { log_info (" user-id: %s\n", sl->uid); + log_info (" created: %s\n", asctimestamp (sl->created)); if (sl->mbox) log_info (" addr-spec: %s\n", sl->mbox); } diff --git a/tools/gpg-wks.h b/tools/gpg-wks.h index 7fc8d9acd..cb89fd501 100644 --- a/tools/gpg-wks.h +++ b/tools/gpg-wks.h @@ -73,6 +73,7 @@ typedef struct policy_flags_s *policy_flags_t; struct uidinfo_list_s { struct uidinfo_list_s *next; + time_t created; /* Time the userid was created. */ char *mbox; /* NULL or the malloced mailbox from UID. */ char uid[1]; }; diff --git a/tools/wks-util.c b/tools/wks-util.c index bc076a7c0..8fc0a2e5c 100644 --- a/tools/wks-util.c +++ b/tools/wks-util.c @@ -94,7 +94,7 @@ wks_write_status (int no, const char *format, ...) /* Append UID to LIST and return the new item. On success LIST is * updated. On error ERRNO is set and NULL returned. */ static uidinfo_list_t -append_to_uidinfo_list (uidinfo_list_t *list, const char *uid) +append_to_uidinfo_list (uidinfo_list_t *list, const char *uid, time_t created) { uidinfo_list_t r, sl; @@ -103,6 +103,7 @@ append_to_uidinfo_list (uidinfo_list_t *list, const char *uid) return NULL; strcpy (sl->uid, uid); + sl->created = created; sl->mbox = mailbox_from_userid (uid); sl->next = NULL; if (!*list) @@ -273,7 +274,8 @@ wks_list_key (estream_t key, char **r_fpr, uidinfo_list_t *r_mboxes) else if (!strcmp (fields[0], "uid") && nfields > 9) { /* Fixme: Unescape fields[9] */ - if (!append_to_uidinfo_list (&mboxes, fields[9])) + if (!append_to_uidinfo_list (&mboxes, fields[9], + parse_timestamp (fields[5], NULL))) { err = gpg_error_from_syserror (); goto leave; -- cgit From 7f7f5d06fa5aa3a3c5ab8d2e59ee76207bfdeaa0 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Mon, 18 Sep 2017 12:52:20 +0200 Subject: wks: Send only the newest UID to the server. * tools/wks-util.c (list_key_status_cb): Rename to key_status_cb. (wks_filter_uid): New. (wks_list_key): Allow FPR to be NULL. Return an error if no fingerprint was found. * tools/gpg-wks-server.c (process_new_key) (check_and_publish): Remove now useless extra check for FPR. * tools/gpg-wks-client.c (command_check): Ditto. (command_send): Filter out the newest uid. -- This fixes the case of having several userids with all the the same mailbox. Now we use the latest user id created. This patch is also a prerequisite to automatically create a new user id for providers with the mailbox-only policy. Signed-off-by: Werner Koch --- tools/gpg-wks-client.c | 60 ++++++++++++++++++++++++++-- tools/gpg-wks-server.c | 14 +------ tools/gpg-wks.h | 2 + tools/wks-util.c | 104 +++++++++++++++++++++++++++++++++++++++++++++---- 4 files changed, 158 insertions(+), 22 deletions(-) (limited to 'tools/wks-util.c') diff --git a/tools/gpg-wks-client.c b/tools/gpg-wks-client.c index 18a0edd72..37b75606b 100644 --- a/tools/gpg-wks-client.c +++ b/tools/gpg-wks-client.c @@ -644,10 +644,9 @@ command_check (char *userid) /* Look closer at the key. */ err = wks_list_key (key, &fpr, &mboxes); - if (err || !fpr) + if (err) { - log_error ("error parsing key: %s\n", - err? gpg_strerror (err) : "no fingerprint found"); + log_error ("error parsing key: %s\n", gpg_strerror (err)); err = gpg_error (GPG_ERR_NO_PUBKEY); goto leave; } @@ -700,6 +699,9 @@ command_send (const char *fingerprint, const char *userid) int no_encrypt = 0; int posteo_hack = 0; const char *domain; + uidinfo_list_t uidlist = NULL; + uidinfo_list_t uid, thisuid; + time_t thistime; memset (&policy, 0, sizeof policy); @@ -769,6 +771,57 @@ command_send (const char *fingerprint, const char *userid) if (policy.auth_submit) log_info ("no confirmation required for '%s'\n", addrspec); + /* In case the key has several uids with the same addr-spec we will + * use the newest one. */ + err = wks_list_key (key, NULL, &uidlist); + if (err) + { + log_error ("error parsing key: %s\n",gpg_strerror (err)); + err = gpg_error (GPG_ERR_NO_PUBKEY); + goto leave; + } + thistime = 0; + thisuid = NULL; + for (uid = uidlist; uid; uid = uid->next) + { + if (!uid->mbox) + continue; /* Should not happen anyway. */ + if (uid->created > thistime) + { + thistime = uid->created; + thisuid = uid; + } + } + if (!thisuid) + thisuid = uid; /* This is the case for a missing timestamp. */ + if (opt.verbose) + log_info ("submitting key with user id '%s'\n", thisuid->uid); + + /* If we have more than one user id we need to filter the key to + * include only THISUID. */ + if (uidlist->next) + { + estream_t newkey; + + es_rewind (key); + err = wks_filter_uid (&newkey, key, thisuid->uid); + if (err) + { + log_error ("error filtering key: %s\n", gpg_strerror (err)); + err = gpg_error (GPG_ERR_NO_PUBKEY); + goto leave; + } + es_fclose (key); + key = newkey; + } + + if (policy.mailbox_only + && ascii_strcasecmp (userid, addrspec)) + { + log_info ("Warning: policy requires 'mailbox-only'" + " - creating new user id'\n"); + } + /* Hack to support posteo but let them disable this by setting the * new policy-version flag. */ if (policy.protocol_version < 3 @@ -885,6 +938,7 @@ command_send (const char *fingerprint, const char *userid) leave: mime_maker_release (mime); xfree (submission_to); + free_uidinfo_list (uidlist); es_fclose (keyenc); es_fclose (key); xfree (addrspec); diff --git a/tools/gpg-wks-server.c b/tools/gpg-wks-server.c index f7aadba3d..7e3f05017 100644 --- a/tools/gpg-wks-server.c +++ b/tools/gpg-wks-server.c @@ -1105,12 +1105,7 @@ process_new_key (server_ctx_t ctx, estream_t key) err = wks_list_key (key, &ctx->fpr, &ctx->mboxes); if (err) goto leave; - if (!ctx->fpr) - { - log_error ("error parsing key (no fingerprint)\n"); - err = gpg_error (GPG_ERR_NO_PUBKEY); - goto leave; - } + log_assert (ctx->fpr); log_info ("fingerprint: %s\n", ctx->fpr); for (sl = ctx->mboxes; sl; sl = sl->next) { @@ -1358,12 +1353,7 @@ check_and_publish (server_ctx_t ctx, const char *address, const char *nonce) err = wks_list_key (key, &ctx->fpr, &ctx->mboxes); if (err) goto leave; - if (!ctx->fpr) - { - log_error ("error parsing key (no fingerprint)\n"); - err = gpg_error (GPG_ERR_NO_PUBKEY); - goto leave; - } + log_assert (ctx->fpr); log_info ("fingerprint: %s\n", ctx->fpr); for (sl = ctx->mboxes; sl; sl = sl->next) if (sl->mbox) diff --git a/tools/gpg-wks.h b/tools/gpg-wks.h index cb89fd501..ece7add5f 100644 --- a/tools/gpg-wks.h +++ b/tools/gpg-wks.h @@ -87,6 +87,8 @@ void wks_write_status (int no, const char *format, ...) GPGRT_ATTR_PRINTF(2,3); void free_uidinfo_list (uidinfo_list_t list); gpg_error_t wks_list_key (estream_t key, char **r_fpr, uidinfo_list_t *r_mboxes); +gpg_error_t wks_filter_uid (estream_t *r_newkey, estream_t key, + const char *uid); gpg_error_t wks_send_mime (mime_maker_t mime); gpg_error_t wks_parse_policy (policy_flags_t flags, estream_t stream, int ignore_unknown); diff --git a/tools/wks-util.c b/tools/wks-util.c index 8fc0a2e5c..889ca36dc 100644 --- a/tools/wks-util.c +++ b/tools/wks-util.c @@ -133,9 +133,9 @@ free_uidinfo_list (uidinfo_list_t list) -/* Helper for wks_list_key. */ +/* Helper for wks_list_key and wks_filter_uid. */ static void -list_key_status_cb (void *opaque, const char *keyword, char *args) +key_status_cb (void *opaque, const char *keyword, char *args) { (void)opaque; @@ -146,7 +146,8 @@ list_key_status_cb (void *opaque, const char *keyword, char *args) /* Run gpg on KEY and store the primary fingerprint at R_FPR and the * list of mailboxes at R_MBOXES. Returns 0 on success; on error NULL - * is stored at R_FPR and R_MBOXES and an error code is returned. */ + * is stored at R_FPR and R_MBOXES and an error code is returned. + * R_FPR may be NULL if the fingerprint is not needed. */ gpg_error_t wks_list_key (estream_t key, char **r_fpr, uidinfo_list_t *r_mboxes) { @@ -164,7 +165,8 @@ wks_list_key (estream_t key, char **r_fpr, uidinfo_list_t *r_mboxes) char *fpr = NULL; uidinfo_list_t mboxes = NULL; - *r_fpr = NULL; + if (r_fpr) + *r_fpr = NULL; *r_mboxes = NULL; /* Open a memory stream. */ @@ -200,7 +202,7 @@ wks_list_key (estream_t key, char **r_fpr, uidinfo_list_t *r_mboxes) } err = gnupg_exec_tool_stream (opt.gpg_program, argv, key, NULL, listing, - list_key_status_cb, NULL); + key_status_cb, NULL); if (err) { log_error ("import failed: %s\n", gpg_strerror (err)); @@ -289,8 +291,17 @@ wks_list_key (estream_t key, char **r_fpr, uidinfo_list_t *r_mboxes) goto leave; } - *r_fpr = fpr; - fpr = NULL; + if (!fpr) + { + err = gpg_error (GPG_ERR_NO_PUBKEY); + goto leave; + } + + if (r_fpr) + { + *r_fpr = fpr; + fpr = NULL; + } *r_mboxes = mboxes; mboxes = NULL; @@ -305,6 +316,85 @@ wks_list_key (estream_t key, char **r_fpr, uidinfo_list_t *r_mboxes) } +/* Run gpg as a filter on KEY and write the output to a new stream + * stored at R_NEWKEY. The new key will containn only the user id + * UID. Returns 0 on success. Only one key is expected in KEY. */ +gpg_error_t +wks_filter_uid (estream_t *r_newkey, estream_t key, const char *uid) +{ + gpg_error_t err; + ccparray_t ccp; + const char **argv = NULL; + estream_t newkey; + char *filterexp = NULL; + + *r_newkey = NULL; + + /* Open a memory stream. */ + newkey = es_fopenmem (0, "w+b"); + if (!newkey) + { + err = gpg_error_from_syserror (); + log_error ("error allocating memory buffer: %s\n", gpg_strerror (err)); + return err; + } + + /* Prefix the key with the MIME content type. */ + es_fputs ("Content-Type: application/pgp-keys\n" + "\n", newkey); + + filterexp = es_bsprintf ("keep-uid=uid=%s", uid); + if (!filterexp) + { + err = gpg_error_from_syserror (); + log_error ("error allocating memory buffer: %s\n", gpg_strerror (err)); + goto leave; + } + + ccparray_init (&ccp, 0); + + ccparray_put (&ccp, "--no-options"); + if (!opt.verbose) + ccparray_put (&ccp, "--quiet"); + else if (opt.verbose > 1) + ccparray_put (&ccp, "--verbose"); + ccparray_put (&ccp, "--batch"); + ccparray_put (&ccp, "--status-fd=2"); + ccparray_put (&ccp, "--always-trust"); + ccparray_put (&ccp, "--armor"); + ccparray_put (&ccp, "--import-options=import-export"); + ccparray_put (&ccp, "--import-filter"); + ccparray_put (&ccp, filterexp); + ccparray_put (&ccp, "--import"); + + ccparray_put (&ccp, NULL); + argv = ccparray_get (&ccp, NULL); + if (!argv) + { + err = gpg_error_from_syserror (); + goto leave; + } + err = gnupg_exec_tool_stream (opt.gpg_program, argv, key, + NULL, newkey, + key_status_cb, NULL); + if (err) + { + log_error ("import/export failed: %s\n", gpg_strerror (err)); + goto leave; + } + + es_rewind (newkey); + *r_newkey = newkey; + newkey = NULL; + + leave: + xfree (filterexp); + xfree (argv); + es_fclose (newkey); + return err; +} + + /* Helper to write mail to the output(s). */ gpg_error_t wks_send_mime (mime_maker_t mime) -- cgit