2
0
mirror of https://github.com/vdukhovni/postfix synced 2025-08-22 09:57:34 +00:00

postfix-3.11-20250713

This commit is contained in:
Wietse Z Venema 2025-07-13 00:00:00 -05:00 committed by Viktor Dukhovni
parent fcc88c9a9c
commit e3501bc815
24 changed files with 684 additions and 142 deletions

View File

@ -29345,3 +29345,53 @@ Apologies for any names omitted.
Cleanup: simplified the rule parser in global/server_acl.c.
Unbroke dict_debug Valgrind checks. File: util/dict_debug_test.sh.
20250710
Bugfix (defect introduced: postfix-2.2, date 20050203):
after detecting a lookup table change, and after starting
a new postscreen process, the old postscreen process logged
an ENOTSOCK error while attempting to accept a connection
on a socket that it was no longer listening on. This error
was introduced first in the multi_server skeleton code, and
was five years later duplicated in the event_server skeleton
that was created for postscreen. Problem reported by Florian
Piekert. Files: master/multi_server.c, master/event_server.c.
20250713
Cleanup: allow "postmap -s" and "postalias -s" with proxied
tables. The proxymap protocol already supported this. Files:
postmap/postmap.c, postalias/postalias.c.
Cleanup: simplified the proxymap protocol and the proxymap
table sharing strategy. Share only table instances that
have identical client-side dictionary flags when opening a
table (instead of sharing tables that have a common subset
of flags). With each client request, propagate all client-side
dictionary flags to the server, and upon request completion,
propagate all resulting server-side dictionary flags to the
client. Files: dict.h, dict_proxy.c, proxymap/proxymap.c,
global/mail_proto.h.
Cleanup; stop hard-coding "dict->flags = DICT_FLAG_FIXED"
in dict_alloc.c. All tables already overwrote that information.
Debugging: the default import_environment now also imports
XDG_RUNTIME_DIR to support GUI debugging a Postfix daemon
process on some platforms (it already imported XAUTHORITY
and DISPLAY for X-based debuggers). These environment
variables are set only when Postfix is started 'by hand'.
File: global/mail_params.h.
Graceful degradation: when a proxymap or proxywrite server
denies access to a table, do not terminate the program.
Instead, return a surrogate object that fails all requests
with an informative message. File: global/dict_proxy.c.
Workaround: added an example to the smtp_reply_filter
documentation that works around Microsoft SASL server
implementations that send a non-empty initial GSSAPI
challenge. File: proto/postconf.proto.
Typo in COMPATIBILITY_README.html. Emmanuel Fusté.

View File

