From 6b9f772914624cc673ba26d49b6e3adc32dd7e0a Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Mon, 12 Nov 2018 07:44:33 +0100 Subject: [PATCH] common: Prepare for parsing mail sub-addresses. * common/mbox-util.c (mailbox_from_userid): Add arg subaddress and implement. Change all callers to pass false for it. * common/t-mbox-util.c (run_mbox_no_sub_test): New. (run_filter): Add arg no_sub. (main): Call new test and add option --no-sub. -- Some stats: In the about 5300000 keys on the SKS servers we found 3055 unique mailboxes with a '+' in it. After removing leading and trailing '+' as well as multiple '+' (e.g. "c++" or "foo+bar+baz") 2697 were left which seem to be valid sub-addresses. To filter mailboxes out from a line delimited list with user-ids (e.g. an SQL output), the command t-mbox-util --verbose --filter can be used; to output w/o sub-addresses add --no-sub. GnuPG-bug-id: 4200 Signed-off-by: Werner Koch --- common/mbox-util.c | 32 ++++++++++++-- common/mbox-util.h | 2 +- common/t-mbox-util.c | 95 ++++++++++++++++++++++++++++++++++++++++-- dirmngr/server.c | 4 +- g10/export.c | 2 +- g10/getkey.c | 2 +- g10/gpg.c | 2 +- g10/import.c | 2 +- g10/keylist.c | 2 +- g10/keyserver.c | 2 +- g10/sign.c | 3 +- g10/tofu.c | 2 +- g10/trustdb.c | 2 +- tools/gpg-wks-client.c | 8 ++-- tools/gpg-wks-server.c | 4 +- tools/wks-util.c | 2 +- 16 files changed, 139 insertions(+), 27 deletions(-) diff --git a/common/mbox-util.c b/common/mbox-util.c index 76255ba38..a9086a3f5 100644 --- a/common/mbox-util.c +++ b/common/mbox-util.c @@ -173,11 +173,12 @@ is_valid_mailbox (const char *name) /* Return the mailbox (local-part@domain) form a standard user id. - All plain ASCII characters in the result are converted to - lowercase. Caller must free the result. Returns NULL if no valid - mailbox was found (or we are out of memory). */ + * All plain ASCII characters in the result are converted to + * lowercase. If SUBADDRESS is 1, '+' denoted sub-addresses are not + * included in the result. Caller must free the result. Returns NULL + * if no valid mailbox was found (or we are out of memory). */ char * -mailbox_from_userid (const char *userid) +mailbox_from_userid (const char *userid, int subaddress) { const char *s, *s_end; size_t len; @@ -226,6 +227,29 @@ mailbox_from_userid (const char *userid) else errno = EINVAL; + if (result && subaddress == 1) + { + char *atsign, *plus; + + if ((atsign = strchr (result, '@'))) + { + /* We consider a subaddress only if there is a single '+' + * in the local part and the '+' is not the first or last + * character. */ + *atsign = 0; + if ((plus = strchr (result, '+')) + && !strchr (plus+1, '+') + && result != plus + && plus[1] ) + { + *atsign = '@'; + memmove (plus, atsign, strlen (atsign)+1); + } + else + *atsign = '@'; + } + } + return result? ascii_strlwr (result): NULL; } diff --git a/common/mbox-util.h b/common/mbox-util.h index 7355ceef5..10ff2c4a0 100644 --- a/common/mbox-util.h +++ b/common/mbox-util.h @@ -22,7 +22,7 @@ int has_invalid_email_chars (const void *buffer, size_t length); int is_valid_mailbox (const char *name); int is_valid_mailbox_mem (const void *buffer, size_t length); -char *mailbox_from_userid (const char *userid); +char *mailbox_from_userid (const char *userid, int subaddress); int is_valid_user_id (const char *uid); int is_valid_domain_name (const char *string); diff --git a/common/t-mbox-util.c b/common/t-mbox-util.c index e9cf41215..ae717f96f 100644 --- a/common/t-mbox-util.c +++ b/common/t-mbox-util.c @@ -83,7 +83,86 @@ run_mbox_test (void) for (idx=0; testtbl[idx].userid; idx++) { - char *mbox = mailbox_from_userid (testtbl[idx].userid); + char *mbox = mailbox_from_userid (testtbl[idx].userid, 0); + + if (!testtbl[idx].mbox) + { + if (mbox) + fail (idx); + } + else if (!mbox) + fail (idx); + else if (strcmp (mbox, testtbl[idx].mbox)) + fail (idx); + + xfree (mbox); + } +} + + +static void +run_mbox_no_sub_test (void) +{ + static struct + { + const char *userid; + const char *mbox; + } testtbl[] = + { + { "foo+bar@example.org", "foo@example.org" }, + { "Werner Koch ", "wk@gnupg.org" }, + { "", "wk@gnupg.org" }, + { "wk@gnupg.org", "wk@gnupg.org" }, + { "wk@gnupg.org ", NULL }, + { " wk@gnupg.org", NULL }, + { "Werner Koch (test) ", "wk@gnupg.org" }, + { "Werner Koch (test)", "wk@gnupg.org" }, + { "Werner Koch ", NULL }, + { "Werner Koch ", NULL }, + { "", "foo@example.org" }, + { "", "foo.@example.org" }, + { "<.foo.@example.org>", ".foo.@example.org" }, + { "", "foo..@example.org" }, + { "", "foo..bar@example.org" }, + { "", NULL }, + { "", NULL }, + { "", NULL }, + { "<@example.org>", NULL }, + { "", NULL }, + { "<@foo@example.org>", NULL }, + { " ()", "foo@example.org" }, + { " ()", "fo()o@example.org" }, + { " ()", "fo()o@example.org" }, + { "fo()o@example.org", NULL}, + { "Mr. Foo ", "foo@example.org"}, + { "foo+bar@example.org", "foo@example.org" }, + { "foo++bar@example.org", "foo++bar@example.org" }, + { "foo++@example.org", "foo++@example.org" }, + { "foo+@example.org", "foo+@example.org" }, + { "+foo@example.org", "+foo@example.org" }, + { "++foo@example.org", "++foo@example.org" }, + { "+foo+@example.org", "+foo+@example.org" }, + { "+@example.org", "+@example.org" }, + { "++@example.org", "++@example.org" }, + { "foo+b@example.org", "foo@example.org" }, + { "foo+ba@example.org", "foo@example.org" }, + { "foo+bar@example.org", "foo@example.org" }, + { "foo+barb@example.org", "foo@example.org" }, + { "foo+barba@example.org", "foo@example.org" }, + { "f+b@example.org", "f@example.org" }, + { "fo+b@example.org", "fo@example.org" }, + + { NULL, NULL } + }; + int idx; + + for (idx=0; testtbl[idx].userid; idx++) + { + char *mbox = mailbox_from_userid (testtbl[idx].userid, 1); if (!testtbl[idx].mbox) { @@ -151,7 +230,7 @@ run_dns_test (void) static void -run_filter (void) +run_filter (int no_sub) { char buf[4096]; int c; @@ -172,7 +251,7 @@ run_filter (void) } count1++; trim_spaces (buf); - mbox = mailbox_from_userid (buf); + mbox = mailbox_from_userid (buf, no_sub); if (mbox) { printf ("%s\n", mbox); @@ -190,6 +269,7 @@ main (int argc, char **argv) { int last_argc = -1; int opt_filter = 0; + int opt_no_sub = 0; if (argc) { argc--; argv++; } @@ -208,6 +288,7 @@ main (int argc, char **argv) " --verbose Print timings etc.\n" " --debug Flyswatter\n" " --filter Filter mboxes from input lines\n" + " --no-sub Ignore '+'-sub-addresses\n" , stdout); exit (0); } @@ -227,6 +308,11 @@ main (int argc, char **argv) opt_filter = 1; argc--; argv++; } + else if (!strcmp (*argv, "--no-sub")) + { + opt_no_sub = 1; + argc--; argv++; + } else if (!strncmp (*argv, "--", 2)) { fprintf (stderr, PGM ": unknown option '%s'\n", *argv); @@ -235,10 +321,11 @@ main (int argc, char **argv) } if (opt_filter) - run_filter (); + run_filter (opt_no_sub); else { run_mbox_test (); + run_mbox_no_sub_test (); run_dns_test (); } diff --git a/dirmngr/server.c b/dirmngr/server.c index 05a530bce..a21e1abb6 100644 --- a/dirmngr/server.c +++ b/dirmngr/server.c @@ -731,7 +731,7 @@ cmd_dns_cert (assuan_context_t ctx, char *line) /* We lowercase ascii characters but the DANE I-D does not allow this. FIXME: Check after the release of the RFC whether to change this. */ - mbox = mailbox_from_userid (line); + mbox = mailbox_from_userid (line, 0); if (!mbox || !(domain = strchr (mbox, '@'))) { err = set_error (GPG_ERR_INV_USER_ID, "no mailbox in user id"); @@ -855,7 +855,7 @@ proc_wkd_get (ctrl_t ctrl, assuan_context_t ctx, char *line) line = skip_options (line); is_wkd_query = !(opt_policy_flags || opt_submission_addr); - mbox = mailbox_from_userid (line); + mbox = mailbox_from_userid (line, 0); if (!mbox || !(domain = strchr (mbox, '@'))) { err = set_error (GPG_ERR_INV_USER_ID, "no mailbox in user id"); diff --git a/g10/export.c b/g10/export.c index 9477b7526..d53be99fe 100644 --- a/g10/export.c +++ b/g10/export.c @@ -1469,7 +1469,7 @@ print_pka_or_dane_records (iobuf_t out, kbnode_t keyblock, PKT_public_key *pk, continue; xfree (mbox); - mbox = mailbox_from_userid (uid->name); + mbox = mailbox_from_userid (uid->name, 0); if (!mbox) continue; diff --git a/g10/getkey.c b/g10/getkey.c index 75ce9cb38..c776a6100 100644 --- a/g10/getkey.c +++ b/g10/getkey.c @@ -1373,7 +1373,7 @@ pubkey_cmp (ctrl_t ctrl, const char *name, struct pubkey_cmp_cookie *old, n; n = find_next_kbnode (n, PKT_USER_ID)) { PKT_user_id *uid = n->pkt->pkt.user_id; - char *mbox = mailbox_from_userid (uid->name); + char *mbox = mailbox_from_userid (uid->name, 0); int match = mbox ? strcasecmp (name, mbox) == 0 : 0; xfree (mbox); diff --git a/g10/gpg.c b/g10/gpg.c index aeb9c6fc0..110289243 100644 --- a/g10/gpg.c +++ b/g10/gpg.c @@ -3130,7 +3130,7 @@ main (int argc, char **argv) break; case oSender: { - char *mbox = mailbox_from_userid (pargs.r.ret_str); + char *mbox = mailbox_from_userid (pargs.r.ret_str, 0); if (!mbox) log_error (_("\"%s\" is not a proper mail address\n"), pargs.r.ret_str); diff --git a/g10/import.c b/g10/import.c index 23258a0a7..8ea5144b5 100644 --- a/g10/import.c +++ b/g10/import.c @@ -1264,7 +1264,7 @@ impex_filter_getval (void *cookie, const char *propname) { if (!uid->mbox) { - uid->mbox = mailbox_from_userid (uid->name); + uid->mbox = mailbox_from_userid (uid->name, 0); } result = uid->mbox; } diff --git a/g10/keylist.c b/g10/keylist.c index 8b7da76ee..793f7dacd 100644 --- a/g10/keylist.c +++ b/g10/keylist.c @@ -1020,7 +1020,7 @@ list_keyblock_print (ctrl_t ctrl, kbnode_t keyblock, int secret, int fpr, char *mbox, *hash, *p; char hashbuf[32]; - mbox = mailbox_from_userid (uid->name); + mbox = mailbox_from_userid (uid->name, 0); if (mbox && (p = strchr (mbox, '@'))) { *p++ = 0; diff --git a/g10/keyserver.c b/g10/keyserver.c index a8c222d3f..44870a610 100644 --- a/g10/keyserver.c +++ b/g10/keyserver.c @@ -2053,7 +2053,7 @@ keyserver_import_wkd (ctrl_t ctrl, const char *name, int quick, /* We want to work on the mbox. That is what dirmngr will do anyway * and we need the mbox for the import filter anyway. */ - mbox = mailbox_from_userid (name); + mbox = mailbox_from_userid (name, 0); if (!mbox) { err = gpg_error_from_syserror (); diff --git a/g10/sign.c b/g10/sign.c index df888136f..b2d1c1826 100644 --- a/g10/sign.c +++ b/g10/sign.c @@ -153,7 +153,8 @@ mk_notation_policy_etc (PKT_signature *sig, char *mbox; /* For now we use the uid which was used to locate the key. */ - if (pksk->user_id && (mbox = mailbox_from_userid (pksk->user_id->name))) + if (pksk->user_id + && (mbox = mailbox_from_userid (pksk->user_id->name, 0))) { if (DBG_LOOKUP) log_debug ("setting Signer's UID to '%s'\n", mbox); diff --git a/g10/tofu.c b/g10/tofu.c index 762b19b7a..44f354512 100644 --- a/g10/tofu.c +++ b/g10/tofu.c @@ -3292,7 +3292,7 @@ show_warning (const char *fingerprint, strlist_t user_id_list) static char * email_from_user_id (const char *user_id) { - char *email = mailbox_from_userid (user_id); + char *email = mailbox_from_userid (user_id, 0); if (! email) { /* Hmm, no email address was provided or we are out of core. Just diff --git a/g10/trustdb.c b/g10/trustdb.c index c46dc50c8..a230a6c03 100644 --- a/g10/trustdb.c +++ b/g10/trustdb.c @@ -1131,7 +1131,7 @@ tdb_get_validity_core (ctrl_t ctrl, if (sig && sig->signers_uid) /* Make sure the UID matches. */ { - char *email = mailbox_from_userid (user_id->name); + char *email = mailbox_from_userid (user_id->name, 0); if (!email || !*email || strcmp (sig->signers_uid, email) != 0) { if (DBG_TRUST) diff --git a/tools/gpg-wks-client.c b/tools/gpg-wks-client.c index bf6b119e0..0be5ea89b 100644 --- a/tools/gpg-wks-client.c +++ b/tools/gpg-wks-client.c @@ -627,11 +627,11 @@ command_supported (char *userid) if (!strchr (userid, '@')) { char *tmp = xstrconcat ("foo@", userid, NULL); - addrspec = mailbox_from_userid (tmp); + addrspec = mailbox_from_userid (tmp, 0); xfree (tmp); } else - addrspec = mailbox_from_userid (userid); + addrspec = mailbox_from_userid (userid, 0); if (!addrspec) { log_error (_("\"%s\" is not a proper mail address\n"), userid); @@ -694,7 +694,7 @@ command_check (char *userid) uidinfo_list_t sl; int found = 0; - addrspec = mailbox_from_userid (userid); + addrspec = mailbox_from_userid (userid, 0); if (!addrspec) { log_error (_("\"%s\" is not a proper mail address\n"), userid); @@ -805,7 +805,7 @@ command_send (const char *fingerprint, const char *userid) goto leave; } - addrspec = mailbox_from_userid (userid); + addrspec = mailbox_from_userid (userid, 0); if (!addrspec) { log_error (_("\"%s\" is not a proper mail address\n"), userid); diff --git a/tools/gpg-wks-server.c b/tools/gpg-wks-server.c index 24b331262..1b533124a 100644 --- a/tools/gpg-wks-server.c +++ b/tools/gpg-wks-server.c @@ -2020,7 +2020,7 @@ command_install_key (const char *fname, const char *userid) char *huname = NULL; int any; - addrspec = mailbox_from_userid (userid); + addrspec = mailbox_from_userid (userid, 0); if (!addrspec) { log_error ("\"%s\" is not a proper mail address\n", userid); @@ -2153,7 +2153,7 @@ fname_from_userid (const char *userid, char **r_fname, char **r_addrspec) if (r_addrspec) *r_addrspec = NULL; - addrspec = mailbox_from_userid (userid); + addrspec = mailbox_from_userid (userid, 0); if (!addrspec) { if (opt.verbose) diff --git a/tools/wks-util.c b/tools/wks-util.c index 729098a02..cf80a25bc 100644 --- a/tools/wks-util.c +++ b/tools/wks-util.c @@ -104,7 +104,7 @@ append_to_uidinfo_list (uidinfo_list_t *list, const char *uid, time_t created) strcpy (sl->uid, uid); sl->created = created; - sl->mbox = mailbox_from_userid (uid); + sl->mbox = mailbox_from_userid (uid, 0); sl->next = NULL; if (!*list) *list = sl;