bounce/bounce_one_service.c, bounce/bounce_notify_verp.c,
bounce/bounce_warn_service.c, bounce/bounce_trace_service.c.
+ Fudge: when translating recipient DSN codes into sender DSN
+ codes, map sender address problems that have no DSN code
+ to *.1.7 (Bad sender's mailbox address syntax) instead of
+ *.1.0 (Other address status) because that loses the distinction
+ between sender and recipient. File: smtpd/smtpd_dsn_fix.c.
+
+20060113
+
+ Cleanup: preserve upper case information of address localpart
+ or extension when mapping one address to another with
+ non-regexp/pcre tables. Files: global/mail_addr_find.c,
+ global/maps_find.c.
+
+20060115
+
+ Bugfix: don't ignore the per-site policy when SSL library
+ initialization fails. Introduced after adopting the TLS
+ patch. File: smtp/smtp_session.c.
+
+20060117
+
+ Safety: daemon processes that need no privileges now insist
+ that they are configured to run without privileges. Files:
+ master/single_server.c, master/multi_server.c,
+ master/trigger_server.c.
+
+ Cleanup: preserve upper case information of address localpart
+ or extension when mapping addresses via regexp/pcre tables.
+ This requires that Postfix does not case fold the search
+ string when searching regexp or pcre tables, so that $number
+ substitutions produce the expected result.
+
+ In order to get a consistent handling of table operations,
+ the search string case folding logic was moved from the
+ application to the individual lookup table modules; the
+ application specifies its case folding preference when it
+ opens a table, and the table folds the search or update
+ string as needed.
+
+ Files: everything that opens a map or multiple maps (to
+ specify the case folding preference), and everything that
+ contained ad-hoc code to lowercase search strings (which
+ is no longer needed).
+
+ Bugfix: as a side effect of this revision of all code that
+ opens tables, the postmap/postalias -n/-N options are no
+ longer silently ignored when the -q (query) and -d (delete)
+ options are specified. Files: postmap/postmap.c,
+ postalias/postalias.c.
+
+ Cleanup: smtp_sasl_passwd_maps lookup keys are folded to
+ lowercase before searching tables such as btree:, dbm: or
+ hash: that have fixed-case fields. File: smtp/smtp_sasl_glue.c.
+
+ Bugfix: per-sender relayhost maps were not locked for shared
+ access.
+
+20060119
+
+ Cleanup: don't look up parent domain substrings in regexp/pcre
+ like tables while searching a hostname in a domain/namaddr_list.
+ File: util/match_ops.c.
+
+20060120
+
+ Cleanup: multiple boolean variables were replaced by a
+ single TLS enforcement level (none, may, encrypt, verify).
+ With Victor Duchovni. Files: smtp_session.c, smtp_proto.c,
+ smtp.h.
+
+ Cleanup: the SMTP per-site policy table was re-implemented
+ in terms of enforcement levels instead of multiple boolean
+ variables. This greatly simplified the code and led to the
+ elimination of non-intuitive behavior as documented next.
+ With Victor Duchovni. Files: smtp_session.c, smtp.h.
+
+ Bugfix: a per-site MUST_NOPEERMATCH policy could not override
+ a main.cf MUST (with peer match) policy.
+
+ Bugfix: a combined TLS per-site (host, next-hop) policy of
+ (NONE, MAY) would change the strongest main.cf MUST policy
+ into NONE, while it changed all weaker main.cf policies
+ into MAY. The result is now NONE for all main.cf policy
+ settings.
+
+20060123
+
+ Feature: recipient_count attribute in SMTPD policy protocol.
+ This is available only in the DATA and END-OF-MESSAGE stage.
+ Based on code by Guo Black. Files: smtpd_check.c.
+
+ Cleanup: renamed MUMBLE_NUM to MUMBLE_INT to make type
+ discrepancies more explicit.
+
+ Bugfix: change 20051208 broke when a connection could not
+ be established. File: util/auto_clnt.c.
+
Open problems:
+ Centralize main.cf parameter input so that defaults work
+ consistently.
+
+ In second-line servers such as proxymap and trivial-rewrite,
+ set the max_idle time limit to a relatively small value so
+ that processes will refresh more often.
+
+ After the 20051222 ISASCII paranoia, lowercase() lowercases
+ ASCII text only.
+
Privacy: remove local command/pathname details from remote
delivery status reports, and log them via local msg_warn().
Remove defer(8) and trace(8) references and man pages. These
are services not program names.
+ dsb_formal -> dsb_form_all, dsb_status -> dsb_form_status
+
"postsuper -r" no longer resets the message arrival time,
because pickup(8) no longer overrides queue file time stamp
information. This can be a problem when mail "on hold" is
deferred queue scan needs to be done, and have the pickup
server stat() the maildrop directory before searching it.
- Mapping from errno to diagnostic text. Or do we just slap
- an SMTP code in front of what is now reported as X-Postfix.
- Or do we punt the issue and issue X-Postfix for all errors
- except SMTP?
-
Low: replace_sender/replace_recipient actions in access
maps?
Med: the TLS certificate verification depth parameters never
worked.
- Med: eliminate the tls_info data structure.
-
Low: reject HELO with any domain name or IP address that
this MTA is the final destination for.
Tinycdb is preferred, since it is a bit faster, has additional useful
functionality and is much simpler to use.
-To build Postfix after you have installed CDB, use something like:
+To build Postfix after you have installed tinycdb, use something like:
% make tidy
% CDB=../../../tinycdb-0.5
"AUXLIBS=$CDB/libcdb.a"
% make
- for tinycdb, or alternatively, for the D.J.B. version:
+Alternatively, for the D.J.B. version of CDB:
% make tidy
% CDB=../../../cdb-0.75
Network -> smtpd(8) <-> anvil(8)
- * The bounce(8) server implements the bounce, defer and trace services, which
- maintain separate directory trees with per-message logfiles. This
- information is used to send delivery or non-delivery notifications to the
- sender.
+ * The bounce(8), defer(8) and trace(8) servers each maintain their own queue
+ directory trees with per-message logfiles. This information is used to send
+ delivery or non-delivery notifications to the sender.
- The trace service implements support for the Postfix "sendmail -bv" and
+ The trace(8) service implements support for the Postfix "sendmail -bv" and
"sendmail -v" commands which produce reports about how Postfix delivers
mail, and is available with Postfix version 2.1 and later. See DEBUG_README
for examples.
| v v
(Non-) bounce(8) Queue id,
- delivery <- defer <- recipient,
- notice trace status
+ delivery <- defer(8) <- recipient,
+ notice trace(8) status
^ |
| v
queue_id=8045F2AB23
sender=foo@bar.tld
recipient=bar@foo.tld
+ recipient_count=0
client_address=1.2.3.4
client_name=another.domain.tld
reverse_client_name=another.domain.tld
the first value or the last attribute value.
* When an attribute value is unavailable, the client either does not send the
- attribute, or sends the attribute with an empty value ("name=").
+ attribute, sends the attribute with an empty value ("name="), or sends a
+ zero value ("name=0") in the case of a numerical attribute.
+
+ * The "recipient" attribute is available only in the "RCPT TO" stage, and in
+ the "DATA" and "END-OF-MESSAGE" stages when Postfix accepted only one
+ recipient for the current message.
+
+ * The "recipient_count" attribute (Postfix 2.3 and later) is non-zero only in
+ the "DATA" and "END-OF-MESSAGE" stages. It specifies the number of
+ recipients that Postfix accepted for the current message.
* The client address is an IPv4 dotted quad in the form 1.2.3.4 or it is an
IPv6 address in the form 1:2:3::4:5:6.
with the necessary definitions. This is done by invoking the command "make
makefiles" in the Postfix top-level directory and with arguments as shown next.
+N\bNO\bOT\bTE\bE:\b: D\bDo\bo n\bno\bot\bt u\bus\bse\be G\bGn\bnu\bu T\bTL\bLS\bS.\b. I\bIt\bt w\bwi\bil\bll\bl s\bsp\bpo\bon\bnt\bta\ban\bne\beo\bou\bus\bsl\bly\by t\bte\ber\brm\bmi\bin\bna\bat\bte\be a\ba p\bpr\bro\boc\bce\bes\bss\bs w\bwi\bit\bth\bh e\bex\bxi\bit\bt
+s\bst\bta\bat\btu\bus\bs c\bco\bod\bde\be 2\b2,\b, i\bin\bns\bst\bte\bea\bad\bd o\bof\bf p\bpr\bro\bop\bpe\ber\brl\bly\by r\bre\bep\bpo\bor\brt\bti\bin\bng\bg p\bpr\bro\bob\bbl\ble\bem\bms\bs t\bto\bo P\bPo\bos\bst\btf\bfi\bix\bx,\b, s\bso\bo t\bth\bha\bat\bt i\bit\bt
+c\bca\ban\bn l\blo\bog\bg t\bth\bhe\bem\bm t\bto\bo t\bth\bhe\be m\bma\bai\bil\bll\blo\bog\bg f\bfi\bil\ble\be.\b.
+
* If the OpenSSL include files (such as ssl.h) are in directory /usr/include/
openssl, and the OpenSSL libraries (such as libssl.so and libcrypto.so) are
in directory /usr/lib:
* Client-side TLS activity logging
* Client-side TLS session cache
* Enabling TLS in the Postfix SMTP client
- * Server certificate verification
+ * Requiring TLS encryption
+ * Disabling server certificate verification
+ * Per-site TLS policies
+ * Closing a DNS loophole with per-site TLS policies
+ * Discovering servers that support TLS
+ * Server certificate verification depth
* Client-side cipher controls
* Miscellaneous client controls
issued by these CAs, append the root certificate to $smtp_tls_CAfile or install
it in the $smtp_tls_CApath directory. When you configure trust in a root CA, it
is not necessary to explicitly trust intermediary CAs signed by the root CA,
-unless $smtp_tls_verify_depth is less than the number of CAs in the certificate
-chain for the servers of interest. With a verify depth of 1 you can only verify
-certificates directly signed by a trusted CA, and all trusted intermediary CAs
-need to be configured explicitly. With a verify depth of 2 you can verify
-servers signed by a root CA or a direct intermediary CA (so long as the server
-is correctly configured to supply its intermediate CA certificate).
+unless $smtp_tls_scert_verifydepth is less than the number of CAs in the
+certificate chain for the servers of interest. With a verify depth of 1 you can
+only verify certificates directly signed by a trusted CA, and all trusted
+intermediary CAs need to be configured explicitly. With a verify depth of 2 you
+can verify servers signed by a root CA or a direct intermediary CA (so long as
+the server is correctly configured to supply its intermediate CA certificate).
RSA key and certificate examples:
plain Postfix is visible. If you enable TLS, the Postfix SMTP client will send
STARTTLS when TLS support is announced by the remote SMTP server.
-WARNING: MS Exchange servers will announce STARTTLS support even when the
-service is not configured, so that the TLS handshake will fail. It may be wise
-to not use this option on your central mail hub, as you don't know in advance
-whether you are going to connect to such a host. Instead, use the
-smtp_tls_per_site recipient/site specific options that are described below.
-
-When the TLS handshake fails and no other server is available, the Postfix SMTP
-client defers the delivery attempt, and the mail stays in the queue.
+When the server accepts the STARTTLS command, but the subsequent TLS handshake
+fails, and no other server is available, the Postfix SMTP client defers the
+delivery attempt, and the mail stays in the queue. After a handshake failure,
+the communications channel is in an indeterminate state and cannot be used for
+non-TLS deliveries.
Example:
/etc/postfix/main.cf:
smtp_use_tls = yes
+R\bRe\beq\bqu\bui\bir\bri\bin\bng\bg T\bTL\bLS\bS e\ben\bnc\bcr\bry\byp\bpt\bti\bio\bon\bn
+
You can ENFORCE the use of TLS, so that the Postfix SMTP client will not
deliver mail over unencrypted connections. In this mode, the remote SMTP server
hostname must match the information in the remote server certificate, and the
server hostname doesn't match, and no other server is available, the delivery
attempt is deferred and the mail stays in the queue.
-The remote SMTP server hostname used in the check is beyond question, as it
-must be the principal hostname (no CNAME allowed here). Checks are performed
-against all names provided as dNSNames in the SubjectAlternativeName. If no
-dNSNames are specified, the CommonName is checked. The behavior may be changed
-with the smtp_tls_enforce_peername option which is discussed below.
+The remote SMTP server hostname is verified against all names provided as
+dNSNames in the SubjectAlternativeName. If no dNSNames are specified, the
+CommonName is checked. Verification may be turned off with the
+smtp_tls_enforce_peername option which is discussed below.
-This option is useful only if you know that you will only connect to servers
-that support RFC 2487 _and_ that present server certificates that meet the
-above requirements. An example would be a client only sends email to one
+Enforcing the use of TLS is useful if you know that you will only connect to
+servers that support RFC 2487 _and_ that present server certificates that meet
+the above requirements. An example would be a client only sends email to one
specific mailhub that offers the necessary STARTTLS support.
Example:
/etc/postfix/main.cf:
- smtp_enforce_tls = no
+ smtp_enforce_tls = yes
+
+D\bDi\bis\bsa\bab\bbl\bli\bin\bng\bg s\bse\ber\brv\bve\ber\br c\bce\ber\brt\bti\bif\bfi\bic\bca\bat\bte\be v\bve\ber\bri\bif\bfi\bic\bca\bat\bti\bio\bon\bn
As of RFC 2487 the requirements for hostname checking for MTA clients are not
set. When TLS is required (smtp_enforce_tls = yes), the option
server hostname checking. In this case, the mail delivery will proceed
regardless of the CommonName etc. listed in the certificate.
-Note: the smtp_tls_enforce_peername setting has no effect on sessions that are
-controlled via the smtp_tls_per_site table.
-
-Disabling the remote SMTP server hostname verification can make sense in closed
-environment where special CAs are created. If not used carefully, this option
-opens the danger of a "man-in-the-middle" attack (the CommonName of this
-possible attacker is logged).
+Despite the potential for eliminating "man-in-the-middle" and other attacks,
+mandatory certificate/peername verification is not viable as a default Internet
+mail delivery policy at this time. A significant fraction of TLS enabled MTAs
+uses self-signed certificates, or certificates that are signed by a private
+certificate authority. On a machine that delivers mail to the Internet, if you
+set smtp_enforce_tls = yes, you should probably also set
+smtp_tls_enforce_peername = no. You can use the per-site TLS policies (see
+below) to enable full peer verification for specific destinations that are
+known to have verifiable TLS server certificates.
Example:
/etc/postfix/main.cf:
- smtp_tls_enforce_peername = yes
-
-Generally, trying TLS can be a bad idea, as some servers offer STARTTLS but the
-negotiation will fail leading to unexplainable failures. Instead, it may be a
-good idea to choose the TLS usage policy based on the recipient or the mailhub
-to which you are connecting.
-
-Deciding the TLS usage policy per recipient may be difficult, since a single
-email delivery attempt can involve several recipients. Instead, use of TLS is
-controlled by the Postfix next-hop destination domain name and by the remote
-SMTP server hostname. If either of these matches an entry in the
-smtp_tls_per_site table, appropriate action is taken.
-
-The remote SMTP server hostname is simply the DNS name of the server that the
-Postfix SMTP client connects to. The next-hop destination is Postfix specific.
-By default, this is the domain name in the recipient address, but this
-information can be overruled by the transport(5) table or by the relayhost
-parameter setting. In these cases the relayhost etc. must be listed in the
-smtp_tls_per_site table, instead of the recipient domain name.
-
-Format of the table: domain or host names are specified on the left-hand side;
-no wildcards are allowed. On the right hand side specify one of the following
-keywords:
+ smtp_enforce_tls = yes
+ smtp_tls_enforce_peername = no
+
+P\bPe\ber\br-\b-s\bsi\bit\bte\be T\bTL\bLS\bS p\bpo\bol\bli\bic\bci\bie\bes\bs
+
+A small fraction of servers offer STARTTLS but the negotiation consistently
+fails, leading to mail aging out of the queue and bouncing back to the sender.
+In such cases, you can use the per-site policies to disable TLS for the problem
+sites. Alternatively, you can enable TLS for just a few specific sites and not
+enable it for all sites.
+
+The smtp_tls_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.
+ next-hop destination
+ This is normally the domain portion of the recipient address, but it
+ may be overruled by information from the transport(5) table, from the
+ relayhost parameter setting, or from the relay_transport setting. When
+ it's not the recipient domain, the next-hop destination can have the
+ Postfix-specific form "[name]", [name]:port", "name" or "name:port".
+
+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
- Don't use TLS at all.
+ Don't use TLS at all. This overrides a less specific M\bMA\bAY\bY 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
- Try to use STARTTLS if offered, otherwise use the unencrypted
- connection.
+ Try to use TLS if the server announces support, otherwise use the
+ unencrypted connection. This has less precedence than a more specific
+ result (including N\bNO\bON\bNE\bE) 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
+ Require TLS encryption, but do not require that the remote SMTP server
+ hostname matches the information in the remote SMTP server certificate,
+ or that the server certificate was issued by a trusted CA. This
+ overrides a less secure N\bNO\bON\bNE\bE or a less specific M\bMA\bAY\bY 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
- Require usage of STARTTLS, require that the remote SMTP server hostname
+ Require TLS encryption, require that the remote SMTP server hostname
matches the information in the remote SMTP server certificate, and
require that the remote SMTP server certificate was issued by a trusted
- CA.
- MUST_NOPEERMATCH
- Require usage of STARTTLS, but do not require that the remote SMTP
- server hostname matches the information in the remote SMTP server
- certificate, or that the server certificate was issued by a trusted CA.
+ CA. This overrides a less secure N\bNO\bON\bNE\bE and M\bMU\bUS\bST\bT_\b_N\bNO\bOP\bPE\bEE\bER\bRM\bMA\bAT\bTC\bCH\bH or a less
+ specific M\bMA\bAY\bY 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 M\bMA\bAY\bY 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.
+
+C\bCl\blo\bos\bsi\bin\bng\bg a\ba D\bDN\bNS\bS l\blo\boo\bop\bph\bho\bol\ble\be w\bwi\bit\bth\bh p\bpe\ber\br-\b-s\bsi\bit\bte\be T\bTL\bLS\bS p\bpo\bol\bli\bic\bci\bie\bes\bs
+
+As long as no secure DNS lookup mechanism is available, false hostnames may
+appear in MX or CNAME responses. 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 the following steps:
+
+ * Eliminate MX lookups. Specify local transport(5) table entries for
+ sensitive domains with explicit smtp:[mailhost] or smtp:[mailhost]:port
+ destinations (you can assure security of this table unlike DNS); in the
+ smtp_tls_per_site table specify the value M\bMU\bUS\bST\bT for the key [mailhost] or
+ smtp:[mailhost]:port. This prevents false hostname information in DNS MX
+ records from changing the server hostname that Postfix uses for TLS policy
+ lookup and server certificate verification.
+
+ * 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 actual TLS usage policy depends not only on whether the next-hop
-destination or remote SMTP server hostname are found in the smtp_tls_per_site
-table, but also on the smtp_enforce_tls setting:
+Example:
- * If no match was found, the policy is applied as specified with
- smtp_enforce_tls.
+ /etc/postfix/main.cf:
+ smtp_tls_per_site = hash:/etc/postfix/tls_per_site
+ relayhost = [msa.example.net]:587
- * If a match was found, and the smtp_enforce_tls policy is "enforce", NONE
- explicitly switches it off; otherwise the "enforce" mode is used even for
- entries that specify MAY.
+ /etc/postfix/tls_per_site:
+ # relayhost exact nexthop match
+ [msa.example.net]:587 MUST
-Special hint for TLS enforcement mode: since no secure DNS lookup mechanism is
-available, mail can be delivered to the wrong remote SMTP server. This is not
-prevented by specifying MUST for the next-hop domain name. The recommended
-setup is: specify local transport(5) table entries for sensitive domains with
-explicit smtp:[mailhost] destinations (since you can assure security of this
-table unlike DNS), then specify MUST for these mail hosts in the
-smtp_tls_per_site table.
+ # example.org (as nexthop) has MX hosts with broken TLS.
+ example.org NONE
-Example:
+ # Except for (as host) mx1.example.org which works.
+ mx1.example.org MAY
- /etc/postfix/main.cf:
- smtp_tls_per_site = hash:/etc/postfix/tls_per_site
+D\bDi\bis\bsc\bco\bov\bve\ber\bri\bin\bng\bg s\bse\ber\brv\bve\ber\brs\bs t\bth\bha\bat\bt s\bsu\bup\bpp\bpo\bor\brt\bt T\bTL\bLS\bS
As we decide on a "per site" basis whether or not to use TLS, it would be good
to have a list of sites that offered "STARTTLS". We can collect it ourselves
/etc/postfix/main.cf:
smtp_tls_note_starttls_offer = yes
-S\bSe\ber\brv\bve\ber\br c\bce\ber\brt\bti\bif\bfi\bic\bca\bat\bte\be v\bve\ber\bri\bif\bfi\bic\bca\bat\bti\bio\bon\bn
+S\bSe\ber\brv\bve\ber\br c\bce\ber\brt\bti\bif\bfi\bic\bca\bat\bte\be v\bve\ber\bri\bif\bfi\bic\bca\bat\bti\bio\bon\bn d\bde\bep\bpt\bth\bh
When verifying a remote SMTP server certificate, a verification depth of 1 is
sufficient if the certificate is directly issued by a CA specified with
and in order to access the TLS session cache databases. Such a protocol
cannot be run across fifos.
+ * smtp_tls_per_site: the MUST_NOPEERMATCH per-site policy cannot override the
+ global "smtp_tls_enforce_peername = yes" setting.
+
+ * smtp_tls_per_site: a combined (NONE + MAY) lookup result for (hostname and
+ next-hop destination) produces counter-intuitive results for different
+ main.cf settings. TLS is enabled with "smtp_tls_enforce_peername = no", but
+ it is disabled when both "smtp_enforce_tls = yes" and
+ "smtp_tls_enforce_peername = yes".
+
+The smtp_tls_per_site limitations were removed by the end of the Postfix 2.2
+support cycle.
+
C\bCr\bre\bed\bdi\bit\bts\bs
* TLS support for Postfix was originally developed by Lutz Jänicke at Cottbus
Technical University.
* Wietse Venema adopted the code, did some restructuring, and compiled this
part of the documentation from Lutz's documents.
+ * Victor Duchovni was instrumental with the re-implementation of the
+ smtp_tls_per_site code in terms of enforcement levels, which simplified the
+ implementation greatly.
If you upgrade from Postfix 2.1 or earlier, read RELEASE_NOTES-2.2
before proceeding.
+Incompatibility with snapshot 20060123
+======================================
+
+Postfix now preserves uppercase information while mapping addresses
+with canonical, virtual, relocated or generic maps; this happens
+even with lookups from regular expression maps. However, the local(8)
+and virtual(8) delivery agents still fold addresses to lower case.
+
+By default, Postfix now folds the search string to lowercase only
+with tables that have fixed-case lookup fields such as btree:,
+hash:, dbm:, ldap:, or *sql:. The search string is no longer case
+folded with tables whose lookup fields can match both upper or lower
+case, such as regexp:, pcre:, or cidr:.
+
+For safety reasons, Postfix no longer allows $number substitution
+in regexp: or pcre: transport tables or per-sender relayhost tables.
+
+For safety reasons, daemons that don't need privileges now insist
+that they are configured as unprivileged in master.cf.
+
+Major changes with snapshot 20060123
+====================================
+
+Postfix now does a better job at preserving upper/lower case
+information while transforming addresses. The table lookup code
+was revised, and is now more careful about when it folds search
+strings to lower case. As a side effect, Postfix now also does a
+better job at being case insensitive where it should, for example
+while searching per-host TLS policies or SASL passwords.
+
+Some obscure behavior was eliminated from the smtp_tls_per_site
+feature, without changes to the user interface. some Postfix internals
+had to be re-structured in preparation for a more general TLS policy
+mechanism; this required that smtp_tls_per_site be re-implemented
+from scratch.
+
+Postfix 2.3 is expected to provide a new per-site TLS policy mechanism
+that eliminates DNS spoofing attacks more effectively; the legacy
+smtp_tls_per_site feature will be kept intact for a few releases
+so that sites can upgrade Postfix without being forced to use a
+different TLS policy mechanism.
+
Incompatibility with snapshot 20060112
======================================
The Postfix SMTP/LMTP client by default no longer allows DNS CNAME
records to override the server hostname that is used for logging,
SASL password lookup, TLS policy selection and TLS server certificate
-verification. Specify "smtp_cname_overrides_servername = no" to get
+verification. Specify "smtp_cname_overrides_servername = yes" to get
the old behavior.
Postfix DSN reports no longer make up their own surrogate SMTP
<p> Tinycdb is preferred, since it is a bit faster, has additional
useful functionality and is much simpler to use. </p>
-<p>To build Postfix after you have installed CDB, use something
+<p>To build Postfix after you have installed tinycdb, use something
like: </p>
<blockquote>
"AUXLIBS=$CDB/libcdb.a"
% make
</pre>
-for tinycdb, or alternatively, for the D.J.B. version:<br>
+</blockquote>
+
+<p> Alternatively, for the D.J.B. version of CDB:<p>
+
+<blockquote>
<pre>
% make tidy
% CDB=../../../cdb-0.75
deliver mail, and for restarting servers that terminate prematurely
because of some problem. The <a href="master.8.html">master(8)</a> server is also responsible
for enforcing the server process count limits as specified in the
-<b>master.cf</b> configuration file. The picture below gives the
+<a href="master.5.html"><b>master.cf</b></a> configuration file. The picture below gives the
program hierarchy when Postfix is started up. Only some of the mail
handling daemon processes are shown. </p>
is likely to be superseded by something more powerful that can also
edit Postfix queue files. </p>
-<li> <p> The <a href="postconf.1.html">postconf(1)</a> command displays or updates Postfix main.cf
+<li> <p> The <a href="postconf.1.html">postconf(1)</a> command displays or updates Postfix <a href="postconf.5.html">main.cf</a>
parameters and displays system dependent information about the
supported file locking methods, and the supported types of lookup
tables. </p>
queue_id=8045F2AB23
sender=foo@bar.tld
recipient=bar@foo.tld
+recipient_count=0
client_address=1.2.3.4
client_name=another.domain.tld
reverse_client_name=another.domain.tld
</p>
<li> <p> When an attribute value is unavailable, the client
- either does not send the attribute, or sends the attribute with
- an empty value ("name="). </p>
+ either does not send the attribute, sends the attribute with
+ an empty value ("name="), or sends a zero value ("name=0") in
+ the case of a numerical attribute. </p>
+
+ <li> <p> The "recipient" attribute is available only in the
+ "RCPT TO" stage, and in the "DATA" and "END-OF-MESSAGE" stages
+ when Postfix accepted only one recipient for the current message.
+ </p>
+
+ <li> <p> The "recipient_count" attribute (Postfix 2.3 and later)
+ is non-zero only in the "DATA" and "END-OF-MESSAGE" stages. It
+ specifies the number of recipients that Postfix accepted for
+ the current message. </p>
<li> <p> The client address is an IPv4 dotted quad in the form
1.2.3.4 or it is an IPv6 address in the form 1:2:3::4:5:6.
<blockquote>
<pre>
- 1 /etc/postfix/master.cf:
+ 1 /etc/postfix/<a href="master.5.html">master.cf</a>:
2 policy unix - n n - - spawn
3 user=nobody argv=/some/where/policy-server
4
- 5 /etc/postfix/main.cf:
+ 5 /etc/postfix/<a href="postconf.5.html">main.cf</a>:
6 <a href="postconf.5.html#smtpd_recipient_restrictions">smtpd_recipient_restrictions</a> =
7 ...
8 <a href="postconf.5.html#reject_unauth_destination">reject_unauth_destination</a>
its child process after 1000 seconds. This is too short for a
policy daemon that may run for as long as an SMTP client is connected
to an SMTP server process. The default time limit is overruled in
-main.cf with an explicit "policy_time_limit" setting. The name of
-the parameter is the name of the master.cf entry ("policy")
+<a href="postconf.5.html">main.cf</a> with an explicit "policy_time_limit" setting. The name of
+the parameter is the name of the <a href="master.5.html">master.cf</a> entry ("policy")
concatenated with the "_time_limit" suffix. </p>
<li> <p> Lines 8, 9: always specify "<a href="postconf.5.html#check_policy_service">check_policy_service</a>" AFTER
<blockquote>
<pre>
- 1 /etc/postfix/master.cf:
+ 1 /etc/postfix/<a href="master.5.html">master.cf</a>:
2 127.0.0.1:9998 inet n n n - - spawn
3 user=nobody argv=/some/where/policy-server
4
- 5 /etc/postfix/main.cf:
+ 5 /etc/postfix/<a href="postconf.5.html">main.cf</a>:
6 <a href="postconf.5.html#smtpd_recipient_restrictions">smtpd_recipient_restrictions</a> =
7 ...
8 <a href="postconf.5.html#reject_unauth_destination">reject_unauth_destination</a>
<p> The /var/mta directory (or whatever you choose) should be
writable by "nobody", or by whatever username you configure below
-in master.cf for the policy service. </p>
+in <a href="master.5.html">master.cf</a> for the policy service. </p>
<p> Example: </p>
<blockquote>
<pre>
-1 /etc/postfix/master.cf:
+1 /etc/postfix/<a href="master.5.html">master.cf</a>:
2 policy unix - n n - - spawn
3 user=nobody argv=/usr/bin/perl /usr/libexec/postfix/greylist.pl
4
-5 /etc/postfix/main.cf:
+5 /etc/postfix/<a href="postconf.5.html">main.cf</a>:
6 policy_time_limit = 3600
</pre>
</blockquote>
its child process after 1000 seconds. This is too short for a
policy daemon that may run for as long as an SMTP client is connected
to an SMTP server process. The default time limit is overruled in
-main.cf with an explicit "policy_time_limit" setting. The name of
-the parameter is the name of the master.cf entry ("policy")
+<a href="postconf.5.html">main.cf</a> with an explicit "policy_time_limit" setting. The name of
+the parameter is the name of the <a href="master.5.html">master.cf</a> entry ("policy")
concatenated with the "_time_limit" suffix. </p>
</ul>
<blockquote>
<pre>
-1 /etc/postfix/master.cf:
+1 /etc/postfix/<a href="master.5.html">master.cf</a>:
2 127.0.0.1:9998 inet n n n - - spawn
3 user=nobody argv=/usr/bin/perl /usr/libexec/postfix/greylist.pl
4
-5 /etc/postfix/main.cf:
+5 /etc/postfix/<a href="postconf.5.html">main.cf</a>:
6 127.0.0.1:9998_time_limit = 3600
</pre>
</blockquote>
<blockquote>
<pre>
- 1 /etc/postfix/main.cf:
+ 1 /etc/postfix/<a href="postconf.5.html">main.cf</a>:
2 <a href="postconf.5.html#smtpd_recipient_restrictions">smtpd_recipient_restrictions</a> =
3 <a href="postconf.5.html#reject_unlisted_recipient">reject_unlisted_recipient</a>
4 ...
<blockquote>
<pre>
- 1 /etc/postfix/main.cf:
+ 1 /etc/postfix/<a href="postconf.5.html">main.cf</a>:
2 <a href="postconf.5.html#smtpd_recipient_restrictions">smtpd_recipient_restrictions</a> =
3 <a href="postconf.5.html#reject_unlisted_recipient">reject_unlisted_recipient</a>
4 ...
done by invoking the command "<tt>make makefiles</tt>" in the Postfix
top-level directory and with arguments as shown next. </p>
+<p> <b> NOTE: Do not use Gnu TLS. It will spontaneously terminate
+a process with exit status code 2, instead of properly reporting
+problems to Postfix, so that it can log them to the maillog file.
+</b> </p>
+
<ul>
<li> <p> If the OpenSSL include files (such as <tt>ssl.h</tt>) are
<blockquote>
<pre>
-/etc/postfix/main.cf:
+/etc/postfix/<a href="postconf.5.html">main.cf</a>:
<a href="postconf.5.html#smtpd_tls_cert_file">smtpd_tls_cert_file</a> = /etc/postfix/server.pem
<a href="postconf.5.html#smtpd_tls_key_file">smtpd_tls_key_file</a> = $<a href="postconf.5.html#smtpd_tls_cert_file">smtpd_tls_cert_file</a>
</pre>
<blockquote>
<pre>
-/etc/postfix/main.cf:
+/etc/postfix/<a href="postconf.5.html">main.cf</a>:
<a href="postconf.5.html#smtpd_tls_dcert_file">smtpd_tls_dcert_file</a> = /etc/postfix/server-dsa.pem
<a href="postconf.5.html#smtpd_tls_dkey_file">smtpd_tls_dkey_file</a> = $<a href="postconf.5.html#smtpd_tls_dcert_file">smtpd_tls_dcert_file</a>
</pre>
<p> Example: </p>
<blockquote>
<pre>
-/etc/postfix/main.cf:
+/etc/postfix/<a href="postconf.5.html">main.cf</a>:
<a href="postconf.5.html#smtpd_tls_CAfile">smtpd_tls_CAfile</a> = /etc/postfix/CAcert.pem
<a href="postconf.5.html#smtpd_tls_CApath">smtpd_tls_CApath</a> = /etc/postfix/certs
</pre>
<blockquote>
<pre>
-/etc/postfix/main.cf:
+/etc/postfix/<a href="postconf.5.html">main.cf</a>:
<a href="postconf.5.html#smtpd_tls_loglevel">smtpd_tls_loglevel</a> = 0
</pre>
</blockquote>
<blockquote>
<pre>
-/etc/postfix/main.cf:
+/etc/postfix/<a href="postconf.5.html">main.cf</a>:
<a href="postconf.5.html#smtpd_tls_received_header">smtpd_tls_received_header</a> = yes
</pre>
</blockquote>
<blockquote>
<pre>
-/etc/postfix/main.cf:
+/etc/postfix/<a href="postconf.5.html">main.cf</a>:
<a href="postconf.5.html#smtpd_use_tls">smtpd_use_tls</a> = yes
</pre>
</blockquote>
<blockquote>
<pre>
-/etc/postfix/main.cf:
+/etc/postfix/<a href="postconf.5.html">main.cf</a>:
<a href="postconf.5.html#smtpd_enforce_tls">smtpd_enforce_tls</a> = yes
</pre>
</blockquote>
(Win32 < 5.0 and Win32 >=5.0 when run on a port<>25
and OE (5.01 Mac on all ports). </p>
-<p> It is strictly discouraged to use this mode from main.cf. If
-you want to support this service, enable a special port in master.cf
+<p> It is strictly discouraged to use this mode from <a href="postconf.5.html">main.cf</a>. If
+you want to support this service, enable a special port in <a href="master.5.html">master.cf</a>
and specify "-o <a href="postconf.5.html#smtpd_tls_wrappermode">smtpd_tls_wrappermode</a> = yes" as an <a href="smtpd.8.html">smtpd(8)</a> command
line option. Port 465 (smtps) was once chosen for this feature.
</p>
<blockquote>
<pre>
-/etc/postfix/master.cf:
+/etc/postfix/<a href="master.5.html">master.cf</a>:
smtps inet n - n - - smtpd
-o <a href="postconf.5.html#smtpd_tls_wrappermode">smtpd_tls_wrappermode</a>=yes -o <a href="postconf.5.html#smtpd_sasl_auth_enable">smtpd_sasl_auth_enable</a>=yes
</pre>
<blockquote>
<pre>
-/etc/postfix/main.cf:
+/etc/postfix/<a href="postconf.5.html">main.cf</a>:
<a href="postconf.5.html#smtpd_tls_ask_ccert">smtpd_tls_ask_ccert</a> = no
</pre>
</blockquote>
<blockquote>
<pre>
-/etc/postfix/main.cf:
+/etc/postfix/<a href="postconf.5.html">main.cf</a>:
<a href="postconf.5.html#smtpd_tls_req_ccert">smtpd_tls_req_ccert</a> = no
</pre>
</blockquote>
<blockquote>
<pre>
-/etc/postfix/main.cf:
+/etc/postfix/<a href="postconf.5.html">main.cf</a>:
<a href="postconf.5.html#smtpd_tls_ccert_verifydepth">smtpd_tls_ccert_verifydepth</a> = 5
</pre>
</blockquote>
<blockquote>
<pre>
-/etc/postfix/main.cf:
+/etc/postfix/<a href="postconf.5.html">main.cf</a>:
<a href="postconf.5.html#smtpd_tls_auth_only">smtpd_tls_auth_only</a> = no
</pre>
</blockquote>
<blockquote>
<pre>
-/etc/postfix/main.cf:
+/etc/postfix/<a href="postconf.5.html">main.cf</a>:
<a href="postconf.5.html#smtpd_tls_session_cache_database">smtpd_tls_session_cache_database</a> = btree:/etc/postfix/smtpd_scache
</pre>
</blockquote>
<blockquote>
<pre>
-/etc/postfix/main.cf:
+/etc/postfix/<a href="postconf.5.html">main.cf</a>:
<a href="postconf.5.html#smtpd_tls_session_cache_timeout">smtpd_tls_session_cache_timeout</a> = 3600s
</pre>
</blockquote>
<blockquote>
<pre>
-/etc/postfix/main.cf:
+/etc/postfix/<a href="postconf.5.html">main.cf</a>:
<a href="postconf.5.html#smtpd_recipient_restrictions">smtpd_recipient_restrictions</a> =
...
<a href="postconf.5.html#permit_tls_clientcerts">permit_tls_clientcerts</a>
<blockquote>
<pre>
-/etc/postfix/main.cf:
+/etc/postfix/<a href="postconf.5.html">main.cf</a>:
<a href="postconf.5.html#relay_clientcerts">relay_clientcerts</a> = hash:/etc/postfix/relay_clientcerts
/etc/postfix/relay_clientcerts:
<blockquote>
<pre>
-/etc/postfix/main.cf:
+/etc/postfix/<a href="postconf.5.html">main.cf</a>:
<a href="postconf.5.html#smtpd_tls_cipherlist">smtpd_tls_cipherlist</a> = DEFAULT
</pre>
</blockquote>
<blockquote>
<pre>
-/etc/postfix/main.cf:
+/etc/postfix/<a href="postconf.5.html">main.cf</a>:
<a href="postconf.5.html#smtpd_tls_dh1024_param_file">smtpd_tls_dh1024_param_file</a> = /etc/postfix/dh_1024.pem
<a href="postconf.5.html#smtpd_tls_dh512_param_file">smtpd_tls_dh512_param_file</a> = /etc/postfix/dh_512.pem
</pre>
<blockquote>
<pre>
-/etc/postfix/main.cf:
+/etc/postfix/<a href="postconf.5.html">main.cf</a>:
<a href="postconf.5.html#smtpd_starttls_timeout">smtpd_starttls_timeout</a> = 300s
</pre>
</blockquote>
<li><a href="#client_tls_cache">Client-side TLS session cache</a>
-<li><a href="#client_tls"> Enabling TLS in the Postfix SMTP client </a>
+<li><a href="#client_tls_enable"> Enabling TLS in the Postfix SMTP client </a>
+
+<li><a href="#client_tls_require"> Requiring TLS encryption </a>
+
+<li><a href="#client_tls_nopeer"> Disabling server certificate verification </a>
+
+<li><a href="#client_tls_per_site"> Per-site TLS policies </a>
+
+<!--
+<li><a href="#client_tls_obs"> Obsolete per-site TLS policy support </a>
+-->
+
+<li><a href="#client_tls_harden"> Closing a DNS loophole with <!-- legacy --> per-site TLS policies </a>
+
+<li><a href="#client_tls_discover"> Discovering servers that support TLS </a>
-<li><a href="#client_vrfy_server">Server certificate verification</a>
+<li><a href="#client_vrfy_server">Server certificate verification depth</a>
<li> <a href="#client_cipher">Client-side cipher controls </a>
certificates issued by these CAs, append the root certificate to
$<a href="postconf.5.html#smtp_tls_CAfile">smtp_tls_CAfile</a> or install it in the $<a href="postconf.5.html#smtp_tls_CApath">smtp_tls_CApath</a> directory. When
you configure trust in a root CA, it is not necessary to explicitly trust
-intermediary CAs signed by the root CA, unless $smtp_tls_verify_depth
+intermediary CAs signed by the root CA, unless $<a href="postconf.5.html#smtp_tls_scert_verifydepth">smtp_tls_scert_verifydepth</a>
is less than the number of CAs in the certificate chain for the servers
of interest. With a verify depth of 1 you can only verify certificates
directly signed by a trusted CA, and all trusted intermediary CAs need to
<blockquote>
<pre>
-/etc/postfix/main.cf:
+/etc/postfix/<a href="postconf.5.html">main.cf</a>:
<a href="postconf.5.html#smtp_tls_cert_file">smtp_tls_cert_file</a> = /etc/postfix/client.pem
<a href="postconf.5.html#smtp_tls_key_file">smtp_tls_key_file</a> = $<a href="postconf.5.html#smtp_tls_cert_file">smtp_tls_cert_file</a>
</pre>
<blockquote>
<pre>
-/etc/postfix/main.cf:
+/etc/postfix/<a href="postconf.5.html">main.cf</a>:
<a href="postconf.5.html#smtp_tls_dcert_file">smtp_tls_dcert_file</a> = /etc/postfix/client-dsa.pem
<a href="postconf.5.html#smtp_tls_dkey_file">smtp_tls_dkey_file</a> = $<a href="postconf.5.html#smtpd_tls_cert_file">smtpd_tls_cert_file</a>
</pre>
<blockquote>
<pre>
-/etc/postfix/main.cf:
+/etc/postfix/<a href="postconf.5.html">main.cf</a>:
<a href="postconf.5.html#smtp_tls_CAfile">smtp_tls_CAfile</a> = /etc/postfix/CAcert.pem
<a href="postconf.5.html#smtp_tls_CApath">smtp_tls_CApath</a> = /etc/postfix/certs
</pre>
<blockquote>
<pre>
-/etc/postfix/main.cf:
+/etc/postfix/<a href="postconf.5.html">main.cf</a>:
<a href="postconf.5.html#smtp_tls_loglevel">smtp_tls_loglevel</a> = 0
</pre>
</blockquote>
<blockquote>
<pre>
-/etc/postfix/main.cf:
+/etc/postfix/<a href="postconf.5.html">main.cf</a>:
<a href="postconf.5.html#smtp_tls_session_cache_database">smtp_tls_session_cache_database</a> = btree:/etc/postfix/smtp_scache
</pre>
</blockquote>
<blockquote>
<pre>
-/etc/postfix/main.cf:
+/etc/postfix/<a href="postconf.5.html">main.cf</a>:
<a href="postconf.5.html#smtp_tls_session_cache_timeout">smtp_tls_session_cache_timeout</a> = 3600s
</pre>
</blockquote>
-<h3><a name="client_tls"> Enabling TLS in the Postfix SMTP client </a>
-</h3>
+<h3><a name="client_tls_enable"> Enabling TLS in the Postfix SMTP
+client </a> </h3>
<p> By default, TLS is disabled in the Postfix SMTP client, so no
difference to plain Postfix is visible. If you enable TLS, the
Postfix SMTP client will send STARTTLS when TLS support is announced
by the remote SMTP server. </p>
-<p> WARNING: MS Exchange servers will announce STARTTLS support
-even when the service is not configured, so that the TLS handshake
-will fail. It may be wise to not use this option on your central
-mail hub, as you don't know in advance whether you are going to
-connect to such a host. Instead, use the <a href="postconf.5.html#smtp_tls_per_site">smtp_tls_per_site</a>
-recipient/site specific options that are described below. </p>
-
-<p> When the TLS handshake fails and no other server is available,
-the Postfix SMTP client defers the delivery attempt, and the mail
-stays in the queue. </p>
+<p> When the server accepts the STARTTLS command, but the subsequent
+TLS handshake fails, and no other server is available, the Postfix SMTP
+client defers the delivery attempt, and the mail stays in the queue. After
+a handshake failure, the communications channel is in an indeterminate
+state and cannot be used for non-TLS deliveries. </p>
<p> Example: </p>
<blockquote>
<pre>
-/etc/postfix/main.cf:
+/etc/postfix/<a href="postconf.5.html">main.cf</a>:
<a href="postconf.5.html#smtp_use_tls">smtp_use_tls</a> = yes
</pre>
</blockquote>
+<h3><a name="client_tls_require"> Requiring TLS encryption </a>
+</h3>
+
<p> You can ENFORCE the use of TLS, so that the Postfix SMTP client
will not deliver mail over unencrypted connections. In this mode,
the remote SMTP server hostname must match the information in the
doesn't match, and no other server is available, the delivery
attempt is deferred and the mail stays in the queue. </p>
-<p> The remote SMTP server hostname used in the check is beyond
-question, as it must be the principal hostname (no CNAME allowed
-here). Checks are performed against all names provided as dNSNames
+<p> The remote SMTP server hostname is verified against all names
+provided as dNSNames
in the SubjectAlternativeName. If no dNSNames are specified, the
-CommonName is checked. The behavior may be changed with the
+CommonName is checked. Verification may be turned off with the
<a href="postconf.5.html#smtp_tls_enforce_peername">smtp_tls_enforce_peername</a> option which is discussed below. </p>
-<p> This option is useful only if you know that you will only
+<p> Enforcing the use of TLS is useful if you know that you will
+only
connect to servers that support <a href="http://www.faqs.org/rfcs/rfc2487.html">RFC 2487</a> _and_ that present server
certificates that meet the above requirements. An example would
be a client only sends email to one specific mailhub that offers
<blockquote>
<pre>
-/etc/postfix/main.cf:
- <a href="postconf.5.html#smtp_enforce_tls">smtp_enforce_tls</a> = no
+/etc/postfix/<a href="postconf.5.html">main.cf</a>:
+ <a href="postconf.5.html#smtp_enforce_tls">smtp_enforce_tls</a> = yes
</pre>
</blockquote>
+<h3> <a name="client_tls_nopeer"> Disabling server certificate
+verification </a> </h3>
+
<p> As of <a href="http://www.faqs.org/rfcs/rfc2487.html">RFC 2487</a> the requirements for hostname checking for MTA
clients are not set. When TLS is required (<a href="postconf.5.html#smtp_enforce_tls">smtp_enforce_tls</a> = yes),
the option <a href="postconf.5.html#smtp_tls_enforce_peername">smtp_tls_enforce_peername</a> can be set to "no" to disable
delivery will proceed regardless of the CommonName etc. listed in
the certificate. </p>
-<p> Note: the <a href="postconf.5.html#smtp_tls_enforce_peername">smtp_tls_enforce_peername</a> setting has no effect on
-sessions that are controlled via the <a href="postconf.5.html#smtp_tls_per_site">smtp_tls_per_site</a> table. </p>
-
-<p> Disabling the remote SMTP server hostname verification can
-make sense in closed environment where special CAs are created.
-If not used carefully, this option opens the danger of a
-"man-in-the-middle" attack (the CommonName of this possible attacker
-is logged). </p>
+<p> Despite the potential for eliminating "man-in-the-middle" and
+other attacks, mandatory certificate/peername verification is not
+viable as a default Internet mail delivery policy at this time. A
+significant fraction of TLS enabled MTAs uses self-signed certificates,
+or certificates that are signed by a private certificate authority.
+On a machine that delivers mail to the Internet, if you set
+<a href="postconf.5.html#smtp_enforce_tls">smtp_enforce_tls</a> = yes, you should probably also set
+<a href="postconf.5.html#smtp_tls_enforce_peername">smtp_tls_enforce_peername</a> = no. You can use the per-site TLS
+policies (see below) to enable full peer verification for specific
+destinations that are known to have verifiable TLS server certificates.
+</p>
<p> Example: </p>
<blockquote>
<pre>
-/etc/postfix/main.cf:
- <a href="postconf.5.html#smtp_tls_enforce_peername">smtp_tls_enforce_peername</a> = yes
+/etc/postfix/<a href="postconf.5.html">main.cf</a>:
+ <a href="postconf.5.html#smtp_enforce_tls">smtp_enforce_tls</a> = yes
+ <a href="postconf.5.html#smtp_tls_enforce_peername">smtp_tls_enforce_peername</a> = no
</pre>
</blockquote>
-<p> Generally, trying TLS can be a bad idea, as some servers offer
-STARTTLS but the negotiation will fail leading to unexplainable
-failures. Instead, it may be a good idea to choose the TLS usage
-policy based on the recipient or the mailhub to which you are
-connecting. </p>
-
-<p> Deciding the TLS usage policy per recipient may be difficult,
-since a single email delivery attempt can involve several recipients.
-Instead, use of TLS is controlled by the Postfix next-hop destination
-domain name and by the remote SMTP server hostname. If either of these
-matches an entry in the <a href="postconf.5.html#smtp_tls_per_site">smtp_tls_per_site</a> table, appropriate action
-is taken. </p>
-
-<p> The remote SMTP server hostname is simply the DNS name of the
-server that the Postfix SMTP client connects to. The next-hop
-destination is Postfix specific. By default, this is the domain
-name in the recipient address, but this information can be overruled
-by the <a href="transport.5.html">transport(5)</a> table or by the <a href="postconf.5.html#relayhost">relayhost</a> parameter setting.
-In these cases the <a href="postconf.5.html#relayhost">relayhost</a> etc. must be listed in the <a href="postconf.5.html#smtp_tls_per_site">smtp_tls_per_site</a>
-table, instead of the recipient domain name. </p>
-
-<p> Format of the table: domain or host names are specified on the
-left-hand side; no wildcards are allowed. On the right hand side
-specify one of the following keywords: </p>
+<h3> <a name="client_tls_per_site"> Per-site TLS policies </a> </h3>
+
+<p> A small fraction of servers offer STARTTLS but the negotiation
+consistently fails, leading to mail aging out of the queue and
+bouncing back to the sender. In such cases, you can use the per-site
+policies to disable TLS for the problem sites. Alternatively, you
+can enable TLS for just a few specific sites and not enable it for
+all sites. </p>
+
+<!-- insert new-style TLS policy mechanism here
+
+<h3> <a name="client_tls_obs"> Obsolete per-site TLS policy support
+</a> </h3>
+
+<p> This section describes an obsolete per-site TLS policy mechanism.
+Unlike the newer mechanism it supports TLS policy lookup by server
+hostname, and lacks control over what names can appear in server
+certificates. Because of this, the obsolete mechanism is vulnerable
+to false DNS hostname information in MX or CNAME records. These
+attacks can be eliminated only with great difficulty. </p>
+
+-->
+
+<p> The <a href="postconf.5.html#smtp_tls_per_site">smtp_tls_per_site</a> table is searched for a policy that matches
+the following information: </p>
<blockquote>
<dl>
-<dt> NONE </dt> <dd> Don't use TLS at all. </dd>
+<dt> remote SMTP server hostname </dt> <dd> 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. </dd>
+
+<dt> next-hop destination </dt> <dd> This is normally the domain
+portion of the recipient address, but it may be overruled by
+information from the <a href="transport.5.html">transport(5)</a> table, from the <a href="postconf.5.html#relayhost">relayhost</a> parameter
+setting, or from the <a href="postconf.5.html#relay_transport">relay_transport</a> setting. When it's not the
+recipient domain, the next-hop destination can have the Postfix-specific
+form "<tt>[name]</tt>", <tt>[name]:port</tt>", "<tt>name</tt>" or
+"<tt>name:port</tt>". </dd>
+
+</dl>
+
+</blockquote>
+
+<p> 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. </p>
+
+<p> The <a href="postconf.5.html#smtp_tls_per_site">smtp_tls_per_site</a> table uses a simple "<i>name whitespace
+value</i>" 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: </p>
-<dt> MAY </dt> <dd> Try to use STARTTLS if offered, otherwise use
-the unencrypted connection. </dd>
+<blockquote>
-<dt> MUST </dt> <dd> Require usage of STARTTLS, require that the
-remote SMTP server hostname matches the information in the remote
-SMTP server certificate, and require that the remote SMTP server
-certificate was issued by a trusted CA. </dd>
+<dl>
-<dt> MUST_NOPEERMATCH </dt> <dd> Require usage of STARTTLS, but do
-not require that the remote SMTP server hostname matches the
-information in the remote SMTP server certificate, or that the
-server certificate was issued by a trusted CA. </dd>
+<dt> NONE </dt> <dd> Don't use TLS at all. This overrides a less
+specific <b>MAY</b> lookup result from the alternate host or next-hop
+lookup key, and overrides the global <a href="postconf.5.html#smtp_use_tls">smtp_use_tls</a>, <a href="postconf.5.html#smtp_enforce_tls">smtp_enforce_tls</a>,
+and <a href="postconf.5.html#smtp_tls_enforce_peername">smtp_tls_enforce_peername</a> settings. </dd>
+
+<dt> MAY </dt> <dd> Try to use TLS if the server announces support,
+otherwise use the unencrypted connection. This has less precedence
+than a more specific result (including <b>NONE</b>) from the alternate
+host or next-hop lookup key, and has less precedence than the more
+specific global "<a href="postconf.5.html#smtp_enforce_tls">smtp_enforce_tls</a> = yes" or "<a href="postconf.5.html#smtp_tls_enforce_peername">smtp_tls_enforce_peername</a>
+= yes". </dd>
+
+<dt> MUST_NOPEERMATCH </dt> <dd> Require TLS encryption, but do not
+require that the remote SMTP server hostname matches the information
+in the remote SMTP server certificate, or that the server certificate
+was issued by a trusted CA. This overrides a less secure <b>NONE</b>
+or a less specific <b>MAY</b> lookup result from the alternate host
+or next-hop lookup key, and overrides the global <a href="postconf.5.html#smtp_use_tls">smtp_use_tls</a>,
+<a href="postconf.5.html#smtp_enforce_tls">smtp_enforce_tls</a> and <a href="postconf.5.html#smtp_tls_enforce_peername">smtp_tls_enforce_peername</a> settings. </dd>
+
+<dt> MUST </dt> <dd> Require TLS encryption, require that the remote
+SMTP server hostname matches the information in the remote SMTP
+server certificate, and require that the remote SMTP server certificate
+was issued by a trusted CA. This overrides a less secure <b>NONE</b>
+and <b>MUST_NOPEERMATCH</b> or a less specific <b>MAY</b> lookup
+result from the alternate host or next-hop lookup key, and overrides
+the global <a href="postconf.5.html#smtp_use_tls">smtp_use_tls</a>, <a href="postconf.5.html#smtp_enforce_tls">smtp_enforce_tls</a> and <a href="postconf.5.html#smtp_tls_enforce_peername">smtp_tls_enforce_peername</a>
+settings. </dd>
</dl>
</blockquote>
-<p> The actual TLS usage policy depends not only on whether the
-next-hop destination or remote SMTP server hostname are found in
-the <a href="postconf.5.html#smtp_tls_per_site">smtp_tls_per_site</a> table, but also on the <a href="postconf.5.html#smtp_enforce_tls">smtp_enforce_tls</a>
-setting: </p>
+<p> The precedences between global (<a href="postconf.5.html">main.cf</a>) and per-site TLS
+policies can be summarized as follows: </p>
<ul>
-<li> <p> If no match was found, the policy is applied as specified
-with <a href="postconf.5.html#smtp_enforce_tls">smtp_enforce_tls</a>. </p>
+<li> <p> When neither the remote SMTP server hostname nor the
+next-hop destination are found in the <a href="postconf.5.html#smtp_tls_per_site">smtp_tls_per_site</a> table, the
+policy is based on <a href="postconf.5.html#smtp_use_tls">smtp_use_tls</a>, <a href="postconf.5.html#smtp_enforce_tls">smtp_enforce_tls</a> and
+<a href="postconf.5.html#smtp_tls_enforce_peername">smtp_tls_enforce_peername</a>. Note: "<a href="postconf.5.html#smtp_enforce_tls">smtp_enforce_tls</a> = yes" and
+"<a href="postconf.5.html#smtp_tls_enforce_peername">smtp_tls_enforce_peername</a> = yes" imply "<a href="postconf.5.html#smtp_use_tls">smtp_use_tls</a> = yes". </p>
-<li> <p> If a match was found, and the <a href="postconf.5.html#smtp_enforce_tls">smtp_enforce_tls</a> policy is
-"enforce", NONE explicitly switches it off; otherwise the "enforce"
-mode is used even for entries that specify MAY. </p>
+<li> <p> 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). </p>
+
+<li> <p> After the per-site policy lookups are combined, the result
+generally overrides the global policy. The exception is the less
+specific <b>MAY</b> per-site policy, which is overruled by the more
+specific global "<a href="postconf.5.html#smtp_enforce_tls">smtp_enforce_tls</a> = yes" with server certificate
+verification as specified with the <a href="postconf.5.html#smtp_tls_enforce_peername">smtp_tls_enforce_peername</a>
+parameter. </p>
</ul>
-<p> Special hint for TLS enforcement mode: since no secure DNS
-lookup mechanism is available, mail can be delivered to the wrong
-remote SMTP server. This is not prevented by specifying MUST for
-the next-hop domain name. The recommended setup is: specify local
-<a href="transport.5.html">transport(5)</a> table entries for sensitive domains with explicit
-<a href="smtp.8.html">smtp</a>:[mailhost] destinations (since you can assure security of this
-table unlike DNS), then specify MUST for these mail hosts in the
-<a href="postconf.5.html#smtp_tls_per_site">smtp_tls_per_site</a> table. </p>
+<h3> <a name="client_tls_harden"> Closing a DNS loophole with
+<!-- legacy --> per-site TLS policies </a> </h3>
+
+<p> As long as no secure DNS lookup mechanism is available, false
+hostnames may appear in MX or CNAME responses. 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 the following steps: </p>
+
+<ul>
+
+<li> <p> Eliminate MX lookups. Specify local <a href="transport.5.html">transport(5)</a> table
+entries for sensitive domains with explicit <a href="smtp.8.html">smtp</a>:[<i>mailhost</i>]
+or <a href="smtp.8.html">smtp</a>:[<i>mailhost</i>]:<i>port</i> destinations (you can assure
+security of this table unlike DNS); in the <a href="postconf.5.html#smtp_tls_per_site">smtp_tls_per_site</a> table
+specify the value <b>MUST</b> for the key [<i>mailhost</i>] or
+<a href="smtp.8.html">smtp</a>:[<i>mailhost</i>]:<i>port</i>. This prevents false hostname
+information in DNS MX records from changing the server hostname
+that Postfix uses for TLS policy lookup and server certificate
+verification. </p>
+
+<li> <p> Disallow CNAME hostname overrides. In <a href="postconf.5.html">main.cf</a> specify
+"<a href="postconf.5.html#smtp_cname_overrides_servername">smtp_cname_overrides_servername</a> = 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. </p>
+
+</ul>
<p> Example: </p>
-
-<blockquote>
-<pre>
-/etc/postfix/main.cf:
+
+<blockquote> <pre>
+/etc/postfix/<a href="postconf.5.html">main.cf</a>:
<a href="postconf.5.html#smtp_tls_per_site">smtp_tls_per_site</a> = hash:/etc/postfix/tls_per_site
+ <a href="postconf.5.html#relayhost">relayhost</a> = [msa.example.net]:587
+
+/etc/postfix/tls_per_site:
+ # <a href="postconf.5.html#relayhost">relayhost</a> exact nexthop match
+ [msa.example.net]:587 MUST
+
+ # example.org (as nexthop) has MX hosts with broken TLS.
+ example.org NONE
+
+ # Except for (as host) mx1.example.org which works.
+ mx1.example.org MAY
</pre>
</blockquote>
+<h3> <a name="client_tls_discover"> Discovering servers that support
+TLS </a> </h3>
+
<p> As we decide on a "per site" basis whether or not to use TLS,
it would be good to have a list of sites that offered "STARTTLS".
We can collect it ourselves with this option. </p>
<blockquote>
<pre>
-/etc/postfix/main.cf:
+/etc/postfix/<a href="postconf.5.html">main.cf</a>:
<a href="postconf.5.html#smtp_tls_note_starttls_offer">smtp_tls_note_starttls_offer</a> = yes
</pre>
</blockquote>
-<h3><a name="client_vrfy_server">Server certificate verification</a> </h3>
+<h3><a name="client_vrfy_server">Server certificate verification depth</a> </h3>
<p> When verifying a remote SMTP server certificate, a verification
depth of 1 is sufficient if the certificate is directly issued by
<blockquote>
<pre>
-/etc/postfix/main.cf:
+/etc/postfix/<a href="postconf.5.html">main.cf</a>:
<a href="postconf.5.html#smtp_tls_scert_verifydepth">smtp_tls_scert_verifydepth</a> = 5
</pre>
</blockquote>
<blockquote>
<pre>
-/etc/postfix/main.cf:
+/etc/postfix/<a href="postconf.5.html">main.cf</a>:
<a href="postconf.5.html#smtp_tls_cipherlist">smtp_tls_cipherlist</a> = DEFAULT
</pre>
</blockquote>
<blockquote>
<pre>
-/etc/postfix/main.cf:
+/etc/postfix/<a href="postconf.5.html">main.cf</a>:
<a href="postconf.5.html#smtp_starttls_timeout">smtp_starttls_timeout</a> = 300s
</pre>
</blockquote>
<blockquote>
<pre>
-/etc/postfix/main.cf:
+/etc/postfix/<a href="postconf.5.html">main.cf</a>:
<a href="postconf.5.html#tls_daemon_random_bytes">tls_daemon_random_bytes</a> = 32
</pre>
</blockquote>
"dev:" for a device special file, or "egd:" for a source with EGD
compatible socket interface. </p>
-<p> Examples (specify only one in main.cf): </p>
+<p> Examples (specify only one in <a href="postconf.5.html">main.cf</a>): </p>
<blockquote>
<pre>
-/etc/postfix/main.cf:
+/etc/postfix/<a href="postconf.5.html">main.cf</a>:
<a href="postconf.5.html#tls_random_source">tls_random_source</a> = dev:/dev/urandom
<a href="postconf.5.html#tls_random_source">tls_random_source</a> = egd:/var/run/egd-pool
</pre>
<blockquote>
<pre>
-/etc/postfix/main.cf:
+/etc/postfix/<a href="postconf.5.html">main.cf</a>:
<a href="postconf.5.html#tls_random_bytes">tls_random_bytes</a> = 32
</pre>
</blockquote>
<blockquote>
<pre>
-/etc/postfix/main.cf:
+/etc/postfix/<a href="postconf.5.html">main.cf</a>:
<a href="postconf.5.html#tls_random_reseed_period">tls_random_reseed_period</a> = 3600s
</pre>
</blockquote>
<blockquote>
<pre>
-/etc/postfix/main.cf:
+/etc/postfix/<a href="postconf.5.html">main.cf</a>:
<a href="postconf.5.html#tls_random_exchange_name">tls_random_exchange_name</a> = /etc/postfix/prng_exch
<a href="postconf.5.html#tls_random_prng_update_period">tls_random_prng_update_period</a> = 3600s
</pre>
</blockquote>
<li> <p> Configure Postfix, by adding the following to
-<tt>/etc/postfix/main.cf</tt>. </p>
+<tt>/etc/postfix/<a href="postconf.5.html">main.cf</a> </tt>. </p>
<blockquote>
<pre>
<ul>
-<li> <p> main.cf: Specify "btree" instead of "sdbm" for TLS
+<li> <p> <a href="postconf.5.html">main.cf</a>: Specify "btree" instead of "sdbm" for TLS
session cache databases. </p>
<p> TLS session cache databases are now accessed only by the
<p> NOTE: You cannot use dbm databases. TLS session objects
are too large. </p>
-<li> <p> master.cf: Specify "unix" instead of "fifo" as
+<li> <p> <a href="master.5.html">master.cf</a>: Specify "unix" instead of "fifo" as
the tlsmgr service type. </p>
<p> The <a href="smtp.8.html">smtp(8)</a> and <a href="smtpd.8.html">smtpd(8)</a> processes now use a client-server
generation (PRNG) pool, and in order to access the TLS session
cache databases. Such a protocol cannot be run across fifos. </p>
+<li> <p> <a href="postconf.5.html#smtp_tls_per_site">smtp_tls_per_site</a>: the MUST_NOPEERMATCH per-site policy
+cannot override the global "<a href="postconf.5.html#smtp_tls_enforce_peername">smtp_tls_enforce_peername</a> = yes" setting.
+</p>
+
+<li> <p> <a href="postconf.5.html#smtp_tls_per_site">smtp_tls_per_site</a>: a combined (NONE + MAY) lookup result
+for (hostname and next-hop destination) produces counter-intuitive
+results for different <a href="postconf.5.html">main.cf</a> settings. TLS is enabled with
+"<a href="postconf.5.html#smtp_tls_enforce_peername">smtp_tls_enforce_peername</a> = no", but it is disabled when both
+"<a href="postconf.5.html#smtp_enforce_tls">smtp_enforce_tls</a> = yes" and "<a href="postconf.5.html#smtp_tls_enforce_peername">smtp_tls_enforce_peername</a> = yes".
+</p>
+
</ul>
+<p> The <a href="postconf.5.html#smtp_tls_per_site">smtp_tls_per_site</a> limitations were removed by the end of
+the Postfix 2.2 support cycle. </p>
+
<h2><a name="credits">Credits </a> </h2>
<ul>
<li> Wietse Venema adopted the code, did some restructuring, and
compiled this part of the documentation from Lutz's documents.
+<li> Victor Duchovni was instrumental with the re-implementation
+of the <a href="postconf.5.html#smtp_tls_per_site">smtp_tls_per_site</a> code in terms of enforcement levels, which
+simplified the implementation greatly.
+
</ul>
</body>
<b>then else</b> and other logical relationships.
<b>CONFIGURATION PARAMETERS</b>
- Changes to <b>main.cf</b> are picked up automatically, as
+ Changes to <a href="postconf.5.html"><b>main.cf</b></a> are picked up automatically, as
<a href="cleanup.8.html"><b>cleanup</b>(8)</a> processes run for only a limited amount of
time. Use the command "<b>postfix reload</b>" to speed up a
change.
Report mail delivery errors to the address speci-
fied with the non-standard Errors-To: message
header, instead of the envelope sender address
- (this feature is removed with Postfix 2.2, is
- turned off by default with Postfix 2.1, and is
- always turned on with older Postfix versions).
+ (this feature is removed with Postfix version 2.2,
+ is turned off by default with Postfix version 2.1,
+ and is always turned on with older Postfix ver-
+ sions).
<b>BUILT-IN CONTENT FILTERING CONTROLS</b>
- Postfix built-in content filtering is meant to stop a
- flood of worms or viruses. It is not a general content
+ Postfix built-in content filtering is meant to stop a
+ flood of worms or viruses. It is not a general content
filter.
<b><a href="postconf.5.html#body_checks">body_checks</a> (empty)</b>
- Optional lookup tables for content inspection as
+ Optional lookup tables for content inspection as
specified in the <b><a href="postconf.5.html#body_checks">body_checks</a></b>(5) manual page.
<b><a href="postconf.5.html#header_checks">header_checks</a> (empty)</b>
- Optional lookup tables for content inspection of
- primary non-MIME message headers, as specified in
+ Optional lookup tables for content inspection of
+ primary non-MIME message headers, as specified in
the <b><a href="postconf.5.html#header_checks">header_checks</a></b>(5) manual page.
Available in Postfix version 2.0 and later:
<b><a href="postconf.5.html#body_checks_size_limit">body_checks_size_limit</a> (51200)</b>
How much text in a message body segment (or attach-
- ment, if you prefer to use that term) is subjected
+ ment, if you prefer to use that term) is subjected
to <a href="postconf.5.html#body_checks">body_checks</a> inspection.
<b><a href="postconf.5.html#mime_header_checks">mime_header_checks</a> ($<a href="postconf.5.html#header_checks">header_checks</a>)</b>
- Optional lookup tables for content inspection of
- MIME related message headers, as described in the
+ Optional lookup tables for content inspection of
+ MIME related message headers, as described in the
<b><a href="postconf.5.html#header_checks">header_checks</a></b>(5) manual page.
<b><a href="postconf.5.html#nested_header_checks">nested_header_checks</a> ($<a href="postconf.5.html#header_checks">header_checks</a>)</b>
- Optional lookup tables for content inspection of
- non-MIME message headers in attached messages, as
+ Optional lookup tables for content inspection of
+ non-MIME message headers in attached messages, as
described in the <b><a href="postconf.5.html#header_checks">header_checks</a></b>(5) manual page.
Available in Postfix version 2.3 and later:
<b><a href="postconf.5.html#message_reject_characters">message_reject_characters</a> (empty)</b>
- The set of characters that Postfix will reject in
+ The set of characters that Postfix will reject in
message content.
<b><a href="postconf.5.html#message_strip_characters">message_strip_characters</a> (empty)</b>
will handle.
<b><a href="postconf.5.html#strict_8bitmime">strict_8bitmime</a> (no)</b>
- Enable both <a href="postconf.5.html#strict_7bit_headers">strict_7bit_headers</a> and strict_8bit-
+ Enable both <a href="postconf.5.html#strict_7bit_headers">strict_7bit_headers</a> and strict_8bit-
mime_body.
<b><a href="postconf.5.html#strict_7bit_headers">strict_7bit_headers</a> (no)</b>
Reject mail with 8-bit text in message headers.
<b><a href="postconf.5.html#strict_8bitmime_body">strict_8bitmime_body</a> (no)</b>
- Reject 8-bit message body text without 8-bit MIME
+ Reject 8-bit message body text without 8-bit MIME
content encoding information.
<b><a href="postconf.5.html#strict_mime_encoding_domain">strict_mime_encoding_domain</a> (no)</b>
Reject mail with invalid Content-Transfer-Encoding:
- information for the message/* or multipart/* MIME
+ information for the message/* or multipart/* MIME
content types.
<b>AUTOMATIC BCC RECIPIENT CONTROLS</b>
mail enters the mail system:
<b><a href="postconf.5.html#always_bcc">always_bcc</a> (empty)</b>
- Optional address that receives a "blind carbon
+ Optional address that receives a "blind carbon
copy" of each message that is received by the Post-
fix mail system.
Available in Postfix version 2.1 and later:
<b><a href="postconf.5.html#sender_bcc_maps">sender_bcc_maps</a> (empty)</b>
- Optional BCC (blind carbon-copy) address lookup
+ Optional BCC (blind carbon-copy) address lookup
tables, indexed by sender address.
<b><a href="postconf.5.html#recipient_bcc_maps">recipient_bcc_maps</a> (empty)</b>
- Optional BCC (blind carbon-copy) address lookup
+ Optional BCC (blind carbon-copy) address lookup
tables, indexed by recipient address.
<b>ADDRESS TRANSFORMATION CONTROLS</b>
- Address rewriting is delegated to the <a href="trivial-rewrite.8.html"><b>trivial-rewrite</b>(8)</a>
- daemon. The <a href="cleanup.8.html"><b>cleanup</b>(8)</a> server implements table driven
+ Address rewriting is delegated to the <a href="trivial-rewrite.8.html"><b>trivial-rewrite</b>(8)</a>
+ daemon. The <a href="cleanup.8.html"><b>cleanup</b>(8)</a> server implements table driven
address mapping.
<b><a href="postconf.5.html#empty_address_recipient">empty_address_recipient</a> (MAILER-DAEMON)</b>
- The recipient of mail addressed to the null
+ The recipient of mail addressed to the null
address.
<b><a href="postconf.5.html#canonical_maps">canonical_maps</a> (empty)</b>
- Optional address mapping lookup tables for message
+ Optional address mapping lookup tables for message
headers and envelopes.
<b><a href="postconf.5.html#recipient_canonical_maps">recipient_canonical_maps</a> (empty)</b>
Optional address mapping lookup tables for envelope
and header sender addresses.
- <b><a href="postconf.5.html#masquerade_classes">masquerade_classes</a> (envelope_sender, header_sender,</b>
+ <b><a href="postconf.5.html#masquerade_classes">masquerade_classes</a> (envelope_sender, header_sender,</b>
<b>header_recipient)</b>
What addresses are subject to address masquerading.
<b><a href="postconf.5.html#masquerade_domains">masquerade_domains</a> (empty)</b>
- Optional list of domains whose subdomain structure
+ Optional list of domains whose subdomain structure
will be stripped off in email addresses.
<b><a href="postconf.5.html#masquerade_exceptions">masquerade_exceptions</a> (empty)</b>
- Optional list of user names that are not subjected
- to address masquerading, even when their address
+ Optional list of user names that are not subjected
+ to address masquerading, even when their address
matches $<a href="postconf.5.html#masquerade_domains">masquerade_domains</a>.
<b><a href="postconf.5.html#propagate_unmatched_extensions">propagate_unmatched_extensions</a> (canonical, virtual)</b>
- What address lookup tables copy an address exten-
+ What address lookup tables copy an address exten-
sion from the lookup key to the lookup result.
Available before Postfix version 2.0:
<b><a href="postconf.5.html#virtual_maps">virtual_maps</a> (empty)</b>
Optional lookup tables with a) names of domains for
- which all addresses are aliased to addresses in
- other local or remote domains, and b) addresses
- that are aliased to addresses in other local or
+ which all addresses are aliased to addresses in
+ other local or remote domains, and b) addresses
+ that are aliased to addresses in other local or
remote domains.
Available in Postfix version 2.0 and later:
<b><a href="postconf.5.html#virtual_alias_maps">virtual_alias_maps</a> ($<a href="postconf.5.html#virtual_maps">virtual_maps</a>)</b>
- Optional lookup tables that alias specific mail
- addresses or domains to other local or remote
+ Optional lookup tables that alias specific mail
+ addresses or domains to other local or remote
address.
Available in Postfix version 2.2 and later:
- <b><a href="postconf.5.html#canonical_classes">canonical_classes</a> (envelope_sender, envelope_recipient,</b>
+ <b><a href="postconf.5.html#canonical_classes">canonical_classes</a> (envelope_sender, envelope_recipient,</b>
<b>header_sender, header_recipient)</b>
- What addresses are subject to <a href="postconf.5.html#canonical_maps">canonical_maps</a>
+ What addresses are subject to <a href="postconf.5.html#canonical_maps">canonical_maps</a>
address mapping.
<b><a href="postconf.5.html#recipient_canonical_classes">recipient_canonical_classes</a> (envelope_recipient,</b>
<b>header_recipient)</b>
- What addresses are subject to <a href="postconf.5.html#recipient_canonical_maps">recipient_canoni</a>-
+ What addresses are subject to <a href="postconf.5.html#recipient_canonical_maps">recipient_canoni</a>-
<a href="postconf.5.html#recipient_canonical_maps">cal_maps</a> address mapping.
<b><a href="postconf.5.html#sender_canonical_classes">sender_canonical_classes</a> (envelope_sender, header_sender)</b>
address mapping.
<b><a href="postconf.5.html#remote_header_rewrite_domain">remote_header_rewrite_domain</a> (empty)</b>
- Don't rewrite message headers from remote clients
+ Don't rewrite message headers from remote clients
at all when this parameter is empty; otherwise, re-
- write message headers and append the specified
+ write message headers and append the specified
domain name to incomplete addresses.
<b>RESOURCE AND RATE CONTROLS</b>
<b><a href="postconf.5.html#duplicate_filter_limit">duplicate_filter_limit</a> (1000)</b>
- The maximal number of addresses remembered by the
- address duplicate filter for <a href="aliases.5.html"><b>aliases</b>(5)</a> or <a href="virtual.5.html"><b>vir-</b></a>
+ The maximal number of addresses remembered by the
+ address duplicate filter for <a href="aliases.5.html"><b>aliases</b>(5)</a> or <a href="virtual.5.html"><b>vir-</b></a>
<a href="virtual.5.html"><b>tual</b>(5)</a> alias expansion, or for <a href="showq.8.html"><b>showq</b>(8)</a> queue dis-
plays.
message header.
<b><a href="postconf.5.html#hopcount_limit">hopcount_limit</a> (50)</b>
- The maximal number of Received: message headers
+ The maximal number of Received: message headers
that is allowed in the primary message headers.
<b><a href="postconf.5.html#in_flow_delay">in_flow_delay</a> (1s)</b>
- Time to pause before accepting a new message, when
+ Time to pause before accepting a new message, when
the message arrival rate exceeds the message deliv-
ery rate.
<b><a href="postconf.5.html#message_size_limit">message_size_limit</a> (10240000)</b>
- The maximal size in bytes of a message, including
+ The maximal size in bytes of a message, including
envelope information.
Available in Postfix version 2.0 and later:
will handle.
<b><a href="postconf.5.html#queue_file_attribute_count_limit">queue_file_attribute_count_limit</a> (100)</b>
- The maximal number of (name=value) attributes that
+ The maximal number of (name=value) attributes that
may be stored in a Postfix queue file.
Available in Postfix version 2.1 and later:
<b><a href="postconf.5.html#virtual_alias_expansion_limit">virtual_alias_expansion_limit</a> (1000)</b>
- The maximal number of addresses that virtual alias
+ The maximal number of addresses that virtual alias
expansion produces from each original recipient.
<b><a href="postconf.5.html#virtual_alias_recursion_limit">virtual_alias_recursion_limit</a> (1000)</b>
- The maximal nesting depth of virtual alias expan-
+ The maximal nesting depth of virtual alias expan-
sion.
<b>MISCELLANEOUS CONTROLS</b>
<b><a href="postconf.5.html#config_directory">config_directory</a> (see 'postconf -d' output)</b>
- The default location of the Postfix main.cf and
- master.cf configuration files.
+ The default location of the Postfix <a href="postconf.5.html">main.cf</a> and
+ <a href="master.5.html">master.cf</a> configuration files.
<b><a href="postconf.5.html#daemon_timeout">daemon_timeout</a> (18000s)</b>
- How much time a Postfix daemon process may take to
- handle a request before it is terminated by a
+ How much time a Postfix daemon process may take to
+ handle a request before it is terminated by a
built-in watchdog timer.
<b><a href="postconf.5.html#delay_logging_resolution_limit">delay_logging_resolution_limit</a> (2)</b>
- The maximal number of digits after the decimal
+ The maximal number of digits after the decimal
point when logging sub-second delay values.
<b><a href="postconf.5.html#delay_warning_time">delay_warning_time</a> (0h)</b>
- The time after which the sender receives the mes-
+ The time after which the sender receives the mes-
sage headers of mail that is still queued.
<b><a href="postconf.5.html#ipc_timeout">ipc_timeout</a> (3600s)</b>
over an internal communication channel.
<b><a href="postconf.5.html#max_idle">max_idle</a> (100s)</b>
- The maximum amount of time that an idle Postfix
- daemon process waits for the next service request
+ The maximum amount of time that an idle Postfix
+ daemon process waits for the next service request
before exiting.
<b><a href="postconf.5.html#max_use">max_use</a> (100)</b>
- The maximal number of connection requests before a
+ The maximal number of connection requests before a
Postfix daemon process terminates.
<b><a href="postconf.5.html#myhostname">myhostname</a> (see 'postconf -d' output)</b>
<b><a href="postconf.5.html#myorigin">myorigin</a> ($<a href="postconf.5.html#myhostname">myhostname</a>)</b>
The domain name that locally-posted mail appears to
- come from, and that locally posted mail is deliv-
+ come from, and that locally posted mail is deliv-
ered to.
<b><a href="postconf.5.html#process_id">process_id</a> (read-only)</b>
- The process ID of a Postfix command or daemon
+ The process ID of a Postfix command or daemon
process.
<b><a href="postconf.5.html#process_name">process_name</a> (read-only)</b>
- The process name of a Postfix command or daemon
+ The process name of a Postfix command or daemon
process.
<b><a href="postconf.5.html#queue_directory">queue_directory</a> (see 'postconf -d' output)</b>
- The location of the Postfix top-level queue direc-
+ The location of the Postfix top-level queue direc-
tory.
<b><a href="postconf.5.html#soft_bounce">soft_bounce</a> (no)</b>
The syslog facility of Postfix logging.
<b><a href="postconf.5.html#syslog_name">syslog_name</a> (postfix)</b>
- The mail system name that is prepended to the
- process name in syslog records, so that "smtpd"
+ The mail system name that is prepended to the
+ process name in syslog records, so that "smtpd"
becomes, for example, "postfix/smtpd".
Available in Postfix version 2.1 and later:
<b><a href="postconf.5.html#enable_original_recipient">enable_original_recipient</a> (yes)</b>
- Enable support for the X-Original-To message
+ Enable support for the X-Original-To message
header.
<b>FILES</b>
<a href="ADDRESS_REWRITING_README.html">ADDRESS_REWRITING_README</a> Postfix address manipulation
<b>LICENSE</b>
- The Secure Mailer license must be distributed with this
+ The Secure Mailer license must be distributed with this
software.
<b>AUTHOR(S)</b>
fore can accumulate outdated or redundant data. In order
to maintain sanity, "refresh" must be executed periodi-
cally. This can be automated with a suitable wakeup timer
- setting in the <b>master.cf</b> configuration file.
+ setting in the <a href="master.5.html"><b>master.cf</b></a> configuration file.
Upon receipt of a request to deliver mail for an eligible
destination, the <a href="flush.8.html"><b>flush</b>(8)</a> server requests delivery of all
in one domain.
<b>CONFIGURATION PARAMETERS</b>
- Changes to <b>main.cf</b> are picked up automatically as <a href="flush.8.html"><b>flush</b>(8)</a>
+ Changes to <a href="postconf.5.html"><b>main.cf</b></a> are picked up automatically as <a href="flush.8.html"><b>flush</b>(8)</a>
processes run for only a limited amount of time. Use the
command "<b>postfix reload</b>" to speed up a change.
<a href="postconf.5.html"><b>postconf</b>(5)</a> for more details including examples.
<b><a href="postconf.5.html#config_directory">config_directory</a> (see 'postconf -d' output)</b>
- The default location of the Postfix main.cf and
- master.cf configuration files.
+ The default location of the Postfix <a href="postconf.5.html">main.cf</a> and
+ <a href="master.5.html">master.cf</a> configuration files.
<b><a href="postconf.5.html#daemon_timeout">daemon_timeout</a> (18000s)</b>
How much time a Postfix daemon process may take to
<b>CONFIGURATION PARAMETERS</b>
As the <a href="pickup.8.html"><b>pickup</b>(8)</a> daemon is a relatively long-running
- process, up to an hour may pass before a <b>main.cf</b> change
+ process, up to an hour may pass before a <a href="postconf.5.html"><b>main.cf</b></a> change
takes effect. Use the command "<b>postfix reload</b>" command to
speed up a change.
<b>MISCELLANEOUS CONTROLS</b>
<b><a href="postconf.5.html#config_directory">config_directory</a> (see 'postconf -d' output)</b>
- The default location of the Postfix main.cf and
- master.cf configuration files.
+ The default location of the Postfix <a href="postconf.5.html">main.cf</a> and
+ <a href="master.5.html">master.cf</a> configuration files.
<b><a href="postconf.5.html#daemon_timeout">daemon_timeout</a> (18000s)</b>
How much time a Postfix daemon process may take to
The format of Postfix alias input files is described in
<a href="aliases.5.html"><b>aliases</b>(5)</a>.
+ By default the lookup key is mapped to lowercase to make
+ the lookups case insensitive; as of Postfix 2.3 this case
+ folding happens only with tables whose lookup keys are
+ fixed-case strings such as btree:, dbm: or hash:. With
+ earlier versions, the lookup key is folded even with
+ tables where a lookup field can match both upper and lower
+ case text, such as <a href="regexp_table.5.html">regexp</a>: and <a href="pcre_table.5.html">pcre</a>:. This resulted in
+ loss of information with $<i>number</i> substitutions.
+
Options:
<b>-c</b> <i>config</i><b>_</b><i>dir</i>
- Read the <b>main.cf</b> configuration file in the named
+ Read the <a href="postconf.5.html"><b>main.cf</b></a> configuration file in the named
directory instead of the default configuration
directory.
- <b>-d</b> <i>key</i> Search the specified maps for <i>key</i> and remove one
- entry per map. The exit status is zero when the
+ <b>-d</b> <i>key</i> Search the specified maps for <i>key</i> and remove one
+ entry per map. The exit status is zero when the
requested information was found.
If a key value of <b>-</b> is specified, the program reads
key values from the standard input stream. The exit
- status is zero when at least one of the requested
+ status is zero when at least one of the requested
keys was found.
<b>-f</b> Do not fold the lookup key to lower case while cre-
- ating or querying a map.
+ ating or querying a table.
- <b>-i</b> Incremental mode. Read entries from standard input
+ <b>-i</b> Incremental mode. Read entries from standard input
and do not truncate an existing database. By
- default, <a href="postalias.1.html"><b>postalias</b>(1)</a> creates a new database from
+ default, <a href="postalias.1.html"><b>postalias</b>(1)</a> creates a new database from
the entries in <i>file</i><b>_</b><i>name</i>.
- <b>-N</b> Include the terminating null character that termi-
- nates lookup keys and values. By default, <b>postal-</b>
- <b>ias</b>(1) does whatever is the default for the host
+ <b>-N</b> Include the terminating null character that termi-
+ nates lookup keys and values. By default, <b>postal-</b>
+ <b>ias</b>(1) does whatever is the default for the host
operating system.
- <b>-n</b> Don't include the terminating null character that
- terminates lookup keys and values. By default,
- <a href="postalias.1.html"><b>postalias</b>(1)</a> does whatever is the default for the
+ <b>-n</b> Don't include the terminating null character that
+ terminates lookup keys and values. By default,
+ <a href="postalias.1.html"><b>postalias</b>(1)</a> does whatever is the default for the
host operating system.
- <b>-o</b> Do not release root privileges when processing a
+ <b>-o</b> Do not release root privileges when processing a
non-root input file. By default, <a href="postalias.1.html"><b>postalias</b>(1)</a> drops
- root privileges and runs as the source file owner
+ root privileges and runs as the source file owner
instead.
<b>-p</b> Do not inherit the file access permissions from the
input file when creating a new file. Instead, cre-
- ate a new file with default access permissions
+ ate a new file with default access permissions
(mode 0644).
- <b>-q</b> <i>key</i> Search the specified maps for <i>key</i> and write the
- first value found to the standard output stream.
+ <b>-q</b> <i>key</i> Search the specified maps for <i>key</i> and write the
+ first value found to the standard output stream.
The exit status is zero when the requested informa-
tion was found.
If a key value of <b>-</b> is specified, the program reads
- key values from the standard input stream and
- writes one line of <i>key: value</i> output for each key
- that was found. The exit status is zero when at
+ key values from the standard input stream and
+ writes one line of <i>key: value</i> output for each key
+ that was found. The exit status is zero when at
least one of the requested keys was found.
<b>-r</b> When updating a table, do not complain about
attempts to update existing entries, and make those
updates anyway.
- <b>-s</b> Retrieve all database elements, and write one line
+ <b>-s</b> Retrieve all database elements, and write one line
of <i>key: value</i> output for each element. The elements
- are printed in database order, which is not neces-
- sarily the same as the original input order. This
- feature is available in Postfix version 2.2 and
+ are printed in database order, which is not neces-
+ sarily the same as the original input order. This
+ feature is available in Postfix version 2.2 and
later, and is not available for all database types.
<b>-v</b> Enable verbose logging for debugging purposes. Mul-
- tiple <b>-v</b> options make the software increasingly
+ tiple <b>-v</b> options make the software increasingly
verbose.
<b>-w</b> When updating a table, do not complain about
- attempts to update existing entries, and ignore
+ attempts to update existing entries, and ignore
those attempts.
Arguments:
<i>file</i><b>_</b><i>type</i>
- The database type. To find out what types are sup-
+ The database type. To find out what types are sup-
ported, use the "<b>postconf -m</b>" command.
- The <a href="postalias.1.html"><b>postalias</b>(1)</a> command can query any supported
- file type, but it can create only the following
+ The <a href="postalias.1.html"><b>postalias</b>(1)</a> command can query any supported
+ file type, but it can create only the following
file types:
- <b>btree</b> The output is a btree file, named
- <i>file</i><b>_</b><i>name</i><b>.db</b>. This is available on systems
+ <b>btree</b> The output is a btree file, named
+ <i>file</i><b>_</b><i>name</i><b>.db</b>. This is available on systems
with support for <b>db</b> databases.
- <b>cdb</b> The output is one file named <i>file</i><b>_</b><i>name</i><b>.cdb</b>.
- This is available on systems with support
+ <b>cdb</b> The output is one file named <i>file</i><b>_</b><i>name</i><b>.cdb</b>.
+ This is available on systems with support
for <b>cdb</b> databases.
- <b>dbm</b> The output consists of two files, named
- <i>file</i><b>_</b><i>name</i><b>.pag</b> and <i>file</i><b>_</b><i>name</i><b>.dir</b>. This is
- available on systems with support for <b>dbm</b>
+ <b>dbm</b> The output consists of two files, named
+ <i>file</i><b>_</b><i>name</i><b>.pag</b> and <i>file</i><b>_</b><i>name</i><b>.dir</b>. This is
+ available on systems with support for <b>dbm</b>
databases.
- <b>hash</b> The output is a hashed file, named
- <i>file</i><b>_</b><i>name</i><b>.db</b>. This is available on systems
+ <b>hash</b> The output is a hashed file, named
+ <i>file</i><b>_</b><i>name</i><b>.db</b>. This is available on systems
with support for <b>db</b> databases.
- <b>sdbm</b> The output consists of two files, named
- <i>file</i><b>_</b><i>name</i><b>.pag</b> and <i>file</i><b>_</b><i>name</i><b>.dir</b>. This is
- available on systems with support for <b>sdbm</b>
+ <b>sdbm</b> The output consists of two files, named
+ <i>file</i><b>_</b><i>name</i><b>.pag</b> and <i>file</i><b>_</b><i>name</i><b>.dir</b>. This is
+ available on systems with support for <b>sdbm</b>
databases.
- When no <i>file</i><b>_</b><i>type</i> is specified, the software uses
- the database type specified via the <b><a href="postconf.5.html#default_database_type">default_data</a>-</b>
+ When no <i>file</i><b>_</b><i>type</i> is specified, the software uses
+ the database type specified via the <b><a href="postconf.5.html#default_database_type">default_data</a>-</b>
<b><a href="postconf.5.html#default_database_type">base_type</a></b> configuration parameter. The default
- value for this parameter depends on the host envi-
+ value for this parameter depends on the host envi-
ronment.
<i>file</i><b>_</b><i>name</i>
- The name of the alias database source file when
+ The name of the alias database source file when
creating a database.
<b>DIAGNOSTICS</b>
- Problems are logged to the standard error stream and to
- <b>syslogd</b>(8). No output means that no problems were
- detected. Duplicate entries are skipped and are flagged
+ Problems are logged to the standard error stream and to
+ <b>syslogd</b>(8). No output means that no problems were
+ detected. Duplicate entries are skipped and are flagged
with a warning.
- <a href="postalias.1.html"><b>postalias</b>(1)</a> terminates with zero exit status in case of
- success (including successful "<b>postalias -q</b>" lookup) and
+ <a href="postalias.1.html"><b>postalias</b>(1)</a> terminates with zero exit status in case of
+ success (including successful "<b>postalias -q</b>" lookup) and
terminates with non-zero exit status in case of failure.
<b>ENVIRONMENT</b>
Enable verbose logging for debugging purposes.
<b>CONFIGURATION PARAMETERS</b>
- The following <b>main.cf</b> parameters are especially relevant
+ The following <a href="postconf.5.html"><b>main.cf</b></a> parameters are especially relevant
to this program.
- The text below provides only a parameter summary. See
+ The text below provides only a parameter summary. See
<a href="postconf.5.html"><b>postconf</b>(5)</a> for more details including examples.
<b><a href="postconf.5.html#alias_database">alias_database</a> (see 'postconf -d' output)</b>
- The alias databases for <a href="local.8.html"><b>local</b>(8)</a> delivery that are
+ The alias databases for <a href="local.8.html"><b>local</b>(8)</a> delivery that are
updated with "<b>newaliases</b>" or with "<b>sendmail -bi</b>".
<b><a href="postconf.5.html#config_directory">config_directory</a> (see 'postconf -d' output)</b>
- The default location of the Postfix main.cf and
- master.cf configuration files.
+ The default location of the Postfix <a href="postconf.5.html">main.cf</a> and
+ <a href="master.5.html">master.cf</a> configuration files.
<b><a href="postconf.5.html#berkeley_db_create_buffer_size">berkeley_db_create_buffer_size</a> (16777216)</b>
- The per-table I/O buffer size for programs that
+ The per-table I/O buffer size for programs that
create Berkeley DB hash or btree tables.
<b><a href="postconf.5.html#berkeley_db_read_buffer_size">berkeley_db_read_buffer_size</a> (131072)</b>
- The per-table I/O buffer size for programs that
+ The per-table I/O buffer size for programs that
read Berkeley DB hash or btree tables.
<b><a href="postconf.5.html#default_database_type">default_database_type</a> (see 'postconf -d' output)</b>
The syslog facility of Postfix logging.
<b><a href="postconf.5.html#syslog_name">syslog_name</a> (postfix)</b>
- The mail system name that is prepended to the
- process name in syslog records, so that "smtpd"
+ The mail system name that is prepended to the
+ process name in syslog records, so that "smtpd"
becomes, for example, "postfix/smtpd".
<b>STANDARDS</b>
<a href="DATABASE_README.html">DATABASE_README</a>, Postfix lookup table overview
<b>LICENSE</b>
- The Secure Mailer license must be distributed with this
+ The Secure Mailer license must be distributed with this
software.
<b>AUTHOR(S)</b>
(default: defer)</b></DT><DD>
<p>
-The name of the <a href="defer.8.html">defer(8)</a> service. This service maintains a record
+The name of the defer service. This service is implemented by the
+<a href="bounce.8.html">bounce(8)</a> daemon and maintains a record
of failed delivery attempts and generates non-delivery notifications.
</p>
</DD>
-<DT><b><a name="plaintext_session_reject_code">plaintext_session_reject_code</a>
+<DT><b><a name="plaintext_reject_code">plaintext_reject_code</a>
(default: 450)</b></DT><DD>
<p>
(default: empty)</b></DT><DD>
<p> Optional lookup tables with the Postfix SMTP client TLS usage
-policy by next-hop domain name and by remote SMTP server hostname.
-</p>
-
-<p> Table format: domain names or server hostnames are specified
-on the left-hand side; no wildcards are allowed. On the right hand
-side specify one of the following keywords: </p>
+policy by next-hop destination and by remote SMTP server hostname.
+When both lookups succeed, 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). </p>
+
+<p> Specify a next-hop destination or server hostname on the left-hand
+side; no wildcards are allowed. The next-hop destination is either
+the recipient domain, or the destination specified with a <a href="transport.5.html">transport(5)</a>
+table, the <a href="postconf.5.html#relayhost">relayhost</a> parameter, or the <a href="postconf.5.html#relay_transport">relay_transport</a> parameter.
+On the right hand side specify one of the following keywords: </p>
<dl>
-<dt> NONE </dt> <dd>Don't use TLS at all. </dd>
-
-<dt> MAY </dt> <dd>Try to use STARTTLS if offered, otherwise use
-the unencrypted connection. </dd>
-
-<dt> MUST </dt> <dd>Require usage of STARTTLS, require that the
-remote SMTP server hostname matches the information in the remote
-SMTP server certificate, and require that the remote SMTP server
-certificate was issued by a trusted CA. </dd>
-
-<dt> MUST_NOPEERMATCH </dt> <dd>Require usage of STARTTLS, but do
-not require that the remote SMTP server hostname matches the
-information in the remote SMTP server certificate, or that the
-server certificate was issued by a trusted CA. </dd>
+<dt> NONE </dt> <dd> Don't use TLS at all. This overrides a less
+specific <b>MAY</b> lookup result from the alternate host or next-hop
+lookup key, and overrides the global <a href="postconf.5.html#smtp_use_tls">smtp_use_tls</a>, <a href="postconf.5.html#smtp_enforce_tls">smtp_enforce_tls</a>,
+and <a href="postconf.5.html#smtp_tls_enforce_peername">smtp_tls_enforce_peername</a> settings. </dd>
+
+<dt> MAY </dt> <dd> Try to use TLS if the server announces support,
+otherwise use the unencrypted connection. This has less precedence
+than a more specific result (including <b>NONE</b>) from the alternate
+host or next-hop lookup key, and has less precedence than the more
+specific global "<a href="postconf.5.html#smtp_enforce_tls">smtp_enforce_tls</a> = yes" or "<a href="postconf.5.html#smtp_tls_enforce_peername">smtp_tls_enforce_peername</a>
+= yes". </dd>
+
+<dt> MUST_NOPEERMATCH </dt> <dd> Require TLS encryption, but do not
+require that the remote SMTP server hostname matches the information
+in the remote SMTP server certificate, or that the server certificate
+was issued by a trusted CA. This overrides a less secure <b>NONE</b>
+or a less specific <b>MAY</b> lookup result from the alternate host
+or next-hop lookup key, and overrides the global <a href="postconf.5.html#smtp_use_tls">smtp_use_tls</a>,
+<a href="postconf.5.html#smtp_enforce_tls">smtp_enforce_tls</a> and <a href="postconf.5.html#smtp_tls_enforce_peername">smtp_tls_enforce_peername</a> settings. </dd>
+
+<dt> MUST </dt> <dd> Require TLS encryption, require that the remote
+SMTP server hostname matches the information in the remote SMTP
+server certificate, and require that the remote SMTP server certificate
+was issued by a trusted CA. This overrides a less secure <b>NONE</b>
+and <b>MUST_NOPEERMATCH</b> or a less specific <b>MAY</b> lookup
+result from the alternate host or next-hop lookup key, and overrides
+the global <a href="postconf.5.html#smtp_use_tls">smtp_use_tls</a>, <a href="postconf.5.html#smtp_enforce_tls">smtp_enforce_tls</a> and <a href="postconf.5.html#smtp_tls_enforce_peername">smtp_tls_enforce_peername</a>
+settings. </dd>
</dl>
-<p> Special hints for enforcement mode: since no secure DNS lookup
-mechanism is available, the recommended setup is: </p>
-
-<dl>
-
-<dt> Postfix 2.2.9 </dt>
-
-<dd> <ul>
-
-<li> Specify "<a href="postconf.5.html#smtp_cname_overrides_servername">smtp_cname_overrides_servername</a> = no". This avoids
-false hostname information in DNS CNAME records that could bypass
-a hostname-based TLS usage policy.
+<p> As long as no secure DNS lookup mechanism is available, false
+hostnames in MX or CNAME responses can change the server hostname
+that Postfix uses 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 the
+following steps: </p>
-<li> Specify local <a href="transport.5.html">transport(5)</a> table entries for sensitive domains
-with explicit <a href="smtp.8.html">smtp</a>:[mailhost] destinations. This avoids false
-hostname information in DNS MX records that could bypass a
-hostname-based TLS usage policy.
-
-<li> Specify MUST for these mail hosts in the <a href="postconf.5.html#smtp_tls_per_site">smtp_tls_per_site</a>
-table.
-
-</ul> </dd>
-
-<dt> Postfix < 2.2.9 </dt>
-
-<dd> <ul>
+<ul>
-<li> Specify local <a href="transport.5.html">transport(5)</a> table entries for sensitive domains
-with explicit <a href="smtp.8.html">smtp</a>:[mailhost] destinations. This avoids false
-hostname information in DNS MX records that could bypass a
-hostname-based TLS usage policy, but cannot avoid false hostname
-information in DNS CNAME records.
+<li> Disallow CNAME hostname overrides. In <a href="postconf.5.html">main.cf</a> specify
+"<a href="postconf.5.html#smtp_cname_overrides_servername">smtp_cname_overrides_servername</a> = 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.
-<li> Specify MUST for these mail hosts in the <a href="postconf.5.html#smtp_tls_per_site">smtp_tls_per_site</a>
-table.
+<li> Eliminate MX lookups. Specify local <a href="transport.5.html">transport(5)</a> table entries
+for sensitive domains with explicit <a href="smtp.8.html">smtp</a>:[mailhost] or <a href="smtp.8.html">smtp</a>:[mailhost]:port
+destinations. This prevents false hostname information in DNS MX
+records from changing the server hostname that Postfix uses for TLS
+policy lookup and server certificate verification.
-</ul> </dd>
+<li> Specify MUST for these mail hosts (including [ ] and port) in
+the <a href="postconf.5.html#smtp_tls_per_site">smtp_tls_per_site</a> table.
-</dl>
+</ul>
<p> </p>
<dt><b><a name="reject_multi_recipient_bounce">reject_multi_recipient_bounce</a></b></dt>
<dd>Reject the request when the envelope sender is the null address,
-and the message has multiple envelope recipients. Although this
-usage is technically allowed, it seems to have no legitimate
-application. <br> Note: this restriction can only work reliably
+and the message has multiple envelope recipients. This usage has
+rare but legitimate applications: under certain conditions,
+multi-recipient mail that was posted with the DSN option NOTIFY=NEVER
+may be forwarded with the null sender address.
+<br> Note: this restriction can only work reliably
when used in <a href="postconf.5.html#smtpd_data_restrictions">smtpd_data_restrictions</a> or
<a href="postconf.5.html#smtpd_end_of_data_restrictions">smtpd_end_of_data_restrictions</a>, because the total number of
recipients is not known at an earlier stage of the SMTP conversation.
restriction should not be used before the client has had a chance
to negotiate encryption with the AUTH or STARTTLS commands.
<br>
-The <a href="postconf.5.html#plaintext_session_reject_code">plaintext_session_reject_code</a> parameter specifies the response
+The <a href="postconf.5.html#plaintext_reject_code">plaintext_reject_code</a> parameter specifies the response
code for rejected requests (default: 450). This feature is available
in Postfix 2.3 and later. </dd>
(default: trace)</b></DT><DD>
<p>
-The name of the <a href="trace.8.html">trace(8)</a> service. This service maintains a record
+The name of the trace service. This service is implemented by the
+<a href="bounce.8.html">bounce(8)</a> daemon and maintains a record
of mail deliveries and produces a mail delivery report when verbose
delivery is requested with "<b>sendmail -v</b>".
</p>
Options:
<b>-c</b> <i>config</i><b>_</b><i>dir</i>
- The <b>main.cf</b> configuration file is in the named
+ The <a href="postconf.5.html"><b>main.cf</b></a> configuration file is in the named
directory instead of the default configuration
directory. See also the MAIL_CONFIG environment
setting below.
<b>ENVIRONMENT</b>
MAIL_CONFIG
- Directory with the <b>main.cf</b> file. In order to avoid
+ Directory with the <a href="postconf.5.html"><b>main.cf</b></a> file. In order to avoid
exploitation of set-group ID privileges, a non-
standard directory is allowed only if:
- <b>o</b> The name is listed in the standard <b>main.cf</b>
+ <b>o</b> The name is listed in the standard <a href="postconf.5.html"><b>main.cf</b></a>
file with the <b><a href="postconf.5.html#alternate_config_directories">alternate_config_directories</a></b>
configuration parameter.
<b>o</b> The command is invoked by the super-user.
<b>CONFIGURATION PARAMETERS</b>
- The following <b>main.cf</b> parameters are especially relevant
+ The following <a href="postconf.5.html"><b>main.cf</b></a> parameters are especially relevant
to this program. The text below provides only a parameter
summary. See <a href="postconf.5.html"><b>postconf</b>(5)</a> for more details including exam-
ples.
environment parameter.
<b><a href="postconf.5.html#config_directory">config_directory</a> (see 'postconf -d' output)</b>
- The default location of the Postfix main.cf and
- master.cf configuration files.
+ The default location of the Postfix <a href="postconf.5.html">main.cf</a> and
+ <a href="master.5.html">master.cf</a> configuration files.
<b><a href="postconf.5.html#import_environment">import_environment</a> (see 'postconf -d' output)</b>
The list of environment parameters that a Postfix
rounding white space is stripped off. Unlike with Postfix
alias databases, quotes cannot be used to protect lookup
keys that contain special characters such as `#' or white-
- space. The <i>key</i> is mapped to lowercase to make mapping
- lookups case insensitive.
+ space.
+
+ By default the lookup key is mapped to lowercase to make
+ the lookups case insensitive; as of Postfix 2.3 this case
+ folding happens only with tables whose lookup keys are
+ fixed-case strings such as btree:, dbm: or hash:. With
+ earlier versions, the lookup key is folded even with
+ tables where a lookup field can match both upper and lower
+ case text, such as <a href="regexp_table.5.html">regexp</a>: and <a href="pcre_table.5.html">pcre</a>:. This resulted in
+ loss of information with $<i>number</i> substitutions.
<b>COMMAND-LINE ARGUMENTS</b>
<b>-c</b> <i>config</i><b>_</b><i>dir</i>
- Read the <b>main.cf</b> configuration file in the named
+ Read the <a href="postconf.5.html"><b>main.cf</b></a> configuration file in the named
directory instead of the default configuration
directory.
keys was found.
<b>-f</b> Do not fold the lookup key to lower case while cre-
- ating or querying a map.
+ ating or querying a table.
<b>-i</b> Incremental mode. Read entries from standard input
and do not truncate an existing database. By
Enable verbose logging for debugging purposes.
<b>CONFIGURATION PARAMETERS</b>
- The following <b>main.cf</b> parameters are especially relevant
+ The following <a href="postconf.5.html"><b>main.cf</b></a> parameters are especially relevant
to this program. The text below provides only a parameter
summary. See <a href="postconf.5.html"><b>postconf</b>(5)</a> for more details including exam-
ples.
read Berkeley DB hash or btree tables.
<b><a href="postconf.5.html#config_directory">config_directory</a> (see 'postconf -d' output)</b>
- The default location of the Postfix main.cf and
- master.cf configuration files.
+ The default location of the Postfix <a href="postconf.5.html">main.cf</a> and
+ <a href="master.5.html">master.cf</a> configuration files.
<b><a href="postconf.5.html#default_database_type">default_database_type</a> (see 'postconf -d' output)</b>
The default database type for use in <a href="newaliases.1.html"><b>newaliases</b>(1)</a>,
The following options are recognized:
<b>-c</b> <i>config</i><b>_</b><i>dir</i>
- The <b>main.cf</b> configuration file is in the named
+ The <a href="postconf.5.html"><b>main.cf</b></a> configuration file is in the named
directory instead of the default configuration
directory. See also the MAIL_CONFIG environment
setting below.
<b>ENVIRONMENT</b>
MAIL_CONFIG
- Directory with the <b>main.cf</b> file. In order to avoid
+ Directory with the <a href="postconf.5.html"><b>main.cf</b></a> file. In order to avoid
exploitation of set-group ID privileges, a non-
standard directory is allowed only if:
- <b>o</b> The name is listed in the standard <b>main.cf</b>
+ <b>o</b> The name is listed in the standard <a href="postconf.5.html"><b>main.cf</b></a>
file with the <b><a href="postconf.5.html#alternate_config_directories">alternate_config_directories</a></b>
configuration parameter.
<b>o</b> The command is invoked by the super-user.
<b>CONFIGURATION PARAMETERS</b>
- The following <b>main.cf</b> parameters are especially relevant
+ The following <a href="postconf.5.html"><b>main.cf</b></a> parameters are especially relevant
to this program. The text below provides only a parameter
summary. See <a href="postconf.5.html"><b>postconf</b>(5)</a> for more details including exam-
ples.
environment parameter.
<b><a href="postconf.5.html#config_directory">config_directory</a> (see 'postconf -d' output)</b>
- The default location of the Postfix main.cf and
- master.cf configuration files.
+ The default location of the Postfix <a href="postconf.5.html">main.cf</a> and
+ <a href="master.5.html">master.cf</a> configuration files.
<b><a href="postconf.5.html#command_directory">command_directory</a> (see 'postconf -d' output)</b>
The location of all postfix administrative com-
In Postfix version 2.2 and later, the proxymap client rec-
ognizes requests to access a table for security-sensitive
purposes, and opens the table directly. This allows the
- same main.cf setting to be used by sensitive and non-sen-
+ same <a href="postconf.5.html">main.cf</a> setting to be used by sensitive and non-sen-
sitive processes.
<b>DIAGNOSTICS</b>
<b>CONFIGURATION PARAMETERS</b>
On busy mail systems a long time may pass before <a href="proxymap.8.html"><b>prox-</b></a>
- <a href="proxymap.8.html"><b>ymap</b>(8)</a> relevant changes to <b>main.cf</b> are picked up. Use the
+ <a href="proxymap.8.html"><b>ymap</b>(8)</a> relevant changes to <a href="postconf.5.html"><b>main.cf</b></a> are picked up. Use the
command "<b>postfix reload</b>" to speed up a change.
The text below provides only a parameter summary. See
<a href="postconf.5.html"><b>postconf</b>(5)</a> for more details including examples.
<b><a href="postconf.5.html#config_directory">config_directory</a> (see 'postconf -d' output)</b>
- The default location of the Postfix main.cf and
- master.cf configuration files.
+ The default location of the Postfix <a href="postconf.5.html">main.cf</a> and
+ <a href="master.5.html">master.cf</a> configuration files.
<b><a href="postconf.5.html#daemon_timeout">daemon_timeout</a> (18000s)</b>
How much time a Postfix daemon process may take to
is left up to the client to handle the situation.
<b>CONFIGURATION PARAMETERS</b>
- Changes to <b>main.cf</b> are picked up automatically, as
+ Changes to <a href="postconf.5.html"><b>main.cf</b></a> are picked up automatically, as
<a href="qmqpd.8.html"><b>qmqpd</b>(8)</a> processes run for only a limited amount of time.
Use the command "<b>postfix reload</b>" to speed up a change.
<b>MISCELLANEOUS CONTROLS</b>
<b><a href="postconf.5.html#config_directory">config_directory</a> (see 'postconf -d' output)</b>
- The default location of the Postfix main.cf and
- master.cf configuration files.
+ The default location of the Postfix <a href="postconf.5.html">main.cf</a> and
+ <a href="master.5.html">master.cf</a> configuration files.
<b><a href="postconf.5.html#daemon_timeout">daemon_timeout</a> (18000s)</b>
How much time a Postfix daemon process may take to
without the appropriate protocol specific handshake.
<b>CONFIGURATION PARAMETERS</b>
- Changes to <b>main.cf</b> are picked up automatically as
+ Changes to <a href="postconf.5.html"><b>main.cf</b></a> are picked up automatically as
<a href="scache.8.html"><b>scache</b>(8)</a> processes run for only a limited amount of time.
Use the command "<b>postfix reload</b>" to speed up a change.
<b>MISCELLANEOUS CONTROLS</b>
<b><a href="postconf.5.html#config_directory">config_directory</a> (see 'postconf -d' output)</b>
- The default location of the Postfix main.cf and
- master.cf configuration files.
+ The default location of the Postfix <a href="postconf.5.html">main.cf</a> and
+ <a href="master.5.html">master.cf</a> configuration files.
<b><a href="postconf.5.html#daemon_timeout">daemon_timeout</a> (18000s)</b>
How much time a Postfix daemon process may take to
These and other features can be selected by specifying the
appropriate combination of command-line options. Some fea-
- tures are controlled by parameters in the <b>main.cf</b> configu-
+ tures are controlled by parameters in the <a href="postconf.5.html"><b>main.cf</b></a> configu-
ration file.
The following options are recognized:
<b>-C</b> <i>config</i><b>_</b><i>file</i>
<b>-C</b> <i>config</i><b>_</b><i>dir</i>
- The path name of the Postfix <b>main.cf</b> file, or of
+ The path name of the Postfix <a href="postconf.5.html"><b>main.cf</b></a> file, or of
its parent directory. This information is ignored
with Postfix versions before 2.3.
- With older Postfix versions, specify a directory
- pathname with the MAIL_CONFIG environment variable
- to override the location of configuration files.
+ With all Postfix versions, you can specify a direc-
+ tory pathname with the MAIL_CONFIG environment
+ variable to override the location of configuration
+ files.
<b>-F</b> <i>full</i><b>_</b><i>name</i>
- Set the sender full name. This is used only with
+ Set the sender full name. This is used only with
messages that have no <b>From:</b> message header.
<b>-f</b> <i>sender</i>
Set the envelope sender address. This is the
- address where delivery problems are sent to. With
+ address where delivery problems are sent to. With
Postfix versions before 2.1, the <b>Errors-To:</b> message
header overrides the error return address.
- <b>-G</b> Gateway (relay) submission, as opposed to initial
- user submission. Either do not rewrite addresses
- at all, or update incomplete addresses with the
+ <b>-G</b> Gateway (relay) submission, as opposed to initial
+ user submission. Either do not rewrite addresses
+ at all, or update incomplete addresses with the
domain information specified with <b>remote_header_re-</b>
<b>write_domain</b>.
- This option is ignored before Postfix version 2.3.
+ This option is ignored before Postfix version 2.3.
<b>-h</b> <i>hop</i><b>_</b><i>count</i> (ignored)
- Hop count limit. Use the <b><a href="postconf.5.html#hopcount_limit">hopcount_limit</a></b> configura-
+ Hop count limit. Use the <b><a href="postconf.5.html#hopcount_limit">hopcount_limit</a></b> configura-
tion parameter instead.
- <b>-I</b> Initialize alias database. See the <b>newaliases</b> com-
+ <b>-I</b> Initialize alias database. See the <b>newaliases</b> com-
mand above.
- <b>-i</b> When reading a message from standard input, don't
- treat a line with only a <b>.</b> character as the end of
+ <b>-i</b> When reading a message from standard input, don't
+ treat a line with only a <b>.</b> character as the end of
input.
<b>-L</b> <i>label</i> (ignored)
- The logging label. Use the <b><a href="postconf.5.html#syslog_name">syslog_name</a></b> configura-
+ The logging label. Use the <b><a href="postconf.5.html#syslog_name">syslog_name</a></b> configura-
tion parameter instead.
<b>-m</b> (ignored)
Backwards compatibility.
<b>-N</b> <i>dsn</i> (default: 'delay, failure')
- Delivery status notification control. Specify
- either a comma-separated list with one or more of
- <b>failure</b> (send notification when delivery fails),
+ Delivery status notification control. Specify
+ either a comma-separated list with one or more of
+ <b>failure</b> (send notification when delivery fails),
<b>delay</b> (send notification when delivery is delayed),
- or <b>success</b> (send notification when the message is
- delivered); or specify <b>never</b> (don't send any noti-
+ or <b>success</b> (send notification when the message is
+ delivered); or specify <b>never</b> (don't send any noti-
fications at all).
This feature is available in Postfix 2.3 and later.
Backwards compatibility.
<b>-oA</b><i>alias</i><b>_</b><i>database</i>
- Non-default alias database. Specify <i>pathname</i> or
+ Non-default alias database. Specify <i>pathname</i> or
<i>type</i>:<i>pathname</i>. See <a href="postalias.1.html"><b>postalias</b>(1)</a> for details.
<b>-O</b> <i>option=value</i> (ignored)
<b>-o8</b> (ignored)
To send 8-bit or binary content, use an appropriate
- MIME encapsulation and specify the appropriate <b>-B</b>
+ MIME encapsulation and specify the appropriate <b>-B</b>
command-line option.
- <b>-oi</b> When reading a message from standard input, don't
- treat a line with only a <b>.</b> character as the end of
+ <b>-oi</b> When reading a message from standard input, don't
+ treat a line with only a <b>.</b> character as the end of
input.
<b>-om</b> (ignored)
- The sender is never eliminated from alias etc.
+ The sender is never eliminated from alias etc.
expansions.
<b>-o</b> <i>x value</i> (ignored)
- Set option <i>x</i> to <i>value</i>. Use the equivalent configu-
- ration parameter in <b>main.cf</b> instead.
+ Set option <i>x</i> to <i>value</i>. Use the equivalent configu-
+ ration parameter in <a href="postconf.5.html"><b>main.cf</b></a> instead.
<b>-r</b> <i>sender</i>
Set the envelope sender address. This is the
- address where delivery problems are sent to. With
+ address where delivery problems are sent to. With
Postfix versions before 2.1, the <b>Errors-To:</b> message
header overrides the error return address.
<b>-R</b> <i>return</i><b>_</b><i>limit</i> (ignored)
- Limit the size of bounced mail. Use the
- <b><a href="postconf.5.html#bounce_size_limit">bounce_size_limit</a></b> configuration parameter instead.
+ Limit the size of bounced mail. Use the
+ <b><a href="postconf.5.html#bounce_size_limit">bounce_size_limit</a></b> configuration parameter instead.
- <b>-q</b> Attempt to deliver all queued mail. This is imple-
+ <b>-q</b> Attempt to deliver all queued mail. This is imple-
mented by executing the <a href="postqueue.1.html"><b>postqueue</b>(1)</a> command.
Warning: flushing undeliverable mail frequently
- will result in poor delivery performance of all
+ will result in poor delivery performance of all
other mail.
<b>-q</b><i>interval</i> (ignored)
- The interval between queue runs. Use the
+ The interval between queue runs. Use the
<b><a href="postconf.5.html#queue_run_delay">queue_run_delay</a></b> configuration parameter instead.
<b>-qR</b><i>site</i>
- Schedule immediate delivery of all mail that is
+ Schedule immediate delivery of all mail that is
queued for the named <i>site</i>. This option accepts only
- <i>site</i> names that are eligible for the "fast flush"
- service, and is implemented by executing the
+ <i>site</i> names that are eligible for the "fast flush"
+ service, and is implemented by executing the
<a href="postqueue.1.html"><b>postqueue</b>(1)</a> command. See <a href="flush.8.html"><b>flush</b>(8)</a> for more infor-
mation about the "fast flush" service.
<b>-qS</b><i>site</i>
- This command is not implemented. Use the slower
+ This command is not implemented. Use the slower
"<b>sendmail -q</b>" command instead.
- <b>-t</b> Extract recipients from message headers. These are
- added to any recipients specified on the command
+ <b>-t</b> Extract recipients from message headers. These are
+ added to any recipients specified on the command
line.
- With Postfix versions prior to 2.1, this option
- requires that no recipient addresses are specified
+ With Postfix versions prior to 2.1, this option
+ requires that no recipient addresses are specified
on the command line.
<b>-U</b> (ignored)
This feature is available in Postfix 2.3 and later.
<b>-XV</b> (Postfix 2.2 and earlier: <b>-V</b>)
- Variable Envelope Return Path. Given an envelope
- sender address of the form <i>owner-listname</i>@<i>origin</i>,
- each recipient <i>user</i>@<i>domain</i> receives mail with a
+ Variable Envelope Return Path. Given an envelope
+ sender address of the form <i>owner-listname</i>@<i>origin</i>,
+ each recipient <i>user</i>@<i>domain</i> receives mail with a
personalized envelope sender address.
- By default, the personalized envelope sender
- address is <i>owner-listname</i><b>+</b><i>user</i><b>=</b><i>domain</i>@<i>origin</i>. The
- default <b>+</b> and <b>=</b> characters are configurable with
- the <b><a href="postconf.5.html#default_verp_delimiters">default_verp_delimiters</a></b> configuration parame-
+ By default, the personalized envelope sender
+ address is <i>owner-listname</i><b>+</b><i>user</i><b>=</b><i>domain</i>@<i>origin</i>. The
+ default <b>+</b> and <b>=</b> characters are configurable with
+ the <b><a href="postconf.5.html#default_verp_delimiters">default_verp_delimiters</a></b> configuration parame-
ter.
<b>-XV</b><i>xy</i> (Postfix 2.2 and earlier: <b>-V</b><i>xy</i>)
- As <b>-XV</b>, but uses <i>x</i> and <i>y</i> as the VERP delimiter
- characters, instead of the characters specified
- with the <b><a href="postconf.5.html#default_verp_delimiters">default_verp_delimiters</a></b> configuration
+ As <b>-XV</b>, but uses <i>x</i> and <i>y</i> as the VERP delimiter
+ characters, instead of the characters specified
+ with the <b><a href="postconf.5.html#default_verp_delimiters">default_verp_delimiters</a></b> configuration
parameter.
- <b>-v</b> Send an email report of the first delivery attempt
- (Postfix versions 2.1 and later). Mail delivery
- always happens in the background. When multiple <b>-v</b>
+ <b>-v</b> Send an email report of the first delivery attempt
+ (Postfix versions 2.1 and later). Mail delivery
+ always happens in the background. When multiple <b>-v</b>
options are given, enable verbose logging for
debugging purposes.
<b>-X</b> <i>log</i><b>_</b><i>file</i> (ignored)
- Log mailer traffic. Use the <b><a href="postconf.5.html#debug_peer_list">debug_peer_list</a></b> and
- <b><a href="postconf.5.html#debug_peer_level">debug_peer_level</a></b> configuration parameters instead.
+ Log mailer traffic. Use the <b><a href="postconf.5.html#debug_peer_list">debug_peer_list</a></b> and
+ <b><a href="postconf.5.html#debug_peer_level">debug_peer_level</a></b> configuration parameters instead.
<b>SECURITY</b>
- By design, this program is not set-user (or group) id.
- However, it must handle data from untrusted users or
- untrusted machines. Thus, the usual precautions need to
+ By design, this program is not set-user (or group) id.
+ However, it must handle data from untrusted users or
+ untrusted machines. Thus, the usual precautions need to
be taken against malicious inputs.
<b>DIAGNOSTICS</b>
- Problems are logged to <b>syslogd</b>(8) and to the standard
+ Problems are logged to <b>syslogd</b>(8) and to the standard
error stream.
<b>ENVIRONMENT</b>
<b>MAIL_DEBUG</b>
Enable debugging with an external command, as spec-
- ified with the <b><a href="postconf.5.html#debugger_command">debugger_command</a></b> configuration
+ ified with the <b><a href="postconf.5.html#debugger_command">debugger_command</a></b> configuration
parameter.
<b>CONFIGURATION PARAMETERS</b>
- The following <b>main.cf</b> parameters are especially relevant
+ The following <a href="postconf.5.html"><b>main.cf</b></a> parameters are especially relevant
to this program. The text below provides only a parameter
- summary. See <a href="postconf.5.html"><b>postconf</b>(5)</a> for more details including exam-
+ summary. See <a href="postconf.5.html"><b>postconf</b>(5)</a> for more details including exam-
ples.
<b>TROUBLE SHOOTING CONTROLS</b>
- The <a href="DEBUG_README.html">DEBUG_README</a> file gives examples of how to trouble
+ The <a href="DEBUG_README.html">DEBUG_README</a> file gives examples of how to trouble
shoot a Postfix system.
<b><a href="postconf.5.html#debugger_command">debugger_command</a> (empty)</b>
mon program is invoked with the -D option.
<b><a href="postconf.5.html#debug_peer_level">debug_peer_level</a> (2)</b>
- The increment in verbose logging level when a
- remote client or server matches a pattern in the
+ The increment in verbose logging level when a
+ remote client or server matches a pattern in the
<a href="postconf.5.html#debug_peer_list">debug_peer_list</a> parameter.
<b><a href="postconf.5.html#debug_peer_list">debug_peer_list</a> (empty)</b>
- Optional list of remote client or server hostname
- or network address patterns that cause the verbose
- logging level to increase by the amount specified
+ Optional list of remote client or server hostname
+ or network address patterns that cause the verbose
+ logging level to increase by the amount specified
in $<a href="postconf.5.html#debug_peer_level">debug_peer_level</a>.
<b>ACCESS CONTROLS</b>
Available in Postfix version 2.2 and later:
<b><a href="postconf.5.html#authorized_flush_users">authorized_flush_users</a> (static:anyone)</b>
- List of users who are authorized to flush the
+ List of users who are authorized to flush the
queue.
<b><a href="postconf.5.html#authorized_mailq_users">authorized_mailq_users</a> (static:anyone)</b>
List of users who are authorized to view the queue.
<b><a href="postconf.5.html#authorized_submit_users">authorized_submit_users</a> (static:anyone)</b>
- List of users who are authorized to submit mail
- with the <a href="sendmail.1.html"><b>sendmail</b>(1)</a> command (and with the privi-
+ List of users who are authorized to submit mail
+ with the <a href="sendmail.1.html"><b>sendmail</b>(1)</a> command (and with the privi-
leged <a href="postdrop.1.html"><b>postdrop</b>(1)</a> helper command).
<b>RESOURCE AND RATE CONTROLS</b>
sent in a non-delivery notification.
<b><a href="postconf.5.html#fork_attempts">fork_attempts</a> (5)</b>
- The maximal number of attempts to fork() a child
+ The maximal number of attempts to fork() a child
process.
<b><a href="postconf.5.html#fork_delay">fork_delay</a> (1s)</b>
process.
<b><a href="postconf.5.html#hopcount_limit">hopcount_limit</a> (50)</b>
- The maximal number of Received: message headers
+ The maximal number of Received: message headers
that is allowed in the primary message headers.
<b><a href="postconf.5.html#queue_run_delay">queue_run_delay</a> (1000s)</b>
- The time between <a href="QSHAPE_README.html#deferred_queue">deferred queue</a> scans by the queue
+ The time between <a href="QSHAPE_README.html#deferred_queue">deferred queue</a> scans by the queue
manager.
<b>FAST FLUSH CONTROLS</b>
<b><a href="postconf.5.html#fast_flush_domains">fast_flush_domains</a> ($<a href="postconf.5.html#relay_domains">relay_domains</a>)</b>
Optional list of destinations that are eligible for
- per-destination logfiles with mail that is queued
+ per-destination logfiles with mail that is queued
to those destinations.
<b>VERP CONTROLS</b>
The <a href="VERP_README.html">VERP_README</a> file describes configuration and operation
- details of Postfix support for variable envelope return
+ details of Postfix support for variable envelope return
path addresses.
<b><a href="postconf.5.html#default_verp_delimiters">default_verp_delimiters</a> (+=)</b>
The two default VERP delimiter characters.
<b><a href="postconf.5.html#verp_delimiter_filter">verp_delimiter_filter</a> (-=+)</b>
- The characters Postfix accepts as VERP delimiter
- characters on the Postfix <a href="sendmail.1.html"><b>sendmail</b>(1)</a> command line
+ The characters Postfix accepts as VERP delimiter
+ characters on the Postfix <a href="sendmail.1.html"><b>sendmail</b>(1)</a> command line
and in SMTP commands.
<b>MISCELLANEOUS CONTROLS</b>
<b><a href="postconf.5.html#alias_database">alias_database</a> (see 'postconf -d' output)</b>
- The alias databases for <a href="local.8.html"><b>local</b>(8)</a> delivery that are
+ The alias databases for <a href="local.8.html"><b>local</b>(8)</a> delivery that are
updated with "<b>newaliases</b>" or with "<b>sendmail -bi</b>".
<b><a href="postconf.5.html#command_directory">command_directory</a> (see 'postconf -d' output)</b>
- The location of all postfix administrative com-
+ The location of all postfix administrative com-
mands.
<b><a href="postconf.5.html#config_directory">config_directory</a> (see 'postconf -d' output)</b>
- The default location of the Postfix main.cf and
- master.cf configuration files.
+ The default location of the Postfix <a href="postconf.5.html">main.cf</a> and
+ <a href="master.5.html">master.cf</a> configuration files.
<b><a href="postconf.5.html#daemon_directory">daemon_directory</a> (see 'postconf -d' output)</b>
- The directory with Postfix support programs and
+ The directory with Postfix support programs and
daemon programs.
<b><a href="postconf.5.html#default_database_type">default_database_type</a> (see 'postconf -d' output)</b>
<a href="postalias.1.html"><b>postalias</b>(1)</a> and <a href="postmap.1.html"><b>postmap</b>(1)</a> commands.
<b><a href="postconf.5.html#delay_warning_time">delay_warning_time</a> (0h)</b>
- The time after which the sender receives the mes-
+ The time after which the sender receives the mes-
sage headers of mail that is still queued.
<b><a href="postconf.5.html#enable_errors_to">enable_errors_to</a> (no)</b>
- Report mail delivery errors to the address speci-
- fied with the non-standard Errors-To: message
- header, instead of the envelope sender address
- (this feature is removed with Postfix 2.2, is
- turned off by default with Postfix 2.1, and is
- always turned on with older Postfix versions).
+ Report mail delivery errors to the address speci-
+ fied with the non-standard Errors-To: message
+ header, instead of the envelope sender address
+ (this feature is removed with Postfix version 2.2,
+ is turned off by default with Postfix version 2.1,
+ and is always turned on with older Postfix ver-
+ sions).
<b><a href="postconf.5.html#mail_owner">mail_owner</a> (postfix)</b>
The UNIX system account that owns the Postfix queue
<a href="postconf.5.html#reject_non_fqdn_sender">reject_non_fqdn_sender</a> or <a href="postconf.5.html#reject_non_fqdn_recipient">reject_non_fqdn_recipient</a>
restriction.
- <b>plaintext_reject_code (450)</b>
+ <b><a href="postconf.5.html#plaintext_reject_code">plaintext_reject_code</a> (450)</b>
The numerical Postfix SMTP server response code
when a request is rejected by the <b>reject_plain-</b>
<b>text_session</b> restriction.
files.
<b>CONFIGURATION PARAMETERS</b>
- Changes to <b>main.cf</b> are not picked up automatically,
+ Changes to <a href="postconf.5.html"><b>main.cf</b></a> are not picked up automatically,
because <a href="tlsmgr.8.html"><b>tlsmgr</b>(8)</a> is a persistent processes. Use the com-
mand "<b>postfix reload</b>" after a configuration change.
<b>MISCELLANEOUS CONTROLS</b>
<b><a href="postconf.5.html#config_directory">config_directory</a> (see 'postconf -d' output)</b>
- The default location of the Postfix main.cf and
- master.cf configuration files.
+ The default location of the Postfix <a href="postconf.5.html">main.cf</a> and
+ <a href="master.5.html">master.cf</a> configuration files.
<b><a href="postconf.5.html#daemon_timeout">daemon_timeout</a> (18000s)</b>
How much time a Postfix daemon process may take to
<i>transport</i>
The delivery agent to use. This is the first
- field of an entry in the <b>master.cf</b> file.
+ field of an entry in the <a href="master.5.html"><b>master.cf</b></a> file.
<i>nexthop</i>
The host to send to and optional delivery
Problems and transactions are logged to <b>syslogd</b>(8).
<b>CONFIGURATION PARAMETERS</b>
- On busy mail systems a long time may pass before a <b>main.cf</b>
+ On busy mail systems a long time may pass before a <a href="postconf.5.html"><b>main.cf</b></a>
change affecting <a href="trivial-rewrite.8.html"><b>trivial-rewrite</b>(8)</a> is picked up. Use the
command "<b>postfix reload</b>" to speed up a change.
<b>MISCELLANEOUS CONTROLS</b>
<b><a href="postconf.5.html#config_directory">config_directory</a> (see 'postconf -d' output)</b>
- The default location of the Postfix main.cf and
- master.cf configuration files.
+ The default location of the Postfix <a href="postconf.5.html">main.cf</a> and
+ <a href="master.5.html">master.cf</a> configuration files.
<b><a href="postconf.5.html#daemon_timeout">daemon_timeout</a> (18000s)</b>
How much time a Postfix daemon process may take to
maintaining three tables, use an LDAP or MYSQL database.
<b>CONFIGURATION PARAMETERS</b>
- Changes to <b>main.cf</b> are picked up automatically, as <a href="virtual.8.html"><b>vir-</b></a>
+ Changes to <a href="postconf.5.html"><b>main.cf</b></a> are picked up automatically, as <a href="virtual.8.html"><b>vir-</b></a>
<a href="virtual.8.html"><b>tual</b>(8)</a> processes run for only a limited amount of time.
Use the command "<b>postfix reload</b>" to speed up a change.
<a href="postconf.5.html#virtual_transport">tual_transport</a> mail delivery transport.
<b><a href="postconf.5.html#virtual_transport">virtual_transport</a> (virtual)</b>
- The default mail delivery transport for domains
- that match the $<a href="postconf.5.html#virtual_mailbox_domains">virtual_mailbox_domains</a> parameter
- value.
+ The default mail delivery transport and next-hop
+ destination for final delivery to domains listed
+ with $<a href="postconf.5.html#virtual_mailbox_domains">virtual_mailbox_domains</a>.
<b>LOCKING CONTROLS</b>
<b><a href="postconf.5.html#virtual_mailbox_lock">virtual_mailbox_lock</a> (see 'postconf -d' output)</b>
<b>MISCELLANEOUS CONTROLS</b>
<b><a href="postconf.5.html#config_directory">config_directory</a> (see 'postconf -d' output)</b>
- The default location of the Postfix main.cf and
- master.cf configuration files.
+ The default location of the Postfix <a href="postconf.5.html">main.cf</a> and
+ <a href="master.5.html">master.cf</a> configuration files.
<b><a href="postconf.5.html#daemon_timeout">daemon_timeout</a> (18000s)</b>
How much time a Postfix daemon process may take to
man8/bounce.8: ../src/bounce/bounce.c
../mantools/fixman ../proto/postconf.proto $? >junk && \
- (cmp -s junk $? || mv junk $?)
+ (cmp -s junk $? || mv junk $?) && rm -f junk
../mantools/srctoman $? >$@
man8/defer.8:
man8/cleanup.8: ../src/cleanup/cleanup.c
../mantools/fixman ../proto/postconf.proto $? >junk && \
- (cmp -s junk $? || mv junk $?)
+ (cmp -s junk $? || mv junk $?) && rm -f junk
../mantools/srctoman $? >$@
man8/anvil.8: ../src/anvil/anvil.c
../mantools/fixman ../proto/postconf.proto $? >junk && \
- (cmp -s junk $? || mv junk $?)
+ (cmp -s junk $? || mv junk $?) && rm -f junk
../mantools/srctoman $? >$@
man8/scache.8: ../src/scache/scache.c
../mantools/fixman ../proto/postconf.proto $? >junk && \
- (cmp -s junk $? || mv junk $?)
+ (cmp -s junk $? || mv junk $?) && rm -f junk
../mantools/srctoman $? >$@
man8/discard.8: ../src/discard/discard.c
../mantools/fixman ../proto/postconf.proto $? >junk && \
- (cmp -s junk $? || mv junk $?)
+ (cmp -s junk $? || mv junk $?) && rm -f junk
../mantools/srctoman $? >$@
man8/error.8: ../src/error/error.c
../mantools/fixman ../proto/postconf.proto $? >junk && \
- (cmp -s junk $? || mv junk $?)
+ (cmp -s junk $? || mv junk $?) && rm -f junk
../mantools/srctoman $? >$@
man8/flush.8: ../src/flush/flush.c
../mantools/fixman ../proto/postconf.proto $? >junk && \
- (cmp -s junk $? || mv junk $?)
+ (cmp -s junk $? || mv junk $?) && rm -f junk
../mantools/srctoman $? >$@
man8/local.8: ../src/local/local.c
../mantools/fixman ../proto/postconf.proto $? >junk && \
- (cmp -s junk $? || mv junk $?)
+ (cmp -s junk $? || mv junk $?) && rm -f junk
../mantools/srctoman $? >$@
man8/lmtp.8:
man8/master.8: ../src/master/master.c
../mantools/fixman ../proto/postconf.proto $? >junk && \
- (cmp -s junk $? || mv junk $?)
+ (cmp -s junk $? || mv junk $?) && rm -f junk
../mantools/srctoman $? >$@
man8/oqmgr.8: ../src/oqmgr/qmgr.c
../mantools/fixman ../proto/postconf.proto $? >junk && \
- (cmp -s junk $? || mv junk $?)
+ (cmp -s junk $? || mv junk $?) && rm -f junk
../mantools/srctoman $? | \
sed -e 's/qmgr[^_]/o&/' \
-e 's/qmgr$$/o&/' \
man8/pickup.8: ../src/pickup/pickup.c
../mantools/fixman ../proto/postconf.proto $? >junk && \
- (cmp -s junk $? || mv junk $?)
+ (cmp -s junk $? || mv junk $?) && rm -f junk
../mantools/srctoman $? >$@
man8/pipe.8: ../src/pipe/pipe.c
../mantools/fixman ../proto/postconf.proto $? >junk && \
- (cmp -s junk $? || mv junk $?)
+ (cmp -s junk $? || mv junk $?) && rm -f junk
../mantools/srctoman $? >$@
man8/proxymap.8: ../src/proxymap/proxymap.c
../mantools/fixman ../proto/postconf.proto $? >junk && \
- (cmp -s junk $? || mv junk $?)
+ (cmp -s junk $? || mv junk $?) && rm -f junk
../mantools/srctoman $? >$@
man8/qmgr.8: ../src/qmgr/qmgr.c
../mantools/fixman ../proto/postconf.proto $? >junk && \
- (cmp -s junk $? || mv junk $?)
+ (cmp -s junk $? || mv junk $?) && rm -f junk
../mantools/srctoman $? >$@
man8/qmqpd.8: ../src/qmqpd/qmqpd.c
../mantools/fixman ../proto/postconf.proto $? >junk && \
- (cmp -s junk $? || mv junk $?)
+ (cmp -s junk $? || mv junk $?) && rm -f junk
../mantools/srctoman $? >$@
man8/showq.8: ../src/showq/showq.c
../mantools/fixman ../proto/postconf.proto $? >junk && \
- (cmp -s junk $? || mv junk $?)
+ (cmp -s junk $? || mv junk $?) && rm -f junk
../mantools/srctoman $? >$@
man8/spawn.8: ../src/spawn/spawn.c
../mantools/fixman ../proto/postconf.proto $? >junk && \
- (cmp -s junk $? || mv junk $?)
+ (cmp -s junk $? || mv junk $?) && rm -f junk
../mantools/srctoman $? >$@
man8/smtp.8: ../src/smtp/smtp.c
../mantools/fixman ../proto/postconf.proto $? >junk && \
- (cmp -s junk $? || mv junk $?)
+ (cmp -s junk $? || mv junk $?) && rm -f junk
../mantools/srctoman $? >$@
man8/smtpd.8: ../src/smtpd/smtpd.c
../mantools/fixman ../proto/postconf.proto $? >junk && \
- (cmp -s junk $? || mv junk $?)
+ (cmp -s junk $? || mv junk $?) && rm -f junk
../mantools/srctoman $? >$@
man8/virtual.8: ../src/virtual/virtual.c
../mantools/fixman ../proto/postconf.proto $? >junk && \
- (cmp -s junk $? || mv junk $?)
+ (cmp -s junk $? || mv junk $?) && rm -f junk
../mantools/srctoman $? >$@
man8/verify.8: ../src/verify/verify.c
../mantools/fixman ../proto/postconf.proto $? >junk && \
- (cmp -s junk $? || mv junk $?)
+ (cmp -s junk $? || mv junk $?) && rm -f junk
../mantools/srctoman $? >$@
man8/trace.8:
man8/tlsmgr.8: ../src/tlsmgr/tlsmgr.c
../mantools/fixman ../proto/postconf.proto $? >junk && \
- (cmp -s junk $? || mv junk $?)
+ (cmp -s junk $? || mv junk $?) && rm -f junk
../mantools/srctoman $? >$@
man8/trivial-rewrite.8: ../src/trivial-rewrite/trivial-rewrite.c
../mantools/fixman ../proto/postconf.proto $? >junk && \
- (cmp -s junk $? || mv junk $?)
+ (cmp -s junk $? || mv junk $?) && rm -f junk
../mantools/srctoman $? >$@
man1/postalias.1: ../src/postalias/postalias.c
../mantools/fixman ../proto/postconf.proto $? >junk && \
- (cmp -s junk $? || mv junk $?)
+ (cmp -s junk $? || mv junk $?) && rm -f junk
../mantools/srctoman $? >$@
man1/postcat.1: ../src/postcat/postcat.c
../mantools/fixman ../proto/postconf.proto $? >junk && \
- (cmp -s junk $? || mv junk $?)
+ (cmp -s junk $? || mv junk $?) && rm -f junk
../mantools/srctoman $? >$@
man1/postconf.1: ../src/postconf/postconf.c
../mantools/fixman ../proto/postconf.proto $? >junk && \
- (cmp -s junk $? || mv junk $?)
+ (cmp -s junk $? || mv junk $?) && rm -f junk
../mantools/srctoman $? >$@
man1/postdrop.1: ../src/postdrop/postdrop.c
../mantools/fixman ../proto/postconf.proto $? >junk && \
- (cmp -s junk $? || mv junk $?)
+ (cmp -s junk $? || mv junk $?) && rm -f junk
../mantools/srctoman $? >$@
man1/postfix.1: ../src/postfix/postfix.c
../mantools/fixman ../proto/postconf.proto $? >junk && \
- (cmp -s junk $? || mv junk $?)
+ (cmp -s junk $? || mv junk $?) && rm -f junk
../mantools/srctoman $? >$@
man1/postkick.1: ../src/postkick/postkick.c
../mantools/fixman ../proto/postconf.proto $? >junk && \
- (cmp -s junk $? || mv junk $?)
+ (cmp -s junk $? || mv junk $?) && rm -f junk
../mantools/srctoman $? >$@
man1/postlock.1: ../src/postlock/postlock.c
../mantools/fixman ../proto/postconf.proto $? >junk && \
- (cmp -s junk $? || mv junk $?)
+ (cmp -s junk $? || mv junk $?) && rm -f junk
../mantools/srctoman $? >$@
man1/postlog.1: ../src/postlog/postlog.c
../mantools/fixman ../proto/postconf.proto $? >junk && \
- (cmp -s junk $? || mv junk $?)
+ (cmp -s junk $? || mv junk $?) && rm -f junk
../mantools/srctoman $? >$@
man1/postmap.1: ../src/postmap/postmap.c
../mantools/fixman ../proto/postconf.proto $? >junk && \
- (cmp -s junk $? || mv junk $?)
+ (cmp -s junk $? || mv junk $?) && rm -f junk
../mantools/srctoman $? >$@
man1/postqueue.1: ../src/postqueue/postqueue.c
../mantools/fixman ../proto/postconf.proto $? >junk && \
- (cmp -s junk $? || mv junk $?)
+ (cmp -s junk $? || mv junk $?) && rm -f junk
../mantools/srctoman $? >$@
man1/postsuper.1: ../src/postsuper/postsuper.c
../mantools/fixman ../proto/postconf.proto $? >junk && \
- (cmp -s junk $? || mv junk $?)
+ (cmp -s junk $? || mv junk $?) && rm -f junk
../mantools/srctoman $? >$@
man1/sendmail.1: ../src/sendmail/sendmail.c
../mantools/fixman ../proto/postconf.proto $? >junk && \
- (cmp -s junk $? || mv junk $?)
+ (cmp -s junk $? || mv junk $?) && rm -f junk
../mantools/srctoman $? >$@
man1/mailq.1:
man1/smtp-sink.1: ../src/smtpstone/smtp-sink.c
../mantools/fixman ../proto/postconf.proto $? >junk && \
- (cmp -s junk $? || mv junk $?)
+ (cmp -s junk $? || mv junk $?) && rm -f junk
../mantools/srctoman $? >$@
man1/smtp-source.1: ../src/smtpstone/smtp-source.c
../mantools/fixman ../proto/postconf.proto $? >junk && \
- (cmp -s junk $? || mv junk $?)
+ (cmp -s junk $? || mv junk $?) && rm -f junk
../mantools/srctoman $? >$@
man5/tcp_table.5: ../proto/tcp_table
man1/qmqp-sink.1: ../src/smtpstone/qmqp-sink.c
../mantools/fixman ../proto/postconf.proto $? >junk && \
- (cmp -s junk $? || mv junk $?)
+ (cmp -s junk $? || mv junk $?) && rm -f junk
../mantools/srctoman $? >$@
man1/qmqp-source.1: ../src/smtpstone/qmqp-source.c
../mantools/fixman ../proto/postconf.proto $? >junk && \
- (cmp -s junk $? || mv junk $?)
+ (cmp -s junk $? || mv junk $?) && rm -f junk
../mantools/srctoman $? >$@
man1/qshape.1: ../auxiliary/qshape/qshape.pl
#../mantools/fixman ../proto/postconf.proto $? >junk && \
- # (cmp -s junk $? || mv junk $?)
+ # (cmp -s junk $? || mv junk $?) && rm -f junk
../mantools/srctoman - $? >$@
The format of Postfix alias input files is described in
\fBaliases\fR(5).
+By default the lookup key is mapped to lowercase to make
+the lookups case insensitive; as of Postfix 2.3 this case
+folding happens only with tables whose lookup keys are
+fixed-case strings such as btree:, dbm: or hash:. With
+earlier versions, the lookup key is folded even with tables
+where a lookup field can match both upper and lower case
+text, such as regexp: and pcre:. This resulted in loss of
+information with $\fInumber\fR substitutions.
+
Options:
.IP "\fB-c \fIconfig_dir\fR"
Read the \fBmain.cf\fR configuration file in the named directory
when at least one of the requested keys was found.
.IP \fB-f\fR
Do not fold the lookup key to lower case while creating or querying
-a map.
+a table.
.IP \fB-i\fR
Incremental mode. Read entries from standard input and do not
truncate an existing database. By default, \fBpostalias\fR(1) creates
The \fIkey\fR and \fIvalue\fR are processed as is, except that
surrounding white space is stripped off. Unlike with Postfix alias
databases, quotes cannot be used to protect lookup keys that contain
-special characters such as `#' or whitespace. The \fIkey\fR is mapped
-to lowercase to make mapping lookups case insensitive.
+special characters such as `#' or whitespace.
+
+By default the lookup key is mapped to lowercase to make
+the lookups case insensitive; as of Postfix 2.3 this case
+folding happens only with tables whose lookup keys are
+fixed-case strings such as btree:, dbm: or hash:. With
+earlier versions, the lookup key is folded even with tables
+where a lookup field can match both upper and lower case
+text, such as regexp: and pcre:. This resulted in loss of
+information with $\fInumber\fR substitutions.
.SH "COMMAND-LINE ARGUMENTS"
.na
.nf
when at least one of the requested keys was found.
.IP \fB-f\fR
Do not fold the lookup key to lower case while creating or querying
-a map.
+a table.
.IP \fB-i\fR
Incremental mode. Read entries from standard input and do not
truncate an existing database. By default, \fBpostmap\fR(1) creates
parent directory. This information is ignored with Postfix
versions before 2.3.
-With older Postfix versions, specify a directory pathname
+With all Postfix versions, you can specify a directory pathname
with the MAIL_CONFIG environment variable to override the
location of configuration files.
.IP "\fB-F \fIfull_name\fR
.IP "\fBenable_errors_to (no)\fR"
Report mail delivery errors to the address specified with the
non-standard Errors-To: message header, instead of the envelope
-sender address (this feature is removed with Postfix 2.2, is
-turned off by default with Postfix 2.1, and is always turned on
+sender address (this feature is removed with Postfix version 2.2, is
+turned off by default with Postfix version 2.1, and is always turned on
with older Postfix versions).
.IP "\fBmail_owner (postfix)\fR"
The UNIX system account that owns the Postfix queue and most Postfix
.PP
Do not change this unless you have a complete understanding of RFC 821.
.SH defer_service_name (default: defer)
-The name of the \fBdefer\fR(8) service. This service maintains a record
+The name of the defer service. This service is implemented by the
+\fBbounce\fR(8) daemon and maintains a record
of failed delivery attempts and generates non-delivery notifications.
.PP
This feature is available in Postfix 2.0 and later.
submissions from the Postfix maildrop queue.
.PP
This feature is available in Postfix 2.0 and later.
-.SH plaintext_session_reject_code (default: 450)
+.SH plaintext_reject_code (default: 450)
The numerical Postfix SMTP server response code when a request
is rejected by the \fBreject_plaintext_session\fR restriction.
.PP
.ft R
.SH smtp_tls_per_site (default: empty)
Optional lookup tables with the Postfix SMTP client TLS usage
-policy by next-hop domain name and by remote SMTP server hostname.
-.PP
-Table format: domain names or server hostnames are specified
-on the left-hand side; no wildcards are allowed. On the right hand
-side specify one of the following keywords:
+policy by next-hop destination and by remote SMTP server hostname.
+When both lookups succeed, 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).
+.PP
+Specify a next-hop destination or server hostname on the left-hand
+side; no wildcards are allowed. The next-hop destination is either
+the recipient domain, or the destination specified with a \fBtransport\fR(5)
+table, the relayhost parameter, or the relay_transport parameter.
+On the right hand side specify one of the following keywords:
.IP "NONE"
-Don't use TLS at all.
+Don't use TLS at all. This overrides a less
+specific \fBMAY\fR 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.
.IP "MAY"
-Try to use STARTTLS if offered, otherwise use
-the unencrypted connection.
-.IP "MUST"
-Require usage of STARTTLS, require that the
-remote SMTP server hostname matches the information in the remote
-SMTP server certificate, and require that the remote SMTP server
-certificate was issued by a trusted CA.
+Try to use TLS if the server announces support,
+otherwise use the unencrypted connection. This has less precedence
+than a more specific result (including \fBNONE\fR) 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".
.IP "MUST_NOPEERMATCH"
-Require usage of STARTTLS, but do
-not require that the remote SMTP server hostname matches the
-information in the remote SMTP server certificate, or that the
-server certificate was issued by a trusted CA.
-.PP
-Special hints for enforcement mode: since no secure DNS lookup
-mechanism is available, the recommended setup is:
-.IP "Postfix 2.2.9"
-.IP \(bu
-Specify "smtp_cname_overrides_servername = no". This avoids
-false hostname information in DNS CNAME records that could bypass
-a hostname-based TLS usage policy.
-.IP \(bu
-Specify local \fBtransport\fR(5) table entries for sensitive domains
-with explicit smtp:[mailhost] destinations. This avoids false
-hostname information in DNS MX records that could bypass a
-hostname-based TLS usage policy.
+Require TLS encryption, but do not
+require that the remote SMTP server hostname matches the information
+in the remote SMTP server certificate, or that the server certificate
+was issued by a trusted CA. This overrides a less secure \fBNONE\fR
+or a less specific \fBMAY\fR 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.
+.IP "MUST"
+Require TLS encryption, require that the remote
+SMTP server hostname matches the information in the remote SMTP
+server certificate, and require that the remote SMTP server certificate
+was issued by a trusted CA. This overrides a less secure \fBNONE\fR
+and \fBMUST_NOPEERMATCH\fR or a less specific \fBMAY\fR 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.
+.PP
+As long as no secure DNS lookup mechanism is available, false
+hostnames in MX or CNAME responses can change the server hostname
+that Postfix uses 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 the
+following steps:
.IP \(bu
-Specify MUST for these mail hosts in the smtp_tls_per_site
-table.
-.IP "Postfix < 2.2.9"
+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.
.IP \(bu
-Specify local \fBtransport\fR(5) table entries for sensitive domains
-with explicit smtp:[mailhost] destinations. This avoids false
-hostname information in DNS MX records that could bypass a
-hostname-based TLS usage policy, but cannot avoid false hostname
-information in DNS CNAME records.
+Eliminate MX lookups. Specify local \fBtransport\fR(5) table entries
+for sensitive domains with explicit smtp:[mailhost] or smtp:[mailhost]:port
+destinations. This prevents false hostname information in DNS MX
+records from changing the server hostname that Postfix uses for TLS
+policy lookup and server certificate verification.
.IP \(bu
-Specify MUST for these mail hosts in the smtp_tls_per_site
-table.
+Specify MUST for these mail hosts (including [ ] and port) in
+the smtp_tls_per_site table.
.PP
.SH smtp_tls_scert_verifydepth (default: 5)
The verification depth for remote SMTP server certificates. A
a restriction list, to make the default policy explicit.
.IP "\fBreject_multi_recipient_bounce\fR"
Reject the request when the envelope sender is the null address,
-and the message has multiple envelope recipients. Although this
-usage is technically allowed, it seems to have no legitimate
-application.
+and the message has multiple envelope recipients. This usage has
+rare but legitimate applications: under certain conditions,
+multi-recipient mail that was posted with the DSN option NOTIFY=NEVER
+may be forwarded with the null sender address.
.br
-Note: this restriction can only work reliably
+ Note: this restriction can only work reliably
when used in smtpd_data_restrictions or
smtpd_end_of_data_restrictions, because the total number of
recipients is not known at an earlier stage of the SMTP conversation.
restriction should not be used before the client has had a chance
to negotiate encryption with the AUTH or STARTTLS commands.
.br
-The plaintext_session_reject_code parameter specifies the response
+The plaintext_reject_code parameter specifies the response
code for rejected requests (default: 450). This feature is available
in Postfix 2.3 and later.
.IP "\fBreject_unauth_pipelining\fR"
Note: on OpenBSD systems specify /dev/arandom when /dev/urandom
gives timeout errors.
.SH trace_service_name (default: trace)
-The name of the \fBtrace\fR(8) service. This service maintains a record
+The name of the trace service. This service is implemented by the
+\fBbounce\fR(8) daemon and maintains a record
of mail deliveries and produces a mail delivery report when verbose
delivery is requested with "\fBsendmail -v\fR".
.PP
.IP "\fBenable_errors_to (no)\fR"
Report mail delivery errors to the address specified with the
non-standard Errors-To: message header, instead of the envelope
-sender address (this feature is removed with Postfix 2.2, is
-turned off by default with Postfix 2.1, and is always turned on
+sender address (this feature is removed with Postfix version 2.2, is
+turned off by default with Postfix version 2.1, and is always turned on
with older Postfix versions).
.SH "BUILT-IN CONTENT FILTERING CONTROLS"
.na
Postfix is final destination for the specified list of domains;
mail is delivered via the $virtual_transport mail delivery transport.
.IP "\fBvirtual_transport (virtual)\fR"
-The default mail delivery transport for domains that match the
-$virtual_mailbox_domains parameter value.
+The default mail delivery transport and next-hop destination for
+final delivery to domains listed with $virtual_mailbox_domains.
.SH "LOCKING CONTROLS"
.na
.nf
--- /dev/null
+#!/bin/sh
+
+for i
+do
+ case $i in
+ /*) lynx -dump file://localhost$i;;
+ *) lynx -dump file://localhost`pwd`/$i;;
+ esac
+done
s;\bpar[-</bB>]*\n* *[<bB>]*ent_domain_matches_subdomains\b;<a href="postconf.5.html#parent_domain_matches_subdomains">$&</a>;g;
s;\bpermit_mx_backup_networks\b;<a href="postconf.5.html#permit_mx_backup_networks">$&</a>;g;
s;\bpickup_service_name\b;<a href="postconf.5.html#pickup_service_name">$&</a>;g;
- s;\bplaintext_session_reject_code\b;<a href="postconf.5.html#plaintext_session_reject_code">$&</a>;g;
+ s;\bplaintext_reject_code\b;<a href="postconf.5.html#plaintext_reject_code">$&</a>;g;
s;\bprepend_delivered_header\b;<a href="postconf.5.html#prepend_delivered_header">$&</a>;g;
s;\bprocess_id\b;<a href="postconf.5.html#process_id">$&</a>;g;
s;\bprocess_id_directory\b;<a href="postconf.5.html#process_id_directory">$&</a>;g;
<p> Tinycdb is preferred, since it is a bit faster, has additional
useful functionality and is much simpler to use. </p>
-<p>To build Postfix after you have installed CDB, use something
+<p>To build Postfix after you have installed tinycdb, use something
like: </p>
<blockquote>
"AUXLIBS=$CDB/libcdb.a"
% make
</pre>
-for tinycdb, or alternatively, for the D.J.B. version:<br>
+</blockquote>
+
+<p> Alternatively, for the D.J.B. version of CDB:<p>
+
+<blockquote>
<pre>
% make tidy
% CDB=../../../cdb-0.75
queue_id=8045F2AB23
sender=foo@bar.tld
recipient=bar@foo.tld
+recipient_count=0
client_address=1.2.3.4
client_name=another.domain.tld
reverse_client_name=another.domain.tld
</p>
<li> <p> When an attribute value is unavailable, the client
- either does not send the attribute, or sends the attribute with
- an empty value ("name="). </p>
+ either does not send the attribute, sends the attribute with
+ an empty value ("name="), or sends a zero value ("name=0") in
+ the case of a numerical attribute. </p>
+
+ <li> <p> The "recipient" attribute is available only in the
+ "RCPT TO" stage, and in the "DATA" and "END-OF-MESSAGE" stages
+ when Postfix accepted only one recipient for the current message.
+ </p>
+
+ <li> <p> The "recipient_count" attribute (Postfix 2.3 and later)
+ is non-zero only in the "DATA" and "END-OF-MESSAGE" stages. It
+ specifies the number of recipients that Postfix accepted for
+ the current message. </p>
<li> <p> The client address is an IPv4 dotted quad in the form
1.2.3.4 or it is an IPv6 address in the form 1:2:3::4:5:6.
done by invoking the command "<tt>make makefiles</tt>" in the Postfix
top-level directory and with arguments as shown next. </p>
+<p> <b> NOTE: Do not use Gnu TLS. It will spontaneously terminate
+a process with exit status code 2, instead of properly reporting
+problems to Postfix, so that it can log them to the maillog file.
+</b> </p>
+
<ul>
<li> <p> If the OpenSSL include files (such as <tt>ssl.h</tt>) are
<li><a href="#client_tls_cache">Client-side TLS session cache</a>
-<li><a href="#client_tls"> Enabling TLS in the Postfix SMTP client </a>
+<li><a href="#client_tls_enable"> Enabling TLS in the Postfix SMTP client </a>
+
+<li><a href="#client_tls_require"> Requiring TLS encryption </a>
+
+<li><a href="#client_tls_nopeer"> Disabling server certificate verification </a>
+
+<li><a href="#client_tls_per_site"> Per-site TLS policies </a>
+
+<!--
+<li><a href="#client_tls_obs"> Obsolete per-site TLS policy support </a>
+-->
+
+<li><a href="#client_tls_harden"> Closing a DNS loophole with <!-- legacy --> per-site TLS policies </a>
+
+<li><a href="#client_tls_discover"> Discovering servers that support TLS </a>
-<li><a href="#client_vrfy_server">Server certificate verification</a>
+<li><a href="#client_vrfy_server">Server certificate verification depth</a>
<li> <a href="#client_cipher">Client-side cipher controls </a>
certificates issued by these CAs, append the root certificate to
$smtp_tls_CAfile or install it in the $smtp_tls_CApath directory. When
you configure trust in a root CA, it is not necessary to explicitly trust
-intermediary CAs signed by the root CA, unless $smtp_tls_verify_depth
+intermediary CAs signed by the root CA, unless $smtp_tls_scert_verifydepth
is less than the number of CAs in the certificate chain for the servers
of interest. With a verify depth of 1 you can only verify certificates
directly signed by a trusted CA, and all trusted intermediary CAs need to
</pre>
</blockquote>
-<h3><a name="client_tls"> Enabling TLS in the Postfix SMTP client </a>
-</h3>
+<h3><a name="client_tls_enable"> Enabling TLS in the Postfix SMTP
+client </a> </h3>
<p> By default, TLS is disabled in the Postfix SMTP client, so no
difference to plain Postfix is visible. If you enable TLS, the
Postfix SMTP client will send STARTTLS when TLS support is announced
by the remote SMTP server. </p>
-<p> WARNING: MS Exchange servers will announce STARTTLS support
-even when the service is not configured, so that the TLS handshake
-will fail. It may be wise to not use this option on your central
-mail hub, as you don't know in advance whether you are going to
-connect to such a host. Instead, use the smtp_tls_per_site
-recipient/site specific options that are described below. </p>
-
-<p> When the TLS handshake fails and no other server is available,
-the Postfix SMTP client defers the delivery attempt, and the mail
-stays in the queue. </p>
+<p> When the server accepts the STARTTLS command, but the subsequent
+TLS handshake fails, and no other server is available, the Postfix SMTP
+client defers the delivery attempt, and the mail stays in the queue. After
+a handshake failure, the communications channel is in an indeterminate
+state and cannot be used for non-TLS deliveries. </p>
<p> Example: </p>
</pre>
</blockquote>
+<h3><a name="client_tls_require"> Requiring TLS encryption </a>
+</h3>
+
<p> You can ENFORCE the use of TLS, so that the Postfix SMTP client
will not deliver mail over unencrypted connections. In this mode,
the remote SMTP server hostname must match the information in the
doesn't match, and no other server is available, the delivery
attempt is deferred and the mail stays in the queue. </p>
-<p> The remote SMTP server hostname used in the check is beyond
-question, as it must be the principal hostname (no CNAME allowed
-here). Checks are performed against all names provided as dNSNames
+<p> The remote SMTP server hostname is verified against all names
+provided as dNSNames
in the SubjectAlternativeName. If no dNSNames are specified, the
-CommonName is checked. The behavior may be changed with the
+CommonName is checked. Verification may be turned off with the
smtp_tls_enforce_peername option which is discussed below. </p>
-<p> This option is useful only if you know that you will only
+<p> Enforcing the use of TLS is useful if you know that you will
+only
connect to servers that support RFC 2487 _and_ that present server
certificates that meet the above requirements. An example would
be a client only sends email to one specific mailhub that offers
<blockquote>
<pre>
/etc/postfix/main.cf:
- smtp_enforce_tls = no
+ smtp_enforce_tls = yes
</pre>
</blockquote>
+<h3> <a name="client_tls_nopeer"> Disabling server certificate
+verification </a> </h3>
+
<p> As of RFC 2487 the requirements for hostname checking for MTA
clients are not set. When TLS is required (smtp_enforce_tls = yes),
the option smtp_tls_enforce_peername can be set to "no" to disable
delivery will proceed regardless of the CommonName etc. listed in
the certificate. </p>
-<p> Note: the smtp_tls_enforce_peername setting has no effect on
-sessions that are controlled via the smtp_tls_per_site table. </p>
-
-<p> Disabling the remote SMTP server hostname verification can
-make sense in closed environment where special CAs are created.
-If not used carefully, this option opens the danger of a
-"man-in-the-middle" attack (the CommonName of this possible attacker
-is logged). </p>
+<p> Despite the potential for eliminating "man-in-the-middle" and
+other attacks, mandatory certificate/peername verification is not
+viable as a default Internet mail delivery policy at this time. A
+significant fraction of TLS enabled MTAs uses self-signed certificates,
+or certificates that are signed by a private certificate authority.
+On a machine that delivers mail to the Internet, if you set
+smtp_enforce_tls = yes, you should probably also set
+smtp_tls_enforce_peername = no. You can use the per-site TLS
+policies (see below) to enable full peer verification for specific
+destinations that are known to have verifiable TLS server certificates.
+</p>
<p> Example: </p>
<blockquote>
<pre>
/etc/postfix/main.cf:
- smtp_tls_enforce_peername = yes
+ smtp_enforce_tls = yes
+ smtp_tls_enforce_peername = no
</pre>
</blockquote>
-<p> Generally, trying TLS can be a bad idea, as some servers offer
-STARTTLS but the negotiation will fail leading to unexplainable
-failures. Instead, it may be a good idea to choose the TLS usage
-policy based on the recipient or the mailhub to which you are
-connecting. </p>
-
-<p> Deciding the TLS usage policy per recipient may be difficult,
-since a single email delivery attempt can involve several recipients.
-Instead, use of TLS is controlled by the Postfix next-hop destination
-domain name and by the remote SMTP server hostname. If either of these
-matches an entry in the smtp_tls_per_site table, appropriate action
-is taken. </p>
-
-<p> The remote SMTP server hostname is simply the DNS name of the
-server that the Postfix SMTP client connects to. The next-hop
-destination is Postfix specific. By default, this is the domain
-name in the recipient address, but this information can be overruled
-by the transport(5) table or by the relayhost parameter setting.
-In these cases the relayhost etc. must be listed in the smtp_tls_per_site
-table, instead of the recipient domain name. </p>
-
-<p> Format of the table: domain or host names are specified on the
-left-hand side; no wildcards are allowed. On the right hand side
-specify one of the following keywords: </p>
+<h3> <a name="client_tls_per_site"> Per-site TLS policies </a> </h3>
+
+<p> A small fraction of servers offer STARTTLS but the negotiation
+consistently fails, leading to mail aging out of the queue and
+bouncing back to the sender. In such cases, you can use the per-site
+policies to disable TLS for the problem sites. Alternatively, you
+can enable TLS for just a few specific sites and not enable it for
+all sites. </p>
+
+<!-- insert new-style TLS policy mechanism here
+
+<h3> <a name="client_tls_obs"> Obsolete per-site TLS policy support
+</a> </h3>
+
+<p> This section describes an obsolete per-site TLS policy mechanism.
+Unlike the newer mechanism it supports TLS policy lookup by server
+hostname, and lacks control over what names can appear in server
+certificates. Because of this, the obsolete mechanism is vulnerable
+to false DNS hostname information in MX or CNAME records. These
+attacks can be eliminated only with great difficulty. </p>
+
+-->
+
+<p> The smtp_tls_per_site table is searched for a policy that matches
+the following information: </p>
<blockquote>
<dl>
-<dt> NONE </dt> <dd> Don't use TLS at all. </dd>
+<dt> remote SMTP server hostname </dt> <dd> 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. </dd>
+
+<dt> next-hop destination </dt> <dd> This is normally the domain
+portion of the recipient address, but it may be overruled by
+information from the transport(5) table, from the relayhost parameter
+setting, or from the relay_transport setting. When it's not the
+recipient domain, the next-hop destination can have the Postfix-specific
+form "<tt>[name]</tt>", <tt>[name]:port</tt>", "<tt>name</tt>" or
+"<tt>name:port</tt>". </dd>
+
+</dl>
+
+</blockquote>
+
+<p> 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. </p>
+
+<p> The smtp_tls_per_site table uses a simple "<i>name whitespace
+value</i>" 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: </p>
-<dt> MAY </dt> <dd> Try to use STARTTLS if offered, otherwise use
-the unencrypted connection. </dd>
+<blockquote>
-<dt> MUST </dt> <dd> Require usage of STARTTLS, require that the
-remote SMTP server hostname matches the information in the remote
-SMTP server certificate, and require that the remote SMTP server
-certificate was issued by a trusted CA. </dd>
+<dl>
-<dt> MUST_NOPEERMATCH </dt> <dd> Require usage of STARTTLS, but do
-not require that the remote SMTP server hostname matches the
-information in the remote SMTP server certificate, or that the
-server certificate was issued by a trusted CA. </dd>
+<dt> NONE </dt> <dd> Don't use TLS at all. This overrides a less
+specific <b>MAY</b> 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. </dd>
+
+<dt> MAY </dt> <dd> Try to use TLS if the server announces support,
+otherwise use the unencrypted connection. This has less precedence
+than a more specific result (including <b>NONE</b>) 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". </dd>
+
+<dt> MUST_NOPEERMATCH </dt> <dd> Require TLS encryption, but do not
+require that the remote SMTP server hostname matches the information
+in the remote SMTP server certificate, or that the server certificate
+was issued by a trusted CA. This overrides a less secure <b>NONE</b>
+or a less specific <b>MAY</b> 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. </dd>
+
+<dt> MUST </dt> <dd> Require TLS encryption, require that the remote
+SMTP server hostname matches the information in the remote SMTP
+server certificate, and require that the remote SMTP server certificate
+was issued by a trusted CA. This overrides a less secure <b>NONE</b>
+and <b>MUST_NOPEERMATCH</b> or a less specific <b>MAY</b> 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. </dd>
</dl>
</blockquote>
-<p> The actual TLS usage policy depends not only on whether the
-next-hop destination or remote SMTP server hostname are found in
-the smtp_tls_per_site table, but also on the smtp_enforce_tls
-setting: </p>
+<p> The precedences between global (main.cf) and per-site TLS
+policies can be summarized as follows: </p>
<ul>
-<li> <p> If no match was found, the policy is applied as specified
-with smtp_enforce_tls. </p>
+<li> <p> 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". </p>
-<li> <p> If a match was found, and the smtp_enforce_tls policy is
-"enforce", NONE explicitly switches it off; otherwise the "enforce"
-mode is used even for entries that specify MAY. </p>
+<li> <p> 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). </p>
+
+<li> <p> After the per-site policy lookups are combined, the result
+generally overrides the global policy. The exception is the less
+specific <b>MAY</b> 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. </p>
</ul>
-<p> Special hint for TLS enforcement mode: since no secure DNS
-lookup mechanism is available, mail can be delivered to the wrong
-remote SMTP server. This is not prevented by specifying MUST for
-the next-hop domain name. The recommended setup is: specify local
-transport(5) table entries for sensitive domains with explicit
-smtp:[mailhost] destinations (since you can assure security of this
-table unlike DNS), then specify MUST for these mail hosts in the
-smtp_tls_per_site table. </p>
+<h3> <a name="client_tls_harden"> Closing a DNS loophole with
+<!-- legacy --> per-site TLS policies </a> </h3>
+
+<p> As long as no secure DNS lookup mechanism is available, false
+hostnames may appear in MX or CNAME responses. 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 the following steps: </p>
+
+<ul>
+
+<li> <p> Eliminate MX lookups. Specify local transport(5) table
+entries for sensitive domains with explicit smtp:[<i>mailhost</i>]
+or smtp:[<i>mailhost</i>]:<i>port</i> destinations (you can assure
+security of this table unlike DNS); in the smtp_tls_per_site table
+specify the value <b>MUST</b> for the key [<i>mailhost</i>] or
+smtp:[<i>mailhost</i>]:<i>port</i>. This prevents false hostname
+information in DNS MX records from changing the server hostname
+that Postfix uses for TLS policy lookup and server certificate
+verification. </p>
+
+<li> <p> 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. </p>
+
+</ul>
<p> Example: </p>
-
-<blockquote>
-<pre>
+
+<blockquote> <pre>
/etc/postfix/main.cf:
smtp_tls_per_site = hash:/etc/postfix/tls_per_site
+ relayhost = [msa.example.net]:587
+
+/etc/postfix/tls_per_site:
+ # relayhost exact nexthop match
+ [msa.example.net]:587 MUST
+
+ # example.org (as nexthop) has MX hosts with broken TLS.
+ example.org NONE
+
+ # Except for (as host) mx1.example.org which works.
+ mx1.example.org MAY
</pre>
</blockquote>
+<h3> <a name="client_tls_discover"> Discovering servers that support
+TLS </a> </h3>
+
<p> As we decide on a "per site" basis whether or not to use TLS,
it would be good to have a list of sites that offered "STARTTLS".
We can collect it ourselves with this option. </p>
</pre>
</blockquote>
-<h3><a name="client_vrfy_server">Server certificate verification</a> </h3>
+<h3><a name="client_vrfy_server">Server certificate verification depth</a> </h3>
<p> When verifying a remote SMTP server certificate, a verification
depth of 1 is sufficient if the certificate is directly issued by
</blockquote>
<li> <p> Configure Postfix, by adding the following to
-<tt>/etc/postfix/main.cf</tt>. </p>
+<tt>/etc/postfix/main.cf </tt>. </p>
<blockquote>
<pre>
generation (PRNG) pool, and in order to access the TLS session
cache databases. Such a protocol cannot be run across fifos. </p>
+<li> <p> smtp_tls_per_site: the MUST_NOPEERMATCH per-site policy
+cannot override the global "smtp_tls_enforce_peername = yes" setting.
+</p>
+
+<li> <p> smtp_tls_per_site: a combined (NONE + MAY) lookup result
+for (hostname and next-hop destination) produces counter-intuitive
+results for different main.cf settings. TLS is enabled with
+"smtp_tls_enforce_peername = no", but it is disabled when both
+"smtp_enforce_tls = yes" and "smtp_tls_enforce_peername = yes".
+</p>
+
</ul>
+<p> The smtp_tls_per_site limitations were removed by the end of
+the Postfix 2.2 support cycle. </p>
+
<h2><a name="credits">Credits </a> </h2>
<ul>
<li> Wietse Venema adopted the code, did some restructuring, and
compiled this part of the documentation from Lutz's documents.
+<li> Victor Duchovni was instrumental with the re-implementation
+of the smtp_tls_per_site code in terms of enforcement levels, which
+simplified the implementation greatly.
+
</ul>
</body>
<dt><b><a name="reject_multi_recipient_bounce">reject_multi_recipient_bounce</a></b></dt>
<dd>Reject the request when the envelope sender is the null address,
-and the message has multiple envelope recipients. Although this
-usage is technically allowed, it seems to have no legitimate
-application. <br> Note: this restriction can only work reliably
+and the message has multiple envelope recipients. This usage has
+rare but legitimate applications: under certain conditions,
+multi-recipient mail that was posted with the DSN option NOTIFY=NEVER
+may be forwarded with the null sender address.
+<br> Note: this restriction can only work reliably
when used in smtpd_data_restrictions or
smtpd_end_of_data_restrictions, because the total number of
recipients is not known at an earlier stage of the SMTP conversation.
restriction should not be used before the client has had a chance
to negotiate encryption with the AUTH or STARTTLS commands.
<br>
-The plaintext_session_reject_code parameter specifies the response
+The plaintext_reject_code parameter specifies the response
code for rejected requests (default: 450). This feature is available
in Postfix 2.3 and later. </dd>
%PARAM defer_service_name defer
<p>
-The name of the defer(8) service. This service maintains a record
+The name of the defer service. This service is implemented by the
+bounce(8) daemon and maintains a record
of failed delivery attempts and generates non-delivery notifications.
</p>
%PARAM trace_service_name trace
<p>
-The name of the trace(8) service. This service maintains a record
+The name of the trace service. This service is implemented by the
+bounce(8) daemon and maintains a record
of mail deliveries and produces a mail delivery report when verbose
delivery is requested with "<b>sendmail -v</b>".
</p>
%PARAM smtp_tls_per_site
<p> Optional lookup tables with the Postfix SMTP client TLS usage
-policy by next-hop domain name and by remote SMTP server hostname.
-</p>
-
-<p> Table format: domain names or server hostnames are specified
-on the left-hand side; no wildcards are allowed. On the right hand
-side specify one of the following keywords: </p>
+policy by next-hop destination and by remote SMTP server hostname.
+When both lookups succeed, 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). </p>
+
+<p> Specify a next-hop destination or server hostname on the left-hand
+side; no wildcards are allowed. The next-hop destination is either
+the recipient domain, or the destination specified with a transport(5)
+table, the relayhost parameter, or the relay_transport parameter.
+On the right hand side specify one of the following keywords: </p>
<dl>
-<dt> NONE </dt> <dd>Don't use TLS at all. </dd>
-
-<dt> MAY </dt> <dd>Try to use STARTTLS if offered, otherwise use
-the unencrypted connection. </dd>
-
-<dt> MUST </dt> <dd>Require usage of STARTTLS, require that the
-remote SMTP server hostname matches the information in the remote
-SMTP server certificate, and require that the remote SMTP server
-certificate was issued by a trusted CA. </dd>
-
-<dt> MUST_NOPEERMATCH </dt> <dd>Require usage of STARTTLS, but do
-not require that the remote SMTP server hostname matches the
-information in the remote SMTP server certificate, or that the
-server certificate was issued by a trusted CA. </dd>
+<dt> NONE </dt> <dd> Don't use TLS at all. This overrides a less
+specific <b>MAY</b> 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. </dd>
+
+<dt> MAY </dt> <dd> Try to use TLS if the server announces support,
+otherwise use the unencrypted connection. This has less precedence
+than a more specific result (including <b>NONE</b>) 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". </dd>
+
+<dt> MUST_NOPEERMATCH </dt> <dd> Require TLS encryption, but do not
+require that the remote SMTP server hostname matches the information
+in the remote SMTP server certificate, or that the server certificate
+was issued by a trusted CA. This overrides a less secure <b>NONE</b>
+or a less specific <b>MAY</b> 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. </dd>
+
+<dt> MUST </dt> <dd> Require TLS encryption, require that the remote
+SMTP server hostname matches the information in the remote SMTP
+server certificate, and require that the remote SMTP server certificate
+was issued by a trusted CA. This overrides a less secure <b>NONE</b>
+and <b>MUST_NOPEERMATCH</b> or a less specific <b>MAY</b> 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. </dd>
</dl>
-<p> Special hints for enforcement mode: since no secure DNS lookup
-mechanism is available, the recommended setup is: </p>
-
-<dl>
-
-<dt> Postfix 2.2.9 </dt>
-
-<dd> <ul>
-
-<li> Specify "smtp_cname_overrides_servername = no". This avoids
-false hostname information in DNS CNAME records that could bypass
-a hostname-based TLS usage policy.
+<p> As long as no secure DNS lookup mechanism is available, false
+hostnames in MX or CNAME responses can change the server hostname
+that Postfix uses 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 the
+following steps: </p>
-<li> Specify local transport(5) table entries for sensitive domains
-with explicit smtp:[mailhost] destinations. This avoids false
-hostname information in DNS MX records that could bypass a
-hostname-based TLS usage policy.
-
-<li> Specify MUST for these mail hosts in the smtp_tls_per_site
-table.
-
-</ul> </dd>
-
-<dt> Postfix < 2.2.9 </dt>
-
-<dd> <ul>
+<ul>
-<li> Specify local transport(5) table entries for sensitive domains
-with explicit smtp:[mailhost] destinations. This avoids false
-hostname information in DNS MX records that could bypass a
-hostname-based TLS usage policy, but cannot avoid false hostname
-information in DNS CNAME records.
+<li> 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.
-<li> Specify MUST for these mail hosts in the smtp_tls_per_site
-table.
+<li> Eliminate MX lookups. Specify local transport(5) table entries
+for sensitive domains with explicit smtp:[mailhost] or smtp:[mailhost]:port
+destinations. This prevents false hostname information in DNS MX
+records from changing the server hostname that Postfix uses for TLS
+policy lookup and server certificate verification.
-</ul> </dd>
+<li> Specify MUST for these mail hosts (including [ ] and port) in
+the smtp_tls_per_site table.
-</dl>
+</ul>
<p> </p>
<p> This feature is available in Postfix 2.3 and later. </p>
-%PARAM plaintext_session_reject_code 450
+%PARAM plaintext_reject_code 450
<p>
The numerical Postfix SMTP server response code when a request
if ((anvil_remote =
(ANVIL_REMOTE *) htable_find(anvil_remote_map, ident)) == 0) {
attr_print_plain(client_stream, ATTR_FLAG_NONE,
- ATTR_TYPE_NUM, ANVIL_ATTR_STATUS, ANVIL_STAT_OK,
- ATTR_TYPE_NUM, ANVIL_ATTR_COUNT, 0,
- ATTR_TYPE_NUM, ANVIL_ATTR_RATE, 0,
- ATTR_TYPE_NUM, ANVIL_ATTR_MAIL, 0,
- ATTR_TYPE_NUM, ANVIL_ATTR_RCPT, 0,
- ATTR_TYPE_NUM, ANVIL_ATTR_NTLS, 0,
+ ATTR_TYPE_INT, ANVIL_ATTR_STATUS, ANVIL_STAT_OK,
+ ATTR_TYPE_INT, ANVIL_ATTR_COUNT, 0,
+ ATTR_TYPE_INT, ANVIL_ATTR_RATE, 0,
+ ATTR_TYPE_INT, ANVIL_ATTR_MAIL, 0,
+ ATTR_TYPE_INT, ANVIL_ATTR_RCPT, 0,
+ ATTR_TYPE_INT, ANVIL_ATTR_NTLS, 0,
ATTR_TYPE_END);
} else {
&& anvil_remote->start + var_anvil_time_unit < event_time())
ANVIL_REMOTE_RSET_RATE(anvil_remote, 0);
attr_print_plain(client_stream, ATTR_FLAG_NONE,
- ATTR_TYPE_NUM, ANVIL_ATTR_STATUS, ANVIL_STAT_OK,
- ATTR_TYPE_NUM, ANVIL_ATTR_COUNT, anvil_remote->count,
- ATTR_TYPE_NUM, ANVIL_ATTR_RATE, anvil_remote->rate,
- ATTR_TYPE_NUM, ANVIL_ATTR_MAIL, anvil_remote->mail,
- ATTR_TYPE_NUM, ANVIL_ATTR_RCPT, anvil_remote->rcpt,
- ATTR_TYPE_NUM, ANVIL_ATTR_NTLS, anvil_remote->ntls,
+ ATTR_TYPE_INT, ANVIL_ATTR_STATUS, ANVIL_STAT_OK,
+ ATTR_TYPE_INT, ANVIL_ATTR_COUNT, anvil_remote->count,
+ ATTR_TYPE_INT, ANVIL_ATTR_RATE, anvil_remote->rate,
+ ATTR_TYPE_INT, ANVIL_ATTR_MAIL, anvil_remote->mail,
+ ATTR_TYPE_INT, ANVIL_ATTR_RCPT, anvil_remote->rcpt,
+ ATTR_TYPE_INT, ANVIL_ATTR_NTLS, anvil_remote->ntls,
ATTR_TYPE_END);
}
}
* Respond to the local server.
*/
attr_print_plain(client_stream, ATTR_FLAG_NONE,
- ATTR_TYPE_NUM, ANVIL_ATTR_STATUS, ANVIL_STAT_OK,
- ATTR_TYPE_NUM, ANVIL_ATTR_COUNT, anvil_remote->count,
- ATTR_TYPE_NUM, ANVIL_ATTR_RATE, anvil_remote->rate,
+ ATTR_TYPE_INT, ANVIL_ATTR_STATUS, ANVIL_STAT_OK,
+ ATTR_TYPE_INT, ANVIL_ATTR_COUNT, anvil_remote->count,
+ ATTR_TYPE_INT, ANVIL_ATTR_RATE, anvil_remote->rate,
ATTR_TYPE_END);
/*
*/
ANVIL_REMOTE_INCR_MAIL(anvil_remote);
attr_print_plain(client_stream, ATTR_FLAG_NONE,
- ATTR_TYPE_NUM, ANVIL_ATTR_STATUS, ANVIL_STAT_OK,
- ATTR_TYPE_NUM, ANVIL_ATTR_RATE, anvil_remote->mail,
+ ATTR_TYPE_INT, ANVIL_ATTR_STATUS, ANVIL_STAT_OK,
+ ATTR_TYPE_INT, ANVIL_ATTR_RATE, anvil_remote->mail,
ATTR_TYPE_END);
/*
*/
ANVIL_REMOTE_INCR_RCPT(anvil_remote);
attr_print_plain(client_stream, ATTR_FLAG_NONE,
- ATTR_TYPE_NUM, ANVIL_ATTR_STATUS, ANVIL_STAT_OK,
- ATTR_TYPE_NUM, ANVIL_ATTR_RATE, anvil_remote->rcpt,
+ ATTR_TYPE_INT, ANVIL_ATTR_STATUS, ANVIL_STAT_OK,
+ ATTR_TYPE_INT, ANVIL_ATTR_RATE, anvil_remote->rcpt,
ATTR_TYPE_END);
/*
*/
ANVIL_REMOTE_INCR_NTLS(anvil_remote);
attr_print_plain(client_stream, ATTR_FLAG_NONE,
- ATTR_TYPE_NUM, ANVIL_ATTR_STATUS, ANVIL_STAT_OK,
- ATTR_TYPE_NUM, ANVIL_ATTR_RATE, anvil_remote->ntls,
+ ATTR_TYPE_INT, ANVIL_ATTR_STATUS, ANVIL_STAT_OK,
+ ATTR_TYPE_INT, ANVIL_ATTR_RATE, anvil_remote->ntls,
ATTR_TYPE_END);
/*
* Respond to local server.
*/
attr_print_plain(client_stream, ATTR_FLAG_NONE,
- ATTR_TYPE_NUM, ANVIL_ATTR_STATUS, ANVIL_STAT_OK,
- ATTR_TYPE_NUM, ANVIL_ATTR_RATE, rate,
+ ATTR_TYPE_INT, ANVIL_ATTR_STATUS, ANVIL_STAT_OK,
+ ATTR_TYPE_INT, ANVIL_ATTR_RATE, rate,
ATTR_TYPE_END);
}
* Respond to the local server.
*/
attr_print_plain(client_stream, ATTR_FLAG_NONE,
- ATTR_TYPE_NUM, ANVIL_ATTR_STATUS, ANVIL_STAT_OK,
+ ATTR_TYPE_INT, ANVIL_ATTR_STATUS, ANVIL_STAT_OK,
ATTR_TYPE_END);
}
if (rp->name == 0) {
msg_warn("unrecognized request: \"%s\", ignored", STR(request));
attr_print_plain(client_stream, ATTR_FLAG_NONE,
- ATTR_TYPE_NUM, ANVIL_ATTR_STATUS, ANVIL_STAT_FAIL,
+ ATTR_TYPE_INT, ANVIL_ATTR_STATUS, ANVIL_STAT_FAIL,
ATTR_TYPE_END);
break;
}
* Read and validate the client request.
*/
if (mail_command_server(client,
- ATTR_TYPE_NUM, MAIL_ATTR_FLAGS, &flags,
+ ATTR_TYPE_INT, MAIL_ATTR_FLAGS, &flags,
ATTR_TYPE_STR, MAIL_ATTR_QUEUEID, queue_id,
ATTR_TYPE_FUNC, rcpb_scan, (void *) rcpt_buf,
ATTR_TYPE_FUNC, dsb_scan, (void *) dsn_buf,
* Read and validate the client request.
*/
if (mail_command_server(client,
- ATTR_TYPE_NUM, MAIL_ATTR_FLAGS, &flags,
+ ATTR_TYPE_INT, MAIL_ATTR_FLAGS, &flags,
ATTR_TYPE_STR, MAIL_ATTR_QUEUE, queue_name,
ATTR_TYPE_STR, MAIL_ATTR_QUEUEID, queue_id,
ATTR_TYPE_STR, MAIL_ATTR_ENCODING, encoding,
ATTR_TYPE_STR, MAIL_ATTR_SENDER, sender,
ATTR_TYPE_STR, MAIL_ATTR_DSN_ENVID, dsn_envid,
- ATTR_TYPE_NUM, MAIL_ATTR_DSN_RET, &dsn_ret,
+ ATTR_TYPE_INT, MAIL_ATTR_DSN_RET, &dsn_ret,
ATTR_TYPE_END) != 7) {
msg_warn("malformed request");
return (-1);
* Read and validate the client request.
*/
if (mail_command_server(client,
- ATTR_TYPE_NUM, MAIL_ATTR_FLAGS, &flags,
+ ATTR_TYPE_INT, MAIL_ATTR_FLAGS, &flags,
ATTR_TYPE_STR, MAIL_ATTR_QUEUE, queue_name,
ATTR_TYPE_STR, MAIL_ATTR_QUEUEID, queue_id,
ATTR_TYPE_STR, MAIL_ATTR_ENCODING, encoding,
ATTR_TYPE_STR, MAIL_ATTR_SENDER, sender,
ATTR_TYPE_STR, MAIL_ATTR_DSN_ENVID, dsn_envid,
- ATTR_TYPE_NUM, MAIL_ATTR_DSN_RET, &dsn_ret,
+ ATTR_TYPE_INT, MAIL_ATTR_DSN_RET, &dsn_ret,
ATTR_TYPE_STR, MAIL_ATTR_VERPDL, verp_delims,
ATTR_TYPE_END) != 8) {
msg_warn("malformed request");
* Read and validate the client request.
*/
if (mail_command_server(client,
- ATTR_TYPE_NUM, MAIL_ATTR_FLAGS, &flags,
+ ATTR_TYPE_INT, MAIL_ATTR_FLAGS, &flags,
ATTR_TYPE_STR, MAIL_ATTR_QUEUE, queue_name,
ATTR_TYPE_STR, MAIL_ATTR_QUEUEID, queue_id,
ATTR_TYPE_STR, MAIL_ATTR_ENCODING, encoding,
ATTR_TYPE_STR, MAIL_ATTR_SENDER, sender,
ATTR_TYPE_STR, MAIL_ATTR_DSN_ENVID, dsn_envid,
- ATTR_TYPE_NUM, MAIL_ATTR_DSN_RET, &dsn_ret,
+ ATTR_TYPE_INT, MAIL_ATTR_DSN_RET, &dsn_ret,
ATTR_TYPE_FUNC, rcpb_scan, (void *) rcpt_buf,
ATTR_TYPE_FUNC, dsb_scan, (void *) dsn_buf,
ATTR_TYPE_END) != 9) {
* request-specific protocol routines take care of the remainder.
*/
if (attr_scan(client, ATTR_FLAG_STRICT | ATTR_FLAG_MORE,
- ATTR_TYPE_NUM, MAIL_ATTR_NREQ, &command, 0) != 1) {
+ ATTR_TYPE_INT, MAIL_ATTR_NREQ, &command, 0) != 1) {
msg_warn("malformed request");
status = -1;
} else if (command == BOUNCE_CMD_VERP) {
* client.
*/
attr_print(client, ATTR_FLAG_NONE,
- ATTR_TYPE_NUM, MAIL_ATTR_STATUS, status,
+ ATTR_TYPE_INT, MAIL_ATTR_STATUS, status,
ATTR_TYPE_END);
vstream_fflush(client);
/* .IP "\fBenable_errors_to (no)\fR"
/* Report mail delivery errors to the address specified with the
/* non-standard Errors-To: message header, instead of the envelope
-/* sender address (this feature is removed with Postfix 2.2, is
-/* turned off by default with Postfix 2.1, and is always turned on
+/* sender address (this feature is removed with Postfix version 2.2, is
+/* turned off by default with Postfix version 2.1, and is always turned on
/* with older Postfix versions).
/* BUILT-IN CONTENT FILTERING CONTROLS
/* .ad
ATTR_TYPE_STR, MAIL_ATTR_QUEUEID, state->queue_id,
ATTR_TYPE_END);
if (attr_scan(src, ATTR_FLAG_STRICT,
- ATTR_TYPE_NUM, MAIL_ATTR_FLAGS, &flags,
+ ATTR_TYPE_INT, MAIL_ATTR_FLAGS, &flags,
ATTR_TYPE_END) != 1) {
state->errs |= CLEANUP_STAT_BAD;
flags = 0;
*/
status = cleanup_flush(state); /* in case state is modified */
attr_print(src, ATTR_FLAG_NONE,
- ATTR_TYPE_NUM, MAIL_ATTR_STATUS, status,
+ ATTR_TYPE_INT, MAIL_ATTR_STATUS, status,
ATTR_TYPE_STR, MAIL_ATTR_WHY, state->reason ?
state->reason : "",
ATTR_TYPE_END);
if (*var_canonical_maps)
cleanup_comm_canon_maps =
- maps_create(VAR_CANONICAL_MAPS, var_canonical_maps, DICT_FLAG_LOCK);
+ maps_create(VAR_CANONICAL_MAPS, var_canonical_maps,
+ DICT_FLAG_LOCK | DICT_FLAG_FOLD_FIX);
if (*var_send_canon_maps)
cleanup_send_canon_maps =
maps_create(VAR_SEND_CANON_MAPS, var_send_canon_maps,
- DICT_FLAG_LOCK);
+ DICT_FLAG_LOCK | DICT_FLAG_FOLD_FIX);
if (*var_rcpt_canon_maps)
cleanup_rcpt_canon_maps =
maps_create(VAR_RCPT_CANON_MAPS, var_rcpt_canon_maps,
- DICT_FLAG_LOCK);
+ DICT_FLAG_LOCK | DICT_FLAG_FOLD_FIX);
if (*var_virt_alias_maps)
cleanup_virt_alias_maps = maps_create(VAR_VIRT_ALIAS_MAPS,
var_virt_alias_maps,
- DICT_FLAG_LOCK);
+ DICT_FLAG_LOCK
+ | DICT_FLAG_FOLD_FIX);
if (*var_canon_classes)
cleanup_comm_canon_flags =
name_mask(VAR_CANON_CLASSES, canon_class_table,
if (*var_send_bcc_maps)
cleanup_send_bcc_maps =
maps_create(VAR_SEND_BCC_MAPS, var_send_bcc_maps,
- DICT_FLAG_LOCK);
+ DICT_FLAG_LOCK | DICT_FLAG_FOLD_FIX);
if (*var_rcpt_bcc_maps)
cleanup_rcpt_bcc_maps =
maps_create(VAR_RCPT_BCC_MAPS, var_rcpt_bcc_maps,
- DICT_FLAG_LOCK);
+ DICT_FLAG_LOCK | DICT_FLAG_FOLD_FIX);
flush_init();
}
&& mail_queue_id_ok(STR(queue_id)))
status = flush_add_service(lowercase(STR(site)), STR(queue_id));
attr_print(client_stream, ATTR_FLAG_NONE,
- ATTR_TYPE_NUM, MAIL_ATTR_STATUS, status,
+ ATTR_TYPE_INT, MAIL_ATTR_STATUS, status,
ATTR_TYPE_END);
} else if (STREQ(STR(request), FLUSH_REQ_SEND)) {
site = vstring_alloc(10);
status = flush_send_service(lowercase(STR(site)),
REFRESH_AND_DELIVER);
attr_print(client_stream, ATTR_FLAG_NONE,
- ATTR_TYPE_NUM, MAIL_ATTR_STATUS, status,
+ ATTR_TYPE_INT, MAIL_ATTR_STATUS, status,
ATTR_TYPE_END);
} else if (STREQ(STR(request), FLUSH_REQ_REFRESH)
|| STREQ(STR(request), wakeup)) {
attr_print(client_stream, ATTR_FLAG_NONE,
- ATTR_TYPE_NUM, MAIL_ATTR_STATUS, FLUSH_STAT_OK,
+ ATTR_TYPE_INT, MAIL_ATTR_STATUS, FLUSH_STAT_OK,
ATTR_TYPE_END);
vstream_fflush(client_stream);
(void) flush_refresh_service(var_fflush_refresh);
} else if (STREQ(STR(request), FLUSH_REQ_PURGE)) {
attr_print(client_stream, ATTR_FLAG_NONE,
- ATTR_TYPE_NUM, MAIL_ATTR_STATUS, FLUSH_STAT_OK,
+ ATTR_TYPE_INT, MAIL_ATTR_STATUS, FLUSH_STAT_OK,
ATTR_TYPE_END);
vstream_fflush(client_stream);
(void) flush_refresh_service(0);
}
} else
attr_print(client_stream, ATTR_FLAG_NONE,
- ATTR_TYPE_NUM, MAIL_ATTR_STATUS, status,
+ ATTR_TYPE_INT, MAIL_ATTR_STATUS, status,
ATTR_TYPE_END);
vstring_free(request);
if (site)
sent.c smtp_stream.c split_addr.c string_list.c strip_addr.c \
sys_exits.c timed_ipc.c tok822_find.c tok822_node.c tok822_parse.c \
tok822_resolve.c tok822_rewrite.c tok822_tree.c trace.c verify.c \
- verify_clnt.c verp_sender.c virtual8_maps.c xtext.c scache_single.c \
+ verify_clnt.c verp_sender.c xtext.c scache_single.c \
scache_clnt.c scache_multi.c user_acl.c mkmap_cdb.c mkmap_sdbm.c \
ehlo_mask.c \
wildcard_inet_addr.c valid_mailhost_addr.c dsn_util.c dsn_mask.c \
sent.o smtp_stream.o split_addr.o string_list.o strip_addr.o \
sys_exits.o timed_ipc.o tok822_find.o tok822_node.o tok822_parse.o \
tok822_resolve.o tok822_rewrite.o tok822_tree.o trace.o verify.o \
- verify_clnt.o verp_sender.o virtual8_maps.o xtext.o scache_single.o \
+ verify_clnt.o verp_sender.o xtext.o scache_single.o \
scache_clnt.o scache_multi.o user_acl.o mkmap_cdb.o mkmap_sdbm.o \
ehlo_mask.o \
wildcard_inet_addr.o valid_mailhost_addr.o dsn_util.o dsn_mask.o \
rec_streamlf.h rec_type.h recipient_list.h record.h resolve_clnt.h \
resolve_local.h rewrite_clnt.h sent.h smtp_stream.h split_addr.h \
string_list.h strip_addr.h sys_exits.h timed_ipc.h tok822.h \
- trace.h verify.h verify_clnt.h verp_sender.h virtual8_maps.h \
+ trace.h verify.h verify_clnt.h verp_sender.h \
xtext.h scache.h user_acl.h ehlo_mask.h db_common.h \
wildcard_inet_addr.h valid_mailhost_addr.h dsn_util.h dsn_mask.h \
dsn_attr_map.h dsn.h dsn_buf.h rcpt_buf.h rcpt_print.h dsn_print.h \
off_cvt quote_822_local rec2stream recdump resolve_clnt \
resolve_local rewrite_clnt stream2rec string_list tok822_parse \
quote_821_local mail_conf_time mime_state strip_addr \
- virtual8_maps verify_clnt xtext anvil_clnt scache ehlo_mask \
+ verify_clnt xtext anvil_clnt scache ehlo_mask \
valid_mailhost_addr own_inet_addr
LIBS = ../../lib/libutil.a
$(CC) -DTEST $(CFLAGS) -o $@ $@.c $(LIB) $(LIBS) $(SYSLIBS)
mv junk $@.o
-virtual8_maps: $(LIB) $(LIBS)
- mv $@.o junk
- $(CC) -DTEST $(CFLAGS) -o $@ $@.c $(LIB) $(LIBS) $(SYSLIBS)
- mv junk $@.o
-
verify_clnt: $(LIB) $(LIBS)
mv $@.o junk
$(CC) $(CFLAGS) -DTEST -o $@ $@.c $(LIB) $(LIBS) $(SYSLIBS)
tests: tok822_test mime_test mime_nest mime_8bit mime_dom mime_trunc \
mime_cvt mime_cvt2 mime_cvt3 strip_addr_test tok822_limit_test \
- virtual8_test xtext_test scache_multi_test ehlo_mask_test \
+ xtext_test scache_multi_test ehlo_mask_test \
namadr_list_test
tok822_test: tok822_parse tok822_parse.in tok822_parse.ref
diff strip_addr.ref strip_addr.tmp
rm -f strip_addr.tmp
-virtual8_test: virtual8_maps virtual8_map virtual8.in virtual8.ref \
- ../postmap/postmap
- ../postmap/postmap hash:virtual8_map
- ./virtual8_maps <virtual8.in hash:virtual8_map >virtual8.tmp
- diff virtual8.ref virtual8.tmp
- rm -f virtual8.tmp virtual8_map.db
-
xtext_test: xtext
./xtext <xtext.c | od -cb >xtext.tmp
od -cb <xtext.c >xtext.ref
dict_mysql.o: ../../include/mymalloc.h
dict_mysql.o: ../../include/myrand.h
dict_mysql.o: ../../include/split_at.h
+dict_mysql.o: ../../include/stringops.h
dict_mysql.o: ../../include/sys_defs.h
dict_mysql.o: ../../include/vbuf.h
dict_mysql.o: ../../include/vstream.h
dict_pgsql.o: ../../include/mymalloc.h
dict_pgsql.o: ../../include/myrand.h
dict_pgsql.o: ../../include/split_at.h
+dict_pgsql.o: ../../include/stringops.h
dict_pgsql.o: ../../include/sys_defs.h
dict_pgsql.o: ../../include/vbuf.h
dict_pgsql.o: ../../include/vstream.h
dsn_mask.o: ../../include/name_code.h
dsn_mask.o: ../../include/name_mask.h
dsn_mask.o: ../../include/sys_defs.h
+dsn_mask.o: ../../include/vbuf.h
+dsn_mask.o: ../../include/vstring.h
dsn_mask.o: dsn_mask.c
dsn_mask.o: dsn_mask.h
dsn_print.o: ../../include/attr.h
dsn_util.o: dsn_util.h
ehlo_mask.o: ../../include/name_mask.h
ehlo_mask.o: ../../include/sys_defs.h
+ehlo_mask.o: ../../include/vbuf.h
+ehlo_mask.o: ../../include/vstring.h
ehlo_mask.o: ehlo_mask.c
ehlo_mask.o: ehlo_mask.h
ext_prop.o: ../../include/name_mask.h
ext_prop.o: ../../include/sys_defs.h
+ext_prop.o: ../../include/vbuf.h
+ext_prop.o: ../../include/vstring.h
ext_prop.o: ext_prop.c
ext_prop.o: ext_prop.h
ext_prop.o: mail_params.h
input_transp.o: ../../include/msg.h
input_transp.o: ../../include/name_mask.h
input_transp.o: ../../include/sys_defs.h
+input_transp.o: ../../include/vbuf.h
+input_transp.o: ../../include/vstring.h
input_transp.o: cleanup_user.h
input_transp.o: input_transp.c
input_transp.o: input_transp.h
mail_conf_bool.o: ../../include/sys_defs.h
mail_conf_bool.o: ../../include/vbuf.h
mail_conf_bool.o: ../../include/vstream.h
+mail_conf_bool.o: ../../include/vstring.h
mail_conf_bool.o: mail_conf.h
mail_conf_bool.o: mail_conf_bool.c
mail_conf_int.o: ../../include/argv.h
mail_dict.o: ../../include/sys_defs.h
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_mysql.h
mail_dict.o: dict_pgsql.h
mail_dict.o: mail_dict.h
mail_error.o: ../../include/name_mask.h
mail_error.o: ../../include/sys_defs.h
+mail_error.o: ../../include/vbuf.h
+mail_error.o: ../../include/vstring.h
mail_error.o: mail_error.c
mail_error.o: mail_error.h
mail_flush.o: ../../include/attr.h
mbox_conf.o: ../../include/argv.h
mbox_conf.o: ../../include/name_mask.h
mbox_conf.o: ../../include/sys_defs.h
+mbox_conf.o: ../../include/vbuf.h
+mbox_conf.o: ../../include/vstring.h
mbox_conf.o: mail_params.h
mbox_conf.o: mbox_conf.c
mbox_conf.o: mbox_conf.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_open.o: ../../include/sys_defs.h
mkmap_open.o: ../../include/vbuf.h
mkmap_open.o: ../../include/vstream.h
+mkmap_open.o: ../../include/vstring.h
mkmap_open.o: mkmap.h
mkmap_open.o: mkmap_open.c
mkmap_sdbm.o: ../../include/argv.h
verp_sender.o: mail_params.h
verp_sender.o: verp_sender.c
verp_sender.o: verp_sender.h
-virtual8_maps.o: ../../include/argv.h
-virtual8_maps.o: ../../include/dict.h
-virtual8_maps.o: ../../include/msg.h
-virtual8_maps.o: ../../include/mymalloc.h
-virtual8_maps.o: ../../include/sys_defs.h
-virtual8_maps.o: ../../include/vbuf.h
-virtual8_maps.o: ../../include/vstream.h
-virtual8_maps.o: mail_params.h
-virtual8_maps.o: maps.h
-virtual8_maps.o: strip_addr.h
-virtual8_maps.o: virtual8_maps.c
-virtual8_maps.o: virtual8_maps.h
wildcard_inet_addr.o: ../../include/inet_addr_host.h
wildcard_inet_addr.o: ../../include/inet_addr_list.h
wildcard_inet_addr.o: ../../include/msg.h
event_disable_readwrite(vstream_fileno(ap->fp));
abounce_done(ap, attr_scan(ap->fp, ATTR_FLAG_STRICT,
- ATTR_TYPE_NUM, MAIL_ATTR_STATUS, &status,
+ ATTR_TYPE_INT, MAIL_ATTR_STATUS, &status,
ATTR_TYPE_END) == 1 ? status : -1);
}
ap->fp = mail_connect_wait(class, service);
if (attr_print(ap->fp, ATTR_FLAG_NONE,
- ATTR_TYPE_NUM, MAIL_ATTR_NREQ, command,
- ATTR_TYPE_NUM, MAIL_ATTR_FLAGS, flags,
+ ATTR_TYPE_INT, MAIL_ATTR_NREQ, command,
+ ATTR_TYPE_INT, MAIL_ATTR_FLAGS, flags,
ATTR_TYPE_STR, MAIL_ATTR_QUEUE, queue,
ATTR_TYPE_STR, MAIL_ATTR_QUEUEID, id,
ATTR_TYPE_STR, MAIL_ATTR_ENCODING, encoding,
ATTR_TYPE_STR, MAIL_ATTR_SENDER, sender,
ATTR_TYPE_STR, MAIL_ATTR_DSN_ENVID, dsn_envid,
- ATTR_TYPE_NUM, MAIL_ATTR_DSN_RET, dsn_ret,
+ ATTR_TYPE_INT, MAIL_ATTR_DSN_RET, dsn_ret,
ATTR_TYPE_STR, MAIL_ATTR_VERPDL, verp,
ATTR_TYPE_END) == 0
&& vstream_fflush(ap->fp) == 0) {
ap->fp = mail_connect_wait(class, service);
if (attr_print(ap->fp, ATTR_FLAG_NONE,
- ATTR_TYPE_NUM, MAIL_ATTR_NREQ, command,
- ATTR_TYPE_NUM, MAIL_ATTR_FLAGS, flags,
+ ATTR_TYPE_INT, MAIL_ATTR_NREQ, command,
+ ATTR_TYPE_INT, MAIL_ATTR_FLAGS, flags,
ATTR_TYPE_STR, MAIL_ATTR_QUEUE, queue,
ATTR_TYPE_STR, MAIL_ATTR_QUEUEID, id,
ATTR_TYPE_STR, MAIL_ATTR_ENCODING, encoding,
ATTR_TYPE_STR, MAIL_ATTR_SENDER, sender,
ATTR_TYPE_STR, MAIL_ATTR_DSN_ENVID, dsn_envid,
- ATTR_TYPE_NUM, MAIL_ATTR_DSN_RET, dsn_ret,
+ ATTR_TYPE_INT, MAIL_ATTR_DSN_RET, dsn_ret,
ATTR_TYPE_END) == 0
&& vstream_fflush(ap->fp) == 0) {
event_enable_read(vstream_fileno(ap->fp), abounce_event, (char *) ap);
ATTR_TYPE_STR, ANVIL_ATTR_IDENT, ident,
ATTR_TYPE_END,
ATTR_FLAG_MISSING, /* Reply attributes. */
- ATTR_TYPE_NUM, ANVIL_ATTR_STATUS, &status,
- ATTR_TYPE_NUM, ANVIL_ATTR_COUNT, count,
- ATTR_TYPE_NUM, ANVIL_ATTR_RATE, rate,
- ATTR_TYPE_NUM, ANVIL_ATTR_MAIL, msgs,
- ATTR_TYPE_NUM, ANVIL_ATTR_RCPT, rcpts,
- ATTR_TYPE_NUM, ANVIL_ATTR_NTLS, newtls,
+ ATTR_TYPE_INT, ANVIL_ATTR_STATUS, &status,
+ ATTR_TYPE_INT, ANVIL_ATTR_COUNT, count,
+ ATTR_TYPE_INT, ANVIL_ATTR_RATE, rate,
+ ATTR_TYPE_INT, ANVIL_ATTR_MAIL, msgs,
+ ATTR_TYPE_INT, ANVIL_ATTR_RCPT, rcpts,
+ ATTR_TYPE_INT, ANVIL_ATTR_NTLS, newtls,
ATTR_TYPE_END) != 6)
status = ANVIL_STAT_FAIL;
else if (status != ANVIL_STAT_OK)
ATTR_TYPE_STR, ANVIL_ATTR_IDENT, ident,
ATTR_TYPE_END,
ATTR_FLAG_MISSING, /* Reply attributes. */
- ATTR_TYPE_NUM, ANVIL_ATTR_STATUS, &status,
- ATTR_TYPE_NUM, ANVIL_ATTR_COUNT, count,
- ATTR_TYPE_NUM, ANVIL_ATTR_RATE, rate,
+ ATTR_TYPE_INT, ANVIL_ATTR_STATUS, &status,
+ ATTR_TYPE_INT, ANVIL_ATTR_COUNT, count,
+ ATTR_TYPE_INT, ANVIL_ATTR_RATE, rate,
ATTR_TYPE_END) != 3)
status = ANVIL_STAT_FAIL;
else if (status != ANVIL_STAT_OK)
ATTR_TYPE_STR, ANVIL_ATTR_IDENT, ident,
ATTR_TYPE_END,
ATTR_FLAG_MISSING, /* Reply attributes. */
- ATTR_TYPE_NUM, ANVIL_ATTR_STATUS, &status,
- ATTR_TYPE_NUM, ANVIL_ATTR_RATE, msgs,
+ ATTR_TYPE_INT, ANVIL_ATTR_STATUS, &status,
+ ATTR_TYPE_INT, ANVIL_ATTR_RATE, msgs,
ATTR_TYPE_END) != 2)
status = ANVIL_STAT_FAIL;
else if (status != ANVIL_STAT_OK)
ATTR_TYPE_STR, ANVIL_ATTR_IDENT, ident,
ATTR_TYPE_END,
ATTR_FLAG_MISSING, /* Reply attributes. */
- ATTR_TYPE_NUM, ANVIL_ATTR_STATUS, &status,
- ATTR_TYPE_NUM, ANVIL_ATTR_RATE, rcpts,
+ ATTR_TYPE_INT, ANVIL_ATTR_STATUS, &status,
+ ATTR_TYPE_INT, ANVIL_ATTR_RATE, rcpts,
ATTR_TYPE_END) != 2)
status = ANVIL_STAT_FAIL;
else if (status != ANVIL_STAT_OK)
ATTR_TYPE_STR, ANVIL_ATTR_IDENT, ident,
ATTR_TYPE_END,
ATTR_FLAG_MISSING, /* Reply attributes. */
- ATTR_TYPE_NUM, ANVIL_ATTR_STATUS, &status,
- ATTR_TYPE_NUM, ANVIL_ATTR_RATE, newtls,
+ ATTR_TYPE_INT, ANVIL_ATTR_STATUS, &status,
+ ATTR_TYPE_INT, ANVIL_ATTR_RATE, newtls,
ATTR_TYPE_END) != 2)
status = ANVIL_STAT_FAIL;
else if (status != ANVIL_STAT_OK)
ATTR_TYPE_STR, ANVIL_ATTR_IDENT, ident,
ATTR_TYPE_END,
ATTR_FLAG_MISSING, /* Reply attributes. */
- ATTR_TYPE_NUM, ANVIL_ATTR_STATUS, &status,
- ATTR_TYPE_NUM, ANVIL_ATTR_RATE, newtls,
+ ATTR_TYPE_INT, ANVIL_ATTR_STATUS, &status,
+ ATTR_TYPE_INT, ANVIL_ATTR_RATE, newtls,
ATTR_TYPE_END) != 2)
status = ANVIL_STAT_FAIL;
else if (status != ANVIL_STAT_OK)
ATTR_TYPE_STR, ANVIL_ATTR_IDENT, ident,
ATTR_TYPE_END,
ATTR_FLAG_MISSING, /* Reply attributes. */
- ATTR_TYPE_NUM, ANVIL_ATTR_STATUS, &status,
+ ATTR_TYPE_INT, ANVIL_ATTR_STATUS, &status,
ATTR_TYPE_END) != 1)
status = ANVIL_STAT_FAIL;
else if (status != ANVIL_STAT_OK)
if (mail_command_client(MAIL_CLASS_PRIVATE, var_soft_bounce ?
var_defer_service : var_bounce_service,
- ATTR_TYPE_NUM, MAIL_ATTR_NREQ, BOUNCE_CMD_APPEND,
- ATTR_TYPE_NUM, MAIL_ATTR_FLAGS, flags,
+ ATTR_TYPE_INT, MAIL_ATTR_NREQ, BOUNCE_CMD_APPEND,
+ ATTR_TYPE_INT, MAIL_ATTR_FLAGS, flags,
ATTR_TYPE_STR, MAIL_ATTR_QUEUEID, id,
ATTR_TYPE_FUNC, rcpt_print, (void *) rcpt,
ATTR_TYPE_FUNC, dsn_print, (void *) &my_dsn,
if (var_soft_bounce)
return (-1);
if (mail_command_client(MAIL_CLASS_PRIVATE, var_bounce_service,
- ATTR_TYPE_NUM, MAIL_ATTR_NREQ, BOUNCE_CMD_FLUSH,
- ATTR_TYPE_NUM, MAIL_ATTR_FLAGS, flags,
+ ATTR_TYPE_INT, MAIL_ATTR_NREQ, BOUNCE_CMD_FLUSH,
+ ATTR_TYPE_INT, MAIL_ATTR_FLAGS, flags,
ATTR_TYPE_STR, MAIL_ATTR_QUEUE, queue,
ATTR_TYPE_STR, MAIL_ATTR_QUEUEID, id,
ATTR_TYPE_STR, MAIL_ATTR_ENCODING, encoding,
ATTR_TYPE_STR, MAIL_ATTR_SENDER, sender,
ATTR_TYPE_STR, MAIL_ATTR_DSN_ENVID, dsn_envid,
- ATTR_TYPE_NUM, MAIL_ATTR_DSN_RET, dsn_ret,
+ ATTR_TYPE_INT, MAIL_ATTR_DSN_RET, dsn_ret,
ATTR_TYPE_END) == 0) {
return (0);
} else if ((flags & BOUNCE_FLAG_CLEAN) == 0) {
if (var_soft_bounce)
return (-1);
if (mail_command_client(MAIL_CLASS_PRIVATE, var_bounce_service,
- ATTR_TYPE_NUM, MAIL_ATTR_NREQ, BOUNCE_CMD_VERP,
- ATTR_TYPE_NUM, MAIL_ATTR_FLAGS, flags,
+ ATTR_TYPE_INT, MAIL_ATTR_NREQ, BOUNCE_CMD_VERP,
+ ATTR_TYPE_INT, MAIL_ATTR_FLAGS, flags,
ATTR_TYPE_STR, MAIL_ATTR_QUEUE, queue,
ATTR_TYPE_STR, MAIL_ATTR_QUEUEID, id,
ATTR_TYPE_STR, MAIL_ATTR_ENCODING, encoding,
ATTR_TYPE_STR, MAIL_ATTR_SENDER, sender,
ATTR_TYPE_STR, MAIL_ATTR_DSN_ENVID, dsn_envid,
- ATTR_TYPE_NUM, MAIL_ATTR_DSN_RET, dsn_ret,
+ ATTR_TYPE_INT, MAIL_ATTR_DSN_RET, dsn_ret,
ATTR_TYPE_STR, MAIL_ATTR_VERPDL, verp_delims,
ATTR_TYPE_END) == 0) {
return (0);
my_dsn.action = "failed";
if (mail_command_client(MAIL_CLASS_PRIVATE, var_bounce_service,
- ATTR_TYPE_NUM, MAIL_ATTR_NREQ, BOUNCE_CMD_ONE,
- ATTR_TYPE_NUM, MAIL_ATTR_FLAGS, flags,
+ ATTR_TYPE_INT, MAIL_ATTR_NREQ, BOUNCE_CMD_ONE,
+ ATTR_TYPE_INT, MAIL_ATTR_FLAGS, flags,
ATTR_TYPE_STR, MAIL_ATTR_QUEUE, queue,
ATTR_TYPE_STR, MAIL_ATTR_QUEUEID, id,
ATTR_TYPE_STR, MAIL_ATTR_ENCODING, encoding,
ATTR_TYPE_STR, MAIL_ATTR_SENDER, sender,
ATTR_TYPE_STR, MAIL_ATTR_DSN_ENVID, dsn_envid,
- ATTR_TYPE_NUM, MAIL_ATTR_DSN_RET, dsn_ret,
+ ATTR_TYPE_INT, MAIL_ATTR_DSN_RET, dsn_ret,
ATTR_TYPE_FUNC, rcpt_print, (void *) rcpt,
ATTR_TYPE_FUNC, dsn_print, (void *) &my_dsn,
ATTR_TYPE_END) == 0
my_dsn.action = "delayed";
if (mail_command_client(MAIL_CLASS_PRIVATE, var_defer_service,
- ATTR_TYPE_NUM, MAIL_ATTR_NREQ, BOUNCE_CMD_APPEND,
- ATTR_TYPE_NUM, MAIL_ATTR_FLAGS, flags,
+ ATTR_TYPE_INT, MAIL_ATTR_NREQ, BOUNCE_CMD_APPEND,
+ ATTR_TYPE_INT, MAIL_ATTR_FLAGS, flags,
ATTR_TYPE_STR, MAIL_ATTR_QUEUEID, id,
ATTR_TYPE_FUNC, rcpt_print, (void *) rcpt,
ATTR_TYPE_FUNC, dsn_print, (void *) &my_dsn,
flags |= BOUNCE_FLAG_DELRCPT;
if (mail_command_client(MAIL_CLASS_PRIVATE, var_defer_service,
- ATTR_TYPE_NUM, MAIL_ATTR_NREQ, BOUNCE_CMD_FLUSH,
- ATTR_TYPE_NUM, MAIL_ATTR_FLAGS, flags,
+ ATTR_TYPE_INT, MAIL_ATTR_NREQ, BOUNCE_CMD_FLUSH,
+ ATTR_TYPE_INT, MAIL_ATTR_FLAGS, flags,
ATTR_TYPE_STR, MAIL_ATTR_QUEUE, queue,
ATTR_TYPE_STR, MAIL_ATTR_QUEUEID, id,
ATTR_TYPE_STR, MAIL_ATTR_ENCODING, encoding,
ATTR_TYPE_STR, MAIL_ATTR_SENDER, sender,
ATTR_TYPE_STR, MAIL_ATTR_DSN_ENVID, dsn_envid,
- ATTR_TYPE_NUM, MAIL_ATTR_DSN_RET, dsn_ret,
+ ATTR_TYPE_INT, MAIL_ATTR_DSN_RET, dsn_ret,
ATTR_TYPE_END) == 0) {
return (0);
} else {
const char *sender, const char *envid, int dsn_ret)
{
if (mail_command_client(MAIL_CLASS_PRIVATE, var_defer_service,
- ATTR_TYPE_NUM, MAIL_ATTR_NREQ, BOUNCE_CMD_WARN,
- ATTR_TYPE_NUM, MAIL_ATTR_FLAGS, flags,
+ ATTR_TYPE_INT, MAIL_ATTR_NREQ, BOUNCE_CMD_WARN,
+ ATTR_TYPE_INT, MAIL_ATTR_FLAGS, flags,
ATTR_TYPE_STR, MAIL_ATTR_QUEUE, queue,
ATTR_TYPE_STR, MAIL_ATTR_QUEUEID, id,
ATTR_TYPE_STR, MAIL_ATTR_SENDER, sender,
ATTR_TYPE_STR, MAIL_ATTR_DSN_ENVID, envid,
- ATTR_TYPE_NUM, MAIL_ATTR_DSN_RET, dsn_ret,
+ ATTR_TYPE_INT, MAIL_ATTR_DSN_RET, dsn_ret,
ATTR_TYPE_END) == 0) {
return (0);
} else {
int stat;
if (attr_scan(stream, ATTR_FLAG_STRICT,
- ATTR_TYPE_NUM, MAIL_ATTR_STATUS, &stat,
+ ATTR_TYPE_INT, MAIL_ATTR_STATUS, &stat,
ATTR_TYPE_END) != 1) {
msg_warn("%s: malformed response", VSTREAM_PATH(stream));
stat = -1;
int stat;
attr_print(stream, ATTR_FLAG_NONE,
- ATTR_TYPE_NUM, MAIL_ATTR_FLAGS, request->flags,
+ ATTR_TYPE_INT, MAIL_ATTR_FLAGS, request->flags,
ATTR_TYPE_STR, MAIL_ATTR_QUEUE, request->queue_name,
ATTR_TYPE_STR, MAIL_ATTR_QUEUEID, request->queue_id,
ATTR_TYPE_LONG, MAIL_ATTR_OFFSET, request->data_offset,
ATTR_TYPE_STR, MAIL_ATTR_ENCODING, request->encoding,
ATTR_TYPE_STR, MAIL_ATTR_SENDER, request->sender,
ATTR_TYPE_STR, MAIL_ATTR_DSN_ENVID, request->dsn_envid,
- ATTR_TYPE_NUM, MAIL_ATTR_DSN_RET, request->dsn_ret,
+ ATTR_TYPE_INT, MAIL_ATTR_DSN_RET, request->dsn_ret,
ATTR_TYPE_FUNC, msg_stats_print, (void *) &request->msg_stats,
ATTR_TYPE_STR, MAIL_ATTR_CLIENT_NAME, request->client_name,
ATTR_TYPE_STR, MAIL_ATTR_CLIENT_ADDR, request->client_addr,
ATTR_TYPE_STR, MAIL_ATTR_SASL_USERNAME, request->sasl_username,
ATTR_TYPE_STR, MAIL_ATTR_SASL_SENDER, request->sasl_sender,
ATTR_TYPE_STR, MAIL_ATTR_RWR_CONTEXT, request->rewrite_context,
- ATTR_TYPE_NUM, MAIL_ATTR_RCPT_COUNT, 1,
+ ATTR_TYPE_INT, MAIL_ATTR_RCPT_COUNT, 1,
ATTR_TYPE_END);
attr_print(stream, ATTR_FLAG_NONE,
ATTR_TYPE_FUNC, rcpt_print, (void *) rcpt,
if (attr_scan(stream, ATTR_FLAG_STRICT,
ATTR_TYPE_FUNC, dsb_scan, (void *) dsb,
- ATTR_TYPE_NUM, MAIL_ATTR_STATUS, &stat,
+ ATTR_TYPE_INT, MAIL_ATTR_STATUS, &stat,
ATTR_TYPE_END) != 2) {
msg_warn("%s: malformed response", VSTREAM_PATH(stream));
return (DELIVER_PASS_UNKNOWN);
if (msg_verbose)
msg_info("deliver_request_initial: send initial status");
attr_print(stream, ATTR_FLAG_NONE,
- ATTR_TYPE_NUM, MAIL_ATTR_STATUS, 0,
+ ATTR_TYPE_INT, MAIL_ATTR_STATUS, 0,
ATTR_TYPE_END);
if ((err = vstream_fflush(stream)) != 0)
if (msg_verbose)
hop_status->reason, status);
attr_print(stream, ATTR_FLAG_NONE,
ATTR_TYPE_FUNC, dsn_print, (void *) hop_status,
- ATTR_TYPE_NUM, MAIL_ATTR_STATUS, status,
+ ATTR_TYPE_INT, MAIL_ATTR_STATUS, status,
ATTR_TYPE_END);
if ((err = vstream_fflush(stream)) != 0)
if (msg_verbose)
* the conversation when they send bad information.
*/
if (attr_scan(stream, ATTR_FLAG_STRICT,
- ATTR_TYPE_NUM, MAIL_ATTR_FLAGS, &request->flags,
+ ATTR_TYPE_INT, MAIL_ATTR_FLAGS, &request->flags,
ATTR_TYPE_STR, MAIL_ATTR_QUEUE, queue_name,
ATTR_TYPE_STR, MAIL_ATTR_QUEUEID, queue_id,
ATTR_TYPE_LONG, MAIL_ATTR_OFFSET, &request->data_offset,
ATTR_TYPE_STR, MAIL_ATTR_ENCODING, encoding,
ATTR_TYPE_STR, MAIL_ATTR_SENDER, address,
ATTR_TYPE_STR, MAIL_ATTR_DSN_ENVID, dsn_envid,
- ATTR_TYPE_NUM, MAIL_ATTR_DSN_RET, &dsn_ret,
+ ATTR_TYPE_INT, MAIL_ATTR_DSN_RET, &dsn_ret,
ATTR_TYPE_FUNC, msg_stats_scan, (void *) &request->msg_stats,
ATTR_TYPE_STR, MAIL_ATTR_CLIENT_NAME, client_name,
ATTR_TYPE_STR, MAIL_ATTR_CLIENT_ADDR, client_addr,
ATTR_TYPE_STR, MAIL_ATTR_SASL_USERNAME, sasl_username,
ATTR_TYPE_STR, MAIL_ATTR_SASL_SENDER, sasl_sender,
ATTR_TYPE_STR, MAIL_ATTR_RWR_CONTEXT, rewrite_context,
- ATTR_TYPE_NUM, MAIL_ATTR_RCPT_COUNT, &rcpt_count,
+ ATTR_TYPE_INT, MAIL_ATTR_RCPT_COUNT, &rcpt_count,
ATTR_TYPE_END) != 20) {
msg_warn("%s: error receiving common attributes", myname);
return (-1);
if (msg_verbose)
msg_info("%s: In dict_ldap_lookup", myname);
+ /*
+ * Optionally fold the key.
+ */
+ if (dict->fold_buf) {
+ vstring_strcpy(dict->fold_buf, name);
+ name = lowercase(vstring_str(dict->fold_buf));
+ }
+
/*
* If they specified a domain list for this map, then only search for
* addresses in domains on the list. This can significantly reduce the
myfree(dict_ldap->tls_random_file);
myfree(dict_ldap->tls_cipher_suite);
#endif
+ if (dict->fold_buf)
+ vstring_free(dict->fold_buf);
dict_free(dict);
}
dict_ldap->dict.flags |= DICT_FLAG_PATTERN;
else
dict_ldap->dict.flags |= DICT_FLAG_FIXED;
+ if (dict_flags & DICT_FLAG_FOLD_FIX)
+ dict_ldap->dict.fold_buf = vstring_alloc(10);
attr = cfg_get_str(dict_ldap->parser, "result_attribute",
"maildrop", 0, 0);
#include "find_inet.h"
#include "myrand.h"
#include "events.h"
+#include "stringops.h"
/* Global library. */
db_quote_callback_t quote_func = dict_mysql_quote;
dict_errno = 0;
-
+
+ /*
+ * Optionally fold the key.
+ */
+ if (dict->fold_buf) {
+ vstring_strcpy(dict->fold_buf, name);
+ name = lowercase(vstring_str(dict->fold_buf));
+ }
+
/*
* If there is a domain list for this map, then only search for
* addresses in domains on the list. This can significantly reduce
dict_mysql->dict.flags |= DICT_FLAG_PATTERN;
else
dict_mysql->dict.flags |= DICT_FLAG_FIXED;
+ if (dict_mysql->dict.flags & DICT_FLAG_FOLD_FIX)
+ dict_mysql->dict.fold_buf = vstring_alloc(10);
hosts = cfg_get_str(p, "hosts", "", 0, 0);
argv_free(dict_mysql->hosts);
if (dict_mysql->ctx)
db_common_free_ctx(dict_mysql->ctx);
+ if (dict->fold_buf)
+ vstring_free(dict->fold_buf);
dict_free(dict);
}
#include "find_inet.h"
#include "myrand.h"
#include "events.h"
+#include "stringops.h"
/* Global library. */
INIT_VSTR(result, 10);
dict_errno = 0;
+
+ /*
+ * Optionally fold the key.
+ */
+ if (dict->fold_buf) {
+ vstring_strcpy(dict->fold_buf, name);
+ name = lowercase(vstring_str(dict->fold_buf));
+ }
+
/*
* If there is a domain list for this map, then only search for
* addresses in domains on the list. This can significantly reduce
dict_pgsql->dict.flags |= DICT_FLAG_PATTERN;
else
dict_pgsql->dict.flags |= DICT_FLAG_FIXED;
+ if (dict_pgsql->dict.flags & DICT_FLAG_FOLD_FIX)
+ dict_pgsql->dict.fold_buf = vstring_alloc(10);
hosts = cfg_get_str(p, "hosts", "", 0, 0);
argv_free(dict_pgsql->hosts);
if (dict_pgsql->ctx)
db_common_free_ctx(dict_pgsql->ctx);
+ if (dict->fold_buf)
+ vstring_free(dict->fold_buf);
dict_free(dict);
}
if (attr_print(stream, ATTR_FLAG_NONE,
ATTR_TYPE_STR, MAIL_ATTR_REQ, PROXY_REQ_LOOKUP,
ATTR_TYPE_STR, MAIL_ATTR_TABLE, dict->name,
- ATTR_TYPE_NUM, MAIL_ATTR_FLAGS, dict_proxy->in_flags,
+ ATTR_TYPE_INT, MAIL_ATTR_FLAGS, dict_proxy->in_flags,
ATTR_TYPE_STR, MAIL_ATTR_KEY, key,
ATTR_TYPE_END) != 0
|| vstream_fflush(stream)
|| attr_scan(stream, ATTR_FLAG_STRICT,
- ATTR_TYPE_NUM, MAIL_ATTR_STATUS, &status,
+ ATTR_TYPE_INT, MAIL_ATTR_STATUS, &status,
ATTR_TYPE_STR, MAIL_ATTR_VALUE, dict_proxy->result,
ATTR_TYPE_END) != 2) {
if (msg_verbose || (errno != EPIPE && errno != ENOENT))
msg_warn("%s: service %s: %m", myname, VSTREAM_PATH(stream));
} else {
if (msg_verbose)
- msg_info("%s: table=%s flags=0%o key=%s -> status=%d result=%s",
- myname, dict->name, dict_proxy->in_flags, key,
+ msg_info("%s: table=%s flags=%s key=%s -> status=%d result=%s",
+ myname, dict->name,
+ dict_flags_str(dict_proxy->in_flags), key,
status, STR(dict_proxy->result));
switch (status) {
case PROXY_STAT_BAD:
if (attr_print(stream, ATTR_FLAG_NONE,
ATTR_TYPE_STR, MAIL_ATTR_REQ, PROXY_REQ_OPEN,
ATTR_TYPE_STR, MAIL_ATTR_TABLE, dict_proxy->dict.name,
- ATTR_TYPE_NUM, MAIL_ATTR_FLAGS, dict_proxy->in_flags,
+ ATTR_TYPE_INT, MAIL_ATTR_FLAGS, dict_proxy->in_flags,
ATTR_TYPE_END) != 0
|| vstream_fflush(stream)
|| attr_scan(stream, ATTR_FLAG_STRICT,
- ATTR_TYPE_NUM, MAIL_ATTR_STATUS, &status,
- ATTR_TYPE_NUM, MAIL_ATTR_FLAGS, &server_flags,
+ ATTR_TYPE_INT, MAIL_ATTR_STATUS, &status,
+ ATTR_TYPE_INT, MAIL_ATTR_FLAGS, &server_flags,
ATTR_TYPE_END) != 2) {
if (msg_verbose || (errno != EPIPE && errno != ENOENT))
msg_warn("%s: service %s: %m", VSTREAM_PATH(stream), myname);
} else {
if (msg_verbose)
- msg_info("%s: connect to map=%s status=%d server_flags=0%o",
- myname, dict_proxy->dict.name, status, server_flags);
+ msg_info("%s: connect to map=%s status=%d server_flags=%s",
+ myname, dict_proxy->dict.name, status,
+ dict_flags_str(server_flags));
switch (status) {
case PROXY_STAT_BAD:
msg_fatal("%s open failed for table \"%s\": invalid request",
const char *dsn_notify_str(int mask)
{
- return (str_name_mask_opt("DSN NOTIFY command", dsn_notify_table,
- mask, NAME_MASK_FATAL | NAME_MASK_COMMA));
+ return (str_name_mask_opt((VSTRING *) 0, "DSN NOTIFY command",
+ dsn_notify_table, mask,
+ NAME_MASK_FATAL | NAME_MASK_COMMA));
}
-starttls, 8bitmime, verp, etrn, etrn -> 0x51 -> 8BITMIME ETRN VERP
-foobar, auth, pipelining, size, vrfy -> 0x2e -> AUTH PIPELINING SIZE VRFY
-xclient, xforward -> 0x180 -> XCLIENT XFORWARD
+starttls, 8bitmime, verp, etrn, etrn -> 0xd1 -> 8BITMIME ETRN VERP STARTTLS
+foobar, auth, pipelining, size, vrfy -> 0x2e -> AUTH PIPELINING SIZE VRFY
+xclient, xforward -> 0x300 -> XCLIENT XFORWARD
/* DESCRIPTION
/* mail_addr_find() searches the specified maps for an entry with as
/* key the specified address, and derivations from that address.
-/* The search is case insensitive.
+/* It is up to the caller to specify its case sensitivity
+/* preferences when it opens the maps.
/* The result is overwritten upon each call.
/*
/* An address that is in the form \fIuser\fR matches itself.
/*
* Initialize.
*/
- full_key = lowercase(mystrdup(address));
+ full_key = mystrdup(address);
if (*var_rcpt_delim == 0) {
bare_key = saved_ext = 0;
} else {
* Initialize.
*/
mail_conf_read();
- path = maps_create(argv[0], argv[1], DICT_FLAG_LOCK);
+ path = maps_create(argv[0], argv[1], DICT_FLAG_LOCK | DICT_FLAG_FOLD_FIX);
while (vstring_fgets_nonl(buffer, VSTREAM_IN)) {
extent = 0;
result = mail_addr_find(path, STR(buffer), &extent);
msg_verbose = 1;
if (chdir(var_queue_dir) < 0)
msg_fatal("chdir %s: %m", var_queue_dir);
- path = maps_create(argv[0], argv[1], DICT_FLAG_LOCK);
+ path = maps_create(argv[0], argv[1], DICT_FLAG_LOCK | DICT_FLAG_FOLD_FIX);
while (vstring_fgets_nonl(buffer, VSTREAM_IN)) {
msg_info("=== Address extension on, extension propagation on ===");
UPDATE(var_rcpt_delim, "+");
va_end(ap);
if (status != 0
|| attr_scan(stream, ATTR_FLAG_STRICT,
- ATTR_TYPE_NUM, MAIL_ATTR_STATUS, &status, 0) != 1)
+ ATTR_TYPE_INT, MAIL_ATTR_STATUS, &status, 0) != 1)
status = -1;
(void) vstream_fclose(stream);
return (status);
* Receive the peer's completion status.
*/
if ((why && attr_scan(info->stream, ATTR_FLAG_STRICT,
- ATTR_TYPE_NUM, MAIL_ATTR_STATUS, &status,
+ ATTR_TYPE_INT, MAIL_ATTR_STATUS, &status,
ATTR_TYPE_STR, MAIL_ATTR_WHY, why,
ATTR_TYPE_END) != 2)
|| (!why && attr_scan(info->stream, ATTR_FLAG_MISSING,
- ATTR_TYPE_NUM, MAIL_ATTR_STATUS, &status,
+ ATTR_TYPE_INT, MAIL_ATTR_STATUS, &status,
ATTR_TYPE_END) != 1))
status = CLEANUP_STAT_WRITE;
* Patches change both the patchlevel and the release date. Snapshots have no
* patchlevel; they change the release date only.
*/
-#define MAIL_RELEASE_DATE "20060112"
+#define MAIL_RELEASE_DATE "20060123"
#define MAIL_VERSION_NUMBER "2.3"
#ifdef SNAPSHOT
/* locking. Dictionaries are opened read-only, and in-memory
/* dictionary instances are shared.
/*
-/* Lookups are case sensitive.
-/*
/* maps_create() takes list of type:name pairs and opens the
/* named dictionaries.
/* The result is a handle that must be specified along with all
/* other maps_xxx() operations.
/* See dict_open(3) for a description of flags.
+/* This includes the flags that specify preferences for search
+/* string case folding.
/*
/* maps_find() searches the specified list of dictionaries
/* in the specified order for the named key. The result is in
/* .IP map_names
/* Null-terminated string with type:name dictionary specifications,
/* separated by whitespace or commas.
+/* .IP flags
+/* With maps_create(), flags that are passed to dict_open().
+/* With maps_find(), flags that control searching behavior
+/* as documented above.
/* .IP maps
/* A result from maps_create().
/* .IP key
#define OPEN_FLAGS O_RDONLY
while ((map_type_name = mystrtok(&bufp, sep)) != 0) {
- vstring_sprintf(map_type_name_flags, "%s(%o,%o)",
- map_type_name, OPEN_FLAGS, dict_flags);
+ vstring_sprintf(map_type_name_flags, "%s(%o,%s)",
+ map_type_name, OPEN_FLAGS,
+ dict_flags_str(dict_flags));
if ((dict = dict_handle(vstring_str(map_type_name_flags))) == 0)
dict = dict_open(map_type_name, OPEN_FLAGS, dict_flags);
if ((dict->flags & dict_flags) != dict_flags)
ATTR_TYPE_STR, MAIL_ATTR_QUEUEID, id,
ATTR_TYPE_END) != 1
|| attr_print(stream, ATTR_FLAG_NONE,
- ATTR_TYPE_NUM, MAIL_ATTR_FLAGS, cleanup_flags,
+ ATTR_TYPE_INT, MAIL_ATTR_FLAGS, cleanup_flags,
ATTR_TYPE_END) != 0)
msg_fatal("unable to contact the %s service", var_cleanup_service);
rec_fputs(cleanup, REC_TYPE_END, "");
if (vstream_fflush(cleanup)
|| attr_scan(cleanup, ATTR_FLAG_MISSING,
- ATTR_TYPE_NUM, MAIL_ATTR_STATUS, &status,
+ ATTR_TYPE_INT, MAIL_ATTR_STATUS, &status,
ATTR_TYPE_END) != 1)
status = CLEANUP_STAT_WRITE;
}
ATTR_TYPE_STR, MAIL_ATTR_RECIP, rcpt->address,
ATTR_TYPE_LONG, MAIL_ATTR_OFFSET, &rcpt->offset,
ATTR_TYPE_STR, MAIL_ATTR_DSN_ORCPT, rcpt->dsn_orcpt,
- ATTR_TYPE_NUM, MAIL_ATTR_DSN_NOTIFY, &rcpt->dsn_notify,
+ ATTR_TYPE_INT, MAIL_ATTR_DSN_NOTIFY, &rcpt->dsn_notify,
ATTR_TYPE_END);
return (ret == 5 ? 1 : -1);
}
ATTR_TYPE_STR, MAIL_ATTR_RECIP, rcpt->address,
ATTR_TYPE_LONG, MAIL_ATTR_OFFSET, rcpt->offset,
ATTR_TYPE_STR, MAIL_ATTR_DSN_ORCPT, rcpt->dsn_orcpt,
- ATTR_TYPE_NUM, MAIL_ATTR_DSN_NOTIFY, rcpt->dsn_notify,
+ ATTR_TYPE_INT, MAIL_ATTR_DSN_NOTIFY, rcpt->dsn_notify,
ATTR_TYPE_END);
return (ret);
}
ATTR_TYPE_END) != 0
|| vstream_fflush(stream)
|| attr_scan(stream, ATTR_FLAG_STRICT,
- ATTR_TYPE_NUM, MAIL_ATTR_FLAGS, &server_flags,
+ ATTR_TYPE_INT, MAIL_ATTR_FLAGS, &server_flags,
ATTR_TYPE_STR, MAIL_ATTR_TRANSPORT, reply->transport,
ATTR_TYPE_STR, MAIL_ATTR_NEXTHOP, reply->nexthop,
ATTR_TYPE_STR, MAIL_ATTR_RECIP, reply->recipient,
- ATTR_TYPE_NUM, MAIL_ATTR_FLAGS, &reply->flags,
+ ATTR_TYPE_INT, MAIL_ATTR_FLAGS, &reply->flags,
ATTR_TYPE_END) != 5) {
if (msg_verbose || (errno != EPIPE && errno != ENOENT))
msg_warn("problem talking to service %s: %m",
ATTR_TYPE_END) != 0
|| vstream_fflush(stream)
|| attr_scan(stream, ATTR_FLAG_STRICT,
- ATTR_TYPE_NUM, MAIL_ATTR_FLAGS, &server_flags,
+ ATTR_TYPE_INT, MAIL_ATTR_FLAGS, &server_flags,
ATTR_TYPE_STR, MAIL_ATTR_ADDR, result,
ATTR_TYPE_END) != 2) {
if (msg_verbose || (errno != EPIPE && errno != ENOENT))
errno = 0;
if (attr_print(stream, ATTR_FLAG_NONE,
ATTR_TYPE_STR, MAIL_ATTR_REQ, SCACHE_REQ_SAVE_ENDP,
- ATTR_TYPE_NUM, MAIL_ATTR_TTL, endp_ttl,
+ ATTR_TYPE_INT, MAIL_ATTR_TTL, endp_ttl,
ATTR_TYPE_STR, MAIL_ATTR_LABEL, endp_label,
ATTR_TYPE_STR, MAIL_ATTR_PROP, endp_prop,
ATTR_TYPE_END) != 0
#endif
|| LOCAL_SEND_FD(vstream_fileno(stream), fd) < 0
|| attr_scan(stream, ATTR_FLAG_STRICT,
- ATTR_TYPE_NUM, MAIL_ATTR_STATUS, &status,
+ ATTR_TYPE_INT, MAIL_ATTR_STATUS, &status,
ATTR_TYPE_END) != 1) {
if (msg_verbose || (errno != EPIPE && errno != ENOENT))
msg_warn("problem talking to service %s: %m",
ATTR_TYPE_END) != 0
|| vstream_fflush(stream)
|| attr_scan(stream, ATTR_FLAG_STRICT,
- ATTR_TYPE_NUM, MAIL_ATTR_STATUS, &status,
+ ATTR_TYPE_INT, MAIL_ATTR_STATUS, &status,
ATTR_TYPE_STR, MAIL_ATTR_PROP, endp_prop,
ATTR_TYPE_END) != 2) {
if (msg_verbose || (errno != EPIPE && errno != ENOENT))
errno = 0;
if (attr_print(stream, ATTR_FLAG_NONE,
ATTR_TYPE_STR, MAIL_ATTR_REQ, SCACHE_REQ_SAVE_DEST,
- ATTR_TYPE_NUM, MAIL_ATTR_TTL, dest_ttl,
+ ATTR_TYPE_INT, MAIL_ATTR_TTL, dest_ttl,
ATTR_TYPE_STR, MAIL_ATTR_LABEL, dest_label,
ATTR_TYPE_STR, MAIL_ATTR_PROP, dest_prop,
ATTR_TYPE_STR, MAIL_ATTR_LABEL, endp_label,
ATTR_TYPE_END) != 0
|| vstream_fflush(stream)
|| attr_scan(stream, ATTR_FLAG_STRICT,
- ATTR_TYPE_NUM, MAIL_ATTR_STATUS, &status,
+ ATTR_TYPE_INT, MAIL_ATTR_STATUS, &status,
ATTR_TYPE_END) != 1) {
if (msg_verbose || (errno != EPIPE && errno != ENOENT))
msg_warn("problem talking to service %s: %m",
ATTR_TYPE_END) != 0
|| vstream_fflush(stream)
|| attr_scan(stream, ATTR_FLAG_STRICT,
- ATTR_TYPE_NUM, MAIL_ATTR_STATUS, &status,
+ ATTR_TYPE_INT, MAIL_ATTR_STATUS, &status,
ATTR_TYPE_STR, MAIL_ATTR_PROP, dest_prop,
ATTR_TYPE_STR, MAIL_ATTR_PROP, endp_prop,
ATTR_TYPE_END) != 3) {
my_dsn.reason = vstring_str(why);
if (mail_command_client(MAIL_CLASS_PRIVATE, var_trace_service,
- ATTR_TYPE_NUM, MAIL_ATTR_NREQ, BOUNCE_CMD_APPEND,
- ATTR_TYPE_NUM, MAIL_ATTR_FLAGS, flags,
+ ATTR_TYPE_INT, MAIL_ATTR_NREQ, BOUNCE_CMD_APPEND,
+ ATTR_TYPE_INT, MAIL_ATTR_FLAGS, flags,
ATTR_TYPE_STR, MAIL_ATTR_QUEUEID, id,
ATTR_TYPE_FUNC, rcpt_print, (void *) rcpt,
ATTR_TYPE_FUNC, dsn_print, (void *) &my_dsn,
const char *dsn_envid, int dsn_ret)
{
if (mail_command_client(MAIL_CLASS_PRIVATE, var_trace_service,
- ATTR_TYPE_NUM, MAIL_ATTR_NREQ, BOUNCE_CMD_TRACE,
- ATTR_TYPE_NUM, MAIL_ATTR_FLAGS, flags,
+ ATTR_TYPE_INT, MAIL_ATTR_NREQ, BOUNCE_CMD_TRACE,
+ ATTR_TYPE_INT, MAIL_ATTR_FLAGS, flags,
ATTR_TYPE_STR, MAIL_ATTR_QUEUE, queue,
ATTR_TYPE_STR, MAIL_ATTR_QUEUEID, id,
ATTR_TYPE_STR, MAIL_ATTR_ENCODING, encoding,
ATTR_TYPE_STR, MAIL_ATTR_SENDER, sender,
ATTR_TYPE_STR, MAIL_ATTR_DSN_ENVID, dsn_envid,
- ATTR_TYPE_NUM, MAIL_ATTR_DSN_RET, dsn_ret,
+ ATTR_TYPE_INT, MAIL_ATTR_DSN_RET, dsn_ret,
ATTR_TYPE_END) == 0) {
return (0);
} else {
ATTR_TYPE_END) != 0
|| vstream_fflush(stream)
|| attr_scan(stream, ATTR_FLAG_MISSING,
- ATTR_TYPE_NUM, MAIL_ATTR_STATUS, &request_status,
- ATTR_TYPE_NUM, MAIL_ATTR_ADDR_STATUS, addr_status,
+ ATTR_TYPE_INT, MAIL_ATTR_STATUS, &request_status,
+ ATTR_TYPE_INT, MAIL_ATTR_ADDR_STATUS, addr_status,
ATTR_TYPE_STR, MAIL_ATTR_WHY, why,
ATTR_TYPE_END) != 3) {
if (msg_verbose || (errno != EPIPE && errno != ENOENT))
if (attr_print(stream, ATTR_FLAG_NONE,
ATTR_TYPE_STR, MAIL_ATTR_REQ, VRFY_REQ_UPDATE,
ATTR_TYPE_STR, MAIL_ATTR_ADDR, addr,
- ATTR_TYPE_NUM, MAIL_ATTR_ADDR_STATUS, addr_status,
+ ATTR_TYPE_INT, MAIL_ATTR_ADDR_STATUS, addr_status,
ATTR_TYPE_STR, MAIL_ATTR_WHY, why,
ATTR_TYPE_END) != 0
|| attr_scan(stream, ATTR_FLAG_MISSING,
- ATTR_TYPE_NUM, MAIL_ATTR_STATUS, &request_status,
+ ATTR_TYPE_INT, MAIL_ATTR_STATUS, &request_status,
ATTR_TYPE_END) != 1) {
if (msg_verbose || (errno != EPIPE && errno != ENOENT))
msg_warn("problem talking to service %s: %m",
+++ /dev/null
-aaa@domain.tld
-aaa+xxx@domain.tld
-bbb@domain.tld
-bbb+yyy@domain.tld
-ccc@domain.tld
-ccc+zzz@domain.tld
-aaa@domain.ttt
-aaa+bbb@domain.ttt
+++ /dev/null
-aaa@domain.tld -> aaa
-aaa+xxx@domain.tld -> aaa
-bbb@domain.tld -> bbb
-bbb+yyy@domain.tld -> bbb
-ccc@domain.tld -> catchall
-ccc+zzz@domain.tld -> catchall
-aaa@domain.ttt -> (none)
-aaa+bbb@domain.ttt -> (none)
+++ /dev/null
-@domain.tld catchall
-aaa@domain.tld aaa
-bbb@domain.tld bbb
+++ /dev/null
-/*++
-/* NAME
-/* virtual8_maps 3
-/* SUMMARY
-/* virtual delivery agent map lookups
-/* SYNOPSIS
-/* #include <virtual8_maps.h>
-/*
-/* MAPS *virtual8_maps_create(title, map_names, flags)
-/* const char *title;
-/* const char *map_names;
-/* int flags;
-/*
-/* const char *virtual8_maps_find(maps, recipient)
-/* MAPS *maps;
-/* const char *recipient;
-/*
-/* MAPS *virtual8_maps_free(maps)
-/* MAPS *maps;
-/* DESCRIPTION
-/* This module does user lookups for the virtual delivery
-/* agent. The code is made available as a library module so that
-/* other programs can perform compatible queries.
-/*
-/* Lookups are case sensitive.
-/*
-/* virtual8_maps_create() takes list of type:name pairs and opens the
-/* named dictionaries.
-/* The result is a handle that must be specified along with all
-/* other virtual8_maps_xxx() operations.
-/* See dict_open(3) for a description of flags.
-/*
-/* virtual8_maps_find() searches the specified list of dictionaries
-/* in the specified order for the named key. The result is in
-/* memory that is overwritten upon each call.
-/*
-/* virtual8_maps_free() releases storage claimed by virtual8_maps_create()
-/* and conveniently returns a null pointer.
-/*
-/* Arguments:
-/* .IP title
-/* String used for diagnostics. Typically one specifies the
-/* type of information stored in the lookup tables.
-/* .IP map_names
-/* Null-terminated string with type:name dictionary specifications,
-/* separated by whitespace or commas.
-/* .IP maps
-/* A result from maps_create().
-/* .IP key
-/* Null-terminated string with a lookup key. Table lookup is case
-/* sensitive.
-/* DIAGNOSTICS
-/* The dict_errno variable is non-zero in case of problems.
-/* BUGS
-/* This code is a temporary solution that implements a hard-coded
-/* lookup strategy. In a future version of Postfix, the lookup
-/* strategy should become configurable.
-/* SEE ALSO
-/* virtual(8) virtual mailbox delivery agent
-/* maps(3) multi-dictionary search
-/* dict_open(3) low-level dictionary interface
-/* 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 <sys_defs.h>
-#include <string.h>
-
-/* Utility library. */
-
-#include <msg.h>
-#include <mymalloc.h>
-
-/* Global library. */
-
-#include <maps.h>
-#include <mail_params.h>
-#include <strip_addr.h>
-#include <virtual8_maps.h>
-
-/* Application-specific. */
-
-/* virtual8_maps_find - lookup for virtual delivery agent */
-
-const char *virtual8_maps_find(MAPS *maps, const char *recipient)
-{
- const char *ratsign;
- const char *result;
- char *bare = 0;
-
- /*
- * Look up the address minus the optional extension. This is done first,
- * to avoid hammering the database with extended address lookups, and to
- * have straightforward semantics (extensions are always ignored).
- */
- if (*var_rcpt_delim
- && (bare = strip_addr(recipient, (char **) 0, *var_rcpt_delim)) != 0) {
- result = maps_find(maps, bare, DICT_FLAG_FIXED);
- myfree(bare);
- if (result != 0 || dict_errno != 0)
- return (result);
- }
-
- /*
- * Look up the full address. Allow regexp table searches.
- */
- if (bare == 0) {
- result = maps_find(maps, recipient, DICT_FLAG_NONE);
- if (result != 0 || dict_errno != 0)
- return (result);
- }
-
- /*
- * Look up the @domain catch-all.
- */
- if ((ratsign = strrchr(recipient, '@')) == 0)
- return (0);
- return (maps_find(maps, ratsign, DICT_FLAG_FIXED));
-}
-
-#ifdef TEST
-
-#include <vstream.h>
-#include <vstring.h>
-#include <vstring_vstream.h>
-
-#define STR(x) vstring_str(x)
-
-int main(int argc, char **argv)
-{
- VSTRING *buffer;
- MAPS *maps;
- const char *result;
-
- if (argc != 2)
- msg_fatal("usage: %s mapname", argv[0]);
-
- var_rcpt_delim = "+";
- var_double_bounce_sender = DEF_DOUBLE_BOUNCE;
-
- maps = virtual8_maps_create("testmap", argv[1], DICT_FLAG_LOCK);
- buffer = vstring_alloc(1);
-
- while (vstring_fgets_nonl(buffer, VSTREAM_IN)) {
- result = virtual8_maps_find(maps, STR(buffer));
- vstream_printf("%s -> %s\n", STR(buffer), result ? result : "(none)");
- vstream_fflush(VSTREAM_OUT);
- }
- virtual8_maps_free(maps);
- vstring_free(buffer);
- return (0);
-}
-
-#endif
+++ /dev/null
-#ifndef _VIRTUAL8_MAPS_H_INCLUDED_
-#define _VIRTUAL8_MAPS_H_INCLUDED_
-
-/*++
-/* NAME
-/* virtual8_maps 3h
-/* SUMMARY
-/* virtual delivery agent compatibility
-/* SYNOPSIS
-/* #include <virtual8_maps.h>
-/* DESCRIPTION
-/* .nf
-
- /*
- * Global library.
- */
-#include <maps.h>
-
- /*
- * External interface.
- */
-#define virtual8_maps_create(title, map_names, flags) \
- maps_create((title), (map_names), (flags))
-extern const char *virtual8_maps_find(MAPS *, const char *);
-#define virtual8_maps_free(maps) maps_free((maps))
-
-/* 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
#define FORWARD_CLEANUP_FLAGS (CLEANUP_FLAG_BOUNCE | CLEANUP_FLAG_MASK_INTERNAL)
attr_print(cleanup, ATTR_FLAG_NONE,
- ATTR_TYPE_NUM, MAIL_ATTR_FLAGS, FORWARD_CLEANUP_FLAGS,
+ ATTR_TYPE_INT, MAIL_ATTR_FLAGS, FORWARD_CLEANUP_FLAGS,
ATTR_TYPE_END);
/*
if (status == 0)
if (vstream_fflush(info->cleanup)
|| attr_scan(info->cleanup, ATTR_FLAG_MISSING,
- ATTR_TYPE_NUM, MAIL_ATTR_STATUS, &status,
+ ATTR_TYPE_INT, MAIL_ATTR_STATUS, &status,
ATTR_TYPE_END) != 1)
status = 1;
set_file_limit(var_mailbox_limit);
}
alias_maps = maps_create("aliases", var_alias_maps,
- DICT_FLAG_LOCK | DICT_FLAG_PARANOID);
+ DICT_FLAG_LOCK | DICT_FLAG_PARANOID
+ | DICT_FLAG_FOLD_FIX);
flush_init();
}
*/
if (*var_mbox_transp_maps && transp_maps == 0)
transp_maps = maps_create(VAR_MBOX_TRANSP_MAPS, var_mbox_transp_maps,
- DICT_FLAG_LOCK);
+ DICT_FLAG_LOCK | DICT_FLAG_NO_REGSUB);
if (*var_mbox_transp_maps
&& (map_transport = maps_find(transp_maps, state.msg_attr.user,
- DICT_FLAG_FIXED)) != 0) {
+ DICT_FLAG_NONE)) != 0) {
state.msg_attr.rcpt.offset = -1L;
*statusp = deliver_pass(MAIL_CLASS_PRIVATE, map_transport,
state.request, &state.msg_attr.rcpt);
if (*var_mailbox_cmd_maps && cmd_maps == 0)
cmd_maps = maps_create(VAR_MAILBOX_CMD_MAPS, var_mailbox_cmd_maps,
- DICT_FLAG_LOCK);
+ DICT_FLAG_LOCK | DICT_FLAG_PARANOID);
if (*var_mailbox_cmd_maps
&& (map_command = maps_find(cmd_maps, state.msg_attr.user,
- DICT_FLAG_FIXED)) != 0) {
+ DICT_FLAG_NONE)) != 0) {
status = deliver_command(state, usr_attr, map_command);
} else if (*var_mailbox_command) {
status = deliver_command(state, usr_attr, var_mailbox_command);
*/
if (*var_fbck_transp_maps && transp_maps == 0)
transp_maps = maps_create(VAR_FBCK_TRANSP_MAPS, var_fbck_transp_maps,
- DICT_FLAG_LOCK);
+ DICT_FLAG_LOCK | DICT_FLAG_NO_REGSUB);
if (*var_fbck_transp_maps
&& (map_transport = maps_find(transp_maps, state.msg_attr.user,
- DICT_FLAG_FIXED)) != 0) {
+ DICT_FLAG_NONE)) != 0) {
return (deliver_pass(MAIL_CLASS_PRIVATE, map_transport,
state.request, &state.msg_attr.rcpt));
}
char *oval;
char *generation;
int msg_vstream_needed = 0;
+ int privileged = 0;
/*
* Process environment options as early as we can.
if (user_name)
msg_fatal("service %s requires privileged operation",
service_name);
+ privileged = 1;
break;
default:
msg_panic("%s: unknown argument type: %d", myname, key);
}
va_end(ap);
+ if (privileged == 0 && user_name == 0)
+ msg_fatal("service %s requires unprivileged operation", service_name);
+
if (root_dir)
root_dir = var_queue_dir;
if (user_name)
char *oval;
char *generation;
int msg_vstream_needed = 0;
+ int privileged = 0;
/*
* Process environment options as early as we can.
if (user_name)
msg_fatal("service %s requires privileged operation",
service_name);
+ privileged = 1;
break;
default:
msg_panic("%s: unknown argument type: %d", myname, key);
}
va_end(ap);
+ if (privileged == 0 && user_name == 0)
+ msg_fatal("service %s requires unprivileged operation", service_name);
+
if (root_dir)
root_dir = var_queue_dir;
if (user_name)
char *oval;
char *generation;
int msg_vstream_needed = 0;
+ int privileged = 0;
/*
* Process environment options as early as we can.
if (user_name)
msg_fatal("service %s requires privileged operation",
service_name);
+ privileged = 1;
break;
default:
msg_panic("%s: unknown argument type: %d", myname, key);
}
va_end(ap);
+ if (privileged == 0 && user_name == 0)
+ msg_fatal("service %s requires unprivileged operation", service_name);
+
if (root_dir)
root_dir = var_queue_dir;
if (user_name)
msg_warn("%s: premature disconnect", VSTREAM_PATH(stream));
return (DELIVER_STAT_CRASH);
} else if (attr_scan(stream, ATTR_FLAG_STRICT,
- ATTR_TYPE_NUM, MAIL_ATTR_STATUS, &stat,
+ ATTR_TYPE_INT, MAIL_ATTR_STATUS, &stat,
ATTR_TYPE_END) != 1) {
msg_warn("%s: malformed response", VSTREAM_PATH(stream));
return (DELIVER_STAT_CRASH);
return (DELIVER_STAT_CRASH);
} else if (attr_scan(stream, ATTR_FLAG_STRICT,
ATTR_TYPE_FUNC, dsb_scan, (void *) dsb,
- ATTR_TYPE_NUM, MAIL_ATTR_STATUS, &stat,
+ ATTR_TYPE_INT, MAIL_ATTR_STATUS, &stat,
ATTR_TYPE_END) != 2) {
msg_warn("%s: malformed response", VSTREAM_PATH(stream));
return (DELIVER_STAT_CRASH);
| (message->inspect_xport ? DEL_REQ_FLAG_BOUNCE : DEL_REQ_FLAG_DEFLT);
(void) QMGR_MSG_STATS(&stats, message);
attr_print(stream, ATTR_FLAG_NONE,
- ATTR_TYPE_NUM, MAIL_ATTR_FLAGS, flags,
+ ATTR_TYPE_INT, MAIL_ATTR_FLAGS, flags,
ATTR_TYPE_STR, MAIL_ATTR_QUEUE, message->queue_name,
ATTR_TYPE_STR, MAIL_ATTR_QUEUEID, message->queue_id,
ATTR_TYPE_LONG, MAIL_ATTR_OFFSET, message->data_offset,
ATTR_TYPE_STR, MAIL_ATTR_ENCODING, message->encoding,
ATTR_TYPE_STR, MAIL_ATTR_SENDER, sender,
ATTR_TYPE_STR, MAIL_ATTR_DSN_ENVID, message->dsn_envid,
- ATTR_TYPE_NUM, MAIL_ATTR_DSN_RET, message->dsn_ret,
+ ATTR_TYPE_INT, MAIL_ATTR_DSN_RET, message->dsn_ret,
ATTR_TYPE_FUNC, msg_stats_print, (void *) &stats,
ATTR_TYPE_STR, MAIL_ATTR_CLIENT_NAME, message->client_name,
ATTR_TYPE_STR, MAIL_ATTR_CLIENT_ADDR, message->client_addr,
ATTR_TYPE_STR, MAIL_ATTR_SASL_USERNAME, message->sasl_username,
ATTR_TYPE_STR, MAIL_ATTR_SASL_SENDER, message->sasl_sender,
ATTR_TYPE_STR, MAIL_ATTR_RWR_CONTEXT, message->rewrite_context,
- ATTR_TYPE_NUM, MAIL_ATTR_RCPT_COUNT, list.len,
+ ATTR_TYPE_INT, MAIL_ATTR_RCPT_COUNT, list.len,
ATTR_TYPE_END);
if (sender_buf != 0)
vstring_free(sender_buf);
*/
rec_fputs(cleanup, REC_TYPE_END, "");
if (attr_scan(cleanup, ATTR_FLAG_MISSING,
- ATTR_TYPE_NUM, MAIL_ATTR_STATUS, &status,
+ ATTR_TYPE_INT, MAIL_ATTR_STATUS, &status,
ATTR_TYPE_END) != 1)
return (cleanup_service_error(info, CLEANUP_STAT_WRITE));
ATTR_TYPE_STR, MAIL_ATTR_QUEUEID, buf,
ATTR_TYPE_END) != 1
|| attr_print(cleanup, ATTR_FLAG_NONE,
- ATTR_TYPE_NUM, MAIL_ATTR_FLAGS, cleanup_flags,
+ ATTR_TYPE_INT, MAIL_ATTR_FLAGS, cleanup_flags,
ATTR_TYPE_END) != 0) {
status = KEEP_MESSAGE_FILE;
} else {
/* The format of Postfix alias input files is described in
/* \fBaliases\fR(5).
/*
+/* By default the lookup key is mapped to lowercase to make
+/* the lookups case insensitive; as of Postfix 2.3 this case
+/* folding happens only with tables whose lookup keys are
+/* fixed-case strings such as btree:, dbm: or hash:. With
+/* earlier versions, the lookup key is folded even with tables
+/* where a lookup field can match both upper and lower case
+/* text, such as regexp: and pcre:. This resulted in loss of
+/* information with $\fInumber\fR substitutions.
+/*
/* Options:
/* .IP "\fB-c \fIconfig_dir\fR"
/* Read the \fBmain.cf\fR configuration file in the named directory
/* when at least one of the requested keys was found.
/* .IP \fB-f\fR
/* Do not fold the lookup key to lower case while creating or querying
-/* a map.
+/* a table.
/* .IP \fB-i\fR
/* Incremental mode. Read entries from standard input and do not
/* truncate an existing database. By default, \fBpostalias\fR(1) creates
/*
* Store the value under a case-insensitive key.
*/
- if (dict_flags & DICT_FLAG_FOLD_KEY)
- lowercase(STR(key_buffer));
mkmap_append(mkmap, STR(key_buffer), STR(value_buffer));
}
* maps.
*/
while (vstring_get_nonl(keybuf, in) != VSTREAM_EOF) {
- if (dict_flags & DICT_FLAG_FOLD_KEY)
- lowercase(STR(keybuf));
for (n = 0; n < map_count; n++) {
if (dicts[n] == 0)
dicts[n] = ((map_name = split_at(maps[n], ':')) != 0 ?
- dict_open3(maps[n], map_name, O_RDONLY, DICT_FLAG_LOCK) :
- dict_open3(var_db_type, maps[n], O_RDONLY, DICT_FLAG_LOCK));
+ dict_open3(maps[n], map_name, O_RDONLY, dict_flags) :
+ dict_open3(var_db_type, maps[n], O_RDONLY, dict_flags));
if ((value = dict_get(dicts[n], STR(keybuf))) != 0) {
if (*value == 0) {
msg_warn("table %s:%s: key %s: empty string result is not allowed",
/* postalias_query - query a map and print the result to stdout */
static int postalias_query(const char *map_type, const char *map_name,
- const char *key)
+ const char *key, int dict_flags)
{
DICT *dict;
const char *value;
- dict = dict_open3(map_type, map_name, O_RDONLY, DICT_FLAG_LOCK);
+ dict = dict_open3(map_type, map_name, O_RDONLY, dict_flags);
if ((value = dict_get(dict, key)) != 0) {
if (*value == 0) {
msg_warn("table %s:%s: key %s: empty string result is not allowed",
/* postalias_deletes - apply multiple requests from stdin */
-static int postalias_deletes(VSTREAM *in, char **maps, const int map_count)
+static int postalias_deletes(VSTREAM *in, char **maps, const int map_count,
+ int dict_flags)
{
int found = 0;
VSTRING *keybuf = vstring_alloc(100);
dicts = (DICT **) mymalloc(sizeof(*dicts) * map_count);
for (n = 0; n < map_count; n++)
dicts[n] = ((map_name = split_at(maps[n], ':')) != 0 ?
- dict_open3(maps[n], map_name, O_RDWR, DICT_FLAG_LOCK) :
- dict_open3(var_db_type, maps[n], O_RDWR, DICT_FLAG_LOCK));
+ dict_open3(maps[n], map_name, O_RDWR, dict_flags) :
+ dict_open3(var_db_type, maps[n], O_RDWR, dict_flags));
/*
* Perform all requests.
/* postalias_delete - delete a key value pair from a map */
static int postalias_delete(const char *map_type, const char *map_name,
- const char *key)
+ const char *key, int dict_flags)
{
DICT *dict;
int status;
- dict = dict_open3(map_type, map_name, O_RDWR, DICT_FLAG_LOCK);
+ dict = dict_open3(map_type, map_name, O_RDWR, dict_flags);
status = dict_del(dict, key);
dict_close(dict);
return (status == 0);
/* postalias_seq - print all map entries to stdout */
-static void postalias_seq(const char *map_type, const char *map_name)
+static void postalias_seq(const char *map_type, const char *map_name,
+ int dict_flags)
{
DICT *dict;
const char *key;
const char *value;
int func;
- dict = dict_open3(map_type, map_name, O_RDONLY, DICT_FLAG_LOCK);
+ dict = dict_open3(map_type, map_name, O_RDONLY, dict_flags);
for (func = DICT_SEQ_FUN_FIRST; /* void */ ; func = DICT_SEQ_FUN_NEXT) {
if (dict_seq(dict, func, &key, &value) != 0)
break;
struct stat st;
int postalias_flags = POSTALIAS_FLAG_AS_OWNER | POSTALIAS_FLAG_SAVE_PERM;
int open_flags = O_RDWR | O_CREAT | O_TRUNC;
- int dict_flags = DICT_FLAG_DUP_WARN | DICT_FLAG_FOLD_KEY;
+ int dict_flags = DICT_FLAG_DUP_WARN | DICT_FLAG_FOLD_FIX;
char *query = 0;
char *delkey = 0;
int sequence = 0;
delkey = optarg;
break;
case 'f':
- dict_flags &= ~DICT_FLAG_FOLD_KEY;
+ dict_flags &= ~DICT_FLAG_FOLD_FIX;
break;
case 'i':
open_flags &= ~O_TRUNC;
if (optind + 1 > argc)
usage(argv[0]);
if (strcmp(delkey, "-") == 0)
- exit(postalias_deletes(VSTREAM_IN, argv + optind, argc - optind) == 0);
+ exit(postalias_deletes(VSTREAM_IN, argv + optind, argc - optind,
+ dict_flags | DICT_FLAG_LOCK) == 0);
found = 0;
while (optind < argc) {
if ((path_name = split_at(argv[optind], ':')) != 0) {
- found |= postalias_delete(argv[optind], path_name, delkey);
+ found |= postalias_delete(argv[optind], path_name, delkey,
+ dict_flags | DICT_FLAG_LOCK);
} else {
- found |= postalias_delete(var_db_type, argv[optind], delkey);
+ found |= postalias_delete(var_db_type, argv[optind], delkey,
+ dict_flags | DICT_FLAG_LOCK);
}
optind++;
}
usage(argv[0]);
if (strcmp(query, "-") == 0)
exit(postalias_queries(VSTREAM_IN, argv + optind, argc - optind,
- dict_flags) == 0);
- if (dict_flags & DICT_FLAG_FOLD_KEY)
- lowercase(query);
+ dict_flags | DICT_FLAG_LOCK) == 0);
while (optind < argc) {
if ((path_name = split_at(argv[optind], ':')) != 0) {
- found = postalias_query(argv[optind], path_name, query);
+ found = postalias_query(argv[optind], path_name, query,
+ dict_flags | DICT_FLAG_LOCK);
} else {
- found = postalias_query(var_db_type, argv[optind], query);
+ found = postalias_query(var_db_type, argv[optind], query,
+ dict_flags | DICT_FLAG_LOCK);
}
if (found)
exit(0);
} else if (sequence) {
while (optind < argc) {
if ((path_name = split_at(argv[optind], ':')) != 0) {
- postalias_seq(argv[optind], path_name);
+ postalias_seq(argv[optind], path_name,
+ dict_flags | DICT_FLAG_LOCK);
} else {
- postalias_seq(var_db_type, argv[optind]);
+ postalias_seq(var_db_type, argv[optind],
+ dict_flags | DICT_FLAG_LOCK);
}
exit(0);
}
* Send the completion status to the caller and terminate.
*/
attr_print(VSTREAM_OUT, ATTR_FLAG_NONE,
- ATTR_TYPE_NUM, MAIL_ATTR_STATUS, status,
+ ATTR_TYPE_INT, MAIL_ATTR_STATUS, status,
ATTR_TYPE_STR, MAIL_ATTR_WHY, "",
ATTR_TYPE_END);
vstream_fflush(VSTREAM_OUT);
/* The \fIkey\fR and \fIvalue\fR are processed as is, except that
/* surrounding white space is stripped off. Unlike with Postfix alias
/* databases, quotes cannot be used to protect lookup keys that contain
-/* special characters such as `#' or whitespace. The \fIkey\fR is mapped
-/* to lowercase to make mapping lookups case insensitive.
+/* special characters such as `#' or whitespace.
+/*
+/* By default the lookup key is mapped to lowercase to make
+/* the lookups case insensitive; as of Postfix 2.3 this case
+/* folding happens only with tables whose lookup keys are
+/* fixed-case strings such as btree:, dbm: or hash:. With
+/* earlier versions, the lookup key is folded even with tables
+/* where a lookup field can match both upper and lower case
+/* text, such as regexp: and pcre:. This resulted in loss of
+/* information with $\fInumber\fR substitutions.
/* COMMAND-LINE ARGUMENTS
/* .ad
/* .fi
/* when at least one of the requested keys was found.
/* .IP \fB-f\fR
/* Do not fold the lookup key to lower case while creating or querying
-/* a map.
+/* a table.
/* .IP \fB-i\fR
/* Incremental mode. Read entries from standard input and do not
/* truncate an existing database. By default, \fBpostmap\fR(1) creates
/*
* Store the value under a case-insensitive key.
*/
- if (dict_flags & DICT_FLAG_FOLD_KEY)
- lowercase(key);
mkmap_append(mkmap, key, value);
}
* maps.
*/
while (vstring_get_nonl(keybuf, in) != VSTREAM_EOF) {
- if (dict_flags & DICT_FLAG_FOLD_KEY)
- lowercase(STR(keybuf));
for (n = 0; n < map_count; n++) {
if (dicts[n] == 0)
dicts[n] = ((map_name = split_at(maps[n], ':')) != 0 ?
- dict_open3(maps[n], map_name, O_RDONLY, DICT_FLAG_LOCK) :
- dict_open3(var_db_type, maps[n], O_RDONLY, DICT_FLAG_LOCK));
+ dict_open3(maps[n], map_name, O_RDONLY, dict_flags) :
+ dict_open3(var_db_type, maps[n], O_RDONLY, dict_flags));
if ((value = dict_get(dicts[n], STR(keybuf))) != 0) {
if (*value == 0) {
msg_warn("table %s:%s: key %s: empty string result is not allowed",
/* postmap_query - query a map and print the result to stdout */
static int postmap_query(const char *map_type, const char *map_name,
- const char *key)
+ const char *key, int dict_flags)
{
DICT *dict;
const char *value;
- dict = dict_open3(map_type, map_name, O_RDONLY, DICT_FLAG_LOCK);
+ dict = dict_open3(map_type, map_name, O_RDONLY, dict_flags);
if ((value = dict_get(dict, key)) != 0) {
if (*value == 0) {
msg_warn("table %s:%s: key %s: empty string result is not allowed",
/* postmap_deletes - apply multiple requests from stdin */
-static int postmap_deletes(VSTREAM *in, char **maps, const int map_count)
+static int postmap_deletes(VSTREAM *in, char **maps, const int map_count,
+ int dict_flags)
{
int found = 0;
VSTRING *keybuf = vstring_alloc(100);
dicts = (DICT **) mymalloc(sizeof(*dicts) * map_count);
for (n = 0; n < map_count; n++)
dicts[n] = ((map_name = split_at(maps[n], ':')) != 0 ?
- dict_open3(maps[n], map_name, O_RDWR, DICT_FLAG_LOCK) :
- dict_open3(var_db_type, maps[n], O_RDWR, DICT_FLAG_LOCK));
+ dict_open3(maps[n], map_name, O_RDWR, dict_flags) :
+ dict_open3(var_db_type, maps[n], O_RDWR, dict_flags));
/*
* Perform all requests.
/* postmap_delete - delete a (key, value) pair from a map */
static int postmap_delete(const char *map_type, const char *map_name,
- const char *key)
+ const char *key, int dict_flags)
{
DICT *dict;
int status;
- dict = dict_open3(map_type, map_name, O_RDWR, DICT_FLAG_LOCK);
+ dict = dict_open3(map_type, map_name, O_RDWR, dict_flags);
status = dict_del(dict, key);
dict_close(dict);
return (status == 0);
/* postmap_seq - print all map entries to stdout */
-static void postmap_seq(const char *map_type, const char *map_name)
+static void postmap_seq(const char *map_type, const char *map_name,
+ int dict_flags)
{
DICT *dict;
const char *key;
const char *value;
int func;
- dict = dict_open3(map_type, map_name, O_RDONLY, DICT_FLAG_LOCK);
+ dict = dict_open3(map_type, map_name, O_RDONLY, dict_flags);
for (func = DICT_SEQ_FUN_FIRST; /* void */ ; func = DICT_SEQ_FUN_NEXT) {
if (dict_seq(dict, func, &key, &value) != 0)
break;
struct stat st;
int postmap_flags = POSTMAP_FLAG_AS_OWNER | POSTMAP_FLAG_SAVE_PERM;
int open_flags = O_RDWR | O_CREAT | O_TRUNC;
- int dict_flags = DICT_FLAG_DUP_WARN | DICT_FLAG_FOLD_KEY;
+ int dict_flags = DICT_FLAG_DUP_WARN | DICT_FLAG_FOLD_FIX;
char *query = 0;
char *delkey = 0;
int sequence = 0;
delkey = optarg;
break;
case 'f':
- dict_flags &= ~DICT_FLAG_FOLD_KEY;
+ dict_flags &= ~DICT_FLAG_FOLD_FIX;
break;
case 'i':
open_flags &= ~O_TRUNC;
if (optind + 1 > argc)
usage(argv[0]);
if (strcmp(delkey, "-") == 0)
- exit(postmap_deletes(VSTREAM_IN, argv + optind, argc - optind) == 0);
+ exit(postmap_deletes(VSTREAM_IN, argv + optind, argc - optind,
+ dict_flags | DICT_FLAG_LOCK) == 0);
found = 0;
while (optind < argc) {
if ((path_name = split_at(argv[optind], ':')) != 0) {
- found |= postmap_delete(argv[optind], path_name, delkey);
+ found |= postmap_delete(argv[optind], path_name, delkey,
+ dict_flags | DICT_FLAG_LOCK);
} else {
- found |= postmap_delete(var_db_type, argv[optind], delkey);
+ found |= postmap_delete(var_db_type, argv[optind], delkey,
+ dict_flags | DICT_FLAG_LOCK);
}
optind++;
}
usage(argv[0]);
if (strcmp(query, "-") == 0)
exit(postmap_queries(VSTREAM_IN, argv + optind, argc - optind,
- dict_flags) == 0);
- if (dict_flags & DICT_FLAG_FOLD_KEY)
- lowercase(query);
+ dict_flags | DICT_FLAG_LOCK) == 0);
while (optind < argc) {
if ((path_name = split_at(argv[optind], ':')) != 0) {
- found = postmap_query(argv[optind], path_name, query);
+ found = postmap_query(argv[optind], path_name, query,
+ dict_flags | DICT_FLAG_LOCK);
} else {
- found = postmap_query(var_db_type, argv[optind], query);
+ found = postmap_query(var_db_type, argv[optind], query,
+ dict_flags | DICT_FLAG_LOCK);
}
if (found)
exit(0);
} else if (sequence) {
while (optind < argc) {
if ((path_name = split_at(argv[optind], ':')) != 0) {
- postmap_seq(argv[optind], path_name);
+ postmap_seq(argv[optind], path_name,
+ dict_flags | DICT_FLAG_LOCK);
} else {
- postmap_seq(var_db_type, argv[optind]);
+ postmap_seq(var_db_type, argv[optind],
+ dict_flags | DICT_FLAG_LOCK);
}
exit(0);
}
postqueue.o: ../../include/flush_clnt.h
postqueue.o: ../../include/iostuff.h
postqueue.o: ../../include/mail_conf.h
+postqueue.o: ../../include/mail_dict.h
postqueue.o: ../../include/mail_flush.h
postqueue.o: ../../include/mail_params.h
postqueue.o: ../../include/mail_proto.h
#include <smtp_stream.h>
#include <user_acl.h>
#include <valid_mailhost_addr.h>
+#include <mail_dict.h>
/* Application-specific. */
/*
* Open one instance of a map for each combination of name+flags.
*/
- vstring_sprintf(map_type_name_flags, "%s:%o",
- map_type_name, request_flags);
+ vstring_sprintf(map_type_name_flags, "%s:%s",
+ map_type_name, dict_flags_str(request_flags));
if ((dict = dict_handle(STR(map_type_name_flags))) == 0)
dict = dict_open(map_type_name, READ_OPEN_FLAGS, request_flags);
if (dict == 0)
*/
if (attr_scan(client_stream, ATTR_FLAG_STRICT,
ATTR_TYPE_STR, MAIL_ATTR_TABLE, request_map,
- ATTR_TYPE_NUM, MAIL_ATTR_FLAGS, &request_flags,
+ ATTR_TYPE_INT, MAIL_ATTR_FLAGS, &request_flags,
ATTR_TYPE_STR, MAIL_ATTR_KEY, request_key,
ATTR_TYPE_END) != 3) {
reply_status = PROXY_STAT_BAD;
* Respond to the client.
*/
attr_print(client_stream, ATTR_FLAG_NONE,
- ATTR_TYPE_NUM, MAIL_ATTR_STATUS, reply_status,
+ ATTR_TYPE_INT, MAIL_ATTR_STATUS, reply_status,
ATTR_TYPE_STR, MAIL_ATTR_VALUE, reply_value,
ATTR_TYPE_END);
}
*/
if (attr_scan(client_stream, ATTR_FLAG_STRICT,
ATTR_TYPE_STR, MAIL_ATTR_TABLE, request_map,
- ATTR_TYPE_NUM, MAIL_ATTR_FLAGS, &request_flags,
+ ATTR_TYPE_INT, MAIL_ATTR_FLAGS, &request_flags,
ATTR_TYPE_END) != 2) {
reply_status = PROXY_STAT_BAD;
reply_flags = 0;
* Respond to the client.
*/
attr_print(client_stream, ATTR_FLAG_NONE,
- ATTR_TYPE_NUM, MAIL_ATTR_STATUS, reply_status,
- ATTR_TYPE_NUM, MAIL_ATTR_FLAGS, reply_flags,
+ ATTR_TYPE_INT, MAIL_ATTR_STATUS, reply_status,
+ ATTR_TYPE_INT, MAIL_ATTR_FLAGS, reply_flags,
ATTR_TYPE_END);
}
} else {
msg_warn("unrecognized request: \"%s\", ignored", STR(request));
attr_print(client_stream, ATTR_FLAG_NONE,
- ATTR_TYPE_NUM, MAIL_ATTR_STATUS, PROXY_STAT_BAD,
+ ATTR_TYPE_INT, MAIL_ATTR_STATUS, PROXY_STAT_BAD,
ATTR_TYPE_END);
}
}
msg_warn("%s: premature disconnect", VSTREAM_PATH(stream));
return (DELIVER_STAT_CRASH);
} else if (attr_scan(stream, ATTR_FLAG_STRICT,
- ATTR_TYPE_NUM, MAIL_ATTR_STATUS, &stat,
+ ATTR_TYPE_INT, MAIL_ATTR_STATUS, &stat,
ATTR_TYPE_END) != 1) {
msg_warn("%s: malformed response", VSTREAM_PATH(stream));
return (DELIVER_STAT_CRASH);
return (DELIVER_STAT_CRASH);
} else if (attr_scan(stream, ATTR_FLAG_STRICT,
ATTR_TYPE_FUNC, dsb_scan, (void *) dsb,
- ATTR_TYPE_NUM, MAIL_ATTR_STATUS, &stat,
+ ATTR_TYPE_INT, MAIL_ATTR_STATUS, &stat,
ATTR_TYPE_END) != 2) {
msg_warn("%s: malformed response", VSTREAM_PATH(stream));
return (DELIVER_STAT_CRASH);
| (message->inspect_xport ? DEL_REQ_FLAG_BOUNCE : DEL_REQ_FLAG_DEFLT);
(void) QMGR_MSG_STATS(&stats, message);
attr_print(stream, ATTR_FLAG_NONE,
- ATTR_TYPE_NUM, MAIL_ATTR_FLAGS, flags,
+ ATTR_TYPE_INT, MAIL_ATTR_FLAGS, flags,
ATTR_TYPE_STR, MAIL_ATTR_QUEUE, message->queue_name,
ATTR_TYPE_STR, MAIL_ATTR_QUEUEID, message->queue_id,
ATTR_TYPE_LONG, MAIL_ATTR_OFFSET, message->data_offset,
ATTR_TYPE_STR, MAIL_ATTR_ENCODING, message->encoding,
ATTR_TYPE_STR, MAIL_ATTR_SENDER, sender,
ATTR_TYPE_STR, MAIL_ATTR_DSN_ENVID, message->dsn_envid,
- ATTR_TYPE_NUM, MAIL_ATTR_DSN_RET, message->dsn_ret,
+ ATTR_TYPE_INT, MAIL_ATTR_DSN_RET, message->dsn_ret,
ATTR_TYPE_FUNC, msg_stats_print, (void *) &stats,
ATTR_TYPE_STR, MAIL_ATTR_CLIENT_NAME, message->client_name,
ATTR_TYPE_STR, MAIL_ATTR_CLIENT_ADDR, message->client_addr,
ATTR_TYPE_STR, MAIL_ATTR_SASL_USERNAME, message->sasl_username,
ATTR_TYPE_STR, MAIL_ATTR_SASL_SENDER, message->sasl_sender,
ATTR_TYPE_STR, MAIL_ATTR_RWR_CONTEXT, message->rewrite_context,
- ATTR_TYPE_NUM, MAIL_ATTR_RCPT_COUNT, list.len,
+ ATTR_TYPE_INT, MAIL_ATTR_RCPT_COUNT, list.len,
ATTR_TYPE_END);
if (sender_buf != 0)
vstring_free(sender_buf);
state->dest = mail_stream_service(MAIL_CLASS_PUBLIC, var_cleanup_service);
if (state->dest == 0
|| attr_print(state->dest->stream, ATTR_FLAG_NONE,
- ATTR_TYPE_NUM, MAIL_ATTR_FLAGS, cleanup_flags,
+ ATTR_TYPE_INT, MAIL_ATTR_FLAGS, cleanup_flags,
ATTR_TYPE_END) != 0)
msg_fatal("unable to connect to the %s %s service",
MAIL_CLASS_PUBLIC, var_cleanup_service);
if (attr_scan(client_stream,
ATTR_FLAG_STRICT,
- ATTR_TYPE_NUM, MAIL_ATTR_TTL, &ttl,
+ ATTR_TYPE_INT, MAIL_ATTR_TTL, &ttl,
ATTR_TYPE_STR, MAIL_ATTR_LABEL, scache_endp_label,
ATTR_TYPE_STR, MAIL_ATTR_PROP, scache_endp_prop,
ATTR_TYPE_END) != 3
|| ttl <= 0) {
msg_warn("%s: bad or missing request parameter", myname);
attr_print(client_stream, ATTR_FLAG_NONE,
- ATTR_TYPE_NUM, MAIL_ATTR_STATUS, SCACHE_STAT_BAD,
+ ATTR_TYPE_INT, MAIL_ATTR_STATUS, SCACHE_STAT_BAD,
ATTR_TYPE_END);
return;
} else if (
(fd = LOCAL_RECV_FD(vstream_fileno(client_stream))) < 0) {
msg_warn("%s: unable to receive file descriptor: %m", myname);
(void) attr_print(client_stream, ATTR_FLAG_NONE,
- ATTR_TYPE_NUM, MAIL_ATTR_STATUS, SCACHE_STAT_FAIL,
+ ATTR_TYPE_INT, MAIL_ATTR_STATUS, SCACHE_STAT_FAIL,
ATTR_TYPE_END);
return;
} else {
ttl > var_scache_ttl_lim ? var_scache_ttl_lim : ttl,
STR(scache_endp_label), STR(scache_endp_prop), fd);
(void) attr_print(client_stream, ATTR_FLAG_NONE,
- ATTR_TYPE_NUM, MAIL_ATTR_STATUS, SCACHE_STAT_OK,
+ ATTR_TYPE_INT, MAIL_ATTR_STATUS, SCACHE_STAT_OK,
ATTR_TYPE_END);
scache_size(scache, &size);
if (size.endp_count > scache_endp_count)
ATTR_TYPE_END) != 1) {
msg_warn("%s: bad or missing request parameter", myname);
attr_print(client_stream, ATTR_FLAG_NONE,
- ATTR_TYPE_NUM, MAIL_ATTR_STATUS, SCACHE_STAT_BAD,
+ ATTR_TYPE_INT, MAIL_ATTR_STATUS, SCACHE_STAT_BAD,
ATTR_TYPE_STR, MAIL_ATTR_PROP, "",
ATTR_TYPE_END);
return;
} else if ((fd = scache_find_endp(scache, STR(scache_endp_label),
scache_endp_prop)) < 0) {
attr_print(client_stream, ATTR_FLAG_NONE,
- ATTR_TYPE_NUM, MAIL_ATTR_STATUS, SCACHE_STAT_FAIL,
+ ATTR_TYPE_INT, MAIL_ATTR_STATUS, SCACHE_STAT_FAIL,
ATTR_TYPE_STR, MAIL_ATTR_PROP, "",
ATTR_TYPE_END);
scache_endp_miss++;
return;
} else {
attr_print(client_stream, ATTR_FLAG_NONE,
- ATTR_TYPE_NUM, MAIL_ATTR_STATUS, SCACHE_STAT_OK,
+ ATTR_TYPE_INT, MAIL_ATTR_STATUS, SCACHE_STAT_OK,
ATTR_TYPE_STR, MAIL_ATTR_PROP, STR(scache_endp_prop),
ATTR_TYPE_END);
if (vstream_fflush(client_stream) != 0
if (attr_scan(client_stream,
ATTR_FLAG_STRICT,
- ATTR_TYPE_NUM, MAIL_ATTR_TTL, &ttl,
+ ATTR_TYPE_INT, MAIL_ATTR_TTL, &ttl,
ATTR_TYPE_STR, MAIL_ATTR_LABEL, scache_dest_label,
ATTR_TYPE_STR, MAIL_ATTR_PROP, scache_dest_prop,
ATTR_TYPE_STR, MAIL_ATTR_LABEL, scache_endp_label,
|| ttl <= 0) {
msg_warn("%s: bad or missing request parameter", myname);
attr_print(client_stream, ATTR_FLAG_NONE,
- ATTR_TYPE_NUM, MAIL_ATTR_STATUS, SCACHE_STAT_BAD,
+ ATTR_TYPE_INT, MAIL_ATTR_STATUS, SCACHE_STAT_BAD,
ATTR_TYPE_END);
return;
} else {
STR(scache_dest_label), STR(scache_dest_prop),
STR(scache_endp_label));
attr_print(client_stream, ATTR_FLAG_NONE,
- ATTR_TYPE_NUM, MAIL_ATTR_STATUS, SCACHE_STAT_OK,
+ ATTR_TYPE_INT, MAIL_ATTR_STATUS, SCACHE_STAT_OK,
ATTR_TYPE_END);
scache_size(scache, &size);
if (size.dest_count > scache_dest_count)
ATTR_TYPE_END) != 1) {
msg_warn("%s: bad or missing request parameter", myname);
attr_print(client_stream, ATTR_FLAG_NONE,
- ATTR_TYPE_NUM, MAIL_ATTR_STATUS, SCACHE_STAT_BAD,
+ ATTR_TYPE_INT, MAIL_ATTR_STATUS, SCACHE_STAT_BAD,
ATTR_TYPE_STR, MAIL_ATTR_PROP, "",
ATTR_TYPE_STR, MAIL_ATTR_PROP, "",
ATTR_TYPE_END);
scache_dest_prop,
scache_endp_prop)) < 0) {
attr_print(client_stream, ATTR_FLAG_NONE,
- ATTR_TYPE_NUM, MAIL_ATTR_STATUS, SCACHE_STAT_FAIL,
+ ATTR_TYPE_INT, MAIL_ATTR_STATUS, SCACHE_STAT_FAIL,
ATTR_TYPE_STR, MAIL_ATTR_PROP, "",
ATTR_TYPE_STR, MAIL_ATTR_PROP, "",
ATTR_TYPE_END);
return;
} else {
attr_print(client_stream, ATTR_FLAG_NONE,
- ATTR_TYPE_NUM, MAIL_ATTR_STATUS, SCACHE_STAT_OK,
+ ATTR_TYPE_INT, MAIL_ATTR_STATUS, SCACHE_STAT_OK,
ATTR_TYPE_STR, MAIL_ATTR_PROP, STR(scache_dest_prop),
ATTR_TYPE_STR, MAIL_ATTR_PROP, STR(scache_endp_prop),
ATTR_TYPE_END);
msg_warn("unrecognized request: \"%s\", ignored",
STR(scache_request));
attr_print(client_stream, ATTR_FLAG_NONE,
- ATTR_TYPE_NUM, MAIL_ATTR_STATUS, SCACHE_STAT_BAD,
+ ATTR_TYPE_INT, MAIL_ATTR_STATUS, SCACHE_STAT_BAD,
ATTR_TYPE_END);
}
}
/* parent directory. This information is ignored with Postfix
/* versions before 2.3.
/*
-/* With older Postfix versions, specify a directory pathname
+/* With all Postfix versions, you can specify a directory pathname
/* with the MAIL_CONFIG environment variable to override the
/* location of configuration files.
/* .IP "\fB-F \fIfull_name\fR
/* .IP "\fBenable_errors_to (no)\fR"
/* Report mail delivery errors to the address specified with the
/* non-standard Errors-To: message header, instead of the envelope
-/* sender address (this feature is removed with Postfix 2.2, is
-/* turned off by default with Postfix 2.1, and is always turned on
+/* sender address (this feature is removed with Postfix version 2.2, is
+/* turned off by default with Postfix version 2.1, and is always turned on
/* with older Postfix versions).
/* .IP "\fBmail_owner (postfix)\fR"
/* The UNIX system account that owns the Postfix queue and most Postfix
TESTSRC =
DEFS = -I. -I$(INC_DIR) -D$(SYSTYPE)
CFLAGS = $(DEBUG) $(OPT) $(DEFS)
-TESTPROG= smtp_unalias smtp_map11
+TESTPROG= smtp_unalias smtp_map11 legacy levels
PROG = smtp
INC_DIR = ../../include
LIBS = ../../lib/libmaster.a ../../lib/libtls.a ../../lib/libdns.a \
smtp_map11: smtp_map11.c $(LIBS)
$(CC) $(CFLAGS) -DTEST -o $@ $@.c $(LIBS) $(SYSLIBS)
+legacy: legacy.c $(LIBS)
+ $(CC) $(CFLAGS) -DTEST -o $@ $@.c $(LIBS)
+
+levels: levels.c $(LIBS)
+ $(CC) $(CFLAGS) -DTEST -o $@ $@.c $(LIBS)
+
# This needs trivial-rewrite service and myorigin==mydomain
smtp_map11_test: smtp_map11 map11_map smtp_map11.ref
../postmap/postmap map11_map
--- /dev/null
+ /*
+ * The old legacy TLS per-site policy engine, implemented with multiple
+ * boolean variables, stripped down for exhaustive comparison with the new
+ * legacy policy engine.
+ */
+/* System library. */
+
+#include <sys_defs.h>
+#include <string.h>
+#include <stdlib.h>
+
+#ifdef STRCASECMP_IN_STRINGS_H
+#include <strings.h>
+#endif
+
+/* Utility library. */
+
+#include <msg.h>
+#include <vstring.h>
+#include <vstring_vstream.h>
+#include <stringops.h>
+
+ /*
+ * Global policy variables.
+ */
+int var_smtp_enforce_tls;
+int var_smtp_tls_enforce_peername;
+int var_smtp_use_tls;
+
+ /*
+ * Simplified session structure.
+ */
+typedef struct {
+ int tls_use_tls;
+ int tls_enforce_tls;
+ int tls_enforce_peername;
+} SMTP_SESSION;
+
+ /*
+ * Per-site policies can override main.cf settings.
+ */
+typedef struct {
+ int dont_use; /* don't use TLS */
+ int use; /* useless, see above */
+ int enforce; /* must always use TLS */
+ int enforce_peername; /* must verify certificate name */
+} SMTP_TLS_SITE_POLICY;
+
+/* smtp_tls_site_policy - look up per-site TLS policy */
+
+static void smtp_tls_site_policy(SMTP_TLS_SITE_POLICY *policy,
+ const char *lookup)
+{
+
+ /*
+ * Initialize the default policy.
+ */
+ policy->dont_use = 0;
+ policy->use = 0;
+ policy->enforce = 0;
+ policy->enforce_peername = 0;
+
+ /*
+ * Look up a non-default policy.
+ */
+ if (strcasecmp(lookup, "-")) {
+ if (!strcasecmp(lookup, "NONE"))
+ policy->dont_use = 1;
+ else if (!strcasecmp(lookup, "MAY"))
+ policy->use = 1;
+ else if (!strcasecmp(lookup, "MUST"))
+ policy->enforce = policy->enforce_peername = 1;
+ else if (!strcasecmp(lookup, "MUST_NOPEERMATCH"))
+ policy->enforce = 1;
+ else
+ msg_fatal("unknown TLS policy '%s'", lookup);
+ }
+}
+
+static void policy(SMTP_SESSION *session, const char *host, const char *dest)
+{
+ SMTP_TLS_SITE_POLICY host_policy;
+ SMTP_TLS_SITE_POLICY rcpt_policy;
+
+ session->tls_use_tls = session->tls_enforce_tls = 0;
+ session->tls_enforce_peername = 0;
+
+ /*
+ * Override the main.cf TLS policy with an optional per-site policy.
+ */
+ smtp_tls_site_policy(&host_policy, host);
+ smtp_tls_site_policy(&rcpt_policy, dest);
+
+ /*
+ * Fix 200601: a combined per-site (NONE + MAY) policy changed global
+ * MUST into NONE, and all weaker global policies into MAY. This was
+ * discovered with exhaustive simulation. Fix verified by comparing
+ * exhaustive simulation results with Postfix 2.3 which re-implements
+ * per-site policies from the ground up.
+ */
+#ifdef FIX200601
+ if ((host_policy.dont_use || rcpt_policy.dont_use)
+ && (host_policy.use || rcpt_policy.use)) {
+ host_policy.use = rcpt_policy.use = 0;
+ host_policy.dont_use = rcpt_policy.dont_use = 1;
+ }
+#endif
+
+ /*
+ * Set up TLS enforcement for this session.
+ */
+ if ((var_smtp_enforce_tls && !host_policy.dont_use && !rcpt_policy.dont_use)
+ || host_policy.enforce || rcpt_policy.enforce)
+ session->tls_enforce_tls = session->tls_use_tls = 1;
+
+ /*
+ * Set up peername checking for this session.
+ *
+ * We want to make sure that a MUST* entry in the tls_per_site table always
+ * has precedence. MUST always must lead to a peername check,
+ * MUST_NOPEERMATCH must always disable it. Only when no explicit setting
+ * has been found, the default will be used.
+ *
+ * Fix 200601: a per-site MUST_NOPEERMATCH policy could not override a
+ * global MUST policy. Fix verified by comparing exhaustive simulation
+ * results with Postfix 2.3 which re-implements per-site policy from the
+ * ground up.
+ */
+ if (host_policy.enforce && host_policy.enforce_peername)
+ session->tls_enforce_peername = 1;
+ else if (rcpt_policy.enforce && rcpt_policy.enforce_peername)
+ session->tls_enforce_peername = 1;
+ else if (
+#ifdef FIX200601
+ !host_policy.enforce && !rcpt_policy.enforce && /* Fix 200601 */
+#endif
+ var_smtp_enforce_tls && var_smtp_tls_enforce_peername)
+ session->tls_enforce_peername = 1;
+ else if ((var_smtp_use_tls && !host_policy.dont_use && !rcpt_policy.dont_use) || host_policy.use || rcpt_policy.use)
+ session->tls_use_tls = 1;
+}
+
+static void set_global_policy(const char *global)
+{
+ var_smtp_tls_enforce_peername = var_smtp_enforce_tls = var_smtp_use_tls = 0;
+
+ if (strcasecmp(global, "must") == 0) {
+ var_smtp_enforce_tls = 1; /* XXX */
+ var_smtp_tls_enforce_peername = 1;
+ } else if (strcasecmp(global, "must_nopeermatch") == 0) {
+ var_smtp_enforce_tls = 1;
+ } else if (strcasecmp(global, "may") == 0) {
+ var_smtp_use_tls = 1;
+ } else if (strcasecmp(global, "-") !=0) {
+ msg_fatal("unknown global policy: %s", global);
+ }
+}
+
+static const char *print_policy(SMTP_SESSION *session)
+{
+ if (session->tls_enforce_peername && session->tls_enforce_tls)
+ return ("must");
+ if (session->tls_enforce_tls)
+ return ("must_nopeermatch");
+ if (session->tls_use_tls)
+ return ("may");
+ return ("none");
+}
+
+int main(int argc, char **argv)
+{
+ SMTP_SESSION session;
+ VSTRING *buf = vstring_alloc(200);
+ char *cp;
+ const char *global;
+ const char *host;
+ const char *dest;
+ const char *result;
+ const char *sep = " \t\r\n";
+
+ vstream_printf("%-20s %-20s %-20s %s\n",
+ "host", "dest", "global", "result");
+ while (vstring_get_nonl(buf, VSTREAM_IN) >= 0) {
+ cp = vstring_str(buf);
+ if (*cp == 0 || *cp == '#') {
+ vstream_printf("%s\n", cp);
+ } else {
+ if ((host = mystrtok(&cp, sep)) == 0)
+ msg_fatal("missing host policy");
+ if ((dest = mystrtok(&cp, sep)) == 0)
+ msg_fatal("missing nexthop policy");
+ if ((global = mystrtok(&cp, sep)) == 0)
+ msg_fatal("missing global policy");
+ if (mystrtok(&cp, sep) != 0)
+ msg_fatal("garbage after global policy");
+ set_global_policy(global);
+ policy(&session, host, dest);
+ result = print_policy(&session);
+ vstream_printf("%-20s %-20s %-20s %s\n",
+ host, dest, global, result);
+ }
+ vstream_fflush(VSTREAM_OUT);
+ }
+ exit(0);
+}
--- /dev/null
+ /*
+ * The new legacy TLS per-site policy engine, re-implemented in terms of
+ * enforcement levels, stripped down for exhaustive comparisons with the old
+ * legacy policy engine.
+ *
+ * This is the code that will be used in Postfix 2.3 so that sites can upgrade
+ * Postfix without being forced to change to the new TLS policy model.
+ */
+
+/* System library. */
+
+#include <sys_defs.h>
+#include <string.h>
+#include <stdlib.h>
+
+#ifdef STRCASECMP_IN_STRINGS_H
+#include <strings.h>
+#endif
+
+/* Utility library. */
+
+#include <msg.h>
+#include <vstring.h>
+#include <vstring_vstream.h>
+#include <stringops.h>
+
+ /*
+ * Application-specific.
+ */
+#include <smtp.h>
+
+ /*
+ * Global policy variables.
+ */
+int var_smtp_enforce_tls;
+int var_smtp_tls_enforce_peername;
+int var_smtp_use_tls;
+
+/* smtp_tls_policy_lookup - look up per-site TLS policy */
+
+static void smtp_tls_policy_lookup(int *site_level, const char *lookup)
+{
+
+ /*
+ * Look up a non-default policy. In case of multiple lookup results, the
+ * precedence order is a permutation of the TLS enforcement level order:
+ * VERIFY, ENCRYPT, NONE, MAY, NOTFOUND. I.e. we override MAY with a more
+ * specific policy including NONE, otherwise we choose the stronger
+ * enforcement level.
+ */
+ if (strcasecmp(lookup, "-")) {
+ if (!strcasecmp(lookup, "NONE")) {
+ /* NONE overrides MAY or NOTFOUND. */
+ if (*site_level <= SMTP_TLS_LEV_MAY)
+ *site_level = SMTP_TLS_LEV_NONE;
+ } else if (!strcasecmp(lookup, "MAY")) {
+ /* MAY overrides NOTFOUND but not NONE. */
+ if (*site_level < SMTP_TLS_LEV_NONE)
+ *site_level = SMTP_TLS_LEV_MAY;
+ } else if (!strcasecmp(lookup, "MUST_NOPEERMATCH")) {
+ if (*site_level < SMTP_TLS_LEV_ENCRYPT)
+ *site_level = SMTP_TLS_LEV_ENCRYPT;
+ } else if (!strcasecmp(lookup, "MUST")) {
+ if (*site_level < SMTP_TLS_LEV_VERIFY)
+ *site_level = SMTP_TLS_LEV_VERIFY;
+ } else {
+ msg_fatal("unknown TLS policy '%s'", lookup);
+ }
+ }
+}
+
+static int policy(const char *host, const char *dest)
+{
+ int global_level;
+ int site_level;
+ int tls_level;
+
+ /*
+ * Compute the global TLS policy. This is the default policy level when
+ * no per-site policy exists. It also is used to override a wild-card
+ * per-site policy.
+ */
+ if (var_smtp_enforce_tls)
+ global_level = var_smtp_tls_enforce_peername ?
+ SMTP_TLS_LEV_VERIFY : SMTP_TLS_LEV_ENCRYPT;
+ else
+ global_level = var_smtp_use_tls ?
+ SMTP_TLS_LEV_MAY : SMTP_TLS_LEV_NONE;
+
+ /*
+ * Compute the per-site TLS enforcement level. For compatibility with the
+ * original TLS patch, this algorithm is gives equal precedence to host
+ * and next-hop policies.
+ */
+ site_level = SMTP_TLS_LEV_NOTFOUND;
+
+ smtp_tls_policy_lookup(&site_level, dest);
+ smtp_tls_policy_lookup(&site_level, host);
+
+ /*
+ * Override a wild-card per-site policy with a more specific global
+ * policy.
+ *
+ * With the original TLS patch, 1) a per-site ENCRYPT could not override a
+ * global VERIFY, and 2) a combined per-site (NONE+MAY) policy produced
+ * inconsistent results: it changed a global VERIFY into NONE, while
+ * producing MAY with all weaker global policy settings.
+ *
+ * With the current implementation, a combined per-site (NONE+MAY)
+ * consistently overrides global policy with NONE, and global policy can
+ * override only a per-site MAY wildcard. That is, specific policies
+ * consistently override wildcard policies, and (non-wildcard) per-site
+ * policies consistently override global policies.
+ */
+ if (site_level == SMTP_TLS_LEV_NOTFOUND
+ || (site_level == SMTP_TLS_LEV_MAY
+ && global_level > SMTP_TLS_LEV_MAY))
+ tls_level = global_level;
+ else
+ tls_level = site_level;
+
+ return (tls_level);
+}
+
+static void set_global_policy(const char *global)
+{
+ var_smtp_tls_enforce_peername = var_smtp_enforce_tls = var_smtp_use_tls = 0;
+
+ if (strcasecmp(global, "must") == 0) {
+ var_smtp_enforce_tls = 1; /* XXX */
+ var_smtp_tls_enforce_peername = 1;
+ } else if (strcasecmp(global, "must_nopeermatch") == 0) {
+ var_smtp_enforce_tls = 1;
+ } else if (strcasecmp(global, "may") == 0) {
+ var_smtp_use_tls = 1;
+ } else if (strcasecmp(global, "-") !=0) {
+ msg_fatal("unknown global policy: %s", global);
+ }
+}
+
+static const char *print_policy(int level)
+{
+ if (level == SMTP_TLS_LEV_VERIFY)
+ return ("must");
+ if (level == SMTP_TLS_LEV_ENCRYPT)
+ return ("must_nopeermatch");
+ if (level == SMTP_TLS_LEV_MAY)
+ return ("may");
+ if (level == SMTP_TLS_LEV_NONE)
+ return ("none");
+ msg_panic("unknown policy level %d", level);
+}
+
+int main(int argc, char **argv)
+{
+ VSTRING *buf = vstring_alloc(200);
+ char *cp;
+ const char *global;
+ const char *host;
+ const char *dest;
+ const char *result;
+ const char *sep = " \t\r\n";
+ int level;
+
+ vstream_printf("%-20s %-20s %-20s %s\n",
+ "host", "dest", "global", "result");
+ while (vstring_get_nonl(buf, VSTREAM_IN) > 0) {
+ cp = vstring_str(buf);
+ if (*cp == 0 || *cp == '#') {
+ vstream_printf("%s\n", cp);
+ } else {
+ if ((host = mystrtok(&cp, sep)) == 0)
+ msg_fatal("missing host policy");
+ if ((dest = mystrtok(&cp, sep)) == 0)
+ msg_fatal("missing nexthop policy");
+ if ((global = mystrtok(&cp, sep)) == 0)
+ msg_fatal("missing global policy");
+ if (mystrtok(&cp, sep) != 0)
+ msg_fatal("garbage after global policy");
+ set_global_policy(global);
+ level = policy(host, dest);
+ result = print_policy(level);
+ vstream_printf("%-20s %-20s %-20s %s\n",
+ host, dest, global, result);
+ }
+ vstream_fflush(VSTREAM_OUT);
+ }
+ exit(0);
+}
if (*var_smtp_generic_maps)
smtp_generic_maps =
maps_create(VAR_SMTP_GENERIC_MAPS, var_smtp_generic_maps,
- DICT_FLAG_LOCK);
+ DICT_FLAG_LOCK | DICT_FLAG_FOLD_FIX);
}
/* pre_accept - see if tables have changed */
#define SMTP_MISC_FLAG_FINAL_SERVER (1<<5)
#define SMTP_MISC_FLAG_CONN_CACHE (1<<6)
+ /*
+ * TLS enforcement level. Actual TLS policies will be NONE or higher.
+ *
+ * There are two pseudo levels: NOTFOUND is a sentinel value for the ease of
+ * implementation; MAY is a wild-card that indicates "anything goes".
+ *
+ * Non pseudo levels can also be used to indicate the actual security level of
+ * a session.
+ */
+#define SMTP_TLS_LEV_NOTFOUND (-1) /* sentinel */
+#define SMTP_TLS_LEV_NONE 0 /* plain-text only */
+#define SMTP_TLS_LEV_MAY 1 /* wildcard */
+#define SMTP_TLS_LEV_ENCRYPT 2 /* encrypted connection */
+#define SMTP_TLS_LEV_VERIFY 3 /* certificate verified */
+#define SMTP_TLS_LEV_STRICT 4 /* "secure" verification */
+
/*
* smtp.c
*/
* TLS related state.
*/
#ifdef USE_TLS
- int tls_use_tls; /* can do TLS */
- int tls_enforce_tls; /* must do TLS */
- int tls_enforce_peername; /* cert must match */
+ int tls_level; /* TLS enforcement level */
TLScontext_t *tls_context; /* TLS session state */
#endif
/* lookups are done via the Internet domain name service (DNS).
/* A reasonable number of CNAME indirections is permitted. When
/* DNS lookups are disabled, host address lookup is done with
-/* gethostbyname().
+/* getnameinfo() or gethostbyname().
/*
/* smtp_domain_addr() looks up the network addresses for mail
/* exchanger hosts listed for the named domain. Addresses are
/*
/* smtp_connect() attempts to establish an SMTP/LMTP session with a host
/* that represents the destination domain, or with an optional fallback
-/* relay when the destination cannot be found, or when all the
-/* destination servers are unavailable. It skips over IP addresses
+/* relay when {the destination cannot be found, or when all the
+/* destination servers are unavailable}. It skips over IP addresses
/* that fail to complete the SMTP/LMTP handshake and tries to find
/* an alternate server when an SMTP/LMTP session fails to deliver.
/*
/* destinations may be specified as "unix:pathname", "inet:host"
/* or "inet:host:port".
/*
-/* By default, the Internet domain name service is queried for mail
+/* With SMTP, the Internet domain name service is queried for mail
/* exchanger hosts. Quote the domain name with `[' and `]' to
/* suppress mail exchanger lookups.
/*
if (argc < 3)
msg_fatal("usage: %s maptype:mapname address...", argv[0]);
- maps = maps_create(argv[1], argv[1], 0);
+ maps = maps_create(argv[1], argv[1], DICT_FLAG_FOLD_FIX);
mail_params_init();
if (chdir(var_queue_dir) < 0)
msg_fatal("chdir(%s): %m", var_queue_dir);
if (n == 0 && strcasecmp(word, var_myhostname) == 0) {
if (state->misc_flags & SMTP_MISC_FLAG_LOOP_DETECT)
msg_warn("host %s greeted me with my own hostname %s",
- session->namaddr, var_myhostname);
+ session->namaddrport, var_myhostname);
} else if (strcasecmp(word, "ESMTP") == 0)
session->features |= SMTP_FEATURE_ESMTP;
}
* Optionally log unused STARTTLS opportunities.
*/
if ((session->features & SMTP_FEATURE_STARTTLS) &&
- (var_smtp_tls_note_starttls_offer) &&
- (!(session->tls_enforce_tls || session->tls_use_tls)))
+ var_smtp_tls_note_starttls_offer &&
+ session->tls_level <= SMTP_TLS_LEV_NONE)
msg_info("Host offered STARTTLS: [%s]", session->host);
/*
* Decide whether or not to send STARTTLS.
*/
if ((session->features & SMTP_FEATURE_STARTTLS) != 0
- && smtp_tls_ctx != 0
- && (session->tls_use_tls || session->tls_enforce_tls)) {
+ && smtp_tls_ctx != 0 && session->tls_level >= SMTP_TLS_LEV_MAY) {
/*
* Prepare for disaster.
* although support for it was announced in the EHLO response.
*/
session->features &= ~SMTP_FEATURE_STARTTLS;
- if (session->tls_enforce_tls)
+ if (session->tls_level >= SMTP_TLS_LEV_ENCRYPT)
return (smtp_site_fail(state, session->host, resp,
"TLS is required, but host %s refused to start TLS: %s",
session->namaddr,
* block. When TLS is required we must never, ever, end up in
* plain-text mode.
*/
- if (session->tls_enforce_tls) {
+ if (session->tls_level >= SMTP_TLS_LEV_ENCRYPT) {
if (!(session->features & SMTP_FEATURE_STARTTLS)) {
return (smtp_site_fail(state, DSN_BY_LOCAL_MTA,
SMTP_RESP_FAKE(&fake, "4.7.4"),
session->tls_context =
tls_client_start(smtp_tls_ctx, session->stream,
var_smtp_starttls_tmout,
- session->tls_enforce_peername,
- session->host,
- lowercase(vstring_str(serverid)));
+ session->tls_level >= SMTP_TLS_LEV_VERIFY,
+ session->host, lowercase(vstring_str(serverid)));
vstring_free(serverid);
if (session->tls_context == 0)
return (smtp_site_fail(state, DSN_BY_LOCAL_MTA,
&& (value = mail_addr_find(smtp_sasl_passwd_map,
state->request->sender, (char **) 0)) != 0)
|| (value = maps_find(smtp_sasl_passwd_map, session->host, 0)) != 0
- || (value = maps_find(smtp_sasl_passwd_map, session->dest, 0)) != 0) {
+ || (value = maps_find(smtp_sasl_passwd_map, session->dest, 0)) != 0) {
session->sasl_username = mystrdup(value);
passwd = split_at(session->sasl_username, ':');
session->sasl_passwd = mystrdup(passwd ? passwd : "");
* shared locks for reading, just in case someone updates the table.
*/
smtp_sasl_passwd_map = maps_create("smtp_sasl_passwd",
- var_smtp_sasl_passwd, DICT_FLAG_LOCK);
+ var_smtp_sasl_passwd,
+ DICT_FLAG_LOCK | DICT_FLAG_FOLD_FIX);
if ((smtp_sasl_impl = xsasl_client_init(var_smtp_sasl_type,
var_smtp_sasl_path)) == 0)
msg_fatal("SASL library initialization");
#ifdef USE_TLS
- /*
- * Per-site policies can override main.cf settings.
- */
-typedef struct {
- int dont_use; /* don't use TLS */
- int use; /* useless, see above */
- int enforce; /* must always use TLS */
- int enforce_peername; /* must verify certificate name */
-} SMTP_TLS_SITE_POLICY;
-
static MAPS *tls_per_site; /* lookup table(s) */
/* smtp_tls_list_init - initialize per-site policy lists */
void smtp_tls_list_init(void)
{
tls_per_site = maps_create(VAR_SMTP_TLS_PER_SITE, var_smtp_tls_per_site,
- DICT_FLAG_LOCK);
+ DICT_FLAG_LOCK | DICT_FLAG_FOLD_FIX);
+}
+
+/* smtp_tls_policy_print - printpolicy level */
+
+static void smtp_tls_policy_print(const char *name, int level)
+{
+ msg_info("%s TLS level: %s", name,
+ level == SMTP_TLS_LEV_VERIFY ? "verify" :
+ level == SMTP_TLS_LEV_ENCRYPT ? "encrypt" :
+ level == SMTP_TLS_LEV_MAY ? "may" :
+ level == SMTP_TLS_LEV_NONE ? "none" :
+ "unknown");
}
-/* smtp_tls_site_policy - look up per-site TLS policy */
+/* smtp_tls_policy_lookup - look up per-site TLS security level */
-static void smtp_tls_site_policy(SMTP_TLS_SITE_POLICY *policy,
- const char *site_name,
- const char *site_class)
+static void smtp_tls_policy_lookup(int *site_level, const char *site_name,
+ const char *site_class)
{
const char *lookup;
- char *lookup_key;
/*
- * Initialize the default policy.
+ * Look up a non-default policy. In case of multiple lookup results, the
+ * precedence order is a permutation of the TLS enforcement level order:
+ * VERIFY, ENCRYPT, NONE, MAY, NOTFOUND. I.e. we override MAY with a more
+ * specific policy including NONE, otherwise we choose the stronger
+ * enforcement level.
*/
- policy->dont_use = 0;
- policy->use = 0;
- policy->enforce = 0;
- policy->enforce_peername = 0;
+ if ((lookup = maps_find(tls_per_site, site_name, 0)) != 0) {
+ if (!strcasecmp(lookup, "NONE")) {
+ /* NONE overrides MAY or NOTFOUND. */
+ if (*site_level <= SMTP_TLS_LEV_MAY)
+ *site_level = SMTP_TLS_LEV_NONE;
+ } else if (!strcasecmp(lookup, "MAY")) {
+ /* MAY overrides NOTFOUND but not NONE. */
+ if (*site_level < SMTP_TLS_LEV_NONE)
+ *site_level = SMTP_TLS_LEV_MAY;
+ } else if (!strcasecmp(lookup, "MUST_NOPEERMATCH")) {
+ if (*site_level < SMTP_TLS_LEV_ENCRYPT)
+ *site_level = SMTP_TLS_LEV_ENCRYPT;
+ } else if (!strcasecmp(lookup, "MUST")) {
+ if (*site_level < SMTP_TLS_LEV_VERIFY)
+ *site_level = SMTP_TLS_LEV_VERIFY;
+ } else {
+ msg_warn("Table %s: ignoring unknown TLS policy '%s' for %s %s",
+ var_smtp_tls_per_site, lookup, site_class, site_name);
+ }
+ }
+}
+
+/* smtp_tls_level_init - configure session TLS enforcement level */
+
+static int smtp_tls_level_init(const char *dest, const char *host)
+{
+ int global_level;
+ int site_level;
+ int tls_level;
/*
- * Look up a non-default policy.
+ * Compute the global TLS policy. This is the default policy level when
+ * no per-site policy exists. It also is used to override a wild-card
+ * per-site policy.
*/
- lookup_key = lowercase(mystrdup(site_name));
- if ((lookup = maps_find(tls_per_site, lookup_key, 0)) != 0) {
- if (!strcasecmp(lookup, "NONE"))
- policy->dont_use = 1;
- else if (!strcasecmp(lookup, "MAY"))
- policy->use = 1;
- else if (!strcasecmp(lookup, "MUST"))
- policy->enforce = policy->enforce_peername = 1;
- else if (!strcasecmp(lookup, "MUST_NOPEERMATCH"))
- policy->enforce = 1;
- else
- msg_warn("Table %s: ignoring unknown TLS policy '%s' for %s %s",
- var_smtp_tls_per_site, lookup, site_class, site_name);
+ if (var_smtp_enforce_tls)
+ global_level = var_smtp_tls_enforce_peername ?
+ SMTP_TLS_LEV_VERIFY : SMTP_TLS_LEV_ENCRYPT;
+ else
+ global_level = var_smtp_use_tls ?
+ SMTP_TLS_LEV_MAY : SMTP_TLS_LEV_NONE;
+ if (msg_verbose)
+ smtp_tls_policy_print("global", global_level);
+
+ /*
+ * Compute the per-site TLS enforcement level. For compatibility with the
+ * original TLS patch, this algorithm is gives equal precedence to host
+ * and next-hop policies.
+ */
+ site_level = SMTP_TLS_LEV_NOTFOUND;
+
+ if (tls_per_site) {
+ smtp_tls_policy_lookup(&site_level, dest, "next-hop destination");
+ if (strcasecmp(dest, host) != 0)
+ smtp_tls_policy_lookup(&site_level, host, "server hostname");
+ if (msg_verbose)
+ smtp_tls_policy_print("site", site_level);
}
- myfree(lookup_key);
+
+ /*
+ * Override a wild-card per-site policy with a more specific global
+ * policy.
+ *
+ * With the original TLS patch, 1) a per-site ENCRYPT could not override a
+ * global VERIFY, and 2) a combined per-site (NONE+MAY) policy produced
+ * inconsistent results: it changed a global VERIFY into NONE, while
+ * producing MAY with all weaker global policy settings.
+ *
+ * With the current implementation, a combined per-site (NONE+MAY)
+ * consistently overrides global policy with NONE, and global policy can
+ * override only a per-site MAY wildcard. That is, specific policies
+ * consistently override wildcard policies, and (non-wildcard) per-site
+ * policies consistently override global policies.
+ */
+ if (site_level == SMTP_TLS_LEV_NOTFOUND
+ || (site_level == SMTP_TLS_LEV_MAY
+ && global_level > SMTP_TLS_LEV_MAY))
+ tls_level = global_level;
+ else
+ tls_level = site_level;
+
+ if (msg_verbose && tls_per_site)
+ smtp_tls_policy_print("effective", tls_level);
+
+ return (tls_level);
}
#endif
{
SMTP_SESSION *session;
-#ifdef USE_TLS
- SMTP_TLS_SITE_POLICY host_policy;
- SMTP_TLS_SITE_POLICY rcpt_policy;
-
-#endif
-
session = (SMTP_SESSION *) mymalloc(sizeof(*session));
session->stream = stream;
session->dest = mystrdup(dest);
smtp_sasl_connect(session);
#endif
-#ifdef USE_TLS
- session->tls_use_tls = session->tls_enforce_tls = 0;
- session->tls_enforce_peername = 0;
- session->tls_context = 0;
-
/*
- * Override the main.cf TLS policy with an optional per-site policy.
+ * Need to pass the session as a parameter when the new-style per-nexthop
+ * policies can specify not only security level thresholds, but also how
+ * security levels are defined.
*/
- if (smtp_tls_ctx != 0) {
- smtp_tls_site_policy(&host_policy, host, "receiving host");
- smtp_tls_site_policy(&rcpt_policy, dest, "recipient domain");
-
- /*
- * Set up TLS enforcement for this session.
- */
- if ((var_smtp_enforce_tls && !host_policy.dont_use && !rcpt_policy.dont_use)
- || host_policy.enforce || rcpt_policy.enforce)
- session->tls_enforce_tls = session->tls_use_tls = 1;
-
- /*
- * Set up peername checking for this session.
- *
- * We want to make sure that a MUST* entry in the tls_per_site table
- * always has precedence. MUST always must lead to a peername check,
- * MUST_NOPEERMATCH must always disable it. Only when no explicit
- * setting has been found, the default will be used. There is the
- * case left, that both "host" and "recipient" settings conflict. In
- * this case, the "host" setting wins.
- */
- if (host_policy.enforce && host_policy.enforce_peername)
- session->tls_enforce_peername = 1;
- else if (rcpt_policy.enforce && rcpt_policy.enforce_peername)
- session->tls_enforce_peername = 1;
- else if (var_smtp_enforce_tls && var_smtp_tls_enforce_peername)
- session->tls_enforce_peername = 1;
- else if ((var_smtp_use_tls && !host_policy.dont_use && !rcpt_policy.dont_use) || host_policy.use || rcpt_policy.use)
- session->tls_use_tls = 1;
- }
+#ifdef USE_TLS
+ session->tls_context = 0;
+ session->tls_level = smtp_tls_level_init(dest, host);
#endif
session->state = 0;
debug_peer_check(host, addr);
--- /dev/null
+- - -
+- - may
+- - must_nopeermatch
+- - must
+- none -
+- none may
+- none must_nopeermatch
+- none must
+- may -
+- may may
+- may must_nopeermatch
+- may must
+- must_nopeermatch -
+- must_nopeermatch may
+- must_nopeermatch must_nopeermatch
+- must_nopeermatch must
+- must -
+- must may
+- must must_nopeermatch
+- must must
+
+none none -
+none none may
+none none must_nopeermatch
+none none must
+none may -
+none may may
+none may must_nopeermatch
+none may must
+none must_nopeermatch -
+none must_nopeermatch may
+none must_nopeermatch must_nopeermatch
+none must_nopeermatch must
+none must -
+none must may
+none must must_nopeermatch
+none must must
+
+may may -
+may may may
+may may must_nopeermatch
+may may must
+may must_nopeermatch -
+may must_nopeermatch may
+may must_nopeermatch must_nopeermatch
+may must_nopeermatch must
+may must -
+may must may
+may must must_nopeermatch
+may must must
+
+must_nopeermatch must_nopeermatch -
+must_nopeermatch must_nopeermatch may
+must_nopeermatch must_nopeermatch must_nopeermatch
+must_nopeermatch must_nopeermatch must
+must_nopeermatch must -
+must_nopeermatch must may
+must_nopeermatch must must_nopeermatch
+must_nopeermatch must must
+
+must must -
+must must may
+must must must_nopeermatch
+must must must
--- /dev/null
+host dest global result
+- - - none
+- - may may
+- - must_nopeermatch must_nopeermatch
+- - must must
+- none - none
+- none may none
+- none must_nopeermatch none
+- none must none
+- may - may
+- may may may
+- may must_nopeermatch must_nopeermatch
+- may must must
+- must_nopeermatch - must_nopeermatch
+- must_nopeermatch may must_nopeermatch
+- must_nopeermatch must_nopeermatch must_nopeermatch
+- must_nopeermatch must must_nopeermatch
+- must - must
+- must may must
+- must must_nopeermatch must
+- must must must
+
+none none - none
+none none may none
+none none must_nopeermatch none
+none none must none
+none may - none
+none may may none
+none may must_nopeermatch none
+none may must none
+none must_nopeermatch - must_nopeermatch
+none must_nopeermatch may must_nopeermatch
+none must_nopeermatch must_nopeermatch must_nopeermatch
+none must_nopeermatch must must_nopeermatch
+none must - must
+none must may must
+none must must_nopeermatch must
+none must must must
+
+may may - may
+may may may may
+may may must_nopeermatch must_nopeermatch
+may may must must
+may must_nopeermatch - must_nopeermatch
+may must_nopeermatch may must_nopeermatch
+may must_nopeermatch must_nopeermatch must_nopeermatch
+may must_nopeermatch must must_nopeermatch
+may must - must
+may must may must
+may must must_nopeermatch must
+may must must must
+
+must_nopeermatch must_nopeermatch - must_nopeermatch
+must_nopeermatch must_nopeermatch may must_nopeermatch
+must_nopeermatch must_nopeermatch must_nopeermatch must_nopeermatch
+must_nopeermatch must_nopeermatch must must_nopeermatch
+must_nopeermatch must - must
+must_nopeermatch must may must
+must_nopeermatch must must_nopeermatch must
+must_nopeermatch must must must
+
+must must - must
+must must may must
+must must must_nopeermatch must
+must must must must
smtpd_xforward.c smtpd_dsn_fix.c
OBJS = smtpd.o smtpd_token.o smtpd_check.o smtpd_chat.o smtpd_state.o \
smtpd_peer.o smtpd_sasl_proto.o smtpd_sasl_glue.o smtpd_proxy.o \
- smtpd_xforward.o smtpd_dsn_fix.c
+ smtpd_xforward.o smtpd_dsn_fix.o
HDRS = smtpd_token.h smtpd_check.h smtpd_chat.h smtpd_sasl_proto.h \
smtpd_sasl_glue.h smtpd_proxy.h smtpd_dsn_fix.h
TESTSRC = smtpd_token_test.c
tidy: clean
tests: smtpd_check_test smtpd_check_test2 smtpd_acl_test smtpd_exp_test \
- smtpd_token_test smtpd_check_test4 smtpd_check_dsn
+ smtpd_token_test smtpd_check_test4 smtpd_check_dsn_test
smtpd_check_test: smtpd_check smtpd_check.in smtpd_check.ref smtpd_check_access
../postmap/postmap hash:smtpd_check_access
smtpd_check.o: ../../include/valid_mailhost_addr.h
smtpd_check.o: ../../include/vbuf.h
smtpd_check.o: ../../include/verify_clnt.h
-smtpd_check.o: ../../include/virtual8_maps.h
smtpd_check.o: ../../include/vstream.h
smtpd_check.o: ../../include/vstring.h
smtpd_check.o: smtpd.h
}
if ((discard_mask & EHLO_MASK_VRFY) == 0)
if (var_disable_vrfy_cmd == 0)
- ENQUEUE_FIX_REPLY(state, reply_buf, "VRFY");
+ ENQUEUE_FIX_REPLY(state, reply_buf, SMTPD_CMD_VRFY);
if ((discard_mask & EHLO_MASK_ETRN) == 0)
- ENQUEUE_FIX_REPLY(state, reply_buf, "ETRN");
+ ENQUEUE_FIX_REPLY(state, reply_buf, SMTPD_CMD_ETRN);
#ifdef USE_TLS
if ((discard_mask & EHLO_MASK_STARTTLS) == 0)
if ((state->tls_use_tls || state->tls_enforce_tls) && (!state->tls_context))
- ENQUEUE_FIX_REPLY(state, reply_buf, "STARTTLS");
+ ENQUEUE_FIX_REPLY(state, reply_buf, SMTPD_CMD_STARTTLS);
#endif
#ifdef USE_SASL_AUTH
if ((discard_mask & EHLO_MASK_AUTH) == 0) {
var_cleanup_service);
if (state->dest == 0
|| attr_print(state->dest->stream, ATTR_FLAG_NONE,
- ATTR_TYPE_NUM, MAIL_ATTR_FLAGS, cleanup_flags,
+ ATTR_TYPE_INT, MAIL_ATTR_FLAGS, cleanup_flags,
ATTR_TYPE_END) != 0)
msg_fatal("unable to connect to the %s %s service",
MAIL_CLASS_PUBLIC, var_cleanup_service);
* waiting for a reply, it just increases latency.
*/
if (state->proxy) {
- (void) smtpd_proxy_cmd(state, SMTPD_PROX_WANT_NONE, "QUIT");
+ (void) smtpd_proxy_cmd(state, SMTPD_PROX_WANT_NONE, SMTPD_CMD_QUIT);
smtpd_proxy_close(state);
}
if (state->xforward.flags)
#define SMTPD_CMD_FLAG_PRE_TLS (1<<1) /* allow before STARTTLS */
static SMTPD_CMD smtpd_cmd_table[] = {
- "HELO", helo_cmd, SMTPD_CMD_FLAG_LIMIT | SMTPD_CMD_FLAG_PRE_TLS,
- "EHLO", ehlo_cmd, SMTPD_CMD_FLAG_LIMIT | SMTPD_CMD_FLAG_PRE_TLS,
+ SMTPD_CMD_HELO, helo_cmd, SMTPD_CMD_FLAG_LIMIT | SMTPD_CMD_FLAG_PRE_TLS,
+ SMTPD_CMD_EHLO, ehlo_cmd, SMTPD_CMD_FLAG_LIMIT | SMTPD_CMD_FLAG_PRE_TLS,
#ifdef USE_TLS
- "STARTTLS", starttls_cmd, SMTPD_CMD_FLAG_PRE_TLS,
+ SMTPD_CMD_STARTTLS, starttls_cmd, SMTPD_CMD_FLAG_PRE_TLS,
#endif
#ifdef USE_SASL_AUTH
- "AUTH", smtpd_sasl_auth_cmd, 0,
+ SMTPD_CMD_AUTH, smtpd_sasl_auth_cmd, 0,
#endif
- "MAIL", mail_cmd, 0,
- "RCPT", rcpt_cmd, 0,
- "DATA", data_cmd, 0,
- "RSET", rset_cmd, SMTPD_CMD_FLAG_LIMIT,
- "NOOP", noop_cmd, SMTPD_CMD_FLAG_LIMIT | SMTPD_CMD_FLAG_PRE_TLS,
- "VRFY", vrfy_cmd, SMTPD_CMD_FLAG_LIMIT,
- "ETRN", etrn_cmd, SMTPD_CMD_FLAG_LIMIT,
- "QUIT", quit_cmd, SMTPD_CMD_FLAG_PRE_TLS,
- "XCLIENT", xclient_cmd, SMTPD_CMD_FLAG_LIMIT,
- "XFORWARD", xforward_cmd, SMTPD_CMD_FLAG_LIMIT,
+ SMTPD_CMD_MAIL, mail_cmd, 0,
+ SMTPD_CMD_RCPT, rcpt_cmd, 0,
+ SMTPD_CMD_DATA, data_cmd, 0,
+ SMTPD_CMD_RSET, rset_cmd, SMTPD_CMD_FLAG_LIMIT,
+ SMTPD_CMD_NOOP, noop_cmd, SMTPD_CMD_FLAG_LIMIT | SMTPD_CMD_FLAG_PRE_TLS,
+ SMTPD_CMD_VRFY, vrfy_cmd, SMTPD_CMD_FLAG_LIMIT,
+ SMTPD_CMD_ETRN, etrn_cmd, SMTPD_CMD_FLAG_LIMIT,
+ SMTPD_CMD_QUIT, quit_cmd, SMTPD_CMD_FLAG_PRE_TLS,
+ SMTPD_CMD_XCLIENT, xclient_cmd, SMTPD_CMD_FLAG_LIMIT,
+ SMTPD_CMD_XFORWARD, xforward_cmd, SMTPD_CMD_FLAG_LIMIT,
0,
};
#define SMTPD_AFTER_CONNECT "CONNECT"
#define SMTPD_AFTER_DOT "END-OF-MESSAGE"
+ /*
+ * Other stages. These are sometimes used to change the way information is
+ * logged or what information will be available for access control.
+ */
+#define SMTPD_CMD_HELO "HELO"
+#define SMTPD_CMD_EHLO "EHLO"
+#define SMTPD_CMD_STARTTLS "STARTTLS"
+#define SMTPD_CMD_AUTH "AUTH"
+#define SMTPD_CMD_MAIL "MAIL"
+#define SMTPD_CMD_RCPT "RCPT"
+#define SMTPD_CMD_DATA "DATA"
+#define SMTPD_CMD_EOD SMTPD_AFTER_DOT /* XXX Was: END-OF-DATA */
+#define SMTPD_CMD_RSET "RSET"
+#define SMTPD_CMD_NOOP "NOOP"
+#define SMTPD_CMD_VRFY "VRFY"
+#define SMTPD_CMD_ETRN "ETRN"
+#define SMTPD_CMD_QUIT "QUIT"
+#define SMTPD_CMD_XCLIENT "XCLIENT"
+#define SMTPD_CMD_XFORWARD "XFORWARD"
+
/*
* Representation of unknown client information within smtpd processes. This
* is not the representation that Postfix uses in queue files, in queue
#include <mail_addr_find.h>
#include <match_parent_style.h>
#include <strip_addr.h>
-#include <virtual8_maps.h>
#include <cleanup_user.h>
#include <record.h>
#include <rec_type.h>
policy_client_register(name);
else if ((flags & SMTPD_CHECK_PARSE_MAPS)
&& strchr(name, ':') && dict_handle(name) == 0) {
- dict_register(name, dict_open(name, O_RDONLY, DICT_FLAG_LOCK));
+ dict_register(name, dict_open(name, O_RDONLY, DICT_FLAG_LOCK
+ | DICT_FLAG_FOLD_FIX));
}
last = name;
}
var_perm_mx_networks);
#ifdef USE_TLS
relay_ccerts = maps_create(VAR_RELAY_CCERTS, var_smtpd_relay_ccerts,
- DICT_FLAG_LOCK);
+ DICT_FLAG_LOCK | DICT_FLAG_FOLD_FIX);
#endif
/*
* Pre-parse and pre-open the recipient maps.
*/
local_rcpt_maps = maps_create(VAR_LOCAL_RCPT_MAPS, var_local_rcpt_maps,
- DICT_FLAG_LOCK);
+ DICT_FLAG_LOCK | DICT_FLAG_FOLD_FIX);
rcpt_canon_maps = maps_create(VAR_RCPT_CANON_MAPS, var_rcpt_canon_maps,
- DICT_FLAG_LOCK);
+ DICT_FLAG_LOCK | DICT_FLAG_FOLD_FIX);
canonical_maps = maps_create(VAR_CANONICAL_MAPS, var_canonical_maps,
- DICT_FLAG_LOCK);
+ DICT_FLAG_LOCK | DICT_FLAG_FOLD_FIX);
virt_alias_maps = maps_create(VAR_VIRT_ALIAS_MAPS, var_virt_alias_maps,
- DICT_FLAG_LOCK);
- virt_mailbox_maps = virtual8_maps_create(VAR_VIRT_MAILBOX_MAPS,
- var_virt_mailbox_maps,
- DICT_FLAG_LOCK);
+ DICT_FLAG_LOCK | DICT_FLAG_FOLD_FIX);
+ virt_mailbox_maps = maps_create(VAR_VIRT_MAILBOX_MAPS,
+ var_virt_mailbox_maps,
+ DICT_FLAG_LOCK | DICT_FLAG_FOLD_FIX);
relay_rcpt_maps = maps_create(VAR_RELAY_RCPT_MAPS, var_relay_rcpt_maps,
- DICT_FLAG_LOCK);
+ DICT_FLAG_LOCK | DICT_FLAG_FOLD_FIX);
#ifdef TEST
virt_alias_doms = string_list_init(MATCH_FLAG_NONE, var_virt_alias_doms);
* Templates for RBL rejection replies.
*/
rbl_reply_maps = maps_create(VAR_RBL_REPLY_MAPS, var_rbl_reply_maps,
- DICT_FLAG_LOCK);
+ DICT_FLAG_LOCK | DICT_FLAG_FOLD_FIX);
/*
* Sender to login name mapping.
*/
smtpd_sender_login_maps = maps_create(VAR_SMTPD_SND_AUTH_MAPS,
var_smtpd_snd_auth_maps,
- DICT_FLAG_LOCK);
+ DICT_FLAG_LOCK | DICT_FLAG_FOLD_FIX);
/*
* error_text is used for returning error responses.
#ifdef USE_TLS
static int permit_tls_clientcerts(SMTPD_STATE *state, int permit_all_certs)
{
- char *low_name;
const char *found;
if (!state->tls_context)
}
if (state->tls_context->peer_verified
&& state->tls_context->peer_fingerprint) {
- low_name = lowercase(mystrdup(state->tls_context->peer_fingerprint));
- found = maps_find(relay_ccerts, low_name, DICT_FLAG_FIXED);
- myfree(low_name);
+ found = maps_find(relay_ccerts, state->tls_context->peer_fingerprint,
+ DICT_FLAG_NONE);
if (found) {
if (msg_verbose)
msg_info("Relaying allowed for certified client: %s", found);
&& (vstream_peek(state->client) > 0
|| peekfd(vstream_fileno(state->client)) > 0)
&& (strcasecmp(state->protocol, MAIL_PROTO_ESMTP) != 0
- || strcasecmp(state->where, "DATA") == 0)) {
+ || strcasecmp(state->where, SMTPD_CMD_DATA) == 0)) {
return (smtpd_check_reject(state, MAIL_ERROR_PROTOCOL,
503, "5.5.0",
"<%s>: %s rejected: Improper use of SMTP command pipelining",
msg_warn("%s service failure", var_verify_service);
DEFER_IF_PERMIT2(state, MAIL_ERROR_POLICY,
450, strcmp(reply_class, SMTPD_NAME_SENDER) == 0 ?
- "4.1.0" : "4.1.1",
+ SND_DSN : "4.1.1",
"<%s>: %s rejected: address verification problem",
reply_name, reply_class);
rqst_status = SMTPD_CHECK_DUNNO;
case DEL_RCPT_STAT_DEFER:
DEFER_IF_PERMIT3(state, MAIL_ERROR_POLICY,
450, strcmp(reply_class, SMTPD_NAME_SENDER) == 0 ?
- "4.1.0" : "4.1.1",
+ SND_DSN : "4.1.1",
"<%s>: %s rejected: unverified address: %.250s",
reply_name, reply_class, STR(why));
rqst_status = SMTPD_CHECK_DUNNO;
smtpd_check_reject(state, MAIL_ERROR_POLICY,
unv_addr_code,
strcmp(reply_class, SMTPD_NAME_SENDER) == 0 ?
- "4.1.0" : "4.1.1",
+ SND_DSN : "4.1.1",
"<%s>: %s rejected: undeliverable address: %s",
reply_name, reply_class, STR(why));
break;
/*
* ETRN does not receive mail so we can't store queue file records.
*/
- if (strcmp(state->where, "ETRN") == 0) {
+ if (strcmp(state->where, SMTPD_CMD_ETRN) == 0) {
msg_warn("access table %s: action %s is unavailable in %s",
table, action, VAR_ETRN_CHECKS);
return (0);
const char *reply_class, const char *def_acl)
{
char *myname = "check_access";
- char *low_name = lowercase(mystrdup(name));
const char *value;
DICT *dict;
-#define CHK_ACCESS_RETURN(x,y) { *found = y; myfree(low_name); return(x); }
+#define CHK_ACCESS_RETURN(x,y) \
+ { *found = y; return(x); }
#define FULL 0
#define PARTIAL DICT_FLAG_FIXED
#define FOUND 1
if ((dict = dict_handle(table)) == 0)
msg_panic("%s: dictionary not found: %s", myname, table);
if (flags == 0 || (flags & dict->flags) != 0) {
- if ((value = dict_get(dict, low_name)) != 0)
+ if ((value = dict_get(dict, name)) != 0)
CHK_ACCESS_RETURN(check_table_result(state, table, value, name,
reply_name, reply_class,
def_acl), FOUND);
const char *def_acl)
{
char *myname = "check_domain_access";
- char *low_domain = lowercase(mystrdup(domain));
- char *name;
- char *next;
+ const char *name;
+ const char *next;
const char *value;
DICT *dict;
int maybe_numerical = 1;
* key, because Berkeley DB cannot deal with it. [Victor Duchovni, Morgan
* Stanley].
*/
-#define CHK_DOMAIN_RETURN(x,y) { *found = y; myfree(low_domain); return(x); }
+#define CHK_DOMAIN_RETURN(x,y) { *found = y; return(x); }
if ((dict = dict_handle(table)) == 0)
msg_panic("%s: dictionary not found: %s", myname, table);
- for (name = low_domain; *name != 0; name = next) {
+ for (name = domain; *name != 0; name = next) {
if (flags == 0 || (flags & dict->flags) != 0) {
if ((value = dict_get(dict, name)) != 0)
CHK_DOMAIN_RETURN(check_table_result(state, table, value,
const char *myname = "rbl_reject_reply";
VSTRING *why = 0;
const char *template = 0;
- char *low_name;
SMTPD_RBL_EXPAND_CONTEXT rbl_exp;
int result;
DSN_SPLIT dp;
* Use the server-specific reply template or use the default one.
*/
if (*var_rbl_reply_maps) {
- low_name = lowercase(mystrdup(rbl_domain));
- template = maps_find(rbl_reply_maps, low_name, 0);
- myfree(low_name);
+ template = maps_find(rbl_reply_maps, rbl_domain, DICT_FLAG_NONE);
}
why = vstring_alloc(100);
rbl_exp.state = state;
state->sender ? state->sender : "",
ATTR_TYPE_STR, MAIL_ATTR_RECIP,
state->recipient ? state->recipient : "",
+ ATTR_TYPE_INT, MAIL_ATTR_RCPT_COUNT,
+ ((strcasecmp(state->where, SMTPD_CMD_DATA) == 0) ||
+ (strcasecmp(state->where, SMTPD_AFTER_DOT) == 0)) ?
+ state->rcpt_count : 0,
ATTR_TYPE_STR, MAIL_ATTR_QUEUEID,
state->queue_id ? state->queue_id : "",
ATTR_TYPE_STR, MAIL_ATTR_INSTANCE,
IF_ENCRYPTED(state->tls_context->protocol, ""),
ATTR_TYPE_STR, MAIL_ATTR_CRYPTO_CIPHER,
IF_ENCRYPTED(state->tls_context->cipher_name, ""),
- ATTR_TYPE_NUM, MAIL_ATTR_CRYPTO_KEYSIZE,
- IF_ENCRYPTED(state->tls_context->cipher_usebits, 0),
+ ATTR_TYPE_INT, MAIL_ATTR_CRYPTO_KEYSIZE,
+ IF_ENCRYPTED(state->tls_context->cipher_usebits, 0),
#endif
ATTR_TYPE_END,
ATTR_FLAG_MISSING, /* Reply attributes. */
status = check_recipient_rcpt_maps(state, state->recipient);
} else if (strcasecmp(name, REJECT_MUL_RCPT_BOUNCE) == 0) {
if (state->sender && *state->sender == 0 && state->rcpt_count
- > (strcmp(state->where, "DATA") ? 0 : 1))
+ > (strcmp(state->where, SMTPD_CMD_DATA) ? 0 : 1))
status = smtpd_check_reject(state, MAIL_ERROR_POLICY,
var_mul_rcpt_code, "5.5.3",
"<%s>: %s rejected: Multi-recipient bounce",
/*
* Search the recipient lookup tables of the respective address class.
*
- * XXX Use the less expensive maps_find() (case is already folded) instead
- * of the baroque mail_addr_find(). But then we have to strip the domain
- * and deal with address extensions ourselves.
+ * XXX Use the less expensive maps_find() (built-in case folding) instead of
+ * the baroque mail_addr_find(). But then we have to strip the domain and
+ * deal with address extensions ourselves.
*
* XXX But that would break sites that use the virtual delivery agent for
* local delivery, because the virtual delivery agent requires
status = setjmp(smtpd_check_buf);
if (status == 0 && data_restrctions->argc)
status = generic_checks(state, data_restrctions,
- "DATA", SMTPD_NAME_DATA, NO_DEF_ACL);
+ SMTPD_CMD_DATA, SMTPD_NAME_DATA, NO_DEF_ACL);
/*
* Force permission into deferral when some earlier temporary error may
status = setjmp(smtpd_check_buf);
if (status == 0 && eod_restrictions->argc)
status = generic_checks(state, eod_restrictions,
- "END-OF-DATA", SMTPD_NAME_EOD, NO_DEF_ACL);
+ SMTPD_CMD_EOD, SMTPD_NAME_EOD, NO_DEF_ACL);
/*
* Force permission into deferral when some earlier temporary error may
int var_smtpd_policy_ttl;
int var_smtpd_rej_unl_from;
int var_smtpd_rej_unl_rcpt;
+int var_plaintext_code;
+bool var_smtpd_peername_lookup;
static INT_TABLE int_table[] = {
"msg_verbose", 0, &msg_verbose,
VAR_VERIFY_POLL_COUNT, DEF_VERIFY_POLL_COUNT, &var_verify_poll_count,
VAR_SMTPD_REJ_UNL_FROM, DEF_SMTPD_REJ_UNL_FROM, &var_smtpd_rej_unl_from,
VAR_SMTPD_REJ_UNL_RCPT, DEF_SMTPD_REJ_UNL_RCPT, &var_smtpd_rej_unl_rcpt,
+ VAR_PLAINTEXT_CODE, DEF_PLAINTEXT_CODE, &var_plaintext_code,
+ VAR_SMTPD_PEERNAME_LOOKUP, DEF_SMTPD_PEERNAME_LOOKUP, &var_smtpd_peername_lookup,
0,
};
/* resolve_clnt_query - stub */
-void resolve_clnt(const char *class, const char *addr, RESOLVE_REPLY *reply)
+void resolve_clnt(const char *class, const char *unused_sender, const char *addr,
+ RESOLVE_REPLY *reply)
{
const char *domain;
state.name_status =
state.reverse_name_status =
atoi(args->argv[3]);
+ else if (strcmp(state.name, "unknown") == 0)
+ state.name_status =
+ state.reverse_name_status =
+ SMTPD_PEER_CODE_TEMP;
else
state.name_status =
state.reverse_name_status =
if (strcasecmp(args->argv[0], VAR_VIRT_ALIAS_MAPS) == 0) {
UPDATE_STRING(var_virt_alias_maps, args->argv[1]);
UPDATE_MAPS(virt_alias_maps, VAR_VIRT_ALIAS_MAPS,
- var_virt_alias_maps, DICT_FLAG_LOCK);
+ var_virt_alias_maps, DICT_FLAG_LOCK
+ | DICT_FLAG_FOLD_FIX);
resp = 0;
break;
}
if (strcasecmp(args->argv[0], VAR_VIRT_MAILBOX_MAPS) == 0) {
UPDATE_STRING(var_virt_mailbox_maps, args->argv[1]);
UPDATE_MAPS(virt_mailbox_maps, VAR_VIRT_MAILBOX_MAPS,
- var_virt_mailbox_maps, DICT_FLAG_LOCK);
+ var_virt_mailbox_maps, DICT_FLAG_LOCK
+ | DICT_FLAG_FOLD_FIX);
resp = 0;
break;
}
if (strcasecmp(args->argv[0], VAR_LOCAL_RCPT_MAPS) == 0) {
UPDATE_STRING(var_local_rcpt_maps, args->argv[1]);
UPDATE_MAPS(local_rcpt_maps, VAR_LOCAL_RCPT_MAPS,
- var_local_rcpt_maps, DICT_FLAG_LOCK);
+ var_local_rcpt_maps, DICT_FLAG_LOCK
+ | DICT_FLAG_FOLD_FIX);
resp = 0;
break;
}
if (strcasecmp(args->argv[0], VAR_RELAY_RCPT_MAPS) == 0) {
UPDATE_STRING(var_relay_rcpt_maps, args->argv[1]);
UPDATE_MAPS(relay_rcpt_maps, VAR_RELAY_RCPT_MAPS,
- var_relay_rcpt_maps, DICT_FLAG_LOCK);
+ var_relay_rcpt_maps, DICT_FLAG_LOCK
+ | DICT_FLAG_FOLD_FIX);
resp = 0;
break;
}
if (strcasecmp(args->argv[0], VAR_CANONICAL_MAPS) == 0) {
UPDATE_STRING(var_canonical_maps, args->argv[1]);
UPDATE_MAPS(canonical_maps, VAR_CANONICAL_MAPS,
- var_canonical_maps, DICT_FLAG_LOCK);
+ var_canonical_maps, DICT_FLAG_LOCK
+ | DICT_FLAG_FOLD_FIX);
resp = 0;
break;
}
if (strcasecmp(args->argv[0], VAR_RBL_REPLY_MAPS) == 0) {
UPDATE_STRING(var_rbl_reply_maps, args->argv[1]);
UPDATE_MAPS(rbl_reply_maps, VAR_RBL_REPLY_MAPS,
- var_rbl_reply_maps, DICT_FLAG_LOCK);
+ var_rbl_reply_maps, DICT_FLAG_LOCK
+ | DICT_FLAG_FOLD_FIX);
resp = 0;
break;
}
>>> client foo 123.123.123.123
OK
>>> helo foo.
-./smtpd_check: <queue id>: reject: HELO from foo[123.123.123.123]: 450 4.1.0 <foo.>: Helo command rejected: Host not found; proto=SMTP helo=<foo.>
-450 4.1.0 <foo.>: Helo command rejected: Host not found
+./smtpd_check: <queue id>: reject: HELO from foo[123.123.123.123]: 450 4.7.1 <foo.>: Helo command rejected: Host not found; proto=SMTP helo=<foo.>
+450 4.7.1 <foo.>: Helo command rejected: Host not found
>>> helo foo
-./smtpd_check: <queue id>: reject: HELO from foo[123.123.123.123]: 450 4.1.0 <foo>: Helo command rejected: Host not found; proto=SMTP helo=<foo>
-450 4.1.0 <foo>: Helo command rejected: Host not found
+./smtpd_check: <queue id>: reject: HELO from foo[123.123.123.123]: 450 4.7.1 <foo>: Helo command rejected: Host not found; proto=SMTP helo=<foo>
+450 4.7.1 <foo>: Helo command rejected: Host not found
>>> helo spike.porcupine.org
./smtpd_check: <queue id>: reject: HELO from foo[123.123.123.123]: 554 5.7.1 <spike.porcupine.org>: Helo command rejected: name server spike.porcupine.org; proto=SMTP helo=<spike.porcupine.org>
554 5.7.1 <spike.porcupine.org>: Helo command rejected: name server spike.porcupine.org
>>> helo_restrictions reject_invalid_hostname,reject_unknown_hostname
OK
>>> helo 123.123.123.123
-./smtpd_check: <queue id>: reject: HELO from foo[123.123.123.123]: 450 4.1.0 <123.123.123.123>: Helo command rejected: Host not found; proto=SMTP helo=<123.123.123.123>
-450 4.1.0 <123.123.123.123>: Helo command rejected: Host not found
+./smtpd_check: <queue id>: reject: HELO from foo[123.123.123.123]: 450 4.7.1 <123.123.123.123>: Helo command rejected: Host not found; proto=SMTP helo=<123.123.123.123>
+450 4.7.1 <123.123.123.123>: Helo command rejected: Host not found
>>> helo [123.123.123.123]
OK
>>> helo [::]
>>> client foo 123.123.123.123
OK
>>> helo foo.
-./smtpd_check: <queue id>: reject: HELO from foo[123.123.123.123]: 450 4.1.0 <foo.>: Helo command rejected: Host not found; proto=SMTP helo=<foo.>
-450 4.1.0 <foo.>: Helo command rejected: Host not found
+./smtpd_check: <queue id>: reject: HELO from foo[123.123.123.123]: 450 4.7.1 <foo.>: Helo command rejected: Host not found; proto=SMTP helo=<foo.>
+450 4.7.1 <foo.>: Helo command rejected: Host not found
>>> helo foo
-./smtpd_check: <queue id>: reject: HELO from foo[123.123.123.123]: 450 4.1.0 <foo>: Helo command rejected: Host not found; proto=SMTP helo=<foo>
-450 4.1.0 <foo>: Helo command rejected: Host not found
+./smtpd_check: <queue id>: reject: HELO from foo[123.123.123.123]: 450 4.7.1 <foo>: Helo command rejected: Host not found; proto=SMTP helo=<foo>
+450 4.7.1 <foo>: Helo command rejected: Host not found
>>> helo spike.porcupine.org
./smtpd_check: <queue id>: reject: HELO from foo[123.123.123.123]: 554 5.7.1 <spike.porcupine.org>: Helo command rejected: name server spike.porcupine.org; proto=SMTP helo=<spike.porcupine.org>
554 5.7.1 <spike.porcupine.org>: Helo command rejected: name server spike.porcupine.org
>>> sender_restrictions hash:./smtpd_check_access
OK
>>> mail user@4.1.1_dsn
-./smtpd_check: mapping DSN status 4.1.1 into Sender address status 4.1.0
-./smtpd_check: <queue id>: reject: MAIL from dummy[dummy]: 554 5.1.0 <user@4.1.1_dsn>: Sender address rejected: reject; from=<user@4.1.1_dsn> proto=SMTP helo=<4.4.0_dsn>
-554 5.1.0 <user@4.1.1_dsn>: Sender address rejected: reject
+./smtpd_check: mapping DSN status 4.1.1 into Sender address status 4.1.7
+./smtpd_check: <queue id>: reject: MAIL from dummy[dummy]: 554 5.1.7 <user@4.1.1_dsn>: Sender address rejected: reject; from=<user@4.1.1_dsn> proto=SMTP helo=<4.4.0_dsn>
+554 5.1.7 <user@4.1.1_dsn>: Sender address rejected: reject
>>> mail user@4.1.2_dsn
./smtpd_check: mapping DSN status 4.1.2 into Sender address status 4.1.8
./smtpd_check: <queue id>: reject: MAIL from dummy[dummy]: 554 5.1.8 <user@4.1.2_dsn>: Sender address rejected: reject; from=<user@4.1.2_dsn> proto=SMTP helo=<4.4.0_dsn>
./smtpd_check: <queue id>: reject: MAIL from dummy[dummy]: 554 5.1.7 <user@4.1.3_dsn>: Sender address rejected: reject; from=<user@4.1.3_dsn> proto=SMTP helo=<4.4.0_dsn>
554 5.1.7 <user@4.1.3_dsn>: Sender address rejected: reject
>>> mail user@4.1.4_dsn
-./smtpd_check: mapping DSN status 4.1.4 into Sender address status 4.1.0
-./smtpd_check: <queue id>: reject: MAIL from dummy[dummy]: 554 5.1.0 <user@4.1.4_dsn>: Sender address rejected: reject; from=<user@4.1.4_dsn> proto=SMTP helo=<4.4.0_dsn>
-554 5.1.0 <user@4.1.4_dsn>: Sender address rejected: reject
+./smtpd_check: mapping DSN status 4.1.4 into Sender address status 4.1.7
+./smtpd_check: <queue id>: reject: MAIL from dummy[dummy]: 554 5.1.7 <user@4.1.4_dsn>: Sender address rejected: reject; from=<user@4.1.4_dsn> proto=SMTP helo=<4.4.0_dsn>
+554 5.1.7 <user@4.1.4_dsn>: Sender address rejected: reject
>>> mail user@4.1.5_dsn
./smtpd_check: mapping DSN status 4.1.5 into Sender address status 4.1.0
./smtpd_check: <queue id>: reject: MAIL from dummy[dummy]: 554 5.1.0 <user@4.1.5_dsn>: Sender address rejected: reject; from=<user@4.1.5_dsn> proto=SMTP helo=<4.4.0_dsn>
554 5.1.0 <user@4.1.5_dsn>: Sender address rejected: reject
>>> mail user@4.1.6_dsn
-./smtpd_check: mapping DSN status 4.1.6 into Sender address status 4.1.0
-./smtpd_check: <queue id>: reject: MAIL from dummy[dummy]: 554 5.1.0 <user@4.1.6_dsn>: Sender address rejected: reject; from=<user@4.1.6_dsn> proto=SMTP helo=<4.4.0_dsn>
-554 5.1.0 <user@4.1.6_dsn>: Sender address rejected: reject
+./smtpd_check: mapping DSN status 4.1.6 into Sender address status 4.1.7
+./smtpd_check: <queue id>: reject: MAIL from dummy[dummy]: 554 5.1.7 <user@4.1.6_dsn>: Sender address rejected: reject; from=<user@4.1.6_dsn> proto=SMTP helo=<4.4.0_dsn>
+554 5.1.7 <user@4.1.6_dsn>: Sender address rejected: reject
>>> mail user@4.1.7_dsn
./smtpd_check: <queue id>: reject: MAIL from dummy[dummy]: 554 5.1.7 <user@4.1.7_dsn>: Sender address rejected: reject; from=<user@4.1.7_dsn> proto=SMTP helo=<4.4.0_dsn>
554 5.1.7 <user@4.1.7_dsn>: Sender address rejected: reject
static struct dsn_map dsn_map[] = {
/* - Sender - Recipient */
- "1", "4.1.0", "4.1.1", /* 4.1.1: Bad dest mbox addr */
+ "1", SND_DSN, "4.1.1", /* 4.1.1: Bad dest mbox addr */
"2", "4.1.8", "4.1.2", /* 4.1.2: Bad dest system addr */
"3", "4.1.7", "4.1.3", /* 4.1.3: Bad dest mbox addr syntax */
- "4", "4.1.0", "4.1.4", /* 4.1.4: Dest mbox addr ambiguous */
+ "4", SND_DSN, "4.1.4", /* 4.1.4: Dest mbox addr ambiguous */
"5", "4.1.0", "4.1.5", /* 4.1.5: Dest mbox addr valid */
- "6", "4.1.0", "4.1.6", /* 4.1.6: Mailbox has moved */
+ "6", SND_DSN, "4.1.6", /* 4.1.6: Mailbox has moved */
"7", "4.1.7", "4.1.3", /* 4.1.7: Bad sender mbox addr syntax */
"8", "4.1.8", "4.1.2", /* 4.1.8: Bad sender system addr */
0, "4.1.0", "4.1.0", /* Default mapping */
#define SMTPD_NAME_DATA "Data command"
#define SMTPD_NAME_EOD "End-of-data"
+ /*
+ * Workaround for absence of "bad sender address" status code: use "bad
+ * sender address syntax" instead. If we were to use "4.1.0" then we would
+ * lose the critical distinction between sender and recipient problems.
+ */
+#define SND_DSN "4.1.7"
+
extern const char *smtpd_dsn_fix(const char *, const char *);
/* LICENSE
spawn.o: ../../include/timed_wait.h
spawn.o: ../../include/vbuf.h
spawn.o: ../../include/vstream.h
+spawn.o: ../../include/vstring.h
spawn.o: spawn.c
if (attr_clnt_request(tls_mgr,
ATTR_FLAG_NONE, /* Request attributes */
ATTR_TYPE_STR, TLS_MGR_ATTR_REQ, TLS_MGR_REQ_SEED,
- ATTR_TYPE_NUM, TLS_MGR_ATTR_SIZE, len,
+ ATTR_TYPE_INT, TLS_MGR_ATTR_SIZE, len,
ATTR_TYPE_END,
ATTR_FLAG_MISSING, /* Reply attributes */
- ATTR_TYPE_NUM, TLS_MGR_ATTR_STATUS, &status,
+ ATTR_TYPE_INT, TLS_MGR_ATTR_STATUS, &status,
ATTR_TYPE_DATA, TLS_MGR_ATTR_SEED, buf,
ATTR_TYPE_END) != 2)
status = TLS_MGR_STAT_FAIL;
ATTR_TYPE_STR, TLS_MGR_ATTR_REQ, TLS_MGR_REQ_POLICY,
ATTR_TYPE_END,
ATTR_FLAG_MISSING, /* Reply attributes */
- ATTR_TYPE_NUM, TLS_MGR_ATTR_STATUS, &status,
- ATTR_TYPE_NUM, TLS_MGR_ATTR_POLICY, policy,
+ ATTR_TYPE_INT, TLS_MGR_ATTR_STATUS, &status,
+ ATTR_TYPE_INT, TLS_MGR_ATTR_POLICY, policy,
ATTR_TYPE_END) != 2)
status = TLS_MGR_STAT_FAIL;
return (status);
if (attr_clnt_request(tls_mgr,
ATTR_FLAG_NONE, /* Request */
ATTR_TYPE_STR, TLS_MGR_ATTR_REQ, TLS_MGR_REQ_LOOKUP,
- ATTR_TYPE_NUM, TLS_MGR_ATTR_CACHE_TYPE, cache_type,
+ ATTR_TYPE_INT, TLS_MGR_ATTR_CACHE_TYPE, cache_type,
ATTR_TYPE_STR, TLS_MGR_ATTR_CACHE_ID, cache_id,
ATTR_TYPE_END,
ATTR_FLAG_MISSING, /* Reply */
- ATTR_TYPE_NUM, TLS_MGR_ATTR_STATUS, &status,
+ ATTR_TYPE_INT, TLS_MGR_ATTR_STATUS, &status,
ATTR_TYPE_DATA, TLS_MGR_ATTR_SESSION, buf,
ATTR_TYPE_END) != 2)
status = TLS_MGR_STAT_FAIL;
if (attr_clnt_request(tls_mgr,
ATTR_FLAG_NONE, /* Request */
ATTR_TYPE_STR, TLS_MGR_ATTR_REQ, TLS_MGR_REQ_UPDATE,
- ATTR_TYPE_NUM, TLS_MGR_ATTR_CACHE_TYPE, cache_type,
+ ATTR_TYPE_INT, TLS_MGR_ATTR_CACHE_TYPE, cache_type,
ATTR_TYPE_STR, TLS_MGR_ATTR_CACHE_ID, cache_id,
ATTR_TYPE_DATA, TLS_MGR_ATTR_SESSION, len, buf,
ATTR_TYPE_END,
ATTR_FLAG_MISSING, /* Reply */
- ATTR_TYPE_NUM, TLS_MGR_ATTR_STATUS, &status,
+ ATTR_TYPE_INT, TLS_MGR_ATTR_STATUS, &status,
ATTR_TYPE_END) != 1)
status = TLS_MGR_STAT_FAIL;
return (status);
if (attr_clnt_request(tls_mgr,
ATTR_FLAG_NONE, /* Request */
ATTR_TYPE_STR, TLS_MGR_ATTR_REQ, TLS_MGR_REQ_DELETE,
- ATTR_TYPE_NUM, TLS_MGR_ATTR_CACHE_TYPE, cache_type,
+ ATTR_TYPE_INT, TLS_MGR_ATTR_CACHE_TYPE, cache_type,
ATTR_TYPE_STR, TLS_MGR_ATTR_CACHE_ID, cache_id,
ATTR_TYPE_END,
ATTR_FLAG_MISSING, /* Reply */
- ATTR_TYPE_NUM, TLS_MGR_ATTR_STATUS, &status,
+ ATTR_TYPE_INT, TLS_MGR_ATTR_STATUS, &status,
ATTR_TYPE_END) != 1)
status = TLS_MGR_STAT_FAIL;
return (status);
static char *tls_text_name(X509_NAME *name, int nid, char *label, int gripe)
{
int len;
- char *text;
+ int pos;
+ X509_NAME_ENTRY *entry;
+ ASN1_STRING *entry_str;
+ unsigned char *tmp;
+ char *result;
- if ((len = X509_NAME_get_text_by_NID(name, nid, 0, 0)) < 0) {
+ if (name == 0
+ || (pos = X509_NAME_get_index_by_NID(name, nid, -1)) < 0) {
if (gripe != DONT_GRIPE) {
msg_warn("peer certificate has no %s", label);
tls_print_errors();
return (0);
}
+#if 0
+ /*
+ * If the match is required unambiguous, insist that that no
+ * other values be present.
+ */
+ if (unique == UNIQUE && X509_NAME_get_index_by_NID(name, nid, pos) >= 0) {
+ msg_warn("multiple %ss in peer certificate", label);
+ return (0);
+ }
+#endif
+
+ if ((entry = X509_NAME_get_entry(name, pos)) == 0) {
+ /* This should not happen */
+ msg_warn("error reading peer certificate %s entry", label);
+ tls_print_errors();
+ return (0);
+ }
+
+ if ((entry_str = X509_NAME_ENTRY_get_data(entry)) == 0) {
+ /* This should not happen */
+ msg_warn("error reading peer certificate %s data", label);
+ tls_print_errors();
+ return (0);
+ }
+
+ if ((len = ASN1_STRING_to_UTF8(&tmp, entry_str)) < 0) {
+ /* This should not happen */
+ msg_warn("error decoding peer certificate %s data", label);
+ tls_print_errors();
+ return (0);
+ }
+
/*
* Since the peer CN is used in peer verification, take care to detect
* truncation due to excessive length or internal NULs.
*/
if (len >= CCERT_BUFSIZ) {
+ OPENSSL_free(tmp);
msg_warn("peer %s too long: %d", label, (int) len);
return (0);
}
- text = mymalloc(len + 1);
- X509_NAME_get_text_by_NID(name, nid, text, len + 1);
- if (strlen(text) != len) {
+
+ /*
+ * Standard UTF8 does not encode NUL as 0b11000000, that is
+ * a Java "feature". So we need to check for embedded NULs.
+ */
+ if (strlen(tmp) != len) {
msg_warn("internal NUL in peer %s", label);
- myfree(text);
- text = 0;
+ OPENSSL_free(tmp);
+ return (0);
}
- return (text);
+
+ result = mystrdup(tmp);
+ OPENSSL_free(tmp);
+ return (result);
}
/* tls_peer_CN - extract peer common name from certificate */
char *cn;
cn = tls_text_name(X509_get_subject_name(peercert),
- NID_commonName, "CN", DO_GRIPE);
+ NID_commonName, "subject CN", DO_GRIPE);
return (cn);
}
*/
if (STREQ(STR(request), TLS_MGR_REQ_LOOKUP)) {
if (attr_scan(client_stream, ATTR_FLAG_STRICT,
- ATTR_TYPE_NUM, TLS_MGR_ATTR_CACHE_TYPE, &cache_type,
+ ATTR_TYPE_INT, TLS_MGR_ATTR_CACHE_TYPE, &cache_type,
ATTR_TYPE_STR, TLS_MGR_ATTR_CACHE_ID, cache_id,
ATTR_TYPE_END) == 2) {
if ((cache = WHICH_CACHE_INFO(cache_type)) == 0) {
}
}
attr_print(client_stream, ATTR_FLAG_NONE,
- ATTR_TYPE_NUM, MAIL_ATTR_STATUS, status,
+ ATTR_TYPE_INT, MAIL_ATTR_STATUS, status,
ATTR_TYPE_DATA, TLS_MGR_ATTR_SESSION,
LEN(buffer), STR(buffer),
ATTR_TYPE_END);
*/
else if (STREQ(STR(request), TLS_MGR_REQ_UPDATE)) {
if (attr_scan(client_stream, ATTR_FLAG_STRICT,
- ATTR_TYPE_NUM, TLS_MGR_ATTR_CACHE_TYPE, &cache_type,
+ ATTR_TYPE_INT, TLS_MGR_ATTR_CACHE_TYPE, &cache_type,
ATTR_TYPE_STR, TLS_MGR_ATTR_CACHE_ID, cache_id,
ATTR_TYPE_DATA, TLS_MGR_ATTR_SESSION, buffer,
ATTR_TYPE_END) == 3) {
}
}
attr_print(client_stream, ATTR_FLAG_NONE,
- ATTR_TYPE_NUM, MAIL_ATTR_STATUS, status,
+ ATTR_TYPE_INT, MAIL_ATTR_STATUS, status,
ATTR_TYPE_END);
}
*/
else if (STREQ(STR(request), TLS_MGR_REQ_DELETE)) {
if (attr_scan(client_stream, ATTR_FLAG_STRICT,
- ATTR_TYPE_NUM, TLS_MGR_ATTR_CACHE_TYPE, &cache_type,
+ ATTR_TYPE_INT, TLS_MGR_ATTR_CACHE_TYPE, &cache_type,
ATTR_TYPE_STR, TLS_MGR_ATTR_CACHE_ID, cache_id,
ATTR_TYPE_END) == 2) {
if ((cache = WHICH_CACHE_INFO(cache_type)) == 0) {
}
}
attr_print(client_stream, ATTR_FLAG_NONE,
- ATTR_TYPE_NUM, MAIL_ATTR_STATUS, status,
+ ATTR_TYPE_INT, MAIL_ATTR_STATUS, status,
ATTR_TYPE_END);
}
*/
else if (STREQ(STR(request), TLS_MGR_REQ_SEED)) {
if (attr_scan(client_stream, ATTR_FLAG_STRICT,
- ATTR_TYPE_NUM, TLS_MGR_ATTR_SIZE, &len,
+ ATTR_TYPE_INT, TLS_MGR_ATTR_SIZE, &len,
ATTR_TYPE_END) == 1) {
VSTRING_RESET(buffer);
if (len <= 0 || len > 255) {
}
}
attr_print(client_stream, ATTR_FLAG_NONE,
- ATTR_TYPE_NUM, MAIL_ATTR_STATUS, status,
+ ATTR_TYPE_INT, MAIL_ATTR_STATUS, status,
ATTR_TYPE_DATA, TLS_MGR_ATTR_SEED,
LEN(buffer), STR(buffer),
ATTR_TYPE_END);
status = TLS_MGR_STAT_OK;
}
attr_print(client_stream, ATTR_FLAG_NONE,
- ATTR_TYPE_NUM, MAIL_ATTR_STATUS, status,
- ATTR_TYPE_NUM, TLS_MGR_ATTR_POLICY, cache_types,
+ ATTR_TYPE_INT, MAIL_ATTR_STATUS, status,
+ ATTR_TYPE_INT, TLS_MGR_ATTR_POLICY, cache_types,
ATTR_TYPE_END);
}
*/
else {
attr_print(client_stream, ATTR_FLAG_NONE,
- ATTR_TYPE_NUM, MAIL_ATTR_STATUS, TLS_MGR_STAT_FAIL,
+ ATTR_TYPE_INT, MAIL_ATTR_STATUS, TLS_MGR_STAT_FAIL,
ATTR_TYPE_END);
}
vstream_fflush(client_stream);
STR(nexthop), STR(nextrcpt), flags);
attr_print(stream, ATTR_FLAG_NONE,
- ATTR_TYPE_NUM, MAIL_ATTR_FLAGS, server_flags,
+ ATTR_TYPE_INT, MAIL_ATTR_FLAGS, server_flags,
ATTR_TYPE_STR, MAIL_ATTR_TRANSPORT, STR(channel),
ATTR_TYPE_STR, MAIL_ATTR_NEXTHOP, STR(nexthop),
ATTR_TYPE_STR, MAIL_ATTR_RECIP, STR(nextrcpt),
- ATTR_TYPE_NUM, MAIL_ATTR_FLAGS, flags,
+ ATTR_TYPE_INT, MAIL_ATTR_FLAGS, flags,
ATTR_TYPE_END);
if (vstream_fflush(stream) != 0) {
if (*var_relocated_maps)
relocated_maps =
maps_create(VAR_RELOCATED_MAPS, var_relocated_maps,
- DICT_FLAG_LOCK);
+ DICT_FLAG_LOCK | DICT_FLAG_FOLD_FIX);
}
vstring_str(address), vstring_str(result));
attr_print(stream, ATTR_FLAG_NONE,
- ATTR_TYPE_NUM, MAIL_ATTR_FLAGS, server_flags,
+ ATTR_TYPE_INT, MAIL_ATTR_FLAGS, server_flags,
ATTR_TYPE_STR, MAIL_ATTR_ADDR, vstring_str(result),
ATTR_TYPE_END);
tp = (TRANSPORT_INFO *) mymalloc(sizeof(*tp));
tp->transport_path = maps_create(transport_maps_name, transport_maps,
- DICT_FLAG_LOCK);
+ DICT_FLAG_LOCK | DICT_FLAG_FOLD_FIX
+ | DICT_FLAG_NO_REGSUB);
tp->wildcard_channel = tp->wildcard_nexthop = 0;
tp->transport_errno = 0;
return (tp);
const char *rcpt_domain,
VSTRING *channel, VSTRING *nexthop)
{
- char *full_addr;
char *stripped_addr;
char *ratsign = 0;
const char *name;
msg_warn("transport_lookup: null address - skipping table lookup");
return (NOTFOUND);
}
- full_addr = lowercase(mystrdup(addr));
-
- /*
- * The optimizer will replace multiple instances of this macro expansion
- * by gotos to a single instance that does the same thing.
- */
-#define RETURN_FREE(x) { \
- myfree(full_addr); \
- return (x); \
- }
/*
* Look up the full address with the FULL flag to include regexp maps in
* the query.
*/
- if ((ratsign = strrchr(full_addr, '@')) == 0 || ratsign[1] == 0)
- msg_panic("transport_lookup: bad address: \"%s\"", full_addr);
+ if ((ratsign = strrchr(addr, '@')) == 0 || ratsign[1] == 0)
+ msg_panic("transport_lookup: bad address: \"%s\"", addr);
- if (find_transport_entry(tp, full_addr, rcpt_domain, FULL, channel, nexthop))
- RETURN_FREE(FOUND);
+ if (find_transport_entry(tp, addr, rcpt_domain, FULL, channel, nexthop))
+ return (FOUND);
if (dict_errno != 0)
- RETURN_FREE(NOTFOUND);
+ return (NOTFOUND);
/*
* If the full address did not match, and there is an address extension,
* look up the stripped address with the PARTIAL flag to avoid matching
* partial lookup keys with regular expressions.
*/
- if ((stripped_addr = strip_addr(full_addr, DISCARD_EXTENSION,
+ if ((stripped_addr = strip_addr(addr, DISCARD_EXTENSION,
*var_rcpt_delim)) != 0) {
found = find_transport_entry(tp, stripped_addr, rcpt_domain, PARTIAL,
channel, nexthop);
myfree(stripped_addr);
if (found)
- RETURN_FREE(FOUND);
+ return (FOUND);
if (dict_errno != 0)
- RETURN_FREE(NOTFOUND);
+ return (NOTFOUND);
}
/*
*/
for (name = ratsign + 1; *name != 0; name = next) {
if (find_transport_entry(tp, name, rcpt_domain, PARTIAL, channel, nexthop))
- RETURN_FREE(FOUND);
+ return (FOUND);
if (dict_errno != 0)
- RETURN_FREE(NOTFOUND);
+ return (NOTFOUND);
if ((next = strchr(name + 1, '.')) == 0)
break;
if (transport_match_parent_style == MATCH_FLAG_PARENT)
transport_wildcard_init(tp);
if (tp->transport_errno) {
dict_errno = tp->transport_errno;
- RETURN_FREE(NOTFOUND);
+ return (NOTFOUND);
} else if (tp->wildcard_channel) {
update_entry(STR(tp->wildcard_channel), STR(tp->wildcard_nexthop),
rcpt_domain, channel, nexthop);
- RETURN_FREE(FOUND);
+ return (FOUND);
}
/*
* We really did not find it.
*/
- RETURN_FREE(NOTFOUND);
+ return (NOTFOUND);
}
if (*RES_PARAM_VALUE(resolve_regular.snd_relay_maps))
resolve_regular.snd_relay_info =
maps_create(resolve_regular.snd_relay_maps_name,
- RES_PARAM_VALUE(resolve_regular.snd_relay_maps), 0);
+ RES_PARAM_VALUE(resolve_regular.snd_relay_maps),
+ DICT_FLAG_LOCK | DICT_FLAG_FOLD_FIX
+ | DICT_FLAG_NO_REGSUB);
if (*RES_PARAM_VALUE(resolve_verify.snd_relay_maps))
resolve_verify.snd_relay_info =
maps_create(resolve_verify.snd_relay_maps_name,
- RES_PARAM_VALUE(resolve_verify.snd_relay_maps), 0);
+ RES_PARAM_VALUE(resolve_verify.snd_relay_maps),
+ DICT_FLAG_LOCK | DICT_FLAG_FOLD_FIX
+ | DICT_FLAG_NO_REGSUB);
}
/* post_jail_init - initialize after entering chroot jail */
dict.o: mac_parse.h
dict.o: msg.h
dict.o: mymalloc.h
+dict.o: name_mask.h
dict.o: readlline.h
dict.o: stringops.h
dict.o: sys_defs.h
dict_alloc.o: sys_defs.h
dict_alloc.o: vbuf.h
dict_alloc.o: vstream.h
+dict_alloc.o: vstring.h
dict_cdb.o: argv.h
dict_cdb.o: dict.h
dict_cdb.o: dict_cdb.c
dict_debug.o: sys_defs.h
dict_debug.o: vbuf.h
dict_debug.o: vstream.h
+dict_debug.o: vstring.h
dict_env.o: argv.h
dict_env.o: dict.h
dict_env.o: dict_env.c
dict_env.o: msg.h
dict_env.o: mymalloc.h
dict_env.o: safe.h
+dict_env.o: stringops.h
dict_env.o: sys_defs.h
dict_env.o: vbuf.h
dict_env.o: vstream.h
+dict_env.o: vstring.h
dict_ht.o: argv.h
dict_ht.o: dict.h
dict_ht.o: dict_ht.c
dict_ht.o: sys_defs.h
dict_ht.o: vbuf.h
dict_ht.o: vstream.h
+dict_ht.o: vstring.h
dict_ni.o: dict_ni.c
dict_ni.o: sys_defs.h
dict_nis.o: argv.h
dict_nis.o: dict_nis.h
dict_nis.o: msg.h
dict_nis.o: mymalloc.h
+dict_nis.o: stringops.h
dict_nis.o: sys_defs.h
dict_nis.o: vbuf.h
dict_nis.o: vstream.h
dict_static.o: sys_defs.h
dict_static.o: vbuf.h
dict_static.o: vstream.h
+dict_static.o: vstring.h
dict_tcp.o: argv.h
dict_tcp.o: connect.h
dict_tcp.o: dict.h
dict_unix.o: dict_unix.h
dict_unix.o: msg.h
dict_unix.o: mymalloc.h
+dict_unix.o: stringops.h
dict_unix.o: sys_defs.h
dict_unix.o: vbuf.h
dict_unix.o: vstream.h
inet_proto.o: mymalloc.h
inet_proto.o: name_mask.h
inet_proto.o: sys_defs.h
+inet_proto.o: vbuf.h
+inet_proto.o: vstring.h
inet_trigger.o: connect.h
inet_trigger.o: events.h
inet_trigger.o: inet_trigger.c
* Attribute types. See attr_scan(3) for documentation.
*/
#define ATTR_TYPE_END 0 /* end of data */
-#define ATTR_TYPE_NUM 1 /* Unsigned integer */
+#define ATTR_TYPE_INT 1 /* Unsigned integer */
+#define ATTR_TYPE_NUM ATTR_TYPE_INT
#define ATTR_TYPE_STR 2 /* Character string */
#define ATTR_TYPE_HASH 3 /* Hash table */
#define ATTR_TYPE_NV 3 /* Name-value table */
* routines.
*/
#ifdef TEST
-#define ATTR_NAME_NUM "number"
+#define ATTR_NAME_INT "number"
#define ATTR_NAME_STR "string"
#define ATTR_NAME_LONG "long_number"
#define ATTR_NAME_DATA "data"
case ATTR_TYPE_DATA:
SKIP_ARG2(ap, ssize_t, char *);
break;
- case ATTR_TYPE_NUM:
+ case ATTR_TYPE_INT:
SKIP_ARG(ap, int);
break;
case ATTR_TYPE_LONG:
if (++count >= 2
|| msg_verbose
|| (errno && errno != EPIPE && errno != ENOENT && errno != ECONNRESET))
- msg_warn("problem talking to server %s: %m", VSTREAM_PATH(stream));
+ msg_warn("problem talking to server %s: %m",
+ auto_clnt_name(client->auto_clnt));
if (count >= 2)
return (-1);
sleep(1); /* XXX make configurable */
/* .IP type
/* The type determines the arguments that follow.
/* .RS
-/* .IP "ATTR_TYPE_NUM (char *, int)"
+/* .IP "ATTR_TYPE_INT (char *, int)"
/* This argument is followed by an attribute name and an integer.
/* .IP "ATTR_TYPE_LONG (char *, long)"
/* This argument is followed by an attribute name and a long integer.
*/
while ((attr_type = va_arg(ap, int)) != ATTR_TYPE_END) {
switch (attr_type) {
- case ATTR_TYPE_NUM:
+ case ATTR_TYPE_INT:
attr_name = va_arg(ap, char *);
vstream_fwrite(fp, attr_name, strlen(attr_name) + 1);
int_val = va_arg(ap, int);
htable_enter(table, "foo-name", mystrdup("foo-value"));
htable_enter(table, "bar-name", mystrdup("bar-value"));
attr_print0(VSTREAM_OUT, ATTR_FLAG_NONE,
- ATTR_TYPE_NUM, ATTR_NAME_NUM, 4711,
+ ATTR_TYPE_INT, ATTR_NAME_INT, 4711,
ATTR_TYPE_LONG, ATTR_NAME_LONG, 1234,
ATTR_TYPE_STR, ATTR_NAME_STR, "whoopee",
ATTR_TYPE_DATA, ATTR_NAME_DATA, strlen("whoopee"), "whoopee",
ATTR_TYPE_HASH, table,
ATTR_TYPE_END);
attr_print0(VSTREAM_OUT, ATTR_FLAG_NONE,
- ATTR_TYPE_NUM, ATTR_NAME_NUM, 4711,
+ ATTR_TYPE_INT, ATTR_NAME_INT, 4711,
ATTR_TYPE_LONG, ATTR_NAME_LONG, 1234,
ATTR_TYPE_STR, ATTR_NAME_STR, "whoopee",
ATTR_TYPE_DATA, ATTR_NAME_DATA, strlen("whoopee"), "whoopee",
/* .IP type
/* The type determines the arguments that follow.
/* .RS
-/* .IP "ATTR_TYPE_NUM (char *, int)"
+/* .IP "ATTR_TYPE_INT (char *, int)"
/* This argument is followed by an attribute name and an integer.
/* .IP "ATTR_TYPE_LONG (char *, long)"
/* This argument is followed by an attribute name and a long integer.
*/
while ((attr_type = va_arg(ap, int)) != ATTR_TYPE_END) {
switch (attr_type) {
- case ATTR_TYPE_NUM:
+ case ATTR_TYPE_INT:
attr_name = va_arg(ap, char *);
attr_print64_str(fp, attr_name, strlen(attr_name));
int_val = va_arg(ap, int);
htable_enter(table, "foo-name", mystrdup("foo-value"));
htable_enter(table, "bar-name", mystrdup("bar-value"));
attr_print64(VSTREAM_OUT, ATTR_FLAG_NONE,
- ATTR_TYPE_NUM, ATTR_NAME_NUM, 4711,
+ ATTR_TYPE_INT, ATTR_NAME_INT, 4711,
ATTR_TYPE_LONG, ATTR_NAME_LONG, 1234,
ATTR_TYPE_STR, ATTR_NAME_STR, "whoopee",
ATTR_TYPE_DATA, ATTR_NAME_DATA, strlen("whoopee"), "whoopee",
ATTR_TYPE_HASH, table,
ATTR_TYPE_END);
attr_print64(VSTREAM_OUT, ATTR_FLAG_NONE,
- ATTR_TYPE_NUM, ATTR_NAME_NUM, 4711,
+ ATTR_TYPE_INT, ATTR_NAME_INT, 4711,
ATTR_TYPE_LONG, ATTR_NAME_LONG, 1234,
ATTR_TYPE_STR, ATTR_NAME_STR, "whoopee",
ATTR_TYPE_DATA, ATTR_NAME_DATA, strlen("whoopee"), "whoopee",
/* .IP type
/* The type determines the arguments that follow.
/* .RS
-/* .IP "ATTR_TYPE_NUM (char *, int)"
+/* .IP "ATTR_TYPE_INT (char *, int)"
/* This argument is followed by an attribute name and an integer.
/* .IP "ATTR_TYPE_LONG (char *, long)"
/* This argument is followed by an attribute name and a long integer.
*/
while ((attr_type = va_arg(ap, int)) != ATTR_TYPE_END) {
switch (attr_type) {
- case ATTR_TYPE_NUM:
+ case ATTR_TYPE_INT:
attr_name = va_arg(ap, char *);
int_val = va_arg(ap, int);
vstream_fprintf(fp, "%s=%u\n", attr_name, (unsigned) int_val);
htable_enter(table, "foo-name", mystrdup("foo-value"));
htable_enter(table, "bar-name", mystrdup("bar-value"));
attr_print_plain(VSTREAM_OUT, ATTR_FLAG_NONE,
- ATTR_TYPE_NUM, ATTR_NAME_NUM, 4711,
+ ATTR_TYPE_INT, ATTR_NAME_INT, 4711,
ATTR_TYPE_LONG, ATTR_NAME_LONG, 1234,
ATTR_TYPE_STR, ATTR_NAME_STR, "whoopee",
ATTR_TYPE_DATA, ATTR_NAME_DATA, strlen("whoopee"), "whoopee",
ATTR_TYPE_HASH, table,
ATTR_TYPE_END);
attr_print_plain(VSTREAM_OUT, ATTR_FLAG_NONE,
- ATTR_TYPE_NUM, ATTR_NAME_NUM, 4711,
+ ATTR_TYPE_INT, ATTR_NAME_INT, 4711,
ATTR_TYPE_LONG, ATTR_NAME_LONG, 1234,
ATTR_TYPE_STR, ATTR_NAME_STR, "whoopee",
ATTR_TYPE_DATA, ATTR_NAME_DATA, strlen("whoopee"), "whoopee",
/* .IP type
/* The type argument determines the arguments that follow.
/* .RS
-/* .IP "ATTR_TYPE_NUM (char *, int *)"
+/* .IP "ATTR_TYPE_INT (char *, int *)"
/* This argument is followed by an attribute name and an integer pointer.
/* .IP "ATTR_TYPE_LONG (char *, long *)"
/* This argument is followed by an attribute name and a long pointer.
* Do the requested conversion.
*/
switch (wanted_type) {
- case ATTR_TYPE_NUM:
+ case ATTR_TYPE_INT:
number = va_arg(ap, unsigned int *);
if ((ch = attr_scan0_number(fp, number, str_buf,
"input attribute value")) < 0)
msg_vstream_init(used_argv[0], VSTREAM_ERR);
if ((ret = attr_scan0(VSTREAM_IN,
ATTR_FLAG_STRICT,
- ATTR_TYPE_NUM, ATTR_NAME_NUM, &int_val,
+ ATTR_TYPE_INT, ATTR_NAME_INT, &int_val,
ATTR_TYPE_LONG, ATTR_NAME_LONG, &long_val,
ATTR_TYPE_STR, ATTR_NAME_STR, str_val,
ATTR_TYPE_DATA, ATTR_NAME_DATA, data_val,
ATTR_TYPE_HASH, table,
ATTR_TYPE_END)) > 4) {
- vstream_printf("%s %d\n", ATTR_NAME_NUM, int_val);
+ vstream_printf("%s %d\n", ATTR_NAME_INT, int_val);
vstream_printf("%s %ld\n", ATTR_NAME_LONG, long_val);
vstream_printf("%s %s\n", ATTR_NAME_STR, STR(str_val));
vstream_printf("%s %s\n", ATTR_NAME_DATA, STR(str_val));
}
if ((ret = attr_scan0(VSTREAM_IN,
ATTR_FLAG_STRICT,
- ATTR_TYPE_NUM, ATTR_NAME_NUM, &int_val,
+ ATTR_TYPE_INT, ATTR_NAME_INT, &int_val,
ATTR_TYPE_LONG, ATTR_NAME_LONG, &long_val,
ATTR_TYPE_STR, ATTR_NAME_STR, str_val,
ATTR_TYPE_DATA, ATTR_NAME_DATA, data_val,
ATTR_TYPE_END)) == 4) {
- vstream_printf("%s %d\n", ATTR_NAME_NUM, int_val);
+ vstream_printf("%s %d\n", ATTR_NAME_INT, int_val);
vstream_printf("%s %ld\n", ATTR_NAME_LONG, long_val);
vstream_printf("%s %s\n", ATTR_NAME_STR, STR(str_val));
vstream_printf("%s %s\n", ATTR_NAME_DATA, STR(data_val));
/* .IP type
/* The type argument determines the arguments that follow.
/* .RS
-/* .IP "ATTR_TYPE_NUM (char *, int *)"
+/* .IP "ATTR_TYPE_INT (char *, int *)"
/* This argument is followed by an attribute name and an integer pointer.
/* .IP "ATTR_TYPE_LONG (char *, long *)"
/* This argument is followed by an attribute name and a long pointer.
* elements.
*/
switch (wanted_type) {
- case ATTR_TYPE_NUM:
+ case ATTR_TYPE_INT:
if (ch != ':') {
msg_warn("missing value for number attribute %s from %s",
STR(name_buf), VSTREAM_PATH(fp));
msg_vstream_init(used_argv[0], VSTREAM_ERR);
if ((ret = attr_scan64(VSTREAM_IN,
ATTR_FLAG_STRICT,
- ATTR_TYPE_NUM, ATTR_NAME_NUM, &int_val,
+ ATTR_TYPE_INT, ATTR_NAME_INT, &int_val,
ATTR_TYPE_LONG, ATTR_NAME_LONG, &long_val,
ATTR_TYPE_STR, ATTR_NAME_STR, str_val,
ATTR_TYPE_DATA, ATTR_NAME_DATA, data_val,
ATTR_TYPE_HASH, table,
ATTR_TYPE_END)) > 4) {
- vstream_printf("%s %d\n", ATTR_NAME_NUM, int_val);
+ vstream_printf("%s %d\n", ATTR_NAME_INT, int_val);
vstream_printf("%s %ld\n", ATTR_NAME_LONG, long_val);
vstream_printf("%s %s\n", ATTR_NAME_STR, STR(str_val));
vstream_printf("%s %s\n", ATTR_NAME_DATA, STR(data_val));
}
if ((ret = attr_scan64(VSTREAM_IN,
ATTR_FLAG_STRICT,
- ATTR_TYPE_NUM, ATTR_NAME_NUM, &int_val,
+ ATTR_TYPE_INT, ATTR_NAME_INT, &int_val,
ATTR_TYPE_LONG, ATTR_NAME_LONG, &long_val,
ATTR_TYPE_STR, ATTR_NAME_STR, str_val,
ATTR_TYPE_DATA, ATTR_NAME_DATA, data_val,
ATTR_TYPE_END)) == 4) {
- vstream_printf("%s %d\n", ATTR_NAME_NUM, int_val);
+ vstream_printf("%s %d\n", ATTR_NAME_INT, int_val);
vstream_printf("%s %ld\n", ATTR_NAME_LONG, long_val);
vstream_printf("%s %s\n", ATTR_NAME_STR, STR(str_val));
vstream_printf("%s %s\n", ATTR_NAME_DATA, STR(data_val));
if (vstream_fflush(VSTREAM_OUT) != 0)
msg_fatal("write error: %m");
+ vstring_free(data_val);
vstring_free(str_val);
htable_free(table, myfree);
/* .IP type
/* The type argument determines the arguments that follow.
/* .RS
-/* .IP "ATTR_TYPE_NUM (char *, int *)"
+/* .IP "ATTR_TYPE_INT (char *, int *)"
/* This argument is followed by an attribute name and an integer pointer.
/* .IP "ATTR_TYPE_LONG (char *, long *)"
/* This argument is followed by an attribute name and a long pointer.
* Do the requested conversion.
*/
switch (wanted_type) {
- case ATTR_TYPE_NUM:
+ case ATTR_TYPE_INT:
if (ch != '=') {
msg_warn("missing value for number attribute %s from %s",
STR(name_buf), VSTREAM_PATH(fp));
msg_vstream_init(used_argv[0], VSTREAM_ERR);
if ((ret = attr_scan_plain(VSTREAM_IN,
ATTR_FLAG_STRICT,
- ATTR_TYPE_NUM, ATTR_NAME_NUM, &int_val,
+ ATTR_TYPE_INT, ATTR_NAME_INT, &int_val,
ATTR_TYPE_LONG, ATTR_NAME_LONG, &long_val,
ATTR_TYPE_STR, ATTR_NAME_STR, str_val,
ATTR_TYPE_DATA, ATTR_NAME_DATA, data_val,
ATTR_TYPE_HASH, table,
ATTR_TYPE_END)) > 4) {
- vstream_printf("%s %d\n", ATTR_NAME_NUM, int_val);
+ vstream_printf("%s %d\n", ATTR_NAME_INT, int_val);
vstream_printf("%s %ld\n", ATTR_NAME_LONG, long_val);
vstream_printf("%s %s\n", ATTR_NAME_STR, STR(str_val));
vstream_printf("%s %s\n", ATTR_NAME_DATA, STR(data_val));
}
if ((ret = attr_scan_plain(VSTREAM_IN,
ATTR_FLAG_STRICT,
- ATTR_TYPE_NUM, ATTR_NAME_NUM, &int_val,
+ ATTR_TYPE_INT, ATTR_NAME_INT, &int_val,
ATTR_TYPE_LONG, ATTR_NAME_LONG, &long_val,
ATTR_TYPE_STR, ATTR_NAME_STR, str_val,
ATTR_TYPE_DATA, ATTR_NAME_DATA, data_val,
ATTR_TYPE_END)) == 4) {
- vstream_printf("%s %d\n", ATTR_NAME_NUM, int_val);
+ vstream_printf("%s %d\n", ATTR_NAME_INT, int_val);
vstream_printf("%s %ld\n", ATTR_NAME_LONG, long_val);
vstream_printf("%s %s\n", ATTR_NAME_STR, STR(str_val));
vstream_printf("%s %s\n", ATTR_NAME_DATA, STR(data_val));
if (vstream_fflush(VSTREAM_OUT) != 0)
msg_fatal("write error: %m");
+ vstring_free(data_val);
vstring_free(str_val);
htable_free(table, myfree);
/* void auto_clnt_recover(auto_clnt)
/* AUTO_CLNT *auto_clnt;
/*
+/* const char *auto_clnt_name(auto_clnt)
+/* AUTO_CLNT *auto_clnt;
+/*
/* void auto_clnt_free(auto_clnt)
/* AUTO_CLNT *auto_clnt;
/* DESCRIPTION
/* auto_clnt_recover() recovers from a server-initiated disconnect
/* that happened in the middle of an I/O operation.
/*
+/* auto_clnt_name() returns the name of the specified client endpoint.
+/*
/* auto_clnt_free() destroys of the specified client endpoint.
/*
/* Arguments:
return (auto_clnt);
}
+/* auto_clnt_name - return client stream name */
+
+const char *auto_clnt_name(AUTO_CLNT *auto_clnt)
+{
+ return (auto_clnt->endpoint);
+}
+
/* auto_clnt_free - destroy client stream instance */
void auto_clnt_free(AUTO_CLNT *auto_clnt)
extern AUTO_CLNT *auto_clnt_create(const char *, int, int, int);
extern VSTREAM *auto_clnt_access(AUTO_CLNT *);
extern void auto_clnt_recover(AUTO_CLNT *);
+extern const char *auto_clnt_name(AUTO_CLNT *);
extern void auto_clnt_free(AUTO_CLNT *);
/* LICENSE
/* void dict_load_fp(dict_name, fp)
/* const char *dict_name;
/* VSTREAM *fp;
+/*
+/* const char *dict_flags_str(dict_flags)
+/* int dict_flags;
/* DESCRIPTION
/* This module maintains a collection of name-value dictionaries.
/* Each dictionary has its own name and has its own methods to read
/*
/* dict_load_fp() reads name-value entries from an open stream.
/* It has the same semantics as the dict_load_file() function.
+/*
+/* dict_flags_str() returns a printable representation of the
+/* specified dictionary flags. The result is overwritten upon
+/* each call.
/* SEE ALSO
/* htable(3)
/* BUGS
#include "mac_expand.h"
#include "stringops.h"
#include "iostuff.h"
+#include "name_mask.h"
#include "dict.h"
#include "dict_ht.h"
{
return (dict_changed_name() != 0);
}
+
+ /*
+ * Mapping between flag names and flag values.
+ */
+static NAME_MASK dict_mask[] = {
+ "warn_dup", (1 << 0), /* if file, warn about dups */
+ "ignore_dup", (1 << 1), /* if file, ignore dups */
+ "try0null", (1 << 2), /* do not append 0 to key/value */
+ "try1null", (1 << 3), /* append 0 to key/value */
+ "fixed", (1 << 4), /* fixed key map */
+ "pattern", (1 << 5), /* keys are patterns */
+ "lock", (1 << 6), /* lock before access */
+ "replace", (1 << 7), /* if file, replace dups */
+ "sync_update", (1 << 8), /* if file, sync updates */
+ "debug", (1 << 9), /* log access */
+ "no_regsub", (1 << 11), /* disallow regexp substitution */
+ "no_proxy", (1 << 12), /* disallow proxy mapping */
+ "no_unauth", (1 << 13), /* disallow unauthenticated data */
+ "fold_fix", (1 << 14), /* case-fold with fixed-case key map */
+ "fold_mul", (1 << 15), /* case-fold with multi-case key map */
+};
+
+/* dict_flags_str - convert mask to string for debugging purposes */
+
+const char *dict_flags_str(int dict_flags)
+{
+ static VSTRING *buf = 0;
+
+ if (buf == 0)
+ buf = vstring_alloc(1);
+
+ return (str_name_mask_opt(buf, "dictionary flags", dict_mask, dict_flags,
+ NAME_MASK_RETURN | NAME_MASK_PIPE));
+}
*/
#include <vstream.h>
#include <argv.h>
+#include <vstring.h>
/*
* Generic dictionary interface - in reality, a dictionary extends this
int lock_fd; /* for dict_update() lock */
int stat_fd; /* change detection */
time_t mtime; /* mod time at open */
+ VSTRING *fold_buf; /* key folding buffer */
} DICT;
extern DICT *dict_alloc(const char *, const char *, ssize_t);
#define DICT_FLAG_DUP_REPLACE (1<<7) /* if file, replace dups */
#define DICT_FLAG_SYNC_UPDATE (1<<8) /* if file, sync updates */
#define DICT_FLAG_DEBUG (1<<9) /* log access */
-#define DICT_FLAG_FOLD_KEY (1<<10) /* lowercase the lookup key */
+/*#define DICT_FLAG_FOLD_KEY (1<<10) /* lowercase the lookup key */
#define DICT_FLAG_NO_REGSUB (1<<11) /* disallow regexp substitution */
#define DICT_FLAG_NO_PROXY (1<<12) /* disallow proxy mapping */
#define DICT_FLAG_NO_UNAUTH (1<<13) /* disallow unauthenticated data */
+#define DICT_FLAG_FOLD_FIX (1<<14) /* case-fold key with fixed-case map */
+#define DICT_FLAG_FOLD_MUL (1<<15) /* case-fold key with multi-case map */
+#define DICT_FLAG_FOLD_ANY (DICT_FLAG_FOLD_FIX | DICT_FLAG_FOLD_MUL)
+
+ /* IMPORTANT: Update the dict_mask[] table when the above changes */
#define DICT_FLAG_PARANOID \
(DICT_FLAG_NO_REGSUB | DICT_FLAG_NO_PROXY | DICT_FLAG_NO_UNAUTH)
extern void dict_walk(DICT_WALK_ACTION, char *);
extern int dict_changed(void);
extern const char *dict_changed_name(void);
+extern const char *dict_flags_str(int);
/* LICENSE
/* .ad
static void dict_default_close(DICT *dict)
{
msg_fatal("%s table %s: close operation is not supported",
- dict->type, dict->name);
+ dict->type, dict->name);
}
/* dict_alloc - allocate dictionary object, initialize super-class */
dict->lock_fd = -1;
dict->stat_fd = -1;
dict->mtime = 0;
+ dict->fold_buf = 0;
return dict;
}
#include "stringops.h"
#include "iostuff.h"
#include "myflock.h"
+#include "stringops.h"
#include "dict.h"
#include "dict_cdb.h"
/* CDB is constant, so do not try to acquire a lock. */
+ /*
+ * Optionally fold the key.
+ */
+ if (dict->fold_buf) {
+ vstring_strcpy(dict->fold_buf, name);
+ name = lowercase(vstring_str(dict->fold_buf));
+ }
+
/*
* See if this CDB file was written with one null byte appended to key
* and value.
cdb_free(&dict_cdbq->cdb);
close(dict->stat_fd);
+ if (dict->fold_buf)
+ vstring_free(dict->fold_buf);
dict_free(dict);
}
if ((dict_flags & (DICT_FLAG_TRY1NULL | DICT_FLAG_TRY0NULL)) == 0)
dict_flags |= DICT_FLAG_TRY0NULL | DICT_FLAG_TRY1NULL;
dict_cdbq->dict.flags = dict_flags | DICT_FLAG_FIXED;
+ if (dict_flags & DICT_FLAG_FOLD_FIX)
+ dict_cdbq->dict.fold_buf = vstring_alloc(10);
myfree(cdb_path);
return (&dict_cdbq->dict);
unsigned ksize, vsize;
int r;
+ /*
+ * Optionally fold the key.
+ */
+ if (dict->fold_buf) {
+ vstring_strcpy(dict->fold_buf, name);
+ name = lowercase(vstring_str(dict->fold_buf));
+ }
+
ksize = strlen(name);
vsize = strlen(value);
msg_fatal("close database %s: %m", dict_cdbm->cdb_path);
myfree(dict_cdbm->cdb_path);
myfree(dict_cdbm->tmp_path);
+ if (dict->fold_buf)
+ vstring_free(dict->fold_buf);
dict_free(dict);
}
&& (dict_flags & DICT_FLAG_TRY0NULL))
dict_flags &= ~DICT_FLAG_TRY0NULL;
dict_cdbm->dict.flags = dict_flags | DICT_FLAG_FIXED;
+ if (dict_flags & DICT_FLAG_FOLD_FIX)
+ dict_cdbm->dict.fold_buf = vstring_alloc(10);
return (&dict_cdbm->dict);
}
memset(&db_key, 0, sizeof(db_key));
memset(&db_value, 0, sizeof(db_value));
+ /*
+ * Optionally fold the key.
+ */
+ if (dict->fold_buf) {
+ vstring_strcpy(dict->fold_buf, name);
+ name = lowercase(vstring_str(dict->fold_buf));
+ }
+
/*
* Acquire a shared lock.
*/
if ((dict->flags & (DICT_FLAG_TRY1NULL | DICT_FLAG_TRY0NULL)) == 0)
msg_panic("dict_db_update: no DICT_FLAG_TRY1NULL | DICT_FLAG_TRY0NULL flag");
+ /*
+ * Optionally fold the key.
+ */
+ if (dict->fold_buf) {
+ vstring_strcpy(dict->fold_buf, name);
+ name = lowercase(vstring_str(dict->fold_buf));
+ }
+
memset(&db_key, 0, sizeof(db_key));
memset(&db_value, 0, sizeof(db_value));
db_key.data = (void *) name;
if ((dict->flags & (DICT_FLAG_TRY1NULL | DICT_FLAG_TRY0NULL)) == 0)
msg_panic("dict_db_delete: no DICT_FLAG_TRY1NULL | DICT_FLAG_TRY0NULL flag");
+ /*
+ * Optionally fold the key.
+ */
+ if (dict->fold_buf) {
+ vstring_strcpy(dict->fold_buf, name);
+ name = lowercase(vstring_str(dict->fold_buf));
+ }
+
memset(&db_key, 0, sizeof(db_key));
/*
vstring_free(dict_db->key_buf);
if (dict_db->val_buf)
vstring_free(dict_db->val_buf);
+ if (dict->fold_buf)
+ vstring_free(dict->fold_buf);
dict_free(dict);
}
dict_db->dict.flags = dict_flags | DICT_FLAG_FIXED;
if ((dict_flags & (DICT_FLAG_TRY1NULL | DICT_FLAG_TRY0NULL)) == 0)
dict_db->dict.flags |= (DICT_FLAG_TRY1NULL | DICT_FLAG_TRY0NULL);
+ if (dict_flags & DICT_FLAG_FOLD_FIX)
+ dict_db->dict.fold_buf = vstring_alloc(10);
dict_db->db = db;
#if DB_VERSION_MAJOR > 1
dict_db->cursor = 0;
dict_errno = 0;
+ /*
+ * Optionally fold the key.
+ */
+ if (dict->fold_buf) {
+ vstring_strcpy(dict->fold_buf, name);
+ name = lowercase(vstring_str(dict->fold_buf));
+ }
+
/*
* Acquire an exclusive lock.
*/
if ((dict->flags & (DICT_FLAG_TRY1NULL | DICT_FLAG_TRY0NULL)) == 0)
msg_panic("dict_dbm_update: no DICT_FLAG_TRY1NULL | DICT_FLAG_TRY0NULL flag");
+ /*
+ * Optionally fold the key.
+ */
+ if (dict->fold_buf) {
+ vstring_strcpy(dict->fold_buf, name);
+ name = lowercase(vstring_str(dict->fold_buf));
+ }
+
dbm_key.dptr = (void *) name;
dbm_value.dptr = (void *) value;
dbm_key.dsize = strlen(name);
if ((dict->flags & (DICT_FLAG_TRY1NULL | DICT_FLAG_TRY0NULL)) == 0)
msg_panic("dict_dbm_delete: no DICT_FLAG_TRY1NULL | DICT_FLAG_TRY0NULL flag");
+ /*
+ * Optionally fold the key.
+ */
+ if (dict->fold_buf) {
+ vstring_strcpy(dict->fold_buf, name);
+ name = lowercase(vstring_str(dict->fold_buf));
+ }
+
/*
* Acquire an exclusive lock.
*/
vstring_free(dict_dbm->key_buf);
if (dict_dbm->val_buf)
vstring_free(dict_dbm->val_buf);
+ if (dict->fold_buf)
+ vstring_free(dict->fold_buf);
dict_free(dict);
}
dict_dbm->dict.flags = dict_flags | DICT_FLAG_FIXED;
if ((dict_flags & (DICT_FLAG_TRY0NULL | DICT_FLAG_TRY1NULL)) == 0)
dict_dbm->dict.flags |= (DICT_FLAG_TRY0NULL | DICT_FLAG_TRY1NULL);
+ if (dict_flags & DICT_FLAG_FOLD_FIX)
+ dict_dbm->dict.fold_buf = vstring_alloc(10);
dict_dbm->dbm = dbm;
dict_dbm->key_buf = 0;
dict_dbm->val_buf = 0;
#include "mymalloc.h"
#include "msg.h"
#include "safe.h"
+#include "stringops.h"
#include "dict.h"
#include "dict_env.h"
/* dict_env_update - update environment array */
-static void dict_env_update(DICT *unused_dict, const char *name, const char *value)
+static void dict_env_update(DICT *dict, const char *name, const char *value)
{
+
+ /*
+ * Optionally fold the key.
+ */
+ if (dict->fold_buf) {
+ vstring_strcpy(dict->fold_buf, name);
+ name = lowercase(vstring_str(dict->fold_buf));
+ }
if (setenv(name, value, 1))
msg_fatal("setenv: %m");
}
/* dict_env_lookup - access environment array */
-static const char *dict_env_lookup(DICT *unused_dict, const char *name)
+static const char *dict_env_lookup(DICT *dict, const char *name)
{
dict_errno = 0;
+ /*
+ * Optionally fold the key.
+ */
+ if (dict->fold_buf) {
+ vstring_strcpy(dict->fold_buf, name);
+ name = lowercase(vstring_str(dict->fold_buf));
+ }
return (safe_getenv(name));
}
static void dict_env_close(DICT *dict)
{
+ if (dict->fold_buf)
+ vstring_free(dict->fold_buf);
dict_free(dict);
}
dict->update = dict_env_update;
dict->close = dict_env_close;
dict->flags = dict_flags | DICT_FLAG_FIXED;
- return (DICT_DEBUG(dict));
+ if (dict_flags & DICT_FLAG_FOLD_FIX)
+ dict->fold_buf = vstring_alloc(10);
+ return (DICT_DEBUG (dict));
}
#include "dict_ni.h"
#include "msg.h"
#include "mymalloc.h"
+#include "stringops.h"
typedef struct {
DICT dict; /* my super */
{
DICT_NI *d = (DICT_NI *) dict;
+ /*
+ * Optionally fold the key.
+ */
+ if (dict->fold_buf) {
+ vstring_strcpy(dict->fold_buf, key);
+ key = lowercase(vstring_str(dict->fold_buf));
+ }
return dict_ni_do_lookup(d->dict.name, NETINFO_PROP_KEY,
key, NETINFO_PROP_VALUE);
}
{
DICT_NI *d = (DICT_NI *) dict;
+ if (dict->fold_buf)
+ vstring_free(dict->fold_buf);
dict_free(dict);
}
d->dict.lookup = dict_ni_lookup;
d->dict.close = dict_ni_close;
d->dict.flags = dict_flags | DICT_FLAG_FIXED;
+ if (dict_flags & DICT_FLAG_FOLD_FIX)
+ d->dict.fold_buf = vstring_alloc(10);
return (DICT_DEBUG (&d->dict));
}
#include "msg.h"
#include "mymalloc.h"
#include "vstring.h"
+#include "stringops.h"
#include "dict.h"
#include "dict_nis.h"
if (dict_nis_domain == dict_nis_disabled)
return (0);
+ /*
+ * Optionally fold the key.
+ */
+ if (dict->fold_buf) {
+ vstring_strcpy(dict->fold_buf, key);
+ key = lowercase(vstring_str(dict->fold_buf));
+ }
+
/*
* See if this NIS map was written with one null byte appended to key and
* value.
static void dict_nis_close(DICT *dict)
{
+ if (dict->fold_buf)
+ vstring_free(dict->fold_buf);
dict_free(dict);
}
dict_nis->dict.flags = dict_flags | DICT_FLAG_FIXED;
if ((dict_flags & (DICT_FLAG_TRY1NULL | DICT_FLAG_TRY0NULL)) == 0)
dict_nis->dict.flags |= (DICT_FLAG_TRY1NULL | DICT_FLAG_TRY0NULL);
+ if (dict_flags & DICT_FLAG_FOLD_FIX)
+ dict_nis->dict.fold_buf = vstring_alloc(10);
if (dict_nis_domain == 0)
dict_nis_init();
return (DICT_DEBUG (&dict_nis->dict));
quoted_key = vstring_alloc(100);
}
+ /*
+ * Optionally fold the key.
+ */
+ if (dict->fold_buf) {
+ vstring_strcpy(dict->fold_buf, key);
+ key = lowercase(vstring_str(dict->fold_buf));
+ }
+
/*
* Check that the lookup key does not contain characters disallowed by
* nis+(1).
DICT_NISPLUS *dict_nisplus = (DICT_NISPLUS *) dict;
myfree(dict_nisplus->template);
+ if (dict->fold_buf)
+ vstring_free(dict->fold_buf);
dict_free(dict);
}
dict_nisplus->dict.lookup = dict_nisplus_lookup;
dict_nisplus->dict.close = dict_nisplus_close;
dict_nisplus->dict.flags = dict_flags | DICT_FLAG_FIXED;
+ if (dict_flags & DICT_FLAG_FOLD_FIX)
+ dict_nisplus->dict.fold_buf = vstring_alloc(10);
/*
* Convert the query template into an indexed name and column number. The
/* .IP DICT_FLAG_LOCK
/* With maps where this is appropriate, acquire an exclusive lock
/* before writing, and acquire a shared lock before reading.
+/* .IP DICT_FLAG_FOLD_FIX
+/* With databases whose lookup fields are fixed-case strings,
+/* fold the search key to lower case before accessing the
+/* database. This includes hash:, cdb:, dbm:. nis:, ldap:,
+/* *sql.
+/* .IP DICT_FLAG_FOLD_MUL
+/* With databases where one lookup field can match both upper
+/* and lower case, fold the search key to lower case before
+/* accessing the database. This includes regexp: and pcre:
+/* .IP DICT_FLAG_FOLD_ANY
+/* Short-hand for (DICT_FLAG_FOLD_FIX | DICT_FLAG_FOLD_MUL).
/* .IP DICT_FLAG_SYNC_UPDATE
/* With file-based maps, flush I/O buffers to file after each update.
/* Thus feature is not supported with some file-based dictionaries.
static NORETURN usage(char *myname)
{
- msg_fatal("usage: %s type:file read|write|create", myname);
+ msg_fatal("usage: %s type:file read|write|create [fold]", myname);
}
int main(int argc, char **argv)
const char *key;
const char *value;
int ch;
+ int dict_flags = DICT_FLAG_LOCK | DICT_FLAG_DUP_REPLACE;
signal(SIGPIPE, SIG_IGN);
}
}
optind = OPTIND;
- if (argc - optind != 2)
+ if (argc - optind < 2 || argc - optind > 3)
usage(argv[0]);
if (strcasecmp(argv[optind + 1], "create") == 0)
open_flags = O_CREAT | O_RDWR | O_TRUNC;
open_flags = O_RDONLY;
else
msg_fatal("unknown access mode: %s", argv[2]);
+ if (argv[optind + 2] && strcasecmp(argv[optind + 2], "fold") == 0)
+ dict_flags |= DICT_FLAG_FOLD_ANY;
dict_name = argv[optind];
- dict = dict_open(dict_name, open_flags, DICT_FLAG_LOCK | DICT_FLAG_DUP_REPLACE);
+ 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);
dict_pcre->dict.name, match_rule->rule.lineno);
else
msg_fatal("regexp %s, line %d: pcre_get_substring error: %d",
- dict_pcre->dict.name, match_rule->rule.lineno, ret);
+ dict_pcre->dict.name, match_rule->rule.lineno, ret);
}
if (*pp == 0) {
myfree((char *) pp);
static void dict_pcre_exec_error(const char *mapname, int lineno, int errval)
{
switch (errval) {
- case 0:
+ case 0:
msg_warn("pcre map %s, line %d: too many (...)",
mapname, lineno);
return;
if (msg_verbose)
msg_info("dict_pcre_lookup: %s: %s", dict->name, lookup_string);
+ /*
+ * Optionally fold the key.
+ */
+ if (dict->fold_buf) {
+ vstring_strcpy(dict->fold_buf, lookup_string);
+ lookup_string = lowercase(vstring_str(dict->fold_buf));
+ }
for (rule = dict_pcre->head; rule; rule = rule->next) {
/*
}
if (dict_pcre->expansion_buf)
vstring_free(dict_pcre->expansion_buf);
+ if (dict->fold_buf)
+ vstring_free(dict->fold_buf);
dict_free(dict);
}
sizeof(DICT_PCRE_MATCH_RULE));
match_rule->match = regexp.match;
match_rule->max_sub = prescan_context.max_sub;
- if (prescan_context.literal)
- match_rule->replacement = prescan_context.literal;
- else
+ if (prescan_context.literal)
+ match_rule->replacement = prescan_context.literal;
+ else
match_rule->replacement = mystrdup(p);
match_rule->pattern = engine.pattern;
match_rule->hints = engine.hints;
dict_pcre->dict.lookup = dict_pcre_lookup;
dict_pcre->dict.close = dict_pcre_close;
dict_pcre->dict.flags = dict_flags | DICT_FLAG_PATTERN;
+ if (dict_flags & DICT_FLAG_FOLD_MUL)
+ dict_pcre->dict.fold_buf = vstring_alloc(10);
dict_pcre->head = 0;
dict_pcre->expansion_buf = 0;
if (msg_verbose)
msg_info("dict_regexp_lookup: %s: %s", dict->name, lookup_string);
+ /*
+ * Optionally fold the key.
+ */
+ if (dict->fold_buf) {
+ vstring_strcpy(dict->fold_buf, lookup_string);
+ lookup_string = lowercase(vstring_str(dict->fold_buf));
+ }
for (rule = dict_regexp->head; rule; rule = rule->next) {
/*
myfree((char *) dict_regexp->pmatch);
if (dict_regexp->expansion_buf)
vstring_free(dict_regexp->expansion_buf);
+ if (dict->fold_buf)
+ vstring_free(dict->fold_buf);
dict_free(dict);
}
* result string, or when the highest numbered substring is less than
* the total number of () subpatterns.
*/
- if (prescan_context.max_sub == 0)
+ if (prescan_context.max_sub == 0)
first_pat.options |= REG_NOSUB;
if (prescan_context.max_sub > 0 && first_pat.match == 0) {
msg_warn("regexp map %s, line %d: $number found in negative match "
"replacement text: skipping this rule", mapname, lineno);
CREATE_MATCHOP_ERROR_RETURN(0);
- }
+ }
if (prescan_context.max_sub > 0 && (dict_flags & DICT_FLAG_NO_REGSUB)) {
msg_warn("regexp map %s, line %d: "
"regular expression substitution is not allowed: "
dict_regexp->dict.lookup = dict_regexp_lookup;
dict_regexp->dict.close = dict_regexp_close;
dict_regexp->dict.flags = dict_flags | DICT_FLAG_PATTERN;
+ if (dict_flags & DICT_FLAG_FOLD_MUL)
+ dict_regexp->dict.fold_buf = vstring_alloc(10);
dict_regexp->head = 0;
dict_regexp->pmatch = 0;
dict_regexp->expansion_buf = 0;
dict_errno = 0;
+ /*
+ * Optionally fold the key.
+ */
+ if (dict->fold_buf) {
+ vstring_strcpy(dict->fold_buf, name);
+ name = lowercase(vstring_str(dict->fold_buf));
+ }
+
/*
* Acquire an exclusive lock.
*/
if ((dict->flags & (DICT_FLAG_TRY1NULL | DICT_FLAG_TRY0NULL)) == 0)
msg_panic("dict_sdbm_update: no DICT_FLAG_TRY1NULL | DICT_FLAG_TRY0NULL flag");
+ /*
+ * Optionally fold the key.
+ */
+ if (dict->fold_buf) {
+ vstring_strcpy(dict->fold_buf, name);
+ name = lowercase(vstring_str(dict->fold_buf));
+ }
+
dbm_key.dptr = (void *) name;
dbm_value.dptr = (void *) value;
dbm_key.dsize = strlen(name);
if ((dict->flags & (DICT_FLAG_TRY1NULL | DICT_FLAG_TRY0NULL)) == 0)
msg_panic("dict_sdbm_delete: no DICT_FLAG_TRY1NULL | DICT_FLAG_TRY0NULL flag");
+ /*
+ * Optionally fold the key.
+ */
+ if (dict->fold_buf) {
+ vstring_strcpy(dict->fold_buf, name);
+ name = lowercase(vstring_str(dict->fold_buf));
+ }
+
/*
* Acquire an exclusive lock.
*/
vstring_free(dict_sdbm->key_buf);
if (dict_sdbm->val_buf)
vstring_free(dict_sdbm->val_buf);
+ if (dict->fold_buf)
+ vstring_free(dict->fold_buf);
dict_free(dict);
}
dict_sdbm->dict.flags = dict_flags | DICT_FLAG_FIXED;
if ((dict_flags & (DICT_FLAG_TRY0NULL | DICT_FLAG_TRY1NULL)) == 0)
dict_sdbm->dict.flags |= (DICT_FLAG_TRY0NULL | DICT_FLAG_TRY1NULL);
+ if (dict_flags & DICT_FLAG_FOLD_FIX)
+ dict_sdbm->dict.fold_buf = vstring_alloc(10);
dict_sdbm->dbm = dbm;
dict_sdbm->key_buf = 0;
dict_sdbm->val_buf = 0;
if (msg_verbose)
msg_info("%s: key %s", myname, key);
+ /*
+ * Optionally fold the key.
+ */
+ if (dict->fold_buf) {
+ vstring_strcpy(dict->fold_buf, key);
+ key = lowercase(vstring_str(dict->fold_buf));
+ }
for (tries = 0; /* see below */ ; /* see below */ ) {
/*
vstring_free(dict_tcp->raw_buf);
if (dict_tcp->hex_buf)
vstring_free(dict_tcp->hex_buf);
+ if (dict->fold_buf)
+ vstring_free(dict->fold_buf);
dict_free(dict);
}
dict_tcp->dict.lookup = dict_tcp_lookup;
dict_tcp->dict.close = dict_tcp_close;
dict_tcp->dict.flags = dict_flags | DICT_FLAG_PATTERN;
+ if (dict_flags & DICT_FLAG_FOLD_MUL)
+ dict_tcp->dict.fold_buf = vstring_alloc(10);
return (DICT_DEBUG (&dict_tcp->dict));
}
#include "msg.h"
#include "mymalloc.h"
#include "vstring.h"
+#include "stringops.h"
#include "dict.h"
#include "dict_unix.h"
/* dict_unix_getpwnam - find password table entry */
-static const char *dict_unix_getpwnam(DICT *unused_dict, const char *key)
+static const char *dict_unix_getpwnam(DICT *dict, const char *key)
{
struct passwd *pwd;
static VSTRING *buf;
dict_errno = 0;
+ /*
+ * Optionally fold the key.
+ */
+ if (dict->fold_buf) {
+ vstring_strcpy(dict->fold_buf, key);
+ key = lowercase(vstring_str(dict->fold_buf));
+ }
if ((pwd = getpwnam(key)) == 0) {
if (sanity_checked == 0) {
sanity_checked = 1;
/* dict_unix_getgrnam - find group table entry */
-static const char *dict_unix_getgrnam(DICT *unused_dict, const char *key)
+static const char *dict_unix_getgrnam(DICT *dict, const char *key)
{
struct group *grp;
static VSTRING *buf;
dict_errno = 0;
+ /*
+ * Optionally fold the key.
+ */
+ if (dict->fold_buf) {
+ vstring_strcpy(dict->fold_buf, key);
+ key = lowercase(vstring_str(dict->fold_buf));
+ }
if ((grp = getgrnam(key)) == 0) {
if (sanity_checked == 0) {
sanity_checked = 1;
static void dict_unix_close(DICT *dict)
{
+ if (dict->fold_buf)
+ vstring_free(dict->fold_buf);
dict_free(dict);
}
dict_unix->dict.lookup = lp->lookup;
dict_unix->dict.close = dict_unix_close;
dict_unix->dict.flags = dict_flags | DICT_FLAG_FIXED;
+ if (dict_flags & DICT_FLAG_FOLD_FIX)
+ dict_unix->dict.fold_buf = vstring_alloc(10);
+
return (DICT_DEBUG (&dict_unix->dict));
}
htable_delete(hash, ht[0]->key, (void (*) (char *)) 0);
if (hash->used > 0)
msg_panic("%d entries not deleted", hash->used);
+ myfree((char *) ht_info);
+ htable_free(hash, (void (*) (char *)) 0);
+ vstring_free(buf);
return (0);
}
if (buf == 0)
buf = vstring_alloc(10);
#define OPEN_FLAGS O_RDONLY
-#define DICT_FLAGS DICT_FLAG_LOCK
+#define DICT_FLAGS (DICT_FLAG_LOCK | DICT_FLAG_FOLD_FIX)
#define STR(x) vstring_str(x)
for (map_type_name = pattern; *map_type_name == '!'; map_type_name++)
/* void */ ;
- vstring_sprintf(buf, "%s(%o,%o)", pattern, OPEN_FLAGS, DICT_FLAGS);
+ vstring_sprintf(buf, "%s(%o,%s)", pattern, OPEN_FLAGS,
+ dict_flags_str(DICT_FLAGS));
map_type_name_flags = STR(buf) + (map_type_name - pattern);
if (dict_handle(map_type_name_flags) == 0)
dict_register(map_type_name_flags,
{
char *myname = "match_string";
int match;
- char *key;
if (msg_verbose)
msg_info("%s: %s ~? %s", myname, string, pattern);
* Try dictionary lookup: exact match.
*/
if (MATCH_DICTIONARY(pattern)) {
- key = lowercase(mystrdup(string));
- match = (dict_lookup(pattern, key) != 0);
- myfree(key);
+ match = (dict_lookup(pattern, string) != 0);
if (match != 0)
return (1);
if (dict_errno != 0)
char *myname = "match_hostname";
const char *pd;
const char *entry;
- char *next;
- char *temp;
+ const char *next;
int match;
+ DICT *dict;
if (msg_verbose)
msg_info("%s: %s ~? %s", myname, name, pattern);
/*
* Try dictionary lookup: exact match and parent domains.
+ *
+ * Don't look up parent domain substrings with regexp maps etc.
*/
if (MATCH_DICTIONARY(pattern)) {
- temp = lowercase(mystrdup(name));
+ if ((dict = dict_handle(pattern)) == 0)
+ msg_panic("%s: unknown dictionary: %s", myname, pattern);
match = 0;
- for (entry = temp; *entry != 0; entry = next) {
- if ((match = (dict_lookup(pattern, entry) != 0)) != 0)
- break;
- if (dict_errno != 0)
- msg_fatal("%s: table lookup problem", pattern);
+ for (entry = name; *entry != 0; entry = next) {
+ if (entry == name || (dict->flags & DICT_FLAG_FIXED)) {
+ match = (dict_get(dict, entry) != 0);
+ if (msg_verbose > 1)
+ msg_info("%s: lookup %s:%s %s: %s",
+ myname, dict->type, dict->name, entry,
+ match ? "found" : "notfound");
+ if (match != 0)
+ break;
+ if (dict_errno != 0)
+ msg_fatal("%s: table lookup problem", pattern);
+ }
if ((next = strchr(entry + 1, '.')) == 0)
break;
if (flags & MATCH_FLAG_PARENT)
next += 1;
}
- myfree(temp);
return (match);
}
./myaddrinfo: === hostname belly.porcupine.org ===
-./myaddrinfo: belly.porcupine.org -> family=28 sock=1 proto=6 2001:240:5c7:0:250:56ff:fe10:bd03
-./myaddrinfo: 2001:240:5c7:0:250:56ff:fe10:bd03 -> belly.porcupine.org
+./myaddrinfo: belly.porcupine.org -> family=28 sock=1 proto=6 2001:240:587:0:250:56ff:fe10:bd03
+./myaddrinfo: 2001:240:587:0:250:56ff:fe10:bd03 -> belly.porcupine.org
./myaddrinfo: belly.porcupine.org -> family=2 sock=1 proto=6 168.100.189.6
./myaddrinfo: 168.100.189.6 -> belly.porcupine.org
./myaddrinfo: === host address 168.100.189.2 ===
/* const char *names;
/* int flags;
/*
-/* const char *str_name_mask_opt(context, table, mask, flags)
+/* const char *str_name_mask_opt(buf, context, table, mask, flags)
+/* VSTRING *buf;
/* const char *context;
/* NAME_MASK *table;
/* int mask;
/* with additional fine control.
/*
/* Arguments:
+/* .IP buf
+/* Null pointer or pointer to buffer storage.
/* .IP context
/* What kind of names and
/* masks are being manipulated, in order to make error messages
/* it has no effect with str_name_mask().
/* .IP NAME_MASK_COMMA
/* Use comma instead of space when converting a mask to string.
+/* .IP NAME_MASK_PIPE
+/* Use "|" instead of space when converting a mask to string.
/* .RE
/* The value NAME_MASK_NONE explicitly requests no features,
/* and NAME_MASK_DEFAULT enables the default options.
/* str_name_mask_opt - mask to string */
-const char *str_name_mask_opt(const char *context, NAME_MASK *table,
+const char *str_name_mask_opt(VSTRING *buf, const char *context,
+ NAME_MASK *table,
int mask, int flags)
{
char *myname = "name_mask";
NAME_MASK *np;
int len;
- static VSTRING *buf = 0;
- int delim = (flags & NAME_MASK_COMMA ? ',' : ' ');
-
- if (buf == 0)
- buf = vstring_alloc(1);
-
+ static VSTRING *my_buf = 0;
+ int delim = (flags & NAME_MASK_COMMA ? ',' :
+ (flags & NAME_MASK_PIPE ? '|' : ' '));
+
+ if (buf == 0) {
+ if (my_buf == 0)
+ my_buf = vstring_alloc(1);
+ buf = my_buf;
+ }
VSTRING_RESET(buf);
for (np = table; mask != 0; np++) {
while (--argc && *++argv) {
mask = name_mask("test", table, *argv);
vstream_printf("%s -> 0x%x -> %s\n",
- *argv, mask, str_name_mask("mask_test", table, mask));
+ *argv, mask, str_name_mask((VSTRING *) 0, "mask_test",
+ table, mask));
vstream_fflush(VSTREAM_OUT);
}
vstring_free(buf);
/* DESCRIPTION
/* .nf
+ /*
+ * Utility library.
+ */
+#include <vstring.h>
+
/*
* External interface.
*/
#define NAME_MASK_ANY_CASE (1<<1)
#define NAME_MASK_RETURN (1<<2)
#define NAME_MASK_COMMA (1<<3)
+#define NAME_MASK_PIPE (1<<4)
#define NAME_MASK_MATCH_REQ NAME_MASK_FATAL
#define name_mask(tag, table, str) \
name_mask_opt((tag), (table), (str), NAME_MASK_DEFAULT)
#define str_name_mask(tag, table, mask) \
- str_name_mask_opt((tag), (table), (mask), NAME_MASK_DEFAULT)
+ str_name_mask_opt(((VSTRING *) 0), (tag), (table), (mask), NAME_MASK_DEFAULT)
extern int name_mask_opt(const char *, NAME_MASK *, const char *, int);
-extern const char *str_name_mask_opt(const char *, NAME_MASK *, int, int);
+extern const char *str_name_mask_opt(VSTRING *, const char *, NAME_MASK *, int, int);
/* LICENSE
/* .ad
VSTRING *out = vstring_alloc(10);
int un_escape = 1;
- if (argc > 2 || (un_escape = strcmp(argv[1], "-e")) != 0)
+ if (argc > 2 || (argc > 1 && (un_escape = strcmp(argv[1], "-e"))) != 0)
msg_fatal("usage: %s [-e (escape)]", argv[0]);
if (un_escape) {
if (attr_scan(client_stream, ATTR_FLAG_STRICT,
ATTR_TYPE_STR, MAIL_ATTR_ADDR, addr,
- ATTR_TYPE_NUM, MAIL_ATTR_ADDR_STATUS, &addr_status,
+ ATTR_TYPE_INT, MAIL_ATTR_ADDR_STATUS, &addr_status,
ATTR_TYPE_STR, MAIL_ATTR_WHY, text,
ATTR_TYPE_END) == 3) {
/* FIX 200501 IPv6 patch did not neuter ":" in address literals. */
msg_warn("bad recipient status %d for recipient %s",
addr_status, STR(addr));
attr_print(client_stream, ATTR_FLAG_NONE,
- ATTR_TYPE_NUM, MAIL_ATTR_STATUS, VRFY_STAT_BAD,
+ ATTR_TYPE_INT, MAIL_ATTR_STATUS, VRFY_STAT_BAD,
ATTR_TYPE_END);
} else {
dict_put(verify_map, STR(addr), STR(buf));
}
attr_print(client_stream, ATTR_FLAG_NONE,
- ATTR_TYPE_NUM, MAIL_ATTR_STATUS, VRFY_STAT_OK,
+ ATTR_TYPE_INT, MAIL_ATTR_STATUS, VRFY_STAT_OK,
ATTR_TYPE_END);
}
}
* Respond to the client.
*/
attr_print(client_stream, ATTR_FLAG_NONE,
- ATTR_TYPE_NUM, MAIL_ATTR_STATUS, VRFY_STAT_OK,
- ATTR_TYPE_NUM, MAIL_ATTR_ADDR_STATUS, addr_status,
+ ATTR_TYPE_INT, MAIL_ATTR_STATUS, VRFY_STAT_OK,
+ ATTR_TYPE_INT, MAIL_ATTR_ADDR_STATUS, addr_status,
ATTR_TYPE_STR, MAIL_ATTR_WHY, text,
ATTR_TYPE_END);
} else {
msg_warn("unrecognized request: \"%s\", ignored", STR(request));
attr_print(client_stream, ATTR_FLAG_NONE,
- ATTR_TYPE_NUM, MAIL_ATTR_STATUS, VRFY_STAT_BAD,
+ ATTR_TYPE_INT, MAIL_ATTR_STATUS, VRFY_STAT_BAD,
ATTR_TYPE_END);
}
}
/* Postfix is final destination for the specified list of domains;
/* mail is delivered via the $virtual_transport mail delivery transport.
/* .IP "\fBvirtual_transport (virtual)\fR"
-/* The default mail delivery transport for domains that match the
-/* $virtual_mailbox_domains parameter value.
+/* The default mail delivery transport and next-hop destination for
+/* final delivery to domains listed with $virtual_mailbox_domains.
/* LOCKING CONTROLS
/* .ad
/* .fi
*/
set_eugid(var_owner_uid, var_owner_gid);
+ /*
+ * No case folding needed: the recipient address is case folded.
+ */
virtual_mailbox_maps =
maps_create(VAR_VIRT_MAILBOX_MAPS, var_virt_mailbox_maps,
DICT_FLAG_LOCK | DICT_FLAG_PARANOID);
xsasl_cyrus_log.o: xsasl_cyrus_log.c
xsasl_cyrus_security.o: ../../include/name_mask.h
xsasl_cyrus_security.o: ../../include/sys_defs.h
+xsasl_cyrus_security.o: ../../include/vbuf.h
+xsasl_cyrus_security.o: ../../include/vstring.h
xsasl_cyrus_security.o: xsasl_cyrus_common.h
xsasl_cyrus_security.o: xsasl_cyrus_security.c
xsasl_cyrus_server.o: ../../include/argv.h