date. Snapshots change only the release date, unless they include
the same bugfixes as a patch release.
+Incompatible changes with Postfix snapshot 2.0.16-20031203
+==========================================================
+
+Many SMTPD reject logfile entries now show NOQUEUE instead of a
+queue ID. This is because Postfix no longer creates queue file
+before the SMTP server has received a valid recipient.
+
+The experimental XADDR and XLOGINFO extensions to SMTP are now
+replaced by XCLIENT.
+
+Major changes with Postfix snapshot 2.0.16-20031203
+===================================================
+
+The XCLIENT extension to SMTP replaces the short-lived XADDR and
+XLOGINFO extensions. Details are given in the XCLIENT_README file.
+
+XCLIENT supports the following features:
+
+- SMTPD access rule testing. Send "xclient override client_name=xxx
+client_addr=yyy" in SMTP sessions and pretend that you are sending
+mail as the specified client.
+
+- Remote client information forwarding through a content filter to
+improve logging by down-stream mail software. Send "xclient forward
+client_name=xxx client_addr=yyy client_proto=aaa client_helo=bbb"
+to specify the original client information that should be logged
+and stored with the next MAIL FROM transaction.
+
Incompatible changes with Postfix snapshot 2.0.16-20031111
==========================================================
The demo greylist policy server is now case insensitive.
+The demo greylist policy server now uses BTREE files which greatly
+improves stability.
+
Major changes with Postfix snapshot 2.0.16-20031111
===================================================
/*
* Check the queue file space, if applicable.
*/
-#define USE_SMTPD_PROXY(state) \
- (SMTPD_STAND_ALONE(state) == 0 && *var_smtpd_proxy_filt)
-
if (!USE_SMTPD_PROXY(state)) {
if ((err = smtpd_check_size(state, state->msg_size)) != 0) {
smtpd_chat_reply(state, "%s", err);
myfree(state->verp_delims);
state->verp_delims = 0;
}
+ if (state->proxy_mail) {
+ myfree(state->proxy_mail);
+ state->proxy_mail = 0;
+ }
+ if (state->saved_filter) {
+ myfree(state->saved_filter);
+ state->saved_filter = 0;
+ }
+ if (state->saved_redirect) {
+ myfree(state->saved_redirect);
+ state->saved_redirect = 0;
+ }
+ state->saved_flags = 0;
#ifdef USE_SASL_AUTH
if (var_smtpd_sasl_enable)
smtpd_sasl_mail_reset(state);
(void) smtpd_proxy_cmd(state, SMTPD_PROX_WANT_NONE, "QUIT");
smtpd_proxy_close(state);
}
- if (state->proxy_mail) {
- myfree(state->proxy_mail);
- state->proxy_mail = 0;
- }
if (state->xclient.used)
smtpd_xclient_reset(state);
}
}
/*
+ * Flush out any access table actions that are delegated to the cleanup
+ * server, and that may trigger before we accept the first valid
+ * recipient.
+ *
* Terminate the message envelope segment. Start the message content
* segment, and prepend our own Received: header. If there is only one
* recipient, list the recipient address.
* Suppress our own Received: header in the unlikely case that we are an
* intermediate proxy.
*/
- if (state->cleanup)
+ if (state->cleanup) {
+ if (state->saved_filter)
+ rec_fprintf(state->cleanup, REC_TYPE_FILT, "%s", state->saved_filter);
+ if (state->saved_redirect)
+ rec_fprintf(state->cleanup, REC_TYPE_RDR, "%s", state->saved_redirect);
+ if (state->saved_flags)
+ rec_fprintf(state->cleanup, REC_TYPE_FLGS, "%d", state->saved_flags);
rec_fputs(state->cleanup, REC_TYPE_MESG, "");
+ }
if (!state->proxy || state->xclient.used == 0) {
out_fprintf(out_stream, REC_TYPE_NORM,
"Received: from %s (%s [%s])",
*/
#define STR vstring_str
#define CONST_STR(x) ((const char *) vstring_str(x))
+#define UPDATE_STRING(ptr,val) { if (ptr) myfree(ptr); ptr = mystrdup(val); }
/*
* If some decision can't be made due to a temporary error, then change
return (rqst_status);
}
-/* warn_skip_access_action - FILTER etc. action in unsupported context */
+/* can_delegate_action - can we delegate this to the cleanup server */
+
+#ifndef TEST
-static void warn_skip_access_action(const char *table, const char *action,
- const char *reply_class)
+static int can_delegate_action(SMTPD_STATE *state, 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 we're not using the cleanup server, then there is no way that we
+ * can support actions such as FILTER or HOLD that are delegated to the
+ * cleanup server.
*/
- 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);
+ if (USE_SMTPD_PROXY(state)) {
+ msg_warn("access table %s: with %s specified, action %s is unavailable",
+ table, VAR_SMTPD_PROXY_FILT, action);
+ return (0);
+ }
+
+ /*
+ * If delay_reject=no, then client and helo restrictions take effect
+ * immediately, outside any particular mail transaction context. For
+ * example, rejecting HELO does not affect subsequent mail deliveries.
+ * Thus, if delay_reject=no, client and helo actions such as FILTER or
+ * HOLD also should not affect subsequent mail deliveries. Hmm...
+ */
+ if (var_smtpd_delay_reject == 0
+ && (strcmp(reply_class, SMTPD_NAME_CLIENT) == 0
+ || strcmp(reply_class, SMTPD_NAME_HELO) == 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);
+ return (0);
}
+ return (1);
}
+#endif
+
/* check_table_result - translate table lookup result into pass/reject */
static int check_table_result(SMTPD_STATE *state, const char *table,
*/
if (STREQUAL(value, "FILTER", cmd_len)) {
#ifndef TEST
- if (state->dest == 0) {
- warn_skip_access_action(table, "FILTER", reply_class);
+ if (can_delegate_action(state, table, "FILTER", reply_class) == 0)
return (SMTPD_CHECK_DUNNO);
- }
#endif
if (*cmd_text == 0) {
msg_warn("access map %s entry \"%s\" has FILTER entry without value",
reply_name, reply_class, cmd_text);
log_whatsup(state, "filter", STR(error_text));
#ifndef TEST
- rec_fprintf(state->dest->stream, REC_TYPE_FILT, "%s", cmd_text);
+ UPDATE_STRING(state->saved_filter, cmd_text);
#endif
return (SMTPD_CHECK_DUNNO);
}
*/
if (STREQUAL(value, "HOLD", cmd_len)) {
#ifndef TEST
- if (state->dest == 0) {
- warn_skip_access_action(table, "HOLD", reply_class);
+ if (can_delegate_action(state, table, "HOLD", reply_class) == 0)
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));
#ifndef TEST
- rec_fprintf(state->dest->stream, REC_TYPE_FLGS, "%d",
- CLEANUP_FLAG_HOLD);
+ state->saved_flags |= CLEANUP_FLAG_HOLD;
#endif
return (SMTPD_CHECK_DUNNO);
}
*/
if (STREQUAL(value, "DISCARD", cmd_len)) {
#ifndef TEST
- if (state->dest == 0) {
- warn_skip_access_action(table, "DISCARD", reply_class);
+ if (can_delegate_action(state, table, "DISCARD", reply_class) == 0)
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));
#ifndef TEST
- rec_fprintf(state->dest->stream, REC_TYPE_FLGS, "%d",
- CLEANUP_FLAG_DISCARD);
+ state->saved_flags |= CLEANUP_FLAG_DISCARD;
state->discard = 1;
#endif
return (SMTPD_CHECK_OK);
*/
if (STREQUAL(value, "REDIRECT", cmd_len)) {
#ifndef TEST
- if (state->dest == 0) {
- warn_skip_access_action(table, "REDIRECT", reply_class);
+ if (can_delegate_action(state, table, "REDIRECT", reply_class) == 0)
return (SMTPD_CHECK_DUNNO);
- }
#endif
if (strchr(cmd_text, '@') == 0) {
msg_warn("access map %s entry \"%s\" requires user@domain target",
reply_name, reply_class, cmd_text);
log_whatsup(state, "redirect", STR(error_text));
#ifndef TEST
- rec_fprintf(state->dest->stream, REC_TYPE_RDR, "%s", cmd_text);
+ UPDATE_STRING(state->saved_redirect, cmd_text);
#endif
return (SMTPD_CHECK_DUNNO);
}
*/
case 4:
case 3:
-#define UPDATE_STRING(ptr,val) { if (ptr) myfree(ptr); ptr = mystrdup(val); }
-
if (strcasecmp(args->argv[0], "client") == 0) {
state.where = "CONNECT";
UPDATE_STRING(state.name, args->argv[1]);