aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorWerner Koch <[email protected]>2015-02-24 16:43:57 +0000
committerWerner Koch <[email protected]>2015-02-24 16:46:22 +0000
commit93fa3d5c1760f3fee5412fb29d58fbd60db16ea9 (patch)
treeb89b401ea5231a9300aca6a9f299d693c36923bd
parentcommon: Add another test case to zb32.c (diff)
downloadgnupg-93fa3d5c1760f3fee5412fb29d58fbd60db16ea9.tar.gz
gnupg-93fa3d5c1760f3fee5412fb29d58fbd60db16ea9.zip
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 <[email protected]>
-rw-r--r--g10/Makefile.am5
-rw-r--r--g10/mailbox.c184
-rw-r--r--g10/main.h10
-rw-r--r--g10/misc.c75
-rw-r--r--g10/t-mailbox.c127
5 files changed, 322 insertions, 79 deletions
diff --git a/g10/Makefile.am b/g10/Makefile.am
index 0a021195a..070492406 100644
--- a/g10/Makefile.am
+++ b/g10/Makefile.am
@@ -83,6 +83,7 @@ common_source = \
textfilter.c \
progress.c \
misc.c \
+ mailbox.c \
rmd160.c rmd160.h \
options.h \
openfile.c \
@@ -154,9 +155,11 @@ gpgv2_LDADD = $(LDADD) $(LIBGCRYPT_LIBS) \
gpgv2_LDFLAGS = $(extra_bin_ldflags)
t_common_ldadd =
-module_tests = t-rmd160
+module_tests = t-rmd160 t-mailbox
t_rmd160_SOURCES = t-rmd160.c rmd160.c
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
diff --git a/g10/mailbox.c b/g10/mailbox.c
new file mode 100644
index 000000000..64b818f37
--- /dev/null
+++ b/g10/mailbox.c
@@ -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 <[email protected]>"
+ and return true if this is the case. */
+int
+is_valid_user_id (const char *uid)
+{
+ if (!uid || !*uid)
+ return 0;
+
+ return 1;
+}
diff --git a/g10/main.h b/g10/main.h
index d313afb1c..8c326f645 100644
--- a/g10/main.h
+++ b/g10/main.h
@@ -162,9 +162,6 @@ char *optsep(char **stringp);
char *argsplit(char *string);
int parse_options(char *str,unsigned int *options,
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);
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);
+/*-- 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 --*/
void set_status_fd ( int fd );
int is_status_enabled ( void );
diff --git a/g10/misc.c b/g10/misc.c
index 276ff0a1a..4cff2dc88 100644
--- a/g10/misc.c
+++ b/g10/misc.c
@@ -70,18 +70,6 @@
#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
/* 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 <[email protected]>"
- 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. */
int
path_access(const char *file,int mode)
diff --git a/g10/t-mailbox.c b/g10/t-mailbox.c
new file mode 100644
index 000000000..aa7cf3399
--- /dev/null
+++ b/g10/t-mailbox.c
@@ -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 <[email protected]>", "[email protected]" },
+ { "[email protected] ", NULL },
+ { " [email protected]", NULL },
+ { "Werner Koch (test) <[email protected]>", "[email protected]" },
+ { "Werner Koch <[email protected]> (test)", "[email protected]" },
+ { "Werner Koch <[email protected] (test)", NULL },
+ { "Werner Koch <[email protected] >", NULL },
+ { "Werner Koch <[email protected]", NULL },
+ { "", NULL },
+ { "@", NULL },
+ { "bar <>", NULL },
+ { "<[email protected].>", NULL },
+ { "<[email protected]>", NULL },
+ { "<foo@.>", NULL },
+ { "<@example.org>", NULL },
+ { "<foo@@example.org>", NULL },
+ { "<@[email protected]>", NULL },
+ { "<fo()[email protected]> ()", "fo()[email protected]" },
+ { "<fo()[email protected]> ()", "fo()[email protected]" },
+ { "fo()[email protected]", NULL},
+ { 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;
+}