| Network-> |
For servers that are not public Internet MX hosts, Postfix
@@ -389,19 +390,14 @@ since the headers may be changed by intermediate servers.
By default, TLS is disabled in the Postfix SMTP server, so no
difference to plain Postfix is visible. Explicitly switch it on
-with "smtpd_tls_security_level = may" (Postfix 2.3 and
-later) or "smtpd_use_tls = yes" (obsolete but still
-supported).
+with "smtpd_tls_security_level = may".
Example:
/etc/postfix/main.cf:
- # Postfix 2.3 and later
smtpd_tls_security_level = may
- # Obsolete, but still supported
- smtpd_use_tls = yes
@@ -417,9 +413,8 @@ private key. This is intended behavior.
You can ENFORCE the use of TLS,
so that the Postfix SMTP server announces STARTTLS and accepts no
mail without TLS encryption, by setting
-"smtpd_tls_security_level = encrypt" (Postfix 2.3 and
-later) or "smtpd_enforce_tls = yes" (obsolete but still
-supported). According to RFC 2487 this MUST NOT be applied in case
+"smtpd_tls_security_level = encrypt". According to RFC 2487 this
+MUST NOT be applied in case
of a publicly-referenced Postfix SMTP server. This option is off
by default and should only seldom be used.
@@ -428,10 +423,7 @@ by default and should only seldom be used.
/etc/postfix/main.cf:
- # Postfix 2.3 and later
smtpd_tls_security_level = encrypt
- # Obsolete, but still supported
- smtpd_enforce_tls = yes
@@ -473,7 +465,7 @@ when client certificates are requested, and abort the SMTP session. So
this option is "off" by default. You will however need the certificate
if you want to use certificate based relaying with, for example, the
permit_tls_clientcerts feature. A server that wants client certificates
-must first present its own certificate. While Postfix 2.3 by default
+must first present its own certificate. While Postfix by default
offers anonymous ciphers to remote SMTP clients, these are automatically
suppressed
when the Postfix SMTP server is configured to ask for client
@@ -485,10 +477,7 @@ certificates.
/etc/postfix/main.cf:
smtpd_tls_ask_ccert = yes
- # Postfix 2.3 and later
smtpd_tls_security_level = may
- # Obsolete, but still supported
- smtpd_use_tls = yes
@@ -505,10 +494,7 @@ logged.
/etc/postfix/main.cf:
smtpd_tls_req_ccert = yes
- # Postfix 2.3 and later
smtpd_tls_security_level = encrypt
- # Obsolete, but still supported
- smtpd_enforce_tls = yes
@@ -539,12 +525,10 @@ configured to supply its intermediate CA certificate).
Sending AUTH data over an unencrypted channel poses a security
risk. When TLS layer encryption is required
-("smtpd_tls_security_level = encrypt" or the obsolete
-"smtpd_enforce_tls = yes"), the Postfix SMTP server will
+("smtpd_tls_security_level = encrypt"), the Postfix SMTP server will
announce and accept AUTH only after the TLS layer has been activated
with STARTTLS. When TLS layer encryption is optional
-("smtpd_tls_security_level = may" or the obsolete
-"smtpd_enforce_tls = no"), it may however still be useful
+("smtpd_tls_security_level = may"), it may however still be useful
to only offer AUTH when TLS is active. To maintain compatibility
with non-TLS clients, the default is to accept AUTH without encryption.
In order to change this behavior, set
@@ -695,12 +679,6 @@ the name of the user or host:
- The description below is for Postfix 2.3; for Postfix < 2.3 the
-smtpd_tls_cipherlist parameter specifies the acceptable ciphers as an
-explicit OpenSSL cipherlist. The obsolete setting applies even when TLS
-encryption is not enforced. Use of this control on public MX hosts is
-strongly discouraged.
-
The Postfix SMTP server supports 5 distinct cipher security levels
as specified by the smtpd_tls_mandatory_ciphers configuration parameter,
which determines the cipher grade with mandatory TLS encryption. The
@@ -732,7 +710,7 @@ smtpd_tls_mandatory_protocols configuration parameter. The
corresponding smtpd_tls_protocols parameter (Postfix ≥ 2.6)
controls the SSL/TLS protocols used with opportunistic TLS.
- For a server that is not a public Internet MX host, Postfix (≥ 2.3)
+ For a server that is not a public Internet MX host, Postfix
supports configurations with no server
certificates that use only the anonymous ciphers. This is
enabled by explicitly setting "smtpd_tls_cert_file = none"
@@ -870,10 +848,6 @@ key configuration
Per-destination TLS policy
- Obsolete per-site TLS policy support
-
- Closing a DNS loophole with obsolete per-site TLS policies
-
Discovering servers that support TLS
Server certificate verification depth
@@ -934,32 +908,26 @@ The "null" ciphers provide authentication without encryption.
At the "none" TLS security level, TLS encryption is
-disabled. This is the default security level. With Postfix 2.3 and later,
-it can be configured explicitly by setting "smtp_tls_security_level = none".
+disabled. This is the default security level, and
+can be configured explicitly by setting "smtp_tls_security_level = none".
+For LMTP, use the corresponding "lmtp_" parameter.
- With Postfix 2.2 and earlier, or when smtp_tls_security_level is set to
-its default (backwards compatible) empty value, the appropriate configuration
-settings are "smtp_use_tls = no" and "smtp_enforce_tls = no".
-With either approach, TLS is not used even if supported by the server.
-For LMTP, use the corresponding "lmtp_" parameters.
-
- Per destination settings may override this default setting, in which case
+ Per-destination settings may override this default setting, in which case
TLS is used selectively, only with destinations explicitly configured
for TLS.
You can disable TLS for a subset of destinations, while leaving
-it enabled for the rest. With the Postfix 2.3 and later TLS policy table, specify the "none"
-security level. With the obsolete per-site
-table, specify the "NONE" keyword.
+security level.
At the "may" TLS security level, TLS encryption is opportunistic.
The SMTP transaction is encrypted if the STARTTLS ESMTP feature
is supported by the server. Otherwise, messages are sent in the clear.
-With Postfix 2.3 and later, opportunistic TLS can be configured by
-setting "smtp_tls_security_level = may".
+Opportunistic TLS can be configured by setting "smtp_tls_security_level = may".
+For LMTP, use the corresponding "lmtp_" parameter.
Since sending in the clear is acceptable, demanding stronger
than default TLS security mostly reduces inter-operability. If you
@@ -970,17 +938,12 @@ and cipher grade
used with opportunistic TLS. With earlier releases the opportunistic TLS
cipher grade is always "export" and no protocols are disabled.
- With Postfix 2.2 and earlier, or when smtp_tls_security_level is
-set to its default (backwards compatible) empty value, the appropriate
-configuration settings are "smtp_use_tls = yes" and
-"smtp_enforce_tls = no".
-For LMTP use the corresponding "lmtp_" parameters.
-
With opportunistic TLS, mail delivery continues even if the
-server certificate is untrusted or bears the wrong name. Starting
-with Postfix 2.3, when the TLS handshake fails for an opportunistic
-TLS session, rather than give up on mail delivery, the transaction
-is retried with TLS disabled. Trying an unencrypted connection makes
+server certificate is untrusted or bears the wrong name.
+When the TLS handshake fails for an opportunistic
+TLS session, rather than give up on mail delivery, the Postfix SMTP
+client retries the transaction
+with TLS disabled. Trying an unencrypted connection makes
it possible to deliver mail to sites with non-interoperable server
TLS implementations.
@@ -994,9 +957,8 @@ Attempts to configure opportunistic encryption of LMTP sessions will
be ignored with a warning written to the mail logs.
You can enable opportunistic TLS just for selected destinations. With
-the Postfix 2.3 and later TLS policy table,
-specify the "may" security level. With the obsolete per-site table, specify the "MAY" keyword.
+the Postfix TLS policy table,
+specify the "may" security level.
This is the most common security level for TLS protected SMTP
sessions, stronger security is not generally available and, if needed,
@@ -1012,27 +974,18 @@ on TLS limitations above.
- Postfix 2.2 syntax:
-
-
-
-/etc/postfix/main.cf:
- smtp_use_tls = yes
- smtp_enforce_tls = no
-
-
-
At the "encrypt" TLS security level, messages are sent only
over TLS encrypted sessions. The SMTP transaction is aborted unless
the STARTTLS ESMTP feature is supported by the remote SMTP server.
If no suitable
-servers are found, the message will be deferred. With Postfix 2.3
-and later, mandatory TLS encryption can be configured by setting
+servers are found, the message will be deferred.
+Mandatory TLS encryption can be configured by setting
"smtp_tls_security_level = encrypt". Even though TLS
encryption is always used, mail delivery continues even if the server
-certificate is untrusted or bears the wrong name.
+certificate is untrusted or bears the wrong name.
+For LMTP, use the corresponding "lmtp_" parameter.
At this security level and higher, the smtp_tls_mandatory_protocols
and smtp_tls_mandatory_ciphers configuration parameters determine
@@ -1042,12 +995,6 @@ met, the mail transaction is aborted. The documentation for these
parameters includes useful interoperability and security guidelines.
- With Postfix 2.2 and earlier, or when smtp_tls_security_level
-is set to its default (backwards compatible) empty value, the
-appropriate configuration settings are "smtp_enforce_tls = yes"
-and "smtp_tls_enforce_peername = no". For LMTP use the corresponding
-"lmtp_" parameters.
-
Despite the potential for eliminating passive eavesdropping attacks,
mandatory TLS encryption is not viable as a default security level for
mail delivery to the public Internet. Most MX hosts do not support TLS at
@@ -1056,12 +1003,9 @@ that delivers mail to the Internet, you should not configure mandatory
TLS encryption as the default security level.
You can enable mandatory TLS encryption just for specific destinations.
-With the Postfix 2.3 and later TLS policy
-table, specify the "encrypt" security level. With the
-obsolete per-site table, specify the
-"MUST_NOPEERMATCH" keyword. While the obsolete approach still works
-with Postfix 2.3, it is strongly discouraged: users of Postfix 2.3 and later
-should use the new TLS policy settings.
+With the Postfix TLS policy
+table, specify the "encrypt" security level.
+
Examples:
@@ -1083,20 +1027,6 @@ level sessions.
- Postfix 2.2 syntax (no support for sub-domains without resorting to
-regexp tables). With Postfix 2.3 and later, do not use the obsolete per-site table.
-
-
-
-/etc/postfix/main.cf:
- smtp_tls_per_site = hash:/etc/postfix/tls_per_site
-
-/etc/postfix/tls_per_site:
- example.com MUST_NOPEERMATCH
-
-
-
In the next example, secure message submission is configured
via the MSA "[example.net]:587". TLS sessions are encrypted
without authentication, because this MSA does not possess an acceptable
@@ -1128,28 +1058,6 @@ just in case the transport table entries are not specified consistently.
- Postfix 2.2 syntax:
-
- Note: Avoid policy lookups with the bare hostname (for
-example, "example.net"). Instead,
-use the destination (for example, "[example.net]:587"), as the per-site table lookup key (a recipient domain
-or MX-enabled transport nexthop with no port suffix may look like a bare
-hostname, but is still a suitable destination). With Postfix 2.3
-and later,
-do not use the obsolete per-site table;
-use the new policy table instead.
-
-
-
-/etc/postfix/main.cf:
- smtp_tls_per_site = hash:/etc/postfix/tls_per_site
-
-/etc/postfix/tls_per_site:
- [example.net]:587 MUST_NOPEERMATCH
-
-
-
Certificate fingerprint verification is available with Postfix
@@ -1234,13 +1142,8 @@ server certificate verification can be configured by setting
smtp_tls_verify_cert_match parameter can override the default
"hostname" certificate name matching strategy. Fine-tuning the
matching strategy is generally only appropriate for secure-channel destinations.
-
- With Postfix 2.2 and earlier, or when smtp_tls_security_level
-is set to its default (backwards compatible) empty value, the
-appropriate configuration settings are "smtp_enforce_tls = yes" and
-"smtp_tls_enforce_peername = yes". For LMTP use the corresponding
-"lmtp_" parameters.
+href="#client_tls_secure">secure-channel destinations.
+For LMTP use the corresponding "lmtp_" parameters.
If the server certificate chain is trusted (see smtp_tls_CAfile
and smtp_tls_CApath), any DNS names in the SubjectAlternativeName
@@ -1269,12 +1172,9 @@ href="#client_tls_secure">secure-channel configuration instead.
You can enable mandatory server certificate verification just
-for specific destinations. With the Postfix 2.3 and later TLS policy table, specify the "verify"
-security level. With the obsolete per-site
-table, specify the "MUST" keyword. While the obsolete approach
-still works with Postfix 2.3, it is strongly discouraged: users of
-Postfix 2.3 and later should use the new TLS policy settings.
+security level.
Example:
@@ -1295,36 +1195,16 @@ to example.com recipients uses "high" grade ciphers.
- Postfix 2.2 syntax:
-
-
-/etc/postfix/main.cf:
- indexed = ${default_database_type}:${config_directory}/
- smtp_tls_CAfile = ${config_directory}/CAfile.pem
- smtp_tls_per_site = ${indexed}tls_per_site
-
-/etc/postfix/tls_per_site:
- example.com MUST
-
-
-
At the secure TLS security level, messages are sent only over
secure-channel TLS sessions where DNS forgery resistant server
certificate verification succeeds. If no suitable servers are found, the
-message will be deferred. With Postfix 2.3 and later, secure-channels
+message will be deferred. Postfix secure-channels
can be configured by setting "smtp_tls_security_level = secure".
The smtp_tls_secure_cert_match parameter can override the default
-"nexthop, dot-nexthop" certificate match strategy.
-
- With Postfix 2.2 and earlier, or when smtp_tls_security_level
-is set to its default (backwards compatible) empty value, the
-appropriate configuration settings are "smtp_enforce_tls = yes"
-and "smtp_tls_enforce_peername = yes" with additional settings to
-harden peer certificate verification
-against forged DNS data. For LMTP, use the corresponding "lmtp_"
-parameters.
+"nexthop, dot-nexthop" certificate match strategy.
+For LMTP, use the corresponding "lmtp_" parameters.
If the server certificate chain is trusted (see smtp_tls_CAfile and
smtp_tls_CApath), any DNS names in the SubjectAlternativeName certificate
@@ -1351,18 +1231,14 @@ sends all email to a central mailhub that offers the necessary
STARTTLS support.
You can enable secure TLS verification just for specific destinations.
-With the Postfix 2.3 and later TLS policy table,
-specify the "secure" security level. With the obsolete
-per-site table, specify the "MUST"
-keyword and harden the certificate
-verification against DNS forgery. While the obsolete approach still
-works with Postfix 2.3, it is strongly discouraged: users of Postfix 2.3
-and later
-should use the new TLS policy settings.
+With the Postfix TLS policy table,
+specify the "secure" security level.
Examples:
- Secure-channel TLS without transport(5) table overrides:
+
+
+-
Secure-channel TLS without transport(5) table overrides:
The Postfix SMTP client will encrypt all traffic and verify the
destination name
@@ -1408,18 +1284,14 @@ the first approach is more appropriate in most cases.
- Secure-channel TLS with transport(5) table overrides:
+ -
Secure-channel TLS with transport(5) table overrides:
In this case traffic to example.com and its related domains
is sent to a single logical gateway (to avoid a single point of failure,
its name may resolve to one or more load-balancer addresses, or to the
combined addresses of multiple physical hosts). All the physical hosts
reachable via the gateway's IP addresses have the logical gateway name
-listed in their certificates. This secure-channel configuration can also
-be implemented via a hardened variant of
-the MUST policy in the obsolete per-site
-table. As stated above, this approach has the potential to mis-deliver
-email if the related domains change hands.
+listed in their certificates.
@@ -1438,35 +1310,7 @@ email if the related domains change hands.
- Postfix 2.2.9 and later syntax:
-
- Note: Avoid policy lookups with the bare hostname (for
-example, "tls.example.com"). Instead, use the destination (for
-example, "[tls.example.com]") as the per-site table lookup key (a recipient domain
-or MX-enabled transport nexthop with no port suffix may look like a bare
-hostname, but is still a suitable destination). With Postfix 2.3
-and later,
-do not use the obsolete per-site table;
-use the new policy table instead.
-
-
-
-/etc/postfix/main.cf:
- smtp_cname_overrides_servername = no
- smtp_tls_CAfile = /etc/postfix/CAfile.pem
- transport_maps = hash:/etc/postfix/transport
- smtp_tls_per_site = hash:/etc/postfix/tls_per_site
-
-/etc/postfix/transport:
- example.com smtp:[tls.example.com]
- example.co.uk smtp:[tls.example.com]
- example.co.jp smtp:[tls.example.com]
-
-/etc/postfix/tls_per_site:
- [tls.example.com] MUST
-
-
+
@@ -1778,9 +1622,9 @@ constraints on the sending and receiving sites that preclude ubiquitous
deployment. One needs to manually configure this type of security for
each destination domain, and in many cases implement non-default TLS
policy table entries for additional
-domains hosted at a common secured destination. With Postfix 2.3, we
-make secure-channel configurations substantially easier to configure,
-but they will never be the norm. For the generic domain with which you
+domains hosted at a common secured destination. For these reasons
+secure-channel configurations
+will never be the norm. For the generic domain with which you
have made no specific security arrangements, this security level is not
a good fit.
@@ -1790,7 +1634,7 @@ TLS use self-signed certificates or private CAs. This further limits
the applicability of verified TLS on the public Internet.
Historical note: while the documentation of these issues and many of the
-related features are new with Postfix 2.3, the issue was well
+related features were new with Postfix 2.3, the issue was well
understood before Postfix 1.0, when Lutz Jänicke was designing
the first unofficial Postfix TLS patch. See his original post http://www.imc.org/ietf-apps-tls/mail-archive/msg00304.html
@@ -1803,23 +1647,15 @@ uses indirect naming (via MX records) more frequently.
- The current TLS policy table was introduced with Postfix 2.3. For
-earlier releases, read the description of the obsolete Postfix 2.2 per-site table.
-
A small fraction of servers offer STARTTLS but the negotiation
-consistently fails. With Postfix 2.3, so long as encryption is not
-enforced, the delivery is immediately retried with TLS disabled. You no
-longer need to explicitly disable TLS for the problem destinations.
-As soon as their TLS software or configuration is repaired, encryption
-will be used.
+consistently fails. As long as encryption is not mandatory, the
+Postfix SMTP client retries the delivery immediately with TLS
+disabled, without any need to explicitly disable TLS for the problem
+destinations.
- The new policy table is specified via the smtp_tls_policy_maps
+ The policy table is specified via the smtp_tls_policy_maps
parameter. This lists optional lookup tables with the Postfix SMTP client
-TLS security policy by next-hop destination. When $smtp_tls_policy_maps
-is not empty, the obsolete smtp_tls_per_site parameter is ignored
-(a warning is written to the logs if both parameter values are
-non-empty).
+TLS security policy by next-hop destination.
The TLS policy table is indexed by the full next-hop destination,
which is either the recipient domain, or the verbatim next-hop
@@ -1968,211 +1804,6 @@ table can render the "secure" level vulnerable to DNS forgery. Do not use
the "hostname" strategy for secure-channel
configurations in environments where DNS security is not assured.
-
-
- This section describes an obsolete per-site TLS policy mechanism.
-Unlike the Postfix 2.3 policy table
-mechanism, this uses as a policy lookup key a potentially untrusted
-server hostname, and lacks control over what names can appear in
-server certificates. Because of this, the obsolete mechanism is
-typically vulnerable to false DNS hostname information in MX or
-CNAME records. These attacks can be eliminated only with great
-difficulty. The new policy table
-makes secure-channel configurations
-easier and provides more control over the cipher and protocol selection
-for sessions with mandatory encryption.
-
- Avoid policy lookups with the bare hostname. Instead, use the
-full destination nexthop (enclosed in [] with a possible ":port"
-suffix) as the per-site table lookup key (a recipient domain or
-MX-enabled transport nexthop with no port suffix may look like a bare
-hostname, but is still a suitable destination). With Postfix 2.3
-and later,
-use of the obsolete approach documented here is strongly discouraged:
-use the new policy table instead.
-
- Starting with Postfix 2.3, the underlying TLS enforcement levels are
-common to the obsolete per-site table and the new policy table. The
-main.cf smtp_tls_mandatory_ciphers and smtp_tls_mandatory_protocols
-parameters control the TLS ciphers and protocols for mandatory
-encryption regardless of which table is used. The
-smtp_tls_verify_cert_match parameter determines the match strategy
-for the obsolete "MUST" keyword in the same way as for the "verify"
-level in the new policy.
-
- With Postfix < 2.3, the obsolete smtp_tls_cipherlist parameter
-is also applied for opportunistic TLS sessions, and should be used with
-care, or not at all. Setting cipherlist restrictions that are incompatible
-with a remote SMTP server render that server unreachable, TLS handshakes
-are always attempted and always fail.
-
- When smtp_tls_policy_maps is empty (default) and smtp_tls_per_site
-is not empty, the per-site table is searched for a policy that matches
-the following information:
-
-
-
-
-
-- remote SMTP server hostname
- This is simply the DNS
-name of the server that the Postfix SMTP client connects to; this
-name may be obtained from other DNS lookups, such as MX lookups or
-CNAME lookups. Use of the hostname lookup key is discouraged; always
-use the next-hop destination instead.
-
-- next-hop destination
- This is normally the domain portion
-of the recipient address, but it may be overridden by information from
-the transport(5) table, from the relayhost parameter setting, or from
-the relay_transport setting. When it is not the recipient domain, the
-next-hop destination can have the Postfix-specific form "[name]",
-"[name]:port", "name" or "name:port". This is
-the recommended lookup key for per-site policy lookups (and incidentally
-for SASL password lookups).
-
-
-
-
-
- When both the hostname lookup and the next-hop lookup succeed,
-the host policy does not automatically override the next-hop policy.
-Instead, precedence is given to either the more specific or the
-more secure per-site policy as described below.
-
- The smtp_tls_per_site table uses a simple "name whitespace
-value" format. Specify host names or next-hop destinations on
-the left-hand side; no wildcards are allowed. On the right hand
-side specify one of the following keywords:
-
-
-
-
-
-- NONE
- No TLS. This overrides a less specific "MAY" lookup
-result from the alternate host or next-hop lookup key, and overrides
-the global smtp_use_tls, smtp_enforce_tls, and smtp_tls_enforce_peername
-settings.
-
-- MAY
- Opportunistic TLS. This has less precedence than
-a more specific result (including "NONE") from the alternate host or
-next-hop lookup key, and has less precedence than the more specific global
-"smtp_enforce_tls = yes" or "smtp_tls_enforce_peername = yes".
-
-- MUST_NOPEERMATCH
- Mandatory TLS encryption. This
-overrides a less secure "NONE" or a less specific "MAY" lookup result
-from the alternate host or next-hop lookup key, and overrides the global
-smtp_use_tls, smtp_enforce_tls and smtp_tls_enforce_peername settings.
-
-
-- MUST
- Mandatory server certificate verification.
-This overrides a less secure "NONE" and "MUST_NOPEERMATCH" or a
-less specific "MAY" lookup result from the alternate host or next-hop
-lookup key, and overrides the global smtp_use_tls, smtp_enforce_tls
-and smtp_tls_enforce_peername settings.
-
-
-
-
-
- The precedences between global (main.cf) and per-site TLS
-policies can be summarized as follows:
-
-
-
--
When neither the remote SMTP server hostname nor the
-next-hop destination are found in the smtp_tls_per_site table, the
-policy is based on smtp_use_tls, smtp_enforce_tls and
-smtp_tls_enforce_peername. Note: "smtp_enforce_tls = yes" and
-"smtp_tls_enforce_peername = yes" imply "smtp_use_tls = yes".
-
- -
When both hostname and next-hop destination lookups produce
-a result, the more specific per-site policy (NONE, MUST, etc)
-overrides the less specific one (MAY), and the more secure per-site
-policy (MUST, etc) overrides the less secure one (NONE).
-
- -
After the per-site policy lookups are combined, the result
-generally overrides the global policy. The exception is the less
-specific "MAY" per-site policy, which is overruled by the more
-specific global "smtp_enforce_tls = yes" with server certificate
-verification as specified with the smtp_tls_enforce_peername
-parameter.
-
-
-
-
-
- For a general discussion of TLS security for SMTP see TLS limitations above. What follows applies
-only to Postfix 2.2.9 and subsequent Postfix 2.2 patch levels. Do
-not use this approach with Postfix 2.3
-and later; instead see the instructions under secure server certificate verification.
-
- As long as no secure DNS lookup mechanism is available, false
-hostnames in MX or CNAME responses can change Postfix's notion of the
-server hostname that is used for TLS policy lookup and server certificate
-verification. Even with a perfect match between the server hostname and
-the server certificate, there is no guarantee that Postfix is connected
-to the right server. To avoid this loophole, take all of the following
-steps:
-
-
-
--
Use a dedicated message delivery transport (for example,
-"securetls") as illustrated below.
-
- -
Eliminate MX lookups. Specify local transport(5) table
-entries for sensitive domains with explicit securetls:[mailhost]
-or securetls:[mailhost]:port destinations (you can
-assure security of this table unlike DNS). This prevents false
-hostname information in DNS MX records from changing Postfix's
-notion of the server hostname that is used for TLS policy lookup
-and server certificate verification. The "securetls" transport is
-configured to enforce TLS with peername verification, and to disable
-the SMTP connection cache which could interfere with enforcement
-of smtp_tls_per_site policies.
-
- -
Disallow CNAME hostname overrides. In main.cf, specify
-"smtp_cname_overrides_servername = no". This prevents false hostname
-information in DNS CNAME records from changing the server hostname
-that Postfix uses for TLS policy lookup and server certificate
-verification. This feature requires Postfix 2.2.9 or later. The
-default value is "no" starting with Postfix 2.3.
-
-
-
- Example:
-
- We give the non-default
-"securetls" transport an explicit master.cf process limit, so that we
-don't raise its process limit when raising $default_process_limit. The
-total process limit for *all* transports should stay somewhat under 1024
-(the typical select() file descriptor limit); otherwise transports may
-be throttled under steady high load, compounding congestion. It is not
-uncommon at high volume sites to set the default process limit to 500
-or more.
-
- We also default the "securetls" transport TLS security level to
-MUST, obviating the need for per-site table entries for secure-channel
-destinations.
-
-
-
-/etc/postfix/main.cf:
- transport_maps = hash:/etc/postfix/transport
-
-/etc/postfix/transport:
- example.com securetls:[tls.example.com]
-
-/etc/postfix/master.cf:
- securetls unix - - n - 100 smtp
- -o smtp_enforce_tls=yes
- -o smtp_tls_enforce_peername=yes
-
-
-
@@ -2601,10 +2232,7 @@ but don't require them from all clients.
smtpd_tls_session_cache_database =
btree:/var/lib/postfix/smtpd_tls_session_cache
tls_random_source = dev:/dev/urandom
- # Postfix 2.3 and later
smtpd_tls_security_level = may
- # Obsolete, but still supported
- smtpd_use_tls = yes
diff --git a/postfix/proto/TUNING_README.html b/postfix/proto/TUNING_README.html
index 5c7b5b39b..09a362a96 100644
--- a/postfix/proto/TUNING_README.html
+++ b/postfix/proto/TUNING_README.html
@@ -551,13 +551,13 @@ mail deliveries.
The default_process_limit configuration parameter gives direct
control over how many daemon processes Postfix will run. As of
-Postfix 2.0 the default limit is 100 smtp client processes, 100
-smtp server processes, and so on. This may overwhelm systems with
+Postfix 2.0 the default limit is 100 SMTP client processes, 100
+SMTP server processes, and so on. This may overwhelm systems with
little memory, as well as networks with low bandwidth.
You can change the global process limit by specifying a
non-default default_process_limit in the main.cf file. For example,
-to run up to 10 smtp client processes, 10 smtp server processes,
+to run up to 10 SMTP client processes, 10 SMTP server processes,
and so on:
diff --git a/postfix/proto/memcache_table b/postfix/proto/memcache_table
new file mode 100644
index 000000000..83d687a39
--- /dev/null
+++ b/postfix/proto/memcache_table
@@ -0,0 +1,169 @@
+#++
+# NAME
+# memcache_table 5
+# SUMMARY
+# Postfix memcache client configuration
+# SYNOPSIS
+# \fBpostmap -q "\fIstring\fB" memcache:/etc/postfix/filename\fR
+#
+# \fBpostmap -q - memcache:/etc/postfix/\fIfilename\fR <\fIinputfile\fR
+# DESCRIPTION
+# The Postfix mail system uses optional tables for address
+# rewriting or mail routing. These tables are usually in
+# \fBdbm\fR or \fBdb\fR format.
+#
+# Alternatively, lookup tables can be specified as memcache
+# instances. In order to use memcache lookups, define a
+# memcache source as a lookup table in main.cf, for example:
+#
+# .nf
+# virtual_alias_maps = memcache:/etc/postfix/memcache-aliases.cf
+# .fi
+#
+# The file /etc/postfix/memcache-aliases.cf has the same
+# format as the Postfix main.cf file, and specifies the
+# parameters described below.
+#
+# The Postfix memcache client supports the lookup and update
+# operations.
+# MEMCACHE PARAMETERS
+# .ad
+# .fi
+# .IP "\fBhosts (default: localhost:11211)\fR"
+# The memcache servers that Postfix will try to connect to.
+# Specify a hostname or address, optionally followed by ":"
+# and a port name or number. The default port is 11211.
+# Examples:
+#
+# .nf
+# hosts = memcache01.example.com
+# memcache02.example.com
+# .fi
+# .IP "\fBkey_format (default: %s)\fB"
+# Format of the lookup and update keys in memcache queries.
+# By default, these are the same as the lookup and update
+# keys that are given to the Postfix memcache client.
+#
+# When the same memcache database is used to cache information
+# from multiple tables, you can use the \fBkey_format\fR
+# feature to avoid name collisions by prepending a fixed
+# string. Examples:
+#
+# .nf
+# key_format = aliases:%s
+# key_format = access:%s
+# .fi
+#
+# The \fBkey_format\fR parameter supports the following '%'
+# expansions:
+# .RS
+# .IP "\fB\fB%%\fR\fR"
+# This is replaced by a literal '%' character.
+# .IP "\fB\fB%s\fR\fR"
+# This is replaced by the memcache client input key.
+# .IP "\fB\fB%u\fR\fR"
+# When the input key is an address of the form user@domain,
+# \fB%u\fR is replaced by the SQL quoted local part of the
+# address. Otherwise, \fB%u\fR is replaced by the entire
+# search string. If the localpart is empty, a lookup is
+# silently suppressed and returns no results (an update is
+# skipped with a warning).
+# .IP "\fB\fB%d\fR\fR"
+# When the input key is an address of the form user@domain,
+# \fB%d\fR is replaced by the domain part of the address.
+# Otherwise, a lookup is silently suppressed and returns no
+# results (an update is skipped with a warning).
+# .IP "\fB\fB%[SUD]\fR\fR"
+# The upper-case equivalents of the above expansions behave
+# in the \fBkey_format\fR parameter identically to their
+# lower-case counter-parts.
+# .IP "\fB\fB%[1-9]\fR\fR"
+# The patterns %1, %2, ... %9 are replaced by the corresponding
+# most significant component of the input key's domain. If
+# the input key is \fIuser@mail.example.com\fR, then %1 is
+# \fBcom\fR, %2 is \fBexample\fR and %3 is \fBmail\fR. If the
+# input key is unqualified or does not have enough domain
+# components to satisfy all the specified patterns, a lookup
+# is silently suppressed and returns no results (an update
+# is skipped with a warning).
+# .RE
+# .IP "\fBdomain (default: no domain list)\fR"
+# This feature can significantly reduce database server load.
+# Specify a list of domain names, paths to files, or dictionaries.
+# When specified, only fully qualified search keys with a
+# *non-empty* localpart and a matching domain are eligible
+# for lookup or update: bare 'user' lookups, bare domain
+# lookups and "@domain" lookups are silently skipped (updates
+# are skipped with a warning). Example:
+#
+# .nf
+# domain = example.com, hash:/etc/postfix/searchdomains
+# .fi
+# .IP "\fBflags (default: 0)\fR"
+# Optional flags that should be stored along with a memcache
+# update.
+# .IP "\fBttl (default: 604800)\fR"
+# The expiration time in seconds of memcache updates.
+# The default is one week.
+#
+# When using memcache tables with \fBpostscreen\fR(8) or
+# \fBverify\fR(8), specify a zero *_cache_cleanup_interval
+# value, and specify the largest \fBpostscreen\fR(8) *_ttl
+# value or \fBverify\fR(8) *_expire_time value as the memcache
+# map's \fBttl\fR value.
+#
+# Note: according to memcache protocol documentation, a value
+# greater than 30 days (2592000 seconds) specifies absolute UNIX
+# time. Smaller values are relative to the time of the update.
+# BUGS
+# The Postfix memcache client is based on libmemcache, which
+# will terminate its process after a memcache server goes
+# down. To avoid this, set up redundant memcache servers that
+# have no common source of failure.
+#
+# The Postfix memcache client cannot be used for security-sensitive
+# tables such as \fBalias_maps\fR (these may contain
+# "\fI|command\fR and "\fI/file/name\fR" destinations), or
+# \fBvirtual_uid_maps\fR and \fBvirtual_gid_maps\fR (these
+# specify UNIX process privileges). In a typical deployment
+# a memcache database is shared via a TCP socket, and is
+# therefore writable not only by Postfix, but by any process
+# that can talk to the memcache server.
+#
+# The Postfix memcache client requires additional configuration
+# when used with the \fBpostscreen\fR(8) and \fBverify\fR(8)
+# daemons. For details see the \fBttl\fR parameter discussion
+# at the end of the MEMCACHE PARAMETERS section in this
+# document.
+#
+# The Postfix memcache client is supported only with libmemcache
+# version 1.4.0. Some libmemcache features are documented
+# by reading libmemcache source code, instead a proper API.
+# SEE ALSO
+# postmap(1), Postfix lookup table manager
+# postconf(5), configuration parameters
+# README FILES
+# .ad
+# .fi
+# Use "\fBpostconf readme_directory\fR" or
+# "\fBpostconf html_directory\fR" to locate this information.
+# .na
+# .nf
+# DATABASE_README, Postfix lookup table overview
+# MEMCACHE_README, Postfix memcache client guide
+# LICENSE
+# .ad
+# .fi
+# The Secure Mailer license must be distributed with this software.
+# HISTORY
+# .ad
+# .fi
+# The first memcache client for Postfix was written by Omar
+# Kilani. Besides being implemented on libmemcache, this
+# implementation bears no resemblance to his work.
+# AUTHOR(S)
+# Wietse Venema
+# IBM T.J. Watson Research
+# P.O. Box 704
+# Yorktown Heights, NY 10598, USA
+#--
diff --git a/postfix/src/global/Makefile.in b/postfix/src/global/Makefile.in
index 365b5b1ad..489027763 100644
--- a/postfix/src/global/Makefile.in
+++ b/postfix/src/global/Makefile.in
@@ -30,7 +30,8 @@ SRCS = abounce.c anvil_clnt.c been_here.c bounce.c bounce_log.c \
verp_sender.c wildcard_inet_addr.c xtext.c delivered_hdr.c \
fold_addr.c header_body_checks.c mkmap_proxy.c data_redirect.c \
match_service.c mail_conf_nint.c addr_match_list.c mail_conf_nbool.c \
- smtp_reply_footer.c safe_ultostr.c verify_sender_addr.c
+ smtp_reply_footer.c safe_ultostr.c verify_sender_addr.c \
+ dict_memcache.c mail_version.c
OBJS = abounce.o anvil_clnt.o been_here.o bounce.o bounce_log.o \
canon_addr.o cfg_parser.o cleanup_strerror.o cleanup_strflags.o \
clnt_stream.o conv_time.o db_common.o debug_peer.o debug_process.o \
@@ -62,7 +63,8 @@ OBJS = abounce.o anvil_clnt.o been_here.o bounce.o bounce_log.o \
verp_sender.o wildcard_inet_addr.o xtext.o delivered_hdr.o \
fold_addr.o header_body_checks.o mkmap_proxy.o data_redirect.o \
match_service.o mail_conf_nint.o addr_match_list.o mail_conf_nbool.o \
- smtp_reply_footer.o safe_ultostr.o verify_sender_addr.o
+ smtp_reply_footer.o safe_ultostr.o verify_sender_addr.o \
+ dict_memcache.o mail_version.o
HDRS = abounce.h anvil_clnt.h been_here.h bounce.h bounce_log.h \
canon_addr.h cfg_parser.h cleanup_user.h clnt_stream.h config.h \
conv_time.h db_common.h debug_peer.h debug_process.h defer.h \
@@ -88,7 +90,7 @@ HDRS = abounce.h anvil_clnt.h been_here.h bounce.h bounce_log.h \
verp_sender.h wildcard_inet_addr.h xtext.h delivered_hdr.h \
fold_addr.h header_body_checks.h data_redirect.h match_service.h \
addr_match_list.h smtp_reply_footer.h safe_ultostr.h \
- verify_sender_addr.h
+ verify_sender_addr.h dict_memcache.h
TESTSRC = rec2stream.c stream2rec.c recdump.c
DEFS = -I. -I$(INC_DIR) -D$(SYSTYPE)
CFLAGS = $(DEBUG) $(OPT) $(DEFS)
@@ -101,7 +103,8 @@ TESTPROG= domain_list dot_lockfile mail_addr_crunch mail_addr_find \
quote_821_local mail_conf_time mime_state strip_addr \
verify_clnt xtext anvil_clnt scache ehlo_mask \
valid_mailhost_addr own_inet_addr header_body_checks \
- data_redirect addr_match_list safe_ultostr verify_sender_addr
+ data_redirect addr_match_list safe_ultostr verify_sender_addr \
+ mail_version mail_dict
LIBS = ../../lib/libutil.a
LIB_DIR = ../../lib
@@ -293,9 +296,16 @@ safe_ultostr: safe_ultostr.c $(LIB) $(LIBS)
verify_sender_addr: verify_sender_addr.c $(LIB) $(LIBS)
$(CC) $(CFLAGS) -DTEST -o $@ $@.c $(LIB) $(LIBS) $(SYSLIBS)
+mail_version: mail_version.c $(LIB) $(LIBS)
+ $(CC) $(CFLAGS) -DTEST -o $@ $@.c $(LIB) $(LIBS) $(SYSLIBS)
+
+mail_dict: mail_dict.c $(LIB) $(LIBS)
+ $(CC) $(CFLAGS) -DTEST -o $@ $@.c $(LIB) $(LIBS) $(SYSLIBS)
+
tests: tok822_test mime_tests strip_addr_test tok822_limit_test \
xtext_test scache_multi_test ehlo_mask_test \
- namadr_list_test mail_conf_time_test header_body_checks_tests
+ namadr_list_test mail_conf_time_test header_body_checks_tests \
+ mail_version_test
mime_tests: mime_test mime_nest mime_8bit mime_dom mime_trunc mime_cvt \
mime_cvt2 mime_cvt3 mime_garb1 mime_garb2 mime_garb3 mime_garb4
@@ -387,6 +397,11 @@ xtext_test: xtext
cmp xtext.ref xtext.tmp
rm -f xtext.ref xtext.tmp
+mail_version_test: mail_version mail_version.in mail_version.ref
+ ./mail_version mail_version.tmp
+ diff mail_version.ref mail_version.tmp
+ rm -f mail_version.tmp
+
# Requires: Postfix running, root privileges
rewrite_clnt_test: rewrite_clnt rewrite_clnt.in rewrite_clnt.ref
@@ -850,6 +865,23 @@ dict_ldap.o: dict_ldap.c
dict_ldap.o: dict_ldap.h
dict_ldap.o: mail_conf.h
dict_ldap.o: string_list.h
+dict_memcache.o: ../../include/argv.h
+dict_memcache.o: ../../include/binhash.h
+dict_memcache.o: ../../include/dict.h
+dict_memcache.o: ../../include/match_list.h
+dict_memcache.o: ../../include/match_ops.h
+dict_memcache.o: ../../include/msg.h
+dict_memcache.o: ../../include/mymalloc.h
+dict_memcache.o: ../../include/stringops.h
+dict_memcache.o: ../../include/sys_defs.h
+dict_memcache.o: ../../include/vbuf.h
+dict_memcache.o: ../../include/vstream.h
+dict_memcache.o: ../../include/vstring.h
+dict_memcache.o: cfg_parser.h
+dict_memcache.o: db_common.h
+dict_memcache.o: dict_memcache.c
+dict_memcache.o: dict_memcache.h
+dict_memcache.o: string_list.h
dict_mysql.o: ../../include/argv.h
dict_mysql.o: ../../include/dict.h
dict_mysql.o: ../../include/events.h
@@ -1302,6 +1334,7 @@ mail_dict.o: ../../include/vbuf.h
mail_dict.o: ../../include/vstream.h
mail_dict.o: ../../include/vstring.h
mail_dict.o: dict_ldap.h
+mail_dict.o: dict_memcache.h
mail_dict.o: dict_mysql.h
mail_dict.o: dict_pgsql.h
mail_dict.o: dict_proxy.h
@@ -1437,7 +1470,14 @@ mail_trigger.o: ../../include/vstream.h
mail_trigger.o: mail_params.h
mail_trigger.o: mail_proto.h
mail_trigger.o: mail_trigger.c
+mail_version.o: ../../include/mymalloc.h
+mail_version.o: ../../include/split_at.h
+mail_version.o: ../../include/stringops.h
+mail_version.o: ../../include/sys_defs.h
+mail_version.o: ../../include/vbuf.h
+mail_version.o: ../../include/vstring.h
mail_version.o: mail_version.c
+mail_version.o: mail_version.h
maps.o: ../../include/argv.h
maps.o: ../../include/dict.h
maps.o: ../../include/msg.h
@@ -1520,7 +1560,15 @@ mime_state.o: mail_params.h
mime_state.o: mime_state.c
mime_state.o: mime_state.h
mime_state.o: rec_type.h
+mkmap_cdb.o: ../../include/argv.h
+mkmap_cdb.o: ../../include/dict.h
+mkmap_cdb.o: ../../include/dict_cdb.h
+mkmap_cdb.o: ../../include/mymalloc.h
mkmap_cdb.o: ../../include/sys_defs.h
+mkmap_cdb.o: ../../include/vbuf.h
+mkmap_cdb.o: ../../include/vstream.h
+mkmap_cdb.o: ../../include/vstring.h
+mkmap_cdb.o: mkmap.h
mkmap_cdb.o: mkmap_cdb.c
mkmap_db.o: ../../include/argv.h
mkmap_db.o: ../../include/dict.h
diff --git a/postfix/src/global/db_common.c b/postfix/src/global/db_common.c
index 6a2fa4bec..4dbeedb93 100644
--- a/postfix/src/global/db_common.c
+++ b/postfix/src/global/db_common.c
@@ -49,6 +49,9 @@
/* value indicates that data-depedent '%' expansions were found in the input
/* template.
/*
+/* db_common_alloc() provides a way to use db_common_parse_domain()
+/* etc. without prior db_common_parse() call.
+/*
/* \fIdb_common_expand\fR expands the specifiers in \fIformat\fR.
/* When the input data lacks all fields needed for the expansion, zero
/* is returned and the query or result should be skipped. Otherwise
@@ -163,6 +166,20 @@ typedef struct {
int nparts;
} DB_COMMON_CTX;
+/* db_common_alloc - allocate db_common context */
+
+void *db_common_alloc(DICT *dict)
+{
+ DB_COMMON_CTX *ctx;
+
+ ctx = (DB_COMMON_CTX *) mymalloc(sizeof *ctx);
+ ctx->dict = dict;
+ ctx->domain = 0;
+ ctx->flags = 0;
+ ctx->nparts = 0;
+ return ((void *) ctx);
+}
+
/* db_common_parse - validate query or result template */
int db_common_parse(DICT *dict, void **ctxPtr, const char *format, int query)
@@ -171,13 +188,9 @@ int db_common_parse(DICT *dict, void **ctxPtr, const char *format, int query
const char *cp;
int dynamic = 0;
- if (ctx == 0) {
- ctx = (DB_COMMON_CTX *) (*ctxPtr = mymalloc(sizeof *ctx));
- ctx->dict = dict;
- ctx->domain = 0;
- ctx->flags = 0;
- ctx->nparts = 0;
- }
+ if (ctx == 0)
+ ctx = (DB_COMMON_CTX *) (*ctxPtr = db_common_alloc(dict));
+
for (cp = format; *cp; ++cp)
if (*cp == '%')
switch (*++cp) {
diff --git a/postfix/src/global/db_common.h b/postfix/src/global/db_common.h
index ce7adc1e1..26ebf9731 100644
--- a/postfix/src/global/db_common.h
+++ b/postfix/src/global/db_common.h
@@ -21,6 +21,7 @@
typedef void (*db_quote_callback_t)(DICT *, const char *, VSTRING *);
extern int db_common_parse(DICT *, void **, const char *, int);
+extern void *db_common_alloc(DICT *);
extern void db_common_parse_domain(CFG_PARSER *, void *);
extern int db_common_dict_partial(void *);
extern int db_common_expand(void *, const char *, const char *,
diff --git a/postfix/src/global/dict_memcache.c b/postfix/src/global/dict_memcache.c
new file mode 100644
index 000000000..ee3c33c6a
--- /dev/null
+++ b/postfix/src/global/dict_memcache.c
@@ -0,0 +1,493 @@
+/*++
+/* NAME
+/* dict_memcache 3
+/* SUMMARY
+/* dictionary interface to memcache databases
+/* SYNOPSIS
+/* #include
+/*
+/* DICT *dict_memcache_open(name, open_flags, dict_flags)
+/* const char *name;
+/* int open_flags;
+/* int dict_flags;
+/* DESCRIPTION
+/* dict_memcache_open() opens a memcache database, providing
+/* a dictionary interface for Postfix key->value mappings.
+/* The result is a pointer to the installed dictionary.
+/*
+/* Configuration parameters are described in memcache_table(5).
+/*
+/* Arguments:
+/* .IP name
+/* Either the path to the Postfix memcache configuration file
+/* (if it starts with '/' or '.'), or the parameter name prefix
+/* which will be used to obtain main.cf configuration parameters.
+/* .IP open_flags
+/* O_RDONLY or O_RDWR. This function ignores flags that don't
+/* specify a read, write or append mode.
+/* .IP dict_flags
+/* See dict_open(3).
+/* SEE ALSO
+/* dict(3) generic dictionary manager
+/* BUGS
+/* This code requires libmemcache 1.4.0, because some parts
+/* of their API are documented by looking at the implementation.
+/* HISTORY
+/* The first memcache client for Postfix was written by:
+/* Omar Kilani
+/* omar@tinysofa.com
+/* This implementation bears no resemblance to his work.
+/* AUTHOR(S)
+/* Wietse Venema
+/* IBM T.J. Watson Research
+/* P.O. Box 704
+/* Yorktown Heights, NY 10598, USA
+/*--*/
+
+/* System library. */
+
+#include "sys_defs.h"
+
+#ifdef HAS_MEMCACHE
+#include
+#include
+
+#if !defined(MEMCACHE_VERNUM) || MEMCACHE_VERNUM != 10400
+#error "Postfix memcache supports only libmemcache version 1.4.0"
+#endif
+
+/* Utility library. */
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+/* Global library. */
+
+#include
+#include
+
+/* Application-specific. */
+
+#include
+
+ /*
+ * Robustness tests (with a single memcache server) proved disappointing.
+ *
+ * After failure to connect to the memcache server, libmemcache reports the
+ * error once. From then on it silently discards all updates and always
+ * reports "not found" for all lookups, without ever reporting an error. To
+ * avoid this, we destroy the memcache client and create a new one after
+ * libmemcache reports an error.
+ *
+ * Even more problematic is that libmemcache will terminate the process when
+ * the memcache server connection is lost (the libmemcache error message is:
+ * "read(2) failed: Socket is already connected"). Unfortunately, telling
+ * libmemcache not to terminate the process will result in an assertion
+ * failure followed by core dump.
+ *
+ * Conclusion: if we want robust code, then we should use our own memcache
+ * protocol implementation instead of libmemcache.
+ */
+
+ /*
+ * Structure of one memcache dictionary handle.
+ */
+typedef struct {
+ DICT dict; /* parent class */
+ struct memcache_ctxt *mc_ctxt; /* libmemcache context */
+ struct memcache *mc; /* libmemcache object */
+ CFG_PARSER *parser; /* common parameter parser */
+ void *dbc_ctxt; /* db_common context */
+ char *key_format; /* query key translation */
+ int mc_ttl; /* memcache expiration */
+ int mc_flags; /* memcache flags */
+ VSTRING *key_buf; /* lookup key */
+ VSTRING *res_buf; /* lookup result */
+} DICT_MC;
+
+ /*
+ * Default memcache options.
+ */
+#define DICT_MC_DEF_HOST "localhost"
+#define DICT_MC_DEF_PORT "11211"
+#define DICT_MC_DEF_HOST_PORT DICT_MC_DEF_HOST ":" DICT_MC_DEF_PORT
+#define DICT_MC_DEF_KEY_FMT "%s"
+#define DICT_MC_DEF_TTL (7 * 86400)
+#define DICT_MC_DEF_FLAGS 0
+
+ /*
+ * libmemcache can report errors through an application call-back function,
+ * but there is no support for passing application context to the call-back.
+ * The call-back API has two documented arguments: pointer to memcache_ctxt,
+ * and pointer to memcache_ectxt. The memcache_ctxt data structure has no
+ * space for application context, and the mcm_err() function zero-fills the
+ * memcache_ectxt data structure, making it useless for application context.
+ *
+ * We use our own hash table to find our dictionary handle, so that we can
+ * report errors in the proper context.
+ */
+static BINHASH *dict_mc_hash;
+
+ /*
+ * SLMs.
+ */
+#define STR(x) vstring_str(x)
+#define LEN(x) VSTRING_LEN(x)
+
+/*#define msg_verbose 1*/
+
+/* dict_memcache_error_cb - error call-back */
+
+static int dict_memcache_error_cb(MCM_ERR_FUNC_ARGS)
+{
+ const char *myname = "dict_memcache_error_cb";
+ const struct memcache_ctxt *ctxt;
+ struct memcache_err_ctxt *ectxt;
+ DICT_MC *dict_mc;
+ void (*log_fn) (const char *,...);
+
+ /*
+ * Play by the rules of the libmemcache API.
+ */
+ MCM_ERR_INIT_CTXT(ctxt, ectxt);
+
+ /*
+ * Locate our own dictionary handle for error reporting context.
+ * Unfortunately, the ctxt structure does not store application context,
+ * and mcm_err() zero-fills the ectxt structure, making it useless for
+ * storing application context. We use our own hash table instead.
+ */
+ if ((dict_mc = (DICT_MC *) binhash_find(dict_mc_hash, (char *) &ctxt,
+ sizeof(ctxt))) == 0)
+ msg_panic("%s: can't locate DICT_MC database handle", myname);
+
+ /*
+ * Report the error in our context, and set dict_errno for possible
+ * errors. We override dict_errno when an error was recoverable.
+ */
+ switch (ectxt->severity) {
+ default:
+#ifdef DICT_MC_RECOVER_FROM_DISCONNECT
+ /* Code below causes an assert failure and core dump. */
+ if (ectxt->errcode == MCM_ERR_SYS_READ)
+ /* Also: MCM_ERR_SYS_WRITEV, MCM_ERR_SYS_SETSOCKOPT */
+ ectxt->cont = 'y';
+#endif
+ /* FALLTHROUGH */
+ case MCM_ERR_LVL_NOTICE:
+ log_fn = msg_warn;
+ dict_errno = 1;
+ break;
+ case MCM_ERR_LVL_INFO:
+ log_fn = msg_info;
+ break;
+ }
+ log_fn((ectxt)->errnum ? "database %s:%s: libmemcache error: %s: %m" :
+ "database %s:%s: libmemcache error: %s",
+ DICT_TYPE_MEMCACHE, dict_mc->dict.name, (ectxt)->errstr);
+ return (0);
+}
+
+static void dict_memcache_mc_free(DICT_MC *);
+static void dict_memcache_mc_init(DICT_MC *);
+
+/* dict_memcache_recover - recover after libmemcache error */
+
+static void dict_memcache_recover(DICT_MC *dict_mc)
+{
+ int saved_dict_errno;
+
+ /*
+ * XXX If we don't try to recover from the first error, libmemcache will
+ * silently skip all subsequent database operations.
+ */
+ saved_dict_errno = dict_errno;
+ dict_memcache_mc_free(dict_mc);
+ dict_memcache_mc_init(dict_mc);
+ dict_errno = saved_dict_errno;
+}
+
+/* dict_memcache_prepare_key - prepare lookup key */
+
+static int dict_memcache_prepare_key(DICT_MC *dict_mc, const char *name)
+{
+
+ /*
+ * Optionally case-fold the search string.
+ */
+ if (dict_mc->dict.flags & DICT_FLAG_FOLD_FIX) {
+ if (dict_mc->dict.fold_buf == 0)
+ dict_mc->dict.fold_buf = vstring_alloc(10);
+ vstring_strcpy(dict_mc->dict.fold_buf, name);
+ name = lowercase(STR(dict_mc->dict.fold_buf));
+ }
+
+ /*
+ * Optionally expand the query key format.
+ */
+#define DICT_MC_NO_KEY (0)
+#define DICT_MC_NO_QUOTING ((void (*)(DICT *, const char *, VSTRING *)) 0)
+
+ if (dict_mc->key_format != 0
+ && strcmp(dict_mc->key_format, DICT_MC_DEF_KEY_FMT) != 0) {
+ VSTRING_RESET(dict_mc->key_buf);
+ if (db_common_expand(dict_mc->dbc_ctxt, dict_mc->key_format,
+ name, DICT_MC_NO_KEY, dict_mc->key_buf,
+ DICT_MC_NO_QUOTING) == 0)
+ return (0);
+ } else {
+ vstring_strcpy(dict_mc->key_buf, name);
+ }
+
+ /*
+ * The length indicates whether the expansion is empty or not.
+ */
+ return (LEN(dict_mc->key_buf));
+}
+
+/* dict_memcache_update - update memcache database */
+
+static void dict_memcache_update(DICT *dict, const char *name,
+ const char *value)
+{
+ const char *myname = "dict_memcache_update";
+ DICT_MC *dict_mc = (DICT_MC *) dict;
+
+ /*
+ * Skip updates with a null key, noisily. This would result in loss of
+ * information.
+ */
+ if (dict_memcache_prepare_key(dict_mc, name) == 0) {
+ dict_errno = 1;
+ msg_warn("database %s:%s: name \"%s\" expands to empty lookup key "
+ "-- skipping update", DICT_TYPE_MEMCACHE,
+ dict_mc->dict.name, name);
+ return;
+ }
+
+ /*
+ * Our error call-back routine will report errors and set dict_errno.
+ */
+ dict_errno = (mcm_set(dict_mc->mc_ctxt, dict_mc->mc, STR(dict_mc->key_buf),
+ LEN(dict_mc->key_buf), value, strlen(value),
+ dict_mc->mc_ttl, dict_mc->mc_flags) != 0);
+ if (msg_verbose)
+ msg_info("%s: %s: update key \"%s\" => \"%s\" %s",
+ myname, dict_mc->dict.name, STR(dict_mc->key_buf), value,
+ dict_errno ? "(error)" : "(no error)");
+
+ /*
+ * Recover after server failure.
+ */
+ if (dict_errno)
+ dict_memcache_recover(dict_mc);
+}
+
+/* dict_memcache_lookup - lookup memcache database */
+
+static const char *dict_memcache_lookup(DICT *dict, const char *name)
+{
+ const char *myname = "dict_memcache_lookup";
+ DICT_MC *dict_mc = (DICT_MC *) dict;
+ struct memcache_req *req;
+ struct memcache_res *res;
+ const char *retval;
+
+ /*
+ * Skip lookups with a null key, silently. This is just asking for
+ * information that cannot exist.
+ */
+#define DICT_MC_SKIP(why, map_name, key) do { \
+ if (msg_verbose) \
+ msg_info("%s: %s: skipping lookup of key \"%s\": %s", \
+ myname, (map_name), (key), (why)); \
+ return (0); \
+ } while (0)
+
+ if (*name == 0)
+ DICT_MC_SKIP("empty lookup key", dict_mc->dict.name, name);
+ if (db_common_check_domain(dict_mc->dbc_ctxt, name) == 0)
+ DICT_MC_SKIP("domain mismatch", dict_mc->dict.name, name);
+ if (dict_memcache_prepare_key(dict_mc, name) == 0)
+ DICT_MC_SKIP("empty lookup key expansion", dict_mc->dict.name, name);
+
+ /*
+ * Our error call-back routine will report errors and set dict_errno. We
+ * reset dict_errno after an error turns out to be recoverable.
+ */
+ if ((req = mcm_req_new(dict_mc->mc_ctxt)) == 0)
+ msg_fatal("%s: can't create new request: %m", myname); /* XXX */
+ /* Not: mcm_req_add(), because that makes unnecessary copy of the key. */
+ if ((res = mcm_req_add_ref(dict_mc->mc_ctxt, req, STR(dict_mc->key_buf),
+ LEN(dict_mc->key_buf))) == 0)
+ msg_fatal("%s: can't create new result: %m", myname); /* XXX */
+
+ dict_errno = 0;
+ mcm_get(dict_mc->mc_ctxt, dict_mc->mc, req);
+ if (mcm_res_found(dict_mc->mc_ctxt, res) && res->bytes) {
+ vstring_strncpy(dict_mc->res_buf, res->val, res->bytes);
+ retval = STR(dict_mc->res_buf);
+ dict_errno = 0;
+ } else {
+ retval = 0;
+ }
+ mcm_res_free(dict_mc->mc_ctxt, req, res);
+ mcm_req_free(dict_mc->mc_ctxt, req);
+
+ if (msg_verbose)
+ msg_info("%s: %s: key %s => %s",
+ myname, dict_mc->dict.name, STR(dict_mc->key_buf),
+ retval ? STR(dict_mc->res_buf) :
+ dict_errno ? "(error)" : "(not found)");
+
+ /*
+ * Recover after server failure.
+ */
+ if (dict_errno)
+ dict_memcache_recover(dict_mc);
+
+ return (retval);
+}
+
+/* dict_memcache_mc_free - destroy libmemcache objects */
+
+static void dict_memcache_mc_free(DICT_MC *dict_mc)
+{
+ binhash_delete(dict_mc_hash, (char *) &dict_mc->mc_ctxt,
+ sizeof(dict_mc->mc_ctxt), (void (*) (char *)) 0);
+ mcm_free(dict_mc->mc_ctxt, dict_mc->mc);
+ mcMemFreeCtxt(dict_mc->mc_ctxt);
+}
+
+/* dict_memcache_mc_init - create libmemcache objects */
+
+static void dict_memcache_mc_init(DICT_MC *dict_mc)
+{
+ const char *myname = "dict_memcache_mc_init";
+ char *servers;
+ char *server;
+ char *cp;
+
+ /*
+ * Create the libmemcache objects.
+ */
+ dict_mc->mc_ctxt =
+ mcMemNewCtxt((mcFreeFunc) myfree, (mcMallocFunc) mymalloc,
+ (mcMallocFunc) mymalloc, (mcReallocFunc) myrealloc);
+ if (dict_mc->mc_ctxt == 0)
+ msg_fatal("error creating memcache context: %m"); /* XXX */
+ dict_mc->mc = mcm_new(dict_mc->mc_ctxt);
+ if (dict_mc->mc == 0)
+ msg_fatal("error creating memcache object: %m"); /* XXX */
+
+ /*
+ * Set up call-back info for error reporting.
+ */
+ if (dict_mc_hash == 0)
+ dict_mc_hash = binhash_create(1);
+ binhash_enter(dict_mc_hash, (char *) &dict_mc->mc_ctxt,
+ sizeof(dict_mc->mc_ctxt), (char *) dict_mc);
+ mcErrSetupCtxt(dict_mc->mc_ctxt, dict_memcache_error_cb);
+
+ /*
+ * Add the server list.
+ */
+ cp = servers = cfg_get_str(dict_mc->parser, "hosts",
+ DICT_MC_DEF_HOST_PORT, 0, 0);
+ while ((server = mystrtok(&cp, " ,\t\r\n")) != 0) {
+ if (msg_verbose)
+ msg_info("%s: database %s:%s: adding server %s",
+ myname, DICT_TYPE_MEMCACHE, dict_mc->dict.name, server);
+ if (mcm_server_add4(dict_mc->mc_ctxt, dict_mc->mc, server) < 0)
+ msg_warn("database %s:%s: error adding server %s",
+ DICT_TYPE_MEMCACHE, dict_mc->dict.name, server);
+ }
+ myfree(servers);
+}
+
+/* dict_memcache_close - close memcache database */
+
+static void dict_memcache_close(DICT *dict)
+{
+ DICT_MC *dict_mc = (DICT_MC *) dict;
+
+ dict_memcache_mc_free(dict_mc);
+ cfg_parser_free(dict_mc->parser);
+ db_common_free_ctx(dict_mc->dbc_ctxt);
+ vstring_free(dict_mc->key_buf);
+ vstring_free(dict_mc->res_buf);
+ if (dict_mc->key_format)
+ myfree(dict_mc->key_format);
+ if (dict->fold_buf)
+ vstring_free(dict->fold_buf);
+ dict_free(dict);
+}
+
+/* dict_memcache_open - open memcache database */
+
+DICT *dict_memcache_open(const char *name, int open_flags, int dict_flags)
+{
+ DICT_MC *dict_mc;
+
+ /*
+ * Sanity checks.
+ */
+ if (dict_flags & DICT_FLAG_NO_UNAUTH)
+ msg_fatal("%s:%s map is not allowed for security-sensitive data",
+ DICT_TYPE_MEMCACHE, name);
+ open_flags &= (O_RDONLY | O_RDWR | O_WRONLY | O_APPEND);
+ if (open_flags != O_RDONLY && open_flags != O_RDWR)
+ msg_fatal("%s:%s map requires O_RDONLY or O_RDWR access mode",
+ DICT_TYPE_MEMCACHE, name);
+
+ /*
+ * Create the dictionary object.
+ */
+ dict_mc = (DICT_MC *) dict_alloc(DICT_TYPE_MEMCACHE, name,
+ sizeof(*dict_mc));
+ dict_mc->dict.lookup = dict_memcache_lookup;
+ if (open_flags == O_RDWR)
+ dict_mc->dict.update = dict_memcache_update;
+ dict_mc->dict.close = dict_memcache_close;
+ dict_mc->dict.flags = dict_flags;
+ dict_mc->key_buf = vstring_alloc(10);
+ dict_mc->res_buf = vstring_alloc(10);
+
+ /*
+ * Parse the configuration file.
+ */
+ dict_mc->parser = cfg_parser_alloc(name);
+ dict_mc->key_format = cfg_get_str(dict_mc->parser, "key_format",
+ DICT_MC_DEF_KEY_FMT, 0, 0);
+ dict_mc->mc_ttl = cfg_get_int(dict_mc->parser, "ttl",
+ DICT_MC_DEF_TTL, 0, 0);
+ dict_mc->mc_flags = cfg_get_int(dict_mc->parser, "flags",
+ DICT_MC_DEF_FLAGS, 0, 0);
+
+ /*
+ * Initialize the memcache objects.
+ */
+ dict_memcache_mc_init(dict_mc);
+
+ /*
+ * Parse templates and common database parameters. Maps that use
+ * substring keys should only be used with the full input key.
+ */
+ dict_mc->dbc_ctxt = 0;
+ db_common_parse(&dict_mc->dict, &dict_mc->dbc_ctxt,
+ dict_mc->key_format, 1);
+ db_common_parse_domain(dict_mc->parser, dict_mc->dbc_ctxt);
+ if (db_common_dict_partial(dict_mc->dbc_ctxt))
+ /* Breaks recipient delimiters */
+ dict_mc->dict.flags |= DICT_FLAG_PATTERN;
+ else
+ dict_mc->dict.flags |= DICT_FLAG_FIXED;
+
+ return (&dict_mc->dict);
+}
+
+#endif
diff --git a/postfix/src/global/dict_memcache.h b/postfix/src/global/dict_memcache.h
new file mode 100644
index 000000000..3b6e7a406
--- /dev/null
+++ b/postfix/src/global/dict_memcache.h
@@ -0,0 +1,38 @@
+#ifndef _DICT_MEMCACHE_INCLUDED_
+#define _DICT_MEMCACHE_INCLUDED_
+
+/*++
+/* NAME
+/* dict_memcache 3h
+/* SUMMARY
+/* dictionary interface to memcache databases
+/* SYNOPSIS
+/* #include
+/* DESCRIPTION
+/* .nf
+
+ /*
+ * Utility library.
+ */
+#include
+
+ /*
+ * External interface.
+ */
+#define DICT_TYPE_MEMCACHE "memcache"
+
+extern DICT *dict_memcache_open(const char *name, int unused_flags,
+ int dict_flags);
+
+/* LICENSE
+/* .ad
+/* .fi
+/* The Secure Mailer license must be distributed with this software.
+/* AUTHOR(S)
+/* Wietse Venema
+/* IBM T.J. Watson Research
+/* P.O. Box 704
+/* Yorktown Heights, NY 10598, USA
+/*--*/
+
+#endif
diff --git a/postfix/src/global/mail_dict.c b/postfix/src/global/mail_dict.c
index 337861d11..3d456ea7d 100644
--- a/postfix/src/global/mail_dict.c
+++ b/postfix/src/global/mail_dict.c
@@ -37,6 +37,7 @@
#include
#include
#include
+#include
#include
typedef struct {
@@ -57,6 +58,9 @@ static const DICT_OPEN_INFO dict_open_info[] = {
#endif
#ifdef HAS_SQLITE
DICT_TYPE_SQLITE, dict_sqlite_open,
+#endif
+#ifdef HAS_MEMCACHE
+ DICT_TYPE_MEMCACHE, dict_memcache_open,
#endif
0,
};
@@ -70,3 +74,17 @@ void mail_dict_init(void)
for (dp = dict_open_info; dp->type; dp++)
dict_open_register(dp->type, dp->open);
}
+
+#ifdef TEST
+
+ /*
+ * Proof-of-concept test program.
+ */
+int main(int argc, char **argv)
+{
+ mail_dict_init();
+ dict_test(argc, argv);
+ return (0);
+}
+
+#endif
diff --git a/postfix/src/global/mail_proto.h b/postfix/src/global/mail_proto.h
index ad0505b98..da5dc31af 100644
--- a/postfix/src/global/mail_proto.h
+++ b/postfix/src/global/mail_proto.h
@@ -257,6 +257,7 @@ extern char *mail_pathname(const char *, const char *);
#define MAIL_ATTR_CIPHER_NAME "cipher_name"
#define MAIL_ATTR_CIPHER_USEBITS "cipher_usebits"
#define MAIL_ATTR_CIPHER_ALGBITS "cipher_algbits"
+#define MAIL_ATTR_SERVER_ID "server_id"
/*
* SMTP reply footer support.
diff --git a/postfix/src/global/mail_version.c b/postfix/src/global/mail_version.c
index e69de29bb..6b2402132 100644
--- a/postfix/src/global/mail_version.c
+++ b/postfix/src/global/mail_version.c
@@ -0,0 +1,258 @@
+/*++
+/* NAME
+/* mail_version 3
+/* SUMMARY
+/* time-dependent probe sender addresses
+/* SYNOPSIS
+/* #include
+/*
+/* typedef struct {
+/* char *program; /* postfix */
+/* int major; /* 2 */
+/* int minor; /* 9 */
+/* int patch; /* patchlevel or -1 */
+/* char *snapshot; /* null or snapshot info */
+/* } MAIL_VERSION;
+/*
+/* MAIL_VERSION *mail_version_parse(version_string, why)
+/* const char *version_string;
+/* const char **why;
+/*
+/* void mail_version_free(mp)
+/* MAIL_VERSION *mp;
+/*
+/* const char *get_mail_version()
+/*
+/* int check_mail_version(version_string)
+/* const char *version_string;
+/* DESCRIPTION
+/* This module understands the format of Postfix version strings
+/* (for example the default value of "mail_version"), and
+/* provides support to compare the compile-time version of a
+/* Postfix program with the run-time version of a Postfix
+/* library. Apparently, some distributions don't use proper
+/* so-number versioning, causing programs to fail erratically
+/* after an update replaces the library but not the program.
+/*
+/* A Postfix version string consists of two or three parts
+/* separated by a single "-" character:
+/* .IP \(bu
+/* The first part is a string with the program name.
+/* .IP \(bu
+/* The second part is the program version: either two or three
+/* non-negative integer numbers separated by single "."
+/* character. Stable releases have a major version, minor
+/* version and patchlevel; experimental releases (snapshots)
+/* have only major and minor version numbers.
+/* .IP \(bu
+/* The third part is ignored with a stable release, otherwise
+/* it is a string with the snapshot release date plus some
+/* optional information.
+/*
+/* mail_version_parse() parses a version string.
+/*
+/* get_mail_version() returns the version string (the value
+/* of DEF_MAIL_VERSION) that is compiled into the library.
+/*
+/* check_mail_version() compares the caller's version string
+/* (usually the value of DEF_MAIL_VERSION) that is compiled
+/* into the caller, and logs a warning when the strings differ.
+/* DIAGNOSTICS
+/* In the case of a parsing error, mail_version_parse() returns
+/* a null pointer, and sets the why argument to a string with
+/* problem details.
+/* LICENSE
+/* .ad
+/* .fi
+/* The Secure Mailer license must be distributed with this software.
+/* AUTHOR(S)
+/* Wietse Venema
+/* IBM T.J. Watson Research
+/* P.O. Box 704
+/* Yorktown Heights, NY 10598, USA
+/*--*/
+
+/* System library. */
+
+#include
+#include
+#include
+
+/* Utility library. */
+
+#include
+#include
+#include
+#include
+
+/* Global library. */
+
+#include
+
+/* mail_version_int - convert integer */
+
+static int mail_version_int(const char *strval)
+{
+ char *end;
+ int intval;
+ long longval;
+
+ errno = 0;
+ intval = longval = strtol(strval, &end, 10);
+ if (*strval == 0 || *end != 0 || errno == ERANGE || longval != intval)
+ intval = (-1);
+ return (intval);
+}
+
+/* mail_version_worker - do the parsing work */
+
+static const char *mail_version_worker(MAIL_VERSION *mp, char *cp)
+{
+ char *major_field;
+ char *minor_field;
+ char *patch_field;
+
+ /*
+ * Program name.
+ */
+ if ((mp->program = mystrtok(&cp, "-")) == 0)
+ return ("no program name");
+
+ /*
+ * Major, minor, patchlevel. If this is a stable release, then we ignore
+ * text after the patchlevel, in case there are vendor extensions.
+ */
+ if ((major_field = mystrtok(&cp, "-")) == 0)
+ return ("missing major version");
+
+ if ((minor_field = split_at(major_field, '.')) == 0)
+ return ("missing minor version");
+ if ((mp->major = mail_version_int(major_field)) < 0)
+ return ("bad major version");
+ patch_field = split_at(minor_field, '.');
+ if ((mp->minor = mail_version_int(minor_field)) < 0)
+ return ("bad minor version");
+
+ if (patch_field == 0)
+ mp->patch = -1;
+ else if ((mp->patch = mail_version_int(patch_field)) < 0)
+ return ("bad patchlevel");
+
+ /*
+ * Experimental release. If this is not a stable release, we take
+ * everything to the end of the string.
+ */
+ if (patch_field != 0)
+ mp->snapshot = 0;
+ else if ((mp->snapshot = mystrtok(&cp, "")) == 0)
+ return ("missing snapshot field");
+
+ return (0);
+}
+
+/* mail_version_parse - driver */
+
+MAIL_VERSION *mail_version_parse(const char *string, const char **why)
+{
+ MAIL_VERSION *mp;
+ char *saved_string;
+ const char *err;
+
+ mp = (MAIL_VERSION *) mymalloc(sizeof(*mp));
+ saved_string = mystrdup(string);
+ if ((err = mail_version_worker(mp, saved_string)) != 0) {
+ *why = err;
+ myfree(saved_string);
+ myfree((char *) mp);
+ return (0);
+ } else {
+ return (mp);
+ }
+}
+
+/* mail_version_free - destroy version information */
+
+void mail_version_free(MAIL_VERSION *mp)
+{
+ myfree(mp->program);
+ myfree((char *) mp);
+}
+
+/* get_mail_version - return parsed mail version string */
+
+const char *get_mail_version(void)
+{
+ return (DEF_MAIL_VERSION);
+}
+
+/* check_mail_version - compare caller version with library version */
+
+void check_mail_version(const char *version_string)
+{
+ if (strcmp(version_string, DEF_MAIL_VERSION) != 0)
+ msg_warn("Postfix library version mis-match: wanted %s, found %s",
+ version_string, DEF_MAIL_VERSION);
+}
+
+#ifdef TEST
+
+#include
+#include
+#include
+#include
+
+#define STR(x) vstring_str(x)
+
+/* parse_sample - parse a sample string from argv or stdin */
+
+static void parse_sample(const char *sample)
+{
+ MAIL_VERSION *mp;
+ const char *why;
+
+ mp = mail_version_parse(sample, &why);
+ if (mp == 0) {
+ vstream_printf("ERROR: %s: %s\n", sample, why);
+ } else {
+ vstream_printf("program: %s\t", mp->program);
+ vstream_printf("major: %d\t", mp->major);
+ vstream_printf("minor: %d\t", mp->minor);
+ if (mp->patch < 0)
+ vstream_printf("snapshot: %s\n", mp->snapshot);
+ else
+ vstream_printf("patch: %d\n", mp->patch);
+ mail_version_free(mp);
+ }
+ vstream_fflush(VSTREAM_OUT);
+}
+
+/* main - the main program */
+
+int main(int argc, char **argv)
+{
+ VSTRING *inbuf = vstring_alloc(1);
+ int have_tty = isatty(0);
+
+ if (argc > 1) {
+ while (--argc > 0 && *++argv)
+ parse_sample(*argv);
+ } else {
+ for (;;) {
+ if (have_tty) {
+ vstream_printf("> ");
+ vstream_fflush(VSTREAM_OUT);
+ }
+ if (vstring_fgets_nonl(inbuf, VSTREAM_IN) <= 0)
+ break;
+ if (have_tty == 0)
+ vstream_printf("> %s\n", STR(inbuf));
+ if (*STR(inbuf) == 0 || *STR(inbuf) == '#')
+ continue;
+ parse_sample(STR(inbuf));
+ }
+ }
+ vstring_free(inbuf);
+ return (0);
+}
+
+#endif
diff --git a/postfix/src/global/mail_version.h b/postfix/src/global/mail_version.h
index b7c89e0f6..2f815b661 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 "20111205"
+#define MAIL_RELEASE_DATE "20111209"
#define MAIL_VERSION_NUMBER "2.9"
#ifdef SNAPSHOT
@@ -67,6 +67,29 @@ extern char *var_mail_release;
#define MAIL_VERSION_STAMP_ALLOCATE \
mail_version_stamp = strdup(VAR_MAIL_VERSION "=" DEF_MAIL_VERSION)
+ /*
+ * Mail version string parser, plus support to compare the compile-time
+ * version string of a Postfix program with the run-time version string of a
+ * Postfix shared library. When programs are not updated, they may fail in
+ * erratic ways when linked against a newer run-time library. Of course the
+ * right solution is so-number versioning of the Postfix run-time library.
+ */
+typedef struct {
+ char *program; /* postfix */
+ int major; /* 2 */
+ int minor; /* 9 */
+ int patch; /* null */
+ char *snapshot; /* 20111209-nonprod */
+} MAIL_VERSION;
+
+extern MAIL_VERSION *mail_version_parse(const char *, const char **);
+extern void mail_version_free(MAIL_VERSION *);
+extern const char *get_mail_version(void);
+extern void check_mail_version(const char *);
+
+#define MAIL_VERSION_CHECK \
+ check_mail_version(DEF_MAIL_VERSION)
+
/* LICENSE
/* .ad
/* .fi
diff --git a/postfix/src/global/mail_version.in b/postfix/src/global/mail_version.in
new file mode 100644
index 000000000..1cf75d8af
--- /dev/null
+++ b/postfix/src/global/mail_version.in
@@ -0,0 +1,8 @@
+1
+1-2
+1-2.3
+1-2.3.4.5
+1-2.3.4-5
+1-2.3-5
+1-2.3-5-6
+1-2.3-5.6
diff --git a/postfix/src/global/mail_version.ref b/postfix/src/global/mail_version.ref
new file mode 100644
index 000000000..5dbc3ab08
--- /dev/null
+++ b/postfix/src/global/mail_version.ref
@@ -0,0 +1,16 @@
+> 1
+ERROR: 1: missing major version
+> 1-2
+ERROR: 1-2: missing minor version
+> 1-2.3
+ERROR: 1-2.3: missing snapshot field
+> 1-2.3.4.5
+ERROR: 1-2.3.4.5: bad patchlevel
+> 1-2.3.4-5
+program: 1 major: 2 minor: 3 patch: 4
+> 1-2.3-5
+program: 1 major: 2 minor: 3 snapshot: 5
+> 1-2.3-5-6
+program: 1 major: 2 minor: 3 snapshot: 5-6
+> 1-2.3-5.6
+program: 1 major: 2 minor: 3 snapshot: 5.6
diff --git a/postfix/src/master/Makefile.in b/postfix/src/master/Makefile.in
index 53f65bd9e..a78173916 100644
--- a/postfix/src/master/Makefile.in
+++ b/postfix/src/master/Makefile.in
@@ -92,6 +92,7 @@ event_server.o: ../../include/mail_conf.h
event_server.o: ../../include/mail_dict.h
event_server.o: ../../include/mail_params.h
event_server.o: ../../include/mail_task.h
+event_server.o: ../../include/mail_version.h
event_server.o: ../../include/msg.h
event_server.o: ../../include/msg_syslog.h
event_server.o: ../../include/msg_vstream.h
@@ -278,6 +279,7 @@ multi_server.o: ../../include/mail_conf.h
multi_server.o: ../../include/mail_dict.h
multi_server.o: ../../include/mail_params.h
multi_server.o: ../../include/mail_task.h
+multi_server.o: ../../include/mail_version.h
multi_server.o: ../../include/msg.h
multi_server.o: ../../include/msg_syslog.h
multi_server.o: ../../include/msg_vstream.h
@@ -307,6 +309,7 @@ single_server.o: ../../include/mail_conf.h
single_server.o: ../../include/mail_dict.h
single_server.o: ../../include/mail_params.h
single_server.o: ../../include/mail_task.h
+single_server.o: ../../include/mail_version.h
single_server.o: ../../include/msg.h
single_server.o: ../../include/msg_syslog.h
single_server.o: ../../include/msg_vstream.h
@@ -336,6 +339,7 @@ trigger_server.o: ../../include/mail_conf.h
trigger_server.o: ../../include/mail_dict.h
trigger_server.o: ../../include/mail_params.h
trigger_server.o: ../../include/mail_task.h
+trigger_server.o: ../../include/mail_version.h
trigger_server.o: ../../include/msg.h
trigger_server.o: ../../include/msg_syslog.h
trigger_server.o: ../../include/msg_vstream.h
diff --git a/postfix/src/master/event_server.c b/postfix/src/master/event_server.c
index 21ff0d5a9..37d7e0970 100644
--- a/postfix/src/master/event_server.c
+++ b/postfix/src/master/event_server.c
@@ -226,6 +226,7 @@
#include
#include
#include
+#include
/* Process manager. */
@@ -577,6 +578,11 @@ NORETURN event_server_main(int argc, char **argv, MULTI_SERVER_FN service,...)
if (msg_verbose)
msg_info("daemon started");
+ /*
+ * Check the Postfix library version as soon as we enable logging.
+ */
+ MAIL_VERSION_CHECK;
+
/*
* Initialize from the configuration file. Allow command-line options to
* override compiled-in defaults or configured parameter values.
diff --git a/postfix/src/master/master.c b/postfix/src/master/master.c
index cef01e401..532eb789e 100644
--- a/postfix/src/master/master.c
+++ b/postfix/src/master/master.c
@@ -293,6 +293,11 @@ int main(int argc, char **argv)
*/
msg_syslog_init(mail_task(var_procname), LOG_PID, LOG_FACILITY);
+ /*
+ * Check the Postfix library version as soon as we enable logging.
+ */
+ MAIL_VERSION_CHECK;
+
/*
* The mail system must be run by the superuser so it can revoke
* privileges for selected operations. That's right - it takes privileges
diff --git a/postfix/src/master/multi_server.c b/postfix/src/master/multi_server.c
index 6477894f5..0b5e678c6 100644
--- a/postfix/src/master/multi_server.c
+++ b/postfix/src/master/multi_server.c
@@ -214,6 +214,7 @@
#include
#include
#include
+#include
/* Process manager. */
@@ -573,6 +574,11 @@ NORETURN multi_server_main(int argc, char **argv, MULTI_SERVER_FN service,...)
if (msg_verbose)
msg_info("daemon started");
+ /*
+ * Check the Postfix library version as soon as we enable logging.
+ */
+ MAIL_VERSION_CHECK;
+
/*
* Initialize from the configuration file. Allow command-line options to
* override compiled-in defaults or configured parameter values.
diff --git a/postfix/src/master/single_server.c b/postfix/src/master/single_server.c
index 94937eb97..aba479cd5 100644
--- a/postfix/src/master/single_server.c
+++ b/postfix/src/master/single_server.c
@@ -191,6 +191,7 @@
#include
#include
#include
+#include
/* Process manager. */
@@ -456,6 +457,11 @@ NORETURN single_server_main(int argc, char **argv, SINGLE_SERVER_FN service,...)
if (msg_verbose)
msg_info("daemon started");
+ /*
+ * Check the Postfix library version as soon as we enable logging.
+ */
+ MAIL_VERSION_CHECK;
+
/*
* Initialize from the configuration file. Allow command-line options to
* override compiled-in defaults or configured parameter values.
diff --git a/postfix/src/master/trigger_server.c b/postfix/src/master/trigger_server.c
index 10d6621a2..df3bf2054 100644
--- a/postfix/src/master/trigger_server.c
+++ b/postfix/src/master/trigger_server.c
@@ -201,6 +201,7 @@
#include
#include
#include
+#include
/* Process manager. */
@@ -467,6 +468,11 @@ NORETURN trigger_server_main(int argc, char **argv, TRIGGER_SERVER_FN service,..
if (msg_verbose)
msg_info("daemon started");
+ /*
+ * Check the Postfix library version as soon as we enable logging.
+ */
+ MAIL_VERSION_CHECK;
+
/*
* Initialize from the configuration file. Allow command-line options to
* override compiled-in defaults or configured parameter values.
diff --git a/postfix/src/postalias/postalias.c b/postfix/src/postalias/postalias.c
index 34336cd7e..9b17d0207 100644
--- a/postfix/src/postalias/postalias.c
+++ b/postfix/src/postalias/postalias.c
@@ -669,6 +669,11 @@ int main(int argc, char **argv)
msg_vstream_init(argv[0], VSTREAM_ERR);
msg_syslog_init(mail_task(argv[0]), LOG_PID, LOG_FACILITY);
+ /*
+ * Check the Postfix library version as soon as we enable logging.
+ */
+ MAIL_VERSION_CHECK;
+
/*
* Parse JCL.
*/
diff --git a/postfix/src/postconf/postconf.c b/postfix/src/postconf/postconf.c
index 0de2b48ec..eea582ac6 100644
--- a/postfix/src/postconf/postconf.c
+++ b/postfix/src/postconf/postconf.c
@@ -175,6 +175,9 @@
/* .IP "\fBldap\fR (read-only)"
/* Perform lookups using the LDAP protocol. This is described
/* in \fBldap_table\fR(5).
+/* .IP "\fBmemcache\fR (read-write)"
+/* Perform lookups using the memcache protocol. This is described
+/* in \fBmemcache_table\fR(5).
/* .IP "\fBmysql\fR (read-only)"
/* Perform lookups using the MYSQL protocol. This is described
/* in \fBmysql_table\fR(5).
diff --git a/postfix/src/postdrop/postdrop.c b/postfix/src/postdrop/postdrop.c
index a2df01ece..84f8e69e0 100644
--- a/postfix/src/postdrop/postdrop.c
+++ b/postfix/src/postdrop/postdrop.c
@@ -265,6 +265,11 @@ int main(int argc, char **argv)
msg_syslog_init(mail_task("postdrop"), LOG_PID, LOG_FACILITY);
set_mail_conf_str(VAR_PROCNAME, var_procname = mystrdup(argv[0]));
+ /*
+ * Check the Postfix library version as soon as we enable logging.
+ */
+ MAIL_VERSION_CHECK;
+
/*
* Parse JCL. This program is set-gid and must sanitize all command-line
* arguments. The configuration directory argument is validated by the
diff --git a/postfix/src/postfix/postfix.c b/postfix/src/postfix/postfix.c
index c7b8c97ec..60343668e 100644
--- a/postfix/src/postfix/postfix.c
+++ b/postfix/src/postfix/postfix.c
@@ -240,6 +240,7 @@
/* Table lookup mechanisms:
/* cidr_table(5), Associate CIDR pattern with value
/* ldap_table(5), Postfix LDAP client
+/* memcache_table(5), Postfix memcache client
/* mysql_table(5), Postfix MYSQL client
/* nisplus_table(5), Postfix NIS+ client
/* pcre_table(5), Associate PCRE pattern with value
@@ -436,6 +437,11 @@ int main(int argc, char **argv)
msg_vstream_init(argv[0], VSTREAM_ERR);
msg_syslog_init(argv[0], LOG_PID, LOG_FACILITY);
+ /*
+ * Check the Postfix library version as soon as we enable logging.
+ */
+ MAIL_VERSION_CHECK;
+
/*
* The mail system must be run by the superuser so it can revoke
* privileges for selected operations. That's right - it takes privileges
@@ -524,7 +530,7 @@ int main(int argc, char **argv)
/*
* Run the management script.
*/
- if (force_single_instance
+ if (force_single_instance
|| argv_split(var_multi_conf_dirs, "\t\r\n, ")->argc == 0) {
script = concatenate(var_daemon_dir, "/postfix-script", (char *) 0);
if (optind < 1)
diff --git a/postfix/src/postlog/postlog.c b/postfix/src/postlog/postlog.c
index 000ff70d6..67715ae9e 100644
--- a/postfix/src/postlog/postlog.c
+++ b/postfix/src/postlog/postlog.c
@@ -208,6 +208,11 @@ int main(int argc, char **argv)
msg_syslog_init(tag, LOG_PID, LOG_FACILITY);
tag = 0;
+ /*
+ * Check the Postfix library version as soon as we enable logging.
+ */
+ MAIL_VERSION_CHECK;
+
/*
* Parse switches.
*/
diff --git a/postfix/src/postmap/postmap.c b/postfix/src/postmap/postmap.c
index e956aed9b..19bb02e5b 100644
--- a/postfix/src/postmap/postmap.c
+++ b/postfix/src/postmap/postmap.c
@@ -784,6 +784,11 @@ int main(int argc, char **argv)
msg_vstream_init(argv[0], VSTREAM_ERR);
msg_syslog_init(mail_task(argv[0]), LOG_PID, LOG_FACILITY);
+ /*
+ * Check the Postfix library version as soon as we enable logging.
+ */
+ MAIL_VERSION_CHECK;
+
/*
* Parse JCL.
*/
@@ -857,7 +862,7 @@ int main(int argc, char **argv)
if (strcmp(var_syslog_name, DEF_SYSLOG_NAME) != 0)
msg_syslog_init(mail_task(argv[0]), LOG_PID, LOG_FACILITY);
mail_dict_init();
- if ((query == 0 || strcmp(query, "-") != 0)
+ if ((query == 0 || strcmp(query, "-") != 0)
&& (postmap_flags & POSTMAP_FLAG_ANY_KEY))
msg_fatal("specify -b -h or -m only with \"-q -\"");
diff --git a/postfix/src/postmulti/postmulti.c b/postfix/src/postmulti/postmulti.c
index 30633ae26..c0ff9df36 100644
--- a/postfix/src/postmulti/postmulti.c
+++ b/postfix/src/postmulti/postmulti.c
@@ -1658,6 +1658,11 @@ int main(int argc, char **argv)
msg_vstream_init(argv[0], VSTREAM_ERR);
msg_syslog_init(argv[0], LOG_PID, LOG_FACILITY);
+ /*
+ * Check the Postfix library version as soon as we enable logging.
+ */
+ MAIL_VERSION_CHECK;
+
if ((config_dir = getenv(CONF_ENV_PATH)) != 0
&& strcmp(config_dir, DEF_CONFIG_DIR) != 0)
msg_fatal("Non-default configuration directory: %s=%s",
diff --git a/postfix/src/postqueue/postqueue.c b/postfix/src/postqueue/postqueue.c
index 4dfedabb7..d6ed5ccc4 100644
--- a/postfix/src/postqueue/postqueue.c
+++ b/postfix/src/postqueue/postqueue.c
@@ -477,6 +477,11 @@ int main(int argc, char **argv)
msg_syslog_init(mail_task("postqueue"), LOG_PID, LOG_FACILITY);
set_mail_conf_str(VAR_PROCNAME, var_procname = mystrdup(argv[0]));
+ /*
+ * Check the Postfix library version as soon as we enable logging.
+ */
+ MAIL_VERSION_CHECK;
+
/*
* Parse JCL. This program is set-gid and must sanitize all command-line
* parameters. The configuration directory argument is validated by the
diff --git a/postfix/src/postscreen/postscreen.c b/postfix/src/postscreen/postscreen.c
index d7307f8dc..3b79900b8 100644
--- a/postfix/src/postscreen/postscreen.c
+++ b/postfix/src/postscreen/postscreen.c
@@ -1121,7 +1121,7 @@ int main(int argc, char **argv)
VAR_PSC_NSMTP_TTL, DEF_PSC_NSMTP_TTL, &var_psc_nsmtp_ttl, 1, 0,
VAR_PSC_BARLF_TTL, DEF_PSC_BARLF_TTL, &var_psc_barlf_ttl, 1, 0,
VAR_PSC_CACHE_RET, DEF_PSC_CACHE_RET, &var_psc_cache_ret, 1, 0,
- VAR_PSC_CACHE_SCAN, DEF_PSC_CACHE_SCAN, &var_psc_cache_scan, 1, 0,
+ VAR_PSC_CACHE_SCAN, DEF_PSC_CACHE_SCAN, &var_psc_cache_scan, 0, 0,
VAR_PSC_WATCHDOG, DEF_PSC_WATCHDOG, &var_psc_watchdog, 10, 0,
0,
};
diff --git a/postfix/src/postscreen/postscreen_starttls.c b/postfix/src/postscreen/postscreen_starttls.c
index eb5d95a52..f9ad58bcd 100644
--- a/postfix/src/postscreen/postscreen_starttls.c
+++ b/postfix/src/postscreen/postscreen_starttls.c
@@ -229,6 +229,7 @@ void psc_starttls_open(PSC_STATE *smtp_state, EVENT_NOTIFY_FN resume_event)
ATTR_TYPE_STR, MAIL_ATTR_REMOTE_ENDPT, STR(remote_endpt),
ATTR_TYPE_INT, MAIL_ATTR_FLAGS, TLS_PROXY_FLAG_ROLE_SERVER,
ATTR_TYPE_INT, MAIL_ATTR_TIMEOUT, psc_normal_cmd_time_limit,
+ ATTR_TYPE_STR, MAIL_ATTR_SERVER_ID, MAIL_SERVICE_SMTPD, /* XXX */
ATTR_TYPE_END);
if (vstream_fflush(tlsproxy_stream) != 0) {
msg_warn("error sending request to %s service: %m", psc_tlsp_service);
diff --git a/postfix/src/postsuper/postsuper.c b/postfix/src/postsuper/postsuper.c
index fba2f1a39..7e3b2b98c 100644
--- a/postfix/src/postsuper/postsuper.c
+++ b/postfix/src/postsuper/postsuper.c
@@ -1137,6 +1137,11 @@ int main(int argc, char **argv)
msg_syslog_init(mail_task(argv[0]), LOG_PID, LOG_FACILITY);
set_mail_conf_str(VAR_PROCNAME, var_procname = mystrdup(argv[0]));
+ /*
+ * Check the Postfix library version as soon as we enable logging.
+ */
+ MAIL_VERSION_CHECK;
+
/*
* Disallow unsafe practices, and refuse to run set-uid (or as the child
* of a set-uid process). Whenever a privileged wrapper program is
diff --git a/postfix/src/sendmail/sendmail.c b/postfix/src/sendmail/sendmail.c
index a1a5dd792..9560f4840 100644
--- a/postfix/src/sendmail/sendmail.c
+++ b/postfix/src/sendmail/sendmail.c
@@ -1016,6 +1016,11 @@ int main(int argc, char **argv)
msg_syslog_init(mail_task("sendmail"), LOG_PID, LOG_FACILITY);
set_mail_conf_str(VAR_PROCNAME, var_procname = mystrdup(argv[0]));
+ /*
+ * Check the Postfix library version as soon as we enable logging.
+ */
+ MAIL_VERSION_CHECK;
+
/*
* Some sites mistakenly install Postfix sendmail as set-uid root. Drop
* set-uid privileges only when root, otherwise some systems will not
diff --git a/postfix/src/tlsproxy/tlsproxy.c b/postfix/src/tlsproxy/tlsproxy.c
index 8a0fd74d7..8195f1b01 100644
--- a/postfix/src/tlsproxy/tlsproxy.c
+++ b/postfix/src/tlsproxy/tlsproxy.c
@@ -692,7 +692,7 @@ static void tlsp_start_tls(TLSP_STATE *state)
timeout = 0, /* unused */
requirecert = (var_tlsp_tls_req_ccert
&& var_tlsp_enforce_tls),
- serverid = MAIL_SERVICE_SMTPD, /* XXX */
+ serverid = state->server_id,
namaddr = state->remote_endpt,
cipher_grade = cipher_grade,
cipher_exclusions = STR(cipher_exclusions),
@@ -775,6 +775,7 @@ static void tlsp_get_request_event(int event, char *context)
VSTREAM *plaintext_stream = state->plaintext_stream;
int plaintext_fd = vstream_fileno(plaintext_stream);
static VSTRING *remote_endpt;
+ static VSTRING *server_id;
int req_flags;
int timeout;
int ready;
@@ -782,8 +783,10 @@ static void tlsp_get_request_event(int event, char *context)
/*
* One-time initialization.
*/
- if (remote_endpt == 0)
+ if (remote_endpt == 0) {
remote_endpt = vstring_alloc(10);
+ server_id = vstring_alloc(10);
+ }
/*
* At this point we still manually manage plaintext read/write/timeout
@@ -803,7 +806,8 @@ static void tlsp_get_request_event(int event, char *context)
ATTR_TYPE_STR, MAIL_ATTR_REMOTE_ENDPT, remote_endpt,
ATTR_TYPE_INT, MAIL_ATTR_FLAGS, &req_flags,
ATTR_TYPE_INT, MAIL_ATTR_TIMEOUT, &timeout,
- ATTR_TYPE_END) != 3) {
+ ATTR_TYPE_STR, MAIL_ATTR_SERVER_ID, server_id,
+ ATTR_TYPE_END) != 4) {
msg_warn("%s: receive request attributes: %m", myname);
event_disable_readwrite(plaintext_fd);
tlsp_state_free(state);
@@ -835,6 +839,7 @@ static void tlsp_get_request_event(int event, char *context)
*/
else {
state->remote_endpt = mystrdup(STR(remote_endpt));
+ state->server_id = mystrdup(STR(server_id));
msg_info("CONNECT %s %s",
(req_flags & TLS_PROXY_FLAG_ROLE_SERVER) ? "from" :
(req_flags & TLS_PROXY_FLAG_ROLE_CLIENT) ? "to" :
diff --git a/postfix/src/tlsproxy/tlsproxy.h b/postfix/src/tlsproxy/tlsproxy.h
index 340e02fff..e3e1d11fa 100644
--- a/postfix/src/tlsproxy/tlsproxy.h
+++ b/postfix/src/tlsproxy/tlsproxy.h
@@ -32,6 +32,7 @@ typedef struct {
EVENT_NOTIFY_FN ciphertext_timer; /* kludge */
int timeout; /* read/write time limit */
char *remote_endpt; /* printable remote endpoint */
+ char *server_id; /* cache management */
TLS_SESS_STATE *tls_context; /* llibtls state */
int ssl_last_err; /* TLS I/O state */
} TLSP_STATE;
diff --git a/postfix/src/tlsproxy/tlsproxy_state.c b/postfix/src/tlsproxy/tlsproxy_state.c
index 1dcf5b889..1161b89f5 100644
--- a/postfix/src/tlsproxy/tlsproxy_state.c
+++ b/postfix/src/tlsproxy/tlsproxy_state.c
@@ -46,6 +46,9 @@
/* .IP remote_endpt
/* Printable remote endpoint name.
/* The destructor will automatically destroy the string.
+/* .IP server_id
+/* TLS session cache identifier.
+/* The destructor will automatically destroy the string.
/* DIAGNOSTICS
/* All errors are fatal.
/* LICENSE
@@ -103,6 +106,7 @@ TLSP_STATE *tlsp_state_create(const char *service,
state->ciphertext_timer = 0;
state->timeout = -1;
state->remote_endpt = 0;
+ state->server_id = 0;
state->tls_context = 0;
return (state);
@@ -126,6 +130,8 @@ void tlsp_state_free(TLSP_STATE *state)
msg_info("DISCONNECT %s", state->remote_endpt);
myfree(state->remote_endpt);
}
+ if (state->server_id)
+ myfree(state->server_id);
if (state->tls_context)
tls_free_context(state->tls_context);
myfree((char *) state);
diff --git a/postfix/src/util/Makefile.in b/postfix/src/util/Makefile.in
index 13c4048aa..7ecf8b319 100644
--- a/postfix/src/util/Makefile.in
+++ b/postfix/src/util/Makefile.in
@@ -33,7 +33,7 @@ SRCS = alldig.c allprint.c argv.c argv_split.c attr_clnt.c attr_print0.c \
allascii.c load_file.c killme_after.c vstream_tweak.c \
unix_pass_listen.c unix_pass_trigger.c edit_file.c inet_windowsize.c \
unix_pass_fd_fix.c dict_cache.c valid_utf_8.c dict_thash.c \
- ip_match.c nbbio.c stream_pass_connect.c base32_code.c
+ ip_match.c nbbio.c stream_pass_connect.c base32_code.c dict_test.c
OBJS = alldig.o allprint.o argv.o argv_split.o attr_clnt.o attr_print0.o \
attr_print64.o attr_print_plain.o attr_scan0.o attr_scan64.o \
attr_scan_plain.o auto_clnt.o base64_code.o basename.o binhash.o \
@@ -68,7 +68,7 @@ OBJS = alldig.o allprint.o argv.o argv_split.o attr_clnt.o attr_print0.o \
allascii.o load_file.o killme_after.o vstream_tweak.o \
unix_pass_listen.o unix_pass_trigger.o edit_file.o inet_windowsize.o \
unix_pass_fd_fix.o dict_cache.o valid_utf_8.o dict_thash.o \
- ip_match.o nbbio.o stream_pass_connect.o base32_code.o
+ ip_match.o nbbio.o stream_pass_connect.o base32_code.o dict_test.o
HDRS = argv.h attr.h attr_clnt.h auto_clnt.h base64_code.h binhash.h \
chroot_uid.h cidr_match.h clean_env.h connect.h ctable.h dict.h \
dict_cdb.h dict_cidr.h dict_db.h dict_dbm.h dict_env.h dict_ht.h \
@@ -1039,6 +1039,17 @@ dict_tcp.o: vbuf.h
dict_tcp.o: vstream.h
dict_tcp.o: vstring.h
dict_tcp.o: vstring_vstream.h
+dict_test.o: argv.h
+dict_test.o: dict.h
+dict_test.o: dict_test.c
+dict_test.o: msg.h
+dict_test.o: msg_vstream.h
+dict_test.o: stringops.h
+dict_test.o: sys_defs.h
+dict_test.o: vbuf.h
+dict_test.o: vstream.h
+dict_test.o: vstring.h
+dict_test.o: vstring_vstream.h
dict_thash.o: argv.h
dict_thash.o: dict.h
dict_thash.o: dict_thash.c
diff --git a/postfix/src/util/dict.c b/postfix/src/util/dict.c
index af41c7663..0731a2b87 100644
--- a/postfix/src/util/dict.c
+++ b/postfix/src/util/dict.c
@@ -401,12 +401,26 @@ void dict_load_file(const char *dict_name, const char *path)
void dict_load_fp(const char *dict_name, VSTREAM *fp)
{
+ const char *myname = "dict_load_fp";
VSTRING *buf;
char *member;
char *val;
int lineno;
const char *err;
struct stat st;
+ DICT_NODE *node;
+ DICT *dict;
+
+ /*
+ * Instantiate the dictionary even if the file is empty.
+ */
+ if ((node = dict_node(dict_name)) == 0) {
+ if (dict_unknown_allowed == 0)
+ msg_fatal("%s: unknown dictionary: %s", myname, dict_name);
+ dict = dict_ht_open(dict_name, O_CREAT | O_RDWR, 0);
+ dict_register(dict_name, dict);
+ } else
+ dict = node->dict;
buf = vstring_alloc(100);
lineno = 0;
@@ -417,11 +431,13 @@ void dict_load_fp(const char *dict_name, VSTREAM *fp)
if ((err = split_nameval(STR(buf), &member, &val)) != 0)
msg_fatal("%s, line %d: %s: \"%s\"",
VSTREAM_PATH(fp), lineno, err, STR(buf));
- dict_update(dict_name, member, val);
+ if (msg_verbose > 1)
+ msg_info("%s: %s = %s", myname, member, val);
+ dict->update(dict, member, val);
}
vstring_free(buf);
- dict_handle(dict_name)->owner.uid = st.st_uid;
- dict_handle(dict_name)->owner.status = (st.st_uid != 0);
+ dict->owner.uid = st.st_uid;
+ dict->owner.status = (st.st_uid != 0);
}
/* dict_eval_lookup - macro parser call-back routine */
diff --git a/postfix/src/util/dict.h b/postfix/src/util/dict.h
index e8449491d..36d49c89f 100644
--- a/postfix/src/util/dict.h
+++ b/postfix/src/util/dict.h
@@ -164,6 +164,11 @@ extern int dict_changed(void);
extern const char *dict_changed_name(void);
extern const char *dict_flags_str(int);
+ /*
+ * Driver for interactive or scripted tests.
+ */
+void dict_test(int, char **);
+
/* LICENSE
/* .ad
/* .fi
diff --git a/postfix/src/util/dict_open.c b/postfix/src/util/dict_open.c
index 766fa0098..d5ae3d5a0 100644
--- a/postfix/src/util/dict_open.c
+++ b/postfix/src/util/dict_open.c
@@ -382,135 +382,11 @@ ARGV *dict_mapnames()
#ifdef TEST
/*
- * Proof-of-concept test program. Create, update or read a database. When
- * the input is a name=value pair, the database is updated, otherwise the
- * program assumes that the input specifies a lookup key and prints the
- * corresponding value.
+ * Proof-of-concept test program.
*/
-
-/* System library. */
-
-#include
-#include
-#include
-#include
-
-/* Utility library. */
-
-#include "vstring.h"
-#include "vstream.h"
-#include "msg_vstream.h"
-#include "vstring_vstream.h"
-
-static NORETURN usage(char *myname)
-{
- msg_fatal("usage: %s type:file read|write|create [fold] [sync]", myname);
-}
-
int main(int argc, char **argv)
{
- VSTRING *keybuf = vstring_alloc(1);
- VSTRING *inbuf = vstring_alloc(1);
- DICT *dict;
- char *dict_name;
- int open_flags;
- char *bufp;
- char *cmd;
- const char *key;
- const char *value;
- int ch;
- int dict_flags = DICT_FLAG_LOCK | DICT_FLAG_DUP_REPLACE;
- int n;
-
- signal(SIGPIPE, SIG_IGN);
-
- msg_vstream_init(argv[0], VSTREAM_ERR);
- while ((ch = GETOPT(argc, argv, "v")) > 0) {
- switch (ch) {
- default:
- usage(argv[0]);
- case 'v':
- msg_verbose++;
- break;
- }
- }
- optind = OPTIND;
- if (argc - optind < 2)
- usage(argv[0]);
- if (strcasecmp(argv[optind + 1], "create") == 0)
- open_flags = O_CREAT | O_RDWR | O_TRUNC;
- else if (strcasecmp(argv[optind + 1], "write") == 0)
- open_flags = O_RDWR;
- else if (strcasecmp(argv[optind + 1], "read") == 0)
- open_flags = O_RDONLY;
- else
- msg_fatal("unknown access mode: %s", argv[2]);
- for (n = 2; argv[optind + n]; n++) {
- if (strcasecmp(argv[optind + 2], "fold") == 0)
- dict_flags |= DICT_FLAG_FOLD_ANY;
- else if (strcasecmp(argv[optind + 2], "sync") == 0)
- dict_flags |= DICT_FLAG_SYNC_UPDATE;
- else
- usage(argv[0]);
- }
- dict_name = argv[optind];
- dict = dict_open(dict_name, open_flags, dict_flags);
- dict_register(dict_name, dict);
- while (vstring_fgets_nonl(inbuf, VSTREAM_IN)) {
- bufp = vstring_str(inbuf);
- if (!isatty(0)) {
- vstream_printf("> %s\n", bufp);
- vstream_fflush(VSTREAM_OUT);
- }
- if (*bufp == '#')
- continue;
- if ((cmd = mystrtok(&bufp, " ")) == 0) {
- vstream_printf("usage: del key|get key|put key=value|first|next\n");
- vstream_fflush(VSTREAM_OUT);
- continue;
- }
- if (dict_changed_name())
- msg_warn("dictionary has changed");
- key = *bufp ? vstring_str(unescape(keybuf, mystrtok(&bufp, " ="))) : 0;
- value = mystrtok(&bufp, " =");
- if (strcmp(cmd, "del") == 0 && key && !value) {
- if (dict_del(dict, key))
- vstream_printf("%s: not found\n", key);
- else
- vstream_printf("%s: deleted\n", key);
- } else if (strcmp(cmd, "get") == 0 && key && !value) {
- if ((value = dict_get(dict, key)) == 0) {
- vstream_printf("%s: %s\n", key,
- dict_errno == DICT_ERR_RETRY ?
- "soft error" : "not found");
- } else {
- vstream_printf("%s=%s\n", key, value);
- }
- } else if (strcmp(cmd, "put") == 0 && key && value) {
- dict_put(dict, key, value);
- vstream_printf("%s=%s\n", key, value);
- } else if (strcmp(cmd, "first") == 0 && !key && !value) {
- if (dict_seq(dict, DICT_SEQ_FUN_FIRST, &key, &value) == 0)
- vstream_printf("%s=%s\n", key, value);
- else
- vstream_printf("%s\n",
- dict_errno == DICT_ERR_RETRY ?
- "soft error" : "not found");
- } else if (strcmp(cmd, "next") == 0 && !key && !value) {
- if (dict_seq(dict, DICT_SEQ_FUN_NEXT, &key, &value) == 0)
- vstream_printf("%s=%s\n", key, value);
- else
- vstream_printf("%s\n",
- dict_errno == DICT_ERR_RETRY ?
- "soft error" : "not found");
- } else {
- vstream_printf("usage: del key|get key|put key=value|first|next\n");
- }
- vstream_fflush(VSTREAM_OUT);
- }
- vstring_free(keybuf);
- vstring_free(inbuf);
- dict_close(dict);
+ dict_test(argc, argv);
return (0);
}
diff --git a/postfix/src/util/dict_test.c b/postfix/src/util/dict_test.c
new file mode 100644
index 000000000..e4f780b6a
--- /dev/null
+++ b/postfix/src/util/dict_test.c
@@ -0,0 +1,141 @@
+ /*
+ * Proof-of-concept test program. Create, update or read a database. When
+ * the input is a name=value pair, the database is updated, otherwise the
+ * program assumes that the input specifies a lookup key and prints the
+ * corresponding value.
+ */
+
+/* System library. */
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+/* Utility library. */
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+static NORETURN usage(char *myname)
+{
+ msg_fatal("usage: %s type:file read|write|create [fold] [sync]", myname);
+}
+
+void dict_test(int argc, char **argv)
+{
+ VSTRING *keybuf = vstring_alloc(1);
+ VSTRING *inbuf = vstring_alloc(1);
+ DICT *dict;
+ char *dict_name;
+ int open_flags;
+ char *bufp;
+ char *cmd;
+ const char *key;
+ const char *value;
+ int ch;
+ int dict_flags = DICT_FLAG_LOCK | DICT_FLAG_DUP_REPLACE;
+ int n;
+
+ signal(SIGPIPE, SIG_IGN);
+
+ msg_vstream_init(argv[0], VSTREAM_ERR);
+ while ((ch = GETOPT(argc, argv, "v")) > 0) {
+ switch (ch) {
+ default:
+ usage(argv[0]);
+ case 'v':
+ msg_verbose++;
+ break;
+ }
+ }
+ optind = OPTIND;
+ if (argc - optind < 2)
+ usage(argv[0]);
+ if (strcasecmp(argv[optind + 1], "create") == 0)
+ open_flags = O_CREAT | O_RDWR | O_TRUNC;
+ else if (strcasecmp(argv[optind + 1], "write") == 0)
+ open_flags = O_RDWR;
+ else if (strcasecmp(argv[optind + 1], "read") == 0)
+ open_flags = O_RDONLY;
+ else
+ msg_fatal("unknown access mode: %s", argv[2]);
+ for (n = 2; argv[optind + n]; n++) {
+ if (strcasecmp(argv[optind + 2], "fold") == 0)
+ dict_flags |= DICT_FLAG_FOLD_ANY;
+ else if (strcasecmp(argv[optind + 2], "sync") == 0)
+ dict_flags |= DICT_FLAG_SYNC_UPDATE;
+ else
+ usage(argv[0]);
+ }
+ dict_name = argv[optind];
+ dict = dict_open(dict_name, open_flags, dict_flags);
+ dict_register(dict_name, dict);
+ while (vstring_fgets_nonl(inbuf, VSTREAM_IN)) {
+ bufp = vstring_str(inbuf);
+ if (!isatty(0)) {
+ vstream_printf("> %s\n", bufp);
+ vstream_fflush(VSTREAM_OUT);
+ }
+ if (*bufp == '#')
+ continue;
+ if ((cmd = mystrtok(&bufp, " ")) == 0) {
+ vstream_printf("usage: del key|get key|put key=value|first|next\n");
+ vstream_fflush(VSTREAM_OUT);
+ continue;
+ }
+ if (dict_changed_name())
+ msg_warn("dictionary has changed");
+ key = *bufp ? vstring_str(unescape(keybuf, mystrtok(&bufp, " ="))) : 0;
+ value = mystrtok(&bufp, " =");
+ if (strcmp(cmd, "del") == 0 && key && !value) {
+ if (dict_del(dict, key))
+ vstream_printf("%s: not found\n", key);
+ else
+ vstream_printf("%s: deleted\n", key);
+ } else if (strcmp(cmd, "get") == 0 && key && !value) {
+ if ((value = dict_get(dict, key)) == 0) {
+ vstream_printf("%s: %s\n", key,
+ dict_errno == DICT_ERR_RETRY ?
+ "soft error" : "not found");
+ } else {
+ vstream_printf("%s=%s\n", key, value);
+ }
+ } else if (strcmp(cmd, "put") == 0 && key && value) {
+ /* XXX dict_put returns void, so dict_memcache sets dict_errno. */
+ dict_errno = 0;
+ dict_put(dict, key, value);
+ if (dict_errno)
+ vstream_printf("%s: soft error\n", key);
+ else
+ vstream_printf("%s=%s\n", key, value);
+ } else if (strcmp(cmd, "first") == 0 && !key && !value) {
+ if (dict_seq(dict, DICT_SEQ_FUN_FIRST, &key, &value) == 0)
+ vstream_printf("%s=%s\n", key, value);
+ else
+ vstream_printf("%s\n",
+ dict_errno == DICT_ERR_RETRY ?
+ "soft error" : "not found");
+ } else if (strcmp(cmd, "next") == 0 && !key && !value) {
+ if (dict_seq(dict, DICT_SEQ_FUN_NEXT, &key, &value) == 0)
+ vstream_printf("%s=%s\n", key, value);
+ else
+ vstream_printf("%s\n",
+ dict_errno == DICT_ERR_RETRY ?
+ "soft error" : "not found");
+ } else {
+ vstream_printf("usage: del key|get key|put key=value|first|next\n");
+ }
+ vstream_fflush(VSTREAM_OUT);
+ }
+ vstring_free(keybuf);
+ vstring_free(inbuf);
+ dict_close(dict);
+}
|