2
0
mirror of https://github.com/vdukhovni/postfix synced 2025-08-22 18:07:41 +00:00

postfix-3.10-20250109

This commit is contained in:
Wietse Z Venema 2025-01-09 00:00:00 -05:00 committed by Viktor Dukhovni
parent a98bc4ee9b
commit 085f0e5f31
16 changed files with 191 additions and 54 deletions

View File

@ -28780,3 +28780,18 @@ Apologies for any names omitted.
Cleanup: the netstring client sets or clears errno to improve Cleanup: the netstring client sets or clears errno to improve
error messages from its callers. File: util/netstring.c. 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.

View File

@ -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 maintained with the postmap(1) or postalias(1) command. The DATABASE_README
document has general information about Postfix databases. document has general information about Postfix databases.
CDB support is available with Postfix 2.2 and later releases. This document You can use "cdb:" tables wherever you can use read-only "hash", "btree" or
describes how to build Postfix with CDB support. "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 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 database library dependencies. And that was exactly what dynamic database
client loading was meant to avoid. 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.

View File

@ -19,6 +19,9 @@ Wish list:
relay_recipient_maps empty should default to 'no valid relay_recipient_maps empty should default to 'no valid
recipients'. Subject to compatibility level. 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 The Milter 'quarantine' action should be reported with a
call-back function, instead of setting the Milter default call-back function, instead of setting the Milter default
reply. However, we still need the existing 'reply' based reply. However, we still need the existing 'reply' based

View File

@ -296,7 +296,7 @@ test -d "$config_directory" || {
instances=`test ! -f $def_config_directory/main.cf || instances=`test ! -f $def_config_directory/main.cf ||
$POSTCONF -qc $def_config_directory -h multi_instance_directories | $POSTCONF -qc $def_config_directory -h multi_instance_directories |
sed 's/,/ /'` || exit 1 sed 'y/,/ /'` || exit 1
update_shared_files=1 update_shared_files=1
for name in $instances for name in $instances

View File

@ -97,7 +97,7 @@ def_config_directory=`$command_directory/postconf -dh config_directory` || {
instances=`test ! -f $def_config_directory/main.cf || instances=`test ! -f $def_config_directory/main.cf ||
$command_directory/postconf -qc $def_config_directory \ $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! $FATAL cannot execute $command_directory/postconf!
exit 1 exit 1
} }

View File

@ -188,7 +188,7 @@ POSTFIX=$command_directory/postfix
# Canonicalize the instance directory list. The list is specified # Canonicalize the instance directory list. The list is specified
# in startup order. # in startup order.
instance_dirs=`$POSTCONF -h multi_instance_directories | sed 's/,/ /'` || instance_dirs=`$POSTCONF -h multi_instance_directories | sed 'y/,/ /'` ||
exit 1 exit 1
case "$1" in case "$1" in

View File

