ACLC_DKIM_SIGNER,
ACLC_DKIM_STATUS,
#endif
-#ifdef EXPERIMENTAL_DMARC
+#ifdef SUPPORT_DMARC
ACLC_DMARC_STATUS,
#endif
ACLC_DNSLISTS,
[ACLC_DKIM_SIGNER] = { US"dkim_signers", TRUE, FALSE, (unsigned int) ~ACL_BIT_DKIM },
[ACLC_DKIM_STATUS] = { US"dkim_status", TRUE, FALSE, (unsigned int) ~ACL_BIT_DKIM },
#endif
-#ifdef EXPERIMENTAL_DMARC
+#ifdef SUPPORT_DMARC
[ACLC_DMARC_STATUS] = { US"dmarc_status", TRUE, FALSE, (unsigned int) ~ACL_BIT_DATA },
#endif
#ifndef DISABLE_DKIM
CONTROL_DKIM_VERIFY,
#endif
-#ifdef EXPERIMENTAL_DMARC
+#ifdef SUPPORT_DMARC
CONTROL_DMARC_VERIFY,
CONTROL_DMARC_FORENSIC,
#endif
CONTROL_NO_PIPELINING,
CONTROL_QUEUE_ONLY,
-#if defined(SUPPORT_TLS) && defined(EXPERIMENTAL_REQUIRETLS)
- CONTROL_REQUIRETLS,
-#endif
CONTROL_SUBMISSION,
CONTROL_SUPPRESS_LOCAL_FIXUPS,
#ifdef SUPPORT_I18N
},
#endif
-#ifdef EXPERIMENTAL_DMARC
+#ifdef SUPPORT_DMARC
[CONTROL_DMARC_VERIFY] =
{ US"dmarc_disable_verify", FALSE,
ACL_BIT_DATA | ACL_BIT_NOTSMTP | ACL_BIT_NOTSMTP_START
},
-#if defined(SUPPORT_TLS) && defined(EXPERIMENTAL_REQUIRETLS)
-[CONTROL_REQUIRETLS] =
- { US"requiretls", FALSE,
- (unsigned)
- ~(ACL_BIT_MAIL | ACL_BIT_RCPT | ACL_BIT_PREDATA |
- ACL_BIT_DATA | ACL_BIT_MIME |
- ACL_BIT_NOTSMTP)
- },
-#endif
-
[CONTROL_SUBMISSION] =
{ US"submission", TRUE,
(unsigned)
if ((v = acl_checkname(name, verbs, nelem(verbs))) < 0)
{
- if (this == NULL)
+ if (!this)
{
*error = string_sprintf("unknown ACL verb \"%s\" in \"%s\"", name,
saveline);
*error = string_sprintf("malformed ACL line \"%s\"", saveline);
return NULL;
}
- this = store_get(sizeof(acl_block));
+ this = store_get(sizeof(acl_block), FALSE);
*lastp = this;
lastp = &(this->next);
this->next = NULL;
- this->verb = v;
this->condition = NULL;
+ this->verb = v;
+ this->srcline = config_lineno; /* for debug output */
+ this->srcfile = config_filename; /**/
condp = &(this->condition);
if (*s == 0) continue; /* No condition on this line */
if (*s == '!')
return NULL;
}
- cond = store_get(sizeof(acl_condition_block));
+ cond = store_get(sizeof(acl_condition_block), FALSE);
cond->next = NULL;
cond->type = c;
cond->u.negated = negated;
{
uschar *endptr;
- if (Ustrncmp(s, "acl_c", 5) != 0 &&
- Ustrncmp(s, "acl_m", 5) != 0)
+ if (Ustrncmp(s, "acl_c", 5) != 0 && Ustrncmp(s, "acl_m", 5) != 0)
{
*error = string_sprintf("invalid variable name after \"set\" in ACL "
- "modifier \"set %s\" (must start \"acl_c\" or \"acl_m\")", s);
+ "modifier \"set %s\" (must start \"acl_c\" or \"acl_m\")", s);
return NULL;
}
if (!isdigit(*endptr) && *endptr != '_')
{
*error = string_sprintf("invalid variable name after \"set\" in ACL "
- "modifier \"set %s\" (digit or underscore must follow acl_c or acl_m)",
- s);
+ "modifier \"set %s\" (digit or underscore must follow acl_c or acl_m)",
+ s);
return NULL;
}
- while (*endptr != 0 && *endptr != '=' && !isspace(*endptr))
+ while (*endptr && *endptr != '=' && !isspace(*endptr))
{
if (!isalnum(*endptr) && *endptr != '_')
- {
- *error = string_sprintf("invalid character \"%c\" in variable name "
- "in ACL modifier \"set %s\"", *endptr, s);
- return NULL;
- }
+ {
+ *error = string_sprintf("invalid character \"%c\" in variable name "
+ "in ACL modifier \"set %s\"", *endptr, s);
+ return NULL;
+ }
endptr++;
}
if (!*hptr)
{
- header_line *h = store_get(sizeof(header_line));
+ /* The header_line struct itself is not tainted, though it points to
+ tainted data. */
+ header_line *h = store_get(sizeof(header_line), FALSE);
h->text = hdr;
h->next = NULL;
h->type = newtype;
tree_node *t;
const uschar *found;
int priority, weight, port;
-dns_answer dnsa;
+dns_answer * dnsa = store_get_dns_answer();
dns_scan dnss;
dns_record *rr;
int rc, type;
if (string_is_ip_address(domain, NULL) != 0)
{
if (!dns_csa_use_reverse) return CSA_UNKNOWN;
- dns_build_reverse(domain, target);
- domain = target;
+ domain = dns_build_reverse(domain);
}
/* Find out if we've already done the CSA check for this domain. If we have,
t = tree_search(csa_cache, domain);
if (t != NULL) return t->data.val;
-t = store_get_perm(sizeof(tree_node) + Ustrlen(domain));
+t = store_get_perm(sizeof(tree_node) + Ustrlen(domain), is_tainted(domain));
Ustrcpy(t->name, domain);
(void)tree_insertnode(&csa_cache, t);
/* Now we are ready to do the actual DNS lookup(s). */
found = domain;
-switch (dns_special_lookup(&dnsa, domain, T_CSA, &found))
+switch (dns_special_lookup(dnsa, domain, T_CSA, &found))
{
/* If something bad happened (most commonly DNS_AGAIN), defer. */
/* Scan the reply for well-formed CSA SRV records. */
-for (rr = dns_next_rr(&dnsa, &dnss, RESET_ANSWERS);
+for (rr = dns_next_rr(dnsa, &dnss, RESET_ANSWERS);
rr;
- rr = dns_next_rr(&dnsa, &dnss, RESET_NEXT)) if (rr->type == T_SRV)
+ rr = dns_next_rr(dnsa, &dnss, RESET_NEXT)) if (rr->type == T_SRV)
{
const uschar * p = rr->data;
client's IP address is listed as one of the SRV target addresses. Save the
target hostname then break to scan the additional data for its addresses. */
- (void)dn_expand(dnsa.answer, dnsa.answer + dnsa.answerlen, p,
+ (void)dn_expand(dnsa->answer, dnsa->answer + dnsa->answerlen, p,
(DN_EXPAND_ARG4_TYPE)target, sizeof(target));
DEBUG(D_acl) debug_printf_indent("CSA target is %s\n", target);
because it does not fully support SRV records), we need to do another lookup
to obtain the target addresses; otherwise we have a definitive result. */
-rc = acl_verify_csa_address(&dnsa, &dnss, RESET_ADDITIONAL, target);
+rc = acl_verify_csa_address(dnsa, &dnss, RESET_ADDITIONAL, target);
if (rc != CSA_FAIL_NOADDR) return t->data.val = rc;
/* The DNS lookup type corresponds to the IP version used by the client. */
lookup_dnssec_authenticated = NULL;
-switch (dns_lookup(&dnsa, target, type, NULL))
+switch (dns_lookup(dnsa, target, type, NULL))
{
/* If something bad happened (most commonly DNS_AGAIN), defer. */
/* If the query succeeded, scan the addresses and return the result. */
case DNS_SUCCEED:
- rc = acl_verify_csa_address(&dnsa, &dnss, RESET_ANSWERS, target);
+ rc = acl_verify_csa_address(dnsa, &dnss, RESET_ANSWERS, target);
if (rc != CSA_FAIL_NOADDR) return t->data.val = rc;
/* else fall through */
unsigned alt_opt_sep; /* >0 Non-/ option separator (custom parser) */
} verify_type_t;
static verify_type_t verify_type_list[] = {
- /* name value where no-opt opt-sep */
- { US"reverse_host_lookup", VERIFY_REV_HOST_LKUP, ~0, FALSE, 0 },
- { US"certificate", VERIFY_CERT, ~0, TRUE, 0 },
- { US"helo", VERIFY_HELO, ~0, TRUE, 0 },
- { US"csa", VERIFY_CSA, ~0, FALSE, 0 },
+ /* name value where no-opt opt-sep */
+ { US"reverse_host_lookup", VERIFY_REV_HOST_LKUP, (unsigned)~0, FALSE, 0 },
+ { US"certificate", VERIFY_CERT, (unsigned)~0, TRUE, 0 },
+ { US"helo", VERIFY_HELO, (unsigned)~0, TRUE, 0 },
+ { US"csa", VERIFY_CSA, (unsigned)~0, FALSE, 0 },
{ US"header_syntax", VERIFY_HDR_SYNTAX, ACL_BIT_DATA | ACL_BIT_NOTSMTP, TRUE, 0 },
- { US"not_blind", VERIFY_NOT_BLIND, ACL_BIT_DATA | ACL_BIT_NOTSMTP, TRUE, 0 },
+ { US"not_blind", VERIFY_NOT_BLIND, ACL_BIT_DATA | ACL_BIT_NOTSMTP, FALSE, 0 },
{ US"header_sender", VERIFY_HDR_SNDR, ACL_BIT_DATA | ACL_BIT_NOTSMTP, FALSE, 0 },
{ US"sender", VERIFY_SNDR, ACL_BIT_MAIL | ACL_BIT_RCPT
|ACL_BIT_PREDATA | ACL_BIT_DATA | ACL_BIT_NOTSMTP,
case VERIFY_NOT_BLIND:
/* Check that no recipient of this message is "blind", that is, every envelope
recipient must be mentioned in either To: or Cc:. */
+ {
+ BOOL case_sensitive = TRUE;
- if ((rc = verify_check_notblind()) != OK)
+ while ((ss = string_nextinlist(&list, &sep, NULL, 0)))
+ if (strcmpic(ss, US"case_insensitive") == 0)
+ case_sensitive = FALSE;
+ else
+ {
+ *log_msgptr = string_sprintf("unknown option \"%s\" in ACL "
+ "condition \"verify %s\"", ss, arg);
+ return ERROR;
+ }
+
+ if ((rc = verify_check_notblind(case_sensitive)) != OK)
{
- *log_msgptr = string_sprintf("bcc recipient detected");
+ *log_msgptr = US"bcc recipient detected";
if (smtp_return_error_details)
*user_msgptr = string_sprintf("Rejected after DATA: %s", *log_msgptr);
}
return rc;
+ }
/* The remaining verification tests check recipient and sender addresses,
either from the envelope or from the header. There are a number of
string_cat(NULL, US"error in arguments to \"ratelimit\" condition: ");
va_start(ap, format);
-g = string_vformat(g, TRUE, format, ap);
+g = string_vformat(g, SVFMT_EXTEND|SVFMT_REBUFFER, format, ap);
va_end(ap);
-gstring_reset_unused(g);
+gstring_release_unused(g);
*log_msgptr = string_from_gstring(g);
return ERROR;
}
/* We aren't using a pre-computed rate, so get a previously recorded rate
from the database, which will be updated and written back if required. */
-if (!(dbm = dbfn_open(US"ratelimit", O_RDWR, &dbblock, TRUE)))
+if (!(dbm = dbfn_open(US"ratelimit", O_RDWR, &dbblock, TRUE, TRUE)))
{
store_pool = old_pool;
sender_rate = NULL;
/* 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);
+ dbdb = store_get(dbdb_size, FALSE); /* not tainted */
}
else
{
extra = (int)limit * 2 - sizeof(dbdb->bloom);
if (extra < 0) extra = 0;
dbdb_size = sizeof(*dbdb) + extra;
- dbdb = store_get(dbdb_size);
+ dbdb = store_get(dbdb_size, FALSE); /* not tainted */
dbdb->bloom_epoch = tv.tv_sec;
dbdb->bloom_size = sizeof(dbdb->bloom) + extra;
memset(dbdb->bloom, 0, dbdb->bloom_size);
dbfn_close(dbm);
-/* Store the result in the tree for future reference. */
+/* 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));
+t = store_get(sizeof(tree_node) + Ustrlen(key), is_tainted(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));
+h = store_get(sizeof(host_item), FALSE);
memset(h, 0, sizeof(host_item));
h->name = hostname;
h->port = portnum;
break;
#endif
- #ifndef DISABLE_DKIM
+#ifndef DISABLE_DKIM
case CONTROL_DKIM_VERIFY:
f.dkim_disable_verify = TRUE;
- #ifdef EXPERIMENTAL_DMARC
+# ifdef SUPPORT_DMARC
/* Since DKIM was blocked, skip DMARC too */
f.dmarc_disable_verify = TRUE;
f.dmarc_enable_forensic = FALSE;
- #endif
+# endif
break;
- #endif
+#endif
- #ifdef EXPERIMENTAL_DMARC
+#ifdef SUPPORT_DMARC
case CONTROL_DMARC_VERIFY:
f.dmarc_disable_verify = TRUE;
break;
case CONTROL_DMARC_FORENSIC:
f.dmarc_enable_forensic = TRUE;
break;
- #endif
+#endif
case CONTROL_DSCP:
if (*p == '/')
cancel_cutthrough_connection(TRUE, US"queueing forced");
break;
-#if defined(SUPPORT_TLS) && defined(EXPERIMENTAL_REQUIRETLS)
- case CONTROL_REQUIRETLS:
- tls_requiretls |= REQUIRETLS_MSG;
- break;
-#endif
case CONTROL_SUBMISSION:
originator_name = US"";
f.submission_mode = TRUE;
break;
#endif
- #ifdef EXPERIMENTAL_DMARC
+#ifdef SUPPORT_DMARC
case ACLC_DMARC_STATUS:
if (!f.dmarc_has_been_checked)
dmarc_process();
rc = match_isinlist(dmarc_exim_expand_query(DMARC_VERIFY_STATUS),
&arg,0,NULL,NULL,MCL_STRING,TRUE,NULL);
break;
- #endif
+#endif
case ACLC_DNSLISTS:
rc = verify_check_dnsbl(where, &arg, log_msgptr);
(sender_host_address == NULL)? US"" : sender_host_address,
CUSS &host_data);
if (rc == DEFER) *log_msgptr = search_error_message;
- if (host_data) host_data = string_copy_malloc(host_data);
+ if (host_data) host_data = string_copy_perm(host_data, TRUE);
break;
case ACLC_LOCAL_PARTS:
"Directory separator not permitted in queue name: '%s'", arg);
return ERROR;
}
- queue_name = string_copy_malloc(arg);
+ queue_name = string_copy_perm(arg, FALSE);
break;
case ACLC_RATELIMIT:
sender_address_cache, -1, 0, CUSS &sender_data);
break;
- /* Connection variables must persist forever */
+ /* Connection variables must persist forever; message variables not */
case ACLC_SET:
{
int old_pool = store_pool;
- if ( cb->u.varname[0] == 'c'
-#ifndef DISABLE_DKIM
- || cb->u.varname[0] == 'd'
-#endif
+ if ( cb->u.varname[0] != 'm'
#ifndef DISABLE_EVENT
|| event_name /* An event is being delivered */
#endif
if (Ustrchr(ss, ' ') == NULL)
{
- tree_node *t = tree_search(acl_anchor, ss);
- if (t != NULL)
+ tree_node * t = tree_search(acl_anchor, ss);
+ if (t)
{
- acl = (acl_block *)(t->data.ptr);
- if (acl == NULL)
+ if (!(acl = (acl_block *)(t->data.ptr)))
{
HDEBUG(D_acl) debug_printf_indent("ACL \"%s\" is empty: implicit DENY\n", ss);
return FAIL;
else if (*ss == '/')
{
struct stat statbuf;
- fd = Uopen(ss, O_RDONLY, 0);
- if (fd < 0)
+ if (is_tainted(ss))
+ {
+ log_write(0, LOG_MAIN|LOG_PANIC,
+ "attempt to open tainted ACL file name \"%s\"", ss);
+ /* Avoid leaking info to an attacker */
+ *log_msgptr = US"internal configuration error";
+ return ERROR;
+ }
+ if ((fd = Uopen(ss, O_RDONLY, 0)) < 0)
{
*log_msgptr = string_sprintf("failed to open ACL file \"%s\": %s", ss,
strerror(errno));
return ERROR;
}
-
if (fstat(fd, &statbuf) != 0)
{
*log_msgptr = string_sprintf("failed to fstat ACL file \"%s\": %s", ss,
return ERROR;
}
- acl_text = store_get(statbuf.st_size + 1);
+ /* 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_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));
+ tree_node *t = store_get_perm(sizeof(tree_node) + Ustrlen(ss), is_tainted(ss));
Ustrcpy(t->name, ss);
t->data.ptr = acl;
(void)tree_insertnode(&acl_anchor, t);
*log_msgptr = *user_msgptr = NULL;
f.acl_temp_details = FALSE;
- HDEBUG(D_acl) debug_printf_indent("processing \"%s\"\n", verbs[acl->verb]);
+ HDEBUG(D_acl) debug_printf_indent("processing \"%s\" (%s %d)\n",
+ verbs[acl->verb], acl->srcfile, acl->srcline);
/* Clear out any search error message from a previous check before testing
this condition. */
switch (cond)
{
case DEFER:
- HDEBUG(D_acl) debug_printf_indent("%s: condition test deferred in %s\n", verbs[acl->verb], acl_name);
- if (basic_errno != ERRNO_CALLOUTDEFER)
- {
- if (search_error_message != NULL && *search_error_message != 0)
- *log_msgptr = search_error_message;
- if (smtp_return_error_details) f.acl_temp_details = TRUE;
- }
- else
- f.acl_temp_details = TRUE;
- if (acl->verb != ACL_WARN) return DEFER;
- break;
+ HDEBUG(D_acl) debug_printf_indent("%s: condition test deferred in %s\n",
+ verbs[acl->verb], acl_name);
+ if (basic_errno != ERRNO_CALLOUTDEFER)
+ {
+ if (search_error_message != NULL && *search_error_message != 0)
+ *log_msgptr = search_error_message;
+ if (smtp_return_error_details) f.acl_temp_details = TRUE;
+ }
+ else
+ f.acl_temp_details = TRUE;
+ if (acl->verb != ACL_WARN) return DEFER;
+ break;
default: /* Paranoia */
case ERROR:
- HDEBUG(D_acl) debug_printf_indent("%s: condition test error in %s\n", verbs[acl->verb], acl_name);
- return ERROR;
+ HDEBUG(D_acl) debug_printf_indent("%s: condition test error in %s\n",
+ verbs[acl->verb], acl_name);
+ return ERROR;
case OK:
- HDEBUG(D_acl) debug_printf_indent("%s: condition test succeeded in %s\n",
- verbs[acl->verb], acl_name);
- break;
+ HDEBUG(D_acl) debug_printf_indent("%s: condition test succeeded in %s\n",
+ verbs[acl->verb], acl_name);
+ break;
case FAIL:
- HDEBUG(D_acl) debug_printf_indent("%s: condition test failed in %s\n", verbs[acl->verb], acl_name);
- break;
+ HDEBUG(D_acl) debug_printf_indent("%s: condition test failed in %s\n",
+ verbs[acl->verb], acl_name);
+ break;
/* DISCARD and DROP can happen only from a nested ACL condition, and
DISCARD can happen only for an "accept" or "discard" verb. */
case DISCARD:
- HDEBUG(D_acl) debug_printf_indent("%s: condition test yielded \"discard\" in %s\n",
- verbs[acl->verb], acl_name);
- break;
+ HDEBUG(D_acl) debug_printf_indent("%s: condition test yielded \"discard\" in %s\n",
+ verbs[acl->verb], acl_name);
+ break;
case FAIL_DROP:
- HDEBUG(D_acl) debug_printf_indent("%s: condition test yielded \"drop\" in %s\n",
- verbs[acl->verb], acl_name);
- break;
+ HDEBUG(D_acl) debug_printf_indent("%s: condition test yielded \"drop\" in %s\n",
+ verbs[acl->verb], acl_name);
+ break;
}
/* At this point, cond for most verbs is either OK or FAIL or (as a result of
switch(acl->verb)
{
case ACL_ACCEPT:
- if (cond == OK || cond == DISCARD)
- {
- HDEBUG(D_acl) debug_printf_indent("end of %s: ACCEPT\n", acl_name);
- return cond;
- }
- if (endpass_seen)
- {
- HDEBUG(D_acl) debug_printf_indent("accept: endpass encountered - denying access\n");
- return cond;
- }
- break;
+ if (cond == OK || cond == DISCARD)
+ {
+ HDEBUG(D_acl) debug_printf_indent("end of %s: ACCEPT\n", acl_name);
+ return cond;
+ }
+ if (endpass_seen)
+ {
+ HDEBUG(D_acl) debug_printf_indent("accept: endpass encountered - denying access\n");
+ return cond;
+ }
+ break;
case ACL_DEFER:
- if (cond == OK)
- {
- HDEBUG(D_acl) debug_printf_indent("end of %s: DEFER\n", acl_name);
- if (acl_quit_check) goto badquit;
- f.acl_temp_details = TRUE;
- return DEFER;
- }
- break;
+ if (cond == OK)
+ {
+ HDEBUG(D_acl) debug_printf_indent("end of %s: DEFER\n", acl_name);
+ if (acl_quit_check) goto badquit;
+ f.acl_temp_details = TRUE;
+ return DEFER;
+ }
+ break;
case ACL_DENY:
- if (cond == OK)
- {
- HDEBUG(D_acl) debug_printf_indent("end of %s: DENY\n", acl_name);
- if (acl_quit_check) goto badquit;
- return FAIL;
- }
- break;
+ if (cond == OK)
+ {
+ HDEBUG(D_acl) debug_printf_indent("end of %s: DENY\n", acl_name);
+ if (acl_quit_check) goto badquit;
+ return FAIL;
+ }
+ break;
case ACL_DISCARD:
- if (cond == OK || cond == DISCARD)
- {
- HDEBUG(D_acl) debug_printf_indent("end of %s: DISCARD\n", acl_name);
- if (acl_quit_check) goto badquit;
- return DISCARD;
- }
- if (endpass_seen)
- {
- HDEBUG(D_acl) debug_printf_indent("discard: endpass encountered - denying access\n");
- return cond;
- }
- break;
+ if (cond == OK || cond == DISCARD)
+ {
+ HDEBUG(D_acl) debug_printf_indent("end of %s: DISCARD\n", acl_name);
+ if (acl_quit_check) goto badquit;
+ return DISCARD;
+ }
+ if (endpass_seen)
+ {
+ HDEBUG(D_acl)
+ debug_printf_indent("discard: endpass encountered - denying access\n");
+ return cond;
+ }
+ break;
case ACL_DROP:
- if (cond == OK)
- {
- HDEBUG(D_acl) debug_printf_indent("end of %s: DROP\n", acl_name);
- if (acl_quit_check) goto badquit;
- return FAIL_DROP;
- }
- break;
+ if (cond == OK)
+ {
+ HDEBUG(D_acl) debug_printf_indent("end of %s: DROP\n", acl_name);
+ if (acl_quit_check) goto badquit;
+ return FAIL_DROP;
+ }
+ break;
case ACL_REQUIRE:
- if (cond != OK)
- {
- HDEBUG(D_acl) debug_printf_indent("end of %s: not OK\n", acl_name);
- if (acl_quit_check) goto badquit;
- return cond;
- }
- break;
+ if (cond != OK)
+ {
+ HDEBUG(D_acl) debug_printf_indent("end of %s: not OK\n", acl_name);
+ if (acl_quit_check) goto badquit;
+ return cond;
+ }
+ break;
case ACL_WARN:
- if (cond == OK)
- acl_warn(where, *user_msgptr, *log_msgptr);
- 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 = *user_msgptr = NULL; /* In case implicit DENY follows */
- break;
+ if (cond == OK)
+ acl_warn(where, *user_msgptr, *log_msgptr);
+ 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 = *user_msgptr = NULL; /* In case implicit DENY follows */
+ break;
default:
- log_write(0, LOG_MAIN|LOG_PANIC_DIE, "internal ACL error: unknown verb %d",
- acl->verb);
- break;
+ log_write(0, LOG_MAIN|LOG_PANIC_DIE, "internal ACL error: unknown verb %d",
+ acl->verb);
+ break;
}
/* Pass to the next ACL item */
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));
+ node = store_get(sizeof(tree_node) + Ustrlen(name), is_tainted(name));
Ustrcpy(node->name, name);
(void)tree_insertnode(root, node);
}
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);
}