@ -0,0 +1,459 @@
PPoossttffiixx BBaacckkwwaarrddss--CCoommppaattiibbiilliittyy SSaaffeettyy NNeett
-------------------------------------------------------------------------------
PPuurrppoossee ooff tthhiiss ddooccuummeenntt
Postfix 3.0 introduces a safety net that runs Postfix programs with backwards-
compatible default settings after an upgrade. The safety net will log a warning
whenever a "new" default setting could have an negative effect on your mail
flow.
This document provides information on the following topics:
* Detailed descriptions of Postfix backwards-compatibility warnings.
* What backwards-compatible settings you may have to make permanent in
main.cf or master.cf.
* How to turn off Postfix backwards-compatibility warnings.
OOvveerrvviieeww
With backwards compatibility turned on, Postfix logs a message whenever a
backwards-compatible default setting may be required for continuity of service.
Based on this logging the system administrator can decide if any backwards-
compatible settings need to be made permanent in main.cf or master.cf, before
turning off the backwards-compatibility safety net as described at the end of
this document.
Logged with compatibility_level < 1:
* Using backwards-compatible default setting append_dot_mydomain=yes
* Using backwards-compatible default setting chroot=y
* Using backwards-compatible default setting "smtpd_relay_restrictions =
(empty)"
* Using backwards-compatible default setting smtputf8_enable=no
Logged with compatibility_level < 2:
* Using backwards-compatible default setting mynetworks_style=subnet
* Using backwards-compatible default setting relay_domains=$mydestination
Logged with compatibility_level < 3.6:
* Using backwards-compatible default setting smtpd_tls_fingerprint_digest=md5
* Using backwards-compatible default setting smtp_tls_fingerprint_digest=md5
* Using backwards-compatible default setting lmtp_tls_fingerprint_digest=md5
* Using backwards-compatible default setting
smtpd_relay_before_recipient_restrictions=no
* Using backwards-compatible default setting respectful_logging=no
Logged with compatibility_level < 3.11:
* using backwards-compatible default setting
smtp_tlsrpt_skip_reused_handshakes=yes
* using backwards-compatible default setting xxx_security_level=(empty)
If such a message is logged in the context of a legitimate request, the system
administrator should make the backwards-compatible setting permanent in main.cf
or master.cf, as detailed in the sections that follow.
When no more backwards-compatible settings need to be made permanent, the
system administrator should turn off the backwards-compatibility safety net as
described at the end of this document.
UUssiinngg bbaacckkwwaarrddss--ccoommppaattiibbllee ddeeffaauulltt sseettttiinngg aappppeenndd__ddoott__mmyyddoommaaiinn==yyeess
The append_dot_mydomain default value has changed from "yes" to "no". This
could result in unexpected non-delivery of email after Postfix is updated from
an older version. The backwards-compatibility safety net is designed to prevent
such surprises.
As long as the append_dot_mydomain parameter is left unspecified at its
implicit default value, and the compatibility_level setting is less than 1,
Postfix may log one of the following messages:
* Messages about missing "localhost" in mydestination or other address class:
postfix/trivial-rewrite[14777]: using backwards-compatible
default setting append_dot_mydomain=yes to rewrite
"localhost" to "localhost.example.com"; please add
"localhost" to mydestination or other address class
If Postfix logs the above message, add "localhost" to mydestination (or
virtual_alias_domains, virtual_mailbox_domains, or relay_domains) and
execute the command "ppoossttffiixx rreellooaadd".
* Messages about incomplete domains in email addresses:
postfix/trivial-rewrite[25835]: using backwards-compatible
default setting append_dot_mydomain=yes to rewrite "foo" to
"foo.example.com"
If Postfix logs the above message for domains different from "localhost",
and the sender cannot be changed to use complete domain names in email
addresses, then the system administrator should make the backwards-
compatible setting "append_dot_mydomain = yes" permanent in main.cf:
# ppoossttccoonnff aappppeenndd__ddoott__mmyyddoommaaiinn==yyeess
# ppoossttffiixx rreellooaadd
UUssiinngg bbaacckkwwaarrddss--ccoommppaattiibbllee ddeeffaauulltt sseettttiinngg cchhrroooott==yy
The master.cf chroot default value has changed from "y" (yes) to "n" (no). The
new default avoids the need for copies of system files under the Postfix queue
directory. However, sites with strict security requirements may want to keep
the chroot feature enabled after updating Postfix from an older version. The
backwards-compatibility safety net is designed allow the administrator to
choose if they want to keep the old behavior.
As long as a master.cf chroot field is left unspecified at its implicit default
value, and the compatibility_level setting is less than 1, Postfix may log the
following message while it reads the master.cf file:
postfix/master[27664]: /etc/postfix/master.cf: line 72: using
backwards-compatible default setting chroot=y
If this service should remain chrooted, then the system administrator should
make the backwards-compatible setting "chroot = y" permanent in master.cf. For
example, to update the chroot setting for the "smtp inet" service:
# ppoossttccoonnff --FF ssmmttpp//iinneett//cchhrroooott==yy
# ppoossttffiixx rreellooaadd
UUssiinngg bbaacckkwwaarrddss--ccoommppaattiibbllee ddeeffaauulltt sseettttiinngg ssmmttppdd__rreellaayy__rreessttrriiccttiioonnss == ((eemmppttyy))
The smtpd_relay_restrictions feature was introduced with Postfix version 2.10,
as a safety mechanism for configuration errors in smtpd_recipient_restrictions
that could make Postfix an open relay.
The smtpd_relay_restrictions implicit default setting forbids mail to remote
destinations from clients that don't match permit_mynetworks or
permit_sasl_authenticated. This could result in unexpected 'Relay access
denied' errors after Postfix is updated from an older Postfix version. The
backwards-compatibility safety net is designed to prevent such surprises.
When the compatibility_level less than 1, and the smtpd_relay_restrictions
parameter is left unspecified at its implicit default setting, Postfix may log
the following message:
postfix/smtpd[38463]: using backwards-compatible default setting
"smtpd_relay_restrictions = (empty)" to avoid "Relay access
denied" error for recipient "user@example.com" from client
"host.example.net[10.0.0.2]"
If this request should not be blocked, then the system administrator should
make the backwards-compatible setting "smtpd_relay_restrictions=" (i.e. empty)
permanent in main.cf:
# ppoossttccoonnff ssmmttppdd__rreellaayy__rreessttrriiccttiioonnss==
# ppoossttffiixx rreellooaadd
UUssiinngg bbaacckkwwaarrddss--ccoommppaattiibbllee ddeeffaauulltt sseettttiinngg ssmmttppuuttff88__eennaabbllee==nnoo
The smtputf8_enable default value has changed from "no" to "yes". With the new
"yes" setting, the Postfix SMTP server rejects non-ASCII addresses from clients
that don't request SMTPUTF8 support, after Postfix is updated from an older
version. The backwards-compatibility safety net is designed to prevent such
surprises.
As long as the smtputf8_enable parameter is left unspecified at its implicit
default value, and the compatibility_level setting is less than 1, Postfix logs
a warning each time an SMTP command uses a non-ASCII address localpart without
requesting SMTPUTF8 support:
postfix/smtpd[27560]: using backwards-compatible default setting
smtputf8_enable=no to accept non-ASCII sender address
"??@example.org" from localhost[127.0.0.1]
postfix/smtpd[27560]: using backwards-compatible default setting
smtputf8_enable=no to accept non-ASCII recipient address
"??@example.com" from localhost[127.0.0.1]
If the address should not be rejected, and the client cannot be updated to use
SMTPUTF8, then the system administrator should make the backwards-compatible
setting "smtputf8_enable = no" permanent in main.cf:
# ppoossttccoonnff ssmmttppuuttff88__eennaabbllee==nnoo
# ppoossttffiixx rreellooaadd
UUssiinngg bbaacckkwwaarrddss--ccoommppaattiibbllee ddeeffaauulltt sseettttiinngg mmyynneettwwoorrkkss__ssttyyllee==ssuubbnneett
The mynetworks_style default value has changed from "subnet" to "host". This
parameter is used to implement the "permit_mynetworks" feature. The change
could cause unexpected 'access denied' errors after Postfix is updated from an
older version. The backwards-compatibility safety net is designed to prevent
such surprises.
As long as the mynetworks and mynetworks_style parameters are left unspecified
at their implicit default values, and the compatibility_level setting is less
than 2, the Postfix SMTP server may log one of the following messages:
postfix/smtpd[17375]: using backwards-compatible default setting
mynetworks_style=subnet to permit request from client
"foo.example.com[10.1.1.1]"
postfix/postscreen[24982]: using backwards-compatible default
setting mynetworks_style=subnet to permit request from client
"10.1.1.1"
If the client request should not be rejected, then the system administrator
should make the backwards-compatible setting "mynetworks_style = subnet"
permanent in main.cf:
# ppoossttccoonnff mmyynneettwwoorrkkss__ssttyyllee==ssuubbnneett
# ppoossttffiixx rreellooaadd
UUssiinngg bbaacckkwwaarrddss--ccoommppaattiibbllee ddeeffaauulltt sseettttiinngg rreellaayy__ddoommaaiinnss==$$mmyyddeessttiinnaattiioonn
The relay_domains default value has changed from "$mydestination" to the empty
value. This could result in unexpected 'Relay access denied' errors or ETRN
errors after Postfix is updated from an older version. The backwards-
compatibility safety net is designed to prevent such surprises.
As long as the relay_domains parameter is left unspecified at its implicit
default value, and the compatibility_level setting is less than 2, Postfix may
log one of the following messages.
* Messages about accepting mail for a remote domain:
postfix/smtpd[19052]: using backwards-compatible default setting
relay_domains=$mydestination to accept mail for domain
"foo.example.com"
postfix/smtpd[19052]: using backwards-compatible default setting
relay_domains=$mydestination to accept mail for address
"user@foo.example.com"
* Messages about providing ETRN service for a remote domain:
postfix/smtpd[19138]: using backwards-compatible default setting
relay_domains=$mydestination to flush mail for domain
"bar.example.com"
postfix/smtp[13945]: using backwards-compatible default setting
relay_domains=$mydestination to update fast-flush logfile for
domain "bar.example.com"
If Postfix should continue to accept mail for that domain or continue to
provide ETRN service for that domain, then the system administrator should make
the backwards-compatible setting "relay_domains = $mydestination" permanent in
main.cf:
# ppoossttccoonnff ''rreellaayy__ddoommaaiinnss==$$mmyyddeessttiinnaattiioonn''
# ppoossttffiixx rreellooaadd
Note: quotes are required as indicated above.
Instead of $mydestination, it may be better to specify an explicit list of
domain names.
UUssiinngg bbaacckkwwaarrddss--ccoommppaattiibbllee ddeeffaauulltt sseettttiinngg ssmmttppdd__ttllss__ffiinnggeerrpprriinntt__ddiiggeesstt==mmdd55
The smtpd_tls_fingerprint_digest default value has changed from "md5" to
"sha256". With the new "sha256" setting, the Postfix SMTP server avoids using
the deprecated "md5" algorithm and computes a more secure digest of the client
certificate.
If you're using the default "md5" setting, or even an explicit "sha1" (also
deprecated) setting, you should consider switching to "sha256". This will
require updating any associated lookup table keys with the "sha256" digests of
the expected client certificate or public key.
As long as the smtpd_tls_fingerprint_digest parameter is left unspecified at
its implicit default value, and the compatibility_level setting is less than
3.6, Postfix logs a warning each time a client certificate or public key
fingerprint is (potentially) used for access control:
postfix/smtpd[27560]: using backwards-compatible default setting
smtpd_tls_fingerprint_digest=md5 to compute certificate fingerprints
Since any client certificate fingerprints are passed in policy service lookups,
and Postfix doesn't know whether the fingerprint will be used, the warning may
also be logged when policy lookups are performed for connections that used a
client certificate, even if the policy service does not in fact examine the
client certificate. To reduce the noise somewhat, such warnings are issued at
most once per smtpd(8) process instance.
If you prefer to stick with "md5", you can suppress the warnings by making that
setting explicit. After addressing any other compatibility warnings, you can
update your compatibility level.
# ppoossttccoonnff ssmmttppdd__ttllss__ffiinnggeerrpprriinntt__ddiiggeesstt==mmdd55
# ppoossttffiixx rreellooaadd
UUssiinngg bbaacckkwwaarrddss--ccoommppaattiibbllee ddeeffaauulltt sseettttiinngg ssmmttpp__ttllss__ffiinnggeerrpprriinntt__ddiiggeesstt==mmdd55
The smtp_tls_fingerprint_digest and lmtp_tls_fingerprint_digest default values
have changed from "md5" to "sha256". With the new "sha256" setting, the Postfix
SMTP and LMTP client avoids using the deprecated "md5" algorithm and computes a
more secure digest of the server certificate.
If you're using the default "md5" setting, or even an explicit "sha1" (also
deprecated) setting, you should consider switching to "sha256". This will
require updating any "fingerprint" security level policies in the TLS policy
table to specify matching "sha256" digests of the expected server certificates
or public keys.
As long as the smtp_tls_fingerprint_digest (or LMTP equivalent) parameter is
left unspecified at its implicit default value, and the compatibility_level
setting is less than 3.6, Postfix logs a warning each time the "fingerprint"
security level is used to specify matching "md5" digests of trusted server
certificates or public keys:
postfix/smtp[27560]: using backwards-compatible default setting
smtp_tls_fingerprint_digest=md5 to compute certificate fingerprints
If you prefer to stick with "md5", you can suppress the warnings by making that
setting explicit. After addressing any other compatibility warnings, you can
update your compatibility level.
# ppoossttccoonnff ''ssmmttpp__ttllss__ffiinnggeerrpprriinntt__ddiiggeesstt == mmdd55'' \\
''llmmttpp__ttllss__ffiinnggeerrpprriinntt__ddiiggeesstt == mmdd55''
# ppoossttffiixx rreellooaadd
UUssiinngg bbaacckkwwaarrddss--ccoommppaattiibbllee ddeeffaauulltt sseettttiinngg
ssmmttppdd__rreellaayy__bbeeffoorree__rreecciippiieenntt__rreessttrriiccttiioonnss==nnoo
The smtpd_relay_before_recipient_restrictions feature was introduced in Postfix
version 3.6, to evaluate smtpd_relay_restrictions before
smtpd_recipient_restrictions. Historically, smtpd_relay_restrictions was
evaluated after smtpd_recipient_restrictions, contradicting documented
behavior.
Background: smtpd_relay_restrictions is primarily designed to enforce a
mail relaying policy, while smtpd_recipient_restrictions is primarily
designed to enforce spam blocking policy. Both are evaluated while replying
to the RCPT TO command, and both support the same features.
To maintain compatibility with earlier versions, Postfix will keep evaluating
smtpd_recipient_restrictions before smtpd_relay_restrictions, as long as the
compatibility_level is less than 3.6, and the
smtpd_relay_before_recipient_restrictions parameter is left unspecified at its
implicit default setting. As a reminder, Postfix may log the following message:
postfix/smtpd[54696]: using backwards-compatible default setting
smtpd_relay_before_recipient_restrictions=no to reject recipient
"user@example.com" from client "host.example.net[10.0.0.2]"
If Postfix should keep evaluating smtpd_recipient_restrictions before
smtpd_relay_restrictions, then the system administrator should make the
backwards-compatible setting "smtpd_relay_before_recipient_restrictions=no"
permanent in main.cf:
# ppoossttccoonnff ssmmttppdd__rreellaayy__bbeeffoorree__rreecciippiieenntt__rreessttrriiccttiioonnss==nnoo
# ppoossttffiixx rreellooaadd
UUssiinngg bbaacckkwwaarrddss--ccoommppaattiibbllee ddeeffaauulltt sseettttiinngg rreessppeeccttffuull__llooggggiinngg==nnoo
Postfix version 3.6 deprecates configuration parameter names and logging that
suggest white is better than black. Instead it prefers 'allowlist, 'denylist',
and variations of those words. While the renamed configuration parameters have
backwards-compatible default values, the changes in logging could affect
logfile analysis tools.
To avoid breaking existing logfile analysis tools, Postfix will keep logging
the deprecated form, as long as the respectful_logging parameter is left
unspecified at its implicit default value, and the compatibility_level setting
is less than 3.6. As a reminder, Postfix may log the following when a remote
SMTP client is allowlisted or denylisted:
postfix/postscreen[22642]: Using backwards-compatible default setting
respectful_logging=no for client [address]:port
If Postfix should keep logging the deprecated form, then the system
administrator should make the backwards-compatible setting "respectful_logging
= no" permanent in main.cf.
# ppoossttccoonnff ""rreessppeeccttffuull__llooggggiinngg == nnoo""
# ppoossttffiixx rreellooaadd
UUssiinngg bbaacckkwwaarrddss--ccoommppaattiibbllee ddeeffaauulltt sseettttiinngg
ssmmttpp__ttllssrrpptt__sskkiipp__rreeuusseedd__hhaannddsshhaakkeess==yyeess
Postfix version 3.11 changes the default value for
smtp_tlsrpt_skip_reused_handshakes from "yes" to "no". The backwards-
compatibility safety net is designed to prevent an unexpected change in
reporting behavior when Postfix is updated from an older version.
As long as the smtp_tlsrpt_skip_reused_handshakes parameter is left unspecified
at its implicit default value, and the compatibility_level setting is less than
3.11, Postfix will log a reminder that it is using the backwards-compatible
default:
postfix/smtp[388157] using backwards-compatible default setting
smtp_tlsrpt_skip_reused_handshakes=yes
To keep the old default setting, the system administrator should make the
backwards-compatible setting "smtp_tlsrpt_skip_reused_handshakes = yes"
permanent in main.cf:
# ppoossttccoonnff ssmmttpp__ttllssrrpptt__sskkiipp__rreeuusseedd__hhaannddsshhaakkeess==yyeess
# ppoossttffiixx rreellooaadd
UUssiinngg bbaacckkwwaarrddss--ccoommppaattiibbllee ddeeffaauulltt sseettttiinngg xxxxxx__sseeccuurriittyy__lleevveell==((eemmppttyy))
Postfix version 3.11 changes the default value for client TLS security levels
from "empty" to "may". The backwards-compatibility safety net is designed to
prevent an unexpected change in mail sending behavior when Postfix is updated
from an older version.
There is no equivalent change for Postfix server TLS security levels, because
changing the level alone is not sufficient. Server-side TLS requires that at
least one private key and one public-key certificate chain are configured.
As long as a TLS security level parameter is left unspecified at its implicit
default value, and the compatibility_level setting is less than 3.11, Postfix
will log one of the following reminders that it is using the backwards-
compatible default:
postfix/smtp[...] using backwards-compatible default setting
smtp_tls_security_level=(empty)
postfix/tlsproxy[...] using backwards-compatible default setting
tlsproxy_client_security_level=(empty)
To keep the old default setting, the system administrator should make the
backwards-compatible empty setting permanent in main.cf:
# ppoossttccoonnff xxxxxx__sseeccuurriittyy__lleevveell==
# ppoossttffiixx rreellooaadd
where xxx is taken from the above compatibility message.
TTuurrnniinngg ooffff tthhee bbaacckkwwaarrddss--ccoommppaattiibbiilliittyy ssaaffeettyy nneett
Backwards compatibility is turned off by updating the compatibility_level
setting in main.cf.
# ppoossttccoonnff ccoommppaattiibbiilliittyy__lleevveell==NN
# ppoossttffiixx rreellooaadd
For N specify the number that is logged in your postfix(1) warning message:
warning: To disable backwards compatibility use "postconf
compatibility_level=N" and "postfix reload"
Sites that don't care about backwards compatibility may set
"compatibility_level = 9999" at their own risk.
Starting with Postfix version 3.6, the compatibility level in the above warning
message is the Postfix version that introduced the last incompatible change.
The level is formatted as major.minor.patch, where patch is usually omitted and
defaults to zero. Earlier compatibility levels are 0, 1 and 2.
NOTE: Postfix 3.6 also introduces support for the "<level", "<=level", and
other operators to compare compatibility levels. With the standard operators
"<", "<=", etc., compatibility level "3.10" would be smaller than "3.9" which
is undesirable.

