Uploaded the wrong postfix-3.11-20250713 tarball. Files:
master/event_server.c, master/multi_server.c.
+
+ Deleted an <openssl/engine.h> dependency, because the feature is
+ being removed from OpenSSL, and Postfix no longer needs it. File:
+ posttls-finger/posttls-finger.c.
+
+ Updated the proxymap(8) manpage and some internal documentation.
+ File: proxymap/proxymap.c.
+
+20250715
+
+ Cleanup: the proxymap 'open' service always returns the
+ dict->flags from a newly-initialized instance. This avoids
+ cross-talk between different clients. File: proxymap/proxymap.c.
+
+20250716
+
+ Bugfix (defect introduced: Postfix 2.7, date 20121223):
+ segfault in the internal: table iterator when the table
+ contained exactly one element. File: util/htable.c.
+
+ Technical debt: allow an element to be deleted before the
+ internal: table's first/next iterator has visited it. File:
+ util/htable.c.
+
+20250716
+
+ Bugfix (defect introduced: Postfix 2.8, date 20101230):
+ after detecting a cache table change and before starting a
+ new postscreen process, the old postscreen process did not
+ close the postscreen_cache_map, and therefore kept an
+ exclusive lock that could prevent a new postscreen process
+ from starting. Problem reported by Florian Piekert. File:
+ postscreen/postscreen.c.
+
+20250717
+
+ Workaround: Postfix daemons no longer automatically restart
+ after a btree:, dbm:, hash:, lmdb:, or sdbm: table file
+ modification time change, when they opened that table for
+ writing. Files: util/dict.c, util/dict_db.c, util/dict_dbm.c,
+ util/dict_lmdb.c, util/dict_sdbm.c.
text..." response, in an attempt to confuse bad SMTP clients so
that they speak before their turn (pre-greet).
- <b><a href="postconf.5.html#postscreen_greet_wait">postscreen_greet_wait</a> (normal: 6s, overload: 2s)</b>
+ <b><a href="postconf.5.html#postscreen_greet_wait">postscreen_greet_wait</a> (normal: 6s, <a href="STRESS_README.html">overload</a>: 2s)</b>
The amount of time that <a href="postscreen.8.html"><b>postscreen</b>(8)</a> will wait for an SMTP
client to send a command before its turn, and for DNS blocklist
lookup results to arrive (default: up to 2 seconds under stress,
The limit on the total number of commands per SMTP session for
<a href="postscreen.8.html"><b>postscreen</b>(8)</a>'s built-in SMTP protocol engine.
- <b><a href="postconf.5.html#postscreen_command_time_limit">postscreen_command_time_limit</a> (normal: 300s, overload: 10s)</b>
+ <b><a href="postconf.5.html#postscreen_command_time_limit">postscreen_command_time_limit</a> (normal: 300s, <a href="STRESS_README.html">overload</a>: 10s)</b>
The time limit to read an entire command line with
<a href="postscreen.8.html"><b>postscreen</b>(8)</a>'s built-in SMTP protocol engine.
<b><a href="postconf.5.html#delay_logging_resolution_limit">delay_logging_resolution_limit</a> (2)</b>
The maximal number of digits after the decimal point when log-
- ging sub-second delay values.
+ ging delay values.
<b><a href="postconf.5.html#command_directory">command_directory</a> (see 'postconf -d' output)</b>
The location of all postfix administrative commands.
111 8th Avenue
New York, NY 10011, USA
+ Wietse Venema
+ porcupine.org
+
POSTSCREEN(8)
</pre> </body> </html>
The <a href="proxymap.8.html"><b>proxymap</b>(8)</a> server implements the following requests:
- <b>open</b> <i>maptype:mapname flags</i>
- Open the table with type <i>maptype</i> and name <i>mapname</i>, as controlled
- by <i>flags</i>. The reply includes the <i>maptype</i> dependent flags (to
- distinguish a fixed string table from a regular expression ta-
- ble).
-
- <b>lookup</b> <i>maptype:mapname flags key</i>
- Look up the data stored under the requested key. The reply is
- the request completion status code and the lookup result value.
- The <i>maptype:mapname</i> and <i>flags</i> are the same as with the <b>open</b>
+ <b>open</b> <i>maptype:mapname instance-flags</i>
+ Open the table with type <i>maptype</i> and name <i>mapname</i>, with initial
+ dictionary flags <i>instance-flags</i>. The reply contains the actual
+ dictionary flags (for example, to distinguish a fixed-string ta-
+ ble from a regular-expression table).
+
+ <b>lookup</b> <i>maptype:mapname instance-flags request-flags key</i>
+ Look up the data stored under the requested key using the dic-
+ tionary flags in <i>request-flags</i>. The reply contains the request
+ completion status code, the resulting dictionary flags, and the
+ lookup result value. The <i>maptype:mapname</i> and <i>instance-flags</i> are
+ the same as with the <b>open</b> request.
+
+ <b>update</b> <i>maptype:mapname instance-flags request-flags key value</i>
+ Update the data stored under the requested key using the dictio-
+ nary flags in <i>request-flags</i>. The reply contains the request
+ completion status code and the resulting dictionary flags. The
+ <i>maptype:mapname</i> and <i>instance-flags</i> are the same as with the <b>open</b>
request.
- <b>update</b> <i>maptype:mapname flags key value</i>
- Update the data stored under the requested key. The reply is
- the request completion status code. The <i>maptype:mapname</i> and
- <i>flags</i> are the same as with the <b>open</b> request.
-
- To implement single-updater maps, specify a process limit of 1
+ To implement single-updater maps, specify a process limit of 1
in the <a href="master.5.html">master.cf</a> file entry for the <b>proxywrite</b> service.
This request is supported in Postfix 2.5 and later.
- <b>delete</b> <i>maptype:mapname flags key</i>
- Delete the data stored under the requested key. The reply is
- the request completion status code. The <i>maptype:mapname</i> and
- <i>flags</i> are the same as with the <b>open</b> request.
+ <b>delete</b> <i>maptype:mapname instance-flags request-flags key</i>
+ Delete the data stored under the requested key, using the dic-
+ tionary flags in <i>request-flags</i>. The reply contains the request
+ completion status code and the resulting dictionary flags. The
+ <i>maptype:mapname</i> and <i>instance-flags</i> are the same as with the <b>open</b>
+ request.
This request is supported in Postfix 2.5 and later.
- <b>sequence</b> <i>maptype:mapname flags function</i>
- Iterate over the specified database. The <i>function</i> is one of
- DICT_SEQ_FUN_FIRST or DICT_SEQ_FUN_NEXT. The reply is the
- request completion status code and a lookup key and result
- value, if found.
+ <b>sequence</b> <i>maptype:mapname instance-flags request-flags function</i>
+ Iterate over the specified database, using the dictionary flags
+ in <i>request-flags</i>. The <i>function</i> is either DICT_SEQ_FUN_FIRST or
+ DICT_SEQ_FUN_NEXT. The reply contains the request completion
+ status code, the resulting dictionary flags, and a lookup key
+ and result value if found. The <i>maptype:mapname</i> and
+ <i>instance-flags</i> are the same as with the <b>open</b> request.
This request is supported in Postfix 2.9 and later.
+ Not implemented: close
+ There is no <b>close</b> request, nor are tables implicitly closed when
+ a client disconnects. The purpose is to share tables among mul-
+ tiple client processes. Due to the absence of an explicit or
+ implicit <b>close</b>, updates are forced to be synchronous.
+
The request completion status is one of OK, RETRY, NOKEY (lookup failed
because the key was not found), BAD (malformed request) or DENY (the
table is not approved for proxy read or update access).
- There is no <b>close</b> command, nor are tables implicitly closed when a
- client disconnects. The purpose is to share tables among multiple
- client processes.
-
<b><a name="server_process_management">SERVER PROCESS MANAGEMENT</a></b>
<a href="proxymap.8.html"><b>proxymap</b>(8)</a> servers run under control by the Postfix <a href="master.8.html"><b>master</b>(8)</a> server.
Each server can handle multiple simultaneous connections. When all
111 8th Avenue
New York, NY 10011, USA
+ Wietse Venema
+ porcupine.org
+
PROXYMAP(8)
</pre> </body> </html>
configuration files.
.IP "\fBdelay_logging_resolution_limit (2)\fR"
The maximal number of digits after the decimal point when logging
-sub\-second delay values.
+delay values.
.IP "\fBcommand_directory (see 'postconf -d' output)\fR"
The location of all postfix administrative commands.
.IP "\fBmax_idle (100s)\fR"
Google, Inc.
111 8th Avenue
New York, NY 10011, USA
+
+Wietse Venema
+porcupine.org
file\-based tables that are not based on \fBlmdb\fR).
.PP
The \fBproxymap\fR(8) server implements the following requests:
-.IP "\fBopen\fR \fImaptype:mapname flags\fR"
+.IP "\fBopen\fR \fImaptype:mapname instance\-flags\fR"
Open the table with type \fImaptype\fR and name \fImapname\fR,
-as controlled by \fIflags\fR. The reply includes the \fImaptype\fR
-dependent flags (to distinguish a fixed string table from a regular
-expression table).
-.IP "\fBlookup\fR \fImaptype:mapname flags key\fR"
-Look up the data stored under the requested key.
-The reply is the request completion status code and
-the lookup result value.
-The \fImaptype:mapname\fR and \fIflags\fR are the same
+with initial dictionary flags \fIinstance\-flags\fR. The reply
+contains the actual dictionary flags (for example, to distinguish
+a fixed\-string table from a regular\-expression table).
+.IP "\fBlookup\fR \fImaptype:mapname instance\-flags request\-flags key\fR"
+Look up the data stored under the requested key using the
+dictionary flags in \fIrequest\-flags\fR.
+The reply contains the request completion status code, the
+resulting dictionary flags, and the lookup result value.
+The \fImaptype:mapname\fR and \fIinstance\-flags\fR are the same
as with the \fBopen\fR request.
-.IP "\fBupdate\fR \fImaptype:mapname flags key value\fR"
-Update 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
+.IP "\fBupdate\fR \fImaptype:mapname instance\-flags request\-flags key value\fR"
+Update the data stored under the requested key using the
+dictionary flags in \fIrequest\-flags\fR.
+The reply contains the request completion status code and the
+resulting dictionary flags.
+The \fImaptype:mapname\fR and \fIinstance\-flags\fR are the same
as with the \fBopen\fR request.
.sp
To implement single\-updater maps, specify a process limit
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
+.IP "\fBdelete\fR \fImaptype:mapname instance\-flags request\-flags key\fR"
+Delete the data stored under the requested key, using the
+dictionary flags in \fIrequest\-flags\fR.
+The reply contains the request completion status code and the
+resulting dictionary flags.
+The \fImaptype:mapname\fR and \fIinstance\-flags\fR are the same
as with the \fBopen\fR request.
.sp
This request is supported in Postfix 2.5 and later.
-.IP "\fBsequence\fR \fImaptype:mapname flags function\fR"
-Iterate over the specified database. The \fIfunction\fR
-is one of DICT_SEQ_FUN_FIRST or DICT_SEQ_FUN_NEXT.
-The reply is the request completion status code and
-a lookup key and result value, if found.
+.IP "\fBsequence\fR \fImaptype:mapname instance\-flags request\-flags function\fR"
+Iterate over the specified database, using the dictionary flags
+in \fIrequest\-flags\fR. The \fIfunction\fR is either
+DICT_SEQ_FUN_FIRST or DICT_SEQ_FUN_NEXT.
+The reply contains the request completion status code, the
+resulting dictionary flags, and a lookup key and result value
+if found.
+The \fImaptype:mapname\fR and \fIinstance\-flags\fR are the same
+as with the \fBopen\fR request.
.sp
This request is supported in Postfix 2.9 and later.
+.IP "Not implemented: close"
+There is no \fBclose\fR request, nor are tables implicitly closed
+when a client disconnects. The purpose is to share tables among
+multiple client processes. Due to the absence of an explicit or
+implicit \fBclose\fR, updates are forced to be synchronous.
.PP
The request completion status is one of OK, RETRY, NOKEY
(lookup failed because the key was not found), BAD (malformed
request) or DENY (the table is not approved for proxy read
or update access).
-
-There is no \fBclose\fR command, nor are tables implicitly closed
-when a client disconnects. The purpose is to share tables among
-multiple client processes.
.SH "SERVER PROCESS MANAGEMENT"
.na
.nf
Google, Inc.
111 8th Avenue
New York, NY 10011, USA
+
+Wietse Venema
+porcupine.org
proxymap proxymap c
postmap postmap c postalias postalias c
client Files dict h dict_proxy c proxymap proxymap c
+ cross talk between different clients File proxymap proxymap c
+ postscreen postscreen c
* Patches change both the patchlevel and the release date. Snapshots have no
* patchlevel; they change the release date only.
*/
-#define MAIL_RELEASE_DATE "20250714"
+#define MAIL_RELEASE_DATE "20250717"
#define MAIL_VERSION_NUMBER "3.11"
#ifdef SNAPSHOT
/* configuration files.
/* .IP "\fBdelay_logging_resolution_limit (2)\fR"
/* The maximal number of digits after the decimal point when logging
-/* sub-second delay values.
+/* delay values.
/* .IP "\fBcommand_directory (see 'postconf -d' output)\fR"
/* The location of all postfix administrative commands.
/* .IP "\fBmax_idle (100s)\fR"
/* Google, Inc.
/* 111 8th Avenue
/* New York, NY 10011, USA
+/*
+/* Wietse Venema
+/* porcupine.org
/*--*/
/* System library. */
if (new_event_time >= last_event_time + 1
&& (name = dict_changed_name()) != 0) {
msg_info("table %s has changed - finishing in the background", name);
- event_server_drain();
+ psc_drain(unused_name, unused_argv);
} else {
last_event_time = new_event_time;
}
#ifdef USE_TLS
#include <tls_proxy.h>
-#include <openssl/engine.h>
#endif
/*
/* file-based tables that are not based on \fBlmdb\fR).
/* .PP
/* The \fBproxymap\fR(8) server implements the following requests:
-/* .IP "\fBopen\fR \fImaptype:mapname flags\fR"
+/* .IP "\fBopen\fR \fImaptype:mapname instance-flags\fR"
/* Open the table with type \fImaptype\fR and name \fImapname\fR,
-/* as controlled by \fIflags\fR. The reply includes the \fImaptype\fR
-/* dependent flags (to distinguish a fixed string table from a regular
-/* expression table).
-/* .IP "\fBlookup\fR \fImaptype:mapname flags key\fR"
-/* Look up the data stored under the requested key.
-/* The reply is the request completion status code and
-/* the lookup result value.
-/* The \fImaptype:mapname\fR and \fIflags\fR are the same
+/* with initial dictionary flags \fIinstance-flags\fR. The reply
+/* contains the actual dictionary flags (for example, to distinguish
+/* a fixed-string table from a regular-expression table).
+/* .IP "\fBlookup\fR \fImaptype:mapname instance-flags request-flags key\fR"
+/* Look up the data stored under the requested key using the
+/* dictionary flags in \fIrequest-flags\fR.
+/* The reply contains the request completion status code, the
+/* resulting dictionary flags, and the lookup result value.
+/* The \fImaptype:mapname\fR and \fIinstance-flags\fR are the same
/* as with the \fBopen\fR request.
-/* .IP "\fBupdate\fR \fImaptype:mapname flags key value\fR"
-/* Update 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
+/* .IP "\fBupdate\fR \fImaptype:mapname instance-flags request-flags key value\fR"
+/* Update the data stored under the requested key using the
+/* dictionary flags in \fIrequest-flags\fR.
+/* The reply contains the request completion status code and the
+/* resulting dictionary flags.
+/* The \fImaptype:mapname\fR and \fIinstance-flags\fR are the same
/* as with the \fBopen\fR request.
/* .sp
/* To implement single-updater maps, specify a process limit
/* 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
+/* .IP "\fBdelete\fR \fImaptype:mapname instance-flags request-flags key\fR"
+/* Delete the data stored under the requested key, using the
+/* dictionary flags in \fIrequest-flags\fR.
+/* The reply contains the request completion status code and the
+/* resulting dictionary flags.
+/* The \fImaptype:mapname\fR and \fIinstance-flags\fR are the same
/* as with the \fBopen\fR request.
/* .sp
/* This request is supported in Postfix 2.5 and later.
-/* .IP "\fBsequence\fR \fImaptype:mapname flags function\fR"
-/* Iterate over the specified database. The \fIfunction\fR
-/* is one of DICT_SEQ_FUN_FIRST or DICT_SEQ_FUN_NEXT.
-/* The reply is the request completion status code and
-/* a lookup key and result value, if found.
+/* .IP "\fBsequence\fR \fImaptype:mapname instance-flags request-flags function\fR"
+/* Iterate over the specified database, using the dictionary flags
+/* in \fIrequest-flags\fR. The \fIfunction\fR is either
+/* DICT_SEQ_FUN_FIRST or DICT_SEQ_FUN_NEXT.
+/* The reply contains the request completion status code, the
+/* resulting dictionary flags, and a lookup key and result value
+/* if found.
+/* The \fImaptype:mapname\fR and \fIinstance-flags\fR are the same
+/* as with the \fBopen\fR request.
/* .sp
/* This request is supported in Postfix 2.9 and later.
+/* .IP "Not implemented: close"
+/* There is no \fBclose\fR request, nor are tables implicitly closed
+/* when a client disconnects. The purpose is to share tables among
+/* multiple client processes. Due to the absence of an explicit or
+/* implicit \fBclose\fR, updates are forced to be synchronous.
/* .PP
/* The request completion status is one of OK, RETRY, NOKEY
/* (lookup failed because the key was not found), BAD (malformed
/* request) or DENY (the table is not approved for proxy read
/* or update access).
-/*
-/* There is no \fBclose\fR command, nor are tables implicitly closed
-/* when a client disconnects. The purpose is to share tables among
-/* multiple client processes.
/* SERVER PROCESS MANAGEMENT
/* .ad
/* .fi
/* Google, Inc.
/* 111 8th Avenue
/* New York, NY 10011, USA
+/*
+/* Wietse Venema
+/* porcupine.org
/*--*/
/* System library. */
static DICT *proxy_map_find(const char *map_type_name, int inst_flags,
int *statp)
{
+ static HTABLE *new_flags;
+ HTABLE_INFO *ht;
DICT *dict;
#define PROXY_COLON DICT_TYPE_PROXY ":"
inst_flags);
if (dict == 0)
msg_panic("proxy_map_find: dict_open null result");
+
+ /*
+ * Remember the mapping from dict->reg_name to the dict->flags of a
+ * newly-initialized instance. Always return an instance with those new
+ * dict->flags, to avoid crosstalk between different clients.
+ */
+ if (new_flags == 0)
+ new_flags = htable_create(100);
+ if ((ht = htable_locate(new_flags, dict->reg_name)) == 0) {
+ (void) htable_enter(new_flags, dict->reg_name,
+ CAST_INT_TO_VOID_PTR(dict->flags));
+ } else {
+ dict->flags = CAST_ANY_PTR_TO_INT(ht->value);
+ }
dict->error = 0;
return (dict);
}
/* .IP "char *context"
/* Application context from the caller.
/* .PP
-/* dict_changed_name() returns non-zero when any dictionary needs to
-/* be re-opened because it has changed or because it was unlinked.
+/* dict_changed_name() returns non-zero when any dictionary is
+/* opened read-only and has changed, or because it was unlinked.
/* A non-zero result is the name of a changed dictionary.
/*
/* dict_load_file_xt() reads name-value entries from the named file.
dict = ((DICT_NODE *) h->value)->dict;
if (dict->stat_fd < 0) /* not file-based */
continue;
- if (dict->mtime == 0) /* not bloody likely */
- msg_warn("%s: table %s: null time stamp", myname, h->key);
+ if (dict->mtime < 0) /* not bloody likely */
+ msg_warn("%s: table %s: negative time stamp", myname, h->key);
if (fstat(dict->stat_fd, &st) < 0)
msg_fatal("%s: fstat: %m", myname);
if (((dict->flags & DICT_FLAG_MULTI_WRITER) == 0
+ && dict->mtime > 0
&& st.st_mtime != dict->mtime)
|| st.st_nlink == 0)
status = h->key;
dict_db->dict.stat_fd = dbfd;
if (fstat(dict_db->dict.stat_fd, &st) < 0)
msg_fatal("dict_db_open: fstat: %m");
- dict_db->dict.mtime = st.st_mtime;
+ if (open_flags == O_RDONLY)
+ dict_db->dict.mtime = st.st_mtime;
dict_db->dict.owner.uid = st.st_uid;
dict_db->dict.owner.status = (st.st_uid != 0);
msg_fatal("open database %s: cannot support GDBM", path);
if (fstat(dict_dbm->dict.stat_fd, &st) < 0)
msg_fatal("dict_dbm_open: fstat: %m");
- dict_dbm->dict.mtime = st.st_mtime;
+ if (open_mode == O_RDONLY)
+ dict_dbm->dict.mtime = st.st_mtime;
dict_dbm->dict.owner.uid = st.st_uid;
dict_dbm->dict.owner.status = (st.st_uid != 0);
msg_fatal("dict_lmdb_open: fstat: %m");
dict_lmdb->dict.lock_fd = dict_lmdb->dict.stat_fd = db_fd;
dict_lmdb->dict.lock_type = MYFLOCK_STYLE_FCNTL;
- dict_lmdb->dict.mtime = st.st_mtime;
+ if (open_flags == O_RDONLY)
+ dict_lmdb->dict.mtime = st.st_mtime;
dict_lmdb->dict.owner.uid = st.st_uid;
dict_lmdb->dict.owner.status = (st.st_uid != 0);
dict_sdbm->dict.stat_fd = sdbm_pagfno(dbm);
if (fstat(dict_sdbm->dict.stat_fd, &st) < 0)
msg_fatal("dict_sdbm_open: fstat: %m");
- dict_sdbm->dict.mtime = st.st_mtime;
+ if (open_flags == O_RDONLY)
+ dict_sdbm->dict.mtime = st.st_mtime;
dict_sdbm->dict.owner.uid = st.st_uid;
dict_sdbm->dict.owner.status = (st.st_uid != 0);
/* htable_sequence() returns the first or next element depending
/* on the value of the "how" argument. Specify HTABLE_SEQ_FIRST
/* to start a new sequence, HTABLE_SEQ_NEXT to continue, and
-/* HTABLE_SEQ_STOP to terminate a sequence early. The caller
-/* must not delete an element before it is visited.
+/* HTABLE_SEQ_STOP to terminate a sequence early.
/* RESTRICTIONS
/* A callback function should not modify the hash table that is
/* specified to its caller.
void htable_delete(HTABLE *table, const char *key, void (*free_fn) (void *))
{
if (table) {
- HTABLE_INFO *ht;
+ HTABLE_INFO *ht, **sp;
HTABLE_INFO **h = table->data + htable_hash(key, table->size);
#define STREQ(x,y) (x == y || (x[0] == y[0] && strcmp(x,y) == 0))
if (free_fn && ht->value)
(*free_fn) (ht->value);
myfree((void *) ht);
+ /* In case the first/next iterator has not yet visited it */
+ for (sp = table->seq_element; sp && *sp; sp++) {
+ if (*sp == ht) {
+ while ((*sp = sp[1]) != 0)
+ sp += 1;
+ break;
+ }
+ }
return;
}
}
myfree((void *) table->seq_bucket);
table->seq_bucket = htable_list(table);
table->seq_element = table->seq_bucket;
- return (*(table->seq_element)++);
+ /* FALLTHROUGH */
case HTABLE_SEQ_NEXT: /* next element */
if (table->seq_element && *table->seq_element)
return (*(table->seq_element)++);