LCOV - code coverage report
Current view: top level - common - mbox-util.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 86 94 91.5 %
Date: 2015-11-05 17:10:59 Functions: 9 10 90.0 %

          Line data    Source code
       1             : /* mbox-util.c - Mail address helper functions
       2             :  * Copyright (C) 1998-2010 Free Software Foundation, Inc.
       3             :  * Copyright (C) 1998-2015 Werner Koch
       4             :  *
       5             :  * This file is part of GnuPG.
       6             :  *
       7             :  * This file is free software; you can redistribute it and/or modify
       8             :  * it under the terms of either
       9             :  *
      10             :  *   - the GNU Lesser General Public License as published by the Free
      11             :  *     Software Foundation; either version 3 of the License, or (at
      12             :  *     your option) any later version.
      13             :  *
      14             :  * or
      15             :  *
      16             :  *   - the GNU General Public License as published by the Free
      17             :  *     Software Foundation; either version 2 of the License, or (at
      18             :  *     your option) any later version.
      19             :  *
      20             :  * or both in parallel, as here.
      21             :  *
      22             :  * This file is distributed in the hope that it will be useful,
      23             :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      24             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      25             :  * GNU General Public License for more details.
      26             :  *
      27             :  * You should have received a copy of the GNU General Public License
      28             :  * along with this program; if not, see <http://www.gnu.org/licenses/>.
      29             :  */
      30             : 
      31             : #include <config.h>
      32             : #include <stdio.h>
      33             : #include <stdlib.h>
      34             : #include <string.h>
      35             : #include <unistd.h>
      36             : #include <errno.h>
      37             : 
      38             : #include "util.h"
      39             : #include "mbox-util.h"
      40             : 
      41             : 
      42             : static int
      43          20 : string_count_chr (const char *string, int c)
      44             : {
      45             :   int count;
      46             : 
      47         311 :   for (count=0; *string; string++ )
      48         291 :     if ( *string == c )
      49          22 :       count++;
      50          20 :   return count;
      51             : }
      52             : 
      53             : static int
      54         238 : mem_count_chr (const void *buffer, int c, size_t length)
      55             : {
      56         238 :   const char *s = buffer;
      57             :   int count;
      58             : 
      59        3179 :   for (count=0; length; length--, s++)
      60        2941 :     if (*s == c)
      61         124 :       count++;
      62         238 :   return count;
      63             : }
      64             : 
      65             : 
      66             : /* This is a case-sensitive version of our memistr.  I wonder why no
      67             :    standard function memstr exists but I better do not use the name
      68             :    memstr to avoid future conflicts.  */
      69             : static const char *
      70         123 : my_memstr (const void *buffer, size_t buflen, const char *sub)
      71             : {
      72         123 :   const unsigned char *buf = buffer;
      73         123 :   const unsigned char *t = (const unsigned char *)buf;
      74         123 :   const unsigned char *s = (const unsigned char *)sub;
      75         123 :   size_t n = buflen;
      76             : 
      77        1965 :   for ( ; n ; t++, n-- )
      78             :     {
      79        1842 :       if (*t == *s)
      80             :         {
      81         123 :           for (buf = t++, buflen = n--, s++; n && *t ==*s; t++, s++, n--)
      82             :             ;
      83         123 :           if (!*s)
      84           0 :             return (const char*)buf;
      85         123 :           t = (const unsigned char *)buf;
      86         123 :           s = (const unsigned char *)sub ;
      87         123 :           n = buflen;
      88             :         }
      89             :     }
      90         123 :   return NULL;
      91             : }
      92             : 
      93             : 
      94             : 
      95             : static int
      96          15 : string_has_ctrl_or_space (const char *string)
      97             : {
      98         240 :   for (; *string; string++ )
      99         226 :     if (!(*string & 0x80) && *string <= 0x20)
     100           1 :       return 1;
     101          14 :   return 0;
     102             : }
     103             : 
     104             : 
     105             : /* Return true if STRING has two consecutive '.' after an '@'
     106             :    sign.  */
     107             : static int
     108          14 : has_dotdot_after_at (const char *string)
     109             : {
     110          14 :   string = strchr (string, '@');
     111          14 :   if (!string)
     112           0 :     return 0; /* No at-sign.  */
     113          14 :   string++;
     114          14 :   return !!strstr (string, "..");
     115             : }
     116             : 
     117             : 
     118             : /* Check whether BUFFER has characters not valid in an RFC-822
     119             :    address.  LENGTH gives the length of BUFFER.
     120             : 
     121             :    To cope with OpenPGP we ignore non-ascii characters so that for
     122             :    example umlauts are legal in an email address.  An OpenPGP user ID
     123             :    must be utf-8 encoded but there is no strict requirement for
     124             :    RFC-822.  Thus to avoid IDNA encoding we put the address verbatim
     125             :    as utf-8 into the user ID under the assumption that mail programs
     126             :    handle IDNA at a lower level and take OpenPGP user IDs as utf-8.
     127             :    Note that we can't do an utf-8 encoding checking here because in
     128             :    keygen.c this function is called with the native encoding and
     129             :    native to utf-8 encoding is only done later.  */
     130             : int
     131         507 : has_invalid_email_chars (const void *buffer, size_t length)
     132             : {
     133         507 :   const unsigned char *s = buffer;
     134         507 :   int at_seen=0;
     135         507 :   const char *valid_chars=
     136             :     "01234567890_-.abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
     137             : 
     138        5324 :   for ( ; length && *s; length--, s++ )
     139             :     {
     140        5086 :       if ((*s & 0x80))
     141           0 :         continue; /* We only care about ASCII.  */
     142        5086 :       if (*s == '@')
     143         125 :         at_seen=1;
     144        5229 :       else if (!at_seen && !(strchr (valid_chars, *s)
     145         268 :                              || strchr ("!#$%&'*+/=?^`{|}~", *s)))
     146         268 :         return 1;
     147        4693 :       else if (at_seen && !strchr (valid_chars, *s))
     148           1 :         return 1;
     149             :     }
     150         238 :   return 0;
     151             : }
     152             : 
     153             : 
     154             : /* Same as is_valid_mailbox (see below) but operates on non-nul
     155             :    terminated buffer.  */
     156             : int
     157         508 : is_valid_mailbox_mem (const void *name_arg, size_t namelen)
     158             : {
     159         508 :   const char *name = name_arg;
     160             : 
     161         631 :   return !( !name
     162         508 :             || !namelen
     163         507 :             || has_invalid_email_chars (name, namelen)
     164         238 :             || mem_count_chr (name, '@', namelen) != 1
     165         124 :             || *name == '@'
     166         123 :             || name[namelen-1] == '@'
     167         123 :             || name[namelen-1] == '.'
     168         123 :             || my_memstr (name, namelen, ".."));
     169             : }
     170             : 
     171             : 
     172             : /* Check whether NAME represents a valid mailbox according to
     173             :    RFC822. Returns true if so. */
     174             : int
     175         508 : is_valid_mailbox (const char *name)
     176             : {
     177         508 :   return name? is_valid_mailbox_mem (name, strlen (name)) : 0;
     178             : }
     179             : 
     180             : 
     181             : /* Return the mailbox (local-part@domain) form a standard user id.
     182             :    All plain ASCII characters in the result are converted to
     183             :    lowercase.  Caller must free the result.  Returns NULL if no valid
     184             :    mailbox was found (or we are out of memory). */
     185             : char *
     186         295 : mailbox_from_userid (const char *userid)
     187             : {
     188             :   const char *s, *s_end;
     189             :   size_t len;
     190         295 :   char *result = NULL;
     191             : 
     192         295 :   s = strchr (userid, '<');
     193         295 :   if (s)
     194             :     {
     195             :       /* Seems to be a standard user id.  */
     196          23 :       s++;
     197          23 :       s_end = strchr (s, '>');
     198          23 :       if (s_end && s_end > s)
     199             :         {
     200          20 :           len = s_end - s;
     201          20 :           result = xtrymalloc (len + 1);
     202          20 :           if (!result)
     203           0 :             return NULL; /* Ooops - out of core.  */
     204          20 :           strncpy (result, s, len);
     205          20 :           result[len] = 0;
     206             :           /* Apply some basic checks on the address.  We do not use
     207             :              is_valid_mailbox because those checks are too strict.  */
     208          40 :           if (string_count_chr (result, '@') != 1  /* Need exactly one '@.  */
     209          18 :               || *result == '@'           /* local-part missing.  */
     210          17 :               || result[len-1] == '@'     /* domain missing.  */
     211          17 :               || result[len-1] == '.'     /* ends with a dot.  */
     212          15 :               || string_has_ctrl_or_space (result)
     213          14 :               || has_dotdot_after_at (result))
     214             :             {
     215           7 :               xfree (result);
     216           7 :               result = NULL;
     217           7 :               errno = EINVAL;
     218             :             }
     219             :         }
     220             :       else
     221           3 :         errno = EINVAL;
     222             :     }
     223         272 :   else if (is_valid_mailbox (userid))
     224             :     {
     225             :       /* The entire user id is a mailbox.  Return that one.  Note that
     226             :          this fallback method has some restrictions on the valid
     227             :          syntax of the mailbox.  However, those who want weird
     228             :          addresses should know about it and use the regular <...>
     229             :          syntax.  */
     230           1 :       result = xtrystrdup (userid);
     231             :     }
     232             :   else
     233         271 :     errno = EINVAL;
     234             : 
     235         295 :   return result? ascii_strlwr (result): NULL;
     236             : }
     237             : 
     238             : 
     239             : /* Check whether UID is a valid standard user id of the form
     240             :      "Heinrich Heine <heinrichh@duesseldorf.de>"
     241             :    and return true if this is the case. */
     242             : int
     243           0 : is_valid_user_id (const char *uid)
     244             : {
     245           0 :   if (!uid || !*uid)
     246           0 :     return 0;
     247             : 
     248           0 :   return 1;
     249             : }

Generated by: LCOV version 1.11