View File

@ -614,7 +614,7 @@ make the backwards-compatible setting "<a href="postconf.5.html#smtp_tlsrpt_skip
default setting <i>xxx</i>_security_level=(empty)</a> </h2>
<p> Postfix version 3.11 changes the default value for client TLS
security levels from "empty" to "yes". The backwards-compatibility
security levels from "empty" to "may". The backwards-compatibility
safety net is designed to prevent an unexpected change in mail
sending behavior when Postfix is updated from an older version.
</p>

View File

@ -4236,15 +4236,20 @@ environment. Examples of relevant environment variables: </p>
<dd>Needed to make "<b>postfix -c</b>" work. </dd>
<dt><b>POSTLOG_HOSTNAME</b></dt>
<dd>Needed to make "<b><a href="postconf.5.html#maillog_file">maillog_file</a></b>" work during daemon
process initialization. </dd>
<dt><b>POSTLOG_SERVICE</b></dt>
<dd>Needed to make "<b><a href="postconf.5.html#maillog_file">maillog_file</a></b>" work during daemon
process initialization. </dd>
<dt><b>POSTLOG_HOSTNAME</b></dt>
<dt><b>XDG_RUNTIME_DIR</b></dt>
<dd>Needed to make "<b><a href="postconf.5.html#maillog_file">maillog_file</a></b>" work during daemon
process initialization. </dd>
<dd>Needed for debugging Postfix daemons with an XDG-style debugger.
</dd>
</dl>
@ -12497,6 +12502,12 @@ line. </p>
<pre>
/etc/postfix/reply_filter:
# Some Microsoft servers violate <a href="https://tools.ietf.org/html/rfc2554">RFC 2554</a> section 4, causing Postfix
# to complain with "non-empty initial GSSAPI challenge from server"
/^334\s+GSSAPI\s+supported/ 334
</pre>
<pre>
# Transform garbage into "250-filler..." so that it looks like
# one line from a multi-line reply. It does not matter what we
# substitute here as long it has the right syntax. The Postfix

