Check query strings of query-style lookups for quoting. Bug 2850
[exim.git] / src / src / transport.c
index 39b8c411abe688239360b08557af2f99870c3a00..96a936503e9d7522844efc5d75497e36d25ec787 100644 (file)
@@ -3,7 +3,7 @@
 *************************************************/
 
 /* Copyright (c) University of Cambridge 1995 - 2018 */
-/* Copyright (c) The Exim Maintainers 2020 */
+/* Copyright (c) The Exim Maintainers 2020 - 2021 */
 /* See the file NOTICE for conditions of use and distribution. */
 
 /* General functions concerned with transportation, and generic options for all
@@ -253,7 +253,6 @@ for (int i = 0; i < 100; i++)
 
   for(;;)
     {
-    fd_set fds;
     /* This code makes use of alarm() in order to implement the timeout. This
     isn't a very tidy way of doing things. Using non-blocking I/O with select()
     provides a neater approach. However, I don't know how to do this when TLS is
@@ -281,8 +280,7 @@ for (int i = 0; i < 100; i++)
     if (rc >= 0 || errno != ENOTCONN || connretry <= 0)
       break;
 
-    FD_ZERO(&fds); FD_SET(fd, &fds);
-    select(fd+1, NULL, &fds, NULL, NULL);      /* could set timout? */
+    poll_one_fd(fd, POLLOUT, -1);              /* could set timeout? retval check? */
     connretry--;
     }
 
@@ -653,7 +651,7 @@ so that we don't handle it again. */
 
 for (ppp = *pdlist; ppp; ppp = ppp->next) if (p == ppp->ptr) return TRUE;
 
-ppp = store_get(sizeof(struct aci), FALSE);
+ppp = store_get(sizeof(struct aci), GET_UNTAINTED);
 ppp->next = *pdlist;
 *pdlist = ppp;
 ppp->ptr = p;
@@ -677,7 +675,7 @@ if (ppp) return TRUE;
 
 /* Remember what we have output, and output it. */
 
-ppp = store_get(sizeof(struct aci), FALSE);
+ppp = store_get(sizeof(struct aci), GET_UNTAINTED);
 ppp->next = *pplist;
 *pplist = ppp;
 ppp->ptr = pp;
@@ -959,10 +957,10 @@ if (!(tctx->options & topt_no_headers))
 
   if (tctx->options & topt_add_return_path)
     {
-    uschar buffer[ADDRESS_MAXLENGTH + 20];
-    int n = sprintf(CS buffer, "Return-path: <%.*s>\n", ADDRESS_MAXLENGTH,
-      return_path);
-    if (!write_chunk(tctx, buffer, n)) goto bad;
+    int n;
+    uschar * s = string_sprintf("Return-path: <%.*s>\n%n",
+                          EXIM_EMAILADDR_MAX, return_path, &n);
+    if (!write_chunk(tctx, s, n)) goto bad;
     }
 
   /* Add envelope-to: if requested */
@@ -1398,7 +1396,7 @@ if (write_pid > 0)
         yield = FALSE;
        }
       else if (!ok)
