2
0
mirror of https://github.com/vdukhovni/postfix synced 2025-09-02 07:05:27 +00:00

postfix-2.3-20051014

This commit is contained in:
Wietse Venema
2005-10-14 00:00:00 -05:00
committed by Viktor Dukhovni
parent 9dba3caad0
commit 3bb375dbd2
16 changed files with 529 additions and 229 deletions

View File

@@ -11177,7 +11177,7 @@ Apologies for any names omitted.
due to expensive crypto operations. Files: global/anvil_clnt.c, due to expensive crypto operations. Files: global/anvil_clnt.c,
anvil/anvil.c, smtpd/smtpd.c. anvil/anvil.c, smtpd/smtpd.c.
Cleanup: eliminated massive code duplicatiom in the anvil Cleanup: eliminated massive code duplication in the anvil
server that resulted from adding similar features one at a server that resulted from adding similar features one at a
time. File: anvil/anvil.c. time. File: anvil/anvil.c.
@@ -11191,6 +11191,37 @@ Apologies for any names omitted.
many MAIL FROM or RCPT TO commands) when we aren't closing many MAIL FROM or RCPT TO commands) when we aren't closing
the connection. File: smtpd/smtpd.c. the connection. File: smtpd/smtpd.c.
20051012
Polishing: content of comments and sequence of code blocks
in the anvil server, TLS request rate error message in the
smtp server, and documentation, but no changes in code.
Files: anvil/anvil.c, smtpd/smtpd.c.
20051013
Horror: some systems have basename() and dirname() and some
don't; some implementations modify their input and some
don't; and some implementations use a private buffer that
is overwritten upon the next call. Postfix will use its own
safer versions called sane_basename() and sane_dirname().
These never modify the input, and allow the caller to control
how memory is allocated for the result. File:
util/sane_basename.c.
Feature: "sendmail -C path-to-main.cf" and "sendmail -C
config_directory" now do what one would expect. File:
sendmail/sendmail.c.
Bugfix: don't do smtpd_end_of_data_restrictions after the
transaction failed due to, e.g., a write error. File:
smtpd/smtpd.c.
Cleanup: the SMTP server now enforces the message_size_limit
even when the client did not send SIZE information with the
MAIL FROM command. This protects before-queue content
filters against over-size messages. File: smtpd/smtpd.c.
Open problems: Open problems:
Try to recognize that Resent- headers appear in blocks, Try to recognize that Resent- headers appear in blocks,
@@ -11199,11 +11230,6 @@ Open problems:
Hard limits on cache sizes (anvil, specifically). Hard limits on cache sizes (anvil, specifically).
Look for systems with XPG basename() declared in <libgen.h>,
and prepare for phasing out the Postfix-supplied one.
Beware, however, that XPG basename() takes (char *), and
not (const char *) because it may change its argument.
Laptop friendliness: make the qmgr remember when the next Laptop friendliness: make the qmgr remember when the next
deferred queue scan needs to be done, and have the pickup deferred queue scan needs to be done, and have the pickup
server stat() the maildrop directory before searching it. server stat() the maildrop directory before searching it.
@@ -11213,11 +11239,6 @@ Open problems:
Or do we punt the issue and issue X-Postfix for all errors Or do we punt the issue and issue X-Postfix for all errors
except SMTP? except SMTP?
Implement smtp_greet() routine to distinguish between reject
before versus after sending HELO/EHLO; this is needed to
eliminate the hack that uses one character lookahead to
find out if the server wants to talk to us.
Low: replace_sender/replace_recipient actions in access Low: replace_sender/replace_recipient actions in access
maps? maps?

View File

@@ -26,10 +26,11 @@ files. With deeply nested aliases or .forward files, this can greatly
reduce the number of queue files and cleanup process instances. To reduce the number of queue files and cleanup process instances. To
get the earlier behavior, specify "frozen_delivered_to = no". get the earlier behavior, specify "frozen_delivered_to = no".
The frozen_delivered_to feature also fixes a long-standing problem The frozen_delivered_to feature can help to alleviate a long-standing
with multiple deliveries to recipients that are listed in multiple problem with multiple deliveries to recipients that are listed
nested aliases, but does so only when only the top-level alias has multiple times in a hierarchy of nested aliases. For this to work,
an owner- alias, and none of the subordinate aliases. only the top-level alias should have an owner- alias, and none of
the subordinate aliases.
Major changes with snapshot 20051011 Major changes with snapshot 20051011
==================================== ====================================

View File

@@ -107,10 +107,16 @@ SENDMAIL(1) SENDMAIL(1)
This feature is available in Postfix version 2.1 This feature is available in Postfix version 2.1
and later. and later.
<b>-C</b> <i>config</i><b>_</b><i>file</i> (ignored) <b>-C</b> <i>config</i><b>_</b><i>file</i>
The path name of the <b>sendmail.cf</b> file. Postfix con-
figuration files are kept in the <b>/etc/postfix</b> <b>-C</b> <i>config</i><b>_</b><i>dir</i>
directory. The path name of the Postfix <b>main.cf</b> file, or of
its parent directory. This information is ignored
with Postfix versions before 2.3.
With older Postfix versions, specify a directory
pathname with the MAIL_CONFIG environment variable
to override the location of configuration files.
<b>-F</b> <i>full</i><b>_</b><i>name</i> <b>-F</b> <i>full</i><b>_</b><i>name</i>
Set the sender full name. This is used only with Set the sender full name. This is used only with

View File

