X-Git-Url: https://git.exim.org/exim.git/blobdiff_plain/ec4b68e5d820109e5954329013a911d4032bc4dc..0f0c8159c43045f4ad847a0129dca7eddd313285:/src/src/acl.c diff --git a/src/src/acl.c b/src/src/acl.c index a721665d4..8fdae0390 100644 --- a/src/src/acl.c +++ b/src/src/acl.c @@ -2,7 +2,7 @@ * Exim - an Internet mail transport agent * *************************************************/ -/* Copyright (c) University of Cambridge 1995 - 2012 */ +/* Copyright (c) University of Cambridge 1995 - 2014 */ /* See the file NOTICE for conditions of use and distribution. */ /* Code for handling Access Control Lists (ACLs) */ @@ -21,8 +21,13 @@ enum { ACL_ACCEPT, ACL_DEFER, ACL_DENY, ACL_DISCARD, ACL_DROP, ACL_REQUIRE, /* ACL verbs */ -static uschar *verbs[] = - { US"accept", US"defer", US"deny", US"discard", US"drop", US"require", +static uschar *verbs[] = { + US"accept", + US"defer", + US"deny", + US"discard", + US"drop", + US"require", US"warn" }; /* For each verb, the conditions for which "message" or "log_message" are used @@ -66,6 +71,9 @@ enum { ACLC_ACL, #ifndef DISABLE_DKIM ACLC_DKIM_SIGNER, ACLC_DKIM_STATUS, +#endif +#ifdef EXPERIMENTAL_DMARC + ACLC_DMARC_STATUS, #endif ACLC_DNSLISTS, ACLC_DOMAINS, @@ -88,6 +96,7 @@ enum { ACLC_ACL, #ifdef WITH_CONTENT_SCAN ACLC_REGEX, #endif + ACLC_REMOVE_HEADER, ACLC_SENDER_DOMAINS, ACLC_SENDERS, ACLC_SET, @@ -98,6 +107,7 @@ enum { ACLC_ACL, ACLC_SPF, ACLC_SPF_GUESS, #endif + ACLC_UDPSEND, ACLC_VERIFY }; /* ACL conditions/modifiers: "delay", "control", "continue", "endpass", @@ -128,6 +138,9 @@ static uschar *conditions[] = { #ifndef DISABLE_DKIM US"dkim_signers", US"dkim_status", +#endif +#ifdef EXPERIMENTAL_DMARC + US"dmarc_status", #endif US"dnslists", US"domains", @@ -150,6 +163,7 @@ static uschar *conditions[] = { #ifdef WITH_CONTENT_SCAN US"regex", #endif + US"remove_header", US"sender_domains", US"senders", US"set", #ifdef WITH_CONTENT_SCAN US"spam", @@ -158,6 +172,7 @@ static uschar *conditions[] = { US"spf", US"spf_guess", #endif + US"udpsend", US"verify" }; @@ -173,6 +188,10 @@ enum { #ifndef DISABLE_DKIM CONTROL_DKIM_VERIFY, #endif + #ifdef EXPERIMENTAL_DMARC + CONTROL_DMARC_VERIFY, + CONTROL_DMARC_FORENSIC, + #endif CONTROL_DSCP, CONTROL_ERROR, CONTROL_CASEFUL_LOCAL_PART, @@ -209,6 +228,10 @@ static uschar *controls[] = { #ifndef DISABLE_DKIM US"dkim_disable_verify", #endif + #ifdef EXPERIMENTAL_DMARC + US"dmarc_disable_verify", + US"dmarc_enable_forensic", + #endif US"dscp", US"error", US"caseful_local_part", @@ -236,7 +259,7 @@ at the outer level. In the other cases, expansion already occurs in the checking functions. */ static uschar cond_expand_at_top[] = { - TRUE, /* acl */ + FALSE, /* acl */ TRUE, /* add_header */ FALSE, /* authenticated */ #ifdef EXPERIMENTAL_BRIGHTMAIL @@ -258,6 +281,9 @@ static uschar cond_expand_at_top[] = { #ifndef DISABLE_DKIM TRUE, /* dkim_signers */ TRUE, /* dkim_status */ +#endif +#ifdef EXPERIMENTAL_DMARC + TRUE, /* dmarc_status */ #endif TRUE, /* dnslists */ FALSE, /* domains */ @@ -280,6 +306,7 @@ static uschar cond_expand_at_top[] = { #ifdef WITH_CONTENT_SCAN TRUE, /* regex */ #endif + TRUE, /* remove_header */ FALSE, /* sender_domains */ FALSE, /* senders */ TRUE, /* set */ @@ -290,6 +317,7 @@ static uschar cond_expand_at_top[] = { TRUE, /* spf */ TRUE, /* spf_guess */ #endif + TRUE, /* udpsend */ TRUE /* verify */ }; @@ -318,6 +346,9 @@ static uschar cond_modifiers[] = { #ifndef DISABLE_DKIM FALSE, /* dkim_signers */ FALSE, /* dkim_status */ +#endif +#ifdef EXPERIMENTAL_DMARC + FALSE, /* dmarc_status */ #endif FALSE, /* dnslists */ FALSE, /* domains */ @@ -340,6 +371,7 @@ static uschar cond_modifiers[] = { #ifdef WITH_CONTENT_SCAN FALSE, /* regex */ #endif + TRUE, /* remove_header */ FALSE, /* sender_domains */ FALSE, /* senders */ TRUE, /* set */ @@ -350,6 +382,7 @@ static uschar cond_modifiers[] = { FALSE, /* spf */ FALSE, /* spf_guess */ #endif + TRUE, /* udpsend */ FALSE /* verify */ }; @@ -364,6 +397,9 @@ static unsigned int cond_forbids[] = { (unsigned int) ~((1<text; + while ((cp = Ustrchr(s, '\n')) != NULL) + { + if (cp[1] == '\0') break; + + /* contains embedded newline; needs doubling */ + ret = string_cat(ret, &size, &ptr, s, cp-s+1); + ret = string_cat(ret, &size, &ptr, US"\n", 1); + s = cp+1; + } + /* last bit of header */ + + ret = string_cat(ret, &size, &ptr, s, cp-s+1); /* newline-sep list */ + } +while((h = h->next)); + +ret[ptr-1] = '\0'; /* overwrite last newline */ +return ret; +} + + +/************************************************* +* Set up removed header line(s) * +*************************************************/ + +/* This function is called by the remove_header modifier. The argument is +treated as a sequence of header names which are added to a colon separated +list, provided there isn't an identical one already there. + +Argument: string of header names +Returns: nothing +*/ + +static void +setup_remove_header(uschar *hnames) +{ +if (*hnames != 0) + { + if (acl_removed_headers == NULL) + acl_removed_headers = hnames; + else + acl_removed_headers = string_sprintf("%s : %s", acl_removed_headers, hnames); + } +} + + /************************************************* * Handle warnings * @@ -1378,7 +1550,7 @@ for (rr = dns_next_rr(&dnsa, &dnss, RESET_ANSWERS); assertion: legitimate SMTP clients are all explicitly authorized with CSA SRV records of their own. */ - if (found != domain) + if (Ustrcmp(found, domain) != 0) { if (port & 1) return t->data.val = CSA_FAIL_EXPLICIT; @@ -1442,6 +1614,7 @@ else DNS_LOOKUP_AGAIN: #endif +lookup_dnssec_authenticated = NULL; switch (dns_lookup(&dnsa, target, type, NULL)) { /* If something bad happened (most commonly DNS_AGAIN), defer. */ @@ -1478,7 +1651,8 @@ switch (dns_lookup(&dnsa, target, type, NULL)) *************************************************/ enum { VERIFY_REV_HOST_LKUP, VERIFY_CERT, VERIFY_HELO, VERIFY_CSA, VERIFY_HDR_SYNTAX, - VERIFY_NOT_BLIND, VERIFY_HDR_SNDR, VERIFY_SNDR, VERIFY_RCPT + VERIFY_NOT_BLIND, VERIFY_HDR_SNDR, VERIFY_SNDR, VERIFY_RCPT, + VERIFY_HDR_NAMES_ASCII }; typedef struct { uschar * name; @@ -1498,7 +1672,8 @@ static verify_type_t verify_type_list[] = { { US"sender", VERIFY_SNDR, (1<value) *user_msgptr = string_sprintf("Rejected after DATA: %s", *log_msgptr); return rc; + case VERIFY_HDR_NAMES_ASCII: + /* Check that all header names are true 7 bit strings + See RFC 5322, 2.2. and RFC 6532, 3. */ + + rc = verify_check_header_names_ascii(log_msgptr); + if (rc != OK && smtp_return_error_details && *log_msgptr != NULL) + *user_msgptr = string_sprintf("Rejected after DATA: %s", *log_msgptr); + return rc; + 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:. */ @@ -2030,8 +2214,8 @@ return rc; BAD_VERIFY: *log_msgptr = string_sprintf("expected \"sender[=address]\", \"recipient\", " - "\"helo\", \"header_syntax\", \"header_sender\" or " - "\"reverse_host_lookup\" at start of ACL condition " + "\"helo\", \"header_syntax\", \"header_sender\", \"header_names_ascii\" " + "or \"reverse_host_lookup\" at start of ACL condition " "\"verify %s\"", arg); return ERROR; } @@ -2168,7 +2352,10 @@ rate measurement as opposed to rate limiting. */ sender_rate_limit = string_nextinlist(&arg, &sep, NULL, 0); if (sender_rate_limit == NULL) + { limit = -1.0; + ss = NULL; /* compiler quietening */ + } else { limit = Ustrtod(sender_rate_limit, &ss); @@ -2650,6 +2837,110 @@ return rc; +/************************************************* +* The udpsend ACL modifier * +*************************************************/ + +/* Called by acl_check_condition() below. + +Arguments: + arg the option string for udpsend= + log_msgptr for error messages + +Returns: OK - Completed. + DEFER - Problem with DNS lookup. + ERROR - Syntax error in options. +*/ + +static int +acl_udpsend(uschar *arg, uschar **log_msgptr) +{ +int sep = 0; +uschar *hostname; +uschar *portstr; +uschar *portend; +host_item *h; +int portnum; +int len; +int r, s; +uschar * errstr; + +hostname = string_nextinlist(&arg, &sep, NULL, 0); +portstr = string_nextinlist(&arg, &sep, NULL, 0); + +if (hostname == NULL) + { + *log_msgptr = US"missing destination host in \"udpsend\" modifier"; + return ERROR; + } +if (portstr == NULL) + { + *log_msgptr = US"missing destination port in \"udpsend\" modifier"; + return ERROR; + } +if (arg == NULL) + { + *log_msgptr = US"missing datagram payload in \"udpsend\" modifier"; + return ERROR; + } +portnum = Ustrtol(portstr, &portend, 10); +if (*portend != '\0') + { + *log_msgptr = US"bad destination port in \"udpsend\" modifier"; + return ERROR; + } + +/* Make a single-item host list. */ +h = store_get(sizeof(host_item)); +memset(h, 0, sizeof(host_item)); +h->name = hostname; +h->port = portnum; +h->mx = MX_NONE; + +if (string_is_ip_address(hostname, NULL)) + h->address = hostname, r = HOST_FOUND; +else + r = host_find_byname(h, NULL, 0, NULL, FALSE); +if (r == HOST_FIND_FAILED || r == HOST_FIND_AGAIN) + { + *log_msgptr = US"DNS lookup failed in \"udpsend\" modifier"; + return DEFER; + } + +HDEBUG(D_acl) + debug_printf("udpsend [%s]:%d %s\n", h->address, portnum, arg); + +r = s = ip_connectedsocket(SOCK_DGRAM, h->address, portnum, portnum, + 1, NULL, &errstr); +if (r < 0) goto defer; +len = Ustrlen(arg); +r = send(s, arg, len, 0); +if (r < 0) + { + errstr = US strerror(errno); + close(s); + goto defer; + } +close(s); +if (r < len) + { + *log_msgptr = + string_sprintf("\"udpsend\" truncated from %d to %d octets", len, r); + return DEFER; + } + +HDEBUG(D_acl) + debug_printf("udpsend %d bytes\n", r); + +return OK; + +defer: +*log_msgptr = string_sprintf("\"udpsend\" failed: %s", errstr); +return DEFER; +} + + + /************************************************* * Handle conditions/modifiers on an ACL item * *************************************************/ @@ -2691,7 +2982,7 @@ uschar *debug_opts = NULL; uschar *p = NULL; int rc = OK; #ifdef WITH_CONTENT_SCAN -int sep = '/'; +int sep = -'/'; #endif for (; cb != NULL; cb = cb->next) @@ -2704,12 +2995,14 @@ for (; cb != NULL; cb = cb->next) if (cb->type == ACLC_MESSAGE) { + HDEBUG(D_acl) debug_printf(" message: %s\n", cb->arg); user_message = cb->arg; continue; } if (cb->type == ACLC_LOG_MESSAGE) { + HDEBUG(D_acl) debug_printf("l_message: %s\n", cb->arg); log_message = cb->arg; continue; } @@ -2785,14 +3078,14 @@ for (; cb != NULL; cb = cb->next) "discard" verb. */ case ACLC_ACL: - rc = acl_check_internal(where, addr, arg, level+1, user_msgptr, log_msgptr); - if (rc == DISCARD && verb != ACL_ACCEPT && verb != ACL_DISCARD) - { - *log_msgptr = string_sprintf("nested ACL returned \"discard\" for " - "\"%s\" command (only allowed with \"accept\" or \"discard\")", - verbs[verb]); - return ERROR; - } + rc = acl_check_wargs(where, addr, arg, level+1, user_msgptr, log_msgptr); + if (rc == DISCARD && verb != ACL_ACCEPT && verb != ACL_DISCARD) + { + *log_msgptr = string_sprintf("nested ACL returned \"discard\" for " + "\"%s\" command (only allowed with \"accept\" or \"discard\")", + verbs[verb]); + return ERROR; + } break; case ACLC_AUTHENTICATED: @@ -2816,7 +3109,9 @@ for (; cb != NULL; cb = cb->next) /* The true/false parsing here should be kept in sync with that used in expand.c when dealing with ECOND_BOOL so that we don't have too many different definitions of what can be a boolean. */ - if (Ustrspn(arg, "0123456789") == Ustrlen(arg)) /* Digits, or empty */ + if (*arg == '-' + ? Ustrspn(arg+1, "0123456789") == Ustrlen(arg+1) /* Negative number */ + : Ustrspn(arg, "0123456789") == Ustrlen(arg)) /* Digits, or empty */ rc = (Uatoi(arg) == 0)? FAIL : OK; else rc = (strcmpic(arg, US"no") == 0 || @@ -2857,6 +3152,21 @@ for (; cb != NULL; cb = cb->next) #ifndef DISABLE_DKIM case CONTROL_DKIM_VERIFY: dkim_disable_verify = TRUE; + #ifdef EXPERIMENTAL_DMARC + /* Since DKIM was blocked, skip DMARC too */ + dmarc_disable_verify = TRUE; + dmarc_enable_forensic = FALSE; + #endif + break; + #endif + + #ifdef EXPERIMENTAL_DMARC + case CONTROL_DMARC_VERIFY: + dmarc_disable_verify = TRUE; + break; + + case CONTROL_DMARC_FORENSIC: + dmarc_enable_forensic = TRUE; break; #endif @@ -2941,8 +3251,9 @@ for (; cb != NULL; cb = cb->next) disable_callout_flush = TRUE; break; - case CONTROL_FAKEDEFER: case CONTROL_FAKEREJECT: + cancel_cutthrough_connection("fakereject"); + case CONTROL_FAKEDEFER: fake_response = (control_type == CONTROL_FAKEDEFER) ? DEFER : FAIL; if (*p == '/') { @@ -2972,10 +3283,12 @@ for (; cb != NULL; cb = cb->next) *log_msgptr = string_sprintf("syntax error in \"control=%s\"", arg); return ERROR; } + cancel_cutthrough_connection("item frozen"); break; case CONTROL_QUEUE_ONLY: queue_only_policy = TRUE; + cancel_cutthrough_connection("queueing forced"); break; case CONTROL_SUBMISSION: @@ -3042,17 +3355,19 @@ for (; cb != NULL; cb = cb->next) case CONTROL_CUTTHROUGH_DELIVERY: if (deliver_freeze) - { - *log_msgptr = string_sprintf("\"control=%s\" on frozen item", arg); - return ERROR; - } - if (queue_only_policy) - { - *log_msgptr = string_sprintf("\"control=%s\" on queue-only item", arg); - return ERROR; - } - cutthrough_delivery = TRUE; - break; + *log_msgptr = US"frozen"; + else if (queue_only_policy) + *log_msgptr = US"queue-only"; + else if (fake_response == FAIL) + *log_msgptr = US"fakereject"; + else + { + cutthrough_delivery = TRUE; + break; + } + *log_msgptr = string_sprintf("\"control=%s\" on %s item", + arg, *log_msgptr); + return ERROR; } break; @@ -3150,6 +3465,18 @@ for (; cb != NULL; cb = cb->next) break; #endif + #ifdef EXPERIMENTAL_DMARC + case ACLC_DMARC_STATUS: + if (!dmarc_has_been_checked) + dmarc_process(); + dmarc_has_been_checked = TRUE; + /* 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); + break; + #endif + case ACLC_DNSLISTS: rc = verify_check_dnsbl(&arg); break; @@ -3256,21 +3583,28 @@ for (; cb != NULL; cb = cb->next) break; #ifdef WITH_CONTENT_SCAN - case ACLC_MALWARE: + case ACLC_MALWARE: /* Run the malware backend. */ { /* Separate the regular expression and any optional parameters. */ uschar *ss = string_nextinlist(&arg, &sep, big_buffer, big_buffer_size); - /* Run the malware backend. */ - rc = malware(&ss); - /* Modify return code based upon the existance of options. */ - while ((ss = string_nextinlist(&arg, &sep, big_buffer, big_buffer_size)) - != NULL) { - if (strcmpic(ss, US"defer_ok") == 0 && rc == DEFER) - { - /* FAIL so that the message is passed to the next ACL */ - rc = FAIL; - } - } + uschar *opt; + BOOL defer_ok = FALSE; + int timeout = 0; + + while ((opt = string_nextinlist(&arg, &sep, NULL, 0))) + if (strcmpic(opt, US"defer_ok") == 0) + defer_ok = TRUE; + else if ( strncmpic(opt, US"tmo=", 4) == 0 + && (timeout = readconf_readtime(opt+4, '\0', FALSE)) < 0 + ) + { + *log_msgptr = string_sprintf("bad timeout value in '%s'", opt); + return ERROR; + } + + rc = malware(ss, timeout); + if (rc == DEFER && defer_ok) + rc = FAIL; /* FAIL so that the message is passed to the next ACL */ } break; @@ -3294,6 +3628,10 @@ for (; cb != NULL; cb = cb->next) break; #endif + case ACLC_REMOVE_HEADER: + setup_remove_header(arg); + break; + case ACLC_SENDER_DOMAINS: { uschar *sdomain; @@ -3349,6 +3687,10 @@ for (; cb != NULL; cb = cb->next) break; #endif + case ACLC_UDPSEND: + rc = acl_udpsend(arg, log_msgptr); + break; + /* If the verb is WARN, discard any user message from verification, because such messages are SMTP responses, not header additions. The latter come only from explicit "message" modifiers. However, put the user message into @@ -3797,7 +4139,11 @@ while (acl != NULL) switch(acl->verb) { case ACL_ACCEPT: - if (cond == OK || cond == DISCARD) return cond; + if (cond == OK || cond == DISCARD) + { + HDEBUG(D_acl) debug_printf("end of %s: ACCEPT\n", acl_name); + return cond; + } if (endpass_seen) { HDEBUG(D_acl) debug_printf("accept: endpass encountered - denying access\n"); @@ -3808,17 +4154,26 @@ while (acl != NULL) case ACL_DEFER: if (cond == OK) { + HDEBUG(D_acl) debug_printf("end of %s: DEFER\n", acl_name); acl_temp_details = TRUE; return DEFER; } break; case ACL_DENY: - if (cond == OK) return FAIL; + if (cond == OK) + { + HDEBUG(D_acl) debug_printf("end of %s: DENY\n", acl_name); + return FAIL; + } break; case ACL_DISCARD: - if (cond == OK || cond == DISCARD) return DISCARD; + if (cond == OK || cond == DISCARD) + { + HDEBUG(D_acl) debug_printf("end of %s: DISCARD\n", acl_name); + return DISCARD; + } if (endpass_seen) { HDEBUG(D_acl) debug_printf("discard: endpass encountered - denying access\n"); @@ -3827,11 +4182,19 @@ while (acl != NULL) break; case ACL_DROP: - if (cond == OK) return FAIL_DROP; + if (cond == OK) + { + HDEBUG(D_acl) debug_printf("end of %s: DROP\n", acl_name); + return FAIL_DROP; + } break; case ACL_REQUIRE: - if (cond != OK) return cond; + if (cond != OK) + { + HDEBUG(D_acl) debug_printf("end of %s: not OK\n", acl_name); + return cond; + } break; case ACL_WARN: @@ -3863,10 +4226,97 @@ return FAIL; } + + +/* Same args as acl_check_internal() above, but the string s is +the name of an ACL followed optionally by up to 9 space-separated arguments. +The name and args are separately expanded. Args go into $acl_arg globals. */ +static int +acl_check_wargs(int where, address_item *addr, uschar *s, int level, + uschar **user_msgptr, uschar **log_msgptr) +{ +uschar * tmp; +uschar * tmp_arg[9]; /* must match acl_arg[] */ +uschar * sav_arg[9]; /* must match acl_arg[] */ +int sav_narg; +uschar * name; +int i; +int ret; + +if (!(tmp = string_dequote(&s)) || !(name = expand_string(tmp))) + goto bad; + +for (i = 0; i < 9; i++) + { + while (*s && isspace(*s)) s++; + if (!*s) break; + if (!(tmp = string_dequote(&s)) || !(tmp_arg[i] = expand_string(tmp))) + { + tmp = name; + goto bad; + } + } + +sav_narg = acl_narg; +acl_narg = i; +for (i = 0; i < acl_narg; i++) + { + sav_arg[i] = acl_arg[i]; + acl_arg[i] = tmp_arg[i]; + } +while (i < 9) + { + sav_arg[i] = acl_arg[i]; + acl_arg[i++] = NULL; + } + +ret = acl_check_internal(where, addr, name, level, user_msgptr, log_msgptr); + +acl_narg = sav_narg; +for (i = 0; i < 9; i++) acl_arg[i] = sav_arg[i]; +return ret; + +bad: +if (expand_string_forcedfail) return ERROR; +*log_msgptr = string_sprintf("failed to expand ACL string \"%s\": %s", + tmp, expand_string_message); +return search_find_defer?DEFER:ERROR; +} + + + /************************************************* * Check access using an ACL * *************************************************/ +/* Alternate interface for ACL, used by expansions */ +int +acl_eval(int where, uschar *s, uschar **user_msgptr, uschar **log_msgptr) +{ +address_item adb; +address_item *addr = NULL; + +*user_msgptr = *log_msgptr = NULL; +sender_verified_failed = NULL; +ratelimiters_cmd = NULL; +log_reject_target = LOG_MAIN|LOG_REJECT; + +if (where == ACL_WHERE_RCPT) + { + adb = address_defaults; + addr = &adb; + addr->address = expand_string(US"$local_part@$domain"); + addr->domain = deliver_domain; + addr->local_part = deliver_localpart; + addr->cc_local_part = deliver_localpart; + addr->lc_local_part = deliver_localpart; + } + +return acl_check_internal(where, addr, s, 0, user_msgptr, log_msgptr); +} + + + /* This is the external interface for ACL checks. It sets up an address and the expansions for $domain and $local_part when called after RCPT, then calls acl_check_internal() to do the actual work. @@ -3885,6 +4335,7 @@ Returns: OK access is granted by an ACCEPT verb DEFER can't tell at the moment ERROR disaster */ +int acl_where = ACL_WHERE_UNKNOWN; int acl_check(int where, uschar *recipient, uschar *s, uschar **user_msgptr, @@ -3899,7 +4350,11 @@ sender_verified_failed = NULL; ratelimiters_cmd = NULL; log_reject_target = LOG_MAIN|LOG_REJECT; -if (where == ACL_WHERE_RCPT) +#ifndef DISABLE_PRDR +if (where == ACL_WHERE_RCPT || where == ACL_WHERE_PRDR ) +#else +if (where == ACL_WHERE_RCPT ) +#endif { adb = address_defaults; addr = &adb; @@ -3913,7 +4368,9 @@ if (where == ACL_WHERE_RCPT) deliver_localpart = addr->local_part; } +acl_where = where; rc = acl_check_internal(where, addr, s, 0, user_msgptr, log_msgptr); +acl_where = ACL_WHERE_UNKNOWN; /* Cutthrough - if requested, and WHERE_RCPT and not yet opened conn as result of recipient-verify, @@ -3937,6 +4394,9 @@ If conn-failure, no action (and keep the spooled copy). switch (where) { case ACL_WHERE_RCPT: +#ifndef DISABLE_PRDR +case ACL_WHERE_PRDR: +#endif if( rcpt_count > 1 ) cancel_cutthrough_connection("more than one recipient"); else if (rc == OK && cutthrough_delivery && cutthrough_fd < 0) @@ -3996,7 +4456,6 @@ return rc; } - /************************************************* * Create ACL variable * *************************************************/ @@ -4055,4 +4514,6 @@ FILE *f = (FILE *)ctx; fprintf(f, "-acl%c %s %d\n%s\n", name[0], name+1, Ustrlen(value), value); } +/* vi: aw ai sw=2 +*/ /* End of acl.c */