Import Debian changes 4.92-8+deb10u3
[hcoop/debian/exim4.git] / src / transports / pipe.c
index 8b87e4a..b94c223 100644 (file)
@@ -2,7 +2,7 @@
 *     Exim - an Internet mail transport agent    *
 *************************************************/
 
-/* Copyright (c) University of Cambridge 1995 - 2015 */
+/* Copyright (c) University of Cambridge 1995 - 2018 */
 /* See the file NOTICE for conditions of use and distribution. */
 
 
@@ -95,6 +95,17 @@ address can appear in the tables drtables.c. */
 int pipe_transport_options_count =
   sizeof(pipe_transport_options)/sizeof(optionlist);
 
+
+#ifdef MACRO_PREDEF
+
+/* Dummy values */
+pipe_transport_options_block pipe_transport_option_defaults = {0};
+void pipe_transport_init(transport_instance *tblock) {}
+BOOL pipe_transport_entry(transport_instance *tblock, address_item *addr) {return FALSE;}
+
+#else   /*!MACRO_PREDEF*/
+
+
 /* Default private options block for the pipe transport. */
 
 pipe_transport_options_block pipe_transport_option_defaults = {
@@ -460,13 +471,18 @@ argv[1] = US"-c";
 /* We have to take special action to handle the special "variable" called
 $pipe_addresses, which is not recognized by the normal expansion function. */
 
-DEBUG(D_transport)
-  debug_printf("shell pipe command before expansion:\n  %s\n", cmd);
-
 if (expand_arguments)
   {
-  uschar *s = cmd;
-  uschar *p = Ustrstr(cmd, "pipe_addresses");
+  uschar * p = Ustrstr(cmd, "pipe_addresses");
+  gstring * g = NULL;
+
+  DEBUG(D_transport)
+    debug_printf("shell pipe command before expansion:\n  %s\n", cmd);
+
+  /* Allow $recipients in the expansion iff it comes from a system filter */
+
+  f.enable_dollar_recipients = addr && addr->parent &&
+    Ustrcmp(addr->parent->address, "system-filter") == 0;
 
   if (p != NULL && (
          (p > cmd && p[-1] == '$') ||
@@ -474,37 +490,30 @@ if (expand_arguments)
     {
     address_item *ad;
     uschar *q = p + 14;
-    int size = Ustrlen(cmd) + 64;
-    int offset;
 
     if (p[-1] == '{') { q++; p--; }
 
-    s = store_get(size);
-    offset = p - cmd - 1;
-    Ustrncpy(s, cmd, offset);
+    g = string_get(Ustrlen(cmd) + 64);
+    g = string_catn(g, cmd, p - cmd - 1);
 
-    for (ad = addr; ad != NULL; ad = ad->next)
+    for (ad = addr; ad; ad = ad->next)
       {
       /*XXX string_append_listele() ? */
-      if (ad != addr) s = string_catn(s, &size, &offset, US" ", 1);
-      s = string_cat(s, &size, &offset, ad->address);
+      if (ad != addr) g = string_catn(g, US" ", 1);
+      g = string_cat(g, ad->address);
       }
 
-    s = string_cat(s, &size, &offset, q);
-    s[offset] = 0;
+    g = string_cat(g, q);
+    argv[2] = (cmd = string_from_gstring(g)) ? expand_string(cmd) : NULL;
     }
+  else
+    argv[2] = expand_string(cmd);
 
-  /* Allow $recipients in the expansion iff it comes from a system filter */
-
-  enable_dollar_recipients = addr != NULL &&
-    addr->parent != NULL &&
-    Ustrcmp(addr->parent->address, "system-filter") == 0;
-  argv[2] = expand_string(s);
-  enable_dollar_recipients = FALSE;
+  f.enable_dollar_recipients = FALSE;
 
-  if (argv[2] == NULL)
+  if (!argv[2])
     {
-    addr->transport_return = search_find_defer? DEFER : expand_fail;
+    addr->transport_return = f.search_find_defer ? DEFER : expand_fail;
     addr->message = string_sprintf("Expansion of command \"%s\" "
       "in %s transport failed: %s",
       cmd, tname, expand_string_message);
@@ -514,9 +523,14 @@ if (expand_arguments)
   DEBUG(D_transport)
     debug_printf("shell pipe command after expansion:\n  %s\n", argv[2]);
   }
-else argv[2] = cmd;
+else
+  {
+  DEBUG(D_transport)
+    debug_printf("shell pipe command (no expansion):\n  %s\n", cmd);
+  argv[2] = cmd;
+  }
 
-argv[3] = (uschar *)0;
+argv[3] = US 0;
 return TRUE;
 }
 
@@ -552,11 +566,11 @@ const uschar *envlist = ob->environment;
 uschar *cmd, *ss;
 uschar *eol = ob->use_crlf ? US"\r\n" : US"\n";
 transport_ctx tctx = {
-  tblock,
-  addr,
-  ob->check_string,
-  ob->escape_string,
-  ob->options /* set at initialization time */
+  .tblock = tblock,
+  .addr = addr,
+  .check_string = ob->check_string,
+  .escape_string = ob->escape_string,
+  ob->options | topt_not_socket /* set at initialization time */
 };
 
 DEBUG(D_transport) debug_printf("%s transport entered\n", tblock->name);
@@ -665,7 +679,7 @@ envp[envcount++] = US"SHELL=/bin/sh";
 if (addr->host_list != NULL)
   envp[envcount++] = string_sprintf("HOST=%s", addr->host_list->name);
 
-if (timestamps_utc) envp[envcount++] = US"TZ=UTC";
+if (f.timestamps_utc) envp[envcount++] = US"TZ=UTC";
 else if (timezone_string != NULL && timezone_string[0] != 0)
   envp[envcount++] = string_sprintf("TZ=%s", timezone_string);
 
@@ -684,10 +698,9 @@ if (envlist)
     }
   }
 
-while ((ss = string_nextinlist(&envlist, &envsep, big_buffer, big_buffer_size))
-       != NULL)
+while ((ss = string_nextinlist(&envlist, &envsep, big_buffer, big_buffer_size)))
    {
-   if (envcount > sizeof(envp)/sizeof(uschar *) - 2)
+   if (envcount > nelem(envp) - 2)
      {
      addr->transport_return = DEFER;
      addr->message = string_sprintf("too many environment settings for "
@@ -701,7 +714,7 @@ envp[envcount] = NULL;
 
 /* If the -N option is set, can't do any more. */
 
-if (dont_deliver)
+if (f.dont_deliver)
   {
   DEBUG(D_transport)
     debug_printf("*** delivery by %s transport bypassed by -N option",
@@ -739,6 +752,7 @@ if ((pid = child_open(USS argv, envp, ob->umask, &fd_in, &fd_out, TRUE)) < 0)
       strerror(errno));
   return FALSE;
   }
+tctx.u.fd = fd_in;
 
 /* Now fork a process to handle the output that comes down the pipe. */
 
@@ -800,7 +814,7 @@ bit here to let the sub-process get going, but it may still not complete. So we
 ignore all writing errors. (When in the test harness, we do do a short sleep so
 any debugging output is likely to be in the same order.) */
 
-if (running_in_test_harness) millisleep(500);
+if (f.running_in_test_harness) millisleep(500);
 
 DEBUG(D_transport) debug_printf("Writing message to pipe\n");
 
@@ -823,13 +837,13 @@ if (ob->message_prefix != NULL)
   uschar *prefix = expand_string(ob->message_prefix);
   if (prefix == NULL)
     {
-    addr->transport_return = search_find_defer? DEFER : PANIC;
+    addr->transport_return = f.search_find_defer? DEFER : PANIC;
     addr->message = string_sprintf("Expansion of \"%s\" (prefix for %s "
       "transport) failed: %s", ob->message_prefix, tblock->name,
       expand_string_message);
     return FALSE;
     }
-  if (!transport_write_block(fd_in, prefix, Ustrlen(prefix)))
+  if (!transport_write_block(&tctx, prefix, Ustrlen(prefix), FALSE))
     goto END_WRITE;
   }
 
@@ -857,7 +871,7 @@ if (ob->use_bsmtp)
 
 /* Now the actual message */
 
-if (!transport_write_message(fd_in, &tctx, 0))
+if (!transport_write_message(&tctx, 0))
     goto END_WRITE;
 
 /* Now any configured suffix */
@@ -867,13 +881,13 @@ if (ob->message_suffix)
   uschar *suffix = expand_string(ob->message_suffix);
   if (!suffix)
     {
-    addr->transport_return = search_find_defer? DEFER : PANIC;
+    addr->transport_return = f.search_find_defer? DEFER : PANIC;
     addr->message = string_sprintf("Expansion of \"%s\" (suffix for %s "
       "transport) failed: %s", ob->message_suffix, tblock->name,
       expand_string_message);
     return FALSE;
     }
-  if (!transport_write_block(fd_in, suffix, Ustrlen(suffix)))
+  if (!transport_write_block(&tctx, suffix, Ustrlen(suffix), FALSE))
     goto END_WRITE;
   }
 
@@ -906,7 +920,7 @@ if (!written_ok)
   if (errno == ETIMEDOUT)
     {
     addr->message = string_sprintf("%stimeout while writing to pipe",
-      transport_filter_timed_out? "transport filter " : "");
+      f.transport_filter_timed_out ? "transport filter " : "");
     addr->transport_return = ob->timeout_defer? DEFER : FAIL;
     timeout = 1;
     }
@@ -972,7 +986,7 @@ if ((rc = child_close(pid, timeout)) != 0)
   This prevents the transport_filter timeout message from getting overwritten
   by the exit error which is not the cause of the problem. */
 
-  else if (transport_filter_timed_out)
+  else if (f.transport_filter_timed_out)
     {
     killpg(pid, SIGKILL);
     kill(outpid, SIGKILL);
@@ -1060,7 +1074,8 @@ if ((rc = child_close(pid, timeout)) != 0)
     else if (!ob->ignore_status)
       {
       uschar *ss;
-      int size, ptr, i;
+      gstring * g;
+      int i;
 
       /* If temp_errors is "*" all codes are temporary. Initialization checks
       that it's either "*" or a list of numbers. If not "*", scan the list of
@@ -1085,9 +1100,7 @@ if ((rc = child_close(pid, timeout)) != 0)
 
       addr->message = string_sprintf("Child process of %s transport returned "
         "%d", tblock->name, rc);
-
-      ptr = Ustrlen(addr->message);
-      size = ptr + 1;
+      g = string_cat(NULL, addr->message);
 
       /* If the return code is > 128, it often means that a shell command
       was terminated by a signal. */
@@ -1099,35 +1112,34 @@ if ((rc = child_close(pid, timeout)) != 0)
 
       if (*ss != 0)
         {
-        addr->message = string_catn(addr->message, &size, &ptr, US" ", 1);
-        addr->message = string_cat (addr->message, &size, &ptr, ss);
+        g = string_catn(g, US" ", 1);
+        g = string_cat (g, ss);
         }
 
       /* Now add the command and arguments */
 
-      addr->message = string_catn(addr->message, &size, &ptr,
-        US" from command:", 14);
+      g = string_catn(g, US" from command:", 14);
 
       for (i = 0; i < sizeof(argv)/sizeof(int *) && argv[i] != NULL; i++)
         {
         BOOL quote = FALSE;
-        addr->message = string_catn(addr->message, &size, &ptr, US" ", 1);
+        g = string_catn(g, US" ", 1);
         if (Ustrpbrk(argv[i], " \t") != NULL)
           {
           quote = TRUE;
-          addr->message = string_catn(addr->message, &size, &ptr, US"\"", 1);
+          g = string_catn(g, US"\"", 1);
           }
-        addr->message = string_cat(addr->message, &size, &ptr, argv[i]);
+        g = string_cat(g, argv[i]);
         if (quote)
-          addr->message = string_catn(addr->message, &size, &ptr, US"\"", 1);
+          g = string_catn(g, US"\"", 1);
         }
 
       /* Add previous filter timeout message, if present. */
 
       if (*tmsg)
-        addr->message = string_cat(addr->message, &size, &ptr, tmsg);
+        g = string_cat(g, tmsg);
 
-      addr->message[ptr] = 0;  /* Ensure concatenated string terminated */
+      addr->message = string_from_gstring(g);
       }
     }
   }
@@ -1150,4 +1162,5 @@ if (addr->transport_return != OK)
 return FALSE;
 }
 
+#endif /*!MACRO_PREDEF*/
 /* End of transport/pipe.c */