View File

@ -2633,13 +2633,16 @@ Needed for debugging Postfix daemons with an X\-windows debugger.
.IP "\fBMAIL_CONFIG\fR"
Needed to make "\fBpostfix \-c\fR" work.
.br
.IP "\fBPOSTLOG_HOSTNAME\fR"
Needed to make "\fBmaillog_file\fR" work during daemon
process initialization.
.br
.IP "\fBPOSTLOG_SERVICE\fR"
Needed to make "\fBmaillog_file\fR" work during daemon
process initialization.
.br
.IP "\fBPOSTLOG_HOSTNAME\fR"
Needed to make "\fBmaillog_file\fR" work during daemon
process initialization.
.IP "\fBXDG_RUNTIME_DIR\fR"
Needed for debugging Postfix daemons with an XDG\-style debugger.
.br
.br
.PP
@ -7892,6 +7895,14 @@ Examples:
.nf
.na
/etc/postfix/reply_filter:
# Some Microsoft servers violate RFC 2554 section 4, causing Postfix
# to complain with "non\-empty initial GSSAPI challenge from server"
/^334\es+GSSAPI\es+supported/ 334
.fi
.ad
.PP
.nf
.na
# Transform garbage into "250\-filler..." so that it looks like
# one line from a multi\-line reply. It does not matter what we
# substitute here as long it has the right syntax. The Postfix

View File

