enum {
CONTROL_AUTH_UNADVERTISED,
- #ifdef EXPERIMENTAL_BRIGHTMAIL
+#ifdef EXPERIMENTAL_BRIGHTMAIL
CONTROL_BMI_RUN,
- #endif
+#endif
CONTROL_DEBUG,
- #ifndef DISABLE_DKIM
+#ifndef DISABLE_DKIM
CONTROL_DKIM_VERIFY,
- #endif
- #ifdef EXPERIMENTAL_DMARC
+#endif
+#ifdef EXPERIMENTAL_DMARC
CONTROL_DMARC_VERIFY,
CONTROL_DMARC_FORENSIC,
- #endif
+#endif
CONTROL_DSCP,
CONTROL_ERROR,
CONTROL_CASEFUL_LOCAL_PART,
CONTROL_QUEUE_ONLY,
CONTROL_SUBMISSION,
CONTROL_SUPPRESS_LOCAL_FIXUPS,
- #ifdef WITH_CONTENT_SCAN
+#ifdef WITH_CONTENT_SCAN
CONTROL_NO_MBOX_UNSPOOL,
- #endif
+#endif
CONTROL_FAKEDEFER,
CONTROL_FAKEREJECT,
+#ifdef EXPERIMENTAL_INTERNATIONAL
+ CONTROL_UTF8_DOWNCONVERT,
+#endif
CONTROL_NO_MULTILINE,
CONTROL_NO_PIPELINING,
CONTROL_NO_DELAY_FLUSH,
static uschar *controls[] = {
US"allow_auth_unadvertised",
- #ifdef EXPERIMENTAL_BRIGHTMAIL
+#ifdef EXPERIMENTAL_BRIGHTMAIL
US"bmi_run",
- #endif
+#endif
US"debug",
- #ifndef DISABLE_DKIM
+#ifndef DISABLE_DKIM
US"dkim_disable_verify",
- #endif
- #ifdef EXPERIMENTAL_DMARC
+#endif
+#ifdef EXPERIMENTAL_DMARC
US"dmarc_disable_verify",
US"dmarc_enable_forensic",
- #endif
+#endif
US"dscp",
US"error",
US"caseful_local_part",
US"queue_only",
US"submission",
US"suppress_local_fixups",
- #ifdef WITH_CONTENT_SCAN
+#ifdef WITH_CONTENT_SCAN
US"no_mbox_unspool",
- #endif
+#endif
US"fakedefer",
US"fakereject",
+#ifdef EXPERIMENTAL_INTERNATIONAL
+ US"utf8_downconvert",
+#endif
US"no_multiline_responses",
US"no_pipelining",
US"no_delay_flush",
(unsigned int)
~((1<<ACL_WHERE_MAIL)|(1<<ACL_WHERE_RCPT)| /* add_header */
(1<<ACL_WHERE_PREDATA)|(1<<ACL_WHERE_DATA)|
- #ifdef EXPERIMENTAL_PRDR
+ #ifndef DISABLE_PRDR
(1<<ACL_WHERE_PRDR)|
#endif
(1<<ACL_WHERE_MIME)|(1<<ACL_WHERE_NOTSMTP)|
(1<<ACL_WHERE_AUTH)| /* bmi_optin */
(1<<ACL_WHERE_CONNECT)|(1<<ACL_WHERE_HELO)|
(1<<ACL_WHERE_DATA)|(1<<ACL_WHERE_MIME)|
- #ifdef EXPERIMENTAL_PRDR
+ #ifndef DISABLE_PRDR
(1<<ACL_WHERE_PRDR)|
#endif
(1<<ACL_WHERE_ETRN)|(1<<ACL_WHERE_EXPN)|
#ifdef EXPERIMENTAL_DCC
(unsigned int)
~((1<<ACL_WHERE_DATA)| /* dcc */
- #ifdef EXPERIMENTAL_PRDR
+ #ifndef DISABLE_PRDR
(1<<ACL_WHERE_PRDR)|
- #endif /* EXPERIMENTAL_PRDR */
+ #endif
(1<<ACL_WHERE_NOTSMTP)),
#endif
#ifdef WITH_OLD_DEMIME
(unsigned int)
~((1<<ACL_WHERE_DATA)| /* demime */
- #ifdef EXPERIMENTAL_PRDR
+ #ifndef DISABLE_PRDR
(1<<ACL_WHERE_PRDR)|
- #endif /* EXPERIMENTAL_PRDR */
+ #endif
(1<<ACL_WHERE_NOTSMTP)),
#endif
(unsigned int)
~((1<<ACL_WHERE_RCPT) /* domains */
- #ifdef EXPERIMENTAL_PRDR
+ #ifndef DISABLE_PRDR
|(1<<ACL_WHERE_PRDR)
#endif
),
(unsigned int)
~((1<<ACL_WHERE_RCPT) /* local_parts */
- #ifdef EXPERIMENTAL_PRDR
+ #ifndef DISABLE_PRDR
|(1<<ACL_WHERE_PRDR)
#endif
),
#ifdef WITH_CONTENT_SCAN
(unsigned int)
~((1<<ACL_WHERE_DATA)| /* malware */
- #ifdef EXPERIMENTAL_PRDR
+ #ifndef DISABLE_PRDR
(1<<ACL_WHERE_PRDR)|
- #endif /* EXPERIMENTAL_PRDR */
+ #endif
(1<<ACL_WHERE_NOTSMTP)),
#endif
#ifdef WITH_CONTENT_SCAN
(unsigned int)
~((1<<ACL_WHERE_DATA)| /* regex */
- #ifdef EXPERIMENTAL_PRDR
+ #ifndef DISABLE_PRDR
(1<<ACL_WHERE_PRDR)|
- #endif /* EXPERIMENTAL_PRDR */
+ #endif
(1<<ACL_WHERE_NOTSMTP)|
(1<<ACL_WHERE_MIME)),
#endif
(unsigned int)
~((1<<ACL_WHERE_MAIL)|(1<<ACL_WHERE_RCPT)| /* remove_header */
(1<<ACL_WHERE_PREDATA)|(1<<ACL_WHERE_DATA)|
- #ifdef EXPERIMENTAL_PRDR
+ #ifndef DISABLE_PRDR
(1<<ACL_WHERE_PRDR)|
#endif
(1<<ACL_WHERE_MIME)|(1<<ACL_WHERE_NOTSMTP)|
#ifdef WITH_CONTENT_SCAN
(unsigned int)
~((1<<ACL_WHERE_DATA)| /* spam */
- #ifdef EXPERIMENTAL_PRDR
+ #ifndef DISABLE_PRDR
(1<<ACL_WHERE_PRDR)|
- #endif /* EXPERIMENTAL_PRDR */
+ #endif
(1<<ACL_WHERE_NOTSMTP)),
#endif
(unsigned int)
~((1<<ACL_WHERE_CONNECT)|(1<<ACL_WHERE_HELO)), /* allow_auth_unadvertised */
- #ifdef EXPERIMENTAL_BRIGHTMAIL
+#ifdef EXPERIMENTAL_BRIGHTMAIL
0, /* bmi_run */
- #endif
+#endif
0, /* debug */
- #ifndef DISABLE_DKIM
+#ifndef DISABLE_DKIM
(1<<ACL_WHERE_DATA)|(1<<ACL_WHERE_NOTSMTP)| /* dkim_disable_verify */
- #ifdef EXPERIMENTAL_PRDR
+# ifndef DISABLE_PRDR
(1<<ACL_WHERE_PRDR)|
- #endif /* EXPERIMENTAL_PRDR */
+# endif
(1<<ACL_WHERE_NOTSMTP_START),
- #endif
+#endif
- #ifdef EXPERIMENTAL_DMARC
+#ifdef EXPERIMENTAL_DMARC
(1<<ACL_WHERE_DATA)|(1<<ACL_WHERE_NOTSMTP)| /* dmarc_disable_verify */
(1<<ACL_WHERE_NOTSMTP_START),
(1<<ACL_WHERE_DATA)|(1<<ACL_WHERE_NOTSMTP)| /* dmarc_enable_forensic */
(1<<ACL_WHERE_NOTSMTP_START),
- #endif
+#endif
(1<<ACL_WHERE_NOTSMTP)|
(1<<ACL_WHERE_NOTSMTP_START)|
(1<<ACL_WHERE_PREDATA)|
(1<<ACL_WHERE_NOTSMTP_START)),
- #ifdef WITH_CONTENT_SCAN
+#ifdef WITH_CONTENT_SCAN
(unsigned int)
~((1<<ACL_WHERE_MAIL)|(1<<ACL_WHERE_RCPT)| /* no_mbox_unspool */
(1<<ACL_WHERE_PREDATA)|(1<<ACL_WHERE_DATA)|
// (1<<ACL_WHERE_PRDR)| /* Not allow one user to freeze for all */
(1<<ACL_WHERE_MIME)),
- #endif
+#endif
(unsigned int)
~((1<<ACL_WHERE_MAIL)|(1<<ACL_WHERE_RCPT)| /* fakedefer */
(1<<ACL_WHERE_PREDATA)|(1<<ACL_WHERE_DATA)|
- #ifdef EXPERIMENTAL_PRDR
+#ifndef DISABLE_PRDR
(1<<ACL_WHERE_PRDR)|
- #endif /* EXPERIMENTAL_PRDR */
+#endif
(1<<ACL_WHERE_MIME)),
(unsigned int)
~((1<<ACL_WHERE_MAIL)|(1<<ACL_WHERE_RCPT)| /* fakereject */
(1<<ACL_WHERE_PREDATA)|(1<<ACL_WHERE_DATA)|
- #ifdef EXPERIMENTAL_PRDR
+#ifndef DISABLE_PRDR
(1<<ACL_WHERE_PRDR)|
- #endif /* EXPERIMENTAL_PRDR */
+#endif
(1<<ACL_WHERE_MIME)),
+#ifdef EXPERIMENTAL_INTERNATIONAL
+ 0, /* utf8_downconvert */
+#endif
+
(1<<ACL_WHERE_NOTSMTP)| /* no_multiline */
(1<<ACL_WHERE_NOTSMTP_START),
} control_def;
static control_def controls_list[] = {
- { US"allow_auth_unadvertised", CONTROL_AUTH_UNADVERTISED, FALSE },
+ { US"allow_auth_unadvertised", CONTROL_AUTH_UNADVERTISED, FALSE },
#ifdef EXPERIMENTAL_BRIGHTMAIL
- { US"bmi_run", CONTROL_BMI_RUN, FALSE },
+ { US"bmi_run", CONTROL_BMI_RUN, FALSE },
#endif
- { US"debug", CONTROL_DEBUG, TRUE },
+ { US"debug", CONTROL_DEBUG, TRUE },
#ifndef DISABLE_DKIM
- { US"dkim_disable_verify", CONTROL_DKIM_VERIFY, FALSE },
+ { US"dkim_disable_verify", CONTROL_DKIM_VERIFY, FALSE },
#endif
#ifdef EXPERIMENTAL_DMARC
- { US"dmarc_disable_verify", CONTROL_DMARC_VERIFY, FALSE },
- { US"dmarc_enable_forensic", CONTROL_DMARC_FORENSIC, FALSE },
+ { US"dmarc_disable_verify", CONTROL_DMARC_VERIFY, FALSE },
+ { US"dmarc_enable_forensic", CONTROL_DMARC_FORENSIC, FALSE },
#endif
- { US"dscp", CONTROL_DSCP, TRUE },
- { US"caseful_local_part", CONTROL_CASEFUL_LOCAL_PART, FALSE },
- { US"caselower_local_part", CONTROL_CASELOWER_LOCAL_PART, FALSE },
- { US"enforce_sync", CONTROL_ENFORCE_SYNC, FALSE },
- { US"freeze", CONTROL_FREEZE, TRUE },
- { US"no_callout_flush", CONTROL_NO_CALLOUT_FLUSH, FALSE },
- { US"no_delay_flush", CONTROL_NO_DELAY_FLUSH, FALSE },
- { US"no_enforce_sync", CONTROL_NO_ENFORCE_SYNC, FALSE },
- { US"no_multiline_responses", CONTROL_NO_MULTILINE, FALSE },
- { US"no_pipelining", CONTROL_NO_PIPELINING, FALSE },
- { US"queue_only", CONTROL_QUEUE_ONLY, FALSE },
+ { US"dscp", CONTROL_DSCP, TRUE },
+ { US"caseful_local_part", CONTROL_CASEFUL_LOCAL_PART, FALSE },
+ { US"caselower_local_part", CONTROL_CASELOWER_LOCAL_PART, FALSE },
+ { US"enforce_sync", CONTROL_ENFORCE_SYNC, FALSE },
+ { US"freeze", CONTROL_FREEZE, TRUE },
+ { US"no_callout_flush", CONTROL_NO_CALLOUT_FLUSH, FALSE },
+ { US"no_delay_flush", CONTROL_NO_DELAY_FLUSH, FALSE },
+ { US"no_enforce_sync", CONTROL_NO_ENFORCE_SYNC, FALSE },
+ { US"no_multiline_responses", CONTROL_NO_MULTILINE, FALSE },
+ { US"no_pipelining", CONTROL_NO_PIPELINING, FALSE },
+ { US"queue_only", CONTROL_QUEUE_ONLY, FALSE },
#ifdef WITH_CONTENT_SCAN
- { US"no_mbox_unspool", CONTROL_NO_MBOX_UNSPOOL, FALSE },
+ { US"no_mbox_unspool", CONTROL_NO_MBOX_UNSPOOL, FALSE },
#endif
- { US"fakedefer", CONTROL_FAKEDEFER, TRUE },
- { US"fakereject", CONTROL_FAKEREJECT, TRUE },
- { US"submission", CONTROL_SUBMISSION, TRUE },
+ { US"fakedefer", CONTROL_FAKEDEFER, TRUE },
+ { US"fakereject", CONTROL_FAKEREJECT, TRUE },
+ { US"submission", CONTROL_SUBMISSION, TRUE },
{ US"suppress_local_fixups", CONTROL_SUPPRESS_LOCAL_FIXUPS, FALSE },
- { US"cutthrough_delivery", CONTROL_CUTTHROUGH_DELIVERY, FALSE }
+ { US"cutthrough_delivery", CONTROL_CUTTHROUGH_DELIVERY, FALSE },
+#ifdef EXPERIMENTAL_INTERNATIONAL
+ { US"utf8_downconvert", CONTROL_UTF8_DOWNCONVERT, TRUE }
+#endif
};
/* Support data structures for Client SMTP Authorization. acl_verify_csa()
/* Enable recursion between acl_check_internal() and acl_check_condition() */
-static int acl_check_wargs(int, address_item *, uschar *, int, uschar **,
+static int acl_check_wargs(int, address_item *, const uschar *, int, uschar **,
uschar **);
*/
static void
-setup_header(uschar *hstring)
+setup_header(const uschar *hstring)
{
-uschar *p, *q;
+const uschar *p, *q;
int hlen = Ustrlen(hstring);
/* Ignore any leading newlines */
/* An empty string does nothing; ensure exactly one final newline. */
if (hlen <= 0) return;
-if (hstring[--hlen] != '\n') hstring = string_sprintf("%s\n", hstring);
-else while(hstring[--hlen] == '\n') hstring[hlen+1] = '\0';
+if (hstring[--hlen] != '\n')
+ q = string_sprintf("%s\n", hstring);
+else if (hstring[hlen-1] == '\n')
+ {
+ uschar * s = string_copy(hstring);
+ while(s[--hlen] == '\n')
+ s[hlen+1] = '\0';
+ q = s;
+ }
+else
+ q = hstring;
/* Loop for multiple header lines, taking care about continuations */
-for (p = q = hstring; *p != 0; )
+for (p = q; *p != 0; )
{
- uschar *s;
+ const uschar *s;
+ uschar * hdr;
int newtype = htype_add_bot;
header_line **hptr = &acl_added_headers;
if (*s == ':' || !isgraph(*s)) break;
}
- s = string_sprintf("%s%.*s", (*s == ':')? "" : "X-ACL-Warn: ", (int) (q - p), p);
- hlen = Ustrlen(s);
+ hdr = string_sprintf("%s%.*s", (*s == ':')? "" : "X-ACL-Warn: ", (int) (q - p), p);
+ hlen = Ustrlen(hdr);
/* See if this line has already been added */
while (*hptr != NULL)
{
- if (Ustrncmp((*hptr)->text, s, hlen) == 0) break;
+ if (Ustrncmp((*hptr)->text, hdr, hlen) == 0) break;
hptr = &((*hptr)->next);
}
if (*hptr == NULL)
{
header_line *h = store_get(sizeof(header_line));
- h->text = s;
+ h->text = hdr;
h->next = NULL;
h->type = newtype;
h->slen = hlen;
*/
static void
-setup_remove_header(uschar *hnames)
+setup_remove_header(const 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);
- }
+ acl_removed_headers = acl_removed_headers
+ ? string_sprintf("%s : %s", acl_removed_headers, hnames)
+ : string_copy(hnames);
}
if (rr->type != T_A
#if HAVE_IPV6
&& rr->type != T_AAAA
- #ifdef SUPPORT_A6
- && rr->type != T_A6
- #endif
#endif
) continue;
*/
static int
-acl_verify_csa(uschar *domain)
+acl_verify_csa(const uschar *domain)
{
tree_node *t;
-uschar *found, *p;
+const uschar *found;
+uschar *p;
int priority, weight, port;
dns_answer dnsa;
dns_scan dnss;
if (domain[0] == '[')
{
- uschar *start = Ustrchr(domain, ':');
+ const uschar *start = Ustrchr(domain, ':');
if (start == NULL) start = domain;
domain = string_copyn(start + 1, Ustrlen(start) - 2);
}
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;
type = T_A;
-#if HAVE_IPV6 && defined(SUPPORT_A6)
-DNS_LOOKUP_AGAIN:
-#endif
-
lookup_dnssec_authenticated = NULL;
switch (dns_lookup(&dnsa, target, type, NULL))
{
/* If something bad happened (most commonly DNS_AGAIN), defer. */
default:
- return t->data.val = CSA_DEFER_ADDR;
+ return t->data.val = CSA_DEFER_ADDR;
/* 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;
- /* else fall through */
+ rc = acl_verify_csa_address(&dnsa, &dnss, RESET_ANSWERS, target);
+ if (rc != CSA_FAIL_NOADDR) return t->data.val = rc;
+ /* else fall through */
/* If the target has no IP addresses, the client cannot have an authorized
IP address. However, if the target site uses A6 records (not AAAA records)
case DNS_NOMATCH:
case DNS_NODATA:
-
- #if HAVE_IPV6 && defined(SUPPORT_A6)
- if (type == T_AAAA) { type = T_A6; goto DNS_LOOKUP_AGAIN; }
- #endif
-
- return t->data.val = CSA_FAIL_NOADDR;
+ return t->data.val = CSA_FAIL_NOADDR;
}
}
unsigned alt_opt_sep; /* >0 Non-/ option separator (custom parser) */
} verify_type_t;
static verify_type_t verify_type_list[] = {
- { US"reverse_host_lookup", VERIFY_REV_HOST_LKUP, ~0, TRUE, 0 },
+ { 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 },
*/
static int
-acl_verify(int where, address_item *addr, uschar *arg,
+acl_verify(int where, address_item *addr, const uschar *arg,
uschar **user_msgptr, uschar **log_msgptr, int *basic_errno)
{
int sep = '/';
*/
uschar *slash = Ustrchr(arg, '/');
-uschar *list = arg;
+const uschar *list = arg;
uschar *ss = string_nextinlist(&list, &sep, big_buffer, big_buffer_size);
verify_type_t * vp;
{
case VERIFY_REV_HOST_LKUP:
if (sender_host_address == NULL) return OK;
- return acl_verify_reverse(user_msgptr, log_msgptr);
+ if ((rc = acl_verify_reverse(user_msgptr, log_msgptr)) == DEFER)
+ while ((ss = string_nextinlist(&list, &sep, big_buffer, big_buffer_size)))
+ if (strcmpic(ss, US"defer_ok") == 0)
+ return OK;
+ return rc;
case VERIFY_CERT:
/* TLS certificate verification is done at STARTTLS time; here we just
while (isspace(*ss)) ss++;
if (*ss++ == '=')
{
+ const uschar * sublist = ss;
int optsep = ',';
uschar *opt;
uschar buffer[256];
- while (isspace(*ss)) ss++;
+ while (isspace(*sublist)) sublist++;
- while ((opt = string_nextinlist(&ss, &optsep, buffer, sizeof(buffer)))
+ while ((opt = string_nextinlist(&sublist, &optsep, buffer, sizeof(buffer)))
!= NULL)
{
callout_opt_t * op;
uschar *save_address_data = deliver_address_data;
sender_vaddr = deliver_make_addr(verify_sender_address, TRUE);
+#ifdef EXPERIMENTAL_INTERNATIONAL
+ if ((sender_vaddr->prop.utf8_msg = message_smtputf8))
+ {
+ sender_vaddr->prop.utf8_downcvt = message_utf8_downconvert == 1;
+ sender_vaddr->prop.utf8_downcvt_maybe = message_utf8_downconvert == -1;
+ }
+#endif
if (no_details) setflag(sender_vaddr, af_sverify_told);
if (verify_sender_address[0] != 0)
{
/* Put the sender address_data value into $sender_address_data */
- sender_address_data = sender_vaddr->p.address_data;
+ sender_address_data = sender_vaddr->prop.address_data;
}
/* A recipient address just gets a straightforward verify; again we must handle
if (testflag((&addr2), af_pass_message)) acl_temp_details = TRUE;
/* Make $address_data visible */
- deliver_address_data = addr2.p.address_data;
+ deliver_address_data = addr2.prop.address_data;
}
/* We have a result from the relevant test. Handle defer overrides first. */
if (rc != OK && verify_sender_address != NULL)
{
if (rc != DEFER)
- {
*log_msgptr = *user_msgptr = US"Sender verify failed";
- }
else if (*basic_errno != ERRNO_CALLOUTDEFER)
- {
*log_msgptr = *user_msgptr = US"Could not complete sender verify";
- }
else
{
*log_msgptr = US"Could not complete sender verify callout";
*/
static int
-decode_control(uschar *arg, uschar **pptr, int where, uschar **log_msgptr)
+decode_control(const uschar *arg, const uschar **pptr, int where, uschar **log_msgptr)
{
int len;
control_def *d;
*/
static int
-acl_ratelimit(uschar *arg, int where, uschar **log_msgptr)
+acl_ratelimit(const uschar *arg, int where, uschar **log_msgptr)
{
double limit, period, count;
uschar *ss;
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);
*/
static int
-acl_udpsend(uschar *arg, uschar **log_msgptr)
+acl_udpsend(const uschar *arg, uschar **log_msgptr)
{
int sep = 0;
uschar *hostname;
uschar *log_message = NULL;
uschar *debug_tag = NULL;
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)
{
- uschar *arg;
+ const uschar *arg;
int control_type;
/* The message and log_message items set up messages to be used in
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;
}
break;
case ACLC_CONTROL:
- control_type = decode_control(arg, &p, where, log_msgptr);
-
- /* Check if this control makes sense at this time */
-
- if ((control_forbids[control_type] & (1 << where)) != 0)
{
- *log_msgptr = string_sprintf("cannot use \"control=%s\" in %s ACL",
- controls[control_type], acl_wherenames[where]);
- return ERROR;
- }
-
- switch(control_type)
- {
- case CONTROL_AUTH_UNADVERTISED:
- allow_auth_unadvertised = TRUE;
- break;
-
- #ifdef EXPERIMENTAL_BRIGHTMAIL
- case CONTROL_BMI_RUN:
- bmi_run = 1;
- break;
- #endif
-
- #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
-
- case CONTROL_DSCP:
- if (*p == '/')
- {
- int fd, af, level, optname, value;
- /* If we are acting on stdin, the setsockopt may fail if stdin is not
- a socket; we can accept that, we'll just debug-log failures anyway. */
- fd = fileno(smtp_in);
- af = ip_get_address_family(fd);
- if (af < 0)
- {
- HDEBUG(D_acl)
- debug_printf("smtp input is probably not a socket [%s], not setting DSCP\n",
- strerror(errno));
- break;
- }
- if (dscp_lookup(p+1, af, &level, &optname, &value))
- {
- if (setsockopt(fd, level, optname, &value, sizeof(value)) < 0)
- {
- HDEBUG(D_acl) debug_printf("failed to set input DSCP[%s]: %s\n",
- p+1, strerror(errno));
- }
- else
- {
- HDEBUG(D_acl) debug_printf("set input DSCP to \"%s\"\n", p+1);
- }
- }
- else
- {
- *log_msgptr = string_sprintf("unrecognised DSCP value in \"control=%s\"", arg);
- return ERROR;
- }
- }
- else
- {
- *log_msgptr = string_sprintf("syntax error in \"control=%s\"", arg);
- return ERROR;
- }
- break;
-
- case CONTROL_ERROR:
- return ERROR;
-
- case CONTROL_CASEFUL_LOCAL_PART:
- deliver_localpart = addr->cc_local_part;
- break;
-
- case CONTROL_CASELOWER_LOCAL_PART:
- deliver_localpart = addr->lc_local_part;
- break;
-
- case CONTROL_ENFORCE_SYNC:
- smtp_enforce_sync = TRUE;
- break;
-
- case CONTROL_NO_ENFORCE_SYNC:
- smtp_enforce_sync = FALSE;
- break;
-
- #ifdef WITH_CONTENT_SCAN
- case CONTROL_NO_MBOX_UNSPOOL:
- no_mbox_unspool = TRUE;
- break;
- #endif
-
- case CONTROL_NO_MULTILINE:
- no_multiline_responses = TRUE;
- break;
-
- case CONTROL_NO_PIPELINING:
- pipelining_enable = FALSE;
- break;
-
- case CONTROL_NO_DELAY_FLUSH:
- disable_delay_flush = TRUE;
- break;
-
- case CONTROL_NO_CALLOUT_FLUSH:
- disable_callout_flush = TRUE;
- break;
-
- case CONTROL_FAKEDEFER:
- case CONTROL_FAKEREJECT:
- fake_response = (control_type == CONTROL_FAKEDEFER) ? DEFER : FAIL;
- if (*p == '/')
- {
- uschar *pp = p + 1;
- while (*pp != 0) pp++;
- fake_response_text = expand_string(string_copyn(p+1, pp-p-1));
- p = pp;
- }
- else
- {
- /* Explicitly reset to default string */
- fake_response_text = US"Your message has been rejected but is being kept for evaluation.\nIf it was a legitimate message, it may still be delivered to the target recipient(s).";
- }
- break;
-
- case CONTROL_FREEZE:
- deliver_freeze = TRUE;
- deliver_frozen_at = time(NULL);
- freeze_tell = freeze_tell_config; /* Reset to configured value */
- if (Ustrncmp(p, "/no_tell", 8) == 0)
- {
- p += 8;
- freeze_tell = NULL;
- }
- if (*p != 0)
- {
- *log_msgptr = string_sprintf("syntax error in \"control=%s\"", arg);
- return ERROR;
- }
- break;
-
- case CONTROL_QUEUE_ONLY:
- queue_only_policy = TRUE;
- break;
-
- case CONTROL_SUBMISSION:
- originator_name = US"";
- submission_mode = TRUE;
- while (*p == '/')
- {
- if (Ustrncmp(p, "/sender_retain", 14) == 0)
- {
- p += 14;
- active_local_sender_retain = TRUE;
- active_local_from_check = FALSE;
- }
- else if (Ustrncmp(p, "/domain=", 8) == 0)
- {
- uschar *pp = p + 8;
- while (*pp != 0 && *pp != '/') pp++;
- submission_domain = string_copyn(p+8, pp-p-8);
- p = pp;
- }
- /* The name= option must be last, because it swallows the rest of
- the string. */
- else if (Ustrncmp(p, "/name=", 6) == 0)
- {
- uschar *pp = p + 6;
- while (*pp != 0) pp++;
- submission_name = string_copy(parse_fix_phrase(p+6, pp-p-6,
- big_buffer, big_buffer_size));
- p = pp;
- }
- else break;
- }
- if (*p != 0)
- {
- *log_msgptr = string_sprintf("syntax error in \"control=%s\"", arg);
- return ERROR;
- }
- break;
-
- case CONTROL_DEBUG:
- while (*p == '/')
- {
- if (Ustrncmp(p, "/tag=", 5) == 0)
- {
- uschar *pp = p + 5;
- while (*pp != '\0' && *pp != '/') pp++;
- debug_tag = string_copyn(p+5, pp-p-5);
- p = pp;
- }
- else if (Ustrncmp(p, "/opts=", 6) == 0)
- {
- uschar *pp = p + 6;
- while (*pp != '\0' && *pp != '/') pp++;
- debug_opts = string_copyn(p+6, pp-p-6);
- p = pp;
- }
- }
- debug_logging_activate(debug_tag, debug_opts);
- break;
-
- case CONTROL_SUPPRESS_LOCAL_FIXUPS:
- suppress_local_fixups = TRUE;
- break;
+ const uschar *p = NULL;
+ control_type = decode_control(arg, &p, where, log_msgptr);
+
+ /* Check if this control makes sense at this time */
+
+ if ((control_forbids[control_type] & (1 << where)) != 0)
+ {
+ *log_msgptr = string_sprintf("cannot use \"control=%s\" in %s ACL",
+ controls[control_type], acl_wherenames[where]);
+ return ERROR;
+ }
+
+ switch(control_type)
+ {
+ case CONTROL_AUTH_UNADVERTISED:
+ allow_auth_unadvertised = TRUE;
+ break;
+
+ #ifdef EXPERIMENTAL_BRIGHTMAIL
+ case CONTROL_BMI_RUN:
+ bmi_run = 1;
+ break;
+ #endif
+
+ #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
+
+ case CONTROL_DSCP:
+ if (*p == '/')
+ {
+ int fd, af, level, optname, value;
+ /* If we are acting on stdin, the setsockopt may fail if stdin is not
+ a socket; we can accept that, we'll just debug-log failures anyway. */
+ fd = fileno(smtp_in);
+ af = ip_get_address_family(fd);
+ if (af < 0)
+ {
+ HDEBUG(D_acl)
+ debug_printf("smtp input is probably not a socket [%s], not setting DSCP\n",
+ strerror(errno));
+ break;
+ }
+ if (dscp_lookup(p+1, af, &level, &optname, &value))
+ {
+ if (setsockopt(fd, level, optname, &value, sizeof(value)) < 0)
+ {
+ HDEBUG(D_acl) debug_printf("failed to set input DSCP[%s]: %s\n",
+ p+1, strerror(errno));
+ }
+ else
+ {
+ HDEBUG(D_acl) debug_printf("set input DSCP to \"%s\"\n", p+1);
+ }
+ }
+ else
+ {
+ *log_msgptr = string_sprintf("unrecognised DSCP value in \"control=%s\"", arg);
+ return ERROR;
+ }
+ }
+ else
+ {
+ *log_msgptr = string_sprintf("syntax error in \"control=%s\"", arg);
+ return ERROR;
+ }
+ break;
+
+ case CONTROL_ERROR:
+ return ERROR;
+
+ case CONTROL_CASEFUL_LOCAL_PART:
+ deliver_localpart = addr->cc_local_part;
+ break;
+
+ case CONTROL_CASELOWER_LOCAL_PART:
+ deliver_localpart = addr->lc_local_part;
+ break;
+
+ case CONTROL_ENFORCE_SYNC:
+ smtp_enforce_sync = TRUE;
+ break;
+
+ case CONTROL_NO_ENFORCE_SYNC:
+ smtp_enforce_sync = FALSE;
+ break;
+
+ #ifdef WITH_CONTENT_SCAN
+ case CONTROL_NO_MBOX_UNSPOOL:
+ no_mbox_unspool = TRUE;
+ break;
+ #endif
+
+ case CONTROL_NO_MULTILINE:
+ no_multiline_responses = TRUE;
+ break;
+
+ case CONTROL_NO_PIPELINING:
+ pipelining_enable = FALSE;
+ break;
+
+ case CONTROL_NO_DELAY_FLUSH:
+ disable_delay_flush = TRUE;
+ break;
+
+ case CONTROL_NO_CALLOUT_FLUSH:
+ disable_callout_flush = TRUE;
+ break;
+
+ case CONTROL_FAKEREJECT:
+ cancel_cutthrough_connection("fakereject");
+ case CONTROL_FAKEDEFER:
+ fake_response = (control_type == CONTROL_FAKEDEFER) ? DEFER : FAIL;
+ if (*p == '/')
+ {
+ const uschar *pp = p + 1;
+ while (*pp != 0) pp++;
+ fake_response_text = expand_string(string_copyn(p+1, pp-p-1));
+ p = pp;
+ }
+ else
+ {
+ /* Explicitly reset to default string */
+ fake_response_text = US"Your message has been rejected but is being kept for evaluation.\nIf it was a legitimate message, it may still be delivered to the target recipient(s).";
+ }
+ break;
+
+ case CONTROL_FREEZE:
+ deliver_freeze = TRUE;
+ deliver_frozen_at = time(NULL);
+ freeze_tell = freeze_tell_config; /* Reset to configured value */
+ if (Ustrncmp(p, "/no_tell", 8) == 0)
+ {
+ p += 8;
+ freeze_tell = NULL;
+ }
+ if (*p != 0)
+ {
+ *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:
+ originator_name = US"";
+ submission_mode = TRUE;
+ while (*p == '/')
+ {
+ if (Ustrncmp(p, "/sender_retain", 14) == 0)
+ {
+ p += 14;
+ active_local_sender_retain = TRUE;
+ active_local_from_check = FALSE;
+ }
+ else if (Ustrncmp(p, "/domain=", 8) == 0)
+ {
+ const uschar *pp = p + 8;
+ while (*pp != 0 && *pp != '/') pp++;
+ submission_domain = string_copyn(p+8, pp-p-8);
+ p = pp;
+ }
+ /* The name= option must be last, because it swallows the rest of
+ the string. */
+ else if (Ustrncmp(p, "/name=", 6) == 0)
+ {
+ const uschar *pp = p + 6;
+ while (*pp != 0) pp++;
+ submission_name = string_copy(parse_fix_phrase(p+6, pp-p-6,
+ big_buffer, big_buffer_size));
+ p = pp;
+ }
+ else break;
+ }
+ if (*p != 0)
+ {
+ *log_msgptr = string_sprintf("syntax error in \"control=%s\"", arg);
+ return ERROR;
+ }
+ break;
+
+ case CONTROL_DEBUG:
+ while (*p == '/')
+ {
+ if (Ustrncmp(p, "/tag=", 5) == 0)
+ {
+ const uschar *pp = p + 5;
+ while (*pp != '\0' && *pp != '/') pp++;
+ debug_tag = string_copyn(p+5, pp-p-5);
+ p = pp;
+ }
+ else if (Ustrncmp(p, "/opts=", 6) == 0)
+ {
+ const uschar *pp = p + 6;
+ while (*pp != '\0' && *pp != '/') pp++;
+ debug_opts = string_copyn(p+6, pp-p-6);
+ p = pp;
+ }
+ }
+ debug_logging_activate(debug_tag, debug_opts);
+ break;
+
+ case CONTROL_SUPPRESS_LOCAL_FIXUPS:
+ suppress_local_fixups = TRUE;
+ break;
+
+ case CONTROL_CUTTHROUGH_DELIVERY:
+ if (prdr_requested)
+ /* Too hard to think about for now. We might in future cutthrough
+ the case where both sides handle prdr and this-node prdr acl
+ is "accept" */
+ *log_msgptr = string_sprintf("PRDR on %s reception\n", arg);
+ else
+ {
+ if (deliver_freeze)
+ *log_msgptr = US"frozen";
+ else if (queue_only_policy)
+ *log_msgptr = US"queue-only";
+ else if (fake_response == FAIL)
+ *log_msgptr = US"fakereject";
+ else
+ {
+ if (rcpt_count == 1) cutthrough.delivery = TRUE;
+ break;
+ }
+ *log_msgptr = string_sprintf("\"control=%s\" on %s item",
+ arg, *log_msgptr);
+ }
+ return ERROR;
+
+ #ifdef EXPERIMENTAL_INTERNATIONAL
+ case CONTROL_UTF8_DOWNCONVERT:
+ if (*p == '/')
+ {
+ if (p[1] == '1')
+ {
+ message_utf8_downconvert = 1;
+ addr->prop.utf8_downcvt = TRUE;
+ addr->prop.utf8_downcvt_maybe = FALSE;
+ p += 2;
+ break;
+ }
+ if (p[1] == '0')
+ {
+ message_utf8_downconvert = 0;
+ addr->prop.utf8_downcvt = FALSE;
+ addr->prop.utf8_downcvt_maybe = FALSE;
+ p += 2;
+ break;
+ }
+ if (p[1] == '-' && p[2] == '1')
+ {
+ message_utf8_downconvert = -1;
+ addr->prop.utf8_downcvt = FALSE;
+ addr->prop.utf8_downcvt_maybe = TRUE;
+ p += 3;
+ break;
+ }
+ *log_msgptr = US"bad option value for control=utf8_downconvert";
+ }
+ else
+ {
+ message_utf8_downconvert = 1;
+ addr->prop.utf8_downcvt = TRUE;
+ addr->prop.utf8_downcvt_maybe = FALSE;
+ break;
+ }
+ return ERROR;
+ #endif
- 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;
}
- break;
#ifdef EXPERIMENTAL_DCC
case ACLC_DCC:
{
/* Seperate the regular expression and any optional parameters. */
- uschar *ss = string_nextinlist(&arg, &sep, big_buffer, big_buffer_size);
+ const uschar * list = arg;
+ uschar *ss = string_nextinlist(&list, &sep, big_buffer, big_buffer_size);
/* Run the dcc backend. */
rc = dcc_process(&ss);
/* Modify return code based upon the existance of options. */
- while ((ss = string_nextinlist(&arg, &sep, big_buffer, big_buffer_size))
- != NULL) {
+ while ((ss = string_nextinlist(&list, &sep, big_buffer, big_buffer_size)))
if (strcmpic(ss, US"defer_ok") == 0 && rc == DEFER)
- {
- /* FAIL so that the message is passed to the next ACL */
- rc = FAIL;
- }
- }
+ rc = FAIL; /* FAIL so that the message is passed to the next ACL */
}
break;
#endif
case ACLC_DOMAINS:
rc = match_isinlist(addr->domain, &arg, 0, &domainlist_anchor,
- addr->domain_cache, MCL_DOMAIN, TRUE, &deliver_domain_data);
+ addr->domain_cache, MCL_DOMAIN, TRUE, CUSS &deliver_domain_data);
break;
/* The value in tls_cipher is the full cipher name, for example,
case ACLC_HOSTS:
rc = verify_check_this_host(&arg, sender_host_cache, NULL,
- (sender_host_address == NULL)? US"" : sender_host_address, &host_data);
+ (sender_host_address == NULL)? US"" : sender_host_address,
+ CUSS &host_data);
if (host_data != NULL) host_data = string_copy_malloc(host_data);
break;
case ACLC_LOCAL_PARTS:
rc = match_isinlist(addr->cc_local_part, &arg, 0,
&localpartlist_anchor, addr->localpart_cache, MCL_LOCALPART, TRUE,
- &deliver_localpart_data);
+ CUSS &deliver_localpart_data);
break;
case ACLC_LOG_REJECT_TARGET:
{
int logbits = 0;
int sep = 0;
- uschar *s = arg;
+ const uschar *s = arg;
uschar *ss;
while ((ss = string_nextinlist(&s, &sep, big_buffer, big_buffer_size))
!= NULL)
case ACLC_LOGWRITE:
{
int logbits = 0;
- uschar *s = arg;
+ const uschar *s = arg;
if (*s == ':')
{
s++;
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;
- }
- }
+ const uschar * list = arg;
+ uschar *ss = string_nextinlist(&list, &sep, big_buffer, big_buffer_size);
+ uschar *opt;
+ BOOL defer_ok = FALSE;
+ int timeout = 0;
+
+ while ((opt = string_nextinlist(&list, &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;
break;
case ACLC_RECIPIENTS:
- rc = match_address_list(addr->address, TRUE, TRUE, &arg, NULL, -1, 0,
- &recipient_data);
+ rc = match_address_list((const uschar *)addr->address, TRUE, TRUE, &arg, NULL, -1, 0,
+ CUSS &recipient_data);
break;
#ifdef WITH_CONTENT_SCAN
break;
case ACLC_SENDERS:
- rc = match_address_list(sender_address, TRUE, TRUE, &arg,
- sender_address_cache, -1, 0, &sender_data);
+ rc = match_address_list((const uschar *)sender_address, TRUE, TRUE, &arg,
+ sender_address_cache, -1, 0, CUSS &sender_data);
break;
/* Connection variables must persist forever */
case ACLC_SPAM:
{
/* Seperate the regular expression and any optional parameters. */
- uschar *ss = string_nextinlist(&arg, &sep, big_buffer, big_buffer_size);
+ const uschar * list = arg;
+ uschar *ss = string_nextinlist(&list, &sep, big_buffer, big_buffer_size);
/* Run the spam backend. */
- rc = spam(&ss);
+ rc = spam(CUSS &ss);
/* Modify return code based upon the existance of options. */
- while ((ss = string_nextinlist(&arg, &sep, big_buffer, big_buffer_size))
+ while ((ss = string_nextinlist(&list, &sep, big_buffer, big_buffer_size))
!= NULL) {
if (strcmpic(ss, US"defer_ok") == 0 && rc == DEFER)
{
int cond;
int basic_errno = 0;
BOOL endpass_seen = FALSE;
+ BOOL acl_quit_check = level == 0
+ && (where == ACL_WHERE_QUIT || where == ACL_WHERE_NOTQUIT);
*log_msgptr = *user_msgptr = NULL;
acl_temp_details = FALSE;
- if ((where == ACL_WHERE_QUIT || where == ACL_WHERE_NOTQUIT) &&
- acl->verb != ACL_ACCEPT &&
- acl->verb != ACL_WARN)
- {
- *log_msgptr = string_sprintf("\"%s\" is not allowed in a QUIT or not-QUIT ACL",
- verbs[acl->verb]);
- return ERROR;
- }
-
HDEBUG(D_acl) debug_printf("processing \"%s\"\n", verbs[acl->verb]);
/* Clear out any search error message from a previous check before testing
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");
case ACL_DEFER:
if (cond == OK)
{
+ HDEBUG(D_acl) debug_printf("end of %s: DEFER\n", acl_name);
+ if (acl_quit_check) goto badquit;
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);
+ if (acl_quit_check) goto badquit;
+ 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);
+ if (acl_quit_check) goto badquit;
+ return DISCARD;
+ }
if (endpass_seen)
{
HDEBUG(D_acl) debug_printf("discard: endpass encountered - denying access\n");
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);
+ if (acl_quit_check) goto badquit;
+ 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);
+ if (acl_quit_check) goto badquit;
+ return cond;
+ }
break;
case ACL_WARN:
HDEBUG(D_acl) debug_printf("end of %s: implicit DENY\n", acl_name);
return FAIL;
+
+badquit:
+ *log_msgptr = string_sprintf("QUIT or not-QUIT teplevel ACL may not fail "
+ "('%s' verb used incorrectly)", verbs[acl->verb]);
+ return ERROR;
}
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,
+acl_check_wargs(int where, address_item *addr, const uschar *s, int level,
uschar **user_msgptr, uschar **log_msgptr)
{
uschar * tmp;
ratelimiters_cmd = NULL;
log_reject_target = LOG_MAIN|LOG_REJECT;
-#ifdef EXPERIMENTAL_PRDR
-if (where == ACL_WHERE_RCPT || where == ACL_WHERE_PRDR )
+#ifndef DISABLE_PRDR
+if (where == ACL_WHERE_RCPT || where == ACL_WHERE_PRDR)
#else
-if (where == ACL_WHERE_RCPT )
+if (where == ACL_WHERE_RCPT)
#endif
{
adb = address_defaults;
*log_msgptr = US"defer in percent_hack_domains check";
return DEFER;
}
+#ifdef EXPERIMENTAL_INTERNATIONAL
+ if ((addr->prop.utf8_msg = message_smtputf8))
+ {
+ addr->prop.utf8_downcvt = message_utf8_downconvert == 1;
+ addr->prop.utf8_downcvt_maybe = message_utf8_downconvert == -1;
+ }
+#endif
deliver_domain = addr->domain;
deliver_localpart = addr->local_part;
}
switch (where)
{
case ACL_WHERE_RCPT:
-#ifdef EXPERIMENTAL_PRDR
+#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)
+ if (rc == OK && cutthrough.delivery && rcpt_count > cutthrough.nrcpt)
open_cutthrough_connection(addr);
break;
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 */