X-Git-Url: https://git.exim.org/exim.git/blobdiff_plain/5fbb51949cbd9765421c5832c2d391f80f8183e9..92583637b25b6bde926f9ca6be7b085e5ac8b1e6:/src/src/acl.c diff --git a/src/src/acl.c b/src/src/acl.c index 57a07296f..2f20821c2 100644 --- a/src/src/acl.c +++ b/src/src/acl.c @@ -1186,8 +1186,6 @@ acl_verify_reverse(uschar **user_msgptr, uschar **log_msgptr) { int rc; -user_msgptr = user_msgptr; /* stop compiler warning */ - /* Previous success */ if (sender_host_name != NULL) return OK; @@ -1315,11 +1313,12 @@ acl_verify_csa(const uschar *domain) tree_node *t; const uschar *found; int priority, weight, port; -dns_answer * dnsa = store_get_dns_answer(); +dns_answer * dnsa; dns_scan dnss; dns_record *rr; -int rc, type; -uschar target[256]; +int rc, type, yield; +#define TARGET_SIZE 256 +uschar * target = store_get(TARGET_SIZE, TRUE); /* 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 @@ -1327,8 +1326,8 @@ instead. If it's a local client (exim -bs), CSA isn't applicable. */ while (isspace(*domain) && *domain != '\0') ++domain; if (*domain == '\0') domain = sender_helo_name; -if (domain == NULL) domain = sender_host_address; -if (sender_host_address == NULL) return CSA_UNKNOWN; +if (!domain) domain = sender_host_address; +if (!sender_host_address) return CSA_UNKNOWN; /* If we have an address literal, strip off the framing ready for turning it into a domain. The framing consists of matched square brackets possibly @@ -1358,8 +1357,8 @@ return the same result again. Otherwise build a new cached result structure for this domain. The name is filled in now, and the value is filled in when we return from this function. */ -t = tree_search(csa_cache, domain); -if (t != NULL) return t->data.val; +if ((t = tree_search(csa_cache, domain))) + return t->data.val; t = store_get_perm(sizeof(tree_node) + Ustrlen(domain), is_tainted(domain)); Ustrcpy(t->name, domain); @@ -1368,23 +1367,26 @@ Ustrcpy(t->name, domain); /* Now we are ready to do the actual DNS lookup(s). */ found = domain; +dnsa = store_get_dns_answer(); switch (dns_special_lookup(dnsa, domain, T_CSA, &found)) { /* If something bad happened (most commonly DNS_AGAIN), defer. */ default: - return t->data.val = CSA_DEFER_SRV; + yield = CSA_DEFER_SRV; + goto out; /* If we found nothing, the client's authorization is unknown. */ case DNS_NOMATCH: case DNS_NODATA: - return t->data.val = CSA_UNKNOWN; + yield = CSA_UNKNOWN; + goto out; /* We got something! Go on to look at the reply in more detail. */ case DNS_SUCCEED: - break; + break; } /* Scan the reply for well-formed CSA SRV records. */ @@ -1415,7 +1417,10 @@ for (rr = dns_next_rr(dnsa, &dnss, RESET_ANSWERS); SRV records of their own. */ if (Ustrcmp(found, domain) != 0) - return t->data.val = port & 1 ? CSA_FAIL_EXPLICIT : CSA_UNKNOWN; + { + yield = port & 1 ? CSA_FAIL_EXPLICIT : CSA_UNKNOWN; + goto out; + } /* This CSA SRV record refers directly to our domain, so we check the value in the weight field to work out the domain's authorization. 0 and 1 are @@ -1423,7 +1428,11 @@ for (rr = dns_next_rr(dnsa, &dnss, RESET_ANSWERS); address in order to authenticate it, so we treat it as unknown; values greater than 3 are undefined. */ - if (weight < 2) return t->data.val = CSA_FAIL_DOMAIN; + if (weight < 2) + { + yield = CSA_FAIL_DOMAIN; + goto out; + } if (weight > 2) continue; @@ -1432,7 +1441,7 @@ for (rr = dns_next_rr(dnsa, &dnss, RESET_ANSWERS); target hostname then break to scan the additional data for its addresses. */ (void)dn_expand(dnsa->answer, dnsa->answer + dnsa->answerlen, p, - (DN_EXPAND_ARG4_TYPE)target, sizeof(target)); + (DN_EXPAND_ARG4_TYPE)target, TARGET_SIZE); DEBUG(D_acl) debug_printf_indent("CSA target is %s\n", target); @@ -1441,7 +1450,11 @@ for (rr = dns_next_rr(dnsa, &dnss, RESET_ANSWERS); /* If we didn't break the loop then no appropriate records were found. */ -if (!rr) return t->data.val = CSA_UNKNOWN; +if (!rr) + { + yield = CSA_UNKNOWN; + goto out; + } /* Do not check addresses if the target is ".", in accordance with RFC 2782. A target of "." indicates there are no valid addresses, so the client cannot @@ -1449,7 +1462,11 @@ be authorized. (This is an odd configuration because weight=2 target=. is equivalent to weight=1, but we check for it in order to keep load off the root name servers.) Note that dn_expand() turns "." into "". */ -if (Ustrcmp(target, "") == 0) return t->data.val = CSA_FAIL_NOADDR; +if (Ustrcmp(target, "") == 0) + { + yield = CSA_FAIL_NOADDR; + goto out; + } /* Scan the additional section of the CSA SRV reply for addresses belonging to the target. If the name server didn't return any additional data (e.g. @@ -1457,7 +1474,11 @@ 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); -if (rc != CSA_FAIL_NOADDR) return t->data.val = rc; +if (rc != CSA_FAIL_NOADDR) + { + yield = rc; + goto out; + } /* The DNS lookup type corresponds to the IP version used by the client. */ @@ -1475,13 +1496,18 @@ switch (dns_lookup(dnsa, target, type, NULL)) /* If something bad happened (most commonly DNS_AGAIN), defer. */ default: - return t->data.val = CSA_DEFER_ADDR; + yield = CSA_DEFER_ADDR; + break; /* If the query succeeded, scan the addresses and return the result. */ case DNS_SUCCEED: rc = acl_verify_csa_address(dnsa, &dnss, RESET_ANSWERS, target); - if (rc != CSA_FAIL_NOADDR) return t->data.val = rc; + if (rc != CSA_FAIL_NOADDR) + { + yield = rc; + break; + } /* else fall through */ /* If the target has no IP addresses, the client cannot have an authorized @@ -1490,8 +1516,14 @@ switch (dns_lookup(dnsa, target, type, NULL)) case DNS_NOMATCH: case DNS_NODATA: - return t->data.val = CSA_FAIL_NOADDR; + yield = CSA_FAIL_NOADDR; + break; } + +out: + +store_free_dns_answer(dnsa); +return t->data.val = yield; } @@ -1517,14 +1549,14 @@ static verify_type_t verify_type_list[] = { { 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, FALSE, 0 }, - { US"header_sender", VERIFY_HDR_SNDR, ACL_BIT_DATA | ACL_BIT_NOTSMTP, FALSE, 0 }, + { US"header_syntax", VERIFY_HDR_SYNTAX, ACL_BITS_HAVEDATA, TRUE, 0 }, + { US"not_blind", VERIFY_NOT_BLIND, ACL_BITS_HAVEDATA, FALSE, 0 }, + { US"header_sender", VERIFY_HDR_SNDR, ACL_BITS_HAVEDATA, FALSE, 0 }, { US"sender", VERIFY_SNDR, ACL_BIT_MAIL | ACL_BIT_RCPT | ACL_BIT_PREDATA | ACL_BIT_DATA | ACL_BIT_NOTSMTP, FALSE, 6 }, { US"recipient", VERIFY_RCPT, ACL_BIT_RCPT, FALSE, 0 }, - { US"header_names_ascii", VERIFY_HDR_NAMES_ASCII, ACL_BIT_DATA | ACL_BIT_NOTSMTP, TRUE, 0 }, + { US"header_names_ascii", VERIFY_HDR_NAMES_ASCII, ACL_BITS_HAVEDATA, TRUE, 0 }, #ifdef EXPERIMENTAL_ARC { US"arc", VERIFY_ARC, ACL_BIT_DATA, FALSE , 0 }, #endif @@ -1789,7 +1821,7 @@ switch(vp->value) /* Remaining items are optional; they apply to sender and recipient verification, including "header sender" verification. */ -while ((ss = string_nextinlist(&list, &sep, big_buffer, big_buffer_size))) +while ((ss = string_nextinlist(&list, &sep, NULL, 0))) { if (strcmpic(ss, US"defer_ok") == 0) defer_ok = TRUE; else if (strcmpic(ss, US"no_details") == 0) no_details = TRUE; @@ -1946,7 +1978,8 @@ if (quota) { if (!*user_msgptr && *log_msgptr) *user_msgptr = string_sprintf("Rejected after %s: %s", - smtp_names[smtp_connection_had[smtp_ch_index-1]], *log_msgptr); + smtp_names[smtp_connection_had[SMTP_HBUFF_PREV(smtp_ch_index)]], + *log_msgptr); if (rc == DEFER) f.acl_temp_details = TRUE; } } @@ -3270,8 +3303,7 @@ for (; cb; cb = cb->next) { const uschar *pp = p + 6; while (*pp) pp++; - submission_name = string_copy(parse_fix_phrase(p+6, pp-p-6, - big_buffer, big_buffer_size)); + submission_name = parse_fix_phrase(p+6, pp-p-6); p = pp; } else break; @@ -3335,37 +3367,41 @@ for (; cb; cb = cb->next) the case where both sides handle prdr and this-node prdr acl is "accept" */ ignored = US"PRDR active"; + else if (f.deliver_freeze) + ignored = US"frozen"; + else if (f.queue_only_policy) + ignored = US"queue-only"; + else if (fake_response == FAIL) + ignored = US"fakereject"; + else if (rcpt_count != 1) + ignored = US"nonfirst rcpt"; + else if (cutthrough.delivery) + ignored = US"repeated"; + else if (cutthrough.callout_hold_only) + { + DEBUG(D_acl) + debug_printf_indent(" cutthrough request upgrades callout hold\n"); + cutthrough.callout_hold_only = FALSE; + cutthrough.delivery = TRUE; /* control accepted */ + } else { - if (f.deliver_freeze) - ignored = US"frozen"; - else if (f.queue_only_policy) - ignored = US"queue-only"; - else if (fake_response == FAIL) - ignored = US"fakereject"; - else + cutthrough.delivery = TRUE; /* control accepted */ + while (*p == '/') { - if (rcpt_count == 1) + const uschar * pp = p+1; + if (Ustrncmp(pp, "defer=", 6) == 0) { - cutthrough.delivery = TRUE; /* control accepted */ - while (*p == '/') - { - const uschar * pp = p+1; - if (Ustrncmp(pp, "defer=", 6) == 0) - { - pp += 6; - if (Ustrncmp(pp, "pass", 4) == 0) cutthrough.defer_pass = TRUE; - /* else if (Ustrncmp(pp, "spool") == 0) ; default */ - } - else - while (*pp && *pp != '/') pp++; - p = pp; - } + pp += 6; + if (Ustrncmp(pp, "pass", 4) == 0) cutthrough.defer_pass = TRUE; + /* else if (Ustrncmp(pp, "spool") == 0) ; default */ } else - ignored = US"nonfirst rcpt"; + while (*pp && *pp != '/') pp++; + p = pp; } } + DEBUG(D_acl) if (ignored) debug_printf(" cutthrough request ignored on %s item\n", ignored); } @@ -3420,11 +3456,11 @@ for (; cb; cb = cb->next) { /* Separate the regular expression and any optional parameters. */ const uschar * list = arg; - uschar *ss = string_nextinlist(&list, &sep, big_buffer, big_buffer_size); + uschar *ss = string_nextinlist(&list, &sep, NULL, 0); /* Run the dcc backend. */ rc = dcc_process(&ss); /* Modify return code based upon the existence of options. */ - while ((ss = string_nextinlist(&list, &sep, big_buffer, big_buffer_size))) + while ((ss = string_nextinlist(&list, &sep, NULL, 0))) if (strcmpic(ss, US"defer_ok") == 0 && rc == DEFER) rc = FAIL; /* FAIL so that the message is passed to the next ACL */ } @@ -3506,14 +3542,14 @@ for (; cb; cb = cb->next) case ACLC_DKIM_SIGNER: if (dkim_cur_signer) rc = match_isinlist(dkim_cur_signer, - &arg,0,NULL,NULL,MCL_STRING,TRUE,NULL); + &arg, 0, NULL, NULL, MCL_STRING, TRUE, NULL); else rc = FAIL; break; case ACLC_DKIM_STATUS: rc = match_isinlist(dkim_verify_status, - &arg,0,NULL,NULL,MCL_STRING,TRUE,NULL); + &arg, 0, NULL, NULL, MCL_STRING, TRUE, NULL); break; #endif @@ -3525,7 +3561,7 @@ for (; cb; cb = cb->next) /* used long way of dmarc_exim_expand_query() in case we need more * view into the process in the future. */ rc = match_isinlist(dmarc_exim_expand_query(DMARC_VERIFY_STATUS), - &arg,0,NULL,NULL,MCL_STRING,TRUE,NULL); + &arg, 0, NULL, NULL, MCL_STRING, TRUE, NULL); break; #endif @@ -3585,7 +3621,7 @@ for (; cb; cb = cb->next) int sep = 0; const uschar *s = arg; uschar * ss; - while ((ss = string_nextinlist(&s, &sep, big_buffer, big_buffer_size))) + while ((ss = string_nextinlist(&s, &sep, NULL, 0))) { if (Ustrcmp(ss, "main") == 0) logbits |= LOG_MAIN; else if (Ustrcmp(ss, "panic") == 0) logbits |= LOG_PANIC; @@ -3638,7 +3674,7 @@ for (; cb; cb = cb->next) { /* Separate the regular expression and any optional parameters. */ const uschar * list = arg; - uschar * ss = string_nextinlist(&list, &sep, big_buffer, big_buffer_size); + uschar * ss = string_nextinlist(&list, &sep, NULL, 0); uschar * opt; BOOL defer_ok = FALSE; int timeout = 0; @@ -3743,11 +3779,11 @@ for (; cb; cb = cb->next) { /* Separate the regular expression and any optional parameters. */ const uschar * list = arg; - uschar *ss = string_nextinlist(&list, &sep, big_buffer, big_buffer_size); + uschar *ss = string_nextinlist(&list, &sep, NULL, 0); rc = spam(CUSS &ss); /* Modify return code based upon the existence of options. */ - while ((ss = string_nextinlist(&list, &sep, big_buffer, big_buffer_size))) + while ((ss = string_nextinlist(&list, &sep, NULL, 0))) if (strcmpic(ss, US"defer_ok") == 0 && rc == DEFER) rc = FAIL; /* FAIL so that the message is passed to the next ACL */ } @@ -4541,7 +4577,8 @@ switch (where) /* Drop cutthrough conns, and drop heldopen verify conns if the previous was not DATA */ { - uschar prev = smtp_connection_had[smtp_ch_index-2]; + uschar prev = + smtp_connection_had[SMTP_HBUFF_PREV(SMTP_HBUFF_PREV(smtp_ch_index))]; BOOL dropverify = !(prev == SCH_DATA || prev == SCH_BDAT); cancel_cutthrough_connection(dropverify, US"quit or conndrop");