@ -35,8 +35,33 @@ under construction). CDB databases are maintained with the <a href="postmap.1.h
or <a href="postalias.1.html">postalias(1)</a> command. The <a href="DATABASE_README.html">DATABASE_README</a> document has general or <a href="postalias.1.html">postalias(1)</a> command. The <a href="DATABASE_README.html">DATABASE_README</a> document has general
information about Postfix databases. </p> information about Postfix databases. </p>
<p> You can use "<a href="CDB_README.html">cdb</a>:" tables wherever you can use read-only "hash",
"btree" or "lmdb" tables with the following limitations: </p>
<ul>
<li> <p> CDB databases cannot be larger than 4GB on LP64 and ILP32
systems, because the CDB library API uses unsigned integers for
file offsets. </p>
<li> <p> The "<b>postmap -i</b>" (incremental record insertion) and
"<b>postmap -d</b>" (incremental record deletion) command-line
options are not available. For the same reason the "<a href="CDB_README.html">cdb</a>:" map type
cannot be used to for persistent caches, such as the address
verification cache for the <a href="verify.8.html">verify(8)</a> service, the TLS session cache
for the <a href="tlsmgr.8.html">tlsmgr(8)</a> service, or the dynamic allowlist for <a href="postscreen.8.html">postscreen(8)</a>.
</p>
<li> <p> The "sequence" operation ("<b>postmap -s</b>" or "<b>postalias
-s</b>") is available only wen Postfix is built with tinycdb by
Michael Tokarev, not with the original cdb library by Daniel Bernstein.
</p>
</ul>
<p> CDB support is available with Postfix 2.2 and later releases. <p> CDB support is available with Postfix 2.2 and later releases.
This document describes how to build Postfix with CDB support. </p> The remainder of this document describes how to build Postfix with
CDB support. </p>
<h2>Building Postfix with CDB support</h2> <h2>Building Postfix with CDB support</h2>
@ -99,12 +124,3 @@ will have CDB database library dependencies. And that was exactly
what dynamic database client loading was meant to avoid. </p> what dynamic database client loading was meant to avoid. </p>
</blockquote> </blockquote>
<p> 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 "<b>postmap -i</b>" (incremental record
insertion) and "<b>postmap -d</b>" (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 <a href="verify.8.html">verify(8)</a> service, or to store
TLS session information for the <a href="tlsmgr.8.html">tlsmgr(8)</a> service. </p>

View File

@ -106,7 +106,7 @@ POSTFIX-WRAPPER(5) POSTFIX-WRAPPER(5)
POSTCONF=$<a href="postconf.5.html#command_directory">command_directory</a>/postconf POSTCONF=$<a href="postconf.5.html#command_directory">command_directory</a>/postconf
POSTFIX=$<a href="postconf.5.html#command_directory">command_directory</a>/postfix POSTFIX=$<a href="postconf.5.html#command_directory">command_directory</a>/postfix
instance_dirs=`$POSTCONF -h <a href="postconf.5.html#multi_instance_directories">multi_instance_directories</a> | instance_dirs=`$POSTCONF -h <a href="postconf.5.html#multi_instance_directories">multi_instance_directories</a> |
sed 's/,/ /'` || exit 1 sed 'y/,/ /'` || exit 1
err=0 err=0
for dir in $<a href="postconf.5.html#config_directory">config_directory</a> $instance_dirs for dir in $<a href="postconf.5.html#config_directory">config_directory</a> $instance_dirs

View File

@ -123,7 +123,7 @@ manager implementation:
POSTCONF=$command_directory/postconf POSTCONF=$command_directory/postconf
POSTFIX=$command_directory/postfix POSTFIX=$command_directory/postfix
instance_dirs=\`$POSTCONF \-h multi_instance_directories | instance_dirs=\`$POSTCONF \-h multi_instance_directories |
sed 's/,/ /'\` || exit 1 sed 'y/,/ /'\` || exit 1
err=0 err=0
for dir in $config_directory $instance_dirs for dir in $config_directory $instance_dirs

View File

@ -35,8 +35,33 @@ under construction). CDB databases are maintained with the postmap(1)
or postalias(1) command. The DATABASE_README document has general or postalias(1) command. The DATABASE_README document has general
information about Postfix databases. </p> information about Postfix databases. </p>
<p> You can use "cdb:" tables wherever you can use read-only "hash",
"btree" or "lmdb" tables with the following limitations: </p>
<ul>
<li> <p> CDB databases cannot be larger than 4GB on LP64 and ILP32
systems, because the CDB library API uses unsigned integers for
file offsets. </p>
<li> <p> The "<b>postmap -i</b>" (incremental record insertion) and
"<b>postmap -d</b>" (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).
</p>
<li> <p> The "sequence" operation ("<b>postmap -s</b>" or "<b>postalias
-s</b>") is available only wen Postfix is built with tinycdb by
Michael Tokarev, not with the original cdb library by Daniel Bernstein.
</p>
</ul>
<p> CDB support is available with Postfix 2.2 and later releases. <p> CDB support is available with Postfix 2.2 and later releases.
This document describes how to build Postfix with CDB support. </p> The remainder of this document describes how to build Postfix with
CDB support. </p>
<h2>Building Postfix with CDB support</h2> <h2>Building Postfix with CDB support</h2>
@ -99,12 +124,3 @@ will have CDB database library dependencies. And that was exactly
what dynamic database client loading was meant to avoid. </p> what dynamic database client loading was meant to avoid. </p>
</blockquote> </blockquote>
<p> 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 "<b>postmap -i</b>" (incremental record
insertion) and "<b>postmap -d</b>" (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. </p>

View File

@ -113,7 +113,7 @@
# POSTCONF=$command_directory/postconf # POSTCONF=$command_directory/postconf
# POSTFIX=$command_directory/postfix # POSTFIX=$command_directory/postfix
# instance_dirs=\`$POSTCONF -h multi_instance_directories | # instance_dirs=\`$POSTCONF -h multi_instance_directories |
# sed 's/,/ /'\` || exit 1 # sed 'y/,/ /'\` || exit 1
# #
# err=0 # err=0
# for dir in $config_directory $instance_dirs # for dir in $config_directory $instance_dirs

View File

@ -1659,3 +1659,4 @@ GECOS
iso iso
ORCPT ORCPT
RET RET
ILP

View File

@ -1854,3 +1854,5 @@ Charset
atext atext
qp qp
cntrl cntrl
TINYCDB
getdata

View File

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

View File

@ -27,7 +27,7 @@ update: ../../bin/$(PROG)
cp $(PROG) ../../bin cp $(PROG) ../../bin
tests: test1 test2 fail_test quote_test file_test lmdb_abb_test \ 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: root_tests:
@ -74,6 +74,17 @@ file_test: $(PROG) file_test.in file_test.ref
diff file_test.ref file_test.tmp diff file_test.ref file_test.tmp
rm -f file_test.tmp file_test_map.* postmap-file-1 postmap-file-2 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 lmdb_abb_test: $(PROG) lmdb_abb lmdb_abb.ref
rm -f lmdb_abb.lmdb rm -f lmdb_abb.lmdb
($(SHLIB_ENV) $(VALGRIND) ./postmap lmdb:lmdb_abb; \ ($(SHLIB_ENV) $(VALGRIND) ./postmap lmdb:lmdb_abb; \
@ -86,6 +97,7 @@ lmdb_bulk_test: $(PROG)
tr A-Z a-z < /usr/share/dict/words| \ tr A-Z a-z < /usr/share/dict/words| \
sed -e 's/.*/& &/' -e 10000q| LANG=C sort -u >lmdb_retry sed -e 's/.*/& &/' -e 10000q| LANG=C sort -u >lmdb_retry
echo lmdb_map_size=10240 >main.cf echo lmdb_map_size=10240 >main.cf
touch -t 197101010000 main.cf
($(SHLIB_ENV) $(VALGRIND) ./postmap -c . lmdb:lmdb_retry; \ ($(SHLIB_ENV) $(VALGRIND) ./postmap -c . lmdb:lmdb_retry; \
$(SHLIB_ENV) $(VALGRIND) ./postmap -s lmdb:lmdb_retry | \ $(SHLIB_ENV) $(VALGRIND) ./postmap -s lmdb:lmdb_retry | \
LANG=C sort > lmdb_retry.tmp) LANG=C sort > lmdb_retry.tmp)
@ -97,6 +109,7 @@ lmdb_incr_test: $(PROG)
tr A-Z a-z < /usr/share/dict/words| \ tr A-Z a-z < /usr/share/dict/words| \
sed -e 's/.*/& &/' -e 1000q| LANG=C sort -u >lmdb_retry sed -e 's/.*/& &/' -e 1000q| LANG=C sort -u >lmdb_retry
echo lmdb_map_size=10240 >main.cf echo lmdb_map_size=10240 >main.cf
touch -t 197101010000 main.cf
($(SHLIB_ENV) $(VALGRIND) ./postmap -ic . lmdb:lmdb_retry <lmdb_retry; \ ($(SHLIB_ENV) $(VALGRIND) ./postmap -ic . lmdb:lmdb_retry <lmdb_retry; \
$(SHLIB_ENV) $(VALGRIND) ./postmap -s lmdb:lmdb_retry | \ $(SHLIB_ENV) $(VALGRIND) ./postmap -s lmdb:lmdb_retry | \
LANG=C sort > lmdb_retry.tmp) LANG=C sort > lmdb_retry.tmp)

View File

@ -84,6 +84,11 @@
typedef struct { typedef struct {
DICT dict; /* generic members */ DICT dict; /* generic members */
struct cdb cdb; /* cdb structure */ 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 */ } DICT_CDBQ; /* query interface */
typedef struct { typedef struct {
@ -93,15 +98,31 @@ typedef struct {
char *tmp_path; /* temporary pathname (.tmp) */ char *tmp_path; /* temporary pathname (.tmp) */
} DICT_CDBM; /* rebuild interface */ } 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 */ /* dict_cdbq_lookup - find database entry, query mode */
static const char *dict_cdbq_lookup(DICT *dict, const char *name) static const char *dict_cdbq_lookup(DICT *dict, const char *name)
{ {
DICT_CDBQ *dict_cdbq = (DICT_CDBQ *) dict; DICT_CDBQ *dict_cdbq = (DICT_CDBQ *) dict;
unsigned vlen;
int status = 0; int status = 0;
static char *buf;
static unsigned len;
const char *result = 0; const char *result = 0;
dict->error = 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); msg_fatal("error reading %s: %m", dict->name);
if (status) { if (status) {
vlen = cdb_datalen(&dict_cdbq->cdb); result = dict_cdbq_get_data(dict_cdbq, &dict_cdbq->val_buf,
if (len < vlen) { cdb_datalen(&dict_cdbq->cdb), cdb_datapos(&dict_cdbq->cdb));
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;
} }
/* No locking so not release the lock. */ /* No locking so not release the lock. */
return (result); 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 */ /* dict_cdbq_close - close data base, query mode */
static void dict_cdbq_close(DICT *dict) static void dict_cdbq_close(DICT *dict)
@ -170,6 +222,12 @@ static void dict_cdbq_close(DICT *dict)
close(dict->stat_fd); close(dict->stat_fd);
if (dict->fold_buf) if (dict->fold_buf)
vstring_free(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); 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, dict_cdbq = (DICT_CDBQ *) dict_alloc(DICT_TYPE_CDB,
cdb_path, sizeof(*dict_cdbq)); cdb_path, sizeof(*dict_cdbq));
dict_cdbq->val_buf = 0;
#if defined(TINYCDB_VERSION) #if defined(TINYCDB_VERSION)
dict_cdbq->key_buf = 0;
dict_cdbq->seq_cptr = 0;
if (cdb_init(&(dict_cdbq->cdb), fd) != 0) if (cdb_init(&(dict_cdbq->cdb), fd) != 0)
msg_fatal("dict_cdbq_open: unable to init %s: %m", cdb_path); msg_fatal("dict_cdbq_open: unable to init %s: %m", cdb_path);
dict_cdbq->dict.sequence = dict_cdbq_sequence;
#else #else
cdb_init(&(dict_cdbq->cdb), fd); cdb_init(&(dict_cdbq->cdb), fd);
#endif #endif