main.cf when "postfix start" is invoked with an obsolete
postfix command. File: conf/post-install.
- Workaround (introduced 20071204): update the wrong proxywrite
- process limit when upgrading an already installed default
- master.cf file. File: conf/post-install.
-
20080207
Cleanup: soft_bounce support for multi-line Milter replies.
Cleanup: multi-line support in SMTP server replies. File:
smtpd/smtpd_chat.c.
+20080215
+
+ Safety: break SASL loop in case both the SASL library and
+ the remote SMTP server are confused. File: smtp/smtp_sasl_glue.c.
+
+20080220
+
+ Safety: the master daemon now sets an exclusive lock on a
+ file $data_directory/master.lock, so that the data directory
+ can't be shared between multiple Postfix instances. This
+ would corrupt files that rely on single-writer updates
+ (examples: verify(8) cache, tlsmgr(8) caches, etc.). File:
+ master/master.c.
+
20080228
Bugfix: bounce(8) segfault on one-line template text.
{rcpt_addr} information. Problem reported by Anton Yuzhaninov.
File: smtpd/smtpd.c.
-20040811
+20080318
+
+ Human factors: the PCRE and regexp maps now give more
+ comprehensible error messages when people make the common
+ mistake of indenting if/endif blocks. Files: util/dict_pcre.c,
+ util/dict_regexp.c.
+
+20080411
Bugfix (introduced Postfix 2.0): after "warn_if_reject
reject_unlisted_recipient/sender", the SMTP server mistakenly
compatibility feature only with queue files that don't
contain logging attributes. Problem reported by Liviu Daia.
Files *qmgr/qmgr_message.c.
+
+20080424
+
+ Cleanup: some warning messages said "regexp" or "regexp
+ map" instead of "pcre map". File: util/dict_pcre.c.
+
+20080428
+
+ Cleanup: the proxy_read_maps (Postfix 2.0) default setting
+ was not updated when adding sender/recipient_bcc_maps
+ (Postfix 2.1) and smtp/lmtp_generic_maps (Postfix 2.3).
+ File: global/mail_params.h.
+
+ Cleanup: the SMTP server's XFORWARD and XCLIENT support was
+ not updated when the smtpd_client_port_logging configuration
+ parameter was added. Code by Victor Duchovni. Files:
+ smtpd/smtpd.c, smtpd/smtpd_peer.c.
transferred. Postfix address verification does not work with such
sites. </p>
-<li> <p> By default, Postfix probe messages have "postmaster@$myorigin"
-as the sender address. This is SAFE because the Postfix SMTP server
-does not reject mail for this address. </p>
+<li> <p> By default, Postfix probe messages have "double-bounce@$myorigin"
+as the sender address (with Postfix versions before 2.5, the default
+is "postmaster@$myorigin"). This is SAFE because the Postfix SMTP
+server does not reject mail for this address. </p>
<p> You can change this into the null address ("address_verify_sender
="). This is UNSAFE because address probes will fail with
%PARAM unverified_sender_reject_code 450
<p>
-The numerical Postfix SMTP server response code when a recipient
+The numerical Postfix SMTP server response code when a sender
address is rejected by the reject_unverified_sender restriction.
</p>
" $" VAR_RCPT_CANON_MAPS \
" $" VAR_RELOCATED_MAPS \
" $" VAR_TRANSPORT_MAPS \
- " $" VAR_MYNETWORKS
+ " $" VAR_MYNETWORKS \
+ " $" VAR_SEND_BCC_MAPS \
+ " $" VAR_RCPT_BCC_MAPS \
+ " $" VAR_SMTP_GENERIC_MAPS \
+ " $" VAR_LMTP_GENERIC_MAPS
extern char *var_proxy_read_maps;
#define VAR_PROXY_WRITE_MAPS "proxy_write_maps"
* Patches change both the patchlevel and the release date. Snapshots have no
* patchlevel; they change the release date only.
*/
-#define MAIL_RELEASE_DATE "20080411"
-#define MAIL_VERSION_NUMBER "2.5.2-RC2"
+#define MAIL_RELEASE_DATE "20080501"
+#define MAIL_VERSION_NUMBER "2.5.2-RC3"
#ifdef SNAPSHOT
# define MAIL_VERSION_DATE "-" MAIL_RELEASE_DATE
/* /etc/postfix/main.cf, global configuration file.
/* /etc/postfix/master.cf, master server configuration file.
/* /var/spool/postfix/pid/master.pid, master lock file.
+/* /var/lib/postfix/master.lock, master lock file.
/* SEE ALSO
/* qmgr(8), queue manager
/* verify(8), address verification
#include <clean_env.h>
#include <argv.h>
#include <safe.h>
+#include <set_eugid.h>
+#include <set_ugid.h>
/* Global library. */
int main(int argc, char **argv)
{
static VSTREAM *lock_fp;
+ static VSTREAM *data_lock_fp;
VSTRING *lock_path;
+ VSTRING *data_lock_path;
off_t inherited_limit;
int debug_me = 0;
int ch;
* isn't locked.
*/
lock_path = vstring_alloc(10);
+ data_lock_path = vstring_alloc(10);
why = vstring_alloc(10);
vstring_sprintf(lock_path, "%s/%s.pid", DEF_PID_DIR, var_procname);
msg_fatal("cannot update lock file %s: %m", vstring_str(lock_path));
close_on_exec(vstream_fileno(lock_fp), CLOSE_ON_EXEC);
+ /*
+ * Lock down the Postfix-writable data directory.
+ */
+ vstring_sprintf(data_lock_path, "%s/%s.lock", var_data_dir, var_procname);
+ set_eugid(var_owner_uid, var_owner_gid);
+ data_lock_fp =
+ open_lock(vstring_str(data_lock_path), O_RDWR | O_CREAT, 0644, why);
+ set_ugid(getuid(), getgid());
+ if (data_lock_fp == 0)
+ msg_fatal("open lock file %s: %s",
+ vstring_str(data_lock_path), vstring_str(why));
+ vstream_fprintf(data_lock_fp, "%*lu\n", (int) sizeof(unsigned long) * 4,
+ (unsigned long) var_pid);
+ if (vstream_fflush(data_lock_fp))
+ msg_fatal("cannot update lock file %s: %m", vstring_str(data_lock_path));
+ close_on_exec(vstream_fileno(data_lock_fp), CLOSE_ON_EXEC);
+
+ /*
+ * Clean up.
+ */
vstring_free(why);
vstring_free(lock_path);
+ vstring_free(data_lock_path);
/*
* Optionally start the debugger on ourself.
if (myflock(vstream_fileno(lock_fp), INTERNAL_LOCK,
MYFLOCK_OP_EXCLUSIVE) < 0)
msg_fatal("refresh exclusive lock: %m");
+ if (myflock(vstream_fileno(data_lock_fp), INTERNAL_LOCK,
+ MYFLOCK_OP_EXCLUSIVE) < 0)
+ msg_fatal("refresh exclusive lock: %m");
#endif
watchdog_start(watchdog); /* same as trigger servers */
event_loop(-1);
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.
*/
if (state->namaddr)
myfree(state->namaddr);
state->namaddr =
- concatenate(state->name, "[", state->addr, "]:",
- state->port, (char *) 0);
+ SMTPD_BUILD_NAMADDRPORT(state->name, state->addr, state->port);
}
/*
myfree(state->xforward.namaddr);
state->xforward.namaddr =
IS_AVAIL_CLIENT_ADDR(state->xforward.addr) ?
- concatenate(state->xforward.name, "[",
- state->xforward.addr, "]:",
- state->xforward.port,
- (char *) 0) : mystrdup(state->xforward.name);
+ SMTPD_BUILD_NAMADDRPORT(state->xforward.name,
+ state->xforward.addr,
+ state->xforward.port) :
+ mystrdup(state->xforward.name);
}
smtpd_chat_reply(state, "250 2.0.0 Ok");
return (0);
#define SMTPD_PEER_CODE_PERM 5
#define SMTPD_PEER_CODE_FORGED 6
+ /*
+ * Construct name[addr] or name[addr]:port as appropriate
+ */
+#define SMTPD_BUILD_NAMADDRPORT(name, addr, port) \
+ concatenate((name), "[", (addr), "]", \
+ var_smtpd_client_port_log ? ":" : (char *) 0, \
+ (port), (char *) 0)
+
/*
* Choose between normal or forwarded attributes.
*
/* The verified client hostname. This name is represented by
/* the string "unknown" when 1) the address->name lookup failed,
/* 2) the name->address mapping fails, or 3) the name->address
-/* does not produce the client IP address.
+/* mapping does not produce the client IP address.
/* .IP reverse_name
/* The unverified client hostname as found with address->name
/* lookup; it is not verified for consistency with the client
/*
* Do the name[addr]:port formatting for pretty reports.
*/
- state->namaddr =
- concatenate(state->name, "[", state->addr, "]",
- var_smtpd_client_port_log ? ":" : (char *) 0,
- state->port, (char *) 0);
+ state->namaddr = SMTPD_BUILD_NAMADDRPORT(state->name, state->addr,
+ state->port);
}
/* smtpd_peer_reset - destroy peer information */
if (ret == PCRE_ERROR_NOSUBSTRING)
return (MAC_PARSE_UNDEF);
else
- msg_fatal("regexp %s, line %d: pcre_get_substring error: %d",
+ msg_fatal("pcre map %s, line %d: pcre_get_substring error: %d",
dict_pcre->dict.name, match_rule->rule.lineno, ret);
}
if (*pp == 0) {
msg_panic("pcre map %s, line %d: pcre_fullinfo failed",
mapname, lineno);
if (prescan_context.max_sub > actual_sub) {
- msg_warn("regexp map %s, line %d: out of range replacement index \"%d\": "
+ msg_warn("pcre map %s, line %d: out of range replacement index \"%d\": "
"skipping this rule", mapname, lineno,
(int) prescan_context.max_sub);
if (engine.pattern)
*/
while (*p && ISSPACE(*p))
++p;
- if (*p)
- msg_warn("pcre map %s, line %d: ignoring extra text after IF",
- mapname, lineno);
+ if (*p) {
+ msg_warn("pcre map %s, line %d: ignoring extra text after "
+ "IF statement: \"%s\"", mapname, lineno, p);
+ msg_warn("pcre map %s, line %d: do not prepend whitespace"
+ " to statements between IF and ENDIF", mapname, lineno);
+ }
/*
* Compile the pattern.
* Unrecognized input.
*/
else {
- msg_warn("regexp map %s, line %d: ignoring unrecognized request",
+ msg_warn("pcre map %s, line %d: ignoring unrecognized request",
mapname, lineno);
return (0);
}
return (0);
while (*p && ISSPACE(*p))
++p;
- if (*p)
- msg_warn("regexp map %s, line %d: ignoring extra text after IF",
- mapname, lineno);
+ if (*p) {
+ msg_warn("regexp map %s, line %d: ignoring extra text after"
+ " IF statement: \"%s\"", mapname, lineno, p);
+ msg_warn("regexp map %s, line %d: do not prepend whitespace"
+ " to statements between IF and ENDIF", mapname, lineno);
+ }
if ((expr = dict_regexp_compile_pat(mapname, lineno, &pattern)) == 0)
return (0);
if_rule = (DICT_REGEXP_IF_RULE *)