-TSINK_STATE
-TSMTPD_CMD
-TSMTPD_DEFER
--TSMTPD_MSG_ACTION
-TSMTPD_RBL_EXPAND_CONTEXT
-TSMTPD_RBL_STATE
-TSMTPD_STATE
systems against exploitation of the remote buffer overflow
vulnerability described in CERT advisory CA-2003-07.
-20030311-17
+20030311-19
Bugfix: the access map actions HOLD, DISCARD, FILTER and
- REDIRECT were broken with smtpd_delay_reject=no. This
- required re-architecting of the actions code. Files:
- smtpd/smtpd.[hc], smtpd/smtpd_check.c, smtpd/smtpd_state.c.
+ REDIRECT were broken with smtpd_delay_reject=no and with
+ ETRN. This required re-architecting of the actions code.
+ Files: smtpd/smtpd.[hc], smtpd/smtpd_check.c, smtpd/smtpd_state.c.
20030315
for non-existent addresses. This required re-architecting
the recipient table lookup code. File: smtpd/smtpd_check.c.
+20030319
+
+ Feature: configurable limit on virtual alias expansion size
+ and nesting depth, via the virtual_alias_expansion_limit
+ and virtual_alias_recursion_limit parameters. The default
+ limits are compatible with past Postfix versions. Victor
+ Duchovni, Morgan Stanley. Files: /sample-resource.cf,
+ html/resource.html, cleanup/cleanup.c, cleanup/cleanup_init.c,
+ cleanup/cleanup_map1n.c.
+
+ Feature: the installation procedure records build information
+ (by default: in /etc/postfix/makedefs.out).
+
Open problems:
Med: make qmgr recipient bounce/defer activity asynchronous
$(MAKE) -f Makefile.in Makefile MAKELEVEL=) || exit 1; \
done;
rm -f Makefile; (set -e; $(SHELL) makedefs && cat Makefile.in) >Makefile
+ (echo "# Do not edit -- this file documents how Postfix was built for your machine."; $(SHELL) makedefs) >makedefs.tmp
+ set +e; if cmp makedefs.tmp conf/makedefs.out; then rm makedefs.tmp; \
+ else mv makedefs.tmp conf/makedefs.out; fi >/dev/null 2>/dev/null
update printfck tests:
set -e; for i in $(DIRS); do \
$config_directory/canonical:f:root:-:644:p
$config_directory/main.cf:f:root:-:644:p
$config_directory/main.cf.default:f:root:-:644
+$config_directory/makedefs.out:f:root:-:644
$config_directory/master.cf:f:root:-:644:p
$config_directory/pcre_table:f:root:-:644:p
$config_directory/postfix-files:f:root:-:644
#
duplicate_filter_limit = 1000
+# The virtual_alias_expansion_limit parameter limits the number of
+# addresses that virtual expansion produces from each original recipient.
+#
+virtual_alias_expansion_limit = 1000
+
+# The virtual_alias_recursion_limit parameter limits the nesting depth of
+# virtual expansion. Currently the recursion limit is applied only to the
+# left branch of the expansion graph, so the depth of the tree can in the
+# worst case reach the sum of the expansion and recursion limits.
+# This may change in the future.
+#
+virtual_alias_recursion_limit = 1000
+
# The fork_attempts parameter limits the number of attempts to
# fork() a process.
#
Limit the amount of recipients extracted from mes-
sage headers.
+ <b>virtual</b><i>_</i><b>alias</b><i>_</i><b>expansion</b><i>_</i><b>limit</b>
+ Limit the number of actual recipients produced by
+ virtual alias expansion from each original recipi-
+ ent.
+
+ <b>virtual</b><i>_</i><b>alias</b><i>_</i><b>recursion</b><i>_</i><b>limit</b>
+ Limit the recursion depth of virtual alias expan-
+ sion.
+
<b>SEE</b> <b>ALSO</b>
<a href="canonical.5.html">canonical(5)</a> canonical address lookup table format
<a href="qmgr.8.html">qmgr(8)</a> queue manager daemon
/etc/postfix/virtual*, virtual mapping table
<b>LICENSE</b>
- The Secure Mailer license must be distributed with this
+ The Secure Mailer license must be distributed with this
software.
<b>AUTHOR(S)</b>
daemon remember when delivering a message. A recipient address is
ignored when it is found in the remembered list.
+<dt> <b>virtual_alias_expansion_limit</b> (default: 1000)
+
+<dd> This limits the number of addresses that result from each original
+recipient by virtual alias expansion in the <a href="cleanup.8.html">
+address cleanup</a> daemon. By default each original recipient is rewritten
+via <b>$virtual_alias_maps</b> to at most 1000 actual recipients.
+
+<dt> <b>virtual_alias_recursion_limit</b> (default: 1000)
+
+<dd> This limits the recursive nesting of virtual alias expansion performed
+by the <a href="cleanup.8.html">address cleanup</a> daemon. Virtual
+alias expansion is recursive, and stops only when an address is not
+found in the table, when an address maps to itself, or when the
+recursion limit is reached.
+
</dl>
<a name="time"><h2> Time limits</h2> </a>
message arrival rate exceeds the message delivery rate.
.IP \fBextract_recipient_limit\fR
Limit the amount of recipients extracted from message headers.
+.IP \fBvirtual_alias_expansion_limit\fR
+Limit the number of actual recipients produced by virtual alias
+expansion from each original recipient.
+.IP \fBvirtual_alias_recursion_limit\fR
+Limit the recursion depth of virtual alias expansion.
.SH SEE ALSO
.na
.nf
/* message arrival rate exceeds the message delivery rate.
/* .IP \fBextract_recipient_limit\fR
/* Limit the amount of recipients extracted from message headers.
+/* .IP \fBvirtual_alias_expansion_limit\fR
+/* Limit the number of actual recipients produced by virtual alias
+/* expansion from each original recipient.
+/* .IP \fBvirtual_alias_recursion_limit\fR
+/* Limit the recursion depth of virtual alias expansion.
/* SEE ALSO
/* canonical(5) canonical address lookup table format
/* qmgr(8) queue manager daemon
char *var_rcpt_witheld; /* recipients not disclosed */
char *var_masq_classes; /* what to masquerade */
int var_qattr_count_limit; /* named attribute limit */
+int var_virt_recur_limit; /* maximum virtual alias recursion */
+int var_virt_expan_limit; /* maximum virtual alias expansion */
int var_body_check_len; /* when to stop body scan */
CONFIG_INT_TABLE cleanup_int_table[] = {
VAR_DUP_FILTER_LIMIT, DEF_DUP_FILTER_LIMIT, &var_dup_filter_limit, 0, 0,
VAR_EXTRA_RCPT_LIMIT, DEF_EXTRA_RCPT_LIMIT, &var_extra_rcpt_limit, 0, 0,
VAR_QATTR_COUNT_LIMIT, DEF_QATTR_COUNT_LIMIT, &var_qattr_count_limit, 1, 0,
+ VAR_VIRT_RECUR_LIMIT, DEF_VIRT_RECUR_LIMIT, &var_virt_recur_limit, 1, 0,
+ VAR_VIRT_EXPAN_LIMIT, DEF_VIRT_EXPAN_LIMIT, &var_virt_expan_limit, 1, 0,
VAR_BODY_CHECK_LEN, DEF_BODY_CHECK_LEN, &var_body_check_len, 0, 0,
0,
};
/* Global library. */
+#include <mail_params.h>
#include <mail_addr_map.h>
#include <cleanup_user.h>
#include <quote_822_local.h>
* pointer.
*/
#define UPDATE(ptr,new) { myfree(ptr); ptr = mystrdup(new); }
-#define MAX_RECURSION 1000
-#define MAX_EXPANSION 1000
#define STR vstring_str
#define RETURN(x) { been_here_free(been_here); return (x); }
for (arg = 0; arg < argv->argc; arg++) {
- if (argv->argc > MAX_EXPANSION) {
+ if (argv->argc > var_virt_expan_limit) {
msg_warn("%s: unreasonable %s map expansion size for %s",
state->queue_id, maps->title, addr);
break;
*/
if (been_here_check_fixed(been_here, argv->argv[arg]) != 0)
break;
- if (count >= MAX_RECURSION) {
+ if (count >= var_virt_recur_limit) {
msg_warn("%s: unreasonable %s map nesting for %s",
state->queue_id, maps->title, addr);
break;
#define DEF_EXTRA_RCPT_LIMIT 10240
extern int var_extra_rcpt_limit;
+#define VAR_VIRT_RECUR_LIMIT "virtual_alias_recursion_limit"
+#define DEF_VIRT_RECUR_LIMIT 1000
+extern int var_virt_recur_limit;
+
+#define VAR_VIRT_EXPAN_LIMIT "virtual_alias_expansion_limit"
+#define DEF_VIRT_EXPAN_LIMIT 1000
+extern int var_virt_expan_limit;
+
/*
* Message/queue size limits.
*/
* Patches change the patchlevel and the release date. Snapshots change the
* release date only, unless they include the same bugfix as a patch release.
*/
-#define MAIL_RELEASE_DATE "20030317"
+#define MAIL_RELEASE_DATE "20030319"
#define VAR_MAIL_VERSION "mail_version"
#define DEF_MAIL_VERSION "2.0.7-" MAIL_RELEASE_DATE
smtpd_chat_reply(state, "501 Syntax: HELO hostname");
return (-1);
}
- if (state->helo_name != 0)
- helo_reset(state);
if (argc > 2)
collapse_args(argc - 1, argv + 1);
if (SMTPD_STAND_ALONE(state) == 0
smtpd_chat_reply(state, "%s", err);
return (-1);
}
+ if (state->helo_name != 0)
+ helo_reset(state);
chat_reset(state, var_smtpd_hist_thrsh);
mail_reset(state);
rcpt_reset(state);
smtpd_chat_reply(state, "501 Syntax: EHLO hostname");
return (-1);
}
- if (state->helo_name != 0)
- helo_reset(state);
if (argc > 2)
collapse_args(argc - 1, argv + 1);
if (SMTPD_STAND_ALONE(state) == 0
smtpd_chat_reply(state, "%s", err);
return (-1);
}
+ if (state->helo_name != 0)
+ helo_reset(state);
chat_reset(state, var_smtpd_hist_thrsh);
mail_reset(state);
rcpt_reset(state);
if (state->helo_name)
myfree(state->helo_name);
state->helo_name = 0;
-
- /*
- * With smtpd_delay_reject=yes, smtpd_helo_restrictions is evaluated at
- * RCPT TO time, and may be evaluated multiple times per message.
- * Per-message smtpd_helo_restrictions side effects (HOLD, DISCARD, etc.)
- * accumulate from one evaluation to the next, and may also depend on
- * client, sender or recipient information. Therefore, any per-message
- * helo restriction side effects need to be reset at the end of a mail
- * delivery transaction.
- *
- * With smtpd_delay_reject=no, smtpd_helo_restrictions is evaluated when
- * HELO/EHLO is issued, and its per-message side effects change only when
- * another HELO/EHLO command is issued. Therefore, any per-message helo
- * restriction side effects must be reset before smtpd_helo_restrictions
- * is evaluated.
- */
- if (var_smtpd_delay_reject == 0) {
- SMTPD_MSG_ACT_FREE(state->action_helo);
- SMTPD_MSG_ACT_ZERO(state->action_helo);
- }
}
/* mail_open_stream - open mail destination */
if (var_smtpd_sasl_enable)
smtpd_sasl_mail_reset(state);
#endif
-
- /*
- * With smtpd_delay_reject=yes, smtpd_sender_restrictions is evaluated at
- * RCPT TO time, and may be evaluated multiple times per message.
- * Per-message smtpd_sender_restrictions side effects (HOLD, DISCARD,
- * etc.) accumulate from one evaluation to the next, and may also depend
- * on client, helo or recipient information.
- *
- * The action_mailrcpt member accumulates both sender and recipient side
- * effects. It needs to be reset after each mail delivery, whether or not
- * it is actually completed.
- */
- SMTPD_MSG_ACT_FREE(state->action_mailrcpt);
- SMTPD_MSG_ACT_ZERO(state->action_mailrcpt);
+ state->discard = 0;
}
/* rcpt_cmd - process RCPT TO command */
state->recipient = 0;
}
state->rcpt_count = 0;
-
- /*
- * With smtpd_delay_reject=yes, smtpd_{client,helo}_restrictions are
- * evaluated at RCPT TO time. They may be evaluated multiple times per
- * message delivery. Per-message {client,helo} restriction side effects
- * (HOLD, DISCARD, etc.) accumulate from one evaluation to the next, and
- * the result may also depend on sender or recipient information.
- * Therefore, per-message {client,helo} restriction side effects need to
- * be reset between deliveries.
- *
- * With smtpd_delay_reject=no, smtpd_{client,helo}_restrictions are
- * evaluated once and take effect over multiple deliveries. Therefore,
- * their per-message side effects must not be reset between deliveries.
- */
- if (var_smtpd_delay_reject) {
- SMTPD_MSG_ACT_FREE(state->action_client);
- SMTPD_MSG_ACT_ZERO(state->action_client);
- SMTPD_MSG_ACT_FREE(state->action_helo);
- SMTPD_MSG_ACT_ZERO(state->action_helo);
- }
}
/* data_cmd - process DATA command */
int first = 1;
VSTRING *why = 0;
int saved_err;
- char *act_value;
/*
* Sanity checks. With ESMTP command pipelining the client can send DATA
*/
if (*var_always_bcc)
rec_fputs(state->cleanup, REC_TYPE_RCPT, var_always_bcc);
- if (SMTPD_MSG_ACT_FLAGS(state) & SMTPD_MSG_ACT_DISCARD) {
- rec_fprintf(state->dest->stream, REC_TYPE_FLGS, "%d",
- CLEANUP_FLAG_DISCARD);
- } else {
- if (SMTPD_MSG_ACT_FLAGS(state) & SMTPD_MSG_ACT_HOLD)
- rec_fprintf(state->cleanup, REC_TYPE_FLGS, "%d",
- CLEANUP_FLAG_HOLD);
- if ((act_value = SMTPD_MSG_ACT_VALUE(state, filter)) != 0)
- rec_fprintf(state->dest->stream, REC_TYPE_FILT, "%s", act_value);
- if ((act_value = SMTPD_MSG_ACT_VALUE(state, redirect)) != 0)
- rec_fprintf(state->dest->stream, REC_TYPE_RDR, "%s", act_value);
- }
rec_fputs(state->cleanup, REC_TYPE_MESG, "");
rec_fprintf(state->cleanup, REC_TYPE_NORM,
"Received: from %s (%s [%s])",
return (-1);
}
if (SMTPD_STAND_ALONE(state) == 0
- && (err = smtpd_check_vrfy(state, argv[1].strval)) != 0) {
+ && (err = smtpd_check_rcpt(state, argv[1].strval)) != 0) {
smtpd_chat_reply(state, "%s", err);
return (-1);
}
int class; /* error notification class */
} SMTPD_DEFER;
- /*
- * Actions that affect all recipients of a given message. That is, we don't
- * "undo" results from one recipient when evaluating the next recipient.
- */
-typedef struct SMTPD_MSG_ACTION {
- int flags; /* see below */
- char *filter; /* filter destination */
- char *redirect; /* redirect destination */
-} SMTPD_MSG_ACTION;
-
-#define SMTPD_MSG_ACT_HOLD (1<<0) /* place message on hold */
-#define SMTPD_MSG_ACT_DISCARD (1<<1) /* discard message */
-#define SMTPD_MSG_ACT_FILTER (1<<2) /* filter message */
-#define SMTPD_MSG_ACT_REDIRECT (1<<3) /* redirect message */
-
- /*
- * Short-hand for when to stop searching restriction lists.
- */
-#define SMTPD_MSG_ACT_FINAL (SMTPD_MSG_ACT_DISCARD)
-
-#define SMTPD_MSG_ACT_ZERO(a) do { \
- (a).flags = 0; \
- (a).filter = 0; \
- (a).redirect = 0; \
- } while (0)
-
-#define SMTPD_MSG_ACT_FREE(a) do { \
- if ((a).filter) myfree((a).filter); \
- if ((a).redirect) myfree((a).redirect); \
- } while (0)
-
-#define SMTPD_MSG_ACT_COPY(d, s) do { \
- SMTPD_MSG_ACT_FREE(d); \
- (d).filter = ((s).filter ? mystrdup((s).filter) : 0); \
- (d).redirect = ((s).redirect ? mystrdup((s).redirect) : 0); \
- } while (0)
-
typedef struct SMTPD_STATE {
int err;
VSTREAM *client;
VSTRING *sasl_encoded;
VSTRING *sasl_decoded;
#endif
- SMTPD_MSG_ACTION *action; /* action from access map */
- SMTPD_MSG_ACTION action_client; /* action after connect */
- SMTPD_MSG_ACTION action_helo; /* action after helo/ehlo */
- SMTPD_MSG_ACTION action_mailrcpt; /* action after mail from/rcpt to */
int rcptmap_checked;
int warn_if_reject; /* force reject into warning */
SMTPD_DEFER defer_if_reject; /* force reject into deferral */
int defer_if_permit_client; /* force permit into warning */
int defer_if_permit_helo; /* force permit into warning */
int defer_if_permit_sender; /* force permit into warning */
+ int discard; /* discard message */
VSTRING *expand_buf; /* scratch space for $name expansion */
} SMTPD_STATE;
-#define SMTPD_MSG_ACT_FLAGS(s) \
- ((s)->action_client.flags | (s)->action_helo.flags \
- | (s)->action_mailrcpt.flags)
-
-#define SMTPD_MSG_ACT_VALUE(s,m) \
- ((s)->action_mailrcpt.m ? (s)->action_mailrcpt.m : \
- (s)->action_helo.m ? (s)->action_helo.m : \
- (s)->action_client.m)
-
extern void smtpd_state_init(SMTPD_STATE *, VSTREAM *);
extern void smtpd_state_reset(SMTPD_STATE *);
/* SMTPD_STATE *state;
/* char *recipient;
/*
-/* char *smtpd_check_vrfy(state, recipient)
-/* SMTPD_STATE *state;
-/* char *recipient;
-/*
/* char *smtpd_check_etrn(state, destination)
/* SMTPD_STATE *state;
/* char *destination;
/* Tables of user names (not addresses) that exist in $mydestination.
/* Mail for local users not in these tables is rejected.
/* .PP
-/* smtpd_check_vrfy() validates the recipient address provided
-/* with a VRFY request. Relevant configuration parameters:
-/* .IP local_recipient_maps
-/* Tables of user names (not addresses) that exist in $mydestination.
-/* Mail for local users not in these tables is rejected.
-/* .PP
/* smtpd_check_etrn() validates the domain name provided with the
/* ETRN command, and other client-provided information. Relevant
/* configuration parameters:
return (rqst_status);
}
+/* warn_skip_access_action - FILTER etc. action in unsupported context */
+
+static void warn_skip_access_action(const char *table, const char *action,
+ const char *reply_class)
+{
+
+ /*
+ * Warn only about FILTER/HOLD/etc. access table actions that appear in
+ * restrictions where they will always be ignored.
+ */
+ if (strcmp(reply_class, SMTPD_NAME_CLIENT) == 0
+ || strcmp(reply_class, SMTPD_NAME_HELO) == 0
+ || strcmp(reply_class, SMTPD_NAME_SENDER) == 0) {
+ if (var_smtpd_delay_reject == 0)
+ msg_warn("access table %s: with %s=%s, "
+ "action %s is always skipped in %s restrictions",
+ table, VAR_SMTPD_DELAY_REJECT, CONFIG_BOOL_NO,
+ action, reply_class);
+ } else {
+ msg_warn("access table %s: action %s is always "
+ "skipped in %s restrictions",
+ table, action, reply_class);
+ }
+}
+
/* check_table_result - translate table lookup result into pass/reject */
static int check_table_result(SMTPD_STATE *state, const char *table,
* mind, and reject/discard the message for other reasons.
*/
if (STREQUAL(value, "FILTER", cmd_len)) {
- if (state->action == 0)
+#ifndef TEST
+ if (state->dest == 0) {
+ warn_skip_access_action(table, "FILTER", reply_class);
return (SMTPD_CHECK_DUNNO);
+ }
+#endif
if (*cmd_text == 0) {
msg_warn("access map %s entry \"%s\" has FILTER entry without value",
table, datum);
vstring_sprintf(error_text, "<%s>: %s triggers FILTER %s",
reply_name, reply_class, cmd_text);
log_whatsup(state, "filter", STR(error_text));
- state->action->flags |= SMTPD_MSG_ACT_FILTER;
- if (state->action->filter)
- myfree(state->action->filter);
- state->action->filter = mystrdup(cmd_text);
+#ifndef TEST
+ rec_fprintf(state->dest->stream, REC_TYPE_FILT, "%s", cmd_text);
+#endif
return (SMTPD_CHECK_DUNNO);
}
}
* reject/discard the message for other reasons.
*/
if (STREQUAL(value, "HOLD", cmd_len)) {
- if (state->action == 0)
+#ifndef TEST
+ if (state->dest == 0) {
+ warn_skip_access_action(table, "HOLD", reply_class);
return (SMTPD_CHECK_DUNNO);
+ }
+#endif
vstring_sprintf(error_text, "<%s>: %s %s", reply_name, reply_class,
*cmd_text ? cmd_text : "triggers HOLD action");
log_whatsup(state, "hold", STR(error_text));
- state->action->flags |= SMTPD_MSG_ACT_HOLD;
+#ifndef TEST
+ rec_fprintf(state->dest->stream, REC_TYPE_FLGS, "%d",
+ CLEANUP_FLAG_HOLD);
+#endif
return (SMTPD_CHECK_DUNNO);
}
* DISCARD means silently discard and claim successful delivery.
*/
if (STREQUAL(value, "DISCARD", cmd_len)) {
- if (state->action == 0)
+#ifndef TEST
+ if (state->dest == 0) {
+ warn_skip_access_action(table, "DISCARD", reply_class);
return (SMTPD_CHECK_DUNNO);
+ }
+#endif
vstring_sprintf(error_text, "<%s>: %s %s", reply_name, reply_class,
*cmd_text ? cmd_text : "triggers DISCARD action");
log_whatsup(state, "discard", STR(error_text));
- state->action->flags |= SMTPD_MSG_ACT_DISCARD;
+#ifndef TEST
+ rec_fprintf(state->dest->stream, REC_TYPE_FLGS, "%d",
+ CLEANUP_FLAG_DISCARD);
+ state->discard = 1;
+#endif
return (SMTPD_CHECK_OK);
}
* change our mind, and reject/discard the message for other reasons.
*/
if (STREQUAL(value, "REDIRECT", cmd_len)) {
- if (state->action == 0)
+#ifndef TEST
+ if (state->dest == 0) {
+ warn_skip_access_action(table, "REDIRECT", reply_class);
return (SMTPD_CHECK_DUNNO);
+ }
+#endif
if (strchr(cmd_text, '@') == 0) {
msg_warn("access map %s entry \"%s\" requires user@domain target",
table, datum);
vstring_sprintf(error_text, "<%s>: %s triggers REDIRECT %s",
reply_name, reply_class, cmd_text);
log_whatsup(state, "redirect", STR(error_text));
- state->action->flags |= SMTPD_MSG_ACT_REDIRECT;
- if (state->action->redirect)
- myfree(state->action->redirect);
- state->action->redirect = mystrdup(cmd_text);
+#ifndef TEST
+ rec_fprintf(state->dest->stream, REC_TYPE_RDR, "%s", cmd_text);
+#endif
return (SMTPD_CHECK_DUNNO);
}
}
for (cpp = restrictions->argv; (name = *cpp) != 0; cpp++) {
- if (state->action && SMTPD_MSG_ACT_FLAGS(state) & SMTPD_MSG_ACT_FINAL)
+ if (state->discard != 0)
break;
if (msg_verbose)
*/
state->defer_if_permit.active = 0;
- /*
- * With smtpd_delay_reject=yes, smtpd_client_restrictions is evaluated at
- * RCPT TO time, and may be evaluated multiple times. Per-message side
- * effects (HOLD, DISCARD, etc.) accumulate from one evaluation to the
- * next, and may also depend on helo, sender or recipient information.
- *
- * With smtpd_delay_reject=no, smtpd_{client,helo}_restrictions are
- * evaluated immediately, and HELO may be given multiple times. The same
- * {client,helo} per-message side effects (HOLD, DISCARD, etc.) apply to
- * multiple deliveries. Therefore, we need separate per-message side
- * effect storage for client, helo, and for sender+recipients.
- */
- state->action = &state->action_client;
-
/*
* Apply restrictions in the order as specified.
*/
*/
state->defer_if_permit.active = state->defer_if_permit_client;
- /*
- * With smtpd_delay_reject=yes, smtpd_helo_restrictions is evaluated at
- * RCPT TO time, and may be evaluated multiple times. Per-message side
- * effects (HOLD, DISCARD, etc.) accumulate from one evaluation to the
- * next, and may also depend on sender or recipient information.
- *
- * With smtpd_delay_reject=no, smtpd_{client,helo}_restrictions are
- * evaluated immediately, and HELO may be given multiple times. The same
- * {client,helo} per-message side effects (HOLD, DISCARD, etc.) apply to
- * multiple deliveries. Therefore, we need separate per-message side
- * effect storage for client, helo, and for sender+recipients.
- */
- state->action = &state->action_helo;
-
/*
* Apply restrictions in the order as specified.
*/
state->defer_if_permit.active = state->defer_if_permit_client
| state->defer_if_permit_helo;
- /*
- * With smtpd_delay_reject=yes, smtpd_sender_restrictions is evaluated at
- * RCPT TO time, and may be evaluated multiple times. Per-message side
- * effects (HOLD, DISCARD, etc.) accumulate from one evaluation to the
- * next, and may also depend on client, helo or recipient information.
- */
- state->action = &state->action_mailrcpt;
-
/*
* Apply restrictions in the order as specified.
*/
/*
* The "check_recipient_maps" restriction is relevant only when
- * responding to RCPT TO. It's effectively disabled with DATA (recipient
- * context is explicitly turned off) and not applicable with undelayed
- * client/helo/sender restrictions (no recipient info) or with ETRN
- * (command not allowed in the middle of an ongoing MAIL transaction).
+ * responding to RCPT TO or VRFY.
*/
state->rcptmap_checked = 0;
*/
state->defer_if_permit.active = state->defer_if_permit_sender;
- /*
- * Per-message side effects (HOLD, DISCARD, etc.) accumulate from one
- * recipient to the next, and may also depend on client, helo or sender
- * information.
- */
- state->action = &state->action_mailrcpt;
-
/*
* Apply restrictions in the order as specified.
*/
* If the "check_recipient_maps" restriction was not applied, and if mail
* is not being rejected or discarded, validate the recipient here.
*/
- if (status == 0 && state->rcptmap_checked == 0
- && (SMTPD_MSG_ACT_FLAGS(state) & SMTPD_MSG_ACT_FINAL) == 0)
+ if (status != SMTPD_CHECK_REJECT && state->rcptmap_checked == 0
+ && state->discard == 0)
status = check_rcpt_maps(state, recipient);
SMTPD_CHECK_RCPT_RETURN(status == SMTPD_CHECK_REJECT ? STR(error_text) : 0);
state->defer_if_permit.active = state->defer_if_permit_client
| state->defer_if_permit_helo;
- /*
- * HOLD, DISCARD, FILTER, etc. are meaningless.
- */
- state->action = 0;
-
/*
* Apply restrictions in the order as specified.
*/
SMTPD_CHECK_ETRN_RETURN(status == SMTPD_CHECK_REJECT ? STR(error_text) : 0);
}
-/* smtpd_check_vrfy - permit if recipient address matches lookup table */
-
-char *smtpd_check_vrfy(SMTPD_STATE *state, char *recipient)
-{
- char *myname = "smtpd_check_vrfy";
- int status;
-
- if (msg_verbose)
- msg_info("%s: %s", myname, recipient);
-
- /*
- * Return here in case of serious trouble.
- */
- SMTPD_CHECK_RESET();
- if ((status = setjmp(smtpd_check_buf)) == 0)
- status = check_rcpt_maps(state, recipient);
-
- return (status == SMTPD_CHECK_REJECT ? STR(error_text) : 0);
-}
-
/* check_rcpt_maps - generic_checks() interface for recipient table check */
static int check_rcpt_maps(SMTPD_STATE *state, const char *recipient)
{
const RESOLVE_REPLY *reply;
+ /*
+ * Duplicate suppression. There's an implicit check_recipient_maps
+ * restriction at the end of all recipient restrictions.
+ */
+ if (state->rcptmap_checked == 1)
+ return (0);
+ state->rcptmap_checked = 1;
+
/*
* Resolve the address.
*/
state.namaddr = concatenate(state.name, "[", state.addr,
"]", (char *) 0);
resp = smtpd_check_client(&state);
- SMTPD_MSG_ACT_FREE(state.action_client);
- SMTPD_MSG_ACT_ZERO(state.action_client);
}
break;
if (strcasecmp(args->argv[0], "helo") == 0) {
state.where = "HELO";
resp = smtpd_check_helo(&state, args->argv[1]);
- SMTPD_MSG_ACT_FREE(state.action_helo);
- SMTPD_MSG_ACT_ZERO(state.action_helo);
UPDATE_STRING(state.helo_name, args->argv[1]);
} else if (strcasecmp(args->argv[0], "mail") == 0) {
state.where = "MAIL";
TRIM_ADDR(args->argv[1], addr);
UPDATE_STRING(state.sender, addr);
resp = smtpd_check_mail(&state, addr);
- SMTPD_MSG_ACT_FREE(state.action_mailrcpt);
- SMTPD_MSG_ACT_ZERO(state.action_mailrcpt);
} else if (strcasecmp(args->argv[0], "rcpt") == 0) {
state.where = "RCPT";
TRIM_ADDR(args->argv[1], addr);
resp = smtpd_check_rcpt(&state, addr);
- SMTPD_MSG_ACT_FREE(state.action_mailrcpt);
- SMTPD_MSG_ACT_ZERO(state.action_mailrcpt);
}
break;
extern char *smtpd_check_client(SMTPD_STATE *);
extern char *smtpd_check_helo(SMTPD_STATE *, char *);
extern char *smtpd_check_mail(SMTPD_STATE *, char *);
-extern char *smtpd_check_vrfy(SMTPD_STATE *, char *);
extern char *smtpd_check_size(SMTPD_STATE *, off_t);
extern char *smtpd_check_rcpt(SMTPD_STATE *, char *);
extern char *smtpd_check_etrn(SMTPD_STATE *, char *);
state->recursion = 0;
state->msg_size = 0;
state->junk_cmds = 0;
- SMTPD_MSG_ACT_ZERO(state->action_client);
- SMTPD_MSG_ACT_ZERO(state->action_helo);
- SMTPD_MSG_ACT_ZERO(state->action_mailrcpt);
state->defer_if_permit_client = 0;
state->defer_if_permit_helo = 0;
state->defer_if_permit_sender = 0;
state->defer_if_reject.reason = 0;
state->defer_if_permit.reason = 0;
+ state->discard = 0;
state->expand_buf = 0;
#ifdef USE_SASL_AUTH
vstring_free(state->defer_if_reject.reason);
if (state->expand_buf)
vstring_free(state->expand_buf);
- SMTPD_MSG_ACT_FREE(state->action_client);
- SMTPD_MSG_ACT_FREE(state->action_helo);
- SMTPD_MSG_ACT_FREE(state->action_mailrcpt);
#ifdef USE_SASL_AUTH
if (var_smtpd_sasl_enable)