Unix socket creds sockopt for BSD-ish platforms
[exim.git] / src / src / expand.c
index cec6efd54ba2e879062c0bf0e7f369a8179657b4..427effedf4606b2b5dc28e1767425672501add6c 100644 (file)
@@ -213,6 +213,7 @@ static uschar *op_table_main[] = {
   US"base62d",
   US"base64",
   US"base64d",
+  US"bless",
   US"domain",
   US"escape",
   US"escape8bit",
@@ -260,6 +261,7 @@ enum {
   EOP_BASE62D,
   EOP_BASE64,
   EOP_BASE64D,
+  EOP_BLESS,
   EOP_DOMAIN,
   EOP_ESCAPE,
   EOP_ESCAPE8BIT,
@@ -464,6 +466,7 @@ typedef struct {
 
 static uschar * fn_recipients(void);
 typedef uschar * stringptr_fn_t(void);
+static uschar * fn_queue_size(void);
 
 /* This table must be kept in alphabetical order. */
 
@@ -667,6 +670,7 @@ static var_entry var_table[] = {
   { "qualify_domain",      vtype_stringptr,   &qualify_domain_sender },
   { "qualify_recipient",   vtype_stringptr,   &qualify_domain_recipient },
   { "queue_name",          vtype_stringptr,   &queue_name },
+  { "queue_size",          vtype_string_func, &fn_queue_size },
   { "rcpt_count",          vtype_int,         &rcpt_count },
   { "rcpt_defer_count",    vtype_int,         &rcpt_defer_count },
   { "rcpt_fail_count",     vtype_int,         &rcpt_fail_count },
@@ -1628,8 +1632,8 @@ for (header_line * h = header_list; h; h = h->next)
 
       /* Trim the header roughly if we're approaching limits */
       inc = t - s;
-      if ((g ? g->ptr : 0) + inc > header_insert_maxlen)
-       inc = header_insert_maxlen - (g ? g->ptr : 0);
+      if (gstring_length(g) + inc > header_insert_maxlen)
+       inc = header_insert_maxlen - gstring_length(g);
 
       /* For raw just copy the data; for a list, add the data as a colon-sep
       list-element; for comma-list add as an unchecked comma,newline sep
@@ -1641,17 +1645,12 @@ for (header_line * h = header_list; h; h = h->next)
       if (flags & FH_WANT_LIST)
         g = string_append_listele_n(g, ':', s, (unsigned)inc);
       else if (flags & FH_WANT_RAW)
-       {
        g = string_catn(g, s, (unsigned)inc);
-       (void) string_from_gstring(g);
-       }
       else if (inc > 0)
-       if (comma)
-         g = string_append2_listele_n(g, US",\n", s, (unsigned)inc);
-       else
-         g = string_append2_listele_n(g, US"\n", s, (unsigned)inc);
+       g = string_append2_listele_n(g, comma ? US",\n" : US"\n",
+         s, (unsigned)inc);
 
-      if (g && g->ptr >= header_insert_maxlen) break;
+      if (gstring_length(g) >= header_insert_maxlen) break;
       }
 
 if (!found) return NULL;       /* No header found */
@@ -1661,7 +1660,7 @@ if (!g) return US"";
 
 *newsize = g->size;
 if (flags & FH_WANT_RAW)
-  return g->s;
+  return string_from_gstring(g);
 
 /* Otherwise do RFC 2047 decoding, translating the charset if requested.
 The rfc2047_decode2() function can return an error with decoded data if the
@@ -1669,16 +1668,12 @@ charset translation fails. If decoding fails, it returns NULL. */
 
 else
   {
-  uschar *decoded, *error;
-
-  decoded = rfc2047_decode2(g->s, check_rfc2047_length, charset, '?', NULL,
-    newsize, &error);
+  uschar * error, * decoded = rfc2047_decode2(string_from_gstring(g),
+    check_rfc2047_length, charset, '?', NULL, newsize, &error);
   if (error)
-    {
     DEBUG(D_any) debug_printf("*** error in RFC 2047 decoding: %s\n"
       "    input was: %s\n", error, g->s);
-    }
-  return decoded ? decoded : g->s;
+  return decoded ? decoded : string_from_gstring(g);
   }
 }
 
@@ -1747,6 +1742,67 @@ return g ? g->s : NULL;
 }
 
 
+/*************************************************
+*               Return size of queue             *
+*************************************************/
+/* Ask the daemon for the queue size */
+
+static uschar *
+fn_queue_size(void)
+{
+struct sockaddr_un sun = {.sun_family = AF_UNIX};
+uschar buf[16];
+int fd;
+ssize_t len;
+const uschar * where;
+
+if ((fd = socket(AF_UNIX, SOCK_DGRAM, 0)) < 0)
+  {
+  DEBUG(D_expand) debug_printf(" socket: %s\n", strerror(errno));
+  return NULL;
+  }
+
+#define ABSTRACT_CLIENT
+#ifdef ABSTRACT_CLIENT
+sun.sun_path[0] = 0;   /* Abstract local socket addr - Linux-specific? */
+len = offsetof(struct sockaddr_un, sun_path) + 1
+  + snprintf(sun.sun_path+1, sizeof(sun.sun_path)-1, "exim_%d", getpid());
+#else
+len = offsetof(struct sockaddr_un, sun_path)
+  + snprintf(sun.sun_path, sizeof(sun.sun_path), "%s/p_%d",
+      spool_directory, getpid());
+#endif
+
+if (bind(fd, (const struct sockaddr *)&sun, len) < 0)
+  { where = US"bind"; goto bad; }
+
+#ifdef notdef
+debug_printf("local%s '%s'\n", *sun.sun_path ? "" : " abstract",
+  sun.sun_path+ (*sun.sun_path ? 0 : 1));
+#endif
+
+sun.sun_path[0] = 0;   /* Abstract local socket addr - Linux-specific? */
+len = offsetof(struct sockaddr_un, sun_path) + 1
+  + snprintf(sun.sun_path+1, sizeof(sun.sun_path)-1, "%s", NOTIFIER_SOCKET_NAME);
+
+if (connect(fd, (const struct sockaddr *)&sun, len) < 0)
+  { where = US"connect"; goto bad; }
+
+buf[0] = NOTIFY_QUEUE_SIZE_REQ;
+if (send(fd, buf, 1, 0) < 0) { where = US"send"; goto bad; }
+
+if ((len = recv(fd, buf, sizeof(buf), 0)) < 0) { where = US"recv"; goto bad; }
+
+close(fd);
+return string_copyn(buf, len);
+
+bad:
+  close(fd);
+  DEBUG(D_expand) debug_printf(" %s: %s\n", where, strerror(errno));
+  return NULL;
+}
+
+
 /*************************************************
 *               Find value of a variable         *
 *************************************************/
@@ -7059,6 +7115,20 @@ while (*s != 0)
         continue;
         }
 
+      case EOP_BLESS:
+       /* This is purely for the convenience of the test harness.  Do not enable
+       it otherwise as it defeats the taint-checking security. */
+
+       if (f.running_in_test_harness)
+         yield = string_cat(yield, is_tainted(sub)
+                                   ? string_copy_taint(sub, FALSE) : sub);
+       else
+         {
+         DEBUG(D_expand) debug_printf_indent("bless operator not supported\n");
+         yield = string_cat(yield, sub);
+         }
+       continue;
+
       case EOP_EXPAND:
         {
         uschar *expanded = expand_string_internal(sub, FALSE, NULL, skipping, TRUE, &resetok);
@@ -8534,7 +8604,7 @@ expand_file_big_buffer(const uschar * filename)
 {
 int fd, off = 0, len;
 
-if ((fd = open(CS filename, O_RDONLY)) < 0)
+if ((fd = exim_open2(CS filename, O_RDONLY)) < 0)
   {
   log_write(0, LOG_MAIN | LOG_PANIC, "unable to open file for reading: %s",
             filename);