@@ -91,9 +91,15 @@ report after verifying each recipient address. This is useful
for testing address rewriting and routing configurations. for testing address rewriting and routing configurations.
.sp .sp
This feature is available in Postfix version 2.1 and later. This feature is available in Postfix version 2.1 and later.
.IP "\fB-C \fIconfig_file\fR (ignored)" .IP "\fB-C \fIconfig_file\fR"
The path name of the \fBsendmail.cf\fR file. Postfix configuration .IP "\fB-C \fIconfig_dir\fR"
files are kept in the \fB/etc/postfix\fR directory. The path name of the Postfix \fBmain.cf\fR file, or of its
parent directory. This information is ignored with Postfix
versions before 2.3.
With older Postfix versions, specify a directory pathname
with the MAIL_CONFIG environment variable to override the
location of configuration files.
.IP "\fB-F \fIfull_name\fR .IP "\fB-F \fIfull_name\fR
Set the sender full name. This is used only with messages that Set the sender full name. This is used only with messages that
have no \fBFrom:\fR message header. have no \fBFrom:\fR message header.

View File

@@ -276,17 +276,168 @@
/* Application-specific. */ /* Application-specific. */
/*
* Configuration parameters.
*/
int var_anvil_time_unit; int var_anvil_time_unit;
int var_anvil_stat_time; int var_anvil_stat_time;
/* /*
* State. * Global dynamic state.
*/ */
static HTABLE *anvil_remote_map; /* indexed by service+ remote client */ static HTABLE *anvil_remote_map; /* indexed by service+ remote client */
/* /*
* Absent a real-time query interface, these are logged at process exit time * Remote connection state, one instance for each (service, client) pair.
* and at regular intervals. */
typedef struct {
char *ident; /* lookup key */
int count; /* connection count */
int rate; /* connection rate */
int mail; /* message rate */
int rcpt; /* recipient rate */
int ntls; /* new TLS session rate */
time_t start; /* time of first rate sample */
} ANVIL_REMOTE;
/*
* Local server state, one instance per anvil client connection. This allows
* us to clean up remote connection state when a local server goes away
* without cleaning up.
*/
typedef struct {
ANVIL_REMOTE *anvil_remote; /* XXX should be list */
} ANVIL_LOCAL;
/*
* The following operations are implemented as macros with recognizable
* names so that we don't lose sight of what the code is trying to do.
*
* Related operations are defined side by side so that the code implementing
* them isn't pages apart.
*/
/* Create new (service, client) state. */
#define ANVIL_REMOTE_FIRST_CONN(remote, id) \
do { \
(remote)->ident = mystrdup(id); \
(remote)->count = 1; \
(remote)->rate = 1; \
(remote)->mail = 0; \
(remote)->rcpt = 0; \
(remote)->ntls = 0; \
(remote)->start = event_time(); \
} while(0)
/* Destroy unused (service, client) state. */
#define ANVIL_REMOTE_FREE(remote) \
do { \
myfree((remote)->ident); \
myfree((char *) (remote)); \
} while(0)
/* Reset or update rate information for existing (service, client) state. */
#define ANVIL_REMOTE_RSET_RATE(remote, _start) \
do { \
(remote)->rate = 0; \
(remote)->mail = 0; \
(remote)->rcpt = 0; \
(remote)->ntls = 0; \
(remote)->start = _start; \
} while(0)
#define ANVIL_REMOTE_INCR_RATE(remote, _what) \
do { \
time_t _now = event_time(); \
if ((remote)->start + var_anvil_time_unit < _now) \
ANVIL_REMOTE_RSET_RATE((remote), _now); \
if ((remote)->_what < INT_MAX) \
(remote)->_what += 1; \
} while(0)
/* Update existing (service, client) state. */
#define ANVIL_REMOTE_NEXT_CONN(remote) \
do { \
ANVIL_REMOTE_INCR_RATE((remote), rate); \
if ((remote)->count == 0) \
event_cancel_timer(anvil_remote_expire, (char *) remote); \
(remote)->count++; \
} while(0)
#define ANVIL_REMOTE_INCR_MAIL(remote) ANVIL_REMOTE_INCR_RATE((remote), mail)
#define ANVIL_REMOTE_INCR_RCPT(remote) ANVIL_REMOTE_INCR_RATE((remote), rcpt)
#define ANVIL_REMOTE_INCR_NTLS(remote) ANVIL_REMOTE_INCR_RATE((remote), ntls)
/* Drop connection from (service, client) state. */
#define ANVIL_REMOTE_DROP_ONE(remote) \
do { \
if ((remote) && (remote)->count > 0) { \
if (--(remote)->count == 0) \
event_request_timer(anvil_remote_expire, (char *) remote, \
var_anvil_time_unit); \
} \
} while(0)
/* Create local server state. */
#define ANVIL_LOCAL_INIT(local) \
do { \
(local)->anvil_remote = 0; \
} while(0)
/* Add remote connection to local server. */
#define ANVIL_LOCAL_ADD_ONE(local, remote) \
do { \
/* XXX allow multiple remote clients per local server. */ \
if ((local)->anvil_remote) \
ANVIL_REMOTE_DROP_ONE((local)->anvil_remote); \
(local)->anvil_remote = (remote); \
} while(0)
/* Test if this remote connection is listed for this local server. */
#define ANVIL_LOCAL_REMOTE_LINKED(local, remote) \
((local)->anvil_remote == (remote))
/* Drop specific remote connection from local server. */
#define ANVIL_LOCAL_DROP_ONE(local, remote) \
do { \
/* XXX allow multiple remote clients per local server. */ \
if ((local)->anvil_remote == (remote)) \
(local)->anvil_remote = 0; \
} while(0)
/* Drop all remote connections from local server. */
#define ANVIL_LOCAL_DROP_ALL(stream, local) \
do { \
/* XXX allow multiple remote clients per local server. */ \
if ((local)->anvil_remote) \
anvil_remote_disconnect((stream), (local)->anvil_remote->ident); \
} while (0)
/*
* Lookup table to map request names to action routines.
*/
typedef struct {
const char *name;
void (*action) (VSTREAM *, const char *);
} ANVIL_REQ_TABLE;
/*
* Run-time statistics for maximal connection counts and event rates. These
* store the peak resource usage, remote connection, and time. Absent a
* query interface, this information is logged at process exit time and at
* configurable intervals.
*/ */
typedef struct { typedef struct {
int value; /* peak value */ int value; /* peak value */
@@ -336,151 +487,6 @@ static time_t max_cache_time; /* time of peak size */
} \ } \
} while (0); } while (0);
/*
* Remote connection state, one instance for each (service, client) pair.
*/
typedef struct {
char *ident; /* lookup key */
int count; /* connection count */
int rate; /* connection rate */
int mail; /* message rate */
int rcpt; /* recipient rate */
int ntls; /* new TLS session rate */
time_t start; /* time of first rate sample */
} ANVIL_REMOTE;
/*
* Local server state, one per server instance. This allows us to clean up
* connection state when a local server goes away without cleaning up.
*/
typedef struct {
ANVIL_REMOTE *anvil_remote; /* XXX should be list */
} ANVIL_LOCAL;
/*
* The following operations are implemented as macros with recognizable
* names so that we don't lose sight of what the code is trying to do.
*
* Related operations are defined side by side so that the code implementing
* them isn't pages apart.
*/
/* Create new (service, client) state. */
#define ANVIL_REMOTE_FIRST_CONN(remote, id) \
do { \
(remote)->ident = mystrdup(id); \
(remote)->count = 1; \
(remote)->rate = 1; \
(remote)->mail = 0; \
(remote)->rcpt = 0; \
(remote)->ntls = 0; \
(remote)->start = event_time(); \
} while(0)
/* Destroy unused (service, client) state. */
#define ANVIL_REMOTE_FREE(remote) \
do { \
myfree((remote)->ident); \
myfree((char *) (remote)); \
} while(0)
/* Reset event rate counters and start of data collection interval. */
#define ANVIL_REMOTE_RSET_RATE(remote, _start) \
do { \
(remote)->rate = 0; \
(remote)->mail = 0; \
(remote)->rcpt = 0; \
(remote)->ntls = 0; \
(remote)->start = _start; \
} while(0)
/* Add connection to (service, client) state. */
#define ANVIL_REMOTE_INCR_RATE(remote, _what) \
do { \
time_t _now = event_time(); \
if ((remote)->start + var_anvil_time_unit < _now) \
ANVIL_REMOTE_RSET_RATE((remote), _now); \
if ((remote)->_what < INT_MAX) \
(remote)->_what += 1; \
} while(0)
#define ANVIL_REMOTE_NEXT_CONN(remote) \
do { \
ANVIL_REMOTE_INCR_RATE((remote), rate); \
if ((remote)->count == 0) \
event_cancel_timer(anvil_remote_expire, (char *) remote); \
(remote)->count++; \
} while(0)
#define ANVIL_REMOTE_INCR_MAIL(remote) ANVIL_REMOTE_INCR_RATE((remote), mail)
#define ANVIL_REMOTE_INCR_RCPT(remote) ANVIL_REMOTE_INCR_RATE((remote), rcpt)
#define ANVIL_REMOTE_INCR_NTLS(remote) ANVIL_REMOTE_INCR_RATE((remote), ntls)
/* Drop connection from (service, client) state. */
#define ANVIL_REMOTE_DROP_ONE(remote) \
do { \
if ((remote) && (remote)->count > 0) { \
if (--(remote)->count == 0) \
event_request_timer(anvil_remote_expire, (char *) remote, \
var_anvil_time_unit); \
} \
} while(0)
/* Create local server state. */
#define ANVIL_LOCAL_INIT(local) \
do { \
(local)->anvil_remote = 0; \
} while(0)
/* Add connection to local server. */
#define ANVIL_LOCAL_ADD_ONE(local, remote) \
do { \
/* XXX allow multiple remote clients per local server. */ \
if ((local)->anvil_remote) \
ANVIL_REMOTE_DROP_ONE((local)->anvil_remote); \
(local)->anvil_remote = (remote); \
} while(0)
/* Test if this remote site is listed for this local client. */
#define ANVIL_LOCAL_REMOTE_LINKED(local, remote) \
((local)->anvil_remote == (remote))
/* Drop connection from local server. */
#define ANVIL_LOCAL_DROP_ONE(local, remote) \
do { \
/* XXX allow multiple remote clients per local server. */ \
if ((local)->anvil_remote == (remote)) \
(local)->anvil_remote = 0; \
} while(0)
/* Drop all connections from local server. */
#define ANVIL_LOCAL_DROP_ALL(stream, local) \
do { \
/* XXX allow multiple remote clients per local server. */ \
if ((local)->anvil_remote) \
anvil_remote_disconnect((stream), (local)->anvil_remote->ident); \
} while (0)
/*
* Lookup table to map request names to action routines.
*/
typedef struct {
const char *name;
void (*action) (VSTREAM *, const char *);
} ANVIL_REQ_TABLE;
/* /*
* Silly little macros. * Silly little macros.
*/ */
@@ -587,8 +593,8 @@ static ANVIL_REMOTE *anvil_remote_conn_update(VSTREAM *client_stream, const char
} }
/* /*
* Record this connection under the local client information, so that we * Record this connection under the local server information, so that we
* can clean up all its connection state when the local client goes away. * can clean up all its connection state when the local server goes away.
*/ */
if ((anvil_local = (ANVIL_LOCAL *) vstream_context(client_stream)) == 0) { if ((anvil_local = (ANVIL_LOCAL *) vstream_context(client_stream)) == 0) {
anvil_local = (ANVIL_LOCAL *) mymalloc(sizeof(*anvil_local)); anvil_local = (ANVIL_LOCAL *) mymalloc(sizeof(*anvil_local));
@@ -617,7 +623,7 @@ static void anvil_remote_connect(VSTREAM *client_stream, const char *ident)
anvil_remote = anvil_remote_conn_update(client_stream, ident); anvil_remote = anvil_remote_conn_update(client_stream, ident);
/* /*
* Respond to the local client. * Respond to the local server.
*/ */
attr_print_plain(client_stream, ATTR_FLAG_NONE, attr_print_plain(client_stream, ATTR_FLAG_NONE,
ATTR_TYPE_NUM, ANVIL_ATTR_STATUS, ANVIL_STAT_OK, ATTR_TYPE_NUM, ANVIL_ATTR_STATUS, ANVIL_STAT_OK,
@@ -648,7 +654,7 @@ static void anvil_remote_mail(VSTREAM *client_stream, const char *ident)
anvil_remote = anvil_remote_conn_update(client_stream, ident); anvil_remote = anvil_remote_conn_update(client_stream, ident);
/* /*
* Update message delivery request rate and respond to local client. * Update message delivery request rate and respond to local server.
*/ */
ANVIL_REMOTE_INCR_MAIL(anvil_remote); ANVIL_REMOTE_INCR_MAIL(anvil_remote);
attr_print_plain(client_stream, ATTR_FLAG_NONE, attr_print_plain(client_stream, ATTR_FLAG_NONE,
@@ -677,7 +683,7 @@ static void anvil_remote_rcpt(VSTREAM *client_stream, const char *ident)
anvil_remote = anvil_remote_conn_update(client_stream, ident); anvil_remote = anvil_remote_conn_update(client_stream, ident);
/* /*
* Update recipient address rate and respond to local client. * Update recipient address rate and respond to local server.
*/ */
ANVIL_REMOTE_INCR_RCPT(anvil_remote); ANVIL_REMOTE_INCR_RCPT(anvil_remote);
attr_print_plain(client_stream, ATTR_FLAG_NONE, attr_print_plain(client_stream, ATTR_FLAG_NONE,
@@ -706,7 +712,7 @@ static void anvil_remote_newtls(VSTREAM *client_stream, const char *ident)
anvil_remote = anvil_remote_conn_update(client_stream, ident); anvil_remote = anvil_remote_conn_update(client_stream, ident);
/* /*
* Update newtls rate and respond to local client. * Update newtls rate and respond to local server.
*/ */
ANVIL_REMOTE_INCR_NTLS(anvil_remote); ANVIL_REMOTE_INCR_NTLS(anvil_remote);
attr_print_plain(client_stream, ATTR_FLAG_NONE, attr_print_plain(client_stream, ATTR_FLAG_NONE,
@@ -747,7 +753,7 @@ static void anvil_remote_newtls_stat(VSTREAM *client_stream, const char *ident)
} }
/* /*
* Respond to local client. * Respond to local server.
*/ */
attr_print_plain(client_stream, ATTR_FLAG_NONE, attr_print_plain(client_stream, ATTR_FLAG_NONE,
ATTR_TYPE_NUM, ANVIL_ATTR_STATUS, ANVIL_STAT_OK, ATTR_TYPE_NUM, ANVIL_ATTR_STATUS, ANVIL_STAT_OK,
@@ -769,8 +775,8 @@ static void anvil_remote_disconnect(VSTREAM *client_stream, const char *ident)
(unsigned long) client_stream, ident); (unsigned long) client_stream, ident);
/* /*
* Update local and remote info if this remote site is listed for this * Update local and remote info if this remote connection is listed for
* local client. * this local server.
*/ */
if ((anvil_local = (ANVIL_LOCAL *) vstream_context(client_stream)) != 0 if ((anvil_local = (ANVIL_LOCAL *) vstream_context(client_stream)) != 0
&& (anvil_remote = && (anvil_remote =
@@ -784,7 +790,7 @@ static void anvil_remote_disconnect(VSTREAM *client_stream, const char *ident)
myname, (unsigned long) anvil_local); myname, (unsigned long) anvil_local);
/* /*
* Respond to the local client. * Respond to the local server.
*/ */
attr_print_plain(client_stream, ATTR_FLAG_NONE, attr_print_plain(client_stream, ATTR_FLAG_NONE,
ATTR_TYPE_NUM, ANVIL_ATTR_STATUS, ANVIL_STAT_OK, ATTR_TYPE_NUM, ANVIL_ATTR_STATUS, ANVIL_STAT_OK,
@@ -805,8 +811,8 @@ static void anvil_service_done(VSTREAM *client_stream, char *unused_service,
(unsigned long) client_stream); (unsigned long) client_stream);
/* /*
* Look up the local client, and get rid of open remote connection state * Look up the local server, and get rid of any remote connection state
* that we still have for this local client. Do not destroy remote client * that we still have for this local server. Do not destroy remote client
* status information before it expires. * status information before it expires.
*/ */
if ((anvil_local = (ANVIL_LOCAL *) vstream_context(client_stream)) != 0) { if ((anvil_local = (ANVIL_LOCAL *) vstream_context(client_stream)) != 0) {
@@ -820,6 +826,31 @@ static void anvil_service_done(VSTREAM *client_stream, char *unused_service,
vstream_fileno(client_stream)); vstream_fileno(client_stream));
} }
/* anvil_status_dump - log and reset extreme usage */
static void anvil_status_dump(char *unused_name, char **unused_argv)
{
ANVIL_MAX_RATE_REPORT(max_conn_rate, "connection");
ANVIL_MAX_COUNT_REPORT(max_conn_count, "connection");
ANVIL_MAX_RATE_REPORT(max_mail_rate, "message");
ANVIL_MAX_RATE_REPORT(max_rcpt_rate, "recipient");
ANVIL_MAX_RATE_REPORT(max_ntls_rate, "newtls");
if (max_cache_size > 0) {
msg_info("statistics: max cache size %d at %.15s",
max_cache_size, ctime(&max_cache_time) + 4);
max_cache_size = 0;
}
}
/* anvil_status_update - log and reset extreme usage periodically */
static void anvil_status_update(int unused_event, char *context)
{
anvil_status_dump((char *) 0, (char **) 0);
event_request_timer(anvil_status_update, context, var_anvil_stat_time);
}
/* anvil_service - perform service for client */ /* anvil_service - perform service for client */
static void anvil_service(VSTREAM *client_stream, char *unused_service, char **argv) static void anvil_service(VSTREAM *client_stream, char *unused_service, char **argv)
@@ -889,8 +920,6 @@ static void anvil_service(VSTREAM *client_stream, char *unused_service, char **a
/* post_jail_init - post-jail initialization */ /* post_jail_init - post-jail initialization */
static void anvil_status_update(int, char *);
static void post_jail_init(char *unused_name, char **unused_argv) static void post_jail_init(char *unused_name, char **unused_argv)
{ {
@@ -910,31 +939,6 @@ static void post_jail_init(char *unused_name, char **unused_argv)
var_use_limit = 0; var_use_limit = 0;
} }
/* anvil_status_dump - log and reset extreme usage */
static void anvil_status_dump(char *unused_name, char **unused_argv)
{
ANVIL_MAX_RATE_REPORT(max_conn_rate, "connection");
ANVIL_MAX_COUNT_REPORT(max_conn_count, "connection");
ANVIL_MAX_RATE_REPORT(max_mail_rate, "message");
ANVIL_MAX_RATE_REPORT(max_rcpt_rate, "recipient");
ANVIL_MAX_RATE_REPORT(max_ntls_rate, "newtls");
if (max_cache_size > 0) {
msg_info("statistics: max cache size %d at %.15s",
max_cache_size, ctime(&max_cache_time) + 4);
max_cache_size = 0;
}
}
/* anvil_status_update - log and reset extreme usage periodically */
static void anvil_status_update(int unused_event, char *context)
{
anvil_status_dump((char *) 0, (char **) 0);
event_request_timer(anvil_status_update, context, var_anvil_stat_time);
}
/* main - pass control to the multi-threaded skeleton */ /* main - pass control to the multi-threaded skeleton */
int main(int argc, char **argv) int main(int argc, char **argv)

View File

@@ -20,7 +20,7 @@
* Patches change both the patchlevel and the release date. Snapshots have no * Patches change both the patchlevel and the release date. Snapshots have no
* patchlevel; they change the release date only. * patchlevel; they change the release date only.
*/ */
#define MAIL_RELEASE_DATE "20051011" #define MAIL_RELEASE_DATE "20051014"
#define MAIL_VERSION_NUMBER "2.3" #define MAIL_VERSION_NUMBER "2.3"
#ifdef SNAPSHOT #ifdef SNAPSHOT

View File

@@ -249,7 +249,7 @@ int main(int argc, char **argv)
*/ */
argv[0] = "postdrop"; argv[0] = "postdrop";
msg_vstream_init(argv[0], VSTREAM_ERR); msg_vstream_init(argv[0], VSTREAM_ERR);
msg_syslog_init(mail_task(argv[0]), LOG_PID, LOG_FACILITY); msg_syslog_init(mail_task("postdrop"), LOG_PID, LOG_FACILITY);
set_mail_conf_str(VAR_PROCNAME, var_procname = mystrdup(argv[0])); set_mail_conf_str(VAR_PROCNAME, var_procname = mystrdup(argv[0]));
/* /*

View File

@@ -59,7 +59,6 @@ postqueue.o: ../../include/argv.h
postqueue.o: ../../include/attr.h postqueue.o: ../../include/attr.h
postqueue.o: ../../include/clean_env.h postqueue.o: ../../include/clean_env.h
postqueue.o: ../../include/connect.h postqueue.o: ../../include/connect.h
postqueue.o: ../../include/debug_process.h
postqueue.o: ../../include/flush_clnt.h postqueue.o: ../../include/flush_clnt.h
postqueue.o: ../../include/iostuff.h postqueue.o: ../../include/iostuff.h
postqueue.o: ../../include/mail_conf.h postqueue.o: ../../include/mail_conf.h

View File

@@ -184,7 +184,6 @@
#include <mail_params.h> #include <mail_params.h>
#include <mail_conf.h> #include <mail_conf.h>
#include <mail_task.h> #include <mail_task.h>
#include <debug_process.h>
#include <mail_run.h> #include <mail_run.h>
#include <mail_flush.h> #include <mail_flush.h>
#include <flush_clnt.h> #include <flush_clnt.h>

View File

@@ -85,9 +85,15 @@
/* for testing address rewriting and routing configurations. /* for testing address rewriting and routing configurations.
/* .sp /* .sp
/* This feature is available in Postfix version 2.1 and later. /* This feature is available in Postfix version 2.1 and later.
/* .IP "\fB-C \fIconfig_file\fR (ignored)" /* .IP "\fB-C \fIconfig_file\fR"
/* The path name of the \fBsendmail.cf\fR file. Postfix configuration /* .IP "\fB-C \fIconfig_dir\fR"
/* files are kept in the \fB/etc/postfix\fR directory. /* The path name of the Postfix \fBmain.cf\fR file, or of its
/* parent directory. This information is ignored with Postfix
/* versions before 2.3.
/*
/* With older Postfix versions, specify a directory pathname
/* with the MAIL_CONFIG environment variable to override the
/* location of configuration files.
/* .IP "\fB-F \fIfull_name\fR /* .IP "\fB-F \fIfull_name\fR
/* Set the sender full name. This is used only with messages that /* Set the sender full name. This is used only with messages that
/* have no \fBFrom:\fR message header. /* have no \fBFrom:\fR message header.
@@ -901,6 +907,7 @@ int main(int argc, char **argv)
char *rewrite_context = MAIL_ATTR_RWR_LOCAL; char *rewrite_context = MAIL_ATTR_RWR_LOCAL;
int dsn_notify = 0; int dsn_notify = 0;
const char *dsn_envid = 0; const char *dsn_envid = 0;
int saved_optind;
/* /*
* Be consistent with file permissions. * Be consistent with file permissions.
@@ -959,8 +966,24 @@ int main(int argc, char **argv)
} }
/* /*
* Further initialization... * Further initialization. Load main.cf first, so that command-line
* options can override main.cf settings. Pre-scan the argument list so
* that we load the right main.cf file.
*/ */
#define GETOPT_LIST "A:B:C:F:GIL:N:O:R:UV:X:b:ce:f:h:imno:p:r:q:tvx"
saved_optind = optind;
while ((c = GETOPT(argc, argv, GETOPT_LIST)) > 0) {
VSTRING *buf = vstring_alloc(1);
if (c == 'C'
&& setenv(CONF_ENV_PATH,
strcmp(sane_basename(buf, optarg), MAIN_CONF_FILE) == 0 ?
sane_dirname(buf, optarg) : optarg, 1) < 0)
msg_fatal_status(EX_UNAVAILABLE, "out of memory");
vstring_free(buf);
}
optind = saved_optind;
mail_conf_read(); mail_conf_read();
get_mail_conf_str_table(str_table); get_mail_conf_str_table(str_table);
@@ -1024,7 +1047,7 @@ int main(int argc, char **argv)
optind++; optind++;
continue; continue;
} }
if ((c = GETOPT(argc, argv, "A:B:C:F:GIL:N:O:R:UV:X:b:ce:f:h:imno:p:r:q:tvx")) <= 0) if ((c = GETOPT(argc, argv, GETOPT_LIST)) <= 0)
break; break;
switch (c) { switch (c) {
default: default:

View File

@@ -2253,13 +2253,18 @@ static int data_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *unused_argv)
if (prev_rec_type != REC_TYPE_CONT && *start == '.' if (prev_rec_type != REC_TYPE_CONT && *start == '.'
&& (state->proxy == 0 ? (++start, --len) == 0 : len == 1)) && (state->proxy == 0 ? (++start, --len) == 0 : len == 1))
break; break;
if (state->err == CLEANUP_STAT_OK) {
state->act_size += len + 2; state->act_size += len + 2;
if (state->err == CLEANUP_STAT_OK if (var_message_limit > 0 && state->act_size > var_message_limit)
&& out_record(out_stream, curr_rec_type, start, len) < 0) state->err = CLEANUP_STAT_SIZE;
else if (out_record(out_stream, curr_rec_type, start, len) < 0)
state->err = out_error; state->err = out_error;
} }
}
state->where = SMTPD_AFTER_DOT; state->where = SMTPD_AFTER_DOT;
if (SMTPD_STAND_ALONE(state) == 0 && (err = smtpd_check_eod(state)) != 0) { if (state->err == CLEANUP_STAT_OK
&& SMTPD_STAND_ALONE(state) == 0
&& (err = smtpd_check_eod(state)) != 0) {
smtpd_chat_reply(state, "%s", err); smtpd_chat_reply(state, "%s", err);
if (state->proxy) { if (state->proxy) {
smtpd_proxy_close(state); smtpd_proxy_close(state);
@@ -2285,8 +2290,7 @@ static int data_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *unused_argv)
if (state->err == CLEANUP_STAT_OK && if (state->err == CLEANUP_STAT_OK &&
*STR(state->proxy_buffer) != '2') *STR(state->proxy_buffer) != '2')
state->err = CLEANUP_STAT_CONT; state->err = CLEANUP_STAT_CONT;
} else { } else if (state->err != CLEANUP_STAT_SIZE) {
state->error_mask |= MAIL_ERROR_SOFTWARE;
state->err |= CLEANUP_STAT_PROXY; state->err |= CLEANUP_STAT_PROXY;
detail = cleanup_stat_detail(CLEANUP_STAT_PROXY); detail = cleanup_stat_detail(CLEANUP_STAT_PROXY);
vstring_sprintf(state->proxy_buffer, vstring_sprintf(state->proxy_buffer,
@@ -3077,7 +3081,7 @@ static void smtpd_start_tls(SMTPD_STATE *state)
smtpd_chat_reply(state, smtpd_chat_reply(state,
"421 4.7.0 %s Error: too many new TLS sessions from %s", "421 4.7.0 %s Error: too many new TLS sessions from %s",
var_myhostname, state->namaddr); var_myhostname, state->namaddr);
msg_warn("Too many new TLS sessions: %d from %s for service %s", msg_warn("New TLS session rate limit exceeded: %d from %s for service %s",
rate, state->namaddr, state->service); rate, state->namaddr, state->service);
/* XXX Use regular return to signal end of session. */ /* XXX Use regular return to signal end of session. */
vstream_longjmp(state->client, SMTP_ERR_QUIET); vstream_longjmp(state->client, SMTP_ERR_QUIET);

View File

@@ -29,7 +29,7 @@ SRCS = alldig.c allprint.c argv.c argv_split.c attr_clnt.c attr_print0.c \
unix_recv_fd.c unix_send_fd.c unix_trigger.c unsafe.c uppercase.c \ unix_recv_fd.c unix_send_fd.c unix_trigger.c unsafe.c uppercase.c \
username.c valid_hostname.c vbuf.c vbuf_print.c vstream.c \ username.c valid_hostname.c vbuf.c vbuf_print.c vstream.c \
vstream_popen.c vstring.c vstring_vstream.c watchdog.c writable.c \ vstream_popen.c vstring.c vstring_vstream.c watchdog.c writable.c \
write_buf.c write_wait.c write_buf.c write_wait.c sane_basename.c
OBJS = alldig.o allprint.o argv.o argv_split.o attr_clnt.o attr_print0.o \ OBJS = alldig.o allprint.o argv.o argv_split.o attr_clnt.o attr_print0.o \
attr_print64.o attr_print_plain.o attr_scan0.o attr_scan64.o \ attr_print64.o attr_print_plain.o attr_scan0.o attr_scan64.o \
attr_scan_plain.o auto_clnt.o base64_code.o basename.o binhash.o \ attr_scan_plain.o auto_clnt.o base64_code.o basename.o binhash.o \
@@ -60,7 +60,7 @@ OBJS = alldig.o allprint.o argv.o argv_split.o attr_clnt.o attr_print0.o \
unix_recv_fd.o unix_send_fd.o unix_trigger.o unsafe.o uppercase.o \ unix_recv_fd.o unix_send_fd.o unix_trigger.o unsafe.o uppercase.o \
username.o valid_hostname.o vbuf.o vbuf_print.o vstream.o \ username.o valid_hostname.o vbuf.o vbuf_print.o vstream.o \
vstream_popen.o vstring.o vstring_vstream.o watchdog.o writable.o \ vstream_popen.o vstring.o vstring_vstream.o watchdog.o writable.o \
write_buf.o write_wait.o write_buf.o write_wait.o sane_basename.o
HDRS = argv.h attr.h attr_clnt.h auto_clnt.h base64_code.h binhash.h \ HDRS = argv.h attr.h attr_clnt.h auto_clnt.h base64_code.h binhash.h \
chroot_uid.h cidr_match.h clean_env.h connect.h ctable.h dict.h \ chroot_uid.h cidr_match.h clean_env.h connect.h ctable.h dict.h \
dict_cdb.h dict_cidr.h dict_db.h dict_dbm.h dict_env.h dict_ht.h \ dict_cdb.h dict_cidr.h dict_db.h dict_dbm.h dict_env.h dict_ht.h \
@@ -96,7 +96,7 @@ TESTPROG= dict_open dup2_pass_on_exec events exec_command fifo_open \
inet_addr_list attr_print64 attr_scan64 base64_code attr_print0 \ inet_addr_list attr_print64 attr_scan64 base64_code attr_print0 \
attr_scan0 host_port attr_scan_plain attr_print_plain htable \ attr_scan0 host_port attr_scan_plain attr_print_plain htable \
unix_recv_fd unix_send_fd stream_recv_fd stream_send_fd hex_code \ unix_recv_fd unix_send_fd stream_recv_fd stream_send_fd hex_code \
myaddrinfo myaddrinfo4 inet_proto myaddrinfo myaddrinfo4 inet_proto sane_basename
LIB_DIR = ../../lib LIB_DIR = ../../lib
INC_DIR = ../../include INC_DIR = ../../include
@@ -387,6 +387,11 @@ inet_proto: $(LIB)
$(CC) $(CFLAGS) -DTEST -o $@ $@.c $(LIB) $(SYSLIBS) $(CC) $(CFLAGS) -DTEST -o $@ $@.c $(LIB) $(SYSLIBS)
mv junk $@.o mv junk $@.o
sane_basename: $(LIB)
mv $@.o junk
$(CC) $(CFLAGS) -DTEST -o $@ $@.c $(LIB) $(SYSLIBS)
mv junk $@.o
stream_test: stream_test.c $(LIB) stream_test: stream_test.c $(LIB)
$(CC) $(CFLAGS) -o $@ $@.c $(LIB) $(SYSLIBS) $(CC) $(CFLAGS) -o $@ $@.c $(LIB) $(SYSLIBS)
@@ -433,6 +438,11 @@ inet_addr_list_test: inet_addr_list
diff inet_addr_list.ref inet_addr_list.tmp diff inet_addr_list.ref inet_addr_list.tmp
rm -f inet_addr_list.tmp rm -f inet_addr_list.tmp
sane_basename_test: sane_basename
./sane_basename <sane_basename.in >sane_basename.tmp 2>&1
diff sane_basename.ref sane_basename.tmp
rm -f sane_basename.tmp
base64_code_test: base64_code base64_code_test: base64_code
./base64_code ./base64_code
@@ -1299,6 +1309,14 @@ sane_accept.o: msg.h
sane_accept.o: sane_accept.c sane_accept.o: sane_accept.c
sane_accept.o: sane_accept.h sane_accept.o: sane_accept.h
sane_accept.o: sys_defs.h sane_accept.o: sys_defs.h
sane_basename.o: msg.h
sane_basename.o: mymalloc.c
sane_basename.o: mymalloc.h
sane_basename.o: sane_basename.c
sane_basename.o: stringops.h
sane_basename.o: sys_defs.h
sane_basename.o: vbuf.h
sane_basename.o: vstring.h
sane_connect.o: msg.h sane_connect.o: msg.h
sane_connect.o: sane_connect.c sane_connect.o: sane_connect.c
sane_connect.o: sane_connect.h sane_connect.o: sane_connect.h

View File

@@ -0,0 +1,180 @@
/*++
/* NAME
/* sane_basename 3
/* SUMMARY
/* split pathname into last component and parent directory
/* SYNOPSIS
/* #include <stringops.h>
/*
/* char *sane_basename(buf, path)
/* VSTRING *buf;
/* const char *path;
/*
/* char *sane_dirname(buf, path)
/* VSTRING *buf;
/* const char *path;
/* DESCRIPTION
/* These functions split a pathname into its last component
/* and its parent directory, excluding any trailing "/"
/* characters from the input. The result is a pointer to "/"
/* when the input is all "/" characters, or a pointer to "."
/* when the input is a null pointer or zero-length string.
/*
/* sane_basename() and sane_dirname() differ as follows
/* from standard basename() and dirname() implementations:
/* .IP \(bu
/* They can use caller-provided storage or private storage.
/* .IP \(bu
/* They never modify their input.
/* .PP
/* sane_basename() returns a pointer to string with the last
/* pathname component.
/*
/* sane_dirname() returns a pointer to string with the parent
/* directory. The result is a pointer to "." when the input
/* contains no '/' character.
/*
/* Arguments:
/* .IP buf
/* Result storage. If a null pointer is specified, each function
/* uses its own private memory that is overwritten upon each call.
/* .IP path
/* The input pathname.
/* LICENSE
/* .ad
/* .fi
/* The Secure Mailer license must be distributed with this
/* software.
/* AUTHOR(S)
/* Wietse Venema
/* IBM T.J. Watson Research
/* P.O. Box 704
/* Yorktown Heights, NY 10598, USA
/*--*/
/* System library. */
#include <sys_defs.h>
/* Utility library. */
#include <vstring.h>
#include <stringops.h>
#define STR(x) vstring_str(x)
/* sane_basename - skip directory prefix */
char *sane_basename(VSTRING *bp, const char *path)
{
static VSTRING *buf;
const char *first;
const char *last;
/*
* Your buffer or mine?
*/
if (bp == 0) {
bp = buf;
if (bp == 0)
bp = buf = vstring_alloc(10);
}
/*
* Special case: return "." for null or zero-length input.
*/
if (path == 0 || *path == 0)
return (STR(vstring_strcpy(bp, ".")));
/*
* Remove trailing '/' characters from input. Return "/" if input is all
* '/' characters.
*/
last = path + strlen(path) - 1;
while (*last == '/') {
if (last == path)
return (STR(vstring_strcpy(bp, "/")));
last--;
}
/*
* The pathname does not end in '/'. Skip to last '/' character if any.
*/
first = last - 1;
while (first >= path && *first != '/')
first--;
return (STR(vstring_strncpy(bp, first + 1, last - first)));
}
/* sane_dirname - keep directory prefix */
char *sane_dirname(VSTRING *bp, const char *path)
{
static VSTRING *buf;
const char *last;
/*
* Your buffer or mine?
*/
if (bp == 0) {
bp = buf;
if (bp == 0)
bp = buf = vstring_alloc(10);
}
/*
* Special case: return "." for null or zero-length input.
*/
if (path == 0 || *path == 0)
return (STR(vstring_strcpy(bp, ".")));
/*
* Remove trailing '/' characters from input. Return "/" if input is all
* '/' characters.
*/
last = path + strlen(path) - 1;
while (*last == '/') {
if (last == path)
return (STR(vstring_strcpy(bp, "/")));
last--;
}
/*
* This pathname does not end in '/'. Skip to last '/' character if any.
*/
while (last >= path && *last != '/')
last--;
if (last < path) /* no '/' */
return (STR(vstring_strcpy(bp, ".")));
/*
* Strip trailing '/' characters from dirname (not strictly needed).
*/
while (last > path && *last == '/')
last--;
return (STR(vstring_strncpy(bp, path, last - path + 1)));
}
#ifdef TEST
#include <vstring_vstream.h>
int main(int argc, char **argv)
{
VSTRING *buf = vstring_alloc(10);
char *dir;
char *base;
while (vstring_get_nonl(buf, VSTREAM_IN) > 0) {
dir = sane_dirname((VSTRING *) 0, STR(buf));
base = sane_basename((VSTRING *) 0, STR(buf));
vstream_printf("input=\"%s\" dir=\"%s\" base=\"%s\"\n",
STR(buf), dir, base);
}
vstream_fflush(VSTREAM_OUT);
vstring_free(buf);
return (0);
}
#endif

View File

@@ -0,0 +1,18 @@
///
/
fo2///
fo2/
fo2
///fo2
/fo2
///fo2///bar///
fo2///bar///
fo2///bar/
fo2/bar
/usr/lib
/usr/
usr
/
.
..

View File

@@ -0,0 +1,18 @@
input="///" dir="/" base="/"
input="/" dir="/" base="/"
input="fo2///" dir="." base="fo2"
input="fo2/" dir="." base="fo2"
input="fo2" dir="." base="fo2"
input="///fo2" dir="/" base="fo2"
input="/fo2" dir="/" base="fo2"
input="///fo2///bar///" dir="///fo2" base="bar"
input="fo2///bar///" dir="fo2" base="bar"
input="fo2///bar/" dir="fo2" base="bar"
input="fo2/bar" dir="fo2" base="bar"
input="" dir="." base="."
input="/usr/lib" dir="/usr" base="lib"
input="/usr/" dir="/" base="usr"
input="usr" dir="." base="usr"
input="/" dir="/" base="/"
input="." dir="." base="."
input=".." dir="." base=".."

View File

@@ -29,8 +29,11 @@ extern char *concatenate(const char *,...);
extern char *mystrtok(char **, const char *); extern char *mystrtok(char **, const char *);
extern char *translit(char *, const char *, const char *); extern char *translit(char *, const char *, const char *);
#ifndef HAVE_BASENAME #ifndef HAVE_BASENAME
#define basename postfix_basename
extern char *basename(const char *); extern char *basename(const char *);
#endif #endif
extern char *sane_basename(VSTRING *, const char *);
extern char *sane_dirname(VSTRING *, const char *);
extern VSTRING *unescape(VSTRING *, const char *); extern VSTRING *unescape(VSTRING *, const char *);
extern int alldig(const char *); extern int alldig(const char *);
extern int allprint(const char *); extern int allprint(const char *);