@ -4,4 +4,4 @@
LANG=C; export LANG
mantools/dehtml proto/*html proto/*.proto | spell | grep -F -vxf proto/stop | grep -F -vxf proto/stop.spell-proto-html
mantools/dehtml proto/*html proto/*.proto | tr '+' ' ' | spell | grep -F -vxf proto/stop | grep -F -vxf proto/stop.spell-proto-html

View File

@ -614,7 +614,7 @@ make the backwards-compatible setting "smtp_tlsrpt_skip_reused_handshakes
default setting <i>xxx</i>_security_level=(empty)</a> </h2>
<p> Postfix version 3.11 changes the default value for client TLS
security levels from "empty" to "yes". The backwards-compatibility
security levels from "empty" to "may". The backwards-compatibility
safety net is designed to prevent an unexpected change in mail
sending behavior when Postfix is updated from an older version.
</p>

View File

@ -1984,15 +1984,20 @@ environment. Examples of relevant environment variables: </p>
<dd>Needed to make "<b>postfix -c</b>" work. </dd>
<dt><b>POSTLOG_HOSTNAME</b></dt>
<dd>Needed to make "<b>maillog_file</b>" work during daemon
process initialization. </dd>
<dt><b>POSTLOG_SERVICE</b></dt>
<dd>Needed to make "<b>maillog_file</b>" work during daemon
process initialization. </dd>
<dt><b>POSTLOG_HOSTNAME</b></dt>
<dt><b>XDG_RUNTIME_DIR</b></dt>
<dd>Needed to make "<b>maillog_file</b>" work during daemon
process initialization. </dd>
<dd>Needed for debugging Postfix daemons with an XDG-style debugger.
</dd>
</dl>
@ -15098,6 +15103,12 @@ line. </p>
<pre>
/etc/postfix/reply_filter:
# Some Microsoft servers violate RFC 2554 section 4, causing Postfix
# to complain with "non-empty initial GSSAPI challenge from server"
/^334\s+GSSAPI\s+supported/ 334
</pre>
<pre>
# Transform garbage into "250-filler..." so that it looks like
# one line from a multi-line reply. It does not matter what we
# substitute here as long it has the right syntax. The Postfix

View File

@ -1683,3 +1683,4 @@ typofix
LD
PRELOAD
rhansen
XDG

View File

@ -179,3 +179,5 @@ proto proto COMPATIBILITY_README html
postconf Makefile in postconf postconf c
dict_open Files util dict hc proxymap proxymap c
proxymap proxymap c
postmap postmap c postalias postalias c
client Files dict h dict_proxy c proxymap proxymap c

View File

@ -106,3 +106,7 @@ Kozmenko
Oleksandr
Bataille
balancers
Unbroke
XDG
ENOTSOCK
FustÃ

View File

@ -113,6 +113,7 @@ static int dict_proxy_sequence(DICT *dict, int function,
VSTREAM *stream;
int status;
int count = 0;
int inst_flags;
int request_flags;
/*
@ -126,8 +127,8 @@ static int dict_proxy_sequence(DICT *dict, int function,
VSTRING_TERMINATE(dict_proxy->reskey);
VSTRING_RESET(dict_proxy->result);
VSTRING_TERMINATE(dict_proxy->result);
request_flags = dict_proxy->inst_flags
| (dict->flags & DICT_FLAG_RQST_MASK);
inst_flags = dict_proxy->inst_flags;
request_flags = dict->flags;
for (;;) {
stream = clnt_stream_access(dict_proxy->clnt);
errno = 0;
@ -136,15 +137,17 @@ static int dict_proxy_sequence(DICT *dict, int function,
|| attr_print(stream, ATTR_FLAG_NONE,
SEND_ATTR_STR(MAIL_ATTR_REQ, PROXY_REQ_SEQUENCE),
SEND_ATTR_STR(MAIL_ATTR_TABLE, dict->name),
SEND_ATTR_INT(MAIL_ATTR_INST_FLAGS, inst_flags),
SEND_ATTR_INT(MAIL_ATTR_FLAGS, request_flags),
SEND_ATTR_INT(MAIL_ATTR_FUNC, function),
ATTR_TYPE_END) != 0
|| vstream_fflush(stream)
|| attr_scan(stream, ATTR_FLAG_STRICT,
RECV_ATTR_INT(MAIL_ATTR_STATUS, &status),
RECV_ATTR_INT(MAIL_ATTR_FLAGS, &dict->flags),
RECV_ATTR_STR(MAIL_ATTR_KEY, dict_proxy->reskey),
RECV_ATTR_STR(MAIL_ATTR_VALUE, dict_proxy->result),
ATTR_TYPE_END) != 3) {
ATTR_TYPE_END) != 4) {
if (msg_verbose || count > 1 || (errno && errno != EPIPE && errno != ENOENT))
msg_warn("%s: service %s: %m", myname, dict_proxy->service);
} else {
@ -194,6 +197,7 @@ static const char *dict_proxy_lookup(DICT *dict, const char *key)
VSTREAM *stream;
int status;
int count = 0;
int inst_flags;
int request_flags;
/*
@ -205,8 +209,8 @@ static const char *dict_proxy_lookup(DICT *dict, const char *key)
*/
VSTRING_RESET(dict_proxy->result);
VSTRING_TERMINATE(dict_proxy->result);
request_flags = dict_proxy->inst_flags
| (dict->flags & DICT_FLAG_RQST_MASK);
inst_flags = dict_proxy->inst_flags;
request_flags = dict->flags;
for (;;) {
stream = clnt_stream_access(dict_proxy->clnt);
errno = 0;
@ -215,14 +219,16 @@ static const char *dict_proxy_lookup(DICT *dict, const char *key)
|| attr_print(stream, ATTR_FLAG_NONE,
SEND_ATTR_STR(MAIL_ATTR_REQ, PROXY_REQ_LOOKUP),
SEND_ATTR_STR(MAIL_ATTR_TABLE, dict->name),
SEND_ATTR_INT(MAIL_ATTR_INST_FLAGS, inst_flags),
SEND_ATTR_INT(MAIL_ATTR_FLAGS, request_flags),
SEND_ATTR_STR(MAIL_ATTR_KEY, key),
ATTR_TYPE_END) != 0
|| vstream_fflush(stream)
|| attr_scan(stream, ATTR_FLAG_STRICT,
RECV_ATTR_INT(MAIL_ATTR_STATUS, &status),
RECV_ATTR_INT(MAIL_ATTR_FLAGS, &dict->flags),
RECV_ATTR_STR(MAIL_ATTR_VALUE, dict_proxy->result),
ATTR_TYPE_END) != 2) {
ATTR_TYPE_END) != 3) {
if (msg_verbose || count > 1 || (errno && errno != EPIPE && errno != ENOENT))
msg_warn("%s: service %s: %m", myname, dict_proxy->service);
} else {
@ -267,6 +273,7 @@ static int dict_proxy_update(DICT *dict, const char *key, const char *value)
VSTREAM *stream;
int status;
int count = 0;
int inst_flags;
int request_flags;
/*
@ -276,8 +283,8 @@ static int dict_proxy_update(DICT *dict, const char *key, const char *value)
* 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->inst_flags
| (dict->flags & DICT_FLAG_RQST_MASK);
inst_flags = dict_proxy->inst_flags;
request_flags = dict->flags;
for (;;) {
stream = clnt_stream_access(dict_proxy->clnt);
errno = 0;
@ -286,6 +293,7 @@ static int dict_proxy_update(DICT *dict, const char *key, const char *value)
|| attr_print(stream, ATTR_FLAG_NONE,
SEND_ATTR_STR(MAIL_ATTR_REQ, PROXY_REQ_UPDATE),
SEND_ATTR_STR(MAIL_ATTR_TABLE, dict->name),
SEND_ATTR_INT(MAIL_ATTR_INST_FLAGS, inst_flags),
SEND_ATTR_INT(MAIL_ATTR_FLAGS, request_flags),
SEND_ATTR_STR(MAIL_ATTR_KEY, key),
SEND_ATTR_STR(MAIL_ATTR_VALUE, value),
@ -293,7 +301,8 @@ static int dict_proxy_update(DICT *dict, const char *key, const char *value)
|| vstream_fflush(stream)
|| attr_scan(stream, ATTR_FLAG_STRICT,
RECV_ATTR_INT(MAIL_ATTR_STATUS, &status),
ATTR_TYPE_END) != 1) {
RECV_ATTR_INT(MAIL_ATTR_FLAGS, &dict->flags),
ATTR_TYPE_END) != 2) {
if (msg_verbose || count > 1 || (errno && errno != EPIPE && errno != ENOENT))
msg_warn("%s: service %s: %m", myname, dict_proxy->service);
} else {
@ -337,6 +346,7 @@ static int dict_proxy_delete(DICT *dict, const char *key)
VSTREAM *stream;
int status;
int count = 0;
int inst_flags;
int request_flags;
/*
@ -346,8 +356,8 @@ static int dict_proxy_delete(DICT *dict, const char *key)
* 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->inst_flags
| (dict->flags & DICT_FLAG_RQST_MASK);
inst_flags = dict_proxy->inst_flags;
request_flags = dict->flags;
for (;;) {
stream = clnt_stream_access(dict_proxy->clnt);
errno = 0;
@ -356,13 +366,15 @@ static int dict_proxy_delete(DICT *dict, const char *key)
|| attr_print(stream, ATTR_FLAG_NONE,
SEND_ATTR_STR(MAIL_ATTR_REQ, PROXY_REQ_DELETE),
SEND_ATTR_STR(MAIL_ATTR_TABLE, dict->name),
SEND_ATTR_INT(MAIL_ATTR_INST_FLAGS, inst_flags),
SEND_ATTR_INT(MAIL_ATTR_FLAGS, request_flags),
SEND_ATTR_STR(MAIL_ATTR_KEY, key),
ATTR_TYPE_END) != 0
|| vstream_fflush(stream)
|| attr_scan(stream, ATTR_FLAG_STRICT,
RECV_ATTR_INT(MAIL_ATTR_STATUS, &status),
ATTR_TYPE_END) != 1) {
RECV_ATTR_INT(MAIL_ATTR_FLAGS, &dict->flags),
ATTR_TYPE_END) != 2) {
if (msg_verbose || count > 1 || (errno && errno != EPIPE && errno !=
ENOENT))
msg_warn("%s: service %s: %m", myname, dict_proxy->service);
@ -478,16 +490,20 @@ DICT *dict_proxy_open(const char *map, int open_flags, int dict_flags)
dict_proxy->dict.delete = dict_proxy_delete;
dict_proxy->dict.sequence = dict_proxy_sequence;
dict_proxy->dict.close = dict_proxy_close;
dict_proxy->inst_flags = (dict_flags & DICT_FLAG_INST_MASK);
dict_proxy->inst_flags = dict_flags;
dict_proxy->reskey = vstring_alloc(10);
dict_proxy->result = vstring_alloc(10);
dict_proxy->clnt = *pstream;
dict_proxy->service = service;
#define DICT_PROXY_ERR_RETURN(d) do { \
DICT *_d = (d); \
dict_proxy_close(&dict_proxy->dict); \
return (_d); \
} while (0)
/*
* Establish initial contact and get the map type specific flags.
*
* XXX Should retrieve flags from local instance.
*/
for (;;) {
stream = clnt_stream_access(dict_proxy->clnt);
@ -496,7 +512,7 @@ DICT *dict_proxy_open(const char *map, int open_flags, int dict_flags)
|| attr_print(stream, ATTR_FLAG_NONE,
SEND_ATTR_STR(MAIL_ATTR_REQ, PROXY_REQ_OPEN),
SEND_ATTR_STR(MAIL_ATTR_TABLE, dict_proxy->dict.name),
SEND_ATTR_INT(MAIL_ATTR_FLAGS, dict_proxy->inst_flags),
SEND_ATTR_INT(MAIL_ATTR_INST_FLAGS, dict_proxy->inst_flags),
ATTR_TYPE_END) != 0
|| vstream_fflush(stream)
|| attr_scan(stream, ATTR_FLAG_STRICT,
@ -512,14 +528,17 @@ DICT *dict_proxy_open(const char *map, int open_flags, int dict_flags)
dict_flags_str(server_flags));
switch (status) {
case PROXY_STAT_BAD:
msg_fatal("%s open failed for table \"%s\": invalid request",
dict_proxy->service, dict_proxy->dict.name);
DICT_PROXY_ERR_RETURN(dict_surrogate(DICT_TYPE_PROXY,
dict_proxy->dict.name, open_flags, dict_flags,
"%s open failed for table \"%s\": invalid request",
dict_proxy->service, dict_proxy->dict.name));
case PROXY_STAT_DENY:
msg_fatal("%s service is not configured for table \"%s\"",
dict_proxy->service, dict_proxy->dict.name);
DICT_PROXY_ERR_RETURN(dict_surrogate(DICT_TYPE_PROXY,
dict_proxy->dict.name, open_flags, dict_flags,
"%s service is not configured for table \"%s\"",
dict_proxy->service, dict_proxy->dict.name));
case PROXY_STAT_OK:
dict_proxy->dict.flags = (dict_flags & ~DICT_FLAG_IMPL_MASK)
| (server_flags & DICT_FLAG_IMPL_MASK);
dict_proxy->dict.flags = server_flags;
return (&dict_proxy->dict);
default:
msg_warn("%s open failed for table \"%s\": unexpected status %d",

View File

@ -2663,7 +2663,8 @@ extern int var_fflush_refresh;
#define VAR_IMPORT_ENVIRON "import_environment"
#define DEF_IMPORT_ENVIRON "MAIL_CONFIG MAIL_DEBUG MAIL_LOGTAG " \
"TZ XAUTHORITY DISPLAY LANG=C " \
"POSTLOG_SERVICE POSTLOG_HOSTNAME"
"POSTLOG_SERVICE POSTLOG_HOSTNAME" \
"XDG_RUNTIME_DIR"
extern char *var_import_environ;
#define VAR_EXPORT_ENVIRON "export_environment"

View File

@ -210,6 +210,8 @@ extern char *mail_pathname(const char *, const char *);
#define MAIL_ATTR_COMPAT_LEVEL "compatibility_level"
#define MAIL_ATTR_MAIL_VERSION "mail_version"
#define MAIL_ATTR_INST_FLAGS "instance_flags"
/*
* Suffixes for sender_name, sender_domain etc.
*/

View File

@ -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 "20250709"
#define MAIL_RELEASE_DATE "20250713"
#define MAIL_VERSION_NUMBER "3.11"
#ifdef SNAPSHOT

View File

@ -273,6 +273,7 @@ static unsigned event_server_generation;
static void (*event_server_pre_disconn) (VSTREAM *, char *, char **);
static void (*event_server_slow_exit) (char *, char **);
static int event_server_watchdog = 1000;
static int event_server_drain_was_called = 0;
/* event_server_exit - normal termination */
@ -327,6 +328,9 @@ int event_server_drain(void)
const char *myname = "event_server_drain";
int fd;
if (event_server_drain_was_called)
return;
switch (fork()) {
/* Try again later. */
case -1:
@ -343,6 +347,7 @@ int event_server_drain(void)
msg_warn("%s: dup2(%d, %d): %m", myname, STDIN_FILENO, fd);
}
var_use_limit = 1;
event_server_drain_was_called = 1;
return (0);
/* Let the master start a new process. */
default:
@ -445,6 +450,9 @@ static void event_server_accept_local(int unused_event, void *context)
int time_left = -1;
int fd;
if (event_server_drain_was_called)
return;
/*
* Be prepared for accept() to fail because some other process already
* got the connection (the number of processes competing for clients is
@ -457,6 +465,8 @@ static void event_server_accept_local(int unused_event, void *context)
if (event_server_pre_accept)
event_server_pre_accept(event_server_name, event_server_argv);
if (event_server_drain_was_called)
return;
fd = LOCAL_ACCEPT(listen_fd);
if (event_server_lock != 0
&& myflock(vstream_fileno(event_server_lock), INTERNAL_LOCK,
@ -483,6 +493,9 @@ static void event_server_accept_pass(int unused_event, void *context)
int fd;
HTABLE *attr = 0;
if (event_server_drain_was_called)
return;
/*
* Be prepared for accept() to fail because some other process already
* got the connection (the number of processes competing for clients is
@ -495,6 +508,8 @@ static void event_server_accept_pass(int unused_event, void *context)
if (event_server_pre_accept)
event_server_pre_accept(event_server_name, event_server_argv);
if (event_server_drain_was_called)
return;
fd = pass_accept_attr(listen_fd, &attr);
if (event_server_lock != 0
&& myflock(vstream_fileno(event_server_lock), INTERNAL_LOCK,
@ -520,6 +535,9 @@ static void event_server_accept_inet(int unused_event, void *context)
int time_left = -1;
int fd;
if (event_server_drain_was_called)
return;
/*
* Be prepared for accept() to fail because some other process already
* got the connection (the number of processes competing for clients is
@ -532,6 +550,8 @@ static void event_server_accept_inet(int unused_event, void *context)
if (event_server_pre_accept)
event_server_pre_accept(event_server_name, event_server_argv);
if (event_server_drain_was_called)
return;
fd = inet_accept(listen_fd);
if (event_server_lock != 0
&& myflock(vstream_fileno(event_server_lock), INTERNAL_LOCK,

View File

@ -260,6 +260,7 @@ static VSTREAM *multi_server_lock;
static int multi_server_in_flow_delay;
static unsigned multi_server_generation;
static void (*multi_server_pre_disconn) (VSTREAM *, char *, char **);
static int multi_server_drain_was_called = 0;
/* multi_server_exit - normal termination */
@ -295,6 +296,9 @@ int multi_server_drain(void)
const char *myname = "multi_server_drain";
int fd;
if (multi_server_drain_was_called)
return;
switch (fork()) {
/* Try again later. */
case -1:
@ -311,6 +315,7 @@ int multi_server_drain(void)
msg_warn("%s: dup2(%d, %d): %m", myname, STDIN_FILENO, fd);
}
var_use_limit = 1;
multi_server_drain_was_called = 1;
return (0);
/* Let the master start a new process. */
default:
@ -429,6 +434,9 @@ static void multi_server_accept_local(int unused_event, void *context)
int time_left = -1;
int fd;
if (multi_server_drain_was_called)
return;
/*
* Be prepared for accept() to fail because some other process already
* got the connection (the number of processes competing for clients is
@ -441,6 +449,8 @@ static void multi_server_accept_local(int unused_event, void *context)
if (multi_server_pre_accept)
multi_server_pre_accept(multi_server_name, multi_server_argv);
if (multi_server_drain_was_called)
return;
fd = LOCAL_ACCEPT(listen_fd);
if (multi_server_lock != 0
&& myflock(vstream_fileno(multi_server_lock), INTERNAL_LOCK,
@ -467,6 +477,9 @@ static void multi_server_accept_pass(int unused_event, void *context)
int fd;
HTABLE *attr = 0;
if (multi_server_drain_was_called)
return;
/*
* Be prepared for accept() to fail because some other process already
* got the connection (the number of processes competing for clients is
@ -479,6 +492,8 @@ static void multi_server_accept_pass(int unused_event, void *context)
if (multi_server_pre_accept)
multi_server_pre_accept(multi_server_name, multi_server_argv);
if (multi_server_drain_was_called)
return;
fd = pass_accept_attr(listen_fd, &attr);
if (multi_server_lock != 0
&& myflock(vstream_fileno(multi_server_lock), INTERNAL_LOCK,
@ -504,6 +519,9 @@ static void multi_server_accept_inet(int unused_event, void *context)
int time_left = -1;
int fd;
if (multi_server_drain_was_called)
return;
/*
* Be prepared for accept() to fail because some other process already
* got the connection (the number of processes competing for clients is
@ -516,6 +534,8 @@ static void multi_server_accept_inet(int unused_event, void *context)
if (multi_server_pre_accept)
multi_server_pre_accept(multi_server_name, multi_server_argv);
if (multi_server_drain_was_called)
return;
fd = inet_accept(listen_fd);
if (multi_server_lock != 0
&& myflock(vstream_fileno(multi_server_lock), INTERNAL_LOCK,

View File

@ -690,8 +690,6 @@ static void postalias_seq(const char *map_type, const char *map_name,
const char *value;
int func;
if (strcmp(map_type, DICT_TYPE_PROXY) == 0)
msg_fatal("can't sequence maps via the proxy service");
dict = dict_open3(map_type, map_name, O_RDONLY, dict_flags);
for (func = DICT_SEQ_FUN_FIRST; /* void */ ; func = DICT_SEQ_FUN_NEXT) {
if (dict_seq(dict, func, &key, &value) != 0)

View File

@ -899,8 +899,6 @@ static void postmap_seq(const char *map_type, const char *map_name,
const char *value;
int func;
if (strcmp(map_type, DICT_TYPE_PROXY) == 0)
msg_fatal("can't sequence maps via the proxy service");
dict = dict_open3(map_type, map_name, O_RDONLY, dict_flags);
for (func = DICT_SEQ_FUN_FIRST; /* void */ ; func = DICT_SEQ_FUN_NEXT) {
if (dict_seq(dict, func, &key, &value) != 0)

View File

@ -320,7 +320,7 @@ static char *get_nested_dict_name(char *type_name)
/* proxy_map_find - look up or open table */
static DICT *proxy_map_find(const char *map_type_name, int request_flags,
static DICT *proxy_map_find(const char *map_type_name, int inst_flags,
int *statp)
{
DICT *dict;
@ -354,26 +354,12 @@ static DICT *proxy_map_find(const char *map_type_name, int request_flags,
/*
* Open one instance of a map for each combination of name+flags.
*
* Assume that a map instance can be shared among clients with different
* paranoia flag settings and with different map lookup flag settings.
*
* XXX The open() flags are passed implicitly, via the selection of the
* service name. For a more sophisticated interface, appropriate subsets
* of open() flags should be received directly from the client.
*/
vstring_sprintf(map_type_name_flags, "%s:%s", map_type_name,
dict_flags_str(request_flags & DICT_FLAG_INST_MASK));
if (msg_verbose)
msg_info("proxy_map_find: %s", STR(map_type_name_flags));
if ((dict = dict_handle(STR(map_type_name_flags))) == 0) {
dict = dict_open(map_type_name, proxy_writer ?
WRITE_OPEN_FLAGS : READ_OPEN_FLAGS,
request_flags);
inst_flags);
if (dict == 0)
msg_panic("proxy_map_find: dict_open null result");
dict_register(STR(map_type_name_flags), dict);
}
dict->error = 0;
return (dict);
}
@ -382,6 +368,7 @@ static DICT *proxy_map_find(const char *map_type_name, int request_flags,
static void proxymap_sequence_service(VSTREAM *client_stream)
{
int inst_flags;
int request_flags;
DICT *dict;
int request_func;
@ -395,19 +382,19 @@ static void proxymap_sequence_service(VSTREAM *client_stream)
*/
if (attr_scan(client_stream, ATTR_FLAG_STRICT,
RECV_ATTR_STR(MAIL_ATTR_TABLE, request_map),
RECV_ATTR_INT(MAIL_ATTR_INST_FLAGS, &inst_flags),
RECV_ATTR_INT(MAIL_ATTR_FLAGS, &request_flags),
RECV_ATTR_INT(MAIL_ATTR_FUNC, &request_func),
ATTR_TYPE_END) != 3
ATTR_TYPE_END) != 4
|| (request_func != DICT_SEQ_FUN_FIRST
&& request_func != DICT_SEQ_FUN_NEXT)) {
reply_status = PROXY_STAT_BAD;
reply_key = reply_value = "";
} else if ((dict = proxy_map_find(STR(request_map), request_flags,
} else if ((dict = proxy_map_find(STR(request_map), inst_flags,
&reply_status)) == 0) {
reply_key = reply_value = "";
} else {
dict->flags = ((dict->flags & ~DICT_FLAG_RQST_MASK)
| (request_flags & DICT_FLAG_RQST_MASK));
dict->flags = request_flags;
dict_status = dict_seq(dict, request_func, &reply_key, &reply_value);
if (dict_status == 0) {
reply_status = PROXY_STAT_OK;
@ -426,6 +413,7 @@ static void proxymap_sequence_service(VSTREAM *client_stream)
*/
attr_print(client_stream, ATTR_FLAG_NONE,
SEND_ATTR_INT(MAIL_ATTR_STATUS, reply_status),
SEND_ATTR_INT(MAIL_ATTR_FLAGS, dict->flags),
SEND_ATTR_STR(MAIL_ATTR_KEY, reply_key),
SEND_ATTR_STR(MAIL_ATTR_VALUE, reply_value),
ATTR_TYPE_END);
@ -435,6 +423,7 @@ static void proxymap_sequence_service(VSTREAM *client_stream)
static void proxymap_lookup_service(VSTREAM *client_stream)
{
int inst_flags;
int request_flags;
DICT *dict;
const char *reply_value;
@ -445,16 +434,16 @@ static void proxymap_lookup_service(VSTREAM *client_stream)
*/
if (attr_scan(client_stream, ATTR_FLAG_STRICT,
RECV_ATTR_STR(MAIL_ATTR_TABLE, request_map),
RECV_ATTR_INT(MAIL_ATTR_INST_FLAGS, &inst_flags),
RECV_ATTR_INT(MAIL_ATTR_FLAGS, &request_flags),
RECV_ATTR_STR(MAIL_ATTR_KEY, request_key),
ATTR_TYPE_END) != 3) {
ATTR_TYPE_END) != 4) {
reply_status = PROXY_STAT_BAD;
reply_value = "";
} else if ((dict = proxy_map_find(STR(request_map), request_flags,
} else if ((dict = proxy_map_find(STR(request_map), inst_flags,
&reply_status)) == 0) {
reply_value = "";
} else if (dict->flags = ((dict->flags & ~DICT_FLAG_RQST_MASK)
| (request_flags & DICT_FLAG_RQST_MASK)),
} else if (dict->flags = request_flags,
(reply_value = dict_get(dict, STR(request_key))) != 0) {
reply_status = PROXY_STAT_OK;
} else if (dict->error == 0) {
@ -471,6 +460,7 @@ static void proxymap_lookup_service(VSTREAM *client_stream)
*/
attr_print(client_stream, ATTR_FLAG_NONE,
SEND_ATTR_INT(MAIL_ATTR_STATUS, reply_status),
SEND_ATTR_INT(MAIL_ATTR_FLAGS, dict->flags),
SEND_ATTR_STR(MAIL_ATTR_VALUE, reply_value),
ATTR_TYPE_END);
}
@ -479,6 +469,7 @@ static void proxymap_lookup_service(VSTREAM *client_stream)
static void proxymap_update_service(VSTREAM *client_stream)
{
int inst_flags;
int request_flags;
DICT *dict;
int dict_status;
@ -495,21 +486,22 @@ static void proxymap_update_service(VSTREAM *client_stream)
*/
if (attr_scan(client_stream, ATTR_FLAG_STRICT,
RECV_ATTR_STR(MAIL_ATTR_TABLE, request_map),
RECV_ATTR_INT(MAIL_ATTR_INST_FLAGS, &inst_flags),
RECV_ATTR_INT(MAIL_ATTR_FLAGS, &request_flags),
RECV_ATTR_STR(MAIL_ATTR_KEY, request_key),
RECV_ATTR_STR(MAIL_ATTR_VALUE, request_value),
ATTR_TYPE_END) != 4) {
ATTR_TYPE_END) != 5) {
reply_status = PROXY_STAT_BAD;
} else if (proxy_writer == 0) {
msg_warn("refusing %s update 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,
} else if ((dict = proxy_map_find(STR(request_map), inst_flags,
&reply_status)) == 0) {
/* void */ ;
} else {
dict->flags = ((dict->flags & ~DICT_FLAG_RQST_MASK)
| (request_flags & DICT_FLAG_RQST_MASK)
/* Sync the table now. Don't abort on duplicate update. */
dict->flags = (request_flags
| DICT_FLAG_SYNC_UPDATE | DICT_FLAG_DUP_REPLACE);
dict_status = dict_put(dict, STR(request_key), STR(request_value));
if (dict_status == 0) {
@ -527,6 +519,7 @@ static void proxymap_update_service(VSTREAM *client_stream)
*/
attr_print(client_stream, ATTR_FLAG_NONE,
SEND_ATTR_INT(MAIL_ATTR_STATUS, reply_status),
SEND_ATTR_INT(MAIL_ATTR_FLAGS, dict->flags),
ATTR_TYPE_END);
}
@ -534,6 +527,7 @@ static void proxymap_update_service(VSTREAM *client_stream)
static void proxymap_delete_service(VSTREAM *client_stream)
{
int inst_flags;
int request_flags;
DICT *dict;
int dict_status;
@ -547,20 +541,21 @@ static void proxymap_delete_service(VSTREAM *client_stream)
*/
if (attr_scan(client_stream, ATTR_FLAG_STRICT,
RECV_ATTR_STR(MAIL_ATTR_TABLE, request_map),
RECV_ATTR_INT(MAIL_ATTR_INST_FLAGS, &inst_flags),
RECV_ATTR_INT(MAIL_ATTR_FLAGS, &request_flags),
RECV_ATTR_STR(MAIL_ATTR_KEY, request_key),
ATTR_TYPE_END) != 3) {
ATTR_TYPE_END) != 4) {
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,
} else if ((dict = proxy_map_find(STR(request_map), inst_flags,
&reply_status)) == 0) {
/* void */ ;
} else {
dict->flags = ((dict->flags & ~DICT_FLAG_RQST_MASK)
| (request_flags & DICT_FLAG_RQST_MASK)
/* Sync the table now. There is no close() request. */
dict->flags = (request_flags
| DICT_FLAG_SYNC_UPDATE);
dict_status = dict_del(dict, STR(request_key));
if (dict_status == 0) {
@ -578,6 +573,7 @@ static void proxymap_delete_service(VSTREAM *client_stream)
*/
attr_print(client_stream, ATTR_FLAG_NONE,
SEND_ATTR_INT(MAIL_ATTR_STATUS, reply_status),
SEND_ATTR_INT(MAIL_ATTR_FLAGS, dict->flags),
ATTR_TYPE_END);
}
@ -585,7 +581,7 @@ static void proxymap_delete_service(VSTREAM *client_stream)
static void proxymap_open_service(VSTREAM *client_stream)
{
int request_flags;
int inst_flags;
DICT *dict;
int reply_status;
int reply_flags;
@ -595,11 +591,11 @@ static void proxymap_open_service(VSTREAM *client_stream)
*/
if (attr_scan(client_stream, ATTR_FLAG_STRICT,
RECV_ATTR_STR(MAIL_ATTR_TABLE, request_map),
RECV_ATTR_INT(MAIL_ATTR_FLAGS, &request_flags),
RECV_ATTR_INT(MAIL_ATTR_INST_FLAGS, &inst_flags),
ATTR_TYPE_END) != 2) {
reply_status = PROXY_STAT_BAD;
reply_flags = 0;
} else if ((dict = proxy_map_find(STR(request_map), request_flags,
} else if ((dict = proxy_map_find(STR(request_map), inst_flags,
&reply_status)) == 0) {
reply_flags = 0;
} else {
@ -843,14 +839,6 @@ int main(int argc, char **argv)
*/
MAIL_VERSION_STAMP_ALLOCATE;
/*
* Workaround for programs that make explicit dict_register() calls with
* a table that is already registered under a different name. This is
* safe only in programs that do not unregister or close a table that is
* registered with multiple names.
*/
dict_allow_multiple_dict_register_names = 1;
/*
* XXX When invoked with the master.cf service name "proxywrite", the
* proxymap daemon will allow update requests. To update a table that is

View File

@ -82,8 +82,6 @@
/* const char *name,
/* int open_flags,
/* int dict_flags)
/*
/* int dict_allow_multiple_dict_register_names;
/* DESCRIPTION
/* This module maintains a collection of name-value dictionaries.
/* Each dictionary has its own name and has its own methods to read
@ -187,14 +185,6 @@
/* This encourages consistent sharing of dictionary instances that
/* have the exact same type:name and (initial) flags. The result
/* value is the string value of the \fIout\fR VSTRING buffer.
/*
/* dict_allow_multiple_dict_register_names enables a temporary
/* workaround for programs that make explicit dict_register()
/* calls with a table that is already registered under a different
/* name. Setting this to non-zero allows a dictionary to be
/* registered under multiple names. This workaround is safe only
/* in programs that do not unregister or close a table that is
/* registered with multiple names.
/* TRUST AND PROVENANCE
/* .ad
/* .fi
@ -339,14 +329,6 @@ typedef struct {
dict = node->dict; \
} while (0)
/*
* Workaround for programs that make explicit dict_register() calls with
* tables that are already registered under a different name. This is safe
* only in programs that do not unregister or close a table that is
* registered with multiple names.
*/
int dict_allow_multiple_dict_register_names = 0;
#define STR(x) vstring_str(x)
/* dict_register_close - trigger dictionary cleanup */
@ -367,8 +349,7 @@ void dict_register(const char *dict_name, DICT *dict_info)
/*
* Enforce referential integrity.
*/
if (dict_allow_multiple_dict_register_names == 0
&& dict_info->reg_name && strcmp(dict_name, dict_info->reg_name) != 0)
if (dict_info->reg_name && strcmp(dict_name, dict_info->reg_name) != 0)
msg_panic("%s: '%s:%s' is already registered under '%s' and cannot "
"also be registered under '%s'", myname, dict_info->type,
dict_info->name, dict_info->reg_name, dict_name);

View File

@ -141,32 +141,12 @@ extern void dict_free(DICT *);
* The subsets of flags that control how a map is used. These are relevant
* mainly for proxymap support. Note: some categories overlap.
*
* DICT_FLAG_IMPL_MASK - flags that are set by the map implementation itself.
*
* DICT_FLAG_PARANOID - requestor flags that forbid the use of insecure map
* types for security-sensitive operations. These flags are checked by the
* map implementation itself upon open, lookup etc. requests.
*
* DICT_FLAG_RQST_MASK - all requestor flags, including paranoid flags, that
* the requestor may change between open, lookup etc. requests. These
* specify requestor properties, not map properties.
*
* DICT_FLAG_INST_MASK - none of the above flags. The requestor may not change
* these flags between open, lookup, etc. requests (although a map may make
* changes to its copy of some of these flags). The proxymap server opens
* only one map instance for all client requests with the same values of
* these flags, and the proxymap client uses its own saved copy of these
* flags. DICT_FLAG_SRC_RHS_IS_FILE is an example of such a flag.
*/
#define DICT_FLAG_PARANOID \
(DICT_FLAG_NO_REGSUB | DICT_FLAG_NO_PROXY | DICT_FLAG_NO_UNAUTH)
#define DICT_FLAG_IMPL_MASK (DICT_FLAG_FIXED | DICT_FLAG_PATTERN | \
DICT_FLAG_MULTI_WRITER)
#define DICT_FLAG_RQST_MASK (DICT_FLAG_FOLD_ANY | DICT_FLAG_LOCK | \
DICT_FLAG_DUP_REPLACE | DICT_FLAG_DUP_WARN | \
DICT_FLAG_DUP_IGNORE | DICT_FLAG_SYNC_UPDATE | \
DICT_FLAG_PARANOID | DICT_FLAG_UTF8_MASK)
#define DICT_FLAG_INST_MASK ~(DICT_FLAG_IMPL_MASK | DICT_FLAG_RQST_MASK)
/*
* Feature tests.
@ -286,14 +266,6 @@ extern DICT *PRINTFLIKE(5, 6) dict_surrogate(const char *, const char *, int, in
extern char *dict_make_registered_name(VSTRING *, const char *, int, int);
extern char *dict_make_registered_name4(VSTRING *, const char *, const char *, int, int);
/*
* Workaround for programs that make explicit dict_register() calls with a
* table that is already registered under a different name. This is safe
* only in programs that do not unregister or close a table that is
* registered with multiple names.
*/
extern int dict_allow_multiple_dict_register_names;
/*
* This name is reserved for matchlist error handling.
*/

View File

@ -147,7 +147,7 @@ DICT *dict_alloc(const char *dict_type, const char *dict_name, ssize_t size)
dict->type = mystrdup(dict_type);
dict->name = mystrdup(dict_name);
dict->flags = DICT_FLAG_FIXED;
dict->flags = 0;
dict->lookup = dict_default_lookup;
dict->update = dict_default_update;
dict->delete = dict_default_delete;

View File

@ -146,14 +146,8 @@ void dict_test(int argc, char **argv)
vstream_printf("dict flags %s\n",
dict_flags_str(dict->flags));
} else if (strcmp(cmd, "masks") == 0 && !key && !value) {
vstream_printf("DICT_FLAG_IMPL_MASK %s\n",
dict_flags_str(DICT_FLAG_IMPL_MASK));
vstream_printf("DICT_FLAG_PARANOID %s\n",
dict_flags_str(DICT_FLAG_PARANOID));
vstream_printf("DICT_FLAG_RQST_MASK %s\n",
dict_flags_str(DICT_FLAG_RQST_MASK));
vstream_printf("DICT_FLAG_INST_MASK %s\n",
dict_flags_str(DICT_FLAG_INST_MASK));
} else {
vstream_printf("usage: %s\n", USAGE);
}