X-Git-Url: https://git.exim.org/exim.git/blobdiff_plain/db3f7b6972f3b003c0413b78afcfbe295ffe0b97..f374b08a8eb32aebe9d3a4a0455313ca911c3ff8:/src/src/acl.c diff --git a/src/src/acl.c b/src/src/acl.c index ac2d39c0c..799af39c3 100644 --- a/src/src/acl.c +++ b/src/src/acl.c @@ -70,7 +70,7 @@ enum { ACLC_ACL, ACLC_DKIM_SIGNER, ACLC_DKIM_STATUS, #endif -#ifdef EXPERIMENTAL_DMARC +#ifdef SUPPORT_DMARC ACLC_DMARC_STATUS, #endif ACLC_DNSLISTS, @@ -192,7 +192,7 @@ static condition_def conditions[] = { [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 @@ -346,7 +346,7 @@ enum { #ifndef DISABLE_DKIM CONTROL_DKIM_VERIFY, #endif -#ifdef EXPERIMENTAL_DMARC +#ifdef SUPPORT_DMARC CONTROL_DMARC_VERIFY, CONTROL_DMARC_FORENSIC, #endif @@ -367,9 +367,6 @@ enum { 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 @@ -420,7 +417,7 @@ static control_def controls_list[] = { }, #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 @@ -515,16 +512,6 @@ static control_def controls_list[] = { }, -#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) @@ -773,7 +760,7 @@ while ((s = (*func)()) != NULL) 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); @@ -790,12 +777,14 @@ while ((s = (*func)()) != NULL) *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 == '!') @@ -835,7 +824,7 @@ while ((s = (*func)()) != NULL) 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; @@ -1033,7 +1022,9 @@ for (p = q; *p; p = q) 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; @@ -1319,7 +1310,7 @@ acl_verify_csa(const uschar *domain) 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; @@ -1354,8 +1345,7 @@ extension to CSA, so we allow it to be turned off for proper conformance. */ 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, @@ -1366,14 +1356,14 @@ we return from this function. */ 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. */ @@ -1394,9 +1384,9 @@ switch (dns_special_lookup(&dnsa, domain, T_CSA, &found)) /* 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; @@ -1436,7 +1426,7 @@ for (rr = dns_next_rr(&dnsa, &dnss, RESET_ANSWERS); 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); @@ -1461,7 +1451,7 @@ to the target. If the name server didn't return any additional data (e.g. 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. */ @@ -1475,7 +1465,7 @@ else 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. */ @@ -1485,7 +1475,7 @@ switch (dns_lookup(&dnsa, target, type, NULL)) /* 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 */ @@ -1517,13 +1507,13 @@ typedef struct { 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, @@ -1722,14 +1712,27 @@ switch(vp->value) 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; + + 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()) != OK) + 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 @@ -2166,10 +2169,10 @@ gstring * g = 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; } @@ -2404,7 +2407,7 @@ if ((t = tree_search(*anchor, key))) /* 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; @@ -2453,7 +2456,7 @@ if (!dbdb) /* No Bloom filter. This basic ratelimit block is initialized below. */ HDEBUG(D_acl) debug_printf_indent("ratelimit creating new rate data block\n"); dbdb_size = sizeof(*dbd); - dbdb = store_get(dbdb_size); + dbdb = store_get(dbdb_size, FALSE); /* not tainted */ } else { @@ -2467,7 +2470,7 @@ if (!dbdb) extra = (int)limit * 2 - sizeof(dbdb->bloom); if (extra < 0) extra = 0; dbdb_size = sizeof(*dbdb) + extra; - dbdb = store_get(dbdb_size); + 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); @@ -2684,9 +2687,10 @@ else 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); @@ -2759,7 +2763,7 @@ if (*portend != '\0') } /* 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; @@ -3024,18 +3028,18 @@ for (; cb; cb = cb->next) 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; @@ -3043,7 +3047,7 @@ for (; cb; cb = cb->next) case CONTROL_DMARC_FORENSIC: f.dmarc_enable_forensic = TRUE; break; - #endif +#endif case CONTROL_DSCP: if (*p == '/') @@ -3166,11 +3170,6 @@ for (; cb; cb = cb->next) 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; @@ -3442,7 +3441,7 @@ for (; cb; cb = cb->next) break; #endif - #ifdef EXPERIMENTAL_DMARC +#ifdef SUPPORT_DMARC case ACLC_DMARC_STATUS: if (!f.dmarc_has_been_checked) dmarc_process(); @@ -3452,7 +3451,7 @@ for (; cb; cb = cb->next) 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); @@ -3496,7 +3495,7 @@ for (; cb; cb = cb->next) (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: @@ -3598,7 +3597,7 @@ for (; cb; cb = cb->next) "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: @@ -3983,11 +3982,10 @@ read an ACL from a file, and save it so it can be re-used. */ 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; @@ -3999,14 +3997,20 @@ if (Ustrchr(ss, ' ') == NULL) 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, @@ -4014,7 +4018,8 @@ if (Ustrchr(ss, ' ') == NULL) 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) @@ -4044,7 +4049,7 @@ if (!acl) 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); @@ -4064,7 +4069,8 @@ while (acl) *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. */ @@ -4079,44 +4085,47 @@ while (acl) 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 @@ -4126,84 +4135,85 @@ while (acl) 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 */ @@ -4520,7 +4530,7 @@ acl_var_create(uschar * name) tree_node * node, ** root = name[0] == 'c' ? &acl_var_c : &acl_var_m; if (!(node = tree_search(*root, name))) { - node = store_get(sizeof(tree_node) + Ustrlen(name)); + node = store_get(sizeof(tree_node) + Ustrlen(name), is_tainted(name)); Ustrcpy(node->name, name); (void)tree_insertnode(root, node); } @@ -4554,6 +4564,7 @@ void 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); }