-TMKMAP_DB
-TMKMAP_DBM
-TMKMAP_OPEN_INFO
+-TMKMAP_SDBM
-TMSG_STATS
-TMULTI_SERVER
-TMVECT
-TOPTIONS
-TPC_DBMS_INFO
-TPC_EVAL_CTX
+-TPC_MASTER_EDIT_REQ
-TPC_MASTER_ENT
+-TPC_MASTER_FIELD_REQ
-TPC_PARAM_CTX
-TPC_PARAM_NODE
+-TPC_PARAM_TABLE
-TPC_SERVICE_DEF
+-TPC_SERVICE_PATTERN
-TPC_STRING_NV
-TPEER_NAME
-TPGSQL_NAME
-TXSASL_CLIENT_CREATE_ARGS
-TXSASL_CLIENT_IMPL
-TXSASL_CLIENT_IMPL_INFO
+-TXSASL_CYRUS_CB
-TXSASL_CYRUS_CLIENT
-TXSASL_CYRUS_ERROR_INFO
-TXSASL_CYRUS_SERVER
-TXSASL_SERVER_CREATE_ARGS
-TXSASL_SERVER_IMPL
-TXSASL_SERVER_IMPL_INFO
+-Tbind_props
-Tcipher_probe_t
+-Tdane_digest
+-Tfilter_ctx
-Tgeneral_name_stack_t
+-Tiana_digest
-Toff_t
-Tregex_t
-Tregmatch_t
-Tsasl_conn_t
-Tsasl_secret_t
-Tsfsistat
+-Tsigset_t
-Tsize_t
-Tssize_t
-Tssl_cipher_stack_t
-Tssl_comp_stack_t
-Ttime_t
+-Ttlsa_filter
-Tx509_extension_stack_t
-Tx509_stack_t
Factor out the master.cf line parser so that it can be
reused for "postconf -Me". File: postconf/postconf_master.c.
+20130113
+
+ Feature: master.cf attribute namespace. "postconf -F" shows
+ individual master.cf fields as "service/type/attribute =
+ value", where attribute is "service", "type", "private",
+ "unprivileged", "wakeup", "process_limit", or "command".
+
20130121
Bugfix (introduced 20120307): the postconf -X option erased
cleanup/cleanup_milter.c, cleanup/cleanup_state.c,
global/xtext.c, global/xtext.h, milter/test-milter.c.
+20131122
+
+ Feature: "postcon -Fe service/type/attribute = value" edits
+ master.cf attribute values. The -e is optional. Example:
+ use "postconf -F "*/*/chroot = n" to turn off chroot on all
+ master.cf services. Files: postconf/postconf.h,
+ postconf/postconf.c, postconf/postcof_master.c,
+ postconf/postconf_edit.c.
+
20131124
Cleanup: remove extra blank line from ccformat output,
making it compatible with the script that Wietse actually
uses (this line was part of a test to detect file truncation,
but it is now obsolete). File: mantools/ccformat.
+
+ Feature: master.cf parameter namespace. "postconf -P" shows
+ master.cf parameter settings as "service/type/parameter =
+ value". This is applicable only to parameter settings in
+ master.cf. Files: postconf/postconf.h, postconf/postconf.c,
+ postconf/postcof_master.c, postconf/postconf_print.c.
+
+ Incompatibility: the master_service_disable syntax has
+ changed: use "service/type" instead of "service.type". The
+ new form is consistent with master.cf parameter namespaces.
+ The old form is still supported to avoid breaking existing
+ configurations. Files: global/master_service.c,
+ master/master_ent.c.
+
+20131125
+
+ Feature: change, add or delete "-o parameter=value" setting
+ in master.cf. Examples: "postconf -P smtp/inet/parameter=value"
+ (add or modify "-o name=value" setting) and "postconf -P
+ smtp/inet/parameter" (delete "-o parameter=value" setting).
+ Files: util/argv.[hc], postconf/postconf.h,
+ postconf/postconf_edit.c, postconf_master.c.
+
+20131126
+
+ Cleanup: Leave SSLv3 enabled with DANE. Viktor Dukhovni.
+ Files: proto/TLS_README.html proto/postconf.proto
+ tls/tls_client.c.
+
+ Cleanup: DANE support: Drop support for usage 0. It SHOULD
+ NOT be supported in DANE with SMTP, and we already don't
+ support digest TLSA RRs in this case, while full content
+ TLSA RRs are not recommended for DNS bloat reasons. Viktor
+ Dukhovni. Files: proto/postconf.proto src/global/mail_params.h
+ src/smtp/smtp.c src/tls/tls_dane.c src/tls/tls_misc.c.
+
+ Feature: TLS support: Support future digest algorithms
+ without re-compilation. Viktor Dukhovni. Files: .indent.pro
+ proto/postconf.proto src/tls/tls_dane.c.
+
+ Feature: DNS support: New configurable digest agility.
+ Viktor Dukhovni. Files: .indent.pro proto/TLS_README.html
+ proto/postconf.proto src/global/mail_params.h src/tls/tls_dane.c
+ src/tls/tls_misc.c.
+
+20131127
+
+ Bugfix (introduced: 20090106): the postconf '-#' option
+ erased prior options. File: postconf/postconf.c.
% c\bca\bat\bt s\bse\ber\brv\bve\ber\br_\b_c\bce\ber\brt\bt.\b.p\bpe\bem\bm i\bin\bnt\bte\ber\brm\bme\bed\bdi\bia\bat\bte\be_\b_C\bCA\bA.\b.p\bpe\bem\bm >\b> s\bse\ber\brv\bve\ber\br.\b.p\bpe\bem\bm
- * If you use RFC 6698 TLSA "2 0 1" or "2 1 1" records to specify root CA
+ * If you publish RFC 6698 TLSA "2 0 1" or "2 1 1" records to specify root CA
certificate digests, you must include the corresponding root CA
- certificates in the "server.pem" certificate file.
+ certificates in the "server.pem" certificate file. See the documentation of
+ the tls_dane_trust_anchor_digest_enable main.cf parameter.
% c\bca\bat\bt s\bse\ber\brv\bve\ber\br_\b_c\bce\ber\brt\bt.\b.p\bpe\bem\bm i\bin\bnt\bte\ber\brm\bme\bed\bdi\bia\bat\bte\be_\b_C\bCA\bA.\b.p\bpe\bem\bm r\bro\boo\bot\bt.\b.p\bpe\bem\bm >\b> s\bse\ber\brv\bve\ber\br.\b.p\bpe\bem\bm
published TLSA records will typically cause the SMTP client to defer mail
delivery. The foregoing also applies to "2 0 2" and "2 1 2" TLSA records or
any other digest of a CA certificate, but it is expected that SHA256 will
- be by far the most common digest for TLSA. You are strongly urged to
- likewise include the root CA certificate in your server certificate file
- even if you use "0 0 1" or "0 1 1" TLSA records. Some DANE implementations
- in SMTP clients (Postfix among them) may treat RFC 6698 certificate usages
- "0" and "2" interchangeably.
-
- By default, support for TLSA records that specify certificate usage "0" via
- a digest is disabled in the Postfix SMTP client. As a best practice,
- publish either "3 0 1" or "3 1 1" TLSA associations that specify the SHA256
- digest of the server certificate public key with the alias-expanded
- hostname of each STARTTLS capable SMTP server. These continue to work when
- a certificate is renewed with the same public/private key pair. See the
- documentation of the tls_dane_trust_anchor_digest_enable main.cf parameter
- for details.
+ be by far the most common digest for TLSA.
+
+ As a best practice, publish either "3 0 1" or "3 1 1" TLSA associations
+ that specify the SHA256 digest of the server certificate public key with
+ the alias-expanded hostname of each STARTTLS capable SMTP server. These
+ continue to work when a certificate is renewed with the same public/private
+ key pair.
For instructions on how to compute the digest of a certificate or its public
key for use in TLSA records, see the documentation of the
This is enabled by explicitly setting "smtpd_tls_cert_file = none" and not
specifying an smtpd_tls_dcert_file or smtpd_tls_eccert_file.
-Example, MSA that requires TLSv1, not SSLv2 or SSLv3, with high grade ciphers:
+Example, MSA that requires TLSv1 or higher, not SSLv2 or SSLv3, with high grade
+ciphers:
/etc/postfix/main.cf:
smtpd_tls_cert_file = /etc/postfix/cert.pem
smtpd_tls_mandatory_ciphers = high
smtpd_tls_mandatory_exclude_ciphers = aNULL, MD5
smtpd_tls_security_level = encrypt
- # Preferred form with Postfix >= 2.5:
+ # Postfix >= 2.5:
smtpd_tls_mandatory_protocols = !SSLv2, !SSLv3
- # Alternative form.
+ # Legacy form with Postfix prior to 2.5:
smtpd_tls_mandatory_protocols = TLSv1
If you want to take advantage of ciphers with ephemeral Diffie-Hellman (EDH)
smtpd_tls_eecdh_grade = strong
Postfix 2.8 and later, in combination with OpenSSL 0.9.7 and later allows TLS
-servers to preempt the TLS client's cipher preference list. This is possible
-only with SSLv3 and later, as in SSLv2 the client chooses the cipher from a
-list supplied by the server.
-
-By default, the OpenSSL server selects the client's most preferred cipher that
-the server supports. With SSLv3 and later, the server may choose its own most
-preferred cipher that is supported (offered) by the client. Setting
-"tls_preempt_cipherlist = yes" enables server cipher preferences. The default
-OpenSSL behavior applies with "tls_preempt_cipherlist = no".
-
-While server cipher selection may in some cases lead to a more secure or
-performant cipher choice, there is some risk of interoperability issues. In the
-past, some SSL clients have listed lower priority ciphers that they did not
-implement correctly. If the server chooses a cipher that the client prefers
-less, it may select a cipher whose client implementation is flawed.
+servers to preempt the TLS client's cipher-suite preference list. This is
+possible only with SSLv3 and later, as in SSLv2 the client chooses the cipher-
+suite from a list supplied by the server.
+
+By default, the OpenSSL server selects the client's most preferred cipher-suite
+that the server supports. With SSLv3 and later, the server may choose its own
+most preferred cipher-suite that is supported (offered) by the client. Setting
+"tls_preempt_cipherlist = yes" enables server cipher-suite preferences. The
+default OpenSSL behavior applies with "tls_preempt_cipherlist = no".
+
+While server cipher-suite selection may in some cases lead to a more secure or
+performant cipher-suite choice, there is some risk of interoperability issues.
+In the past, some SSL clients have listed lower priority ciphers that they did
+not implement correctly. If the server chooses a cipher that the client prefers
+less, it may select a cipher whose client implementation is flawed. Most
+notably Windows 2003 Microsoft Exchange servers have flawed implementations of
+DES-CBC3-SHA, which OpenSSL considers stronger than RC4-SHA. Enabling server
+cipher-suite selection may create interoperability issues with Windows 2003
+Microsoft Exchange clients.
M\bMi\bis\bsc\bce\bel\bll\bla\ban\bne\beo\bou\bus\bs s\bse\ber\brv\bve\ber\br c\bco\bon\bnt\btr\bro\bol\bls\bs
The "dane" level is a stronger form of opportunistic TLS that is resistant to
man in the middle and downgrade attacks when the destination domain uses DNSSEC
to publish DANE TLSA records for its MX hosts. If a remote SMTP server has
-usable DANE TLSA records, these will be used to authenticate the server. If
-TLSA records are published for a given remote SMTP server (implying TLS
-support), but are not usable due to unsupported parameters, the Postfix SMTP
-client will use mandatory unauthenticated TLS. Otherwise, the Postfix SMTP
-client behavior is the same as with may.
+"usable" (see RFC 6698) DANE TLSA records, the server connection will be
+authenticated. When DANE authentication fails, there is no fallback to
+unauthenticated or plaintext delivery.
+
+If TLSA records are published for a given remote SMTP server (implying TLS
+support), but are all "unusable" due to unsupported parameters or malformed
+data, the Postfix SMTP client will use mandatory unauthenticated TLS.
+Otherwise, when no TLSA records are published, the Postfix SMTP client behavior
+is the same as with may.
+
+TLSA records must be published in DNSSEC validated DNS zones. Any TLSA records
+in DNS zones not protected via DNSSEC are ignored. The Postfix SMTP client will
+not look for TLSA records associated with MX hosts whose "A" or "AAAA" records
+lie in an "insecure" DNS zone. Such lookups have been observed to cause
+interoperability issues with poorly implemented DNS servers, and are in any
+case not expected to ever yield "secure" results, since that would require a
+very unlikey DLV DNS trust anchor configured between the host record and the
+associated "_25._tcp" child TLSA record.
The "dane-only" level is a form of secure-channel TLS based on the DANE PKI. If
-usable TLSA records are present these are used to authenticate the remote SMTP
-server. Otherwise, or when server certificate verification fails, delivery via
-the server in question tempfails.
+"usable" TLSA records are present these are used to authenticate the remote
+SMTP server. Otherwise, or when server certificate verification fails, delivery
+via the server in question tempfails.
At both security levels, the TLS policy for the destination is obtained via
TLSA records validated with DNSSEC. For TLSA policy to be in effect, the
destination domain's containing DNS zone must be signed and the Postfix SMTP
client's operating system must be configured to send its DNS queries to a
recursive DNS nameserver that is able to validate the signed records. Each MX
-host's DNS zone should also be signed, and should publish DANE TLSA (RFC 6698)
-records that specify how that MX host's TLS certificate is to be verified. TLSA
-records do not preempt the normal SMTP MX host selection algorithm, if some MX
-hosts support TLSA and others do not, TLS security will vary from delivery to
-delivery. It is up to the domain owner to configure their MX hosts and their
-DNS sensibly. To configure the Postfix SMTP client for DNSSEC lookups see the
-documentation for the smtp_dns_support_level main.cf parameter. The
-tls_dane_trust_anchor_digest_enable main.cf parameter controls optional support
-for trust-anchor digest TLSA records.
-
-The Postfix SMTP client deviates from RFC 6698 in cases where strict adherence
-is likely to create opportunities for delayed (or eventually bounced) email
-with no substantive security gain. Most notably, it is not expected that
-smtp_tls_CAfile and smtp_tls_CApath can reasonably include every public CA that
-a remote SMTP server's administrator may believe to be well-known. Therefore,
-certificate usages "0" and "2" from RFC 6698 which are intended to "constrain"
-existing PKI trust, are instead treated as "trust assertions" and mapped to "1"
-and "3" respectively. That is, with certificate usage "0" and "2", Postfix will
-not require the remote SMTP server's certificate to be trusted with respect to
-any locally defined public CAs, it is the domain owner's responsibility to
-ensure that the certificate associations in their TLSA records are appropriate
-to authenticate their SMTP servers.
-
-In addition, the Postfix SMTP client does not assume that the remote SMTP
-server will necessarily be configured to present the certificate of any usage
-"0" root CA in its TLS protocol certificate_list. Therefore, support for usage
-"0" certificate and public-key digests is disabled by default, see
-tls_dane_trust_anchor_digest_enable for details. While undigested trust-anchor
-certificates in TLSA records are supported, publishing complete certificates in
-DNS is unwise given the resulting excessively large DNS record sizes.
-Therefore, in its default configuration the Postfix SMTP client essentially
-supports only certificate usages "1", "2" and "3" (with "1" treated as though
-it were "3").
-
-Finally, the interaction of DANE with MX hostnames that are CNAMEs differs from
-the draft specification in the names used to construct the associated TLSA
-queries. When the MX hostname is a CNAME, the draft proposal to use the
-unexpanded MX hostname in TLSA lookups is fragile and unintuitive. For this to
-work, the domain owner has to either duplicate the TLSA records of the target
-(host, service) pair in his own DNS or furnish the target host with an
-additional certificate and private key that would be negotiated via SNI.
-Neither of these are robust or easy to manage. It is far better to expand the
-CNAME recursively to the underlying target hostname (keeping track of DNSSEC
-validation along the way) and to use the expanded name to construct the TLSA
-query and, if appropriate, in server certificate name checks. This is the
-approach taken by the Postfix SMTP client, and if sanity prevails will also be
-the approach taken in the final standard.
+host's DNS zone needs to also be signed, and needs to publish DANE TLSA (RFC
+6698) records that specify how that MX host's TLS certificate is to be
+verified.
+
+TLSA records do not preempt the normal SMTP MX host selection algorithm, if
+some MX hosts support TLSA and others do not, TLS security will vary from
+delivery to delivery. It is up to the domain owner to configure their MX hosts
+and their DNS sensibly. To configure the Postfix SMTP client for DNSSEC lookups
+see the documentation for the smtp_dns_support_level main.cf parameter. The
+tls_dane_trust_anchor_digest_enable main.cf parameter controls support for
+trust-anchor digest TLSA records. The tls_dane_digests and
+tls_dane_digest_agility parameters control the list of supported digests and
+digest downgrade attack resistance.
+
+DANE for SMTP MTAs deviates in some details from the baseline DANE protocol in
+RFC 6698. Most notably, it is not expected that SMTP MTAs can reasonably
+include every public CA that a remote SMTP server's administrator may believe
+to be well-known. Nor is there an interactive user to "click OK" when
+authentication fails.
+
+Therefore, certificate usages "0" and "1" from RFC 6698 which are intended to
+"constrain" existing PKI trust, are not supported. TLSA records with usage "0"
+are treated as "unusable". TLSA records with usage "1" are instead treated as
+"trust assertions" and mapped to usage "3". Specifically, with certificate
+usage "1", Postfix will not require the remote SMTP server's certificate to be
+trusted with respect to any locally defined public CAs, it is the domain
+owner's responsibility to ensure that the certificate associations in their
+TLSA records are appropriate to authenticate their SMTP servers.
+
+The Postfix SMTP client supports only certificate usages "2" and "3" (with "1"
+treated as though it were "3"). See tls_dane_trust_anchor_digest_enable for
+usage "2" usability considerations. Support for certificate usage "1" is an
+experiment, it may be withdrawn in the future. Server operators SHOULD NOT
+publish TLSA records with usage "1".
When usable TLSA records are obtained for the remote SMTP server the Postfix
-SMTP client is obligated to include the SNI TLS extension in its SSL client
-hello message. This may help the remote SMTP server live up to its promise to
-provide a certificate that matches its TLSA records. Since TLS extensions
-require TLS 1.0 or later, the Postfix SMTP client must disable SSLv2 and SSLv3
-when SNI is required. If you use "dane" or "dane-only", do not disable TLSv1,
-except perhaps via the policy table for destinations which you are sure will
-support TLSv1.1 or TLSv1.2.
+SMTP client sends the SNI TLS extension in its SSL client hello message. This
+may help the remote SMTP server live up to its promise to provide a certificate
+that matches its TLSA records.
For purposes of protocol and cipher selection, the "dane" security level is
treated like a "mandatory" TLS security level, and weak ciphers and protocols
The pre-requisites for DANE support in the Postfix SMTP client are:
- * A compile-time OpenSSL library that supports the TLS SNI extension and the
- "sha256" and "sha512" message digests.
+ * A compile-time OpenSSL library that supports the TLS SNI extension and
+ "SHA-2" message digests.
* A compile-time DNS resolver library that supports DNSSEC. Postfix binaries
built on an older system will not support DNSSEC even if deployed on a
system with an updated resolver library.
On the SMTP client, there are further complications. When delivering mail to a
given domain, in contrast to HTTPS, one rarely uses the domain name directly as
the target host of the SMTP session. More typically, one uses MX lookups -
-these are usually unauthenticated - to obtain the domain's SMTP server hostname
-(s). When, as is current practice, the client verifies the insecurely obtained
-MX hostname, it is subject to a DNS man-in-the-middle attack.
+- these are usually unauthenticated -- to obtain the domain's SMTP server
+hostname(s). When, as is current practice, the client verifies the insecurely
+obtained MX hostname, it is subject to a DNS man-in-the-middle attack.
Adoption of DNSSEC and RFC6698 (DANE) may gradually (as domains implement
DNSSEC and publish TLSA records for their MX hosts) address the DNS man-in-the-
TLSA records in DNSSEC. If no TLSA records are found, the effective
security level used is may. If TLSA records are found, but none are usable,
the effective security level is encrypt. When usable TLSA records are
- obtained for the remote SMTP server, SSLv2 and SSLv3 are automatically
- disabled (see smtp_tls_mandatory_protocols), and the server certificate
- must match the TLSA records. The tls_dane_trust_anchor_digest_enable
- parameter controls optional support for trust-anchor digest TLSA records.
- RFC 6698 (DANE) TLS authentication and DNSSEC support is available with
- Postfix 2.11 and later.
+ obtained for the remote SMTP server, SSLv2 is automatically disabled (see
+ smtp_tls_mandatory_protocols), and the server certificate must match the
+ TLSA records. RFC 6698 (DANE) TLS authentication and DNSSEC support is
+ available with Postfix 2.11 and later.
d\bda\ban\bne\be-\b-o\bon\bnl\bly\by
Mandatory DANE TLS. The TLS policy for the destination is obtained via TLSA
records in DNSSEC. If no TLSA records are found, or none are usable, no
connection is made to the server. When usable TLSA records are obtained for
- the remote SMTP server, SSLv2 and SSLv3 are automatically disabled (see
+ the remote SMTP server, SSLv2 is automatically disabled (see
smtp_tls_mandatory_protocols), and the server certificate must match the
- TLSA records. The tls_dane_trust_anchor_digest_enable parameter controls
- optional support for trust-anchor digest TLSA records. RFC 6698 (DANE) TLS
- authentication and DNSSEC support is available with Postfix 2.11 and later.
+ TLSA records. RFC 6698 (DANE) TLS authentication and DNSSEC support is
+ available with Postfix 2.11 and later.
f\bfi\bin\bng\bge\ber\brp\bpr\bri\bin\bnt\bt
Certificate fingerprint verification. Available with Postfix 2.5 and later.
At this security level, there are no trusted certificate authorities. The
/etc/postfix/tls_policy:
example.edu none
example.mil may
- example.gov encrypt protocols=SSLv3:TLSv1 ciphers=high
- example.com verify
- match=hostname:dot-nexthop protocols=SSLv3:TLSv1 ciphers=high
+ example.gov encrypt ciphers=high
+ example.com verify match=hostname:dot-nexthop ciphers=high
example.net secure
.example.net secure match=.example.net:example.net
[mail.example.org]:587 secure match=nexthop
smtp_tls_exclude_ciphers = aNULL
# Preferred form with Postfix >= 2.5:
smtp_tls_mandatory_protocols = !SSLv2
- # Alternative form.
+ # Legacy form for Postifx < 2.5:
smtp_tls_mandatory_protocols = SSLv3, TLSv1
# Also available with Postfix >= 2.6:
smtp_tls_ciphers = export
If you upgrade from Postfix 2.9 or earlier, read RELEASE_NOTES-2.10
before proceeding.
+Incompatible changes with snapshot 20131126-nonprod
+===================================================
+
+The master_service_disable syntax has changed: use "service/type"
+instead of "service.type". The new form is consistent with master.cf
+parameter namespaces. The old form is still supported to avoid
+breaking existing configurations.
+
+Major changes with with snapshot 20131126-nonprod
+=================================================
+
+Support for advanced master.cf query and update operations. This
+was implemented primarily to support automated system management
+tools.
+
+The idea is to make all Postfix master.cf details accessible as a
+list of "name=value" pairs, where the names are organized into
+structured name spaces. This allows other programs to query
+information or request updates, without having to worry about the
+exact layout of master.cf files.
+
+First, an example that shows the smtp/inet service in the traditional
+form:
+
+ $ postconf -M smtp/inet
+ smtp inet n - n - - smtpd
+
+Different variants of this command show different amounts of output.
+For example, "postconf -M smtp" enumerates all services that have
+a name "smtp" and any service type ("inet", "unix", etc.), and
+"postconf -M" enumerates all master.cf services.
+
+General rule: each name component that is not present becomes a "*"
+wildcard.
+
+Coming back to the above example, the postconf -F option can now
+enumerate the smtp/inet service fields as follows:
+
+ $ postconf -F smtp/inet
+ smtp/inet/service = smtp
+ smtp/inet/type = inet
+ smtp/inet/private = n
+ smtp/inet/unprivileged = -
+ smtp/inet/chroot = n
+ smtp/inet/wakeup = -
+ smtp/inet/process_limit = -
+ smtp/inet/command = smtpd
+
+This form makes it very easy to change one field in master.cf.
+For example to turn on chroot on the smtp/inet service you use:
+
+ $ postconf -F smtp/inet/chroot=y
+
+Moreover, with "-F" you can specify "*" for service name or service
+type to get a wild-card match. For example, to turn off chroot on
+all Postfix daemons, use this:
+
+ $ postconf -F '*/*/chroot=n'
+
+For a second example, let's look at the submission service. This
+service typically has multple "-o parameter=value" overrides. First
+the traditional view:
+
+ $ postconf -Mf submission
+ submission inet n - n - - smtpd
+ -o smtpd_tls_security_level=encrypt
+ -o smtpd_sasl_auth_enable=yes
+ ...
+
+The postconf -P option can now enumerate these parameters as follows:
+
+ $ postconf -P submission
+ submission/inet/smtpd_sasl_auth_enable = yes
+ submission/inet/smtpd_tls_security_level = encrypt
+ ...
+
+Again, this form makes it very easy to modify one parameter
+setting, for example to change the smtpd_tls_security_level setting for
+the submission/inet service:
+
+ $ postconf -P 'submission/inet/smtpd_tls_security_level=may'
+
+You can create or remove a parametername=parametervalue setting:
+
+Create:
+ $ postconf -P 'submission/inet/parametername=parametervalue'
+
+Remove:
+ $ postconf -PX submission/inet/parametername
+
+Finally, adding master.cf entries is possible, but currently this
+does not yet have "advanced" support. It can only be done at the
+level of the traditional master.cf file format.
+
+For example, to clone the smtp/unix service settings and create a
+new delay/unix service you would enumerate the smtp/unix service
+like this:
+
+ $ postconf -M smtp/unix
+ smtp unix - - n - - smtp
+
+Then you would copy those fields (except the first field) to
+update or create the delay/unix service:
+
+ $ postconf -M delay/unix="delay unix - - n - - smtp"
+
+To combine the above in one command:
+
+ $ postconf -M delay/unix="`postconf -M smtp/unix|awk '{$1 = "delay"}'`"
+
+This is perhaps not super-convenient for manual cloning, but it
+should be sufficient for programmatic configuration management.
+
+The -X (delete entry) and -# (comment out entry) options already
+exist for main.cf, and they now also work work for entire master.cf
+entries:
+
+Remove main.cf or master.cf entry:
+ $ postconf -X parametername
+ $ postconf -MX delay/unix
+
+Comment out main.cf or master.cf entry:
+ $ postconf -# parametername
+ $ postconf -M# delay/unix
+
Major changes with snapshot 20131031
====================================
</pre>
</blockquote>
-<li> <p> If you use <a href="http://tools.ietf.org/html/rfc6698">RFC 6698</a> TLSA "2 0 1" or "2 1 1" records to
+<li> <p> If you publish <a href="http://tools.ietf.org/html/rfc6698">RFC 6698</a> TLSA "2 0 1" or "2 1 1" records to
specify root CA certificate digests, you must include the corresponding
-root CA certificates in the "server.pem" certificate file. </p>
+root CA certificates in the "server.pem" certificate file. See the
+documentation of the <a href="postconf.5.html#tls_dane_trust_anchor_digest_enable">tls_dane_trust_anchor_digest_enable</a> <a href="postconf.5.html">main.cf</a>
+parameter. </p>
<blockquote>
<pre>
</pre>
</blockquote>
-<p> Remote SMTP clients will
-be able to use the TLSA record you publish (which only contains the
-certificate digest) only if they have access to the corresponding
-certificate. Failure to verify certificates per the server's
-published TLSA records will typically cause the SMTP client to defer
-mail delivery. The foregoing also applies to "2 0 2" and "2 1 2"
-TLSA records or any other digest of a CA certificate, but it is
-expected that SHA256 will be by far the most common digest for TLSA.
-You are <i>strongly</i> urged to likewise include the root CA
-certificate in your server certificate file even if you use "0 0
-1" or "0 1 1" TLSA records. Some DANE implementations in SMTP
-clients (Postfix among them) may treat <a href="http://tools.ietf.org/html/rfc6698">RFC 6698</a> certificate usages
-"0" and "2" interchangeably. </p>
-
-<p>By default, support for TLSA records that specify certificate
-usage "0" via a digest is disabled in the Postfix SMTP client. As
-a best practice, publish either "3 0 1" or "3 1 1" TLSA associations
-that specify the SHA256 digest of the server certificate public key
-with the alias-expanded hostname of each STARTTLS capable SMTP
-server. These continue to work when a certificate is renewed with
-the same public/private key pair. See the documentation of the
-<a href="postconf.5.html#tls_dane_trust_anchor_digest_enable">tls_dane_trust_anchor_digest_enable</a> <a href="postconf.5.html">main.cf</a> parameter for details.
-</p>
+<p> Remote SMTP clients will be able to use the TLSA record you
+publish (which only contains the certificate digest) only if they
+have access to the corresponding certificate. Failure to verify
+certificates per the server's published TLSA records will typically
+cause the SMTP client to defer mail delivery. The foregoing also
+applies to "2 0 2" and "2 1 2" TLSA records or any other digest of
+a CA certificate, but it is expected that SHA256 will be by far the
+most common digest for TLSA. </p>
+
+<p> As a best practice, publish either "3 0 1" or "3 1 1" TLSA
+associations that specify the SHA256 digest of the server certificate
+public key with the alias-expanded hostname of each STARTTLS capable
+SMTP server. These continue to work when a certificate is renewed
+with the same public/private key pair. </p>
</ul>
enabled by explicitly setting "<a href="postconf.5.html#smtpd_tls_cert_file">smtpd_tls_cert_file</a> = none"
and not specifying an <a href="postconf.5.html#smtpd_tls_dcert_file">smtpd_tls_dcert_file</a> or <a href="postconf.5.html#smtpd_tls_eccert_file">smtpd_tls_eccert_file</a>. </p>
-<p> Example, MSA that requires TLSv1, not SSLv2 or SSLv3, with high grade
-ciphers: </p>
+<p> Example, MSA that requires TLSv1 or higher, not SSLv2 or SSLv3,
+with high grade ciphers: </p>
<blockquote>
<pre>
<a href="postconf.5.html#smtpd_tls_mandatory_ciphers">smtpd_tls_mandatory_ciphers</a> = high
<a href="postconf.5.html#smtpd_tls_mandatory_exclude_ciphers">smtpd_tls_mandatory_exclude_ciphers</a> = aNULL, MD5
<a href="postconf.5.html#smtpd_tls_security_level">smtpd_tls_security_level</a> = encrypt
- # Preferred form with Postfix ≥ 2.5:
+ # Postfix ≥ 2.5:
<a href="postconf.5.html#smtpd_tls_mandatory_protocols">smtpd_tls_mandatory_protocols</a> = !SSLv2, !SSLv3
- # Alternative form.
+ # Legacy form with Postfix prior to 2.5:
<a href="postconf.5.html#smtpd_tls_mandatory_protocols">smtpd_tls_mandatory_protocols</a> = TLSv1
</pre>
</blockquote>
</blockquote>
<p> Postfix 2.8 and later, in combination with OpenSSL 0.9.7 and later
-allows TLS servers to preempt the TLS client's cipher preference list.
+allows TLS servers to preempt the TLS client's cipher-suite preference list.
This is possible only with SSLv3 and later, as in SSLv2 the client
-chooses the cipher from a list supplied by the server. </p>
+chooses the cipher-suite from a list supplied by the server. </p>
<p> By default, the OpenSSL server selects the client's most preferred
-cipher that the server supports. With SSLv3 and later, the server
-may choose its own most preferred cipher that is supported (offered)
+cipher-suite that the server supports. With SSLv3 and later, the server
+may choose its own most preferred cipher-suite that is supported (offered)
by the client. Setting "<a href="postconf.5.html#tls_preempt_cipherlist">tls_preempt_cipherlist</a> = yes" enables server
-cipher preferences. The default OpenSSL behavior applies with
+cipher-suite preferences. The default OpenSSL behavior applies with
"<a href="postconf.5.html#tls_preempt_cipherlist">tls_preempt_cipherlist</a> = no". </p>
-<p> While server cipher selection may in some cases lead to a more secure
-or performant cipher choice, there is some risk of interoperability
-issues. In the past, some SSL clients have listed lower priority ciphers
-that they did not implement correctly. If the server chooses a cipher
-that the client prefers less, it may select a cipher whose client
-implementation is flawed. </p>
+<p> While server cipher-suite selection may in some cases lead to
+a more secure or performant cipher-suite choice, there is some risk
+of interoperability issues. In the past, some SSL clients have
+listed lower priority ciphers that they did not implement correctly.
+If the server chooses a cipher that the client prefers less, it may
+select a cipher whose client implementation is flawed. Most notably
+Windows 2003 Microsoft Exchange servers have flawed implementations
+of DES-CBC3-SHA, which OpenSSL considers stronger than RC4-SHA.
+Enabling server cipher-suite selection may create interoperability
+issues with Windows 2003 Microsoft Exchange clients. </p>
<h3><a name="server_misc"> Miscellaneous server controls</a> </h3>
href="#client_tls_may">opportunistic</a> TLS that is resistant to
man in the middle and downgrade attacks when the destination domain
uses DNSSEC to publish DANE TLSA records for its MX hosts. If a
-remote SMTP server has usable DANE TLSA records, these will be used
-to authenticate the server. If TLSA records are published for a
-given remote SMTP server (implying TLS support), but are not usable
-due to unsupported parameters, the Postfix SMTP client will use <a
+remote SMTP server has "usable" (see <a href="http://tools.ietf.org/html/rfc6698">RFC 6698</a>) DANE TLSA records,
+the server connection will be authenticated. When DANE authentication
+fails, there is no fallback to unauthenticated or plaintext delivery. </p>
+
+<p> If TLSA records are published for a given remote SMTP server
+(implying TLS support), but are all "unusable" due to unsupported
+parameters or malformed data, the Postfix SMTP client will use <a
href="#client_tls_encrypt">mandatory</a> unauthenticated TLS.
-Otherwise, the Postfix SMTP client behavior is the same as with <a
-href="#client_tls_may">may</a>. </p>
+Otherwise, when no TLSA records are published, the Postfix SMTP
+client behavior is the same as with <a href="#client_tls_may">may</a>. </p>
+
+<p> TLSA records must be published in DNSSEC validated DNS zones.
+Any TLSA records in DNS zones not protected via DNSSEC are ignored.
+The Postfix SMTP client will not look for TLSA records associated
+with MX hosts whose "A" or "AAAA" records lie in an "insecure" DNS
+zone. Such lookups have been observed to cause interoperability
+issues with poorly implemented DNS servers, and are in any case not
+expected to ever yield "secure" results, since that would require
+a very unlikey DLV DNS trust anchor configured between the host
+record and the associated "_25._tcp" child TLSA record. </p>
<p> The "dane-only" level is a form of <a
href="#client_tls_secure">secure-channel</a> TLS based on the DANE PKI.
-If usable TLSA records are present these are used to authenticate the
+If "usable" TLSA records are present these are used to authenticate the
remote SMTP server. Otherwise, or when server certificate verification
fails, delivery via the server in question tempfails. </p>
be signed and the Postfix SMTP client's operating system must be
configured to send its DNS queries to a recursive DNS nameserver
that is able to validate the signed records. Each MX host's DNS
-zone should also be signed, and should publish DANE TLSA (<a href="http://tools.ietf.org/html/rfc6698">RFC 6698</a>)
+zone needs to also be signed, and needs to publish DANE TLSA (<a href="http://tools.ietf.org/html/rfc6698">RFC 6698</a>)
records that specify how that MX host's TLS certificate is to be
-verified. TLSA records do not preempt the normal SMTP MX host
+verified. </p>
+
+<p> TLSA records do not preempt the normal SMTP MX host
selection algorithm, if some MX hosts support TLSA and others do
not, TLS security will vary from delivery to delivery. It is up
to the domain owner to configure their MX hosts and their DNS
sensibly. To configure the Postfix SMTP client for DNSSEC lookups
see the documentation for the <a href="postconf.5.html#smtp_dns_support_level">smtp_dns_support_level</a> <a href="postconf.5.html">main.cf</a>
parameter. The <a href="postconf.5.html#tls_dane_trust_anchor_digest_enable">tls_dane_trust_anchor_digest_enable</a> <a href="postconf.5.html">main.cf</a> parameter
-controls optional support for trust-anchor digest TLSA records.
+controls support for trust-anchor digest TLSA records. The
+<a href="postconf.5.html#tls_dane_digests">tls_dane_digests</a> and tls_dane_digest_agility parameters control
+the list of supported digests and digest downgrade attack resistance.
</p>
-<p> The Postfix SMTP client deviates from <a href="http://tools.ietf.org/html/rfc6698">RFC 6698</a> in cases where
-strict adherence is likely to create opportunities for delayed (or
-eventually bounced) email with no substantive security gain. Most
-notably, it is not expected that <a href="postconf.5.html#smtp_tls_CAfile">smtp_tls_CAfile</a> and <a href="postconf.5.html#smtp_tls_CApath">smtp_tls_CApath</a>
-can reasonably include every public CA that a remote SMTP server's
-administrator may believe to be well-known. Therefore, certificate
-usages "0" and "2" from <a href="http://tools.ietf.org/html/rfc6698">RFC 6698</a> which are intended to "constrain"
-existing PKI trust, are instead treated as "trust assertions" and
-mapped to "1" and "3" respectively. That is, with certificate usage
-"0" and "2", Postfix will not require the remote SMTP server's
-certificate to be trusted with respect to any locally defined public
-CAs, it is the domain owner's responsibility to ensure that the
-certificate associations in their TLSA records are appropriate
-to authenticate their SMTP servers. </p>
-
-<p> In addition, the Postfix SMTP client does not assume that the
-remote SMTP server will necessarily be configured to present the
-certificate of any usage "0" root CA in its TLS protocol <a
-href="https://tools.ietf.org/html/rfc2246#section-7.4.2">certificate_list</a>.
-Therefore, support for usage "0" certificate and public-key digests
-is disabled by default, see <a href="postconf.5.html#tls_dane_trust_anchor_digest_enable">tls_dane_trust_anchor_digest_enable</a> for
-details. While undigested trust-anchor certificates in TLSA records
-are supported, publishing complete certificates in DNS is unwise
-given the resulting excessively large DNS record sizes. Therefore,
-in its default configuration the Postfix SMTP client essentially
-supports only certificate usages "1", "2" and "3" (with "1" treated as
-though it were "3"). </p>
-
-<p> Finally, the interaction of DANE with MX hostnames that are
-CNAMEs differs from the draft specification in the names used to
-construct the associated <a
-href="https://tools.ietf.org/html/draft-ietf-dane-srv-02#section-3.2">TLSA
-queries</a>. When the MX hostname is a CNAME, the draft proposal
-to use the unexpanded MX hostname in TLSA lookups is fragile and
-unintuitive. For this to work, the domain owner has to either
-duplicate the TLSA records of the target (host, service) pair in
-his own DNS or furnish the target host with an additional
-certificate and private key that would be negotiated via SNI.
-Neither of these are robust or easy to manage. It is far better
-to expand the CNAME recursively to the underlying target hostname
-(keeping track of DNSSEC validation along the way) and to use the
-expanded name to construct the TLSA query and, if appropriate, in
-server certificate name checks. This is the approach taken by the
-Postfix SMTP client, and if sanity prevails will also be the approach
-taken in the final standard. </p>
+<p> DANE for SMTP MTAs deviates in some details from the baseline
+DANE protocol in <a href="http://tools.ietf.org/html/rfc6698">RFC 6698</a>. Most notably, it is not expected that
+SMTP MTAs can reasonably include every public CA that a remote SMTP
+server's administrator may believe to be well-known. Nor is there
+an interactive user to "click OK" when authentication fails. </p>
+
+<p> Therefore, certificate usages "0" and "1" from <a href="http://tools.ietf.org/html/rfc6698">RFC 6698</a> which
+are intended to "constrain" existing PKI trust, are not supported.
+TLSA records with usage "0" are treated as "unusable". TLSA records
+with usage "1" are instead treated as "trust assertions" and mapped
+to usage "3". Specifically, with certificate usage "1", Postfix
+will not require the remote SMTP server's certificate to be trusted
+with respect to any locally defined public CAs, it is the domain
+owner's responsibility to ensure that the certificate associations
+in their TLSA records are appropriate to authenticate their SMTP
+servers. </p>
+
+<p> The Postfix SMTP client supports only certificate usages "2"
+and "3" (with "1" treated as though it were "3"). See
+<a href="postconf.5.html#tls_dane_trust_anchor_digest_enable">tls_dane_trust_anchor_digest_enable</a> for usage "2" usability
+considerations. Support for certificate usage "1" is an experiment,
+it may be withdrawn in the future. Server operators SHOULD NOT
+publish TLSA records with usage "1". </p>
<p> When usable TLSA records are obtained for the remote SMTP server
-the Postfix SMTP client is obligated to include the SNI TLS extension
-in its SSL client hello message. This may help the remote SMTP
-server live up to its promise to provide a certificate that matches
-its TLSA records. Since TLS extensions require TLS 1.0 or later,
-the Postfix SMTP client must disable SSLv2 and SSLv3 when SNI is
-required. If you use "dane" or "dane-only", do not disable TLSv1,
-except perhaps via the policy table for destinations which you are
-sure will support TLSv1.1 or TLSv1.2. </p>
+the Postfix SMTP client sends the SNI TLS extension in its SSL
+client hello message. This may help the remote SMTP server live
+up to its promise to provide a certificate that matches its TLSA
+records. </p>
<p> For purposes of protocol and cipher selection, the "dane"
security level is treated like a "mandatory" TLS security level,
<p> When a DANE TLSA record specifies an end-entity (EE) certificate,
(that is the actual server certificate), as with the fingerprint
security level below, no name checks or certificate expiration checks
-are applied. The server certificate (or its public key) either matches
+are applied. The server certificate (or its public key) either matches
the DANE record or not. Server administrators should publish such
EE records in preference to all other types. </p>
<p> The pre-requisites for DANE support in the Postfix SMTP client are: </p>
<ul>
<li> A <i>compile-time</i> OpenSSL library that supports the TLS SNI
-extension and the "sha256" and "sha512" message digests.
+extension and "SHA-2" message digests.
<li> A <i>compile-time</i> DNS resolver library that supports DNSSEC.
Postfix binaries built on an older system will not support DNSSEC even
if deployed on a system with an updated resolver library.
it is a dedicated MSA that only handles outbound mail from trusted clients,
below we focus on the client security policy. </p>
-<p> On the SMTP client, there are further complications. When delivering
-mail to a given domain, in contrast to HTTPS, one rarely uses the domain
-name directly as the target host of the SMTP session. More typically,
-one uses MX lookups - these are usually unauthenticated - to obtain the domain's SMTP server
-hostname(s). When, as is current practice, the client verifies the
-insecurely obtained MX hostname, it is subject to a DNS man-in-the-middle
+<p> On the SMTP client, there are further complications. When
+delivering mail to a given domain, in contrast to HTTPS, one rarely
+uses the domain name directly as the target host of the SMTP session.
+More typically, one uses MX lookups — these are usually
+unauthenticated — to obtain the domain's SMTP server hostname(s).
+When, as is current practice, the client verifies the insecurely
+obtained MX hostname, it is subject to a DNS man-in-the-middle
attack. </p>
<p> Adoption of DNSSEC and <a href="http://tools.ietf.org/html/rfc6698">RFC6698</a> (DANE) may gradually (as domains
used is <a href="#client_tls_may">may</a>. If TLSA records are
found, but none are usable, the effective security level is <a
href="#client_tls_encrypt">encrypt</a>. When usable TLSA records
-are obtained for the remote SMTP server, SSLv2 and SSLv3 are
-automatically disabled (see <a href="postconf.5.html#smtp_tls_mandatory_protocols">smtp_tls_mandatory_protocols</a>), and the
-server certificate must match the TLSA records. The
-<a href="postconf.5.html#tls_dane_trust_anchor_digest_enable">tls_dane_trust_anchor_digest_enable</a> parameter controls optional
-support for trust-anchor digest TLSA records. <a href="http://tools.ietf.org/html/rfc6698">RFC 6698</a> (DANE) TLS
-authentication and DNSSEC support is available with Postfix 2.11
-and later. </dd>
+are obtained for the remote SMTP server, SSLv2 is automatically
+disabled (see <a href="postconf.5.html#smtp_tls_mandatory_protocols">smtp_tls_mandatory_protocols</a>), and the server certificate
+must match the TLSA records. <a href="http://tools.ietf.org/html/rfc6698">RFC 6698</a> (DANE) TLS authentication
+and DNSSEC support is available with Postfix 2.11 and later. </dd>
<dt><b>dane-only</b></dt> <dd><a href="#client_tls_dane">Mandatory DANE TLS</a>.
The TLS policy for the destination is obtained via TLSA records in
DNSSEC. If no TLSA records are found, or none are usable, no
connection is made to the server. When usable TLSA records are
-obtained for the remote SMTP server, SSLv2 and SSLv3 are automatically
-disabled (see <a href="postconf.5.html#smtp_tls_mandatory_protocols">smtp_tls_mandatory_protocols</a>), and the server certificate
-must match the TLSA records. The <a href="postconf.5.html#tls_dane_trust_anchor_digest_enable">tls_dane_trust_anchor_digest_enable</a>
-parameter controls optional support for trust-anchor digest TLSA
-records. <a href="http://tools.ietf.org/html/rfc6698">RFC 6698</a> (DANE) TLS authentication and DNSSEC support is
-available with Postfix 2.11 and later. </dd>
+obtained for the remote SMTP server, SSLv2 is automatically disabled
+(see <a href="postconf.5.html#smtp_tls_mandatory_protocols">smtp_tls_mandatory_protocols</a>), and the server certificate must
+match the TLSA records. <a href="http://tools.ietf.org/html/rfc6698">RFC 6698</a> (DANE) TLS authentication and
+DNSSEC support is available with Postfix 2.11 and later. </dd>
<dt><b>fingerprint</b></dt> <dd><a href="#client_tls_fprint">Certificate
fingerprint verification.</a> Available with Postfix 2.5 and
/etc/postfix/tls_policy:
example.edu none
example.mil may
- example.gov encrypt protocols=SSLv3:TLSv1 ciphers=high
- example.com verify
- match=hostname:dot-nexthop protocols=SSLv3:TLSv1 ciphers=high
+ example.gov encrypt ciphers=high
+ example.com verify match=hostname:dot-nexthop ciphers=high
example.net secure
.example.net secure match=.example.net:example.net
[mail.example.org]:587 secure match=nexthop
<a href="postconf.5.html#smtp_tls_exclude_ciphers">smtp_tls_exclude_ciphers</a> = aNULL
# Preferred form with Postfix ≥ 2.5:
<a href="postconf.5.html#smtp_tls_mandatory_protocols">smtp_tls_mandatory_protocols</a> = !SSLv2
- # Alternative form.
+ # Legacy form for Postifx < 2.5:
<a href="postconf.5.html#smtp_tls_mandatory_protocols">smtp_tls_mandatory_protocols</a> = SSLv3, TLSv1
# Also available with Postfix ≥ 2.6:
<a href="postconf.5.html#smtp_tls_ciphers">smtp_tls_ciphers</a> = export
hostname is not an alias and its address records
lie in an unsigned zone.
- <b><a href="postconf.5.html#tls_dane_trust_anchor_digest_enable">tls_dane_trust_anchor_digest_enable</a> (trust-anchor-asser-</b>
- <b>tion)</b>
+ <b><a href="postconf.5.html#tls_dane_trust_anchor_digest_enable">tls_dane_trust_anchor_digest_enable</a> (yes)</b>
<a href="http://tools.ietf.org/html/rfc6698">RFC 6698</a> trust-anchor digest support in the Postfix
TLS library.
<b><a href="postconf.5.html#tlsmgr_service_name">tlsmgr_service_name</a> (tlsmgr)</b>
- The name of the <a href="tlsmgr.8.html"><b>tlsmgr</b>(8)</a> service entry in mas-
- ter.cf.
+ The name of the <a href="tlsmgr.8.html"><b>tlsmgr</b>(8)</a> service entry in <a href="master.5.html">mas-
+ ter.cf</a>.
<b>OBSOLETE STARTTLS CONTROLS</b>
The following configuration parameters exist for compati-
<b>postconf</b> [<b>-dfhnovx</b>] [<b>-c</b> <i>config</i><b>_</b><i>dir</i>] [<b>-C</b> <i>class,...</i>] [<i>param-</i>
<i>eter ...</i>]
- <b>postconf</b> [<b>-ev</b>] [<b>-c</b> <i>config</i><b>_</b><i>dir</i>] [<i>parameter=value ...</i>]
+ <b>postconf</b> [<b>-ev</b>] [<b>-c</b> <i>config</i><b>_</b><i>dir</i>] <i>parameter=value ...</i>
- <b>postconf</b> [<b>-#vX</b>] [<b>-c</b> <i>config</i><b>_</b><i>dir</i>] [<i>parameter ...</i>]
+ <b>postconf</b> [<b>-#vX</b>] [<b>-c</b> <i>config</i><b>_</b><i>dir</i>] <i>parameter ...</i>
- <b>Managing <a href="master.5.html">master.cf</a>:</b>
+ <b>Managing <a href="master.5.html">master.cf</a> service entries:</b>
- <b>postconf</b> [<b>-fMovx</b>] [<b>-c</b> <i>config</i><b>_</b><i>dir</i>] [<i>service ...</i>]
+ <b>postconf</b> [<b>-fMovx</b>] [<b>-c</b> <i>config</i><b>_</b><i>dir</i>] [<i>service</i>[<b>/</b><i>type</i>] <i>...</i>]
+
+ <b>postconf</b> [<b>-eMv</b>] [<b>-c</b> <i>config</i><b>_</b><i>dir</i>] <i>service</i><b>/</b><i>type=value ...</i>
+
+ <b>postconf</b> [<b>-#MvX</b>] [<b>-c</b> <i>config</i><b>_</b><i>dir</i>] <i>service</i><b>/</b><i>type ...</i>
+
+ <b>Managing <a href="master.5.html">master.cf</a> service fields:</b>
+
+ <b>postconf</b> [<b>-fFovx</b>] [<b>-c</b> <i>config</i><b>_</b><i>dir</i>] [<i>service</i>[<b>/</b><i>type</i>[<b>/</b><i>field</i>]]
+ <i>...</i>]
+
+ <b>postconf</b> [<b>-eFv</b>] [<b>-c</b> <i>config</i><b>_</b><i>dir</i>] <i>service</i><b>/</b><i>type</i><b>/</b><i>field=value</i>
+ <i>...</i>
+
+ <b>Managing <a href="master.5.html">master.cf</a> service parameters:</b>
+
+ <b>postconf</b> [<b>-fPovx</b>] [<b>-c</b> <i>config</i><b>_</b><i>dir</i>] [<i>service</i>[<b>/</b><i>type</i>[<b>/</b><i>parame-</i>
+ <i>ter</i>]] <i>...</i>]
+
+ <b>postconf</b> [<b>-ePv</b>] [<b>-c</b> <i>config</i><b>_</b><i>dir</i>] <i>service</i><b>/</b><i>type</i><b>/</b><i>parame-</i>
+ <i>ter=value ...</i>
+
+ <b>postconf</b> [<b>-PXv</b>] [<b>-c</b> <i>config</i><b>_</b><i>dir</i>] <i>service</i><b>/</b><i>type</i><b>/</b><i>parameter ...</i>
<b>Managing bounce message templates:</b>
By default, the <a href="postconf.1.html"><b>postconf</b>(1)</a> command displays the values of
<a href="postconf.5.html"><b>main.cf</b></a> configuration parameters, and warns about possible
mis-typed parameter names (Postfix 2.9 and later). It can
- also change <a href="postconf.5.html"><b>main.cf</b></a> configuration parameter values, or
- display other configuration information about the Postfix
+ also change <a href="postconf.5.html"><b>main.cf</b></a> configuration parameter values, or
+ display other configuration information about the Postfix
mail system.
Options:
- <b>-a</b> List the available SASL server plug-in types. The
- SASL plug-in type is selected with the
+ <b>-a</b> List the available SASL server plug-in types. The
+ SASL plug-in type is selected with the
<b><a href="postconf.5.html#smtpd_sasl_type">smtpd_sasl_type</a></b> configuration parameter by specify-
ing one of the names listed below.
- <b>cyrus</b> This server plug-in is available when Post-
+ <b>cyrus</b> This server plug-in is available when Post-
fix is built with Cyrus SASL support.
<b>dovecot</b>
This server plug-in uses the Dovecot authen-
tication server, and is available when Post-
- fix is built with any form of SASL support.
+ fix is built with any form of SASL support.
- This feature is available with Postfix 2.3 and
+ This feature is available with Postfix 2.3 and
later.
- <b>-A</b> List the available SASL client plug-in types. The
- SASL plug-in type is selected with the
- <b><a href="postconf.5.html#smtp_sasl_type">smtp_sasl_type</a></b> or <b><a href="postconf.5.html#lmtp_sasl_type">lmtp_sasl_type</a></b> configuration
- parameters by specifying one of the names listed
+ <b>-A</b> List the available SASL client plug-in types. The
+ SASL plug-in type is selected with the
+ <b><a href="postconf.5.html#smtp_sasl_type">smtp_sasl_type</a></b> or <b><a href="postconf.5.html#lmtp_sasl_type">lmtp_sasl_type</a></b> configuration
+ parameters by specifying one of the names listed
below.
- <b>cyrus</b> This client plug-in is available when Post-
+ <b>cyrus</b> This client plug-in is available when Post-
fix is built with Cyrus SASL support.
- This feature is available with Postfix 2.3 and
+ This feature is available with Postfix 2.3 and
later.
<b>-b</b> [<i>template</i><b>_</b><i>file</i>]
Display the message text that appears at the begin-
- ning of delivery status notification (DSN) mes-
+ ning of delivery status notification (DSN) mes-
sages, replacing $<b>name</b> expressions with actual val-
ues as described in <a href="bounce.5.html"><b>bounce</b>(5)</a>.
- To override the built-in templates, specify a tem-
- plate file name at the end of the <a href="postconf.1.html"><b>postconf</b>(1)</a> com-
- mand line, or specify a file name in <a href="postconf.5.html"><b>main.cf</b></a> with
+ To override the built-in templates, specify a tem-
+ plate file name at the end of the <a href="postconf.1.html"><b>postconf</b>(1)</a> com-
+ mand line, or specify a file name in <a href="postconf.5.html"><b>main.cf</b></a> with
the <b><a href="postconf.5.html#bounce_template_file">bounce_template_file</a></b> parameter.
To force selection of the built-in templates, spec-
- ify an empty template file name on the <a href="postconf.1.html"><b>postconf</b>(1)</a>
+ ify an empty template file name on the <a href="postconf.1.html"><b>postconf</b>(1)</a>
command line (in shell language: "").
- This feature is available with Postfix 2.3 and
+ This feature is available with Postfix 2.3 and
later.
<b>-c</b> <i>config</i><b>_</b><i>dir</i>
- The <a href="postconf.5.html"><b>main.cf</b></a> 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.
<b>-C</b> <i>class,...</i>
- When displaying <a href="postconf.5.html"><b>main.cf</b></a> parameters, select only
+ When displaying <a href="postconf.5.html"><b>main.cf</b></a> parameters, select only
parameters from the specified class(es):
<b>builtin</b>
Parameters with built-in names.
<b>service</b>
- Parameters with service-defined names (the
- first field of a <a href="master.5.html"><b>master.cf</b></a> entry plus a
+ Parameters with service-defined names (the
+ first field of a <a href="master.5.html"><b>master.cf</b></a> entry plus a
Postfix-defined suffix).
<b>user</b> Parameters with user-defined names.
The default is as if "<b>-C all</b>" is specified.
<b>-d</b> Print <a href="postconf.5.html"><b>main.cf</b></a> default parameter settings instead of
- actual settings. Specify <b>-df</b> to fold long lines
+ actual settings. Specify <b>-df</b> to fold long lines
for human readability (Postfix 2.9 and later).
- <b>-e</b> Edit the <a href="postconf.5.html"><b>main.cf</b></a> configuration file, and update
- parameter settings with the "<i>name=value</i>" pairs on
- the <a href="postconf.1.html"><b>postconf</b>(1)</a> command line. The file is copied to
- a temporary file then renamed into place. Specify
- quotes to protect special characters and whitespace
- on the <a href="postconf.1.html"><b>postconf</b>(1)</a> command line.
-
- The <b>-e</b> is no longer needed with Postfix version 2.8
- and later.
+ <b>-e</b> Edit the <a href="postconf.5.html"><b>main.cf</b></a> configuration file, and update
+ parameter settings with the "<i>name=value</i>" pairs on
+ the <a href="postconf.1.html"><b>postconf</b>(1)</a> command line.
+
+ With <b>-M</b>, edit the <a href="master.5.html"><b>master.cf</b></a> configuration file, and
+ replace one or more service entries with new values
+ as specified with "<i>service/type=value</i>" on the <a href="postconf.1.html"><b>post-</b></a>
+ <a href="postconf.1.html"><b>conf</b>(1)</a> command line.
+
+ With <b>-F</b>, edit the <a href="master.5.html"><b>master.cf</b></a> configuration file, and
+ replace one or more service fields with new values
+ as specied with "<i>service/type/field=value</i>" on the
+ <a href="postconf.1.html"><b>postconf</b>(1)</a> command line. Currently, the "command"
+ field contains the command name and command argu-
+ ments. this may change in the near future, so that
+ the "command" field contains only the command name,
+ and a new "arguments" pseudofield contains the com-
+ mand arguments.
+
+ With <b>-P</b>, edit the <a href="master.5.html"><b>master.cf</b></a> configuration file, and
+ add or update one or more service parameter set-
+ tings (-o parameter=value settings) with new values
+ as specied with "<i>service/type/parameter=value</i>" on
+ the <a href="postconf.1.html"><b>postconf</b>(1)</a> command line.
+
+ In all cases the file is copied to a temporary file
+ then renamed into place. Specify quotes to protect
+ special characters and whitespace on the <a href="postconf.1.html"><b>post-</b></a>
+ <a href="postconf.1.html"><b>conf</b>(1)</a> command line.
+
+ The <b>-e</b> option is no longer needed with Postfix ver-
+ sion 2.8 and later.
<b>-f</b> Fold long lines when printing <a href="postconf.5.html"><b>main.cf</b></a> or <a href="master.5.html"><b>master.cf</b></a>
configuration file entries, for human readability.
This feature is available with Postfix 2.9 and
later.
- <b>-h</b> Show <a href="postconf.5.html"><b>main.cf</b></a> parameter values without the "<i>name</i> = "
- label that normally precedes the value.
+ <b>-F</b> Show <a href="master.5.html"><b>master.cf</b></a> per-entry field settings (by default
+ all services and all fields), formatted as one
+ "<i>service/type/field=value</i>" per line. Specify <b>-Ff</b> to
+ fold long lines.
+
+ Specify one or more "<i>service/type/field</i>" instances
+ on the <a href="postconf.1.html"><b>postconf</b>(1)</a> command line to limit the output
+ to fields of interest. Trailing parameter name or
+ service type fields that are omitted will be han-
+ dled as "*" wildcard fields.
+
+ This feature is available with Postfix 2.11 and
+ later.
+
+ <b>-h</b> Show parameter or attribute values without the
+ "<i>name</i> = " label that normally precedes the value.
<b>-l</b> List the names of all supported mailbox locking
methods. Postfix supports the following methods:
A non-shared, in-memory hash table. Its con-
tent are lost when a process terminates.
- <b>ldap</b> (read-only)
- LDAP database client. This is described in
- <a href="ldap_table.5.html"><b>ldap_table</b>(5)</a>.
-
<b>lmdb</b> OpenLDAP LMDB database (a memory-mapped,
persistent file). Available on systems with
- support for LMDB databases. This is
+ support for LMDB databases. This is
described in <a href="lmdb_table.5.html"><b>lmdb_table</b>(5)</a>.
+ <b>ldap</b> (read-only)
+ LDAP database client. This is described in
+ <a href="ldap_table.5.html"><b>ldap_table</b>(5)</a>.
+
<b>memcache</b>
Memcache database client. This is described
in <a href="memcache_table.5.html"><b>memcache_table</b>(5)</a>.
with support for MySQL databases. This is
described in <a href="mysql_table.5.html"><b>mysql_table</b>(5)</a>.
- <b>nis</b> (read-only)
- NIS client.
-
- <b>nisplus</b> (read-only)
- NIS+ client.
-
<b>pcre</b> (read-only)
A lookup table based on Perl Compatible Reg-
ular Expressions. The file format is
file contents. Specify <b>-Mf</b> to fold long lines for
human readability.
- If <i>service ...</i> is specified, only the matching ser-
- vices will be output. For example, "<b>postconf -Mf</b>
- <b>inet</b>" will output all services that listen on the
- network.
-
- Specify zero or more arguments, each with a <i>ser-</i>
- <i>vice-type</i> name (<b>inet</b>, <b>unix</b>, <b>fifo</b>, or <b>pass</b>) or with
- a <i>service-name.service-type</i> pair, where <i>service-</i>
- <i>name</i> is the first field of a <a href="master.5.html">master.cf</a> entry.
+ Specify zero or more arguments, each with a <i>ser-</i>
+ <i>vice-name</i> or <i>service-name/service-type</i> pair, where
+ <i>service-name</i> is the first field of a <a href="master.5.html">master.cf</a>
+ entry and <i>service-type</i> is one of (<b>inet</b>, <b>unix</b>, <b>fifo</b>,
+ or <b>pass</b>).
+
+ If <i>service-name</i> or <i>service-name/service-type</i> is
+ specified, only the matching <a href="master.5.html">master.cf</a> entries will
+ be output. For example, "<b>postconf -Mf smtp</b>" will
+ output all services named "smtp", and "<b>postconf -Mf</b>
+ <b>smtp/inet</b>" will output only the smtp service that
+ listens on the network. Trailing service type
+ fields that are omitted will be handled as "*"
+ wildcard fields.
- This feature is available with Postfix 2.9 and
- later.
+ This feature is available with Postfix 2.9 and
+ later. The syntax was changed from "<i>name.type</i>" to
+ "<i>name/type</i>", and "*" wildcard support was added
+ with Postfix 2.11.
- <b>-n</b> Show only configuration parameters that have
- explicit <i>name=value</i> settings in <a href="postconf.5.html"><b>main.cf</b></a>. Specify
+ <b>-n</b> Show only configuration parameters that have
+ explicit <i>name=value</i> settings in <a href="postconf.5.html"><b>main.cf</b></a>. Specify
<b>-nf</b> to fold long lines for human readability (Post-
fix 2.9 and later).
<b>-o</b> <i>name=value</i>
Override <a href="postconf.5.html"><b>main.cf</b></a> parameter settings.
- This feature is available with Postfix 2.10 and
+ This feature is available with Postfix 2.10 and
+ later.
+
+ <b>-p</b> Show <a href="postconf.5.html"><b>main.cf</b></a> parameter settings. This is the
+ default.
+
+ <b>-P</b> Show <a href="master.5.html"><b>master.cf</b></a> service parameter settings (by
+ default all services and all parameters). format-
+ ted as one "<i>service/type/parameter=value</i>" per line.
+ Specify <b>-Pf</b> to fold long lines.
+
+ Specify one or more "<i>service/type/parameter</i>"
+ instances on the <a href="postconf.1.html"><b>postconf</b>(1)</a> command line to limit
+ the output to parameters of interest. Trailing
+ parameter name or service type fields that are
+ omitted will be handled as "*" wildcard fields.
+
+ This feature is available with Postfix 2.11 and
later.
<b>-t</b> [<i>template</i><b>_</b><i>file</i>]
<b>-X</b> Edit the <a href="postconf.5.html"><b>main.cf</b></a> configuration file, and remove the
parameters named on the <a href="postconf.1.html"><b>postconf</b>(1)</a> command line.
- The file is copied to a temporary file then renamed
- into place. Specify a list of parameter names, not
- "<i>name=value</i>" pairs. There is no <a href="postconf.1.html"><b>postconf</b>(1)</a> com-
- mand to perform the reverse operation.
+ Specify a list of parameter names, not "<i>name=value</i>"
+ pairs.
- This feature is available with Postfix 2.10 and
- later.
+ With <b>-M</b>, edit the <a href="master.5.html"><b>master.cf</b></a> configuration file, and
+ remove one or more service entries as specified
+ with "<i>service/type</i>" on the <a href="postconf.1.html"><b>postconf</b>(1)</a> command
+ line.
+
+ With <b>-P</b>, edit the <a href="master.5.html"><b>master.cf</b></a> configuration file, and
+ remove one or more service parameter settings (-o
+ parameter=value settings) as specied with "<i>ser-</i>
+ <i>vice/type/parameter</i>" on the <a href="postconf.1.html"><b>postconf</b>(1)</a> command
+ line.
+
+ In all cases the file is copied to a temporary file
+ then renamed into place. Specify quotes to protect
+ special characters on the <a href="postconf.1.html"><b>postconf</b>(1)</a> command line.
+
+ There is no <a href="postconf.1.html"><b>postconf</b>(1)</a> command to perform the
+ reverse operation.
+
+ This feature is available with Postfix 2.10 and
+ later. Support for -M and -P was added with Post-
+ fix 2.11.
<b>-#</b> Edit the <a href="postconf.5.html"><b>main.cf</b></a> configuration file, and comment
out the parameters named on the <a href="postconf.1.html"><b>postconf</b>(1)</a> command
line, so that those parameters revert to their
- default values. The file is copied to a temporary
- file then renamed into place. Specify a list of
- parameter names, not "<i>name=value</i>" pairs. There is
- no <a href="postconf.1.html"><b>postconf</b>(1)</a> command to perform the reverse oper-
- ation.
+ default values. Specify a list of parameter names,
+ not "<i>name=value</i>" pairs.
+
+ With <b>-M</b>, edit the <a href="master.5.html"><b>master.cf</b></a> configuration file, and
+ comment out one or more service entries as speci-
+ fied with "<i>service/type</i>" on the <a href="postconf.1.html"><b>postconf</b>(1)</a> command
+ line.
+
+ In all cases the file is copied to a temporary file
+ then renamed into place. Specify quotes to protect
+ special characters on the <a href="postconf.1.html"><b>postconf</b>(1)</a> command line.
+
+ There is no <a href="postconf.1.html"><b>postconf</b>(1)</a> command to perform the
+ reverse operation.
This feature is available with Postfix 2.6 and
- later.
+ later. Support for -M was added with Postfix 2.11.
<b>DIAGNOSTICS</b>
Problems are reported to the standard error stream.
Directory with Postfix configuration files.
<b>CONFIGURATION PARAMETERS</b>
- The following <a href="postconf.5.html"><b>main.cf</b></a> 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#config_directory">config_directory</a> (see 'postconf -d' output)</b>
- The default location of the Postfix <a href="postconf.5.html">main.cf</a> and
+ 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#bounce_template_file">bounce_template_file</a> (empty)</b>
- Pathname of a configuration file with bounce mes-
+ Pathname of a configuration file with bounce mes-
sage templates.
<b>FILES</b>
/etc/postfix/<a href="postconf.5.html">main.cf</a>, Postfix configuration parameters
- /etc/postfix/<a href="master.5.html">master.cf</a>, Postfix master daemon configuraton
+ /etc/postfix/<a href="master.5.html">master.cf</a>, Postfix master daemon configuration
<b>SEE ALSO</b>
- <a href="bounce.5.html">bounce(5)</a>, bounce template file format
- <a href="master.5.html">master(5)</a>, <a href="master.5.html">master.cf</a> configuration file syntax
- <a href="postconf.5.html">postconf(5)</a>, <a href="postconf.5.html">main.cf</a> configuration file syntax
+ <a href="bounce.5.html">bounce(5)</a>, bounce template file format <a href="master.5.html">master(5)</a>, <a href="master.5.html">master.cf</a>
+ configuration file syntax <a href="postconf.5.html">postconf(5)</a>, <a href="postconf.5.html">main.cf</a> configuration
+ file syntax
<b>README FILES</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>
- Wietse Venema
- IBM T.J. Watson Research
- P.O. Box 704
- Yorktown Heights, NY 10598, USA
+ Wietse Venema IBM T.J. Watson Research P.O. Box 704 Yorktown
+ Heights, NY 10598, USA
POSTCONF(1)
</pre> </body> </html>
empty value means allow all protocols. The valid protocol names, (see
<b>SSL_get_version(3)</b>), are "SSLv2", "SSLv3" and "TLSv1". </p>
-<p> At the <a href="TLS_README.html#client_tls_dane">dane</a> and
-<a href="TLS_README.html#client_tls_dane">dane-only</a> security
-levels, when usable TLSA records are obtained for the remote SMTP
-server, the Postfix SMTP client is obligated to include the SNI TLS
-extension in its SSL client hello message. This may help the remote
-SMTP server live up to its promise to provide a certificate that
-matches its TLSA records. Since TLS extensions require TLS 1.0 or
-later, the Postfix SMTP client must disable SSLv2 and SSLv3 when
-SNI is required. If you use "dane" or "dane-only" do not disable
-TLSv1, except perhaps via the policy table for destinations which
-you are sure will support TLSv1.1 or TLSv1.2. </p>
-
<p> Note: As of OpenSSL 1.0.1 two new protocols are defined, "TLSv1.1"
and "TLSv1.2". If an older Postfix version is linked against OpenSSL
1.0.1 or later, these, or any other new protocol versions, are
<pre>
# Preferred form with Postfix ≥ 2.5:
<a href="postconf.5.html#smtp_tls_mandatory_protocols">smtp_tls_mandatory_protocols</a> = !SSLv2, !SSLv3
-# Alternative form.
+# Legacy form with Postfix < 2.5:
<a href="postconf.5.html#smtp_tls_mandatory_protocols">smtp_tls_mandatory_protocols</a> = TLSv1
</pre>
href="TLS_README.html#client_tls_may">may</a>. If TLSA records are
found, but none are usable, the effective security level is <a
href="TLS_README.html#client_tls_encrypt">encrypt</a>. When usable
-TLSA records are obtained for the remote SMTP server, SSLv2 and
-SSLv3 are automatically disabled (see <a href="postconf.5.html#smtp_tls_mandatory_protocols">smtp_tls_mandatory_protocols</a>),
-and the server certificate must match the TLSA records. The
-<a href="postconf.5.html#tls_dane_trust_anchor_digest_enable">tls_dane_trust_anchor_digest_enable</a> parameter controls optional
-support for trust-anchor digest TLSA records. <a href="http://tools.ietf.org/html/rfc6698">RFC 6698</a> (DANE) TLS
-authentication and DNSSEC support is available with Postfix 2.11
-and later. </dd>
+TLSA records are obtained for the remote SMTP server, the
+server certificate must match the TLSA records. <a href="http://tools.ietf.org/html/rfc6698">RFC 6698</a> (DANE)
+TLS authentication and DNSSEC support is available with Postfix
+2.11 and later. </dd>
<dt><b><a href="TLS_README.html#client_tls_dane">dane-only</a></b></dt>
<dd>Mandatory DANE TLS. The TLS policy for the destination is
obtained via TLSA records in DNSSEC. If no TLSA records are found,
or none are usable, no connection is made to the server. When
-usable TLSA records are obtained for the remote SMTP server, SSLv2
-and SSLv3 are automatically disabled (see <a href="postconf.5.html#smtp_tls_mandatory_protocols">smtp_tls_mandatory_protocols</a>),
-and the server certificate must match the TLSA records. The
-<a href="postconf.5.html#tls_dane_trust_anchor_digest_enable">tls_dane_trust_anchor_digest_enable</a> parameter controls optional
-support for trust-anchor digest TLSA records. <a href="http://tools.ietf.org/html/rfc6698">RFC 6698</a> (DANE) TLS
+usable TLSA records are obtained for the remote SMTP server, the
+server certificate must match the TLSA records. <a href="http://tools.ietf.org/html/rfc6698">RFC 6698</a> (DANE) TLS
authentication and DNSSEC support is available with Postfix 2.11
and later. </dd>
<p> Example: </p>
<pre>
-# TLSv1 only!
+# TLSv1 or better:
<a href="postconf.5.html#smtp_tls_protocols">smtp_tls_protocols</a> = !SSLv2, !SSLv3
</pre>
effective security level is "may" or "encrypt" respectively. For
purposes of protocol and cipher selection, the "dane" security level
is treated like a "mandatory" TLS security level, and weak ciphers
-and protocols are disabled. SSLv2 and SSLv3 are automatically
-disabled when usable TLSA records are obtained for the remote SMTP
-server, see <a href="postconf.5.html#smtp_tls_mandatory_protocols">smtp_tls_mandatory_protocols</a> for details. Since DANE
-authenticates server certificates the "aNULL" cipher-suites are
-transparently excluded at this level, no need to configure this
-manually. The <a href="postconf.5.html#tls_dane_trust_anchor_digest_enable">tls_dane_trust_anchor_digest_enable</a> <a href="postconf.5.html">main.cf</a> parameter
-controls optional support for trust-anchor digest TLSA records.
-<a href="http://tools.ietf.org/html/rfc6698">RFC 6698</a> (DANE) TLS authentication is available with Postfix 2.11
-and later. </dd>
+and protocols are disabled. Since DANE authenticates server
+certificates the "aNULL" cipher-suites are transparently excluded
+at this level, no need to configure this manually. <a href="http://tools.ietf.org/html/rfc6698">RFC 6698</a> (DANE)
+TLS authentication is available with Postfix 2.11 and later. </dd>
<dt><b><a href="TLS_README.html#client_tls_dane">dane-only</a></b></dt>
-<dd>Mandatory DANE TLS. This is just like "dane" above, only DANE
-TLSA authentication is mandatory. <a href="http://tools.ietf.org/html/rfc6698">RFC 6698</a> (DANE) TLS authentication
-is available with Postfix 2.11 and later. </dd>
+<dd>Mandatory DANE TLS. This is just like "dane" above, but DANE
+TLSA authentication is required. There is no fallback to "may" or
+"encrypt" when TLSA records are missing or unusable. <a href="http://tools.ietf.org/html/rfc6698">RFC 6698</a>
+(DANE) TLS authentication is available with Postfix 2.11 and later.
+</dd>
<dt><b><a href="TLS_README.html#client_tls_fingerprint">fingerprint</a></b></dt>
<dd>Certificate fingerprint verification.
(default: !SSLv2)</b></DT><DD>
<p> The SSL/TLS protocols accepted by the Postfix SMTP server with
-mandatory TLS encryption. If the list is empty, the server supports all
-available SSL/TLS protocol versions. A non-empty value is a list
-of protocol
-names separated by whitespace, commas or colons. The supported protocol
-names are "SSLv2", "SSLv3" and "TLSv1", and are not case sensitive. </p>
+mandatory TLS encryption. If the list is empty, the server supports
+all available SSL/TLS protocol versions. A non-empty value is a
+list of protocol names separated by whitespace, commas or colons.
+The supported protocol names are "SSLv2", "SSLv3" and "TLSv1", and
+are not case sensitive. </p>
<p> Note: As of OpenSSL 1.0.1 two new protocols are defined, "TLSv1.1"
and "TLSv1.2". If an older Postfix version is linked against OpenSSL
<p> Example: </p>
<pre>
-<a href="postconf.5.html#smtpd_tls_mandatory_protocols">smtpd_tls_mandatory_protocols</a> = TLSv1
-# Alternative form with Postfix ≥ 2.5:
<a href="postconf.5.html#smtpd_tls_mandatory_protocols">smtpd_tls_mandatory_protocols</a> = !SSLv2, !SSLv3
+# Legacy form with Postfix < 2.5:
+<a href="postconf.5.html#smtpd_tls_mandatory_protocols">smtpd_tls_mandatory_protocols</a> = TLSv1
</pre>
<p> This feature is available in Postfix 2.3 and later. </p>
<p> This feature is available in Postfix 2.2 and later. </p>
+</DD>
+
+<DT><b><a name="tls_dane_digest_agility">tls_dane_digest_agility</a>
+(default: on)</b></DT><DD>
+
+<p> Configure DANE TLSA digest algorithm agility. When digest
+algorithm agility is enabled, and the server and client support a
+common strong digest algorithm, TLSA records with weaker digest
+algorithms are ignored. </p>
+
+<p> Specify one of the following: </p>
+
+<dl>
+
+<dt><b>off</b></dt>
+<dd> DANE verification examines each well-formed record in the TLSA
+RRset whose matching type is either "0" (no hash used) or is one of
+the digest algorithms listed in $<a href="postconf.5.html#tls_dane_digests">tls_dane_digests</a>. This setting
+is not recommended. </dd>
+
+<dt><b>on</b></dt>
+<dd> From each group of well-formed TLSA RRs a non-zero digest
+matching type with the same certificate usage and selector, DANE
+verification examines only those records whose matching type has
+the highest precedence (appear earliest in $<a href="postconf.5.html#tls_dane_digests">tls_dane_digests</a>) are
+considered. </dd>
+
+<dt><b>maybe</b></dt>
+<dd> For compatibility with digest algorithm agility, each certificate
+or public key whose digest is included in a DANE TLSA RRset, SHOULD
+be published with the same set of digest matching type values as
+any other with the same usage and selector. Therefore, compatible
+TLSA RRsets will contain an identical count of well-formed RRs with
+each non-zero digest matching type for any fixed combination of
+usage and selector. When this constraint is violated, or any of
+the digest records are malformed, digest algorithm agility will
+disabled. Otherwise, digest algorithm agility is enabled. </dd>
+
+</dl>
+
+<p> Digest algorithm agility ensures that the strongest digest
+supported by both the Postfix SMTP client and the remote server is
+used, and weaker digests are ignored. This supports non-disruptive
+deprecation of outdated digest algorithms. </p>
+
+<p> To ensure compatibility with digest algorithm agility during
+key rotation, when a certificate or public key is being replaced
+with another, and both are published during the transition, both
+the old and the new certificate MUST be specified with the same set
+of digests. One can change the list of digest algorithms later,
+once old keys are retired. At any given time, change either the
+list of digests without changing the list of certificates or public
+keys or the list of certificates or public keys without changing
+the list of digests. Full value matching type "0" records are not
+subject to this constraint, but are discouraged due to the size of
+the resulting DNS records. </p>
+
+<p> It is expected that this algorithm agility mechanism will be
+published in a standards track RFC for SMTP with DANE, and also in
+an eventual update to <a href="http://tools.ietf.org/html/rfc6698">RFC 6698</a>. </p>
+
+<p> This feature is available in Postfix 2.11 and later. </p>
+
+
</DD>
<DT><b><a name="tls_dane_digests">tls_dane_digests</a>
<p> <a href="http://tools.ietf.org/html/rfc6698">RFC 6698</a> TLSA resource-record "matching type" digest algorithms
in descending preference order. All the specified algorithms must
be supported by the underlying OpenSSL library, otherwise the Postfix
-SMTP client will not support DANE TLSA security. </p>
+SMTP client will not support DANE TLSA security. </p>
+
+<p> Specify a list of digest names separated by commas and/or
+whitespace. Each digest name may be followed by an optional
+"=<number>" suffix. For example, "sha512" may instead be specified
+as "sha512=2" and "sha256" may instead be specified as "sha256=1".
+The optional number must match the <a
+href="https://www.iana.org/assignments/dane-parameters/dane-parameters.xhtml#matching-types"
+>IANA</a> assigned TLSA matching type number the algorithm in question.
+Postfix will check this constraint for the algorithms it knows about.
+Additional matching type algorithms registered with IANA can be added
+with explicit numbers provided they are supported by OpenSSL. </p>
+
+<p> Invalid list elements are logged with a warning and disable DANE
+support. TLSA RRs that specify digests not included in the list are
+ignored with a warning. </p>
+
+<p> Note: It is unwise to omit sha256 from the digest list. This
+digest algorithm is the only mandatory to implement digest algorithm
+in <a href="http://tools.ietf.org/html/rfc6698">RFC 6698</a>, and many servers are expected publish TLSA records
+with just sha256 digests. Unless one of the standard digests is
+seriously compromised and servers have had ample time to update their
+TLSA records you should not omit any standard digests, just arrange
+them in order from strongest to weakest. </p>
<p> When for a particular combination of "certificate usage" and
-"selector" the TLSA RRset contains a well-formed record with a
-matching type of "0", i.e. a full value of the associated certificate
-or public key, the Postfix SMTP client will ignore all other matching
-types for the same certificate usage and selector. In this case
-the first algorithm listed in <a href="postconf.5.html#tls_dane_digests">tls_dane_digests</a> will be used to
-compute a digest of the full value, which will then be used to match
-certificates or public keys in the server's certificate chain. </p>
-
-<p> Otherwise, when for a particular combination of "certificate
-usage" and "selector" the TLSA RRset contains a records with more
-than one non-zero matching type, i.e. multiple digest algorithms,
-only records with the highest preference digest are used after
-discarding any records with an incorrect digest length as unusable. </p>
-
-<p> This strategy ensures that the strongest digest supported by
-both the Postfix SMTP client and the remote server is used, and
-weaker digests are ignored. This supports non-disruptive deprecation
-of outdated digest algorithms. </p>
-
-<p> The strategy requires that when a TLSA RRset provides association
-data for multiple certificates or public keys, all RRs with the same
-"certificate usage" and "selector" be published with the same set
-of digests. In particular, during key rotation, when a certificate
-or public key is being replaced with another (and both are published
-during the transition) both the old and the new certificate MUST be
-specified with the same set of digests. One can change the list of
-digest algorithms later, once old keys are retired. At any given
-time change either the list of digests without changing the list of
-certificates or public keys or the list of certificates or public
-keys without changing the list of digests. </p>
+"selector" the TLSA RRset contains records with more than one digest
+matching type, the tls_dane_digest_agility parameter determines
+whether all the RRs are used, or only those with the most preferred
+digest matching type. </p>
-<p> It is expected that this algorithm agility mechanism will be
-published in a standards track RFC for SMTP with DANE, and perhaps
-in an eventual update to <a href="http://tools.ietf.org/html/rfc6698">RFC 6698</a>. </p>
+<p> The <a href="postconf.5.html#tls_dane_trust_anchor_digest_enable">tls_dane_trust_anchor_digest_enable</a> parameter controls
+whether any digest TLSA records are acceptable in usage "2" (trust
+anchor assertion) TLSA records. </p>
-<p> This feature is available in Postfix 2.11. </p>
+<p> This feature is available in Postfix 2.11 and later. </p>
</DD>
<DT><b><a name="tls_dane_trust_anchor_digest_enable">tls_dane_trust_anchor_digest_enable</a>
-(default: trust-anchor-assertion)</b></DT><DD>
+(default: yes)</b></DT><DD>
<p> <a href="http://tools.ietf.org/html/rfc6698">RFC 6698</a> trust-anchor digest support in the Postfix TLS library.
-Specify zero or more of the following options, separated by comma or
-whitespace. Option names are case-insensitive. </p>
-
-<dl>
-
-<dt><b>ca-constraint</b></dt>
-
-<dd> Enable support for <a href="http://tools.ietf.org/html/rfc6698">RFC 6698</a> (DANE TLSA) DNS records that
-contain digests of trust-anchors with certificate usage "0".
-These are often public root CAs, and server operators may
-expect that clients will have the corresponding root certificate
-in their CAfile or CApath. Most SSL/TLS servers do not send public
-root CA certificate in their certificate chain, so if Postfix does
-not have the CA certificate locally, there is no way to associate
-the digest with the trust chain from the server. These TLSA records
-are fragile, and only work when you have a complete (whatever that
-means) set of public CAs in your CAfile or CApath. Enable this
-with caution if at all. </dd>
-
-<dt><b>trust-anchor-assertion</b></dt>
-
-<dd> Enable support for <a href="http://tools.ietf.org/html/rfc6698">RFC 6698</a> (DANE TLSA) DNS records that contain
+Enable support for <a href="http://tools.ietf.org/html/rfc6698">RFC 6698</a> (DANE TLSA) DNS records that contain
digests of trust-anchors with certificate usage "2". In this case
the certificate usage logically requires the server administrator
to configure the server to include the trust-anchor certificate in
-the server's SSL certificate chain. These TLSA records are less
-fragile than "ca-constraint" TLSA records, and are enabled by
-default. Having a "complete" CAfile or CApath does not help in
-this case, you are at the mercy of the remote server administrator's
-competence. </dd>
-
-</dl>
+the server's SSL certificate chain. If enough domains mess this
+up, you can disable support for these TLSA records, but you'll no
+longer have secure connections that get it right and only publish
+trust anchor records. </p>
<p> At the <a href="TLS_README.html#client_tls_dane">dane</a>
security level, when a TLSA RRset includes only unusable associations,
the server in question is skipped and delivery is deferred if no
secure servers are found. </p>
+<p> The <a href="postconf.5.html#tls_dane_digests">tls_dane_digests</a> parameter controls the list of digest
+algorithms that are supported in TLSA records. The tls_dane_digest_agility
+parameter controls digest algorithm downgrade attack resistance.
+</p>
+
<p> This feature is available in Postfix 2.11 and later. </p>
issues. In the past, some SSL clients have listed lower priority ciphers
that they did not implement correctly. If the server chooses a cipher
that the client prefers less, it may select a cipher whose client
-implementation is flawed. </p>
+implementation is flawed. Most notably Windows 2003 Microsoft
+Exchange servers have flawed implementations of DES-CBC3-SHA, which
+OpenSSL considers stronger than RC4-SHA. Enabling server cipher-suite
+selection may create interoperability issues with Windows 2003
+Microsoft Exchange clients. </p>
<p> This feature is available in Postfix 2.8 and later, in combination
with OpenSSL 0.9.7 and later. </p>
hostname is not an alias and its address records
lie in an unsigned zone.
- <b><a href="postconf.5.html#tls_dane_trust_anchor_digest_enable">tls_dane_trust_anchor_digest_enable</a> (trust-anchor-asser-</b>
- <b>tion)</b>
+ <b><a href="postconf.5.html#tls_dane_trust_anchor_digest_enable">tls_dane_trust_anchor_digest_enable</a> (yes)</b>
<a href="http://tools.ietf.org/html/rfc6698">RFC 6698</a> trust-anchor digest support in the Postfix
TLS library.
<b><a href="postconf.5.html#tlsmgr_service_name">tlsmgr_service_name</a> (tlsmgr)</b>
- The name of the <a href="tlsmgr.8.html"><b>tlsmgr</b>(8)</a> service entry in mas-
- ter.cf.
+ The name of the <a href="tlsmgr.8.html"><b>tlsmgr</b>(8)</a> service entry in <a href="master.5.html">mas-
+ ter.cf</a>.
<b>OBSOLETE STARTTLS CONTROLS</b>
The following configuration parameters exist for compati-
# Non-production: needs thorough testing, or major changes are still
# needed before the code stabilizes.
-#CCARGS="$CCARGS -DNONPROD"
+CCARGS="$CCARGS -DNONPROD"
sed 's/ / /g' <<EOF
SYSTYPE = $SYSTYPE
[\fB-C \fIclass,...\fR] [\fIparameter ...\fR]
\fBpostconf\fR [\fB-ev\fR] [\fB-c \fIconfig_dir\fR]
-[\fIparameter=value ...\fR]
+\fIparameter=value ...\fR
\fBpostconf\fR [\fB-#vX\fR] [\fB-c \fIconfig_dir\fR]
-[\fIparameter ...\fR]
+\fIparameter ...\fR
-\fBManaging master.cf:\fR
+\fBManaging master.cf service entries:\fR
\fBpostconf\fR [\fB-fMovx\fR] [\fB-c \fIconfig_dir\fR]
-[\fIservice ...\fR]
+[\fIservice\fR[\fB/\fItype\fR]\fI ...\fR]
+
+\fBpostconf\fR [\fB-eMv\fR] [\fB-c \fIconfig_dir\fR]
+\fIservice\fB/\fItype=value ...\fR
+
+\fBpostconf\fR [\fB-#MvX\fR] [\fB-c \fIconfig_dir\fR]
+\fIservice\fB/\fItype ...\fR
+
+\fBManaging master.cf service fields:\fR
+
+\fBpostconf\fR [\fB-fFovx\fR] [\fB-c \fIconfig_dir\fR]
+[\fIservice\fR[\fB/\fItype\fR[\fB/\fIfield\fR]]\fI ...\fR]
+
+\fBpostconf\fR [\fB-eFv\fR] [\fB-c \fIconfig_dir\fR]
+\fIservice\fB/\fItype\fB/\fIfield=value ...\fR
+
+\fBManaging master.cf service parameters:\fR
+
+\fBpostconf\fR [\fB-fPovx\fR] [\fB-c \fIconfig_dir\fR]
+[\fIservice\fR[\fB/\fItype\fR[\fB/\fIparameter\fR]]\fI ...\fR]
+
+\fBpostconf\fR [\fB-ePv\fR] [\fB-c \fIconfig_dir\fR]
+\fIservice\fB/\fItype\fB/\fIparameter=value ...\fR
+
+\fBpostconf\fR [\fB-PXv\fR] [\fB-c \fIconfig_dir\fR]
+\fIservice\fB/\fItype\fB/\fIparameter ...\fR
\fBManaging bounce message templates:\fR
(Postfix 2.9 and later).
.IP \fB-e\fR
Edit the \fBmain.cf\fR configuration file, and update
-parameter settings with the "\fIname=value\fR" pairs
-on the \fBpostconf\fR(1) command line. The file is copied
-to a temporary file then renamed into place.
-Specify quotes to protect special characters and whitespace
-on the \fBpostconf\fR(1) command line.
-
-The \fB-e\fR is no longer needed with Postfix version 2.8
-and later.
+parameter settings with the "\fIname=value\fR" pairs on the
+\fBpostconf\fR(1) command line.
+
+With \fB-M\fR, edit the \fBmaster.cf\fR configuration file,
+and replace one or more service entries with new values as
+specified with "\fIservice/type=value\fR" on the \fBpostconf\fR(1)
+command line.
+
+With \fB-F\fR, edit the \fBmaster.cf\fR configuration file,
+and replace one or more service fields with new values as
+specied with "\fIservice/type/field=value\fR" on the
+\fBpostconf\fR(1) command line. Currently, the "command"
+field contains the command name and command arguments. this
+may change in the near future, so that the "command" field
+contains only the command name, and a new "arguments"
+pseudofield contains the command arguments.
+
+With \fB-P\fR, edit the \fBmaster.cf\fR configuration file,
+and add or update one or more service parameter settings
+(-o parameter=value settings) with new values as specied
+with "\fIservice/type/parameter=value\fR" on the \fBpostconf\fR(1)
+command line.
+
+In all cases the file is copied to a temporary file then
+renamed into place. Specify quotes to protect special
+characters and whitespace on the \fBpostconf\fR(1) command
+line.
+
+The \fB-e\fR option is no longer needed with Postfix version
+2.8 and later.
.IP \fB-f\fR
Fold long lines when printing \fBmain.cf\fR or \fBmaster.cf\fR
configuration file entries, for human readability.
This feature is available with Postfix 2.9 and later.
+.IP \fB-F\fR
+Show \fBmaster.cf\fR per-entry field settings (by default
+all services and all fields), formatted as one
+"\fIservice/type/field=value\fR" per line. Specify \fB-Ff\fR
+to fold long lines.
+
+Specify one or more "\fIservice/type/field\fR" instances
+on the \fBpostconf\fR(1) command line to limit the output
+to fields of interest. Trailing parameter name or service
+type fields that are omitted will be handled as "*" wildcard
+fields.
+
+This feature is available with Postfix 2.11 and later.
.IP \fB-h\fR
-Show \fBmain.cf\fR parameter values without the "\fIname\fR
+Show parameter or attribute values without the "\fIname\fR
= " label that normally precedes the value.
.IP \fB-l\fR
List the names of all supported mailbox locking methods.
This locking method is available on systems with a BSD
compatible library.
.IP \fBfcntl\fR
-A kernel-based advisory locking method for local and remote files.
+A kernel-based advisory locking method for local and remote
+files.
.IP \fBdotlock\fR
-An application-level locking method. An application locks a file
-named \fIfilename\fR by creating a file named \fIfilename\fB.lock\fR.
-The application is expected to remove its own lock file, as well as
-stale lock files that were left behind after abnormal program
-termination.
+An application-level locking method. An application locks
+a file named \fIfilename\fR by creating a file named
+\fIfilename\fB.lock\fR. The application is expected to
+remove its own lock file, as well as stale lock files that
+were left behind after abnormal program termination.
.RE
.IP \fB-m\fR
-List the names of all supported lookup table types. In Postfix
-configuration files,
-lookup tables are specified as \fItype\fB:\fIname\fR, where
-\fItype\fR is one of the types listed below. The table \fIname\fR
-syntax depends on the lookup table type as described in the
-DATABASE_README document.
+List the names of all supported lookup table types. In
+Postfix configuration files, lookup tables are specified
+as \fItype\fB:\fIname\fR, where \fItype\fR is one of the
+types listed below. The table \fIname\fR syntax depends on
+the lookup table type as described in the DATABASE_README
+document.
.RS
.IP \fBbtree\fR
A sorted, balanced tree structure. Available on systems
.IP \fBinternal\fR
A non-shared, in-memory hash table. Its content are lost
when a process terminates.
-.IP "\fBldap\fR (read-only)"
-LDAP database client. This is described in \fBldap_table\fR(5).
.IP "\fBlmdb\fR"
OpenLDAP LMDB database (a memory-mapped, persistent file).
Available on systems with support for LMDB databases. This
is described in \fBlmdb_table\fR(5).
+.IP "\fBldap\fR (read-only)"
+LDAP database client. This is described in \fBldap_table\fR(5).
.IP "\fBmemcache\fR"
Memcache database client. This is described in
\fBmemcache_table\fR(5).
.IP "\fBmysql\fR (read-only)"
MySQL database client. Available on systems with support
for MySQL databases. This is described in \fBmysql_table\fR(5).
-.IP "\fBnis\fR (read-only)"
-NIS client.
-.IP "\fBnisplus\fR (read-only)"
-NIS+ client.
.IP "\fBpcre\fR (read-only)"
A lookup table based on Perl Compatible Regular Expressions.
The file format is described in \fBpcre_table\fR(5).
.IP "\fBsqlite\fR (read-only)"
SQLite database. This is described in \fBsqlite_table\fR(5).
.IP "\fBstatic\fR (read-only)"
-A table that always returns its name as lookup result. For example,
-\fBstatic:foobar\fR always returns the string \fBfoobar\fR as lookup
-result.
+A table that always returns its name as lookup result. For
+example, \fBstatic:foobar\fR always returns the string
+\fBfoobar\fR as lookup result.
.IP "\fBtcp\fR (read-only)"
TCP/IP client. The protocol is described in \fBtcp_table\fR(5).
.IP "\fBtexthash\fR (read-only)"
-Produces similar results as hash: files, except that you don't
-need to run the \fBpostmap\fR(1) command before you can use the file,
-and that it does not detect changes after the file is read.
+Produces similar results as hash: files, except that you
+don't need to run the \fBpostmap\fR(1) command before you
+can use the file, and that it does not detect changes after
+the file is read.
.IP "\fBunix\fR (read-only)"
A limited view of the UNIX authentication database. The
following tables are implemented:
.RS
. IP \fBunix:passwd.byname\fR
-The table is the UNIX password database. The key is a login name.
-The result is a password file entry in \fBpasswd\fR(5) format.
+The table is the UNIX password database. The key is a login
+name. The result is a password file entry in \fBpasswd\fR(5)
+format.
.IP \fBunix:group.byname\fR
-The table is the UNIX group database. The key is a group name.
-The result is a group file entry in \fBgroup\fR(5) format.
+The table is the UNIX group database. The key is a group
+name. The result is a group file entry in \fBgroup\fR(5)
+format.
.RE
.RE
.IP
-Other table types may exist depending on how Postfix was built.
+Other table types may exist depending on how Postfix was
+built.
.IP \fB-M\fR
Show \fBmaster.cf\fR file contents instead of \fBmain.cf\fR
-file contents.
-Specify \fB-Mf\fR to fold long lines for human readability.
+file contents. Specify \fB-Mf\fR to fold long lines for
+human readability.
-If \fIservice ...\fR is specified, only the matching services
-will be output. For example, "\fBpostconf -Mf inet\fR"
-will output all services that listen on the network.
+Specify zero or more arguments, each with a \fIservice-name\fR
+or \fIservice-name/service-type\fR pair, where \fIservice-name\fR
+is the first field of a master.cf entry and \fIservice-type\fR
+is one of (\fBinet\fR, \fBunix\fR, \fBfifo\fR, or \fBpass\fR).
-Specify zero or more arguments, each with a \fIservice-type\fR
-name (\fBinet\fR, \fBunix\fR, \fBfifo\fR, or \fBpass\fR)
-or with a \fIservice-name.service-type\fR pair, where
-\fIservice-name\fR is the first field of a master.cf entry.
+If \fIservice-name\fR or \fIservice-name/service-type\fR
+is specified, only the matching master.cf entries will be
+output. For example, "\fBpostconf -Mf smtp\fR" will output
+all services named "smtp", and "\fBpostconf -Mf smtp/inet\fR"
+will output only the smtp service that listens on the
+network. Trailing service type fields that are omitted
+will be handled as "*" wildcard fields.
-This feature is available with Postfix 2.9 and later.
+This feature is available with Postfix 2.9 and later. The
+syntax was changed from "\fIname.type\fR" to "\fIname/type\fR",
+and "*" wildcard support was added with Postfix 2.11.
.IP \fB-n\fR
Show only configuration parameters that have explicit
-\fIname=value\fR settings in \fBmain.cf\fR.
-Specify \fB-nf\fR to fold long lines for human readability
-(Postfix 2.9 and later).
+\fIname=value\fR settings in \fBmain.cf\fR. Specify \fB-nf\fR
+to fold long lines for human readability (Postfix 2.9 and
+later).
.IP "\fB-o \fIname=value\fR"
Override \fBmain.cf\fR parameter settings.
This feature is available with Postfix 2.10 and later.
+.IP \fB-p\fR
+Show \fBmain.cf\fR parameter settings. This is the default.
+.IP \fB-P\fR
+Show \fBmaster.cf\fR service parameter settings (by default
+all services and all parameters). formatted as one
+"\fIservice/type/parameter=value\fR" per line. Specify
+\fB-Pf\fR to fold long lines.
+
+Specify one or more "\fIservice/type/parameter\fR" instances
+on the \fBpostconf\fR(1) command line to limit the output
+to parameters of interest. Trailing parameter name or
+service type fields that are omitted will be handled as "*"
+wildcard fields.
+
+This feature is available with Postfix 2.11 and later.
.IP "\fB-t\fR [\fItemplate_file\fR]"
Display the templates for text that appears at the beginning
of delivery status notification (DSN) messages, without
This feature is available with Postfix 2.3 and later.
.IP \fB-v\fR
-Enable verbose logging for debugging purposes. Multiple \fB-v\fR
-options make the software increasingly verbose.
+Enable verbose logging for debugging purposes. Multiple
+\fB-v\fR options make the software increasingly verbose.
.IP \fB-x\fR
Expand \fI$name\fR in \fBmain.cf\fR or \fBmaster.cf\fR
parameter values. The expansion is recursive.
This feature is available with Postfix 2.10 and later.
.IP \fB-X\fR
-Edit the \fBmain.cf\fR configuration file, and remove
-the parameters named on the \fBpostconf\fR(1) command line.
-The file is copied to a temporary file then renamed into
-place.
+Edit the \fBmain.cf\fR configuration file, and remove the
+parameters named on the \fBpostconf\fR(1) command line.
Specify a list of parameter names, not "\fIname=value\fR"
-pairs. There is no \fBpostconf\fR(1) command to perform
-the reverse operation.
+pairs.
+
+With \fB-M\fR, edit the \fBmaster.cf\fR configuration file,
+and remove one or more service entries as specified with
+"\fIservice/type\fR" on the \fBpostconf\fR(1) command line.
+
+With \fB-P\fR, edit the \fBmaster.cf\fR configuration file,
+and remove one or more service parameter settings (-o
+parameter=value settings) as specied with
+"\fIservice/type/parameter\fR" on the \fBpostconf\fR(1)
+command line.
+
+In all cases the file is copied to a temporary file then
+renamed into place. Specify quotes to protect special
+characters on the \fBpostconf\fR(1) command line.
+
+There is no \fBpostconf\fR(1) command to perform the reverse
+operation.
This feature is available with Postfix 2.10 and later.
+Support for -M and -P was added with Postfix 2.11.
.IP \fB-#\fR
Edit the \fBmain.cf\fR configuration file, and comment out
the parameters named on the \fBpostconf\fR(1) command line,
so that those parameters revert to their default values.
-The file is copied to a temporary file then renamed into
-place.
Specify a list of parameter names, not "\fIname=value\fR"
-pairs. There is no \fBpostconf\fR(1) command to perform
-the reverse operation.
+pairs.
+
+With \fB-M\fR, edit the \fBmaster.cf\fR configuration file,
+and comment out one or more service entries as specified
+with "\fIservice/type\fR" on the \fBpostconf\fR(1) command
+line.
+
+In all cases the file is copied to a temporary file then
+renamed into place. Specify quotes to protect special
+characters on the \fBpostconf\fR(1) command line.
+
+There is no \fBpostconf\fR(1) command to perform the reverse
+operation.
-This feature is available with Postfix 2.6 and later.
+This feature is available with Postfix 2.6 and later. Support
+for -M was added with Postfix 2.11.
.SH DIAGNOSTICS
.ad
.fi
.nf
.ad
.fi
-The following \fBmain.cf\fR parameters are especially relevant to
-this program.
+The following \fBmain.cf\fR parameters are especially
+relevant to this program.
The text below provides only a parameter summary. See
\fBpostconf\fR(5) for more details including examples.
.na
.nf
/etc/postfix/main.cf, Postfix configuration parameters
-/etc/postfix/master.cf, Postfix master daemon configuraton
+/etc/postfix/master.cf, Postfix master daemon configuration
.SH "SEE ALSO"
.na
.nf
-bounce(5), bounce template file format
-master(5), master.cf configuration file syntax
-postconf(5), main.cf configuration file syntax
+bounce(5), bounce template file format master(5), master.cf
+configuration file syntax postconf(5), main.cf configuration
+file syntax
.SH "README FILES"
.na
.nf
.ad
.fi
-Use "\fBpostconf readme_directory\fR" or
-"\fBpostconf html_directory\fR" to locate this information.
+Use "\fBpostconf readme_directory\fR" or "\fBpostconf
+html_directory\fR" to locate this information.
.na
.nf
DATABASE_README, Postfix lookup table overview
.nf
.ad
.fi
-The Secure Mailer license must be distributed with this software.
+The Secure Mailer license must be distributed with this
+software.
.SH "AUTHOR(S)"
.na
.nf
-Wietse Venema
-IBM T.J. Watson Research
-P.O. Box 704
-Yorktown Heights, NY 10598, USA
+Wietse Venema IBM T.J. Watson Research P.O. Box 704 Yorktown
+Heights, NY 10598, USA
empty value means allow all protocols. The valid protocol names, (see
\\fBfBSSL_get_version\fR(3)\fR), are "SSLv2", "SSLv3" and "TLSv1".
.PP
-At the dane and
-dane-only security
-levels, when usable TLSA records are obtained for the remote SMTP
-server, the Postfix SMTP client is obligated to include the SNI TLS
-extension in its SSL client hello message. This may help the remote
-SMTP server live up to its promise to provide a certificate that
-matches its TLSA records. Since TLS extensions require TLS 1.0 or
-later, the Postfix SMTP client must disable SSLv2 and SSLv3 when
-SNI is required. If you use "dane" or "dane-only" do not disable
-TLSv1, except perhaps via the policy table for destinations which
-you are sure will support TLSv1.1 or TLSv1.2.
-.PP
Note: As of OpenSSL 1.0.1 two new protocols are defined, "TLSv1.1"
and "TLSv1.2". If an older Postfix version is linked against OpenSSL
1.0.1 or later, these, or any other new protocol versions, are
.ft C
# Preferred form with Postfix >= 2.5:
smtp_tls_mandatory_protocols = !SSLv2, !SSLv3
-# Alternative form.
+# Legacy form with Postfix < 2.5:
smtp_tls_mandatory_protocols = TLSv1
.fi
.ad
obtained via TLSA records in DNSSEC. If no TLSA records are found,
the effective security level used is may. If TLSA records are
found, but none are usable, the effective security level is encrypt. When usable
-TLSA records are obtained for the remote SMTP server, SSLv2 and
-SSLv3 are automatically disabled (see smtp_tls_mandatory_protocols),
-and the server certificate must match the TLSA records. The
-tls_dane_trust_anchor_digest_enable parameter controls optional
-support for trust-anchor digest TLSA records. RFC 6698 (DANE) TLS
-authentication and DNSSEC support is available with Postfix 2.11
-and later.
+TLSA records are obtained for the remote SMTP server, the
+server certificate must match the TLSA records. RFC 6698 (DANE)
+TLS authentication and DNSSEC support is available with Postfix
+2.11 and later.
.br
.IP "\fBdane-only\fR"
Mandatory DANE TLS. The TLS policy for the destination is
obtained via TLSA records in DNSSEC. If no TLSA records are found,
or none are usable, no connection is made to the server. When
-usable TLSA records are obtained for the remote SMTP server, SSLv2
-and SSLv3 are automatically disabled (see smtp_tls_mandatory_protocols),
-and the server certificate must match the TLSA records. The
-tls_dane_trust_anchor_digest_enable parameter controls optional
-support for trust-anchor digest TLSA records. RFC 6698 (DANE) TLS
+usable TLSA records are obtained for the remote SMTP server, the
+server certificate must match the TLSA records. RFC 6698 (DANE) TLS
authentication and DNSSEC support is available with Postfix 2.11
and later.
.br
.nf
.na
.ft C
-# TLSv1 only!
+# TLSv1 or better:
smtp_tls_protocols = !SSLv2, !SSLv3
.fi
.ad
effective security level is "may" or "encrypt" respectively. For
purposes of protocol and cipher selection, the "dane" security level
is treated like a "mandatory" TLS security level, and weak ciphers
-and protocols are disabled. SSLv2 and SSLv3 are automatically
-disabled when usable TLSA records are obtained for the remote SMTP
-server, see smtp_tls_mandatory_protocols for details. Since DANE
-authenticates server certificates the "aNULL" cipher-suites are
-transparently excluded at this level, no need to configure this
-manually. The tls_dane_trust_anchor_digest_enable main.cf parameter
-controls optional support for trust-anchor digest TLSA records.
-RFC 6698 (DANE) TLS authentication is available with Postfix 2.11
-and later.
+and protocols are disabled. Since DANE authenticates server
+certificates the "aNULL" cipher-suites are transparently excluded
+at this level, no need to configure this manually. RFC 6698 (DANE)
+TLS authentication is available with Postfix 2.11 and later.
.br
.IP "\fBdane-only\fR"
-Mandatory DANE TLS. This is just like "dane" above, only DANE
-TLSA authentication is mandatory. RFC 6698 (DANE) TLS authentication
-is available with Postfix 2.11 and later.
+Mandatory DANE TLS. This is just like "dane" above, but DANE
+TLSA authentication is required. There is no fallback to "may" or
+"encrypt" when TLSA records are missing or unusable. RFC 6698
+(DANE) TLS authentication is available with Postfix 2.11 and later.
.br
.IP "\fBfingerprint\fR"
Certificate fingerprint verification.
This feature is available in Postfix 2.3 and later.
.SH smtpd_tls_mandatory_protocols (default: !SSLv2)
The SSL/TLS protocols accepted by the Postfix SMTP server with
-mandatory TLS encryption. If the list is empty, the server supports all
-available SSL/TLS protocol versions. A non-empty value is a list
-of protocol
-names separated by whitespace, commas or colons. The supported protocol
-names are "SSLv2", "SSLv3" and "TLSv1", and are not case sensitive.
+mandatory TLS encryption. If the list is empty, the server supports
+all available SSL/TLS protocol versions. A non-empty value is a
+list of protocol names separated by whitespace, commas or colons.
+The supported protocol names are "SSLv2", "SSLv3" and "TLSv1", and
+are not case sensitive.
.PP
Note: As of OpenSSL 1.0.1 two new protocols are defined, "TLSv1.1"
and "TLSv1.2". If an older Postfix version is linked against OpenSSL
.nf
.na
.ft C
-smtpd_tls_mandatory_protocols = TLSv1
-# Alternative form with Postfix >= 2.5:
smtpd_tls_mandatory_protocols = !SSLv2, !SSLv3
+# Legacy form with Postfix < 2.5:
+smtpd_tls_mandatory_protocols = TLSv1
.fi
.ad
.ft R
(or 168bit) session key.
.PP
This feature is available in Postfix 2.2 and later.
+.SH tls_dane_digest_agility (default: on)
+Configure DANE TLSA digest algorithm agility. When digest
+algorithm agility is enabled, and the server and client support a
+common strong digest algorithm, TLSA records with weaker digest
+algorithms are ignored.
+.PP
+Specify one of the following:
+.IP "\fBoff\fR"
+DANE verification examines each well-formed record in the TLSA
+RRset whose matching type is either "0" (no hash used) or is one of
+the digest algorithms listed in $tls_dane_digests. This setting
+is not recommended.
+.br
+.IP "\fBon\fR"
+From each group of well-formed TLSA RRs a non-zero digest
+matching type with the same certificate usage and selector, DANE
+verification examines only those records whose matching type has
+the highest precedence (appear earliest in $tls_dane_digests) are
+considered.
+.br
+.IP "\fBmaybe\fR"
+For compatibility with digest algorithm agility, each certificate
+or public key whose digest is included in a DANE TLSA RRset, SHOULD
+be published with the same set of digest matching type values as
+any other with the same usage and selector. Therefore, compatible
+TLSA RRsets will contain an identical count of well-formed RRs with
+each non-zero digest matching type for any fixed combination of
+usage and selector. When this constraint is violated, or any of
+the digest records are malformed, digest algorithm agility will
+disabled. Otherwise, digest algorithm agility is enabled.
+.br
+.br
+.PP
+Digest algorithm agility ensures that the strongest digest
+supported by both the Postfix SMTP client and the remote server is
+used, and weaker digests are ignored. This supports non-disruptive
+deprecation of outdated digest algorithms.
+.PP
+To ensure compatibility with digest algorithm agility during
+key rotation, when a certificate or public key is being replaced
+with another, and both are published during the transition, both
+the old and the new certificate MUST be specified with the same set
+of digests. One can change the list of digest algorithms later,
+once old keys are retired. At any given time, change either the
+list of digests without changing the list of certificates or public
+keys or the list of certificates or public keys without changing
+the list of digests. Full value matching type "0" records are not
+subject to this constraint, but are discouraged due to the size of
+the resulting DNS records.
+.PP
+It is expected that this algorithm agility mechanism will be
+published in a standards track RFC for SMTP with DANE, and also in
+an eventual update to RFC 6698.
+.PP
+This feature is available in Postfix 2.11 and later.
.SH tls_dane_digests (default: sha512 sha256)
RFC 6698 TLSA resource-record "matching type" digest algorithms
in descending preference order. All the specified algorithms must
be supported by the underlying OpenSSL library, otherwise the Postfix
SMTP client will not support DANE TLSA security.
.PP
+Specify a list of digest names separated by commas and/or
+whitespace. Each digest name may be followed by an optional
+"=<number>" suffix. For example, "sha512" may instead be specified
+as "sha512=2" and "sha256" may instead be specified as "sha256=1".
+The optional number must match the <a
+href="https://www.iana.org/assignments/dane-parameters/dane-parameters.xhtml#matching-types"
+>IANA assigned TLSA matching type number the algorithm in question.
+Postfix will check this constraint for the algorithms it knows about.
+Additional matching type algorithms registered with IANA can be added
+with explicit numbers provided they are supported by OpenSSL.
+.PP
+Invalid list elements are logged with a warning and disable DANE
+support. TLSA RRs that specify digests not included in the list are
+ignored with a warning.
+.PP
+Note: It is unwise to omit sha256 from the digest list. This
+digest algorithm is the only mandatory to implement digest algorithm
+in RFC 6698, and many servers are expected publish TLSA records
+with just sha256 digests. Unless one of the standard digests is
+seriously compromised and servers have had ample time to update their
+TLSA records you should not omit any standard digests, just arrange
+them in order from strongest to weakest.
+.PP
When for a particular combination of "certificate usage" and
-"selector" the TLSA RRset contains a well-formed record with a
-matching type of "0", i.e. a full value of the associated certificate
-or public key, the Postfix SMTP client will ignore all other matching
-types for the same certificate usage and selector. In this case
-the first algorithm listed in tls_dane_digests will be used to
-compute a digest of the full value, which will then be used to match
-certificates or public keys in the server's certificate chain.
-.PP
-Otherwise, when for a particular combination of "certificate
-usage" and "selector" the TLSA RRset contains a records with more
-than one non-zero matching type, i.e. multiple digest algorithms,
-only records with the highest preference digest are used after
-discarding any records with an incorrect digest length as unusable.
-.PP
-This strategy ensures that the strongest digest supported by
-both the Postfix SMTP client and the remote server is used, and
-weaker digests are ignored. This supports non-disruptive deprecation
-of outdated digest algorithms.
-.PP
-The strategy requires that when a TLSA RRset provides association
-data for multiple certificates or public keys, all RRs with the same
-"certificate usage" and "selector" be published with the same set
-of digests. In particular, during key rotation, when a certificate
-or public key is being replaced with another (and both are published
-during the transition) both the old and the new certificate MUST be
-specified with the same set of digests. One can change the list of
-digest algorithms later, once old keys are retired. At any given
-time change either the list of digests without changing the list of
-certificates or public keys or the list of certificates or public
-keys without changing the list of digests.
+"selector" the TLSA RRset contains records with more than one digest
+matching type, the tls_dane_digest_agility parameter determines
+whether all the RRs are used, or only those with the most preferred
+digest matching type.
.PP
-It is expected that this algorithm agility mechanism will be
-published in a standards track RFC for SMTP with DANE, and perhaps
-in an eventual update to RFC 6698.
+The tls_dane_trust_anchor_digest_enable parameter controls
+whether any digest TLSA records are acceptable in usage "2" (trust
+anchor assertion) TLSA records.
.PP
-This feature is available in Postfix 2.11.
-.SH tls_dane_trust_anchor_digest_enable (default: trust-anchor-assertion)
+This feature is available in Postfix 2.11 and later.
+.SH tls_dane_trust_anchor_digest_enable (default: yes)
RFC 6698 trust-anchor digest support in the Postfix TLS library.
-Specify zero or more of the following options, separated by comma or
-whitespace. Option names are case-insensitive.
-.IP "\fBca-constraint\fR"
-Enable support for RFC 6698 (DANE TLSA) DNS records that
-contain digests of trust-anchors with certificate usage "0".
-These are often public root CAs, and server operators may
-expect that clients will have the corresponding root certificate
-in their CAfile or CApath. Most SSL/TLS servers do not send public
-root CA certificate in their certificate chain, so if Postfix does
-not have the CA certificate locally, there is no way to associate
-the digest with the trust chain from the server. These TLSA records
-are fragile, and only work when you have a complete (whatever that
-means) set of public CAs in your CAfile or CApath. Enable this
-with caution if at all.
-.br
-.IP "\fBtrust-anchor-assertion\fR"
Enable support for RFC 6698 (DANE TLSA) DNS records that contain
digests of trust-anchors with certificate usage "2". In this case
the certificate usage logically requires the server administrator
to configure the server to include the trust-anchor certificate in
-the server's SSL certificate chain. These TLSA records are less
-fragile than "ca-constraint" TLSA records, and are enabled by
-default. Having a "complete" CAfile or CApath does not help in
-this case, you are at the mercy of the remote server administrator's
-competence.
-.br
-.br
+the server's SSL certificate chain. If enough domains mess this
+up, you can disable support for these TLSA records, but you'll no
+longer have secure connections that get it right and only publish
+trust anchor records.
.PP
At the dane
security level, when a TLSA RRset includes only unusable associations,
the server in question is skipped and delivery is deferred if no
secure servers are found.
.PP
+The tls_dane_digests parameter controls the list of digest
+algorithms that are supported in TLSA records. The tls_dane_digest_agility
+parameter controls digest algorithm downgrade attack resistance.
+.PP
This feature is available in Postfix 2.11 and later.
.SH tls_disable_workarounds (default: see "postconf -d" output)
List or bit-mask of OpenSSL bug work-arounds to disable.
issues. In the past, some SSL clients have listed lower priority ciphers
that they did not implement correctly. If the server chooses a cipher
that the client prefers less, it may select a cipher whose client
-implementation is flawed.
+implementation is flawed. Most notably Windows 2003 Microsoft
+Exchange servers have flawed implementations of DES-CBC3-SHA, which
+OpenSSL considers stronger than RC4-SHA. Enabling server cipher-suite
+selection may create interoperability issues with Windows 2003
+Microsoft Exchange clients.
.PP
This feature is available in Postfix 2.8 and later, in combination
with OpenSSL 0.9.7 and later.
.IP "\fBsmtp_tls_force_insecure_host_tlsa_lookup (no)\fR"
Lookup the associated DANE TLSA RRset even when a hostname is
not an alias and its address records lie in an unsigned zone.
-.IP "\fBtls_dane_trust_anchor_digest_enable (trust-anchor-assertion)\fR"
+.IP "\fBtls_dane_trust_anchor_digest_enable (yes)\fR"
RFC 6698 trust-anchor digest support in the Postfix TLS library.
.IP "\fBtlsmgr_service_name (tlsmgr)\fR"
The name of the \fBtlsmgr\fR(8) service entry in master.cf.
</pre>
</blockquote>
-<li> <p> If you use RFC 6698 TLSA "2 0 1" or "2 1 1" records to
+<li> <p> If you publish RFC 6698 TLSA "2 0 1" or "2 1 1" records to
specify root CA certificate digests, you must include the corresponding
-root CA certificates in the "server.pem" certificate file. </p>
+root CA certificates in the "server.pem" certificate file. See the
+documentation of the tls_dane_trust_anchor_digest_enable main.cf
+parameter. </p>
<blockquote>
<pre>
</pre>
</blockquote>
-<p> Remote SMTP clients will
-be able to use the TLSA record you publish (which only contains the
-certificate digest) only if they have access to the corresponding
-certificate. Failure to verify certificates per the server's
-published TLSA records will typically cause the SMTP client to defer
-mail delivery. The foregoing also applies to "2 0 2" and "2 1 2"
-TLSA records or any other digest of a CA certificate, but it is
-expected that SHA256 will be by far the most common digest for TLSA.
-You are <i>strongly</i> urged to likewise include the root CA
-certificate in your server certificate file even if you use "0 0
-1" or "0 1 1" TLSA records. Some DANE implementations in SMTP
-clients (Postfix among them) may treat RFC 6698 certificate usages
-"0" and "2" interchangeably. </p>
-
-<p>By default, support for TLSA records that specify certificate
-usage "0" via a digest is disabled in the Postfix SMTP client. As
-a best practice, publish either "3 0 1" or "3 1 1" TLSA associations
-that specify the SHA256 digest of the server certificate public key
-with the alias-expanded hostname of each STARTTLS capable SMTP
-server. These continue to work when a certificate is renewed with
-the same public/private key pair. See the documentation of the
-tls_dane_trust_anchor_digest_enable main.cf parameter for details.
-</p>
+<p> Remote SMTP clients will be able to use the TLSA record you
+publish (which only contains the certificate digest) only if they
+have access to the corresponding certificate. Failure to verify
+certificates per the server's published TLSA records will typically
+cause the SMTP client to defer mail delivery. The foregoing also
+applies to "2 0 2" and "2 1 2" TLSA records or any other digest of
+a CA certificate, but it is expected that SHA256 will be by far the
+most common digest for TLSA. </p>
+
+<p> As a best practice, publish either "3 0 1" or "3 1 1" TLSA
+associations that specify the SHA256 digest of the server certificate
+public key with the alias-expanded hostname of each STARTTLS capable
+SMTP server. These continue to work when a certificate is renewed
+with the same public/private key pair. </p>
</ul>
enabled by explicitly setting "smtpd_tls_cert_file = none"
and not specifying an smtpd_tls_dcert_file or smtpd_tls_eccert_file. </p>
-<p> Example, MSA that requires TLSv1, not SSLv2 or SSLv3, with high grade
-ciphers: </p>
+<p> Example, MSA that requires TLSv1 or higher, not SSLv2 or SSLv3,
+with high grade ciphers: </p>
<blockquote>
<pre>
smtpd_tls_mandatory_ciphers = high
smtpd_tls_mandatory_exclude_ciphers = aNULL, MD5
smtpd_tls_security_level = encrypt
- # Preferred form with Postfix ≥ 2.5:
+ # Postfix ≥ 2.5:
smtpd_tls_mandatory_protocols = !SSLv2, !SSLv3
- # Alternative form.
+ # Legacy form with Postfix prior to 2.5:
smtpd_tls_mandatory_protocols = TLSv1
</pre>
</blockquote>
</blockquote>
<p> Postfix 2.8 and later, in combination with OpenSSL 0.9.7 and later
-allows TLS servers to preempt the TLS client's cipher preference list.
+allows TLS servers to preempt the TLS client's cipher-suite preference list.
This is possible only with SSLv3 and later, as in SSLv2 the client
-chooses the cipher from a list supplied by the server. </p>
+chooses the cipher-suite from a list supplied by the server. </p>
<p> By default, the OpenSSL server selects the client's most preferred
-cipher that the server supports. With SSLv3 and later, the server
-may choose its own most preferred cipher that is supported (offered)
+cipher-suite that the server supports. With SSLv3 and later, the server
+may choose its own most preferred cipher-suite that is supported (offered)
by the client. Setting "tls_preempt_cipherlist = yes" enables server
-cipher preferences. The default OpenSSL behavior applies with
+cipher-suite preferences. The default OpenSSL behavior applies with
"tls_preempt_cipherlist = no". </p>
-<p> While server cipher selection may in some cases lead to a more secure
-or performant cipher choice, there is some risk of interoperability
-issues. In the past, some SSL clients have listed lower priority ciphers
-that they did not implement correctly. If the server chooses a cipher
-that the client prefers less, it may select a cipher whose client
-implementation is flawed. </p>
+<p> While server cipher-suite selection may in some cases lead to
+a more secure or performant cipher-suite choice, there is some risk
+of interoperability issues. In the past, some SSL clients have
+listed lower priority ciphers that they did not implement correctly.
+If the server chooses a cipher that the client prefers less, it may
+select a cipher whose client implementation is flawed. Most notably
+Windows 2003 Microsoft Exchange servers have flawed implementations
+of DES-CBC3-SHA, which OpenSSL considers stronger than RC4-SHA.
+Enabling server cipher-suite selection may create interoperability
+issues with Windows 2003 Microsoft Exchange clients. </p>
<h3><a name="server_misc"> Miscellaneous server controls</a> </h3>
href="#client_tls_may">opportunistic</a> TLS that is resistant to
man in the middle and downgrade attacks when the destination domain
uses DNSSEC to publish DANE TLSA records for its MX hosts. If a
-remote SMTP server has usable DANE TLSA records, these will be used
-to authenticate the server. If TLSA records are published for a
-given remote SMTP server (implying TLS support), but are not usable
-due to unsupported parameters, the Postfix SMTP client will use <a
+remote SMTP server has "usable" (see RFC 6698) DANE TLSA records,
+the server connection will be authenticated. When DANE authentication
+fails, there is no fallback to unauthenticated or plaintext delivery. </p>
+
+<p> If TLSA records are published for a given remote SMTP server
+(implying TLS support), but are all "unusable" due to unsupported
+parameters or malformed data, the Postfix SMTP client will use <a
href="#client_tls_encrypt">mandatory</a> unauthenticated TLS.
-Otherwise, the Postfix SMTP client behavior is the same as with <a
-href="#client_tls_may">may</a>. </p>
+Otherwise, when no TLSA records are published, the Postfix SMTP
+client behavior is the same as with <a href="#client_tls_may">may</a>. </p>
+
+<p> TLSA records must be published in DNSSEC validated DNS zones.
+Any TLSA records in DNS zones not protected via DNSSEC are ignored.
+The Postfix SMTP client will not look for TLSA records associated
+with MX hosts whose "A" or "AAAA" records lie in an "insecure" DNS
+zone. Such lookups have been observed to cause interoperability
+issues with poorly implemented DNS servers, and are in any case not
+expected to ever yield "secure" results, since that would require
+a very unlikey DLV DNS trust anchor configured between the host
+record and the associated "_25._tcp" child TLSA record. </p>
<p> The "dane-only" level is a form of <a
href="#client_tls_secure">secure-channel</a> TLS based on the DANE PKI.
-If usable TLSA records are present these are used to authenticate the
+If "usable" TLSA records are present these are used to authenticate the
remote SMTP server. Otherwise, or when server certificate verification
fails, delivery via the server in question tempfails. </p>
be signed and the Postfix SMTP client's operating system must be
configured to send its DNS queries to a recursive DNS nameserver
that is able to validate the signed records. Each MX host's DNS
-zone should also be signed, and should publish DANE TLSA (RFC 6698)
+zone needs to also be signed, and needs to publish DANE TLSA (RFC 6698)
records that specify how that MX host's TLS certificate is to be
-verified. TLSA records do not preempt the normal SMTP MX host
+verified. </p>
+
+<p> TLSA records do not preempt the normal SMTP MX host
selection algorithm, if some MX hosts support TLSA and others do
not, TLS security will vary from delivery to delivery. It is up
to the domain owner to configure their MX hosts and their DNS
sensibly. To configure the Postfix SMTP client for DNSSEC lookups
see the documentation for the smtp_dns_support_level main.cf
parameter. The tls_dane_trust_anchor_digest_enable main.cf parameter
-controls optional support for trust-anchor digest TLSA records.
+controls support for trust-anchor digest TLSA records. The
+tls_dane_digests and tls_dane_digest_agility parameters control
+the list of supported digests and digest downgrade attack resistance.
</p>
-<p> The Postfix SMTP client deviates from RFC 6698 in cases where
-strict adherence is likely to create opportunities for delayed (or
-eventually bounced) email with no substantive security gain. Most
-notably, it is not expected that smtp_tls_CAfile and smtp_tls_CApath
-can reasonably include every public CA that a remote SMTP server's
-administrator may believe to be well-known. Therefore, certificate
-usages "0" and "2" from RFC 6698 which are intended to "constrain"
-existing PKI trust, are instead treated as "trust assertions" and
-mapped to "1" and "3" respectively. That is, with certificate usage
-"0" and "2", Postfix will not require the remote SMTP server's
-certificate to be trusted with respect to any locally defined public
-CAs, it is the domain owner's responsibility to ensure that the
-certificate associations in their TLSA records are appropriate
-to authenticate their SMTP servers. </p>
-
-<p> In addition, the Postfix SMTP client does not assume that the
-remote SMTP server will necessarily be configured to present the
-certificate of any usage "0" root CA in its TLS protocol <a
-href="https://tools.ietf.org/html/rfc2246#section-7.4.2">certificate_list</a>.
-Therefore, support for usage "0" certificate and public-key digests
-is disabled by default, see tls_dane_trust_anchor_digest_enable for
-details. While undigested trust-anchor certificates in TLSA records
-are supported, publishing complete certificates in DNS is unwise
-given the resulting excessively large DNS record sizes. Therefore,
-in its default configuration the Postfix SMTP client essentially
-supports only certificate usages "1", "2" and "3" (with "1" treated as
-though it were "3"). </p>
-
-<p> Finally, the interaction of DANE with MX hostnames that are
-CNAMEs differs from the draft specification in the names used to
-construct the associated <a
-href="https://tools.ietf.org/html/draft-ietf-dane-srv-02#section-3.2">TLSA
-queries</a>. When the MX hostname is a CNAME, the draft proposal
-to use the unexpanded MX hostname in TLSA lookups is fragile and
-unintuitive. For this to work, the domain owner has to either
-duplicate the TLSA records of the target (host, service) pair in
-his own DNS or furnish the target host with an additional
-certificate and private key that would be negotiated via SNI.
-Neither of these are robust or easy to manage. It is far better
-to expand the CNAME recursively to the underlying target hostname
-(keeping track of DNSSEC validation along the way) and to use the
-expanded name to construct the TLSA query and, if appropriate, in
-server certificate name checks. This is the approach taken by the
-Postfix SMTP client, and if sanity prevails will also be the approach
-taken in the final standard. </p>
+<p> DANE for SMTP MTAs deviates in some details from the baseline
+DANE protocol in RFC 6698. Most notably, it is not expected that
+SMTP MTAs can reasonably include every public CA that a remote SMTP
+server's administrator may believe to be well-known. Nor is there
+an interactive user to "click OK" when authentication fails. </p>
+
+<p> Therefore, certificate usages "0" and "1" from RFC 6698 which
+are intended to "constrain" existing PKI trust, are not supported.
+TLSA records with usage "0" are treated as "unusable". TLSA records
+with usage "1" are instead treated as "trust assertions" and mapped
+to usage "3". Specifically, with certificate usage "1", Postfix
+will not require the remote SMTP server's certificate to be trusted
+with respect to any locally defined public CAs, it is the domain
+owner's responsibility to ensure that the certificate associations
+in their TLSA records are appropriate to authenticate their SMTP
+servers. </p>
+
+<p> The Postfix SMTP client supports only certificate usages "2"
+and "3" (with "1" treated as though it were "3"). See
+tls_dane_trust_anchor_digest_enable for usage "2" usability
+considerations. Support for certificate usage "1" is an experiment,
+it may be withdrawn in the future. Server operators SHOULD NOT
+publish TLSA records with usage "1". </p>
<p> When usable TLSA records are obtained for the remote SMTP server
-the Postfix SMTP client is obligated to include the SNI TLS extension
-in its SSL client hello message. This may help the remote SMTP
-server live up to its promise to provide a certificate that matches
-its TLSA records. Since TLS extensions require TLS 1.0 or later,
-the Postfix SMTP client must disable SSLv2 and SSLv3 when SNI is
-required. If you use "dane" or "dane-only", do not disable TLSv1,
-except perhaps via the policy table for destinations which you are
-sure will support TLSv1.1 or TLSv1.2. </p>
+the Postfix SMTP client sends the SNI TLS extension in its SSL
+client hello message. This may help the remote SMTP server live
+up to its promise to provide a certificate that matches its TLSA
+records. </p>
<p> For purposes of protocol and cipher selection, the "dane"
security level is treated like a "mandatory" TLS security level,
<p> When a DANE TLSA record specifies an end-entity (EE) certificate,
(that is the actual server certificate), as with the fingerprint
security level below, no name checks or certificate expiration checks
-are applied. The server certificate (or its public key) either matches
+are applied. The server certificate (or its public key) either matches
the DANE record or not. Server administrators should publish such
EE records in preference to all other types. </p>
<p> The pre-requisites for DANE support in the Postfix SMTP client are: </p>
<ul>
<li> A <i>compile-time</i> OpenSSL library that supports the TLS SNI
-extension and the "sha256" and "sha512" message digests.
+extension and "SHA-2" message digests.
<li> A <i>compile-time</i> DNS resolver library that supports DNSSEC.
Postfix binaries built on an older system will not support DNSSEC even
if deployed on a system with an updated resolver library.
it is a dedicated MSA that only handles outbound mail from trusted clients,
below we focus on the client security policy. </p>
-<p> On the SMTP client, there are further complications. When delivering
-mail to a given domain, in contrast to HTTPS, one rarely uses the domain
-name directly as the target host of the SMTP session. More typically,
-one uses MX lookups - these are usually unauthenticated - to obtain the domain's SMTP server
-hostname(s). When, as is current practice, the client verifies the
-insecurely obtained MX hostname, it is subject to a DNS man-in-the-middle
+<p> On the SMTP client, there are further complications. When
+delivering mail to a given domain, in contrast to HTTPS, one rarely
+uses the domain name directly as the target host of the SMTP session.
+More typically, one uses MX lookups — these are usually
+unauthenticated — to obtain the domain's SMTP server hostname(s).
+When, as is current practice, the client verifies the insecurely
+obtained MX hostname, it is subject to a DNS man-in-the-middle
attack. </p>
<p> Adoption of DNSSEC and RFC6698 (DANE) may gradually (as domains
used is <a href="#client_tls_may">may</a>. If TLSA records are
found, but none are usable, the effective security level is <a
href="#client_tls_encrypt">encrypt</a>. When usable TLSA records
-are obtained for the remote SMTP server, SSLv2 and SSLv3 are
-automatically disabled (see smtp_tls_mandatory_protocols), and the
-server certificate must match the TLSA records. The
-tls_dane_trust_anchor_digest_enable parameter controls optional
-support for trust-anchor digest TLSA records. RFC 6698 (DANE) TLS
-authentication and DNSSEC support is available with Postfix 2.11
-and later. </dd>
+are obtained for the remote SMTP server, SSLv2 is automatically
+disabled (see smtp_tls_mandatory_protocols), and the server certificate
+must match the TLSA records. RFC 6698 (DANE) TLS authentication
+and DNSSEC support is available with Postfix 2.11 and later. </dd>
<dt><b>dane-only</b></dt> <dd><a href="#client_tls_dane">Mandatory DANE TLS</a>.
The TLS policy for the destination is obtained via TLSA records in
DNSSEC. If no TLSA records are found, or none are usable, no
connection is made to the server. When usable TLSA records are
-obtained for the remote SMTP server, SSLv2 and SSLv3 are automatically
-disabled (see smtp_tls_mandatory_protocols), and the server certificate
-must match the TLSA records. The tls_dane_trust_anchor_digest_enable
-parameter controls optional support for trust-anchor digest TLSA
-records. RFC 6698 (DANE) TLS authentication and DNSSEC support is
-available with Postfix 2.11 and later. </dd>
+obtained for the remote SMTP server, SSLv2 is automatically disabled
+(see smtp_tls_mandatory_protocols), and the server certificate must
+match the TLSA records. RFC 6698 (DANE) TLS authentication and
+DNSSEC support is available with Postfix 2.11 and later. </dd>
<dt><b>fingerprint</b></dt> <dd><a href="#client_tls_fprint">Certificate
fingerprint verification.</a> Available with Postfix 2.5 and
/etc/postfix/tls_policy:
example.edu none
example.mil may
- example.gov encrypt protocols=SSLv3:TLSv1 ciphers=high
- example.com verify
- match=hostname:dot-nexthop protocols=SSLv3:TLSv1 ciphers=high
+ example.gov encrypt ciphers=high
+ example.com verify match=hostname:dot-nexthop ciphers=high
example.net secure
.example.net secure match=.example.net:example.net
[mail.example.org]:587 secure match=nexthop
smtp_tls_exclude_ciphers = aNULL
# Preferred form with Postfix ≥ 2.5:
smtp_tls_mandatory_protocols = !SSLv2
- # Alternative form.
+ # Legacy form for Postifx < 2.5:
smtp_tls_mandatory_protocols = SSLv3, TLSv1
# Also available with Postfix ≥ 2.6:
smtp_tls_ciphers = export
href="TLS_README.html#client_tls_may">may</a>. If TLSA records are
found, but none are usable, the effective security level is <a
href="TLS_README.html#client_tls_encrypt">encrypt</a>. When usable
-TLSA records are obtained for the remote SMTP server, SSLv2 and
-SSLv3 are automatically disabled (see smtp_tls_mandatory_protocols),
-and the server certificate must match the TLSA records. The
-tls_dane_trust_anchor_digest_enable parameter controls optional
-support for trust-anchor digest TLSA records. RFC 6698 (DANE) TLS
-authentication and DNSSEC support is available with Postfix 2.11
-and later. </dd>
+TLSA records are obtained for the remote SMTP server, the
+server certificate must match the TLSA records. RFC 6698 (DANE)
+TLS authentication and DNSSEC support is available with Postfix
+2.11 and later. </dd>
<dt><b><a href="TLS_README.html#client_tls_dane">dane-only</a></b></dt>
<dd>Mandatory DANE TLS. The TLS policy for the destination is
obtained via TLSA records in DNSSEC. If no TLSA records are found,
or none are usable, no connection is made to the server. When
-usable TLSA records are obtained for the remote SMTP server, SSLv2
-and SSLv3 are automatically disabled (see smtp_tls_mandatory_protocols),
-and the server certificate must match the TLSA records. The
-tls_dane_trust_anchor_digest_enable parameter controls optional
-support for trust-anchor digest TLSA records. RFC 6698 (DANE) TLS
+usable TLSA records are obtained for the remote SMTP server, the
+server certificate must match the TLSA records. RFC 6698 (DANE) TLS
authentication and DNSSEC support is available with Postfix 2.11
and later. </dd>
empty value means allow all protocols. The valid protocol names, (see
<b>SSL_get_version(3)</b>), are "SSLv2", "SSLv3" and "TLSv1". </p>
-<p> At the <a href="TLS_README.html#client_tls_dane">dane</a> and
-<a href="TLS_README.html#client_tls_dane">dane-only</a> security
-levels, when usable TLSA records are obtained for the remote SMTP
-server, the Postfix SMTP client is obligated to include the SNI TLS
-extension in its SSL client hello message. This may help the remote
-SMTP server live up to its promise to provide a certificate that
-matches its TLSA records. Since TLS extensions require TLS 1.0 or
-later, the Postfix SMTP client must disable SSLv2 and SSLv3 when
-SNI is required. If you use "dane" or "dane-only" do not disable
-TLSv1, except perhaps via the policy table for destinations which
-you are sure will support TLSv1.1 or TLSv1.2. </p>
-
<p> Note: As of OpenSSL 1.0.1 two new protocols are defined, "TLSv1.1"
and "TLSv1.2". If an older Postfix version is linked against OpenSSL
1.0.1 or later, these, or any other new protocol versions, are
<pre>
# Preferred form with Postfix ≥ 2.5:
smtp_tls_mandatory_protocols = !SSLv2, !SSLv3
-# Alternative form.
+# Legacy form with Postfix < 2.5:
smtp_tls_mandatory_protocols = TLSv1
</pre>
%PARAM smtpd_tls_mandatory_protocols !SSLv2
<p> The SSL/TLS protocols accepted by the Postfix SMTP server with
-mandatory TLS encryption. If the list is empty, the server supports all
-available SSL/TLS protocol versions. A non-empty value is a list
-of protocol
-names separated by whitespace, commas or colons. The supported protocol
-names are "SSLv2", "SSLv3" and "TLSv1", and are not case sensitive. </p>
+mandatory TLS encryption. If the list is empty, the server supports
+all available SSL/TLS protocol versions. A non-empty value is a
+list of protocol names separated by whitespace, commas or colons.
+The supported protocol names are "SSLv2", "SSLv3" and "TLSv1", and
+are not case sensitive. </p>
<p> Note: As of OpenSSL 1.0.1 two new protocols are defined, "TLSv1.1"
and "TLSv1.2". If an older Postfix version is linked against OpenSSL
<p> Example: </p>
<pre>
-smtpd_tls_mandatory_protocols = TLSv1
-# Alternative form with Postfix ≥ 2.5:
smtpd_tls_mandatory_protocols = !SSLv2, !SSLv3
+# Legacy form with Postfix < 2.5:
+smtpd_tls_mandatory_protocols = TLSv1
</pre>
<p> This feature is available in Postfix 2.3 and later. </p>
effective security level is "may" or "encrypt" respectively. For
purposes of protocol and cipher selection, the "dane" security level
is treated like a "mandatory" TLS security level, and weak ciphers
-and protocols are disabled. SSLv2 and SSLv3 are automatically
-disabled when usable TLSA records are obtained for the remote SMTP
-server, see smtp_tls_mandatory_protocols for details. Since DANE
-authenticates server certificates the "aNULL" cipher-suites are
-transparently excluded at this level, no need to configure this
-manually. The tls_dane_trust_anchor_digest_enable main.cf parameter
-controls optional support for trust-anchor digest TLSA records.
-RFC 6698 (DANE) TLS authentication is available with Postfix 2.11
-and later. </dd>
+and protocols are disabled. Since DANE authenticates server
+certificates the "aNULL" cipher-suites are transparently excluded
+at this level, no need to configure this manually. RFC 6698 (DANE)
+TLS authentication is available with Postfix 2.11 and later. </dd>
<dt><b><a href="TLS_README.html#client_tls_dane">dane-only</a></b></dt>
-<dd>Mandatory DANE TLS. This is just like "dane" above, only DANE
-TLSA authentication is mandatory. RFC 6698 (DANE) TLS authentication
-is available with Postfix 2.11 and later. </dd>
+<dd>Mandatory DANE TLS. This is just like "dane" above, but DANE
+TLSA authentication is required. There is no fallback to "may" or
+"encrypt" when TLSA records are missing or unusable. RFC 6698
+(DANE) TLS authentication is available with Postfix 2.11 and later.
+</dd>
<dt><b><a href="TLS_README.html#client_tls_fingerprint">fingerprint</a></b></dt>
<dd>Certificate fingerprint verification.
<p> Example: </p>
<pre>
-# TLSv1 only!
+# TLSv1 or better:
smtp_tls_protocols = !SSLv2, !SSLv3
</pre>
issues. In the past, some SSL clients have listed lower priority ciphers
that they did not implement correctly. If the server chooses a cipher
that the client prefers less, it may select a cipher whose client
-implementation is flawed. </p>
+implementation is flawed. Most notably Windows 2003 Microsoft
+Exchange servers have flawed implementations of DES-CBC3-SHA, which
+OpenSSL considers stronger than RC4-SHA. Enabling server cipher-suite
+selection may create interoperability issues with Windows 2003
+Microsoft Exchange clients. </p>
<p> This feature is available in Postfix 2.8 and later, in combination
with OpenSSL 0.9.7 and later. </p>
<p> This feature is available in Postfix 2.11 and later. </p>
-%PARAM tls_dane_trust_anchor_digest_enable trust-anchor-assertion
+%PARAM tls_dane_trust_anchor_digest_enable yes
<p> RFC 6698 trust-anchor digest support in the Postfix TLS library.
-Specify zero or more of the following options, separated by comma or
-whitespace. Option names are case-insensitive. </p>
-
-<dl>
-
-<dt><b>ca-constraint</b></dt>
-
-<dd> Enable support for RFC 6698 (DANE TLSA) DNS records that
-contain digests of trust-anchors with certificate usage "0".
-These are often public root CAs, and server operators may
-expect that clients will have the corresponding root certificate
-in their CAfile or CApath. Most SSL/TLS servers do not send public
-root CA certificate in their certificate chain, so if Postfix does
-not have the CA certificate locally, there is no way to associate
-the digest with the trust chain from the server. These TLSA records
-are fragile, and only work when you have a complete (whatever that
-means) set of public CAs in your CAfile or CApath. Enable this
-with caution if at all. </dd>
-
-<dt><b>trust-anchor-assertion</b></dt>
-
-<dd> Enable support for RFC 6698 (DANE TLSA) DNS records that contain
+Enable support for RFC 6698 (DANE TLSA) DNS records that contain
digests of trust-anchors with certificate usage "2". In this case
the certificate usage logically requires the server administrator
to configure the server to include the trust-anchor certificate in
-the server's SSL certificate chain. These TLSA records are less
-fragile than "ca-constraint" TLSA records, and are enabled by
-default. Having a "complete" CAfile or CApath does not help in
-this case, you are at the mercy of the remote server administrator's
-competence. </dd>
-
-</dl>
+the server's SSL certificate chain. If enough domains mess this
+up, you can disable support for these TLSA records, but you'll no
+longer have secure connections that get it right and only publish
+trust anchor records. </p>
<p> At the <a href="TLS_README.html#client_tls_dane">dane</a>
security level, when a TLSA RRset includes only unusable associations,
the server in question is skipped and delivery is deferred if no
secure servers are found. </p>
+<p> The tls_dane_digests parameter controls the list of digest
+algorithms that are supported in TLSA records. The tls_dane_digest_agility
+parameter controls digest algorithm downgrade attack resistance.
+</p>
+
<p> This feature is available in Postfix 2.11 and later. </p>
%PARAM tls_wildcard_matches_multiple_labels yes
<p> This feature is available in Postfix 2.11. </p>
+%PARAM tls_dane_digest_agility on
+
+<p> Configure DANE TLSA digest algorithm agility. When digest
+algorithm agility is enabled, and the server and client support a
+common strong digest algorithm, TLSA records with weaker digest
+algorithms are ignored. </p>
+
+<p> Specify one of the following: </p>
+
+<dl>
+
+<dt><b>off</b></dt>
+<dd> DANE verification examines each well-formed record in the TLSA
+RRset whose matching type is either "0" (no hash used) or is one of
+the digest algorithms listed in $tls_dane_digests. This setting
+is not recommended. </dd>
+
+<dt><b>on</b></dt>
+<dd> From each group of well-formed TLSA RRs a non-zero digest
+matching type with the same certificate usage and selector, DANE
+verification examines only those records whose matching type has
+the highest precedence (appear earliest in $tls_dane_digests) are
+considered. </dd>
+
+<dt><b>maybe</b></dt>
+<dd> For compatibility with digest algorithm agility, each certificate
+or public key whose digest is included in a DANE TLSA RRset, SHOULD
+be published with the same set of digest matching type values as
+any other with the same usage and selector. Therefore, compatible
+TLSA RRsets will contain an identical count of well-formed RRs with
+each non-zero digest matching type for any fixed combination of
+usage and selector. When this constraint is violated, or any of
+the digest records are malformed, digest algorithm agility will
+disabled. Otherwise, digest algorithm agility is enabled. </dd>
+
+</dl>
+
+<p> Digest algorithm agility ensures that the strongest digest
+supported by both the Postfix SMTP client and the remote server is
+used, and weaker digests are ignored. This supports non-disruptive
+deprecation of outdated digest algorithms. </p>
+
+<p> To ensure compatibility with digest algorithm agility during
+key rotation, when a certificate or public key is being replaced
+with another, and both are published during the transition, both
+the old and the new certificate MUST be specified with the same set
+of digests. One can change the list of digest algorithms later,
+once old keys are retired. At any given time, change either the
+list of digests without changing the list of certificates or public
+keys or the list of certificates or public keys without changing
+the list of digests. Full value matching type "0" records are not
+subject to this constraint, but are discouraged due to the size of
+the resulting DNS records. </p>
+
+<p> It is expected that this algorithm agility mechanism will be
+published in a standards track RFC for SMTP with DANE, and also in
+an eventual update to RFC 6698. </p>
+
+<p> This feature is available in Postfix 2.11 and later. </p>
+
%PARAM tls_dane_digests sha512 sha256
<p> RFC 6698 TLSA resource-record "matching type" digest algorithms
in descending preference order. All the specified algorithms must
be supported by the underlying OpenSSL library, otherwise the Postfix
-SMTP client will not support DANE TLSA security. </p>
+SMTP client will not support DANE TLSA security. </p>
+
+<p> Specify a list of digest names separated by commas and/or
+whitespace. Each digest name may be followed by an optional
+"=<number>" suffix. For example, "sha512" may instead be specified
+as "sha512=2" and "sha256" may instead be specified as "sha256=1".
+The optional number must match the <a
+href="https://www.iana.org/assignments/dane-parameters/dane-parameters.xhtml#matching-types"
+>IANA</a> assigned TLSA matching type number the algorithm in question.
+Postfix will check this constraint for the algorithms it knows about.
+Additional matching type algorithms registered with IANA can be added
+with explicit numbers provided they are supported by OpenSSL. </p>
+
+<p> Invalid list elements are logged with a warning and disable DANE
+support. TLSA RRs that specify digests not included in the list are
+ignored with a warning. </p>
+
+<p> Note: It is unwise to omit sha256 from the digest list. This
+digest algorithm is the only mandatory to implement digest algorithm
+in RFC 6698, and many servers are expected publish TLSA records
+with just sha256 digests. Unless one of the standard digests is
+seriously compromised and servers have had ample time to update their
+TLSA records you should not omit any standard digests, just arrange
+them in order from strongest to weakest. </p>
<p> When for a particular combination of "certificate usage" and
-"selector" the TLSA RRset contains a well-formed record with a
-matching type of "0", i.e. a full value of the associated certificate
-or public key, the Postfix SMTP client will ignore all other matching
-types for the same certificate usage and selector. In this case
-the first algorithm listed in tls_dane_digests will be used to
-compute a digest of the full value, which will then be used to match
-certificates or public keys in the server's certificate chain. </p>
-
-<p> Otherwise, when for a particular combination of "certificate
-usage" and "selector" the TLSA RRset contains a records with more
-than one non-zero matching type, i.e. multiple digest algorithms,
-only records with the highest preference digest are used after
-discarding any records with an incorrect digest length as unusable. </p>
-
-<p> This strategy ensures that the strongest digest supported by
-both the Postfix SMTP client and the remote server is used, and
-weaker digests are ignored. This supports non-disruptive deprecation
-of outdated digest algorithms. </p>
-
-<p> The strategy requires that when a TLSA RRset provides association
-data for multiple certificates or public keys, all RRs with the same
-"certificate usage" and "selector" be published with the same set
-of digests. In particular, during key rotation, when a certificate
-or public key is being replaced with another (and both are published
-during the transition) both the old and the new certificate MUST be
-specified with the same set of digests. One can change the list of
-digest algorithms later, once old keys are retired. At any given
-time change either the list of digests without changing the list of
-certificates or public keys or the list of certificates or public
-keys without changing the list of digests. </p>
+"selector" the TLSA RRset contains records with more than one digest
+matching type, the tls_dane_digest_agility parameter determines
+whether all the RRs are used, or only those with the most preferred
+digest matching type. </p>
-<p> It is expected that this algorithm agility mechanism will be
-published in a standards track RFC for SMTP with DANE, and perhaps
-in an eventual update to RFC 6698. </p>
+<p> The tls_dane_trust_anchor_digest_enable parameter controls
+whether any digest TLSA records are acceptable in usage "2" (trust
+anchor assertion) TLSA records. </p>
-<p> This feature is available in Postfix 2.11. </p>
+<p> This feature is available in Postfix 2.11 and later. </p>
* dns_lookup.c
*/
extern int dns_lookup_r(const char *, unsigned, unsigned, DNS_RR **,
- VSTRING *, VSTRING *, int *);
+ VSTRING *, VSTRING *, int *);
extern int dns_lookup_rl(const char *, unsigned, DNS_RR **, VSTRING *,
- VSTRING *, int *, int,...);
+ VSTRING *, int *, int,...);
extern int dns_lookup_rv(const char *, unsigned, DNS_RR **, VSTRING *,
- VSTRING *, int *, int, unsigned *);
+ VSTRING *, int *, int, unsigned *);
+
#define dns_lookup(name, type, rflags, list, fqdn, why) \
dns_lookup_r((name), (type), (rflags), (list), (fqdn), (why), (int *) 0)
#define dns_lookup_l(name, rflags, list, fqdn, why, lflags, ...) \
#define DEF_TLS_BC_PKEY_FPRINT 0
extern bool var_tls_bc_pkey_fprint;
+ /*
+ * Ordered list of DANE digest algorithms.
+ */
+#define TLS_DANE_AGILITY_OFF "off"
+#define TLS_DANE_AGILITY_ON "on"
+#define TLS_DANE_AGILITY_MAYBE "maybe"
+#define VAR_TLS_DANE_AGILITY "tls_dane_digest_agility"
+#define DEF_TLS_DANE_AGILITY TLS_DANE_AGILITY_ON
+extern char *var_tls_dane_agility;
+
/*
* Ordered list of DANE digest algorithms.
*/
/*
* External interface for enabling trust-anchor digests, which are risky
* when the corresponding certificate is missing from the peer chain (this
- * can't happend with the leaf certificate).
+ * can't happen with the leaf certificate).
*/
-#define TLS_DANE_CC "ca-constraint"
-#define TLS_DANE_TAA "trust-anchor-assertion"
-#define VAR_TLS_DANE_TA_DGST "tls_dane_trust_anchor_digest_enable"
-#define DEF_TLS_DANE_TA_DGST TLS_DANE_TAA
-extern char *var_tls_dane_ta_dgst;
+#define VAR_TLS_DANE_TAA_DGST "tls_dane_trust_anchor_digest_enable"
+#define DEF_TLS_DANE_TAA_DGST 1
+extern bool var_tls_dane_taa_dgst;
/*
* Sendmail-style mail filter support.
/* that it does not drag in all the LDAP, SQL and other map
/* lookup client code into programs that don't need it.
/*
-/* Each pattern is of the form "name.type" or "type", where
+/* Each pattern is of the form "name/type" or "type", where
/* "name" and "type" are the first two fields of a master.cf
/* entry. Patterns are separated by whitespace and/or commas.
/* Matches are case insensitive. Patterns are matched in the
/* match. In order to reverse the result of a pattern match,
/* precede a pattern with an exclamation point (!).
/*
+/* For backwards compatibility, the form name.type is still
+/* supported.
+/*
/* match_service_init() parses the pattern list. The result
/* must be passed to match_service_match() or match_service_free().
/*
#include <stringops.h>
#include <match_service.h>
+/* match_service_compat - backwards compatibility */
+
+static void match_service_compat(ARGV *argv)
+{
+ char **cpp;
+ char *cp;
+
+ for (cpp = argv->argv; *cpp; cpp++) {
+ if (strrchr(*cpp, '/') == 0 && (cp = strrchr(*cpp, '.')) != 0)
+ *cp = '/';
+ }
+}
+
/* match_service_init - initialize pattern list */
ARGV *match_service_init(const char *patterns)
argv_add(list, item, (char *) 0);
argv_terminate(list);
myfree(saved_patterns);
+ match_service_compat(list);
return (list);
}
for (cpp = patterns; *cpp; cpp++)
argv_add(list, *cpp, (char *) 0);
argv_terminate(list);
+ match_service_compat(list);
return (list);
}
/*
* Sanity check.
*/
- if ((type = strrchr(name_type, '.')) == 0 || *++type == 0)
- msg_panic("%s: malformed service: \"%s\"; need \"name.type\" format",
+ if ((type = strrchr(name_type, '/')) == 0 || *++type == 0)
+ msg_panic("%s: malformed service: \"%s\"; need \"name/type\" format",
myname, name_type);
/*
msg_info("%s: %s ~? %s", myname, name_type, pattern);
for (match = 1; *pattern == '!'; pattern++)
match = !match;
- if (strcasecmp(strchr(pattern, '.') ? name_type : type, pattern) == 0) {
+ if (strcasecmp(strchr(pattern, '/') ? name_type : type, pattern) == 0) {
if (msg_verbose)
msg_info("%s: %s: found match", myname, name_type);
return (match);
continue;
name = cp;
transport = get_str_ent(&bufp, "transport type", (char *) 0);
- vstring_sprintf(junk, "%s.%s", name, transport);
+ vstring_sprintf(junk, "%s/%s", name, transport);
if (match_service_match(master_disable, vstring_str(junk)) == 0)
break;
}
#endif
{
int count;
- char *args;
+ char *args;
for (count = 0; count < add_rcpt_count; count++) {
if ((args = strchr(add_rcpt[count], ' ')) != 0) {
SRCS = postconf.c postconf_builtin.c postconf_edit.c postconf_main.c \
postconf_master.c postconf_misc.c postconf_node.c postconf_other.c \
postconf_service.c postconf_unused.c postconf_user.c postconf_dbms.c \
- postconf_lookup.c
+ postconf_lookup.c postconf_match.c postconf_print.c
OBJS = postconf.o postconf_builtin.o postconf_edit.o postconf_main.o \
postconf_master.o postconf_misc.o postconf_node.o postconf_other.o \
postconf_service.o postconf_unused.o postconf_user.o postconf_dbms.o \
- postconf_lookup.o
+ postconf_lookup.o postconf_match.o postconf_print.o
HDRS = postconf.h
TESTSRC =
DEFS = -I. -I$(INC_DIR) -D$(SYSTYPE)
tests: test1 test2 test3 test4 test5 test6 test7 test8 test9 test10 test11 \
test12 test13 test14 test15 test16 test17 test18 test19 test20 test21 \
test22 test23 test24 test25 test26 test27 test28 test29 test30 test4b \
- test31 test32 test33 test34 test35 test36 test37 test39 test40
+ test31 test32 test33 test34 test35 test36 test37 test39 test40 test41 \
+ test42 test43 test44 test45 test46 test47 test48 test49 test50 test51 \
+ test52 test53 test54 test55 test56
root_tests:
touch main.cf master.cf
echo foo inet - n n - 0 spawn >> master.cf
echo bar unix - n n - 0 spawn >> master.cf
- ./$(PROG) -c . -M inet >test9.tmp 2>&1
+ ./$(PROG) -c . -M '*'/inet >test9.tmp 2>&1
diff test9.ref test9.tmp
rm -f main.cf master.cf test9.tmp
touch main.cf master.cf
echo foo inet - n n - 0 spawn >> master.cf
echo bar unix - n n - 0 spawn >> master.cf
- ./$(PROG) -c . -M bar.inet foo.unix >test10.tmp 2>&1
+ ./$(PROG) -c . -M bar/inet foo/unix >test10.tmp 2>&1
diff test10.ref test10.tmp
rm -f main.cf master.cf test10.tmp
echo foo unix - n n - 0 other >> master.cf
echo bar inet - n n - 0 other >> master.cf
echo baz unix - n n - 0 other >> master.cf
- ./$(PROG) -Mfc . unix >test39.tmp 2>&1
+ ./$(PROG) -Mfc . '*'/unix >test39.tmp 2>&1
diff test39.ref test39.tmp
rm -f main.cf master.cf test39.tmp
echo ' -voaaa=bbb' >> master.cf
echo ' -vo ccc=$$aaa' >> master.cf
echo ' -v -oddd=$$ccc' >> master.cf
- ./$(PROG) -Mfxc . unix >test40.tmp 2>&1
+ ./$(PROG) -Mfxc . '*'/unix >test40.tmp 2>&1
diff test40.ref test40.tmp
rm -f main.cf master.cf test40.tmp
+test41: $(PROG) test41.ref
+ rm -f main.cf master.cf
+ touch main.cf master.cf
+ echo foo unix - n n - 0 other >> master.cf
+ echo bar unix - n n - 0 other >> master.cf
+ echo baz unix - n n - 0 other >> master.cf
+ ./$(PROG) -Pc . bar/unix/xxx=yyy bar/unix/aaa=bbb >test41.tmp 2>&1
+ ./$(PROG) -Mfc. >>test41.tmp 2>&1
+ ./$(PROG) -Pc . bar/unix/xxx=YYY bar/unix/aaa=BBB >>test41.tmp 2>&1
+ ./$(PROG) -Mfc. >>test41.tmp 2>&1
+ ./$(PROG) -Pc . >>test41.tmp 2>&1
+ diff test41.ref test41.tmp
+ rm -f main.cf master.cf test41.tmp
+
+test42: $(PROG) test42.ref
+ rm -f main.cf master.cf
+ touch main.cf master.cf
+ echo foo unix - n n - 0 other >> master.cf
+ echo bar unix - n n - 0 other >> master.cf
+ echo baz unix - n n - 0 other >> master.cf
+ ./$(PROG) -Pc . bar/unix/xxx=yyy bar/unix/aaa=bbb >test42.tmp 2>&1
+ ./$(PROG) -Mfc. >>test42.tmp 2>&1
+ ./$(PROG) -Pc . >>test42.tmp 2>&1
+ ./$(PROG) -PXc. bar/unix/xxx bar/unix/aaa >>test42.tmp 2>&1
+ ./$(PROG) -Mfc. >>test42.tmp 2>&1
+ diff test42.ref test42.tmp
+ rm -f main.cf master.cf test42.tmp
+
+test43: $(PROG) test43.ref
+ rm -f main.cf master.cf
+ touch main.cf master.cf
+ echo foo unix - n n - 0 other >> master.cf
+ echo bar unix - n n - 0 other >> master.cf
+ echo baz unix - n n - 0 other >> master.cf
+ ./$(PROG) -Fc . bar/unix/chroot=y bar/unix/command='aa -stuffobb=cc dd' >test43.tmp 2>&1
+ ./$(PROG) -Mfc. >>test43.tmp 2>&1
+ diff test43.ref test43.tmp
+ rm -f main.cf master.cf test43.tmp
+
+test44: $(PROG) test44.ref
+ rm -f main.cf master.cf
+ touch main.cf master.cf
+ echo foo unix - n n - 0 other >> master.cf
+ echo bar unix - n n - 0 other >> master.cf
+ echo baz unix - n n - 0 other >> master.cf
+ ./$(PROG) -Mc . bar/unix='xx inet - n n - 0 aa -stuffobb=cc dd' >test44.tmp 2>&1
+ ./$(PROG) -Mfc. >>test44.tmp 2>&1
+ diff test44.ref test44.tmp
+ rm -f main.cf master.cf test44.tmp
+
+test45: $(PROG) test45.ref
+ rm -f main.cf master.cf
+ touch main.cf master.cf
+ echo foo unix - n n - 0 other >> master.cf
+ echo bar xxxx - n n - 0 other >> master.cf
+ echo baz unix - n n - 0 other >> master.cf
+ ./$(PROG) -Mfc. >test45.tmp 2>&1 || true
+ diff test45.ref test45.tmp
+ rm -f main.cf master.cf test45.tmp
+
+test46: $(PROG) test46.ref
+ rm -f main.cf master.cf
+ touch main.cf master.cf
+ echo foo unix - n n - 0 other >> master.cf
+ echo bar inet X n n - 0 other >> master.cf
+ echo baz unix - n n - 0 other >> master.cf
+ ./$(PROG) -Mfc. >test46.tmp 2>&1 || true
+ diff test46.ref test46.tmp
+ rm -f main.cf master.cf test46.tmp
+
+test47: $(PROG) test47.ref
+ rm -f main.cf master.cf
+ touch main.cf master.cf
+ echo foo unix - n n - 0 other >> master.cf
+ echo bar inet - X n - 0 other >> master.cf
+ echo baz unix - n n - 0 other >> master.cf
+ ./$(PROG) -Mfc. >test47.tmp 2>&1 || true
+ diff test47.ref test47.tmp
+ rm -f main.cf master.cf test47.tmp
+
+test48: $(PROG) test48.ref
+ rm -f main.cf master.cf
+ touch main.cf master.cf
+ echo foo unix - n n - 0 other >> master.cf
+ echo bar inet - n X - 0 other >> master.cf
+ echo baz unix - n n - 0 other >> master.cf
+ ./$(PROG) -Mfc. >test48.tmp 2>&1 || true
+ diff test48.ref test48.tmp
+ rm -f main.cf master.cf test48.tmp
+
+test49: $(PROG) test49.ref
+ rm -f main.cf master.cf
+ touch main.cf master.cf
+ echo foo unix - n n - 0 other >> master.cf
+ echo bar inet - n n X 0 other >> master.cf
+ echo baz unix - n n - 0 other >> master.cf
+ ./$(PROG) -Mfc. >test49.tmp 2>&1 || true
+ diff test49.ref test49.tmp
+ rm -f main.cf master.cf test49.tmp
+
+test50: $(PROG) test50.ref
+ rm -f main.cf master.cf
+ touch main.cf master.cf
+ echo foo unix - n n - 0 other >> master.cf
+ echo bar inet - n n - X other >> master.cf
+ echo baz unix - n n - 0 other >> master.cf
+ ./$(PROG) -Mfc. >test50.tmp 2>&1 || true
+ diff test50.ref test50.tmp
+ rm -f main.cf master.cf test50.tmp
+
+test51: $(PROG) test51.ref
+ rm -f main.cf master.cf
+ touch main.cf master.cf
+ echo foo unix - n n -? 0 other >> master.cf
+ echo bar inet - n n X? 0 other >> master.cf
+ echo baz unix - n n 0? 0 other >> master.cf
+ ./$(PROG) -Mfc. >test51.tmp 2>&1 || true
+ diff test51.ref test51.tmp
+ rm -f main.cf master.cf test51.tmp
+
+test52: $(PROG) test52.ref
+ rm -f main.cf master.cf
+ touch main.cf master.cf
+ echo foo unix - n n - 0 other >> master.cf
+ echo bar inet - n n 0 0 other >> master.cf
+ echo baz unix - n n 0 0 other >> master.cf
+ ./$(PROG) -MXc. bar/inet foo/unix xxx/yyy
+ ./$(PROG) -Mfc. >test52.tmp 2>&1 || true
+ diff test52.ref test52.tmp
+ rm -f main.cf master.cf test52.tmp
+
+test53: $(PROG) test53.ref
+ rm -f main.cf master.cf
+ touch main.cf master.cf
+ echo foo unix - n n - 0 other >> master.cf
+ echo bar inet - n n 0 0 other >> master.cf
+ echo baz unix - n n 0 0 other >> master.cf
+ ./$(PROG) -M#c. bar/inet xxx/yyy
+ diff test53.ref master.cf
+ rm -f main.cf master.cf test53.tmp
+
+test54: $(PROG) test54.ref
+ rm -f main.cf master.cf
+ touch main.cf master.cf
+ echo foo unix - n n - 0 other >> master.cf
+ echo bar inet - n n 0 0 other >> master.cf
+ echo baz unix - n n 0 0 other >> master.cf
+ ./$(PROG) -M#c. bar/inet foo/unix
+ diff test54.ref master.cf
+ rm -f main.cf master.cf test54.tmp
+
+test55: $(PROG) test55.ref
+ rm -f main.cf master.cf
+ touch main.cf master.cf
+ echo foo unix - n n - 0 other >> master.cf
+ echo bar inet - n n 0 0 other >> master.cf
+ echo baz unix - n n 0 0 other >> master.cf
+ ./$(PROG) -M#c. bar/inet baz/unix
+ diff test55.ref master.cf
+ rm -f main.cf master.cf test55.tmp
+
+test56: $(PROG) test56.ref
+ rm -f main.cf master.cf
+ touch main.cf master.cf
+ echo foo unix - n n - 0 other >> master.cf
+ echo bar inet - n n 0 0 other >> master.cf
+ echo " -o first" >> master.cf
+ echo " -o second" >> master.cf
+ echo baz unix - n n 0 0 other >> master.cf
+ ./$(PROG) -M#c. bar/inet xxx/yyy
+ diff test56.ref master.cf
+ rm -f main.cf master.cf test56.tmp
+
printfck: $(OBJS) $(PROG)
rm -rf printfck
mkdir printfck
postconf.o: ../../include/msg_vstream.h
postconf.o: ../../include/myflock.h
postconf.o: ../../include/mymalloc.h
+postconf.o: ../../include/name_code.h
postconf.o: ../../include/name_mask.h
postconf.o: ../../include/stringops.h
postconf.o: ../../include/sys_defs.h
postconf_builtin.o: ../../include/myflock.h
postconf_builtin.o: ../../include/mymalloc.h
postconf_builtin.o: ../../include/mynetworks.h
+postconf_builtin.o: ../../include/name_code.h
postconf_builtin.o: ../../include/server_acl.h
postconf_builtin.o: ../../include/stringops.h
postconf_builtin.o: ../../include/sys_defs.h
postconf_dbms.o: ../../include/mac_parse.h
postconf_dbms.o: ../../include/mail_conf.h
postconf_dbms.o: ../../include/myflock.h
+postconf_dbms.o: ../../include/name_code.h
postconf_dbms.o: ../../include/split_at.h
postconf_dbms.o: ../../include/stringops.h
postconf_dbms.o: ../../include/sys_defs.h
postconf_edit.o: ../../include/msg.h
postconf_edit.o: ../../include/myflock.h
postconf_edit.o: ../../include/mymalloc.h
+postconf_edit.o: ../../include/name_code.h
postconf_edit.o: ../../include/readlline.h
+postconf_edit.o: ../../include/split_at.h
postconf_edit.o: ../../include/stringops.h
postconf_edit.o: ../../include/sys_defs.h
postconf_edit.o: ../../include/vbuf.h
postconf_lookup.o: ../../include/msg.h
postconf_lookup.o: ../../include/myflock.h
postconf_lookup.o: ../../include/mymalloc.h
+postconf_lookup.o: ../../include/name_code.h
postconf_lookup.o: ../../include/stringops.h
postconf_lookup.o: ../../include/sys_defs.h
postconf_lookup.o: ../../include/vbuf.h
postconf_main.o: ../../include/msg.h
postconf_main.o: ../../include/myflock.h
postconf_main.o: ../../include/mymalloc.h
+postconf_main.o: ../../include/name_code.h
postconf_main.o: ../../include/readlline.h
postconf_main.o: ../../include/stringops.h
postconf_main.o: ../../include/sys_defs.h
postconf_master.o: ../../include/dict.h
postconf_master.o: ../../include/htable.h
postconf_master.o: ../../include/mail_params.h
-postconf_master.o: ../../include/match_service.h
+postconf_master.o: ../../include/master_proto.h
postconf_master.o: ../../include/msg.h
postconf_master.o: ../../include/myflock.h
postconf_master.o: ../../include/mymalloc.h
+postconf_master.o: ../../include/name_code.h
postconf_master.o: ../../include/readlline.h
+postconf_master.o: ../../include/split_at.h
postconf_master.o: ../../include/stringops.h
postconf_master.o: ../../include/sys_defs.h
postconf_master.o: ../../include/vbuf.h
postconf_master.o: ../../include/vstring.h
postconf_master.o: postconf.h
postconf_master.o: postconf_master.c
+postconf_match.o: ../../include/argv.h
+postconf_match.o: ../../include/dict.h
+postconf_match.o: ../../include/htable.h
+postconf_match.o: ../../include/msg.h
+postconf_match.o: ../../include/myflock.h
+postconf_match.o: ../../include/mymalloc.h
+postconf_match.o: ../../include/name_code.h
+postconf_match.o: ../../include/split_at.h
+postconf_match.o: ../../include/sys_defs.h
+postconf_match.o: ../../include/vbuf.h
+postconf_match.o: ../../include/vstream.h
+postconf_match.o: ../../include/vstring.h
+postconf_match.o: postconf.h
+postconf_match.o: postconf_match.c
postconf_misc.o: ../../include/argv.h
postconf_misc.o: ../../include/dict.h
postconf_misc.o: ../../include/htable.h
postconf_misc.o: ../../include/mail_params.h
postconf_misc.o: ../../include/myflock.h
postconf_misc.o: ../../include/mymalloc.h
+postconf_misc.o: ../../include/name_code.h
postconf_misc.o: ../../include/safe.h
postconf_misc.o: ../../include/sys_defs.h
postconf_misc.o: ../../include/vbuf.h
postconf_node.o: ../../include/msg.h
postconf_node.o: ../../include/myflock.h
postconf_node.o: ../../include/mymalloc.h
+postconf_node.o: ../../include/name_code.h
postconf_node.o: ../../include/sys_defs.h
postconf_node.o: ../../include/vbuf.h
postconf_node.o: ../../include/vstream.h
postconf_other.o: ../../include/htable.h
postconf_other.o: ../../include/mbox_conf.h
postconf_other.o: ../../include/myflock.h
+postconf_other.o: ../../include/name_code.h
postconf_other.o: ../../include/sys_defs.h
postconf_other.o: ../../include/vbuf.h
postconf_other.o: ../../include/vstream.h
postconf_other.o: ../../include/xsasl.h
postconf_other.o: postconf.h
postconf_other.o: postconf_other.c
+postconf_print.o: ../../include/argv.h
+postconf_print.o: ../../include/dict.h
+postconf_print.o: ../../include/htable.h
+postconf_print.o: ../../include/msg.h
+postconf_print.o: ../../include/myflock.h
+postconf_print.o: ../../include/name_code.h
+postconf_print.o: ../../include/sys_defs.h
+postconf_print.o: ../../include/vbuf.h
+postconf_print.o: ../../include/vstream.h
+postconf_print.o: ../../include/vstring.h
+postconf_print.o: postconf.h
+postconf_print.o: postconf_print.c
postconf_service.o: ../../include/argv.h
postconf_service.o: ../../include/dict.h
postconf_service.o: ../../include/htable.h
postconf_service.o: ../../include/msg.h
postconf_service.o: ../../include/myflock.h
postconf_service.o: ../../include/mymalloc.h
+postconf_service.o: ../../include/name_code.h
postconf_service.o: ../../include/stringops.h
postconf_service.o: ../../include/sys_defs.h
postconf_service.o: ../../include/vbuf.h
postconf_unused.o: ../../include/mail_params.h
postconf_unused.o: ../../include/msg.h
postconf_unused.o: ../../include/myflock.h
+postconf_unused.o: ../../include/name_code.h
postconf_unused.o: ../../include/sys_defs.h
postconf_unused.o: ../../include/vbuf.h
postconf_unused.o: ../../include/vstream.h
postconf_user.o: ../../include/msg.h
postconf_user.o: ../../include/myflock.h
postconf_user.o: ../../include/mymalloc.h
+postconf_user.o: ../../include/name_code.h
postconf_user.o: ../../include/stringops.h
postconf_user.o: ../../include/sys_defs.h
postconf_user.o: ../../include/vbuf.h
/* [\fB-C \fIclass,...\fR] [\fIparameter ...\fR]
/*
/* \fBpostconf\fR [\fB-ev\fR] [\fB-c \fIconfig_dir\fR]
-/* [\fIparameter=value ...\fR]
+/* \fIparameter=value ...\fR
/*
/* \fBpostconf\fR [\fB-#vX\fR] [\fB-c \fIconfig_dir\fR]
-/* [\fIparameter ...\fR]
+/* \fIparameter ...\fR
/*
-/* \fBManaging master.cf:\fR
+/* \fBManaging master.cf service entries:\fR
/*
/* \fBpostconf\fR [\fB-fMovx\fR] [\fB-c \fIconfig_dir\fR]
-/* [\fIservice ...\fR]
+/* [\fIservice\fR[\fB/\fItype\fR]\fI ...\fR]
+/*
+/* \fBpostconf\fR [\fB-eMv\fR] [\fB-c \fIconfig_dir\fR]
+/* \fIservice\fB/\fItype=value ...\fR
+/*
+/* \fBpostconf\fR [\fB-#MvX\fR] [\fB-c \fIconfig_dir\fR]
+/* \fIservice\fB/\fItype ...\fR
+/*
+/* \fBManaging master.cf service fields:\fR
+/*
+/* \fBpostconf\fR [\fB-fFovx\fR] [\fB-c \fIconfig_dir\fR]
+/* [\fIservice\fR[\fB/\fItype\fR[\fB/\fIfield\fR]]\fI ...\fR]
+/*
+/* \fBpostconf\fR [\fB-eFv\fR] [\fB-c \fIconfig_dir\fR]
+/* \fIservice\fB/\fItype\fB/\fIfield=value ...\fR
+/*
+/* \fBManaging master.cf service parameters:\fR
+/*
+/* \fBpostconf\fR [\fB-fPovx\fR] [\fB-c \fIconfig_dir\fR]
+/* [\fIservice\fR[\fB/\fItype\fR[\fB/\fIparameter\fR]]\fI ...\fR]
+/*
+/* \fBpostconf\fR [\fB-ePv\fR] [\fB-c \fIconfig_dir\fR]
+/* \fIservice\fB/\fItype\fB/\fIparameter=value ...\fR
+/*
+/* \fBpostconf\fR [\fB-PXv\fR] [\fB-c \fIconfig_dir\fR]
+/* \fIservice\fB/\fItype\fB/\fIparameter ...\fR
/*
/* \fBManaging bounce message templates:\fR
/*
/* (Postfix 2.9 and later).
/* .IP \fB-e\fR
/* Edit the \fBmain.cf\fR configuration file, and update
-/* parameter settings with the "\fIname=value\fR" pairs
-/* on the \fBpostconf\fR(1) command line. The file is copied
-/* to a temporary file then renamed into place.
-/* Specify quotes to protect special characters and whitespace
-/* on the \fBpostconf\fR(1) command line.
-/*
-/* The \fB-e\fR is no longer needed with Postfix version 2.8
-/* and later.
+/* parameter settings with the "\fIname=value\fR" pairs on the
+/* \fBpostconf\fR(1) command line.
+/*
+/* With \fB-M\fR, edit the \fBmaster.cf\fR configuration file,
+/* and replace one or more service entries with new values as
+/* specified with "\fIservice/type=value\fR" on the \fBpostconf\fR(1)
+/* command line.
+/*
+/* With \fB-F\fR, edit the \fBmaster.cf\fR configuration file,
+/* and replace one or more service fields with new values as
+/* specied with "\fIservice/type/field=value\fR" on the
+/* \fBpostconf\fR(1) command line. Currently, the "command"
+/* field contains the command name and command arguments. this
+/* may change in the near future, so that the "command" field
+/* contains only the command name, and a new "arguments"
+/* pseudofield contains the command arguments.
+/*
+/* With \fB-P\fR, edit the \fBmaster.cf\fR configuration file,
+/* and add or update one or more service parameter settings
+/* (-o parameter=value settings) with new values as specied
+/* with "\fIservice/type/parameter=value\fR" on the \fBpostconf\fR(1)
+/* command line.
+/*
+/* In all cases the file is copied to a temporary file then
+/* renamed into place. Specify quotes to protect special
+/* characters and whitespace on the \fBpostconf\fR(1) command
+/* line.
+/*
+/* The \fB-e\fR option is no longer needed with Postfix version
+/* 2.8 and later.
/* .IP \fB-f\fR
/* Fold long lines when printing \fBmain.cf\fR or \fBmaster.cf\fR
/* configuration file entries, for human readability.
/*
/* This feature is available with Postfix 2.9 and later.
+/* .IP \fB-F\fR
+/* Show \fBmaster.cf\fR per-entry field settings (by default
+/* all services and all fields), formatted as one
+/* "\fIservice/type/field=value\fR" per line. Specify \fB-Ff\fR
+/* to fold long lines.
+/*
+/* Specify one or more "\fIservice/type/field\fR" instances
+/* on the \fBpostconf\fR(1) command line to limit the output
+/* to fields of interest. Trailing parameter name or service
+/* type fields that are omitted will be handled as "*" wildcard
+/* fields.
+/*
+/* This feature is available with Postfix 2.11 and later.
/* .IP \fB-h\fR
-/* Show \fBmain.cf\fR parameter values without the "\fIname\fR
+/* Show parameter or attribute values without the "\fIname\fR
/* = " label that normally precedes the value.
/* .IP \fB-l\fR
/* List the names of all supported mailbox locking methods.
/* This locking method is available on systems with a BSD
/* compatible library.
/* .IP \fBfcntl\fR
-/* A kernel-based advisory locking method for local and remote files.
+/* A kernel-based advisory locking method for local and remote
+/* files.
/* .IP \fBdotlock\fR
-/* An application-level locking method. An application locks a file
-/* named \fIfilename\fR by creating a file named \fIfilename\fB.lock\fR.
-/* The application is expected to remove its own lock file, as well as
-/* stale lock files that were left behind after abnormal program
-/* termination.
+/* An application-level locking method. An application locks
+/* a file named \fIfilename\fR by creating a file named
+/* \fIfilename\fB.lock\fR. The application is expected to
+/* remove its own lock file, as well as stale lock files that
+/* were left behind after abnormal program termination.
/* .RE
/* .IP \fB-m\fR
-/* List the names of all supported lookup table types. In Postfix
-/* configuration files,
-/* lookup tables are specified as \fItype\fB:\fIname\fR, where
-/* \fItype\fR is one of the types listed below. The table \fIname\fR
-/* syntax depends on the lookup table type as described in the
-/* DATABASE_README document.
+/* List the names of all supported lookup table types. In
+/* Postfix configuration files, lookup tables are specified
+/* as \fItype\fB:\fIname\fR, where \fItype\fR is one of the
+/* types listed below. The table \fIname\fR syntax depends on
+/* the lookup table type as described in the DATABASE_README
+/* document.
/* .RS
/* .IP \fBbtree\fR
/* A sorted, balanced tree structure. Available on systems
/* .IP "\fBsqlite\fR (read-only)"
/* SQLite database. This is described in \fBsqlite_table\fR(5).
/* .IP "\fBstatic\fR (read-only)"
-/* A table that always returns its name as lookup result. For example,
-/* \fBstatic:foobar\fR always returns the string \fBfoobar\fR as lookup
-/* result.
+/* A table that always returns its name as lookup result. For
+/* example, \fBstatic:foobar\fR always returns the string
+/* \fBfoobar\fR as lookup result.
/* .IP "\fBtcp\fR (read-only)"
/* TCP/IP client. The protocol is described in \fBtcp_table\fR(5).
/* .IP "\fBtexthash\fR (read-only)"
-/* Produces similar results as hash: files, except that you don't
-/* need to run the \fBpostmap\fR(1) command before you can use the file,
-/* and that it does not detect changes after the file is read.
+/* Produces similar results as hash: files, except that you
+/* don't need to run the \fBpostmap\fR(1) command before you
+/* can use the file, and that it does not detect changes after
+/* the file is read.
/* .IP "\fBunix\fR (read-only)"
/* A limited view of the UNIX authentication database. The
/* following tables are implemented:
/* .RS
/*. IP \fBunix:passwd.byname\fR
-/* The table is the UNIX password database. The key is a login name.
-/* The result is a password file entry in \fBpasswd\fR(5) format.
+/* The table is the UNIX password database. The key is a login
+/* name. The result is a password file entry in \fBpasswd\fR(5)
+/* format.
/* .IP \fBunix:group.byname\fR
-/* The table is the UNIX group database. The key is a group name.
-/* The result is a group file entry in \fBgroup\fR(5) format.
+/* The table is the UNIX group database. The key is a group
+/* name. The result is a group file entry in \fBgroup\fR(5)
+/* format.
/* .RE
/* .RE
/* .IP
-/* Other table types may exist depending on how Postfix was built.
+/* Other table types may exist depending on how Postfix was
+/* built.
/* .IP \fB-M\fR
/* Show \fBmaster.cf\fR file contents instead of \fBmain.cf\fR
-/* file contents.
-/* Specify \fB-Mf\fR to fold long lines for human readability.
+/* file contents. Specify \fB-Mf\fR to fold long lines for
+/* human readability.
/*
-/* If \fIservice ...\fR is specified, only the matching services
-/* will be output. For example, "\fBpostconf -Mf inet\fR"
-/* will output all services that listen on the network.
+/* Specify zero or more arguments, each with a \fIservice-name\fR
+/* or \fIservice-name/service-type\fR pair, where \fIservice-name\fR
+/* is the first field of a master.cf entry and \fIservice-type\fR
+/* is one of (\fBinet\fR, \fBunix\fR, \fBfifo\fR, or \fBpass\fR).
/*
-/* Specify zero or more arguments, each with a \fIservice-type\fR
-/* name (\fBinet\fR, \fBunix\fR, \fBfifo\fR, or \fBpass\fR)
-/* or with a \fIservice-name.service-type\fR pair, where
-/* \fIservice-name\fR is the first field of a master.cf entry.
+/* If \fIservice-name\fR or \fIservice-name/service-type\fR
+/* is specified, only the matching master.cf entries will be
+/* output. For example, "\fBpostconf -Mf smtp\fR" will output
+/* all services named "smtp", and "\fBpostconf -Mf smtp/inet\fR"
+/* will output only the smtp service that listens on the
+/* network. Trailing service type fields that are omitted
+/* will be handled as "*" wildcard fields.
/*
-/* This feature is available with Postfix 2.9 and later.
+/* This feature is available with Postfix 2.9 and later. The
+/* syntax was changed from "\fIname.type\fR" to "\fIname/type\fR",
+/* and "*" wildcard support was added with Postfix 2.11.
/* .IP \fB-n\fR
/* Show only configuration parameters that have explicit
-/* \fIname=value\fR settings in \fBmain.cf\fR.
-/* Specify \fB-nf\fR to fold long lines for human readability
-/* (Postfix 2.9 and later).
+/* \fIname=value\fR settings in \fBmain.cf\fR. Specify \fB-nf\fR
+/* to fold long lines for human readability (Postfix 2.9 and
+/* later).
/* .IP "\fB-o \fIname=value\fR"
/* Override \fBmain.cf\fR parameter settings.
/*
/* This feature is available with Postfix 2.10 and later.
+/* .IP \fB-p\fR
+/* Show \fBmain.cf\fR parameter settings. This is the default.
+/* .IP \fB-P\fR
+/* Show \fBmaster.cf\fR service parameter settings (by default
+/* all services and all parameters). formatted as one
+/* "\fIservice/type/parameter=value\fR" per line. Specify
+/* \fB-Pf\fR to fold long lines.
+/*
+/* Specify one or more "\fIservice/type/parameter\fR" instances
+/* on the \fBpostconf\fR(1) command line to limit the output
+/* to parameters of interest. Trailing parameter name or
+/* service type fields that are omitted will be handled as "*"
+/* wildcard fields.
+/*
+/* This feature is available with Postfix 2.11 and later.
/* .IP "\fB-t\fR [\fItemplate_file\fR]"
/* Display the templates for text that appears at the beginning
/* of delivery status notification (DSN) messages, without
/*
/* This feature is available with Postfix 2.3 and later.
/* .IP \fB-v\fR
-/* Enable verbose logging for debugging purposes. Multiple \fB-v\fR
-/* options make the software increasingly verbose.
+/* Enable verbose logging for debugging purposes. Multiple
+/* \fB-v\fR options make the software increasingly verbose.
/* .IP \fB-x\fR
/* Expand \fI$name\fR in \fBmain.cf\fR or \fBmaster.cf\fR
/* parameter values. The expansion is recursive.
/*
/* This feature is available with Postfix 2.10 and later.
/* .IP \fB-X\fR
-/* Edit the \fBmain.cf\fR configuration file, and remove
-/* the parameters named on the \fBpostconf\fR(1) command line.
-/* The file is copied to a temporary file then renamed into
-/* place.
+/* Edit the \fBmain.cf\fR configuration file, and remove the
+/* parameters named on the \fBpostconf\fR(1) command line.
/* Specify a list of parameter names, not "\fIname=value\fR"
-/* pairs. There is no \fBpostconf\fR(1) command to perform
-/* the reverse operation.
+/* pairs.
+/*
+/* With \fB-M\fR, edit the \fBmaster.cf\fR configuration file,
+/* and remove one or more service entries as specified with
+/* "\fIservice/type\fR" on the \fBpostconf\fR(1) command line.
+/*
+/* With \fB-P\fR, edit the \fBmaster.cf\fR configuration file,
+/* and remove one or more service parameter settings (-o
+/* parameter=value settings) as specied with
+/* "\fIservice/type/parameter\fR" on the \fBpostconf\fR(1)
+/* command line.
+/*
+/* In all cases the file is copied to a temporary file then
+/* renamed into place. Specify quotes to protect special
+/* characters on the \fBpostconf\fR(1) command line.
+/*
+/* There is no \fBpostconf\fR(1) command to perform the reverse
+/* operation.
/*
/* This feature is available with Postfix 2.10 and later.
+/* Support for -M and -P was added with Postfix 2.11.
/* .IP \fB-#\fR
/* Edit the \fBmain.cf\fR configuration file, and comment out
/* the parameters named on the \fBpostconf\fR(1) command line,
/* so that those parameters revert to their default values.
-/* The file is copied to a temporary file then renamed into
-/* place.
/* Specify a list of parameter names, not "\fIname=value\fR"
-/* pairs. There is no \fBpostconf\fR(1) command to perform
-/* the reverse operation.
+/* pairs.
/*
-/* This feature is available with Postfix 2.6 and later.
+/* With \fB-M\fR, edit the \fBmaster.cf\fR configuration file,
+/* and comment out one or more service entries as specified
+/* with "\fIservice/type\fR" on the \fBpostconf\fR(1) command
+/* line.
+/*
+/* In all cases the file is copied to a temporary file then
+/* renamed into place. Specify quotes to protect special
+/* characters on the \fBpostconf\fR(1) command line.
+/*
+/* There is no \fBpostconf\fR(1) command to perform the reverse
+/* operation.
+/*
+/* This feature is available with Postfix 2.6 and later. Support
+/* for -M was added with Postfix 2.11.
/* DIAGNOSTICS
/* Problems are reported to the standard error stream.
/* ENVIRONMENT
/* CONFIGURATION PARAMETERS
/* .ad
/* .fi
-/* The following \fBmain.cf\fR parameters are especially relevant to
-/* this program.
+/* The following \fBmain.cf\fR parameters are especially
+/* relevant to this program.
/*
/* The text below provides only a parameter summary. See
/* \fBpostconf\fR(5) for more details including examples.
/* Pathname of a configuration file with bounce message templates.
/* FILES
/* /etc/postfix/main.cf, Postfix configuration parameters
-/* /etc/postfix/master.cf, Postfix master daemon configuraton
+/* /etc/postfix/master.cf, Postfix master daemon configuration
/* SEE ALSO
-/* bounce(5), bounce template file format
-/* master(5), master.cf configuration file syntax
-/* postconf(5), main.cf configuration file syntax
+/* bounce(5), bounce template file format master(5), master.cf
+/* configuration file syntax postconf(5), main.cf configuration
+/* file syntax
/* README FILES
/* .ad
/* .fi
-/* Use "\fBpostconf readme_directory\fR" or
-/* "\fBpostconf html_directory\fR" to locate this information.
+/* Use "\fBpostconf readme_directory\fR" or "\fBpostconf
+/* html_directory\fR" to locate this information.
/* .na
/* .nf
/* DATABASE_README, Postfix lookup table overview
/* LICENSE
/* .ad
/* .fi
-/* The Secure Mailer license must be distributed with this software.
+/* 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
+/* Wietse Venema IBM T.J. Watson Research P.O. Box 704 Yorktown
+/* Heights, NY 10598, USA
/*--*/
/* System library. */
*/
MAIL_VERSION_STAMP_DECLARE;
+ /*
+ * This program has so many command-line options that we have to implement a
+ * compatibility matrix to weed out the conflicting option combinations, and
+ * to alert the user about option combinations that have no effect.
+ */
+
+ /*
+ * Options that are mutually-exclusive. First entry must specify the major
+ * modes. Other entries specify conflicts between option modifiers.
+ */
+static const int incompat_options[] = {
+ /* Major modes. */
+ SHOW_SASL_SERV | SHOW_SASL_CLNT | EXP_DSN_TEMPL | SHOW_LOCKS | SHOW_MAPS \
+ |DUMP_DSN_TEMPL | MAIN_PARAM | MASTER_ENTRY | MASTER_FIELD | MASTER_PARAM,
+ /* Modifiers. */
+ SHOW_DEFS | EDIT_CONF | SHOW_NONDEF | COMMENT_OUT | EDIT_EXCL,
+ FOLD_LINE | EDIT_CONF | COMMENT_OUT | EDIT_EXCL,
+ SHOW_EVAL | EDIT_CONF | COMMENT_OUT | EDIT_EXCL,
+ MAIN_OVER | SHOW_DEFS | EDIT_CONF | COMMENT_OUT | EDIT_EXCL,
+ HIDE_NAME | EDIT_CONF | COMMENT_OUT | EDIT_EXCL,
+ 0,
+};
+
+ /*
+ * Options, and the only options that they are compatible with. There must
+ * be one entry for each major mode. Other entries specify compatibility
+ * between option modifiers.
+ */
+static const int compat_options[][2] = {
+ /* Major modes. */
+ {SHOW_SASL_SERV, 0},
+ {SHOW_SASL_CLNT, 0},
+ {EXP_DSN_TEMPL, 0},
+ {SHOW_LOCKS, 0},
+ {SHOW_MAPS, 0,},
+ {DUMP_DSN_TEMPL, 0},
+ {MAIN_PARAM, EDIT_CONF | EDIT_EXCL | COMMENT_OUT | FOLD_LINE | HIDE_NAME \
+ |PARAM_CLASS | SHOW_EVAL | SHOW_DEFS | SHOW_NONDEF | MAIN_OVER},
+ {MASTER_ENTRY, EDIT_CONF | EDIT_EXCL | COMMENT_OUT | FOLD_LINE | MAIN_OVER \
+ |SHOW_EVAL},
+ {MASTER_FIELD, EDIT_CONF | FOLD_LINE | HIDE_NAME | MAIN_OVER | SHOW_EVAL},
+ {MASTER_PARAM, EDIT_CONF | EDIT_EXCL | FOLD_LINE | HIDE_NAME | MAIN_OVER \
+ |SHOW_EVAL},
+ /* Modifiers. */
+ {PARAM_CLASS, MAIN_PARAM | SHOW_DEFS | SHOW_NONDEF},
+ 0,
+};
+
+ /*
+ * Compatibility to string conversion support.
+ */
+static const NAME_MASK compat_names[] = {
+ "-a", SHOW_SASL_SERV,
+ "-A", SHOW_SASL_CLNT,
+ "-b", EXP_DSN_TEMPL,
+ "-C", PARAM_CLASS,
+ "-d", SHOW_DEFS,
+ "-e", EDIT_CONF,
+ "-f", FOLD_LINE,
+ "-F", MASTER_FIELD,
+ "-h", HIDE_NAME,
+ "-l", SHOW_LOCKS,
+ "-m", SHOW_MAPS,
+ "-M", MASTER_ENTRY,
+ "-n", SHOW_NONDEF,
+ "-o", MAIN_OVER,
+ "-p", MAIN_PARAM,
+ "-P", MASTER_PARAM,
+ "-t", DUMP_DSN_TEMPL,
+ "-x", SHOW_EVAL,
+ "-X", EDIT_EXCL,
+ "-#", COMMENT_OUT,
+ 0,
+};
+
+/* usage - enumerate parameters without compatibility info */
+
+static void usage(const char *progname)
+{
+ msg_fatal("usage: %s"
+ " [-a (server SASL types)]"
+ " [-A (client SASL types)]"
+ " [-b (bounce templates)]"
+ " [-c config_dir]"
+ " [-c param_class]"
+ " [-d (parameter defaults)]"
+ " [-e (edit configuration)]"
+ " [-f (fold lines)]"
+ " [-F (master.cf fields)]"
+ " [-h (no names)]"
+ " [-l (lock types)]"
+ " [-m (map types)]"
+ " [-M (master.cf)]"
+ " [-n (non-default parameters)]"
+ " [-o name=value (override parameter value)]"
+ " [-p (main.cf, default)]"
+ " [-P (master.cf parameters)]"
+ " [-t (bounce templates)]"
+ " [-v (verbose)]"
+ " [-x (expand parameter values)]"
+ " [-X (exclude)]"
+ " [-# (comment-out)]"
+ " [name...]", progname);
+}
+
+/* check_exclusive_options - complain about mutually-exclusive options */
+
+static void check_exclusive_options(int optval)
+{
+ const char *myname = "check_exclusive_options";
+ const int *op;
+ int oval;
+ unsigned mask;
+
+ for (op = incompat_options; (oval = *op) != 0; op++) {
+ oval &= optval;
+ for (mask = ~0; (mask & oval) != 0; mask >>= 1) {
+ if ((mask & oval) != oval)
+ msg_fatal("specify one of %s",
+ str_name_mask(myname, compat_names, oval));
+ }
+ }
+}
+
+/* check_compat_options - complain about incompatible options */
+
+static void check_compat_options(int optval)
+{
+ const char *myname = "check_compat_options";
+ VSTRING *buf1 = vstring_alloc(10);
+ VSTRING *buf2 = vstring_alloc(10);
+ const int (*op)[2];
+ int excess;
+
+ for (op = compat_options; op[0][0] != 0; op++) {
+ if ((optval & *op[0]) != 0
+ && (excess = (optval & ~((*op)[0] | (*op)[1]))) != 0)
+ msg_fatal("with option %s, do not specify %s",
+ str_name_mask_opt(buf1, myname, compat_names,
+ (*op)[0], NAME_MASK_NUMBER),
+ str_name_mask_opt(buf2, myname, compat_names, excess,
+ NAME_MASK_NUMBER));
+ }
+ vstring_free(buf1);
+ vstring_free(buf2);
+}
+
/* main */
int main(int argc, char **argv)
int ch;
int fd;
struct stat st;
- int junk;
ARGV *ext_argv = 0;
int param_class = PC_PARAM_MASK_CLASS;
static const NAME_MASK param_class_table[] = {
/*
* Parse JCL.
*/
- while ((ch = GETOPT(argc, argv, "aAbc:C:deEf#hlmMno:tvxX")) > 0) {
+ while ((ch = GETOPT(argc, argv, "aAbc:C:deEfFhlmMno:pPtvxX#")) > 0) {
switch (ch) {
case 'a':
cmd_mode |= SHOW_SASL_SERV;
cmd_mode |= SHOW_SASL_CLNT;
break;
case 'b':
+ cmd_mode |= EXP_DSN_TEMPL;
if (ext_argv)
msg_fatal("specify one of -b and -t");
ext_argv = argv_alloc(2);
cmd_mode |= SHOW_DEFS;
break;
case 'e':
- cmd_mode |= EDIT_MAIN;
+ cmd_mode |= EDIT_CONF;
break;
case 'f':
cmd_mode |= FOLD_LINE;
break;
+ case 'F':
+ cmd_mode |= MASTER_FIELD;
+ break;
case '#':
- cmd_mode = COMMENT_OUT;
+ cmd_mode |= COMMENT_OUT;
break;
case 'h':
- cmd_mode &= ~SHOW_NAME;
+ cmd_mode |= HIDE_NAME;
break;
case 'l':
cmd_mode |= SHOW_LOCKS;
cmd_mode |= SHOW_MAPS;
break;
case 'M':
- cmd_mode |= SHOW_MASTER;
+ cmd_mode |= MASTER_ENTRY;
break;
case 'n':
cmd_mode |= SHOW_NONDEF;
break;
case 'o':
+ cmd_mode |= MAIN_OVER;
if (override_params == 0)
override_params = argv_alloc(2);
argv_add(override_params, optarg, (char *) 0);
break;
+ case 'p':
+ cmd_mode |= MAIN_PARAM;
+ break;
+ case 'P':
+ cmd_mode |= MASTER_PARAM;
+ break;
case 't':
+ cmd_mode |= DUMP_DSN_TEMPL;
if (ext_argv)
msg_fatal("specify one of -b and -t");
ext_argv = argv_alloc(2);
msg_verbose++;
break;
default:
- msg_fatal("usage: %s [-a (server SASL types)] [-A (client SASL types)] [-b (bounce templates)] [-c config_dir] [-C param_class] [-d (defaults)] [-e (edit)] [-f (fold lines)] [-# (comment-out)] [-h (no names)] [-l (lock types)] [-m (map types)] [-M (master.cf)] [-n (non-defaults)] [-v] [-X (exclude)] [name...]", argv[0]);
+ usage(argv[0]);
}
}
+ /*
+ * Make all options explicit, before checking their compatibility.
+ */
+ if ((cmd_mode & incompat_options[0]) == 0)
+ cmd_mode |= MAIN_PARAM;
+ if ((cmd_mode & (MAIN_PARAM | MASTER_ENTRY | MASTER_FIELD | MASTER_PARAM))
+ && argv[optind] && strchr(argv[optind], '='))
+ cmd_mode |= EDIT_CONF;
+
/*
* Sanity check.
*/
- junk = (cmd_mode & (SHOW_DEFS | SHOW_MAPS | SHOW_LOCKS | EDIT_MAIN | SHOW_SASL_SERV | SHOW_SASL_CLNT | COMMENT_OUT | SHOW_MASTER | EDIT_EXCL));
- if (junk != 0 && ((junk != SHOW_DEFS
- && junk != SHOW_MAPS && junk != SHOW_LOCKS && junk != EDIT_MAIN
- && junk != SHOW_SASL_SERV && junk != SHOW_SASL_CLNT
- && junk != COMMENT_OUT && junk != SHOW_MASTER
- && junk != EDIT_EXCL)
- || ext_argv != 0))
- msg_fatal("specify one of -a, -A, -b, -d, -e, -#, -l, -m, -M, and -X");
- if ((cmd_mode & SHOW_EVAL) != 0 && junk != 0 && junk != SHOW_DEFS && junk != SHOW_MASTER)
- msg_fatal("do not specify -x with -a, -A, -b, -e, -#, -l, -m, or -X");
- if ((cmd_mode & SHOW_NONDEF) != 0 && junk != 0)
- msg_fatal("do not specify -n with -a, -A, -b, -d, -e, -#, -l, -m, -M, or -X");
- if (override_params != 0 && junk != 0 && junk != SHOW_MASTER)
- msg_fatal("do not specify -o with -a, -A, -b, -d, -e, -#, -l, -m, or -X");
+ check_exclusive_options(cmd_mode);
+ check_compat_options(cmd_mode);
+
+ if ((cmd_mode & EDIT_CONF) && argc == optind)
+ msg_fatal("-e requires name=value argument");
/*
* Display bounce template information and exit.
/*
* If showing master.cf entries, show them and exit
*/
- else if (cmd_mode & SHOW_MASTER) {
+ else if ((cmd_mode & (MASTER_ENTRY | MASTER_FIELD | MASTER_PARAM))
+ && !(cmd_mode & (EDIT_CONF | EDIT_EXCL | COMMENT_OUT))) {
read_master(FAIL_ON_OPEN_ERROR);
read_parameters();
if (override_params)
register_builtin_parameters(basename(argv[0]), getpid());
register_service_parameters();
register_user_parameters();
- show_master(VSTREAM_OUT, cmd_mode, argv + optind);
+ if (cmd_mode & MASTER_FIELD)
+ show_master_fields(VSTREAM_OUT, cmd_mode, argc - optind, argv + optind);
+ else if (cmd_mode & MASTER_PARAM)
+ show_master_params(VSTREAM_OUT, cmd_mode, argc - optind, argv + optind);
+ else
+ show_master_entries(VSTREAM_OUT, cmd_mode, argc - optind, argv + optind);
}
/*
}
/*
- * Edit main.cf.
+ * Edit main.cf or master.cf.
*/
- else if (cmd_mode & (EDIT_MAIN | COMMENT_OUT | EDIT_EXCL)) {
- edit_parameters(cmd_mode, argc - optind, argv + optind);
- } else if (cmd_mode == DEF_MODE
- && argv[optind] && strchr(argv[optind], '=')) {
- edit_parameters(cmd_mode | EDIT_MAIN, argc - optind, argv + optind);
+ else if (cmd_mode & (EDIT_CONF | COMMENT_OUT | EDIT_EXCL)) {
+ if (optind == argc)
+ msg_fatal("missing service argument");
+ if (cmd_mode & (MASTER_ENTRY | MASTER_FIELD | MASTER_PARAM)) {
+ edit_master(cmd_mode, argc - optind, argv + optind);
+ } else {
+ edit_main(cmd_mode, argc - optind, argv + optind);
+ }
}
/*
#include <htable.h>
#include <argv.h>
#include <dict.h>
+#include <name_code.h>
/*
* What we're supposed to be doing.
*/
#define SHOW_NONDEF (1<<0) /* show main.cf non-default settings */
#define SHOW_DEFS (1<<1) /* show main.cf default setting */
-#define SHOW_NAME (1<<2) /* show main.cf parameter name */
+#define HIDE_NAME (1<<2) /* hide main.cf parameter name */
#define SHOW_MAPS (1<<3) /* show map types */
-#define EDIT_MAIN (1<<4) /* edit main.cf */
+#define EDIT_CONF (1<<4) /* edit main.cf or master.cf */
#define SHOW_LOCKS (1<<5) /* show mailbox lock methods */
#define SHOW_EVAL (1<<6) /* expand main.cf right-hand sides */
#define SHOW_SASL_SERV (1<<7) /* show server auth plugin types */
#define SHOW_SASL_CLNT (1<<8) /* show client auth plugin types */
#define COMMENT_OUT (1<<9) /* #-out selected main.cf entries */
-#define SHOW_MASTER (1<<10) /* show master.cf entries */
+#define MASTER_ENTRY (1<<10) /* manage master.cf entries */
#define FOLD_LINE (1<<11) /* fold long *.cf entries */
#define EDIT_EXCL (1<<12) /* exclude main.cf entries */
+#define MASTER_FIELD (1<<13) /* hierarchical pathname */
+#define MAIN_PARAM (1<<14) /* manage main.cf entries */
+#define EXP_DSN_TEMPL (1<<15) /* expand bounce templates */
+#define PARAM_CLASS (1<<16) /* select parameter class */
+#define MAIN_OVER (1<<17) /* override parameter values */
+#define DUMP_DSN_TEMPL (1<<18) /* show bounce templates */
+#define MASTER_PARAM (1<<19) /* manage master.cf -o name=value */
-#define DEF_MODE SHOW_NAME /* default mode */
+#define DEF_MODE 0
/*
* Structure for one "valid parameter" (built-in, service-defined or valid
* Structure of one master.cf entry.
*/
typedef struct {
- char *name_space; /* service.type, parameter name space */
+ char *name_space; /* service/type, parameter name space */
ARGV *argv; /* null, or master.cf fields */
DICT *all_params; /* null, or all name=value entries */
HTABLE *valid_names; /* null, or "valid" parameter names */
#define PC_MASTER_MIN_FIELDS 8 /* mandatory field count */
- /*
- * Lookup table for master.cf entries. The table is terminated with an entry
- * that has a null argv member.
- */
+#define PC_MASTER_NAME_SERVICE "service"
+#define PC_MASTER_NAME_TYPE "type"
+#define PC_MASTER_NAME_PRIVATE "private"
+#define PC_MASTER_NAME_UNPRIV "unprivileged"
+#define PC_MASTER_NAME_CHROOT "chroot"
+#define PC_MASTER_NAME_WAKEUP "wakeup"
+#define PC_MASTER_NAME_MAXPROC "process_limit"
+#define PC_MASTER_NAME_CMD "command"
+
+#define PC_MASTER_FIELD_SERVICE 0 /* service name */
+#define PC_MASTER_FIELD_TYPE 1 /* service type */
+#define PC_MASTER_FIELD_PRIVATE 2 /* private service */
+#define PC_MASTER_FIELD_UNPRIV 3 /* unprivileged service */
+#define PC_MASTER_FIELD_CHROOT 4 /* chrooted service */
+#define PC_MASTER_FIELD_WAKEUP 5 /* wakeup timer */
+#define PC_MASTER_FIELD_MAXPROC 6 /* process limit */
+#define PC_MASTER_FIELD_CMD 7 /* command */
+
+#define PC_MASTER_FIELD_WILDC -1 /* wild-card */
+#define PC_MASTER_FIELD_NONE -2 /* not available
+ *
+ /* Lookup table for master.cf
+ * entries. The table is terminated
+ * with an entry that has a null argv
+ * member. */
PC_MASTER_ENT *master_table;
/*
/*
* postconf_edit.c
*/
-extern void edit_parameters(int, int, char **);
+extern void edit_main(int, int, char **);
+extern void edit_master(int, int, char **);
/*
* postconf_master.c.
*/
extern const char daemon_options_expecting_value[];
extern void read_master(int);
-extern void show_master(VSTREAM *, int, char **);
+extern void show_master_entries(VSTREAM *, int, int, char **);
+extern const char *parse_master_entry(PC_MASTER_ENT *, const char *);
+extern void print_master_entry(VSTREAM *, int, PC_MASTER_ENT *);
+extern void free_master_entry(PC_MASTER_ENT *);
+extern void show_master_fields(VSTREAM *, int, int, char **);
+extern void edit_master_field(PC_MASTER_ENT *, int, const char *);
+extern void show_master_params(VSTREAM *, int, int, char **);
+extern void edit_master_param(PC_MASTER_ENT *, int, const char *, const char *);
#define WARN_ON_OPEN_ERROR 0
#define FAIL_ON_OPEN_ERROR 1
+#define PC_MASTER_BLANKS " \t\r\n" /* XXX */
+
+ /*
+ * Master.cf parameter namespace management. The idea is to manage master.cf
+ * "-o name=value" settings with other tools than text editors.
+ *
+ * The natural choice is to use "service-name.service-type.parameter-name", but
+ * unfortunately the '.' may appear in service and parameter names.
+ *
+ * For example, a spawn(8) listener can have a service name 127.0.0.1:10028.
+ * This service name becomes part of a service-dependent parameter name
+ * "127.0.0.1:10028_time_limit". All those '.' characters mean we can't use
+ * '.' as the parameter namespace delimiter.
+ *
+ * (We could require that such service names are specified as $foo:port with
+ * the value of "foo" defined in main.cf or at the top of master.cf.)
+ *
+ * But it is easier if we use '/' instead.
+ */
+#define PC_NAMESP_SEP_CH '/'
+#define PC_NAMESP_SEP_STR "/"
+
+#define PC_LEGACY_SEP_CH '.'
+
+ /*
+ * postconf_match.c.
+ */
+#define PC_MATCH_WILDC_STR "*"
+#define PC_MATCH_ANY(p) ((p)[0] == PC_MATCH_WILDC_STR[0] && (p)[1] == 0)
+#define PC_MATCH_STRING(p, s) (PC_MATCH_ANY(p) || strcmp((p), (s)) == 0)
+
+extern ARGV *parse_service_pattern(const char *, int, int);
+extern int parse_field_pattern(const char *);
+
+#define IS_MAGIC_SERVICE_PATTERN(pat) \
+ (PC_MATCH_ANY((pat)->argv[0]) || PC_MATCH_ANY((pat)->argv[1]))
+#define MATCH_SERVICE_PATTERN(pat, name, type) \
+ (PC_MATCH_STRING((pat)->argv[0], (name)) \
+ && PC_MATCH_STRING((pat)->argv[1], (type)))
+
+#define is_magic_field_pattern(pat) ((pat) == PC_MASTER_FIELD_WILDC)
+#define str_field_pattern(pat) ((const char *) (field_name_offset[pat].name))
+
+#define IS_MAGIC_PARAM_PATTERN(pat) PC_MATCH_ANY(pat)
+#define MATCH_PARAM_PATTERN(pat, name) PC_MATCH_STRING((pat), (name))
+
+/* The following is not part of the postconf_match API. */
+extern NAME_CODE field_name_offset[];
+
/*
* postconf_builtin.c.
*/
char *expand_parameter_value(VSTRING *, int, const char *, PC_MASTER_ENT *);
+ /*
+ * postconf_print.c.
+ */
+extern void print_line(VSTREAM *, int, const char *,...);
+
/*
* postconf_unused.c.
*/
/* SYNOPSIS
/* #include <postconf.h>
/*
-/* void edit_parameters(mode, argc, argv)
+/* void edit_main(mode, argc, argv)
+/* int mode;
+/* int argc;
+/* char **argv;
+/*
+/* void edit_master(mode, argc, argv)
/* int mode;
/* int argc;
/* char **argv;
/* DESCRIPTION
-/* Edit the \fBmain.cf\fR configuration file, and update
-/* parameter settings with the "\fIname\fR=\fIvalue\fR" pairs
-/* given on the command line. The file is copied to a temporary
-/* file then renamed into place.
+/* edit_main() edits the \fBmain.cf\fR configuration
+/* file. It replaces or adds parameter settings given as
+/* "\fIname=value\fR" pairs given on the command line, or
+/* removes parameter settings given as "\fIname\fR" on the
+/* command line. The file is copied to a temporary file
+/* then renamed into place.
+/*
+/* edit_master() edits the \fBmaster.cf\fR configuration file.
+/* The file is copied to a temporary file then renamed into
+/* place. Depending on the value of \fBmode\fR:
+/* .IP MASTER_ENTRY
+/* edit_master() replaces or adds entire master.cf entries,
+/* specified on the command line as "\fIname/type = name type
+/* private unprivileged chroot wakeup process_limit command...\fR".
+/* ,IP MASTER_FIELD
+/* edit_master() replaces the value of specific service
+/* attributes, specified on the command line as
+/* "\fIname/type/attribute = value\fR".
+/* .IP MASTER_PARAM
+/* edit_master() replaces the value of specific service
+/* parameters, specified on the command line as
+/* "\fIname/type/parameter = value\fR".
/* DIAGNOSTICS
/* Problems are reported to the standard error stream.
/* FILES
/* /etc/postfix/main.cf, Postfix configuration parameters
/* /etc/postfix/main.cf.tmp, temporary name
+/* /etc/postfix/master.cf, Postfix configuration parameters
+/* /etc/postfix/master.cf.tmp, temporary name
/* LICENSE
/* .ad
/* .fi
#include <edit_file.h>
#include <readlline.h>
#include <stringops.h>
+#include <split_at.h>
/* Global library. */
#define STR(x) vstring_str(x)
-/* edit_parameters - edit parameter file */
+/* find_cf_info - pass-through non-content line, return content or null */
-void edit_parameters(int mode, int argc, char **argv)
+static char *find_cf_info(VSTRING *buf, VSTREAM *dst)
+{
+ char *cp;
+
+ for (cp = STR(buf); ISSPACE(*cp) /* including newline */ ; cp++)
+ /* void */ ;
+ /* Pass-through comment, all-whitespace, or empty line. */
+ if (*cp == '#' || *cp == 0) {
+ vstream_fputs(STR(buf), dst);
+ return (0);
+ } else {
+ return (cp);
+ }
+}
+
+/* next_cf_line - return next content line, pass-through non-content */
+
+static char *next_cf_line(VSTRING *buf, VSTREAM *src, VSTREAM *dst, int *lineno)
+{
+ char *cp;
+
+ while (vstring_get(buf, src) != VSTREAM_EOF) {
+ if (lineno)
+ *lineno += 1;
+ if ((cp = find_cf_info(buf, dst)) != 0)
+ return (cp);
+ }
+ return (0);
+}
+
+/* gobble_cf_line - accumulate multi-line content, pass-through non-content */
+
+static void gobble_cf_line(VSTRING *full_entry_buf, VSTRING *line_buf,
+ VSTREAM *src, VSTREAM *dst, int *lineno)
+{
+ int ch;
+
+ vstring_strcpy(full_entry_buf, STR(line_buf));
+ for (;;) {
+ if ((ch = VSTREAM_GETC(src)) != VSTREAM_EOF)
+ vstream_ungetc(src, ch);
+ if ((ch != '#' && !ISSPACE(ch))
+ || vstring_get(line_buf, src) == VSTREAM_EOF)
+ break;
+ lineno += 1;
+ if (find_cf_info(line_buf, dst))
+ vstring_strcat(full_entry_buf, STR(line_buf));
+ }
+}
+
+/* edit_main - edit main.cf file */
+
+void edit_main(int mode, int argc, char **argv)
{
char *path;
EDIT_FILE *ep;
VSTRING *buf = vstring_alloc(100);
VSTRING *key = vstring_alloc(10);
char *cp;
- char *edit_key;
- char *edit_val;
+ char *pattern;
+ char *edit_value;
HTABLE *table;
struct cvalue {
char *value;
cp++;
if (*cp == '#')
msg_fatal("-e, -X, or -# accepts no comment input");
- if (mode & EDIT_MAIN) {
- if ((err = split_nameval(cp, &edit_key, &edit_val)) != 0)
+ if (mode & EDIT_CONF) {
+ if ((err = split_nameval(cp, &pattern, &edit_value)) != 0)
msg_fatal("%s: \"%s\"", err, cp);
} else if (mode & (COMMENT_OUT | EDIT_EXCL)) {
if (*cp == 0)
msg_fatal("-X or -# requires non-blank parameter names");
if (strchr(cp, '=') != 0)
- msg_fatal("-X or -# requires parameter names only");
- edit_key = cp;
- trimblanks(edit_key, 0);
- edit_val = 0;
+ msg_fatal("-X or -# requires parameter names without value");
+ pattern = cp;
+ trimblanks(pattern, 0);
+ edit_value = 0;
} else {
- msg_panic("edit_parameters: unknown mode %d", mode);
+ msg_panic("edit_main: unknown mode %d", mode);
}
cvalue = (struct cvalue *) mymalloc(sizeof(*cvalue));
- cvalue->value = edit_val;
+ cvalue->value = edit_value;
cvalue->found = 0;
- htable_enter(table, edit_key, (char *) cvalue);
+ htable_enter(table, pattern, (char *) cvalue);
}
/*
#define STR(x) vstring_str(x)
interesting = 0;
- while (vstring_get(buf, src) != VSTREAM_EOF) {
- for (cp = STR(buf); ISSPACE(*cp) /* including newline */ ; cp++)
- /* void */ ;
- /* Copy comment, all-whitespace, or empty line. */
- if (*cp == '#' || *cp == 0) {
- vstream_fputs(STR(buf), dst);
- }
+ while ((cp = next_cf_line(buf, src, dst, (int *) 0)) != 0) {
/* Copy, skip or replace continued text. */
- else if (cp > STR(buf)) {
+ if (cp > STR(buf)) {
if (interesting == 0)
vstream_fputs(STR(buf), dst);
else if (mode & COMMENT_OUT)
if ((interesting = !!cvalue) != 0) {
if (cvalue->found++ == 1)
msg_warn("%s: multiple entries for \"%s\"", path, STR(key));
- if (mode & EDIT_MAIN)
+ if (mode & EDIT_CONF)
vstream_fprintf(dst, "%s = %s\n", STR(key), cvalue->value);
else if (mode & COMMENT_OUT)
vstream_fprintf(dst, "#%s", cp);
/*
* Generate new entries for parameters that were not found.
*/
- if (mode & EDIT_MAIN) {
+ if (mode & EDIT_CONF) {
for (ht_info = ht = htable_list(table); *ht; ht++) {
cvalue = (struct cvalue *) ht[0]->value;
if (cvalue->found == 0)
vstring_free(key);
htable_free(table, myfree);
}
+
+ /*
+ * Data structure to hold a master.cf edit request.
+ */
+typedef struct {
+ int match_count; /* hit count */
+ const char *raw_text; /* unparsed command-line argument */
+ char *parsed_text; /* destructive parse */
+ ARGV *service_pattern; /* service name, type, ... */
+ int field_number; /* attribute field number */
+ const char *param_pattern; /* parameter name */
+ char *edit_value; /* value substring */
+} PC_MASTER_EDIT_REQ;
+
+/* edit_master - edit master.cf file */
+
+void edit_master(int mode, int argc, char **argv)
+{
+ const char *myname = "edit_master";
+ char *path;
+ EDIT_FILE *ep;
+ VSTREAM *src;
+ VSTREAM *dst;
+ VSTRING *line_buf = vstring_alloc(100);
+ VSTRING *parse_buf = vstring_alloc(100);
+ int lineno;
+ PC_MASTER_ENT *new_entry;
+ VSTRING *full_entry_buf = vstring_alloc(100);
+ char *cp;
+ char *pattern;
+ int service_name_type_matched;
+ const char *err;
+ PC_MASTER_EDIT_REQ *edit_reqs;
+ PC_MASTER_EDIT_REQ *req;
+ int num_reqs = argc;
+ const char *edit_opts = "-Me, -Fe, -Pe, -X, or -#";
+ char *service_name;
+ char *service_type;
+
+ /*
+ * Sanity check.
+ */
+ if (num_reqs <= 0)
+ msg_panic("%s: empty argument list", myname);
+
+ /*
+ * Preprocessing: split pattern=value, then split the pattern components.
+ */
+ edit_reqs = (PC_MASTER_EDIT_REQ *) mymalloc(sizeof(*edit_reqs) * num_reqs);
+ for (req = edit_reqs; *argv != 0; req++, argv++) {
+ req->match_count = 0;
+ req->raw_text = *argv;
+ cp = req->parsed_text = mystrdup(req->raw_text);
+ if (strchr(cp, '\n') != 0)
+ msg_fatal("%s accept no multi-line input", edit_opts);
+ while (ISSPACE(*cp))
+ cp++;
+ if (*cp == '#')
+ msg_fatal("%s accept no comment input", edit_opts);
+ /* Separate the pattern from the value. */
+ if (mode & EDIT_CONF) {
+ if ((err = split_nameval(cp, &pattern, &req->edit_value)) != 0)
+ msg_fatal("%s: \"%s\"", err, req->raw_text);
+ } else if (mode & (COMMENT_OUT | EDIT_EXCL)) {
+ if (strchr(cp, '=') != 0)
+ msg_fatal("-X or -# requires names without value");
+ pattern = cp;
+ trimblanks(pattern, 0);
+ req->edit_value = 0;
+ } else {
+ msg_panic("%s: unknown mode %d", myname, mode);
+ }
+
+#define PC_MASTER_MASK (MASTER_ENTRY | MASTER_FIELD | MASTER_PARAM)
+
+ /*
+ * Split name/type or name/type/field pattern into components.
+ */
+ switch (mode & PC_MASTER_MASK) {
+ case MASTER_ENTRY:
+ if ((req->service_pattern =
+ parse_service_pattern(pattern, 2, 2)) == 0)
+ msg_fatal("-Me, -MX or -M# requires service_name/type");
+ break;
+ case MASTER_FIELD:
+ if ((req->service_pattern =
+ parse_service_pattern(pattern, 3, 3)) == 0)
+ msg_fatal("-Fe or -FX requires service_name/type/field_name");
+ req->field_number =
+ parse_field_pattern(req->service_pattern->argv[2]);
+ if (is_magic_field_pattern(req->field_number))
+ msg_fatal("-Fe does not accept wild-card field name");
+ if ((mode & EDIT_CONF)
+ && req->field_number < PC_MASTER_FIELD_CMD
+ && req->edit_value[strcspn(req->edit_value, PC_MASTER_BLANKS)])
+ msg_fatal("-Fe does not accept whitespace in non-command field");
+ break;
+ case MASTER_PARAM:
+ if ((req->service_pattern =
+ parse_service_pattern(pattern, 3, 3)) == 0)
+ msg_fatal("-Pe or -PX requires service_name/type/parameter");
+ req->param_pattern = req->service_pattern->argv[2];
+ if (IS_MAGIC_PARAM_PATTERN(req->param_pattern))
+ msg_fatal("-Pe does not accept wild-card parameter name");
+ if ((mode & EDIT_CONF)
+ && req->edit_value[strcspn(req->edit_value, PC_MASTER_BLANKS)])
+ msg_fatal("-Pe does not accept whitespace in parameter value");
+ break;
+ default:
+ msg_panic("%s: unknown edit mode %d", myname, mode);
+ }
+ }
+
+ /*
+ * Open a temp file for the result. This uses a deterministic name so we
+ * don't leave behind thrash with random names.
+ */
+ set_config_dir();
+ path = concatenate(var_config_dir, "/", MASTER_CONF_FILE, (char *) 0);
+ if ((ep = edit_file_open(path, O_CREAT | O_WRONLY, 0644)) == 0)
+ msg_fatal("open %s%s: %m", path, EDIT_FILE_SUFFIX);
+ dst = ep->tmp_fp;
+
+ /*
+ * Open the original file for input.
+ */
+ if ((src = vstream_fopen(path, O_RDONLY, 0)) == 0) {
+ /* OK to delete, since we control the temp file name exclusively. */
+ (void) unlink(ep->tmp_path);
+ msg_fatal("open %s for reading: %m", path);
+ }
+
+ /*
+ * Copy original file to temp file, while replacing service entries on
+ * the fly.
+ */
+ service_name_type_matched = 0;
+ new_entry = 0;
+ lineno = 0;
+ while ((cp = next_cf_line(parse_buf, src, dst, &lineno)) != 0) {
+ vstring_strcpy(line_buf, STR(parse_buf));
+
+ /*
+ * Copy, skip or replace continued text.
+ */
+ if (cp > STR(parse_buf)) {
+ if (service_name_type_matched == 0)
+ vstream_fputs(STR(line_buf), dst);
+ else if (mode & COMMENT_OUT)
+ vstream_fprintf(dst, "#%s", STR(line_buf));
+ }
+
+ /*
+ * Copy or replace (start of) logical line.
+ */
+ else {
+ service_name_type_matched = 0;
+
+ /*
+ * Parse out the service name and type.
+ */
+ if ((service_name = mystrtok(&cp, PC_MASTER_BLANKS)) == 0
+ || (service_type = mystrtok(&cp, PC_MASTER_BLANKS)) == 0)
+ msg_fatal("file %s: line %d: specify service name and type "
+ "on the same line", path, lineno);
+ if (strchr(service_name, '='))
+ msg_fatal("file %s: line %d: service name syntax \"%s\" is "
+ "unsupported with %s", path, lineno, service_name,
+ edit_opts);
+ if (service_type[strcspn(service_type, "=/")] != 0)
+ msg_fatal("file %s: line %d: "
+ "service type syntax \"%s\" is unsupported with %s",
+ path, lineno, service_type, edit_opts);
+
+ /*
+ * Match each service pattern.
+ */
+ for (req = edit_reqs; req < edit_reqs + num_reqs; req++) {
+ if (MATCH_SERVICE_PATTERN(req->service_pattern, service_name,
+ service_type)) {
+ service_name_type_matched = 1; /* Sticky flag */
+ req->match_count += 1;
+
+ /*
+ * Generate replacement master.cf entries.
+ */
+ if ((mode & EDIT_CONF)
+ || ((mode & MASTER_PARAM) && (mode & EDIT_EXCL))) {
+ switch (mode & PC_MASTER_MASK) {
+
+ /*
+ * Replace master.cf entry field or parameter
+ * value.
+ */
+ case MASTER_FIELD:
+ case MASTER_PARAM:
+ if (new_entry == 0) {
+ /* Gobble up any continuation lines. */
+ gobble_cf_line(full_entry_buf, line_buf, src,
+ dst, &lineno);
+ new_entry = (PC_MASTER_ENT *)
+ mymalloc(sizeof(*new_entry));
+ if ((err = parse_master_entry(new_entry,
+ STR(full_entry_buf))) != 0)
+ msg_fatal("file %s: line %d: %s",
+ path, lineno, err);
+ }
+ if (mode & MASTER_FIELD) {
+ edit_master_field(new_entry, req->field_number,
+ req->edit_value);
+ } else {
+ edit_master_param(new_entry, mode,
+ req->param_pattern,
+ req->edit_value);
+ }
+ break;
+
+ /*
+ * Replace entire master.cf entry.
+ */
+ case MASTER_ENTRY:
+ if (new_entry != 0)
+ free_master_entry(new_entry);
+ new_entry = (PC_MASTER_ENT *)
+ mymalloc(sizeof(*new_entry));
+ if ((err = parse_master_entry(new_entry,
+ req->edit_value)) != 0)
+ msg_fatal("%s: \"%s\"", err, req->raw_text);
+ break;
+ default:
+ msg_panic("%s: unknown edit mode %d", myname, mode);
+ }
+ }
+ }
+ }
+
+ /*
+ * Pass through or replace the current input line.
+ */
+ if (new_entry) {
+ print_master_entry(dst, FOLD_LINE, new_entry);
+ free_master_entry(new_entry);
+ new_entry = 0;
+ } else if (service_name_type_matched == 0) {
+ vstream_fputs(STR(line_buf), dst);
+ } else if (mode & COMMENT_OUT) {
+ vstream_fprintf(dst, "#%s", STR(line_buf));
+ }
+ }
+ }
+
+ /*
+ * Postprocessing: when editing entire service entries, generate new
+ * entries for services not found. Otherwise (editing fields or
+ * parameters), "service not found" is a fatal error.
+ */
+ for (req = edit_reqs; req < edit_reqs + num_reqs; req++) {
+ if (req->match_count == 0) {
+ if ((mode & MASTER_ENTRY) && (mode & EDIT_CONF)) {
+ new_entry = (PC_MASTER_ENT *) mymalloc(sizeof(*new_entry));
+ if ((err = parse_master_entry(new_entry, req->edit_value)) != 0)
+ msg_fatal("%s: \"%s\"", err, req->raw_text);
+ print_master_entry(dst, FOLD_LINE, new_entry);
+ free_master_entry(new_entry);
+ } else if ((mode & MASTER_ENTRY) == 0) {
+ msg_warn("unmatched service_name/type: \"%s\"", req->raw_text);
+ }
+ }
+ }
+
+ /*
+ * When all is well, rename the temp file to the original one.
+ */
+ if (vstream_fclose(src))
+ msg_fatal("read %s: %m", path);
+ if (edit_file_close(ep) != 0)
+ msg_fatal("close %s%s: %m", path, EDIT_FILE_SUFFIX);
+
+ /*
+ * Cleanup.
+ */
+ myfree(path);
+ vstring_free(line_buf);
+ vstring_free(parse_buf);
+ vstring_free(full_entry_buf);
+ for (req = edit_reqs; req < edit_reqs + num_reqs; req++) {
+ argv_free(req->service_pattern);
+ myfree(req->parsed_text);
+ }
+ myfree((char *) edit_reqs);
+}
}
}
-/* print_line - show line possibly folded, and with normalized whitespace */
-
-static void print_line(VSTREAM *fp, int mode, const char *fmt,...)
-{
- va_list ap;
- static VSTRING *buf = 0;
- char *start;
- char *next;
- int line_len = 0;
- int word_len;
-
- /*
- * One-off initialization.
- */
- if (buf == 0)
- buf = vstring_alloc(100);
-
- /*
- * Format the text.
- */
- va_start(ap, fmt);
- vstring_vsprintf(buf, fmt, ap);
- va_end(ap);
-
- /*
- * Normalize the whitespace. We don't use the line_wrap() routine because
- * 1) that function does not normalize whitespace between words and 2) we
- * want to normalize whitespace even when not wrapping lines.
- *
- * XXX Some parameters preserve whitespace: for example, smtpd_banner and
- * smtpd_reject_footer. If we have to preserve whitespace between words,
- * then perhaps readlline() can be changed to canonicalize whitespace
- * that follows a newline.
- */
- for (start = STR(buf); *(start += strspn(start, SEPARATORS)) != 0; start = next) {
- word_len = strcspn(start, SEPARATORS);
- if (*(next = start + word_len) != 0)
- *next++ = 0;
- if (word_len > 0 && line_len > 0) {
- if ((mode & FOLD_LINE) == 0 || line_len + word_len < LINE_LIMIT) {
- vstream_fputs(" ", fp);
- line_len += 1;
- } else {
- vstream_fputs("\n" INDENT_TEXT, fp);
- line_len = INDENT_LEN;
- }
- }
- vstream_fputs(start, fp);
- line_len += word_len;
- }
- vstream_fputs("\n", fp);
-}
-
/* print_parameter - show specific parameter */
static void print_parameter(VSTREAM *fp, int mode, const char *name,
if ((mode & SHOW_EVAL) != 0 && PC_RAW_PARAMETER(node) == 0)
value = expand_parameter_value((VSTRING *) 0, mode, value,
(PC_MASTER_ENT *) 0);
- if (mode & SHOW_NAME) {
+ if ((mode & HIDE_NAME) == 0) {
print_line(fp, mode, "%s = %s\n", name, value);
} else {
print_line(fp, mode, "%s\n", value);
/* void read_master(fail_on_open)
/* int fail_on_open;
/*
-/* void show_master(fp, mode, filters)
+/* void show_master_entries(fp, mode, service_filters)
/* VSTREAM *fp;
/* int mode;
-/* char **filters;
+/* char **service_filters;
+/*
+/* void show_master_fields(fp, mode, n_filters, field_filters)
+/* VSTREAM *fp;
+/* int mode;
+/* int n_filters;
+/* char **field_filters;
+/*
+/* void edit_master_field(masterp, field, new_value)
+/* PC_MASTER_ENT *masterp;
+/* int field;
+/* const char *new_value;
+/*
+/* void show_master_params(fp, mode, argc, **param_filters)
+/* VSTREAM *fp;
+/* int mode;
+/* int argc;
+/* char **param_filters;
+/*
+/* void edit_master_param(masterp, mode, param_name, param_value)
+/* PC_MASTER_ENT *masterp;
+/* int mode;
+/* const char *param_name;
+/* const char *param_value;
+/* AUXILIARY FUNCTIONS
+/* const char *parse_master_entry(masterp, buf)
+/* PC_MASTER_ENT *masterp;
+/* const char *buf;
+/*
+/* void print_master_entry(fp, mode, masterp)
+/* VSTREAM *fp;
+/* int mode;
+/* PC_MASTER_ENT *masterp;
+/*
+/* void free_master_entry(masterp)
+/* PC_MASTER_ENT *masterp;
/* DESCRIPTION
/* read_master() reads entries from master.cf into memory.
/*
-/* show_master() writes the entries in the master.cf file
+/* show_master_entries() writes the entries in the master.cf
+/* file to the specified stream.
+/*
+/* show_master_fields() writes name/type/field=value records to
+/* the specified stream.
+/*
+/* edit_master_field() updates the value of a single-column
+/* or multi-column attribute.
+/*
+/* show_master_params() writes name/type/parameter=value records
/* to the specified stream.
/*
+/* edit_master_param() updates, removes or adds the named
+/* parameter in a master.cf entry (the remove request ignores
+/* the parameter value).
+/*
/* daemon_options_expecting_value[] is an array of master.cf
/* daemon command-line options that expect an option value.
/*
+/* parse_master_entry() parses a (perhaps multi-line) string
+/* that contains a complete master.cf entry, and normalizes
+/* daemon command-line options to simplify further handling.
+/*
+/* print_master_entry() prints a parsed master.cf entry.
+/*
+/* free_master_entry() returns storage to the heap that was
+/* allocated by parse_master_entry().
+/*
/* Arguments
/* .IP fail_on_open
/* Specify FAIL_ON_OPEN if open failure is a fatal error,
/* .IP fp
/* Output stream.
/* .IP mode
-/* If the FOLD_LINE flag is set, show_master() wraps long
-/* output lines.
-/* .IP filters
-/* A list of zero or more expressions in master_service(3)
-/* format. If no list is specified, show_master() outputs
+/* Bit-wise OR of flags. Flags other than the following are ignored.
+/* .RS
+/* .IP FOLD_LINE
+/* Wrap long output lines.
+/* .IP SHOW_EVAL
+/* Expand $name in parameter values.
+/* .IP EDIT_EXCL
+/* Request that edit_master_param() removes the parameter.
+/* .RE
+/* .IP n_filters
+/* The number of command-line filters.
+/* .IP field_filters
+/* A list of zero or more service field patterns (name/type/field).
+/* The output is formatted as "name/type/field = value". If
+/* no filters are specified, show_master_fields() outputs the
+/* fields of all master.cf entries in the specified order.
+/* .IP param_filters
+/* A list of zero or more service parameter patterns
+/* (name/type/parameter). The output is formatted as
+/* "name/type/parameter = value". If no filters are specified,
+/* show_master_params() outputs the parameters of all master.cf
+/* entries in sorted order.
+/* .IP service_filters
+/* A list of zero or more service patterns (name or name/type).
+/* If no filters are specified, show_master_entries() outputs
/* all master.cf entries in the specified order.
+/* .IP field
+/* Index into parsed master.cf entry.
+/* .IP new_value
+/* Replacement value for the specified field. It is split
+/* in whitespace in case of a multi-field attribute.
/* DIAGNOSTICS
/* Problems are reported to the standard error stream.
/* LICENSE
#include <sys_defs.h>
#include <string.h>
+#include <stdlib.h>
+#include <stdarg.h>
/* Utility library. */
#include <vstream.h>
#include <readlline.h>
#include <stringops.h>
+#include <split_at.h>
/* Global library. */
#include <mail_params.h>
-#include <match_service.h>
+
+/* Master library. */
+
+#include <master_proto.h>
/* Application-specific. */
const char daemon_options_expecting_value[] = "o";
+ /*
+ * Data structure to capture a command-line service field filter.
+ */
+typedef struct {
+ int match_count; /* hit count */
+ const char *raw_text; /* full pattern text */
+ ARGV *service_pattern; /* parsed service name, type, ... */
+ int field_pattern; /* parsed field pattern */
+ const char *param_pattern; /* parameter pattern */
+} PC_MASTER_FIELD_REQ;
+
+ /*
+ * Valid inputs.
+ */
+static const char *valid_master_types[] = {
+ MASTER_XPORT_NAME_UNIX,
+ MASTER_XPORT_NAME_FIFO,
+ MASTER_XPORT_NAME_INET,
+ MASTER_XPORT_NAME_PASS,
+ 0,
+};
+
+static const char valid_bool_types[] = "yn-";
+
#define STR(x) vstring_str(x)
/* normalize_options - bring options into canonical form */
for (cp = arg + 1; *cp; cp++) {
if (strchr(daemon_options_expecting_value, *cp) != 0
&& cp > arg + 1) {
- /* Split "-stuffo" into "-stuff" and "-o". */
+ /* Split "-stuffozz" into "-stuff" and "-ozz". */
junk = concatenate("-", cp, (char *) 0);
argv_insert_one(argv, field + 1, junk);
myfree(junk);
}
}
-/* parse_master_line - parse one master line */
+/* fix_fatal - fix multiline text before release */
+
+static NORETURN PRINTFLIKE(1, 2) fix_fatal(const char *fmt,...)
+{
+ VSTRING *buf = vstring_alloc(100);
+ va_list ap;
+
+ /*
+ * Replace newline with whitespace.
+ */
+ va_start(ap, fmt);
+ vstring_vsprintf(buf, fmt, ap);
+ va_end(ap);
+ translit(STR(buf), "\n", " ");
+ msg_fatal("%s", STR(buf));
+ /* NOTREACHED */
+}
+
+/* check_master_entry - sanity check master.cf entry */
+
+static void check_master_entry(ARGV *argv, const char *raw_text)
+{
+ const char **cpp;
+ char *cp;
+ int len;
+ int field;
+
+ cp = argv->argv[PC_MASTER_FIELD_TYPE];
+ for (cpp = valid_master_types; /* see below */ ; cpp++) {
+ if (*cpp == 0)
+ fix_fatal("invalid " PC_MASTER_NAME_TYPE " field \"%s\" in \"%s\"",
+ cp, raw_text);
+ if (strcmp(*cpp, cp) == 0)
+ break;
+ }
+
+ for (field = PC_MASTER_FIELD_PRIVATE; field <= PC_MASTER_FIELD_CHROOT; field++) {
+ cp = argv->argv[field];
+ if (cp[1] != 0 || strchr(valid_bool_types, *cp) == 0)
+ fix_fatal("invalid %s field \%s\" in \"%s\"",
+ str_field_pattern(field), cp, raw_text);
+ }
+
+ cp = argv->argv[PC_MASTER_FIELD_WAKEUP];
+ len = strlen(cp);
+ if (len > 0 && cp[len - 1] == '?')
+ len--;
+ if (!(cp[0] == '-' && len == 1) && strspn(cp, "0123456789") != len)
+ fix_fatal("invalid " PC_MASTER_NAME_WAKEUP " field \%s\" in \"%s\"",
+ cp, raw_text);
+
+ cp = argv->argv[PC_MASTER_FIELD_MAXPROC];
+ if (strcmp("-", cp) != 0 && cp[strspn(cp, "0123456789")] != 0)
+ fix_fatal("invalid " PC_MASTER_NAME_MAXPROC " field \%s\" in \"%s\"",
+ cp, raw_text);
+}
+
+/* free_master_entry - destroy parsed entry */
+
+void free_master_entry(PC_MASTER_ENT *masterp)
+{
+ /* XX Fixme: allocation/deallocation asymmetry. */
+ myfree(masterp->name_space);
+ argv_free(masterp->argv);
+ if (masterp->valid_names)
+ htable_free(masterp->valid_names, myfree);
+ if (masterp->all_params)
+ dict_free(masterp->all_params);
+ myfree((char *) masterp);
+}
+
+/* parse_master_entry - parse one master line */
-static const char *parse_master_line(PC_MASTER_ENT *masterp, const char *buf)
+const char *parse_master_entry(PC_MASTER_ENT *masterp, const char *buf)
{
ARGV *argv;
* The postconf command needs to show default fields as "-", and needs to
* know about all service names so that it can generate service-dependent
* parameter names (transport-dependent etc.).
+ *
+ * XXX Do per-field sanity checks.
*/
-#define MASTER_BLANKS " \t\r\n" /* XXX */
-
- argv = argv_split(buf, MASTER_BLANKS);
+ argv = argv_split(buf, PC_MASTER_BLANKS);
if (argv->argc < PC_MASTER_MIN_FIELDS) {
argv_free(argv); /* Coverity 201311 */
return ("bad field count");
}
+ check_master_entry(argv, buf);
normalize_options(argv);
masterp->name_space =
- concatenate(argv->argv[0], ".", argv->argv[1], (char *) 0);
+ concatenate(argv->argv[0], PC_NAMESP_SEP_STR, argv->argv[1], (char *) 0);
masterp->argv = argv;
masterp->valid_names = 0;
masterp->all_params = 0;
while (readlline(buf, fp, &line_count) != 0) {
master_table = (PC_MASTER_ENT *) myrealloc((char *) master_table,
(entry_count + 2) * sizeof(*master_table));
- if ((err = parse_master_line(master_table + entry_count,
- STR(buf))) != 0)
+ if ((err = parse_master_entry(master_table + entry_count,
+ STR(buf))) != 0)
msg_fatal("file %s: line %d: %s", path, line_count, err);
entry_count += 1;
}
myfree(path);
}
-/* print_master_line - print one master line */
+/* print_master_entry - print one master line */
-static void print_master_line(VSTREAM *fp, int mode, PC_MASTER_ENT *masterp)
+void print_master_entry(VSTREAM *fp, int mode, PC_MASTER_ENT *masterp)
{
char **argv = masterp->argv->argv;
const char *arg;
*/
if (arg[0] != '-' || strcmp(arg, "--") == 0) {
in_daemon_options = 0;
- if ((mode & FOLD_LINE)
- && line_len > column_goal[PC_MASTER_MIN_FIELDS - 1]) {
+#if 0
+ if (mode & FOLD_LINE)
/* Force line wrap. */
line_len = LINE_LIMIT;
- }
+#endif
}
/*
else if (strchr(daemon_options_expecting_value, arg[1]) != 0
&& (aval = argv[field + 1]) != 0) {
+ /* Force line wrap before option with value. */
+ line_len = LINE_LIMIT;
+
/*
* Optionally, expand $name in parameter value.
*/
ADD_SPACE;
ADD_TEXT(aval, strlen(aval));
field += 1;
+
+ /* Force line wrap after option with value. */
+ line_len = LINE_LIMIT;
+
+ }
+ }
+ vstream_fputs("\n", fp);
+
+ if (msg_verbose)
+ vstream_fflush(fp);
+}
+
+/* show_master_entries - show master.cf entries */
+
+void show_master_entries(VSTREAM *fp, int mode, int argc, char **argv)
+{
+ PC_MASTER_ENT *masterp;
+ PC_MASTER_FIELD_REQ *field_reqs;
+ PC_MASTER_FIELD_REQ *req;
+
+ /*
+ * Parse the filter expressions.
+ */
+ if (argc > 0) {
+ field_reqs = (PC_MASTER_FIELD_REQ *)
+ mymalloc(sizeof(*field_reqs) * argc);
+ for (req = field_reqs; req < field_reqs + argc; req++) {
+ req->match_count = 0;
+ req->raw_text = *argv++;
+ req->service_pattern =
+ parse_service_pattern(req->raw_text, 1, 2);
+ if (req->service_pattern == 0)
+ msg_fatal("-M option requires service_name[/type]");
+ }
+ }
+
+ /*
+ * Iterate over the master table.
+ */
+ for (masterp = master_table; masterp->argv != 0; masterp++) {
+ if (argc > 0) {
+ for (req = field_reqs; req < field_reqs + argc; req++) {
+ if (MATCH_SERVICE_PATTERN(req->service_pattern,
+ masterp->argv->argv[0],
+ masterp->argv->argv[1])) {
+ req->match_count++;
+ print_master_entry(fp, mode, masterp);
+ }
+ }
+ } else {
+ print_master_entry(fp, mode, masterp);
+ }
+ }
+
+ /*
+ * Cleanup.
+ */
+ if (argc > 0) {
+ for (req = field_reqs; req < field_reqs + argc; req++) {
+ if (req->match_count == 0)
+ msg_warn("unmatched request: \"%s\"", req->raw_text);
+ argv_free(req->service_pattern);
+ }
+ myfree((char *) field_reqs);
+ }
+}
+
+/* print_master_field - scaffolding */
+
+static void print_master_field(VSTREAM *fp, int mode,
+ PC_MASTER_ENT *masterp,
+ int field)
+{
+ char **argv = masterp->argv->argv;
+ const char *arg;
+ const char *aval;
+ int arg_len;
+ int line_len;
+ int in_daemon_options;
+
+ /*
+ * Show the field value, or the first value in the case of a multi-column
+ * field.
+ */
+#define ADD_CHAR(ch) ADD_TEXT((ch), 1)
+
+ line_len = 0;
+ if ((mode & HIDE_NAME) == 0) {
+ ADD_TEXT(argv[0], strlen(argv[0]));
+ ADD_CHAR(PC_NAMESP_SEP_STR);
+ ADD_TEXT(argv[1], strlen(argv[1]));
+ ADD_CHAR(PC_NAMESP_SEP_STR);
+ ADD_TEXT(str_field_pattern(field), strlen(str_field_pattern(field)));
+ ADD_TEXT(" = ", 3);
+ if (line_len + strlen(argv[field]) > LINE_LIMIT) {
+ vstream_fputs("\n" INDENT_TEXT, fp);
+ line_len = INDENT_LEN;
+ }
+ }
+ ADD_TEXT(argv[field], strlen(argv[field]));
+
+ /*
+ * Format the daemon command-line options and non-option arguments. Here,
+ * we have no data-dependent preference for column positions, but we do
+ * have argument grouping preferences.
+ */
+ if (field == PC_MASTER_FIELD_CMD) {
+ in_daemon_options = 1;
+ for (field += 1; (arg = argv[field]) != 0; field++) {
+ arg_len = strlen(arg);
+ aval = 0;
+ if (in_daemon_options) {
+
+ /*
+ * We make no special case for generic options (-v -D)
+ * options.
+ */
+ if (arg[0] != '-' || strcmp(arg, "--") == 0) {
+ in_daemon_options = 0;
+ } else if (strchr(daemon_options_expecting_value, arg[1]) != 0
+ && (aval = argv[field + 1]) != 0) {
+
+ /* Force line break before option with value. */
+ line_len = LINE_LIMIT;
+
+ /*
+ * Optionally, expand $name in parameter value.
+ */
+ if (strcmp(arg, "-o") == 0
+ && (mode & SHOW_EVAL) != 0)
+ aval = expand_parameter_value((VSTRING *) 0, mode,
+ aval, masterp);
+
+ /*
+ * Keep option and value on the same line.
+ */
+ arg_len += strlen(aval) + 1;
+ }
+ }
+
+ /*
+ * Insert a line break when the next item won't fit.
+ */
+ if (line_len > INDENT_LEN) {
+ if ((mode & FOLD_LINE) == 0
+ || line_len + 1 + arg_len < LINE_LIMIT) {
+ ADD_SPACE;
+ } else {
+ vstream_fputs("\n" INDENT_TEXT, fp);
+ line_len = INDENT_LEN;
+ }
+ }
+ ADD_TEXT(arg, strlen(arg));
+ if (aval) {
+ ADD_SPACE;
+ ADD_TEXT(aval, strlen(aval));
+ field += 1;
+
+ /* Force line break after option with value. */
+ line_len = LINE_LIMIT;
+ }
}
}
vstream_fputs("\n", fp);
+
+ if (msg_verbose)
+ vstream_fflush(fp);
+}
+
+/* show_master_fields - show master.cf fields */
+
+void show_master_fields(VSTREAM *fp, int mode, int argc, char **argv)
+{
+ const char *myname = "show_master_fields";
+ PC_MASTER_ENT *masterp;
+ PC_MASTER_FIELD_REQ *field_reqs;
+ PC_MASTER_FIELD_REQ *req;
+ int field;
+
+ /*
+ * Parse the filter expressions.
+ */
+ if (argc > 0) {
+ field_reqs = (PC_MASTER_FIELD_REQ *)
+ mymalloc(sizeof(*field_reqs) * argc);
+ for (req = field_reqs; req < field_reqs + argc; req++) {
+ req->match_count = 0;
+ req->raw_text = *argv++;
+ req->service_pattern =
+ parse_service_pattern(req->raw_text, 1, 3);
+ if (req->service_pattern == 0)
+ msg_fatal("-F option requires service_name[/type[/field]]");
+ field = req->field_pattern =
+ parse_field_pattern(req->service_pattern->argv[2]);
+ if (is_magic_field_pattern(field) == 0
+ && (field < 0 || field > PC_MASTER_FIELD_CMD))
+ msg_panic("%s: bad attribute field index: %d",
+ myname, field);
+ }
+ }
+
+ /*
+ * Iterate over the master table.
+ */
+ for (masterp = master_table; masterp->argv != 0; masterp++) {
+ if (argc > 0) {
+ for (req = field_reqs; req < field_reqs + argc; req++) {
+ if (MATCH_SERVICE_PATTERN(req->service_pattern,
+ masterp->argv->argv[0],
+ masterp->argv->argv[1])) {
+ req->match_count++;
+ field = req->field_pattern;
+ if (is_magic_field_pattern(field)) {
+ for (field = 0; field <= PC_MASTER_FIELD_CMD; field++)
+ print_master_field(fp, mode, masterp, field);
+ } else {
+ print_master_field(fp, mode, masterp, field);
+ }
+ }
+ }
+ } else {
+ for (field = 0; field <= PC_MASTER_FIELD_CMD; field++)
+ print_master_field(fp, mode, masterp, field);
+ }
+ }
+
+ /*
+ * Cleanup.
+ */
+ if (argc > 0) {
+ for (req = field_reqs; req < field_reqs + argc; req++) {
+ if (req->match_count == 0)
+ msg_warn("unmatched request: \"%s\"", req->raw_text);
+ argv_free(req->service_pattern);
+ }
+ myfree((char *) field_reqs);
+ }
+}
+
+/* edit_master_field - replace master.cf field value. */
+
+void edit_master_field(PC_MASTER_ENT *masterp, int field,
+ const char *new_value)
+{
+
+ /*
+ * Replace multi-column attribute.
+ */
+ if (field == PC_MASTER_FIELD_CMD) {
+ argv_truncate(masterp->argv, PC_MASTER_FIELD_CMD);
+ argv_split_append(masterp->argv, new_value, PC_MASTER_BLANKS);
+ }
+
+ /*
+ * Replace single-column attribute.
+ */
+ else {
+ argv_replace_one(masterp->argv, field, new_value);
+ }
+
+ /*
+ * Do per-field sanity checks.
+ */
+ check_master_entry(masterp->argv, new_value);
+}
+
+/* print_master_param - scaffolding */
+
+static void print_master_param(VSTREAM *fp, int mode, PC_MASTER_ENT *masterp,
+ const char *param_name, const char *param_value)
+{
+ if ((mode & SHOW_EVAL) != 0)
+ param_value = expand_parameter_value((VSTRING *) 0, mode,
+ param_value, masterp);
+ if ((mode & HIDE_NAME) == 0) {
+ print_line(fp, mode, "%s%c%s = %s\n",
+ masterp->name_space, PC_NAMESP_SEP_CH,
+ param_name, param_value);
+ } else {
+ print_line(fp, mode, "%s\n", param_value);
+ }
+ if (msg_verbose)
+ vstream_fflush(fp);
+}
+
+/* sort_argv_cb - sort argv call-back */
+
+static int sort_argv_cb(const void *a, const void *b)
+{
+ return (strcmp(*(char **) a, *(char **) b));
+}
+
+/* show_master_any_param - show any parameter in master.cf service entry */
+
+static void show_master_any_param(VSTREAM *fp, int mode, PC_MASTER_ENT *masterp)
+{
+ const char *myname = "show_master_any_param";
+ ARGV *argv = argv_alloc(10);
+ DICT *dict = masterp->all_params;
+ const char *param_name;
+ const char *param_value;
+ int param_count = 0;
+ int how;
+ char **cpp;
+
+ /*
+ * Print parameters in sorted order. The number of parameters per
+ * master.cf entry is small, so we optmiize for code simplicity and don't
+ * worry about the cost of double lookup.
+ */
+
+ /* Look up the parameter names and ignore the values. */
+
+ for (how = DICT_SEQ_FUN_FIRST;
+ dict->sequence(dict, how, ¶m_name, ¶m_value) == 0;
+ how = DICT_SEQ_FUN_NEXT) {
+ argv_add(argv, param_name, ARGV_END);
+ param_count++;
+ }
+
+ /* Print the parameters in sorted order. */
+
+ qsort(argv->argv, param_count, sizeof(argv->argv[0]), sort_argv_cb);
+ for (cpp = argv->argv; (param_name = *cpp) != 0; cpp++) {
+ if ((param_value = dict_get(dict, param_name)) == 0)
+ msg_panic("%s: parameter name not found: %s", myname, param_name);
+ print_master_param(fp, mode, masterp, param_name, param_value);
+ }
+
+ /*
+ * Clean up.
+ */
+ argv_free(argv);
}
-/* show_master - show master.cf entries */
+/* show_master_params - show master.cf params */
-void show_master(VSTREAM *fp, int mode, char **filters)
+void show_master_params(VSTREAM *fp, int mode, int argc, char **argv)
{
PC_MASTER_ENT *masterp;
- ARGV *service_filter = 0;
+ PC_MASTER_FIELD_REQ *field_reqs;
+ PC_MASTER_FIELD_REQ *req;
+ DICT *dict;
+ const char *param_value;
/*
- * Initialize the service filter.
+ * Parse the filter expressions.
*/
- if (filters[0])
- service_filter = match_service_init_argv(filters);
+ if (argc > 0) {
+ field_reqs = (PC_MASTER_FIELD_REQ *)
+ mymalloc(sizeof(*field_reqs) * argc);
+ for (req = field_reqs; req < field_reqs + argc; req++) {
+ req->match_count = 0;
+ req->raw_text = *argv++;
+ req->service_pattern =
+ parse_service_pattern(req->raw_text, 1, 3);
+ if (req->service_pattern == 0)
+ msg_fatal("-P option requires service_name[/type[/parameter]]");
+ req->param_pattern = req->service_pattern->argv[2];
+ }
+ }
/*
* Iterate over the master table.
*/
- for (masterp = master_table; masterp->argv != 0; masterp++)
- if ((service_filter == 0
- || match_service_match(service_filter, masterp->name_space))
- && ((mode & SHOW_NONDEF) == 0 || masterp->all_params != 0))
- print_master_line(fp, mode, masterp);
+ for (masterp = master_table; masterp->argv != 0; masterp++) {
+ if ((dict = masterp->all_params) != 0) {
+ if (argc > 0) {
+ for (req = field_reqs; req < field_reqs + argc; req++) {
+ if (MATCH_SERVICE_PATTERN(req->service_pattern,
+ masterp->argv->argv[0],
+ masterp->argv->argv[1])) {
+ if (IS_MAGIC_PARAM_PATTERN(req->param_pattern)) {
+ show_master_any_param(fp, mode, masterp);
+ req->match_count += 1;
+ } else if ((param_value = dict_get(dict,
+ req->param_pattern)) != 0) {
+ print_master_param(fp, mode, masterp,
+ req->param_pattern,
+ param_value);
+ req->match_count += 1;
+ }
+ }
+ }
+ } else {
+ show_master_any_param(fp, mode, masterp);
+ }
+ }
+ }
/*
* Cleanup.
*/
- if (service_filter != 0)
- argv_free(service_filter);
+ if (argc > 0) {
+ for (req = field_reqs; req < field_reqs + argc; req++) {
+ if (req->match_count == 0)
+ msg_warn("unmatched request: \"%s\"", req->raw_text);
+ argv_free(req->service_pattern);
+ }
+ myfree((char *) field_reqs);
+ }
+}
+
+/* edit_master_param - update, add or remove -o parameter=value */
+
+void edit_master_param(PC_MASTER_ENT *masterp, int mode,
+ const char *param_name,
+ const char *param_value)
+{
+ const char *myname = "edit_master_param";
+ ARGV *argv = masterp->argv;
+ const char *arg;
+ const char *aval;
+ int param_match = 0;
+ int name_len = strlen(param_name);
+ int field;
+
+ for (field = PC_MASTER_MIN_FIELDS; argv->argv[field] != 0; field++) {
+ arg = argv->argv[field];
+
+ /*
+ * Stop at the first non-option argument or end-of-list.
+ */
+ if (arg[0] != '-' || strcmp(arg, "--") == 0) {
+ break;
+ }
+
+ /*
+ * Zoom in on command-line options with a value.
+ */
+ else if (strchr(daemon_options_expecting_value, arg[1]) != 0
+ && (aval = argv->argv[field + 1]) != 0) {
+
+ /*
+ * Zoom in on "-o parameter=value".
+ */
+ if (strcmp(arg, "-o") == 0) {
+ if (strncmp(aval, param_name, name_len) == 0
+ && aval[name_len] == '=') {
+ param_match = 1;
+ switch (mode & (EDIT_CONF | EDIT_EXCL)) {
+
+ /*
+ * Update parameter=value.
+ */
+ case EDIT_CONF:
+ aval = concatenate(param_name, "=",
+ param_value, (char *) 0);
+ argv_replace_one(argv, field + 1, aval);
+ myfree((char *) aval);
+ if (masterp->all_params)
+ dict_put(masterp->all_params, param_name, param_value);
+ /* XXX Update parameter "used/defined" status. */
+ break;
+
+ /*
+ * Delete parameter=value.
+ */
+ case EDIT_EXCL:
+ argv_delete(argv, field, 2);
+ if (masterp->all_params)
+ dict_del(masterp->all_params, param_name);
+ /* XXX Update parameter "used/defined" status. */
+ field -= 2;
+ break;
+ default:
+ msg_panic("%s: unexpected mode: %d", myname, mode);
+ }
+ }
+ }
+
+ /*
+ * Skip over the command-line option value.
+ */
+ field += 1;
+ }
+ }
+
+ /*
+ * Add unmatched parameter.
+ */
+ if ((mode & EDIT_CONF) && param_match == 0) {
+ /* XXX Generalize: argv_insert(argv, where, list...) */
+ argv_insert_one(argv, field, "-o");
+ aval = concatenate(param_name, "=",
+ param_value, (char *) 0);
+ argv_insert_one(argv, field + 1, aval);
+ if (masterp->all_params)
+ dict_put(masterp->all_params, param_name, param_value);
+ /* XXX May affect parameter "used/defined" status. */
+ myfree((char *) aval);
+ param_match = 1;
+ }
}
--- /dev/null
+/*++
+/* NAME
+/* postconf_match 3
+/* SUMMARY
+/* pattern-matching support
+/* SYNOPSIS
+/* #include <postconf.h>
+/*
+/* int parse_field_pattern(field_expr)
+/* char *field_expr;
+/*
+/* const char *str_field_pattern(field_pattern)
+/* int field_pattern;
+/*
+/* int is_magic_field_pattern(field_pattern)
+/* int field_pattern;
+/*
+/* ARGV *parse_service_pattern(service_expr, min_expr, max_expr)
+/* const char *service_expr;
+/* int min_expr;
+/* int max_expr;
+/*
+/* int IS_MAGIC_SERVICE_PATTERN(service_pattern)
+/* const ARGV *service_pattern;
+/*
+/* int MATCH_SERVICE_PATTERN(service_pattern, service_name,
+/* service_type)
+/* const ARGV *service_pattern;
+/* const char *service_name;
+/* const char *service_type;
+/*
+/* const char *str_field_pattern(field_pattern)
+/* int field_pattern;
+/*
+/* int IS_MAGIC_PARAM_PATTERN(param_pattern)
+/* const char *param_pattern;
+/*
+/* int MATCH_PARAM_PATTERN(param_pattern, param_name)
+/* const char *param_pattern;
+/* const char *param_name;
+/* DESCRIPTION
+/* parse_service_pattern() takes an expression and splits it
+/* up on '/' into an array of sub-expressions, This function
+/* returns null if the input does fewer than "min" or more
+/* than "max" sub-expressions.
+/*
+/* IS_MAGIC_SERVICE_PATTERN() returns non-zero if any of the
+/* service name or service type sub-expressions contains a
+/* matching operator (as opposed to string literals that only
+/* match themselves). This is an unsafe macro that evaluates
+/* its arguments more than once.
+/*
+/* MATCH_SERVICE_PATTERN() matches a service name and type
+/* from master.cf against the parsed pattern. This is an unsafe
+/* macro that evaluates its arguments more than once.
+/*
+/* parse_field_pattern() converts a field sub-expression, and
+/* returns the conversion result.
+/*
+/* str_field_pattern() converts a result from parse_field_pattern()
+/* into string form.
+/*
+/* is_magic_field_pattern() returns non-zero if the field
+/* pattern sub-expression contained a matching operator (as
+/* opposed to a string literal that only matches itself).
+/*
+/* IS_MAGIC_PARAM_PATTERN() returns non-zero if the parameter
+/* sub-expression contains a matching operator (as opposed to
+/* a string literal that only matches itself). This is an
+/* unsafe macro that evaluates its arguments more than once.
+/*
+/* MATCH_PARAM_PATTERN() matches a parameter name from master.cf
+/* against the parsed pattern. This is an unsafe macro that
+/* evaluates its arguments more than once.
+/*
+/* Arguments
+/* .IP field_expr
+/* A field expression.
+/* .IP service_expr
+/* This argument is split on '/' into its constituent
+/* sub-expressions.
+/* .IP min_expr
+/* The minimum number of sub-expressions in service_expr.
+/* .IP max_expr
+/* The maximum number of sub-expressions in service_expr.
+/* .IP service_name
+/* Service name from master.cf.
+/* .IP service_type
+/* Service type from master.cf.
+/* .IP param_pattern
+/* A parameter name expression.
+/* DIAGNOSTICS
+/* Fatal errors: invalid syntax.
+/* 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>
+#include <vstring.h>
+
+/* Global library. */
+
+#include <split_at.h>
+
+/* Application-specific. */
+
+#include <postconf.h>
+
+ /*
+ * Conversion table. Each PC_MASTER_NAME_XXX name entry must be stored at
+ * table offset PC_MASTER_FIELD_XXX. So don't mess it up.
+ */
+NAME_CODE field_name_offset[] = {
+ PC_MASTER_NAME_SERVICE, PC_MASTER_FIELD_SERVICE,
+ PC_MASTER_NAME_TYPE, PC_MASTER_FIELD_TYPE,
+ PC_MASTER_NAME_PRIVATE, PC_MASTER_FIELD_PRIVATE,
+ PC_MASTER_NAME_UNPRIV, PC_MASTER_FIELD_UNPRIV,
+ PC_MASTER_NAME_CHROOT, PC_MASTER_FIELD_CHROOT,
+ PC_MASTER_NAME_WAKEUP, PC_MASTER_FIELD_WAKEUP,
+ PC_MASTER_NAME_MAXPROC, PC_MASTER_FIELD_MAXPROC,
+ PC_MASTER_NAME_CMD, PC_MASTER_FIELD_CMD,
+ "*", PC_MASTER_FIELD_WILDC,
+ 0, PC_MASTER_FIELD_NONE,
+};
+
+/* parse_field_pattern - parse service attribute pattern */
+
+int parse_field_pattern(const char *field_name)
+{
+ int field_pattern;
+
+ if ((field_pattern = name_code(field_name_offset,
+ NAME_CODE_FLAG_STRICT_CASE,
+ field_name)) == PC_MASTER_FIELD_NONE)
+ msg_fatal("invalid service attribute name: \"%s\"", field_name);
+ return (field_pattern);
+}
+
+/* parse_service_pattern - parse service pattern */
+
+ARGV *parse_service_pattern(const char *pattern, int min_expr, int max_expr)
+{
+ ARGV *argv;
+ char **cpp;
+
+ /*
+ * Work around argv_split() lameness.
+ */
+ if (*pattern == '/')
+ return (0);
+ argv = argv_split(pattern, PC_NAMESP_SEP_STR);
+ if (argv->argc < min_expr || argv->argc > max_expr) {
+ argv_free(argv);
+ return (0);
+ }
+
+ /*
+ * Allow '*' only all by itself.
+ */
+ for (cpp = argv->argv; *cpp; cpp++) {
+ if (!PC_MATCH_ANY(*cpp) && strchr(*cpp, PC_MATCH_WILDC_STR[0]) != 0) {
+ argv_free(argv);
+ return (0);
+ }
+ }
+
+ /*
+ * Provide defaults for missing fields.
+ */
+ while (argv->argc < max_expr)
+ argv_add(argv, PC_MATCH_WILDC_STR, ARGV_END);
+ return (argv);
+}
/* set_config_dir - forcibly override var_config_dir */
-void set_config_dir(void)
+void set_config_dir(void)
{
char *config_dir;
if (var_config_dir)
- myfree(var_config_dir);
+ myfree(var_config_dir);
var_config_dir = mystrdup((config_dir = safe_getenv(CONF_ENV_PATH)) != 0 ?
- config_dir : DEF_CONFIG_DIR); /* XXX */
+ config_dir : DEF_CONFIG_DIR); /* XXX */
set_mail_conf_str(VAR_CONFIG_DIR, var_config_dir);
}
--- /dev/null
+/*++
+/* NAME
+/* postconf_print 3
+/* SUMMARY
+/* basic line printing support
+/* SYNOPSIS
+/* #include <postconf.h>
+/*
+/* void print_line(fp, mode, const char *fmt, ...)
+/* VSTREAM *fp;
+/* int mode;
+/* const char *fmt;
+/* DESCRIPTION
+/* print_line() formats text, normalized whitespace, and
+/* optionally folds long lines.
+/*
+/* Arguments:
+/* .IP fp
+/* Output stream.
+/* .IP mode
+/* Bit-wise OR of zero or more of the following (other flags
+/* are ignored):
+/* .RS
+/* .IP FOLD_LINE
+/* Fold long lines.
+/* .RE
+/* .IP fmt
+/* Format string.
+/* DIAGNOSTICS
+/* Problems are reported to the standard error stream.
+/* 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>
+#include <stdarg.h>
+
+/* Utility library. */
+
+#include <msg.h>
+#include <vstream.h>
+#include <vstring.h>
+
+/* Application-specific. */
+
+#include <postconf.h>
+
+/* SLMs. */
+
+#define STR(x) vstring_str(x)
+
+/* print_line - show line possibly folded, and with normalized whitespace */
+
+void print_line(VSTREAM *fp, int mode, const char *fmt,...)
+{
+ va_list ap;
+ static VSTRING *buf = 0;
+ char *start;
+ char *next;
+ int line_len = 0;
+ int word_len;
+
+ /*
+ * One-off initialization.
+ */
+ if (buf == 0)
+ buf = vstring_alloc(100);
+
+ /*
+ * Format the text.
+ */
+ va_start(ap, fmt);
+ vstring_vsprintf(buf, fmt, ap);
+ va_end(ap);
+
+ /*
+ * Normalize the whitespace. We don't use the line_wrap() routine because
+ * 1) that function does not normalize whitespace between words and 2) we
+ * want to normalize whitespace even when not wrapping lines.
+ *
+ * XXX Some parameters preserve whitespace: for example, smtpd_banner and
+ * smtpd_reject_footer. If we have to preserve whitespace between words,
+ * then perhaps readlline() can be changed to canonicalize whitespace
+ * that follows a newline.
+ */
+ for (start = STR(buf); *(start += strspn(start, SEPARATORS)) != 0; start = next) {
+ word_len = strcspn(start, SEPARATORS);
+ if (*(next = start + word_len) != 0)
+ *next++ = 0;
+ if (word_len > 0 && line_len > 0) {
+ if ((mode & FOLD_LINE) == 0 || line_len + word_len < LINE_LIMIT) {
+ vstream_fputs(" ", fp);
+ line_len += 1;
+ } else {
+ vstream_fputs("\n" INDENT_TEXT, fp);
+ line_len = INDENT_LEN;
+ }
+ }
+ vstream_fputs(start, fp);
+ line_len += word_len;
+ }
+ vstream_fputs("\n", fp);
+}
+./postconf: warning: unmatched request: "bar/inet"
+./postconf: warning: unmatched request: "foo/unix"
whatever unix - n n - 0 other
- -o mydestination=yyy -o always_bcc=ccc -o aaa=ccc
+ -o mydestination=yyy
+ -o always_bcc=ccc
+ -o aaa=ccc
-foo unix - n n - 0 other -v -o aaa=bbb -v
- -o ccc=bbb -v -o ddd=bbb
+foo unix - n n - 0 other -v
+ -o aaa=bbb
+ -v
+ -o ccc=bbb
+ -v
+ -o ddd=bbb
--- /dev/null
+foo unix - n n - 0 other
+bar unix - n n - 0 other
+ -o xxx=yyy
+ -o aaa=bbb
+baz unix - n n - 0 other
+foo unix - n n - 0 other
+bar unix - n n - 0 other
+ -o xxx=YYY
+ -o aaa=BBB
+baz unix - n n - 0 other
+bar/unix/aaa = BBB
+bar/unix/xxx = YYY
--- /dev/null
+foo unix - n n - 0 other
+bar unix - n n - 0 other
+ -o xxx=yyy
+ -o aaa=bbb
+baz unix - n n - 0 other
+bar/unix/aaa = bbb
+bar/unix/xxx = yyy
+foo unix - n n - 0 other
+bar unix - n n - 0 other
+baz unix - n n - 0 other
--- /dev/null
+foo unix - n n - 0 other
+bar unix - n y - 0 aa -stuff
+ -o bb=cc
+ dd
+baz unix - n n - 0 other
--- /dev/null
+foo unix - n n - 0 other
+xx inet - n n - 0 aa -stuff
+ -o bb=cc
+ dd
+baz unix - n n - 0 other
--- /dev/null
+./postconf: fatal: invalid type field "xxxx" in "bar xxxx - n n - 0 other"
--- /dev/null
+./postconf: fatal: invalid private field X" in "bar inet X n n - 0 other"
--- /dev/null
+./postconf: fatal: invalid unprivileged field X" in "bar inet - X n - 0 other"
--- /dev/null
+./postconf: fatal: invalid chroot field X" in "bar inet - n X - 0 other"
--- /dev/null
+./postconf: fatal: invalid wakeup field X" in "bar inet - n n X 0 other"
--- /dev/null
+./postconf: fatal: invalid process_limit field X" in "bar inet - n n - X other"
--- /dev/null
+./postconf: fatal: invalid wakeup field X?" in "bar inet - n n X? 0 other"
--- /dev/null
+baz unix - n n 0 0 other
--- /dev/null
+foo unix - n n - 0 other
+#bar inet - n n 0 0 other
+baz unix - n n 0 0 other
--- /dev/null
+#foo unix - n n - 0 other
+#bar inet - n n 0 0 other
+baz unix - n n 0 0 other
--- /dev/null
+foo unix - n n - 0 other
+#bar inet - n n 0 0 other
+#baz unix - n n 0 0 other
--- /dev/null
+foo unix - n n - 0 other
+#bar inet - n n 0 0 other
+# -o first
+# -o second
+baz unix - n n 0 0 other
/* .IP "\fBsmtp_tls_force_insecure_host_tlsa_lookup (no)\fR"
/* Lookup the associated DANE TLSA RRset even when a hostname is
/* not an alias and its address records lie in an unsigned zone.
-/* .IP "\fBtls_dane_trust_anchor_digest_enable (trust-anchor-assertion)\fR"
+/* .IP "\fBtls_dane_trust_anchor_digest_enable (yes)\fR"
/* RFC 6698 trust-anchor digest support in the Postfix TLS library.
/* .IP "\fBtlsmgr_service_name (tlsmgr)\fR"
/* The name of the \fBtlsmgr\fR(8) service entry in master.cf.
props->namaddr, props->protocols);
return (0);
}
- /* The DANE level requires TLS 1.0 or later, not SSLv2 or SSLv3. */
+ /* The DANE level requires SSLv3 or later, not SSLv2. */
if (props->tls_level == TLS_LEV_DANE)
- protomask |= TLS_PROTOCOL_SSLv3 | TLS_PROTOCOL_SSLv2;
+ protomask |= TLS_PROTOCOL_SSLv2;
/*
* Per session cipher selection for sessions with mandatory encryption
/* callback MUST be cleared.
/*
/* tls_dane_resolve() maps a (port, protocol, hostrr) tuple to a
-/* a corresponding TLS_DANE policy structure found in the DNS. The port
+/* corresponding TLS_DANE policy structure found in the DNS. The port
/* argument is in network byte order. A null pointer is returned when
/* the DNS query for the TLSA record tempfailed. In all other cases the
/* return value is a pointer to the corresponding TLS_DANE structure.
#include <timecmp.h>
#include <ctable.h>
#include <hex_code.h>
+#include <safe_ultostr.h>
+#include <split_at.h>
+#include <name_code.h>
#define STR(x) vstring_str(x)
/*
* https://www.iana.org/assignments/dane-parameters/dane-parameters.xhtml
*/
-typedef struct digest_info {
- const char *alg; /* OpenSSL name */
+typedef struct {
+ const char *mdalg;
+ uint8_t dane_id;
+} iana_digest;
+
+static iana_digest iana_table[] = {
+ {"", DNS_TLSA_MATCHING_TYPE_NO_HASH_USED},
+ {"sha256", DNS_TLSA_MATCHING_TYPE_SHA256},
+ {"sha512", DNS_TLSA_MATCHING_TYPE_SHA512},
+ {0, 0}
+};
+
+typedef struct dane_digest {
+ struct dane_digest *next; /* linkage */
+ const char *mdalg; /* OpenSSL name */
const EVP_MD *md; /* OpenSSL EVP handle */
int len; /* digest octet length */
int pref; /* tls_dane_digests index or -1 */
uint8_t dane_id; /* IANA id */
-} digest_info;
+} dane_digest;
#define MAXDIGESTS 256 /* RFC limit */
-digest_info digest_table[] = {
- {"full", 0, 0, 0, DNS_TLSA_MATCHING_TYPE_NO_HASH_USED},
- {"sha256", 0, 0, -1, DNS_TLSA_MATCHING_TYPE_SHA256},
- {"sha512", 0, 0, -1, DNS_TLSA_MATCHING_TYPE_SHA512},
- {0, 0, 0, 0, 0}
+static dane_digest *digest_list;
+static int digest_agility = -1;
+
+#define AGILITY_OFF 0
+#define AGILITY_ON 1
+#define AGILITY_MAYBE 2
+
+static NAME_CODE agility[] = {
+ {TLS_DANE_AGILITY_OFF, AGILITY_OFF},
+ {TLS_DANE_AGILITY_ON, AGILITY_ON},
+ {TLS_DANE_AGILITY_MAYBE, AGILITY_MAYBE},
+ {0, -1}
};
-static int digest_mask;
-
-#define TLS_DANE_ENABLE_CC (1<<0) /* ca-constraint digests OK */
-#define TLS_DANE_ENABLE_TAA (1<<1) /* trust-anchor-assertion digests OK */
-
/*
* This is not intended to be a long-term cache of pre-parsed TLSA data,
* rather we primarily want to avoid fetching and parsing the TLSA records
dane_verbose = on;
}
-/* dane_digest_info - locate digest_table entry for given IANA id */
+/* add_digest - validate and append digest to digest list */
-static digest_info *dane_digest_info(uint8_t dane_id)
+static dane_digest *add_digest(char *mdalg, int pref)
{
- digest_info *di;
+ iana_digest *i;
+ dane_digest *d;
+ int dane_id = -1;
+ const char *dane_mdalg = mdalg;
+ char *value = split_at(mdalg, '=');
+ const EVP_MD *md = 0;
+ size_t mdlen = 0;
+
+ if (value && *value) {
+ unsigned long l;
+ char *endcp;
+
+ /*
+ * XXX: safe_strtoul() does not flag empty or white-space only input.
+ * Since we get idbuf by splitting white-space/comma delimited
+ * tokens, this is not a problem here.
+ */
+ l = safe_strtoul(value, &endcp, 10);
+ if ((l == 0 && (errno == EINVAL || endcp == value))
+ || l >= MAXDIGESTS
+ || *endcp) {
+ msg_warn("Invalid matching type number in %s: %s=%s",
+ VAR_TLS_DANE_DIGESTS, mdalg, value);
+ return (0);
+ }
+ dane_id = l;
+ }
- for (di = digest_table; di->alg; ++di)
- if (di->dane_id == dane_id)
- return (di);
+ /*
+ * Check for known IANA conflicts
+ */
+ for (i = iana_table; i->mdalg; ++i) {
+ if (*mdalg && strcasecmp(i->mdalg, mdalg) == 0) {
+ if (dane_id >= 0 && i->dane_id != dane_id) {
+ msg_warn("Non-standard value in %s: %s%s%s",
+ VAR_TLS_DANE_DIGESTS, mdalg,
+ value ? "=" : "", value ? value : "");
+ return (0);
+ }
+ dane_id = i->dane_id;
+ } else if (i->dane_id == dane_id) {
+ if (*mdalg) {
+ msg_warn("Non-standard algorithm in %s: %s%s%s",
+ VAR_TLS_DANE_DIGESTS, mdalg,
+ value ? "=" : "", value ? value : "");
+ return (0);
+ }
+ dane_mdalg = i->mdalg;
+ }
+ }
+
+ /*
+ * Check for unknown implicit digest or value
+ */
+ if (dane_id < 0 || (dane_id > 0 && !*dane_mdalg)) {
+ msg_warn("Unknown incompletely specified element in %s: %s%s%s",
+ VAR_TLS_DANE_DIGESTS, mdalg,
+ value ? "=" : "", value ? value : "");
+ return 0;
+ }
+
+ /*
+ * Check for duplicate entries
+ */
+ for (d = digest_list; d; d = d->next) {
+ if (strcasecmp(d->mdalg, dane_mdalg) == 0
+ || d->dane_id == dane_id) {
+ msg_warn("Duplicate element in %s: %s%s%s",
+ VAR_TLS_DANE_DIGESTS, mdalg,
+ value ? "=" : "", value ? value : "");
+ return (0);
+ }
+ }
+
+ if (*dane_mdalg
+ && ((md = EVP_get_digestbyname(dane_mdalg)) == 0
+ || (mdlen = EVP_MD_size(md)) <= 0
+ || mdlen > EVP_MAX_MD_SIZE)) {
+ msg_warn("Unimplemented digest algoritm in %s: %s%s%s",
+ VAR_TLS_DANE_DIGESTS, mdalg,
+ value ? "=" : "", value ? value : "");
+ return (0);
+ }
+ d = (dane_digest *) mymalloc(sizeof(*d));
+ d->next = digest_list;
+ d->mdalg = mystrdup(dane_mdalg);
+ d->md = md;
+ d->len = mdlen;
+ d->pref = pref;
+ d->dane_id = dane_id;
+
+ return (digest_list = d);
+}
+
+/* digest_byid - locate digest_table entry for given IANA id */
+
+static dane_digest *digest_byid(uint8_t dane_id)
+{
+ dane_digest *d;
+
+ for (d = digest_list; d; d = d->next)
+ if (d->dane_id == dane_id)
+ return (d);
return (0);
}
-/* dane_digest_pref - digest preference by IANA id */
+/* digest_pref_byid - digest preference by IANA id */
-static int dane_digest_pref(uint8_t dane_id)
+static int digest_pref_byid(uint8_t dane_id)
{
- digest_info *di = dane_digest_info(dane_id);
+ dane_digest *d = digest_byid(dane_id);
- if (di && di->pref >= 0)
- return (di->pref);
- return (MAXDIGESTS + dane_id);
+ return (d ? (d->pref) : (MAXDIGESTS + dane_id));
}
/* gencakey - generate interal DANE root CA key */
static void dane_init(void)
{
- static NAME_MASK ta_dgsts[] = {
- TLS_DANE_CC, TLS_DANE_ENABLE_CC,
- TLS_DANE_TAA, TLS_DANE_ENABLE_TAA,
- 0,
- };
int digest_pref = 0;
char *cp;
char *save;
char *tok;
- digest_info *di;
+ static char fullmtype[] = "=0";
+ dane_digest *d;
- digest_mask =
- name_mask_opt(VAR_TLS_DANE_TA_DGST, ta_dgsts, var_tls_dane_ta_dgst,
- NAME_MASK_ANY_CASE | NAME_MASK_FATAL);
-
- save = cp = mystrdup(var_tls_dane_digests);
- while ((tok = mystrtok(&cp, "\t\n\r ,")) != 0) {
- for (di = digest_table; di->alg; ++di)
- if (strcasecmp(tok, di->alg) == 0)
+ /*
+ * Add the full matching type at highest preference and then the users
+ * configured list.
+ *
+ * The most preferred digest will be used for cert signing and hashing full
+ * values for comparison.
+ */
+ if ((digest_agility = name_code(agility, 0, var_tls_dane_agility)) < 0) {
+ msg_warn("Invalid %s syntax: %s. DANE support disabled.",
+ VAR_TLS_DANE_AGILITY, var_tls_dane_agility);
+ } else if (add_digest(fullmtype, 0)) {
+ save = cp = mystrdup(var_tls_dane_digests);
+ while ((tok = mystrtok(&cp, "\t\n\r ,")) != 0) {
+ if ((d = add_digest(tok, ++digest_pref)) == 0) {
+ signalg = 0;
+ signmd = 0;
break;
- if (di->alg != 0
- && (di->md = EVP_get_digestbyname(di->alg)) != 0
- && (di->len = EVP_MD_size(di->md)) > 0
- && di->len <= EVP_MAX_MD_SIZE) {
-
- /*
- * The most preferred digest will be used for cert signing and
- * digesting for comparison.
- */
- if ((di->pref = ++digest_pref) == 1) {
- signalg = di->alg;
- signmd = di->md;
}
- } else {
- msg_warn("Unsupported DANE digest algorithm: %s", tok);
- continue;
+ if (digest_pref == 1) {
+ signalg = d->mdalg;
+ signmd = d->md;
+ }
}
+ myfree(save);
}
- myfree(save);
-
/* Don't report old news */
ERR_clear_error();
ARGV **argvp;
switch (certusage) {
- case DNS_TLSA_USAGE_CA_CONSTRAINT:
case DNS_TLSA_USAGE_TRUST_ANCHOR_ASSERTION:
- certusage = TLS_DANE_TA; /* Collapse 0/2 -> 2 */
+ certusage = TLS_DANE_TA;
break;
case DNS_TLSA_USAGE_SERVICE_CERTIFICATE_CONSTRAINT:
case DNS_TLSA_USAGE_DOMAIN_ISSUED_CERTIFICATE:
certusage = TLS_DANE_EE; /* Collapse 1/3 -> 3 */
break;
+ default:
+ msg_panic("Unsupported DANE certificate usage: %d", certusage);
}
switch (selector) {
case DNS_TLSA_SELECTOR_SUBJECTPUBLICKEYINFO:
selector = TLS_DANE_PKEY;
break;
+ default:
+ msg_panic("Unsupported DANE selector: %d", selector);
}
tlsap = (certusage == TLS_DANE_EE) ? &dane->ee : &dane->ta;
#ifdef DANE_TLSA_SUPPORT
+#define FILTER_CTX_AGILITY_OK (1<<0)
+#define FILTER_CTX_CHECK_AGILITY (1<<1)
+#define FILTER_CTX_APPLY_AGILITY (1<<2)
+#define FILTER_CTX_PARSE_DATA (1<<3)
+
+#define FILTER_RR_DROP 0
+#define FILTER_RR_KEEP 1
+
+typedef struct filter_ctx {
+ TLS_DANE *dane; /* Parsed result */
+ int count; /* Digest mtype count */
+ int target; /* Digest mtype target count */
+ int flags; /* Action/result bitmask */
+} filter_ctx;
+
+typedef int (*tlsa_filter) (DNS_RR *, filter_ctx *);
+
+/* tlsa_apply - apply filter to each rr in turn */
+
+static DNS_RR *tlsa_apply(DNS_RR *rr, tlsa_filter filter, filter_ctx *ctx)
+{
+ DNS_RR *head = 0; /* First retained RR */
+ DNS_RR *tail = 0; /* Last retained RR */
+ DNS_RR *next;
+
+ for ( /* nop */ ; rr; rr = next) {
+ next = rr->next;
+
+ if (filter(rr, ctx) == FILTER_RR_KEEP) {
+ tail = rr;
+ if (!head)
+ head = rr;
+ } else {
+ if (tail)
+ tail->next = rr->next;
+ rr->next = 0;
+ dns_rr_free(rr);
+ }
+ }
+ return (head);
+}
+
+/* usmdelta - packed usage/selector/mtype bits changing in next record */
+
+static unsigned int usmdelta(uint8_t u, uint8_t s, uint8_t m, DNS_RR *next)
+{
+ uint8_t *ip = (next && next->data_len >= 3) ? (uint8_t *) next->data : 0;
+ uint8_t nu = ip ? *ip++ : ~u;
+ uint8_t ns = ip ? *ip++ : ~s;
+ uint8_t nm = ip ? *ip++ : ~m;
+
+ return (((u ^ nu) << 16) | ((s ^ ns) << 8) | (m ^ nm));
+}
+
/* tlsa_rr_cmp - qsort TLSA rrs in case shuffled by name server */
static int tlsa_rr_cmp(DNS_RR *a, DNS_RR *b)
uint8_t *ai = (uint8_t *) a->data;
uint8_t *bi = (uint8_t *) b->data;
-#define signedcmp(x, y) (((int)(y)) - ((int)(x)))
+#define signedcmp(x, y) (((int)(x)) - ((int)(y)))
if ((cmp = signedcmp(ai[0], bi[0])) != 0
|| (cmp = signedcmp(ai[1], bi[1])) != 0
- || (cmp = dane_digest_pref(ai[2]) - dane_digest_pref(bi[2])) != 0)
+ || (cmp = digest_pref_byid(ai[2]) -
+ digest_pref_byid(bi[2])) != 0)
return (cmp);
}
if ((cmp = a->data_len - b->data_len) != 0)
return (memcmp(a->data, b->data, a->data_len));
}
-/* parse_tlsa_rrs - parse a validated TLSA RRset */
+/* parse_tlsa_rr - parse a validated TLSA RRset */
-static void parse_tlsa_rrs(TLS_DANE *dane, DNS_RR *rr)
+static int parse_tlsa_rr(DNS_RR *rr, filter_ctx *ctx)
{
+ uint8_t *ip;
uint8_t usage;
uint8_t selector;
uint8_t mtype;
- int mlen;
+ ssize_t dlen;
+ const unsigned char *data;
const unsigned char *p;
- uint32_t prev_usage_selector; /* Previous (usage<<8|selector) */
- uint32_t prev_mtype; /* Previous valid mtype for above */
+ int iscname = strcasecmp(rr->rname, rr->qname);
+ const char *q = (iscname) ? (rr)->qname : "";
+ const char *a = (iscname) ? " -> " : "";
+ const char *r = rr->rname;
+ unsigned int change;
+
+ if (rr->type != T_TLSA)
+ msg_panic("unexpected non-TLSA RR type %u for %s%s%s", rr->type,
+ q, a, r);
+
+ /* Drop truncated records */
+ if ((dlen = rr->data_len - 3) < 0) {
+ msg_warn("truncated length %u RR: %s%s%s IN TLSA ...",
+ (unsigned) rr->data_len, q, a, r);
+ ctx->flags &= ~FILTER_CTX_AGILITY_OK;
+ return (FILTER_RR_DROP);
+ }
+ ip = (uint8_t *) rr->data;
+ usage = *ip++;
+ selector = *ip++;
+ mtype = *ip++;
+ change = usmdelta(usage, selector, mtype, rr->next);
+ p = data = (const unsigned char *) ip;
+
+ /*
+ * Handle digest agility for non-zero matching types.
+ */
+ if (mtype) {
+ if (ctx->count && (ctx->flags & FILTER_CTX_APPLY_AGILITY)) {
+ if (change & 0xffff00) /* New usage/selector, */
+ ctx->count = 0; /* disable drop */
+ return (FILTER_RR_DROP);
+ }
+ if ((ctx->flags & FILTER_CTX_CHECK_AGILITY)
+ && (ctx->flags & FILTER_CTX_AGILITY_OK)) {
+ ++ctx->count;
+ if (change) {
+ /*-
+ * Count changed from last mtype for same usage/selector?
+ * Yes, disable agility.
+ * Else, set or (on usage/selector change) reset target.
+ */
+ if (ctx->target && ctx->target != ctx->count)
+ ctx->flags &= ~FILTER_CTX_AGILITY_OK;
+ else
+ ctx->target = (change & ~0xff) ? 0 : ctx->count;
+ ctx->count = 0;
+ }
+ }
+ }
+ /*-
+ * Drop unsupported usages.
+ * Note: NO SUPPORT for usage 0 which does not apply to SMTP.
+ * Note: Best-effort support for usage 1, which simply maps to 3.
+ */
+ switch (usage) {
+ case DNS_TLSA_USAGE_TRUST_ANCHOR_ASSERTION:
+ case DNS_TLSA_USAGE_SERVICE_CERTIFICATE_CONSTRAINT:
+ case DNS_TLSA_USAGE_DOMAIN_ISSUED_CERTIFICATE:
+ break;
+ default:
+ msg_warn("unsupported certificate usage %u in RR: "
+ "%s%s%s IN TLSA %u ...", usage,
+ q, a, r, usage);
+ return (FILTER_RR_DROP);
+ }
-#define NO_PREV 0xffffffff /* Not any usage|selector or
- * mtype */
- prev_usage_selector = NO_PREV;
+ /*
+ * Drop unsupported selectors
+ */
+ switch (selector) {
+ case DNS_TLSA_SELECTOR_FULL_CERTIFICATE:
+ case DNS_TLSA_SELECTOR_SUBJECTPUBLICKEYINFO:
+ break;
+ default:
+ msg_warn("unsupported selector %u in RR: "
+ "%s%s%s IN TLSA %u %u ...", selector,
+ q, a, r, usage, selector);
+ return (FILTER_RR_DROP);
+ }
- if (rr == 0)
- msg_panic("null TLSA rr");
+ if (mtype) {
+ dane_digest *d = digest_byid(mtype);
- for ( /* nop */ ; rr; rr = rr->next) {
- const char *mdalg = 0;
- char *digest;
- int iscname = strcasecmp(rr->rname, rr->qname);
- uint8_t *ip = (uint8_t *) rr->data;
- X509 *x = 0; /* OpenSSL tries to re-use *x if x!=0 */
- EVP_PKEY *k = 0; /* OpenSSL tries to re-use *k if k!=0 */
- digest_info *di;
-
-#define rcname(rr) (iscname ? rr->qname : "")
-#define rarrow(rr) (iscname ? " -> " : "")
-
- if (rr->type != T_TLSA)
- msg_panic("unexpected non-TLSA RR type %u for %s%s%s", rr->type,
- rcname(rr), rarrow(rr), rr->rname);
-
- /* Skip malformed */
- if ((mlen = rr->data_len - 3) < 0) {
- msg_warn("truncated length %u RR: %s%s%s IN TLSA ...",
- (unsigned) rr->data_len, rcname(rr), rarrow(rr), rr->rname);
- continue;
+ if (d == 0) {
+ msg_warn("unsupported matching type %u in RR: "
+ "%s%s%s IN TLSA %u %u %u ...", mtype,
+ q, a, r, usage, selector, mtype);
+ return (FILTER_RR_DROP);
}
- switch (usage = *ip++) {
- default:
- msg_warn("unsupported certificate usage %u in RR: "
- "%s%s%s IN TLSA %u ...", usage,
- rcname(rr), rarrow(rr), rr->rname, usage);
- continue;
- case DNS_TLSA_USAGE_CA_CONSTRAINT:
- case DNS_TLSA_USAGE_TRUST_ANCHOR_ASSERTION:
- case DNS_TLSA_USAGE_SERVICE_CERTIFICATE_CONSTRAINT:
- case DNS_TLSA_USAGE_DOMAIN_ISSUED_CERTIFICATE:
- break;
+ if (dlen != d->len) {
+ msg_warn("malformed %s digest, length %u, in RR: "
+ "%s%s%s IN TLSA %u %u %u ...", d->mdalg, dlen,
+ q, a, r, usage, selector, mtype);
+ ctx->flags &= ~FILTER_CTX_AGILITY_OK;
+ return (FILTER_RR_DROP);
}
-
- switch (selector = *ip++) {
- default:
- msg_warn("unsupported selector %u in RR: "
- "%s%s%s IN TLSA %u %u ...", selector,
- rcname(rr), rarrow(rr), rr->rname, usage, selector);
- continue;
- case DNS_TLSA_SELECTOR_FULL_CERTIFICATE:
- case DNS_TLSA_SELECTOR_SUBJECTPUBLICKEYINFO:
- break;
+ if (!var_tls_dane_taa_dgst
+ && usage == DNS_TLSA_USAGE_TRUST_ANCHOR_ASSERTION) {
+ msg_warn("trust-anchor digests disabled, ignoring RR: "
+ "%s%s%s IN TLSA %u %u %u ...", q, a, r,
+ usage, selector, mtype);
+ return (FILTER_RR_DROP);
}
+ /* New digest mtype next? Prepare to drop following RRs */
+ if (change && (change & 0xffff00) == 0
+ && (ctx->flags & FILTER_CTX_APPLY_AGILITY))
+ ++ctx->count;
- /*
- * Skip all but the most preferred matching type for any given
- * (usage, selector) combination.
- */
- mtype = *ip++;
- if (prev_usage_selector != (usage << 8 | selector))
- prev_mtype = NO_PREV;
- else if (prev_mtype != NO_PREV && prev_mtype != mtype)
- continue;
-
- switch (mtype) {
- default:
- if ((di = dane_digest_info(mtype)) == 0) {
- msg_warn("unsupported matching type %u in RR: "
- "%s%s%s IN TLSA %u %u %u ...", mtype, rcname(rr),
- rarrow(rr), rr->rname, usage, selector, mtype);
- continue;
- }
- if (di->pref < 0) {
- msg_warn("digest algorithm %s locally disabled, in RR: "
- "%s%s%s IN TLSA %u %u %u ...", di->alg,
- rcname(rr), rarrow(rr), rr->rname,
- usage, selector, mtype);
- continue;
- }
- if (mlen != di->len) {
- msg_warn("malformed %s digest, length %u, in RR: "
- "%s%s%s IN TLSA %u %u %u ...", di->alg, mlen,
- rcname(rr), rarrow(rr), rr->rname,
- usage, selector, mtype);
- continue;
- }
- switch (usage) {
- case DNS_TLSA_USAGE_CA_CONSTRAINT:
- if (!(digest_mask & TLS_DANE_ENABLE_CC)) {
- msg_warn("%s trust-anchor %s digests disabled, in RR: "
- "%s%s%s IN TLSA %u %u %u ...", TLS_DANE_CC,
- di->alg, rcname(rr), rarrow(rr), rr->rname,
- usage, selector, mtype);
- continue;
- }
- break;
- case DNS_TLSA_USAGE_TRUST_ANCHOR_ASSERTION:
- if (!(digest_mask & TLS_DANE_ENABLE_TAA)) {
- msg_warn("%s trust-anchor %s digests disabled, in RR: "
- "%s%s%s IN TLSA %u %u %u ...", TLS_DANE_TAA,
- di->alg, rcname(rr), rarrow(rr), rr->rname,
- usage, selector, mtype);
- continue;
- }
- break;
- }
- digest = tls_digest_encode((unsigned char *) ip, di->len);
- dane_add(dane, usage, selector, di->alg, digest);
- break;
+ if (ctx->flags & FILTER_CTX_PARSE_DATA) {
+ char *digest = tls_digest_encode(data, dlen);
+
+ dane_add(ctx->dane, usage, selector, d->mdalg, digest);
+ if (msg_verbose || dane_verbose)
+ msg_info("using DANE RR: %s%s%s IN TLSA %u %u %u %s",
+ q, a, r, usage, selector, mtype, digest);
+ myfree(digest);
+ }
+ } else {
+ X509 *x = 0; /* OpenSSL re-uses *x if x!=0 */
+ EVP_PKEY *k = 0; /* OpenSSL re-uses *k if k!=0 */
- case DNS_TLSA_MATCHING_TYPE_NO_HASH_USED:
- p = (unsigned char *) ip;
-
- /* Validate the cert or public key via d2i_mumble() */
- switch (selector) {
- case DNS_TLSA_SELECTOR_FULL_CERTIFICATE:
- if (!d2i_X509(&x, &p, mlen)) {
- msg_warn("malformed %s in RR: "
- "%s%s%s IN TLSA %u %u %u ...", "certificate",
- rcname(rr), rarrow(rr), rr->rname,
- usage, selector, mtype);
- continue;
- }
- /* Also unusable if public key is malformed */
- if ((k = X509_get_pubkey(x)) == 0) {
- msg_warn("%s public key malformed in RR: "
- "%s%s%s IN TLSA %u %u %u ...", "certificate",
- rcname(rr), rarrow(rr), rr->rname,
- usage, selector, mtype);
+ /* Validate the cert or public key via d2i_mumble() */
+ switch (selector) {
+ case DNS_TLSA_SELECTOR_FULL_CERTIFICATE:
+ if (!d2i_X509(&x, &p, dlen) || dlen != p - data) {
+ msg_warn("malformed %s in RR: "
+ "%s%s%s IN TLSA %u %u %u ...", "certificate",
+ q, a, r, usage, selector, mtype);
+ if (x)
X509_free(x);
- continue;
- }
- EVP_PKEY_free(k);
-
- /*
- * When a full trust-anchor certificate is published via DNS,
- * we may need to use it to validate the server trust chain.
- * Store it away for later use. We collapse certificate
- * usage 0/2 because MTAs don't stock a complete list of the
- * usual browser-trusted CAs. Thus, here (and in the public
- * key case below) we treat the usages identically.
- */
- switch (usage) {
- case DNS_TLSA_USAGE_CA_CONSTRAINT:
- case DNS_TLSA_USAGE_TRUST_ANCHOR_ASSERTION:
- ta_cert_insert(dane, x);
- break;
- }
+ return (FILTER_RR_DROP);
+ }
+ /* Also unusable if public key is malformed or unsupported */
+ k = X509_get_pubkey(x);
+ EVP_PKEY_free(k);
+ if (k == 0) {
+ msg_warn("%s public key malformed in RR: "
+ "%s%s%s IN TLSA %u %u %u ...", "certificate",
+ q, a, r, usage, selector, mtype);
X509_free(x);
- break;
-
- case DNS_TLSA_SELECTOR_SUBJECTPUBLICKEYINFO:
- if (!d2i_PUBKEY(&k, &p, mlen)) {
- msg_warn("malformed %s in RR: "
- "%s%s%s IN TLSA %u %u %u ...", "public key",
- rcname(rr), rarrow(rr), rr->rname,
- usage, selector, mtype);
- continue;
- }
- /* See full cert case above */
- switch (usage) {
- case DNS_TLSA_USAGE_CA_CONSTRAINT:
- case DNS_TLSA_USAGE_TRUST_ANCHOR_ASSERTION:
- ta_pkey_insert(dane, k);
- break;
- }
- EVP_PKEY_free(k);
- break;
+ return (FILTER_RR_DROP);
}
/*
- * The cert or key was valid, just digest the raw object, and
- * encode the digest value.
+ * When a full trust-anchor certificate is published via DNS, we
+ * may need to use it to validate the server trust chain. Store
+ * it away for later use.
*/
- digest = tls_data_fprint((char *) ip, mlen, signalg);
- dane_add(dane, usage, selector, mdalg = signalg, digest);
+ if (usage == DNS_TLSA_USAGE_TRUST_ANCHOR_ASSERTION
+ && (ctx->flags & FILTER_CTX_PARSE_DATA))
+ ta_cert_insert(ctx->dane, x);
+ X509_free(x);
+ break;
+
+ case DNS_TLSA_SELECTOR_SUBJECTPUBLICKEYINFO:
+ if (!d2i_PUBKEY(&k, &p, dlen) || dlen != p - data) {
+ msg_warn("malformed %s in RR: "
+ "%s%s%s IN TLSA %u %u %u ...", "public key",
+ q, a, r, usage, selector, mtype);
+ if (k)
+ EVP_PKEY_free(k);
+ return (FILTER_RR_DROP);
+ }
+ /* See full cert case above */
+ if (usage == DNS_TLSA_USAGE_TRUST_ANCHOR_ASSERTION
+ && (ctx->flags & FILTER_CTX_PARSE_DATA))
+ ta_pkey_insert(ctx->dane, k);
+ EVP_PKEY_free(k);
break;
}
/*
- * Save state
+ * The cert or key was valid, just digest the raw object, and encode
+ * the digest value.
*/
- prev_usage_selector = (usage << 8 | selector);
- prev_mtype = mtype;
+ if (ctx->flags & FILTER_CTX_PARSE_DATA) {
+ char *digest = tls_data_fprint((char *) data, dlen, signalg);
- if (msg_verbose || dane_verbose) {
- switch (mtype) {
- default:
- msg_info("using DANE RR: %s%s%s IN TLSA %u %u %u %s",
- rcname(rr), rarrow(rr), rr->rname,
- usage, selector, mtype, digest);
- break;
- case DNS_TLSA_MATCHING_TYPE_NO_HASH_USED:
+ dane_add(ctx->dane, usage, selector, signalg, digest);
+ if (msg_verbose || dane_verbose)
msg_info("using DANE RR: %s%s%s IN TLSA %u %u %u <%s>; "
- "%s digest %s",
- rcname(rr), rarrow(rr), rr->rname,
- usage, selector, mtype,
+ "%s digest %s", q, a, r, usage, selector, mtype,
(selector == DNS_TLSA_SELECTOR_FULL_CERTIFICATE) ?
- "certificate" : "public key", mdalg, digest);
- break;
- }
+ "certificate" : "public key", signalg, digest);
+ myfree(digest);
}
- myfree(digest);
}
+ return (FILTER_RR_KEEP);
+}
+
+/* process_rrs - filter and parse the TLSA RRset */
+static DNS_RR *process_rrs(TLS_DANE *dane, DNS_RR *rrset)
+{
+ filter_ctx ctx;
+
+ ctx.dane = dane;
+ ctx.count = ctx.target = 0;
+ ctx.flags = 0;
+
+ switch (digest_agility) {
+ case AGILITY_ON:
+ ctx.flags |= FILTER_CTX_APPLY_AGILITY | FILTER_CTX_PARSE_DATA;
+ break;
+ case AGILITY_OFF:
+ ctx.flags |= FILTER_CTX_PARSE_DATA;
+ break;
+ case AGILITY_MAYBE:
+ ctx.flags |= FILTER_CTX_CHECK_AGILITY | FILTER_CTX_AGILITY_OK;
+ break;
+ }
+
+ rrset = tlsa_apply(rrset, parse_tlsa_rr, &ctx);
+
+ if (digest_agility == AGILITY_MAYBE) {
+ /* Two-pass algorithm */
+ if (ctx.flags & FILTER_CTX_AGILITY_OK)
+ ctx.flags = FILTER_CTX_APPLY_AGILITY | FILTER_CTX_PARSE_DATA;
+ else
+ ctx.flags = FILTER_CTX_PARSE_DATA;
+ rrset = tlsa_apply(rrset, parse_tlsa_rr, &ctx);
+ }
if (dane->ta == 0 && dane->ee == 0)
dane->flags |= TLS_DANE_FLAG_EMPTY;
+
+ return (rrset);
}
/* dane_lookup - TLSA record lookup, ctable style */
* same usage and selector.
*/
rrs = dns_rr_sort(rrs, tlsa_rr_cmp);
- parse_tlsa_rrs(dane, rrs);
+ rrs = process_rrs(dane, rrs);
} else
dane->flags |= TLS_DANE_FLAG_NORRS;
- dns_rr_free(rrs);
+ if (rrs)
+ dns_rr_free(rrs);
break;
case DNS_NOTFOUND:
/* char *var_tls_null_clist;
/* char *var_tls_eecdh_strong;
/* char *var_tls_eecdh_ultra;
-/* char *var_tls_dane_ta_dgst;
+/* char *var_tls_dane_agility;
/* char *var_tls_dane_digests;
/* int var_tls_daemon_rand_bytes;
/* bool var_tls_append_def_CA;
+/* bool var_tls_dane_taa_dgst;
/* bool var_tls_preempt_clist;
/* bool var_tls_bc_pkey_fprint;
/* bool var_tls_multi_wildcard;
int var_tls_daemon_rand_bytes;
char *var_tls_eecdh_strong;
char *var_tls_eecdh_ultra;
+char *var_tls_dane_agility;
char *var_tls_dane_digests;
-char *var_tls_dane_ta_dgst;
bool var_tls_append_def_CA;
char *var_tls_bug_tweaks;
char *var_tls_ssl_options;
bool var_tls_bc_pkey_fprint;
+bool var_tls_dane_taa_dgst;
bool var_tls_multi_wildcard;
char *var_tls_mgr_service;
-char *tls_dane_digests;
#ifdef VAR_TLS_PREEMPT_CLIST
bool var_tls_preempt_clist;
VAR_TLS_EECDH_ULTRA, DEF_TLS_EECDH_ULTRA, &var_tls_eecdh_ultra, 1, 0,
VAR_TLS_BUG_TWEAKS, DEF_TLS_BUG_TWEAKS, &var_tls_bug_tweaks, 0, 0,
VAR_TLS_SSL_OPTIONS, DEF_TLS_SSL_OPTIONS, &var_tls_ssl_options, 0, 0,
+ VAR_TLS_DANE_AGILITY, DEF_TLS_DANE_AGILITY, &var_tls_dane_agility, 1, 0,
VAR_TLS_DANE_DIGESTS, DEF_TLS_DANE_DIGESTS, &var_tls_dane_digests, 1, 0,
- VAR_TLS_DANE_TA_DGST, DEF_TLS_DANE_TA_DGST, &var_tls_dane_ta_dgst, 0, 0,
VAR_TLS_MGR_SERVICE, DEF_TLS_MGR_SERVICE, &var_tls_mgr_service, 1, 0,
0,
};
static const CONFIG_BOOL_TABLE bool_table[] = {
VAR_TLS_APPEND_DEF_CA, DEF_TLS_APPEND_DEF_CA, &var_tls_append_def_CA,
VAR_TLS_BC_PKEY_FPRINT, DEF_TLS_BC_PKEY_FPRINT, &var_tls_bc_pkey_fprint,
+ VAR_TLS_DANE_TAA_DGST, DEF_TLS_DANE_TAA_DGST, &var_tls_dane_taa_dgst,
VAR_TLS_PREEMPT_CLIST, DEF_TLS_PREEMPT_CLIST, &var_tls_preempt_clist,
VAR_TLS_MULTI_WILDCARD, DEF_TLS_MULTI_WILDCARD, &var_tls_multi_wildcard,
0,
/* ssize_t pos;
/* const char *arg;
/*
+/* void argv_delete(argvp, pos, how_many)
+/* ARGV *argvp;
+/* ssize_t pos;
+/* ssize_t how_many;
+/*
/* void ARGV_FAKE_BEGIN(argv, arg)
/* const char *arg;
/*
/* argv_replace_one() replaces one string at the specified
/* position.
/*
+/* argv_delete() deletes the specified number of elements
+/* starting at the specified array position. The result is
+/* null-terminated.
+/*
/* ARGV_FAKE_BEGIN/END are an optimization for the case where
/* a single string needs to be passed into an ARGV-based
/* interface. ARGV_FAKE_BEGIN() opens a statement block and
myfree(argvp->argv[where]);
argvp->argv[where] = mystrdup(arg);
}
+
+/* argv_delete - remove string(s) from array */
+
+void argv_delete(ARGV *argvp, ssize_t first, ssize_t how_many)
+{
+ ssize_t pos;
+
+ /*
+ * Sanity check.
+ */
+ if (first < 0 || how_many < 0 || first + how_many > argvp->argc)
+ msg_panic("argv_delete bad range: (start=%ld count=%ld)",
+ (long) first, (long) how_many);
+
+ for (pos = first; pos < first + how_many; pos++)
+ myfree(argvp->argv[pos]);
+ for (pos = first; pos <= argvp->argc - how_many; pos++)
+ argvp->argv[pos] = argvp->argv[pos + how_many];
+ argvp->argc -= how_many;
+}
extern void argv_truncate(ARGV *, ssize_t);
extern void argv_insert_one(ARGV *, ssize_t, const char *);
extern void argv_replace_one(ARGV *, ssize_t, const char *);
+extern void argv_delete(ARGV *, ssize_t, ssize_t);
extern ARGV *argv_free(ARGV *);
extern ARGV *argv_split(const char *, const char *);
/*
/* ARGV *argv_split(string, delim)
/* const char *string;
+/* const char *delim;
/*
/* ARGV *argv_split_count(string, delim, count)
/* const char *string;
+/* const char *delim;
/* ssize_t count;
/*
/* ARGV *argv_split_append(argv, string, delim)
char *cp = buf;
int ipv6 = 0;
- /*
+ /*-
* [host]:port, [host]:, [host].
* [ipv6:ipv6addr]:port, [ipv6:ipv6addr]:, [ipv6:ipv6addr].
*/
MDB_envinfo info;
/*
- * Recover bulk transactions only if they can be restarted. Limit
- * the number of recovery attempts per slmdb(3) API request.
+ * Recover bulk transactions only if they can be restarted. Limit the
+ * number of recovery attempts per slmdb(3) API request.
*/
if ((slmdb->txn != 0 && slmdb->longjmp_fn == 0)
|| ((slmdb->api_retry_count += 1) >= slmdb->api_retry_limit))