-/* $Cambridge: exim/src/src/acl.c,v 1.40 2005/06/20 13:58:22 ph10 Exp $ */
+/* $Cambridge: exim/src/src/acl.c,v 1.52 2005/12/06 10:25:59 ph10 Exp $ */
/*************************************************
* Exim - an Internet mail transport agent *
#endif
CONTROL_ERROR, CONTROL_CASEFUL_LOCAL_PART, CONTROL_CASELOWER_LOCAL_PART,
CONTROL_ENFORCE_SYNC, CONTROL_NO_ENFORCE_SYNC, CONTROL_FREEZE,
- CONTROL_QUEUE_ONLY, CONTROL_SUBMISSION,
+ CONTROL_QUEUE_ONLY, CONTROL_SUBMISSION, CONTROL_SUPPRESS_LOCAL_FIXUPS,
#ifdef WITH_CONTENT_SCAN
CONTROL_NO_MBOX_UNSPOOL,
#endif
CONTROL_FAKEDEFER, CONTROL_FAKEREJECT, CONTROL_NO_MULTILINE };
-/* ACL control names; keep in step with the table above! */
+/* ACL control names; keep in step with the table above! This list is used for
+turning ids into names. The actual list of recognized names is in the variable
+control_def controls_list[] below. The fact that there are two lists is a mess
+and should be tidied up. */
static uschar *controls[] = {
#ifdef EXPERIMENTAL_BRIGHTMAIL
#endif
US"error", US"caseful_local_part",
US"caselower_local_part", US"enforce_sync", US"no_enforce_sync", US"freeze",
- US"queue_only", US"submission",
+ US"queue_only", US"submission", US"suppress_local_fixups",
#ifdef WITH_CONTENT_SCAN
US"no_mbox_unspool",
#endif
+
US"no_multiline"};
/* Flags to indicate for which conditions /modifiers a string expansion is done
~((1<<ACL_WHERE_MAIL)|(1<<ACL_WHERE_RCPT)| /* submission */
(1<<ACL_WHERE_PREDATA)),
+ (unsigned int)
+ ~((1<<ACL_WHERE_MAIL)|(1<<ACL_WHERE_RCPT)| /* suppress_local_fixups */
+ (1<<ACL_WHERE_NOTSMTP)|(1<<ACL_WHERE_PREDATA)),
+
#ifdef WITH_CONTENT_SCAN
(unsigned int)
~((1<<ACL_WHERE_MAIL)|(1<<ACL_WHERE_RCPT)| /* no_mbox_unspool */
static control_def controls_list[] = {
#ifdef EXPERIMENTAL_BRIGHTMAIL
- { US"bmi_run", CONTROL_BMI_RUN, FALSE},
+ { US"bmi_run", CONTROL_BMI_RUN, FALSE },
#endif
#ifdef EXPERIMENTAL_DOMAINKEYS
- { US"dk_verify", CONTROL_DK_VERIFY, FALSE},
-#endif
- { 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, FALSE},
- { US"no_enforce_sync", CONTROL_NO_ENFORCE_SYNC, FALSE},
- { US"no_multiline_responses", CONTROL_NO_MULTILINE, FALSE},
- { US"queue_only", CONTROL_QUEUE_ONLY, FALSE},
+ { US"dk_verify", CONTROL_DK_VERIFY, FALSE },
+#endif
+ { 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, FALSE },
+ { US"no_enforce_sync", CONTROL_NO_ENFORCE_SYNC, FALSE },
+ { US"no_multiline_responses", CONTROL_NO_MULTILINE, 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 }
};
/* Support data structures for Client SMTP Authorization. acl_verify_csa()
address literals, but it's probably the most friendly thing to do. This is an
extension to CSA, so we allow it to be turned off for proper conformance. */
-if (string_is_ip_address(domain, NULL))
+if (string_is_ip_address(domain, NULL) != 0)
{
if (!dns_csa_use_reverse) return CSA_UNKNOWN;
dns_build_reverse(domain, target);
BOOL defer_ok = FALSE;
BOOL callout_defer_ok = FALSE;
BOOL no_details = FALSE;
+BOOL success_on_redirect = FALSE;
address_item *sender_vaddr = NULL;
uschar *verify_sender_address = NULL;
uschar *pm_mailfrom = NULL;
return FAIL;
}
-/* We can test the result of optional HELO verification */
+/* We can test the result of optional HELO verification that might have
+occurred earlier. If not, we can attempt the verification now. */
if (strcmpic(ss, US"helo") == 0)
{
if (slash != NULL) goto NO_OPTIONS;
+ if (!helo_verified && !helo_verify_failed) smtp_verify_helo();
return helo_verified? OK : FAIL;
}
if (strcmpic(ss, US"header_syntax") == 0)
{
if (slash != NULL) goto NO_OPTIONS;
- if (where != ACL_WHERE_DATA && where != ACL_WHERE_NOTSMTP)
- {
- *log_msgptr = string_sprintf("cannot check header contents in ACL for %s "
- "(only possible in ACL for DATA)", acl_wherenames[where]);
- return ERROR;
- }
+ if (where != ACL_WHERE_DATA && where != ACL_WHERE_NOTSMTP) goto WRONG_ACL;
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);
return rc;
}
+/* Check that no recipient of this message is "blind", that is, every envelope
+recipient must be mentioned in either To: or Cc:. */
+
+if (strcmpic(ss, US"not_blind") == 0)
+ {
+ if (slash != NULL) goto NO_OPTIONS;
+ if (where != ACL_WHERE_DATA && where != ACL_WHERE_NOTSMTP) goto WRONG_ACL;
+ rc = verify_check_notblind();
+ if (rc != OK)
+ {
+ *log_msgptr = string_sprintf("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
if (strcmpic(ss, US"header_sender") == 0)
{
- if (where != ACL_WHERE_DATA && where != ACL_WHERE_NOTSMTP)
- {
- *log_msgptr = string_sprintf("cannot check header contents in ACL for %s "
- "(only possible in ACL for DATA)", acl_wherenames[where]);
- return ERROR;
- }
+ if (where != ACL_WHERE_DATA && where != ACL_WHERE_NOTSMTP) goto WRONG_ACL;
verify_header_sender = TRUE;
}
{
if (strcmpic(ss, US"defer_ok") == 0) defer_ok = TRUE;
else if (strcmpic(ss, US"no_details") == 0) no_details = TRUE;
+ else if (strcmpic(ss, US"success_on_redirect") == 0) success_on_redirect = TRUE;
/* These two old options are left for backwards compatibility */
else
verify_options |= vopt_fake_sender;
+ if (success_on_redirect)
+ verify_options |= vopt_success_on_redirect;
+
/* The recipient, qualify, and expn options are never set in
verify_options. */
{
address_item addr2;
+ if (success_on_redirect)
+ verify_options |= vopt_success_on_redirect;
+
/* We must use a copy of the address for verification, because it might
get rewritten. */
*log_msgptr = string_sprintf("unexpected '/' found in \"%s\" "
"(this verify item has no options)", arg);
return ERROR;
+
+/* Calls in the wrong ACL come here */
+
+WRONG_ACL:
+*log_msgptr = string_sprintf("cannot check header contents in ACL for %s "
+ "(only possible in ACL for DATA)", acl_wherenames[where]);
+return ERROR;
}
+ (double)tv.tv_usec / 1000000.0;
double prev_time = (double)dbd->time_stamp
+ (double)dbd->time_usec / 1000000.0;
- double interval = this_time - prev_time;
-
- double i_over_p = interval / period;
- double a = exp(-i_over_p);
/* We must avoid division by zero, and deal gracefully with the clock going
backwards. If we blunder ahead when time is in reverse then the computed
- rate will become bogusly huge. Clamp i/p to a very small number instead. */
+ rate will be bogus. To be safe we clamp interval to a very small number. */
- if (i_over_p <= 0.0) i_over_p = 1e-9;
+ double interval = this_time - prev_time <= 0.0 ? 1e-9
+ : this_time - prev_time;
+
+ double i_over_p = interval / period;
+ double a = exp(-i_over_p);
dbd->time_stamp = tv.tv_sec;
dbd->time_usec = tv.tv_usec;
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 != '/') pp++;
- originator_name = string_copy(parse_fix_phrase(p+6, 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;
}
return ERROR;
}
break;
+
+ case CONTROL_SUPPRESS_LOCAL_FIXUPS:
+ suppress_local_fixups = TRUE;
+ break;
}
break;
return ERROR;
}
acl_text[statbuf.st_size] = 0;
- close(fd);
+ (void)close(fd);
acl_name = string_sprintf("ACL \"%s\"", ss);
HDEBUG(D_acl) debug_printf("read ACL from file %s\n", ss);
case ACL_WARN:
if (cond == OK)
acl_warn(where, *user_msgptr, *log_msgptr);
- else if (cond == DEFER)
+ else if (cond == DEFER && (log_extra_selector & LX_acl_warn_skipped) != 0)
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": ",
Arguments:
where ACL_WHERE_xxxx indicating where called from
- data_string RCPT address, or SMTP command argument, or NULL
+ recipient RCPT address for RCPT check, else NULL
s the input string; NULL is the same as an empty ACL => DENY
user_msgptr where to put a user error (for SMTP response)
log_msgptr where to put a logging message (not for SMTP response)
*/
int
-acl_check(int where, uschar *data_string, uschar *s, uschar **user_msgptr,
+acl_check(int where, uschar *recipient, uschar *s, uschar **user_msgptr,
uschar **log_msgptr)
{
int rc;
address_item adb;
-address_item *addr;
+address_item *addr = NULL;
*user_msgptr = *log_msgptr = NULL;
sender_verified_failed = NULL;
{
adb = address_defaults;
addr = &adb;
- addr->address = data_string;
+ addr->address = recipient;
if (deliver_split_address(addr) == DEFER)
{
*log_msgptr = US"defer in percent_hack_domains check";
deliver_domain = addr->domain;
deliver_localpart = addr->local_part;
}
-else
- {
- addr = NULL;
- smtp_command_argument = data_string;
- }
rc = acl_check_internal(where, addr, s, 0, user_msgptr, log_msgptr);
-smtp_command_argument = deliver_domain =
- deliver_localpart = deliver_address_data = sender_address_data = NULL;
+deliver_domain = deliver_localpart = deliver_address_data =
+ sender_address_data = NULL;
/* A DISCARD response is permitted only for message ACLs, excluding the PREDATA
ACL, which is really in the middle of an SMTP command. */