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 <wk@gnupg.org>
This commit is contained in:
Werner Koch 2018-11-12 07:44:33 +01:00
parent bbed4746ed
commit 6b9f772914
No known key found for this signature in database
GPG Key ID: E3FDFF218E45B72B
16 changed files with 139 additions and 27 deletions

View File

@ -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;
}

View File

@ -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);

View File

@ -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", "wk@gnupg.org" },
{ "wk@gnupg.org ", NULL },
{ " wk@gnupg.org", NULL },
{ "Werner Koch (test) <wk@gnupg.org>", "wk@gnupg.org" },
{ "Werner Koch <wk@gnupg.org> (test)", "wk@gnupg.org" },
{ "Werner Koch <wk@gnupg.org (test)", NULL },
{ "Werner Koch <wk@gnupg.org >", NULL },
{ "Werner Koch <wk@gnupg.org", NULL },
{ "", NULL },
{ "@", NULL },
{ "bar <>", NULL },
{ "<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..bar@example.org>", "foo..bar@example.org" },
{ "<foo@example.org.>", NULL },
{ "<foo@example..org>", NULL },
{ "<foo@.>", NULL },
{ "<@example.org>", NULL },
{ "<foo@@example.org>", NULL },
{ "<@foo@example.org>", NULL },
{ "<foo@example.org> ()", "foo@example.org" },
{ "<fo()o@example.org> ()", "fo()o@example.org" },
{ "<fo()o@example.org> ()", "fo()o@example.org" },
{ "fo()o@example.org", NULL},
{ "Mr. Foo <foo@example.org><bar@example.net>", "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 ();
}

View File

@ -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");

View File

@ -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;

View File

@ -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);

View File

@ -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);

View File

@ -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;
}

View File

@ -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;

View File

@ -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 ();

View File

@ -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);

View File

@ -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

View File

@ -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)

View File

@ -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);

View File

@ -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)

View File

@ -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;