From 13f0daa5f73a84f19a8562e26983cc4476248197 Mon Sep 17 00:00:00 2001 From: Wietse Z Venema Date: Thu, 17 Jul 2025 00:00:00 -0500 Subject: [PATCH] postfix-3.11-20250717 --- postfix/HISTORY | 41 +++++++++++ postfix/html/postscreen.8.html | 9 ++- postfix/html/proxymap.8.html | 68 ++++++++++------- postfix/man/man8/postscreen.8 | 5 +- postfix/man/man8/proxymap.8 | 65 ++++++++++------- postfix/proto/stop.double-history | 2 + postfix/src/global/mail_version.h | 2 +- postfix/src/postscreen/postscreen.c | 7 +- postfix/src/posttls-finger/posttls-finger.c | 1 - postfix/src/proxymap/proxymap.c | 81 ++++++++++++++------- postfix/src/util/dict.c | 9 ++- postfix/src/util/dict_db.c | 3 +- postfix/src/util/dict_dbm.c | 3 +- postfix/src/util/dict_lmdb.c | 3 +- postfix/src/util/dict_sdbm.c | 3 +- postfix/src/util/htable.c | 15 +++- 16 files changed, 217 insertions(+), 100 deletions(-) diff --git a/postfix/HISTORY b/postfix/HISTORY index 15344f8b5..78a961cc7 100644 --- a/postfix/HISTORY +++ b/postfix/HISTORY @@ -29400,3 +29400,44 @@ Apologies for any names omitted. Uploaded the wrong postfix-3.11-20250713 tarball. Files: master/event_server.c, master/multi_server.c. + + Deleted an 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. diff --git a/postfix/html/postscreen.8.html b/postfix/html/postscreen.8.html index e2183ba6f..52a4e206c 100644 --- a/postfix/html/postscreen.8.html +++ b/postfix/html/postscreen.8.html @@ -222,7 +222,7 @@ POSTSCREEN(8) POSTSCREEN(8) text..." response, in an attempt to confuse bad SMTP clients so that they speak before their turn (pre-greet). - postscreen_greet_wait (normal: 6s, overload: 2s) + postscreen_greet_wait (normal: 6s, overload: 2s) The amount of time that postscreen(8) 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, @@ -359,7 +359,7 @@ POSTSCREEN(8) POSTSCREEN(8) The limit on the total number of commands per SMTP session for postscreen(8)'s built-in SMTP protocol engine. - postscreen_command_time_limit (normal: 300s, overload: 10s) + postscreen_command_time_limit (normal: 300s, overload: 10s) The time limit to read an entire command line with postscreen(8)'s built-in SMTP protocol engine. @@ -405,7 +405,7 @@ POSTSCREEN(8) POSTSCREEN(8) delay_logging_resolution_limit (2) The maximal number of digits after the decimal point when log- - ging sub-second delay values. + ging delay values. command_directory (see 'postconf -d' output) The location of all postfix administrative commands. @@ -468,5 +468,8 @@ POSTSCREEN(8) POSTSCREEN(8) 111 8th Avenue New York, NY 10011, USA + Wietse Venema + porcupine.org + POSTSCREEN(8) diff --git a/postfix/html/proxymap.8.html b/postfix/html/proxymap.8.html index b1967216e..e10542502 100644 --- a/postfix/html/proxymap.8.html +++ b/postfix/html/proxymap.8.html @@ -45,51 +45,60 @@ PROXYMAP(8) PROXYMAP(8) The proxymap(8) server implements the following requests: - open maptype:mapname flags - Open the table with type maptype and name mapname, as controlled - by flags. The reply includes the maptype dependent flags (to - distinguish a fixed string table from a regular expression ta- - ble). + open maptype:mapname instance-flags + Open the table with type maptype and name mapname, with initial + dictionary flags instance-flags. The reply contains the actual + dictionary flags (for example, to distinguish a fixed-string ta- + ble from a regular-expression table). - lookup maptype:mapname flags key - Look up the data stored under the requested key. The reply is - the request completion status code and the lookup result value. - The maptype:mapname and flags are the same as with the open + lookup maptype:mapname instance-flags request-flags key + Look up the data stored under the requested key using the dic- + tionary flags in request-flags. The reply contains the request + completion status code, the resulting dictionary flags, and the + lookup result value. The maptype:mapname and instance-flags are + the same as with the open request. + + update maptype:mapname instance-flags request-flags key value + Update the data stored under the requested key using the dictio- + nary flags in request-flags. The reply contains the request + completion status code and the resulting dictionary flags. The + maptype:mapname and instance-flags are the same as with the open request. - update maptype:mapname flags key value - Update the data stored under the requested key. The reply is - the request completion status code. The maptype:mapname and - flags are the same as with the open 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 master.cf file entry for the proxywrite service. This request is supported in Postfix 2.5 and later. - delete maptype:mapname flags key - Delete the data stored under the requested key. The reply is - the request completion status code. The maptype:mapname and - flags are the same as with the open request. + delete maptype:mapname instance-flags request-flags key + Delete the data stored under the requested key, using the dic- + tionary flags in request-flags. The reply contains the request + completion status code and the resulting dictionary flags. The + maptype:mapname and instance-flags are the same as with the open + request. This request is supported in Postfix 2.5 and later. - sequence maptype:mapname flags function - Iterate over the specified database. The function 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. + sequence maptype:mapname instance-flags request-flags function + Iterate over the specified database, using the dictionary flags + in request-flags. The function 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 maptype:mapname and + instance-flags are the same as with the open request. This request is supported in Postfix 2.9 and later. + Not implemented: close + There is no close 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 close, 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 close command, nor are tables implicitly closed when a - client disconnects. The purpose is to share tables among multiple - client processes. - SERVER PROCESS MANAGEMENT proxymap(8) servers run under control by the Postfix master(8) server. Each server can handle multiple simultaneous connections. When all @@ -219,5 +228,8 @@ PROXYMAP(8) PROXYMAP(8) 111 8th Avenue New York, NY 10011, USA + Wietse Venema + porcupine.org + PROXYMAP(8) diff --git a/postfix/man/man8/postscreen.8 b/postfix/man/man8/postscreen.8 index 0231b0a24..07013ea98 100644 --- a/postfix/man/man8/postscreen.8 +++ b/postfix/man/man8/postscreen.8 @@ -410,7 +410,7 @@ The default location of the Postfix main.cf and master.cf 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" @@ -480,3 +480,6 @@ Wietse Venema Google, Inc. 111 8th Avenue New York, NY 10011, USA + +Wietse Venema +porcupine.org diff --git a/postfix/man/man8/proxymap.8 b/postfix/man/man8/proxymap.8 index ff0d7592c..beb841e23 100644 --- a/postfix/man/man8/proxymap.8 +++ b/postfix/man/man8/proxymap.8 @@ -46,21 +46,24 @@ that do not reliably support multiple writers (i.e. all 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 @@ -68,29 +71,36 @@ of 1 in the master.cf file entry for the \fBproxywrite\fR 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 @@ -241,3 +251,6 @@ Wietse Venema Google, Inc. 111 8th Avenue New York, NY 10011, USA + +Wietse Venema +porcupine.org diff --git a/postfix/proto/stop.double-history b/postfix/proto/stop.double-history index 6fb0842b7..96639d384 100644 --- a/postfix/proto/stop.double-history +++ b/postfix/proto/stop.double-history @@ -181,3 +181,5 @@ proto proto COMPATIBILITY_README html 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 diff --git a/postfix/src/global/mail_version.h b/postfix/src/global/mail_version.h index 8c6f9137a..67e8164b5 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 "20250714" +#define MAIL_RELEASE_DATE "20250717" #define MAIL_VERSION_NUMBER "3.11" #ifdef SNAPSHOT diff --git a/postfix/src/postscreen/postscreen.c b/postfix/src/postscreen/postscreen.c index ebb680c06..5f16459ae 100644 --- a/postfix/src/postscreen/postscreen.c +++ b/postfix/src/postscreen/postscreen.c @@ -370,7 +370,7 @@ /* 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" @@ -430,6 +430,9 @@ /* Google, Inc. /* 111 8th Avenue /* New York, NY 10011, USA +/* +/* Wietse Venema +/* porcupine.org /*--*/ /* System library. */ @@ -996,7 +999,7 @@ static void pre_accept(char *unused_name, char **unused_argv) 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; } diff --git a/postfix/src/posttls-finger/posttls-finger.c b/postfix/src/posttls-finger/posttls-finger.c index dc25a3e09..baa5ca81b 100644 --- a/postfix/src/posttls-finger/posttls-finger.c +++ b/postfix/src/posttls-finger/posttls-finger.c @@ -414,7 +414,6 @@ #ifdef USE_TLS #include -#include #endif /* diff --git a/postfix/src/proxymap/proxymap.c b/postfix/src/proxymap/proxymap.c index 270e491a0..4a2c6755a 100644 --- a/postfix/src/proxymap/proxymap.c +++ b/postfix/src/proxymap/proxymap.c @@ -40,21 +40,24 @@ /* 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 @@ -62,29 +65,36 @@ /* 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 @@ -215,6 +225,9 @@ /* Google, Inc. /* 111 8th Avenue /* New York, NY 10011, USA +/* +/* Wietse Venema +/* porcupine.org /*--*/ /* System library. */ @@ -323,6 +336,8 @@ static char *get_nested_dict_name(char *type_name) 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 ":" @@ -360,6 +375,20 @@ static DICT *proxy_map_find(const char *map_type_name, int inst_flags, 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); } diff --git a/postfix/src/util/dict.c b/postfix/src/util/dict.c index 943772325..8189b5e89 100644 --- a/postfix/src/util/dict.c +++ b/postfix/src/util/dict.c @@ -160,8 +160,8 @@ /* .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. @@ -641,11 +641,12 @@ const char *dict_changed_name(void) 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; diff --git a/postfix/src/util/dict_db.c b/postfix/src/util/dict_db.c index 7ac034641..b1ce8327f 100644 --- a/postfix/src/util/dict_db.c +++ b/postfix/src/util/dict_db.c @@ -789,7 +789,8 @@ static DICT *dict_db_open(const char *class, const char *path, int open_flags, 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); diff --git a/postfix/src/util/dict_dbm.c b/postfix/src/util/dict_dbm.c index 0b81134d7..9263c78cc 100644 --- a/postfix/src/util/dict_dbm.c +++ b/postfix/src/util/dict_dbm.c @@ -472,7 +472,8 @@ DICT *dict_dbm_open(const char *path, int open_flags, int dict_flags) 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); diff --git a/postfix/src/util/dict_lmdb.c b/postfix/src/util/dict_lmdb.c index 88e4a03bf..9bf3c50ea 100644 --- a/postfix/src/util/dict_lmdb.c +++ b/postfix/src/util/dict_lmdb.c @@ -653,7 +653,8 @@ DICT *dict_lmdb_open(const char *path, int open_flags, int dict_flags) 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); diff --git a/postfix/src/util/dict_sdbm.c b/postfix/src/util/dict_sdbm.c index f6644138e..33ce6aae8 100644 --- a/postfix/src/util/dict_sdbm.c +++ b/postfix/src/util/dict_sdbm.c @@ -449,7 +449,8 @@ DICT *dict_sdbm_open(const char *path, int open_flags, int dict_flags) 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); diff --git a/postfix/src/util/htable.c b/postfix/src/util/htable.c index 5d659aa18..f069b7cde 100644 --- a/postfix/src/util/htable.c +++ b/postfix/src/util/htable.c @@ -93,8 +93,7 @@ /* 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. @@ -272,7 +271,7 @@ HTABLE_INFO *htable_locate(HTABLE *table, const char *key) 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)) @@ -290,6 +289,14 @@ void htable_delete(HTABLE *table, const char *key, void (*free_fn) (void *)) 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; } } @@ -374,7 +381,7 @@ HTABLE_INFO *htable_sequence(HTABLE *table, int how) 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)++);