Cleanup: preserve multi-line format of header/body Milter
replies. Files: cleanup/cleanup_milter.c, smtpd/smtpd.c.
- Cleanup: nicer multi-line support in the SMTP server. File:
+ Cleanup: multi-line support in SMTP server replies. File:
smtpd/smtpd_chat.c.
SAFETY: postfix-script, postfix-files and post-install are
with an unusable Postfix setup. Files: postfix-install,
Makefile.in, postfix/postfix.c, conf/postfix-files,
conf/postfix-script, conf/post-install.
+
+20080212
+
+ Feature: check_reverse_client_access, to make access decisions
+ based on the unverified client hostname. For safety reasons
+ an OK result is not allowed. Noel Jones. Files:
+ smtpd/smtpd_check.c plus header files and documentation.
+
+20080215
+
+ Safety: break SASL loop in case both the SASL library and the
+ remote SMTP server are confused. File: smtp/smtp_sasl_glue.c.
$database_name="/var/mta/greylist.db";
$greylist_delay=60;
+#
+# Auto-whitelist threshold. Specify 0 to disable, or the number of
+# successful "come backs" after which a client is no longer subject
+# to greylisting.
+#
+$auto_whitelist_threshold = 10;
+
#
# Demo SMTPD access policy routine. The result is an action just like
# it would be specified on the right-hand side of a Postfix access
# Open the database on the fly.
open_database() unless $database_obj;
+ # Search the auto-whitelist.
+ if ($auto_whitelist_threshold > 0) {
+ $count = read_database($attr{"client_address"});
+ if ($count > $auto_whitelist_threshold) {
+ return "dunno";
+ }
+ }
+
# Lookup the time stamp for this client/sender/recipient.
$key =
lc $attr{"client_address"}."/".$attr{"sender"}."/".$attr{"recipient"};
#
syslog $syslog_priority, "request age %d", $now - $time_stamp if $verbose;
if ($now - $time_stamp > $greylist_delay) {
+ # Update the auto-whitelist.
+ if ($auto_whitelist_threshold > 0) {
+ update_database($attr{"client_address"}, $count + 1);
+ }
return "dunno";
} else {
return "defer_if_permit Service temporarily unavailable";
Wish list:
+ To support ternary operator without a huge parsing effort,
+ consider ${value?{xxx}:{yyy}} where ${name} is existing
+ syntax, and where ?{text} and :{text} are new syntax that
+ is unlikely to break existing configurations. Or perhaps
+ it's just too ugly.
+
Make adding Date/From/Message-ID headers dependent on local
- rewrite context?
+ rewrite context.
Write delivery rate delay example (which _README?) and auth
failure cache example (SASL_README). Then include them in
$queue_directory/pid:d:root:-:755:uc
$queue_directory/saved:d:$mail_owner:-:700:ucr
$queue_directory/trace:d:$mail_owner:-:700:ucr
-$daemon_directory/postfix-script:f:root:-:755
-$daemon_directory/postfix-files:f:root:-:644
-$daemon_directory/post-install:f:root:-:755
$daemon_directory/anvil:f:root:-:755
$daemon_directory/bounce:f:root:-:755
$daemon_directory/cleanup:f:root:-:755
$daemon_directory/oqmgr:f:root:-:755
$daemon_directory/pickup:f:root:-:755
$daemon_directory/pipe:f:root:-:755
+$daemon_directory/post-install:f:root:-:755
+$daemon_directory/postfix-files:f:root:-:644
+$daemon_directory/postfix-script:f:root:-:755
$daemon_directory/proxymap:f:root:-:755
$daemon_directory/qmgr:f:root:-:755
$daemon_directory/qmqpd:f:root:-:755
$database_name="/var/mta/greylist.db";
$greylist_delay=60;
+#
+# Auto-whitelist threshold. Specify 0 to disable, or the number of
+# successful "come backs" after which a client is no longer subject
+# to greylisting.
+#
+$auto_whitelist_threshold = 10;
+
#
# Demo SMTPD access policy routine. The result is an action just like
# it would be specified on the right-hand side of a Postfix access
# Open the database on the fly.
open_database() unless $database_obj;
+ # Search the auto-whitelist.
+ if ($auto_whitelist_threshold > 0) {
+ $count = read_database($attr{"client_address"});
+ if ($count > $auto_whitelist_threshold) {
+ return "dunno";
+ }
+ }
+
# Lookup the time stamp for this client/sender/recipient.
$key =
lc $attr{"client_address"}."/".$attr{"sender"}."/".$attr{"recipient"};
#
syslog $syslog_priority, "request age %d", $now - $time_stamp if $verbose;
if ($now - $time_stamp > $greylist_delay) {
+ # Update the auto-whitelist.
+ if ($auto_whitelist_threshold > 0) {
+ update_database($attr{"client_address"}, $count + 1);
+ }
return "dunno";
} else {
return "<a href="postconf.5.html#defer_if_permit">defer_if_permit</a> Service temporarily unavailable";
<li> a /file/name with domain names and/or <a href="postconf.5.html#relayhost">relay host</a> names as
defined above,
-<li> a "<a href="DATABASE_README.html">type:table</a>" with domain names and/or relay hosts name on
+<li> a "<a href="DATABASE_README.html">type:table</a>" with domain names and/or <a href="postconf.5.html#relayhost">relay host</a> names on
the left-hand side. The right-hand side result from "<a href="DATABASE_README.html">type:table</a>"
lookups is ignored.
parent domains, client IP address, or networks obtained by stripping
least significant octets. See the <a href="access.5.html">access(5)</a> manual page for details. </dd>
+<dt><b><a name="check_reverse_client_hostname_access">check_reverse_client_hostname_access</a> <i><a href="DATABASE_README.html">type:table</a></i></b></dt>
+
+<dd>Search the specified access database for the unverified reverse
+client hostname, parent domains, client IP address, or networks
+obtained by stripping least significant octets. See the <a href="access.5.html">access(5)</a>
+manual page for details. Note: a result of "OK" is not allowed for
+safety reasons. Instead, use DUNNO in order to exclude specific
+hosts from blacklists. This feature is available in Postfix 2.6
+and later.</dd>
+
<dt><b><a name="permit_inet_interfaces">permit_inet_interfaces</a></b></dt>
<dd>Permit the request when the client IP address matches
setting for an already installed Postfix system.
This feature is available in Postfix 2.1 and later.
- With Postfix 2.0 and earlier, use "<b>/etc/post-</b>
- <b>fix/post-install set-permissions</b>".
+ With Postfix 2.0 and earlier, use "<b>$<a href="postconf.5.html#config_directory">config_direc</a>-</b>
+ <b><a href="postconf.5.html#config_directory">tory</a>/post-install set-permissions</b>".
<b>upgrade-configuration [</b><i>name</i>=<i>value ...</i><b>]</b>
Update the <a href="postconf.5.html"><b>main.cf</b></a> and <a href="master.5.html"><b>master.cf</b></a> files with infor-
<a href="postconf.5.html">main.cf</a> configuration parameters.
This feature is available in Postfix 2.1 and later.
- With Postfix 2.0 and earlier, use "<b>/etc/post-</b>
- <b>fix/post-install upgrade-configuration</b>".
+ With Postfix 2.0 and earlier, use "<b>$<a href="postconf.5.html#config_directory">config_direc</a>-</b>
+ <b><a href="postconf.5.html#config_directory">tory</a>/post-install upgrade-configuration</b>".
The following options are implemented:
becomes, for example, "postfix/smtpd".
<b>FILES</b>
- /etc/postfix/<a href="postconf.5.html">main.cf</a>, Postfix configuration parameters
- /etc/postfix/<a href="master.5.html">master.cf</a>, Postfix daemon processes
+ Prior to Postfix version 2.6, all of the following files
+ were in <b>$<a href="postconf.5.html#config_directory">config_directory</a></b>. Some files are now in <b>$<a href="postconf.5.html#daemon_directory">dae</a>-</b>
+ <b><a href="postconf.5.html#daemon_directory">mon_directory</a></b> so that they can be shared among multiple
+ instances that run the same Postfix version.
+
+ Use the command "<b>postconf <a href="postconf.5.html#config_directory">config_directory</a></b>" or "<b>postconf</b>
+ <b><a href="postconf.5.html#daemon_directory">daemon_directory</a></b>" to expand the names into their actual
+ values.
+
+ $<a href="postconf.5.html#config_directory">config_directory</a>/<a href="postconf.5.html">main.cf</a>, Postfix configuration parameters
+ $<a href="postconf.5.html#config_directory">config_directory</a>/<a href="master.5.html">master.cf</a>, Postfix daemon processes
$<a href="postconf.5.html#daemon_directory">daemon_directory</a>/postfix-files, file/directory permissions
$<a href="postconf.5.html#daemon_directory">daemon_directory</a>/postfix-script, administrative commands
$<a href="postconf.5.html#daemon_directory">daemon_directory</a>/post-install, post-installation configuration
<a href="QSHAPE_README.html">QSHAPE_README</a>, Postfix queue analysis
<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>
already installed Postfix system.
.sp
This feature is available in Postfix 2.1 and later. With
-Postfix 2.0 and earlier, use "\fB/etc/postfix/post-install
+Postfix 2.0 and earlier, use "\fB$config_directory/post-install
set-permissions\fR".
.IP "\fBupgrade-configuration\fR \fB[\fIname\fR=\fIvalue ...\fB]\fR
Update the \fBmain.cf\fR and \fBmaster.cf\fR files with information
main.cf configuration parameters.
.sp
This feature is available in Postfix 2.1 and later. With
-Postfix 2.0 and earlier, use "\fB/etc/postfix/post-install
+Postfix 2.0 and earlier, use "\fB$config_directory/post-install
upgrade-configuration\fR".
.PP
The following options are implemented:
.SH "FILES"
.na
.nf
-/etc/postfix/main.cf, Postfix configuration parameters
-/etc/postfix/master.cf, Postfix daemon processes
+.ad
+.fi
+Prior to Postfix version 2.6, all of the following files
+were in \fB$config_directory\fR. Some files are now in
+\fB$daemon_directory\fR so that they can be shared among
+multiple instances that run the same Postfix version.
+
+Use the command "\fBpostconf config_directory\fR" or
+"\fBpostconf daemon_directory\fR" to expand the names
+into their actual values.
+.na
+.nf
+
+$config_directory/main.cf, Postfix configuration parameters
+$config_directory/master.cf, Postfix daemon processes
$daemon_directory/postfix-files, file/directory permissions
$daemon_directory/postfix-script, administrative commands
$daemon_directory/post-install, post-installation configuration
a /file/name with domain names and/or relay host names as
defined above,
.IP \(bu
-a "type:table" with domain names and/or relay hosts name on
+a "type:table" with domain names and/or relay host names on
the left-hand side. The right-hand side result from "type:table"
lookups is ignored.
.PP
Search the specified access database for the client hostname,
parent domains, client IP address, or networks obtained by stripping
least significant octets. See the \fBaccess\fR(5) manual page for details.
+.IP "\fBcheck_reverse_client_hostname_access \fItype:table\fR\fR"
+Search the specified access database for the unverified reverse
+client hostname, parent domains, client IP address, or networks
+obtained by stripping least significant octets. See the \fBaccess\fR(5)
+manual page for details. Note: a result of "OK" is not allowed for
+safety reasons. Instead, use DUNNO in order to exclude specific
+hosts from blacklists. This feature is available in Postfix 2.6
+and later.
.IP "\fBpermit_inet_interfaces\fR"
Permit the request when the client IP address matches
$inet_interfaces.
$database_name="/var/mta/greylist.db";
$greylist_delay=60;
+#
+# Auto-whitelist threshold. Specify 0 to disable, or the number of
+# successful "come backs" after which a client is no longer subject
+# to greylisting.
+#
+$auto_whitelist_threshold = 10;
+
#
# Demo SMTPD access policy routine. The result is an action just like
# it would be specified on the right-hand side of a Postfix access
# Open the database on the fly.
open_database() unless $database_obj;
+ # Search the auto-whitelist.
+ if ($auto_whitelist_threshold > 0) {
+ $count = read_database($attr{"client_address"});
+ if ($count > $auto_whitelist_threshold) {
+ return "dunno";
+ }
+ }
+
# Lookup the time stamp for this client/sender/recipient.
$key =
lc $attr{"client_address"}."/".$attr{"sender"}."/".$attr{"recipient"};
#
syslog $syslog_priority, "request age %d", $now - $time_stamp if $verbose;
if ($now - $time_stamp > $greylist_delay) {
+ # Update the auto-whitelist.
+ if ($auto_whitelist_threshold > 0) {
+ update_database($attr{"client_address"}, $count + 1);
+ }
return "dunno";
} else {
return "defer_if_permit Service temporarily unavailable";
<li> a /file/name with domain names and/or relay host names as
defined above,
-<li> a "type:table" with domain names and/or relay hosts name on
+<li> a "type:table" with domain names and/or relay host names on
the left-hand side. The right-hand side result from "type:table"
lookups is ignored.
parent domains, client IP address, or networks obtained by stripping
least significant octets. See the access(5) manual page for details. </dd>
+<dt><b><a name="check_reverse_client_hostname_access">check_reverse_client_hostname_access</a> <i><a href="DATABASE_README.html">type:table</a></i></b></dt>
+
+<dd>Search the specified access database for the unverified reverse
+client hostname, parent domains, client IP address, or networks
+obtained by stripping least significant octets. See the access(5)
+manual page for details. Note: a result of "OK" is not allowed for
+safety reasons. Instead, use DUNNO in order to exclude specific
+hosts from blacklists. This feature is available in Postfix 2.6
+and later.</dd>
+
<dt><b><a name="permit_inet_interfaces">permit_inet_interfaces</a></b></dt>
<dd>Permit the request when the client IP address matches
#define CLEANUP_FLAG_WARN_SEEN (1<<17) /* REC_TYPE_WARN record seen */
#define CLEANUP_FLAG_END_SEEN (1<<18) /* REC_TYPE_END record seen */
- /*
- * Milter replies.
- */
-#define CLEANUP_MILTER_REASON(__state, __reason) do { \
- if ((__state)->reason) \
- myfree((__state)->reason); \
- (__state)->reason = mystrdup(__reason); \
- if ((__state)->smtp_reply) { \
- myfree((__state)->smtp_reply); \
- (__state)->smtp_reply = 0; \
- } \
- } while (0)
-
-#define CLEANUP_MILTER_SMTP_REPLY(__state, __smtp_reply) do { \
- if ((__state)->reason) \
- myfree((__state)->reason); \
- (__state)->reason = mystrdup(__smtp_reply + 4); \
- printable((__state)->reason, '_'); \
- if ((__state)->smtp_reply) \
- myfree((__state)->smtp_reply); \
- (__state)->smtp_reply = mystrdup(__smtp_reply); \
- } while (0)
-
/*
* Mappings.
*/
#define STR(x) vstring_str(x)
#define LEN(x) VSTRING_LEN(x)
+ /*
+ * Milter replies.
+ */
+#define CLEANUP_MILTER_SET_REASON(__state, __reason) do { \
+ if ((__state)->reason) \
+ myfree((__state)->reason); \
+ (__state)->reason = mystrdup(__reason); \
+ if ((__state)->smtp_reply) { \
+ myfree((__state)->smtp_reply); \
+ (__state)->smtp_reply = 0; \
+ } \
+ } while (0)
+
+#define CLEANUP_MILTER_SET_SMTP_REPLY(__state, __smtp_reply) do { \
+ if ((__state)->reason) \
+ myfree((__state)->reason); \
+ (__state)->reason = mystrdup(__smtp_reply + 4); \
+ printable((__state)->reason, '_'); \
+ if ((__state)->smtp_reply) \
+ myfree((__state)->smtp_reply); \
+ (__state)->smtp_reply = mystrdup(__smtp_reply); \
+ } while (0)
+
/* cleanup_milter_set_error - set error flag from errno */
static void cleanup_milter_set_error(CLEANUP_STATE *state, int err)
* queue record processing, and prevents bounces from being sent.
*/
case '4':
- CLEANUP_MILTER_SMTP_REPLY(state, resp);
+ CLEANUP_MILTER_SET_SMTP_REPLY(state, resp);
ret = state->reason;
state->errs |= CLEANUP_STAT_DEFER;
action = "milter-reject";
text = resp + 4;
break;
case '5':
- CLEANUP_MILTER_SMTP_REPLY(state, resp);
+ CLEANUP_MILTER_SET_SMTP_REPLY(state, resp);
ret = state->reason;
state->errs |= CLEANUP_STAT_CONT;
action = "milter-reject";
msg_warn("%s: milter configuration error: can't reject recipient "
"in non-smtpd(8) submission", state->queue_id);
msg_warn("%s: deferring delivery of this message", state->queue_id);
- CLEANUP_MILTER_REASON(state, "4.3.5 Server configuration error");
+ CLEANUP_MILTER_SET_REASON(state, "4.3.5 Server configuration error");
state->errs |= CLEANUP_STAT_DEFER;
}
}
extern int var_access_map_code;
#define CHECK_CLIENT_ACL "check_client_access"
+#define CHECK_REVERSE_CLIENT_ACL "check_reverse_client_hostname_access"
#define CHECK_CCERT_ACL "check_ccert_access"
#define CHECK_HELO_ACL "check_helo_access"
#define CHECK_SENDER_ACL "check_sender_access"
* Patches change both the patchlevel and the release date. Snapshots have no
* patchlevel; they change the release date only.
*/
-#define MAIL_RELEASE_DATE "20080207"
+#define MAIL_RELEASE_DATE "20080216"
#define MAIL_VERSION_NUMBER "2.6"
#ifdef SNAPSHOT
break;
}
}
- for (cp = STR(milter->buf); /* void */ ; cp = next) {
- if (var_soft_bounce) {
+ if (var_soft_bounce) {
+ for (cp = STR(milter->buf); /* void */ ; cp = next) {
if (cp[0] == '5') {
cp[0] = '4';
if (cp[4] == '5')
cp[4] = '4';
}
+ if ((next = strstr(cp, "\r\n")) == 0)
+ break;
+ next += 2;
}
- if ((next = strstr(cp, "\r\n")) == 0)
- break;
- next += 2;
}
if (IN_CONNECT_EVENT(event)) {
#ifdef LIBMILTER_AUTO_DISCONNECT
/* already installed Postfix system.
/* .sp
/* This feature is available in Postfix 2.1 and later. With
-/* Postfix 2.0 and earlier, use "\fB/etc/postfix/post-install
+/* Postfix 2.0 and earlier, use "\fB$config_directory/post-install
/* set-permissions\fR".
/* .IP "\fBupgrade-configuration\fR \fB[\fIname\fR=\fIvalue ...\fB]\fR
/* Update the \fBmain.cf\fR and \fBmaster.cf\fR files with information
/* main.cf configuration parameters.
/* .sp
/* This feature is available in Postfix 2.1 and later. With
-/* Postfix 2.0 and earlier, use "\fB/etc/postfix/post-install
+/* Postfix 2.0 and earlier, use "\fB$config_directory/post-install
/* upgrade-configuration\fR".
/* .PP
/* The following options are implemented:
/* The mail system name that is prepended to the process name in syslog
/* records, so that "smtpd" becomes, for example, "postfix/smtpd".
/* FILES
-/* /etc/postfix/main.cf, Postfix configuration parameters
-/* /etc/postfix/master.cf, Postfix daemon processes
+/* .ad
+/* .fi
+/* Prior to Postfix version 2.6, all of the following files
+/* were in \fB$config_directory\fR. Some files are now in
+/* \fB$daemon_directory\fR so that they can be shared among
+/* multiple instances that run the same Postfix version.
+/*
+/* Use the command "\fBpostconf config_directory\fR" or
+/* "\fBpostconf daemon_directory\fR" to expand the names
+/* into their actual values.
+/* .na
+/* .nf
+/*
+/* $config_directory/main.cf, Postfix configuration parameters
+/* $config_directory/master.cf, Postfix daemon processes
/* $daemon_directory/postfix-files, file/directory permissions
/* $daemon_directory/postfix-script, administrative commands
/* $daemon_directory/post-install, post-installation configuration
const char *mechanism;
int result;
char *line;
+ int steps = 0;
/*
* Sanity check.
*/
while ((resp = smtp_chat_resp(session))->code / 100 == 3) {
+ /*
+ * Sanity check.
+ */
+ if (++steps > 100) {
+ dsb_simple(why, "4.3.0", "SASL authentication failed; "
+ "authentication protocol loop with server %s",
+ session->namaddr);
+ return (-1);
+ }
+
/*
* Process a server challenge.
*/
next = end;
}
smtp_chat_append(state, "Out: ", cp);
+
if (msg_verbose)
msg_info("> %s: %s", state->namaddr, cp);
if (strchr(name, ':') != 0) {
if (def_acl == NO_DEF_ACL) {
- msg_warn("specify one of (%s, %s, %s, %s, %s) before %s restriction \"%s\"",
- CHECK_CLIENT_ACL, CHECK_HELO_ACL, CHECK_SENDER_ACL,
+ msg_warn("specify one of (%s, %s, %s, %s, %s, %s) before %s restriction \"%s\"",
+ CHECK_CLIENT_ACL, CHECK_REVERSE_CLIENT_ACL, CHECK_HELO_ACL, CHECK_SENDER_ACL,
CHECK_RECIP_ACL, CHECK_ETRN_ACL, reply_class, name);
longjmp(smtpd_check_buf,
smtpd_check_reject(state, MAIL_ERROR_SOFTWARE,
status = check_namadr_access(state, *cpp, state->name, state->addr,
FULL, &found, state->namaddr,
SMTPD_NAME_CLIENT, def_acl);
+ } else if (is_map_command(state, name, CHECK_REVERSE_CLIENT_ACL, &cpp)) {
+ status = check_namadr_access(state, *cpp, state->reverse_name, state->addr,
+ FULL, &found, state->namaddr,
+ SMTPD_NAME_REV_CLIENT, def_acl);
+ forbid_whitelist(state, name, status, state->reverse_name);
} else if (strcasecmp(name, REJECT_MAPS_RBL) == 0) {
status = reject_maps_rbl(state);
} else if (strcasecmp(name, REJECT_RBL_CLIENT) == 0
* Internal interface.
*/
#define SMTPD_NAME_CLIENT "Client host"
+#define SMTPD_NAME_REV_CLIENT "Unverified Client host"
#define SMTPD_NAME_CCERT "Client certificate"
#define SMTPD_NAME_HELO "Helo command"
#define SMTPD_NAME_SENDER "Sender address"