Output newline after list of message IDs output by "-Mxxx" operations
[exim.git] / src / src / rda.c
index ee7c1fe96376fcc853e5c64bd270ae7418e8f238..42b7b14a5557ee972fa6b20dece577c05583f6dc 100644 (file)
@@ -42,14 +42,14 @@ static BOOL
 match_tag(const uschar *s, const uschar *tag)
 {
 for (; *tag != 0; s++, tag++)
 match_tag(const uschar *s, const uschar *tag)
 {
 for (; *tag != 0; s++, tag++)
-  {
   if (*tag == ' ')
     {
     while (*s == ' ' || *s == '\t') s++;
     s--;
     }
   if (*tag == ' ')
     {
     while (*s == ' ' || *s == '\t') s++;
     s--;
     }
-  else if (tolower(*s) != tolower(*tag)) break;
-  }
+  else
+   if (tolower(*s) != tolower(*tag)) break;
+
 return (*tag == 0);
 }
 
 return (*tag == 0);
 }
 
@@ -96,37 +96,37 @@ static int
 rda_exists(uschar *filename, uschar **error)
 {
 int rc, saved_errno;
 rda_exists(uschar *filename, uschar **error)
 {
 int rc, saved_errno;
-uschar *slash;
 struct stat statbuf;
 struct stat statbuf;
+uschar * s;
 
 if ((rc = Ustat(filename, &statbuf)) >= 0) return FILE_EXIST;
 saved_errno = errno;
 
 
 if ((rc = Ustat(filename, &statbuf)) >= 0) return FILE_EXIST;
 saved_errno = errno;
 
-Ustrncpy(big_buffer, filename, big_buffer_size - 3);
+s = string_copy(filename);
 sigalrm_seen = FALSE;
 
 if (saved_errno == ENOENT)
   {
 sigalrm_seen = FALSE;
 
 if (saved_errno == ENOENT)
   {
-  slash = Ustrrchr(big_buffer, '/');
-  Ustrcpy(slash+1, ".");
+  uschar * slash = Ustrrchr(s, '/');
+  Ustrcpy(slash+1, US".");
 
 
-  alarm(30);
-  rc = Ustat(big_buffer, &statbuf);
+  ALARM(30);
+  rc = Ustat(s, &statbuf);
   if (rc != 0 && errno == EACCES && !sigalrm_seen)
     {
     *slash = 0;
   if (rc != 0 && errno == EACCES && !sigalrm_seen)
     {
     *slash = 0;
-    rc = Ustat(big_buffer, &statbuf);
+    rc = Ustat(s, &statbuf);
     }
   saved_errno = errno;
     }
   saved_errno = errno;
-  alarm(0);
+  ALARM_CLR(0);
 
 
-  DEBUG(D_route) debug_printf("stat(%s)=%d\n", big_buffer, rc);
+  DEBUG(D_route) debug_printf("stat(%s)=%d\n", s, rc);
   }
 
 if (sigalrm_seen || rc != 0)
   {
   }
 
 if (sigalrm_seen || rc != 0)
   {
-  *error = string_sprintf("failed to stat %s (%s)", big_buffer,
-    sigalrm_seen? "timeout" : strerror(saved_errno));
+  *error = string_sprintf("failed to stat %s (%s)", s,
+    sigalrm_seen?  "timeout" : strerror(saved_errno));
   return FILE_EXIST_UNCLEAR;
   }
 
   return FILE_EXIST_UNCLEAR;
   }
 
@@ -250,11 +250,8 @@ if (!uid_ok)
   if (rdata->pw != NULL && statbuf.st_uid == rdata->pw->pw_uid)
     uid_ok = TRUE;
   else if (rdata->owners != NULL)
   if (rdata->pw != NULL && statbuf.st_uid == rdata->pw->pw_uid)
     uid_ok = TRUE;
   else if (rdata->owners != NULL)
-    {
-    int i;
-    for (i = 1; i <= (int)(rdata->owners[0]); i++)
+    for (int i = 1; i <= (int)(rdata->owners[0]); i++)
       if (rdata->owners[i] == statbuf.st_uid) { uid_ok = TRUE; break; }
       if (rdata->owners[i] == statbuf.st_uid) { uid_ok = TRUE; break; }
-    }
   }
 
 if (!gid_ok)
   }
 
 if (!gid_ok)
