]> git.netwichtig.de Git - user/henk/code/exim.git/blobdiff - src/src/expand.c
Debug: indent builtin-DB operations
[user/henk/code/exim.git] / src / src / expand.c
index b9eeb7c46766352e5e09a7c5bf3d7e1407e5072d..1508dcfd8cfaef914e44ffaaf2cb5fb58ce903a8 100644 (file)
@@ -660,6 +660,9 @@ static var_entry var_table[] = {
   { "regex_match_string",  vtype_stringptr,   &regex_match_string },
 #endif
   { "reply_address",       vtype_reply,       NULL },
+#if defined(SUPPORT_TLS) && defined(EXPERIMENTAL_REQUIRETLS)
+  { "requiretls",          vtype_bool,        &tls_requiretls },
+#endif
   { "return_path",         vtype_stringptr,   &return_path },
   { "return_size_limit",   vtype_int,         &bounce_return_size_limit },
   { "router_name",         vtype_stringptr,   &router_name },
@@ -1680,7 +1683,7 @@ else if (host_lookup_deferred)
   g = string_catn(g, US";\n\tiprev=temperror", 19);
 else if (host_lookup_failed)
   g = string_catn(g, US";\n\tiprev=fail", 13);
-else 
+else
   return g;
 
 if (sender_host_address)
@@ -3550,6 +3553,26 @@ return yield;
 }
 
 
+#ifdef SUPPORT_TLS
+static gstring *
+cat_file_tls(void * tls_ctx, gstring * yield, uschar * eol)
+{
+int rc;
+uschar * s;
+uschar buffer[1024];
+
+while ((rc = tls_read(tls_ctx, buffer, sizeof(buffer))) > 0)
+  for (s = buffer; rc--; s++)
+    yield = eol && *s == '\n'
+      ? string_cat(yield, eol) : string_catn(yield, s, 1);
+
+/* We assume that all errors, and any returns of zero bytes,
+are actually EOF. */
+
+(void) string_from_gstring(yield);
+return yield;
+}
+#endif
 
 
 /*************************************************
@@ -4801,9 +4824,13 @@ while (*s != 0)
       int timeout = 5;
       int save_ptr = yield->ptr;
       FILE *f;
-      uschar *arg;
-      uschar *sub_arg[4];
+      uschar * arg;
+      uschar * sub_arg[4];
+      uschar * server_name = NULL;
+      host_item host;
       BOOL do_shutdown = TRUE;
+      BOOL do_tls = FALSE;     /* Only set under SUPPORT_TLS */
+      void * tls_ctx = NULL;   /* ditto                      */
       blob reqstr;
 
       if (expand_forbid & RDO_READSOCK)
@@ -4846,10 +4873,14 @@ while (*s != 0)
 
        while ((item = string_nextinlist(&list, &sep, NULL, 0)))
          if (Ustrncmp(item, US"shutdown=", 9) == 0)
-           if (Ustrcmp(item + 9, US"no") == 0)
-             do_shutdown = FALSE;
+           { if (Ustrcmp(item + 9, US"no") == 0) do_shutdown = FALSE; }
+#ifdef SUPPORT_TLS
+         else if (Ustrncmp(item, US"tls=", 4) == 0)
+           { if (Ustrcmp(item + 9, US"no") != 0) do_tls = TRUE; }
+#endif
         }
-      else sub_arg[3] = NULL;                     /* No eol if no timeout */
+      else
+       sub_arg[3] = NULL;                     /* No eol if no timeout */
 
       /* If skipping, we don't actually do anything. Otherwise, arrange to
       connect to either an IP or a Unix socket. */
@@ -4861,8 +4892,10 @@ while (*s != 0)
         if (Ustrncmp(sub_arg[0], "inet:", 5) == 0)
           {
           int port;
-          uschar * server_name = sub_arg[0] + 5;
-          uschar * port_name = Ustrrchr(server_name, ':');
+          uschar * port_name;
+
+          server_name = sub_arg[0] + 5;
+          port_name = Ustrrchr(server_name, ':');
 
           /* Sort out the port */
 
@@ -4898,11 +4931,13 @@ while (*s != 0)
             }
 
          fd = ip_connectedsocket(SOCK_STREAM, server_name, port, port,
-                 timeout, NULL, &expand_string_message, &reqstr);
+                 timeout, &host, &expand_string_message,
+                 do_tls ? NULL : &reqstr);
          callout_address = NULL;
          if (fd < 0)
-              goto SOCK_FAIL;
-         reqstr.len = 0;
+           goto SOCK_FAIL;
+         if (!do_tls)
+           reqstr.len = 0;
           }
 
         /* Handle a Unix domain socket */
@@ -4922,6 +4957,7 @@ while (*s != 0)
           sockun.sun_family = AF_UNIX;
           sprintf(sockun.sun_path, "%.*s", (int)(sizeof(sockun.sun_path)-1),
             sub_arg[0]);
