20060823
- Bugfix (introduced Postfix 2.2): vstream_fdclose() did not
- flush unwritten output before disconnecting a stream from
- its file descriptor. File: util/vstream.c.
-
Bugfix (introduced Postfix 2.2): segfault when vstream_fclose()
attempted to flush unwritten output, after vstream_fdclose()
- disconnected the stream from its file descriptor. File:
- util/vstream.c.
+ had already disconnected the stream from its file descriptor.
+ File: util/vstream.c.
+
+ Bugfix (introduced Postfix 2.2): vstream_fdclose() did not
+ flush unwritten output before disconnecting a stream from
+ its file descriptor(s). File: util/vstream.c.
Feature: smtp-sink can capture mail to file, either as one
individual message per file, or as multiple messages per
Portability: inside functions, GCC 4 refuses forward
declarations of static functions. File: smtpstone/smtp-sink.c.
+20060825
+
+ Bugfix (introduced Postfix 2.3): with headers-only mail, a
+ Milter "header insert" action corrupted the queue file. The
+ cleanup server executed some end-of-body action before the
+ end-of-header actions. File: cleanup/cleanup_message.c.
+
+ Robustness: mail delivery agents now detect loops in queue
+ files. Files with too many backward jumps are saved to the
+ "corrupt" directory. File: global/record.c.
+
Wish list:
Make null local-part handling configurable: either expand
and use quotes to protect white space from the
shell. Command names are case-insensitive.
+ <b>-R</b> <i>root-directory</i>
+ Change the process root directory to the specified
+ location. This option requires super-user privi-
+ leges. See also the <b>-u</b> option.
+
<b>-s</b> <i>command,command,...</i>
Log the named commands to syslogd.
Limit the time for receiving a command or sending a
response. The time limit is specified in seconds.
+ <b>-u</b> <i>username</i>
+ Switch to the specified user privileges after open-
+ ing the network socket and optionally changing the
+ process root directory. This option is required
+ when the process runs with super-user privileges.
+ See also the <b>-R</b> option.
+
<b>-v</b> Show the SMTP conversations.
<b>-w</b> <i>delay</i>
DATA, ., RSET, NOOP, and QUIT. Separate command names by
white space or commas, and use quotes to protect white space
from the shell. Command names are case-insensitive.
+.IP "\fB-R \fIroot-directory\fR"
+Change the process root directory to the specified location.
+This option requires super-user privileges. See also the
+\fB-u\fR option.
.IP "\fB-s \fIcommand,command,...\fR"
Log the named commands to syslogd.
.sp
.IP "\fB-t \fItimeout\fR (default: 100)"
Limit the time for receiving a command or sending a response.
The time limit is specified in seconds.
+.IP "\fB-u \fIusername\fR"
+Switch to the specified user privileges after opening the
+network socket and optionally changing the process root
+directory. This option is required when the process runs
+with super-user privileges. See also the \fB-R\fR option.
.IP \fB-v\fR
Show the SMTP conversations.
.IP "\fB-w \fIdelay\fR"
* current file position so we can compute the message size lateron.
*/
else if (type == REC_TYPE_XTRA) {
+ state->mime_errs = mime_state_update(state->mime_state, type, buf, len);
if (state->milters || cleanup_milters)
/* Make room for body modification. */
cleanup_out_format(state, REC_TYPE_PTR, REC_TYPE_PTR_FORMAT, 0L);
- state->mime_errs = mime_state_update(state->mime_state, type, buf, len);
/* Ignore header truncation after primary message headers. */
state->mime_errs &= ~MIME_ERR_TRUNC_HEADER;
if (state->mime_errs && state->reason == 0) {
* Patches change both the patchlevel and the release date. Snapshots have no
* patchlevel; they change the release date only.
*/
-#define MAIL_RELEASE_DATE "20060824"
+#define MAIL_RELEASE_DATE "20060825"
#define MAIL_VERSION_NUMBER "2.4"
#ifdef SNAPSHOT
int rec_goto(VSTREAM *stream, const char *buf)
{
off_t offset;
+ static const char *saved_path;
+ static off_t saved_offset;
+ static int reverse_count;
+ /*
+ * Crude workaround for queue file loops. VSTREAMs currently have no
+ * option to attach application-specific data, so we use global state and
+ * simple logic to detect if an application switches streams. We trigger
+ * on reverse jumps only. There's one reverse jump for every inserted
+ * header, but only one reverse jump for all appended recipients. No-one
+ * is likely to insert 10000 message headers, but someone might append
+ * 10000 recipients.
+ */
+#define STREQ(x,y) ((x) == (y) && strcmp((x), (y)) == 0)
+#define REVERSE_JUMP_LIMIT 10000
+
+ if (!STREQ(saved_path, VSTREAM_PATH(stream))) {
+ saved_path = VSTREAM_PATH(stream);
+ reverse_count = 0;
+ saved_offset = 0;
+ }
while (ISSPACE(*buf))
buf++;
if ((offset = off_cvt_string(buf)) < 0) {
msg_warn("%s: malformed pointer record value: %s",
VSTREAM_PATH(stream), buf);
return (REC_TYPE_ERROR);
+ } else if (offset < saved_offset && ++reverse_count > REVERSE_JUMP_LIMIT) {
+ msg_warn("%s: too many reverse jump records", VSTREAM_PATH(stream));
+ return (REC_TYPE_ERROR);
} else if (offset > 0 && vstream_fseek(stream, offset, SEEK_SET) < 0) {
msg_warn("%s: seek error after pointer record: %m",
VSTREAM_PATH(stream));
return (REC_TYPE_ERROR);
} else {
+ saved_offset = offset;
return (0);
}
}
/* DATA, ., RSET, NOOP, and QUIT. Separate command names by
/* white space or commas, and use quotes to protect white space
/* from the shell. Command names are case-insensitive.
+/* .IP "\fB-R \fIroot-directory\fR"
+/* Change the process root directory to the specified location.
+/* This option requires super-user privileges. See also the
+/* \fB-u\fR option.
/* .IP "\fB-s \fIcommand,command,...\fR"
/* Log the named commands to syslogd.
/* .sp
/* .IP "\fB-t \fItimeout\fR (default: 100)"
/* Limit the time for receiving a command or sending a response.
/* The time limit is specified in seconds.
+/* .IP "\fB-u \fIusername\fR"
+/* Switch to the specified user privileges after opening the
+/* network socket and optionally changing the process root
+/* directory. This option is required when the process runs
+/* with super-user privileges. See also the \fB-R\fR option.
/* .IP \fB-v\fR
/* Show the SMTP conversations.
/* .IP "\fB-w \fIdelay\fR"
static void usage(char *myname)
{
- msg_fatal("usage: %s [-468acCeEFLpPv] [-f commands] [-h hostname] [-m max_concurrency] [-n quit_count] [-q commands] [-r commands] [-s commands] [-w delay] [-d dump-template] [-D dump-template] [-S start-string] [host]:port backlog", myname);
+ msg_fatal("usage: %s [-468acCeEFLpPv] [-f commands] [-h hostname] [-m max_concurrency] [-n quit_count] [-q commands] [-r commands] [-s commands] [-w delay] [-d dump-template] [-D dump-template] [-R root-dir] [-S start-string] [-u user_privs] [host]:port backlog", myname);
}
int main(int argc, char **argv)
int ch;
const char *protocols = INET_PROTO_NAME_ALL;
INET_PROTO_INFO *proto_info;
+ const char *root_dir = 0;
+ const char *user_privs = 0;
/*
* Fix 20051207.
/*
* Parse JCL.
*/
- while ((ch = GETOPT(argc, argv, "468acCeEf:Fh:Ln:m:pPq:r:s:S:t:vw:d:D:")) > 0) {
+ while ((ch = GETOPT(argc, argv, "468acCd:D:eEf:Fh:Ln:m:pPq:r:R:s:S:t:u:vw:")) > 0) {
switch (ch) {
case '4':
protocols = INET_PROTO_NAME_IPV4;
set_cmds_flags(optarg, FLAG_SOFT_ERR);
disable_pipelining = 1;
break;
+ case 'R':
+ root_dir = optarg;
+ break;
case 's':
openlog(basename(argv[0]), LOG_PID, LOG_MAIL);
set_cmds_flags(optarg, FLAG_SYSLOG);
if ((var_tmout = atoi(optarg)) <= 0)
msg_fatal("bad timeout: %s", optarg);
break;
+ case 'u':
+ user_privs = optarg;
+ break;
case 'v':
msg_verbose++;
break;
usage(argv[0]);
if (single_template && shared_template)
msg_fatal("use only one of -d or -D, but not both");
+ if (geteuid() == 0 && user_privs == 0)
+ msg_fatal("-u option is required if running as root");
/*
* Initialize.
argv[optind] += 5;
sock = inet_listen(argv[optind], backlog, BLOCKING);
}
+ if (user_privs)
+ chroot_uid(root_dir, user_privs);
if (single_template)
mysrand((int) time((time_t *) 0));