@@ -262,11 +259,8 @@ if (!gid_ok)
   if (rdata->pw != NULL && statbuf.st_gid == rdata->pw->pw_gid)
     gid_ok = TRUE;
   else if (rdata->owngroups != NULL)
   if (rdata->pw != NULL && statbuf.st_gid == rdata->pw->pw_gid)
     gid_ok = TRUE;
   else if (rdata->owngroups != NULL)
-    {
-    int i;
-    for (i = 1; i <= (int)(rdata->owngroups[0]); i++)
+    for (int i = 1; i <= (int)(rdata->owngroups[0]); i++)
       if (rdata->owngroups[i] == statbuf.st_gid) { gid_ok = TRUE; break; }
       if (rdata->owngroups[i] == statbuf.st_gid) { gid_ok = TRUE; break; }
-    }
   }
 
 if (!uid_ok || !gid_ok)
   }
 
 if (!uid_ok || !gid_ok)
@@ -287,7 +281,7 @@ if (statbuf.st_size > MAX_FILTER_SIZE)
 
 /* Read the file in one go in order to minimize the time we have it open. */
 
 
 /* Read the file in one go in order to minimize the time we have it open. */
 
-filebuf = store_get(statbuf.st_size + 1);
+filebuf = store_get(statbuf.st_size + 1, is_tainted(filename));
 
 if (fread(filebuf, 1, statbuf.st_size, fwd) != statbuf.st_size)
   {
 
 if (fread(filebuf, 1, statbuf.st_size, fwd) != statbuf.st_size)
   {
@@ -372,7 +366,7 @@ if (*filtertype != FILTER_FORWARD)
   int old_expand_forbid = expand_forbid;
 
   DEBUG(D_route) debug_printf("data is %s filter program\n",
   int old_expand_forbid = expand_forbid;
 
   DEBUG(D_route) debug_printf("data is %s filter program\n",
-    (*filtertype == FILTER_EXIM)? "an Exim" : "a Sieve");
+    *filtertype == FILTER_EXIM ? "an Exim" : "a Sieve");
 
   /* RDO_FILTER is an "allow" bit */
 
 
   /* RDO_FILTER is an "allow" bit */
 
@@ -383,8 +377,7 @@ if (*filtertype != FILTER_FORWARD)
     }
 
   expand_forbid =
     }
 
   expand_forbid =
-    (expand_forbid & ~RDO_FILTER_EXPANSIONS) |
-    (options & RDO_FILTER_EXPANSIONS);
+    expand_forbid & ~RDO_FILTER_EXPANSIONS  |  options & RDO_FILTER_EXPANSIONS;
 
   /* RDO_{EXIM,SIEVE}_FILTER are forbid bits */
 
 
   /* RDO_{EXIM,SIEVE}_FILTER are forbid bits */
 
@@ -479,7 +472,8 @@ if (len == 0)
 else
   /* We know we have enough memory so disable the error on "len" */
   /* coverity[tainted_data] */
 else
   /* We know we have enough memory so disable the error on "len" */
   /* coverity[tainted_data] */
-  if (read(fd, *sp = store_get(len), len) != len) return FALSE;
+  /* We trust the data source, so untainted */
+  if (read(fd, *sp = store_get(len, FALSE), len) != len) return FALSE;
 return TRUE;
 }
 
 return TRUE;
 }
 
@@ -492,7 +486,7 @@ return TRUE;
 /* This function is passed a forward list string (unexpanded) or the name of a
 file (unexpanded) whose contents are the forwarding list. The list may in fact
 be a filter program if it starts with "#Exim filter" or "#Sieve filter". Other
 /* This function is passed a forward list string (unexpanded) or the name of a
 file (unexpanded) whose contents are the forwarding list. The list may in fact
 be a filter program if it starts with "#Exim filter" or "#Sieve filter". Other
-types of filter, with different inital tag strings, may be introduced in due
+types of filter, with different initial tag strings, may be introduced in due
 course.
 
 The job of the function is to process the forwarding list or filter. It is
 course.
 
 The job of the function is to process the forwarding list or filter. It is
@@ -558,13 +552,12 @@ uschar *data;
 uschar *readerror = US"";
 void (*oldsignal)(int);
 
 uschar *readerror = US"";
 void (*oldsignal)(int);
 
-DEBUG(D_route) debug_printf("rda_interpret (%s): %s\n",
-  (rdata->isfile)? "file" : "string", rdata->string);
+DEBUG(D_route) debug_printf("rda_interpret (%s): '%s'\n",
+  rdata->isfile ? "file" : "string", string_printing(rdata->string));
 
 /* Do the expansions of the file name or data first, while still privileged. */
 
 
 /* Do the expansions of the file name or data first, while still privileged. */
 
