tidying
[exim.git] / src / src / parse.c
index edbee2646d021769b00315666140211e02666563..4a75d229e8bd5011f8fe1bd0661da1123eba93ae 100644 (file)
@@ -2,9 +2,10 @@
 *     Exim - an Internet mail transport agent    *
 *************************************************/
 
+/* Copyright (c) The Exim Maintainers 2020 - 2023 */
 /* Copyright (c) University of Cambridge 1995 - 2018 */
-/* Copyright (c) The Exim Maintainers 2020 - 2021 */
 /* See the file NOTICE for conditions of use and distribution. */
+/* SPDX-License-Identifier: GPL-2.0-or-later */
 
 /* Functions for parsing addresses */
 
@@ -22,22 +23,25 @@ redundant apparatus. */
 
 #ifdef STAND_ALONE
 
-address_item *deliver_make_addr(uschar *address, BOOL copy)
+address_item *
+deliver_make_addr(uschar *address, BOOL copy)
 {
-address_item *addr = store_get(sizeof(address_item), FALSE);
+address_item *addr = store_get(sizeof(address_item), GET_UNTAINTED);
 addr->next = NULL;
 addr->parent = NULL;
 addr->address = address;
 return addr;
 }
 
-uschar *rewrite_address(uschar *recipient, BOOL dummy1, BOOL dummy2, rewrite_rule
+uschar *
+rewrite_address(uschar *recipient, BOOL dummy1, BOOL dummy2, rewrite_rule
   *dummy3, int dummy4)
 {
 return recipient;
 }
 
-uschar *rewrite_address_qualify(uschar *recipient, BOOL dummy1)
+uschar *
+rewrite_address_qualify(uschar *recipient, BOOL dummy1)
 {
 return recipient;
 }
@@ -65,30 +69,31 @@ Returns:   pointer past the end of the address
 */
 
 uschar *
-parse_find_address_end(const uschar *s, BOOL nl_ends)
+parse_find_address_end(const uschar * s, BOOL nl_ends)
 {
 BOOL source_routing = *s == '@';
-int no_term = source_routing? 1 : 0;
+int no_term = source_routing ? 1 : 0;
 
-while (*s != 0 && (*s != ',' || no_term > 0) && (*s != '\n' || !nl_ends))
+while (*s && (*s != ',' || no_term > 0) && (*s != '\n' || !nl_ends))
   {
   /* Skip single quoted characters. Strictly these should not occur outside
   quoted strings in RFC 822 addresses, but they can in RFC 821 addresses. Pity
   about the lack of consistency, isn't it? */
 
-  if (*s == '\\' && s[1] != 0) s += 2;
+  if (*s == '\\' && s[1])
+    s += 2;
 
   /* Skip quoted items that are not inside brackets. Note that
   quoted pairs are allowed inside quoted strings. */
 
   else if (*s == '\"')
-    {
-    while (*(++s) != 0 && (*s != '\n' || !nl_ends))
+    while (*++s && (*s != '\n' || !nl_ends))
       {
-      if (*s == '\\' && s[1] != 0) s++;
-        else if (*s == '\"') { s++; break; }
+      if (*s == '\\' && s[1])
+       s++;
+      else if (*s == '\"')
+       { s++; break; }
       }
-    }
 
   /* Skip comments, which may include nested brackets, but quotes
   are not recognized inside comments, though quoted pairs are. */
@@ -96,12 +101,13 @@ while (*s != 0 && (*s != ',' || no_term > 0) && (*s != '\n' || !nl_ends))
   else if (*s == '(')
     {
     int level = 1;
-    while (*(++s) != 0 && (*s != '\n' || !nl_ends))
-      {
-      if (*s == '\\' && s[1] != 0) s++;
-        else if (*s == '(') level++;
-          else if (*s == ')' && --level <= 0) { s++; break; }
-      }
+    while (*++s && (*s != '\n' || !nl_ends))
+      if (*s == '\\' && s[1])
+       s++;
+      else if (*s == '(')
+       level++;
+      else if (*s == ')' && --level <= 0)
+       { s++; break; }
     }
 
   /* Non-special character; just advance. Passing the colon in a source
@@ -113,10 +119,12 @@ while (*s != 0 && (*s != ',' || no_term > 0) && (*s != '\n' || !nl_ends))
     if (*s == '<')
       {
       source_routing = s[1] == '@';
-      no_term = source_routing? 2 : 1;
+      no_term = source_routing ? 2 : 1;
       }
-    else if (*s == '>') no_term--;
-    else if (source_routing && *s == ':') no_term--;
+    else if (*s == '>')
+      no_term--;
+    else if (source_routing && *s == ':')
+      no_term--;
     s++;
     }
   }
@@ -627,7 +635,7 @@ uschar *
 parse_extract_address(const uschar *mailbox, uschar **errorptr, int *start, int *end,
   int *domain, BOOL allow_null)
 {
-uschar *yield = store_get(Ustrlen(mailbox) + 1, is_tainted(mailbox));
+uschar * yield = store_get(Ustrlen(mailbox) + 1, mailbox);
 const uschar *startptr, *endptr;
 const uschar *s = US mailbox;
 uschar *t = US yield;
@@ -655,7 +663,7 @@ followed by a route-addr (more words must follow). */
 
 if (*s != '@' && *s != '<')
   {
-  if (*s == 0 || *s == ';')
+  if (!*s || *s == ';')
     {
     if (!*t) FAILED(US"empty address");
     endptr = last_comment_position;
@@ -871,26 +879,26 @@ Returns:       pointer to the original string, if no quoting needed, or
 */
 
 const uschar *
-parse_quote_2047(const uschar *string, int len, const uschar *charset,
+parse_quote_2047(const uschar * string, int len, const uschar * charset,
   BOOL fold)
 {
 const uschar * s = string;
-int hlen, l;
+int hlen, line_off;
 BOOL coded = FALSE;
 BOOL first_byte = FALSE;
 gstring * g =
-  string_fmt_append(NULL, "=?%s?Q?", charset ? charset : US"iso-8859-1");
+  string_fmt_append(NULL, "=?%s?Q?%n", charset ? charset : US"iso-8859-1", &hlen);
 
-hlen = l = g->ptr;
+line_off = hlen;
 
 for (s = string; len > 0; s++, len--)
   {
   int ch = *s;
 
-  if (g->ptr - l > 67 && !first_byte)
+  if (g->ptr - line_off > 67 && !first_byte)
     {
     g = fold ? string_catn(g, US"?=\n ", 4) : string_catn(g, US"?= ", 3);
-    l = g->ptr;
+    line_off = g->ptr;
     g = string_catn(g, g->s, hlen);
     }
 
@@ -994,11 +1002,9 @@ if (i < len)
 /* No non-printers; use the RFC 822 quoting rules */
 
 if (len <= 0 || len >= INT_MAX/4)
-  {
-  return string_copy_taint(CUS"", is_tainted(phrase));
-  }
+  return string_copy_taint(CUS"", phrase);
 
-buffer = store_get((len+1)*4, is_tainted(phrase));
+buffer = store_get((len+1)*4, phrase);
 
 s = phrase;
 end = s + len;
@@ -1243,7 +1249,7 @@ Returns:      FF_DELIVERED      addresses extracted
 
 int
 parse_forward_list(const uschar *s, int options, address_item **anchor,
-  uschar **error, const uschar *incoming_domain, uschar *directory,
+  uschar **error, const uschar *incoming_domain, const uschar *directory,
   error_block **syntax_errors)
 {
 int count = 0;
@@ -1252,18 +1258,15 @@ DEBUG(D_route) debug_printf("parse_forward_list: %s\n", s);
 
 for (;;)
   {
-  int len;
-  int special = 0;
-  int specopt = 0;
-  int specbit = 0;
-  const uschar *ss, *nexts;
-  address_item *addr;
+  int len, special = 0, specopt = 0, specbit = 0;
+  const uschar * ss, * nexts;
+  address_item * addr;
   BOOL inquote = FALSE;
 
   for (;;)
     {
     while (isspace(*s) || *s == ',') s++;
-    if (*s == '#') { while (*s != 0 && *s != '\n') s++; } else break;
+    if (*s == '#') { while (*s && *s != '\n') s++; } else break;
     }
 
   /* When we reach the end of the list, we return FF_DELIVERED if any child
@@ -1287,8 +1290,8 @@ for (;;)
 #ifdef NEVER
     if (count > 0) return FF_DELIVERED;   /* Something was generated */
 
-    if (syntax_errors == NULL ||          /* Not skipping syntax errors, or */
-       *syntax_errors == NULL)            /*   we didn't actually skip any */
+    if (!syntax_errors ||          /* Not skipping syntax errors, or */
+       !*syntax_errors)            /*   we didn't actually skip any */
       return FF_NOTDELIVERED;
 
     *error = string_sprintf("no addresses generated: syntax error in %s: %s",
@@ -1311,7 +1314,7 @@ for (;;)
 
   /* Remove any trailing spaces; we know there's at least one non-space. */
 
-  while (isspace((ss[-1]))) ss--;
+  while (isspace(ss[-1])) ss--;
 
   /* We now have s->start and ss->end of the next address. Remove quotes
   if they completely enclose, remembering the address started with a quote
@@ -1324,7 +1327,7 @@ for (;;)
     ss--;
     inquote = TRUE;
     while (s < ss && isspace(*s)) s++;
-    while (ss > s && isspace((ss[-1]))) ss--;
+    while (ss > s && isspace(ss[-1])) ss--;
     }
 
   /* Set up the length of the address. */
@@ -1360,7 +1363,7 @@ for (;;)
       *error = string_sprintf("\"%.*s\" is not permitted", len, s);
       return FF_ERROR;
       }
-    while (*ss && isspace(*ss)) ss++;  /* skip leading whitespace */
+    Uskip_whitespace(&ss);             /* skip leading whitespace */
     if ((len = Ustrlen(ss)) > 0)       /* ignore trailing newlines */
       for (const uschar * t = ss + len - 1; t >= ss && *t == '\n'; t--) len--;
     *error = string_copyn(ss, len);    /* becomes the error */
@@ -1374,14 +1377,14 @@ for (;;)
 
   if (Ustrncmp(s, ":include:", 9) == 0)
     {
-    uschar *filebuf;
+    uschar * filebuf;
     uschar filename[256];
     const uschar * t = s+9;
     int flen = len - 9;
     int frc;
     struct stat statbuf;
-    address_item *last;
-    FILE *f;
+    address_item * last;
+    FILE * f;
 
     while (flen > 0 && isspace(*t)) { t++; flen--; }
 
@@ -1391,7 +1394,7 @@ for (;;)
       return FF_ERROR;
       }
 
-    if (flen > 255)
+    if (flen > sizeof(filename)-1)
       {
       *error = string_sprintf("included file name \"%s\" is too long", t);
       return FF_ERROR;
@@ -1417,16 +1420,22 @@ for (;;)
       return FF_ERROR;
       }
 
-    if ((*error = is_tainted2(filename, 0, "Tainted name '%s' for included file not permitted\n", filename)))
+    if (is_tainted(filename))
+      {
+      *error = string_sprintf("Tainted name '%s' for included file  not permitted\n",
+       filename);
       return FF_ERROR;
+      }
 
     /* Check file name if required */
 
     if (directory)
       {
       int len = Ustrlen(directory);
-      uschar *p = filename + len;
+      uschar * p;
 
+      while (len > 0 && directory[len-1] == '/') len--;                /* ignore trailing '/' */
+      p = filename + len;
       if (Ustrncmp(filename, directory, len) != 0 || *p != '/')
         {
         *error = string_sprintf("included file %s is not in directory %s",
@@ -1441,7 +1450,7 @@ for (;;)
       with a flag that fails symlinks. */
 
       {
-      int fd = exim_open2(CS directory, O_RDONLY);
+      int fd = exim_open2(CCS directory, O_RDONLY);
       if (fd < 0)
        {
        *error = string_sprintf("failed to open directory %s", directory);
@@ -1451,9 +1460,10 @@ for (;;)
        {
        uschar temp;
        int fd2;
-       uschar * q = p;
+       uschar * q = p + 1;             /* skip dividing '/' */
 
-       while (*++p && *p != '/') ;
+       while (*q == '/') q++;          /* skip extra '/' */
+       while (*++p && *p != '/') ;     /* end of component */
        temp = *p;
        *p = '\0';
 
@@ -1541,7 +1551,7 @@ for (;;)
       return FF_ERROR;
       }
 
-    filebuf = store_get(statbuf.st_size + 1, is_tainted(filename));
+    filebuf = store_get(statbuf.st_size + 1, filename);
     if (fread(filebuf, 1, statbuf.st_size, f) != statbuf.st_size)
       {
       *error = string_sprintf("error while reading included file %s: %s",
@@ -1614,16 +1624,16 @@ for (;;)
     is no domain, treat it as a file or pipe. If it was a quoted item,
     remove the quoting occurrences of \ within it. */
 
-    if ((*s_ltd == '|' || *s_ltd == '/') && (recipient == NULL || domain == 0))
+    if ((*s_ltd == '|' || *s_ltd == '/') && (!recipient || domain == 0))
       {
-      uschar *t = store_get(Ustrlen(s_ltd) + 1, is_tainted(s_ltd));
-      uschar *p = t;
-      uschar *q = s_ltd;
-      while (*q != 0)
+      uschar * t = store_get(Ustrlen(s_ltd) + 1, s_ltd);
+      uschar * p = t, * q = s_ltd;
+
+      while (*q)
         {
         if (inquote)
           {
-          *p++ = (*q == '\\')? *(++q) : *q;
+          *p++ = *q == '\\' ? *++q : *q;
           q++;
           }
         else *p++ = *q++;
@@ -1654,13 +1664,15 @@ for (;;)
 
         if (syntax_errors)
           {
-          error_block *e = store_get(sizeof(error_block), FALSE);
-          error_block *last = *syntax_errors;
-          if (!last) *syntax_errors = e; else
+          error_block * e = store_get(sizeof(error_block), GET_UNTAINTED);
+          error_block * last = *syntax_errors;
+          if (last)
             {
             while (last->next) last = last->next;
             last->next = e;
             }
+          else
+           *syntax_errors = e;
           e->next = NULL;
           e->text1 = *error;
           e->text2 = s_ltd;
@@ -1677,10 +1689,10 @@ for (;;)
       /* Address was successfully parsed. Rewrite, and then make an address
       block. */
 
-      recipient = ((options & RDO_REWRITE) != 0)?
-        rewrite_address(recipient, TRUE, FALSE, global_rewrite_rules,
-          rewrite_existflags) :
-        rewrite_address_qualify(recipient, TRUE);      /*XXX loses track of const */
+      recipient = options & RDO_REWRITE
+       ? rewrite_address(recipient, TRUE, FALSE, global_rewrite_rules,
+                         rewrite_existflags)
+       : rewrite_address_qualify(recipient, TRUE);     /*XXX loses track of const */
       addr = deliver_make_addr(US recipient, TRUE);  /* TRUE => copy recipient, so deconst ok */
       }
 
@@ -1732,7 +1744,7 @@ for the answer, but it may also be very long if we are processing a header
 line. Therefore, take care to release unwanted store afterwards. */
 
 reset_point = store_mark();
-id = *yield = store_get(Ustrlen(str) + 1, is_tainted(str));
+id = *yield = store_get(Ustrlen(str) + 1, str);
 *id++ = *str++;
 
 str = read_addr_spec(str, id, '>', error, &domain);