mirror of
https://github.com/vdukhovni/postfix
synced 2025-08-22 01:49:47 +00:00
postfix-2.9-20110124
This commit is contained in:
parent
506b64785e
commit
ee034fdb56
@ -16514,3 +16514,16 @@ Apologies for any names omitted.
|
||||
Bugfix: support for the "dunno" command somehow disappeared
|
||||
from the postscreen_access_list implementation. File:
|
||||
postscreen/postscreen_access.c.
|
||||
|
||||
20110123
|
||||
|
||||
Feature: read/write deadlines. Deadlines were introduced
|
||||
with postscreen's dummy SMTP engine. In the Postfix SMTP
|
||||
client and server, deadlines limit the total amount of time
|
||||
to read or write one command line, one response line, or
|
||||
one line of message content. This reduces the impact of
|
||||
application exhaustion attacks that trickle data one byte
|
||||
at a time. Files: util/vstream.[hc], global/smtp_stream.c.
|
||||
|
||||
Cleanup: remove #ifdef MIGRATION_WARNING transitional code
|
||||
from postscreen. File: postscreen/postscreen.c.
|
||||
|
@ -505,7 +505,7 @@ mail:
|
||||
|
||||
3. Uncomment the new "smtpd pass ... smtpd" service in master.cf, and
|
||||
duplicate any "-o parameter=value" entries from the smtpd service that was
|
||||
commented out in step 1.
|
||||
commented out in the previous step.
|
||||
|
||||
/etc/postfix/master.cf:
|
||||
smtpd pass - - n - - smtpd
|
||||
|
@ -6,6 +6,9 @@ Wish list:
|
||||
|
||||
Things to do after the stable release:
|
||||
|
||||
Don't forget Apple's code donation for fetching mail from
|
||||
IMAP server.
|
||||
|
||||
vstream_peek_len() and vstream_peek_data() to count the
|
||||
unread data and to access it, respectively. vstream_peek_data()
|
||||
can access the saved read buffer if a double-buffered stream
|
||||
@ -35,6 +38,7 @@ Wish list:
|
||||
means that many tlsproxy_ parameters become postscreen_
|
||||
parameters, and that tls_server_init() parameters move to
|
||||
to tls_server_start(). That is a significant API change.
|
||||
It also means tlsproxy can't open all files before chroot().
|
||||
|
||||
anvil rate limit for sasl_username.
|
||||
|
||||
|
@ -701,7 +701,8 @@ that follow. </p>
|
||||
|
||||
<li> <p> Uncomment the new "<tt>smtpd pass ... smtpd</tt>" service
|
||||
in <a href="master.5.html">master.cf</a>, and duplicate any "<tt>-o parameter=value</tt>" entries
|
||||
from the smtpd service that was commented out in step 1. </p>
|
||||
from the smtpd service that was commented out in the previous step.
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
/etc/postfix/<a href="master.5.html">master.cf</a>:
|
||||
|
@ -701,7 +701,8 @@ that follow. </p>
|
||||
|
||||
<li> <p> Uncomment the new "<tt>smtpd pass ... smtpd</tt>" service
|
||||
in master.cf, and duplicate any "<tt>-o parameter=value</tt>" entries
|
||||
from the smtpd service that was commented out in step 1. </p>
|
||||
from the smtpd service that was commented out in the previous step.
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
/etc/postfix/master.cf:
|
||||
|
@ -20,7 +20,7 @@
|
||||
* Patches change both the patchlevel and the release date. Snapshots have no
|
||||
* patchlevel; they change the release date only.
|
||||
*/
|
||||
#define MAIL_RELEASE_DATE "20110120"
|
||||
#define MAIL_RELEASE_DATE "20110124"
|
||||
#define MAIL_VERSION_NUMBER "2.9"
|
||||
|
||||
#ifdef SNAPSHOT
|
||||
|
@ -52,7 +52,7 @@
|
||||
/* and write operations described below.
|
||||
/* This routine alters the behavior of streams as follows:
|
||||
/* .IP \(bu
|
||||
/* The read/write timeout is set to the specified value.
|
||||
/* The read/write total time limit is set to the specified value.
|
||||
/* .IP \f(bu
|
||||
/* The stream is configured to use double buffering.
|
||||
/* .IP \f(bu
|
||||
@ -151,6 +151,16 @@
|
||||
static void smtp_timeout_reset(VSTREAM *stream)
|
||||
{
|
||||
vstream_clearerr(stream);
|
||||
|
||||
/*
|
||||
* Important: the time limit feature must not introduce any system calls
|
||||
* when the input is already in the buffer, or when the output still fits
|
||||
* in the buffer. Such system calls would really hurt when receiving or
|
||||
* sending body content one line at a time.
|
||||
*/
|
||||
vstream_control(stream,
|
||||
VSTREAM_CTL_TIME_LIMIT, stream->timeout,
|
||||
VSTREAM_CTL_END);
|
||||
}
|
||||
|
||||
/* smtp_timeout_detect - test the per-stream timeout flag */
|
||||
|
@ -416,13 +416,6 @@ int var_psc_post_queue_limit;
|
||||
int var_psc_pre_queue_limit;
|
||||
int var_psc_watchdog;
|
||||
|
||||
#undef MIGRATION_WARNING
|
||||
|
||||
#ifdef MIGRATION_WARNING
|
||||
char *var_psc_wlist_nets;
|
||||
char *var_psc_blist_nets;
|
||||
|
||||
#endif
|
||||
char *var_psc_acl;
|
||||
char *var_psc_blist_action;
|
||||
|
||||
@ -495,11 +488,6 @@ HTABLE *psc_client_concurrency; /* per-client concurrency */
|
||||
/*
|
||||
* Local variables.
|
||||
*/
|
||||
#ifdef MIGRATION_WARNING
|
||||
static ADDR_MATCH_LIST *psc_wlist_nets; /* permanently whitelisted networks */
|
||||
static ADDR_MATCH_LIST *psc_blist_nets; /* permanently blacklisted networks */
|
||||
|
||||
#endif
|
||||
static ARGV *psc_acl; /* permanent white/backlist */
|
||||
static int psc_blist_action; /* PSC_ACT_DROP/ENFORCE/etc */
|
||||
|
||||
@ -715,47 +703,6 @@ static void psc_service(VSTREAM *smtp_client_stream,
|
||||
break;
|
||||
}
|
||||
}
|
||||
#ifdef MIGRATION_WARNING
|
||||
|
||||
/*
|
||||
* The permanent whitelist has highest precedence (never block mail from
|
||||
* whitelisted sites, and never run tests against those sites).
|
||||
*/
|
||||
if (psc_wlist_nets != 0
|
||||
&& psc_addr_match_list_match(psc_wlist_nets, state->smtp_client_addr)) {
|
||||
msg_info("WHITELISTED [%s]:%s", PSC_CLIENT_ADDR_PORT(state));
|
||||
psc_conclude(state);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* The permanent blacklist has second precedence. If the client is
|
||||
* permanently blacklisted, send some generic reply and hang up
|
||||
* immediately, or run more tests for logging purposes.
|
||||
*/
|
||||
if (psc_blist_nets != 0
|
||||
&& psc_addr_match_list_match(psc_blist_nets, state->smtp_client_addr)) {
|
||||
msg_info("BLACKLISTED [%s]:%s", PSC_CLIENT_ADDR_PORT(state));
|
||||
PSC_FAIL_SESSION_STATE(state, PSC_STATE_FLAG_BLIST_FAIL);
|
||||
switch (psc_blist_action) {
|
||||
case PSC_ACT_DROP:
|
||||
PSC_DROP_SESSION_STATE(state,
|
||||
"521 5.3.2 Service currently unavailable\r\n");
|
||||
return;
|
||||
case PSC_ACT_ENFORCE:
|
||||
PSC_ENFORCE_SESSION_STATE(state,
|
||||
"550 5.3.2 Service currently unavailable\r\n");
|
||||
break;
|
||||
case PSC_ACT_IGNORE:
|
||||
PSC_UNFAIL_SESSION_STATE(state, PSC_STATE_FLAG_BLIST_FAIL);
|
||||
/* Not: PSC_PASS_SESSION_STATE. Repeat this test the next time. */
|
||||
break;
|
||||
default:
|
||||
msg_panic("%s: unknown blacklist action value %d",
|
||||
myname, psc_blist_action);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* The temporary whitelist (i.e. the postscreen cache) has the lowest
|
||||
@ -787,7 +734,8 @@ static void psc_service(VSTREAM *smtp_client_stream,
|
||||
}
|
||||
|
||||
/*
|
||||
* Reply with 421 when we can't analyze more connections.
|
||||
* Reply with 421 when we can't analyze more connections. That also means
|
||||
* no deep protocol tests when the noforward flag is raised.
|
||||
*/
|
||||
if (var_psc_pre_queue_limit > 0
|
||||
&& psc_check_queue_length - psc_post_queue_length
|
||||
@ -841,21 +789,6 @@ static void pre_jail_init(char *unused_name, char **unused_argv)
|
||||
* Open read-only maps before dropping privilege, for consistency with
|
||||
* other Postfix daemons.
|
||||
*/
|
||||
#ifdef MIGRATION_WARNING
|
||||
if (*var_psc_wlist_nets)
|
||||
psc_wlist_nets =
|
||||
addr_match_list_init(MATCH_FLAG_NONE, var_psc_wlist_nets);
|
||||
|
||||
if (*var_psc_blist_nets)
|
||||
psc_blist_nets = addr_match_list_init(MATCH_FLAG_NONE,
|
||||
var_psc_blist_nets);
|
||||
if (psc_blist_nets || psc_wlist_nets) {
|
||||
msg_warn("The %s and %s features will be removed soon. Use %s instead",
|
||||
VAR_PSC_WLIST_NETS, VAR_PSC_BLIST_NETS, VAR_PSC_ACL);
|
||||
msg_warn("To stop this warning, specify empty values for %s and %s",
|
||||
VAR_PSC_WLIST_NETS, VAR_PSC_BLIST_NETS);
|
||||
}
|
||||
#endif
|
||||
psc_acl_pre_jail_init();
|
||||
if (*var_psc_acl)
|
||||
psc_acl = psc_acl_parse(var_psc_acl, VAR_PSC_ACL);
|
||||
@ -1095,10 +1028,6 @@ int main(int argc, char **argv)
|
||||
VAR_PSC_PIPEL_ACTION, DEF_PSC_PIPEL_ACTION, &var_psc_pipel_action, 1, 0,
|
||||
VAR_PSC_NSMTP_ACTION, DEF_PSC_NSMTP_ACTION, &var_psc_nsmtp_action, 1, 0,
|
||||
VAR_PSC_BARLF_ACTION, DEF_PSC_BARLF_ACTION, &var_psc_barlf_action, 1, 0,
|
||||
#ifdef MIGRATION_WARNING
|
||||
VAR_PSC_WLIST_NETS, DEF_PSC_WLIST_NETS, &var_psc_wlist_nets, 0, 0,
|
||||
VAR_PSC_BLIST_NETS, DEF_PSC_BLIST_NETS, &var_psc_blist_nets, 0, 0,
|
||||
#endif
|
||||
VAR_PSC_ACL, DEF_PSC_ACL, &var_psc_acl, 0, 0,
|
||||
VAR_PSC_BLIST_ACTION, DEF_PSC_BLIST_ACTION, &var_psc_blist_action, 1, 0,
|
||||
VAR_PSC_FORBID_CMDS, DEF_PSC_FORBID_CMDS, &var_psc_forbid_cmds, 0, 0,
|
||||
|
@ -304,6 +304,12 @@
|
||||
/* int. Use an explicit cast to avoid problems on LP64
|
||||
/* environments and other environments where ssize_t is larger
|
||||
/* than int.
|
||||
/* .IP "VSTREAM_CTL_TIME_LIMIT (int)"
|
||||
/* Specify an upper bound on the total time to complete all
|
||||
/* subsequent read or write operations. This is different from
|
||||
/* VSTREAM_CTL_TIMEOUT, which specifies a deadline for each
|
||||
/* read or write operation. Specify a relative time in seconds,
|
||||
/* or zero to disable this feature.
|
||||
/* .PP
|
||||
/* vstream_fileno() gives access to the file handle associated with
|
||||
/* a buffered stream. With streams that have separate read/write
|
||||
@ -522,6 +528,21 @@ VSTREAM vstream_fstd[] = {
|
||||
#define VSTREAM_FFLUSH_SOME(stream) \
|
||||
vstream_fflush_some((stream), (stream)->buf.len - (stream)->buf.cnt)
|
||||
|
||||
/* Note: this does not change a negative result into a zero result. */
|
||||
#define VSTREAM_SUB_TIME(x, y, z) \
|
||||
do { \
|
||||
(x).tv_sec = (y).tv_sec - (z).tv_sec; \
|
||||
(x).tv_usec = (y).tv_usec - (z).tv_usec; \
|
||||
while ((x).tv_usec < 0) { \
|
||||
(x).tv_usec += 1000000; \
|
||||
(x).tv_sec -= 1; \
|
||||
} \
|
||||
while ((x).tv_usec >= 1000000) { \
|
||||
(x).tv_usec -= 1000000; \
|
||||
(x).tv_sec += 1; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
/* vstream_buf_init - initialize buffer */
|
||||
|
||||
static void vstream_buf_init(VBUF *bp, int flags)
|
||||
@ -590,6 +611,9 @@ static int vstream_fflush_some(VSTREAM *stream, ssize_t to_flush)
|
||||
char *data;
|
||||
ssize_t len;
|
||||
ssize_t n;
|
||||
int timeout;
|
||||
struct timeval before;
|
||||
struct timeval elapsed;
|
||||
|
||||
/*
|
||||
* Sanity checks. It is illegal to flush a read-only stream. Otherwise,
|
||||
@ -630,14 +654,31 @@ static int vstream_fflush_some(VSTREAM *stream, ssize_t to_flush)
|
||||
* any.
|
||||
*/
|
||||
for (data = (char *) bp->data, len = to_flush; len > 0; len -= n, data += n) {
|
||||
if ((n = stream->write_fn(stream->fd, data, len, stream->timeout, stream->context)) <= 0) {
|
||||
if (bp->flags & VSTREAM_FLAG_DEADLINE) {
|
||||
timeout = stream->time_limit.tv_sec + (stream->time_limit.tv_usec > 0);
|
||||
if (timeout <= 0) {
|
||||
bp->flags |= (VSTREAM_FLAG_ERR | VSTREAM_FLAG_TIMEOUT);
|
||||
errno = ETIMEDOUT;
|
||||
return (VSTREAM_EOF);
|
||||
}
|
||||
if (len == to_flush)
|
||||
GETTIMEOFDAY(&before);
|
||||
else
|
||||
before = stream->iotime;
|
||||
} else
|
||||
timeout = stream->timeout;
|
||||
if ((n = stream->write_fn(stream->fd, data, len, timeout, stream->context)) <= 0) {
|
||||
bp->flags |= VSTREAM_FLAG_ERR;
|
||||
if (errno == ETIMEDOUT)
|
||||
bp->flags |= VSTREAM_FLAG_TIMEOUT;
|
||||
return (VSTREAM_EOF);
|
||||
}
|
||||
if (stream->timeout)
|
||||
if (timeout)
|
||||
GETTIMEOFDAY(&stream->iotime);
|
||||
if (bp->flags & VSTREAM_FLAG_DEADLINE) {
|
||||
VSTREAM_SUB_TIME(elapsed, stream->iotime, before);
|
||||
VSTREAM_SUB_TIME(stream->time_limit, stream->time_limit, elapsed);
|
||||
}
|
||||
if (msg_verbose > 2 && stream != VSTREAM_ERR && n != to_flush)
|
||||
msg_info("%s: %d flushed %ld/%ld", myname, stream->fd,
|
||||
(long) n, (long) to_flush);
|
||||
@ -698,6 +739,9 @@ static int vstream_buf_get_ready(VBUF *bp)
|
||||
VSTREAM *stream = VBUF_TO_APPL(bp, VSTREAM, buf);
|
||||
const char *myname = "vstream_buf_get_ready";
|
||||
ssize_t n;
|
||||
struct timeval before;
|
||||
struct timeval elapsed;
|
||||
int timeout;
|
||||
|
||||
/*
|
||||
* Detect a change of I/O direction or position. If so, flush any
|
||||
@ -759,7 +803,17 @@ static int vstream_buf_get_ready(VBUF *bp)
|
||||
* data as is available right now, whichever is less. Update the cached
|
||||
* file seek position, if any.
|
||||
*/
|
||||
switch (n = stream->read_fn(stream->fd, bp->data, bp->len, stream->timeout, stream->context)) {
|
||||
if (bp->flags & VSTREAM_FLAG_DEADLINE) {
|
||||
timeout = stream->time_limit.tv_sec + (stream->time_limit.tv_usec > 0);
|
||||
if (timeout <= 0) {
|
||||
bp->flags |= (VSTREAM_FLAG_ERR | VSTREAM_FLAG_TIMEOUT);
|
||||
errno = ETIMEDOUT;
|
||||
return (VSTREAM_EOF);
|
||||
}
|
||||
GETTIMEOFDAY(&before);
|
||||
} else
|
||||
timeout = stream->timeout;
|
||||
switch (n = stream->read_fn(stream->fd, bp->data, bp->len, timeout, stream->context)) {
|
||||
case -1:
|
||||
bp->flags |= VSTREAM_FLAG_ERR;
|
||||
if (errno == ETIMEDOUT)
|
||||
@ -769,8 +823,12 @@ static int vstream_buf_get_ready(VBUF *bp)
|
||||
bp->flags |= VSTREAM_FLAG_EOF;
|
||||
return (VSTREAM_EOF);
|
||||
default:
|
||||
if (stream->timeout)
|
||||
if (timeout)
|
||||
GETTIMEOFDAY(&stream->iotime);
|
||||
if (bp->flags & VSTREAM_FLAG_DEADLINE) {
|
||||
VSTREAM_SUB_TIME(elapsed, stream->iotime, before);
|
||||
VSTREAM_SUB_TIME(stream->time_limit, stream->time_limit, elapsed);
|
||||
}
|
||||
if (msg_verbose > 2)
|
||||
msg_info("%s: fd %d got %ld", myname, stream->fd, (long) n);
|
||||
bp->cnt = -n;
|
||||
@ -1082,6 +1140,7 @@ VSTREAM *vstream_fdopen(int fd, int flags)
|
||||
stream->context = 0;
|
||||
stream->jbuf = 0;
|
||||
stream->iotime.tv_sec = stream->iotime.tv_usec = 0;
|
||||
stream->time_limit.tv_sec = stream->time_limit.tv_usec = 0;
|
||||
stream->req_bufsize = VSTREAM_BUFSIZE;
|
||||
return (stream);
|
||||
}
|
||||
@ -1227,6 +1286,7 @@ void vstream_control(VSTREAM *stream, int name,...)
|
||||
int old_fd;
|
||||
ssize_t req_bufsize = 0;
|
||||
VSTREAM *stream2;
|
||||
int time_limit;
|
||||
|
||||
#define SWAP(type,a,b) do { type temp = (a); (a) = (b); (b) = (temp); } while (0)
|
||||
|
||||
@ -1334,6 +1394,24 @@ void vstream_control(VSTREAM *stream, int name,...)
|
||||
&& req_bufsize > stream->req_bufsize)
|
||||
stream->req_bufsize = req_bufsize;
|
||||
break;
|
||||
|
||||
/*
|
||||
* Make no gettimeofday() etc. system call until we really know
|
||||
* that we need to do I/O. This avoids a performance hit when
|
||||
* sending or receiving body content one line at a time.
|
||||
*/
|
||||
case VSTREAM_CTL_TIME_LIMIT:
|
||||
time_limit = va_arg(ap, int);
|
||||
if (time_limit < 0) {
|
||||
msg_panic("%s: bad time limit: %d", myname, time_limit);
|
||||
} else if (time_limit == 0) {
|
||||
stream->buf.flags &= ~VSTREAM_FLAG_DEADLINE;
|
||||
} else {
|
||||
stream->buf.flags |= VSTREAM_FLAG_DEADLINE;
|
||||
stream->time_limit.tv_sec = time_limit;
|
||||
stream->time_limit.tv_usec = 0;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
msg_panic("%s: bad name %d", myname, name);
|
||||
}
|
||||
|
@ -57,6 +57,7 @@ typedef struct VSTREAM {
|
||||
int timeout; /* read/write timout */
|
||||
VSTREAM_JMP_BUF *jbuf; /* exception handling */
|
||||
struct timeval iotime; /* time of last fill/flush */
|
||||
struct timeval time_limit; /* read/write time limit */
|
||||
} VSTREAM;
|
||||
|
||||
extern VSTREAM vstream_fstd[]; /* pre-defined streams */
|
||||
@ -76,6 +77,7 @@ extern VSTREAM vstream_fstd[]; /* pre-defined streams */
|
||||
#define VSTREAM_FLAG_SEEK (1<<10) /* seek info valid */
|
||||
#define VSTREAM_FLAG_NSEEK (1<<11) /* can't seek this file */
|
||||
#define VSTREAM_FLAG_DOUBLE (1<<12) /* double buffer */
|
||||
#define VSTREAM_FLAG_DEADLINE (1<<13) /* deadline active */
|
||||
|
||||
#define VSTREAM_PURGE_READ (1<<0) /* flush unread data */
|
||||
#define VSTREAM_PURGE_WRITE (1<<1) /* flush unwritten data */
|
||||
@ -133,6 +135,7 @@ extern void vstream_control(VSTREAM *, int,...);
|
||||
#endif
|
||||
#define VSTREAM_CTL_BUFSIZE 12
|
||||
#define VSTREAM_CTL_SWAP_FD 13
|
||||
#define VSTREAM_CTL_TIME_LIMIT 14
|
||||
|
||||
extern VSTREAM *PRINTFLIKE(1, 2) vstream_printf(const char *,...);
|
||||
extern VSTREAM *PRINTFLIKE(2, 3) vstream_fprintf(VSTREAM *, const char *,...);
|
||||
|
Loading…
x
Reference in New Issue
Block a user