-data = expand_string(rdata->string);
-if (data == NULL)
+if (!(data = expand_string(rdata->string)))
   {
   if (f.expand_string_forcedfail) return FF_NOTDELIVERED;
   *error = string_sprintf("failed to expand \"%s\": %s", rdata->string,
   {
   if (f.expand_string_forcedfail) return FF_NOTDELIVERED;
   *error = string_sprintf("failed to expand \"%s\": %s", rdata->string,
@@ -573,7 +566,7 @@ if (data == NULL)
   }
 rdata->string = data;
 
   }
 rdata->string = data;
 
-DEBUG(D_route) debug_printf("expanded: %s\n", data);
+DEBUG(D_route) debug_printf("expanded: '%s'\n", data);
 
 if (rdata->isfile && data[0] != '/')
   {
 
 if (rdata->isfile && data[0] != '/')
   {
@@ -656,10 +649,9 @@ if ((pid = fork()) == 0)
 
   /* Pass back the contents of any syntax error blocks if we have a pointer */
 
 
   /* Pass back the contents of any syntax error blocks if we have a pointer */
 
-  if (eblockp != NULL)
+  if (eblockp)
     {
     {
-    error_block *ep;
-    for (ep = *eblockp; ep != NULL; ep = ep->next)
+    for (error_block * ep = *eblockp; ep; ep = ep->next)
       if (  rda_write_string(fd, ep->text1) != 0
          || rda_write_string(fd, ep->text2) != 0
         )
       if (  rda_write_string(fd, ep->text1) != 0
          || rda_write_string(fd, ep->text2) != 0
         )
@@ -675,8 +667,7 @@ if ((pid = fork()) == 0)
   if (f.system_filtering)
     {
     int i = 0;
   if (f.system_filtering)
     {
     int i = 0;
-    header_line *h;
-    for (h = header_list; h != waslast->next; i++, h = h->next)
+    for (header_line * h = header_list; h != waslast->next; i++, h = h->next)
       if (  h->type == htype_old
          && write(fd, &i, sizeof(i)) != sizeof(i)
         )
       if (  h->type == htype_old
          && write(fd, &i, sizeof(i)) != sizeof(i)
         )
@@ -714,25 +705,23 @@ if ((pid = fork()) == 0)
   if (yield == FF_DELIVERED || yield == FF_NOTDELIVERED ||
       yield == FF_FAIL || yield == FF_FREEZE)
     {
   if (yield == FF_DELIVERED || yield == FF_NOTDELIVERED ||
       yield == FF_FAIL || yield == FF_FREEZE)
     {
-    address_item *addr;
-    for (addr = *generated; addr; addr = addr->next)
+    for (address_item * addr = *generated; addr; addr = addr->next)
       {
       int reply_options = 0;
       {
       int reply_options = 0;
+      int ig_err = addr->prop.ignore_error ? 1 : 0;
 
       if (  rda_write_string(fd, addr->address) != 0
          || write(fd, &addr->mode, sizeof(addr->mode)) != sizeof(addr->mode)
          || write(fd, &addr->flags, sizeof(addr->flags)) != sizeof(addr->flags)
          || rda_write_string(fd, addr->prop.errors_address) != 0
 
       if (  rda_write_string(fd, addr->address) != 0
          || write(fd, &addr->mode, sizeof(addr->mode)) != sizeof(addr->mode)
          || write(fd, &addr->flags, sizeof(addr->flags)) != sizeof(addr->flags)
          || rda_write_string(fd, addr->prop.errors_address) != 0
+         || write(fd, &ig_err, sizeof(ig_err)) != sizeof(ig_err)
         )
        goto bad;
 
       if (addr->pipe_expandn)
         )
        goto bad;
 
       if (addr->pipe_expandn)
-        {
-        uschar **pp;
-        for (pp = addr->pipe_expandn; *pp; pp++)
+        for (uschar ** pp = addr->pipe_expandn; *pp; pp++)
           if (rda_write_string(fd, *pp) != 0)
            goto bad;
           if (rda_write_string(fd, *pp) != 0)
            goto bad;
-        }
       if (rda_write_string(fd, NULL) != 0)
         goto bad;
 
       if (rda_write_string(fd, NULL) != 0)
         goto bad;
 
@@ -777,7 +766,7 @@ if ((pid = fork()) == 0)
 out:
   (void)close(fd);
   search_tidyup();
 out:
   (void)close(fd);
   search_tidyup();
-  _exit(0);
+  exim_underbar_exit(0);
 
 bad:
   DEBUG(D_rewrite) debug_printf("rda_interpret: failed write to pipe\n");
 
 bad:
   DEBUG(D_rewrite) debug_printf("rda_interpret: failed write to pipe\n");
@@ -807,13 +796,12 @@ if (read(fd, filtertype, sizeof(int)) != sizeof(int) ||
 if (eblockp)
   {
   error_block *e;
 if (eblockp)
   {
   error_block *e;
-  error_block **p;
-  for (p = eblockp; ; p = &e->next)
+  for (error_block ** p = eblockp; ; p = &e->next)
     {
     uschar *s;
     if (!rda_read_string(fd, &s)) goto DISASTER;
     if (!s) break;
     {
     uschar *s;
     if (!rda_read_string(fd, &s)) goto DISASTER;
     if (!s) break;
-    e = store_get(sizeof(error_block));
+    e = store_get(sizeof(error_block), FALSE);
     e->next = NULL;
     e->text1 = s;
     if (!rda_read_string(fd, &s)) goto DISASTER;
     e->next = NULL;
     e->text1 = s;
     if (!rda_read_string(fd, &s)) goto DISASTER;
@@ -877,7 +865,7 @@ if (yield == FF_DELIVERED || yield == FF_NOTDELIVERED ||
     /* First string is the address; NULL => end of addresses */
 
     if (!rda_read_string(fd, &recipient)) goto DISASTER;
     /* First string is the address; NULL => end of addresses */
 
     if (!rda_read_string(fd, &recipient)) goto DISASTER;
-    if (recipient == NULL) break;
+    if (!recipient) break;
 
     /* Hang on the end of the chain */
 
 
     /* Hang on the end of the chain */
 
@@ -887,9 +875,13 @@ if (yield == FF_DELIVERED || yield == FF_NOTDELIVERED ||
 
     /* Next comes the mode and the flags fields */
 
 
     /* Next comes the mode and the flags fields */
 
-    if (read(fd, &addr->mode, sizeof(addr->mode)) != sizeof(addr->mode) ||
-        read(fd, &addr->flags, sizeof(addr->flags)) != sizeof(addr->flags) ||
-        !rda_read_string(fd, &addr->prop.errors_address)) goto DISASTER;
+    if (  read(fd, &addr->mode, sizeof(addr->mode)) != sizeof(addr->mode)
+       || read(fd, &addr->flags, sizeof(addr->flags)) != sizeof(addr->flags)
+       || !rda_read_string(fd, &addr->prop.errors_address)
+       || read(fd, &i, sizeof(i)) != sizeof(i)
+       )
+      goto DISASTER;
+    addr->prop.ignore_error = (i != 0);
 
     /* Next comes a possible setting for $thisaddress and any numerical
     variables for pipe expansion, terminated by a NULL string. The maximum
 
     /* Next comes a possible setting for $thisaddress and any numerical
     variables for pipe expansion, terminated by a NULL string. The maximum
@@ -908,7 +900,7 @@ if (yield == FF_DELIVERED || yield == FF_NOTDELIVERED ||
 
     if (i > 0)
       {
 
     if (i > 0)
       {
-      addr->pipe_expandn = store_get((i+1) * sizeof(uschar *));
+      addr->pipe_expandn = store_get((i+1) * sizeof(uschar *), FALSE);
       addr->pipe_expandn[i] = NULL;
       while (--i >= 0) addr->pipe_expandn[i] = expandn[i];
       }
       addr->pipe_expandn[i] = NULL;
       while (--i >= 0) addr->pipe_expandn[i] = expandn[i];
       }
@@ -918,7 +910,7 @@ if (yield == FF_DELIVERED || yield == FF_NOTDELIVERED ||
     if (read(fd, &reply_options, sizeof(int)) != sizeof(int)) goto DISASTER;
     if ((reply_options & REPLY_EXISTS) != 0)
       {
     if (read(fd, &reply_options, sizeof(int)) != sizeof(int)) goto DISASTER;
     if ((reply_options & REPLY_EXISTS) != 0)
       {
-      addr->reply = store_get(sizeof(reply_item));
+      addr->reply = store_get(sizeof(reply_item), FALSE);
 
       addr->reply->file_expand = (reply_options & REPLY_EXPAND) != 0;
       addr->reply->return_message = (reply_options & REPLY_RETURN) != 0;
 
       addr->reply->file_expand = (reply_options & REPLY_EXPAND) != 0;
       addr->reply->return_message = (reply_options & REPLY_RETURN) != 0;