mirror of
git://git.gnupg.org/gnupg.git
synced 2024-12-22 10:19:57 +01:00
gpg: Add function to extract the mailbox.
* g10/misc.c (has_invalid_email_chars, is_valid_mailbox) (is_valid_user_id): Move to ... * g10/mailbox.c: new file. (string_has_ctrl_or_space, has_dotdot_after_at): New. (has_invalid_email_chars): New. * g10/t-mailbox.c: New. * g10/Makefile.am (module_tests): Add t-mailbox. (t_mailbox_SOURCES, t_mailbox_LDADD): New. -- Signed-off-by: Werner Koch <wk@gnupg.org>
This commit is contained in:
parent
d790111801
commit
93fa3d5c17
@ -83,6 +83,7 @@ common_source = \
|
|||||||
textfilter.c \
|
textfilter.c \
|
||||||
progress.c \
|
progress.c \
|
||||||
misc.c \
|
misc.c \
|
||||||
|
mailbox.c \
|
||||||
rmd160.c rmd160.h \
|
rmd160.c rmd160.h \
|
||||||
options.h \
|
options.h \
|
||||||
openfile.c \
|
openfile.c \
|
||||||
@ -154,9 +155,11 @@ gpgv2_LDADD = $(LDADD) $(LIBGCRYPT_LIBS) \
|
|||||||
gpgv2_LDFLAGS = $(extra_bin_ldflags)
|
gpgv2_LDFLAGS = $(extra_bin_ldflags)
|
||||||
|
|
||||||
t_common_ldadd =
|
t_common_ldadd =
|
||||||
module_tests = t-rmd160
|
module_tests = t-rmd160 t-mailbox
|
||||||
t_rmd160_SOURCES = t-rmd160.c rmd160.c
|
t_rmd160_SOURCES = t-rmd160.c rmd160.c
|
||||||
t_rmd160_LDADD = $(t_common_ldadd)
|
t_rmd160_LDADD = $(t_common_ldadd)
|
||||||
|
t_mailbox_SOURCES = t-mailbox.c mailbox.c
|
||||||
|
t_mailbox_LDADD = $(t_common_ldadd)
|
||||||
|
|
||||||
|
|
||||||
$(PROGRAMS): $(needed_libs) ../common/libgpgrl.a
|
$(PROGRAMS): $(needed_libs) ../common/libgpgrl.a
|
||||||
|
184
g10/mailbox.c
Normal file
184
g10/mailbox.c
Normal file
@ -0,0 +1,184 @@
|
|||||||
|
/* mailbox.c - Mail address helper functions
|
||||||
|
* Copyright (C) 1998-2010 Free Software Foundation, Inc.
|
||||||
|
* Copyright (C) 2014-2015 Werner Koch
|
||||||
|
*
|
||||||
|
* This file is part of GnuPG.
|
||||||
|
*
|
||||||
|
* GnuPG is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* GnuPG is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <config.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
|
#include "gpg.h"
|
||||||
|
#include "util.h"
|
||||||
|
#include "main.h"
|
||||||
|
|
||||||
|
|
||||||
|
static int
|
||||||
|
string_count_chr (const char *string, int c)
|
||||||
|
{
|
||||||
|
int count;
|
||||||
|
|
||||||
|
for (count=0; *string; string++ )
|
||||||
|
if ( *string == c )
|
||||||
|
count++;
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int
|
||||||
|
string_has_ctrl_or_space (const char *string)
|
||||||
|
{
|
||||||
|
for (; *string; string++ )
|
||||||
|
if (!(*string & 0x80) && *string <= 0x20)
|
||||||
|
return 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Return true if STRING has two consecutive '.' after an '@'
|
||||||
|
sign. */
|
||||||
|
static int
|
||||||
|
has_dotdot_after_at (const char *string)
|
||||||
|
{
|
||||||
|
string = strchr (string, '@');
|
||||||
|
if (!string)
|
||||||
|
return 0; /* No at-sign. */
|
||||||
|
string++;
|
||||||
|
return !!strstr (string, "..");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Check whether the string has characters not valid in an RFC-822
|
||||||
|
address. To cope with OpenPGP we ignore non-ascii characters
|
||||||
|
so that for example umlauts are legal in an email address. An
|
||||||
|
OpenPGP user ID must be utf-8 encoded but there is no strict
|
||||||
|
requirement for RFC-822. Thus to avoid IDNA encoding we put the
|
||||||
|
address verbatim as utf-8 into the user ID under the assumption
|
||||||
|
that mail programs handle IDNA at a lower level and take OpenPGP
|
||||||
|
user IDs as utf-8. Note that we can't do an utf-8 encoding
|
||||||
|
checking here because in keygen.c this function is called with the
|
||||||
|
native encoding and native to utf-8 encoding is only done later. */
|
||||||
|
int
|
||||||
|
has_invalid_email_chars (const char *s)
|
||||||
|
{
|
||||||
|
int at_seen=0;
|
||||||
|
const char *valid_chars=
|
||||||
|
"01234567890_-.abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
||||||
|
|
||||||
|
for ( ; *s; s++ )
|
||||||
|
{
|
||||||
|
if ( (*s & 0x80) )
|
||||||
|
continue; /* We only care about ASCII. */
|
||||||
|
if ( *s == '@' )
|
||||||
|
at_seen=1;
|
||||||
|
else if ( !at_seen && !(strchr (valid_chars, *s)
|
||||||
|
|| strchr ("!#$%&'*+/=?^`{|}~", *s)))
|
||||||
|
return 1;
|
||||||
|
else if ( at_seen && !strchr( valid_chars, *s ) )
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Check whether NAME represents a valid mailbox according to
|
||||||
|
RFC822. Returns true if so. */
|
||||||
|
int
|
||||||
|
is_valid_mailbox (const char *name)
|
||||||
|
{
|
||||||
|
return !( !name
|
||||||
|
|| !*name
|
||||||
|
|| has_invalid_email_chars (name)
|
||||||
|
|| string_count_chr (name,'@') != 1
|
||||||
|
|| *name == '@'
|
||||||
|
|| name[strlen(name)-1] == '@'
|
||||||
|
|| name[strlen(name)-1] == '.'
|
||||||
|
|| strstr (name, "..") );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Return the mailbox (local-part@domain) form a standard user id.
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
const char *s, *s_end;
|
||||||
|
size_t len;
|
||||||
|
char *result = NULL;
|
||||||
|
|
||||||
|
s = strchr (userid, '<');
|
||||||
|
if (s)
|
||||||
|
{
|
||||||
|
/* Seems to be a standard user id. */
|
||||||
|
s++;
|
||||||
|
s_end = strchr (s, '>');
|
||||||
|
if (s_end && s_end > s)
|
||||||
|
{
|
||||||
|
len = s_end - s;
|
||||||
|
result = xtrymalloc (len + 1);
|
||||||
|
if (!result)
|
||||||
|
return NULL; /* Ooops - out of core. */
|
||||||
|
strncpy (result, s, len);
|
||||||
|
result[len] = 0;
|
||||||
|
/* Apply some basic checks on the address. We do not use
|
||||||
|
is_valid_mailbox because those checks are too strict. */
|
||||||
|
if (string_count_chr (result, '@') != 1 /* Need exactly one '@. */
|
||||||
|
|| *result == '@' /* local-part missing. */
|
||||||
|
|| result[len-1] == '@' /* domain missing. */
|
||||||
|
|| result[len-1] == '.' /* ends with a dot. */
|
||||||
|
|| string_has_ctrl_or_space (result)
|
||||||
|
|| has_dotdot_after_at (result))
|
||||||
|
{
|
||||||
|
xfree (result);
|
||||||
|
result = NULL;
|
||||||
|
errno = EINVAL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
errno = EINVAL;
|
||||||
|
}
|
||||||
|
else if (is_valid_mailbox (userid))
|
||||||
|
{
|
||||||
|
/* The entire user id is a mailbox. Return that one. Note that
|
||||||
|
this fallback method has some restrictions on the valid
|
||||||
|
syntax of the mailbox. However, those who want weird
|
||||||
|
addresses should know about it and use the regular <...>
|
||||||
|
syntax. */
|
||||||
|
result = xtrystrdup (userid);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
errno = EINVAL;
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Check whether UID is a valid standard user id of the form
|
||||||
|
"Heinrich Heine <heinrichh@duesseldorf.de>"
|
||||||
|
and return true if this is the case. */
|
||||||
|
int
|
||||||
|
is_valid_user_id (const char *uid)
|
||||||
|
{
|
||||||
|
if (!uid || !*uid)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
10
g10/main.h
10
g10/main.h
@ -162,9 +162,6 @@ char *optsep(char **stringp);
|
|||||||
char *argsplit(char *string);
|
char *argsplit(char *string);
|
||||||
int parse_options(char *str,unsigned int *options,
|
int parse_options(char *str,unsigned int *options,
|
||||||
struct parse_options *opts,int noisy);
|
struct parse_options *opts,int noisy);
|
||||||
int has_invalid_email_chars (const char *s);
|
|
||||||
int is_valid_mailbox (const char *name);
|
|
||||||
int is_valid_user_id (const char *uid);
|
|
||||||
const char *get_libexecdir (void);
|
const char *get_libexecdir (void);
|
||||||
int path_access(const char *file,int mode);
|
int path_access(const char *file,int mode);
|
||||||
|
|
||||||
@ -179,6 +176,13 @@ int mpi_print (estream_t stream, gcry_mpi_t a, int mode);
|
|||||||
unsigned int ecdsa_qbits_from_Q (unsigned int qbits);
|
unsigned int ecdsa_qbits_from_Q (unsigned int qbits);
|
||||||
|
|
||||||
|
|
||||||
|
/*-- mailbox.c --*/
|
||||||
|
int has_invalid_email_chars (const char *s);
|
||||||
|
int is_valid_mailbox (const char *name);
|
||||||
|
char *mailbox_from_userid (const char *userid);
|
||||||
|
int is_valid_user_id (const char *uid);
|
||||||
|
|
||||||
|
|
||||||
/*-- status.c --*/
|
/*-- status.c --*/
|
||||||
void set_status_fd ( int fd );
|
void set_status_fd ( int fd );
|
||||||
int is_status_enabled ( void );
|
int is_status_enabled ( void );
|
||||||
|
75
g10/misc.c
75
g10/misc.c
@ -70,18 +70,6 @@
|
|||||||
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
|
||||||
static int
|
|
||||||
string_count_chr (const char *string, int c)
|
|
||||||
{
|
|
||||||
int count;
|
|
||||||
|
|
||||||
for (count=0; *string; string++ )
|
|
||||||
if ( *string == c )
|
|
||||||
count++;
|
|
||||||
return count;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#ifdef ENABLE_SELINUX_HACKS
|
#ifdef ENABLE_SELINUX_HACKS
|
||||||
/* A object and a global variable to keep track of files marked as
|
/* A object and a global variable to keep track of files marked as
|
||||||
@ -1464,69 +1452,6 @@ parse_options(char *str,unsigned int *options,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Check whether the string has characters not valid in an RFC-822
|
|
||||||
address. To cope with OpenPGP we ignore non-ascii characters
|
|
||||||
so that for example umlauts are legal in an email address. An
|
|
||||||
OpenPGP user ID must be utf-8 encoded but there is no strict
|
|
||||||
requirement for RFC-822. Thus to avoid IDNA encoding we put the
|
|
||||||
address verbatim as utf-8 into the user ID under the assumption
|
|
||||||
that mail programs handle IDNA at a lower level and take OpenPGP
|
|
||||||
user IDs as utf-8. Note that we can't do an utf-8 encoding
|
|
||||||
checking here because in keygen.c this function is called with the
|
|
||||||
native encoding and native to utf-8 encoding is only done later. */
|
|
||||||
int
|
|
||||||
has_invalid_email_chars (const char *s)
|
|
||||||
{
|
|
||||||
int at_seen=0;
|
|
||||||
const char *valid_chars=
|
|
||||||
"01234567890_-.abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
|
||||||
|
|
||||||
for ( ; *s; s++ )
|
|
||||||
{
|
|
||||||
if ( (*s & 0x80) )
|
|
||||||
continue; /* We only care about ASCII. */
|
|
||||||
if ( *s == '@' )
|
|
||||||
at_seen=1;
|
|
||||||
else if ( !at_seen && !(strchr (valid_chars, *s)
|
|
||||||
|| strchr ("!#$%&'*+/=?^`{|}~", *s)))
|
|
||||||
return 1;
|
|
||||||
else if ( at_seen && !strchr( valid_chars, *s ) )
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* Check whether NAME represents a valid mailbox according to
|
|
||||||
RFC822. Returns true if so. */
|
|
||||||
int
|
|
||||||
is_valid_mailbox (const char *name)
|
|
||||||
{
|
|
||||||
return !( !name
|
|
||||||
|| !*name
|
|
||||||
|| has_invalid_email_chars (name)
|
|
||||||
|| string_count_chr (name,'@') != 1
|
|
||||||
|| *name == '@'
|
|
||||||
|| name[strlen(name)-1] == '@'
|
|
||||||
|| name[strlen(name)-1] == '.'
|
|
||||||
|| strstr (name, "..") );
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* Check whether UID is a valid standard user id of the form
|
|
||||||
"Heinrich Heine <heinrichh@duesseldorf.de>"
|
|
||||||
and return true if this is the case. */
|
|
||||||
int
|
|
||||||
is_valid_user_id (const char *uid)
|
|
||||||
{
|
|
||||||
if (!uid || !*uid)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* Similar to access(2), but uses PATH to find the file. */
|
/* Similar to access(2), but uses PATH to find the file. */
|
||||||
int
|
int
|
||||||
path_access(const char *file,int mode)
|
path_access(const char *file,int mode)
|
||||||
|
127
g10/t-mailbox.c
Normal file
127
g10/t-mailbox.c
Normal file
@ -0,0 +1,127 @@
|
|||||||
|
/* t-mailbox.c - Module test for mailbox.c
|
||||||
|
* Copyright (C) 2015 Werner Koch
|
||||||
|
*
|
||||||
|
* This file is part of GnuPG.
|
||||||
|
*
|
||||||
|
* GnuPG is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* GnuPG is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <config.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "gpg.h"
|
||||||
|
#include "util.h"
|
||||||
|
#include "main.h"
|
||||||
|
|
||||||
|
#define pass() do { ; } while(0)
|
||||||
|
#define fail(a) do { fprintf (stderr, "%s:%d: test %d failed\n",\
|
||||||
|
__FILE__,__LINE__, (a)); \
|
||||||
|
exit (1); \
|
||||||
|
} while(0)
|
||||||
|
|
||||||
|
|
||||||
|
void *
|
||||||
|
gcry_malloc (size_t n)
|
||||||
|
{
|
||||||
|
return malloc (n);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
char *
|
||||||
|
gcry_strdup (const char *string)
|
||||||
|
{
|
||||||
|
return strdup (string);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
gcry_free (void *a)
|
||||||
|
{
|
||||||
|
if (a)
|
||||||
|
free (a);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
run_test (void)
|
||||||
|
{
|
||||||
|
static struct
|
||||||
|
{
|
||||||
|
const char *userid;
|
||||||
|
const char *mbox;
|
||||||
|
} testtbl[] =
|
||||||
|
{
|
||||||
|
{ "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"},
|
||||||
|
{ NULL, NULL }
|
||||||
|
};
|
||||||
|
int idx;
|
||||||
|
|
||||||
|
for (idx=0; testtbl[idx].userid; idx++)
|
||||||
|
{
|
||||||
|
char *mbox = mailbox_from_userid (testtbl[idx].userid);
|
||||||
|
|
||||||
|
if (!testtbl[idx].mbox)
|
||||||
|
{
|
||||||
|
if (mbox)
|
||||||
|
fail (idx);
|
||||||
|
}
|
||||||
|
else if (!mbox)
|
||||||
|
fail (idx);
|
||||||
|
else if (strcmp (mbox, testtbl[idx].mbox))
|
||||||
|
fail (idx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
main (int argc, char **argv)
|
||||||
|
{
|
||||||
|
(void)argc;
|
||||||
|
(void)argv;
|
||||||
|
|
||||||
|
run_test ();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user