+         server_name = sockun.sun_path;
 
           sigalrm_seen = FALSE;
           alarm(timeout);
@@ -4938,10 +4974,30 @@ while (*s != 0)
               "%s: %s", sub_arg[0], strerror(errno));
             goto SOCK_FAIL;
             }
+         host.name = server_name;
+         host.address = US"";
           }
 
         DEBUG(D_expand) debug_printf_indent("connected to socket %s\n", sub_arg[0]);
 
+#ifdef SUPPORT_TLS
+       if (do_tls)
+         {
+         tls_support tls_dummy = {.sni=NULL};
+         uschar * errstr;
+
+         if (!(tls_ctx = tls_client_start(fd, &host, NULL, NULL,
+# ifdef SUPPORT_DANE
+                               NULL,
+# endif
+                               &tls_dummy, &errstr)))
+           {
+           expand_string_message = string_sprintf("TLS connect failed: %s", errstr);
+           goto SOCK_FAIL;
+           }
+         }
+#endif
+
        /* Allow sequencing of test actions */
        if (running_in_test_harness) millisleep(100);
 
@@ -4951,7 +5007,11 @@ while (*s != 0)
           {
           DEBUG(D_expand) debug_printf_indent("writing \"%s\" to socket\n",
             reqstr.data);
-          if (write(fd, reqstr.data, reqstr.len) != reqstr.len)
+          if ( (
+#ifdef SUPPORT_TLS
+             tls_ctx ? tls_write(tls_ctx, reqstr.data, reqstr.len, FALSE) :
+#endif
+                       write(fd, reqstr.data, reqstr.len)) != reqstr.len)
             {
             expand_string_message = string_sprintf("request write to socket "
               "failed: %s", strerror(errno));
@@ -4964,7 +5024,7 @@ while (*s != 0)
         system doesn't have this function, make it conditional. */
 
 #ifdef SHUT_WR
-       if (do_shutdown) shutdown(fd, SHUT_WR);
+       if (!tls_ctx && do_shutdown) shutdown(fd, SHUT_WR);
 #endif
 
        if (running_in_test_harness) millisleep(100);
@@ -4972,12 +5032,26 @@ while (*s != 0)
         /* Now we need to read from the socket, under a timeout. The function
         that reads a file can be used. */
 
-        f = fdopen(fd, "rb");
+       if (!tls_ctx)
+         f = fdopen(fd, "rb");
         sigalrm_seen = FALSE;
         alarm(timeout);
-        yield = cat_file(f, yield, sub_arg[3]);
+        yield =
+#ifdef SUPPORT_TLS
+         tls_ctx ? cat_file_tls(tls_ctx, yield, sub_arg[3]) :
+#endif
+                   cat_file(f, yield, sub_arg[3]);
         alarm(0);
-        (void)fclose(f);
+
+#ifdef SUPPORT_TLS
+       if (tls_ctx)
+         {
+         tls_close(tls_ctx, TRUE);
+         close(fd);
+         }
+       else
+#endif
+         (void)fclose(f);
 
         /* After a timeout, we restore the pointer in the result, that is,
         make sure we add nothing from the socket. */
@@ -7069,12 +7143,13 @@ while (*s != 0)
         {
         int seq_len = 0, index = 0;
         int bytes_left = 0;
-       long codepoint = -1;
+        long codepoint = -1;
+        int complete;
         uschar seq_buff[4];                    /* accumulate utf-8 here */
 
         while (*sub != 0)
          {
-         int complete = 0;
+         complete = 0;
          uschar c = *sub++;
 
          if (bytes_left)
@@ -7139,6 +7214,13 @@ while (*s != 0)
                        /* ASCII character follows incomplete sequence */
              yield = string_catn(yield, &c, 1);
          }
+        /* If given a sequence truncated mid-character, we also want to report ?
+        * Eg, ${length_1:フィル} is one byte, not one character, so we expect
+        * ${utf8clean:${length_1:フィル}} to yield '?' */
+        if (bytes_left != 0)
+          {
+          yield = string_catn(yield, UTF8_REPLACEMENT_CHAR, 1);
+          }
         continue;
         }
 
@@ -7880,7 +7962,7 @@ expand_hide_passwords(uschar * s)
 {
 return (  (  Ustrstr(s, "failed to expand") != NULL
          || Ustrstr(s, "expansion of ")    != NULL
-         ) 
+         )
        && (  Ustrstr(s, "mysql")   != NULL
          || Ustrstr(s, "pgsql")   != NULL
          || Ustrstr(s, "redis")   != NULL
@@ -7890,7 +7972,7 @@ return (  (  Ustrstr(s, "failed to expand") != NULL
          || Ustrstr(s, "ldapi:")  != NULL
          || Ustrstr(s, "ldapdn:") != NULL
          || Ustrstr(s, "ldapm:")  != NULL
-       )  ) 
+       )  )
   ? US"Temporary internal error" : s;
 }