From 085f0e5f3194e4027e3fe6515b53c75fbb0c1b28 Mon Sep 17 00:00:00 2001
From: Wietse Z Venema
Date: Thu, 9 Jan 2025 00:00:00 -0500
Subject: [PATCH] postfix-3.10-20250109
---
postfix/HISTORY | 15 +++++
postfix/README_FILES/CDB_README | 29 ++++++---
postfix/WISHLIST | 3 +
postfix/conf/post-install | 2 +-
postfix/conf/postfix-script | 2 +-
postfix/conf/postfix-wrapper | 2 +-
postfix/html/CDB_README.html | 36 ++++++++---
postfix/html/postfix-wrapper.5.html | 2 +-
postfix/man/man5/postfix-wrapper.5 | 2 +-
postfix/proto/CDB_README.html | 36 ++++++++---
postfix/proto/postfix-wrapper | 2 +-
postfix/proto/stop | 1 +
postfix/proto/stop.spell-cc | 2 +
postfix/src/global/mail_version.h | 2 +-
postfix/src/postmap/Makefile.in | 15 ++++-
postfix/src/util/dict_cdb.c | 94 ++++++++++++++++++++++++-----
16 files changed, 191 insertions(+), 54 deletions(-)
diff --git a/postfix/HISTORY b/postfix/HISTORY
index c57b542c8..a9fea117b 100644
--- a/postfix/HISTORY
+++ b/postfix/HISTORY
@@ -28780,3 +28780,18 @@ Apologies for any names omitted.
Cleanup: the netstring client sets or clears errno to improve
error messages from its callers. File: util/netstring.c.
+
+20250109
+
+ Bugfix (defect introduced: Postfix 2.6): fixed the parsing
+ of multiple commas in a multi_instance_directories parameter
+ value. Michael Tokarev. Files: conf/postfix-script,
+ conf/post-install, conf/postfix-wrapper, proto/postfix-wrapper.
+
+ Cleanup: replace static result buffer with per-instance buffer.
+ Michael Tokarev. File: util/dict_cdb.c.
+
+ Feature: first/next iterator support for cdb: tables, if
+ built with tinycdb. Michael Tokarev. Wietse added a test
+ and documentation. Files: util/dict_cdb.c proto/CDB_README.html,
+ postmap/Makefile.in.
diff --git a/postfix/README_FILES/CDB_README b/postfix/README_FILES/CDB_README
index 0dbb5cbe2..6ccf26807 100644
--- a/postfix/README_FILES/CDB_README
+++ b/postfix/README_FILES/CDB_README
@@ -17,8 +17,25 @@ temporarily while a CDB file is under construction). CDB databases are
maintained with the postmap(1) or postalias(1) command. The DATABASE_README
document has general information about Postfix databases.
-CDB support is available with Postfix 2.2 and later releases. This document
-describes how to build Postfix with CDB support.
+You can use "cdb:" tables wherever you can use read-only "hash", "btree" or
+"lmdb" tables with the following limitations:
+
+ * CDB databases cannot be larger than 4GB on LP64 and ILP32 systems, because
+ the CDB library API uses unsigned integers for file offsets.
+
+ * The "ppoossttmmaapp --ii" (incremental record insertion) and "ppoossttmmaapp --dd"
+ (incremental record deletion) command-line options are not available. For
+ the same reason the "cdb:" map type cannot be used to for persistent
+ caches, such as the address verification cache for the verify(8) service,
+ the TLS session cache for the tlsmgr(8) service, or the dynamic allowlist
+ for postscreen(8).
+
+ * The "sequence" operation ("ppoossttmmaapp --ss" or "ppoossttaalliiaass --ss") is available only
+ wen Postfix is built with tinycdb by Michael Tokarev, not with the original
+ cdb library by Daniel Bernstein.
+
+CDB support is available with Postfix 2.2 and later releases. The remainder of
+this document describes how to build Postfix with CDB support.
BBuuiillddiinngg PPoossttffiixx wwiitthh CCDDBB ssuuppppoorrtt
@@ -64,11 +81,3 @@ building a dynamically-loaded or statically-loaded CDB database client.
database library dependencies. And that was exactly what dynamic database
client loading was meant to avoid.
-After Postfix has been built with cdb support, you can use "cdb" tables
-wherever you can use read-only "hash", "btree" or "dbm" tables. However, the
-"ppoossttmmaapp --ii" (incremental record insertion) and "ppoossttmmaapp --dd" (incremental
-record deletion) command-line options are not available. For the same reason
-the "cdb" map type cannot be used to store the persistent address verification
-cache for the verify(8) service, or to store TLS session information for the
-tlsmgr(8) service.
-
diff --git a/postfix/WISHLIST b/postfix/WISHLIST
index 64e2ad51f..50f56fd10 100644
--- a/postfix/WISHLIST
+++ b/postfix/WISHLIST
@@ -19,6 +19,9 @@ Wish list:
relay_recipient_maps empty should default to 'no valid
recipients'. Subject to compatibility level.
+ Replace static result buffers with per-instance buffers in
+ dict_unix.c, dict_ni*c.
+
The Milter 'quarantine' action should be reported with a
call-back function, instead of setting the Milter default
reply. However, we still need the existing 'reply' based
diff --git a/postfix/conf/post-install b/postfix/conf/post-install
index cceef6770..cd5f14678 100644
--- a/postfix/conf/post-install
+++ b/postfix/conf/post-install
@@ -296,7 +296,7 @@ test -d "$config_directory" || {
instances=`test ! -f $def_config_directory/main.cf ||
$POSTCONF -qc $def_config_directory -h multi_instance_directories |
- sed 's/,/ /'` || exit 1
+ sed 'y/,/ /'` || exit 1
update_shared_files=1
for name in $instances
diff --git a/postfix/conf/postfix-script b/postfix/conf/postfix-script
index c43d764fb..de86d382b 100755
--- a/postfix/conf/postfix-script
+++ b/postfix/conf/postfix-script
@@ -97,7 +97,7 @@ def_config_directory=`$command_directory/postconf -dh config_directory` || {
instances=`test ! -f $def_config_directory/main.cf ||
$command_directory/postconf -qc $def_config_directory \
- -h multi_instance_directories | sed 's/,/ /'` || {
+ -h multi_instance_directories | sed 'y/,/ /'` || {
$FATAL cannot execute $command_directory/postconf!
exit 1
}
diff --git a/postfix/conf/postfix-wrapper b/postfix/conf/postfix-wrapper
index dd0a51762..cb9dc10d8 100644
--- a/postfix/conf/postfix-wrapper
+++ b/postfix/conf/postfix-wrapper
@@ -188,7 +188,7 @@ POSTFIX=$command_directory/postfix
# Canonicalize the instance directory list. The list is specified
# in startup order.
-instance_dirs=`$POSTCONF -h multi_instance_directories | sed 's/,/ /'` ||
+instance_dirs=`$POSTCONF -h multi_instance_directories | sed 'y/,/ /'` ||
exit 1
case "$1" in
diff --git a/postfix/html/CDB_README.html b/postfix/html/CDB_README.html
index e58ccc818..e6952eed5 100644
--- a/postfix/html/CDB_README.html
+++ b/postfix/html/CDB_README.html
@@ -35,8 +35,33 @@ under construction). CDB databases are maintained with the postalias(1) command. The DATABASE_README document has general
information about Postfix databases.
+ You can use "cdb:" tables wherever you can use read-only "hash",
+"btree" or "lmdb" tables with the following limitations:
+
+
+
+-
CDB databases cannot be larger than 4GB on LP64 and ILP32
+systems, because the CDB library API uses unsigned integers for
+file offsets.
+
+ -
The "postmap -i" (incremental record insertion) and
+"postmap -d" (incremental record deletion) command-line
+options are not available. For the same reason the "cdb:" map type
+cannot be used to for persistent caches, such as the address
+verification cache for the verify(8) service, the TLS session cache
+for the tlsmgr(8) service, or the dynamic allowlist for postscreen(8).
+
+
+ -
The "sequence" operation ("postmap -s" or "postalias
+-s") is available only wen Postfix is built with tinycdb by
+Michael Tokarev, not with the original cdb library by Daniel Bernstein.
+
+
+
+
CDB support is available with Postfix 2.2 and later releases.
-This document describes how to build Postfix with CDB support.
+The remainder of this document describes how to build Postfix with
+CDB support.
Building Postfix with CDB support
@@ -99,12 +124,3 @@ will have CDB database library dependencies. And that was exactly
what dynamic database client loading was meant to avoid.
-
- After Postfix has been built with cdb support, you can use
-"cdb" tables wherever you can use read-only "hash", "btree" or
-"dbm" tables. However, the "postmap -i" (incremental record
-insertion) and "postmap -d" (incremental record deletion)
-command-line options are not available. For the same reason the
-"cdb" map type cannot be used to store the persistent address
-verification cache for the verify(8) service, or to store
-TLS session information for the tlsmgr(8) service.
diff --git a/postfix/html/postfix-wrapper.5.html b/postfix/html/postfix-wrapper.5.html
index 88884eece..845e23126 100644
--- a/postfix/html/postfix-wrapper.5.html
+++ b/postfix/html/postfix-wrapper.5.html
@@ -106,7 +106,7 @@ POSTFIX-WRAPPER(5) POSTFIX-WRAPPER(5)
POSTCONF=$command_directory/postconf
POSTFIX=$command_directory/postfix
instance_dirs=`$POSTCONF -h multi_instance_directories |
- sed 's/,/ /'` || exit 1
+ sed 'y/,/ /'` || exit 1
err=0
for dir in $config_directory $instance_dirs
diff --git a/postfix/man/man5/postfix-wrapper.5 b/postfix/man/man5/postfix-wrapper.5
index 3f4ee9cd0..d6e66910c 100644
--- a/postfix/man/man5/postfix-wrapper.5
+++ b/postfix/man/man5/postfix-wrapper.5
@@ -123,7 +123,7 @@ manager implementation:
POSTCONF=$command_directory/postconf
POSTFIX=$command_directory/postfix
instance_dirs=\`$POSTCONF \-h multi_instance_directories |
- sed 's/,/ /'\` || exit 1
+ sed 'y/,/ /'\` || exit 1
err=0
for dir in $config_directory $instance_dirs
diff --git a/postfix/proto/CDB_README.html b/postfix/proto/CDB_README.html
index 0654551d3..cb25a8a74 100644
--- a/postfix/proto/CDB_README.html
+++ b/postfix/proto/CDB_README.html
@@ -35,8 +35,33 @@ under construction). CDB databases are maintained with the postmap(1)
or postalias(1) command. The DATABASE_README document has general
information about Postfix databases.
+ You can use "cdb:" tables wherever you can use read-only "hash",
+"btree" or "lmdb" tables with the following limitations:
+
+
+
+-
CDB databases cannot be larger than 4GB on LP64 and ILP32
+systems, because the CDB library API uses unsigned integers for
+file offsets.
+
+ -
The "postmap -i" (incremental record insertion) and
+"postmap -d" (incremental record deletion) command-line
+options are not available. For the same reason the "cdb:" map type
+cannot be used to for persistent caches, such as the address
+verification cache for the verify(8) service, the TLS session cache
+for the tlsmgr(8) service, or the dynamic allowlist for postscreen(8).
+
+
+ -
The "sequence" operation ("postmap -s" or "postalias
+-s") is available only wen Postfix is built with tinycdb by
+Michael Tokarev, not with the original cdb library by Daniel Bernstein.
+
+
+
+
CDB support is available with Postfix 2.2 and later releases.
-This document describes how to build Postfix with CDB support.
+The remainder of this document describes how to build Postfix with
+CDB support.
Building Postfix with CDB support
@@ -99,12 +124,3 @@ will have CDB database library dependencies. And that was exactly
what dynamic database client loading was meant to avoid.
-
- After Postfix has been built with cdb support, you can use
-"cdb" tables wherever you can use read-only "hash", "btree" or
-"dbm" tables. However, the "postmap -i" (incremental record
-insertion) and "postmap -d" (incremental record deletion)
-command-line options are not available. For the same reason the
-"cdb" map type cannot be used to store the persistent address
-verification cache for the verify(8) service, or to store
-TLS session information for the tlsmgr(8) service.
diff --git a/postfix/proto/postfix-wrapper b/postfix/proto/postfix-wrapper
index 177282ef7..aaf6a53c6 100644
--- a/postfix/proto/postfix-wrapper
+++ b/postfix/proto/postfix-wrapper
@@ -113,7 +113,7 @@
# POSTCONF=$command_directory/postconf
# POSTFIX=$command_directory/postfix
# instance_dirs=\`$POSTCONF -h multi_instance_directories |
-# sed 's/,/ /'\` || exit 1
+# sed 'y/,/ /'\` || exit 1
#
# err=0
# for dir in $config_directory $instance_dirs
diff --git a/postfix/proto/stop b/postfix/proto/stop
index 22af8cf39..99dfe3199 100644
--- a/postfix/proto/stop
+++ b/postfix/proto/stop
@@ -1659,3 +1659,4 @@ GECOS
iso
ORCPT
RET
+ILP
diff --git a/postfix/proto/stop.spell-cc b/postfix/proto/stop.spell-cc
index 97b670546..4295afb1e 100644
--- a/postfix/proto/stop.spell-cc
+++ b/postfix/proto/stop.spell-cc
@@ -1854,3 +1854,5 @@ Charset
atext
qp
cntrl
+TINYCDB
+getdata
diff --git a/postfix/src/global/mail_version.h b/postfix/src/global/mail_version.h
index dbd0f0afd..08d6ed264 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 "20250107"
+#define MAIL_RELEASE_DATE "20250109"
#define MAIL_VERSION_NUMBER "3.10"
#ifdef SNAPSHOT
diff --git a/postfix/src/postmap/Makefile.in b/postfix/src/postmap/Makefile.in
index 9175767e7..4f114f504 100644
--- a/postfix/src/postmap/Makefile.in
+++ b/postfix/src/postmap/Makefile.in
@@ -27,7 +27,7 @@ update: ../../bin/$(PROG)
cp $(PROG) ../../bin
tests: test1 test2 fail_test quote_test file_test lmdb_abb_test \
- lmdb_bulk_test lmdb_incr_test
+ lmdb_bulk_test lmdb_incr_test cdb_bulk_test
root_tests:
@@ -74,6 +74,17 @@ file_test: $(PROG) file_test.in file_test.ref
diff file_test.ref file_test.tmp
rm -f file_test.tmp file_test_map.* postmap-file-1 postmap-file-2
+cdb_bulk_test: $(PROG)
+ rm -f cdb_bulk.cdb main.cf
+ tr A-Z a-z < /usr/share/dict/words| \
+ sed -e 's/.*/& &/' -e 10000q| LANG=C sort -u >cdb_bulk
+ touch -t 197101010000 main.cf
+ ($(SHLIB_ENV) $(VALGRIND) ./postmap -c . cdb:cdb_bulk; \
+ $(SHLIB_ENV) $(VALGRIND) ./postmap -s cdb:cdb_bulk | \
+ LANG=C sort > cdb_bulk.tmp)
+ cmp cdb_bulk cdb_bulk.tmp
+ rm -f cdb_bulk cdb_bulk.tmp cdb_bulk.cdb main.cf
+
lmdb_abb_test: $(PROG) lmdb_abb lmdb_abb.ref
rm -f lmdb_abb.lmdb
($(SHLIB_ENV) $(VALGRIND) ./postmap lmdb:lmdb_abb; \
@@ -86,6 +97,7 @@ lmdb_bulk_test: $(PROG)
tr A-Z a-z < /usr/share/dict/words| \
sed -e 's/.*/& &/' -e 10000q| LANG=C sort -u >lmdb_retry
echo lmdb_map_size=10240 >main.cf
+ touch -t 197101010000 main.cf
($(SHLIB_ENV) $(VALGRIND) ./postmap -c . lmdb:lmdb_retry; \
$(SHLIB_ENV) $(VALGRIND) ./postmap -s lmdb:lmdb_retry | \
LANG=C sort > lmdb_retry.tmp)
@@ -97,6 +109,7 @@ lmdb_incr_test: $(PROG)
tr A-Z a-z < /usr/share/dict/words| \
sed -e 's/.*/& &/' -e 1000q| LANG=C sort -u >lmdb_retry
echo lmdb_map_size=10240 >main.cf
+ touch -t 197101010000 main.cf
($(SHLIB_ENV) $(VALGRIND) ./postmap -ic . lmdb:lmdb_retry lmdb_retry.tmp)
diff --git a/postfix/src/util/dict_cdb.c b/postfix/src/util/dict_cdb.c
index a9133cc35..ea98363ff 100644
--- a/postfix/src/util/dict_cdb.c
+++ b/postfix/src/util/dict_cdb.c
@@ -84,6 +84,11 @@
typedef struct {
DICT dict; /* generic members */
struct cdb cdb; /* cdb structure */
+ VSTRING *val_buf; /* value result */
+#ifdef TINYCDB_VERSION
+ VSTRING *key_buf; /* key result */
+ unsigned seq_cptr; /* current sequence pointer */
+#endif
} DICT_CDBQ; /* query interface */
typedef struct {
@@ -93,15 +98,31 @@ typedef struct {
char *tmp_path; /* temporary pathname (.tmp) */
} DICT_CDBM; /* rebuild interface */
+/* dict_cdbq_getdata - get data out of the cdb using given buffer */
+
+static const char *dict_cdbq_get_data(DICT_CDBQ *dict_cdbq,
+ VSTRING **bufp, unsigned len, unsigned pos)
+{
+ VSTRING *buf = *bufp;
+
+ if (!buf)
+ buf = *bufp = vstring_alloc(len < 20 ? 20 : len);
+ VSTRING_RESET(buf);
+ VSTRING_SPACE(buf, len);
+
+ if (cdb_read(&dict_cdbq->cdb, vstring_str(buf), len, pos) < 0)
+ msg_fatal("error reading %s: %m", dict_cdbq->dict.name);
+ vstring_set_payload_size(buf, len);
+ VSTRING_TERMINATE(buf);
+ return vstring_str(buf);
+}
+
/* dict_cdbq_lookup - find database entry, query mode */
static const char *dict_cdbq_lookup(DICT *dict, const char *name)
{
DICT_CDBQ *dict_cdbq = (DICT_CDBQ *) dict;
- unsigned vlen;
int status = 0;
- static char *buf;
- static unsigned len;
const char *result = 0;
dict->error = 0;
@@ -141,25 +162,56 @@ static const char *dict_cdbq_lookup(DICT *dict, const char *name)
msg_fatal("error reading %s: %m", dict->name);
if (status) {
- vlen = cdb_datalen(&dict_cdbq->cdb);
- if (len < vlen) {
- if (buf == 0)
- buf = mymalloc(vlen + 1);
- else
- buf = myrealloc(buf, vlen + 1);
- len = vlen;
- }
- if (cdb_read(&dict_cdbq->cdb, buf, vlen,
- cdb_datapos(&dict_cdbq->cdb)) < 0)
- msg_fatal("error reading %s: %m", dict->name);
- buf[vlen] = '\0';
- result = buf;
+ result = dict_cdbq_get_data(dict_cdbq, &dict_cdbq->val_buf,
+ cdb_datalen(&dict_cdbq->cdb), cdb_datapos(&dict_cdbq->cdb));
}
/* No locking so not release the lock. */
return (result);
}
+#ifdef TINYCDB_VERSION
+
+/* dict_cdbq_sequence - traverse the dictionary */
+
+static int dict_cdbq_sequence(DICT *dict, int function,
+ const char **key, const char **value)
+{
+ const char *myname = "dict_cdbq_sequence";
+ DICT_CDBQ *dict_cdbq = (DICT_CDBQ *) dict;
+ int status;
+
+ switch (function) {
+ case DICT_SEQ_FUN_FIRST:
+ cdb_seqinit(&dict_cdbq->seq_cptr, &dict_cdbq->cdb);
+ break;
+ case DICT_SEQ_FUN_NEXT:
+ if (!dict_cdbq->seq_cptr)
+ msg_panic("%s: %s: no cursor", myname, dict_cdbq->dict.name);
+ break;
+ default:
+ msg_panic("%s: invalid function %d", myname, function);
+ }
+
+ status = cdb_seqnext(&dict_cdbq->seq_cptr, &dict_cdbq->cdb);
+
+ if (status < 0)
+ msg_fatal("error seeking %s: %m", dict_cdbq->dict.name);
+
+ if (!status) {
+ dict_cdbq->seq_cptr = 0;
+ return -1; /* not found */
+ }
+ *key = dict_cdbq_get_data(dict_cdbq, &dict_cdbq->key_buf,
+ cdb_keylen(&dict_cdbq->cdb), cdb_keypos(&dict_cdbq->cdb));
+ *value = dict_cdbq_get_data(dict_cdbq, &dict_cdbq->val_buf,
+ cdb_datalen(&dict_cdbq->cdb), cdb_datapos(&dict_cdbq->cdb));
+
+ return 0;
+}
+
+#endif /* TINYCDB_VERSION */
+
/* dict_cdbq_close - close data base, query mode */
static void dict_cdbq_close(DICT *dict)
@@ -170,6 +222,12 @@ static void dict_cdbq_close(DICT *dict)
close(dict->stat_fd);
if (dict->fold_buf)
vstring_free(dict->fold_buf);
+ if (dict_cdbq->val_buf)
+ vstring_free(dict_cdbq->val_buf);
+#ifdef TINYCDB_VERSION
+ if (dict_cdbq->key_buf)
+ vstring_free(dict_cdbq->key_buf);
+#endif
dict_free(dict);
}
@@ -200,9 +258,13 @@ static DICT *dict_cdbq_open(const char *path, int dict_flags)
dict_cdbq = (DICT_CDBQ *) dict_alloc(DICT_TYPE_CDB,
cdb_path, sizeof(*dict_cdbq));
+ dict_cdbq->val_buf = 0;
#if defined(TINYCDB_VERSION)
+ dict_cdbq->key_buf = 0;
+ dict_cdbq->seq_cptr = 0;
if (cdb_init(&(dict_cdbq->cdb), fd) != 0)
msg_fatal("dict_cdbq_open: unable to init %s: %m", cdb_path);
+ dict_cdbq->dict.sequence = dict_cdbq_sequence;
#else
cdb_init(&(dict_cdbq->cdb), fd);
#endif