-        {
+        {              /* Try to drain the pipe; read fails are don't care */
        int dummy = read(pfd[pipe_read], (void *)&save_errno, sizeof(int));
         dummy = read(pfd[pipe_read], (void *)&tctx->addr->more_errno, sizeof(int));
         dummy = read(pfd[pipe_read], (void *)&tctx->addr->delivery_time, sizeof(struct timeval));
@@ -1523,7 +1521,7 @@ for (host_item * host = hostlist; host; host = host->next)
 
   if (!(host_record = dbfn_read(dbm_file, host->name)))
     {
-    host_record = store_get(sizeof(dbdata_wait) + MESSAGE_ID_LENGTH, FALSE);
+    host_record = store_get(sizeof(dbdata_wait) + MESSAGE_ID_LENGTH, GET_UNTAINTED);
     host_record->count = host_record->sequence = 0;
     }
 
@@ -1587,7 +1585,7 @@ for (host_item * host = hostlist; host; host = host->next)
   else
     {
     dbdata_wait *newr =
-      store_get(sizeof(dbdata_wait) + host_length + MESSAGE_ID_LENGTH, FALSE);
+      store_get(sizeof(dbdata_wait) + host_length + MESSAGE_ID_LENGTH, GET_UNTAINTED);
     memcpy(newr, host_record, sizeof(dbdata_wait) + host_length);
     host_record = newr;
     }
@@ -1721,7 +1719,7 @@ while (1)
 
   /* create an array to read entire message queue into memory for processing  */
 
-  msgq = store_get(sizeof(msgq_t) * host_record->count, FALSE);
+  msgq = store_get(sizeof(msgq_t) * host_record->count, GET_UNTAINTED);
   msgq_count = host_record->count;
   msgq_actual = msgq_count;
 
@@ -1729,7 +1727,7 @@ while (1)
     {
     msgq[i].bKeep = TRUE;
 
-    Ustrncpy_nt(msgq[i].message_id, host_record->text + (i * MESSAGE_ID_LENGTH), 
+    Ustrncpy_nt(msgq[i].message_id, host_record->text + (i * MESSAGE_ID_LENGTH),
       MESSAGE_ID_LENGTH);
     msgq[i].message_id[MESSAGE_ID_LENGTH] = 0;
     }
@@ -1880,9 +1878,21 @@ void
 transport_do_pass_socket(const uschar *transport_name, const uschar *hostname,
   const uschar *hostaddress, uschar *id, int socket_fd)
 {
-int i = 27;
+int i = 13;
 const uschar **argv;
 
+#ifndef DISABLE_TLS
+if (smtp_peer_options & OPTION_TLS) i += 6;
+#endif
+#ifdef EXPERIMENTAL_ESMTP_LIMITS
+if (continue_limit_mail || continue_limit_rcpt || continue_limit_rcptdom)
+                                   i += 4;
+#endif
+if (queue_run_pid != (pid_t)0)     i += 3;
+#ifdef SUPPORT_SOCKS
+if (proxy_session)                 i += 5;
+#endif
+
 /* Set up the calling arguments; use the standard function for the basics,
 but we have a number of extras that may be added. */
 
@@ -1916,6 +1926,16 @@ if (smtp_peer_options & OPTION_TLS)
     argv[i++] = US"-MCT";
 #endif
 
+#ifdef EXPERIMENTAL_ESMTP_LIMITS
+if (continue_limit_rcpt || continue_limit_rcptdom)
+  {
+  argv[i++] = US"-MCL";
+  argv[i++] = string_sprintf("%u", continue_limit_mail);
+  argv[i++] = string_sprintf("%u", continue_limit_rcpt);
+  argv[i++] = string_sprintf("%u", continue_limit_rcptdom);
+  }
+#endif
+
 if (queue_run_pid != (pid_t)0)
   {
   argv[i++] = US"-MCQ";
@@ -1976,13 +1996,23 @@ Returns:          FALSE if fork fails; TRUE otherwise
 
 BOOL
 transport_pass_socket(const uschar *transport_name, const uschar *hostname,
-  const uschar *hostaddress, uschar *id, int socket_fd)
+  const uschar *hostaddress, uschar *id, int socket_fd
+#ifdef EXPERIMENTAL_ESMTP_LIMITS
+  , unsigned peer_limit_mail, unsigned peer_limit_rcpt, unsigned peer_limit_rcptdom
+#endif
+  )
 {
 pid_t pid;
 int status;
 
 DEBUG(D_transport) debug_printf("transport_pass_socket entered\n");
 
+#ifdef EXPERIMENTAL_ESMTP_LIMITS
+continue_limit_mail = peer_limit_mail;
+continue_limit_rcpt = peer_limit_rcpt;
+continue_limit_rcptdom = peer_limit_rcptdom;
+#endif
+
 if ((pid = exim_fork(US"continued-transport-interproc")) == 0)
   {
   /* Disconnect entirely from the parent process. If we are running in the
@@ -2061,7 +2091,7 @@ delivery batch option is set. */
 
 for (address_item * ad = addr; ad; ad = ad->next) address_count++;
 max_args = address_count + 60;
-*argvptr = argv = store_get((max_args+1)*sizeof(uschar *), FALSE);
+*argvptr = argv = store_get((max_args+1)*sizeof(uschar *), GET_UNTAINTED);
 
 /* Split the command up into arguments terminated by white space. Lose
 trailing space at the start and end. Double-quoted arguments can contain \\ and
@@ -2077,7 +2107,7 @@ for (; *s != 0 && argcount < max_args; argcount++)
     {
     ss = s + 1;
     while (*ss != 0 && *ss != '\'') ss++;
-    argv[argcount] = ss = store_get(ss - s++, is_tainted(cmd));
+    argv[argcount] = ss = store_get(ss - s++, cmd);
     while (*s != 0 && *s != '\'') *ss++ = *s++;
     if (*s != 0) s++;
     *ss++ = 0;
@@ -2177,7 +2207,6 @@ if (expand_arguments)
       int address_pipe_argcount = 0;
       int address_pipe_max_args;
       uschar **address_pipe_argv;
-      BOOL tainted;
 
       /* We can never have more then the argv we will be loading into */
       address_pipe_max_args = max_args - argcount + 1;
@@ -2186,13 +2215,12 @@ if (expand_arguments)
         debug_printf("address_pipe_max_args=%d\n", address_pipe_max_args);
 
       /* We allocate an additional for (uschar *)0 */
-      address_pipe_argv = store_get((address_pipe_max_args+1)*sizeof(uschar *), FALSE);
+      address_pipe_argv = store_get((address_pipe_max_args+1)*sizeof(uschar *), GET_UNTAINTED);
 
       /* +1 because addr->local_part[0] == '|' since af_force_command is set */
       s = expand_string(addr->local_part + 1);
-      tainted = is_tainted(s);
 
-      if (s == NULL || *s == '\0')
+      if (!s || *s == '\0')
         {
         addr->transport_return = FAIL;
         addr->message = string_sprintf("Expansion of \"%s\" "
@@ -2203,15 +2231,16 @@ if (expand_arguments)
 
       while (isspace(*s)) s++; /* strip leading space */
 
-      while (*s != 0 && address_pipe_argcount < address_pipe_max_args)
+      while (*s && address_pipe_argcount < address_pipe_max_args)
         {
         if (*s == '\'')
           {
-          ss = s + 1;
-          while (*ss != 0 && *ss != '\'') ss++;
-          address_pipe_argv[address_pipe_argcount++] = ss = store_get(ss - s++, tainted);
-          while (*s != 0 && *s != '\'') *ss++ = *s++;
-          if (*s != 0) s++;
+         int n;
+          for (ss = s + 1; *ss && *ss != '\''; ) ss++;
+         n = ss - s++;
+          address_pipe_argv[address_pipe_argcount++] = ss = store_get(n, s);
+          while (*s && *s != '\'') *ss++ = *s++;
+          if (*s) s++;
           *ss++ = 0;
           }
         else address_pipe_argv[address_pipe_argcount++] =
@@ -2247,12 +2276,12 @@ if (expand_arguments)
         }
 
       /* If we are not just able to replace the slot that contained
-       * $address_pipe (address_pipe_argcount == 1)
-       * We have to move the existing argv by address_pipe_argcount - 1
-       * Visually if address_pipe_argcount == 2:
-       * [argv 0][argv 1][argv 2($address_pipe)][argv 3][0]
-       * [argv 0][argv 1][ap_arg0][ap_arg1][old argv 3][0]
-       */
+      $address_pipe (address_pipe_argcount == 1)
+      We have to move the existing argv by address_pipe_argcount - 1
+      Visually if address_pipe_argcount == 2:
+      [argv 0][argv 1][argv 2($address_pipe)][argv 3][0]
+      [argv 0][argv 1][ap_arg0][ap_arg1][old argv 3][0] */
+
       if (address_pipe_argcount > 1)
         memmove(
           /* current position + additional args */
@@ -2264,15 +2293,12 @@ if (expand_arguments)
         );
 
       /* Now we fill in the slots we just moved argv out of
-       * [argv 0][argv 1][argv 2=pipeargv[0]][argv 3=pipeargv[1]][old argv 3][0]
-       */
+      [argv 0][argv 1][argv 2=pipeargv[0]][argv 3=pipeargv[1]][old argv 3][0] */
+
       for (int address_pipe_i = 0;
            address_pipe_argv[address_pipe_i] != US 0;
-           address_pipe_i++)
-        {
+           address_pipe_i++, argcount++)
         argv[i++] = address_pipe_argv[address_pipe_i];
-        argcount++;
-        }
 
       /* Subtract one since we replace $address_pipe */
       argcount--;
@@ -2316,6 +2342,19 @@ if (expand_arguments)
 return TRUE;
 }
 
+
+
+/* For error messages, a string describing the config location associated
+with current processing.  NULL if we are not in a transport. */
+/* Name only, for now */
+
+uschar *
+transport_current_name(void)
+{
+if (!transport_name) return NULL;
+return string_sprintf(" (transport %s, %s %d)", transport_name, driver_srcfile, driver_srcline);
+}
+
 #endif /*!MACRO_PREDEF*/
 /* vi: aw ai sw=2
 */