From d510de3fec1abedbc7af638559dab3ef7e26d10e Mon Sep 17 00:00:00 2001
From: Wietse Venema Note: the data_directory parameter (for caches and pseudo-random
+numbers) was introduced with Postfix version 2.5. The number of connections that Postfix can manage simultaneously
diff --git a/postfix/html/mailq.1.html b/postfix/html/mailq.1.html
index 52a9a8645..15009baf5 100644
--- a/postfix/html/mailq.1.html
+++ b/postfix/html/mailq.1.html
@@ -363,9 +363,10 @@ SENDMAIL(1) SENDMAIL(1)
The maximal number of Received: message headers
that is allowed in the primary message headers.
- queue_run_delay (version dependent)
+ queue_run_delay (300s)
The time between deferred queue scans by the queue
- manager.
+ manager; prior to Postfix 2.4 the default value was
+ 1000s.
FAST FLUSH CONTROLS
The ETRN_README file describes configuration and operation
@@ -373,37 +374,37 @@ SENDMAIL(1) SENDMAIL(1)
fast_flush_domains ($relay_domains)
Optional list of destinations that are eligible for
- per-destination logfiles with mail that is queued
+ per-destination logfiles with mail that is queued
to those destinations.
VERP CONTROLS
The VERP_README file describes configuration and operation
- details of Postfix support for variable envelope return
+ details of Postfix support for variable envelope return
path addresses.
default_verp_delimiters (+=)
The two default VERP delimiter characters.
verp_delimiter_filter (-=+)
- The characters Postfix accepts as VERP delimiter
- characters on the Postfix sendmail(1) command line
+ The characters Postfix accepts as VERP delimiter
+ characters on the Postfix sendmail(1) command line
and in SMTP commands.
MISCELLANEOUS CONTROLS
alias_database (see 'postconf -d' output)
- The alias databases for local(8) delivery that are
+ The alias databases for local(8) delivery that are
updated with "newaliases" or with "sendmail -bi".
command_directory (see 'postconf -d' output)
- The location of all postfix administrative com-
+ The location of all postfix administrative com-
mands.
config_directory (see 'postconf -d' output)
- The default location of the Postfix main.cf and
+ The default location of the Postfix main.cf and
master.cf configuration files.
daemon_directory (see 'postconf -d' output)
- The directory with Postfix support programs and
+ The directory with Postfix support programs and
daemon programs.
default_database_type (see 'postconf -d' output)
@@ -411,16 +412,16 @@ SENDMAIL(1) SENDMAIL(1)
postalias(1) and postmap(1) commands.
delay_warning_time (0h)
- The time after which the sender receives the mes-
+ The time after which the sender receives the mes-
sage headers of mail that is still queued.
enable_errors_to (no)
- Report mail delivery errors to the address speci-
- fied with the non-standard Errors-To: message
- header, instead of the envelope sender address
- (this feature is removed with Postfix version 2.2,
- is turned off by default with Postfix version 2.1,
- and is always turned on with older Postfix ver-
+ Report mail delivery errors to the address speci-
+ fied with the non-standard Errors-To: message
+ header, instead of the envelope sender address
+ (this feature is removed with Postfix version 2.2,
+ is turned off by default with Postfix version 2.1,
+ and is always turned on with older Postfix ver-
sions).
mail_owner (postfix)
@@ -428,21 +429,21 @@ SENDMAIL(1) SENDMAIL(1)
and most Postfix daemon processes.
queue_directory (see 'postconf -d' output)
- The location of the Postfix top-level queue direc-
+ The location of the Postfix top-level queue direc-
tory.
remote_header_rewrite_domain (empty)
- Don't rewrite message headers from remote clients
+ Don't rewrite message headers from remote clients
at all when this parameter is empty; otherwise, re-
- write message headers and append the specified
+ write message headers and append the specified
domain name to incomplete addresses.
syslog_facility (mail)
The syslog facility of Postfix logging.
syslog_name (postfix)
- The mail system name that is prepended to the
- process name in syslog records, so that "smtpd"
+ The mail system name that is prepended to the
+ process name in syslog records, so that "smtpd"
becomes, for example, "postfix/smtpd".
FILES
@@ -467,7 +468,7 @@ SENDMAIL(1) SENDMAIL(1)
VERP_README, Postfix VERP howto
LICENSE
- The Secure Mailer license must be distributed with this
+ The Secure Mailer license must be distributed with this
software.
AUTHOR(S)
diff --git a/postfix/html/newaliases.1.html b/postfix/html/newaliases.1.html
index 52a9a8645..15009baf5 100644
--- a/postfix/html/newaliases.1.html
+++ b/postfix/html/newaliases.1.html
@@ -363,9 +363,10 @@ SENDMAIL(1) SENDMAIL(1)
The maximal number of Received: message headers
that is allowed in the primary message headers.
- queue_run_delay (version dependent)
+ queue_run_delay (300s)
The time between deferred queue scans by the queue
- manager.
+ manager; prior to Postfix 2.4 the default value was
+ 1000s.
FAST FLUSH CONTROLS
The ETRN_README file describes configuration and operation
@@ -373,37 +374,37 @@ SENDMAIL(1) SENDMAIL(1)
fast_flush_domains ($relay_domains)
Optional list of destinations that are eligible for
- per-destination logfiles with mail that is queued
+ per-destination logfiles with mail that is queued
to those destinations.
VERP CONTROLS
The VERP_README file describes configuration and operation
- details of Postfix support for variable envelope return
+ details of Postfix support for variable envelope return
path addresses.
default_verp_delimiters (+=)
The two default VERP delimiter characters.
verp_delimiter_filter (-=+)
- The characters Postfix accepts as VERP delimiter
- characters on the Postfix sendmail(1) command line
+ The characters Postfix accepts as VERP delimiter
+ characters on the Postfix sendmail(1) command line
and in SMTP commands.
MISCELLANEOUS CONTROLS
alias_database (see 'postconf -d' output)
- The alias databases for local(8) delivery that are
+ The alias databases for local(8) delivery that are
updated with "newaliases" or with "sendmail -bi".
command_directory (see 'postconf -d' output)
- The location of all postfix administrative com-
+ The location of all postfix administrative com-
mands.
config_directory (see 'postconf -d' output)
- The default location of the Postfix main.cf and
+ The default location of the Postfix main.cf and
master.cf configuration files.
daemon_directory (see 'postconf -d' output)
- The directory with Postfix support programs and
+ The directory with Postfix support programs and
daemon programs.
default_database_type (see 'postconf -d' output)
@@ -411,16 +412,16 @@ SENDMAIL(1) SENDMAIL(1)
postalias(1) and postmap(1) commands.
delay_warning_time (0h)
- The time after which the sender receives the mes-
+ The time after which the sender receives the mes-
sage headers of mail that is still queued.
enable_errors_to (no)
- Report mail delivery errors to the address speci-
- fied with the non-standard Errors-To: message
- header, instead of the envelope sender address
- (this feature is removed with Postfix version 2.2,
- is turned off by default with Postfix version 2.1,
- and is always turned on with older Postfix ver-
+ Report mail delivery errors to the address speci-
+ fied with the non-standard Errors-To: message
+ header, instead of the envelope sender address
+ (this feature is removed with Postfix version 2.2,
+ is turned off by default with Postfix version 2.1,
+ and is always turned on with older Postfix ver-
sions).
mail_owner (postfix)
@@ -428,21 +429,21 @@ SENDMAIL(1) SENDMAIL(1)
and most Postfix daemon processes.
queue_directory (see 'postconf -d' output)
- The location of the Postfix top-level queue direc-
+ The location of the Postfix top-level queue direc-
tory.
remote_header_rewrite_domain (empty)
- Don't rewrite message headers from remote clients
+ Don't rewrite message headers from remote clients
at all when this parameter is empty; otherwise, re-
- write message headers and append the specified
+ write message headers and append the specified
domain name to incomplete addresses.
syslog_facility (mail)
The syslog facility of Postfix logging.
syslog_name (postfix)
- The mail system name that is prepended to the
- process name in syslog records, so that "smtpd"
+ The mail system name that is prepended to the
+ process name in syslog records, so that "smtpd"
becomes, for example, "postfix/smtpd".
FILES
@@ -467,7 +468,7 @@ SENDMAIL(1) SENDMAIL(1)
VERP_README, Postfix VERP howto
LICENSE
- The Secure Mailer license must be distributed with this
+ The Secure Mailer license must be distributed with this
software.
AUTHOR(S)
diff --git a/postfix/html/postconf.5.html b/postfix/html/postconf.5.html
index cc7f6d06d..7d364d855 100644
--- a/postfix/html/postconf.5.html
+++ b/postfix/html/postconf.5.html
@@ -1500,6 +1500,19 @@ The default time unit is s (seconds).
The directory with Postfix-writable data files (for example:
+caches, pseudo-random numbers). This directory must be owned by
+the mail_owner account, and must not be shared with non-Postfix
+software. This feature is available in Postfix 2.5 and later.
-The lookup tables that the proxymap(8) server is allowed to
-access for the read-write service.
+The lookup tables that the proxymap(8) server is allowed to access
+for the read-write service. If implemented with local files, these
+tables are preferably stored under the location specified with the
+data_directory configuration parameter.
Table references that don't begin with proxy: are ignored.
Note: the data_directory parameter (for caches and pseudo-random
+numbers) was introduced with Postfix version 2.5. The number of connections that Postfix can manage simultaneously
diff --git a/postfix/proto/postconf.proto b/postfix/proto/postconf.proto
index d5002584f..8a1889615 100644
--- a/postfix/proto/postconf.proto
+++ b/postfix/proto/postconf.proto
@@ -7216,8 +7216,10 @@ This feature is available in Postfix 2.0 and later.
%PARAM proxy_write_maps see "postconf -d" output
-The lookup tables that the proxymap(8) server is allowed to
-access for the read-write service.
+The lookup tables that the proxymap(8) server is allowed to access
+for the read-write service. If implemented with local files, these
+tables are preferably stored under the location specified with the
+data_directory configuration parameter.
Table references that don't begin with proxy: are ignored.
+DEF_DAEMON_DIR daemon_directory
/usr/libexec/postfix
+
DEF_DATA_DIR data_directory
+/var/lib/postfix
@@ -333,6 +336,9 @@ default
+DEF_MAILQ_PATH mailq_path /usr/bin/mailq
4.5 - Support for thousands of processes
+DEF_DAEMON_DIR daemon_directory
/usr/libexec/postfix
+
DEF_DATA_DIR data_directory
+/var/lib/postfix
@@ -333,6 +336,9 @@ default
+DEF_MAILQ_PATH mailq_path /usr/bin/mailq
4.5 - Support for thousands of processes
This feature is available in Postfix 2.5 and later.
+ +%PARAM data_directory see "postconf -d" output + +The directory with Postfix-writable data files (for example: +caches, pseudo-random numbers). This directory must be owned by +the mail_owner account, and must not be shared with non-Postfix +software.
+ +This feature is available in Postfix 2.5 and later.
diff --git a/postfix/src/global/dict_proxy.c b/postfix/src/global/dict_proxy.c index e4f788473..8005c8d36 100644 --- a/postfix/src/global/dict_proxy.c +++ b/postfix/src/global/dict_proxy.c @@ -70,6 +70,8 @@ typedef struct { DICT dict; /* generic members */ + CLNT_STREAM *clnt; /* client handle (shared) */ + const char *service; /* service name */ int in_flags; /* caller-specified flags */ VSTRING *result; /* storage */ } DICT_PROXY; @@ -81,9 +83,10 @@ typedef struct { #define VSTREQ(v,s) (strcmp(STR(v),s) == 0) /* - * All proxied maps within a process share the same query/reply socket. + * All proxied maps of the same type share the same query/reply socket. */ -static CLNT_STREAM *proxy_stream; +static CLNT_STREAM *proxymap_stream; /* read-only maps */ +static CLNT_STREAM *proxywrite_stream; /* read-write maps */ /* dict_proxy_lookup - find table entry */ @@ -108,7 +111,7 @@ static const char *dict_proxy_lookup(DICT *dict, const char *key) request_flags = (dict_proxy->in_flags & DICT_FLAG_RQST_MASK) | (dict->flags & DICT_FLAG_RQST_MASK); for (;;) { - stream = clnt_stream_access(proxy_stream); + stream = clnt_stream_access(dict_proxy->clnt); errno = 0; count += 1; if (attr_print(stream, ATTR_FLAG_NONE, @@ -134,10 +137,10 @@ static const char *dict_proxy_lookup(DICT *dict, const char *key) case PROXY_STAT_BAD: msg_fatal("%s lookup failed for table \"%s\" key \"%s\": " "invalid request", - MAIL_SERVICE_PROXYMAP, dict->name, key); + dict_proxy->service, dict->name, key); case PROXY_STAT_DENY: msg_fatal("%s service is not configured for table \"%s\"", - MAIL_SERVICE_PROXYMAP, dict->name); + dict_proxy->service, dict->name); case PROXY_STAT_OK: return (STR(dict_proxy->result)); case PROXY_STAT_NOKEY: @@ -149,10 +152,10 @@ static const char *dict_proxy_lookup(DICT *dict, const char *key) default: msg_warn("%s lookup failed for table \"%s\" key \"%s\": " "unexpected reply status %d", - MAIL_SERVICE_PROXYMAP, dict->name, key, status); + dict_proxy->service, dict->name, key, status); } } - clnt_stream_recover(proxy_stream); + clnt_stream_recover(dict_proxy->clnt); sleep(1); /* XXX make configurable */ } } @@ -178,7 +181,7 @@ static void dict_proxy_update(DICT *dict, const char *key, const char *value) request_flags = (dict_proxy->in_flags & DICT_FLAG_RQST_MASK) | (dict->flags & DICT_FLAG_RQST_MASK); for (;;) { - stream = clnt_stream_access(proxy_stream); + stream = clnt_stream_access(dict_proxy->clnt); errno = 0; count += 1; if (attr_print(stream, ATTR_FLAG_NONE, @@ -197,25 +200,90 @@ static void dict_proxy_update(DICT *dict, const char *key, const char *value) } else { if (msg_verbose) msg_info("%s: table=%s flags=%s key=%s value=%s -> status=%d", - myname, dict->name, dict_flags_str(request_flags), + myname, dict->name, dict_flags_str(request_flags), key, value, status); switch (status) { case PROXY_STAT_BAD: - msg_fatal("%s lookup failed for table \"%s\" key \"%s\": " + msg_fatal("%s update failed for table \"%s\" key \"%s\": " "invalid request", - MAIL_SERVICE_PROXYMAP, dict->name, key); + dict_proxy->service, dict->name, key); case PROXY_STAT_DENY: msg_fatal("%s update access is not configured for table \"%s\"", - MAIL_SERVICE_PROXYMAP, dict->name); + dict_proxy->service, dict->name); case PROXY_STAT_OK: return; default: msg_warn("%s update failed for table \"%s\" key \"%s\": " "unexpected reply status %d", - MAIL_SERVICE_PROXYMAP, dict->name, key, status); + dict_proxy->service, dict->name, key, status); } } - clnt_stream_recover(proxy_stream); + clnt_stream_recover(dict_proxy->clnt); + sleep(1); /* XXX make configurable */ + } +} + +/* dict_proxy_delete - delete table entry */ + +static int dict_proxy_delete(DICT *dict, const char *key) +{ + const char *myname = "dict_proxy_delete"; + DICT_PROXY *dict_proxy = (DICT_PROXY *) dict; + VSTREAM *stream; + int status; + int count = 0; + int request_flags; + + /* + * The client and server live in separate processes that may start and + * terminate independently. We cannot rely on a persistent connection, + * let alone on persistent state (such as a specific open table) that is + * associated with a specific connection. Each lookup needs to specify + * the table and the flags that were specified to dict_proxy_open(). + */ + request_flags = (dict_proxy->in_flags & DICT_FLAG_RQST_MASK) + | (dict->flags & DICT_FLAG_RQST_MASK); + for (;;) { + stream = clnt_stream_access(dict_proxy->clnt); + errno = 0; + count += 1; + if (attr_print(stream, ATTR_FLAG_NONE, + ATTR_TYPE_STR, MAIL_ATTR_REQ, PROXY_REQ_DELETE, + ATTR_TYPE_STR, MAIL_ATTR_TABLE, dict->name, + ATTR_TYPE_INT, MAIL_ATTR_FLAGS, request_flags, + ATTR_TYPE_STR, MAIL_ATTR_KEY, key, + ATTR_TYPE_END) != 0 + || vstream_fflush(stream) + || attr_scan(stream, ATTR_FLAG_STRICT, + ATTR_TYPE_INT, MAIL_ATTR_STATUS, &status, + ATTR_TYPE_END) != 1) { + if (msg_verbose || count > 1 || (errno && errno != EPIPE && errno != + ENOENT)) + msg_warn("%s: service %s: %m", myname, VSTREAM_PATH(stream)); + } else { + if (msg_verbose) + msg_info("%s: table=%s flags=%s key=%s -> status=%d", + myname, dict->name, dict_flags_str(request_flags), + key, status); + switch (status) { + case PROXY_STAT_BAD: + msg_fatal("%s delete failed for table \"%s\" key \"%s\": " + "invalid request", + dict_proxy->service, dict->name, key); + case PROXY_STAT_DENY: + msg_fatal("%s update access is not configured for table \"%s\"", + dict_proxy->service, dict->name); + case PROXY_STAT_OK: + return 0; + case PROXY_STAT_NOKEY: + return 1; + default: + msg_warn("%s delete failed for table \"%s\" key \"%s\": " + "unexpected reply status %d", + dict_proxy->service, dict->name, key, status); + } + } + clnt_stream_recover(dict_proxy->clnt); sleep(1); /* XXX make configurable */ } } @@ -239,8 +307,11 @@ DICT *dict_proxy_open(const char *map, int open_flags, int dict_flags) VSTREAM *stream; int server_flags; int status; + const char *service; + const char *relative_path; char *kludge = 0; char *prefix; + CLNT_STREAM **pstream; /* * Sanity checks. @@ -250,7 +321,15 @@ DICT *dict_proxy_open(const char *map, int open_flags, int dict_flags) * server; only sets that make sense. For now, the flags are passed * implicitly by choosing between the proxymap or proxywrite service. */ - if (open_flags != O_RDONLY && open_flags != (O_RDWR | O_CREAT)) + if (open_flags == O_RDONLY) { + pstream = &proxymap_stream; + service = MAIL_SERVICE_PROXYMAP; + relative_path = MAIL_CLASS_PRIVATE "/" MAIL_SERVICE_PROXYMAP; + } else if (open_flags == (O_RDWR | O_CREAT)) { + pstream = &proxywrite_stream; + service = MAIL_SERVICE_PROXYWRITE; + relative_path = MAIL_CLASS_PRIVATE "/" MAIL_SERVICE_PROXYWRITE; + } else msg_fatal("%s: %s map open requires O_RDONLY or O_RDWR|O_CREAT mode", map, DICT_TYPE_PROXY); @@ -269,33 +348,29 @@ DICT *dict_proxy_open(const char *map, int open_flags, int dict_flags) dict_alloc(DICT_TYPE_PROXY, map, sizeof(*dict_proxy)); dict_proxy->dict.lookup = dict_proxy_lookup; dict_proxy->dict.update = dict_proxy_update; + dict_proxy->dict.delete = dict_proxy_delete; dict_proxy->dict.close = dict_proxy_close; dict_proxy->in_flags = dict_flags; dict_proxy->result = vstring_alloc(10); /* - * Use a shared stream for all proxied table lookups. + * Use a shared stream for proxied table lookups of the same type. * * XXX Use absolute pathname to make this work from non-daemon processes. */ - if (proxy_stream == 0) { - if (access(open_flags == O_RDONLY ? - MAIL_CLASS_PRIVATE "/" MAIL_SERVICE_PROXYMAP : - MAIL_CLASS_PRIVATE "/" MAIL_SERVICE_PROXYWRITE, - F_OK) == 0) + if (*pstream == 0) { + if (access(relative_path, F_OK) == 0) prefix = MAIL_CLASS_PRIVATE; else prefix = kludge = concatenate(var_queue_dir, "/", MAIL_CLASS_PRIVATE, (char *) 0); - proxy_stream = clnt_stream_create(prefix, - open_flags == O_RDONLY ? - MAIL_SERVICE_PROXYMAP : - MAIL_SERVICE_PROXYWRITE, - var_ipc_idle_limit, - var_ipc_ttl_limit); + *pstream = clnt_stream_create(prefix, service, var_ipc_idle_limit, + var_ipc_ttl_limit); if (kludge) myfree(kludge); } + dict_proxy->clnt = *pstream; + dict_proxy->service = service; /* * Establish initial contact and get the map type specific flags. @@ -303,7 +378,7 @@ DICT *dict_proxy_open(const char *map, int open_flags, int dict_flags) * XXX Should retrieve flags from local instance. */ for (;;) { - stream = clnt_stream_access(proxy_stream); + stream = clnt_stream_access(dict_proxy->clnt); errno = 0; if (attr_print(stream, ATTR_FLAG_NONE, ATTR_TYPE_STR, MAIL_ATTR_REQ, PROXY_REQ_OPEN, @@ -325,20 +400,20 @@ DICT *dict_proxy_open(const char *map, int open_flags, int dict_flags) switch (status) { case PROXY_STAT_BAD: msg_fatal("%s open failed for table \"%s\": invalid request", - MAIL_SERVICE_PROXYMAP, dict_proxy->dict.name); + dict_proxy->service, dict_proxy->dict.name); case PROXY_STAT_DENY: msg_fatal("%s service is not configured for table \"%s\"", - MAIL_SERVICE_PROXYMAP, dict_proxy->dict.name); + dict_proxy->service, dict_proxy->dict.name); case PROXY_STAT_OK: dict_proxy->dict.flags = dict_proxy->in_flags | (server_flags & DICT_FLAG_IMPL_MASK); return (DICT_DEBUG (&dict_proxy->dict)); default: msg_warn("%s open failed for table \"%s\": unexpected status %d", - MAIL_SERVICE_PROXYMAP, dict_proxy->dict.name, status); + dict_proxy->service, dict_proxy->dict.name, status); } } - clnt_stream_recover(proxy_stream); + clnt_stream_recover(dict_proxy->clnt); sleep(1); /* XXX make configurable */ } } diff --git a/postfix/src/global/dict_proxy.h b/postfix/src/global/dict_proxy.h index 2a1e3fd21..6d55842d4 100644 --- a/postfix/src/global/dict_proxy.h +++ b/postfix/src/global/dict_proxy.h @@ -29,6 +29,7 @@ extern DICT *dict_proxy_open(const char *, int, int); #define PROXY_REQ_OPEN "open" #define PROXY_REQ_LOOKUP "lookup" #define PROXY_REQ_UPDATE "update" +#define PROXY_REQ_DELETE "delete" #define PROXY_STAT_OK 0 /* operation succeeded */ #define PROXY_STAT_NOKEY 1 /* requested key not found */ diff --git a/postfix/src/global/mail_params.c b/postfix/src/global/mail_params.c index d12e4bd90..54e48368f 100644 --- a/postfix/src/global/mail_params.c +++ b/postfix/src/global/mail_params.c @@ -26,6 +26,7 @@ /* gid_t var_default_gid; /* char *var_config_dir; /* char *var_daemon_dir; +/* char *var_data_dir; /* char *var_command_dir; /* char *var_queue_dir; /* int var_use_limit; @@ -200,6 +201,7 @@ uid_t var_default_uid; gid_t var_default_gid; char *var_config_dir; char *var_daemon_dir; +char *var_data_dir; char *var_command_dir; char *var_queue_dir; int var_use_limit; @@ -504,6 +506,7 @@ void mail_params_init() VAR_MYORIGIN, DEF_MYORIGIN, &var_myorigin, 1, 0, VAR_RELAYHOST, DEF_RELAYHOST, &var_relayhost, 0, 0, VAR_DAEMON_DIR, DEF_DAEMON_DIR, &var_daemon_dir, 1, 0, + VAR_DATA_DIR, DEF_DATA_DIR, &var_data_dir, 1, 0, VAR_COMMAND_DIR, DEF_COMMAND_DIR, &var_command_dir, 1, 0, VAR_QUEUE_DIR, DEF_QUEUE_DIR, &var_queue_dir, 1, 0, VAR_PID_DIR, DEF_PID_DIR, &var_pid_dir, 1, 0, diff --git a/postfix/src/global/mail_params.h b/postfix/src/global/mail_params.h index ca7679f47..aac05a6ba 100644 --- a/postfix/src/global/mail_params.h +++ b/postfix/src/global/mail_params.h @@ -260,6 +260,15 @@ extern char *var_command_dir; #endif extern char *var_pid_dir; + /* + * Location of writable data files. + */ +#define VAR_DATA_DIR "data_directory" +#ifndef DEF_DATA_DIR +#define DEF_DATA_DIR "/var/lib/postfix" +#endif +extern char *var_data_dir; + /* * Program startup time. */ diff --git a/postfix/src/global/mail_version.h b/postfix/src/global/mail_version.h index 287cba84b..3e91849b7 100644 --- a/postfix/src/global/mail_version.h +++ b/postfix/src/global/mail_version.h @@ -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 "2007111204" +#define MAIL_RELEASE_DATE "2007111205" #define MAIL_VERSION_NUMBER "2.5" #ifdef SNAPSHOT diff --git a/postfix/src/oqmgr/qmgr_queue.c b/postfix/src/oqmgr/qmgr_queue.c index ae3de84c2..1cc8f50c9 100644 --- a/postfix/src/oqmgr/qmgr_queue.c +++ b/postfix/src/oqmgr/qmgr_queue.c @@ -148,6 +148,13 @@ static void qmgr_queue_resume(int event, char *context) queue->window = 1; if (queue->todo_refcount > 0) qmgr_active_drain(); + + /* + * Every event handler that leaves a queue in the "ready" state should + * remove the queue when it is empty. + */ + if (QMGR_QUEUE_READY(queue) && queue->todo.next == 0 && queue->busy.next == 0) + qmgr_queue_done(queue); } /* qmgr_queue_suspend - briefly suspend a destination */ diff --git a/postfix/src/postalias/postalias.c b/postfix/src/postalias/postalias.c index 186601f56..cd0569173 100644 --- a/postfix/src/postalias/postalias.c +++ b/postfix/src/postalias/postalias.c @@ -516,6 +516,7 @@ static int postalias_deletes(VSTREAM *in, char **maps, const int map_count, DICT **dicts; const char *map_name; int n; + int open_flags; /* * Sanity check. @@ -530,10 +531,12 @@ static int postalias_deletes(VSTREAM *in, char **maps, const int map_count, for (n = 0; n < map_count; n++) { map_name = split_at(maps[n], ':'); if (map_name && strcmp(maps[n], DICT_TYPE_PROXY) == 0) - msg_fatal("can't delete map entries via the proxy service"); + open_flags = O_RDWR | O_CREAT; /* XXX */ + else + open_flags = O_RDWR; dicts[n] = (map_name != 0 ? - dict_open3(maps[n], map_name, O_RDWR, dict_flags) : - dict_open3(var_db_type, maps[n], O_RDWR, dict_flags)); + dict_open3(maps[n], map_name, open_flags, dict_flags) : + dict_open3(var_db_type, maps[n], open_flags, dict_flags)); } /* @@ -562,10 +565,13 @@ static int postalias_delete(const char *map_type, const char *map_name, { DICT *dict; int status; + int open_flags; if (strcmp(map_type, DICT_TYPE_PROXY) == 0) - msg_fatal("can't delete map entries via the proxy service"); - dict = dict_open3(map_type, map_name, O_RDWR, dict_flags); + open_flags = O_RDWR | O_CREAT; /* XXX */ + else + open_flags = O_RDWR; + dict = dict_open3(map_type, map_name, open_flags, dict_flags); status = dict_del(dict, key); dict_close(dict); return (status == 0); diff --git a/postfix/src/postfix/postfix.c b/postfix/src/postfix/postfix.c index a0a4a9609..132aedd6f 100644 --- a/postfix/src/postfix/postfix.c +++ b/postfix/src/postfix/postfix.c @@ -132,6 +132,11 @@ /* The location of Postfix README files that describe how to build, /* configure or operate a specific Postfix subsystem or feature. /* .PP +/* Available in Postfix version 2.5 and later: +/* .IP "\fBdata_directory (see 'postconf -d' output)\fR" +/* The directory with Postfix-writable data files (for example: +/* caches, pseudo-random numbers). +/* .PP /* Other configuration parameters: /* .IP "\fBconfig_directory (see 'postconf -d' output)\fR" /* The default location of the Postfix main.cf and master.cf @@ -430,6 +435,7 @@ int main(int argc, char **argv) check_setenv(VAR_COMMAND_DIR, var_command_dir); /* main.cf */ check_setenv(VAR_DAEMON_DIR, var_daemon_dir); /* main.cf */ + check_setenv(VAR_DATA_DIR, var_data_dir); /* main.cf */ check_setenv(VAR_QUEUE_DIR, var_queue_dir); /* main.cf */ check_setenv(VAR_CONFIG_DIR, var_config_dir); /* main.cf */ diff --git a/postfix/src/postmap/postmap.c b/postfix/src/postmap/postmap.c index 2631c7e45..f2f28e0b5 100644 --- a/postfix/src/postmap/postmap.c +++ b/postfix/src/postmap/postmap.c @@ -463,6 +463,7 @@ static int postmap_deletes(VSTREAM *in, char **maps, const int map_count, DICT **dicts; const char *map_name; int n; + int open_flags; /* * Sanity check. @@ -477,10 +478,12 @@ static int postmap_deletes(VSTREAM *in, char **maps, const int map_count, for (n = 0; n < map_count; n++) { map_name = split_at(maps[n], ':'); if (map_name && strcmp(maps[n], DICT_TYPE_PROXY) == 0) - msg_fatal("can't delete map entries via the proxy service"); + open_flags = O_RDWR | O_CREAT; /* XXX */ + else + open_flags = O_RDWR; dicts[n] = (map_name != 0 ? - dict_open3(maps[n], map_name, O_RDWR, dict_flags) : - dict_open3(var_db_type, maps[n], O_RDWR, dict_flags)); + dict_open3(maps[n], map_name, open_flags, dict_flags) : + dict_open3(var_db_type, maps[n], open_flags, dict_flags)); } /* @@ -509,10 +512,13 @@ static int postmap_delete(const char *map_type, const char *map_name, { DICT *dict; int status; + int open_flags; if (strcmp(map_type, DICT_TYPE_PROXY) == 0) - msg_fatal("can't delete map entries via the proxy service"); - dict = dict_open3(map_type, map_name, O_RDWR, dict_flags); + open_flags = O_RDWR | O_CREAT; /* XXX */ + else + open_flags = O_RDWR; + dict = dict_open3(map_type, map_name, open_flags, dict_flags); status = dict_del(dict, key); dict_close(dict); return (status == 0); diff --git a/postfix/src/proxymap/proxymap.c b/postfix/src/proxymap/proxymap.c index c3b5e23d4..2a3c392af 100644 --- a/postfix/src/proxymap/proxymap.c +++ b/postfix/src/proxymap/proxymap.c @@ -62,6 +62,13 @@ /* service. /* .sp /* This request is supported in Postfix 2.5 and later. +/* .IP "\fBdelete\fR \fImaptype:mapname flags key\fR" +/* Delete the data stored under the requested key. +/* The reply is the request completion status code. +/* The \fImaptype:mapname\fR and \fIflags\fR are the same +/* as with the \fBopen\fR request. +/* .sp +/* This request is supported in Postfix 2.5 and later. /* .PP /* The request completion status is one of OK, RETRY, NOKEY /* (lookup failed because the key was not found), BAD (malformed @@ -100,6 +107,15 @@ /* requests to access a table for security-sensitive purposes, /* and opens the table directly. This allows the same main.cf /* setting to be used by sensitive and non-sensitive processes. +/* +/* Postfix-writable data files should be stored under a dedicated +/* directory that is writable only by the $\fBmail_owner\fR +/* account, such as the $\fBdata_directory\fR directory. +/* +/* In particular, Postfix-writable files should never exist +/* in root-owned directories. That would open up a particular +/* type of security hole where ownership (root) does not match +/* content provenance (Postfix). /* DIAGNOSTICS /* Problems and transactions are logged to \fBsyslogd\fR(8). /* BUGS @@ -149,9 +165,12 @@ /* access for the read-only service. /* .PP /* Available in Postfix 2.5 and later: +/* .IP "\fBdata_directory (see 'postconf -d' output)\fR" +/* The directory with Postfix-writable data files (for example: +/* caches, pseudo-random numbers). /* .IP "\fBproxy_write_maps (see 'postconf -d' output)\fR" -/* The lookup tables that the \fBproxymap\fR(8) server is allowed to -/* access for the read-write service. +/* The lookup tables that the \fBproxymap\fR(8) server is allowed to access +/* for the read-write service. /* SEE ALSO /* postconf(5), configuration parameters /* master(5), generic daemon options @@ -397,6 +416,49 @@ static void proxymap_update_service(VSTREAM *client_stream) ATTR_TYPE_END); } +/* proxymap_delete_service - remote delete service */ + +static void proxymap_delete_service(VSTREAM *client_stream) +{ + int request_flags; + DICT *dict; + int reply_status; + + /* + * Process the request. + * + * XXX We don't close maps, so we must turn on synchronous update to ensure + * that the on-disk data is in a consistent state between updates. + */ + if (attr_scan(client_stream, ATTR_FLAG_STRICT, + ATTR_TYPE_STR, MAIL_ATTR_TABLE, request_map, + ATTR_TYPE_INT, MAIL_ATTR_FLAGS, &request_flags, + ATTR_TYPE_STR, MAIL_ATTR_KEY, request_key, + ATTR_TYPE_END) != 3) { + reply_status = PROXY_STAT_BAD; + } else if (proxy_writer == 0) { + msg_warn("refusing %s delete request on non-%s service", + STR(request_map), MAIL_SERVICE_PROXYWRITE); + reply_status = PROXY_STAT_DENY; + } else if ((dict = proxy_map_find(STR(request_map), request_flags, + &reply_status)) == 0) { + /* void */ ; + } else { + dict->flags = ((dict->flags & ~DICT_FLAG_RQST_MASK) + | (request_flags & DICT_FLAG_RQST_MASK) + | DICT_FLAG_SYNC_UPDATE); + reply_status = + dict_del(dict, STR(request_key)) ? PROXY_STAT_OK : PROXY_STAT_NOKEY; + } + + /* + * Respond to the client. + */ + attr_print(client_stream, ATTR_FLAG_NONE, + ATTR_TYPE_INT, MAIL_ATTR_STATUS, reply_status, + ATTR_TYPE_END); +} + /* proxymap_open_service - open remote lookup table */ static void proxymap_open_service(VSTREAM *client_stream) @@ -457,6 +519,8 @@ static void proxymap_service(VSTREAM *client_stream, char *unused_service, proxymap_lookup_service(client_stream); } else if (VSTREQ(request, PROXY_REQ_UPDATE)) { proxymap_update_service(client_stream); + } else if (VSTREQ(request, PROXY_REQ_DELETE)) { + proxymap_delete_service(client_stream); } else if (VSTREQ(request, PROXY_REQ_OPEN)) { proxymap_open_service(client_stream); } else { diff --git a/postfix/src/qmgr/qmgr_queue.c b/postfix/src/qmgr/qmgr_queue.c index 8d9a1528e..2a81740e9 100644 --- a/postfix/src/qmgr/qmgr_queue.c +++ b/postfix/src/qmgr/qmgr_queue.c @@ -150,6 +150,13 @@ static void qmgr_queue_resume(int event, char *context) queue->window = 1; if (queue->todo_refcount > 0) qmgr_active_drain(); + + /* + * Every event handler that leaves a queue in the "ready" state should + * remove the queue when it is empty. + */ + if (QMGR_QUEUE_READY(queue) && queue->todo.next == 0 && queue->busy.next == 0) + qmgr_queue_done(queue); } /* qmgr_queue_suspend - briefly suspend a destination */ diff --git a/postfix/src/sendmail/sendmail.c b/postfix/src/sendmail/sendmail.c index 30fef831e..e2da158ba 100644 --- a/postfix/src/sendmail/sendmail.c +++ b/postfix/src/sendmail/sendmail.c @@ -288,8 +288,9 @@ /* .IP "\fBhopcount_limit (50)\fR" /* The maximal number of Received: message headers that is allowed /* in the primary message headers. -/* .IP "\fBqueue_run_delay (version dependent)\fR" -/* The time between deferred queue scans by the queue manager. +/* .IP "\fBqueue_run_delay (300s)\fR" +/* The time between deferred queue scans by the queue manager; +/* prior to Postfix 2.4 the default value was 1000s. /* FAST FLUSH CONTROLS /* .ad /* .fi @@ -687,7 +688,8 @@ static void enqueue(const int flags, const char *encoding, rec_fputs(dst, REC_TYPE_FROM, saved_sender); if (verp_delims && *saved_sender == 0) msg_fatal_status(EX_USAGE, - "-V option requires non-null sender address"); + "%s(%ld): -V option requires non-null sender address", + saved_sender, (long) uid); if (encoding) rec_fprintf(dst, REC_TYPE_ATTR, "%s=%s", MAIL_ATTR_ENCODING, encoding); if (DEL_REQ_TRACE_FLAGS(flags)) @@ -735,7 +737,8 @@ static void enqueue(const int flags, const char *encoding, rec_fputs(dst, REC_TYPE_MESG, ""); if (DEL_REQ_TRACE_ONLY(flags) != 0) { if (flags & SM_FLAG_XRCPT) - msg_fatal_status(EX_USAGE, "-t option cannot be used with -bv"); + msg_fatal_status(EX_USAGE, "%s(%ld): -t option cannot be used with -bv", + saved_sender, (long) uid); if (*saved_sender) rec_fprintf(dst, REC_TYPE_NORM, "From: %s", saved_sender); rec_fprintf(dst, REC_TYPE_NORM, "Subject: probe"); @@ -850,9 +853,10 @@ static void enqueue(const int flags, const char *encoding, } if (rcpt_count == 0) msg_fatal_status(EX_USAGE, (flags & SM_FLAG_XRCPT) ? - "No recipient addresses found in message header" : + "%s(%ld): No recipient addresses found in message header" : "Recipient addresses must be specified on" - " the command line or via the -t option"); + " the command line or via the -t option", + saved_sender, (long) uid); /* * Identify the end of the queue file.