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
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'&>"
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%&
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
------------
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",
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",
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",
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",
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 */
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);
static int acl_check_wargs(int, address_item *, const uschar *, uschar **,
uschar **);
+static acl_block * acl_current = NULL;
+
/*************************************************
* Find control in list *
*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;
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;
{
/* 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;
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
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);
/* 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
{
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);
/* 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);
}
/* 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;
+/************************************************/
+/* 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 *
*************************************************/
}
/* 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)
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);
/* 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;
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;
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);
}
*/
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 */
}
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;
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;
{
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));
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;
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;
{
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);
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__); */
{
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;
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;
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)
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;
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. */
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
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)
{
uschar *
b64encode(const uschar * clear, int len)
{
-return b64encode_taint(clear, len, is_tainted(clear));
+return b64encode_taint(clear, len, clear);
}
/* 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;
}
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';
};
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;
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. */
/* 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)
{
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;
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];
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; }
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;
}
}
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;
}
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);
/* 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);
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);
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);
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;
#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" ");
{
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);
}
}
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;
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++;
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);
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 */
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;
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++;
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;
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;
{
/* 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;
}
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)
/* 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);
{
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
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;
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;
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;
}
{
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;
}
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);
}
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;
}
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;
/* 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
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;
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;
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;
&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;
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':
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;
/* -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;
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;
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]);
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;
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*/
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;
/* -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 */
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 */
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 */
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;
{
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
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;
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;
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;
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;
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;
{
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();
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 */
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;
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)));
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)
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);
/* 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);
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);
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;
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);
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)
{
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)
{
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";
}
/* 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];
/* 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" : ";
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 */
goto EXPAND_FAILED; /*{{*/
if (*s++ != '}')
{
+ /*{*/
expand_string_message =
string_sprintf("missing '}' closing first arg of %s", name);
goto EXPAND_FAILED_CURLY;
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);
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);
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 */
} /* 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;
}
}
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)))
{
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");
}
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");
EXPAND_FAILED:
if (left) *left = s;
DEBUG(D_expand)
+ {
DEBUG(D_noutf8)
{
debug_printf_indent("|failed to expand: %s\n", string);
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;
/* 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;
}
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;
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;
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)
{
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");
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);
/* 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;
/* 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;
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;
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;
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"";
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 =
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);
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);
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 *);
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 *);
#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 *);
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,
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
#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)
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 */
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;
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;
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;
/* 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);
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. */
}
-/* 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;
}
#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;
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*/
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;
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 */
/* 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 */
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)
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);
}
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);
}
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;
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);
}
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;
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;
|| 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;
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;
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;
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)))
{
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;
/* 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
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++)
/* 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 */
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. */
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;
/* 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
/* 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;
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
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)
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 *);
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);
}
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
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);
}
+/* 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;
*************************************************/
/* 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. */
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;
}
/* 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;
/* 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... */
/* ... 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;
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)
/* 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;
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';
}
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;
/* 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;
/* 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))
{
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 */
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;
}
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;
}
/* 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;
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
*/
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;
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))
{
else
{
- uschar *ss = s + len;
+ uschar * ss = s + len;
/* Find the last char before any trailing spaces */
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)))
/* 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,
/* 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;
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++))
{
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++ = '\"';
/* 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);
/*
/* 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;
/* 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)
{
/* 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)
{
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)
{
/* 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;
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;
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++))
{
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");
}
/* 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;
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;
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;
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))
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;
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;
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;
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
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));
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... */
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);
/* 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);
/* 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);
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;
#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;
}
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;
/* 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;
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",
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)
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)
{
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);
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);
{
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++)
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;
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;
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++)
{
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)))
{
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;
}
/* 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;
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;
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;
}
}
#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)
{
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
&& 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
(*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;
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;
/* 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)
{
/* 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;
}
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;
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];
}
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;
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;
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;
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);
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);
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);
}
}
*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 */
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);
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;
}
+/* 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);
+}
+
+
+
/*************************************************
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,
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;
}
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));
}
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
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
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;
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;
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));
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;
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;
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 */
}
/* 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);
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;
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;
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;
}
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;
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);
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)
{
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);
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);
}
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);
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
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;
{
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;
}
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)
{
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 */
/* 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. */
/* 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);
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);
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. */
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;
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;
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);
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
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;
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);
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
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
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;
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);
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;
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;
}
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;
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;
}
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]);
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;
}
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;
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)
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;
/* 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;
{
#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;
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>
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
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,
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));
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;
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;
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;
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)
(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;
}
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
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;
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;
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':
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
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;
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':
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;
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;
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)
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);
(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
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
#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 */
(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 == '-');
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 == '-');
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
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;
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++;
&& 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;
}
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);
}
/*************************************************
- 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
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. */
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
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",
[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",
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
{
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;
}
}
+#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
/******************************************************************************/
-/*************************************************
-* 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
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;
}
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,
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;
}
Arguments:
size amount wanted
+ proto_mem class: get store conformant to this
func function from which called
linenumber line number in source file
*/
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 *
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;
"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
#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;
}
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
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;
}
#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))
{
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
}
}
+/* 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;
}
+/**************/
/* 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.
*/
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)
{
}
#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;
}
rmark
-store_mark_3(const char *func, int linenumber)
+store_mark_3(const char * func, int linenumber)
{
void ** p;
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;
}
Arguments:
block block of store to consider
+ pp pool containing the block
func function from which called
linenumber line number in source file
*/
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. */
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;
}
#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
}
store_pool = oldpool;
}
-void message_tidyup(void)
+void
+message_tidyup(void)
{
int oldpool;
if (!message_reset_point) return;
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 */
/* Define symbols for identifying the store pools. */
-#define NPOOLS 10
enum { POOL_MAIN,
POOL_PERM,
POOL_CONFIG,
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. */
/* 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) \
/* 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 */
/* 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. */
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;
*/
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);
}
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)
{
/* 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 */
sep_is_special = iscntrl(sep);
/* Handle the case when a buffer is provided. */
+/*XXX need to also deal with qouted-requirements mismatch */
if (buffer)
{
{
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
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);
}
/* 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,
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 */
/* 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*/
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
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 */
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 *,
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
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 */
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));
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)))
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); }
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;
{
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);
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;
}
/* 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)
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);
}
{
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;
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;
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;
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);
}
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++] = '/';
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");
!= 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);
!= 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);
!= 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);
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);
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);
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);
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))
)
!= 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);
/* 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);
}
}
/* 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)
{
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);
}
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;
/* 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;
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;
}
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;
}
/* 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;
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
{
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;
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;
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\" "
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++] =
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
*/
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 != '/')
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)
{
{
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";
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
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;
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);
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);
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);
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;
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);
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] = '-';
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)
{
{
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;
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;
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;
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);
*/
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
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;
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
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 -----
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
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
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
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
--- /dev/null
+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'
}
# 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)/;
rcpt to:<c@d>
quit
****
+# Check the quote-tracking of tainted data.
+# Currently this will log but continue.
exim -odi -d ph10
Test message
.
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
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
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
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
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
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
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
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
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"
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
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
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"
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
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"
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"
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
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
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
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
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
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"
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
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
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"
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
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"
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"
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
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
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"
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
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
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"
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"
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"
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
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