* Exim - an Internet mail transport agent *
*************************************************/
-/* Copyright (c) University of Cambridge 1995 - 2015 */
+/* Copyright (c) University of Cambridge 1995 - 2016 */
/* See the file NOTICE for conditions of use and distribution. */
/* Code for handling Access Control Lists (ACLs) */
ACLC_DECODE,
#endif
ACLC_DELAY,
-#ifdef WITH_OLD_DEMIME
- ACLC_DEMIME,
-#endif
#ifndef DISABLE_DKIM
ACLC_DKIM_SIGNER,
ACLC_DKIM_STATUS,
US"decode",
#endif
US"delay",
-#ifdef WITH_OLD_DEMIME
- US"demime",
-#endif
#ifndef DISABLE_DKIM
US"dkim_signers",
US"dkim_status",
#endif
CONTROL_FAKEDEFER,
CONTROL_FAKEREJECT,
-#ifdef EXPERIMENTAL_INTERNATIONAL
+#ifdef SUPPORT_I18N
CONTROL_UTF8_DOWNCONVERT,
#endif
CONTROL_NO_MULTILINE,
#endif
US"fakedefer",
US"fakereject",
-#ifdef EXPERIMENTAL_INTERNATIONAL
+#ifdef SUPPORT_I18N
US"utf8_downconvert",
#endif
US"no_multiline_responses",
TRUE, /* decode */
#endif
TRUE, /* delay */
-#ifdef WITH_OLD_DEMIME
- TRUE, /* demime */
-#endif
#ifndef DISABLE_DKIM
TRUE, /* dkim_signers */
TRUE, /* dkim_status */
FALSE, /* decode */
#endif
TRUE, /* delay */
-#ifdef WITH_OLD_DEMIME
- FALSE, /* demime */
-#endif
#ifndef DISABLE_DKIM
FALSE, /* dkim_signers */
FALSE, /* dkim_status */
(1<<ACL_WHERE_NOTQUIT), /* delay */
- #ifdef WITH_OLD_DEMIME
- (unsigned int)
- ~((1<<ACL_WHERE_DATA)| /* demime */
- #ifndef DISABLE_PRDR
- (1<<ACL_WHERE_PRDR)|
- #endif
- (1<<ACL_WHERE_NOTSMTP)),
- #endif
-
#ifndef DISABLE_DKIM
(unsigned int)
~(1<<ACL_WHERE_DKIM), /* dkim_signers */
~(1<<ACL_WHERE_DATA), /* dmarc_status */
#endif
- (1<<ACL_WHERE_NOTSMTP)| /* dnslists */
- (1<<ACL_WHERE_NOTSMTP_START),
+ /* Explicit key lookups can be made in non-smtp ACLs so pass
+ always and check in the verify processing itself. */
+
+ 0, /* dnslists */
(unsigned int)
~((1<<ACL_WHERE_RCPT) /* domains */
+ |(1<<ACL_WHERE_VRFY)
#ifndef DISABLE_PRDR
|(1<<ACL_WHERE_PRDR)
#endif
(unsigned int)
~((1<<ACL_WHERE_RCPT) /* local_parts */
+ |(1<<ACL_WHERE_VRFY)
#ifndef DISABLE_PRDR
|(1<<ACL_WHERE_PRDR)
#endif
#endif
(1<<ACL_WHERE_MIME)),
-#ifdef EXPERIMENTAL_INTERNATIONAL
+#ifdef SUPPORT_I18N
0, /* utf8_downconvert */
#endif
{ US"submission", CONTROL_SUBMISSION, TRUE },
{ US"suppress_local_fixups", CONTROL_SUPPRESS_LOCAL_FIXUPS, FALSE },
{ US"cutthrough_delivery", CONTROL_CUTTHROUGH_DELIVERY, FALSE },
-#ifdef EXPERIMENTAL_INTERNATIONAL
+#ifdef SUPPORT_I18N
{ US"utf8_downconvert", CONTROL_UTF8_DOWNCONVERT, TRUE }
#endif
};
/* An empty string does nothing; ensure exactly one final newline. */
if (hlen <= 0) return;
-if (hstring[--hlen] != '\n')
+if (hstring[--hlen] != '\n') /* no newline */
q = string_sprintf("%s\n", hstring);
-else if (hstring[hlen-1] == '\n')
+else if (hstring[hlen-1] == '\n') /* double newline */
{
uschar * s = string_copy(hstring);
while(s[--hlen] == '\n')
for (;;)
{
- q = Ustrchr(q, '\n');
+ q = Ustrchr(q, '\n'); /* we know there was a newline */
if (*(++q) != ' ' && *q != '\t') break;
}
fn_hdrs_added(void)
{
uschar * ret = NULL;
+int size = 0;
+int ptr = 0;
header_line * h = acl_added_headers;
uschar * s;
uschar * cp;
-int size = 0;
-int ptr = 0;
if (!h) return 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);
+ ret = string_catn(ret, &size, &ptr, s, cp-s+1);
+ ret = string_catn(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 */
+ ret = string_catn(ret, &size, &ptr, s, cp-s+1); /* newline-sep list */
}
while((h = h->next));
test whether it was successful or not. (This is for optional verification; for
mandatory verification, the connection doesn't last this long.) */
- if (tls_in.certificate_verified) return OK;
- *user_msgptr = US"no verified certificate";
- return FAIL;
+ if (tls_in.certificate_verified) return OK;
+ *user_msgptr = US"no verified certificate";
+ return FAIL;
case VERIFY_HELO:
/* We can test the result of optional HELO verification that might have
occurred earlier. If not, we can attempt the verification now. */
- if (!helo_verified && !helo_verify_failed) smtp_verify_helo();
- return helo_verified? OK : FAIL;
+ if (!helo_verified && !helo_verify_failed) smtp_verify_helo();
+ return helo_verified? OK : FAIL;
case VERIFY_CSA:
/* Do Client SMTP Authorization checks in a separate function, and turn the
result code into user-friendly strings. */
- rc = acl_verify_csa(list);
- *log_msgptr = *user_msgptr = string_sprintf("client SMTP authorization %s",
+ rc = acl_verify_csa(list);
+ *log_msgptr = *user_msgptr = string_sprintf("client SMTP authorization %s",
csa_reason_string[rc]);
- csa_status = csa_status_string[rc];
- DEBUG(D_acl) debug_printf("CSA result %s\n", csa_status);
- return csa_return_code[rc];
+ csa_status = csa_status_string[rc];
+ DEBUG(D_acl) debug_printf("CSA result %s\n", csa_status);
+ return csa_return_code[rc];
case VERIFY_HDR_SYNTAX:
/* Check that all relevant header lines have the correct syntax. If there is
always). */
rc = verify_check_headers(log_msgptr);
- if (rc != OK && smtp_return_error_details && *log_msgptr != NULL)
- *user_msgptr = string_sprintf("Rejected after DATA: %s", *log_msgptr);
+ if (rc != OK && *log_msgptr)
+ if (smtp_return_error_details)
+ *user_msgptr = string_sprintf("Rejected after DATA: %s", *log_msgptr);
+ else
+ acl_verify_message = *log_msgptr;
return rc;
case VERIFY_HDR_NAMES_ASCII:
uschar *save_address_data = deliver_address_data;
sender_vaddr = deliver_make_addr(verify_sender_address, TRUE);
-#ifdef EXPERIMENTAL_INTERNATIONAL
+#ifdef SUPPORT_I18N
if ((sender_vaddr->prop.utf8_msg = message_smtputf8))
{
sender_vaddr->prop.utf8_downcvt = message_utf8_downconvert == 1;
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);
- if (tolower(*ss) == 'k') { limit *= 1024.0; ss++; }
- else if (tolower(*ss) == 'm') { limit *= 1024.0*1024.0; ss++; }
- else if (tolower(*ss) == 'g') { limit *= 1024.0*1024.0*1024.0; ss++; }
- }
+ return ratelimit_error(log_msgptr, "sender rate limit not set");
+
+limit = Ustrtod(sender_rate_limit, &ss);
+if (tolower(*ss) == 'k') { limit *= 1024.0; ss++; }
+else if (tolower(*ss) == 'm') { limit *= 1024.0*1024.0; ss++; }
+else if (tolower(*ss) == 'g') { limit *= 1024.0*1024.0*1024.0; ss++; }
+
if (limit < 0.0 || *ss != '\0')
return ratelimit_error(log_msgptr,
"\"%s\" is not a positive number", sender_rate_limit);
break;
case CONTROL_CUTTHROUGH_DELIVERY:
+#ifndef DISABLE_PRDR
if (prdr_requested)
+#else
+ if (0)
+#endif
/* 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" */
}
return ERROR;
- #ifdef EXPERIMENTAL_INTERNATIONAL
+#ifdef SUPPORT_I18N
case CONTROL_UTF8_DOWNCONVERT:
if (*p == '/')
{
break;
}
return ERROR;
- #endif
+#endif
}
break;
}
break;
- #ifdef WITH_OLD_DEMIME
- case ACLC_DEMIME:
- rc = demime(&arg);
- break;
- #endif
-
#ifndef DISABLE_DKIM
case ACLC_DKIM_SIGNER:
if (dkim_cur_signer != NULL)
#endif
case ACLC_DNSLISTS:
- rc = verify_check_dnsbl(&arg);
+ rc = verify_check_dnsbl(where, &arg, log_msgptr);
break;
case ACLC_DOMAINS:
case ACLC_SET:
{
int old_pool = store_pool;
- if (cb->u.varname[0] == 'c') store_pool = POOL_PERM;
+ if ( cb->u.varname[0] == 'c'
+#ifndef DISABLE_EVENT
+ || event_name /* An event is being delivered */
+#endif
+ )
+ store_pool = POOL_PERM;
acl_var_create(cb->u.varname)->data.ptr = string_copy(arg);
store_pool = old_pool;
}
case ACLC_VERIFY:
rc = acl_verify(where, addr, arg, user_msgptr, log_msgptr, basic_errno);
- acl_verify_message = *user_msgptr;
+ if (*user_msgptr)
+ acl_verify_message = *user_msgptr;
if (verb == ACL_WARN) *user_msgptr = NULL;
break;
case ACL_WARN:
if (cond == OK)
acl_warn(where, *user_msgptr, *log_msgptr);
- else if (cond == DEFER && (log_extra_selector & LX_acl_warn_skipped) != 0)
+ 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_reject_target = LOG_MAIN|LOG_REJECT;
#ifndef DISABLE_PRDR
-if (where == ACL_WHERE_RCPT || where == ACL_WHERE_PRDR)
+if (where==ACL_WHERE_RCPT || where==ACL_WHERE_VRFY || where==ACL_WHERE_PRDR)
#else
-if (where == ACL_WHERE_RCPT)
+if (where==ACL_WHERE_RCPT || where==ACL_WHERE_VRFY)
#endif
{
adb = address_defaults;
*log_msgptr = US"defer in percent_hack_domains check";
return DEFER;
}
-#ifdef EXPERIMENTAL_INTERNATIONAL
+#ifdef SUPPORT_I18N
if ((addr->prop.utf8_msg = message_smtputf8))
{
addr->prop.utf8_downcvt = message_utf8_downconvert == 1;
and rcpt acl returned accept,
and first recipient (cancel on any subsequents)
open one now and run it up to RCPT acceptance.
-A failed verify should cancel cutthrough request.
-
+A failed verify should cancel cutthrough request,
+and will pass the fail to the originator.
Initial implementation: dual-write to spool.
Assume the rxd datastream is now being copied byte-for-byte to an open cutthrough connection.
#ifndef DISABLE_PRDR
case ACL_WHERE_PRDR:
#endif
- if (rc == OK && cutthrough.delivery && rcpt_count > cutthrough.nrcpt)
- open_cutthrough_connection(addr);
+ if (host_checking_callout) /* -bhc mode */
+ cancel_cutthrough_connection("host-checking mode");
+ else if (rc == OK && cutthrough.delivery && rcpt_count > cutthrough.nrcpt)
+ rc = open_cutthrough_connection(addr);
break;
case ACL_WHERE_PREDATA:
- if( rc == OK )
+ if (rc == OK)
cutthrough_predata();
else
cancel_cutthrough_connection("predata acl not ok");