Postfix version 2.2 patch 10 fixes minor problems, as usual.
- "sendmail -t" did not remove the CR from lines ending in CRLF.
- Workaround for fatal errors in PCRE maps when an expression in
() matches empty text (the PCRE library returns an inappropriate
error code).
- Fixes for non-security bugs that Coverity found in code that
handles impossible error conditions.
Beware: Coverity's claim of "17 original defects" in Postfix includes
14 false positives; that is, 14 are bugs in Coverity, not in Postfix.
Inflated claims like this may make their own product look good, but
they are hamful for the reputation of open source projects.
Prereq: "2.2.9"
diff -cr /var/tmp/postfix-2.2.9/src/global/mail_version.h ./src/global/mail_version.h
*** /var/tmp/postfix-2.2.9/src/global/mail_version.h Tue Feb 21 14:27:49 2006
--- ./src/global/mail_version.h Wed Apr 5 16:40:28 2006
***************
*** 20,27 ****
* Patches change the patchlevel and the release date. Snapshots change the
* release date only.
*/
! #define MAIL_RELEASE_DATE "20060221"
! #define MAIL_VERSION_NUMBER "2.2.9"
#define VAR_MAIL_VERSION "mail_version"
#ifdef SNAPSHOT
--- 20,27 ----
* Patches change the patchlevel and the release date. Snapshots change the
* release date only.
*/
! #define MAIL_RELEASE_DATE "20060405"
! #define MAIL_VERSION_NUMBER "2.2.10"
#define VAR_MAIL_VERSION "mail_version"
#ifdef SNAPSHOT
diff -cr /var/tmp/postfix-2.2.9/HISTORY ./HISTORY
*** /var/tmp/postfix-2.2.9/HISTORY Tue Feb 21 16:24:32 2006
--- ./HISTORY Wed Apr 5 15:15:03 2006
***************
*** 10872,10874 ****
--- 10872,10922 ----
Workaround: don't consume in_flow tokens when incoming mail
is placed on hold. Back-ported from Postfix 2.3. File:
cleanup/cleanup_api.c.
+
+ 20060310
+
+ Workaround: null-terminate the input after stripping CR,
+ and before passing the input to the MIME processor. Leandro
+ Santi. The fix, a rewrite of the MIME processor input
+ handling, is too much change for a stable release. File:
+ sendmail/sendmail.c.
+
+ 20060315
+
+ Workaround: the PCRE library reports an inappropriate error
+ code (invalid substring) when $number refers to a valid ()
+ expression that matches the null string. This caused fatal
+ run-time errors. File: dict_pcre.c.
+
+ 20060324
+
+ Bugfix: mis-placed parenthesis in SMTP before-filter error
+ test. A filter timeout was mis-reported as lost connection.
+ Found in code review. File: smtpd/smtpd_proxy.c.
+
+ 20060403
+ Bugfix: the pipe-to-command error message was lost when the
+ command could not be executed. File: global/pipe_command.c.
+
+ 20060404
+
+ Bugfix in sanity check: after reading a record from the
+ address verification database, a sanity check did not reject
+ a record with all-zero time stamp fields. Such records are
+ never written; the test is there just in case something is
+ broken, so that Postfix will not blindly march on and create
+ chaos. The sanity check tested pointer values, instead of
+ dereferencing the pointers. Found by Coverity. File:
+ verify/verify.c.
+
+ Bugfix in sanity check: when the maildir delivery routine
+ opens an output file it looks up the file attributes via
+ the file handle it just got. There is a sanity check that
+ detects if the attribute lookup fails, an error that never
+ happens. The code that handles the impossible error did not
+ close the output file. This would cause a virtual or local
+ delivery agent to waste up to 100 file descriptors. But
+ for that error to happen the system would have to be so
+ sick that you would have more serious problems than a file
+ descriptor leak. Found by Coverity. Files: local/maildir.c,
+ virtual/maildir.c.
diff -cr /var/tmp/postfix-2.2.9/html/postconf.5.html ./html/postconf.5.html
*** /var/tmp/postfix-2.2.9/html/postconf.5.html Mon Jan 30 20:09:38 2006
--- ./html/postconf.5.html Wed Mar 15 14:20:02 2006
***************
*** 8226,8242 ****
- The sender domain matches $mydestination, $inet_interfaces or
! $proxy_interfaces, but the recipient is not listed in
$local_recipient_maps, and $local_recipient_maps is not null.
!
- The sender domain matches $virtual_alias_domains but the recipient
is not listed in $virtual_alias_maps.
- The sender domain matches $virtual_mailbox_domains but the
! recipient is not listed in $virtual_mailbox_maps, and $virtual_mailbox_maps
is not null.
!
- The sender domain matches $relay_domains but the recipient is
not listed in $relay_recipient_maps, and $relay_recipient_maps is
not null.
--- 8226,8242 ----
- The sender domain matches $mydestination, $inet_interfaces or
! $proxy_interfaces, but the sender is not listed in
$local_recipient_maps, and $local_recipient_maps is not null.
!
- The sender domain matches $virtual_alias_domains but the sender
is not listed in $virtual_alias_maps.
- The sender domain matches $virtual_mailbox_domains but the
! sender is not listed in $virtual_mailbox_maps, and $virtual_mailbox_maps
is not null.
!
- The sender domain matches $relay_domains but the sender is
not listed in $relay_recipient_maps, and $relay_recipient_maps is
not null.
diff -cr /var/tmp/postfix-2.2.9/man/man5/postconf.5 ./man/man5/postconf.5
*** /var/tmp/postfix-2.2.9/man/man5/postconf.5 Mon Jan 30 20:09:38 2006
--- ./man/man5/postconf.5 Wed Mar 15 14:20:03 2006
***************
*** 4705,4721 ****
of forged mail from worms or viruses.
.IP \(bu
The sender domain matches $mydestination, $inet_interfaces or
! $proxy_interfaces, but the recipient is not listed in
$local_recipient_maps, and $local_recipient_maps is not null.
.IP \(bu
! The sender domain matches $virtual_alias_domains but the recipient
is not listed in $virtual_alias_maps.
.IP \(bu
The sender domain matches $virtual_mailbox_domains but the
! recipient is not listed in $virtual_mailbox_maps, and $virtual_mailbox_maps
is not null.
.IP \(bu
! The sender domain matches $relay_domains but the recipient is
not listed in $relay_recipient_maps, and $relay_recipient_maps is
not null.
.PP
--- 4705,4721 ----
of forged mail from worms or viruses.
.IP \(bu
The sender domain matches $mydestination, $inet_interfaces or
! $proxy_interfaces, but the sender is not listed in
$local_recipient_maps, and $local_recipient_maps is not null.
.IP \(bu
! The sender domain matches $virtual_alias_domains but the sender
is not listed in $virtual_alias_maps.
.IP \(bu
The sender domain matches $virtual_mailbox_domains but the
! sender is not listed in $virtual_mailbox_maps, and $virtual_mailbox_maps
is not null.
.IP \(bu
! The sender domain matches $relay_domains but the sender is
not listed in $relay_recipient_maps, and $relay_recipient_maps is
not null.
.PP
diff -cr /var/tmp/postfix-2.2.9/proto/postconf.proto ./proto/postconf.proto
*** /var/tmp/postfix-2.2.9/proto/postconf.proto Mon Jan 30 20:09:29 2006
--- ./proto/postconf.proto Wed Mar 15 14:19:42 2006
***************
*** 7172,7188 ****
- The sender domain matches $mydestination, $inet_interfaces or
! $proxy_interfaces, but the recipient is not listed in
$local_recipient_maps, and $local_recipient_maps is not null.
!
- The sender domain matches $virtual_alias_domains but the recipient
is not listed in $virtual_alias_maps.
- The sender domain matches $virtual_mailbox_domains but the
! recipient is not listed in $virtual_mailbox_maps, and $virtual_mailbox_maps
is not null.
!
- The sender domain matches $relay_domains but the recipient is
not listed in $relay_recipient_maps, and $relay_recipient_maps is
not null.
--- 7172,7188 ----
- The sender domain matches $mydestination, $inet_interfaces or
! $proxy_interfaces, but the sender is not listed in
$local_recipient_maps, and $local_recipient_maps is not null.
!
- The sender domain matches $virtual_alias_domains but the sender
is not listed in $virtual_alias_maps.
- The sender domain matches $virtual_mailbox_domains but the
! sender is not listed in $virtual_mailbox_maps, and $virtual_mailbox_maps
is not null.
!
- The sender domain matches $relay_domains but the sender is
not listed in $relay_recipient_maps, and $relay_recipient_maps is
not null.
diff -cr /var/tmp/postfix-2.2.9/src/global/pipe_command.c ./src/global/pipe_command.c
*** /var/tmp/postfix-2.2.9/src/global/pipe_command.c Mon Jun 21 19:50:14 2004
--- ./src/global/pipe_command.c Mon Apr 3 21:16:43 2006
***************
*** 131,136 ****
--- 131,137 ----
#include
#include
+ #include
#include
#include
#include
***************
*** 345,351 ****
int pipe_command(VSTREAM *src, VSTRING *why,...)
{
! char *myname = "pipe_comand";
va_list ap;
VSTREAM *cmd_in_stream;
VSTREAM *cmd_out_stream;
--- 346,352 ----
int pipe_command(VSTREAM *src, VSTRING *why,...)
{
! char *myname = "pipe_command";
va_list ap;
VSTREAM *cmd_in_stream;
VSTREAM *cmd_out_stream;
***************
*** 421,426 ****
--- 422,428 ----
* parent can kill not just the child but also its offspring.
*/
case 0:
+ (void) msg_cleanup((MSG_CLEANUP_FN) 0);
set_ugid(args.uid, args.gid);
if (setsid() < 0)
msg_warn("setsid failed: %m");
***************
*** 462,469 ****
--- 464,479 ----
/*
* Process plumbing. If possible, avoid running a shell.
+ *
+ * As a safety for buggy libraries, we close the syslog socket.
+ * Otherwise we could leak a file descriptor that was created by a
+ * privileged process.
+ *
+ * XXX To avoid losing fatal error messages we open a VSTREAM and
+ * capture the output in the parent process.
*/
closelog();
+ msg_vstream_init(var_procname, VSTREAM_ERR);
if (args.argv) {
execvp(args.argv[0], args.argv);
msg_fatal("%s: execvp %s: %m", myname, args.argv[0]);
diff -cr /var/tmp/postfix-2.2.9/src/local/maildir.c ./src/local/maildir.c
*** /var/tmp/postfix-2.2.9/src/local/maildir.c Wed Jun 23 11:19:23 2004
--- ./src/local/maildir.c Wed Apr 5 15:13:10 2006
***************
*** 189,195 ****
|| (dst = vstream_fopen(tmpfile, O_WRONLY | O_CREAT | O_EXCL, 0600)) == 0)) {
vstring_sprintf(why, "create %s: %m", tmpfile);
} else if (fstat(vstream_fileno(dst), &st) < 0) {
! vstring_sprintf(why, "create %s: %m", tmpfile);
} else {
vstring_sprintf(buf, "%lu.V%lxI%lxM%lu.%s",
(unsigned long) starttime.tv_sec,
--- 189,201 ----
|| (dst = vstream_fopen(tmpfile, O_WRONLY | O_CREAT | O_EXCL, 0600)) == 0)) {
vstring_sprintf(why, "create %s: %m", tmpfile);
} else if (fstat(vstream_fileno(dst), &st) < 0) {
!
! /*
! * Coverity 200604: file descriptor leak in code that never executes.
! * Code replaced by msg_fatal(), as it is not worthwhile to continue
! * after an impossible error condition.
! */
! msg_fatal("fstat %s: %m", tmpfile);
} else {
vstring_sprintf(buf, "%lu.V%lxI%lxM%lu.%s",
(unsigned long) starttime.tv_sec,
diff -cr /var/tmp/postfix-2.2.9/src/sendmail/sendmail.c ./src/sendmail/sendmail.c
*** /var/tmp/postfix-2.2.9/src/sendmail/sendmail.c Wed Mar 2 09:34:43 2005
--- ./src/sendmail/sendmail.c Fri Mar 10 13:52:08 2006
***************
*** 742,749 ****
skip_from_ = 0;
}
if (strip_cr == STRIP_CR_DO && type == REC_TYPE_NORM)
! if (VSTRING_LEN(buf) > 0 && vstring_end(buf)[-1] == '\r')
vstring_truncate(buf, VSTRING_LEN(buf) - 1);
if ((flags & SM_FLAG_AEOF) && prev_type != REC_TYPE_CONT
&& VSTRING_LEN(buf) == 1 && *STR(buf) == '.')
break;
--- 742,751 ----
skip_from_ = 0;
}
if (strip_cr == STRIP_CR_DO && type == REC_TYPE_NORM)
! if (VSTRING_LEN(buf) > 0 && vstring_end(buf)[-1] == '\r') {
vstring_truncate(buf, VSTRING_LEN(buf) - 1);
+ VSTRING_TERMINATE(buf);
+ }
if ((flags & SM_FLAG_AEOF) && prev_type != REC_TYPE_CONT
&& VSTRING_LEN(buf) == 1 && *STR(buf) == '.')
break;
diff -cr /var/tmp/postfix-2.2.9/src/smtpd/smtpd_proxy.c ./src/smtpd/smtpd_proxy.c
*** /var/tmp/postfix-2.2.9/src/smtpd/smtpd_proxy.c Mon Oct 25 16:59:12 2004
--- ./src/smtpd/smtpd_proxy.c Fri Mar 24 17:08:52 2006
***************
*** 416,422 ****
if (vstream_ftimeout(state->proxy)
|| vstream_ferror(state->proxy)
|| vstream_feof(state->proxy)
! || ((err = vstream_setjmp(state->proxy) != 0)
&& smtpd_proxy_rdwr_error(state->proxy, err))) {
state->error_mask |= MAIL_ERROR_SOFTWARE;
state->err |= CLEANUP_STAT_PROXY;
--- 416,422 ----
if (vstream_ftimeout(state->proxy)
|| vstream_ferror(state->proxy)
|| vstream_feof(state->proxy)
! || ((err = vstream_setjmp(state->proxy)) != 0
&& smtpd_proxy_rdwr_error(state->proxy, err))) {
state->error_mask |= MAIL_ERROR_SOFTWARE;
state->err |= CLEANUP_STAT_PROXY;
diff -cr /var/tmp/postfix-2.2.9/src/util/dict_pcre.c ./src/util/dict_pcre.c
*** /var/tmp/postfix-2.2.9/src/util/dict_pcre.c Thu Nov 13 10:10:04 2003
--- ./src/util/dict_pcre.c Wed Mar 15 10:11:25 2006
***************
*** 171,178 ****
ctxt->matches, n, &pp);
if (ret < 0) {
if (ret == PCRE_ERROR_NOSUBSTRING)
! msg_fatal("regexp %s, line %d: replace index out of range",
! ctxt->mapname, ctxt->lineno);
else
msg_fatal("regexp %s, line %d: pcre_get_substring error: %d",
ctxt->mapname, ctxt->lineno, ret);
--- 171,177 ----
ctxt->matches, n, &pp);
if (ret < 0) {
if (ret == PCRE_ERROR_NOSUBSTRING)
! return (MAC_PARSE_UNDEF);
else
msg_fatal("regexp %s, line %d: pcre_get_substring error: %d",
ctxt->mapname, ctxt->lineno, ret);
***************
*** 543,548 ****
--- 542,548 ----
int dict_flags)
{
char *p;
+ int actual_sub;
p = line;
***************
*** 599,604 ****
--- 599,621 ----
*/
if (dict_pcre_compile(mapname, lineno, ®exp, &engine) == 0)
return (0);
+ #ifdef PCRE_INFO_CAPTURECOUNT
+ if (pcre_fullinfo(engine.pattern, engine.hints,
+ PCRE_INFO_CAPTURECOUNT,
+ (void *) &actual_sub) != 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\": "
+ "skipping this rule", mapname, lineno,
+ (int) prescan_context.max_sub);
+ if (engine.pattern)
+ myfree((char *) engine.pattern);
+ if (engine.hints)
+ myfree((char *) engine.hints);
+ return (0);
+ }
+ #endif
/*
* Save the result.
diff -cr /var/tmp/postfix-2.2.9/src/util/dict_pcre.ref ./src/util/dict_pcre.ref
*** /var/tmp/postfix-2.2.9/src/util/dict_pcre.ref Fri Jul 4 17:38:45 2003
--- ./src/util/dict_pcre.ref Wed Mar 15 09:56:50 2006
***************
*** 2,20 ****
--- 2,35 ----
./dict_open: warning: pcre map dict_pcre.map, line 5: ignoring extra text after ENDIF
./dict_open: warning: pcre map dict_pcre.map, line 8: unknown regexp option "!": skipping this rule
./dict_open: warning: dict_pcre.map, line 9: no replacement text: using empty string
+ ./dict_open: warning: regexp map dict_pcre.map, line 10: out of range replacement index "5": skipping this rule
./dict_open: warning: pcre map dict_pcre.map, line 17: $number found in negative match replacement text: skipping this rule
./dict_open: warning: pcre map dict_pcre.map, line 22: no regexp: skipping this rule
+ > get true
true: not found
+ > get true1
true1=1
+ > get true2
true2: not found
+ > get truefalse2
truefalse2=2
+ > get 3
3: not found
+ > get true3
true3=3
+ > get c
c=
+ > get d
d: not found
+ > get 1234
1234=(1)(2)(3)(4)
+ > get 123
123=(1)(2)(3)
+ > get bar/find
bar/find: not found
+ > get bar/whynot
bar/whynot=Don't have a liquor license
+ > get bar/elbereth
bar/elbereth=(elbereth)
+ > get say/elbereth
say/elbereth: not found
diff -cr /var/tmp/postfix-2.2.9/src/verify/verify.c ./src/verify/verify.c
*** /var/tmp/postfix-2.2.9/src/verify/verify.c Fri Feb 4 16:00:53 2005
--- ./src/verify/verify.c Wed Apr 5 15:11:55 2006
***************
*** 266,276 ****
*probed = atol(probed_text);
*updated = atol(updated_text);
*status = atoi(buf);
if ((*status == DEL_RCPT_STAT_OK
|| *status == DEL_RCPT_STAT_DEFER
|| *status == DEL_RCPT_STAT_BOUNCE
|| *status == DEL_RCPT_STAT_TODO)
! && (probed || updated))
return (0);
}
msg_warn("bad address verify table entry: %.100s", buf);
--- 266,283 ----
*probed = atol(probed_text);
*updated = atol(updated_text);
*status = atoi(buf);
+
+ /*
+ * Coverity 200604: the code incorrectly tested (probed || updated),
+ * so that the sanity check never detected all-zero time stamps. Such
+ * records are never written. If we read a record with all-zero time
+ * stamps, then something is badly broken.
+ */
if ((*status == DEL_RCPT_STAT_OK
|| *status == DEL_RCPT_STAT_DEFER
|| *status == DEL_RCPT_STAT_BOUNCE
|| *status == DEL_RCPT_STAT_TODO)
! && (*probed || *updated))
return (0);
}
msg_warn("bad address verify table entry: %.100s", buf);
diff -cr /var/tmp/postfix-2.2.9/src/virtual/maildir.c ./src/virtual/maildir.c
*** /var/tmp/postfix-2.2.9/src/virtual/maildir.c Wed Jun 23 11:18:50 2004
--- ./src/virtual/maildir.c Wed Apr 5 15:13:10 2006
***************
*** 187,193 ****
|| (dst = vstream_fopen(tmpfile, O_WRONLY | O_CREAT | O_EXCL, 0600)) == 0)) {
vstring_sprintf(why, "create %s: %m", tmpfile);
} else if (fstat(vstream_fileno(dst), &st) < 0) {
! vstring_sprintf(why, "create %s: %m", tmpfile);
} else {
vstring_sprintf(buf, "%lu.V%lxI%lxM%lu.%s",
(unsigned long) starttime.tv_sec,
--- 187,199 ----
|| (dst = vstream_fopen(tmpfile, O_WRONLY | O_CREAT | O_EXCL, 0600)) == 0)) {
vstring_sprintf(why, "create %s: %m", tmpfile);
} else if (fstat(vstream_fileno(dst), &st) < 0) {
!
! /*
! * Coverity 200604: file descriptor leak in code that never executes.
! * Code replaced by msg_fatal(), as it is not worthwhile to continue
! * after an impossible error condition.
! */
! msg_fatal("fstat %s: %m", tmpfile);
} else {
vstring_sprintf(buf, "%lu.V%lxI%lxM%lu.%s",
(unsigned long) starttime.tv_sec,