Check query strings of query-style lookups for quoting. Bug 2850
authorJeremy Harris <jgh146exb@wizmail.org>
Thu, 3 Mar 2022 22:23:42 +0000 (22:23 +0000)
committerJeremy Harris <jgh146exb@wizmail.org>
Thu, 3 Mar 2022 22:23:42 +0000 (22:23 +0000)
110 files changed:
doc/doc-docbook/spec.xfpt
doc/doc-txt/NewStuff
src/OS/unsupported/os.c-IRIX
src/OS/unsupported/os.c-IRIX6
src/OS/unsupported/os.c-IRIX632
src/OS/unsupported/os.c-IRIX65
src/exim_monitor/em_main.c
src/exim_monitor/em_queue.c
src/src/acl.c
src/src/arc.c
src/src/auths/pwcheck.c
src/src/auths/xtextdecode.c
src/src/auths/xtextencode.c
src/src/base64.c
src/src/bmi_spam.c
src/src/child.c
src/src/daemon.c
src/src/dbfn.c
src/src/deliver.c
src/src/dkim.c
src/src/dmarc.c
src/src/dns.c
src/src/dnsbl.c
src/src/drtables.c
src/src/exim.c
src/src/exim_dbmbuild.c
src/src/exim_dbutil.c
src/src/expand.c
src/src/filter.c
src/src/filtertest.c
src/src/functions.h
src/src/globals.c
src/src/globals.h
src/src/hash.c
src/src/header.c
src/src/host.c
src/src/local_scan.h
src/src/log.c
src/src/lookupapi.h
src/src/lookups/cdb.c
src/src/lookups/dbmdb.c
src/src/lookups/ibase.c
src/src/lookups/json.c
src/src/lookups/ldap.c
src/src/lookups/lmdb.c
src/src/lookups/mysql.c
src/src/lookups/nisplus.c
src/src/lookups/oracle.c
src/src/lookups/pgsql.c
src/src/lookups/readsock.c
src/src/lookups/redis.c
src/src/lookups/sqlite.c
src/src/malware.c
src/src/match.c
src/src/mime.c
src/src/moan.c
src/src/os.c
src/src/parse.c
src/src/pdkim/pdkim.c
src/src/pdkim/signing.c
src/src/queue.c
src/src/rda.c
src/src/readconf.c
src/src/receive.c
src/src/regex.c
src/src/retry.c
src/src/rewrite.c
src/src/rfc2047.c
src/src/route.c
src/src/routers/dnslookup.c
src/src/routers/ipliteral.c
src/src/routers/iplookup.c
src/src/routers/manualroute.c
src/src/routers/redirect.c
src/src/routers/rf_change_domain.c
src/src/routers/rf_get_munge_headers.c
src/src/search.c
src/src/sieve.c
src/src/smtp_in.c
src/src/spam.c
src/src/spool_in.c
src/src/spool_out.c
src/src/store.c
src/src/store.h
src/src/string.c
src/src/structs.h
src/src/tls-gnu.c
src/src/tls-openssl.c
src/src/tls.c
src/src/tlscert-gnu.c
src/src/tlscert-openssl.c
src/src/transport.c
src/src/transports/appendfile.c
src/src/transports/autoreply.c
src/src/transports/pipe.c
src/src/transports/smtp.c
src/src/tree.c
src/src/utf8.c
src/src/verify.c
test/confs/2610
test/confs/2620
test/log/2610
test/paniclog/2610 [new file with mode: 0644]
test/runtest
test/scripts/2610-MySQL/2610
test/stderr/2200
test/stderr/2201
test/stderr/2202
test/stderr/2610
test/stderr/2620

index 1bc63bff30c98034cbd26bee964489987d7ad152..bfadeb10a97c26a1f64cd807ec52024a1d877b12 100644 (file)
@@ -6839,6 +6839,12 @@ version of the lookup key.
 The &'query-style'& type accepts a generalized database query. No particular
 key value is assumed by Exim for query-style lookups. You can use whichever
 Exim variables you need to construct the database query.
+.cindex "tainted data" "quoting for lookups"
+.new
+If tainted data is used in the query then it should be quuted by
+using the &*${quote_*&<&'lookup-type'&>&*:*&<&'string'&>&*}*& expansion operator
+appropriate for the lookup.
+.wen
 .endlist
 
 The code for each lookup type is in a separate source file that is included in
@@ -40994,8 +41000,18 @@ was received, in the conventional Unix form &-- the number of seconds since the
 start of the epoch. The second number is a count of the number of messages
 warning of delayed delivery that have been sent to the sender.
 
-There follow a number of lines starting with a hyphen. These can appear in any
-order, and are omitted when not relevant:
+.new
+There follow a number of lines starting with a hyphen.
+These contain variables, can appear in any
+order, and are omitted when not relevant.
+
+If there is a second hyphen after the first,
+the corresponding data is tainted.
+If there is a value in parentheses, the data is quoted for a lookup.
+
+The following word specifies a variable,
+and the remainder of the item depends on the variable.
+.wen
 
 .vlist
 .vitem "&%-acl%&&~<&'number'&>&~<&'length'&>"
@@ -41151,9 +41167,6 @@ was received from the client, this records the Distinguished Name from that
 certificate.
 .endlist
 
-Any of the above may have an extra hyphen prepended, to indicate the the
-corresponding data is untrusted.
-
 Following the options there is a list of those addresses to which the message
 is not to be delivered. This set of addresses is initialized from the command
 line when the &%-t%& option is used and &%extract_addresses_remove_arguments%&
index 394eb144d224b5c6c0b63d5e7a770c2a41695cdd..730508adc944d618d08c338920a96b14d3023cf9 100644 (file)
@@ -19,6 +19,9 @@ Version 4.96
 
  5. The ACL "debug" control gains options "stop", "pretrigger" and "trigger".
 
+ 6. Query-style lookups are now checked for quoting, if the query string is
+    built using untrusted data ("tainted").  For now lack of quoting is merely
+    logged; a future release will upgrade this to an error.
 
 Version 4.95
 ------------
index c1539cb507846273acf5c7096b92c87f735a5738..d7a8b4f7a644576576522e6e0bcb475129e610e6 100644 (file)
@@ -59,7 +59,7 @@ if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0)
   log_write(0, LOG_PANIC_DIE, "iflist-sysctl-estimate failed: %s",
     strerror(errno));
 
-buf = store_get(needed, FALSE);
+buf = store_get(needed, GET_UNTAINTED);
 
 if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0)
   log_write(0, LOG_PANIC_DIE, "sysctl of ifnet list failed: %s",
index c1539cb507846273acf5c7096b92c87f735a5738..d7a8b4f7a644576576522e6e0bcb475129e610e6 100644 (file)
@@ -59,7 +59,7 @@ if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0)
   log_write(0, LOG_PANIC_DIE, "iflist-sysctl-estimate failed: %s",
     strerror(errno));
 
-buf = store_get(needed, FALSE);
+buf = store_get(needed, GET_UNTAINTED);
 
 if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0)
   log_write(0, LOG_PANIC_DIE, "sysctl of ifnet list failed: %s",
index c1539cb507846273acf5c7096b92c87f735a5738..d7a8b4f7a644576576522e6e0bcb475129e610e6 100644 (file)
@@ -59,7 +59,7 @@ if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0)
   log_write(0, LOG_PANIC_DIE, "iflist-sysctl-estimate failed: %s",
     strerror(errno));
 
-buf = store_get(needed, FALSE);
+buf = store_get(needed, GET_UNTAINTED);
 
 if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0)
   log_write(0, LOG_PANIC_DIE, "sysctl of ifnet list failed: %s",
index c1539cb507846273acf5c7096b92c87f735a5738..d7a8b4f7a644576576522e6e0bcb475129e610e6 100644 (file)
@@ -59,7 +59,7 @@ if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0)
   log_write(0, LOG_PANIC_DIE, "iflist-sysctl-estimate failed: %s",
     strerror(errno));
 
-buf = store_get(needed, FALSE);
+buf = store_get(needed, GET_UNTAINTED);
 
 if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0)
   log_write(0, LOG_PANIC_DIE, "sysctl of ifnet list failed: %s",
index 38c72307a9b443d1c70943a73b7b5e2fafbc1cfa..af1323064b963a9cd05eacb434f63c00aa14959c 100644 (file)
@@ -594,7 +594,7 @@ constructing file names and things. This call will initialize
 the store_get() function. */
 
 store_init();
-big_buffer = store_get(big_buffer_size, FALSE);
+big_buffer = store_get(big_buffer_size, GET_UNTAINTED);
 
 /* Set up the version string and date and output them */
 
index 2146fcb8ce420c66b87fd1e064e3bedeca8dd46c..276f3379b6a8d71c2801d04f4f85c23fe67fb51c 100644 (file)
@@ -138,8 +138,8 @@ tree_node *
 acl_var_create(uschar *name)
 {
 tree_node *node, **root;
-root = (name[0] == 'c')? &acl_var_c : &acl_var_m;
-node = store_get(sizeof(tree_node) + Ustrlen(name), FALSE);
+root = name[0] == 'c' ? &acl_var_c : &acl_var_m;
+node = store_get(sizeof(tree_node) + Ustrlen(name), GET_UNTAINTED);
 Ustrcpy(node->name, name);
 node->data.ptr = NULL;
 (void)tree_insertnode(root, node);
index 46615ce24c8671eac6896286b95833bc6a2984fe..aa8699a8a41965d8a27d2d72b73aba31d249a110 100644 (file)
@@ -642,6 +642,8 @@ static uschar *ratelimit_option_string[] = {
 static int acl_check_wargs(int, address_item *, const uschar *, uschar **,
     uschar **);
 
+static acl_block * acl_current = NULL;
+
 
 /*************************************************
 *            Find control in list                *
@@ -806,7 +808,7 @@ while ((s = (*func)()))
       *error = string_sprintf("malformed ACL line \"%s\"", saveline);
       return NULL;
       }
-    this = store_get(sizeof(acl_block), FALSE);
+    this = store_get(sizeof(acl_block), GET_UNTAINTED);
     *lastp = this;
     lastp = &(this->next);
     this->next = NULL;
@@ -853,7 +855,7 @@ while ((s = (*func)()))
     return NULL;
     }
 
-  cond = store_get(sizeof(acl_condition_block), FALSE);
+  cond = store_get(sizeof(acl_condition_block), GET_UNTAINTED);
   cond->next = NULL;
   cond->type = c;
   cond->u.negated = negated;
@@ -1052,7 +1054,7 @@ for (p = q; *p; p = q)
     {
     /* The header_line struct itself is not tainted, though it points to
     possibly tainted data. */
-    header_line * h = store_get(sizeof(header_line), FALSE);
+    header_line * h = store_get(sizeof(header_line), GET_UNTAINTED);
     h->text = hdr;
     h->next = NULL;
     h->type = newtype;
@@ -1341,7 +1343,7 @@ dns_scan dnss;
 dns_record *rr;
 int rc, type, yield;
 #define TARGET_SIZE 256
-uschar * target = store_get(TARGET_SIZE, TRUE);
+uschar * target = store_get(TARGET_SIZE, GET_TAINTED);
 
 /* Work out the domain we are using for the CSA lookup. The default is the
 client's HELO domain. If the client has not said HELO, use its IP address
@@ -1383,7 +1385,7 @@ we return from this function. */
 if ((t = tree_search(csa_cache, domain)))
   return t->data.val;
 
-t = store_get_perm(sizeof(tree_node) + Ustrlen(domain), is_tainted(domain));
+t = store_get_perm(sizeof(tree_node) + Ustrlen(domain), domain);
 Ustrcpy(t->name, domain);
 (void)tree_insertnode(&csa_cache, t);
 
@@ -2585,7 +2587,7 @@ if (!dbdb)
     /* No Bloom filter. This basic ratelimit block is initialized below. */
     HDEBUG(D_acl) debug_printf_indent("ratelimit creating new rate data block\n");
     dbdb_size = sizeof(*dbd);
-    dbdb = store_get(dbdb_size, FALSE);                /* not tainted */
+    dbdb = store_get(dbdb_size, GET_UNTAINTED);
     }
   else
     {
@@ -2599,7 +2601,7 @@ if (!dbdb)
     extra = (int)limit * 2 - sizeof(dbdb->bloom);
     if (extra < 0) extra = 0;
     dbdb_size = sizeof(*dbdb) + extra;
-    dbdb = store_get(dbdb_size, FALSE);                /* not tainted */
+    dbdb = store_get(dbdb_size, GET_UNTAINTED);
     dbdb->bloom_epoch = tv.tv_sec;
     dbdb->bloom_size = sizeof(dbdb->bloom) + extra;
     memset(dbdb->bloom, 0, dbdb->bloom_size);
@@ -2819,7 +2821,7 @@ dbfn_close(dbm);
 /* Store the result in the tree for future reference.  Take the taint status
 from the key for consistency even though it's unlikely we'll ever expand this. */
 
-t = store_get(sizeof(tree_node) + Ustrlen(key), is_tainted(key));
+t = store_get(sizeof(tree_node) + Ustrlen(key), key);
 t->data.ptr = dbd;
 Ustrcpy(t->name, key);
 (void)tree_insertnode(anchor, t);
@@ -3029,7 +3031,7 @@ if (*portend != '\0')
   }
 
 /* Make a single-item host list. */
-h = store_get(sizeof(host_item), FALSE);
+h = store_get(sizeof(host_item), GET_UNTAINTED);
 memset(h, 0, sizeof(host_item));
 h->name = hostname;
 h->port = portnum;
@@ -4201,6 +4203,18 @@ for(;;)
 
 
 
+/************************************************/
+/* For error messages, a string describing the config location
+associated with current processing. NULL if not in an ACL. */
+
+uschar *
+acl_current_verb(void)
+{
+if (acl_current) return string_sprintf(" (ACL %s, %s %d)",
+    verbs[acl_current->verb], acl_current->srcfile, acl_current->srcline);
+return NULL;
+}
+
 /*************************************************
 *        Check access using an ACL               *
 *************************************************/
@@ -4321,7 +4335,7 @@ if (Ustrchr(ss, ' ') == NULL)
       }
 
     /* If the string being used as a filename is tainted, so is the file content */
-    acl_text = store_get(statbuf.st_size + 1, is_tainted(ss));
+    acl_text = store_get(statbuf.st_size + 1, ss);
     acl_text_end = acl_text + statbuf.st_size + 1;
 
     if (read(fd, acl_text, statbuf.st_size) != statbuf.st_size)
@@ -4351,7 +4365,7 @@ if (!acl)
   if (!acl && *log_msgptr) return ERROR;
   if (fd >= 0)
     {
-    tree_node *t = store_get_perm(sizeof(tree_node) + Ustrlen(ss), is_tainted(ss));
+    tree_node * t = store_get_perm(sizeof(tree_node) + Ustrlen(ss), ss);
     Ustrcpy(t->name, ss);
     t->data.ptr = acl;
     (void)tree_insertnode(&acl_anchor, t);
@@ -4360,7 +4374,7 @@ if (!acl)
 
 /* Now we have an ACL to use. It's possible it may be NULL. */
 
-while (acl)
+while ((acl_current = acl))
   {
   int cond;
   int basic_errno = 0;
@@ -4507,8 +4521,8 @@ while (acl)
       else if (cond == DEFER && LOGGING(acl_warn_skipped))
        log_write(0, LOG_MAIN, "%s Warning: ACL \"warn\" statement skipped: "
          "condition test deferred%s%s", host_and_ident(TRUE),
-         (*log_msgptr == NULL)? US"" : US": ",
-         (*log_msgptr == NULL)? US"" : *log_msgptr);
+         *log_msgptr ? US": " : US"",
+         *log_msgptr ? *log_msgptr : US"");
       *log_msgptr = *user_msgptr = NULL;  /* In case implicit DENY follows */
       break;
 
@@ -4833,7 +4847,7 @@ acl_var_create(uschar * name)
 tree_node * node, ** root = name[0] == 'c' ? &acl_var_c : &acl_var_m;
 if (!(node = tree_search(*root, name)))
   {
-  node = store_get(sizeof(tree_node) + Ustrlen(name), is_tainted(name));
+  node = store_get(sizeof(tree_node) + Ustrlen(name), name);
   Ustrcpy(node->name, name);
   (void)tree_insertnode(root, node);
   }
@@ -4864,11 +4878,17 @@ Returns:  nothing
 */
 
 void
-acl_var_write(uschar *name, uschar *value, void *ctx)
+acl_var_write(uschar * name, uschar * value, void * ctx)
 {
-FILE *f = (FILE *)ctx;
-if (is_tainted(value)) putc('-', f);
-fprintf(f, "-acl%c %s %d\n%s\n", name[0], name+1, Ustrlen(value), value);
+FILE * f = (FILE *)ctx;
+putc('-', f);
+if (is_tainted(value))
+  {
+  int q = quoter_for_address(value);
+  putc('-', f);
+  if (is_real_quoter(q)) fprintf(f, "(%s)", lookup_list[q]->name);
+  }
+fprintf(f, "acl%c %s %d\n%s\n", name[0], name+1, Ustrlen(value), value);
 }
 
 #endif /* !MACRO_PREDEF */
index e0ee19950cf451ee2882654843c3adb14965a8dc..a9523890dca0775be911cc5c62a80f96d583f1c7 100644 (file)
@@ -142,7 +142,7 @@ for (pas = &ctx->arcset_chain, prev = NULL, next = ctx->arcset_chain;
   }
 
 DEBUG(D_acl) debug_printf("ARC: new instance %u\n", i);
-*pas = as = store_get(sizeof(arc_set), FALSE);
+*pas = as = store_get(sizeof(arc_set), GET_UNTAINTED);
 memset(as, 0, sizeof(arc_set));
 as->next = next;
 as->prev = prev;
@@ -200,7 +200,7 @@ al->complete = h;
 
 if (!instance_only)
   {
-  al->rawsig_no_b_val.data = store_get(h->slen + 1, TRUE);     /* tainted */
+  al->rawsig_no_b_val.data = store_get(h->slen + 1, GET_TAINTED);
   memcpy(al->rawsig_no_b_val.data, h->text, off);      /* copy the header name blind */
   r = al->rawsig_no_b_val.data + off;
   al->rawsig_no_b_val.len = off;
@@ -386,7 +386,7 @@ arc_insert_hdr(arc_ctx * ctx, header_line * h, unsigned off, unsigned hoff,
 {
 unsigned i;
 arc_set * as;
-arc_line * al = store_get(sizeof(arc_line), FALSE), ** alp;
+arc_line * al = store_get(sizeof(arc_line), GET_UNTAINTED), ** alp;
 uschar * e;
 
 memset(al, 0, sizeof(arc_line));
@@ -497,7 +497,7 @@ const uschar * e;
 DEBUG(D_acl) debug_printf("ARC: collecting arc sets\n");
 for (h = header_list; h; h = h->next)
   {
-  r = store_get(sizeof(hdr_rlist), FALSE);
+  r = store_get(sizeof(hdr_rlist), GET_UNTAINTED);
   r->prev = rprev;
   r->used = FALSE;
   r->h = h;
@@ -1103,7 +1103,7 @@ out:
 static hdr_rlist *
 arc_rlist_entry(hdr_rlist * list, const uschar * s, int len)
 {
-hdr_rlist * r = store_get(sizeof(hdr_rlist) + sizeof(header_line), FALSE);
+hdr_rlist * r = store_get(sizeof(hdr_rlist) + sizeof(header_line), GET_UNTAINTED);
 header_line * h = r->h = (header_line *)(r+1);
 
 r->prev = list;
@@ -1195,7 +1195,7 @@ arc_sign_append_aar(gstring * g, arc_ctx * ctx,
 {
 int aar_off = gstring_length(g);
 arc_set * as =
-  store_get(sizeof(arc_set) + sizeof(arc_line) + sizeof(header_line), FALSE);
+  store_get(sizeof(arc_set) + sizeof(arc_line) + sizeof(header_line), GET_UNTAINTED);
 arc_line * al = (arc_line *)(as+1);
 header_line * h = (header_line *)(al+1);
 
@@ -1305,7 +1305,7 @@ int col;
 int hashtype = pdkim_hashname_to_hashtype(US"sha256", 6);      /*XXX hardwired */
 blob sig;
 int ams_off;
-arc_line * al = store_get(sizeof(header_line) + sizeof(arc_line), FALSE);
+arc_line * al = store_get(sizeof(header_line) + sizeof(arc_line), GET_UNTAINTED);
 header_line * h = (header_line *)(al+1);
 
 /* debug_printf("%s\n", __FUNCTION__); */
@@ -1420,7 +1420,7 @@ arc_sign_prepend_as(gstring * arcset_interim, arc_ctx * ctx,
 {
 gstring * arcset;
 uschar * status = arc_ar_cv_status(ar);
-arc_line * al = store_get(sizeof(header_line) + sizeof(arc_line), FALSE);
+arc_line * al = store_get(sizeof(header_line) + sizeof(arc_line), GET_UNTAINTED);
 header_line * h = (header_line *)(al+1);
 uschar * badline_str;
 
index 8e51f17578f6a4564f435d2d64ff31ee801ce184..f2188bb6a3428a797962d3c882528eadaac7ce66 100644 (file)
@@ -291,7 +291,7 @@ static int read_string(int fd, uschar **retval) {
             return -1;
         } else {
            /* Assume the file is trusted, so no tainting */
-            *retval = store_get(count + 1, FALSE);
+            *retval = store_get(count + 1, GET_UNTAINTED);
             rc = (retry_read(fd, *retval, count) < (int) count);
             (*retval)[count] = '\0';
             return count;
index 95cf5dab2c4c2f84ec7e3e6974cf066be5694351..3940767faff3fe8360a4cac0cab9f2e0c262394c 100644 (file)
@@ -33,7 +33,7 @@ int
 auth_xtextdecode(uschar *code, uschar **ptr)
 {
 register int x;
-uschar *result = store_get(Ustrlen(code) + 1, is_tainted(code));
+uschar * result = store_get(Ustrlen(code) + 1, code);
 *ptr = result;
 
 while ((x = (*code++)) != 0)
index 30ff8f11ddb039401f34d74c1e2ccfea0e1210ff..46f9c021cfe6871e044facaef7be42abf9a60552 100644 (file)
@@ -40,7 +40,7 @@ in order to get the right amount of store. */
 while (c -- > 0)
   count += ((x = *p++) < 33 || x > 127 || x == '+' || x == '=')? 3 : 1;
 
-pp = code = store_get(count, is_tainted(clear));
+pp = code = store_get(count, clear);
 
 p = US clear;
 c = len;
index 29f9c77b0d59746cc17c8963df92ddad4d841cf9..f7ed0b5b514c4f54be57b7790876eff2942c1be2 100644 (file)
@@ -157,10 +157,10 @@ b64decode(const uschar *code, uschar **ptr)
 int x, y;
 uschar *result;
 
-{
+ {
   int l = Ustrlen(code);
-  *ptr = result = store_get(1 + l/4 * 3 + l%4, is_tainted(code));
-}
+  *ptr = result = store_get(1 + l/4 * 3 + l%4, code);
+ }
 
 /* Each cycle of the loop handles a quantum of 4 input bytes. For the last
 quantum this may decode to 1, 2, or 3 output bytes. */
@@ -234,6 +234,7 @@ would probably run more slowly.
 Arguments:
   clear       points to the clear text bytes
   len         the number of bytes to encode
+  proto_mem   taint indicator
 
 Returns:      a pointer to the zero-terminated base 64 string, which
               is in working store
@@ -243,10 +244,10 @@ static uschar *enc64table =
   US"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
 
 uschar *
-b64encode_taint(const uschar * clear, int len, BOOL tainted)
+b64encode_taint(const uschar * clear, int len, const void * proto_mem)
 {
-uschar *code = store_get(4*((len+2)/3) + 1, tainted);
-uschar *p = code;
+uschar * code = store_get(4*((len+2)/3) + 1, proto_mem);
+uschar * p = code;
 
 while (len-- >0)
   {
@@ -287,7 +288,7 @@ return code;
 uschar *
 b64encode(const uschar * clear, int len)
 {
-return b64encode_taint(clear, len, is_tainted(clear));
+return b64encode_taint(clear, len, clear);
 }
 
 
index 6972bc3a7957bdac5f09028b0cd59448734974c6..334022b004b0c9f9e25da33ec908cf43306cdf20 100644 (file)
@@ -193,16 +193,16 @@ uschar *bmi_process_message(header_line *header_list, int data_fd) {
   /* Get store for the verdict string.  Since we are processing message data, assume that
   the verdict is tainted.  XXX this should use a growable-string  */
 
-  verdicts = store_get(1, TRUE);
+  verdicts = store_get(1, GET_TAINTED);
   *verdicts = '\0';
 
   for ( err = bmiAccessFirstVerdict(message, &verdict);
-        verdict != NULL;
+        verdict;
         err = bmiAccessNextVerdict(message, verdict, &verdict) ) {
     char *verdict_str;
 
     err = bmiCreateStrFromVerdict(verdict,&verdict_str);
-    if (!store_extend(verdicts, TRUE,
+    if (!store_extend(verdicts,
          Ustrlen(verdicts)+1, Ustrlen(verdicts)+1+strlen(verdict_str)+1)) {
       /* can't allocate more store */
       return NULL;
@@ -302,7 +302,7 @@ uschar *bmi_get_alt_location(uschar *base64_verdict) {
   }
   else {
     /* deliver to alternate location */
-    rc = store_get(strlen(bmiVerdictAccessDestination(verdict))+1, TRUE);
+    rc = store_get(strlen(bmiVerdictAccessDestination(verdict))+1, GET_TAINTED);
     Ustrcpy(rc, bmiVerdictAccessDestination(verdict));
     rc[strlen(bmiVerdictAccessDestination(verdict))] = '\0';
   };
@@ -327,7 +327,7 @@ uschar *bmi_get_base64_verdict(uschar *bmi_local_part, uschar *bmi_domain) {
     return NULL;
 
   /* allocate room for the b64 verdict string */
-  verdict_buffer = store_get(Ustrlen(bmi_verdicts)+1, TRUE);
+  verdict_buffer = store_get(Ustrlen(bmi_verdicts)+1, GET_TAINTED);
 
   /* loop through verdicts */
   verdict_ptr = bmi_verdicts;
index 07115bee43863bca0b98eec4733346821fedd938..38b9d32fad97907f0091e3dbcbdd9ed2a23eebb3 100644 (file)
@@ -76,7 +76,7 @@ int n = 0;
 int extra = pcount ? *pcount : 0;
 uschar **argv;
 
-argv = store_get((extra + acount + MAX_CLMACROS + 24) * sizeof(char *), FALSE);
+argv = store_get((extra + acount + MAX_CLMACROS + 24) * sizeof(char *), GET_UNTAINTED);
 
 /* In all case, the list starts out with the path, any macros, and a changed
 config file. */
index 4a3cb6adbeea99b1bd5a957442bcc5f72ccff690..daedf0080fb7b9af8e647a45db09fa4b52f8dd14 100644 (file)
@@ -1346,7 +1346,7 @@ DEBUG(D_any|D_v) debug_selector |= D_pid;
 /* Allocate enough pollstructs for inetd mode plus the ancillary sockets;
 also used when there are no listen sockets. */
 
-fd_polls = store_get(sizeof(struct pollfd) * 3, FALSE);
+fd_polls = store_get(sizeof(struct pollfd) * 3, GET_UNTAINTED);
 
 if (f.inetd_wait_mode)
   {
@@ -1534,7 +1534,7 @@ if (f.daemon_listen && !f.inetd_wait_mode)
   sep = 0;
   while ((s = string_nextinlist(&list, &sep, NULL, 0)))
     pct++;
-  default_smtp_port = store_get((pct+1) * sizeof(int), FALSE);
+  default_smtp_port = store_get((pct+1) * sizeof(int), GET_UNTAINTED);
   list = daemon_smtp_port;
   sep = 0;
   for (pct = 0;
@@ -1623,7 +1623,7 @@ if (f.daemon_listen && !f.inetd_wait_mode)
     ipa->port = default_smtp_port[0];
     for (int i = 1; default_smtp_port[i] > 0; i++)
       {
-      ip_address_item *new = store_get(sizeof(ip_address_item), FALSE);
+      ip_address_item * new = store_get(sizeof(ip_address_item), GET_UNTAINTED);
 
       memcpy(new->address, ipa->address, Ustrlen(ipa->address) + 1);
       new->port = default_smtp_port[i];
@@ -1683,7 +1683,7 @@ if (f.daemon_listen && !f.inetd_wait_mode)
   for (ipa = addresses; ipa; ipa = ipa->next)
     listen_socket_count++;
   fd_polls = store_get(sizeof(struct pollfd) * (listen_socket_count + 2),
-                           FALSE);
+                           GET_UNTAINTED);
   for (struct pollfd * p = fd_polls; p < fd_polls + listen_socket_count + 2;
        p++)
     { p->fd = -1; p->events = POLLIN; }
@@ -1709,7 +1709,7 @@ if (f.daemon_listen)
 
   if (smtp_accept_max > 0)
     {
-    smtp_slots = store_get(smtp_accept_max * sizeof(smtp_slot), FALSE);
+    smtp_slots = store_get(smtp_accept_max * sizeof(smtp_slot), GET_UNTAINTED);
     for (int i = 0; i < smtp_accept_max; i++) smtp_slots[i] = empty_smtp_slot;
     }
   }
@@ -1991,7 +1991,7 @@ of them (and also if we are doing queue runs). */
 
 if (queue_interval > 0 && local_queue_run_max > 0)
   {
-  queue_pid_slots = store_get(local_queue_run_max * sizeof(pid_t), FALSE);
+  queue_pid_slots = store_get(local_queue_run_max * sizeof(pid_t), GET_UNTAINTED);
   for (int i = 0; i < local_queue_run_max; i++) queue_pid_slots[i] = 0;
   }
 
index 9c64d6a525b11dfee57f32c707f8636bf6e838e1..c318c2f5893309433c9db2173f05199586c1e03a 100644 (file)
@@ -268,7 +268,7 @@ dbfn_read_with_length(open_db *dbblock, const uschar *key, int *length)
 void *yield;
 EXIM_DATUM key_datum, result_datum;
 int klen = Ustrlen(key) + 1;
-uschar * key_copy = store_get(klen, is_tainted(key));
+uschar * key_copy = store_get(klen, key);
 
 memcpy(key_copy, key, klen);
 
@@ -284,7 +284,7 @@ if (!EXIM_DBGET(dbblock->dbptr, key_datum, result_datum)) return NULL;
 /* Assume the data store could have been tainted.  Properly, we should
 store the taint status with the data. */
 
-yield = store_get(EXIM_DATUM_SIZE(result_datum), TRUE);
+yield = store_get(EXIM_DATUM_SIZE(result_datum), GET_TAINTED);
 memcpy(yield, EXIM_DATUM_DATA(result_datum), EXIM_DATUM_SIZE(result_datum));
 if (length) *length = EXIM_DATUM_SIZE(result_datum);
 
@@ -343,7 +343,7 @@ dbfn_write(open_db *dbblock, const uschar *key, void *ptr, int length)
 EXIM_DATUM key_datum, value_datum;
 dbdata_generic *gptr = (dbdata_generic *)ptr;
 int klen = Ustrlen(key) + 1;
-uschar * key_copy = store_get(klen, is_tainted(key));
+uschar * key_copy = store_get(klen, key);
 
 memcpy(key_copy, key, klen);
 gptr->time_stamp = time(NULL);
@@ -377,7 +377,7 @@ int
 dbfn_delete(open_db *dbblock, const uschar *key)
 {
 int klen = Ustrlen(key) + 1;
-uschar * key_copy = store_get(klen, is_tainted(key));
+uschar * key_copy = store_get(klen, key);
 
 DEBUG(D_hints_lookup) debug_printf_indent("dbfn_delete: key=%s\n", key);
 
index 5c60e3ff5feec73ac9f06fea97d7b5ee20111667..8f85626a09320321e697915a74ee3c97d2993560 100644 (file)
@@ -146,7 +146,7 @@ Returns:      a pointer to an initialized address_item
 address_item *
 deliver_make_addr(uschar *address, BOOL copy)
 {
-address_item *addr = store_get(sizeof(address_item), FALSE);
+address_item * addr = store_get(sizeof(address_item), GET_UNTAINTED);
 *addr = address_defaults;
 if (copy) address = string_copy(address);
 addr->address = address;
@@ -1148,7 +1148,7 @@ pointer to a single host item in their host list, for use by the transport. */
 #endif
 
 reset_point = store_mark();
-g = string_get_tainted(256, TRUE);     /* addrs will be tainted, so avoid copy */
+g = string_get_tainted(256, GET_TAINTED);      /* addrs will be tainted, so avoid copy */
 
 if (msg)
   g = string_append(g, 2, host_and_ident(TRUE), US" ");
@@ -2376,27 +2376,29 @@ if ((pid = exim_fork(US"delivery-local")) == 0)
     {
     BOOL ok = TRUE;
     set_process_info("delivering %s to %s using %s", message_id,
-     addr->local_part, addr->transport->name);
+     addr->local_part, tp->name);
 
-    /* Setting this global in the subprocess means we need never clear it */
+    /* Setting these globals in the subprocess means we need never clear them */
     transport_name = addr->transport->name;
+    driver_srcfile = tp->srcfile;
+    driver_srcline = tp->srcline;
 
     /* If a transport filter has been specified, set up its argument list.
     Any errors will get put into the address, and FALSE yielded. */
 
-    if (addr->transport->filter_command)
+    if (tp->filter_command)
       {
       ok = transport_set_up_command(&transport_filter_argv,
-        addr->transport->filter_command,
+        tp->filter_command,
         TRUE, PANIC, addr, US"transport filter", NULL);
-      transport_filter_timeout = addr->transport->filter_timeout;
+      transport_filter_timeout = tp->filter_timeout;
       }
     else transport_filter_argv = NULL;
 
     if (ok)
       {
-      debug_print_string(addr->transport->debug_string);
-      replicate = !(addr->transport->info->code)(addr->transport, addr);
+      debug_print_string(tp->debug_string);
+      replicate = !(tp->info->code)(addr->transport, addr);
       }
     }
 
@@ -3049,7 +3051,7 @@ while (addr_local)
     else for (addr2 = addr; addr2; addr2 = addr2->next)
       if (addr2->transport_return == OK)
        {
-       addr3 = store_get(sizeof(address_item), FALSE);
+       addr3 = store_get(sizeof(address_item), GET_UNTAINTED);
        *addr3 = *addr2;
        addr3->next = NULL;
        addr3->shadow_message = US &addr2->shadow_message;
@@ -3444,7 +3446,7 @@ while (!done)
 
       if (!r || !(*ptr & rf_delete))
        {
-       r = store_get(sizeof(retry_item), FALSE);
+       r = store_get(sizeof(retry_item), GET_UNTAINTED);
        r->next = addr->retries;
        addr->retries = r;
        r->flags = *ptr++;
@@ -3635,7 +3637,7 @@ while (!done)
 
          if (*ptr)
            {
-           h = store_get(sizeof(host_item), FALSE);
+           h = store_get(sizeof(host_item), GET_UNTAINTED);
            h->name = string_copy(ptr);
            while (*ptr++);
            h->address = string_copy(ptr);
@@ -4213,10 +4215,10 @@ set up, do so. */
 
 if (!parlist)
   {
-  parlist = store_get(remote_max_parallel * sizeof(pardata), FALSE);
+  parlist = store_get(remote_max_parallel * sizeof(pardata), GET_UNTAINTED);
   for (poffset = 0; poffset < remote_max_parallel; poffset++)
     parlist[poffset].pid = 0;
-  parpoll = store_get(remote_max_parallel * sizeof(struct pollfd), FALSE);
+  parpoll = store_get(remote_max_parallel * sizeof(struct pollfd), GET_UNTAINTED);
   }
 
 /* Now loop for each remote delivery */
@@ -4664,8 +4666,10 @@ all pipes, so I do not see a reason to use non-blocking IO here
     int fd = pfd[pipe_write];
     host_item *h;
 
-    /* Setting this global in the subprocess means we need never clear it */
-    transport_name = tp->name;
+    /* Setting these globals in the subprocess means we need never clear them */
+    transport_name = addr->transport->name;
+    driver_srcfile = tp->srcfile;
+    driver_srcline = tp->srcline;
 
     /* There are weird circumstances in which logging is disabled */
     f.disable_logging = tp->disable_logging;
@@ -5111,7 +5115,7 @@ where they are locally interpreted. [The new draft "821" is more explicit on
 this, Jan 1999.] We know the syntax is valid, so this can be done by simply
 removing quoting backslashes and any unquoted doublequotes. */
 
-t = addr->cc_local_part = store_get(len+1, is_tainted(address));
+t = addr->cc_local_part = store_get(len+1, address);
 while(len-- > 0)
   {
   int c = *address++;
@@ -5154,7 +5158,7 @@ if (percent_hack_domains)
 
   if (new_address)
     {
-    address_item *new_parent = store_get(sizeof(address_item), FALSE);
+    address_item * new_parent = store_get(sizeof(address_item), GET_UNTAINTED);
     *new_parent = *addr;
     addr->parent = new_parent;
     new_parent->child_count = 1;
@@ -6552,7 +6556,7 @@ while (addr_new)           /* Loop until all addresses dealt with */
       if (Ustrcmp(addr->address, "/dev/null") == 0)
         {
        transport_instance * save_t = addr->transport;
-       transport_instance * t = store_get(sizeof(*t), is_tainted(save_t));
+       transport_instance * t = store_get(sizeof(*t), save_t);
        *t = *save_t;
        t->name = US"**bypassed**";
        addr->transport = t;
@@ -7386,7 +7390,7 @@ for (address_item * a = addr_succeed; a; a = a->next)
     {
     /* copy and relink address_item and send report with all of them at once later */
     address_item * addr_next = addr_senddsn;
-    addr_senddsn = store_get(sizeof(address_item), FALSE);
+    addr_senddsn = store_get(sizeof(address_item), GET_UNTAINTED);
     *addr_senddsn = *a;
     addr_senddsn->next = addr_next;
     }
index 0c5e84788872ae7f359ce65e329fd93b3cacbd3f..0153024df8f5498861f76b4058049e7e8f3f402b 100644 (file)
@@ -50,7 +50,7 @@ dkim_exim_query_dns_txt(const uschar * name)
 dns_answer * dnsa = store_get_dns_answer();
 dns_scan dnss;
 rmark reset_point = store_mark();
-gstring * g = string_get_tainted(256, TRUE);
+gstring * g = string_get_tainted(256, GET_TAINTED);
 
 lookup_dnssec_authenticated = NULL;
 if (dns_lookup(dnsa, name, T_TXT, NULL) != DNS_SUCCEED)
index 00aab2beeced77d2829e8d9ab14b7c6138fee910..f1b18bd59976935a8ee637cb749fd79d85c74890 100644 (file)
@@ -530,7 +530,7 @@ if (!dmarc_abort && !sender_host_authenticated)
   /* Can't use exim's string manipulation functions so allocate memory
   for libopendmarc using its max hostname length definition. */
 
-  dmarc_domain = store_get(DMARC_MAXHOSTNAMELEN, TRUE);
+  dmarc_domain = store_get(DMARC_MAXHOSTNAMELEN, GET_TAINTED);
   libdm_status = opendmarc_policy_fetch_utilized_domain(dmarc_pctx,
     dmarc_domain, DMARC_MAXHOSTNAMELEN-1);
   store_release_above(dmarc_domain + Ustrlen(dmarc_domain)+1);
index 07c51e2dc37447e53e29b19790dc8e3ce8748552..dd29d5c15d39ea31a6be0f30bc0e617794faa67b 100644 (file)
@@ -258,7 +258,7 @@ else
   {
   int v6[4];
 
-  g = string_get_tainted(32, is_tainted(string));
+  g = string_get_tainted(32, string);
   (void)host_aton(string, v6);
 
   /* The original specification for IPv6 reverse lookup was to invert each
@@ -637,7 +637,7 @@ if ((previous = tree_search(tree_dns_fails, node_name)))
   e = previous->data.ptr;
 else
   {
-  e = store_get_perm(DNS_FAILNODE_SIZE, is_tainted(name));
+  e = store_get_perm(DNS_FAILNODE_SIZE, name);
   new = (void *)(e+1);
   dns_fail_tag(new->name, name, type);
   new->data.ptr = e;
@@ -1065,7 +1065,7 @@ for (int i = 0; i <= dns_cname_loops; i++)
     return DNS_FAIL;
 
   /* DNS data comes from the outside, hence tainted */
-  data = store_get(256, TRUE);
+  data = store_get(256, GET_TAINTED);
   if (dn_expand(dnsa->answer, dnsa->answer + dnsa->answerlen,
       cname_rr.data, (DN_EXPAND_ARG4_TYPE)data, 256) < 0)
     return DNS_FAIL;
@@ -1293,7 +1293,7 @@ if (rr->type == T_A)
   if (p + 4 <= dnsa_lim)
     {
     /* the IP is not regarded as tainted */
-    yield = store_get(sizeof(dns_address) + 20, FALSE);
+    yield = store_get(sizeof(dns_address) + 20, GET_UNTAINTED);
     (void)sprintf(CS yield->address, "%d.%d.%d.%d", p[0], p[1], p[2], p[3]);
     yield->next = NULL;
     }
@@ -1307,7 +1307,7 @@ else
     {
     struct in6_addr in6;
     for (int i = 0; i < 16; i++) in6.s6_addr[i] = rr->data[i];
-    yield = store_get(sizeof(dns_address) + 50, FALSE);
+    yield = store_get(sizeof(dns_address) + 50, GET_UNTAINTED);
     inet_ntop(AF_INET6, &in6, CS yield->address, 50);
     yield->next = NULL;
     }
index 5335b777b70a070dbd7065653b669cd727fe7d90..e95da266ba5557d96237760b98e637938c9fca9f 100644 (file)
@@ -115,9 +115,9 @@ else
 
   else
     {  /* Set up a tree entry to cache the lookup */
-    t = store_get(sizeof(tree_node) + qlen + 1 + 1, is_tainted(query));
+    t = store_get(sizeof(tree_node) + qlen + 1 + 1, query);
     Ustrcpy(t->name, query);
-    t->data.ptr = cb = store_get(sizeof(dnsbl_cache_block), FALSE);
+    t->data.ptr = cb = store_get(sizeof(dnsbl_cache_block), GET_UNTAINTED);
     (void)tree_insertnode(&dnsbl_cache, t);
     }
 
@@ -365,7 +365,7 @@ if (cb->rc == DNS_SUCCEED)
          int len = (rr->data)[0];
          if (len > 511) len = 127;
          store_pool = POOL_PERM;
-         cb->text = string_copyn_taint(CUS (rr->data+1), len, TRUE);
+         cb->text = string_copyn_taint(CUS (rr->data+1), len, GET_TAINTED);
          store_pool = old_pool;
          break;
          }
index a4958b179754dfa5db0d3539734e179beaecce82..39f58f803cb42ac04ff48b2d6caf572af5280aca 100644 (file)
@@ -518,7 +518,7 @@ static struct lookupmodulestr *lookupmodules = NULL;
 static void
 addlookupmodule(void *dl, struct lookup_module_info *info)
 {
-struct lookupmodulestr *p = store_get(sizeof(struct lookupmodulestr), FALSE);
+struct lookupmodulestr *p = store_get(sizeof(struct lookupmodulestr), GET_UNTAINTED);
 
 p->dl = dl;
 p->info = info;
index bedac628b0a852d3494194ea962b8c48188700d5..eada6bbf8177b232af589361a865873f8a05973f 100644 (file)
@@ -1902,7 +1902,7 @@ big_buffer = store_malloc(big_buffer_size);
 /* Set up the handler for the data request signal, and set the initial
 descriptive text. */
 
-process_info = store_get(PROCESS_INFO_SIZE, TRUE);     /* tainted */
+process_info = store_get(PROCESS_INFO_SIZE, GET_TAINTED);
 set_process_info("initializing");
 os_restarting_signal(SIGUSR1, usr1_handler);           /* exiwhat */
 #ifdef SA_SIGINFO
@@ -2273,7 +2273,9 @@ on the second character (the one after '-'), to save some effort. */
          if (!*argrest || Ustrcmp(argrest, "c") == 0)
            {
            if (++i >= argc) { badarg = TRUE; break; }
-           sender_host_address = string_copy_taint(exim_str_fail_toolong(argv[i], EXIM_IPADDR_MAX, "-bh"), TRUE);
+           sender_host_address = string_copy_taint(
+                 exim_str_fail_toolong(argv[i], EXIM_IPADDR_MAX, "-bh"),
+                 GET_TAINTED);
            host_checking = checking = f.log_testing_mode = TRUE;
            f.host_checking_callout = *argrest == 'c';
            message_logs = FALSE;
@@ -2746,7 +2748,9 @@ on the second character (the one after '-'), to save some effort. */
     case 'F':
     if (!*argrest)
       if (++i < argc) argrest = argv[i]; else { badarg = TRUE; break; }
-    originator_name = string_copy_taint(exim_str_fail_toolong(argrest, EXIM_HUMANNAME_MAX, "-F"), TRUE);
+    originator_name = string_copy_taint(
+                 exim_str_fail_toolong(argrest, EXIM_HUMANNAME_MAX, "-F"),
+                 GET_TAINTED);
     f.sender_name_forced = TRUE;
     break;
 
@@ -2774,7 +2778,7 @@ on the second character (the one after '-'), to save some effort. */
         if (i+1 < argc) argrest = argv[++i]; else { badarg = TRUE; break; }
       (void) exim_str_fail_toolong(argrest, EXIM_DISPLAYMAIL_MAX, "-f");
       if (!*argrest)
-        *(sender_address = store_get(1, FALSE)) = '\0';  /* Ensure writeable memory */
+        *(sender_address = store_get(1, GET_UNTAINTED)) = '\0';  /* Ensure writeable memory */
       else
         {
         uschar * temp = argrest + Ustrlen(argrest) - 1;
@@ -2789,7 +2793,7 @@ on the second character (the one after '-'), to save some effort. */
                  &dummy_start, &dummy_end, &sender_address_domain, TRUE)))
           exim_fail("exim: bad -f address \"%s\": %s\n", argrest, errmess);
 
-       sender_address = string_copy_taint(sender_address, TRUE);
+       sender_address = string_copy_taint(sender_address, GET_TAINTED);
 #ifdef SUPPORT_I18N
        message_smtputf8 =  string_is_utf8(sender_address);
        allow_utf8_domains = FALSE;
@@ -2839,7 +2843,7 @@ on the second character (the one after '-'), to save some effort. */
       exim_fail("exim: the -L syslog name is too long: \"%s\"\n", argrest);
     if (sz < 1)
       exim_fail("exim: the -L syslog name is too short\n");
-    cmdline_syslog_name = string_copy_taint(argrest, TRUE);
+    cmdline_syslog_name = string_copy_taint(argrest, GET_TAINTED);
     break;
 
     case 'M':
@@ -2869,9 +2873,15 @@ on the second character (the one after '-'), to save some effort. */
       if (msg_action_arg >= 0)
         exim_fail("exim: incompatible arguments\n");
 
-      continue_transport = string_copy_taint(exim_str_fail_toolong(argv[++i], EXIM_DRIVERNAME_MAX, "-C internal transport"), TRUE);
-      continue_hostname = string_copy_taint(exim_str_fail_toolong(argv[++i], EXIM_HOSTNAME_MAX, "-C internal hostname"), TRUE);
-      continue_host_address = string_copy_taint(exim_str_fail_toolong(argv[++i], EXIM_IPADDR_MAX, "-C internal hostaddr"), TRUE);
+      continue_transport = string_copy_taint(
+       exim_str_fail_toolong(argv[++i], EXIM_DRIVERNAME_MAX, "-C internal transport"),
+       GET_TAINTED);
+      continue_hostname = string_copy_taint(
+       exim_str_fail_toolong(argv[++i], EXIM_HOSTNAME_MAX, "-C internal hostname"),
+       GET_TAINTED);
+      continue_host_address = string_copy_taint(
+       exim_str_fail_toolong(argv[++i], EXIM_IPADDR_MAX, "-C internal hostaddr"),
+       GET_TAINTED);
       continue_sequence = Uatoi(argv[++i]);
       msg_action = MSG_DELIVER;
       msg_action_arg = ++i;
@@ -2916,7 +2926,9 @@ on the second character (the one after '-'), to save some effort. */
     /* -MCd: for debug, set a process-purpose string */
 
        case 'd': if (++i < argc)
-                   process_purpose = string_copy_taint(exim_str_fail_toolong(argv[i], EXIM_DRIVERNAME_MAX, "-MCd"), TRUE);
+                   process_purpose = string_copy_taint(
+                     exim_str_fail_toolong(argv[i], EXIM_DRIVERNAME_MAX, "-MCd"),
+                     GET_TAINTED);
                  else badarg = TRUE;
                  break;
 
@@ -2924,7 +2936,9 @@ on the second character (the one after '-'), to save some effort. */
        from the commandline should be tainted - but we will need an untainted
        value for the spoolfile when doing a -odi delivery process. */
 
-       case 'G': if (++i < argc) queue_name = string_copy_taint(exim_str_fail_toolong(argv[i], EXIM_DRIVERNAME_MAX, "-MCG"), FALSE);
+       case 'G': if (++i < argc) queue_name = string_copy_taint(
+                     exim_str_fail_toolong(argv[i], EXIM_DRIVERNAME_MAX, "-MCG"),
+                     GET_UNTAINTED);
                  else badarg = TRUE;
                  break;
 
@@ -2953,13 +2967,13 @@ on the second character (the one after '-'), to save some effort. */
        case 'p': proxy_session = TRUE;
                  if (++i < argc)
                    {
-                   proxy_local_address = string_copy_taint(argv[i], TRUE);
+                   proxy_local_address = string_copy_taint(argv[i], GET_TAINTED);
                    if (++i < argc)
                      {
                      proxy_local_port = Uatoi(argv[i]);
                      if (++i < argc)
                        {
-                       proxy_external_address = string_copy_taint(argv[i], TRUE);
+                       proxy_external_address = string_copy_taint(argv[i], GET_TAINTED);
                        if (++i < argc)
                          {
                          proxy_external_port = Uatoi(argv[i]);
@@ -2997,7 +3011,9 @@ on the second character (the one after '-'), to save some effort. */
        case 'r':
        case 's': if (++i < argc)
                    {
-                   continue_proxy_sni = string_copy_taint(exim_str_fail_toolong(argv[i], EXIM_HOSTNAME_MAX, "-MCr/-MCs"), TRUE);
+                   continue_proxy_sni = string_copy_taint(
+                     exim_str_fail_toolong(argv[i], EXIM_HOSTNAME_MAX, "-MCr/-MCs"),
+                     GET_TAINTED);
                    if (argrest[1] == 'r') continue_proxy_dane = TRUE;
                    }
                  else badarg = TRUE;
@@ -3009,13 +3025,17 @@ on the second character (the one after '-'), to save some effort. */
     and the TLS cipher. */
 
        case 't': if (++i < argc)
-                   sending_ip_address = string_copy_taint(exim_str_fail_toolong(argv[i], EXIM_IPADDR_MAX, "-MCt IP"), TRUE);
+                   sending_ip_address = string_copy_taint(
+                     exim_str_fail_toolong(argv[i], EXIM_IPADDR_MAX, "-MCt IP"),
+                     GET_TAINTED);
                  else badarg = TRUE;
                  if (++i < argc)
                    sending_port = (int)(Uatol(argv[i]));
                  else badarg = TRUE;
                  if (++i < argc)
-                   continue_proxy_cipher = string_copy_taint(exim_str_fail_toolong(argv[i], EXIM_CIPHERNAME_MAX, "-MCt cipher"), TRUE);
+                   continue_proxy_cipher = string_copy_taint(
+                     exim_str_fail_toolong(argv[i], EXIM_CIPHERNAME_MAX, "-MCt cipher"),
+                     GET_TAINTED);
                  else badarg = TRUE;
                  /*FALLTHROUGH*/
 
@@ -3078,12 +3098,11 @@ on the second character (the one after '-'), to save some effort. */
    else if (Ustrcmp(argrest, "G") == 0)
       {
       msg_action = MSG_SETQUEUE;
-      queue_name_dest = string_copy_taint(exim_str_fail_toolong(argv[++i], EXIM_DRIVERNAME_MAX, "-MG"), TRUE);
-      }
-    else if (Ustrcmp(argrest, "mad") == 0)
-      {
-      msg_action = MSG_MARK_ALL_DELIVERED;
+      queue_name_dest = string_copy_taint(
+       exim_str_fail_toolong(argv[++i], EXIM_DRIVERNAME_MAX, "-MG"),
+       GET_TAINTED);
       }
+    else if (Ustrcmp(argrest, "mad") == 0) msg_action = MSG_MARK_ALL_DELIVERED;
     else if (Ustrcmp(argrest, "md") == 0)
       {
       msg_action = MSG_MARK_DELIVERED;
@@ -3291,27 +3310,37 @@ on the second character (the one after '-'), to save some effort. */
        /* -oMa: Set sender host address */
 
        if (Ustrcmp(argrest, "a") == 0)
-         sender_host_address = string_copy_taint(exim_str_fail_toolong(argv[++i], EXIM_IPADDR_MAX, "-oMa"), TRUE);
+         sender_host_address = string_copy_taint(
+           exim_str_fail_toolong(argv[++i], EXIM_IPADDR_MAX, "-oMa"),
+           GET_TAINTED);
 
        /* -oMaa: Set authenticator name */
 
        else if (Ustrcmp(argrest, "aa") == 0)
-         sender_host_authenticated = string_copy_taint(exim_str_fail_toolong(argv[++i], EXIM_DRIVERNAME_MAX, "-oMaa"), TRUE);
+         sender_host_authenticated = string_copy_taint(
+           exim_str_fail_toolong(argv[++i], EXIM_DRIVERNAME_MAX, "-oMaa"),
+           GET_TAINTED);
 
        /* -oMas: setting authenticated sender */
 
        else if (Ustrcmp(argrest, "as") == 0)
-         authenticated_sender = string_copy_taint(exim_str_fail_toolong(argv[++i], EXIM_EMAILADDR_MAX, "-oMas"), TRUE);
+         authenticated_sender = string_copy_taint(
+           exim_str_fail_toolong(argv[++i], EXIM_EMAILADDR_MAX, "-oMas"),
+           GET_TAINTED);
 
        /* -oMai: setting authenticated id */
 
        else if (Ustrcmp(argrest, "ai") == 0)
-         authenticated_id = string_copy_taint(exim_str_fail_toolong(argv[++i], EXIM_EMAILADDR_MAX, "-oMas"), TRUE);
+         authenticated_id = string_copy_taint(
+           exim_str_fail_toolong(argv[++i], EXIM_EMAILADDR_MAX, "-oMas"),
+           GET_TAINTED);
 
        /* -oMi: Set incoming interface address */
 
        else if (Ustrcmp(argrest, "i") == 0)
-         interface_address = string_copy_taint(exim_str_fail_toolong(argv[++i], EXIM_IPADDR_MAX, "-oMi"), TRUE);
+         interface_address = string_copy_taint(
+           exim_str_fail_toolong(argv[++i], EXIM_IPADDR_MAX, "-oMi"),
+           GET_TAINTED);
 
        /* -oMm: Message reference */
 
@@ -3331,19 +3360,25 @@ on the second character (the one after '-'), to save some effort. */
          if (received_protocol)
            exim_fail("received_protocol is set already\n");
          else
-           received_protocol = string_copy_taint(exim_str_fail_toolong(argv[++i], EXIM_DRIVERNAME_MAX, "-oMr"), TRUE);
+           received_protocol = string_copy_taint(
+             exim_str_fail_toolong(argv[++i], EXIM_DRIVERNAME_MAX, "-oMr"),
+             GET_TAINTED);
 
        /* -oMs: Set sender host name */
 
        else if (Ustrcmp(argrest, "s") == 0)
-         sender_host_name = string_copy_taint(exim_str_fail_toolong(argv[++i], EXIM_HOSTNAME_MAX, "-oMs"), TRUE);
+         sender_host_name = string_copy_taint(
+           exim_str_fail_toolong(argv[++i], EXIM_HOSTNAME_MAX, "-oMs"),
+           GET_TAINTED);
 
        /* -oMt: Set sender ident */
 
        else if (Ustrcmp(argrest, "t") == 0)
          {
          sender_ident_set = TRUE;
-         sender_ident = string_copy_taint(exim_str_fail_toolong(argv[++i], EXIM_IDENTUSER_MAX, "-oMt"), TRUE);
+         sender_ident = string_copy_taint(
+           exim_str_fail_toolong(argv[++i], EXIM_IDENTUSER_MAX, "-oMt"),
+           GET_TAINTED);
          }
 
        /* Else a bad argument */
@@ -3401,7 +3436,9 @@ on the second character (the one after '-'), to save some effort. */
 
       case 'X':
        if (*argrest) badarg = TRUE;
-       else override_local_interfaces = string_copy_taint(exim_str_fail_toolong(argv[++i], 1024, "-oX"), TRUE);
+       else override_local_interfaces = string_copy_taint(
+         exim_str_fail_toolong(argv[++i], 1024, "-oX"),
+         GET_TAINTED);
        break;
 
       /* -oY: Override creation of daemon notifier socket */
@@ -3449,12 +3486,14 @@ on the second character (the one after '-'), to save some effort. */
         exim_fail("received_protocol is set already\n");
 
       if (!hn)
-        received_protocol = string_copy_taint(exim_str_fail_toolong(argrest, EXIM_DRIVERNAME_MAX, "-p<protocol>"), TRUE);
+        received_protocol = string_copy_taint(
+         exim_str_fail_toolong(argrest, EXIM_DRIVERNAME_MAX, "-p<protocol>"),
+         GET_TAINTED);
       else
         {
         (void) exim_str_fail_toolong(argrest, (EXIM_DRIVERNAME_MAX+1+EXIM_HOSTNAME_MAX), "-p<protocol>:<host>");
-        received_protocol = string_copyn_taint(argrest, hn - argrest, TRUE);
-        sender_host_name = string_copy_taint(hn + 1, TRUE);
+        received_protocol = string_copyn_taint(argrest, hn - argrest, GET_TAINTED);
+        sender_host_name = string_copy_taint(hn + 1, GET_TAINTED);
         }
       }
     break;
@@ -3523,9 +3562,9 @@ on the second character (the one after '-'), to save some effort. */
        {
        queue_interval = 0;
        if (i+1 < argc && mac_ismsgid(argv[i+1]))
-         start_queue_run_id = string_copy_taint(argv[++i], TRUE);
+         start_queue_run_id = string_copy_taint(argv[++i], GET_TAINTED);
        if (i+1 < argc && mac_ismsgid(argv[i+1]))
-         stop_queue_run_id = string_copy_taint(argv[++i], TRUE);
+         stop_queue_run_id = string_copy_taint(argv[++i], GET_TAINTED);
        }
 
     /* -q[f][f][l][G<name>/]<n>: Run the queue at regular intervals, optionally
@@ -3573,7 +3612,9 @@ on the second character (the one after '-'), to save some effort. */
        tainted_selectstr = argv[++i];
       else
        exim_fail("exim: string expected after -R\n");
-      deliver_selectstring = string_copy_taint(exim_str_fail_toolong(tainted_selectstr, EXIM_EMAILADDR_MAX, "-R"), TRUE);
+      deliver_selectstring = string_copy_taint(
+       exim_str_fail_toolong(tainted_selectstr, EXIM_EMAILADDR_MAX, "-R"),
+       GET_TAINTED);
       }
     break;
 
@@ -3616,7 +3657,9 @@ on the second character (the one after '-'), to save some effort. */
        tainted_selectstr = argv[++i];
       else
        exim_fail("exim: string expected after -S\n");
-      deliver_selectstring_sender = string_copy_taint(exim_str_fail_toolong(tainted_selectstr, EXIM_EMAILADDR_MAX, "-S"), TRUE);
+      deliver_selectstring_sender = string_copy_taint(
+       exim_str_fail_toolong(tainted_selectstr, EXIM_EMAILADDR_MAX, "-S"),
+       GET_TAINTED);
       }
     break;
 
@@ -3627,7 +3670,7 @@ on the second character (the one after '-'), to save some effort. */
 
     case 'T':
     if (f.running_in_test_harness && Ustrcmp(argrest, "qt") == 0)
-      fudged_queue_times = string_copy_taint(argv[++i], TRUE);
+      fudged_queue_times = string_copy_taint(argv[++i], GET_TAINTED);
     else badarg = TRUE;
     break;
 
@@ -3704,7 +3747,9 @@ on the second character (the one after '-'), to save some effort. */
     case 'z':
     if (!*argrest)
       if (++i < argc)
-       log_oneline = string_copy_taint(exim_str_fail_toolong(argv[i], 2048, "-z logtext"), TRUE);
+       log_oneline = string_copy_taint(
+         exim_str_fail_toolong(argv[i], 2048, "-z logtext"),
+         GET_TAINTED);
       else
         exim_fail("exim: file name expected after %s\n", argv[i-1]);
     break;
@@ -5172,7 +5217,9 @@ if (verify_address_mode || f.address_test_mode)
     while (recipients_arg < argc)
       {
       /* Supplied addresses are tainted since they come from a user */
-      uschar * s = string_copy_taint(exim_str_fail_toolong(argv[recipients_arg++], EXIM_DISPLAYMAIL_MAX, "address verification"), TRUE);
+      uschar * s = string_copy_taint(
+       exim_str_fail_toolong(argv[recipients_arg++], EXIM_DISPLAYMAIL_MAX, "address verification"),
+       GET_TAINTED);
       while (*s)
         {
         BOOL finished = FALSE;
@@ -5189,7 +5236,10 @@ if (verify_address_mode || f.address_test_mode)
     {
     uschar * s = get_stdinput(NULL, NULL);
     if (!s) break;
-    test_address(string_copy_taint(exim_str_fail_toolong(s, EXIM_DISPLAYMAIL_MAX, "address verification (stdin)"), TRUE), flags, &exit_value);
+    test_address(string_copy_taint(
+       exim_str_fail_toolong(s, EXIM_DISPLAYMAIL_MAX, "address verification (stdin)"),
+       GET_TAINTED),
+      flags, &exit_value);
     }
 
   route_tidyup();
@@ -5329,7 +5379,7 @@ if (host_checking)
   it. The code works for both IPv4 and IPv6, as it happens. */
 
   size = host_aton(sender_host_address, x);
-  sender_host_address = store_get(48, FALSE);  /* large enough for full IPv6 */
+  sender_host_address = store_get(48, GET_UNTAINTED);  /* large enough for full IPv6 */
   (void)host_nmtoa(size, x, -1, sender_host_address, ':');
 
   /* Now set up for testing */
@@ -5701,11 +5751,13 @@ for (BOOL more = TRUE; more; )
       uschar * errmess;
       /* There can be multiple addresses, so EXIM_DISPLAYMAIL_MAX (tuned for 1) is too short.
        * We'll still want to cap it to something, just in case. */
-      uschar * s = string_copy_taint(exim_str_fail_toolong(list[i], BIG_BUFFER_SIZE, "address argument"), TRUE);
+      uschar * s = string_copy_taint(
+       exim_str_fail_toolong(list[i], BIG_BUFFER_SIZE, "address argument"),
+       GET_TAINTED);
 
       /* Loop for each comma-separated address */
 
-      while (*s != 0)
+      while (*s)
         {
         BOOL finished = FALSE;
         uschar *recipient;
@@ -5767,7 +5819,7 @@ for (BOOL more = TRUE; more; )
                 errors_sender_rc : EXIT_FAILURE;
             }
 
-        receive_add_recipient(string_copy_taint(recipient, TRUE), -1);
+        receive_add_recipient(string_copy_taint(recipient, GET_TAINTED), -1);
         s = ss;
         if (!finished)
           while (*(++s) != 0 && (*s == ',' || isspace(*s)));
index 45a3f1083730f23729f3cfc84f5de33061d0585a..ff7205d3d5e707b0264c317a230b3b089d353ba7 100644 (file)
@@ -42,7 +42,7 @@ uschar *
 readconf_printtime(int t)
 { return NULL; }
 void *
-store_get_3(int size, BOOL tainted, const char *filename, int linenumber)
+store_get_3(int size, const void * proto_mem, const char *filename, int linenumber)
 { return NULL; }
 void **
 store_reset_3(void **ptr, const char *filename, int linenumber)
index 5f2e664172a1fcabbeb703ec5cd7f8d79a840e75..798f2fed6e520fe3d39bb13b61bc13a6b00420c2 100644 (file)
@@ -430,7 +430,7 @@ dbfn_read_with_length(open_db *dbblock, const uschar *key, int *length)
 void *yield;
 EXIM_DATUM key_datum, result_datum;
 int klen = Ustrlen(key) + 1;
-uschar * key_copy = store_get(klen, is_tainted(key));
+uschar * key_copy = store_get(klen, key);
 
 memcpy(key_copy, key, klen);
 
@@ -444,7 +444,7 @@ if (!EXIM_DBGET(dbblock->dbptr, key_datum, result_datum)) return NULL;
 /* Assume for now that anything stored could have been tainted. Properly
 we should store the taint status along with the data. */
 
-yield = store_get(EXIM_DATUM_SIZE(result_datum), TRUE);
+yield = store_get(EXIM_DATUM_SIZE(result_datum), GET_TAINTED);
 memcpy(yield, EXIM_DATUM_DATA(result_datum), EXIM_DATUM_SIZE(result_datum));
 if (length) *length = EXIM_DATUM_SIZE(result_datum);
 
@@ -477,7 +477,7 @@ dbfn_write(open_db *dbblock, const uschar *key, void *ptr, int length)
 EXIM_DATUM key_datum, value_datum;
 dbdata_generic *gptr = (dbdata_generic *)ptr;
 int klen = Ustrlen(key) + 1;
-uschar * key_copy = store_get(klen, is_tainted(key));
+uschar * key_copy = store_get(klen, key);
 
 memcpy(key_copy, key, klen);
 gptr->time_stamp = time(NULL);
@@ -509,7 +509,7 @@ int
 dbfn_delete(open_db *dbblock, const uschar *key)
 {
 int klen = Ustrlen(key) + 1;
-uschar * key_copy = store_get(klen, is_tainted(key));
+uschar * key_copy = store_get(klen, key);
 
 memcpy(key_copy, key, klen);
 EXIM_DATUM key_datum;
@@ -1249,7 +1249,7 @@ for (key = dbfn_scan(dbm, TRUE, &cursor);
      key;
      key = dbfn_scan(dbm, FALSE, &cursor))
   {
-  key_item *k = store_get(sizeof(key_item) + Ustrlen(key), is_tainted(key));
+  key_item * k = store_get(sizeof(key_item) + Ustrlen(key), key);
   k->next = keychain;
   keychain = k;
   Ustrcpy(k->key, key);
index 9b315b42b1de133b15564181cdb2b16a0adbf774..0eb9fbff45a5a239e36f6169bc005a5ff5dfe021 100644 (file)
@@ -1288,7 +1288,7 @@ expand_getlistele(int field, const uschar * list)
 const uschar * tlist = list;
 int sep = 0;
 /* Tainted mem for the throwaway element copies */
-uschar * dummy = store_get(2, TRUE);
+uschar * dummy = store_get(2, GET_TAINTED);
 
 if (field < 0)
   {
@@ -1975,7 +1975,7 @@ switch (vp->type)
       int len = message_body_visible;
 
       if (len > message_size) len = message_size;
-      *ss = body = store_get(len+1, TRUE);
+      *ss = body = store_get(len+1, GET_TAINTED);
       body[0] = 0;
       if (vp->type == vtype_msgbody_end)
        {
@@ -3834,8 +3834,8 @@ Returns:  pointer to string containing the last three
 static uschar *
 prvs_daystamp(int day_offset)
 {
-uschar *days = store_get(32, FALSE);         /* Need at least 24 for cases */
-(void)string_format(days, 32, TIME_T_FMT,    /* where TIME_T_FMT is %lld */
+uschar * days = store_get(32, GET_UNTAINTED);      /* Need at least 24 for cases */
+(void)string_format(days, 32, TIME_T_FMT,         /* where TIME_T_FMT is %lld */
   (time(NULL) + day_offset*86400)/86400);
 return (Ustrlen(days) >= 3) ? &days[Ustrlen(days)-3] : US"100";
 }
@@ -3906,7 +3906,7 @@ chash_end(HMAC_SHA1, &h, innerhash, 20, finalhash);
 
 /* Hashing is deemed sufficient to de-taint any input data */
 
-p = finalhash_hex = store_get(40, FALSE);
+p = finalhash_hex = store_get(40, GET_UNTAINTED);
 for (int i = 0; i < 3; i++)
   {
   *p++ = hex_digits[(finalhash[i] & 0xf0) >> 4];
@@ -4347,7 +4347,7 @@ list = ((namedlist_block *)(t->data.ptr))->string;
 /* The list could be quite long so we (re)use a buffer for each element
 rather than getting each in new memory */
 
-if (is_tainted(list)) buffer = store_get(LISTNAMED_BUF_SIZE, TRUE);
+if (is_tainted(list)) buffer = store_get(LISTNAMED_BUF_SIZE, GET_TAINTED);
 while ((item = string_nextinlist(&list, &sep, buffer, LISTNAMED_BUF_SIZE)))
   {
   uschar * buf = US" : ";
@@ -4604,13 +4604,13 @@ while (*s)
     buffer. */
 
     if (!yield)
-      g = store_get(sizeof(gstring), FALSE);
+      g = store_get(sizeof(gstring), GET_UNTAINTED);
     else if (yield->ptr == 0)
       {
       if (resetok) reset_point = store_reset(reset_point);
       yield = NULL;
       reset_point = store_mark();
-      g = store_get(sizeof(gstring), FALSE);   /* alloc _before_ calling find_variable() */
+      g = store_get(sizeof(gstring), GET_UNTAINTED);   /* alloc _before_ calling find_variable() */
       }
 
     /* Header */
@@ -6436,6 +6436,7 @@ while (*s)
        goto EXPAND_FAILED;                                             /*{{*/
       if (*s++ != '}')
         {
+       /*{*/
        expand_string_message =
          string_sprintf("missing '}' closing first arg of %s", name);
        goto EXPAND_FAILED_CURLY;
@@ -6835,7 +6836,7 @@ while (*s)
           log_write(0, LOG_MAIN|LOG_PANIC, "%s", expand_string_message);
           goto EXPAND_FAILED;
           }
-        t = store_get_perm(sizeof(tree_node) + Ustrlen(argv[0]), is_tainted(argv[0]));
+        t = store_get_perm(sizeof(tree_node) + Ustrlen(argv[0]), argv[0]);
         Ustrcpy(t->name, argv[0]);
         t->data.ptr = handle;
         (void)tree_insertnode(&dlobj_anchor, t);
@@ -7364,7 +7365,7 @@ NOT_ITEM: ;
       case EOP_LISTCOUNT:
        {
        int cnt = 0, sep = 0;
-       uschar * buf = store_get(2, is_tainted(sub));
+       uschar * buf = store_get(2, sub);
 
        while (string_nextinlist(CUSS &sub, &sep, buf, 1)) cnt++;
        yield = string_fmt_append(yield, "%d", cnt);
@@ -7624,109 +7625,108 @@ NOT_ITEM: ;
            goto EXPAND_FAILED;
            }
 
-        if (lookup_list[n]->quote)
-          sub = (lookup_list[n]->quote)(sub, opt);
-        else if (opt)
-         sub = NULL;
+         if (lookup_list[n]->quote)
+           sub = (lookup_list[n]->quote)(sub, opt, (unsigned)n);
+         else if (opt)
+           sub = NULL;
 
-        if (!sub)
-          {
-          expand_string_message = string_sprintf(
-            "\"%s\" unrecognized after \"${quote_%s\"",                /*}*/
-            opt, arg);
-          goto EXPAND_FAILED;
-          }
+         if (!sub)
+           {
+           expand_string_message = string_sprintf(
+             "\"%s\" unrecognized after \"${quote_%s\"",       /*}*/
+             opt, arg);
+           goto EXPAND_FAILED;
+           }
 
-        yield = string_cat(yield, sub);
-        break;
-        }
+         yield = string_cat(yield, sub);
+         break;
+         }
 
-      /* rx quote sticks in \ before any non-alphameric character so that
-      the insertion works in a regular expression. */
+       /* rx quote sticks in \ before any non-alphameric character so that
+       the insertion works in a regular expression. */
 
-      case EOP_RXQUOTE:
-        {
-        uschar *t = sub - 1;
-        while (*(++t) != 0)
-          {
-          if (!isalnum(*t))
-            yield = string_catn(yield, US"\\", 1);
-          yield = string_catn(yield, t, 1);
-          }
-        break;
-        }
+       case EOP_RXQUOTE:
+         {
+         uschar *t = sub - 1;
+         while (*(++t) != 0)
+           {
+           if (!isalnum(*t))
+             yield = string_catn(yield, US"\\", 1);
+           yield = string_catn(yield, t, 1);
+           }
+         break;
+         }
 
-      /* RFC 2047 encodes, assuming headers_charset (default ISO 8859-1) as
-      prescribed by the RFC, if there are characters that need to be encoded */
+       /* RFC 2047 encodes, assuming headers_charset (default ISO 8859-1) as
+       prescribed by the RFC, if there are characters that need to be encoded */
 
-      case EOP_RFC2047:
-        yield = string_cat(yield,
-                           parse_quote_2047(sub, Ustrlen(sub), headers_charset,
-                             FALSE));
-        break;
+       case EOP_RFC2047:
+         yield = string_cat(yield,
+                             parse_quote_2047(sub, Ustrlen(sub), headers_charset,
+                               FALSE));
+         break;
 
-      /* RFC 2047 decode */
+       /* RFC 2047 decode */
 
-      case EOP_RFC2047D:
-        {
-        int len;
-        uschar *error;
-        uschar *decoded = rfc2047_decode(sub, check_rfc2047_length,
-          headers_charset, '?', &len, &error);
-        if (error)
-          {
-          expand_string_message = error;
-          goto EXPAND_FAILED;
-          }
-        yield = string_catn(yield, decoded, len);
-        break;
-        }
+       case EOP_RFC2047D:
+         {
+         int len;
+         uschar *error;
+         uschar *decoded = rfc2047_decode(sub, check_rfc2047_length,
+           headers_charset, '?', &len, &error);
+         if (error)
+           {
+           expand_string_message = error;
+           goto EXPAND_FAILED;
+           }
+         yield = string_catn(yield, decoded, len);
+         break;
+         }
 
-      /* from_utf8 converts UTF-8 to 8859-1, turning non-existent chars into
-      underscores */
+       /* from_utf8 converts UTF-8 to 8859-1, turning non-existent chars into
+       underscores */
 
-      case EOP_FROM_UTF8:
-        {
-       uschar * buff = store_get(4, is_tainted(sub));
-        while (*sub)
-          {
-          int c;
-          GETUTF8INC(c, sub);
-          if (c > 255) c = '_';
-          buff[0] = c;
-          yield = string_catn(yield, buff, 1);
-          }
-        break;
-        }
+       case EOP_FROM_UTF8:
+         {
+         uschar * buff = store_get(4, sub);
+         while (*sub)
+           {
+           int c;
+           GETUTF8INC(c, sub);
+           if (c > 255) c = '_';
+           buff[0] = c;
+           yield = string_catn(yield, buff, 1);
+           }
+         break;
+         }
 
-      /* replace illegal UTF-8 sequences by replacement character  */
+       /* replace illegal UTF-8 sequences by replacement character  */
 
-      #define UTF8_REPLACEMENT_CHAR US"?"
+       #define UTF8_REPLACEMENT_CHAR US"?"
 
-      case EOP_UTF8CLEAN:
-        {
-        int seq_len = 0, index = 0;
-        int bytes_left = 0;
-        long codepoint = -1;
-        int complete;
-        uschar seq_buff[4];                    /* accumulate utf-8 here */
+       case EOP_UTF8CLEAN:
+         {
+         int seq_len = 0, index = 0;
+         int bytes_left = 0;
+         long codepoint = -1;
+         int complete;
+         uschar seq_buff[4];                   /* accumulate utf-8 here */
 
-       /* Manually track tainting, as we deal in individual chars below */
+         /* Manually track tainting, as we deal in individual chars below */
 
-       if (is_tainted(sub))
-         if (yield->s && yield->ptr)
-           gstring_rebuffer(yield);
-         else
-           yield->s = store_get(yield->size = Ustrlen(sub), TRUE);
+         if (!yield->s || !yield->ptr)
+           yield->s = store_get(yield->size = Ustrlen(sub), sub);
+         else if (is_incompatible(yield->s, sub))
+           gstring_rebuffer(yield, sub);
 
-       /* Check the UTF-8, byte-by-byte */
+         /* Check the UTF-8, byte-by-byte */
 
-        while (*sub)
-         {
-         complete = 0;
-         uschar c = *sub++;
+         while (*sub)
+           {
+           complete = 0;
+           uschar c = *sub++;
 
-         if (bytes_left)
+           if (bytes_left)
              {
              if ((c & 0xc0) != 0x80)
                      /* wrong continuation byte; invalidate all bytes */
@@ -8149,9 +8149,34 @@ NOT_ITEM: ;
        }       /* EOP_* switch */
 
        DEBUG(D_expand)
-       if (start > 0 || *s)            /* only if not the sole expansion of the line */
-         debug_expansion_interim(US"op-res",
-                                 yield->s + start, yield->ptr - start, skipping);
+       {
+       const uschar * s = yield->s + start;
+       int i = yield->ptr - start;
+       BOOL tainted = is_tainted(s);
+
+       DEBUG(D_noutf8)
+         {
+         debug_printf_indent("|-----op-res: %.*s\n", i, s);
+         if (tainted)
+           {
+           debug_printf_indent("%s     \\__", skipping ? "|     " : "      ");
+           debug_print_taint(yield->s);
+           }
+         }
+       else
+         {
+         debug_printf_indent(UTF8_VERT_RIGHT
+           UTF8_HORIZ UTF8_HORIZ UTF8_HORIZ UTF8_HORIZ UTF8_HORIZ
+           "op-res: %.*s\n", i, s);
+         if (tainted)
+           {
+           debug_printf_indent("%s",
+             skipping
+             ? UTF8_VERT "             " : "           " UTF8_UP_RIGHT UTF8_HORIZ UTF8_HORIZ);
+           debug_print_taint(yield->s);
+           }
+         }
+       }
        continue;
        }
     }
@@ -8172,13 +8197,13 @@ NOT_ITEM: ;
     gstring * g = NULL;
 
     if (!yield)
-      g = store_get(sizeof(gstring), FALSE);
+      g = store_get(sizeof(gstring), GET_UNTAINTED);
     else if (yield->ptr == 0)
       {
       if (resetok) reset_point = store_reset(reset_point);
       yield = NULL;
       reset_point = store_mark();
-      g = store_get(sizeof(gstring), FALSE);   /* alloc _before_ calling find_variable() */
+      g = store_get(sizeof(gstring), GET_UNTAINTED);   /* alloc _before_ calling find_variable() */
       }
     if (!(value = find_variable(name, FALSE, skipping, &newsize)))
       {
@@ -8244,8 +8269,10 @@ DEBUG(D_expand)
     debug_printf_indent("%sresult: %s\n",
       skipping ? "|-----" : "\\_____", yield->s);
     if (tainted)
-      debug_printf_indent("%s     \\__(tainted)\n",
-       skipping ? "|     " : "      ");
+      {
+      debug_printf_indent("%s     \\__", skipping ? "|     " : "      ");
+      debug_print_taint(yield->s);
+      }
     if (skipping)
       debug_printf_indent("\\___skipping: result is not used\n");
     }
@@ -8259,9 +8286,12 @@ DEBUG(D_expand)
       skipping ? UTF8_VERT_RIGHT : UTF8_UP_RIGHT,
       yield->s);
     if (tainted)
-      debug_printf_indent("%s(tainted)\n",
+      {
+      debug_printf_indent("%s",
        skipping
        ? UTF8_VERT "             " : "           " UTF8_UP_RIGHT UTF8_HORIZ UTF8_HORIZ);
+      debug_print_taint(yield->s);
+      }
     if (skipping)
       debug_printf_indent(UTF8_UP_RIGHT UTF8_HORIZ UTF8_HORIZ UTF8_HORIZ
        "skipping: result is not used\n");
@@ -8288,6 +8318,7 @@ that is a bad idea, because expand_string_message is in dynamic store. */
 EXPAND_FAILED:
 if (left) *left = s;
 DEBUG(D_expand)
+  {
   DEBUG(D_noutf8)
     {
     debug_printf_indent("|failed to expand: %s\n", string);
@@ -8307,6 +8338,7 @@ DEBUG(D_expand)
     if (f.expand_string_forcedfail)
       debug_printf_indent(UTF8_UP_RIGHT "failure was forced\n");
     }
+  }
 if (resetok_p && !resetok) *resetok_p = FALSE;
 expand_level--;
 return NULL;
index 887bc8bc15b455af95826776853bc556be0a0d7f..629bbf5363fea923be392ac9770694edbe59ebb3 100644 (file)
@@ -498,7 +498,7 @@ for (;;)
 
     /* Build a condition block from the specific word. */
 
-    c = store_get(sizeof(condition_block), FALSE);
+    c = store_get(sizeof(condition_block), GET_UNTAINTED);
     c->left.u = c->right.u = NULL;
     c->testfor = testfor;
     testfor = TRUE;
@@ -528,7 +528,7 @@ for (;;)
           }
         ptr = nextitem(ptr, buffer, sizeof(buffer), TRUE);
         if (*error_pointer) break;
-        aa = store_get(sizeof(string_item), FALSE);
+        aa = store_get(sizeof(string_item), GET_UNTAINTED);
         aa->text = string_copy(buffer);
         aa->next = c->left.a;
         c->left.a = aa;
@@ -684,7 +684,7 @@ for (;;)
 
     else if (Ustrcmp(buffer, "and") == 0)
       {
-      condition_block *andc = store_get(sizeof(condition_block), FALSE);
+      condition_block * andc = store_get(sizeof(condition_block), GET_UNTAINTED);
       andc->parent = current_parent;
       andc->type = cond_and;
       andc->testfor = TRUE;
@@ -702,8 +702,8 @@ for (;;)
 
     else if (Ustrcmp(buffer, "or") == 0)
       {
-      condition_block *orc = store_get(sizeof(condition_block), FALSE);
-      condition_block *or_parent = NULL;
+      condition_block * orc = store_get(sizeof(condition_block), GET_UNTAINTED);
+      condition_block * or_parent = NULL;
 
       if (current_parent)
         {
@@ -860,6 +860,8 @@ terminated by white space, but there are two exceptions, which are the "if" and
 as brackets are allowed in conditions and users will expect not to require
 white space here. */
 
+*buffer = '\0';        /* compiler quietening */
+
 if (Ustrncmp(ptr, "if(", 3) == 0)
   {
   Ustrcpy(buffer, US"if");
@@ -1019,9 +1021,10 @@ switch (command)
     FALSE for logging commands, and it doesn't matter for testprint, as
     that doesn't change the "delivered" status. */
 
-    if (*error_pointer) yield = FALSE; else
+    if (*error_pointer) yield = FALSE;
+    else
       {
-      new = store_get(sizeof(filter_cmd) + sizeof(union argtypes), FALSE);
+      new = store_get(sizeof(filter_cmd) + sizeof(union argtypes), GET_UNTAINTED);
       new->next = NULL;
       **lastcmdptr = new;
       *lastcmdptr = &(new->next);
@@ -1105,12 +1108,12 @@ switch (command)
   /* Finish has no arguments; fmsg defaults to NULL */
 
   case finish_command:
-  new = store_get(sizeof(filter_cmd), FALSE);
+  new = store_get(sizeof(filter_cmd), GET_UNTAINTED);
   new->next = NULL;
   **lastcmdptr = new;
   *lastcmdptr = &(new->next);
   new->command = command;
-  new->seen = seen_force? seen_value : FALSE;
+  new->seen = seen_force ? seen_value : FALSE;
   new->args[0].u = fmsg;
   break;
 
@@ -1129,7 +1132,7 @@ switch (command)
 
   /* Set up the command block for if */
 
-  new = store_get(sizeof(filter_cmd) + 4 * sizeof(union argtypes), FALSE);
+  new = store_get(sizeof(filter_cmd) + 4 * sizeof(union argtypes), GET_UNTAINTED);
   new->next = NULL;
   **lastcmdptr = new;
   *lastcmdptr = &new->next;
@@ -1157,7 +1160,7 @@ switch (command)
     while (had_else_endif == had_elif)
       {
       filter_cmd *newnew =
-        store_get(sizeof(filter_cmd) + 4 * sizeof(union argtypes), FALSE);
+        store_get(sizeof(filter_cmd) + 4 * sizeof(union argtypes), GET_UNTAINTED);
       new->args[2].f = newnew;
       new = newnew;
       new->next = NULL;
@@ -1210,10 +1213,10 @@ switch (command)
 
   case mail_command:
   case vacation_command:
-  new = store_get(sizeof(filter_cmd) + mailargs_total * sizeof(union argtypes), FALSE);
+  new = store_get(sizeof(filter_cmd) + mailargs_total * sizeof(union argtypes), GET_UNTAINTED);
   new->next = NULL;
   new->command = command;
-  new->seen = seen_force? seen_value : FALSE;
+  new->seen = seen_force ? seen_value : FALSE;
   new->noerror = noerror_force;
   for (i = 0; i < mailargs_total; i++) new->args[i].u = NULL;
 
@@ -1892,7 +1895,7 @@ while (commands)
        if (expand_nmax >= 0 || filter_thisaddress != NULL)
          {
          int ecount = expand_nmax >= 0 ? expand_nmax : -1;
-         uschar **ss = store_get(sizeof(uschar *) * (ecount + 3), FALSE);
+         uschar ** ss = store_get(sizeof(uschar *) * (ecount + 3), GET_UNTAINTED);
 
          addr->pipe_expandn = ss;
          if (!filter_thisaddress) filter_thisaddress = US"";
@@ -2304,7 +2307,7 @@ while (commands)
          addr->next = *generated;
          *generated = addr;
 
-         addr->reply = store_get(sizeof(reply_item), FALSE);
+         addr->reply = store_get(sizeof(reply_item), GET_UNTAINTED);
          addr->reply->from = NULL;
          addr->reply->to = string_copy(to);
          addr->reply->file_expand =
index 621ca76e9df7a3d32ef3b31be4c351e2a40726b2..125e9c87906bfd58d450cc8601c5cc2eb730191e 100644 (file)
@@ -114,7 +114,7 @@ if (body_len >= message_body_visible)
   int above = message_body_visible - below;
   if (above > 0)
     {
-    uschar *temp = store_get(below, TRUE);
+    uschar * temp = store_get(below, GET_UNTAINTED);
     memcpy(temp, message_body_end, below);
     memmove(message_body_end, s+1, above);
     memcpy(message_body_end + above, temp, below);
@@ -180,7 +180,7 @@ if (fstat(fd, &statbuf) != 0)
   return FALSE;
   }
 
-filebuf = store_get(statbuf.st_size + 1, is_tainted(filename));
+filebuf = store_get(statbuf.st_size + 1, filename);
 rc = read(fd, filebuf, statbuf.st_size);
 (void)close(fd);
 
index e4d9b1a58d93f0d0f6278b47e429ffc60d350de5..43840d4f668917e23af325567a6bfdc6f4190829 100644 (file)
@@ -98,6 +98,7 @@ extern int     tlsa_lookup(const host_item *, dns_answer *, BOOL);
 
 extern acl_block *acl_read(uschar *(*)(void), uschar **);
 extern int     acl_check(int, uschar *, uschar *, uschar **, uschar **);
+extern uschar *acl_current_verb(void);
 extern int     acl_eval(int, uschar *, uschar **, uschar **);
 
 extern tree_node *acl_var_create(uschar *);
@@ -131,6 +132,7 @@ extern int     auth_read_input(const uschar *);
 extern gstring * auth_show_supported(gstring *);
 extern uschar *auth_xtextencode(uschar *, int);
 extern int     auth_xtextdecode(uschar *, uschar **);
+extern uschar *authenticator_current_name(void);
 
 #ifdef EXPERIMENTAL_ARC
 extern gstring *authres_arc(gstring *);
@@ -147,7 +149,7 @@ extern gstring *authres_spf(gstring *);
 #endif
 
 extern uschar *b64encode(const uschar *, int);
-extern uschar *b64encode_taint(const uschar *, int, BOOL);
+extern uschar *b64encode_taint(const uschar *, int, const void *);
 extern int     b64decode(const uschar *, uschar **);
 extern int     bdat_getc(unsigned);
 extern uschar *bdat_getbuf(unsigned *);
@@ -465,6 +467,7 @@ extern BOOL    route_find_expanded_user(uschar *, uschar *, uschar *,
 extern void    route_init(void);
 extern gstring * route_show_supported(gstring *);
 extern void    route_tidyup(void);
+extern uschar *router_current_name(void);
 
 extern uschar *search_args(int, uschar *, uschar *, uschar **, const uschar *);
 extern uschar *search_find(void *, const uschar *, uschar *, int,
@@ -602,9 +605,10 @@ extern uschar *tod_stamp(int);
 
 extern BOOL    transport_check_waiting(const uschar *, const uschar *, int, uschar *,
                  oicf, void*);
-extern void    transport_init(void);
+extern uschar *transport_current_name(void);
 extern void    transport_do_pass_socket(const uschar *, const uschar *,
                 const uschar *, uschar *, int);
+extern void    transport_init(void);
 extern BOOL    transport_pass_socket(const uschar *, const uschar *, const uschar *, uschar *, int
 #ifdef EXPERIMENTAL_ESMTP_LIMITS
                        , unsigned, unsigned, unsigned
@@ -678,6 +682,18 @@ return is_tainted_fn(p);
 #endif
 }
 
+static inline BOOL
+is_incompatible(const void * old, const void * new)
+{
+#if defined(COMPILE_UTILITY) || defined(MACRO_PREDEF) || defined(EM_VERSION_C)
+return FALSE;
+
+#else
+extern BOOL is_incompatible_fn(const void *, const void *);
+return is_incompatible_fn(old, new);
+#endif
+}
+
 /******************************************************************************/
 /* String functions */
 static inline uschar * __Ustrcat(uschar * dst, const uschar * src, const char * func, int line)
@@ -770,32 +786,32 @@ The result is explicitly nul-terminated.
 
 static inline uschar *
 string_copyn_taint_trc(const uschar * s, unsigned len,
-       BOOL tainted, const char * func, int line)
+       const void * proto_mem, const char * func, int line)
 {
-uschar * ss = store_get_3(len + 1, tainted, func, line);
+uschar * ss = store_get_3(len + 1, proto_mem, func, line);
 memcpy(ss, s, len);
 ss[len] = '\0';
 return ss;
 }
 
 static inline uschar *
-string_copy_taint_trc(const uschar * s, BOOL tainted, const char * func, int line)
-{ return string_copyn_taint_trc(s, Ustrlen(s), tainted, func, line); }
+string_copy_taint_trc(const uschar * s, const void * proto_mem, const char * func, int line)
+{ return string_copyn_taint_trc(s, Ustrlen(s), proto_mem, func, line); }
 
 static inline uschar *
 string_copyn_trc(const uschar * s, unsigned len, const char * func, int line)
-{ return string_copyn_taint_trc(s, len, is_tainted(s), func, line); }
+{ return string_copyn_taint_trc(s, len, s, func, line); }
 static inline uschar *
 string_copy_trc(const uschar * s, const char * func, int line)
-{ return string_copy_taint_trc(s, is_tainted(s), func, line); }
+{ return string_copy_taint_trc(s, s, func, line); }
 
 
 /* String-copy functions explicitly setting the taint status */
 
-#define string_copyn_taint(s, len, tainted) \
-       string_copyn_taint_trc((s), (len), (tainted), __FUNCTION__, __LINE__)
-#define string_copy_taint(s, tainted) \
-       string_copy_taint_trc((s), (tainted), __FUNCTION__, __LINE__)
+#define string_copyn_taint(s, len, proto_mem) \
+       string_copyn_taint_trc((s), (len), (proto_mem), __FUNCTION__, __LINE__)
+#define string_copy_taint(s, proto_mem) \
+       string_copy_taint_trc((s), (proto_mem), __FUNCTION__, __LINE__)
 
 /* Simple string-copy functions maintaining the taint */
 
@@ -817,7 +833,7 @@ Returns:  copy of string in new store, with letters lowercased
 static inline uschar *
 string_copylc(const uschar * s)
 {
-uschar * ss = store_get(Ustrlen(s) + 1, is_tainted(s));
+uschar * ss = store_get(Ustrlen(s) + 1, s);
 uschar * p = ss;
 while (*s) *p++ = tolower(*s++);
 *p = 0;
@@ -843,8 +859,8 @@ Returns:    copy of string in new store, with letters lowercased
 static inline uschar *
 string_copynlc(uschar * s, int n)
 {
-uschar *ss = store_get(n + 1, is_tainted(s));
-uschar *p = ss;
+uschar * ss = store_get(n + 1, s);
+uschar * p = ss;
 while (n-- > 0) *p++ = tolower(*s++);
 *p = 0;
 return ss;
@@ -870,7 +886,7 @@ int len = Ustrlen(s) + 1;
 uschar *ss;
 
 store_pool = POOL_PERM;
-ss = store_get(len, force_taint || is_tainted(s));
+ss = store_get(len, force_taint ? GET_TAINTED : s);
 memcpy(ss, s, len);
 store_pool = old_pool;
 return ss;
@@ -898,13 +914,13 @@ va_end(ap);
 
 /* Create a growable-string with some preassigned space */
 
-#define string_get_tainted(size, tainted) \
-       string_get_tainted_trc((size), (tainted), __FUNCTION__, __LINE__)
+#define string_get_tainted(size, proto_mem) \
+       string_get_tainted_trc((size), (proto_mem), __FUNCTION__, __LINE__)
 
 static inline gstring *
-string_get_tainted_trc(unsigned size, BOOL tainted, const char * func, unsigned line)
+string_get_tainted_trc(unsigned size, const void * proto_mem, const char * func, unsigned line)
 {
-gstring * g = store_get_3(sizeof(gstring) + size, tainted, func, line);
+gstring * g = store_get_3(sizeof(gstring) + size, proto_mem, func, line);
 g->size = size;                /*XXX would be good if we could see the actual alloc size */
 g->ptr = 0;
 g->s = US(g + 1);
@@ -917,7 +933,7 @@ return g;
 static inline gstring *
 string_get_trc(unsigned size, const char * func, unsigned line)
 {
-return string_get_tainted_trc(size, FALSE, func, line);
+return string_get_tainted_trc(size, GET_UNTAINTED, func, line);
 }
 
 /* NUL-terminate the C string in the growable-string, and return it. */
@@ -970,12 +986,13 @@ return g;
 }
 
 
-/* Copy the content of a string to tainted memory */
+/* Copy the content of a string to tainted memory.  The proto_mem arg
+will always be tainted, and suitable as a prototype. */
 
 static inline void
-gstring_rebuffer(gstring * g)
+gstring_rebuffer(gstring * g, const void * proto_mem)
 {
-uschar * s = store_get(g->size, TRUE);
+uschar * s = store_get_3(g->size, proto_mem, __FUNCTION__, __LINE__);
 memcpy(s, g->s, g->ptr);
 g->s = s;
 }
@@ -1052,7 +1069,7 @@ spool_fname(const uschar * purpose, const uschar * subdir, const uschar * fname,
 #ifdef COMPILE_UTILITY         /* version avoiding string-extension */
 int len = Ustrlen(spool_directory) + 1 + Ustrlen(queue_name) + 1 + Ustrlen(purpose) + 1
        + Ustrlen(subdir) + 1 + Ustrlen(fname) + Ustrlen(suffix) + 1;
-uschar * buf = store_get(len, FALSE);
+uschar * buf = store_get(len, GET_UNTAINTED);
 string_format(buf, len, "%s/%s/%s/%s/%s%s",
        spool_directory, queue_name, purpose, subdir, fname, suffix);
 return buf;
index 012c637dd98d6e6f33759548f812a4f301cadf99..c3cccf1f2c42589a9515126108939fa0aa9ed932 100644 (file)
@@ -650,6 +650,7 @@ auth_instance auth_defaults    = {
 uschar *auth_defer_msg         = US"reason not recorded";
 uschar *auth_defer_user_msg    = US"";
 const uschar *auth_vars[AUTH_VARS];
+uschar *authenticator_name     = NULL;
 int     auto_thaw              = 0;
 #ifdef WITH_CONTENT_SCAN
 int     av_failed              = FALSE;        /* boolean but accessed as vtype_int*/
@@ -894,6 +895,8 @@ uschar *dnslist_text           = NULL;
 uschar *dnslist_value          = NULL;
 tree_node *domainlist_anchor   = NULL;
 int     domainlist_count       = 0;
+const uschar *driver_srcfile   = NULL;
+int     driver_srcline        = 0;
 uschar *dsn_from               = US DEFAULT_DSN_FROM;
 unsigned int dtrigger_selector = 0;
 
index 02fcc9f3394a6e6a32f84dec29b6be00f14f1e18..f447b0096694d69dcbfb7d32840b8aebe10132b5 100644 (file)
@@ -364,6 +364,7 @@ extern uschar *authenticated_fail_id;  /* ID that failed authentication */
 extern uschar *authenticated_id;       /* ID that was authenticated */
 extern uschar *authenticated_sender;   /* From AUTH on MAIL */
 extern BOOL    authentication_failed;  /* TRUE if AUTH was tried and failed */
+extern uschar *authenticator_name;     /* for debug and error messages */
 extern uschar *auth_advertise_hosts;   /* Only advertise to these */
 extern auth_info auths_available[];    /* Vector of available auth mechanisms */
 extern auth_instance *auths;           /* Chain of instantiated auths */
@@ -573,6 +574,8 @@ extern int     domainlist_count;       /* Number defined */
 
 /* This option is now a no-opt, retained for compatibility */
 extern BOOL    drop_cr;                /* For broken local MUAs */
+extern const uschar *driver_srcfile;   /* For debug & errors */
+extern int     driver_srcline;        /* For debug & errors */
 
 extern unsigned int dtrigger_selector; /* when to start debug */
 
index c50c49aadb50c0f651a4c4cd79bb609a15f32c68..b5323b69c2496f21dc64e48a63b9262ad8369e96 100644 (file)
@@ -116,7 +116,7 @@ void
 exim_sha_finish(hctx * h, blob * b)
 {
 /* Hashing is sufficient to purify any tainted input */
-b->data = store_get(b->len = h->hashlen, FALSE);
+b->data = store_get(b->len = h->hashlen, GET_UNTAINTED);
 
 # if OPENSSL_VERSION_NUMBER < 0x30000000L
 switch (h->method)
@@ -179,7 +179,7 @@ gnutls_hash(h->sha, data, len);
 void
 exim_sha_finish(hctx * h, blob * b)
 {
-b->data = store_get(b->len = h->hashlen, FALSE);
+b->data = store_get(b->len = h->hashlen, GET_UNTAINTED);
 gnutls_hash_output(h->sha, b->data);
 }
 
@@ -216,7 +216,7 @@ gcry_md_write(h->sha, data, len);
 void
 exim_sha_finish(hctx * h, blob * b)
 {
-b->data = store_get(b->len = h->hashlen, FALSE);
+b->data = store_get(b->len = h->hashlen, GET_UNTAINTED);
 memcpy(b->data, gcry_md_read(h->sha, 0), h->hashlen);
 }
 
@@ -254,7 +254,7 @@ switch (h->method)
 void
 exim_sha_finish(hctx * h, blob * b)
 {
-b->data = store_get(b->len = h->hashlen, FALSE);
+b->data = store_get(b->len = h->hashlen, GET_INTAINTED);
 switch (h->method)
   {
   case HASH_SHA1:   sha1_finish(h->u.sha1, b->data); break;
@@ -492,7 +492,7 @@ native_sha1_mid(&h->sha1, US data); /* implicit size always 64 */
 void
 exim_sha_finish(hctx * h, blob * b)
 {
-b->data = store_get(b->len = h->hashlen, FALSE);
+b->data = store_get(b->len = h->hashlen, GET_UNTAINTED);
 
 native_sha1_end(&h->sha1, NULL, 0, b->data);
 }
index 9bd376633c5f4b8bc2751224073119b4549be5ec..df84e2a538221215e1593906b7c8a5607d52826b 100644 (file)
@@ -102,7 +102,7 @@ gstring gs;
 
 if (!header_last) return NULL;
 
-gs.s = buf = store_get(HEADER_ADD_BUFFER_SIZE, FALSE);
+gs.s = buf = store_get(HEADER_ADD_BUFFER_SIZE, GET_UNTAINTED);
 gs.size = HEADER_ADD_BUFFER_SIZE;
 gs.ptr = 0;
 
@@ -182,7 +182,7 @@ for (p = q = gs.s; *p; p = q)
     if (*(++q) != ' ' && *q != '\t') break;
     }
 
-  new = store_get(sizeof(header_line), FALSE);
+  new = store_get(sizeof(header_line), GET_UNTAINTED);
   new->text = string_copyn(p, q - p);
   new->slen = q - p;
   new->type = type;
index 02d2da3621aa1e8c4b2d3187b553f7fdef1641be..e99e6cebab1fdd421d57bb573a73abf7673238f7 100644 (file)
@@ -197,9 +197,9 @@ if ((ipa = string_is_ip_address(lname, NULL)) != 0)
      ||  ipa == 6 && af == AF_INET6)
     {
     int x[4];
-    yield = store_get(sizeof(struct hostent), FALSE);
-    alist = store_get(2 * sizeof(char *), FALSE);
-    adds  = store_get(alen, FALSE);
+    yield = store_get(sizeof(struct hostent), GET_UNTAINTED);
+    alist = store_get(2 * sizeof(char *), GET_UNTAINTED);
+    adds  = store_get(alen, GET_UNTAINTED);
     yield->h_name = CS name;
     yield->h_aliases = NULL;
     yield->h_addrtype = af;
@@ -251,9 +251,9 @@ else
        rr = dns_next_rr(dnsa, &dnss, RESET_NEXT)) if (rr->type == type)
     count++;
 
-  yield = store_get(sizeof(struct hostent), FALSE);
-  alist = store_get((count + 1) * sizeof(char *), FALSE);
-  adds  = store_get(count *alen, FALSE);
+  yield = store_get(sizeof(struct hostent), GET_UNTAINTED);
+  alist = store_get((count + 1) * sizeof(char *), GET_UNTAINTED);
+  adds  = store_get(count *alen, GET_UNTAINTED);
 
   yield->h_name = CS name;
   yield->h_aliases = NULL;
@@ -328,12 +328,12 @@ while ((name = string_nextinlist(&list, &sep, NULL, 0)))
     continue;
     }
 
-  h = store_get(sizeof(host_item), FALSE);
+  h = store_get(sizeof(host_item), GET_UNTAINTED);
   h->name = name;
   h->address = NULL;
   h->port = PORT_NONE;
   h->mx = fake_mx;
-  h->sort_key = randomize? (-fake_mx)*1000 + random_number(1000) : 0;
+  h->sort_key = randomize ? (-fake_mx)*1000 + random_number(1000) : 0;
   h->status = hstatus_unknown;
   h->why = hwhy_unknown;
   h->last_try = 0;
@@ -732,7 +732,6 @@ host_build_ifacelist(const uschar *list, uschar *name)
 int sep = 0;
 uschar *s;
 ip_address_item * yield = NULL, * last = NULL, * next;
-BOOL taint = is_tainted(list);
 
 while ((s = string_nextinlist(&list, &sep, NULL, 0)))
   {
@@ -751,7 +750,7 @@ while ((s = string_nextinlist(&list, &sep, NULL, 0)))
   address above. The field in the ip_address_item is large enough to hold an
   IPv6 address. */
 
-  next = store_get(sizeof(ip_address_item), taint);
+  next = store_get(sizeof(ip_address_item), list);
   next->next = NULL;
   Ustrcpy(next->address, s);
   next->port = port;
@@ -949,7 +948,7 @@ else
 
 /* If there is no buffer, put the string into some new store. */
 
-if (!buffer) buffer = store_get(46, FALSE);
+if (!buffer) buffer = store_get(46, GET_UNTAINTED);
 
 /* Callers of this function with a non-NULL buffer must ensure that it is
 large enough to hold an IPv6 address, namely, at least 46 bytes. That's what
@@ -1587,7 +1586,7 @@ Put it in permanent memory. */
 
     for (uschar ** aliases = USS hosts->h_aliases; *aliases; aliases++) count++;
     store_pool = POOL_PERM;
-    ptr = sender_host_aliases = store_get(count * sizeof(uschar *), FALSE);
+    ptr = sender_host_aliases = store_get(count * sizeof(uschar *), GET_UNTAINTED);
     store_pool = POOL_TAINT_PERM;
 
     for (uschar ** aliases = USS hosts->h_aliases; *aliases; aliases++)
@@ -1709,7 +1708,7 @@ while ((ordername = string_nextinlist(&list, &sep, NULL, 0)))
       /* Get store for the list of aliases. For compatibility with
       gethostbyaddr, we make an empty list if there are none. */
 
-      aptr = sender_host_aliases = store_get(count * sizeof(uschar *), FALSE);
+      aptr = sender_host_aliases = store_get(count * sizeof(uschar *), GET_UNTAINTED);
 
       /* Re-scan and extract the names */
 
@@ -1717,7 +1716,7 @@ while ((ordername = string_nextinlist(&list, &sep, NULL, 0)))
            rr;
            rr = dns_next_rr(dnsa, &dnss, RESET_NEXT)) if (rr->type == T_PTR)
         {
-        uschar * s = store_get(ssize, TRUE);   /* names are tainted */
+        uschar * s = store_get(ssize, GET_TAINTED);    /* names are tainted */
 
         /* If an overlong response was received, the data will have been
         truncated and dn_expand may fail. */
@@ -2119,7 +2118,7 @@ for (int i = 1; i <= times;
 
     else
       {
-      host_item *next = store_get(sizeof(host_item), FALSE);
+      host_item *next = store_get(sizeof(host_item), GET_UNTAINTED);
       next->name = host->name;
 #ifndef DISABLE_TLS
       next->certname = host->certname;
@@ -2456,7 +2455,7 @@ for (; i >= 0; i--)
        /* Not a duplicate */
 
        new_sort_key = host->mx * 1000 + random_number(500) + randoffset;
-       next = store_get(sizeof(host_item), FALSE);
+       next = store_get(sizeof(host_item), GET_UNTAINTED);
 
        /* New address goes first: insert the new block after the first one
        (so as not to disturb the original pointer) but put the new address
@@ -2863,7 +2862,7 @@ for (dns_record * rr = dns_next_rr(dnsa, &dnss, RESET_ANSWERS);
   /* Make a new host item and seek the correct insertion place */
     {
     int sort_key = precedence * 1000 + weight;
-    host_item *next = store_get(sizeof(host_item), FALSE);
+    host_item * next = store_get(sizeof(host_item), GET_UNTAINTED);
     next->name = string_copy_dnsdomain(data);
     next->address = NULL;
     next->port = port;
index 076fd6aa4ed0858af8172dd8aaf0a823445dbf26..375a8764234b6388d6b1056030781af166096a9f 100644 (file)
@@ -40,8 +40,8 @@ ABI is changed in a non backward compatible way. The minor number is increased
 each time a new feature is added (in a way that doesn't break backward
 compatibility). */
 
-#define LOCAL_SCAN_ABI_VERSION_MAJOR 5
-#define LOCAL_SCAN_ABI_VERSION_MINOR 1
+#define LOCAL_SCAN_ABI_VERSION_MAJOR 6
+#define LOCAL_SCAN_ABI_VERSION_MINOR 0
 #define LOCAL_SCAN_ABI_VERSION \
   LOCAL_SCAN_ABI_VERSION_MAJOR.LOCAL_SCAN_ABI_VERSION_MINOR
 
@@ -208,12 +208,12 @@ extern void    smtp_vprintf(const char *, BOOL, va_list);
        string_sprintf_trc(fmt, US __FUNCTION__, __LINE__, __VA_ARGS__)
 extern uschar *string_sprintf_trc(const char *, const uschar *, unsigned, ...) ALMOST_PRINTF(1,4);
 
-#define store_get(size, tainted) \
-       store_get_3(size, tainted, __FUNCTION__, __LINE__)
-extern void   *store_get_3(int, BOOL, const char *, int)       ALLOC ALLOC_SIZE(1) WARN_UNUSED_RESULT;
-#define store_get_perm(size, tainted) \
-       store_get_perm_3(size, tainted, __FUNCTION__, __LINE__)
-extern void   *store_get_perm_3(int, BOOL, const char *, int)  ALLOC ALLOC_SIZE(1) WARN_UNUSED_RESULT;
+#define store_get(size, proto_mem) \
+       store_get_3((size), (proto_mem), __FUNCTION__, __LINE__)
+extern void   *store_get_3(int, const void *, const char *, int)       ALLOC ALLOC_SIZE(1) WARN_UNUSED_RESULT;
+#define store_get_perm(size, proto_mem) \
+       store_get_perm_3((size), (proto_mem), __FUNCTION__, __LINE__)
+extern void   *store_get_perm_3(int, const void *, const char *, int)  ALLOC ALLOC_SIZE(1) WARN_UNUSED_RESULT;
 
 
 #if defined(LOCAL_SCAN) || defined(DLFUNC_IMPL)
@@ -230,7 +230,7 @@ with the original name. */
 
 extern uschar * string_copy_function(const uschar *);
 extern uschar * string_copyn_function(const uschar *, int n);
-extern uschar * string_copy_taint_function(const uschar *, BOOL tainted);
+extern uschar * string_copy_taint_function(const uschar *, const void * proto_mem);
 extern pid_t    child_open_exim_function(int *, const uschar *);
 extern pid_t    child_open_exim2_function(int *, uschar *, uschar *, const uschar *);
 extern pid_t    child_open_function(uschar **, uschar **, int, int *, int *, BOOL, const uschar *);
index 7a73b154a303ebf0884cf659885314983a7cefbc..6126b205858dadf0eb45c6aa421a60c52034e2be 100644 (file)
@@ -288,8 +288,11 @@ if (fd < 0 && errno == ENOENT)
   uschar *lastslash = Ustrrchr(name, '/');
   *lastslash = 0;
   created = directory_make(NULL, name, LOG_DIRECTORY_MODE, FALSE);
-  DEBUG(D_any) debug_printf("%s log directory %s\n",
-    created ? "created" : "failed to create", name);
+  DEBUG(D_any)
+    if (created)
+      debug_printf("created log directory %s\n", name);
+    else
+      debug_printf("failed to create log directory %s: %s\n", name, strerror(errno));
   *lastslash = '/';
   if (created) fd = Uopen(name, flags, LOG_MODE);
   }
@@ -452,7 +455,7 @@ return fd;
 it does not exist. This may be called recursively on failure, in order to open
 the panic log.
 
-The directory is in the static variable file_path. This is static so that it
+The directory is in the static variable file_path. This is static so that
 the work of sorting out the path is done just once per Exim process.
 
 Exim is normally configured to avoid running as root wherever possible, the log
@@ -512,6 +515,10 @@ switch (type)
     Ustrcpy(debuglog_name, buffer);
     if (tag)
       {
+      if (is_tainted(tag))
+       die(US"exim: tainted tag for debug log filename",
+             US"Logging failure; please try later");
+
       /* this won't change the offset of the datestamp */
       ok2 = string_format(buffer, sizeof(buffer), "%s%s",
         debuglog_name, tag);
@@ -720,10 +727,17 @@ while ((t = string_nextinlist(&tt, &sep, log_buffer, LOG_BUFFER_SIZE)))
 }
 
 
+/* Close mainlog, unless we do not see a chance to open the file mainlog later
+again.  This will happen if we log from a transport process (which has dropped
+privs); something we traditionally avoid, but the introduction of taint-tracking
+and resulting detection of errors is makinng harder. */
+
 void
 mainlog_close(void)
 {
-if (mainlogfd < 0) return;
+if (mainlogfd < 0
+   || !(geteuid() == 0 || geteuid() == exim_uid))
+  return;
 (void)close(mainlogfd);
 mainlogfd = -1;
 mainlog_inode = 0;
index d8364dbb9970c278db9e8b1559491ed1985b1b44..af7f59a06811e2d123df33636bf4412b8b34da3b 100644 (file)
@@ -3,7 +3,7 @@
 *************************************************/
 
 /* Copyright (c) University of Cambridge 1995 - 2015 */
-/* Copyright (c) The Exim Maintainers 2020 */
+/* Copyright (c) The Exim Maintainers 2022 */
 /* See the file NOTICE for conditions of use and distribution. */
 
 
@@ -42,16 +42,19 @@ typedef struct lookup_info {
   void (*tidy)(void);             /* tidy function */
   uschar *(*quote)(               /* quoting function */
     uschar *,                     /* string to quote */
-    uschar *);                    /* additional data from quote name */
+    uschar *,                     /* additional data from quote name */
+    unsigned);                   /* lookup type index */
   gstring * (*version_report)(    /* diagnostic function */
-    gstring *);                   /* true: stdout.  false: debug */
+    gstring *);                   /* string to appand to */
 } lookup_info;
 
 /* This magic number is used by the following lookup_module_info structure
    for checking API compatibility. It used to be equivalent to the string"LMM3" */
-#define LOOKUP_MODULE_INFO_MAGIC 0x4c4d4933
+#define LOOKUP_MODULE_INFO_MAGIC 0x4c4d4935
 /* Version 2 adds: version_report */
 /* Version 3 change: non/cache becomes TTL in seconds */
+/* Version 4 add: index on quoting function */
+/* Version 5 change: version report now adds to a gstring */
 
 typedef struct lookup_module_info {
   uint magic;
index 7b9c2cdfd2107b211405a42885d702c580191818..5f8498809fe0857660081900f8eba70e108f782e 100644 (file)
@@ -178,7 +178,7 @@ if (statbuf.st_size < CDB_HASH_TABLE)
   }
 
 /* Having got a file open we need the structure to put things in */
-cdbp = store_get(sizeof(struct cdb_state), FALSE);
+cdbp = store_get(sizeof(struct cdb_state), GET_UNTAINTED);
 /* store_get() does not return if memory was not available... */
 /* preload the structure.... */
 cdbp->fileno = fileno;
@@ -213,7 +213,7 @@ DEBUG(D_lookup) debug_printf_indent("cdb mmap failed - %d\n", errno);
 /* get a buffer to stash the basic offsets in - this should speed
 things up a lot - especially on multiple lookups */
 
-cdbp->cdb_offsets = store_get(CDB_HASH_TABLE, FALSE);
+cdbp->cdb_offsets = store_get(CDB_HASH_TABLE, GET_UNTAINTED);
 
 /* now fill the buffer up... */
 
@@ -343,7 +343,7 @@ if (cdbp->cdb_map != NULL)
           /* ... and the returned result.  Assume it is not
           tainted, lacking any way of telling.  */
 
-          *result = store_get(item_dat_len + 1, FALSE);
+          *result = store_get(item_dat_len + 1, GET_UNTAINTED);
           memcpy(*result, item_ptr, item_dat_len);
           (*result)[item_dat_len] = 0;
           return OK;
@@ -387,7 +387,7 @@ for (int loop = 0; (loop < hash_offlen); ++loop)
     if (item_key_len == key_len)
       {                                        /* finally check if key matches */
       rmark reset_point = store_mark();
-      uschar * item_key = store_get(key_len, TRUE); /* keys liable to be tainted */
+      uschar * item_key = store_get(key_len, GET_TAINTED); /* keys liable to be tainted */
 
       if (cdb_bread(cdbp->fileno, item_key, key_len) == -1) return DEFER;
       if (Ustrncmp(keystring, item_key, key_len) == 0)
@@ -401,7 +401,7 @@ for (int loop = 0; (loop < hash_offlen); ++loop)
         /* then we build a new result string.  We know we have enough
         memory so disable Coverity errors about the tainted item_dat_ken */
 
-        *result = store_get(item_dat_len + 1, FALSE);
+        *result = store_get(item_dat_len + 1, GET_UNTAINTED);
         /* coverity[tainted_data] */
         if (cdb_bread(cdbp->fileno, *result, item_dat_len) == -1)
          return DEFER;
index c53e5555446ae342867a911751ec9f64bd45caf4..c607f7b9c50cb6be3520c48904169c6598abfd06 100644 (file)
@@ -149,7 +149,7 @@ int buflen, bufleft, key_item_len, sep = 0;
 or less than, the length of the delimited list passed in + 1. */
 
 buflen = length + 3;
-key_buffer = store_get(buflen, is_tainted(keystring));
+key_buffer = store_get(buflen, keystring);
 
 key_buffer[0] = '\0';
 
index e1692992b85087b93f25788244cacb37ea2081f2..d72623037a4cb9850701341e5c8ead55c48ca700 100644 (file)
@@ -177,7 +177,7 @@ if (cn)
   }
 else
   {
-  cn = store_get(sizeof(ibase_connection), FALSE);
+  cn = store_get(sizeof(ibase_connection), GET_UNTAINTED);
   cn->server = server_copy;
   cn->dbh = NULL;
   cn->transh = NULL;
@@ -252,7 +252,7 @@ if (isc_dsql_allocate_statement(status, &cn->dbh, &stmth))
 
 /* Lacking any information, assume that the data is untainted */
 reset_point = store_mark();
-out_sqlda = store_get(XSQLDA_LENGTH(1), FALSE);
+out_sqlda = store_get(XSQLDA_LENGTH(1), GET_UNTAINTED);
 out_sqlda->version = SQLDA_VERSION1;
 out_sqlda->sqln = 1;
 
@@ -272,7 +272,7 @@ if (isc_dsql_prepare
 /* re-allocate the output structure if there's more than one field */
 if (out_sqlda->sqln < out_sqlda->sqld)
   {
-  XSQLDA *new_sqlda = store_get(XSQLDA_LENGTH(out_sqlda->sqld), FALSE);
+  XSQLDA *new_sqlda = store_get(XSQLDA_LENGTH(out_sqlda->sqld), GET_UNTAINTED);
   if (isc_dsql_describe
       (status, &stmth, out_sqlda->version, new_sqlda))
     {
@@ -294,46 +294,46 @@ for (i = 0, var = out_sqlda->sqlvar; i < out_sqlda->sqld; i++, var++)
   switch (var->sqltype & ~1)
     {
     case SQL_VARYING:
-       var->sqldata = CS store_get(sizeof(char) * var->sqllen + 2, FALSE);
+       var->sqldata = CS store_get(sizeof(char) * var->sqllen + 2, GET_UNTAINTED);
        break;
     case SQL_TEXT:
-       var->sqldata = CS store_get(sizeof(char) * var->sqllen, FALSE);
+       var->sqldata = CS store_get(sizeof(char) * var->sqllen, GET_UNTAINTED);
        break;
     case SQL_SHORT:
-       var->sqldata = CS  store_get(sizeof(short), FALSE);
+       var->sqldata = CS  store_get(sizeof(short), GET_UNTAINTED);
        break;
     case SQL_LONG:
-       var->sqldata = CS  store_get(sizeof(ISC_LONG), FALSE);
+       var->sqldata = CS  store_get(sizeof(ISC_LONG), GET_UNTAINTED);
        break;
 #ifdef SQL_INT64
     case SQL_INT64:
-       var->sqldata = CS  store_get(sizeof(ISC_INT64), FALSE);
+       var->sqldata = CS  store_get(sizeof(ISC_INT64), GET_UNTAINTED);
        break;
 #endif
     case SQL_FLOAT:
-       var->sqldata = CS  store_get(sizeof(float), FALSE);
+       var->sqldata = CS  store_get(sizeof(float), GET_UNTAINTED);
        break;
     case SQL_DOUBLE:
-       var->sqldata = CS  store_get(sizeof(double), FALSE);
+       var->sqldata = CS  store_get(sizeof(double), GET_UNTAINTED);
        break;
 #ifdef SQL_TIMESTAMP
     case SQL_DATE:
-       var->sqldata = CS  store_get(sizeof(ISC_QUAD), FALSE);
+       var->sqldata = CS  store_get(sizeof(ISC_QUAD), GET_UNTAINTED);
        break;
 #else
     case SQL_TIMESTAMP:
-       var->sqldata = CS  store_get(sizeof(ISC_TIMESTAMP), FALSE);
+       var->sqldata = CS  store_get(sizeof(ISC_TIMESTAMP), GET_UNTAINTED);
        break;
     case SQL_TYPE_DATE:
-       var->sqldata = CS  store_get(sizeof(ISC_DATE), FALSE);
+       var->sqldata = CS  store_get(sizeof(ISC_DATE), GET_UNTAINTED);
        break;
     case SQL_TYPE_TIME:
-       var->sqldata = CS  store_get(sizeof(ISC_TIME), FALSE);
+       var->sqldata = CS  store_get(sizeof(ISC_TIME), GET_UNTAINTED);
        break;
   #endif
     }
   if (var->sqltype & 1)
-    var->sqlind = (short *) store_get(sizeof(short), FALSE);
+    var->sqlind = (short *) store_get(sizeof(short), GET_UNTAINTED);
   }
 
 /* finally, we're ready to execute the statement */
@@ -492,51 +492,32 @@ can't quote "on spec".
 Arguments:
   s          the string to be quoted
   opt        additional option text or NULL if none
+  idx       lookup type index
 
 Returns:     the processed string or NULL for a bad option
 */
 
-static uschar *ibase_quote(uschar * s, uschar * opt)
+static uschar *
+ibase_quote(uschar * s, uschar * opt, unsigned idx)
 {
-    register int c;
-    int count = 0;
-    uschar *t = s;
-    uschar *quoted;
-
-    if (opt != NULL)
-        return NULL;            /* No options recognized */
-
-    while ((c = *t++) != 0)
-        if (Ustrchr("\n\t\r\b\'\"\\", c) != NULL)
-            count++;
-
-    if (count == 0)
-        return s;
-    t = quoted = store_get(Ustrlen(s) + count + 1, FALSE);
-
-    while ((c = *s++) != 0) {
-        if (Ustrchr("'", c) != NULL) {
-            *t++ = '\'';
-            *t++ = '\'';
-/*    switch(c)
-      {
-      case '\n': *t++ = 'n';
-      break;
-      case '\t': *t++ = 't';
-      break;
-      case '\r': *t++ = 'r';
-      break;
-      case '\b': *t++ = 'b';
-      break;
-      default:   *t++ = c;
-      break;
-      }*/
-        } else
-            *t++ = c;
-    }
+int c;
+int count = 0;
+uschar * t = s, * quoted;
+
+if (opt)
+  return NULL;            /* No options recognized */
+
+while ((c = *t++))
+  if (c == '\'') count++;
+
+t = quoted = store_get_quoted(Ustrlen(s) + count + 1, s, idx);
+
+while ((c = *s++))
+  if (c == '\'') { *t++ = '\''; *t++ = '\''; }
+  else *t++ = c;
 
-    *t = 0;
-    return quoted;
+*t = 0;
+return quoted;
 }
 
 
index 7f2478b63045a3acf38108b7b47f4cf0b553b8fc..e53ddc21957af65930bb198ca4d486fa99c119d1 100644 (file)
@@ -24,7 +24,7 @@ Assume that the file is trusted, so no tainting */
 static void *
 json_malloc(size_t nbytes)
 {
-void * p = store_get((int)nbytes, FALSE);
+void * p = store_get((int)nbytes, GET_UNTAINTED);
 /* debug_printf("%s %d: %p\n", __FUNCTION__, (int)nbytes, p); */
 return p;
 }
index 4152663586381e2212334a13f91c47d80b916954..6065d2b8e14e4ec9286b665f93a17b439a53c0a5 100644 (file)
@@ -496,7 +496,7 @@ if (!lcp)
 
   /* Now add this connection to the chain of cached connections */
 
-  lcp = store_get(sizeof(LDAP_CONNECTION), FALSE);
+  lcp = store_get(sizeof(LDAP_CONNECTION), GET_UNTAINTED);
   lcp->host = host ? string_copy(host) : NULL;
   lcp->bound = FALSE;
   lcp->user = NULL;
@@ -1405,6 +1405,7 @@ Arguments:
   s          the string to be quoted
   opt        additional option text or NULL if none
              only "dn" is recognized
+  idx       lookup type index
 
 Returns:     the processed string or NULL for a bad option
 */
@@ -1430,18 +1431,15 @@ quote_ldap_dn, respectively. */
 
 
 static uschar *
-eldap_quote(uschar *s, uschar *opt)
+eldap_quote(uschar * s, uschar * opt, unsigned idx)
 {
-register int c;
-int count = 0;
-int len = 0;
+int c, count = 0, len = 0;
 BOOL dn = FALSE;
-uschar *t = s;
-uschar *quoted;
+uschar * t = s, * quoted;
 
 /* Test for a DN quotation. */
 
-if (opt != NULL)
+if (opt)
   {
   if (Ustrcmp(opt, "dn") != 0) return NULL;    /* No others recognized */
   dn = TRUE;
@@ -1454,24 +1452,25 @@ where, for example, < turns into %5C%3C. For simplicity, we just add 5 for each
 possibly escaped character. The really fast way would be just to test for
 non-alphanumerics, but it is probably better to spot a few others that are
 never escaped, because if there are no specials at all, we can avoid copying
-the string. */
+the string.
+XXX No longer true; we always copy, to support quoted-enforcement */
 
-while ((c = *t++) != 0)
+while ((c = *t++))
   {
   len++;
   if (!isalnum(c) && Ustrchr(ALWAYS_LITERAL, c) == NULL) count += 5;
   }
-if (count == 0) return s;
+/*if (count == 0) return s;*/
 
 /* Get sufficient store to hold the quoted string */
 
-t = quoted = store_get(len + count + 1, is_tainted(s));
+t = quoted = store_get_quoted(len + count + 1, s, idx);
 
 /* Handle plain quote_ldap */
 
 if (!dn)
   {
-  while ((c = *s++) != 0)
+  while ((c = *s++))
     {
     if (!isalnum(c))
       {
@@ -1496,7 +1495,7 @@ if (!dn)
 
 else
   {
-  uschar *ss = s + len;
+  uschar * ss = s + len;
 
   /* Find the last char before any trailing spaces */
 
index 5fe86fea24b3a7df2a24d30078f1dca15e2398c4..042229a550a0a201d139b326a7ce7f0d3c5f4893 100644 (file)
@@ -31,7 +31,7 @@ Lmdbstrct * lmdb_p;
 int ret, save_errno;
 const uschar * errstr;
 
-lmdb_p = store_get(sizeof(Lmdbstrct), FALSE);
+lmdb_p = store_get(sizeof(Lmdbstrct), GET_UNTAINTED);
 lmdb_p->txn = NULL;
 
 if ((ret = mdb_env_create(&db_env)))
index 782ad2a5fb1c73642ecb531064ef0f4148b6f060..d874d88cc94cd727aec63a6f35982a81ffb698cd 100644 (file)
@@ -231,7 +231,7 @@ if (!cn)
 
   /* Get store for a new handle, initialize it, and connect to the server */
 
-  mysql_handle = store_get(sizeof(MYSQL), FALSE);
+  mysql_handle = store_get(sizeof(MYSQL), GET_UNTAINTED);
   mysql_init(mysql_handle);
   mysql_options(mysql_handle, MYSQL_READ_DEFAULT_GROUP, CS group);
   if (mysql_real_connect(mysql_handle,
@@ -247,7 +247,7 @@ if (!cn)
 
   /* Add the connection to the cache */
 
-  cn = store_get(sizeof(mysql_connection), FALSE);
+  cn = store_get(sizeof(mysql_connection), GET_UNTAINTED);
   cn->server = server_copy;
   cn->handle = mysql_handle;
   cn->next = mysql_connections;
@@ -413,25 +413,26 @@ can't quote "on spec".
 Arguments:
   s          the string to be quoted
   opt        additional option text or NULL if none
+  idx       lookup type index
 
 Returns:     the processed string or NULL for a bad option
 */
 
 static uschar *
-mysql_quote(uschar * s, uschar * opt)
+mysql_quote(uschar * s, uschar * opt, unsigned idx)
 {
-register int c;
-int count = 0;
-uschar *t = s;
-uschar *quoted;
+int c, count = 0;
+uschar * t = s, * quoted;
 
 if (opt) return NULL;     /* No options recognized */
 
 while ((c = *t++))
   if (Ustrchr("\n\t\r\b\'\"\\", c) != NULL) count++;
 
-if (count == 0) return s;
-t = quoted = store_get(Ustrlen(s) + count + 1, is_tainted(s));
+/* Old code:  if (count == 0) return s;
+Now always allocate and copy, to track the quoted status. */
+
+t = quoted = store_get_quoted(Ustrlen(s) + count + 1, s, idx);
 
 while ((c = *s++))
   {
index dc3735b6bac7fe40846458011ed33d05bef015f0..0892fc4c3dcca017c43a186d40971686ce71cbc1 100644 (file)
@@ -226,25 +226,24 @@ characters. No options are recognized.
 Arguments:
   s          the string to be quoted
   opt        additional option text or NULL if none
+  idx       lookup type index
 
 Returns:     the processed string or NULL for a bad option
 */
 
 static uschar *
-nisplus_quote(uschar *s, uschar *opt)
+nisplus_quote(uschar * s, uschar * opt, unsigned idx)
 {
 int count = 0;
-uschar *quoted;
-uschar *t = s;
+uschar * quoted, * t = s;
 
-if (opt != NULL) return NULL;    /* No options recognized */
+if (opt) return NULL;    /* No options recognized */
 
-while (*t != 0) if (*t++ == '\"') count++;
-if (count == 0) return s;
+while (*t) if (*t++ == '\"') count++;
 
-t = quoted = store_get(Ustrlen(s) + count + 1, is_tainted(s));
+t = quoted = store_get_quoted(Ustrlen(s) + count + 1, s, idx);
 
-while (*s != 0)
+while (*s)
   {
   *t++ = *s;
   if (*s++ == '\"') *t++ = '\"';
index 0429a8f8400439cba9809bc98810247124ef0114..8a6954035faf7e27fc92ba4e3a300f7ff9e998ae 100644 (file)
@@ -306,8 +306,8 @@ if (!cn)
 
   /* Get store for a new connection, initialize it, and connect to the server */
 
-   oracle_handle = store_get(sizeof(struct cda_def), FALSE);
-   hda = store_get(HDA_SIZE, FALSE);
+   oracle_handle = store_get(sizeof(struct cda_def), GET_UNTAINTED);
+   hda = store_get(HDA_SIZE, GET_UNTAINTED);
    memset(hda,'\0',HDA_SIZE);
 
   /*
@@ -330,7 +330,7 @@ if (!cn)
 
   /* Add the connection to the cache */
 
-  cn = store_get(sizeof(oracle_connection), FALSE);
+  cn = store_get(sizeof(oracle_connection), GET_UNTAINTED);
   cn->server = server_copy;
   cn->handle = oracle_handle;
   cn->next = oracle_connections;
@@ -349,7 +349,7 @@ else
 
 /* We have a connection. Open a cursor and run the query */
 
-cda = store_get(sizeof(Cda_Def), FALSE);
+cda = store_get(sizeof(Cda_Def), GET_UNTAINTED);
 
 if (oopen(cda, oracle_handle, (text *)0, -1, -1, (text *)0, -1) != 0)
   {
@@ -370,8 +370,8 @@ if (oparse(cda, (text *)query, (sb4) -1,
 /* Find the number of fields returned and sort out their types. If the number
 is one, we don't add field names to the data. Otherwise we do. */
 
-def = store_get(sizeof(Ora_Define)*MAX_SELECT_LIST_SIZE, FALSE);
-desc = store_get(sizeof(Ora_Describe)*MAX_SELECT_LIST_SIZE, FALSE);
+def = store_get(sizeof(Ora_Define)*MAX_SELECT_LIST_SIZE, GET_UNTAINTED);
+desc = store_get(sizeof(Ora_Describe)*MAX_SELECT_LIST_SIZE, GET_UNTAINTED);
 
 if ((num_fields = describe_define(cda,def,desc)) == -1)
   {
@@ -543,27 +543,25 @@ messages, since that isn't likely to be treated as a pattern of any kind.
 Arguments:
   s          the string to be quoted
   opt        additional option text or NULL if none
+  idx       lookup type index
 
 Returns:     the processed string or NULL for a bad option
 */
 
 static uschar *
-oracle_quote(uschar *s, uschar *opt)
+oracle_quote(uschar * s, uschar * opt, unsigned idx)
 {
-register int c;
-int count = 0;
-uschar *t = s;
-uschar *quoted;
+int c, count = 0;
+uschar * t = s, * quoted;
 
-if (opt != NULL) return NULL;    /* No options are recognized */
+if (opt) return NULL;    /* No options are recognized */
 
-while ((c = *t++) != 0)
+while ((c = *t++))
   if (strchr("\n\t\r\b\'\"\\", c) != NULL) count++;
 
-if (count == 0) return s;
-t = quoted = store_get((int)strlen(s) + count + 1, is_tainted(s));
+t = quoted = store_get_quoted((int)Ustrlen(s) + count + 1, s, idx);
 
-while ((c = *s++) != 0)
+while ((c = *s++))
   {
   if (strchr("\n\t\r\b\'\"\\", c) != NULL)
     {
index c3053430e531d2880385d27e5556c6ede1ee9cb4..dc5fd57502817cda7da1f441b0711b7ba7be0f51 100644 (file)
@@ -262,7 +262,7 @@ if (!cn)
 
   /* Add the connection to the cache */
 
-  cn = store_get(sizeof(pgsql_connection), FALSE);
+  cn = store_get(sizeof(pgsql_connection), GET_UNTAINTED);
   cn->server = server_copy;
   cn->handle = pg_conn;
   cn->next = pgsql_connections;
@@ -414,12 +414,13 @@ Why, I don't know. Seems odd for just string escaping...]
 Arguments:
   s          the string to be quoted
   opt        additional option text or NULL if none
+  idx       lookup type index
 
 Returns:     the processed string or NULL for a bad option
 */
 
 static uschar *
-pgsql_quote(uschar * s, uschar * opt)
+pgsql_quote(uschar * s, uschar * opt, unsigned idx)
 {
 int count = 0, c;
 uschar * t = s, * quoted;
@@ -429,8 +430,7 @@ if (opt) return NULL;     /* No options recognized */
 while ((c = *t++))
   if (Ustrchr("\n\t\r\b\'\"\\", c) != NULL) count++;
 
-if (count == 0) return s;
-t = quoted = store_get(Ustrlen(s) + count + 1, is_tainted(s));
+t = quoted = store_get_quoted(Ustrlen(s) + count + 1, s, idx);
 
 while ((c = *s++))
   {
index 44159455d9448d14bfac9f0453b2841604ee485e..dfde999454d2cdccb24e97528fbb6aac118f36b0 100644 (file)
@@ -150,7 +150,7 @@ that connection cacheing at the framework layer works. */
 static void *
 readsock_open(const uschar * filename, uschar ** errmsg)
 {
-client_conn_ctx * cctx = store_get(sizeof(*cctx), FALSE);
+client_conn_ctx * cctx = store_get(sizeof(*cctx), GET_UNTAINTED);
 cctx->sock = -1;
 cctx->tls_ctx = NULL;
 DEBUG(D_lookup) debug_printf_indent("readsock: allocated context\n");
index 0bc506093f79c6a2ce5016101d5af54803e51718..2ddc99abcf5907a3f349f08318cd75b4a1e9cc30 100644 (file)
@@ -171,7 +171,7 @@ if (!cn)
     }
 
   /* Add the connection to the cache */
-  cn = store_get(sizeof(redis_connection), FALSE);
+  cn = store_get(sizeof(redis_connection), GET_UNTAINTED);
   cn->server = server_copy;
   cn->handle = redis_handle;
   cn->next = redis_connections;
@@ -399,27 +399,25 @@ whitespace into an argument.
 Arguments:
   s          the string to be quoted
   opt        additional option text or NULL if none
+  idx       lookup type index
 
 Returns:     the processed string or NULL for a bad option
 */
 
 static uschar *
-redis_quote(uschar *s, uschar *opt)
+redis_quote(uschar * s, uschar * opt, unsigned idx)
 {
-register int c;
-int count = 0;
-uschar *t = s;
-uschar *quoted;
+int c, count = 0;
+uschar * t = s, * quoted;
 
 if (opt) return NULL;     /* No options recognized */
 
-while ((c = *t++) != 0)
+while ((c = *t++))
   if (isspace(c) || c == '\\') count++;
 
-if (count == 0) return s;
-t = quoted = store_get(Ustrlen(s) + count + 1, is_tainted(s));
+t = quoted = store_get_quoted(Ustrlen(s) + count + 1, s, idx);
 
-while ((c = *s++) != 0)
+while ((c = *s++))
   {
   if (isspace(c) || c == '\\') *t++ = '\\';
   *t++ = c;
index 65e7cffc9e89e5dcb2a51ce7e7b3228d60fe12c0..69c0ac7ba2f56c4251e35a816f44cadc41ca002a 100644 (file)
@@ -126,26 +126,25 @@ for sqlite is the single quote, and it is quoted by doubling.
 Arguments:
   s          the string to be quoted
   opt        additional option text or NULL if none
+  idx       lookup type index
 
 Returns:     the processed string or NULL for a bad option
 */
 
 static uschar *
-sqlite_quote(uschar *s, uschar *opt)
+sqlite_quote(uschar * s, uschar * opt, unsigned idx)
 {
-register int c;
-int count = 0;
-uschar *t = s;
-uschar *quoted;
+int c, count = 0;
+uschar * t = s, * quoted;
 
-if (opt != NULL) return NULL;     /* No options recognized */
+if (opt) return NULL;     /* No options recognized */
 
-while ((c = *t++) != 0) if (c == '\'') count++;
+while ((c = *t++)) if (c == '\'') count++;
+count += t - s;
 
-if (count == 0) return s;
-t = quoted = store_get(Ustrlen(s) + count + 1, is_tainted(s));
+t = quoted = store_get_quoted(count + 1, s, idx);
 
-while ((c = *s++) != 0)
+while ((c = *s++))
   {
   if (c == '\'') *t++ = '\'';
   *t++ = c;
index d9ab3b9dd19658a584da824d4b04f85ec2857b57..289b6467232fa992411ceba46f34175191b1836a 100644 (file)
@@ -934,7 +934,7 @@ badseek:  err = errno;
          drweb_slen = ntohl(drweb_slen);
 
          /* assume tainted, since it is external input */
-         tmpbuf = store_get(drweb_slen, TRUE);
+         tmpbuf = store_get(drweb_slen, GET_TAINTED);
 
          /* read report body */
          if (!recv_len(malware_daemon_ctx.sock, tmpbuf, drweb_slen, tmo))
@@ -1471,9 +1471,9 @@ badseek:  err = errno;
        int subsep = ' ';
 
        /* Local file; so we def want to use_scan_command and don't want to try
-        * passing IP/port combinations */
+       passing IP/port combinations */
        use_scan_command = TRUE;
-       cd = (clamd_address *) store_get(sizeof(clamd_address), FALSE);
+       cd = (clamd_address *) store_get(sizeof(clamd_address), GET_UNTAINTED);
 
        /* extract socket-path part */
        sublist = scanner_options;
@@ -1507,7 +1507,7 @@ badseek:  err = errno;
            continue;
            }
 
-         cd = (clamd_address *) store_get(sizeof(clamd_address), FALSE);
+         cd = (clamd_address *) store_get(sizeof(clamd_address), GET_UNTAINTED);
 
          /* extract host and port part */
          sublist = scanner_options;
index 069d0f672ca5178274cdf8601aa0085aef86ffaf..a1ec5616b975a374862f913fdebbd569b2e4117a 100644 (file)
@@ -432,11 +432,9 @@ match_check_list(const uschar **listptr, int sep, tree_node **anchorptr,
   void *arg, int type, const uschar *name, const uschar **valueptr)
 {
 int yield = OK;
-unsigned int *original_cache_bits = *cache_ptr;
-BOOL include_unknown = FALSE;
-BOOL ignore_unknown = FALSE;
-BOOL include_defer = FALSE;
-BOOL ignore_defer = FALSE;
+unsigned int * original_cache_bits = *cache_ptr;
+BOOL include_unknown = FALSE, ignore_unknown = FALSE,
+      include_defer = FALSE, ignore_defer = FALSE;
 const uschar *list;
 uschar *sss;
 uschar *ot = NULL;
@@ -445,8 +443,8 @@ uschar *ot = NULL;
 
 HDEBUG(D_any)
   {
-  uschar *listname = readconf_find_option(listptr);
-  if (listname[0] != 0) ot = string_sprintf("%s in %s?", name, listname);
+  uschar * listname = readconf_find_option(listptr);
+  if (*listname) ot = string_sprintf("%s in %s?", name, listname);
   }
 
 /* If the list is empty, the answer is no. Skip the debugging output for
@@ -669,7 +667,7 @@ while ((sss = string_nextinlist(&list, &sep, NULL, 0)))
             so we use the permanent store pool */
 
             store_pool = POOL_PERM;
-            p = store_get(sizeof(namedlist_cacheblock), FALSE);
+            p = store_get(sizeof(namedlist_cacheblock), GET_UNTAINTED);
             p->key = string_copy(get_check_key(arg, type));
 
 
index 8f30bcc8a7c4979e22155840bf7a1c69548f3675..ddf923c254b603314242a444da192ccc0220f72d 100644 (file)
@@ -501,7 +501,7 @@ uschar * header = NULL;
 struct mime_boundary_context nested_context;
 
 /* reserve a line buffer to work in.  Assume tainted data. */
-header = store_get(MIME_MAX_HEADER_SIZE+1, TRUE);
+header = store_get(MIME_MAX_HEADER_SIZE+1, GET_TAINTED);
 
 /* Not actually used at the moment, but will be vital to fixing
  * some RFC 2046 nonconformance later... */
index c8755911fc1237fb36b757ea2e2f014502bab9d5..efa0f02e8300d4116fdb9ef03948891d9edfaf5c 100644 (file)
@@ -386,7 +386,7 @@ if (bounce_return_message)
   if (bounce_return_body && message_file)
     {
     BOOL enddot = f.dot_ends && message_file == stdin;
-    uschar * buf = store_get(bounce_return_linesize_limit+2, TRUE);
+    uschar * buf = store_get(bounce_return_linesize_limit+2, GET_TAINTED);
 
     if (firstline) fprintf(fp, "%s", CS firstline);
 
index 2bb5bbef121ffb8f97c12862578f58d35b19c0e6..1b826f3dc1c2164e5d8f8bb6349aaaabded1b346 100644 (file)
@@ -511,7 +511,7 @@ for (struct ifaddrs * ifa = ifalist; ifa; ifa = ifa->ifa_next)
   /* Create a data block for the address, fill in the data, and put it on the
   chain. */
 
-  next = store_get(sizeof(ip_address_item), FALSE);
+  next = store_get(sizeof(ip_address_item), GET_UNTAINTED);
   next->next = NULL;
   next->port = 0;
   (void)host_ntoa(-1, ifa_addr, next->address, NULL);
@@ -746,7 +746,7 @@ for (char * cp = buf; cp < buf + ifc.V_ifc_len; cp += len)
   /* Create a data block for the address, fill in the data, and put it on the
   chain. */
 
-  next = store_get(sizeof(ip_address_item), FALSE);
+  next = store_get(sizeof(ip_address_item), GET_UNTAINTED);
   next->next = NULL;
   next->port = 0;
   (void)host_ntoa(-1, addrp, next->address, NULL);
@@ -778,13 +778,13 @@ interfaces. We just return the loopback address(es). */
 ip_address_item *
 os_common_find_running_interfaces(void)
 {
-ip_address_item *yield = store_get(sizeof(address_item), FALSE);
+ip_address_item *yield = store_get(sizeof(address_item), GET_UNTAINTED);
 yield->address = US"127.0.0.1";
 yield->port = 0;
 yield->next = NULL;
 
 #if HAVE_IPV6
-yield->next = store_get(sizeof(address_item), FALSE);
+yield->next = store_get(sizeof(address_item), GET_UNTAINTED);
 yield->next->address = US"::1";
 yield->next->port = 0;
 yield->next->next = NULL;
index cf673e7167b9541ad6e89264703bcbba6978f302..3a7a4f18a7e52f33ce4de6fad7e5b50960902087 100644 (file)
@@ -22,22 +22,25 @@ redundant apparatus. */
 
 #ifdef STAND_ALONE
 
-address_item *deliver_make_addr(uschar *address, BOOL copy)
+address_item *
+deliver_make_addr(uschar *address, BOOL copy)
 {
-address_item *addr = store_get(sizeof(address_item), FALSE);
+address_item *addr = store_get(sizeof(address_item), GET_UNTAINTED);
 addr->next = NULL;
 addr->parent = NULL;
 addr->address = address;
 return addr;
 }
 
-uschar *rewrite_address(uschar *recipient, BOOL dummy1, BOOL dummy2, rewrite_rule
+uschar *
+rewrite_address(uschar *recipient, BOOL dummy1, BOOL dummy2, rewrite_rule
   *dummy3, int dummy4)
 {
 return recipient;
 }
 
-uschar *rewrite_address_qualify(uschar *recipient, BOOL dummy1)
+uschar *
+rewrite_address_qualify(uschar *recipient, BOOL dummy1)
 {
 return recipient;
 }
@@ -627,7 +630,7 @@ uschar *
 parse_extract_address(const uschar *mailbox, uschar **errorptr, int *start, int *end,
   int *domain, BOOL allow_null)
 {
-uschar *yield = store_get(Ustrlen(mailbox) + 1, is_tainted(mailbox));
+uschar * yield = store_get(Ustrlen(mailbox) + 1, mailbox);
 const uschar *startptr, *endptr;
 const uschar *s = US mailbox;
 uschar *t = US yield;
@@ -994,11 +997,9 @@ if (i < len)
 /* No non-printers; use the RFC 822 quoting rules */
 
 if (len <= 0 || len >= INT_MAX/4)
-  {
-  return string_copy_taint(CUS"", is_tainted(phrase));
-  }
+  return string_copy_taint(CUS"", phrase);
 
-buffer = store_get((len+1)*4, is_tainted(phrase));
+buffer = store_get((len+1)*4, phrase);
 
 s = phrase;
 end = s + len;
@@ -1545,7 +1546,7 @@ for (;;)
       return FF_ERROR;
       }
 
-    filebuf = store_get(statbuf.st_size + 1, is_tainted(filename));
+    filebuf = store_get(statbuf.st_size + 1, filename);
     if (fread(filebuf, 1, statbuf.st_size, f) != statbuf.st_size)
       {
       *error = string_sprintf("error while reading included file %s: %s",
@@ -1620,7 +1621,7 @@ for (;;)
 
     if ((*s_ltd == '|' || *s_ltd == '/') && (!recipient || domain == 0))
       {
-      uschar * t = store_get(Ustrlen(s_ltd) + 1, is_tainted(s_ltd));
+      uschar * t = store_get(Ustrlen(s_ltd) + 1, s_ltd);
       uschar * p = t, * q = s_ltd;
 
       while (*q)
@@ -1658,7 +1659,7 @@ for (;;)
 
         if (syntax_errors)
           {
-          error_block * e = store_get(sizeof(error_block), FALSE);
+          error_block * e = store_get(sizeof(error_block), GET_UNTAINTED);
           error_block * last = *syntax_errors;
           if (last)
             {
@@ -1738,7 +1739,7 @@ for the answer, but it may also be very long if we are processing a header
 line. Therefore, take care to release unwanted store afterwards. */
 
 reset_point = store_mark();
-id = *yield = store_get(Ustrlen(str) + 1, is_tainted(str));
+id = *yield = store_get(Ustrlen(str) + 1, str);
 *id++ = *str++;
 
 str = read_addr_spec(str, id, '>', error, &domain);
index 3aa4360dac731b55e2982c702d8f008ed46762c3..13218df8c9c6a42a092ba7e6d6e230643d9acce5 100644 (file)
@@ -248,7 +248,7 @@ debug_printf("\n");
 static pdkim_stringlist *
 pdkim_prepend_stringlist(pdkim_stringlist * base, const uschar * str)
 {
-pdkim_stringlist * new_entry = store_get(sizeof(pdkim_stringlist), FALSE);
+pdkim_stringlist * new_entry = store_get(sizeof(pdkim_stringlist), GET_UNTAINTED);
 
 memset(new_entry, 0, sizeof(pdkim_stringlist));
 new_entry->value = string_copy(str);
@@ -338,7 +338,7 @@ pdkim_relax_header_n(const uschar * header, int len, BOOL append_crlf)
 {
 BOOL past_field_name = FALSE;
 BOOL seen_wsp = FALSE;
-uschar * relaxed = store_get(len+3, TRUE);     /* tainted */
+uschar * relaxed = store_get(len+3, GET_TAINTED);
 uschar * q = relaxed;
 
 for (const uschar * p = header; p - header < len; p++)
@@ -418,7 +418,7 @@ pdkim_decode_qp(const uschar * str)
 int nchar = 0;
 uschar * q;
 const uschar * p = str;
-uschar * n = store_get(Ustrlen(str)+1, TRUE);
+uschar * n = store_get(Ustrlen(str)+1, GET_TAINTED);
 
 *n = '\0';
 q = n;
@@ -475,7 +475,7 @@ BOOL past_hname = FALSE;
 BOOL in_b_val = FALSE;
 int where = PDKIM_HDR_LIMBO;
 
-sig = store_get(sizeof(pdkim_signature), FALSE);
+sig = store_get(sizeof(pdkim_signature), GET_UNTAINTED);
 memset(sig, 0, sizeof(pdkim_signature));
 sig->bodylength = -1;
 
@@ -484,7 +484,7 @@ sig->version = 0;
 sig->keytype = -1;
 sig->hashtype = -1;
 
-q = sig->rawsig_no_b_val = store_get(Ustrlen(raw_hdr)+1, TRUE);        /* tainted */
+q = sig->rawsig_no_b_val = store_get(Ustrlen(raw_hdr)+1, GET_TAINTED);
 
 for (uschar * p = raw_hdr; ; p++)
   {
@@ -664,7 +664,7 @@ const uschar * ele;
 int sep = ';';
 pdkim_pubkey * pub;
 
-pub = store_get(sizeof(pdkim_pubkey), TRUE);   /* tainted */
+pub = store_get(sizeof(pdkim_pubkey), GET_TAINTED);
 memset(pub, 0, sizeof(pdkim_pubkey));
 
 while ((ele = string_nextinlist(&raw_record, &sep, NULL, 0)))
@@ -1919,14 +1919,14 @@ pdkim_init_verify(uschar * (*dns_txt_callback)(const uschar *), BOOL dot_stuffin
 {
 pdkim_ctx * ctx;
 
-ctx = store_get(sizeof(pdkim_ctx), FALSE);
+ctx = store_get(sizeof(pdkim_ctx), GET_UNTAINTED);
 memset(ctx, 0, sizeof(pdkim_ctx));
 
 if (dot_stuffing) ctx->flags = PDKIM_DOT_TERM;
 /* The line-buffer is for message data, hence tainted */
-ctx->linebuf = store_get(PDKIM_MAX_BODY_LINE_LEN, TRUE);
+ctx->linebuf = store_get(PDKIM_MAX_BODY_LINE_LEN, GET_TAINTED);
 ctx->dns_txt_callback = dns_txt_callback;
-ctx->cur_header = string_get_tainted(36, TRUE);
+ctx->cur_header = string_get_tainted(36, GET_TAINTED);
 
 return ctx;
 }
@@ -1947,7 +1947,7 @@ if (!domain || !selector || !privkey)
 
 /* Allocate & init one signature struct */
 
-sig = store_get(sizeof(pdkim_signature), FALSE);
+sig = store_get(sizeof(pdkim_signature), GET_UNTAINTED);
 memset(sig, 0, sizeof(pdkim_signature));
 
 sig->bodylength = -1;
@@ -2035,7 +2035,7 @@ for (b = ctx->bodyhash; b; b = b->next)
 
 DEBUG(D_receive) debug_printf("DKIM: new bodyhash %d/%d/%ld\n",
                              hashtype, canon_method, bodylength);
-b = store_get(sizeof(pdkim_bodyhash), FALSE);
+b = store_get(sizeof(pdkim_bodyhash), GET_UNTAINTED);
 b->next = ctx->bodyhash;
 b->hashtype = hashtype;
 b->canon_method = canon_method;
@@ -2080,7 +2080,7 @@ pdkim_init_context(pdkim_ctx * ctx, BOOL dot_stuffed,
 memset(ctx, 0, sizeof(pdkim_ctx));
 ctx->flags = dot_stuffed ? PDKIM_MODE_SIGN | PDKIM_DOT_TERM : PDKIM_MODE_SIGN;
 /* The line buffer is for message data, hence tainted */
-ctx->linebuf = store_get(PDKIM_MAX_BODY_LINE_LEN, TRUE);
+ctx->linebuf = store_get(PDKIM_MAX_BODY_LINE_LEN, GET_TAINTED);
 DEBUG(D_acl) ctx->dns_txt_callback = dns_txt_callback;
 }
 
index 561eb61619f8ee6bbe658b785790b1ffe4600cef..a71d6369297e17fa39adabdb15d9bda0c3d1d8f5 100644 (file)
@@ -507,7 +507,7 @@ switch (hash)
   }
 
 #define SIGSPACE 128
-sig->data = store_get(SIGSPACE, FALSE);
+sig->data = store_get(SIGSPACE, GET_UNTAINTED);
 
 if (gcry_mpi_cmp (sign_ctx->p, sign_ctx->q) > 0)
   {
@@ -766,7 +766,7 @@ switch (hash)
 if (  (ctx = EVP_MD_CTX_new())
    && EVP_DigestSignInit(ctx, NULL, md, NULL, sign_ctx->key) > 0
    && EVP_DigestSign(ctx, NULL, &siglen, NULL, 0) > 0
-   && (sig->data = store_get(siglen, FALSE))
+   && (sig->data = store_get(siglen, GET_UNTAINTED))
 
    /* Obtain the signature (slen could change here!) */
    && EVP_DigestSign(ctx, sig->data, &siglen, data->data, data->len) > 0
@@ -782,7 +782,7 @@ if (  (ctx = EVP_MD_CTX_create())
    && EVP_DigestSignInit(ctx, NULL, md, NULL, sign_ctx->key) > 0
    && EVP_DigestSignUpdate(ctx, data->data, data->len) > 0
    && EVP_DigestSignFinal(ctx, NULL, &siglen) > 0
-   && (sig->data = store_get(siglen, FALSE))
+   && (sig->data = store_get(siglen, GET_UNTAINTED))
  
    /* Obtain the signature (slen could change here!) */
    && EVP_DigestSignFinal(ctx, sig->data, &siglen) > 0
index dff6168c02012528febf1ceb8475e01fe611eee1..2933c5439841055d450e9130ff007f212a3b0299 100644 (file)
@@ -214,8 +214,8 @@ for (; i <= *subcount; i++)
        (*pcount)++;
       else
        {
-       queue_filename *next =
-         store_get(sizeof(queue_filename) + Ustrlen(name), is_tainted(name));
+       queue_filename * next =
+         store_get(sizeof(queue_filename) + Ustrlen(name), name);
        Ustrcpy(next->text, name);
        next->dir_uschar = subdirchar;
 
@@ -901,8 +901,8 @@ if (count > 0)
   queue_filename *last = NULL;
   for (int i = 0; i < count; i++)
     {
-    queue_filename *next =
-      store_get(sizeof(queue_filename) + Ustrlen(list[i]) + 2, is_tainted(list[i]));
+    queue_filename * next =
+      store_get(sizeof(queue_filename) + Ustrlen(list[i]) + 2, list[i]);
     sprintf(CS next->text, "%s-H", list[i]);
     next->dir_uschar = '*';
     next->next = NULL;
index dba2e20fb26d5be6ce5dcbd7e0f189133ec335b5..10a44c15c45883e080070b64b2ce3fa5ebb12829 100644 (file)
@@ -284,7 +284,7 @@ if (statbuf.st_size > MAX_FILTER_SIZE)
 
 /* Read the file in one go in order to minimize the time we have it open. */
 
-filebuf = store_get(statbuf.st_size + 1, is_tainted(filename));
+filebuf = store_get(statbuf.st_size + 1, filename);
 
 if (fread(filebuf, 1, statbuf.st_size, fwd) != statbuf.st_size)
   {
@@ -476,7 +476,7 @@ else
   /* We know we have enough memory so disable the error on "len" */
   /* coverity[tainted_data] */
   /* We trust the data source, so untainted */
-  if (read(fd, *sp = store_get(len, FALSE), len) != len) return FALSE;
+  if (read(fd, *sp = store_get(len, GET_UNTAINTED), len) != len) return FALSE;
 return TRUE;
 }
 
@@ -808,7 +808,7 @@ if (eblockp)
     uschar *s;
     if (!rda_read_string(fd, &s)) goto DISASTER;
     if (!s) break;
-    e = store_get(sizeof(error_block), FALSE);
+    e = store_get(sizeof(error_block), GET_UNTAINTED);
     e->next = NULL;
     e->text1 = s;
     if (!rda_read_string(fd, &s)) goto DISASTER;
@@ -907,7 +907,7 @@ if (yield == FF_DELIVERED || yield == FF_NOTDELIVERED ||
 
     if (i > 0)
       {
-      addr->pipe_expandn = store_get((i+1) * sizeof(uschar *), FALSE);
+      addr->pipe_expandn = store_get((i+1) * sizeof(uschar *), GET_UNTAINTED);
       addr->pipe_expandn[i] = NULL;
       while (--i >= 0) addr->pipe_expandn[i] = expandn[i];
       }
@@ -917,7 +917,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)
       {
-      addr->reply = store_get(sizeof(reply_item), FALSE);
+      addr->reply = store_get(sizeof(reply_item), GET_UNTAINTED);
 
       addr->reply->file_expand = (reply_options & REPLY_EXPAND) != 0;
       addr->reply->return_message = (reply_options & REPLY_RETURN) != 0;
index 763a0c5f09e0477841b7d509d95e53751c66ec67..dc43d30f58afbad5cd16f808006759c5c4cd8318 100644 (file)
@@ -646,7 +646,7 @@ Args:
 macro_item *
 macro_create(const uschar * name, const uschar * val, BOOL command_line)
 {
-macro_item * m = store_get(sizeof(macro_item), FALSE);
+macro_item * m = store_get(sizeof(macro_item), GET_UNTAINTED);
 
 READCONF_DEBUG fprintf(stderr, "%s: '%s' '%s'\n", __FUNCTION__, name, val);
 m->next = NULL;
@@ -1076,7 +1076,7 @@ for (;;)
 
     if (config_lines)
       save_config_position(config_filename, config_lineno);
-    save = store_get(sizeof(config_file_item), FALSE);
+    save = store_get(sizeof(config_file_item), GET_UNTAINTED);
     save->next = config_file_stack;
     config_file_stack = save;
     save->file = config_file;
@@ -1425,7 +1425,7 @@ Returns:      the control block for the parsed rule.
 static rewrite_rule *
 readconf_one_rewrite(const uschar *p, int *existflags, BOOL isglobal)
 {
-rewrite_rule *next = store_get(sizeof(rewrite_rule), FALSE);
+rewrite_rule * next = store_get(sizeof(rewrite_rule), GET_UNTAINTED);
 
 next->next = NULL;
 next->key = string_dequote(&p);
@@ -3021,7 +3021,7 @@ if (*numberp >= max)
 Uskip_whitespace(&s);
 ss = s;
 while (isalnum(*s) || *s == '_') s++;
-t = store_get(sizeof(tree_node) + s-ss, is_tainted(ss));
+t = store_get(sizeof(tree_node) + s-ss, ss);
 Ustrncpy(t->name, ss, s-ss);
 t->name[s-ss] = 0;
 Uskip_whitespace(&s);
@@ -3279,7 +3279,7 @@ if (f.trusted_config && Ustrcmp(filename, US"/dev/null"))
   if (statbuf.st_size > 8192)
     {
     rmark r = store_mark();
-    void * dummy = store_get((int)statbuf.st_size, FALSE);
+    void * dummy = store_get((int)statbuf.st_size, GET_UNTAINTED);
     store_reset(r);
     }
   }
@@ -3769,6 +3769,8 @@ while ((buffer = get_config_line()))
     *p = d;
     p = &d->next;
     d->name = string_copy(name);
+    d->srcfile = config_filename;
+    d->srcline = config_lineno; 
 
     /* Clear out the "set" bits in the generic options */
 
@@ -4056,7 +4058,7 @@ while ((p = get_config_line()))
   const uschar *pp;
   uschar *error;
 
-  next = store_get(sizeof(retry_config), FALSE);
+  next = store_get(sizeof(retry_config), GET_UNTAINTED);
   next->next = NULL;
   *chain = next;
   chain = &(next->next);
@@ -4100,7 +4102,7 @@ while ((p = get_config_line()))
 
   while (*p)
     {
-    retry_rule *rule = store_get(sizeof(retry_rule), FALSE);
+    retry_rule * rule = store_get(sizeof(retry_rule), GET_UNTAINTED);
     *rchain = rule;
     rchain = &(rule->next);
     rule->next = NULL;
@@ -4194,6 +4196,18 @@ f.smtp_in_early_pipe_no_auth = nauths > 16;
 }
 
 
+/* For error messages, a string describing the config location associated
+with current processing.  NULL if we are not in an authenticator. */
+
+uschar *
+authenticator_current_name(void)
+{
+if (!authenticator_name) return NULL;
+return string_sprintf(" (authenticator %s, %s %d)", authenticator_name, driver_srcfile, driver_srcline);
+}
+
+
+
 
 
 /*************************************************
@@ -4250,7 +4264,7 @@ while(acl_line)
   if (*p != ':' || name[0] == 0)
     log_write(0, LOG_PANIC_DIE|LOG_CONFIG_IN, "missing or malformed ACL name");
 
-  node = store_get_perm(sizeof(tree_node) + Ustrlen(name), is_tainted(name));
+  node = store_get_perm(sizeof(tree_node) + Ustrlen(name), name);
   Ustrcpy(node->name, name);
   if (!tree_insertnode(&acl_anchor, node))
     log_write(0, LOG_PANIC_DIE|LOG_CONFIG_IN,
@@ -4395,7 +4409,7 @@ save_config_line(const uschar* line)
 static config_line_item *current;
 config_line_item *next;
 
-next = (config_line_item*) store_get(sizeof(config_line_item), FALSE);
+next = (config_line_item*) store_get(sizeof(config_line_item), GET_UNTAINTED);
 next->line = string_copy(line);
 next->next = NULL;
 
index 058a74cb2bf0b36e2f8e3afd29df93bc2fd0f9e1..ba84967c1caa70a4cd34d6889c9ecb331b389ac0 100644 (file)
@@ -527,7 +527,7 @@ if (recipients_count >= recipients_list_max)
     }
 
   recipients_list_max = recipients_list_max ? 2*recipients_list_max : 50;
-  recipients_list = store_get(recipients_list_max * sizeof(recipient_item), FALSE);
+  recipients_list = store_get(recipients_list_max * sizeof(recipient_item), GET_UNTAINTED);
   if (oldlist)
     memcpy(recipients_list, oldlist, oldmax * sizeof(recipient_item));
   }
@@ -1760,17 +1760,18 @@ if (extract_recip || !smtp_input)
 header. Temporarily mark it as "old", i.e. not to be used. We keep header_last
 pointing to the end of the chain to make adding headers simple. */
 
-received_header = header_list = header_last = store_get(sizeof(header_line), FALSE);
+received_header = header_list = header_last = store_get(sizeof(header_line), GET_UNTAINTED);
 header_list->next = NULL;
 header_list->type = htype_old;
 header_list->text = NULL;
 header_list->slen = 0;
 
-/* Control block for the next header to be read. */
+/* Control block for the next header to be read.
+The data comes from the message, so is tainted. */
 
 reset_point = store_mark();
-next = store_get(sizeof(header_line), FALSE);  /* not tainted */
-next->text = store_get(header_size, TRUE);     /* tainted */
+next = store_get(sizeof(header_line), GET_UNTAINTED);
+next->text = store_get(header_size, GET_TAINTED);
 
 /* Initialize message id to be null (indicating no message read), and the
 header names list to be the normal list. Indicate there is no data file open
@@ -1917,10 +1918,8 @@ for (;;)
       goto OVERSIZE;
     header_size *= 2;
 
-    /* The data came from the message, so is tainted. */
-
-    if (!store_extend(next->text, TRUE, oldsize, header_size))
-      next->text = store_newblock(next->text, TRUE, header_size, ptr);
+    if (!store_extend(next->text, oldsize, header_size))
+      next->text = store_newblock(next->text, header_size, ptr);
     }
 
   /* Cope with receiving a binary zero. There is dispute about whether
@@ -2309,8 +2308,8 @@ OVERSIZE:
 
   reset_point = store_mark();
   header_size = 256;
-  next = store_get(sizeof(header_line), FALSE);
-  next->text = store_get(header_size, TRUE);
+  next = store_get(sizeof(header_line), GET_UNTAINTED);
+  next->text = store_get(header_size, GET_TAINTED);
   ptr = 0;
   had_zero = 0;
   prevlines_length = 0;
@@ -2594,7 +2593,7 @@ if (extract_recip)
         white space that follows the newline must not be removed - it is part
         of the header. */
 
-        pp = recipient = store_get(ss - s + 1, is_tainted(s));
+        pp = recipient = store_get(ss - s + 1, s);
         for (uschar * p = s; p < ss; p++) if (*p != '\n') *pp++ = *p;
         *pp = 0;
 
@@ -2626,7 +2625,7 @@ if (extract_recip)
         if (!recipient && Ustrcmp(errmess, "empty address") != 0)
           {
           int len = Ustrlen(s);
-          error_block *b = store_get(sizeof(error_block), FALSE);
+          error_block * b = store_get(sizeof(error_block), GET_UNTAINTED);
           while (len > 0 && isspace(s[len-1])) len--;
           b->next = NULL;
           b->text1 = string_printing(string_copyn(s, len));
@@ -2825,7 +2824,7 @@ function may mess with the real recipients. */
 
 if (LOGGING(received_recipients))
   {
-  raw_recipients = store_get(recipients_count * sizeof(uschar *), FALSE);
+  raw_recipients = store_get(recipients_count * sizeof(uschar *), GET_UNTAINTED);
   for (int i = 0; i < recipients_count; i++)
     raw_recipients[i] = string_copy(recipients_list[i].address);
   raw_recipients_count = recipients_count;
index 2b3e308a2b9372b3eafd513fd9d72d1a1a3ec1b5..c1acf4c6e9d7e2c59f50a5e38568f0592cda354e 100644 (file)
@@ -55,7 +55,7 @@ while ((regex_string = string_nextinlist(&list, &sep, NULL, 0)))
       continue;
       }
 
-    ri = store_get(sizeof(pcre_list), FALSE);
+    ri = store_get(sizeof(pcre_list), GET_UNTAINTED);
     ri->re = re;
     ri->pcre_text = regex_string;
     ri->next = re_list_head;
@@ -133,7 +133,7 @@ if (!(re_list_head = compile(*listptr)))
   return FAIL;                 /* no regexes -> nothing to do */
 
 /* match each line against all regexes */
-linebuffer = store_get(32767, TRUE);   /* tainted */
+linebuffer = store_get(32767, GET_TAINTED);
 while (fgets(CS linebuffer, 32767, mbox_file))
   {
   if (  mime_stream && mime_current_boundary           /* check boundary */
@@ -204,7 +204,7 @@ if (!(f = fopen(CS mime_decoded_filename, "rb")))
   }
 
 /* get 32k memory, tainted */
-mime_subject = store_get(32767, TRUE);
+mime_subject = store_get(32767, GET_TAINTED);
 
 mime_subject_len = fread(mime_subject, 1, 32766, f);
 
index 1993b776877d1aef60b0fb399ae64ad4c06d91e3..8127388104f974ed4d9beb6d7d3a7b38ce2dfc2a 100644 (file)
@@ -292,7 +292,7 @@ Returns:  nothing
 void
 retry_add_item(address_item *addr, uschar *key, int flags)
 {
-retry_item *rti = store_get(sizeof(retry_item), FALSE);
+retry_item * rti = store_get(sizeof(retry_item), GET_UNTAINTED);
 host_item * host = addr->host_used;
 
 rti->next = addr->retries;
@@ -669,7 +669,7 @@ for (int i = 0; i < 3; i++)
         if (!retry_record)
           {
           retry_record = store_get(sizeof(dbdata_retry) + message_length,
-                                  is_tainted(message));
+                                  message);
           message_space = message_length;
           retry_record->first_failed = now;
           retry_record->last_try = now;
@@ -815,7 +815,7 @@ for (int i = 0; i < 3; i++)
        if (message_length > message_space)
          {
          dbdata_retry * newr =
-           store_get(sizeof(dbdata_retry) + message_length, is_tainted(message));
+           store_get(sizeof(dbdata_retry) + message_length, message);
          memcpy(newr, retry_record, sizeof(dbdata_retry));
          retry_record = newr;
          }
index 42a63048f9b79367627fe62947ef489e1efafa23..9420e79b98dd8f5b391fb0f7a3008d18123a3eab 100644 (file)
@@ -603,7 +603,7 @@ while (*s)
     int oldlen = end - start;
 
     header_line * prev = newh ? newh : h;
-    uschar * newt = store_get_perm(prev->slen - oldlen + newlen + 4, TRUE);
+    uschar * newt = store_get_perm(prev->slen - oldlen + newlen + 4, GET_TAINTED);
     uschar * newtstart = newt;
 
     int type = prev->type;
@@ -667,7 +667,7 @@ while (*s)
 
     store_reset(function_reset_point);
     function_reset_point = store_mark();
-    newh = store_get(sizeof(header_line), FALSE);
+    newh = store_get(sizeof(header_line), GET_UNTAINTED);
     newh->type = type;
     newh->slen = slen;
     newh->text = string_copyn(newtstart, slen);
index 4679d767750ab9ce86ce544eaec66375ae85a69b..1138d2dbefadb4976036d84c3583dce6d9a5cee2 100644 (file)
@@ -47,7 +47,7 @@ rfc2047_qpdecode(uschar *string, uschar **ptrptr)
 int len = 0;
 uschar *ptr;
 
-ptr = *ptrptr = store_get(Ustrlen(string) + 1, is_tainted(string));  /* No longer than this */
+ptr = *ptrptr = store_get(Ustrlen(string) + 1, string);  /* No longer than this */
 
 while (*string != 0)
   {
@@ -209,7 +209,7 @@ building the result as we go. The result may be longer than the input if it is
 translated into a multibyte code such as UTF-8. That's why we use the dynamic
 string building code. */
 
-yield = store_get(sizeof(gstring) + ++size, is_tainted(string));
+yield = store_get(sizeof(gstring) + ++size, string);
 yield->size = size;
 yield->ptr = 0;
 yield->s = US(yield + 1);
index 225a19046e5fa327acebe63731cca160811dc8e8..ae04c7917a648128e27af8e8caee98cd1ca2a37b 100644 (file)
@@ -1499,7 +1499,7 @@ for (uschar * ele; (ele = string_nextinlist(&varlist, &sep, NULL, 0)); )
 
   if (!(node = tree_search(*root, name)))
     {                          /* name should never be tainted */
-    node = store_get(sizeof(tree_node) + Ustrlen(name), FALSE);
+    node = store_get(sizeof(tree_node) + Ustrlen(name), GET_UNTAINTED);
     Ustrcpy(node->name, name);
     (void)tree_insertnode(root, node);
     }
@@ -1693,7 +1693,7 @@ for (r = addr->start_router ? addr->start_router : routers; r; r = nextr)
       int lplen = Ustrlen(addr->local_part) - slen;
       addr->suffix = vlen
        ? addr->local_part + lplen
-       : string_copy_taint(addr->local_part + lplen, slen);
+       : string_copy_taint(addr->local_part + lplen, GET_UNTAINTED);
       addr->suffix_v = addr->suffix + Ustrlen(addr->suffix) - vlen;
       addr->local_part = string_copyn(addr->local_part, lplen);
       DEBUG(D_route) debug_printf("stripped suffix %s\n", addr->suffix);
@@ -1710,6 +1710,8 @@ for (r = addr->start_router ? addr->start_router : routers; r; r = nextr)
   the local part sorted. */
 
   router_name = r->name;
+  driver_srcfile = r->srcfile;
+  driver_srcline = r->srcline;
   deliver_set_expansions(addr);
 
   /* For convenience, the pre-router checks are in a separate function, which
@@ -1717,7 +1719,7 @@ for (r = addr->start_router ? addr->start_router : routers; r; r = nextr)
 
   if ((rc = check_router_conditions(r, addr, verify, &pw, &error)) != OK)
     {
-    router_name = NULL;
+    driver_srcfile = router_name = NULL; driver_srcline = 0;
     if (rc == SKIP) continue;
     addr->message = error;
     yield = rc;
@@ -1768,7 +1770,7 @@ for (r = addr->start_router ? addr->start_router : routers; r; r = nextr)
           {
           DEBUG(D_route)
             debug_printf("\"more\"=false: skipping remaining routers\n");
-         router_name = NULL;
+         driver_srcfile = router_name = NULL; driver_srcline = 0;
           r = NULL;
           break;
           }
@@ -1820,7 +1822,7 @@ for (r = addr->start_router ? addr->start_router : routers; r; r = nextr)
   yield = (r->info->code)(r, addr, pw, verify, paddr_local, paddr_remote,
     addr_new, addr_succeed);
 
-  router_name = NULL;
+  driver_srcfile = router_name = NULL; driver_srcline = 0;
 
   if (yield == FAIL)
     {
@@ -2048,10 +2050,23 @@ if (yield == DEFER && addr->message)
   addr->message = expand_hide_passwords(addr->message);
 
 deliver_set_expansions(NULL);
-router_name = NULL;
+driver_srcfile = router_name = NULL; driver_srcline = 0;
 f.disable_logging = FALSE;
 return yield;
 }
 
+
+
+/* For error messages, a string describing the config location associated
+with current processing.  NULL if we are not in a router. */
+/* Name only, for now */
+
+uschar *
+router_current_name(void)
+{
+if (!router_name) return NULL;
+return string_sprintf(" (router %s, %s %d)", router_name, driver_srcfile, driver_srcline);
+}
+
 #endif /*!MACRO_PREDEF*/
 /* End of route.c */
index 977b58d4536b8283540a11bbd177608ecc3901b0..807191b916be85e4ccb006f46403ca7af06ea3d8 100644 (file)
@@ -456,7 +456,7 @@ if (rc != OK) return rc;
 /* Get store in which to preserve the original host item, chained on
 to the address. */
 
-addr->host_list = store_get(sizeof(host_item), FALSE);
+addr->host_list = store_get(sizeof(host_item), GET_UNTAINTED);
 addr->host_list[0] = h;
 
 /* Fill in the transport and queue the address for delivery. */
index 80f37797019b366a07a9220f26ca4006797f0ffc..f2ec486fbe3f9731b477a553ca93b1a14d513993 100644 (file)
@@ -146,7 +146,7 @@ if (verify_check_this_host(CUSS&rblock->ignore_target_hosts,
 
 /* Set up a host item */
 
-h = store_get(sizeof(host_item), FALSE);
+h = store_get(sizeof(host_item), GET_UNTAINTED);
 
 h->next = NULL;
 h->address = string_copy(ip);
index 2237d038600962703a4a7a25a02ec195d48fd2b9..bbef1c063b4e772b3b9a00a62d70b035fdd113e2 100644 (file)
@@ -161,7 +161,7 @@ uschar *reply;
 uschar *hostname, *reroute, *domain;
 const uschar *listptr;
 uschar host_buffer[256];
-host_item *host = store_get(sizeof(host_item), FALSE);
+host_item *host = store_get(sizeof(host_item), GET_UNTAINTED);
 address_item *new_addr;
 iplookup_router_options_block *ob =
   (iplookup_router_options_block *)(rblock->options_block);
@@ -172,7 +172,7 @@ int sep = 0;
 DEBUG(D_route) debug_printf("%s router called for %s: domain = %s\n",
   rblock->name, addr->address, addr->domain);
 
-reply = store_get(256, TRUE);  /* tainted data */
+reply = store_get(256, GET_TAINTED);
 
 /* Build the query string to send. If not explicitly given, a default of
 "user@domain user@domain" is used. */
index e3ef1eadb8fe8019949a6452b7e27133ddeab96a..12d87a6898814ee6389c22e08433632ab0b94887 100644 (file)
@@ -399,7 +399,7 @@ if (transport && transport->info->local)
   if (hostlist[0])
     {
     host_item *h;
-    addr->host_list = h = store_get(sizeof(host_item), FALSE);
+    addr->host_list = h = store_get(sizeof(host_item), GET_UNTAINTED);
     h->name = string_copy(hostlist);
     h->address = NULL;
     h->port = PORT_NONE;
index 7d24737586d104e6c2b5532dbba87f13885b3ba0..bcad394027fc231154bd721d3b517b5cc1b27eaf 100644 (file)
@@ -676,7 +676,7 @@ switch (frc)
 
     if (filtertype != FILTER_FORWARD && ob->skip_syntax_errors)
       {
-      eblock = store_get(sizeof(error_block), FALSE);
+      eblock = store_get(sizeof(error_block), GET_UNTAINTED);
       eblock->next = NULL;
       eblock->text1 = addr->message;
       eblock->text2 = NULL;
index 39c41fc9da0c37884b11591e9220f0d08b0b4550..e3a623aec197a2ce19b857b772333a8c628316ef 100644 (file)
@@ -35,9 +35,9 @@ void
 rf_change_domain(address_item *addr, const uschar *domain, BOOL rewrite,
   address_item **addr_new)
 {
-address_item *parent = store_get(sizeof(address_item), FALSE);
-uschar *at = Ustrrchr(addr->address, '@');
-uschar *address = string_sprintf("%.*s@%s",
+address_item * parent = store_get(sizeof(address_item), GET_UNTAINTED);
+uschar * at = Ustrrchr(addr->address, '@');
+uschar * address = string_sprintf("%.*s@%s",
   (int)(at - addr->address), addr->address, domain);
 
 DEBUG(D_route) debug_printf("domain changed to %s\n", domain);
index 5f0bbc993887b298d4e5960bb397f9289f5b7ab2..4cd1752d4c46102804269b0ea8d05b915c9dc62a 100644 (file)
@@ -59,7 +59,7 @@ if (rblock->extra_headers)
       shared with other addresses. The output function outputs them in reverse
       order. */
 
-      header_line *  h = store_get(sizeof(header_line), FALSE);
+      header_line *  h = store_get(sizeof(header_line), GET_UNTAINTED);
 
       /* We used to use string_sprintf() to add the newline if needed, but that
       causes problems if the header line is exceedingly long (e.g. adding
@@ -69,7 +69,7 @@ if (rblock->extra_headers)
        h->text = s;
       else
        {
-       h->text = store_get(slen+2, is_tainted(s));
+       h->text = store_get(slen+2, s);
        memcpy(h->text, s, slen);
        h->text[slen++] = '\n';
        h->text[slen] = 0;
index d93397f096a32cde7f71330600d2f75008aaf604..979dae739638946d5e5686a8381442b371010c76 100644 (file)
@@ -476,8 +476,8 @@ count alone. */
 
 if (!t)
   {
-  t = store_get(sizeof(tree_node) + Ustrlen(keybuffer), FALSE);
-  t->data.ptr = c = store_get(sizeof(search_cache), FALSE);
+  t = store_get(sizeof(tree_node) + Ustrlen(keybuffer), GET_UNTAINTED);
+  t->data.ptr = c = store_get(sizeof(search_cache), GET_UNTAINTED);
   c->item_cache = NULL;
   Ustrcpy(t->name, keybuffer);
   tree_insertnode(&search_tree, t);
@@ -578,6 +578,47 @@ else
       filename ? US"file" : US"database",
       keystring,
       filename ? US"\n  in " : US"", filename ? filename : US"");
+    if (!filename && is_tainted(keystring))
+      {
+      debug_printf_indent("                             ");
+      debug_print_taint(keystring);
+      }
+    }
+
+  /* Check that the query, for query-style lookups,
+  is either untainted or properly quoted for the lookup type.
+
+  XXX Should we this move into lf_sqlperform() ?  The server-taint check is there.
+  */
+
+  if (  !filename && lookup_list[search_type]->quote
+     && is_tainted(keystring) && !is_quoted_like(keystring, search_type))
+    {
+    uschar * s = acl_current_verb();
+    if (!s) s = authenticator_current_name();  /* must be before transport */
+    if (!s) s = transport_current_name();      /* must be before router */
+    if (!s) s = router_current_name(); /* GCC ?: would be good, but not in clang */
+    if (!s) s = US"";
+#ifdef enforce_quote_protection_notyet
+    search_error_message = string_sprintf(
+      "tainted search query is not properly quoted%s: %s%s",
+      s, keystring);
+    f.search_find_defer = TRUE;
+#else
+     {
+      int q = quoter_for_address(keystring);
+      /* If we're called from a transport, no privs to open the paniclog;
+      the logging punts to using stderr - and that seems to stop the debug
+      stream. */
+      log_write(0,
+       transport_name ? LOG_MAIN : LOG_MAIN|LOG_PANIC,
+       "tainted search query is not properly quoted%s: %s", s, keystring);
+
+      DEBUG(D_lookup) debug_printf_indent("search_type %d (%s) quoting %d (%s)\n",
+       search_type, lookup_list[search_type]->name,
+       q, is_real_quoter(q) ? lookup_list[q]->name : US"none");
+     }
+#endif
     }
 
   /* Call the code for the different kinds of search. DEFER is handled
@@ -585,7 +626,7 @@ else
   distinguish if necessary. */
 
   if (lookup_list[search_type]->find(c->handle, filename, keystring, keylength,
-      &data, &search_error_message, &do_cache, opts) == DEFER)
+         &data, &search_error_message, &do_cache, opts) == DEFER)
     f.search_find_defer = TRUE;
 
   /* A record that has been found is now in data, which is either NULL
@@ -603,8 +644,8 @@ else
     if (!t)    /* No existing entry.  Create new one. */
       {
       int len = keylength + 1;
-      e = store_get(sizeof(expiring_data) + sizeof(tree_node) + len,
-                   is_tainted(keystring));
+      /* The cache node value should never be expanded so use tainted mem */
+      e = store_get(sizeof(expiring_data) + sizeof(tree_node) + len, GET_TAINTED);
       t = (tree_node *)(e+1);
       memcpy(t->name, keystring, len);
       t->data.ptr = e;
@@ -777,7 +818,7 @@ else if (partial >= 0)
   if (affixlen == 0) keystring2 = keystring; else
     {
     keystring2 = store_get(len + affixlen + 1,
-                       is_tainted(keystring) || is_tainted(affix));
+         is_tainted(keystring) || is_tainted(affix) ? GET_TAINTED : GET_UNTAINTED);
     Ustrncpy(keystring2, affix, affixlen);
     Ustrcpy(keystring2 + affixlen, keystring);
     DEBUG(D_lookup) debug_printf_indent("trying partial match %s\n", keystring2);
index f693ebf4e9de9421a8acf784ee9ec3d793c6d307..d1f5d93c8c343a36525804befa6abf081677c6e2 100644 (file)
@@ -245,7 +245,7 @@ for (int pass = 0; pass <= 1; pass++)
     dst->length=0;
   else
     {
-    dst->character = store_get(dst->length+1, is_tainted(src->character)); /* plus one for \0 */
+    dst->character = store_get(dst->length+1, src->character); /* plus one for \0 */
     new=dst->character;
     }
   for (const uschar * start = src->character, * end = start + src->length;
@@ -444,16 +444,16 @@ if (*uri && *uri!='?')
         filter->errmsg=US"Invalid URI encoding";
         return -1;
         }
-      new=store_get(sizeof(string_item), FALSE);
-      new->text = store_get(to.length+1, is_tainted(to.character));
+      new = store_get(sizeof(string_item), GET_UNTAINTED);
+      new->text = store_get(to.length+1, to.character);
       if (to.length) memcpy(new->text, to.character, to.length);
-      new->text[to.length]='\0';
-      new->next=*recipient;
-      *recipient=new;
+      new->text[to.length] = '\0';
+      new->next = *recipient;
+      *recipient = new;
       }
     else
       {
-      filter->errmsg=US"Missing addr-spec in URI";
+      filter->errmsg = US"Missing addr-spec in URI";
       return -1;
       }
     if (*uri=='%') uri+=3;
@@ -502,8 +502,8 @@ if (*uri=='?')
       }
     if (hname.length==2 && strcmpic(hname.character, US"to")==0)
       {
-      new=store_get(sizeof(string_item), FALSE);
-      new->text = store_get(hvalue.length+1, is_tainted(hvalue.character));
+      new=store_get(sizeof(string_item), GET_UNTAINTED);
+      new->text = store_get(hvalue.length+1, hvalue.character);
       if (hvalue.length) memcpy(new->text, hvalue.character, hvalue.length);
       new->text[hvalue.length]='\0';
       new->next=*recipient;
@@ -1729,7 +1729,7 @@ if (*filter->pc=='[') /* string list */
       struct String *new;
 
       dataCapacity = dataCapacity ? dataCapacity * 2 : 4;
-      new = store_get(sizeof(struct String) * dataCapacity, FALSE);
+      new = store_get(sizeof(struct String) * dataCapacity, GET_UNTAINTED);
 
       if (d) memcpy(new,d,sizeof(struct String)*dataLength);
       d = new;
@@ -1767,7 +1767,7 @@ if (*filter->pc=='[') /* string list */
   }
 else /* single string */
   {
-  if (!(d=store_get(sizeof(struct String)*2, FALSE)))
+  if (!(d=store_get(sizeof(struct String)*2, GET_UNTAINTED)))
     return -1;
 
   m=parse_string(filter,&d[0]);
@@ -3073,7 +3073,7 @@ while (*filter->pc)
         if (!already)
           /* New notification, process it */
           {
-          struct Notification * sent = store_get(sizeof(struct Notification), FALSE);
+          struct Notification * sent = store_get(sizeof(struct Notification), GET_UNTAINTED);
           sent->method=method;
           sent->importance=importance;
           sent->message=message;
@@ -3212,9 +3212,9 @@ while (*filter->pc)
           }
         for (struct String * a = addresses; a->length != -1; ++a)
           {
-          string_item * new = store_get(sizeof(string_item), FALSE);
+          string_item * new = store_get(sizeof(string_item), GET_UNTAINTED);
 
-          new->text = store_get(a->length+1, is_tainted(a->character));
+          new->text = store_get(a->length+1, a->character);
           if (a->length) memcpy(new->text,a->character,a->length);
           new->text[a->length]='\0';
           new->next=aliases;
@@ -3327,7 +3327,7 @@ while (*filter->pc)
           addr->prop.ignore_error = TRUE;
           addr->next = *generated;
           *generated = addr;
-          addr->reply = store_get(sizeof(reply_item), FALSE);
+          addr->reply = store_get(sizeof(reply_item), GET_UNTAINTED);
           memset(addr->reply,0,sizeof(reply_item)); /* XXX */
           addr->reply->to = string_copy(sender_address);
           if (from.length==-1)
index 9efc816fa8e56b91fdc537ed2ba25df30aa43340..852148fcf594294dbe7944ea9773dcc69bccc0fb 100644 (file)
@@ -342,7 +342,7 @@ if (!sender_address                         /* No transaction in progress */
 
 if (recipients_count > 0)
   {
-  raw_recipients = store_get(recipients_count * sizeof(uschar *), FALSE);
+  raw_recipients = store_get(recipients_count * sizeof(uschar *), GET_UNTAINTED);
   for (int i = 0; i < recipients_count; i++)
     raw_recipients[i] = recipients_list[i].address;
   raw_recipients_count = recipients_count;
@@ -2572,7 +2572,7 @@ acl_var_c = NULL;
 
 /* Allow for trailing 0 in the command and data buffers.  Tainted. */
 
-smtp_cmd_buffer = store_get_perm(2*SMTP_CMD_BUFFER_SIZE + 2, TRUE);
+smtp_cmd_buffer = store_get_perm(2*SMTP_CMD_BUFFER_SIZE + 2, GET_TAINTED);
 
 smtp_cmd_buffer[0] = 0;
 smtp_data_buffer = smtp_cmd_buffer + SMTP_CMD_BUFFER_SIZE + 1;
@@ -2682,7 +2682,7 @@ if (!f.sender_host_unknown)
     {
     #if OPTSTYLE == 1
     EXIM_SOCKLEN_T optlen = sizeof(struct ip_options) + MAX_IPOPTLEN;
-    struct ip_options *ipopt = store_get(optlen, FALSE);
+    struct ip_options *ipopt = store_get(optlen, GET_UNTAINTED);
     #elif OPTSTYLE == 2
     struct ip_opts ipoptblock;
     struct ip_opts *ipopt = &ipoptblock;
@@ -3777,6 +3777,12 @@ smtp_in_auth(auth_instance *au, uschar ** s, uschar ** ss)
 const uschar *set_id = NULL;
 int rc;
 
+/* Set up globals for error messages */
+
+authenticator_name = au->name;
+driver_srcfile = au->srcfile;
+driver_srcline = au->srcline;
+
 /* Run the checking code, passing the remainder of the command line as
 data. Initials the $auth<n> variables as empty. Initialize $0 empty and set
 it as the only set numerical variable. The authenticator may set $auth<n>
@@ -3797,6 +3803,7 @@ rc = (au->info->servercode)(au, smtp_cmd_data);
 if (au->set_id) set_id = expand_string(au->set_id);
 expand_nmax = -1;        /* Reset numeric variables */
 for (int i = 0; i < AUTH_VARS; i++) auth_vars[i] = NULL;   /* Reset $auth<n> */
+driver_srcfile = authenticator_name = NULL; driver_srcline = 0;
 
 /* The value of authenticated_id is stored in the spool file and printed in
 log lines. It must not contain binary zeros or newline characters. In
@@ -4369,7 +4376,7 @@ while (done <= 0)
       if (!user_msg)
        {
        /* sender_host_name below will be tainted, so save on copy when we hit it */
-       g = string_get_tainted(24, TRUE);
+       g = string_get_tainted(24, GET_TAINTED);
        g = string_fmt_append(g, "%.3s %s Hello %s%s%s",
          smtp_code,
          smtp_active_hostname,
index e3316ed968f4912e04dc253c1d2ac18570b7dd9d..614c9ecc702e8062d60c14143233f81fd2f26f6f 100644 (file)
@@ -269,7 +269,7 @@ start = time(NULL);
     uschar * s;
 
     DEBUG(D_acl) debug_printf_indent("spamd: addr entry '%s'\n", address);
-    sd = store_get(sizeof(spamd_address_container), FALSE);
+    sd = store_get(sizeof(spamd_address_container), GET_UNTAINTED);
 
     for (sublist = address, args = 0, spamd_param_init(sd);
         (s = string_nextinlist(&sublist, &sublist_sep, NULL, 0));
index de6ee7e51ca12035c7cdb7f8adad6766c39b84a6..940baa4197abd5a822e678a3a242a6cca4342e83 100644 (file)
@@ -186,7 +186,7 @@ BOOL right = buffer[1] == 'Y';
 
 if (n < 5) return FALSE;    /* malformed line */
 buffer[n-1] = 0;            /* Remove \n */
-node = store_get(sizeof(tree_node) + n - 3, TRUE);     /* rcpt names tainted */
+node = store_get(sizeof(tree_node) + n - 3, GET_TAINTED);      /* rcpt names tainted */
 *connect = node;
 Ustrcpy(node->name, buffer + 3);
 node->data.ptr = NULL;
@@ -442,7 +442,7 @@ n = Ustrlen(big_buffer);
 if (n < 3 || big_buffer[0] != '<' || big_buffer[n-2] != '>')
   goto SPOOL_FORMAT_ERROR;
 
-sender_address = store_get(n-2, TRUE); /* tainted */
+sender_address = store_get(n-2, GET_TAINTED);
 Ustrncpy(sender_address, big_buffer+1, n-3);
 sender_address[n-3] = 0;
 
@@ -479,11 +479,13 @@ versions that do not understand them, just ignore any lines starting with "-"
 that we don't recognize. Otherwise it wouldn't be possible to back off a new
 version that left new-style flags written on the spool.
 
-If the line starts with "--" the content of the variable is tainted.  */
+If the line starts with "--" the content of the variable is tainted.
+If the line start "--(<lookuptype>)" it is also quoted for the given <lookuptype>.
+*/
 
 for (;;)
   {
-  BOOL tainted;
+  const void * proto_mem;
   uschar * var;
   const uschar * p;
 
@@ -491,8 +493,23 @@ for (;;)
   if (big_buffer[0] != '-') break;
   big_buffer[Ustrlen(big_buffer)-1] = 0;
 
-  tainted = big_buffer[1] == '-';
-  var =  big_buffer + (tainted ? 2 : 1);
+  proto_mem = big_buffer[1] == '-' ? GET_TAINTED : GET_UNTAINTED;
+  var =  big_buffer + (proto_mem == GET_UNTAINTED ? 1 : 2);
+  if (*var == '(')                             /* marker for quoted value */
+    {
+    uschar * s;
+    int idx;
+    for (s = ++var; *s != ')'; ) s++;
+#ifndef COMPILE_UTILITY
+    if ((idx = search_findtype(var, s - var)) < 0)
+      {
+      DEBUG(D_any) debug_printf("Unrecognised quoter %.*s\n", (int)(s - var), var+1);
+      goto SPOOL_FORMAT_ERROR;
+      }
+    proto_mem = store_get_quoted(1, GET_TAINTED, idx);
+#endif  /* COMPILE_UTILITY */
+    var = s + 1;
+    }
   p = var + 1;
 
   switch(*var)
@@ -516,7 +533,7 @@ for (;;)
         (int)(endptr - var - 5), var + 5);
       if (sscanf(CS endptr, " %d", &count) != 1) goto SPOOL_FORMAT_ERROR;
       node = acl_var_create(name);
-      node->data.ptr = store_get(count + 1, tainted);
+      node->data.ptr = store_get(count + 1, proto_mem);
       if (fread(node->data.ptr, 1, count+1, fp) < count) goto SPOOL_READ_ERROR;
       ((uschar*)node->data.ptr)[count] = 0;
       }
@@ -527,11 +544,11 @@ for (;;)
       f.allow_unqualified_sender = TRUE;
 
     else if (Ustrncmp(p, "uth_id", 6) == 0)
-      authenticated_id = string_copy_taint(var + 8, tainted);
+      authenticated_id = string_copy_taint(var + 8, proto_mem);
     else if (Ustrncmp(p, "uth_sender", 10) == 0)
-      authenticated_sender = string_copy_taint(var + 12, tainted);
+      authenticated_sender = string_copy_taint(var + 12, proto_mem);
     else if (Ustrncmp(p, "ctive_hostname", 14) == 0)
-      smtp_active_hostname = string_copy_taint(var + 16, tainted);
+      smtp_active_hostname = string_copy_taint(var + 16, proto_mem);
 
     /* For long-term backward compatibility, we recognize "-acl", which was
     used before the number of ACL variables changed from 10 to 20. This was
@@ -555,7 +572,7 @@ for (;;)
       else
         (void) string_format(name, sizeof(name), "%c%u", 'm', index - 10);
       node = acl_var_create(name);
-      node->data.ptr = store_get(count + 1, tainted);
+      node->data.ptr = store_get(count + 1, proto_mem);
       /* We sanity-checked the count, so disable the Coverity error */
       /* coverity[tainted_data] */
       if (fread(node->data.ptr, 1, count+1, fp) < count) goto SPOOL_READ_ERROR;
@@ -570,7 +587,7 @@ for (;;)
       body_zerocount = Uatoi(var + 14);
 #ifdef EXPERIMENTAL_BRIGHTMAIL
     else if (Ustrncmp(p, "mi_verdicts ", 12) == 0)
-      bmi_verdicts = string_copy_taint(var + 13, tainted);
+      bmi_verdicts = string_copy_taint(var + 13, proto_mem);
 #endif
     break;
 
@@ -581,7 +598,7 @@ for (;;)
     else if (Ustrncmp(p, "sn_ret", 6) == 0)
       dsn_ret= atoi(CS var + 7);
     else if (Ustrncmp(p, "sn_envid", 8) == 0)
-      dsn_envid = string_copy_taint(var + 10, tainted);
+      dsn_envid = string_copy_taint(var + 10, proto_mem);
     break;
 
     case 'f':
@@ -599,13 +616,13 @@ for (;;)
     else if (Ustrcmp(p, "ost_lookup_failed") == 0)
       host_lookup_failed = TRUE;
     else if (Ustrncmp(p, "ost_auth_pubname", 16) == 0)
-      sender_host_auth_pubname = string_copy_taint(var + 18, tainted);
+      sender_host_auth_pubname = string_copy_taint(var + 18, proto_mem);
     else if (Ustrncmp(p, "ost_auth", 8) == 0)
-      sender_host_authenticated = string_copy_taint(var + 10, tainted);
+      sender_host_authenticated = string_copy_taint(var + 10, proto_mem);
     else if (Ustrncmp(p, "ost_name", 8) == 0)
-      sender_host_name = string_copy_taint(var + 10, tainted);
+      sender_host_name = string_copy_taint(var + 10, proto_mem);
     else if (Ustrncmp(p, "elo_name", 8) == 0)
-      sender_helo_name = string_copy_taint(var + 10, tainted);
+      sender_helo_name = string_copy_taint(var + 10, proto_mem);
 
     /* We now record the port number after the address, separated by a
     dot. For compatibility during upgrading, do nothing if there
@@ -614,7 +631,7 @@ for (;;)
     else if (Ustrncmp(p, "ost_address", 11) == 0)
       {
       sender_host_port = host_address_extract_port(var + 13);
-      sender_host_address = string_copy_taint(var + 13, tainted);
+      sender_host_address = string_copy_taint(var + 13, proto_mem);
       }
     break;
 
@@ -622,10 +639,10 @@ for (;;)
     if (Ustrncmp(p, "nterface_address", 16) == 0)
       {
       interface_port = host_address_extract_port(var + 18);
-      interface_address = string_copy_taint(var + 18, tainted);
+      interface_address = string_copy_taint(var + 18, proto_mem);
       }
     else if (Ustrncmp(p, "dent", 4) == 0)
-      sender_ident = string_copy_taint(var + 6, tainted);
+      sender_ident = string_copy_taint(var + 6, proto_mem);
     break;
 
     case 'l':
@@ -635,7 +652,7 @@ for (;;)
       f.local_error_message = TRUE;
 #ifdef HAVE_LOCAL_SCAN
     else if (Ustrncmp(p, "ocal_scan ", 10) == 0)
-      local_scan_data = string_copy_taint(var + 11, tainted);
+      local_scan_data = string_copy_taint(var + 11, proto_mem);
 #endif
     break;
 
@@ -652,7 +669,7 @@ for (;;)
 
     case 'r':
     if (Ustrncmp(p, "eceived_protocol", 16) == 0)
-      received_protocol = string_copy_taint(var + 18, tainted);
+      received_protocol = string_copy_taint(var + 18, proto_mem);
     else if (Ustrncmp(p, "eceived_time_usec", 17) == 0)
       {
       unsigned usec;
@@ -678,11 +695,11 @@ for (;;)
       f.sender_set_untrusted = TRUE;
 #ifdef WITH_CONTENT_SCAN
     else if (Ustrncmp(p, "pam_bar ", 8) == 0)
-      spam_bar = string_copy_taint(var + 9, tainted);
+      spam_bar = string_copy_taint(var + 9, proto_mem);
     else if (Ustrncmp(p, "pam_score ", 10) == 0)
-      spam_score = string_copy_taint(var + 11, tainted);
+      spam_score = string_copy_taint(var + 11, proto_mem);
     else if (Ustrncmp(p, "pam_score_int ", 14) == 0)
-      spam_score_int = string_copy_taint(var + 15, tainted);
+      spam_score_int = string_copy_taint(var + 15, proto_mem);
 #endif
 #ifndef COMPILE_UTILITY
     else if (Ustrncmp(p, "pool_file_wireformat", 20) == 0)
@@ -702,7 +719,7 @@ for (;;)
       if (Ustrncmp(q, "certificate_verified", 20) == 0)
        tls_in.certificate_verified = TRUE;
       else if (Ustrncmp(q, "cipher", 6) == 0)
-       tls_in.cipher = string_copy_taint(q+7, tainted);
+       tls_in.cipher = string_copy_taint(q+7, proto_mem);
 # ifndef COMPILE_UTILITY       /* tls support fns not built in */
       else if (Ustrncmp(q, "ourcert", 7) == 0)
        (void) tls_import_cert(q+8, &tls_in.ourcert);
@@ -710,9 +727,9 @@ for (;;)
        (void) tls_import_cert(q+9, &tls_in.peercert);
 # endif
       else if (Ustrncmp(q, "peerdn", 6) == 0)
-       tls_in.peerdn = string_unprinting(string_copy_taint(q+7, tainted));
+       tls_in.peerdn = string_unprinting(string_copy_taint(q+7, proto_mem));
       else if (Ustrncmp(q, "sni", 3) == 0)
-       tls_in.sni = string_unprinting(string_copy_taint(q+4, tainted));
+       tls_in.sni = string_unprinting(string_copy_taint(q+4, proto_mem));
       else if (Ustrncmp(q, "ocsp", 4) == 0)
        tls_in.ocsp = q[5] - '0';
 # ifndef DISABLE_TLS_RESUME
@@ -720,7 +737,7 @@ for (;;)
        tls_in.resumption = q[11] - 'A';
 # endif
       else if (Ustrncmp(q, "ver", 3) == 0)
-       tls_in.ver = string_copy_taint(q+4, tainted);
+       tls_in.ver = string_copy_taint(q+4, proto_mem);
       }
     break;
 #endif
@@ -775,7 +792,7 @@ DEBUG(D_deliver) debug_printf_indent("recipients_count=%d\n", rcount);
 #endif  /* COMPILE_UTILITY */
 
 recipients_list_max = rcount;
-recipients_list = store_get(rcount * sizeof(recipient_item), FALSE);
+recipients_list = store_get(rcount * sizeof(recipient_item), GET_UNTAINTED);
 
 /* We sanitised the count and know we have enough memory, so disable
 the Coverity error on recipients_count */
@@ -875,7 +892,7 @@ for (recipients_count = 0; recipients_count < rcount; recipients_count++)
 
     (void)sscanf(CS p+1, "%d", &flags);
 
-    if ((flags & 0x01) != 0)      /* one_time data exists */
+    if (flags & 0x01)      /* one_time data exists */
       {
       int len;
       while (isdigit(*(--p)) || *p == ',' || *p == '-');
@@ -884,12 +901,12 @@ for (recipients_count = 0; recipients_count < rcount; recipients_count++)
       if (len > 0)
         {
         p -= len;
-        errors_to = string_copy_taint(p, TRUE);
+        errors_to = string_copy_taint(p, GET_TAINTED);
         }
       }
 
-    *(--p) = 0;   /* Terminate address */
-    if ((flags & 0x02) != 0)      /* one_time data exists */
+    *--p = 0;   /* Terminate address */
+    if (flags & 0x02)      /* one_time data exists */
       {
       int len;
       while (isdigit(*(--p)) || *p == ',' || *p == '-');
@@ -898,11 +915,11 @@ for (recipients_count = 0; recipients_count < rcount; recipients_count++)
       if (len > 0)
         {
         p -= len;
-        orcpt = string_copy_taint(p, TRUE);
+        orcpt = string_copy_taint(p, GET_TAINTED);
         }
       }
 
-    *(--p) = 0;   /* Terminate address */
+    *--p = 0;   /* Terminate address */
     }
 #if !defined(COMPILE_UTILITY)
   else
@@ -916,7 +933,7 @@ for (recipients_count = 0; recipients_count < rcount; recipients_count++)
       big_buffer, errors_to);
 #endif
 
-  recipients_list[recipients_count].address = string_copy_taint(big_buffer, TRUE);
+  recipients_list[recipients_count].address = string_copy_taint(big_buffer, GET_TAINTED);
   recipients_list[recipients_count].pno = pno;
   recipients_list[recipients_count].errors_to = errors_to;
   recipients_list[recipients_count].orcpt = orcpt;
@@ -948,11 +965,11 @@ while ((n = fgetc(fp)) != EOF)
 
   if (read_headers)
     {
-    h = store_get(sizeof(header_line), FALSE);
+    h = store_get(sizeof(header_line), GET_UNTAINTED);
     h->next = NULL;
     h->type = flag[0];
     h->slen = n;
-    h->text = store_get(n+1, TRUE);    /* tainted */
+    h->text = store_get(n+1, GET_TAINTED);
 
     if (h->type == htype_received) received_count++;
 
@@ -1055,7 +1072,7 @@ if (  Ufgets(big_buffer, big_buffer_size, fp) != NULL
    && big_buffer[0] == '<' && big_buffer[n-2] == '>'
    )
   {
-  yield = store_get(n-2, TRUE);        /* tainted */
+  yield = store_get(n-2, GET_TAINTED);
   Ustrncpy(yield, big_buffer+1, n-3);
   yield[n-3] = 0;
   }
index 13e8dd66436e212b4a9dc04afbf854dd96470f8b..d5cad86d48f8cc918f76fa0a54f5e75b283905e9 100644 (file)
@@ -120,8 +120,14 @@ return z;
 static void
 spool_var_write(FILE * fp, const uschar * name, const uschar * val)
 {
-if (is_tainted(val)) putc('-', fp);
-fprintf(fp, "-%s %s\n", name, val);
+putc('-', fp);
+if (is_tainted(val))
+  {
+  int q = quoter_for_address(val);
+  putc('-', fp);
+  if (is_real_quoter(q)) fprintf(fp, "(%s)", lookup_list[q]->name);
+  }
+fprintf(fp, "%s %s\n", name, val);
 }
 
 /*************************************************
index 8603a8fb11e568cef40de7e2b659e32554333c30..1e555cc18588ac4ec723b4249697023149f018f7 100644 (file)
@@ -44,7 +44,9 @@ The following different types of store are recognized:
 - There is a dedicated pool for configuration data read from the config file(s).
   Once complete, it is made readonly.
 
-. Orthogonal to the three pool types, there are two classes of memory: untainted
+- There are pools for each active combination of lookup-quoting, dynamically created.
+
+. Orthogonal to the four main pool types, there are two classes of memory: untainted
   and tainted.  The latter is used for values derived from untrusted input, and
   the string-expansion mechanism refuses to operate on such values (obviously,
   it can expand an untainted value to return a tainted result).  The classes
@@ -100,6 +102,38 @@ typedef struct storeblock {
   size_t length;
 } storeblock;
 
+/* Pool descriptor struct */
+
+typedef struct pooldesc {
+  storeblock * chainbase;              /* list of blocks in pool */
+  storeblock * current_block;          /* top block, still with free space */
+  void *       next_yield;             /* next allocation point */
+  int          yield_length;           /* remaining space in current block */
+  unsigned     store_block_order;      /* log2(size) block allocation size */
+
+  /* This variable is set by store_get() to its yield, and by store_reset() to
+  NULL. This enables string_cat() to optimize its store handling for very long
+  strings. That's why the variable is global. */
+
+  void *       store_last_get;
+
+  /* These are purely for stats-gathering */
+
+  int          nbytes;
+  int          maxbytes;
+  int          nblocks;
+  int          maxblocks;
+  unsigned     maxorder;
+} pooldesc;
+
+/* Enhanced pool descriptor for quoted pools */
+
+typedef struct quoted_pooldesc {
+  pooldesc                     pool;
+  unsigned                     quoter;
+  struct quoted_pooldesc *     next;
+} quoted_pooldesc;
+
 /* Just in case we find ourselves on a system where the structure above has a
 length that is not a multiple of the alignment, set up a macro for the padded
 length. */
@@ -131,11 +165,13 @@ even if the length is zero (which is used for getting a point to reset to). */
 
 int store_pool = POOL_MAIN;
 
-static storeblock *chainbase[NPOOLS];
-static storeblock *current_block[NPOOLS];
-static void *next_yield[NPOOLS];
-static int yield_length[NPOOLS];
-static unsigned store_block_order[NPOOLS];
+pooldesc paired_pools[N_PAIRED_POOLS];
+quoted_pooldesc * quoted_pools = NULL;
+
+static int n_nonpool_blocks;   /* current number of direct store_malloc() blocks */
+static int max_nonpool_blocks;
+static int max_pool_malloc;    /* max value for pool_malloc */
+static int max_nonpool_malloc; /* max value for nonpool_malloc */
 
 /* pool_malloc holds the amount of memory used by the store pools; this goes up
 and down as store is reset or released. nonpool_malloc is the total got by
@@ -145,27 +181,9 @@ pointer. */
 static int pool_malloc;
 static int nonpool_malloc;
 
-/* This variable is set by store_get() to its yield, and by store_reset() to
-NULL. This enables string_cat() to optimize its store handling for very long
-strings. That's why the variable is global. */
-
-void *store_last_get[NPOOLS];
-
-/* These are purely for stats-gathering */
-
-static int nbytes[NPOOLS];     /* current bytes allocated */
-static int maxbytes[NPOOLS];   /* max number reached */
-static int nblocks[NPOOLS];    /* current number of blocks allocated */
-static int maxblocks[NPOOLS];
-static unsigned maxorder[NPOOLS];
-static int n_nonpool_blocks;   /* current number of direct store_malloc() blocks */
-static int max_nonpool_blocks;
-static int max_pool_malloc;    /* max value for pool_malloc */
-static int max_nonpool_malloc; /* max value for nonpool_malloc */
-
 
 #ifndef COMPILE_UTILITY
-static const uschar * pooluse[NPOOLS] = {
+static const uschar * pooluse[N_PAIRED_POOLS] = {
 [POOL_MAIN] =          US"main",
 [POOL_PERM] =          US"perm",
 [POOL_CONFIG] =                US"config",
@@ -177,7 +195,7 @@ static const uschar * pooluse[NPOOLS] = {
 [POOL_TAINT_SEARCH] =  US"search",
 [POOL_TAINT_MESSAGE] = US"message",
 };
-static const uschar * poolclass[NPOOLS] = {
+static const uschar * poolclass[N_PAIRED_POOLS] = {
 [POOL_MAIN] =          US"untainted",
 [POOL_PERM] =          US"untainted",
 [POOL_CONFIG] =                US"untainted",
@@ -196,21 +214,71 @@ static void * internal_store_malloc(size_t, const char *, int);
 static void   internal_store_free(void *, const char *, int linenumber);
 
 /******************************************************************************/
+
+static void
+pool_init(pooldesc * pp)
+{
+memset(pp, 0, sizeof(*pp));
+pp->yield_length = -1;
+pp->store_block_order = 12; /* log2(allocation_size) ie. 4kB */
+}
+
 /* Initialisation, for things fragile with parameter channges when using
 static initialisers. */
 
 void
 store_init(void)
 {
-for (int i = 0; i < NPOOLS; i++)
-  {
-  yield_length[i] = -1;
-  store_block_order[i] = 12; /* log2(allocation_size) ie. 4kB */
-  }
+for (pooldesc * pp = paired_pools; pp < paired_pools + N_PAIRED_POOLS; pp++)
+  pool_init(pp);
 }
 
 /******************************************************************************/
+/* Locating elements given memory pointer */
+
+static BOOL
+is_pointer_in_block(const storeblock * b, const void * p)
+{
+uschar * bc = US b + ALIGNED_SIZEOF_STOREBLOCK;
+return US p >= bc && US p < bc + b->length;
+}
+
+static pooldesc *
+pool_current_for_pointer(const void * p)
+{
+storeblock * b;
+
+for (quoted_pooldesc * qp = quoted_pools; qp; qp = qp->next)
+  if ((b = qp->pool.current_block) && is_pointer_in_block(b, p))
+    return &qp->pool;
+
+for (pooldesc * pp = paired_pools; pp < paired_pools + N_PAIRED_POOLS; pp++)
+  if ((b = pp->current_block) && is_pointer_in_block(b, p))
+    return pp;
+return NULL;
+}
 
+static pooldesc *
+pool_for_pointer(const void * p)
+{
+pooldesc * pp;
+storeblock * b;
+
+if ((pp = pool_current_for_pointer(p))) return pp;
+
+for (quoted_pooldesc * qp = quoted_pools; qp; qp = qp->next)
+  for (b = qp->pool.chainbase; b; b = b->next)
+    if (is_pointer_in_block(b, p)) return &qp->pool;
+
+for (pp = paired_pools; pp < paired_pools + N_PAIRED_POOLS; pp++)
+  for (b = pp->chainbase; b; b = b->next)
+    if (is_pointer_in_block(b, p)) return pp;
+
+log_write(0, LOG_MAIN|LOG_PANIC_DIE, "bad memory reference; pool not found");
+return NULL;
+}
+
+/******************************************************************************/
 /* Test if a pointer refers to tainted memory.
 
 Slower version check, for use when platform intermixes malloc and mmap area
@@ -225,19 +293,27 @@ is_tainted_fn(const void * p)
 {
 storeblock * b;
 
-for (int pool = POOL_TAINT_BASE; pool < nelem(chainbase); pool++)
-  if ((b = current_block[pool]))
-    {
-    uschar * bc = US b + ALIGNED_SIZEOF_STOREBLOCK;
-    if (US p >= bc && US p < bc + b->length) return TRUE;
-    }
+if (p == GET_UNTAINTED) return FALSE;
+if (p == GET_TAINTED) return TRUE;
+
+for (pooldesc * pp = paired_pools + POOL_TAINT_BASE;
+     pp < paired_pools + N_PAIRED_POOLS; pp++)
+  if ((b = pp->current_block))
+    if (is_pointer_in_block(b, p)) return TRUE;
+
+for (quoted_pooldesc * qp = quoted_pools; qp; qp = qp->next)
+  if (b = qp->pool.current_block)
+    if (is_pointer_in_block(b, p)) return TRUE;
+
+for (pooldesc * pp = paired_pools + POOL_TAINT_BASE;
+     pp < paired_pools + N_PAIRED_POOLS; pp++)
+  for (b = pp->chainbase; b; b = b->next)
+    if (is_pointer_in_block(b, p)) return TRUE;
+
+for (quoted_pooldesc * qp = quoted_pools; qp; qp = qp->next)
+  for (b = qp->pool.chainbase; b; b = b->next)
+    if (is_pointer_in_block(b, p)) return TRUE;
 
-for (int pool = POOL_TAINT_BASE; pool < nelem(chainbase); pool++)
-  for (b = chainbase[pool]; b; b = b->next)
-    {
-    uschar * bc = US b + ALIGNED_SIZEOF_STOREBLOCK;
-    if (US p >= bc && US p < bc + b->length) return TRUE;
-    }
 return FALSE;
 }
 
@@ -250,13 +326,41 @@ log_write(0, LOG_MAIN|LOG_PANIC_DIE, "Taint mismatch, %s: %s %d\n",
 }
 
 
+#ifndef COMPILE_UTILITY
+/* Return the pool for the given quoter, or null */
+
+static pooldesc *
+pool_for_quoter(unsigned quoter)
+{
+for (quoted_pooldesc * qp = quoted_pools; qp; qp = qp->next)
+  if (qp->quoter == quoter)
+    return &qp->pool;
+return NULL;
+}
+
+/* Allocate/init a new quoted-pool and return the pool */
+
+static pooldesc *
+quoted_pool_new(unsigned quoter)
+{
+// debug_printf("allocating quoted-pool\n");
+quoted_pooldesc * qp = store_get_perm(sizeof(quoted_pooldesc), GET_UNTAINTED);
+
+pool_init(&qp->pool);
+qp->quoter = quoter;
+qp->next = quoted_pools;
+quoted_pools = qp;
+return &qp->pool;
+}
+#endif
+
 
 /******************************************************************************/
 void
 store_writeprotect(int pool)
 {
 #if !defined(COMPILE_UTILITY) && !defined(MISSING_POSIX_MEMALIGN)
-for (storeblock * b = chainbase[pool]; b; b = b->next)
+for (storeblock * b =  paired_pools[pool].chainbase; b; b = b->next)
   if (mprotect(b, ALIGNED_SIZEOF_STOREBLOCK + b->length, PROT_READ) != 0)
     DEBUG(D_any) debug_printf("config block mprotect: (%d) %s\n", errno, strerror(errno));
 #endif
@@ -264,29 +368,9 @@ for (storeblock * b = chainbase[pool]; b; b = b->next)
 
 /******************************************************************************/
 
-/*************************************************
-*       Get a block from the current pool        *
-*************************************************/
-
-/* Running out of store is a total disaster. This function is called via the
-macro store_get(). It passes back a block of store within the current big
-block, getting a new one if necessary. The address is saved in
-store_last_was_get.
-
-Arguments:
-  size        amount wanted, bytes
-  tainted     class: set to true for untrusted data (eg. from smtp input)
-  func        function from which called
-  linenumber  line number in source file
-
-Returns:      pointer to store (panic on malloc failure)
-*/
-
-void *
-store_get_3(int size, BOOL tainted, const char * func, int linenumber)
+static void *
+pool_get(pooldesc * pp, int size, BOOL align_mem, const char * func, int linenumber)
 {
-int pool = tainted ? store_pool + POOL_TAINT_BASE : store_pool;
-
 /* Ensure we've been asked to allocate memory.
 A negative size is a sign of a security problem.
 A zero size might be also suspect, but our internal usage deliberately
@@ -310,23 +394,23 @@ if (size % alignment != 0) size += alignment - (size % alignment);
 size is STORE_BLOCK_SIZE, and we would expect this to be the norm, since
 these functions are mostly called for small amounts of store. */
 
-if (size > yield_length[pool])
+if (size > pp->yield_length)
   {
   int length = MAX(
-         STORE_BLOCK_SIZE(store_block_order[pool]) - ALIGNED_SIZEOF_STOREBLOCK,
+         STORE_BLOCK_SIZE(pp->store_block_order) - ALIGNED_SIZEOF_STOREBLOCK,
          size);
   int mlength = length + ALIGNED_SIZEOF_STOREBLOCK;
   storeblock * newblock;
 
   /* Sometimes store_reset() may leave a block for us; check if we can use it */
 
-  if (  (newblock = current_block[pool])
+  if (  (newblock = pp->current_block)
      && (newblock = newblock->next)
      && newblock->length < length
      )
     {
     /* Give up on this block, because it's too small */
-    nblocks[pool]--;
+    pp->nblocks--;
     internal_store_free(newblock, func, linenumber);
     newblock = NULL;
     }
@@ -335,16 +419,16 @@ if (size > yield_length[pool])
 
   if (!newblock)
     {
-    if ((nbytes[pool] += mlength) > maxbytes[pool])
-      maxbytes[pool] = nbytes[pool];
+    if ((pp->nbytes += mlength) > pp->maxbytes)
+      pp->maxbytes = pp->nbytes;
     if ((pool_malloc += mlength) > max_pool_malloc)    /* Used in pools */
       max_pool_malloc = pool_malloc;
     nonpool_malloc -= mlength;                 /* Exclude from overall total */
-    if (++nblocks[pool] > maxblocks[pool])
-      maxblocks[pool] = nblocks[pool];
+    if (++pp->nblocks > pp->maxblocks)
+      pp->maxblocks = pp->nblocks;
 
 #ifndef MISSING_POSIX_MEMALIGN
-    if (pool == POOL_CONFIG)
+    if (align_mem)
       {
       long pgsize = sysconf(_SC_PAGESIZE);
       int err = posix_memalign((void **)&newblock,
@@ -361,43 +445,97 @@ if (size > yield_length[pool])
     newblock->next = NULL;
     newblock->length = length;
 #ifndef RESTRICTED_MEMORY
-    if (store_block_order[pool]++ > maxorder[pool])
-      maxorder[pool] = store_block_order[pool];
+    if (pp->store_block_order++ > pp->maxorder)
+      pp->maxorder = pp->store_block_order;
 #endif
 
-    if (!chainbase[pool])
-      chainbase[pool] = newblock;
+    if (! pp->chainbase)
+       pp->chainbase = newblock;
     else
-      current_block[pool]->next = newblock;
+      pp->current_block->next = newblock;
     }
 
-  current_block[pool] = newblock;
-  yield_length[pool] = newblock->length;
-  next_yield[pool] =
-    (void *)(CS current_block[pool] + ALIGNED_SIZEOF_STOREBLOCK);
-  (void) VALGRIND_MAKE_MEM_NOACCESS(next_yield[pool], yield_length[pool]);
+  pp->current_block = newblock;
+  pp->yield_length = newblock->length;
+  pp->next_yield =
+    (void *)(CS pp->current_block + ALIGNED_SIZEOF_STOREBLOCK);
+  (void) VALGRIND_MAKE_MEM_NOACCESS(pp->next_yield, pp->yield_length);
   }
 
 /* There's (now) enough room in the current block; the yield is the next
 pointer. */
 
-store_last_get[pool] = next_yield[pool];
+pp->store_last_get = pp->next_yield;
 
-/* Cut out the debugging stuff for utilities, but stop picky compilers from
-giving warnings. */
+(void) VALGRIND_MAKE_MEM_UNDEFINED(pp->store_last_get, size);
+/* Update next pointer and number of bytes left in the current block. */
+
+pp->next_yield = (void *)(CS pp->next_yield + size);
+pp->yield_length -= size;
+return pp->store_last_get;
+}
+
+/*************************************************
+*       Get a block from the current pool        *
+*************************************************/
+
+/* Running out of store is a total disaster. This function is called via the
+macro store_get(). The current store_pool is used, adjusting for taint.
+If the protoype is quoted, use a quoted-pool.
+Return a block of store within the current big block of the pool, getting a new
+one if necessary. The address is saved in store_last_get for the pool.
+
+Arguments:
+  size        amount wanted, bytes
+  proto_mem   class: get store conformant to this
+               Special values: 0 forces untainted, 1 forces tainted
+  func        function from which called
+  linenumber  line number in source file
+
+Returns:      pointer to store (panic on malloc failure)
+*/
 
+void *
+store_get_3(int size, const void * proto_mem, const char * func, int linenumber)
+{
 #ifndef COMPILE_UTILITY
-DEBUG(D_memory)
-  debug_printf("---%d Get %6p %5d %-14s %4d\n", pool,
-    store_last_get[pool], size, func, linenumber);
-#endif  /* COMPILE_UTILITY */
+int quoter = quoter_for_address(proto_mem);
+#endif
+pooldesc * pp;
+void * yield;
 
-(void) VALGRIND_MAKE_MEM_UNDEFINED(store_last_get[pool], size);
-/* Update next pointer and number of bytes left in the current block. */
+#ifndef COMPILE_UTILITY
+if (!is_real_quoter(quoter))
+#endif
+  {
+  BOOL tainted = is_tainted(proto_mem);
+  int pool = tainted ? store_pool + POOL_TAINT_BASE : store_pool;
+  pp = paired_pools + pool;
+  yield = pool_get(pp, size, (pool == POOL_CONFIG), func, linenumber);
 
-next_yield[pool] = (void *)(CS next_yield[pool] + size);
-yield_length[pool] -= size;
-return store_last_get[pool];
+  /* Cut out the debugging stuff for utilities, but stop picky compilers from
+  giving warnings. */
+
+#ifndef COMPILE_UTILITY
+  DEBUG(D_memory)
+    debug_printf("---%d Get %6p %5d %-14s %4d\n", pool,
+      pp->store_last_get, size, func, linenumber);
+#endif
+  }
+#ifndef COMPILE_UTILITY
+else
+  {
+  DEBUG(D_memory)
+    debug_printf("allocating quoted-block for quoter %u (from %s %d)\n",
+      quoter, func, linenumber);
+  if (!(pp = pool_for_quoter(quoter))) pp = quoted_pool_new(quoter);
+  yield = pool_get(pp, size, FALSE, func, linenumber);
+  DEBUG(D_memory)
+    debug_printf("---QQ Get %6p %5d %-14s %4d\n",
+      pp->store_last_get, size, func, linenumber);
+  }
+#endif
+return yield;
 }
 
 
@@ -411,6 +549,7 @@ be obtained.
 
 Arguments:
   size        amount wanted
+  proto_mem   class: get store conformant to this
   func        function from which called
   linenumber  line number in source file
 
@@ -418,17 +557,131 @@ Returns:      pointer to store (panic on malloc failure)
 */
 
 void *
-store_get_perm_3(int size, BOOL tainted, const char * func, int linenumber)
+store_get_perm_3(int size, const void * proto_mem, const char * func, int linenumber)
 {
 void * yield;
 int old_pool = store_pool;
 store_pool = POOL_PERM;
-yield = store_get_3(size, tainted, func, linenumber);
+yield = store_get_3(size, proto_mem, func, linenumber);
 store_pool = old_pool;
 return yield;
 }
 
 
+#ifndef COMPILE_UTILITY
+/*************************************************
+*  Get a block annotated as being lookup-quoted  *
+*************************************************/
+
+/* Allocate from pool a pool consistent with the proto_mem augmented by the
+requested quoter type.
+
+XXX currently not handling mark/release
+
+Args:  size            number of bytes to allocate
+       quoter          id for the quoting type
+       func            caller, for debug
+       linenumber      caller, for debug
+
+Return:        allocated memory block
+*/
+
+static void *
+store_force_get_quoted(int size, unsigned quoter,
+  const char * func, int linenumber)
+{
+pooldesc * pp = pool_for_quoter(quoter);
+void * yield;
+
+DEBUG(D_memory)
+  debug_printf("allocating quoted-block for quoter %u (from %s %d)\n", quoter, func, linenumber);
+
+if (!pp) pp = quoted_pool_new(quoter);
+yield = pool_get(pp, size, FALSE, func, linenumber);
+
+DEBUG(D_memory)
+  debug_printf("---QQ Get %6p %5d %-14s %4d\n",
+    pp->store_last_get, size, func, linenumber);
+
+return yield;
+}
+
+/* Maybe get memory for the specified quoter, but only if the
+prototype memory is tainted. Otherwise, get plain memory.
+*/
+void *
+store_get_quoted_3(int size, const void * proto_mem, unsigned quoter,
+  const char * func, int linenumber)
+{
+// debug_printf("store_get_quoted_3: quoter %u\n", quoter);
+return is_tainted(proto_mem)
+  ? store_force_get_quoted(size, quoter, func, linenumber)
+  : store_get_3(size, proto_mem, func, linenumber);
+}
+
+/* Return quoter for given address, or -1 if not in a quoted-pool. */
+int
+quoter_for_address(const void * p)
+{
+for (quoted_pooldesc * qp = quoted_pools; qp; qp = qp->next)
+  {
+  pooldesc * pp = &qp->pool;
+  storeblock * b;
+
+  if (b = pp->current_block)
+    if (is_pointer_in_block(b, p))
+      return qp->quoter;
+
+  for (b = pp->chainbase; b; b = b->next)
+    if (is_pointer_in_block(b, p))
+      return qp->quoter;
+  }
+return -1;
+}
+
+/* Return TRUE iff the given address is quoted for the given type.
+There is extra complexity to handle lookup providers with multiple
+find variants but shared quote functions. */
+BOOL
+is_quoted_like(const void * p, unsigned quoter)
+{
+int pq = quoter_for_address(p);
+BOOL y =
+  is_real_quoter(pq) && lookup_list[pq]->quote == lookup_list[quoter]->quote;
+/* debug_printf("is_quoted(%p, %u): %c\n", p, quoter, y?'T':'F'); */
+return y;
+}
+
+/* Return TRUE if the quoter value indicates an actual quoter */
+BOOL
+is_real_quoter(int quoter)
+{
+return quoter >= 0;
+}
+
+/* Return TRUE if the "new" data requires that the "old" data
+be recopied to new-class memory.  We order the classes as
+
+  2: tainted, not quoted
+  1: quoted (which is also tainted)
+  0: untainted
+
+If the "new" is higher-order than the "old", they are not compatible
+and a copy is needed.  If both are quoted, but the quoters differ,
+not compatible.  Otherwise they are compatible.
+*/
+BOOL
+is_incompatible_fn(const void * old, const void * new)
+{
+int oq, nq;
+unsigned oi, ni;
+
+ni = is_real_quoter(nq = quoter_for_address(new)) ? 1 : is_tainted(new) ? 2 : 0;
+oi = is_real_quoter(oq = quoter_for_address(old)) ? 1 : is_tainted(old) ? 2 : 0;
+return ni > oi || ni == oi && nq != oq;
+}
+
+#endif /*!COMPILE_UTILITY*/
 
 /*************************************************
 *      Extend a block if it is at the top        *
@@ -451,13 +704,16 @@ Arguments:
 Returns:     TRUE if the block is at the top of the stack and has been
              extended; FALSE if it isn't at the top of the stack, or cannot
              be extended
+
+XXX needs extension for quoted-tracking.  This assumes that the global store_pool
+is the one to alloc from, which breaks with separated pools.
 */
 
 BOOL
-store_extend_3(void *ptr, BOOL tainted, int oldsize, int newsize,
-   const char *func, int linenumber)
+store_extend_3(void * ptr, int oldsize, int newsize,
+   const char * func, int linenumber)
 {
-int pool = tainted ? store_pool + POOL_TAINT_BASE : store_pool;
+pooldesc * pp = pool_for_pointer(ptr);
 int inc = newsize - oldsize;
 int rounded_oldsize = oldsize;
 
@@ -466,17 +722,11 @@ if (oldsize < 0 || newsize < oldsize || newsize >= INT_MAX/2)
             "bad memory extension requested (%d -> %d bytes) at %s %d",
             oldsize, newsize, func, linenumber);
 
-/* Check that the block being extended was already of the required taint status;
-refuse to extend if not. */
-
-if (is_tainted(ptr) != tainted)
-  return FALSE;
-
 if (rounded_oldsize % alignment != 0)
   rounded_oldsize += alignment - (rounded_oldsize % alignment);
 
-if (CS ptr + rounded_oldsize != CS (next_yield[pool]) ||
-    inc > yield_length[pool] + rounded_oldsize - oldsize)
+if (CS ptr + rounded_oldsize != CS (pp->next_yield) ||
+    inc > pp->yield_length + rounded_oldsize - oldsize)
   return FALSE;
 
 /* Cut out the debugging stuff for utilities, but stop picky compilers from
@@ -484,13 +734,26 @@ giving warnings. */
 
 #ifndef COMPILE_UTILITY
 DEBUG(D_memory)
-  debug_printf("---%d Ext %6p %5d %-14s %4d\n", pool, ptr, newsize,
-    func, linenumber);
+  {
+  quoted_pooldesc * qp;
+  for (qp = quoted_pools; qp; qp = qp->next)
+    if (pp == &qp->pool)
+      {
+      debug_printf("---Q%d Ext %6p %5d %-14s %4d\n",
+       (int)(qp - quoted_pools),
+       ptr, newsize, func, linenumber);
+      break;
+      }
+  if (!qp)
+    debug_printf("---%d Ext %6p %5d %-14s %4d\n",
+      (int)(pp - paired_pools),
+      ptr, newsize, func, linenumber);
+  }
 #endif  /* COMPILE_UTILITY */
 
 if (newsize % alignment != 0) newsize += alignment - (newsize % alignment);
-next_yield[pool] = CS ptr + newsize;
-yield_length[pool] -= newsize - rounded_oldsize;
+pp->next_yield = CS ptr + newsize;
+pp->yield_length -= newsize - rounded_oldsize;
 (void) VALGRIND_MAKE_MEM_UNDEFINED(ptr + oldsize, inc);
 return TRUE;
 }
@@ -515,6 +778,8 @@ that are now unused. Call with a cookie obtained from store_mark() only; do
 not call with a pointer returned by store_get().  Both the untainted and tainted
 pools corresposding to store_pool are reset.
 
+Quoted pools are not handled.
+
 Arguments:
   ptr         place to back up to
   pool       pool holding the pointer
@@ -528,23 +793,26 @@ static void
 internal_store_reset(void * ptr, int pool, const char *func, int linenumber)
 {
 storeblock * bb;
-storeblock * b = current_block[pool];
+pooldesc * pp = paired_pools + pool;
+storeblock * b = pp->current_block;
 char * bc = CS b + ALIGNED_SIZEOF_STOREBLOCK;
 int newlength, count;
 #ifndef COMPILE_UTILITY
 int oldmalloc = pool_malloc;
 #endif
 
+if (!b) return;        /* exim_dumpdb gets this, becuse it has never used tainted mem */
+
 /* Last store operation was not a get */
 
-store_last_get[pool] = NULL;
+pp->store_last_get = NULL;
 
 /* See if the place is in the current block - as it often will be. Otherwise,
 search for the block in which it lies. */
 
 if (CS ptr < bc || CS ptr > bc + b->length)
   {
-  for (b = chainbase[pool]; b; b = b->next)
+  for (b =  pp->chainbase; b; b = b->next)
     {
     bc = CS b + ALIGNED_SIZEOF_STOREBLOCK;
     if (CS ptr >= bc && CS ptr <= bc + b->length) break;
@@ -570,17 +838,17 @@ if (debug_store)
   }
 #endif
 (void) VALGRIND_MAKE_MEM_NOACCESS(ptr, newlength);
-next_yield[pool] = CS ptr + (newlength % alignment);
-count = yield_length[pool];
-count = (yield_length[pool] = newlength - (newlength % alignment)) - count;
-current_block[pool] = b;
+pp->next_yield = CS ptr + (newlength % alignment);
+count = pp->yield_length;
+count = (pp->yield_length = newlength - (newlength % alignment)) - count;
+pp->current_block = b;
 
 /* Free any subsequent block. Do NOT free the first
 successor, if our current block has less than 256 bytes left. This should
 prevent us from flapping memory. However, keep this block only when it has
 a power-of-two size so probably is not a custom inflated one. */
 
-if (  yield_length[pool] < STOREPOOL_MIN_SIZE
+if (  pp->yield_length < STOREPOOL_MIN_SIZE
    && b->next
    && is_pwr2_size(b->next->length + ALIGNED_SIZEOF_STOREBLOCK))
   {
@@ -608,14 +876,14 @@ while ((b = bb))
                        func, linenumber);
 #endif
   bb = bb->next;
-  nbytes[pool] -= siz;
+  pp->nbytes -= siz;
   pool_malloc -= siz;
-  nblocks[pool]--;
+  pp->nblocks--;
   if (pool != POOL_CONFIG)
     internal_store_free(b, func, linenumber);
 
 #ifndef RESTRICTED_MEMORY
-  if (store_block_order[pool] > 13) store_block_order[pool]--;
+  if (pp->store_block_order > 13) pp->store_block_order--;
 #endif
   }
 
@@ -631,8 +899,12 @@ DEBUG(D_memory)
 }
 
 
+/* Back up the pool pair, untainted and tainted, of the store_pool setting.
+Quoted pools are not handled.
+*/
+
 rmark
-store_reset_3(rmark r, const char *func, int linenumber)
+store_reset_3(rmark r, const char * func, int linenumber)
 {
 void ** ptr = r;
 
@@ -649,6 +921,7 @@ return NULL;
 }
 
 
+/**************/
 
 /* Free tail-end unused allocation.  This lets us allocate a big chunk
 early, for cases when we only discover later how much was really needed.
@@ -661,32 +934,26 @@ XXX needs rationalising
 */
 
 void
-store_release_above_3(void *ptr, const char *func, int linenumber)
+store_release_above_3(void * ptr, const char * func, int linenumber)
 {
+pooldesc * pp;
+
 /* Search all pools' "current" blocks.  If it isn't one of those,
 ignore it (it usually will be). */
 
-for (int pool = 0; pool < nelem(current_block); pool++)
+if ((pp = pool_current_for_pointer(ptr)))
   {
-  storeblock * b = current_block[pool];
-  char * bc;
+  storeblock * b = pp->current_block;
   int count, newlength;
 
-  if (!b)
-    continue;
-
-  bc = CS b + ALIGNED_SIZEOF_STOREBLOCK;
-  if (CS ptr < bc || CS ptr > bc + b->length)
-    continue;
-
   /* Last store operation was not a get */
 
-  store_last_get[pool] = NULL;
+  pp->store_last_get = NULL;
 
   /* Back up, rounding to the alignment if necessary. When testing, flatten
   the released memory. */
 
-  newlength = bc + b->length - CS ptr;
+  newlength = (CS b + ALIGNED_SIZEOF_STOREBLOCK) + b->length - CS ptr;
 #ifndef COMPILE_UTILITY
   if (debug_store)
     {
@@ -699,17 +966,27 @@ for (int pool = 0; pool < nelem(current_block); pool++)
     }
 #endif
   (void) VALGRIND_MAKE_MEM_NOACCESS(ptr, newlength);
-  next_yield[pool] = CS ptr + (newlength % alignment);
-  count = yield_length[pool];
-  count = (yield_length[pool] = newlength - (newlength % alignment)) - count;
+  pp->next_yield = CS ptr + (newlength % alignment);
+  count = pp->yield_length;
+  count = (pp->yield_length = newlength - (newlength % alignment)) - count;
 
   /* Cut out the debugging stuff for utilities, but stop picky compilers from
   giving warnings. */
 
 #ifndef COMPILE_UTILITY
   DEBUG(D_memory)
-    debug_printf("---%d Rel %6p %5d %-14s %4d\tpool %d\n", pool, ptr, count,
-      func, linenumber, pool_malloc);
+    {
+    quoted_pooldesc * qp;
+    for (qp = quoted_pools; qp; qp = qp->next)
+      if (pp == &qp->pool)
+       debug_printf("---Q%d Rel %6p %5d %-14s %4d\tpool %d\n",
+         (int)(qp - quoted_pools),
+         ptr, count, func, linenumber, pool_malloc);
+    if (!qp)
+      debug_printf("---%d Rel %6p %5d %-14s %4d\tpool %d\n",
+       (int)(pp - paired_pools), ptr, count,
+       func, linenumber, pool_malloc);
+    }
 #endif
   return;
   }
@@ -722,7 +999,7 @@ DEBUG(D_memory)
 
 
 rmark
-store_mark_3(const char *func, int linenumber)
+store_mark_3(const char * func, int linenumber)
 {
 void ** p;
 
@@ -741,8 +1018,8 @@ a cookie (actually the address in the untainted pool) to the caller.
 Reset uses the cookie to recover the t-mark, winds back the tainted pool with it
 and winds back the untainted pool with the cookie. */
 
-p = store_get_3(sizeof(void *), FALSE, func, linenumber);
-*p = store_get_3(0, TRUE, func, linenumber);
+p = store_get_3(sizeof(void *), GET_UNTAINTED, func, linenumber);
+*p = store_get_3(0, GET_TAINTED, func, linenumber);
 return p;
 }
 
@@ -758,6 +1035,7 @@ block, and if so, releases that block.
 
 Arguments:
   block       block of store to consider
+  pp         pool containing the block
   func        function from which called
   linenumber  line number in source file
 
@@ -765,20 +1043,20 @@ Returns:      nothing
 */
 
 static void
-store_release_3(void * block, int pool, const char * func, int linenumber)
+store_release_3(void * block, pooldesc * pp, const char * func, int linenumber)
 {
 /* It will never be the first block, so no need to check that. */
 
-for (storeblock * b = chainbase[pool]; b; b = b->next)
+for (storeblock * b =  pp->chainbase; b; b = b->next)
   {
   storeblock * bb = b->next;
   if (bb && CS block == CS bb + ALIGNED_SIZEOF_STOREBLOCK)
     {
     int siz = bb->length + ALIGNED_SIZEOF_STOREBLOCK;
     b->next = bb->next;
-    nbytes[pool] -= siz;
+    pp->nbytes -= siz;
     pool_malloc -= siz;
-    nblocks[pool]--;
+    pp->nblocks--;
 
     /* Cut out the debugging stuff for utilities, but stop picky compilers
     from giving warnings. */
@@ -816,35 +1094,30 @@ the pointer it is given is the first thing in a block, and that nothing
 has been allocated since. If so, releases that block.
 
 Arguments:
-  block
-  newsize
-  len
+  oldblock
+  newsize      requested size
+  len          current size
 
 Returns:       new location of data
 */
 
 void *
-store_newblock_3(void * block, BOOL tainted, int newsize, int len,
+store_newblock_3(void * oldblock, int newsize, int len,
   const char * func, int linenumber)
 {
-int pool = tainted ? store_pool + POOL_TAINT_BASE : store_pool;
-BOOL release_ok = !tainted && store_last_get[pool] == block;
-uschar * newtext;
-
-#if !defined(MACRO_PREDEF) && !defined(COMPILE_UTILITY)
-if (is_tainted(block) != tainted)
-  die_tainted(US"store_newblock", CUS func, linenumber);
-#endif
+pooldesc * pp = pool_for_pointer(oldblock);
+BOOL release_ok = !is_tainted(oldblock) && pp->store_last_get == oldblock;             /*XXX why tainted not handled? */
+uschar * newblock;
 
 if (len < 0 || len > newsize)
   log_write(0, LOG_MAIN|LOG_PANIC_DIE,
             "bad memory extension requested (%d -> %d bytes) at %s %d",
             len, newsize, func, linenumber);
 
-newtext = store_get(newsize, tainted);
-memcpy(newtext, block, len);
-if (release_ok) store_release_3(block, pool, func, linenumber);
-return (void *)newtext;
+newblock = store_get(newsize, oldblock);
+memcpy(newblock, oldblock, len);
+if (release_ok) store_release_3(oldblock, pp, func, linenumber);
+return (void *)newblock;
 }
 
 
@@ -960,13 +1233,25 @@ store_exit(void)
 #ifndef COMPILE_UTILITY
 DEBUG(D_memory)
  {
+ int i;
  debug_printf("----Exit nonpool max: %3d kB in %d blocks\n",
   (max_nonpool_malloc+1023)/1024, max_nonpool_blocks);
  debug_printf("----Exit npools  max: %3d kB\n", max_pool_malloc/1024);
- for (int i = 0; i < NPOOLS; i++)
-  debug_printf("----Exit  pool %d max: %3d kB in %d blocks at order %u\t%s %s\n",
-    i, (maxbytes[i]+1023)/1024, maxblocks[i], maxorder[i],
+
+ for (i = 0; i < N_PAIRED_POOLS; i++)
+   {
+   pooldesc * pp = paired_pools + i;
+   debug_printf("----Exit  pool %2d max: %3d kB in %d blocks at order %u\t%s %s\n",
+    i, (pp->maxbytes+1023)/1024, pp->maxblocks, pp->maxorder,
     poolclass[i], pooluse[i]);
+   }
+ i = 0;
+ for (quoted_pooldesc * qp = quoted_pools; qp; i++, qp = qp->next)
+   {
+   pooldesc * pp = &qp->pool;
+   debug_printf("----Exit  pool Q%d max: %3d kB in %d blocks at order %u\ttainted quoted:%s\n",
+    i, (pp->maxbytes+1023)/1024, pp->maxblocks, pp->maxorder, lookup_list[qp->quoter]->name);
+   }
  }
 #endif
 }
@@ -986,7 +1271,8 @@ if (!message_reset_point) message_reset_point = store_mark();
 store_pool = oldpool;
 }
 
-void message_tidyup(void)
+void
+message_tidyup(void)
 {
 int oldpool;
 if (!message_reset_point) return;
@@ -996,4 +1282,19 @@ message_reset_point = store_reset(message_reset_point);
 store_pool = oldpool;
 }
 
+/******************************************************************************/
+/* Debug analysis of address */
+
+#ifndef COMPILE_UTILITY
+void
+debug_print_taint(const void * p)
+{
+int q = quoter_for_address(p);
+if (!is_tainted(p)) return;
+debug_printf("(tainted");
+if (is_real_quoter(q)) debug_printf(", quoted:%s", lookup_list[q]->name);
+debug_printf(")\n");
+}
+#endif
+
 /* End of store.c */
index 3e42408422f762fdba5e060487072710992ff3ef..1917e654d6333802de6ad5b99dc73efbd8271fb2 100644 (file)
@@ -13,7 +13,6 @@
 
 /* Define symbols for identifying the store pools. */
 
-#define NPOOLS 10
 enum { POOL_MAIN,
        POOL_PERM,
        POOL_CONFIG,
@@ -26,13 +25,16 @@ enum { POOL_MAIN,
        POOL_TAINT_PERM,
        POOL_TAINT_CONFIG,
        POOL_TAINT_SEARCH,
-       POOL_TAINT_MESSAGE };
+       POOL_TAINT_MESSAGE,
+
+       N_PAIRED_POOLS
+};
 
 /* This variable (the one for the current pool) is set by store_get() to its
 yield, and by store_reset() to NULL. This allows string_cat() to optimize its
 store handling. */
 
-extern void *store_last_get[NPOOLS];
+extern void * store_last_get[];
 
 /* This variable contains the current store pool number. */
 
@@ -41,18 +43,20 @@ extern int store_pool;
 /* Macros for calling the memory allocation routines with
 tracing information for debugging. */
 
-#define store_extend(addr, tainted, old, new) \
-  store_extend_3(addr, tainted, old, new, __FUNCTION__, __LINE__)
+#define store_extend(addr, old, new) \
+  store_extend_3(addr, old, new, __FUNCTION__, __LINE__)
 
 #define store_free(addr) \
        store_free_3(addr, __FUNCTION__, __LINE__)
 /* store_get & store_get_perm are in local_scan.h */
+#define store_get_quoted(size, proto_mem, quoter) \
+       store_get_quoted_3((size), (proto_mem), (quoter), __FUNCTION__, __LINE__)
 #define store_malloc(size) \
        store_malloc_3(size, __FUNCTION__, __LINE__)
 #define store_mark(void) \
        store_mark_3(__FUNCTION__, __LINE__)
-#define store_newblock(addr, tainted, newsize, datalen) \
-       store_newblock_3(addr, tainted, newsize, datalen, __FUNCTION__, __LINE__)
+#define store_newblock(oldblock, newsize, datalen) \
+       store_newblock_3(oldblock, newsize, datalen, __FUNCTION__, __LINE__)
 #define store_release_above(addr) \
        store_release_above_3(addr, __FUNCTION__, __LINE__)
 #define store_reset(mark) \
@@ -62,15 +66,24 @@ tracing information for debugging. */
 /* The real functions */
 typedef void ** rmark;
 
-extern BOOL    store_extend_3(void *, BOOL, int, int, const char *, int);
+extern BOOL    store_extend_3(void *, int, int, const char *, int);
 extern void    store_free_3(void *, const char *, int);
 /* store_get_3 & store_get_perm_3 are in local_scan.h */
-extern void   *store_malloc_3(size_t, const char *, int)               ALLOC ALLOC_SIZE(1) WARN_UNUSED_RESULT;
+extern void *  store_get_quoted_3(int, const void *, unsigned, const char *, int);
+extern void *  store_malloc_3(size_t, const char *, int)               ALLOC ALLOC_SIZE(1) WARN_UNUSED_RESULT;
 extern rmark   store_mark_3(const char *, int);
-extern void   *store_newblock_3(void *, BOOL, int, int, const char *, int);
+extern void *  store_newblock_3(void *, int, int, const char *, int);
 extern void    store_release_above_3(void *, const char *, int);
 extern rmark   store_reset_3(rmark, const char *, int);
 
+#define GET_UNTAINTED  (const void *)0
+#define GET_TAINTED    (const void *)1
+
+extern int     quoter_for_address(const void *);
+extern BOOL    is_quoted_like(const void *, unsigned);
+extern BOOL    is_real_quoter(int);
+extern void    debug_print_taint(const void * p);
+
 #endif  /* STORE_H */
 
 /* End of store.h */
index 1e7922457cee09a2b6e0f6f175600bf2552d517b..4d870ec9ac1a96f37776e5ba9e197122483a9c9a 100644 (file)
@@ -313,7 +313,7 @@ if (nonprintcount == 0) return s;
 /* Get a new block of store guaranteed big enough to hold the
 expanded string. */
 
-tt = ss = store_get(length + nonprintcount * 3 + 1, is_tainted(s));
+tt = ss = store_get(length + nonprintcount * 3 + 1, s);
 
 /* Copy everything, escaping non printers. */
 
@@ -371,7 +371,7 @@ p = Ustrchr(s, '\\');
 if (!p) return s;
 
 len = Ustrlen(s) + 1;
-ss = store_get(len, is_tainted(s));
+ss = store_get(len, s);
 
 q = ss;
 off = p - s;
@@ -428,18 +428,18 @@ Returns:  copy of string in new store with the same taint status
 */
 
 uschar *
-string_copy_function(const uschar *s)
+string_copy_function(const uschar * s)
 {
-return string_copy_taint(s, is_tainted(s));
+return string_copy_taint(s, s);
 }
 
 /* As above, but explicitly specifying the result taint status
 */
 
 uschar *
-string_copy_taint_function(const uschar * s, BOOL tainted)
+string_copy_taint_function(const uschar * s, const void * proto_mem)
 {
-return string_copy_taint(s, tainted);
+return string_copy_taint(s, proto_mem);
 }
 
 
@@ -568,7 +568,7 @@ uschar *
 string_copy_dnsdomain(uschar * s)
 {
 uschar * yield;
-uschar * ss = yield = store_get(Ustrlen(s) + 1, TRUE); /* always treat as tainted */
+uschar * ss = yield = store_get(Ustrlen(s) + 1, GET_TAINTED);  /* always treat as tainted */
 
 while (*s)
   {
@@ -626,7 +626,7 @@ else
 
 /* Get enough store to copy into */
 
-t = yield = store_get(s - *sptr + 1, is_tainted(*sptr));
+t = yield = store_get(s - *sptr + 1, *sptr);
 s = *sptr;
 
 /* Do the copy */
@@ -911,6 +911,7 @@ if (!*s) return NULL;
 sep_is_special = iscntrl(sep);
 
 /* Handle the case when a buffer is provided. */
+/*XXX need to also deal with qouted-requirements mismatch */
 
 if (buffer)
   {
@@ -1087,7 +1088,6 @@ gstring_grow(gstring * g, int count)
 {
 int p = g->ptr;
 int oldsize = g->size;
-BOOL tainted = is_tainted(g->s);
 
 /* Mostly, string_cat() is used to build small strings of a few hundred
 characters at most. There are times, however, when the strings are very much
@@ -1119,8 +1119,8 @@ is at its start.) However, we can do this only if we know that the old string
 was the last item on the dynamic memory stack. This is the case if it matches
 store_last_get. */
 
-if (!store_extend(g->s, tainted, oldsize, g->size))
-  g->s = store_newblock(g->s, tainted, g->size, p);
+if (!store_extend(g->s, oldsize, g->size))
+  g->s = store_newblock(g->s, g->size, p);
 }
 
 
@@ -1150,24 +1150,27 @@ Returns:   growable string, changed if copied for expansion.
 /* coverity[+alloc] */
 
 gstring *
-string_catn(gstring * g, const uschar *s, int count)
+string_catn(gstring * g, const uschar * s, int count)
 {
 int p;
-BOOL srctaint = is_tainted(s);
 
 if (count < 0)
   log_write(0, LOG_MAIN|LOG_PANIC_DIE,
     "internal error in string_catn (count %d)", count);
 if (count == 0) return g;
 
+/*debug_printf("string_catn '%.*s'\n", count, s);*/
 if (!g)
   {
   unsigned inc = count < 4096 ? 127 : 1023;
   unsigned size = ((count + inc) &  ~inc) + 1; /* round up requested count */
-  g = string_get_tainted(size, srctaint);
+  g = string_get_tainted(size, s);
+  }
+else if (is_incompatible(g->s, s))
+  {
+/* debug_printf("rebuf A\n"); */
+  gstring_rebuffer(g, s);
   }
-else if (srctaint && !is_tainted(g->s))
-  gstring_rebuffer(g);
 
 if (g->ptr < 0 || g->ptr > g->size)
   log_write(0, LOG_MAIN|LOG_PANIC_DIE,
@@ -1310,7 +1313,6 @@ enum ltypes { L_NORMAL=1, L_SHORT=2, L_LONG=3, L_LONGLONG=4, L_LONGDOUBLE=5, L_S
 
 int width, precision, off, lim, need;
 const char * fp = format;      /* Deliberately not unsigned */
-BOOL dest_tainted = FALSE;
 
 string_datestamp_offset = -1;  /* Datestamp not inserted */
 string_datestamp_length = 0;   /* Datestamp not inserted */
@@ -1323,16 +1325,15 @@ assert(g);
 
 /* Ensure we have a string, to save on checking later */
 if (!g) g = string_get(16);
-else if (!(flags & SVFMT_TAINT_NOCHK)) dest_tainted = is_tainted(g->s);
 
-if (!(flags & SVFMT_TAINT_NOCHK) && !dest_tainted && is_tainted(format))
+if (!(flags & SVFMT_TAINT_NOCHK) && is_incompatible(g->s, format))
   {
 #ifndef MACRO_PREDEF
   if (!(flags & SVFMT_REBUFFER))
     die_tainted(US"string_vformat", func, line);
 #endif
-  gstring_rebuffer(g);
-  dest_tainted = TRUE;
+/* debug_printf("rebuf B\n"); */
+  gstring_rebuffer(g, format);
   }
 #endif /*!COMPILE_UTILITY*/
 
@@ -1552,12 +1553,12 @@ while (*fp)
       if (!s) s = null;
       slen = Ustrlen(s);
 
-      if (!(flags & SVFMT_TAINT_NOCHK) && !dest_tainted && is_tainted(s))
+      if (!(flags & SVFMT_TAINT_NOCHK) && is_incompatible(g->s, s))
        if (flags & SVFMT_REBUFFER)
          {
-         gstring_rebuffer(g);
+/* debug_printf("%s %d: untainted workarea, tainted %%s :- rebuffer\n", __FUNCTION__, __LINE__); */
+         gstring_rebuffer(g, s);
          gp = CS g->s + g->ptr;
-         dest_tainted = TRUE;
          }
 #ifndef MACRO_PREDEF
        else
index a42c26d397aac2e6921ba3d56ecac88ba300fdf4..8c103caa82c988096286f8d4d1dfe27d5ace8bfb 100644 (file)
@@ -133,11 +133,15 @@ typedef struct driver_instance {
   uschar *name;                   /* Instance name */
   struct driver_info *info;       /* Points to info for this driver */
   void   *options_block;          /* Pointer to private options */
+
   uschar *driver_name;            /* All start with this generic option */
+  const uschar *srcfile;         /* and config source info for errors */
+  int    srcline;
 } driver_instance;
 
 typedef struct driver_info {
   uschar *driver_name;            /* Name of driver */
+
   optionlist *options;            /* Table of private options names */
   int    *options_count;          /* -> Number of entries in table */
   void   *options_block;          /* Points to default private block */
@@ -159,6 +163,9 @@ typedef struct transport_instance {
   struct transport_info *info;    /* Info for this driver */
   void *options_block;            /* Pointer to private options */
   uschar *driver_name;            /* Must be first */
+  const uschar *srcfile;
+  int    srcline;
+
   int   (*setup)(                 /* Setup entry point */
     struct transport_instance *,
     struct address_item *,
@@ -283,6 +290,8 @@ typedef struct router_instance {
   struct router_info *info;
   void   *options_block;          /* Pointer to private options */
   uschar *driver_name;            /* Must be first */
+  const uschar *srcfile;
+  int    srcline;
 
   uschar *address_data;           /* Arbitrary data */
 #ifdef EXPERIMENTAL_BRIGHTMAIL
@@ -400,6 +409,9 @@ typedef struct auth_instance {
   struct auth_info *info;         /* Pointer to driver info block */
   void   *options_block;          /* Pointer to private options */
   uschar *driver_name;            /* Must be first */
+  const uschar *srcfile;
+  int    srcline;
+
   uschar *advertise_condition;    /* Are we going to advertise this?*/
   uschar *client_condition;       /* Should the client try this? */
   uschar *public_name;            /* Advertised name */
index 10f038446c7e0e5c7d0785e9c81da0932fd344d5..1a2cd915c3e5539c091a78deba14538babc1b83f 100644 (file)
@@ -2031,7 +2031,7 @@ if (host)
 
   int old_pool = store_pool;
   store_pool = POOL_PERM;
-  state = store_get(sizeof(exim_gnutls_state_st), FALSE);
+  state = store_get(sizeof(exim_gnutls_state_st), GET_UNTAINTED);
   store_pool = old_pool;
 
   memcpy(state, &exim_gnutls_state_init, sizeof(exim_gnutls_state_init));
@@ -2431,8 +2431,8 @@ else
       for (nrec = 0; state->dane_data_len[nrec]; ) nrec++;
       nrec++;
 
-      dd = store_get(nrec * sizeof(uschar *), FALSE);
-      ddl = store_get(nrec * sizeof(int), FALSE);
+      dd = store_get(nrec * sizeof(uschar *), GET_UNTAINTED);
+      ddl = store_get(nrec * sizeof(int), GET_UNTAINTED);
       nrec--;
 
       if ((rc = dane_state_init(&s, 0)))
@@ -2889,7 +2889,7 @@ else
 
   while (string_nextinlist(&list, &sep, NULL, 0)) cnt++;
 
-  p = store_get(sizeof(gnutls_datum_t) * cnt, is_tainted(exp_alpn));
+  p = store_get(sizeof(gnutls_datum_t) * cnt, exp_alpn);
   list = exp_alpn;
   for (int i = 0; s = string_nextinlist(&list, &sep, NULL, 0); i++)
     { p[i].data = s; p[i].size = Ustrlen(s); }
@@ -3208,8 +3208,8 @@ for (dns_record * rr = dns_next_rr(dnsa, &dnss, RESET_ANSWERS); rr;
      rr = dns_next_rr(dnsa, &dnss, RESET_NEXT)
     ) if (rr->type == T_TLSA) i++;
 
-dane_data = store_get(i * sizeof(uschar *), FALSE);
-dane_data_len = store_get(i * sizeof(int), FALSE);
+dane_data = store_get(i * sizeof(uschar *), GET_UNTAINTED);
+dane_data_len = store_get(i * sizeof(int), GET_UNTAINTED);
 
 i = 0;
 for (dns_record * rr = dns_next_rr(dnsa, &dnss, RESET_ANSWERS); rr;
@@ -3322,7 +3322,7 @@ if (gnutls_session_get_flags(session) & GNUTLS_SFLAGS_SESSION_TICKET)
       {
       open_db dbblock, * dbm_file;
       int dlen = sizeof(dbdata_tls_session) + tkt.size;
-      dbdata_tls_session * dt = store_get(dlen, TRUE);
+      dbdata_tls_session * dt = store_get(dlen, GET_TAINTED);
 
       DEBUG(D_tls) debug_printf("session data size %u\n", (unsigned)tkt.size);
       memcpy(dt->session, tkt.data, tkt.size);
index 26279848653bea2c964432fa32bd2b8b5e1b0263..14ba2fc0cd989422adaa03f141be5febdbc57428 100644 (file)
@@ -1446,7 +1446,7 @@ supply_response:
   ocsp_resplist ** op = &state->u_ocsp.server.olist, * oentry;
   while (oentry = *op)
     op = &oentry->next;
-  *op = oentry = store_get(sizeof(ocsp_resplist), FALSE);
+  *op = oentry = store_get(sizeof(ocsp_resplist), GET_UNTAINTED);
   oentry->next = NULL;
   oentry->resp = resp;
   }
@@ -2174,7 +2174,7 @@ DEBUG(D_tls) debug_printf("Received TLS SNI \"%s\"%s\n", servername,
 
 /* Make the extension value available for expansion */
 store_pool = POOL_PERM;
-tls_in.sni = string_copy_taint(US servername, TRUE);
+tls_in.sni = string_copy_taint(US servername, GET_TAINTED);
 store_pool = old_pool;
 
 if (!reexpand_tls_files_for_sni)
@@ -3464,9 +3464,9 @@ See description in https://paquier.xyz/postgresql-2/channel-binding-openssl/ */
   size_t len = SSL_get_peer_finished(ssl, &c, 0);
   int old_pool = store_pool;
 
-  SSL_get_peer_finished(ssl, s = store_get((int)len, FALSE), len);
+  SSL_get_peer_finished(ssl, s = store_get((int)len, GET_UNTAINTED), len);
   store_pool = POOL_PERM;
-    tls_in.channelbinding = b64encode_taint(CUS s, (int)len, FALSE);
+    tls_in.channelbinding = b64encode_taint(CUS s, (int)len, GET_UNTAINTED);
   store_pool = old_pool;
   DEBUG(D_tls) debug_printf("Have channel bindings cached for possible auth usage %p\n", tls_in.channelbinding);
   }
@@ -3702,7 +3702,7 @@ if (SSL_SESSION_is_resumable(ss))         /* 1.1.1 */
   {
   int len = i2d_SSL_SESSION(ss, NULL);
   int dlen = sizeof(dbdata_tls_session) + len;
-  dbdata_tls_session * dt = store_get(dlen, TRUE);
+  dbdata_tls_session * dt = store_get(dlen, GET_TAINTED);
   uschar * s = dt->session;
   open_db dbblock, * dbm_file;
 
@@ -3807,7 +3807,7 @@ else
   but it's little extra code complexity in the client. */
 
   const uschar * list = exp_alpn;
-  uschar * p = store_get(Ustrlen(exp_alpn), is_tainted(exp_alpn)), * s, * t;
+  uschar * p = store_get(Ustrlen(exp_alpn), exp_alpn), * s, * t;
   int sep = 0;
   uschar len;
 
@@ -3861,7 +3861,7 @@ BOOL require_ocsp = FALSE;
 
 rc = store_pool;
 store_pool = POOL_PERM;
-exim_client_ctx = store_get(sizeof(exim_openssl_client_tls_ctx), FALSE);
+exim_client_ctx = store_get(sizeof(exim_openssl_client_tls_ctx), GET_UNTAINTED);
 exim_client_ctx->corked = NULL;
 store_pool = rc;
 
@@ -4147,9 +4147,9 @@ tlsp->cipher_stdname = cipher_stdname_ssl(exim_client_ctx->ssl);
   size_t len = SSL_get_finished(exim_client_ctx->ssl, &c, 0);
   int old_pool = store_pool;
 
-  SSL_get_finished(exim_client_ctx->ssl, s = store_get((int)len, TRUE), len);
+  SSL_get_finished(exim_client_ctx->ssl, s = store_get((int)len, GET_TAINTED), len);
   store_pool = POOL_PERM;
-    tlsp->channelbinding = b64encode_taint(CUS s, (int)len, TRUE);
+    tlsp->channelbinding = b64encode_taint(CUS s, (int)len, GET_TAINTED);
   store_pool = old_pool;
   DEBUG(D_tls) debug_printf("Have channel bindings cached for possible auth usage %p %p\n", tlsp->channelbinding, tlsp);
   }
index e6b1bf7a70aa8595afa7b5a2d8b088046031a42a..bc3261ad2a0eda32f757fac9d04d3a2a2aab6ebc 100644 (file)
@@ -209,7 +209,7 @@ for (;;)
 
   if (!(S_ISLNK(sb.st_mode))) break;
 
-  t = store_get(1024, FALSE);
+  t = store_get(1024, GET_UNTAINTED);
   Ustrncpy(t, s, 1022);
   j = Ustrlen(s);
   t[j++] = '/';
index cbc7accf051d3ddd7309c933805b9ba13520824f..99acf5ec078cfb4989347e35b5f0f2b619daac6d 100644 (file)
@@ -115,7 +115,7 @@ size_t len = 32;
 if (mod && Ustrcmp(mod, "int") == 0)
   return string_sprintf("%u", (unsigned)t);
 
-cp = store_get(len, FALSE);
+cp = store_get(len, GET_UNTAINTED);
 if (f.timestamps_utc)
   {
   uschar * tz = to_tz(US"GMT0");
@@ -149,7 +149,7 @@ if ((ret = gnutls_x509_crt_get_issuer_dn(cert, CS cp, &siz))
     != GNUTLS_E_SHORT_MEMORY_BUFFER)
   return g_err("gi0", __FUNCTION__, ret);
 
-cp = store_get(siz, TRUE);
+cp = store_get(siz, GET_TAINTED);
 if ((ret = gnutls_x509_crt_get_issuer_dn(cert, CS cp, &siz)) < 0)
   return g_err("gi1", __FUNCTION__, ret);
 
@@ -203,7 +203,7 @@ if ((ret = gnutls_x509_crt_get_signature((gnutls_x509_crt_t)cert, CS cp1, &len))
     != GNUTLS_E_SHORT_MEMORY_BUFFER)
   return g_err("gs0", __FUNCTION__, ret);
 
-cp1 = store_get(len*4+1, TRUE);
+cp1 = store_get(len*4+1, GET_TAINTED);
 if (gnutls_x509_crt_get_signature((gnutls_x509_crt_t)cert, CS cp1, &len) != 0)
   return g_err("gs1", __FUNCTION__, ret);
 
@@ -233,7 +233,7 @@ if ((ret = gnutls_x509_crt_get_dn(cert, CS cp, &siz))
     != GNUTLS_E_SHORT_MEMORY_BUFFER)
   return g_err("gs0", __FUNCTION__, ret);
 
-cp = store_get(siz, TRUE);
+cp = store_get(siz, GET_TAINTED);
 if ((ret = gnutls_x509_crt_get_dn(cert, CS cp, &siz)) < 0)
   return g_err("gs1", __FUNCTION__, ret);
 
@@ -261,7 +261,7 @@ ret = gnutls_x509_crt_get_extension_by_oid ((gnutls_x509_crt_t)cert,
 if (ret != GNUTLS_E_SHORT_MEMORY_BUFFER)
   return g_err("ge0", __FUNCTION__, ret);
 
-cp1 = store_get(siz*4 + 1, TRUE);
+cp1 = store_get(siz*4 + 1, GET_TAINTED);
 
 ret = gnutls_x509_crt_get_extension_by_oid ((gnutls_x509_crt_t)cert,
   CS oid, idx, CS cp1, &siz, &crit);
@@ -317,7 +317,7 @@ for (int index = 0;; index++)
       return g_err("gs0", __FUNCTION__, ret);
     }
 
-  ele = store_get(siz+1, TRUE);
+  ele = store_get(siz+1, GET_TAINTED);
   if ((ret = gnutls_x509_crt_get_subject_alt_name(
     (gnutls_x509_crt_t)cert, index, ele, &siz, NULL)) < 0)
     return g_err("gs1", __FUNCTION__, ret);
@@ -400,7 +400,7 @@ for (int index = 0;; index++)
       return g_err("gc0", __FUNCTION__, ret);
     }
 
-  ele = store_get(siz, TRUE);
+  ele = store_get(siz, GET_TAINTED);
   if ((ret = gnutls_x509_crt_get_crl_dist_points(
       (gnutls_x509_crt_t)cert, index, ele, &siz, NULL, NULL)) < 0)
     return g_err("gc1", __FUNCTION__, ret);
@@ -423,7 +423,7 @@ int fail;
 
 if (  (fail = gnutls_x509_crt_export((gnutls_x509_crt_t)cert,
        GNUTLS_X509_FMT_DER, cp, &len)) != GNUTLS_E_SHORT_MEMORY_BUFFER
-   || !(cp = store_get((int)len, TRUE), TRUE)  /* tainted */
+   || !(cp = store_get((int)len, GET_TAINTED), TRUE)   /* tainted */
    || (fail = gnutls_x509_crt_export((gnutls_x509_crt_t)cert,
         GNUTLS_X509_FMT_DER, cp, &len))
    )
@@ -448,7 +448,7 @@ if ((ret = gnutls_x509_crt_get_fingerprint(cert, algo, NULL, &siz))
     != GNUTLS_E_SHORT_MEMORY_BUFFER)
   return g_err("gf0", __FUNCTION__, ret);
 
-cp = store_get(siz*3+1, TRUE);
+cp = store_get(siz*3+1, GET_TAINTED);
 if ((ret = gnutls_x509_crt_get_fingerprint(cert, algo, cp, &siz)) < 0)
   return g_err("gf1", __FUNCTION__, ret);
 
index 403dc4236c89975f8b63032fabe91b8bb54cd80d..abe34966b120d96c1fd7c17a7a300d1fc05d7a07 100644 (file)
@@ -171,7 +171,7 @@ else
 
       /* convert to string in our format */
       len = 32;
-      s = store_get(len, FALSE);
+      s = store_get(len, GET_UNTAINTED);
       strftime(CS s, (size_t)len, "%b %e %T %Y %z", tm_p);
       }
     }
@@ -335,7 +335,7 @@ M_ASN1_OCTET_STRING_print(bp, adata);
 /* binary data, DER encoded */
 /* just dump for now */
 len = BIO_get_mem_data(bp, &cp1);
-cp3 = cp2 = store_get(len*3+1, TRUE);
+cp3 = cp2 = store_get(len*3+1, GET_TAINTED);
 
 while(len)
   {
@@ -502,7 +502,7 @@ if (!X509_digest(cert,fdig,md,&n))
   expand_string_message = US"tls_cert_fprt: out of mem\n";
   return NULL;
   }
-cp = store_get(n*2+1, TRUE);
+cp = store_get(n*2+1, GET_TAINTED);
 for (int j = 0; j < (int)n; j++) sprintf(CS cp+2*j, "%02X", md[j]);
 return(cp);
 }
index ef523657ea05b36f122ade55b8c838a22e9d2a50..96a936503e9d7522844efc5d75497e36d25ec787 100644 (file)
@@ -651,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;
@@ -675,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;
@@ -1521,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;
     }
 
@@ -1585,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;
     }
@@ -1719,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;
 
@@ -2091,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
@@ -2107,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;
@@ -2207,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;
@@ -2216,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\" "
@@ -2233,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++] =
@@ -2343,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
 */
index 440f0de204102616eb2298a2cde26af4fd0593fd..43fe883f6a064ecedcac290a70d99038f0d3100b 100644 (file)
@@ -3191,7 +3191,7 @@ else
           uschar *iptr = expand_string(nametag);
           if (iptr)
             {
-            uschar *etag = store_get(Ustrlen(iptr) + 2, is_tainted(iptr));
+            uschar *etag = store_get(Ustrlen(iptr) + 2, iptr);
             uschar *optr = etag;
             for ( ; *iptr; iptr++)
               if (mac_isgraph(*iptr) && *iptr != '/')
index 13e2eaf19692cf94aa5174ee8569a0a6718337a4..217c54ccd2a912d71704dbf02f99a0bdf3ca04d8 100644 (file)
@@ -437,7 +437,7 @@ if (oncelog && *oncelog && to)
 
     cache_size = statbuf.st_size;
     add_size = sizeof(time_t) + Ustrlen(to) + 1;
-    cache_buff = store_get(cache_size + add_size, is_tainted(oncelog));
+    cache_buff = store_get(cache_size + add_size, oncelog);
 
     if (read(cache_fd, cache_buff, cache_size) != cache_size)
       {
index 2ec4a72fbcd8dd3115d48fdab35166c4830e2d1c..df3693abaa275bbc2768ececce8e52301fe6fddb 100644 (file)
@@ -435,7 +435,7 @@ set_up_shell_command(const uschar ***argvptr, uschar *cmd,
 {
 const uschar **argv;
 
-*argvptr = argv = store_get((4)*sizeof(uschar *), FALSE);
+*argvptr = argv = store_get((4)*sizeof(uschar *), GET_UNTAINTED);
 
 argv[0] = US"/bin/sh";
 argv[1] = US"-c";
index d36e95ce5882204431b79246b6ed663eddbbfec1..6a979a243811f53e206f136b0ffd9a92f47cc8e3 100644 (file)
@@ -1433,10 +1433,17 @@ smtp_transport_options_block * ob = sx->conn_args.ob;   /* transport options */
 host_item * host = sx->conn_args.host;                 /* host to deliver to */
 int rc;
 
+/* Set up globals for error messages */
+
+authenticator_name = au->name;
+driver_srcfile = au->srcfile;
+driver_srcline = au->srcline;
+
 sx->outblock.authenticating = TRUE;
 rc = (au->info->clientcode)(au, sx, ob->command_timeout,
                            sx->buffer, sizeof(sx->buffer));
 sx->outblock.authenticating = FALSE;
+driver_srcfile = authenticator_name = NULL; driver_srcline = 0;
 DEBUG(D_transport) debug_printf("%s authenticator yielded %d\n", au->name, rc);
 
 /* A temporary authentication failure must hold up delivery to
@@ -3685,7 +3692,7 @@ int rc;
 
 uschar *message = NULL;
 uschar new_message_id[MESSAGE_ID_LENGTH + 1];
-smtp_context * sx = store_get(sizeof(*sx), TRUE);      /* tainted, for the data buffers */
+smtp_context * sx = store_get(sizeof(*sx), GET_TAINTED);       /* tainted, for the data buffers */
 BOOL pass_message = FALSE;
 #ifdef EXPERIMENTAL_ESMTP_LIMITS
 BOOL mail_limit = FALSE;
@@ -5591,7 +5598,7 @@ retry_non_continued:
 
       if (expanded_hosts)
        {
-       thost = store_get(sizeof(host_item), FALSE);
+       thost = store_get(sizeof(host_item), GET_UNTAINTED);
        *thost = *host;
        thost->name = string_copy(host->name);
        thost->address = string_copy(host->address);
index f2c97db1e087575f0473846cbb4b45a03705dbfb..a4210373836db840480679f486eaac43ee210657 100644 (file)
@@ -31,7 +31,7 @@ void
 tree_add_nonrecipient(const uschar *s)
 {
 rmark rpoint = store_mark();
-tree_node *node = store_get(sizeof(tree_node) + Ustrlen(s), is_tainted(s));
+tree_node * node = store_get(sizeof(tree_node) + Ustrlen(s), s);
 Ustrcpy(node->name, s);
 node->data.ptr = NULL;
 if (!tree_insertnode(&tree_nonrecipients, node)) store_reset(rpoint);
@@ -56,7 +56,7 @@ void
 tree_add_duplicate(const uschar *s, address_item *addr)
 {
 rmark rpoint = store_mark();
-tree_node *node = store_get(sizeof(tree_node) + Ustrlen(s), is_tainted(s));
+tree_node * node = store_get(sizeof(tree_node) + Ustrlen(s), s);
 Ustrcpy(node->name, s);
 node->data.ptr = addr;
 if (!tree_insertnode(&tree_duplicates, node)) store_reset(rpoint);
@@ -82,7 +82,7 @@ tree_node *node;
 uschar s[256];
 sprintf(CS s, "T:%.200s:%s", h->name, h->address);
 node = store_get(sizeof(tree_node) + Ustrlen(s),
-                       is_tainted(h->name) || is_tainted(h->address));
+           is_tainted(h->name) || is_tainted(h->address) ? GET_TAINTED : GET_UNTAINTED);
 Ustrcpy(node->name, s);
 node->data.val = h->why;
 if (h->status == hstatus_unusable_expired) node->data.val += 256;
@@ -374,7 +374,7 @@ static void
 tree_add_var(uschar * name, uschar * val, void * ctx)
 {
 tree_node ** root = ctx;
-tree_node * node = store_get(sizeof(tree_node) + Ustrlen(name), is_tainted(name));
+tree_node * node = store_get(sizeof(tree_node) + Ustrlen(name), name);
 Ustrcpy(node->name, name);
 node->data.ptr = val;
 (void) tree_insertnode(root, node);
index f035dafd042c2e6c16603d5e9eac4b067e415a6d..168e7fc7f90c60a8d5f7d9313750a69a8e44b34b 100644 (file)
@@ -148,7 +148,7 @@ if (!p || !ucs4_len)
   return NULL;
   }
 p_len = ucs4_len*4;    /* this multiplier is pure guesswork */
-res = store_get(p_len+5, is_tainted(utf8));
+res = store_get(p_len+5, utf8);
 
 res[0] = 'x'; res[1] = 'n'; res[2] = res[3] = '-';
 
@@ -177,7 +177,7 @@ uschar * s, * res;
 DEBUG(D_expand) debug_printf("l_a2u: '%s'\n", alabel);
 alabel += 4;
 p_len = Ustrlen(alabel);
-p = store_get((p_len+1) * sizeof(*p), is_tainted(alabel));
+p = store_get((p_len+1) * sizeof(*p), alabel);
 
 if ((rc = punycode_decode(p_len, CCS alabel, &p_len, p, NULL)) != PUNYCODE_SUCCESS)
   {
index a5c6de576d002004593fea290f14db50159e6dd3..d78b8bf24724e186a0224811e146a9784ff9b0d1 100644 (file)
@@ -78,7 +78,7 @@ if (type[0] == 'd' && cache_record->result != ccache_reject)
   {
   if (length == sizeof(dbdata_callout_cache_obs))
     {
-    dbdata_callout_cache *new = store_get(sizeof(dbdata_callout_cache), FALSE);
+    dbdata_callout_cache * new = store_get(sizeof(dbdata_callout_cache), GET_UNTAINTED);
     memcpy(new, cache_record, length);
     new->postmaster_stamp = new->random_stamp = new->time_stamp;
     cache_record = new;
@@ -400,7 +400,7 @@ if (addr->transport == cutthrough.addr.transport)
 
        if (done)
          {
-         address_item * na = store_get(sizeof(address_item), FALSE);
+         address_item * na = store_get(sizeof(address_item), GET_UNTAINTED);
          *na = cutthrough.addr;
          cutthrough.addr = *addr;
          cutthrough.addr.host_used = &cutthrough.host;
@@ -651,7 +651,7 @@ coding means skipping this whole loop and doing the append separately.  */
       log_write(0, LOG_MAIN|LOG_PANIC, "<%s>: %s", addr->address,
         addr->message);
 
-    if (!sx) sx = store_get(sizeof(*sx), TRUE);        /* tainted buffers */
+    if (!sx) sx = store_get(sizeof(*sx), GET_TAINTED); /* tainted buffers */
     memset(sx, 0, sizeof(*sx));
 
     sx->addrlist = sx->first_addr = addr;
@@ -1096,7 +1096,7 @@ no_conn:
       for (address_item * caddr = &cutthrough.addr, * parent = addr->parent;
           parent;
           caddr = caddr->parent, parent = parent->parent)
-        *(caddr->parent = store_get(sizeof(address_item), FALSE)) = *parent;
+        *(caddr->parent = store_get(sizeof(address_item), GET_UNTAINTED)) = *parent;
 
       ctctx.outblock.buffer = ctbuffer;
       ctctx.outblock.buffersize = sizeof(ctbuffer);
@@ -2872,28 +2872,27 @@ Returns:         OK      matched
 */
 
 int
-check_host(void *arg, const uschar *ss, const uschar **valueptr, uschar **error)
+check_host(void * arg, const uschar * ss, const uschar ** valueptr, uschar ** error)
 {
-check_host_block *cb = (check_host_block *)arg;
+check_host_block * cb = (check_host_block *)arg;
 int mlen = -1;
 int maskoffset;
-BOOL iplookup = FALSE;
-BOOL isquery = FALSE;
-BOOL isiponly = cb->host_name != NULL && cb->host_name[0] == 0;
-const uschar *t;
+BOOL iplookup = FALSE, isquery = FALSE;
+BOOL isiponly = cb->host_name && !cb->host_name[0];
+const uschar * t;
 uschar * semicolon, * endname, * opts;
-uschar **aliases;
+uschar ** aliases;
 
 /* Optimize for the special case when the pattern is "*". */
 
-if (*ss == '*' && ss[1] == 0) return OK;
+if (*ss == '*' && !ss[1]) return OK;
 
 /* If the pattern is empty, it matches only in the case when there is no host -
 this can occur in ACL checking for SMTP input using the -bs option. In this
 situation, the host address is the empty string. */
 
-if (cb->host_address[0] == 0) return (*ss == 0)? OK : FAIL;
-if (*ss == 0) return FAIL;
+if (!cb->host_address[0]) return *ss ? FAIL : OK;
+if (!*ss) return FAIL;
 
 /* If the pattern is precisely "@" then match against the primary host name,
 provided that host name matching is permitted; if it's "@[]" match against the
@@ -2930,7 +2929,7 @@ course slashes may be present in lookups, but not preceded only by digits and
 dots). */
 
 for (t = ss; isdigit(*t) || *t == '.'; ) t++;
-if (*t == 0 || (*t == '/' && t != ss))
+if (!*t  || (*t == '/' && t != ss))
   {
   *error = US"malformed IPv4 address or address mask";
   return ERROR;
index 98a93b63b4b075064146f5ceba158ce53ad2cdf1..9b139d2b6aea75a0337352243f62a1e48d496020 100644 (file)
@@ -10,6 +10,7 @@ domainlist local_domains = @
 hostlist   relay_hosts = net-mysql;select * from them where id='$sender_host_address'
 
 acl_smtp_rcpt = check_recipient
+acl_not_smtp = check_notsmtp
 
 PARTIAL = 127.0.0.1::PORT_N
 SSPEC = PARTIAL/test/root/pass
@@ -23,31 +24,40 @@ begin acl
 check_recipient:
          # Tainted-data checks
   warn
-         # taint only in lookup string
-         set acl_m0 =  ok:   ${lookup mysql                    {select name from them where id = '$local_part'}}
+         # taint only in lookup string, properly quoted
+         set acl_m0 =  ok:   ${lookup mysql                    {select name from them where id = '${quote_mysql:$local_part}'}}
+         # taint only in lookup string, but not quoted
+         set acl_m0 =  FAIL: ${lookup mysql,no_rd              {select name from them where id = '$local_part'}}
+  warn
          # option on lookup type unaffected
-         set acl_m0 =  ok:   ${lookup mysql,servers=SSPEC      {select name from them where id = '$local_part'}}
+         set acl_m0 =  ok:   ${lookup mysql,servers=SSPEC      {select name from them where id = '${quote_mysql:$local_part}'}}
          # partial server-spec, indexing main-option, works
-         set acl_m0 =  ok:   ${lookup mysql,servers=PARTIAL    {select name from them where id = '$local_part'}}
+         set acl_m0 =  ok:   ${lookup mysql,servers=PARTIAL    {select name from them where id = '${quote_mysql:$local_part}'}}
          # oldstyle server spec, prepended to lookup string, fails with taint
-         set acl_m0 =  FAIL: ${lookup mysql     {servers=SSPEC; select name from them where id = '$local_part'}}
+         set acl_m0 =  FAIL: ${lookup mysql     {servers=SSPEC; select name from them where id = '${quote_mysql:$local_part}'}}
 
-         # In list-stle lookup, tainted lookup string is ok if server spec comes from main-option
+         # In list-style lookup, tainted lookup string is ok if server spec comes from main-option
   warn   set acl_m0 =  ok:   hostlist
-         hosts =       net-mysql;select * from them where id='$local_part'
+         hosts =       net-mysql;select * from them where id='${quote_mysql:$local_part}'
          # ... but setting a per-query servers spec fails due to the taint
   warn   set acl_m0 =  FAIL: hostlist
-         hosts =       <& net-mysql;servers=SSPEC; select * from them where id='$local_part'
+         hosts =       <& net-mysql;servers=SSPEC; select * from them where id='${quote_mysql:$local_part}'
 
          # The newer server-list-as-option-to-lookup-type is not a solution to tainted data in the lookup, because
          # string-expansion is done before list-expansion so the taint contaminates the entire list.
   warn   set acl_m0 =  FAIL: hostlist
-         hosts =       <& net-mysql,servers=SSPEC; select * from them where id='$local_part'
+         hosts =       <& net-mysql,servers=SSPEC; select * from them where id='${quote_mysql:$local_part}'
 
   accept  domains = +local_domains
+         # the quoted status of this var should survive being passed via spoolfile
+         set acl_m_qtest = ${quote_mysql:$local_part}
   accept  hosts = +relay_hosts
   deny    message = relay not permitted
 
+check_notsmtp:
+  accept
+         # the quoted status of this var should survive being passed via spoolfile
+         set acl_m_qtest = ${quote_mysql:$recipients}
 
 # ----- Routers -----
 
@@ -55,7 +65,10 @@ begin routers
 
 r1:
   driver = accept
-  address_data = ${lookup mysql{select name from them where id='ph10'}}
+  debug_print =        acl_m_qtest: <$acl_m_qtest> lkup: <${lookup mysql{select name from them where id='$acl_m_qtest'}}>
+
+  # this tests the unquoted case, but will need enhancement when we enforce (vs. just logging), else no transport call
+  address_data = ${lookup mysql{select name from them where id='$local_part'}}
   transport = t1
 
 
@@ -66,7 +79,7 @@ begin transports
 t1:
   driver = appendfile
   file = DIR/test-mail/\
-    ${lookup mysql{select id from them where id='ph10'}{$value}fail}
+    ${lookup mysql{select id from them where id='$local_part'}{$value}fail}
   user = CALLER
 
 
index 85d25035f9c6150a5d1314a7ae4116e4b881f8c8..70a460e242bd07fb07c36753ca704a0b89737c11 100644 (file)
@@ -25,26 +25,29 @@ begin acl
 check_recipient:
          # Tainted-data checks
   warn
-         # taint only in lookup string
-         set acl_m0 =  ok:   ${lookup pgsql                    {select name from them where id = '$local_part'}}
+         # taint only in lookup string, properly quoted
+         set acl_m0 =  ok:   ${lookup pgsql                    {select name from them where id = '${quote_pgsql:$local_part}'}}
+         # taint only in lookup string, but not quoted
+         set acl_m0 =  FAIL: ${lookup pgsql,cache=no_rd        {select name from them where id = '$local_part'}}
+  warn
          # option on lookup type unaffected
-         set acl_m0 =  ok:   ${lookup pgsql,servers=SERVERS    {select name from them where id = '$local_part'}}
+         set acl_m0 =  ok:   ${lookup pgsql,servers=SERVERS      {select name from them where id = '${quote_pgsql:$local_part}'}}
          # partial server-spec, indexing main-option, works
-         set acl_m0 =  ok:   ${lookup pgsql,servers=PARTIAL    {select name from them where id = '$local_part'}}
+         set acl_m0 =  ok:   ${lookup pgsql,servers=PARTIAL    {select name from them where id = '${quote_pgsql:$local_part}'}}
          # oldstyle server spec, prepended to lookup string, fails with taint
-         set acl_m0 =  FAIL: ${lookup pgsql     {servers=SERVERS; select name from them where id = '$local_part'}}
+         set acl_m0 =  FAIL: ${lookup pgsql     {servers=SERVERS; select name from them where id = '${quote_pgsql:$local_part}'}}
 
-         # In list-stle lookup, tainted lookup string is ok if server spec comes from main-option
+         # In list-style lookup, tainted lookup string is ok if server spec comes from main-option
   warn   set acl_m0 =  ok:   hostlist
-         hosts =       net-pgsql;select * from them where id='$local_part'
+         hosts =       net-pgsql;select * from them where id='${quote_pgsql:$local_part}'
          # ... but setting a per-query servers spec fails due to the taint
   warn   set acl_m0 =  FAIL: hostlist
-         hosts =       <& net-pgsql;servers=SERVERS; select * from them where id='$local_part'
+         hosts =       <& net-pgsql;servers=SERVERS; select * from them where id='${quote_pgsql:$local_part}'
 
          # The newer server-list-as-option-to-lookup-type is not a solution to tainted data in the lookup, because
          # string-expansion is done before list-expansion so the taint contaminates the entire list.
   warn   set acl_m0 =  FAIL: hostlist
-         hosts =       <& net-pgsql,servers=SERVERS; select * from them where id='$local_part'
+         hosts =       <& net-pgsql,servers=SERVERS; select * from them where id='${quote_pgsql:$local_part}'
 
   accept  domains = +local_domains
   accept  hosts = +relay_hosts
index 38ea30eb64beaf83ffce00e1a913fdb0817d358e..380c7a32d4789acb7575cb642ed20e77cddd18ab 100644 (file)
@@ -1,3 +1,5 @@
 1999-03-02 09:44:33 10HmaX-0005vi-00 <= CALLER@myhost.test.ex U=CALLER P=local S=sss
+1999-03-02 09:44:33 10HmaX-0005vi-00 tainted search query is not properly quoted (router r1, TESTSUITE/test-config 66): select name from them where id='ph10'
+1999-03-02 09:44:33 10HmaX-0005vi-00 tainted search query is not properly quoted (transport t1, TESTSUITE/test-config 79): select id from them where id='ph10'
 1999-03-02 09:44:33 10HmaX-0005vi-00 => ph10 <ph10@myhost.test.ex> R=r1 T=t1
 1999-03-02 09:44:33 10HmaX-0005vi-00 Completed
diff --git a/test/paniclog/2610 b/test/paniclog/2610
new file mode 100644 (file)
index 0000000..920e276
--- /dev/null
@@ -0,0 +1 @@
+1999-03-02 09:44:33 10HmaX-0005vi-00 tainted search query is not properly quoted (router r1, TESTSUITE/test-config 66): select name from them where id='ph10'
index 6f1bd0adda28fa536ee93b9f27e700a11c54e26e..2ac6198eb3f23a8b475b2e96ffba42fb7dd20e7b 100755 (executable)
@@ -1297,7 +1297,7 @@ RESET_AFTER_EXTRA_LINE_READ:
       }
 
     # Different builds will have different lookup types included
-    s/^search_type \K\d+ \((\w+)\) quoting -1 \(none\)$/NN ($1) quoting -1 (none)/;
+    s/^\s*search_type \K\d+ \((\w+)\) quoting -1 \(none\)$/NN ($1) quoting -1 (none)/;
 
     # DISABLE_OCSP
     next if /in hosts_requ(est|ire)_ocsp\? (no|yes)/;
index 3065eac44b04f86dcb65c4cbfad68eb3994b7b86..ba4a67bb085283319fd560f28121d1fd3eac45b3 100644 (file)
@@ -87,6 +87,8 @@ mail from:<a@b>
 rcpt to:<c@d>
 quit
 ****
+# Check the quote-tracking of tainted data.
+# Currently this will log but continue.
 exim -odi -d ph10
 Test message
 .
index 9631e9b82273c247f0f2345f836604615009ac82..b37f75f9362031917bc220ae91d1c36c9017f04d 100644 (file)
@@ -35,6 +35,7 @@ search_tidyup called
   internal_search_find: file="NULL"
     type=dnsdb key="a=shorthost.test.ex" opts=NULL
   database lookup required for a=shorthost.test.ex
+                               (tainted)
   dnsdb key: shorthost.test.ex
   creating new cache entry
   lookup yielded: 127.0.0.1
@@ -46,6 +47,7 @@ search_tidyup called
   internal_search_find: file="NULL"
     type=dnsdb key="a=shorthost.test.ex" opts=NULL
   cached data found but out-of-date;   database lookup required for a=shorthost.test.ex
+                               (tainted)
   dnsdb key: shorthost.test.ex
   replacing old cache entry
   lookup yielded: 127.0.0.1
index 229de2ce0076cdae86a6819468ca8e7eb5a2e88a..c1c39ef28b308266bb98ef90be03e57d811eb2fb 100644 (file)
@@ -34,6 +34,7 @@ LRU list:
 internal_search_find: file="NULL"
   type=dnsdb key="test.ex" opts=NULL
 database lookup required for test.ex
+                             (tainted)
 dnsdb key: test.ex
 DNS lookup of test.ex (TXT) using fakens
 DNS lookup of test.ex (TXT) succeeded
@@ -96,6 +97,7 @@ LRU list:
 internal_search_find: file="NULL"
   type=dnsdb key="unknown" opts=NULL
 database lookup required for unknown
+                             (tainted)
 dnsdb key: unknown
 DNS lookup of unknown (TXT) using fakens
 DNS lookup of unknown (TXT) gave HOST_NOT_FOUND
@@ -161,6 +163,7 @@ LRU list:
 internal_search_find: file="NULL"
   type=dnsdb key="a=shorthost.test.ex" opts=NULL
 database lookup required for a=shorthost.test.ex
+                             (tainted)
 dnsdb key: shorthost.test.ex
 creating new cache entry
 lookup yielded: 127.0.0.1
@@ -181,6 +184,7 @@ LRU list:
 internal_search_find: file="NULL"
   type=dnsdb key="a=shorthost.test.ex" opts=NULL
 cached data found but out-of-date; database lookup required for a=shorthost.test.ex
+                             (tainted)
 dnsdb key: shorthost.test.ex
 replacing old cache entry
 lookup yielded: 127.0.0.1
index ad234c6affa74e577e16f70797b9cac1a9ee7dcc..dd9f2ff14adef2f3067a0ef61b9197658d1b6738 100644 (file)
@@ -43,6 +43,7 @@ check hosts = +ignore_unknown : *.$sender_address_domain : $sender_address_domai
  internal_search_find: file="NULL"
    type=dnsdb key=">:defer_never,mxh=cioce.test.again.dns" opts=NULL
  database lookup required for >:defer_never,mxh=cioce.test.again.dns
+                              (tainted)
  dnsdb key: cioce.test.again.dns
 DNS lookup of cioce.test.again.dns (MX) using fakens
 DNS lookup of cioce.test.again.dns (MX) gave TRY_AGAIN
index 731952ed99cb71d7959903394d8afdd61e72eec4..56ae41f8e165b8b2779f14855ea45c5eff816baa 100644 (file)
@@ -266,7 +266,7 @@ log directory space = nnnnnK inodes = nnnnn check_space = 10240K inodes = 100
 SMTP>> 250 OK
 SMTP<< rcpt to:<c@d>
 using ACL "check_recipient"
-processing "warn" (TESTSUITE/test-config 25)
+processing "warn" (TESTSUITE/test-config 26)
  search_open: mysql "NULL"
  search_find: file="NULL"
    key="select name from them where id = 'c'" partial=-1 affix=NULL starflags=0 opts=NULL
@@ -274,13 +274,35 @@ processing "warn" (TESTSUITE/test-config 25)
  internal_search_find: file="NULL"
    type=mysql key="select name from them where id = 'c'" opts=NULL
  database lookup required for select name from them where id = 'c'
+                              (tainted, quoted:mysql)
  MySQL query: "select name from them where id = 'c'" opts 'NULL'
  MYSQL new connection: host=127.0.0.1 port=1223 socket=NULL database=test user=root
  MYSQL: no data found
  creating new cache entry
  lookup failed
-check set acl_m0 = ok:   ${lookup mysql                    {select name from them where id = '$local_part'}}
+check set acl_m0 = ok:   ${lookup mysql                    {select name from them where id = '${quote_mysql:$local_part}'}}
                  = ok:   
+ search_open: mysql "NULL"
+   cached open
+ search_find: file="NULL"
+   key="select name from them where id = 'c'" partial=-1 affix=NULL starflags=0 opts="no_rd"
+ LRU list:
+ internal_search_find: file="NULL"
+   type=mysql key="select name from them where id = 'c'" opts="no_rd"
+ cached data found but wrong opts;  database lookup required for select name from them where id = 'c'
+                              (tainted)
+LOG: MAIN PANIC
+  tainted search query is not properly quoted (ACL warn, TESTSUITE/test-config 26): select name from them where id = 'c'
+ search_type NN (mysql) quoting -1 (none)
+ MySQL query: "select name from them where id = 'c'" opts 'no_rd'
+ MYSQL using cached connection for 127.0.0.1:1223/test/root
+ MYSQL: no data found
+ replacing old cache entry
+ lookup failed
+check set acl_m0 = FAIL: ${lookup mysql,no_rd              {select name from them where id = '$local_part'}}
+                 = FAIL: 
+warn: condition test succeeded in ACL "check_recipient"
+processing "warn" (TESTSUITE/test-config 31)
  search_open: mysql "NULL"
    cached open
  search_find: file="NULL"
@@ -289,12 +311,13 @@ check set acl_m0 = ok:   ${lookup mysql                    {select name from the
  internal_search_find: file="NULL"
    type=mysql key="select name from them where id = 'c'" opts="servers=127.0.0.1::1223/test/root/pass"
  cached data found but wrong opts;  database lookup required for select name from them where id = 'c'
+                              (tainted, quoted:mysql)
  MySQL query: "select name from them where id = 'c'" opts 'servers=127.0.0.1::1223/test/root/pass'
  MYSQL using cached connection for 127.0.0.1:1223/test/root
  MYSQL: no data found
  replacing old cache entry
  lookup failed
-check set acl_m0 = ok:   ${lookup mysql,servers=127.0.0.1::1223/test/root/pass      {select name from them where id = '$local_part'}}
+check set acl_m0 = ok:   ${lookup mysql,servers=127.0.0.1::1223/test/root/pass      {select name from them where id = '${quote_mysql:$local_part}'}}
                  = ok:   
  search_open: mysql "NULL"
    cached open
@@ -304,12 +327,13 @@ check set acl_m0 = ok:   ${lookup mysql,servers=127.0.0.1::1223/test/root/pass
  internal_search_find: file="NULL"
    type=mysql key="select name from them where id = 'c'" opts="servers=127.0.0.1::1223"
  cached data found but wrong opts;  database lookup required for select name from them where id = 'c'
+                              (tainted, quoted:mysql)
  MySQL query: "select name from them where id = 'c'" opts 'servers=127.0.0.1::1223'
  MYSQL using cached connection for 127.0.0.1:1223/test/root
  MYSQL: no data found
  replacing old cache entry
  lookup failed
-check set acl_m0 = ok:   ${lookup mysql,servers=127.0.0.1::1223    {select name from them where id = '$local_part'}}
+check set acl_m0 = ok:   ${lookup mysql,servers=127.0.0.1::1223    {select name from them where id = '${quote_mysql:$local_part}'}}
                  = ok:   
  search_open: mysql "NULL"
    cached open
@@ -319,14 +343,15 @@ check set acl_m0 = ok:   ${lookup mysql,servers=127.0.0.1::1223    {select name
  internal_search_find: file="NULL"
    type=mysql key="servers=127.0.0.1::1223/test/root/pass; select name from them where id = 'c'" opts=NULL
  database lookup required for servers=127.0.0.1::1223/test/root/pass; select name from them where id = 'c'
+                              (tainted, quoted:mysql)
  MySQL query: "servers=127.0.0.1::1223/test/root/pass; select name from them where id = 'c'" opts 'NULL'
  lookup deferred: MySQL server "127.0.0.1:1223/test/root/pass" is tainted
 warn: condition test deferred in ACL "check_recipient"
 LOG: MAIN
   H=(test) [10.0.0.0] Warning: ACL "warn" statement skipped: condition test deferred: MySQL server "127.0.0.1:1223/test/root/pass" is tainted
-processing "warn" (TESTSUITE/test-config 36)
+processing "warn" (TESTSUITE/test-config 40)
 check set acl_m0 = ok:   hostlist
-check hosts = net-mysql;select * from them where id='$local_part'
+check hosts = net-mysql;select * from them where id='${quote_mysql:$local_part}'
 search_open: mysql "NULL"
   cached open
 search_find: file="NULL"
@@ -335,6 +360,7 @@ LRU list:
 internal_search_find: file="NULL"
   type=mysql key="select * from them where id='c'" opts=NULL
 database lookup required for select * from them where id='c'
+                             (tainted, quoted:mysql)
 MySQL query: "select * from them where id='c'" opts 'NULL'
 MYSQL using cached connection for 127.0.0.1:1223/test/root
 MYSQL: no data found
@@ -342,9 +368,9 @@ creating new cache entry
 lookup failed
 host in "net-mysql;select * from them where id='c'"? no (end of list)
 warn: condition test failed in ACL "check_recipient"
-processing "warn" (TESTSUITE/test-config 39)
+processing "warn" (TESTSUITE/test-config 43)
 check set acl_m0 = FAIL: hostlist
-check hosts = <& net-mysql;servers=127.0.0.1::1223/test/root/pass; select * from them where id='$local_part'
+check hosts = <& net-mysql;servers=127.0.0.1::1223/test/root/pass; select * from them where id='${quote_mysql:$local_part}'
 search_open: mysql "NULL"
   cached open
 search_find: file="NULL"
@@ -353,15 +379,16 @@ LRU list:
 internal_search_find: file="NULL"
   type=mysql key="servers=127.0.0.1::1223/test/root/pass; select * from them where id='c'" opts=NULL
 database lookup required for servers=127.0.0.1::1223/test/root/pass; select * from them where id='c'
+                             (tainted, quoted:mysql)
 MySQL query: "servers=127.0.0.1::1223/test/root/pass; select * from them where id='c'" opts 'NULL'
 lookup deferred: MySQL server "127.0.0.1:1223/test/root/pass" is tainted
 host in "<& net-mysql;servers=127.0.0.1::1223/test/root/pass; select * from them where id='c'"? list match deferred for net-mysql;servers=127.0.0.1::1223/test/root/pass; select * from them where id='c'
 warn: condition test deferred in ACL "check_recipient"
 LOG: MAIN
   H=(test) [10.0.0.0] Warning: ACL "warn" statement skipped: condition test deferred: MySQL server "127.0.0.1:1223/test/root/pass" is tainted
-processing "warn" (TESTSUITE/test-config 44)
+processing "warn" (TESTSUITE/test-config 48)
 check set acl_m0 = FAIL: hostlist
-check hosts = <& net-mysql,servers=127.0.0.1::1223/test/root/pass; select * from them where id='$local_part'
+check hosts = <& net-mysql,servers=127.0.0.1::1223/test/root/pass; select * from them where id='${quote_mysql:$local_part}'
 search_open: mysql "NULL"
   cached open
 search_find: file="NULL"
@@ -370,18 +397,19 @@ LRU list:
 internal_search_find: file="NULL"
   type=mysql key=" select * from them where id='c'" opts="servers=127.0.0.1::1223/test/root/pass"
 database lookup required for  select * from them where id='c'
+                             (tainted, quoted:mysql)
 MySQL query: " select * from them where id='c'" opts 'servers=127.0.0.1::1223/test/root/pass'
 lookup deferred: MySQL server "127.0.0.1:1223/test/root/pass" is tainted
 host in "<& net-mysql,servers=127.0.0.1::1223/test/root/pass; select * from them where id='c'"? list match deferred for net-mysql,servers=127.0.0.1::1223/test/root/pass; select * from them where id='c'
 warn: condition test deferred in ACL "check_recipient"
 LOG: MAIN
   H=(test) [10.0.0.0] Warning: ACL "warn" statement skipped: condition test deferred: MySQL server "127.0.0.1:1223/test/root/pass" is tainted
-processing "accept" (TESTSUITE/test-config 47)
+processing "accept" (TESTSUITE/test-config 51)
 check domains = +local_domains
 d in "@"? no (end of list)
 d in "+local_domains"? no (end of list)
 accept: condition test failed in ACL "check_recipient"
-processing "accept" (TESTSUITE/test-config 48)
+processing "accept" (TESTSUITE/test-config 54)
 check hosts = +relay_hosts
 search_open: mysql "NULL"
   cached open
@@ -399,7 +427,7 @@ lookup failed
 host in "net-mysql;select * from them where id='10.0.0.0'"? no (end of list)
 host in "+relay_hosts"? no (end of list)
 accept: condition test failed in ACL "check_recipient"
-processing "deny" (TESTSUITE/test-config 49)
+processing "deny" (TESTSUITE/test-config 55)
   message: relay not permitted
 deny: condition test succeeded in ACL "check_recipient"
 end of ACL "check_recipient": DENY
@@ -452,6 +480,12 @@ P Received: from CALLER by myhost.test.ex with local (Exim x.yz)
        id 10HmaX-0005vi-00
        for ph10@myhost.test.ex;
        Tue, 2 Mar 1999 09:44:33 +0000
+using ACL "check_notsmtp"
+processing "accept" (TESTSUITE/test-config 58)
+check set acl_m_qtest = ${quote_mysql:$recipients}
+                      = ph10@myhost.test.ex
+accept: condition test succeeded in ACL "check_notsmtp"
+end of ACL "check_notsmtp": ACCEPT
 Writing spool header file: TESTSUITE/spool//input//hdr.10HmaX-0005vi-00
 DSN: **** SPOOL_OUT - address: <ph10@myhost.test.ex> errorsto: <NULL> orcpt: <NULL> dsn_flags: 0x0
 Renaming spool header file: TESTSUITE/spool//input//10HmaX-0005vi-00-H
@@ -501,16 +535,35 @@ ph10@myhost.test.ex: queued for routing
 routing ph10@myhost.test.ex
 --------> r1 router <--------
 local_part=ph10 domain=myhost.test.ex
+ search_open: mysql "NULL"
+ search_find: file="NULL"
+   key="select name from them where id='ph10@myhost.test.ex'" partial=-1 affix=NULL starflags=0 opts=NULL
+ LRU list:
+ internal_search_find: file="NULL"
+   type=mysql key="select name from them where id='ph10@myhost.test.ex'" opts=NULL
+ database lookup required for select name from them where id='ph10@myhost.test.ex'
+                              (tainted, quoted:mysql)
+ MySQL query: "select name from them where id='ph10@myhost.test.ex'" opts 'NULL'
+ MYSQL new connection: host=127.0.0.1 port=1223 socket=NULL database=test user=root
+ MYSQL: no data found
+ creating new cache entry
+ lookup failed
+acl_m_qtest: <ph10@myhost.test.ex> lkup: <>
 processing address_data
  search_open: mysql "NULL"
+   cached open
  search_find: file="NULL"
    key="select name from them where id='ph10'" partial=-1 affix=NULL starflags=0 opts=NULL
  LRU list:
  internal_search_find: file="NULL"
    type=mysql key="select name from them where id='ph10'" opts=NULL
  database lookup required for select name from them where id='ph10'
+                              (tainted)
+LOG: MAIN PANIC
+  tainted search query is not properly quoted (router r1, TESTSUITE/test-config 66): select name from them where id='ph10'
+ search_type NN (mysql) quoting -1 (none)
  MySQL query: "select name from them where id='ph10'" opts 'NULL'
- MYSQL new connection: host=127.0.0.1 port=1223 socket=NULL database=test user=root
+ MYSQL using cached connection for 127.0.0.1:1223/test/root
  creating new cache entry
  lookup yielded: Philip Hazel
 calling r1 router
@@ -554,6 +607,10 @@ appendfile transport entered
  internal_search_find: file="NULL"
    type=mysql key="select id from them where id='ph10'" opts=NULL
  database lookup required for select id from them where id='ph10'
+                              (tainted)
+LOG: MAIN
+  tainted search query is not properly quoted (transport t1, TESTSUITE/test-config 79): select id from them where id='ph10'
+ search_type NN (mysql) quoting -1 (none)
  MySQL query: "select id from them where id='ph10'" opts 'NULL'
  MYSQL new connection: host=127.0.0.1 port=1223 socket=NULL database=test user=root
  creating new cache entry
index 991e61efa458ba2de3cda835b82ce1c34af37598..dd3fa88440e9267f71184747e52b5fd9c526e1e4 100644 (file)
@@ -260,13 +260,35 @@ processing "warn" (TESTSUITE/test-config 27)
  internal_search_find: file="NULL"
    type=pgsql key="select name from them where id = 'c'" opts=NULL
  database lookup required for select name from them where id = 'c'
+                              (tainted, quoted:pgsql)
  PostgreSQL query: "select name from them where id = 'c'" opts 'NULL'
  PGSQL new connection: host=localhost port=1223 database=test user=CALLER
  PGSQL: no data found
  creating new cache entry
  lookup failed
-check set acl_m0 = ok:   ${lookup pgsql                    {select name from them where id = '$local_part'}}
+check set acl_m0 = ok:   ${lookup pgsql                    {select name from them where id = '${quote_pgsql:$local_part}'}}
                  = ok:   
+ search_open: pgsql "NULL"
+   cached open
+ search_find: file="NULL"
+   key="select name from them where id = 'c'" partial=-1 affix=NULL starflags=0 opts="cache=no_rd"
+ LRU list:
+ internal_search_find: file="NULL"
+   type=pgsql key="select name from them where id = 'c'" opts=NULL
+ cached data found but no_rd option set;  database lookup required for select name from them where id = 'c'
+                              (tainted)
+LOG: MAIN PANIC
+  tainted search query is not properly quoted (ACL warn, TESTSUITE/test-config 27): select name from them where id = 'c'
+ search_type NN (pgsql) quoting -1 (none)
+ PostgreSQL query: "select name from them where id = 'c'" opts 'NULL'
+ PGSQL using cached connection for localhost:1223/test/CALLER
+ PGSQL: no data found
+ replacing old cache entry
+ lookup failed
+check set acl_m0 = FAIL: ${lookup pgsql,cache=no_rd        {select name from them where id = '$local_part'}}
+                 = FAIL: 
+warn: condition test succeeded in ACL "check_recipient"
+processing "warn" (TESTSUITE/test-config 32)
  search_open: pgsql "NULL"
    cached open
  search_find: file="NULL"
@@ -275,12 +297,13 @@ check set acl_m0 = ok:   ${lookup pgsql                    {select name from the
  internal_search_find: file="NULL"
    type=pgsql key="select name from them where id = 'c'" opts="servers=localhost::1223/test/CALLER/"
  cached data found but wrong opts;  database lookup required for select name from them where id = 'c'
+                              (tainted, quoted:pgsql)
  PostgreSQL query: "select name from them where id = 'c'" opts 'servers=localhost::1223/test/CALLER/'
  PGSQL using cached connection for localhost:1223/test/CALLER
  PGSQL: no data found
  replacing old cache entry
  lookup failed
-check set acl_m0 = ok:   ${lookup pgsql,servers=localhost::1223/test/CALLER/    {select name from them where id = '$local_part'}}
+check set acl_m0 = ok:   ${lookup pgsql,servers=localhost::1223/test/CALLER/      {select name from them where id = '${quote_pgsql:$local_part}'}}
                  = ok:   
  search_open: pgsql "NULL"
    cached open
@@ -290,12 +313,13 @@ check set acl_m0 = ok:   ${lookup pgsql,servers=localhost::1223/test/CALLER/
  internal_search_find: file="NULL"
    type=pgsql key="select name from them where id = 'c'" opts="servers=localhost::1223"
  cached data found but wrong opts;  database lookup required for select name from them where id = 'c'
+                              (tainted, quoted:pgsql)
  PostgreSQL query: "select name from them where id = 'c'" opts 'servers=localhost::1223'
  PGSQL using cached connection for localhost:1223/test/CALLER
  PGSQL: no data found
  replacing old cache entry
  lookup failed
-check set acl_m0 = ok:   ${lookup pgsql,servers=localhost::1223    {select name from them where id = '$local_part'}}
+check set acl_m0 = ok:   ${lookup pgsql,servers=localhost::1223    {select name from them where id = '${quote_pgsql:$local_part}'}}
                  = ok:   
  search_open: pgsql "NULL"
    cached open
@@ -305,14 +329,15 @@ check set acl_m0 = ok:   ${lookup pgsql,servers=localhost::1223    {select name
  internal_search_find: file="NULL"
    type=pgsql key="servers=localhost::1223/test/CALLER/; select name from them where id = 'c'" opts=NULL
  database lookup required for servers=localhost::1223/test/CALLER/; select name from them where id = 'c'
+                              (tainted, quoted:pgsql)
  PostgreSQL query: "servers=localhost::1223/test/CALLER/; select name from them where id = 'c'" opts 'NULL'
  lookup deferred: PostgreSQL server "localhost:1223/test/CALLER/" is tainted
 warn: condition test deferred in ACL "check_recipient"
 LOG: MAIN
   H=(test) [10.0.0.0] Warning: ACL "warn" statement skipped: condition test deferred: PostgreSQL server "localhost:1223/test/CALLER/" is tainted
-processing "warn" (TESTSUITE/test-config 38)
+processing "warn" (TESTSUITE/test-config 41)
 check set acl_m0 = ok:   hostlist
-check hosts = net-pgsql;select * from them where id='$local_part'
+check hosts = net-pgsql;select * from them where id='${quote_pgsql:$local_part}'
 search_open: pgsql "NULL"
   cached open
 search_find: file="NULL"
@@ -321,6 +346,7 @@ LRU list:
 internal_search_find: file="NULL"
   type=pgsql key="select * from them where id='c'" opts=NULL
 database lookup required for select * from them where id='c'
+                             (tainted, quoted:pgsql)
 PostgreSQL query: "select * from them where id='c'" opts 'NULL'
 PGSQL using cached connection for localhost:1223/test/CALLER
 PGSQL: no data found
@@ -328,9 +354,9 @@ creating new cache entry
 lookup failed
 host in "net-pgsql;select * from them where id='c'"? no (end of list)
 warn: condition test failed in ACL "check_recipient"
-processing "warn" (TESTSUITE/test-config 41)
+processing "warn" (TESTSUITE/test-config 44)
 check set acl_m0 = FAIL: hostlist
-check hosts = <& net-pgsql;servers=localhost::1223/test/CALLER/; select * from them where id='$local_part'
+check hosts = <& net-pgsql;servers=localhost::1223/test/CALLER/; select * from them where id='${quote_pgsql:$local_part}'
 search_open: pgsql "NULL"
   cached open
 search_find: file="NULL"
@@ -339,15 +365,16 @@ LRU list:
 internal_search_find: file="NULL"
   type=pgsql key="servers=localhost::1223/test/CALLER/; select * from them where id='c'" opts=NULL
 database lookup required for servers=localhost::1223/test/CALLER/; select * from them where id='c'
+                             (tainted, quoted:pgsql)
 PostgreSQL query: "servers=localhost::1223/test/CALLER/; select * from them where id='c'" opts 'NULL'
 lookup deferred: PostgreSQL server "localhost:1223/test/CALLER/" is tainted
 host in "<& net-pgsql;servers=localhost::1223/test/CALLER/; select * from them where id='c'"? list match deferred for net-pgsql;servers=localhost::1223/test/CALLER/; select * from them where id='c'
 warn: condition test deferred in ACL "check_recipient"
 LOG: MAIN
   H=(test) [10.0.0.0] Warning: ACL "warn" statement skipped: condition test deferred: PostgreSQL server "localhost:1223/test/CALLER/" is tainted
-processing "warn" (TESTSUITE/test-config 46)
+processing "warn" (TESTSUITE/test-config 49)
 check set acl_m0 = FAIL: hostlist
-check hosts = <& net-pgsql,servers=localhost::1223/test/CALLER/; select * from them where id='$local_part'
+check hosts = <& net-pgsql,servers=localhost::1223/test/CALLER/; select * from them where id='${quote_pgsql:$local_part}'
 search_open: pgsql "NULL"
   cached open
 search_find: file="NULL"
@@ -356,18 +383,19 @@ LRU list:
 internal_search_find: file="NULL"
   type=pgsql key=" select * from them where id='c'" opts="servers=localhost::1223/test/CALLER/"
 database lookup required for  select * from them where id='c'
+                             (tainted, quoted:pgsql)
 PostgreSQL query: " select * from them where id='c'" opts 'servers=localhost::1223/test/CALLER/'
 lookup deferred: PostgreSQL server "localhost:1223/test/CALLER/" is tainted
 host in "<& net-pgsql,servers=localhost::1223/test/CALLER/; select * from them where id='c'"? list match deferred for net-pgsql,servers=localhost::1223/test/CALLER/; select * from them where id='c'
 warn: condition test deferred in ACL "check_recipient"
 LOG: MAIN
   H=(test) [10.0.0.0] Warning: ACL "warn" statement skipped: condition test deferred: PostgreSQL server "localhost:1223/test/CALLER/" is tainted
-processing "accept" (TESTSUITE/test-config 49)
+processing "accept" (TESTSUITE/test-config 52)
 check domains = +local_domains
 d in "@"? no (end of list)
 d in "+local_domains"? no (end of list)
 accept: condition test failed in ACL "check_recipient"
-processing "accept" (TESTSUITE/test-config 50)
+processing "accept" (TESTSUITE/test-config 53)
 check hosts = +relay_hosts
 search_open: pgsql "NULL"
   cached open
@@ -385,7 +413,7 @@ lookup failed
 host in "net-pgsql;select * from them where id='10.0.0.0'"? no (end of list)
 host in "+relay_hosts"? no (end of list)
 accept: condition test failed in ACL "check_recipient"
-processing "deny" (TESTSUITE/test-config 51)
+processing "deny" (TESTSUITE/test-config 54)
   message: relay not permitted
 deny: condition test succeeded in ACL "check_recipient"
 end of ACL "check_recipient": DENY
@@ -403,13 +431,35 @@ processing "warn" (TESTSUITE/test-config 27)
  internal_search_find: file="NULL"
    type=pgsql key="select name from them where id = 'c'" opts=NULL
  cached data found but wrong opts;  database lookup required for select name from them where id = 'c'
+                              (tainted, quoted:pgsql)
  PostgreSQL query: "select name from them where id = 'c'" opts 'NULL'
  PGSQL using cached connection for localhost:1223/test/CALLER
  PGSQL: no data found
  replacing old cache entry
  lookup failed
-check set acl_m0 = ok:   ${lookup pgsql                    {select name from them where id = '$local_part'}}
+check set acl_m0 = ok:   ${lookup pgsql                    {select name from them where id = '${quote_pgsql:$local_part}'}}
                  = ok:   
+ search_open: pgsql "NULL"
+   cached open
+ search_find: file="NULL"
+   key="select name from them where id = 'c'" partial=-1 affix=NULL starflags=0 opts="cache=no_rd"
+ LRU list:
+ internal_search_find: file="NULL"
+   type=pgsql key="select name from them where id = 'c'" opts=NULL
+ cached data found but no_rd option set;  database lookup required for select name from them where id = 'c'
+                              (tainted)
+LOG: MAIN PANIC
+  tainted search query is not properly quoted (ACL warn, TESTSUITE/test-config 27): select name from them where id = 'c'
+ search_type NN (pgsql) quoting -1 (none)
+ PostgreSQL query: "select name from them where id = 'c'" opts 'NULL'
+ PGSQL using cached connection for localhost:1223/test/CALLER
+ PGSQL: no data found
+ replacing old cache entry
+ lookup failed
+check set acl_m0 = FAIL: ${lookup pgsql,cache=no_rd        {select name from them where id = '$local_part'}}
+                 = FAIL: 
+warn: condition test succeeded in ACL "check_recipient"
+processing "warn" (TESTSUITE/test-config 32)
  search_open: pgsql "NULL"
    cached open
  search_find: file="NULL"
@@ -418,12 +468,13 @@ check set acl_m0 = ok:   ${lookup pgsql                    {select name from the
  internal_search_find: file="NULL"
    type=pgsql key="select name from them where id = 'c'" opts="servers=localhost::1223/test/CALLER/"
  cached data found but wrong opts;  database lookup required for select name from them where id = 'c'
+                              (tainted, quoted:pgsql)
  PostgreSQL query: "select name from them where id = 'c'" opts 'servers=localhost::1223/test/CALLER/'
  PGSQL using cached connection for localhost:1223/test/CALLER
  PGSQL: no data found
  replacing old cache entry
  lookup failed
-check set acl_m0 = ok:   ${lookup pgsql,servers=localhost::1223/test/CALLER/    {select name from them where id = '$local_part'}}
+check set acl_m0 = ok:   ${lookup pgsql,servers=localhost::1223/test/CALLER/      {select name from them where id = '${quote_pgsql:$local_part}'}}
                  = ok:   
  search_open: pgsql "NULL"
    cached open
@@ -433,12 +484,13 @@ check set acl_m0 = ok:   ${lookup pgsql,servers=localhost::1223/test/CALLER/
  internal_search_find: file="NULL"
    type=pgsql key="select name from them where id = 'c'" opts="servers=localhost::1223"
  cached data found but wrong opts;  database lookup required for select name from them where id = 'c'
+                              (tainted, quoted:pgsql)
  PostgreSQL query: "select name from them where id = 'c'" opts 'servers=localhost::1223'
  PGSQL using cached connection for localhost:1223/test/CALLER
  PGSQL: no data found
  replacing old cache entry
  lookup failed
-check set acl_m0 = ok:   ${lookup pgsql,servers=localhost::1223    {select name from them where id = '$local_part'}}
+check set acl_m0 = ok:   ${lookup pgsql,servers=localhost::1223    {select name from them where id = '${quote_pgsql:$local_part}'}}
                  = ok:   
  search_open: pgsql "NULL"
    cached open
@@ -448,14 +500,15 @@ check set acl_m0 = ok:   ${lookup pgsql,servers=localhost::1223    {select name
  internal_search_find: file="NULL"
    type=pgsql key="servers=localhost::1223/test/CALLER/; select name from them where id = 'c'" opts=NULL
  database lookup required for servers=localhost::1223/test/CALLER/; select name from them where id = 'c'
+                              (tainted, quoted:pgsql)
  PostgreSQL query: "servers=localhost::1223/test/CALLER/; select name from them where id = 'c'" opts 'NULL'
  lookup deferred: PostgreSQL server "localhost:1223/test/CALLER/" is tainted
 warn: condition test deferred in ACL "check_recipient"
 LOG: MAIN
   H=(test) [10.0.0.0] Warning: ACL "warn" statement skipped: condition test deferred: PostgreSQL server "localhost:1223/test/CALLER/" is tainted
-processing "warn" (TESTSUITE/test-config 38)
+processing "warn" (TESTSUITE/test-config 41)
 check set acl_m0 = ok:   hostlist
-check hosts = net-pgsql;select * from them where id='$local_part'
+check hosts = net-pgsql;select * from them where id='${quote_pgsql:$local_part}'
 search_open: pgsql "NULL"
   cached open
 search_find: file="NULL"
@@ -467,9 +520,9 @@ cached data used for lookup of select * from them where id='c'
 lookup failed
 host in "net-pgsql;select * from them where id='c'"? no (end of list)
 warn: condition test failed in ACL "check_recipient"
-processing "warn" (TESTSUITE/test-config 41)
+processing "warn" (TESTSUITE/test-config 44)
 check set acl_m0 = FAIL: hostlist
-check hosts = <& net-pgsql;servers=localhost::1223/test/CALLER/; select * from them where id='$local_part'
+check hosts = <& net-pgsql;servers=localhost::1223/test/CALLER/; select * from them where id='${quote_pgsql:$local_part}'
 search_open: pgsql "NULL"
   cached open
 search_find: file="NULL"
@@ -478,15 +531,16 @@ LRU list:
 internal_search_find: file="NULL"
   type=pgsql key="servers=localhost::1223/test/CALLER/; select * from them where id='c'" opts=NULL
 database lookup required for servers=localhost::1223/test/CALLER/; select * from them where id='c'
+                             (tainted, quoted:pgsql)
 PostgreSQL query: "servers=localhost::1223/test/CALLER/; select * from them where id='c'" opts 'NULL'
 lookup deferred: PostgreSQL server "localhost:1223/test/CALLER/" is tainted
 host in "<& net-pgsql;servers=localhost::1223/test/CALLER/; select * from them where id='c'"? list match deferred for net-pgsql;servers=localhost::1223/test/CALLER/; select * from them where id='c'
 warn: condition test deferred in ACL "check_recipient"
 LOG: MAIN
   H=(test) [10.0.0.0] Warning: ACL "warn" statement skipped: condition test deferred: PostgreSQL server "localhost:1223/test/CALLER/" is tainted
-processing "warn" (TESTSUITE/test-config 46)
+processing "warn" (TESTSUITE/test-config 49)
 check set acl_m0 = FAIL: hostlist
-check hosts = <& net-pgsql,servers=localhost::1223/test/CALLER/; select * from them where id='$local_part'
+check hosts = <& net-pgsql,servers=localhost::1223/test/CALLER/; select * from them where id='${quote_pgsql:$local_part}'
 search_open: pgsql "NULL"
   cached open
 search_find: file="NULL"
@@ -495,18 +549,19 @@ LRU list:
 internal_search_find: file="NULL"
   type=pgsql key=" select * from them where id='c'" opts="servers=localhost::1223/test/CALLER/"
 database lookup required for  select * from them where id='c'
+                             (tainted, quoted:pgsql)
 PostgreSQL query: " select * from them where id='c'" opts 'servers=localhost::1223/test/CALLER/'
 lookup deferred: PostgreSQL server "localhost:1223/test/CALLER/" is tainted
 host in "<& net-pgsql,servers=localhost::1223/test/CALLER/; select * from them where id='c'"? list match deferred for net-pgsql,servers=localhost::1223/test/CALLER/; select * from them where id='c'
 warn: condition test deferred in ACL "check_recipient"
 LOG: MAIN
   H=(test) [10.0.0.0] Warning: ACL "warn" statement skipped: condition test deferred: PostgreSQL server "localhost:1223/test/CALLER/" is tainted
-processing "accept" (TESTSUITE/test-config 49)
+processing "accept" (TESTSUITE/test-config 52)
 check domains = +local_domains
 d in "@"? no (end of list)
 d in "+local_domains"? no (end of list)
 accept: condition test failed in ACL "check_recipient"
-processing "accept" (TESTSUITE/test-config 50)
+processing "accept" (TESTSUITE/test-config 53)
 check hosts = +relay_hosts
 search_open: pgsql "NULL"
   cached open
@@ -520,7 +575,7 @@ lookup failed
 host in "net-pgsql;select * from them where id='10.0.0.0'"? no (end of list)
 host in "+relay_hosts"? no (end of list)
 accept: condition test failed in ACL "check_recipient"
-processing "deny" (TESTSUITE/test-config 51)
+processing "deny" (TESTSUITE/test-config 54)
   message: relay not permitted
 deny: condition test succeeded in ACL "check_recipient"
 end of ACL "check_recipient": DENY