Postfix queue file permissions and access methods, in case
someone compromises the postfix account. Michael Tokarev,
who received the insights from Solar Designer, who tested
- Postfix with his "openwatch" kernel module. Files:
- master/master_wakeup.c, util/fifo_trigger.c, postfix-script.
+ Postfix with a kernel module that is paranoid about open()
+ calls. Files: master/master_wakeup.c, util/fifo_trigger.c,
+ postfix-script.
Convenience: issue a warning instead of aborting when the
local machine name is not in fully-qualified domain form.
Safety: configuration file comments no longer span multiple
lines when the next line begins with whitespace; multi-line
input is no longer terminated by a comment line, by an all
- white space line, or by an empty line. Files: util/readlline.c,
- postconf/postconf.c.
+ white space line, or by an empty line. Michael Tokarev made
+ the crucial suggestion to simplify the readline routine.
+ Files: util/readlline.c, postconf/postconf.c.
Cleanup: proper detection of big number overflow in EHLO
- and MAIL FROM size announcements. Files: global/off_cvt.c,
+ and MAIL FROM size announcements, with input from Victor
+ Duchovny, Morgan Stanley. Files: global/off_cvt.c,
smtpd/smtpd.c, smtp/smtp_proto.c, util/alldig.c.
Forward compatibility: added queue file record types for
Cleanup: safe_open() now returns sensible errno values so
that the fifo_trigger() external interface is restored.
+20011225
+
+ Upgrade: PCRE_README now describes PCRE version 3.x.
+
+ Cleanup: flush SMTPD command history upon receipt of EHLO,
+ RSET, and upon DATA completion, only if it exceeds
+ $smtpd_history_flush_threshold lines (default: 100).
+ Distant derivative of code by Michael Tokarev. File:
+ smtpd/smtpd.c.
+
Open problems:
Low: after reorganizing configuration parameters, add flags
For queue locking, NFS is not an issue because you cannot share
Postfix queues between Postfix instances anyawy.
-For mailbox locking, some systems such as FreeBSD use flock() by
-default (use: ``postconf mailbox_delivery_lock'' to find out about
-your system). flock() does not work over NFS. This causes loss of
-mail when multiple hosts access the same mailboxes.
+For mailbox locking, some systems use flock() by default (use:
+``postconf mailbox_delivery_lock'' and ``postconf virtual_mailbox_lock''
+to find out about your system). flock() does not work over NFS.
+This causes loss of mail when multiple hosts access the same
+mailboxes.
In order to have mailbox locking over NFS you have to configure
everything to use fcntl() locks for mailbox access (or switch to
-maildir style). With Postfix you'd specify:
+maildir style, which needs no application-level lock controls).
+
+To turn on fcntl locks with Postfix you specify:
virtual_mailbox_lock = fcntl
mailbox_delivery_lock = fcntl
This is useful only if all mailbox access software uses fcntl()
locks. I have no information on how well fcntl() locks work on NFS.
-You can also "play safe" and try to throw in username.lock files:
+You can also "play safe" and throw in username.lock files:
virtual_mailbox_lock = fcntl, dotlock
mailbox_delivery_lock = fcntl, dotlock
-this is the mix that many packages end up using.
+this is the mix that many applications end up using.
-To: wietse@porcupine.org (Wietse Venema)
-Cc: postfix-users@postfix.org (Postfix users)
-Subject: regexp map patch
-In-reply-to: Your message of "Thu, 25 Feb 1999 19:51:25 CDT."
- <19990226005125.69B3C4596E@spike.porcupine.org>
-Date: Tue, 02 Mar 1999 11:04:02 +1100
-From: Andrew McNamara <andrewm@connect.com.au>
-Message-Id: <19990302000403.074C7ED7D@melang.off.connect.com.au>
-Sender: owner-postfix-users@postfix.org
-Precedence: bulk
-Return-Path: <owner-postfix-users@postfix.org>
+PCRE (Perl Compatible Regular Expressions) map support
+======================================================
-I've written [code] to add a regexp map type. It utilises the PCRE
-library (Perl Compatible Regular Expressions), which can be obtained
-from:
+The optional "pcre" map type allows you to specify regular expressions
+with the PERL style notation such as \s for space and \S for
+non-space.
- ftp://ftp.csx.cam.ac.uk/pub/software/programming/pcre
+One possible use is to add a restriction to main.cf:
-You will need to add -DHAS_PCRE and a -I for the PCRE header to CCARGS,
-and add the path to the PCRE library to AUXLIBS, for example:
+ smtpd_recipient_restrictions = ... pcre:/opt/postfix/etc/smtprecipient ...
- make -f Makefile.init makefiles 'CCARGS=-DHAS_PCRE -I../../../pcre-2.08' \
- 'AUXLIBS=../../../pcre-2.08/libpcre.a'
+The regular expressions are read from the file specified - sample
+regexp patterns are shown in the Postfix pcre_table(5) manual page.
-[note: pcre versions before 2.06 are no longer compatible -- Wietse]
+Building Postfix with PCRE support
+==================================
-One possible use is to add a line to main.cf:
+In the future, Postfix will have a plug-in interface for adding
+map types. Until then you need to compile PCRE support into Postfix.
- smtpd_recipient_restrictions = pcre:/opt/postfix/etc/smtprecipient
+You need the PCRE library (Perl Compatible Regular Expressions),
+which can be obtained from:
-The regular expressions are read from the file specified and compiled -
-a sample regexp file for this usage is included in the patch.
+ ftp://ftp.csx.cam.ac.uk/pub/software/programming/pcre/
-Any feedback is appreciated (from Wietse in particular :-). Have
-fun.
+Postfix was tested with PCRE versions 2.8 and 3.7.
-[I've changed the code so that it can be used for other Postfix
-table lookups, not just for junk mail control. In particular,
-regular expressions in canonical tables could be very useful.
+In order to build Postfix with PCRE support you need to add -DHAS_PCRE
+and a -I for the PCRE include file to CCARGS, and add the path to the
+PCRE library to AUXLIBS, for example:
-For the sake of robustness, I have disabled the matching of partial
-addresses (user@, domain, user, @domain) that is normally done with
-Postfix access control tables, canonical maps and virtual maps.
+ make -f Makefile.init makefiles \
+ "CCARGS=-DHAS_PCRE -I/usr/local/include" \
+ "AUXLIBS=-L/usr/local/lib -lpcre"
+
+NOTE: pcre versions prior to 2.06 cannot be used.
+
+Things to know
+==============
+
+For the sake of robustness, Postfix disables the matching of partial
+addresses (breaking down user@domain into user@, domain, user,
+@domain) that is normally done with Postfix access control tables,
+canonical maps and virtual maps.
As a side effect, pcre maps can only match user@domain strings, so
that regexps cannot be used for local alias database lookups. That
-would be a security exposure anyway -- Wietse.]
+would be a security exposure anyway.
-Incompatible changes with snapshot-200112XX
+Incompatible changes with snapshot-20011226
===========================================
Postfix configuration file comments no longer continue on the next
surprises, but it may cause unexpected behavior with existing,
improperly formatted, configuration files. Caveat user.
-Major changes with snapshot-200112XX
+Major changes with snapshot-20011226
====================================
In Postfix configuration files, comment lines are allowed to begin
# warn_if_reject: next restriction logs a warning instead of rejecting.
smtpd_etrn_restrictions =
+# The smtpd_history_flush_threshold specifies how many lines the SMTP
+# server command history is allowed to contain before it is flushed
+# to postmaster upon receipt of EHLO, RSET, or end of DATA.
+#
+smtpd_history_flush_threshold = 100
+
# The smtpd_noop_commands parameter specifies a list of commands that
# the Postfix SMTP server replies to with "250 Ok", without doing any
# syntax checks and without changing state. This list overrides any
file system for the SMTP server to accept any mail
at all.
+ <b>smtpd</b><i>_</i><b>history</b><i>_</i><b>flush</b><i>_</i><b>threshold</b>
+ Flush the command history to postmaster after
+ receipt of RSET etc. only if the number of history
+ lines exceeds the given threshold.
+
<b>Tarpitting</b>
<b>smtpd</b><i>_</i><b>error</b><i>_</i><b>sleep</b><i>_</i><b>time</b>
Time to wait in seconds before sending a 4xx or 5xx
.IP \fBqueue_minfree\fR
Minimal amount of free space in bytes in the queue file system
for the SMTP server to accept any mail at all.
+.IP \fBsmtpd_history_flush_threshold\fR
+Flush the command history to postmaster after receipt of RSET etc.
+only if the number of history lines exceeds the given threshold.
.SH Tarpitting
.ad
.fi
extern int var_smtpd_err_sleep;
#define VAR_SMTPD_JUNK_CMD "smtpd_junk_command_limit"
-#define DEF_SMTPD_JUNK_CMD 1000
+#define DEF_SMTPD_JUNK_CMD 100
extern int var_smtpd_junk_cmd_limit;
+#define VAR_SMTPD_HIST_THRSH "smtpd_history_flush_threshold"
+#define DEF_SMTPD_HIST_THRSH 100
+extern int var_smtpd_hist_thrsh;
+
#define VAR_SMTPD_NOOP_CMDS "smtpd_noop_commands"
#define DEF_SMTPD_NOOP_CMDS ""
extern char *var_smtpd_noop_cmds;
* Version of this program.
*/
#define VAR_MAIL_VERSION "mail_version"
-#define DEF_MAIL_VERSION "Snapshot-20011223"
+#define DEF_MAIL_VERSION "Snapshot-20011226"
extern char *var_mail_version;
/* LICENSE
{
int ch;
off_t result;
- off_t last;
+ off_t res2;
+ off_t res4;
+ off_t res8;
+ off_t res10;
/*
- * We're not doing this often, so simplicity has precedence over
- * performance.
+ * Multiplication by numbers > 2 can overflow without producing a smaller
+ * result mod 2^N (where N is the number of bits in the result type).
+ * (Victor Duchovny, Morgan Stanley).
*/
- for (last = result = 0; (ch = *(unsigned char *) str) != 0; str++) {
+ for (result = 0; (ch = *(unsigned char *) str) != 0; str++) {
if (!ISDIGIT(ch))
return (-1);
- result *= 10;
- if (result < last)
+ if ((res2 = result + result) < result)
+ return (-1);
+ if ((res4 = res2 + res2) < res2)
+ return (-1);
+ if ((res8 = res4 + res4) < res4)
+ return (-1);
+ if ((res10 = res8 + res2) < res8)
+ return (-1);
+ if ((result = res10 + ch - '0') < res10)
return (-1);
- result += ch - '0';
- last = result;
}
return (result);
}
* applications (says the INSTALL documentation).
*
* Result of a discussion with Michael Tokarev, who received his
- * insights from Solar Designer, who tested Postfix with his
- * "openwatch" kernel module.
+ * insights from Solar Designer, who tested Postfix with a kernel
+ * module that is paranoid about open() calls.
*/
case MASTER_SERV_TYPE_FIFO:
set_eugid(var_owner_uid, var_owner_gid);
state->features |= SMTP_FEATURE_PIPELINING;
else if (strcasecmp(word, "SIZE") == 0) {
state->features |= SMTP_FEATURE_SIZE;
- if ((word = mystrtok(&words, " \t=")) != 0) {
+ if ((word = mystrtok(&words, " \t")) != 0) {
if (!alldig(word))
msg_warn("bad size limit \"%s\" in EHLO reply from %s",
word, session->namaddr);
}
}
if (msg_verbose)
- msg_info("server features: 0x%x", state->features);
+ msg_info("server features: 0x%x size %.0f",
+ state->features, (double) state->size_limit);
#ifdef USE_SASL_AUTH
if (var_smtp_sasl_enable && (state->features & SMTP_FEATURE_AUTH))
* connection caching.
*/
if (state->size_limit > 0 && state->size_limit < request->data_size) {
- smtp_mesg_fail(state, resp->code,
+ smtp_mesg_fail(state, 552,
"message size %lu exceeds size limit %.0f of server %s",
request->data_size, (double) state->size_limit,
session->namaddr);
- return (0);
+ RETURN(0);
}
/*
tests: smtpd_check_test smtpd_check_test2 smtpd_acl_test smtpd_token_test
smtpd_check_test: smtpd_check smtpd_check.in smtpd_check.ref
- ../postmap/postmap smtpd_check_access
+ ../postmap/postmap hash:smtpd_check_access
./smtpd_check <smtpd_check.in >smtpd_check.tmp 2>&1
diff smtpd_check.ref smtpd_check.tmp
rm -f smtpd_check.tmp smtpd_check_access.*
smtpd_check_test2: smtpd_check smtpd_check.in2 smtpd_check.ref2
- ../postmap/postmap smtpd_check_access
+ ../postmap/postmap hash:smtpd_check_access
./smtpd_check <smtpd_check.in2 >smtpd_check.tmp 2>&1
diff smtpd_check.ref2 smtpd_check.tmp
rm -f smtpd_check.tmp smtpd_check_access.*
smtpd_acl_test: smtpd_check smtpd_acl.in smtpd_acl.ref
- ../postmap/postmap smtpd_check_access
+ ../postmap/postmap hash:smtpd_check_access
./smtpd_check <smtpd_acl.in >smtpd_check.tmp 2>&1
diff smtpd_acl.ref smtpd_check.tmp
rm -f smtpd_check.tmp smtpd_check_access.*
/* .IP \fBqueue_minfree\fR
/* Minimal amount of free space in bytes in the queue file system
/* for the SMTP server to accept any mail at all.
+/* .IP \fBsmtpd_history_flush_threshold\fR
+/* Flush the command history to postmaster after receipt of RSET etc.
+/* only if the number of history lines exceeds the given threshold.
/* .SH Tarpitting
/* .ad
/* .fi
char *var_smtpd_snd_auth_maps;
char *var_smtpd_noop_cmds;
char *var_smtpd_null_key;
+int var_smtpd_hist_thrsh;
/*
* Global state, for stand-alone mode queue file cleanup. When this is
static void helo_reset(SMTPD_STATE *);
static void mail_reset(SMTPD_STATE *);
static void rcpt_reset(SMTPD_STATE *);
-static void chat_reset(SMTPD_STATE *);
+static void chat_reset(SMTPD_STATE *, int);
/* collapse_args - put arguments together again */
if (state->helo_name != 0)
helo_reset(state);
#ifndef RFC821_SYNTAX
- chat_reset(state);
+ chat_reset(state, var_smtpd_hist_thrsh);
mail_reset(state);
rcpt_reset(state);
#endif
/*
* Cleanup. The client may send another MAIL command.
*/
- chat_reset(state);
+ chat_reset(state, var_smtpd_hist_thrsh);
mail_reset(state);
rcpt_reset(state);
if (why)
/*
* Restore state to right after HELO/EHLO command.
*/
- chat_reset(state);
+ chat_reset(state, var_smtpd_hist_thrsh);
mail_reset(state);
rcpt_reset(state);
smtpd_chat_reply(state, "250 Ok");
/* chat_reset - notify postmaster and reset conversation log */
-static void chat_reset(SMTPD_STATE *state)
+static void chat_reset(SMTPD_STATE *state, int threshold)
{
/*
* report problems when running in stand-alone mode: postmaster notices
* require availability of the cleanup service.
*/
- if (state->history != 0 && SMTPD_STAND_ALONE(state) == 0
- && (state->error_mask & state->notify_mask))
- smtpd_chat_notify(state);
- state->error_mask = 0;
- smtpd_chat_reset(state);
+ if (state->history != 0 && state->history->argc > threshold) {
+ if (SMTPD_STAND_ALONE(state) == 0
+ && (state->error_mask & state->notify_mask))
+ smtpd_chat_notify(state);
+ state->error_mask = 0;
+ smtpd_chat_reset(state);
+ }
}
/*
if (var_smtpd_sasl_enable)
smtpd_sasl_auth_reset(state);
#endif
- chat_reset(state);
+ chat_reset(state, 0);
mail_reset(state);
rcpt_reset(state);
}
VAR_REJECT_CODE, DEF_REJECT_CODE, &var_reject_code, 0, 0,
VAR_NON_FQDN_CODE, DEF_NON_FQDN_CODE, &var_non_fqdn_code, 0, 0,
VAR_SMTPD_JUNK_CMD, DEF_SMTPD_JUNK_CMD, &var_smtpd_junk_cmd_limit, 1, 0,
+ VAR_SMTPD_HIST_THRSH, DEF_SMTPD_HIST_THRSH, &var_smtpd_hist_thrsh, 1, 0,
0,
};
static CONFIG_TIME_TABLE time_table[] = {
smtpd_delay_reject 0
mynetworks 127.0.0.0/8,168.100.189.0/28
relay_domains porcupine.org
+smtpd_null_access_lookup_key <>
#
# Test check_domain_access()
#
rcpt anyone@ok.domain
# Expect: OK
rcpt bad-sender@ok.domain
+#
+# check_sender_access specific
+#
+mail <>
OK
>>> relay_domains porcupine.org
OK
+>>> smtpd_null_access_lookup_key <>
+OK
>>> #
>>> # Test check_domain_access()
>>> #
>>> # Expect: OK
>>> rcpt bad-sender@ok.domain
OK
+>>> #
+>>> # check_sender_access specific
+>>> #
+>>> mail <>
+./smtpd_check: reject: MAIL from bar.duno.com[44.33.44.33]: 550 <>: Sender address rejected: Go away postmaster; from=<>
+550 <>: Sender address rejected: Go away postmaster
{
char *line;
+ if (state->notify_mask == 0)
+ return;
+
if (state->history == 0)
state->history = argv_alloc(10);
line = concatenate(direction, STR(state->buffer), (char *) 0);
reject@ok.domain REJECT
ok@ok.domain OK
ok.domain OK
+<> 550 Go away postmaster