/* ACL verbs */
static uschar *verbs[] = {
- US"accept",
- US"defer",
- US"deny",
- US"discard",
- US"drop",
- US"require",
- US"warn" };
+ [ACL_ACCEPT] = US"accept",
+ [ACL_DEFER] = US"defer",
+ [ACL_DENY] = US"deny",
+ [ACL_DISCARD] = US"discard",
+ [ACL_DROP] = US"drop",
+ [ACL_REQUIRE] = US"require",
+ [ACL_WARN] = US"warn"
+};
/* For each verb, the conditions for which "message" or "log_message" are used
are held as a bitmap. This is to avoid expanding the strings unnecessarily. For
the code. */
static int msgcond[] = {
- (1<<OK) | (1<<FAIL) | (1<<FAIL_DROP), /* accept */
- (1<<OK), /* defer */
- (1<<OK), /* deny */
- (1<<OK) | (1<<FAIL) | (1<<FAIL_DROP), /* discard */
- (1<<OK), /* drop */
- (1<<FAIL) | (1<<FAIL_DROP), /* require */
- (1<<OK) /* warn */
+ [ACL_ACCEPT] = (1<<OK) | (1<<FAIL) | (1<<FAIL_DROP),
+ [ACL_DEFER] = (1<<OK),
+ [ACL_DENY] = (1<<OK),
+ [ACL_DISCARD] = (1<<OK) | (1<<FAIL) | (1<<FAIL_DROP),
+ [ACL_DROP] = (1<<OK),
+ [ACL_REQUIRE] = (1<<FAIL) | (1<<FAIL_DROP),
+ [ACL_WARN] = (1<<OK)
};
/* ACL condition and modifier codes - keep in step with the table that
} condition_def;
static condition_def conditions[] = {
- { US"acl", FALSE, FALSE, 0 },
+ [ACLC_ACL] = { US"acl", FALSE, FALSE, 0 },
- { US"add_header", TRUE, TRUE,
- (unsigned int)
- ~((1<<ACL_WHERE_MAIL)|(1<<ACL_WHERE_RCPT)|
- (1<<ACL_WHERE_PREDATA)|(1<<ACL_WHERE_DATA)|
+ [ACLC_ADD_HEADER] = { US"add_header", TRUE, TRUE,
+ (unsigned int)
+ ~((1<<ACL_WHERE_MAIL)|(1<<ACL_WHERE_RCPT)|
+ (1<<ACL_WHERE_PREDATA)|(1<<ACL_WHERE_DATA)|
#ifndef DISABLE_PRDR
- (1<<ACL_WHERE_PRDR)|
+ (1<<ACL_WHERE_PRDR)|
#endif
- (1<<ACL_WHERE_MIME)|(1<<ACL_WHERE_NOTSMTP)|
- (1<<ACL_WHERE_DKIM)|
- (1<<ACL_WHERE_NOTSMTP_START)),
+ (1<<ACL_WHERE_MIME)|(1<<ACL_WHERE_NOTSMTP)|
+ (1<<ACL_WHERE_DKIM)|
+ (1<<ACL_WHERE_NOTSMTP_START)),
},
- { US"authenticated", FALSE, FALSE,
- (1<<ACL_WHERE_NOTSMTP)|
- (1<<ACL_WHERE_NOTSMTP_START)|
- (1<<ACL_WHERE_CONNECT)|(1<<ACL_WHERE_HELO),
+ [ACLC_AUTHENTICATED] = { US"authenticated", FALSE, FALSE,
+ (1<<ACL_WHERE_NOTSMTP)|
+ (1<<ACL_WHERE_NOTSMTP_START)|
+ (1<<ACL_WHERE_CONNECT)|(1<<ACL_WHERE_HELO),
},
#ifdef EXPERIMENTAL_BRIGHTMAIL
- { US"bmi_optin", TRUE, TRUE,
- (1<<ACL_WHERE_AUTH)|
- (1<<ACL_WHERE_CONNECT)|(1<<ACL_WHERE_HELO)|
- (1<<ACL_WHERE_DATA)|(1<<ACL_WHERE_MIME)|
+ [ACLC_BMI_OPTIN] = { US"bmi_optin", TRUE, TRUE,
+ (1<<ACL_WHERE_AUTH)|
+ (1<<ACL_WHERE_CONNECT)|(1<<ACL_WHERE_HELO)|
+ (1<<ACL_WHERE_DATA)|(1<<ACL_WHERE_MIME)|
# ifndef DISABLE_PRDR
- (1<<ACL_WHERE_PRDR)|
+ (1<<ACL_WHERE_PRDR)|
# endif
- (1<<ACL_WHERE_ETRN)|(1<<ACL_WHERE_EXPN)|
- (1<<ACL_WHERE_MAILAUTH)|
- (1<<ACL_WHERE_MAIL)|(1<<ACL_WHERE_STARTTLS)|
- (1<<ACL_WHERE_VRFY)|(1<<ACL_WHERE_PREDATA)|
- (1<<ACL_WHERE_NOTSMTP_START),
+ (1<<ACL_WHERE_ETRN)|(1<<ACL_WHERE_EXPN)|
+ (1<<ACL_WHERE_MAILAUTH)|
+ (1<<ACL_WHERE_MAIL)|(1<<ACL_WHERE_STARTTLS)|
+ (1<<ACL_WHERE_VRFY)|(1<<ACL_WHERE_PREDATA)|
+ (1<<ACL_WHERE_NOTSMTP_START),
},
#endif
- { US"condition", TRUE, FALSE, 0 },
- { US"continue", TRUE, TRUE, 0 },
+ [ACLC_CONDITION] = { US"condition", TRUE, FALSE, 0 },
+ [ACLC_CONTINUE] = { US"continue", TRUE, TRUE, 0 },
/* Certain types of control are always allowed, so we let it through
always and check in the control processing itself. */
- { US"control", TRUE, TRUE, 0 },
+ [ACLC_CONTROL] = { US"control", TRUE, TRUE, 0 },
#ifdef EXPERIMENTAL_DCC
- { US"dcc", TRUE, FALSE,
- (unsigned int)
- ~((1<<ACL_WHERE_DATA)|
+ [ACLC_DCC] = { US"dcc", TRUE, FALSE,
+ (unsigned int)
+ ~((1<<ACL_WHERE_DATA)|
# ifndef DISABLE_PRDR
- (1<<ACL_WHERE_PRDR)|
+ (1<<ACL_WHERE_PRDR)|
# endif
- (1<<ACL_WHERE_NOTSMTP)),
+ (1<<ACL_WHERE_NOTSMTP)),
},
#endif
#ifdef WITH_CONTENT_SCAN
- { US"decode", TRUE, FALSE, (unsigned int) ~(1<<ACL_WHERE_MIME) },
+ [ACLC_DECODE] = { US"decode", TRUE, FALSE, (unsigned int) ~(1<<ACL_WHERE_MIME) },
#endif
- { US"delay", TRUE, TRUE, (1<<ACL_WHERE_NOTQUIT) },
+ [ACLC_DELAY] = { US"delay", TRUE, TRUE, (1<<ACL_WHERE_NOTQUIT) },
#ifndef DISABLE_DKIM
- { US"dkim_signers", TRUE, FALSE, (unsigned int) ~(1<<ACL_WHERE_DKIM) },
- { US"dkim_status", TRUE, FALSE, (unsigned int) ~(1<<ACL_WHERE_DKIM) },
+ [ACLC_DKIM_SIGNER] = { US"dkim_signers", TRUE, FALSE, (unsigned int) ~(1<<ACL_WHERE_DKIM) },
+ [ACLC_DKIM_STATUS] = { US"dkim_status", TRUE, FALSE, (unsigned int) ~(1<<ACL_WHERE_DKIM) },
#endif
#ifdef EXPERIMENTAL_DMARC
- { US"dmarc_status", TRUE, FALSE, (unsigned int) ~(1<<ACL_WHERE_DATA) },
+ [ACLC_DMARC_STATUS] = { US"dmarc_status", TRUE, FALSE, (unsigned int) ~(1<<ACL_WHERE_DATA) },
#endif
/* Explicit key lookups can be made in non-smtp ACLs so pass
always and check in the verify processing itself. */
- { US"dnslists", TRUE, FALSE, 0 },
+ [ACLC_DNSLISTS] = { US"dnslists", TRUE, FALSE, 0 },
- { US"domains", FALSE, FALSE,
- (unsigned int)
- ~((1<<ACL_WHERE_RCPT)
- |(1<<ACL_WHERE_VRFY)
+ [ACLC_DOMAINS] = { US"domains", FALSE, FALSE,
+ (unsigned int)
+ ~((1<<ACL_WHERE_RCPT)
+ |(1<<ACL_WHERE_VRFY)
#ifndef DISABLE_PRDR
- |(1<<ACL_WHERE_PRDR)
+ |(1<<ACL_WHERE_PRDR)
#endif
),
},
- { US"encrypted", FALSE, FALSE,
- (1<<ACL_WHERE_NOTSMTP)|
- (1<<ACL_WHERE_CONNECT)|
- (1<<ACL_WHERE_NOTSMTP_START)|
- (1<<ACL_WHERE_HELO),
+ [ACLC_ENCRYPTED] = { US"encrypted", FALSE, FALSE,
+ (1<<ACL_WHERE_NOTSMTP)|
+ (1<<ACL_WHERE_CONNECT)|
+ (1<<ACL_WHERE_NOTSMTP_START)|
+ (1<<ACL_WHERE_HELO),
},
- { US"endpass", TRUE, TRUE, 0 },
+ [ACLC_ENDPASS] = { US"endpass", TRUE, TRUE, 0 },
- { US"hosts", FALSE, FALSE,
- (1<<ACL_WHERE_NOTSMTP)|
- (1<<ACL_WHERE_NOTSMTP_START),
+ [ACLC_HOSTS] = { US"hosts", FALSE, FALSE,
+ (1<<ACL_WHERE_NOTSMTP)|
+ (1<<ACL_WHERE_NOTSMTP_START),
},
- { US"local_parts", FALSE, FALSE,
- (unsigned int)
- ~((1<<ACL_WHERE_RCPT)
- |(1<<ACL_WHERE_VRFY)
- #ifndef DISABLE_PRDR
- |(1<<ACL_WHERE_PRDR)
- #endif
+ [ACLC_LOCAL_PARTS] = { US"local_parts", FALSE, FALSE,
+ (unsigned int)
+ ~((1<<ACL_WHERE_RCPT)
+ |(1<<ACL_WHERE_VRFY)
+#ifndef DISABLE_PRDR
+ |(1<<ACL_WHERE_PRDR)
+#endif
),
},
- { US"log_message", TRUE, TRUE, 0 },
- { US"log_reject_target", TRUE, TRUE, 0 },
- { US"logwrite", TRUE, TRUE, 0 },
+ [ACLC_LOG_MESSAGE] = { US"log_message", TRUE, TRUE, 0 },
+ [ACLC_LOG_REJECT_TARGET] = { US"log_reject_target", TRUE, TRUE, 0 },
+ [ACLC_LOGWRITE] = { US"logwrite", TRUE, TRUE, 0 },
#ifdef WITH_CONTENT_SCAN
- { US"malware", TRUE, FALSE,
- (unsigned int)
- ~((1<<ACL_WHERE_DATA)|
+ [ACLC_MALWARE] = { US"malware", TRUE, FALSE,
+ (unsigned int)
+ ~((1<<ACL_WHERE_DATA)|
# ifndef DISABLE_PRDR
- (1<<ACL_WHERE_PRDR)|
+ (1<<ACL_WHERE_PRDR)|
# endif
- (1<<ACL_WHERE_NOTSMTP)),
+ (1<<ACL_WHERE_NOTSMTP)),
},
#endif
- { US"message", TRUE, TRUE, 0 },
+ [ACLC_MESSAGE] = { US"message", TRUE, TRUE, 0 },
#ifdef WITH_CONTENT_SCAN
- { US"mime_regex", TRUE, FALSE, (unsigned int) ~(1<<ACL_WHERE_MIME) },
+ [ACLC_MIME_REGEX] = { US"mime_regex", TRUE, FALSE, (unsigned int) ~(1<<ACL_WHERE_MIME) },
#endif
- { US"queue", TRUE, TRUE,
- (1<<ACL_WHERE_NOTSMTP)|
+ [ACLC_QUEUE] = { US"queue", TRUE, TRUE,
+ (1<<ACL_WHERE_NOTSMTP)|
#ifndef DISABLE_PRDR
- (1<<ACL_WHERE_PRDR)|
+ (1<<ACL_WHERE_PRDR)|
#endif
- (1<<ACL_WHERE_DATA),
+ (1<<ACL_WHERE_DATA),
},
- { US"ratelimit", TRUE, FALSE, 0 },
- { US"recipients", FALSE, FALSE, (unsigned int) ~(1<<ACL_WHERE_RCPT) },
+ [ACLC_RATELIMIT] = { US"ratelimit", TRUE, FALSE, 0 },
+ [ACLC_RECIPIENTS] = { US"recipients", FALSE, FALSE, (unsigned int) ~(1<<ACL_WHERE_RCPT) },
#ifdef WITH_CONTENT_SCAN
- { US"regex", TRUE, FALSE,
- (unsigned int)
- ~((1<<ACL_WHERE_DATA)|
+ [ACLC_REGEX] = { US"regex", TRUE, FALSE,
+ (unsigned int)
+ ~((1<<ACL_WHERE_DATA)|
# ifndef DISABLE_PRDR
- (1<<ACL_WHERE_PRDR)|
+ (1<<ACL_WHERE_PRDR)|
# endif
- (1<<ACL_WHERE_NOTSMTP)|
- (1<<ACL_WHERE_MIME)),
+ (1<<ACL_WHERE_NOTSMTP)|
+ (1<<ACL_WHERE_MIME)),
},
#endif
- { US"remove_header", TRUE, TRUE,
- (unsigned int)
- ~((1<<ACL_WHERE_MAIL)|(1<<ACL_WHERE_RCPT)|
- (1<<ACL_WHERE_PREDATA)|(1<<ACL_WHERE_DATA)|
+ [ACLC_REMOVE_HEADER] = { US"remove_header", TRUE, TRUE,
+ (unsigned int)
+ ~((1<<ACL_WHERE_MAIL)|(1<<ACL_WHERE_RCPT)|
+ (1<<ACL_WHERE_PREDATA)|(1<<ACL_WHERE_DATA)|
#ifndef DISABLE_PRDR
- (1<<ACL_WHERE_PRDR)|
+ (1<<ACL_WHERE_PRDR)|
#endif
- (1<<ACL_WHERE_MIME)|(1<<ACL_WHERE_NOTSMTP)|
- (1<<ACL_WHERE_NOTSMTP_START)),
+ (1<<ACL_WHERE_MIME)|(1<<ACL_WHERE_NOTSMTP)|
+ (1<<ACL_WHERE_NOTSMTP_START)),
},
- { US"sender_domains", FALSE, FALSE,
- (1<<ACL_WHERE_AUTH)|(1<<ACL_WHERE_CONNECT)|
- (1<<ACL_WHERE_HELO)|
- (1<<ACL_WHERE_MAILAUTH)|(1<<ACL_WHERE_QUIT)|
- (1<<ACL_WHERE_ETRN)|(1<<ACL_WHERE_EXPN)|
- (1<<ACL_WHERE_STARTTLS)|(1<<ACL_WHERE_VRFY),
+ [ACLC_SENDER_DOMAINS] = { US"sender_domains", FALSE, FALSE,
+ (1<<ACL_WHERE_AUTH)|(1<<ACL_WHERE_CONNECT)|
+ (1<<ACL_WHERE_HELO)|
+ (1<<ACL_WHERE_MAILAUTH)|(1<<ACL_WHERE_QUIT)|
+ (1<<ACL_WHERE_ETRN)|(1<<ACL_WHERE_EXPN)|
+ (1<<ACL_WHERE_STARTTLS)|(1<<ACL_WHERE_VRFY),
},
- { US"senders", FALSE, FALSE,
- (1<<ACL_WHERE_AUTH)|(1<<ACL_WHERE_CONNECT)|
- (1<<ACL_WHERE_HELO)|
- (1<<ACL_WHERE_MAILAUTH)|(1<<ACL_WHERE_QUIT)|
- (1<<ACL_WHERE_ETRN)|(1<<ACL_WHERE_EXPN)|
- (1<<ACL_WHERE_STARTTLS)|(1<<ACL_WHERE_VRFY),
+ [ACLC_SENDERS] = { US"senders", FALSE, FALSE,
+ (1<<ACL_WHERE_AUTH)|(1<<ACL_WHERE_CONNECT)|
+ (1<<ACL_WHERE_HELO)|
+ (1<<ACL_WHERE_MAILAUTH)|(1<<ACL_WHERE_QUIT)|
+ (1<<ACL_WHERE_ETRN)|(1<<ACL_WHERE_EXPN)|
+ (1<<ACL_WHERE_STARTTLS)|(1<<ACL_WHERE_VRFY),
},
- { US"set", TRUE, TRUE, 0 },
+ [ACLC_SET] = { US"set", TRUE, TRUE, 0 },
#ifdef WITH_CONTENT_SCAN
- { US"spam", TRUE, FALSE,
- (unsigned int)
- ~((1<<ACL_WHERE_DATA)|
+ [ACLC_SPAM] = { US"spam", TRUE, FALSE,
+ (unsigned int) ~((1<<ACL_WHERE_DATA)|
# ifndef DISABLE_PRDR
- (1<<ACL_WHERE_PRDR)|
+ (1<<ACL_WHERE_PRDR)|
# endif
- (1<<ACL_WHERE_NOTSMTP)),
+ (1<<ACL_WHERE_NOTSMTP)),
},
#endif
#ifdef EXPERIMENTAL_SPF
- { US"spf", TRUE, FALSE,
- (1<<ACL_WHERE_AUTH)|(1<<ACL_WHERE_CONNECT)|
- (1<<ACL_WHERE_HELO)|
- (1<<ACL_WHERE_MAILAUTH)|
- (1<<ACL_WHERE_ETRN)|(1<<ACL_WHERE_EXPN)|
- (1<<ACL_WHERE_STARTTLS)|(1<<ACL_WHERE_VRFY)|
- (1<<ACL_WHERE_NOTSMTP)|
- (1<<ACL_WHERE_NOTSMTP_START),
+ [ACLC_SPF] = { US"spf", TRUE, FALSE,
+ (1<<ACL_WHERE_AUTH)|(1<<ACL_WHERE_CONNECT)|
+ (1<<ACL_WHERE_HELO)|
+ (1<<ACL_WHERE_MAILAUTH)|
+ (1<<ACL_WHERE_ETRN)|(1<<ACL_WHERE_EXPN)|
+ (1<<ACL_WHERE_STARTTLS)|(1<<ACL_WHERE_VRFY)|
+ (1<<ACL_WHERE_NOTSMTP)|
+ (1<<ACL_WHERE_NOTSMTP_START),
},
- { US"spf_guess", TRUE, FALSE,
- (1<<ACL_WHERE_AUTH)|(1<<ACL_WHERE_CONNECT)|
- (1<<ACL_WHERE_HELO)|
- (1<<ACL_WHERE_MAILAUTH)|
- (1<<ACL_WHERE_ETRN)|(1<<ACL_WHERE_EXPN)|
- (1<<ACL_WHERE_STARTTLS)|(1<<ACL_WHERE_VRFY)|
- (1<<ACL_WHERE_NOTSMTP)|
- (1<<ACL_WHERE_NOTSMTP_START),
+ [ACLC_SPF_GUESS] = { US"spf_guess", TRUE, FALSE,
+ (1<<ACL_WHERE_AUTH)|(1<<ACL_WHERE_CONNECT)|
+ (1<<ACL_WHERE_HELO)|
+ (1<<ACL_WHERE_MAILAUTH)|
+ (1<<ACL_WHERE_ETRN)|(1<<ACL_WHERE_EXPN)|
+ (1<<ACL_WHERE_STARTTLS)|(1<<ACL_WHERE_VRFY)|
+ (1<<ACL_WHERE_NOTSMTP)|
+ (1<<ACL_WHERE_NOTSMTP_START),
},
#endif
- { US"udpsend", TRUE, TRUE, 0 },
+ [ACLC_UDPSEND] = { US"udpsend", TRUE, TRUE, 0 },
/* Certain types of verify are always allowed, so we let it through
always and check in the verify function itself */
- { US"verify", TRUE, FALSE,
- 0
- },
+ [ACLC_VERIFY] = { US"verify", TRUE, FALSE, 0 },
};
} control_def;
static control_def controls_list[] = {
+ /* name has_option forbids */
+[CONTROL_AUTH_UNADVERTISED] =
{ US"allow_auth_unadvertised", FALSE,
- (unsigned)
- ~((1<<ACL_WHERE_CONNECT)|(1<<ACL_WHERE_HELO))
+ (unsigned)
+ ~((1<<ACL_WHERE_CONNECT)|(1<<ACL_WHERE_HELO))
},
#ifdef EXPERIMENTAL_BRIGHTMAIL
- { US"bmi_run", FALSE, 0 },
+[CONTROL_BMI_RUN] =
+ { US"bmi_run", FALSE, 0 },
#endif
+[CONTROL_CASEFUL_LOCAL_PART] =
{ US"caseful_local_part", FALSE, (unsigned) ~(1<<ACL_WHERE_RCPT) },
+[CONTROL_CASELOWER_LOCAL_PART] =
{ US"caselower_local_part", FALSE, (unsigned) ~(1<<ACL_WHERE_RCPT) },
- { US"cutthrough_delivery", TRUE, 0 },
- { US"debug", TRUE, 0 },
+[CONTROL_CUTTHROUGH_DELIVERY] =
+ { US"cutthrough_delivery", TRUE, 0 },
+[CONTROL_DEBUG] =
+ { US"debug", TRUE, 0 },
#ifndef DISABLE_DKIM
+[CONTROL_DKIM_VERIFY] =
{ US"dkim_disable_verify", FALSE,
- (1<<ACL_WHERE_DATA)|(1<<ACL_WHERE_NOTSMTP)|
+ (1<<ACL_WHERE_DATA)|(1<<ACL_WHERE_NOTSMTP)|
# ifndef DISABLE_PRDR
- (1<<ACL_WHERE_PRDR)|
+ (1<<ACL_WHERE_PRDR)|
# endif
- (1<<ACL_WHERE_NOTSMTP_START)
+ (1<<ACL_WHERE_NOTSMTP_START)
},
#endif
#ifdef EXPERIMENTAL_DMARC
+[CONTROL_DMARC_VERIFY] =
{ US"dmarc_disable_verify", FALSE,
- (1<<ACL_WHERE_DATA)|(1<<ACL_WHERE_NOTSMTP)|(1<<ACL_WHERE_NOTSMTP_START)
+ (1<<ACL_WHERE_DATA)|(1<<ACL_WHERE_NOTSMTP)|(1<<ACL_WHERE_NOTSMTP_START)
},
+[CONTROL_DMARC_FORENSIC] =
{ US"dmarc_enable_forensic", FALSE,
- (1<<ACL_WHERE_DATA)|(1<<ACL_WHERE_NOTSMTP)|(1<<ACL_WHERE_NOTSMTP_START)
+ (1<<ACL_WHERE_DATA)|(1<<ACL_WHERE_NOTSMTP)|(1<<ACL_WHERE_NOTSMTP_START)
},
#endif
+[CONTROL_DSCP] =
{ US"dscp", TRUE,
- (1<<ACL_WHERE_NOTSMTP)|(1<<ACL_WHERE_NOTSMTP_START)|(1<<ACL_WHERE_NOTQUIT)
+ (1<<ACL_WHERE_NOTSMTP)|(1<<ACL_WHERE_NOTSMTP_START)|(1<<ACL_WHERE_NOTQUIT)
},
+[CONTROL_ENFORCE_SYNC] =
{ US"enforce_sync", FALSE,
- (1<<ACL_WHERE_NOTSMTP)|(1<<ACL_WHERE_NOTSMTP_START)
+ (1<<ACL_WHERE_NOTSMTP)|(1<<ACL_WHERE_NOTSMTP_START)
},
/* Pseudo-value for decode errors */
+[CONTROL_ERROR] =
{ US"error", FALSE, 0 },
+[CONTROL_FAKEDEFER] =
{ US"fakedefer", TRUE,
- (unsigned)
- ~((1<<ACL_WHERE_MAIL)|(1<<ACL_WHERE_RCPT)|
- (1<<ACL_WHERE_PREDATA)|(1<<ACL_WHERE_DATA)|
+ (unsigned)
+ ~((1<<ACL_WHERE_MAIL)|(1<<ACL_WHERE_RCPT)|
+ (1<<ACL_WHERE_PREDATA)|(1<<ACL_WHERE_DATA)|
#ifndef DISABLE_PRDR
- (1<<ACL_WHERE_PRDR)|
+ (1<<ACL_WHERE_PRDR)|
#endif
- (1<<ACL_WHERE_MIME))
+ (1<<ACL_WHERE_MIME))
},
+[CONTROL_FAKEREJECT] =
{ US"fakereject", TRUE,
- (unsigned)
- ~((1<<ACL_WHERE_MAIL)|(1<<ACL_WHERE_RCPT)|
- (1<<ACL_WHERE_PREDATA)|(1<<ACL_WHERE_DATA)|
+ (unsigned)
+ ~((1<<ACL_WHERE_MAIL)|(1<<ACL_WHERE_RCPT)|
+ (1<<ACL_WHERE_PREDATA)|(1<<ACL_WHERE_DATA)|
#ifndef DISABLE_PRDR
- (1<<ACL_WHERE_PRDR)|
+ (1<<ACL_WHERE_PRDR)|
#endif
- (1<<ACL_WHERE_MIME))
+ (1<<ACL_WHERE_MIME))
},
+[CONTROL_FREEZE] =
{ US"freeze", TRUE,
- (unsigned)
- ~((1<<ACL_WHERE_MAIL)|(1<<ACL_WHERE_RCPT)|
- (1<<ACL_WHERE_PREDATA)|(1<<ACL_WHERE_DATA)|
- // (1<<ACL_WHERE_PRDR)| /* Not allow one user to freeze for all */
- (1<<ACL_WHERE_NOTSMTP)|(1<<ACL_WHERE_MIME))
+ (unsigned)
+ ~((1<<ACL_WHERE_MAIL)|(1<<ACL_WHERE_RCPT)|
+ (1<<ACL_WHERE_PREDATA)|(1<<ACL_WHERE_DATA)|
+ // (1<<ACL_WHERE_PRDR)| /* Not allow one user to freeze for all */
+ (1<<ACL_WHERE_NOTSMTP)|(1<<ACL_WHERE_MIME))
},
+[CONTROL_NO_CALLOUT_FLUSH] =
{ US"no_callout_flush", FALSE,
- (1<<ACL_WHERE_NOTSMTP)| (1<<ACL_WHERE_NOTSMTP_START)
+ (1<<ACL_WHERE_NOTSMTP)| (1<<ACL_WHERE_NOTSMTP_START)
},
+[CONTROL_NO_DELAY_FLUSH] =
{ US"no_delay_flush", FALSE,
- (1<<ACL_WHERE_NOTSMTP)|(1<<ACL_WHERE_NOTSMTP_START)
+ (1<<ACL_WHERE_NOTSMTP)|(1<<ACL_WHERE_NOTSMTP_START)
},
+[CONTROL_NO_ENFORCE_SYNC] =
{ US"no_enforce_sync", FALSE,
- (1<<ACL_WHERE_NOTSMTP)|(1<<ACL_WHERE_NOTSMTP_START)
+ (1<<ACL_WHERE_NOTSMTP)|(1<<ACL_WHERE_NOTSMTP_START)
},
#ifdef WITH_CONTENT_SCAN
+[CONTROL_NO_MBOX_UNSPOOL] =
{ US"no_mbox_unspool", FALSE,
- (unsigned)
- ~((1<<ACL_WHERE_MAIL)|(1<<ACL_WHERE_RCPT)|
- (1<<ACL_WHERE_PREDATA)|(1<<ACL_WHERE_DATA)|
- // (1<<ACL_WHERE_PRDR)| /* Not allow one user to freeze for all */
- (1<<ACL_WHERE_MIME))
+ (unsigned)
+ ~((1<<ACL_WHERE_MAIL)|(1<<ACL_WHERE_RCPT)|
+ (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
+[CONTROL_NO_MULTILINE] =
{ US"no_multiline_responses", FALSE,
- (1<<ACL_WHERE_NOTSMTP)|(1<<ACL_WHERE_NOTSMTP_START)
+ (1<<ACL_WHERE_NOTSMTP)|(1<<ACL_WHERE_NOTSMTP_START)
},
+[CONTROL_NO_PIPELINING] =
{ US"no_pipelining", FALSE,
- (1<<ACL_WHERE_NOTSMTP)|(1<<ACL_WHERE_NOTSMTP_START)
+ (1<<ACL_WHERE_NOTSMTP)|(1<<ACL_WHERE_NOTSMTP_START)
},
+[CONTROL_QUEUE_ONLY] =
{ US"queue_only", FALSE,
- (unsigned)
- ~((1<<ACL_WHERE_MAIL)|(1<<ACL_WHERE_RCPT)|
- (1<<ACL_WHERE_PREDATA)|(1<<ACL_WHERE_DATA)|
- // (1<<ACL_WHERE_PRDR)| /* Not allow one user to freeze for all */
- (1<<ACL_WHERE_NOTSMTP)|(1<<ACL_WHERE_MIME))
+ (unsigned)
+ ~((1<<ACL_WHERE_MAIL)|(1<<ACL_WHERE_RCPT)|
+ (1<<ACL_WHERE_PREDATA)|(1<<ACL_WHERE_DATA)|
+ // (1<<ACL_WHERE_PRDR)| /* Not allow one user to freeze for all */
+ (1<<ACL_WHERE_NOTSMTP)|(1<<ACL_WHERE_MIME))
},
+[CONTROL_SUBMISSION] =
{ US"submission", TRUE,
- (unsigned)
- ~((1<<ACL_WHERE_MAIL)|(1<<ACL_WHERE_RCPT)|(1<<ACL_WHERE_PREDATA))
+ (unsigned)
+ ~((1<<ACL_WHERE_MAIL)|(1<<ACL_WHERE_RCPT)|(1<<ACL_WHERE_PREDATA))
},
+[CONTROL_SUPPRESS_LOCAL_FIXUPS] =
{ US"suppress_local_fixups", FALSE,
(unsigned)
~((1<<ACL_WHERE_MAIL)|(1<<ACL_WHERE_RCPT)|(1<<ACL_WHERE_PREDATA)|
(1<<ACL_WHERE_NOTSMTP_START))
},
#ifdef SUPPORT_I18N
+[CONTROL_UTF8_DOWNCONVERT] =
{ US"utf8_downconvert", TRUE, 0 }
#endif
};
the aim is to make the usual configuration simple. */
static int csa_return_code[] = {
- OK, OK, OK, OK,
- FAIL, FAIL, FAIL, FAIL
+ [CSA_UNKNOWN] = OK,
+ [CSA_OK] = OK,
+ [CSA_DEFER_SRV] = OK,
+ [CSA_DEFER_ADDR] = OK,
+ [CSA_FAIL_EXPLICIT] = FAIL,
+ [CSA_FAIL_DOMAIN] = FAIL,
+ [CSA_FAIL_NOADDR] = FAIL,
+ [CSA_FAIL_MISMATCH] = FAIL
};
static uschar *csa_status_string[] = {
- US"unknown", US"ok", US"defer", US"defer",
- US"fail", US"fail", US"fail", US"fail"
+ [CSA_UNKNOWN] = US"unknown",
+ [CSA_OK] = US"ok",
+ [CSA_DEFER_SRV] = US"defer",
+ [CSA_DEFER_ADDR] = US"defer",
+ [CSA_FAIL_EXPLICIT] = US"fail",
+ [CSA_FAIL_DOMAIN] = US"fail",
+ [CSA_FAIL_NOADDR] = US"fail",
+ [CSA_FAIL_MISMATCH] = US"fail"
};
static uschar *csa_reason_string[] = {
- US"unknown",
- US"ok",
- US"deferred (SRV lookup failed)",
- US"deferred (target address lookup failed)",
- US"failed (explicit authorization required)",
- US"failed (host name not authorized)",
- US"failed (no authorized addresses)",
- US"failed (client address mismatch)"
+ [CSA_UNKNOWN] = US"unknown",
+ [CSA_OK] = US"ok",
+ [CSA_DEFER_SRV] = US"deferred (SRV lookup failed)",
+ [CSA_DEFER_ADDR] = US"deferred (target address lookup failed)",
+ [CSA_FAIL_EXPLICIT] = US"failed (explicit authorization required)",
+ [CSA_FAIL_DOMAIN] = US"failed (host name not authorized)",
+ [CSA_FAIL_NOADDR] = US"failed (no authorized addresses)",
+ [CSA_FAIL_MISMATCH] = US"failed (client address mismatch)"
};
/* Options for the ratelimit condition. Note that there are two variants of
(((var) == RATE_PER_WHAT) ? ((var) = RATE_##new) : ((var) = RATE_PER_CLASH))
static uschar *ratelimit_option_string[] = {
- US"?", US"!", US"per_addr", US"per_byte", US"per_cmd",
- US"per_conn", US"per_mail", US"per_rcpt", US"per_rcpt"
+ [RATE_PER_WHAT] = US"?",
+ [RATE_PER_CLASH] = US"!",
+ [RATE_PER_ADDR] = US"per_addr",
+ [RATE_PER_BYTE] = US"per_byte",
+ [RATE_PER_CMD] = US"per_cmd",
+ [RATE_PER_CONN] = US"per_conn",
+ [RATE_PER_MAIL] = US"per_mail",
+ [RATE_PER_RCPT] = US"per_rcpt",
+ [RATE_PER_ALLRCPTS] = US"per_rcpt"
};
/* Enable recursion between acl_check_internal() and acl_check_condition() */
-static int acl_check_wargs(int, address_item *, const uschar *, int, uschar **,
+static int acl_check_wargs(int, address_item *, const uschar *, uschar **,
uschar **);
uschar *
fn_hdrs_added(void)
{
-uschar * ret = NULL;
-int size = 0;
-int ptr = 0;
+gstring * g = NULL;
header_line * h = acl_added_headers;
uschar * s;
uschar * cp;
if (cp[1] == '\0') break;
/* contains embedded newline; needs doubling */
- ret = string_catn(ret, &size, &ptr, s, cp-s+1);
- ret = string_catn(ret, &size, &ptr, US"\n", 1);
+ g = string_catn(g, s, cp-s+1);
+ g = string_catn(g, US"\n", 1);
s = cp+1;
}
/* last bit of header */
- ret = string_catn(ret, &size, &ptr, s, cp-s+1); /* newline-sep list */
+/*XXX could we use add_listele? */
+ g = string_catn(g, s, cp-s+1); /* newline-sep list */
}
while((h = h->next));
-ret[ptr-1] = '\0'; /* overwrite last newline */
-return ret;
+g->s[g->ptr - 1] = '\0'; /* overwrite last newline */
+return g->s;
}
int length = Ustrlen(text) + 1;
log_write(0, LOG_MAIN, "%s", text);
logged = store_malloc(sizeof(string_item) + length);
- logged->text = (uschar *)logged + sizeof(string_item);
+ logged->text = US logged + sizeof(string_item);
memcpy(logged->text, text, length);
logged->next = acl_warn_logged;
acl_warn_logged = logged;
/* Need to do a lookup */
HDEBUG(D_acl)
- debug_printf("looking up host name to force name/address consistency check\n");
+ debug_printf_indent("looking up host name to force name/address consistency check\n");
if ((rc = host_name_lookup()) != OK)
{
{
/* If the client IP address matches the target IP address, it's good! */
- DEBUG(D_acl) debug_printf("CSA target address is %s\n", da->address);
+ DEBUG(D_acl) debug_printf_indent("CSA target address is %s\n", da->address);
if (strcmpic(sender_host_address, da->address) == 0) return CSA_OK;
}
GETSHORT(port, p);
DEBUG(D_acl)
- debug_printf("CSA priority=%d weight=%d port=%d\n", priority, weight, port);
+ debug_printf_indent("CSA priority=%d weight=%d port=%d\n", priority, weight, port);
/* Check the CSA version number */
(void)dn_expand(dnsa.answer, dnsa.answer + dnsa.answerlen, p,
(DN_EXPAND_ARG4_TYPE)target, sizeof(target));
- DEBUG(D_acl) debug_printf("CSA target is %s\n", target);
+ DEBUG(D_acl) debug_printf_indent("CSA target is %s\n", target);
break;
}
unsigned alt_opt_sep; /* >0 Non-/ option separator (custom parser) */
} verify_type_t;
static verify_type_t verify_type_list[] = {
+ /* name value where no-opt opt-sep */
{ 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 },
enum { CALLOUT_DEFER_OK, CALLOUT_NOCACHE, CALLOUT_RANDOM, CALLOUT_USE_SENDER,
CALLOUT_USE_POSTMASTER, CALLOUT_POSTMASTER, CALLOUT_FULLPOSTMASTER,
CALLOUT_MAILFROM, CALLOUT_POSTMASTER_MAILFROM, CALLOUT_MAXWAIT, CALLOUT_CONNECT,
- CALLOUT_TIME
+ CALLOUT_HOLD, CALLOUT_TIME /* TIME must be last */
};
typedef struct {
uschar * name;
BOOL timeval; /* Has a time value */
} callout_opt_t;
static callout_opt_t callout_opt_list[] = {
+ /* name value flag has-opt has-time */
{ US"defer_ok", CALLOUT_DEFER_OK, 0, FALSE, FALSE },
{ US"no_cache", CALLOUT_NOCACHE, vopt_callout_no_cache, FALSE, FALSE },
{ US"random", CALLOUT_RANDOM, vopt_callout_random, FALSE, FALSE },
{ US"mailfrom", CALLOUT_MAILFROM, 0, TRUE, FALSE },
{ US"maxwait", CALLOUT_MAXWAIT, 0, TRUE, TRUE },
{ US"connect", CALLOUT_CONNECT, 0, TRUE, TRUE },
+ { US"hold", CALLOUT_HOLD, vopt_callout_hold, FALSE, FALSE },
{ NULL, CALLOUT_TIME, 0, FALSE, TRUE }
};
/* Handle name/address consistency verification in a separate function. */
for (vp= verify_type_list;
- (char *)vp < (char *)verify_type_list + sizeof(verify_type_list);
+ CS vp < CS verify_type_list + sizeof(verify_type_list);
vp++
)
if (vp->alt_opt_sep ? strncmpic(ss, vp->name, vp->alt_opt_sep) == 0
: strcmpic (ss, vp->name) == 0)
break;
-if ((char *)vp >= (char *)verify_type_list + sizeof(verify_type_list))
+if (CS vp >= CS verify_type_list + sizeof(verify_type_list))
goto BAD_VERIFY;
if (vp->no_options && slash != NULL)
*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);
+ DEBUG(D_acl) debug_printf_indent("CSA result %s\n", csa_status);
return csa_return_code[rc];
case VERIFY_HDR_SYNTAX:
uschar buffer[256];
while (isspace(*sublist)) sublist++;
- while ((opt = string_nextinlist(&sublist, &optsep, buffer, sizeof(buffer)))
- != NULL)
+ while ((opt = string_nextinlist(&sublist, &optsep, buffer, sizeof(buffer))))
{
callout_opt_t * op;
double period = 1.0F;
}
while (isspace(*opt)) opt++;
}
- if (op->timeval)
+ if (op->timeval && (period = readconf_readtime(opt, 0, FALSE)) < 0)
{
- period = readconf_readtime(opt, 0, FALSE);
- if (period < 0)
- {
- *log_msgptr = string_sprintf("bad time value in ACL condition "
- "\"verify %s\"", arg);
- return ERROR;
- }
+ *log_msgptr = string_sprintf("bad time value in ACL condition "
+ "\"verify %s\"", arg);
+ return ERROR;
}
switch(op->value)
rc = sender_vaddr->special_action;
*basic_errno = sender_vaddr->basic_errno;
}
- HDEBUG(D_acl) debug_printf("using cached sender verify result\n");
+ HDEBUG(D_acl) debug_printf_indent("using cached sender verify result\n");
}
/* Do a new verification, and cache the result. The cache is used to avoid
rc = verify_address(sender_vaddr, NULL, verify_options, callout,
callout_overall, callout_connect, se_mailfrom, pm_mailfrom, &routed);
- HDEBUG(D_acl) debug_printf("----------- end verify ------------\n");
+ HDEBUG(D_acl) debug_printf_indent("----------- end verify ------------\n");
if (rc != OK)
*basic_errno = sender_vaddr->basic_errno;
DEBUG(D_acl)
{
if (Ustrcmp(sender_vaddr->address, verify_sender_address) != 0)
- debug_printf("sender %s verified ok as %s\n",
+ debug_printf_indent("sender %s verified ok as %s\n",
verify_sender_address, sender_vaddr->address);
else
- debug_printf("sender %s verified ok\n",
+ debug_printf_indent("sender %s verified ok\n",
verify_sender_address);
}
}
addr2 = *addr;
rc = verify_address(&addr2, NULL, verify_options|vopt_is_recipient, callout,
callout_overall, callout_connect, se_mailfrom, pm_mailfrom, NULL);
- HDEBUG(D_acl) debug_printf("----------- end verify ------------\n");
+ HDEBUG(D_acl) debug_printf_indent("----------- end verify ------------\n");
*basic_errno = addr2.basic_errno;
*log_msgptr = addr2.message;
if (rc == DEFER && (defer_ok ||
(callout_defer_ok && *basic_errno == ERRNO_CALLOUTDEFER)))
{
- HDEBUG(D_acl) debug_printf("verify defer overridden by %s\n",
+ HDEBUG(D_acl) debug_printf_indent("verify defer overridden by %s\n",
defer_ok? "defer_ok" : "callout_defer_ok");
rc = OK;
}
key);
HDEBUG(D_acl)
- debug_printf("ratelimit condition count=%.0f %.1f/%s\n", count, limit, key);
+ debug_printf_indent("ratelimit condition count=%.0f %.1f/%s\n", count, limit, key);
/* See if we have already computed the rate by looking in the relevant tree.
For per-connection rate limiting, store tree nodes and dbdata in the permanent
store_pool = old_pool;
sender_rate = string_sprintf("%.1f", dbd->rate);
HDEBUG(D_acl)
- debug_printf("ratelimit found pre-computed rate %s\n", sender_rate);
+ debug_printf_indent("ratelimit found pre-computed rate %s\n", sender_rate);
return rc;
}
/* We aren't using a pre-computed rate, so get a previously recorded rate
from the database, which will be updated and written back if required. */
-dbm = dbfn_open(US"ratelimit", O_RDWR, &dbblock, TRUE);
-if (dbm == NULL)
+if (!(dbm = dbfn_open(US"ratelimit", O_RDWR, &dbblock, TRUE)))
{
store_pool = old_pool;
sender_rate = NULL;
- HDEBUG(D_acl) debug_printf("ratelimit database not available\n");
+ HDEBUG(D_acl) debug_printf_indent("ratelimit database not available\n");
*log_msgptr = US"ratelimit database not available";
return DEFER;
}
if (dbdb != NULL)
{
/* Locate the basic ratelimit block inside the DB data. */
- HDEBUG(D_acl) debug_printf("ratelimit found key in database\n");
+ HDEBUG(D_acl) debug_printf_indent("ratelimit found key in database\n");
dbd = &dbdb->dbd;
/* Forget the old Bloom filter if it is too old, so that we count each
if(unique != NULL && tv.tv_sec > dbdb->bloom_epoch + period)
{
- HDEBUG(D_acl) debug_printf("ratelimit discarding old Bloom filter\n");
+ HDEBUG(D_acl) debug_printf_indent("ratelimit discarding old Bloom filter\n");
dbdb = NULL;
}
if(unique != NULL && dbdb_size < sizeof(*dbdb))
{
- HDEBUG(D_acl) debug_printf("ratelimit discarding undersize Bloom filter\n");
+ HDEBUG(D_acl) debug_printf_indent("ratelimit discarding undersize Bloom filter\n");
dbdb = NULL;
}
}
if (unique == NULL)
{
/* No Bloom filter. This basic ratelimit block is initialized below. */
- HDEBUG(D_acl) debug_printf("ratelimit creating new rate data block\n");
+ HDEBUG(D_acl) debug_printf_indent("ratelimit creating new rate data block\n");
dbdb_size = sizeof(*dbd);
dbdb = store_get(dbdb_size);
}
else
{
int extra;
- HDEBUG(D_acl) debug_printf("ratelimit creating new Bloom filter\n");
+ HDEBUG(D_acl) debug_printf_indent("ratelimit creating new Bloom filter\n");
/* See the long comment below for an explanation of the magic number 2.
The filter has a minimum size in case the rate limit is very small;
/* Scan the bits corresponding to this event. A zero bit means we have
not seen it before. Ensure all bits are set to record this event. */
- HDEBUG(D_acl) debug_printf("ratelimit checking uniqueness of %s\n", unique);
+ HDEBUG(D_acl) debug_printf_indent("ratelimit checking uniqueness of %s\n", unique);
seen = TRUE;
for (n = 0; n < 8; n++, hash += hinc)
if (seen)
{
- HDEBUG(D_acl) debug_printf("ratelimit event found in Bloom filter\n");
+ HDEBUG(D_acl) debug_printf_indent("ratelimit event found in Bloom filter\n");
count = 0.0;
}
else
- HDEBUG(D_acl) debug_printf("ratelimit event added to Bloom filter\n");
+ HDEBUG(D_acl) debug_printf_indent("ratelimit event added to Bloom filter\n");
}
/* If there was no previous ratelimit data block for this key, initialize
if (dbd == NULL)
{
- HDEBUG(D_acl) debug_printf("ratelimit initializing new key's rate data\n");
+ HDEBUG(D_acl) debug_printf_indent("ratelimit initializing new key's rate data\n");
dbd = &dbdb->dbd;
dbd->time_stamp = tv.tv_sec;
dbd->time_usec = tv.tv_usec;
if ((rc == FAIL && leaky) || strict)
{
dbfn_write(dbm, key, dbdb, dbdb_size);
- HDEBUG(D_acl) debug_printf("ratelimit db updated\n");
+ HDEBUG(D_acl) debug_printf_indent("ratelimit db updated\n");
}
else
{
- HDEBUG(D_acl) debug_printf("ratelimit db not updated: %s\n",
+ HDEBUG(D_acl) debug_printf_indent("ratelimit db not updated: %s\n",
readonly? "readonly mode" : "over the limit, but leaky");
}
sender_rate = string_sprintf("%.1f", dbd->rate);
HDEBUG(D_acl)
- debug_printf("ratelimit computed rate %s\n", sender_rate);
+ debug_printf_indent("ratelimit computed rate %s\n", sender_rate);
return rc;
}
}
HDEBUG(D_acl)
- debug_printf("udpsend [%s]:%d %s\n", h->address, portnum, arg);
+ debug_printf_indent("udpsend [%s]:%d %s\n", h->address, portnum, arg);
+/*XXX this could better use sendto */
r = s = ip_connectedsocket(SOCK_DGRAM, h->address, portnum, portnum,
- 1, NULL, &errstr);
+ 1, NULL, &errstr, NULL);
if (r < 0) goto defer;
len = Ustrlen(arg);
r = send(s, arg, len, 0);
}
HDEBUG(D_acl)
- debug_printf("udpsend %d bytes\n", r);
+ debug_printf_indent("udpsend %d bytes\n", r);
return OK;
if (cb->type == ACLC_MESSAGE)
{
- HDEBUG(D_acl) debug_printf(" message: %s\n", cb->arg);
+ HDEBUG(D_acl) debug_printf_indent(" 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);
+ HDEBUG(D_acl) debug_printf_indent("l_message: %s\n", cb->arg);
log_message = cb->arg;
continue;
}
HDEBUG(D_acl)
{
int lhswidth = 0;
- debug_printf("check %s%s %n",
+ debug_printf_indent("check %s%s %n",
(!conditions[cb->type].is_modifier && cb->u.negated)? "!":"",
conditions[cb->type].name, &lhswidth);
"discard" verb. */
case ACLC_ACL:
- rc = acl_check_wargs(where, addr, arg, level+1, user_msgptr, log_msgptr);
+ rc = acl_check_wargs(where, addr, arg, user_msgptr, log_msgptr);
if (rc == DISCARD && verb != ACL_ACCEPT && verb != ACL_DISCARD)
{
*log_msgptr = string_sprintf("nested ACL returned \"discard\" for "
if (af < 0)
{
HDEBUG(D_acl)
- debug_printf("smtp input is probably not a socket [%s], not setting DSCP\n",
+ debug_printf_indent("smtp input is probably not a socket [%s], not setting DSCP\n",
strerror(errno));
break;
}
{
if (setsockopt(fd, level, optname, &value, sizeof(value)) < 0)
{
- HDEBUG(D_acl) debug_printf("failed to set input DSCP[%s]: %s\n",
+ HDEBUG(D_acl) debug_printf_indent("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);
+ HDEBUG(D_acl) debug_printf_indent("set input DSCP to \"%s\"\n", p+1);
}
}
else
break;
case CONTROL_FAKEREJECT:
- cancel_cutthrough_connection("fakereject");
+ cancel_cutthrough_connection(TRUE, US"fakereject");
case CONTROL_FAKEDEFER:
fake_response = (control_type == CONTROL_FAKEDEFER) ? DEFER : FAIL;
if (*p == '/')
*log_msgptr = string_sprintf("syntax error in \"control=%s\"", arg);
return ERROR;
}
- cancel_cutthrough_connection("item frozen");
+ cancel_cutthrough_connection(TRUE, US"item frozen");
break;
case CONTROL_QUEUE_ONLY:
queue_only_policy = TRUE;
- cancel_cutthrough_connection("queueing forced");
+ cancel_cutthrough_connection(TRUE, US"queueing forced");
break;
case CONTROL_SUBMISSION:
}
else
{
- HDEBUG(D_acl) debug_printf("delay modifier requests %d-second delay\n",
+ HDEBUG(D_acl) debug_printf_indent("delay modifier requests %d-second delay\n",
delay);
if (host_checking)
{
HDEBUG(D_acl)
- debug_printf("delay skipped in -bh checking mode\n");
+ debug_printf_indent("delay skipped in -bh checking mode\n");
}
/* NOTE 1: Remember that we may be
n = 1;
}
if (poll(&p, n, delay*1000) > 0)
- HDEBUG(D_acl) debug_printf("delay cancelled by peer close\n");
+ HDEBUG(D_acl) debug_printf_indent("delay cancelled by peer close\n");
}
#else
/* It appears to be impossible to detect that a TCP/IP connection has
break;
case ACLC_RECIPIENTS:
- rc = match_address_list((const uschar *)addr->address, TRUE, TRUE, &arg, NULL, -1, 0,
+ rc = match_address_list(CUS addr->address, TRUE, TRUE, &arg, NULL, -1, 0,
CUSS &recipient_data);
break;
{
uschar *sdomain;
sdomain = Ustrrchr(sender_address, '@');
- sdomain = (sdomain == NULL)? US"" : sdomain + 1;
+ sdomain = sdomain ? sdomain + 1 : US"";
rc = match_isinlist(sdomain, &arg, 0, &domainlist_anchor,
sender_domain_cache, MCL_DOMAIN, TRUE, NULL);
}
break;
case ACLC_SENDERS:
- rc = match_address_list((const uschar *)sender_address, TRUE, TRUE, &arg,
+ rc = match_address_list(CUS sender_address, TRUE, TRUE, &arg,
sender_address_cache, -1, 0, CUSS &sender_data);
break;
where where called from
addr address item when called from RCPT; otherwise NULL
s the input string; NULL is the same as an empty ACL => DENY
- level the nesting level
user_msgptr where to put a user error (for SMTP response)
log_msgptr where to put a logging message (not for SMTP response)
*/
static int
-acl_check_internal(int where, address_item *addr, uschar *s, int level,
+acl_check_internal(int where, address_item *addr, uschar *s,
uschar **user_msgptr, uschar **log_msgptr)
{
int fd = -1;
/* Catch configuration loops */
-if (level > 20)
+if (acl_level > 20)
{
*log_msgptr = US"ACL nested too deep: possible loop";
return ERROR;
}
-if (s == NULL)
+if (!s)
{
- HDEBUG(D_acl) debug_printf("ACL is NULL: implicit DENY\n");
+ HDEBUG(D_acl) debug_printf_indent("ACL is NULL: implicit DENY\n");
return FAIL;
}
/* At top level, we expand the incoming string. At lower levels, it has already
been expanded as part of condition processing. */
-if (level == 0)
+if (acl_level == 0)
{
- ss = expand_string(s);
- if (ss == NULL)
+ if (!(ss = expand_string(s)))
{
if (expand_string_forcedfail) return OK;
*log_msgptr = string_sprintf("failed to expand ACL string \"%s\": %s", s,
}
else ss = s;
-while (isspace(*ss))ss++;
+while (isspace(*ss)) ss++;
/* If we can't find a named ACL, the default is to parse it as an inline one.
(Unless it begins with a slash; non-existent files give rise to an error.) */
acl = (acl_block *)(t->data.ptr);
if (acl == NULL)
{
- HDEBUG(D_acl) debug_printf("ACL \"%s\" is empty: implicit DENY\n", ss);
+ HDEBUG(D_acl) debug_printf_indent("ACL \"%s\" is empty: implicit DENY\n", ss);
return FAIL;
}
acl_name = string_sprintf("ACL \"%s\"", ss);
- HDEBUG(D_acl) debug_printf("using ACL \"%s\"\n", ss);
+ HDEBUG(D_acl) debug_printf_indent("using ACL \"%s\"\n", ss);
}
else if (*ss == '/')
(void)close(fd);
acl_name = string_sprintf("ACL \"%s\"", ss);
- HDEBUG(D_acl) debug_printf("read ACL from file %s\n", ss);
+ HDEBUG(D_acl) debug_printf_indent("read ACL from file %s\n", ss);
}
}
int cond;
int basic_errno = 0;
BOOL endpass_seen = FALSE;
- BOOL acl_quit_check = level == 0
+ BOOL acl_quit_check = acl_level == 0
&& (where == ACL_WHERE_QUIT || where == ACL_WHERE_NOTQUIT);
*log_msgptr = *user_msgptr = NULL;
acl_temp_details = FALSE;
- HDEBUG(D_acl) debug_printf("processing \"%s\"\n", verbs[acl->verb]);
+ HDEBUG(D_acl) debug_printf_indent("processing \"%s\"\n", verbs[acl->verb]);
/* Clear out any search error message from a previous check before testing
this condition. */
search_error_message = NULL;
- cond = acl_check_condition(acl->verb, acl->condition, where, addr, level,
+ cond = acl_check_condition(acl->verb, acl->condition, where, addr, acl_level,
&endpass_seen, user_msgptr, log_msgptr, &basic_errno);
/* Handle special returns: DEFER causes a return except on a WARN verb;
switch (cond)
{
case DEFER:
- HDEBUG(D_acl) debug_printf("%s: condition test deferred in %s\n", verbs[acl->verb], acl_name);
+ HDEBUG(D_acl) debug_printf_indent("%s: condition test deferred in %s\n", verbs[acl->verb], acl_name);
if (basic_errno != ERRNO_CALLOUTDEFER)
{
if (search_error_message != NULL && *search_error_message != 0)
default: /* Paranoia */
case ERROR:
- HDEBUG(D_acl) debug_printf("%s: condition test error in %s\n", verbs[acl->verb], acl_name);
+ HDEBUG(D_acl) debug_printf_indent("%s: condition test error in %s\n", verbs[acl->verb], acl_name);
return ERROR;
case OK:
- HDEBUG(D_acl) debug_printf("%s: condition test succeeded in %s\n",
+ HDEBUG(D_acl) debug_printf_indent("%s: condition test succeeded in %s\n",
verbs[acl->verb], acl_name);
break;
case FAIL:
- HDEBUG(D_acl) debug_printf("%s: condition test failed in %s\n", verbs[acl->verb], acl_name);
+ HDEBUG(D_acl) debug_printf_indent("%s: condition test failed in %s\n", verbs[acl->verb], acl_name);
break;
/* DISCARD and DROP can happen only from a nested ACL condition, and
DISCARD can happen only for an "accept" or "discard" verb. */
case DISCARD:
- HDEBUG(D_acl) debug_printf("%s: condition test yielded \"discard\" in %s\n",
+ HDEBUG(D_acl) debug_printf_indent("%s: condition test yielded \"discard\" in %s\n",
verbs[acl->verb], acl_name);
break;
case FAIL_DROP:
- HDEBUG(D_acl) debug_printf("%s: condition test yielded \"drop\" in %s\n",
+ HDEBUG(D_acl) debug_printf_indent("%s: condition test yielded \"drop\" in %s\n",
verbs[acl->verb], acl_name);
break;
}
case ACL_ACCEPT:
if (cond == OK || cond == DISCARD)
{
- HDEBUG(D_acl) debug_printf("end of %s: ACCEPT\n", acl_name);
+ HDEBUG(D_acl) debug_printf_indent("end of %s: ACCEPT\n", acl_name);
return cond;
}
if (endpass_seen)
{
- HDEBUG(D_acl) debug_printf("accept: endpass encountered - denying access\n");
+ HDEBUG(D_acl) debug_printf_indent("accept: endpass encountered - denying access\n");
return cond;
}
break;
case ACL_DEFER:
if (cond == OK)
{
- HDEBUG(D_acl) debug_printf("end of %s: DEFER\n", acl_name);
+ HDEBUG(D_acl) debug_printf_indent("end of %s: DEFER\n", acl_name);
if (acl_quit_check) goto badquit;
acl_temp_details = TRUE;
return DEFER;
case ACL_DENY:
if (cond == OK)
{
- HDEBUG(D_acl) debug_printf("end of %s: DENY\n", acl_name);
+ HDEBUG(D_acl) debug_printf_indent("end of %s: DENY\n", acl_name);
if (acl_quit_check) goto badquit;
return FAIL;
}
case ACL_DISCARD:
if (cond == OK || cond == DISCARD)
{
- HDEBUG(D_acl) debug_printf("end of %s: DISCARD\n", acl_name);
+ HDEBUG(D_acl) debug_printf_indent("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");
+ HDEBUG(D_acl) debug_printf_indent("discard: endpass encountered - denying access\n");
return cond;
}
break;
case ACL_DROP:
if (cond == OK)
{
- HDEBUG(D_acl) debug_printf("end of %s: DROP\n", acl_name);
+ HDEBUG(D_acl) debug_printf_indent("end of %s: DROP\n", acl_name);
if (acl_quit_check) goto badquit;
return FAIL_DROP;
}
case ACL_REQUIRE:
if (cond != OK)
{
- HDEBUG(D_acl) debug_printf("end of %s: not OK\n", acl_name);
+ HDEBUG(D_acl) debug_printf_indent("end of %s: not OK\n", acl_name);
if (acl_quit_check) goto badquit;
return cond;
}
/* We have reached the end of the ACL. This is an implicit DENY. */
-HDEBUG(D_acl) debug_printf("end of %s: implicit DENY\n", acl_name);
+HDEBUG(D_acl) debug_printf_indent("end of %s: implicit DENY\n", acl_name);
return FAIL;
badquit:
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, const uschar *s, int level,
+acl_check_wargs(int where, address_item *addr, const uschar *s,
uschar **user_msgptr, uschar **log_msgptr)
{
uschar * tmp;
acl_arg[i++] = NULL;
}
-ret = acl_check_internal(where, addr, name, level, user_msgptr, log_msgptr);
+acl_level++;
+ret = acl_check_internal(where, addr, name, user_msgptr, log_msgptr);
+acl_level--;
acl_narg = sav_narg;
for (i = 0; i < 9; i++) acl_arg[i] = sav_arg[i];
{
address_item adb;
address_item *addr = NULL;
+int rc;
*user_msgptr = *log_msgptr = NULL;
sender_verified_failed = NULL;
addr->lc_local_part = deliver_localpart;
}
-return acl_check_internal(where, addr, s, 0, user_msgptr, log_msgptr);
+acl_level++;
+rc = acl_check_internal(where, addr, s, user_msgptr, log_msgptr);
+acl_level--;
+return rc;
}
}
acl_where = where;
-rc = acl_check_internal(where, addr, s, 0, user_msgptr, log_msgptr);
+acl_level = 0;
+rc = acl_check_internal(where, addr, s, user_msgptr, log_msgptr);
+acl_level = 0;
acl_where = ACL_WHERE_UNKNOWN;
/* Cutthrough - if requested,
#ifndef DISABLE_PRDR
case ACL_WHERE_PRDR:
#endif
+
if (host_checking_callout) /* -bhc mode */
- cancel_cutthrough_connection("host-checking mode");
+ cancel_cutthrough_connection(TRUE, US"host-checking mode");
else if ( rc == OK
&& cutthrough.delivery
if (*--s && isdigit(*s) && *--s && isdigit(*s)) *user_msgptr = s;
acl_temp_details = TRUE;
}
- else
+ else
{
- HDEBUG(D_acl) debug_printf("cutthrough defer; will spool\n");
+ HDEBUG(D_acl) debug_printf_indent("cutthrough defer; will spool\n");
rc = OK;
}
break;
if (rc == OK)
cutthrough_predata();
else
- cancel_cutthrough_connection("predata acl not ok");
+ cancel_cutthrough_connection(TRUE, US"predata acl not ok");
break;
case ACL_WHERE_QUIT:
case ACL_WHERE_NOTQUIT:
- cancel_cutthrough_connection("quit or notquit");
+ /* Drop cutthrough conns, and drop heldopen verify conns if
+ the previous was not DATA */
+ {
+ uschar prev = smtp_connection_had[smtp_ch_index-2];
+ BOOL dropverify = !(prev == SCH_DATA || prev == SCH_BDAT);
+
+ cancel_cutthrough_connection(dropverify, US"quit or conndrop");
break;
+ }
default:
break;
*/
tree_node *
-acl_var_create(uschar *name)
+acl_var_create(uschar * name)
{
-tree_node *node, **root;
-root = (name[0] == 'c')? &acl_var_c : &acl_var_m;
-node = tree_search(*root, name);
-if (node == NULL)
+tree_node * node, ** root = name[0] == 'c' ? &acl_var_c : &acl_var_m;
+if (!(node = tree_search(*root, name)))
{
node = store_get(sizeof(tree_node) + Ustrlen(name));
Ustrcpy(node->name, name);