diff --git a/postfix/HISTORY b/postfix/HISTORY index cae5b09da..efb39cca3 100644 --- a/postfix/HISTORY +++ b/postfix/HISTORY @@ -22537,3 +22537,11 @@ Apologies for any names omitted. and "PASS" disables header, body, and Milter inspection for the remainder of the message content. Contributed by Hobbit. Files: cleanup/cleanup_message.c, global/header_body_checks.c. + +20161024 + + Feature: smtpd_milter_maps, per-client Milter configuration + that overrides smtpd_milters, and that has the same syntax. + Files: mantools/postlink, proto/MILTER_README.html, + proto/postconf.proto, global/mail_params.h, smtpd/smtpd.c, + smtpd/smtpd.h, smtpd/smtpd_sasl_proto.c, smtpd/smtpd_state.c. diff --git a/postfix/README_FILES/MILTER_README b/postfix/README_FILES/MILTER_README index e56a7d5ea..a1b68b68d 100644 --- a/postfix/README_FILES/MILTER_README +++ b/postfix/README_FILES/MILTER_README @@ -1,8 +1,8 @@ -PPoossttffiixx bbeeffoorree--qquueeuuee MMiilltteerr ssuuppppoorrtt +Postfix before-queue Milter support ------------------------------------------------------------------------------- -IInnttrroodduuccttiioonn +Introduction Postfix implements support for the Sendmail version 8 Milter (mail filter) protocol. This protocol is used by applications that run outside the MTA to @@ -30,7 +30,7 @@ This document provides information on the following topics: * Workarounds * Limitations -HHooww MMiilltteerr aapppplliiccaattiioonnss pplluugg iinnttoo PPoossttffiixx +How Milter applications plug into Postfix The Postfix Milter implementation uses two different lists of mail filters: one list of filters for SMTP mail only, and one list of filters for non-SMTP mail. @@ -80,7 +80,7 @@ Postfix architecture). Local -> sendmail(1) -BBuuiillddiinngg MMiilltteerr aapppplliiccaattiioonnss +Building Milter applications Milter applications have been written in C, JAVA and Perl, but this document deals with C applications only. For these, you need an object library that @@ -94,25 +94,25 @@ some Linux systems). Once libmilter is installed, applications such as OpenDKIM and OpenDMARC build out of the box without requiring any tinkering: - $ ggzzccaatt ooppeennddkkiimm--xx..yy..zz..ttaarr..ggzz || ttaarr xxff -- - $ ccdd ooppeennddkkiimm--xx..yy..zz - $ ..//ccoonnffiigguurree ......ooppttiioonnss...... - $ mmaakkee + $ gzcat opendkim-x.y.z.tar.gz | tar xf - + $ cd opendkim-x.y.z + $ ./configure ...options... + $ make [...lots of output omitted...] - $ mmaakkee iinnssttaallll + $ make install -RRuunnnniinngg MMiilltteerr aapppplliiccaattiioonnss +Running Milter applications To run a Milter application, see the documentation of the filter for options. A typical command looks like this: - # //ssoommee//wwhheerree//ooppeennddkkiimm --ll --uu uusseerriidd --pp iinneett::ppoorrttnnuummbbeerr@@llooccaallhhoosstt ......ootthheerr - ooppttiioonnss...... + # /some/where/opendkim -l -u userid -p inet:portnumber@localhost ...other + options... Please specify a userid value that isn't used for other applications (not "postfix", not "www", etc.). -CCoonnffiigguurriinngg PPoossttffiixx +Configuring Postfix Like Sendmail, Postfix has a lot of configuration options that control how it talks to Milter applications. Besides global options that apply to all Milter @@ -127,10 +127,11 @@ Information in this section: * Milter protocol version * Milter protocol timeouts * Different settings for different Milter applications + * Different settings for different SMTP clients * Sendmail macro emulation * What macros will Postfix send to Milters? -SSMMTTPP--OOnnllyy MMiilltteerr aapppplliiccaattiioonnss +SMTP-Only Milter applications The SMTP-only Milter applications handle mail that arrives via the Postfix smtpd(8) server. They are typically used to filter unwanted mail, and to sign @@ -158,20 +159,23 @@ from other Milter applications. The general syntax for listening sockets is as follows: - uunniixx::pathname + unix:pathname Connect to the local UNIX-domain server that is bound to the specified pathname. If the smtpd(8) or cleanup(8) process runs chrooted, an absolute pathname is interpreted relative to the Postfix queue directory. - iinneett::host::port + inet:host:port Connect to the specified TCP port on the specified local or remote host. The host and port can be specified in numeric or symbolic form. NOTE: Postfix syntax differs from Milter syntax which has the form - iinneett::port@@host. + inet:port@host. -NNoonn--SSMMTTPP MMiilltteerr aapppplliiccaattiioonnss +For advanced configuration see "Different settings for different SMTP clients" +and "Different settings for different Milter applications". + +Non-SMTP Milter applications The non-SMTP Milter applications handle mail that arrives via the Postfix sendmail(1) command-line or via the Postfix qmqpd(8) server. They are typically @@ -222,7 +226,7 @@ must not REJECT or TEMPFAIL simulated RCPT TO commands. When a non_smtpd_milters application REJECTs or TEMPFAILs a recipient, Postfix will report a configuration error, and mail will stay in the queue. -SSiiggnniinngg iinntteerrnnaallllyy--ggeenneerraatteedd bboouunnccee mmeessssaaggeess +Signing internally-generated bounce messages Postfix normally does not apply content filters to mail that is generated internally such as bounces or Postmaster notifications. Filtering internally- @@ -239,7 +243,7 @@ non_smtpd_milters, header_checks or body_checks (lines 3-5 below). 4 header_checks = don't reject internally-generated bounces 5 body_checks = don't reject internally-generated bounces -MMiilltteerr eerrrroorr hhaannddlliinngg +Milter error handling The milter_default_action parameter specifies how Postfix handles Milter application errors. The default action is to respond with a temporary error @@ -256,16 +260,16 @@ the message in the "hold" queue, and is available with Postfix 2.6 or later. See "Different settings for different Milter applications" for advanced configuration options. -MMiilltteerr pprroottooccooll vveerrssiioonn +Milter protocol version As Postfix is not built with the Sendmail libmilter library, you may need to configure the Milter protocol version that Postfix should use. The default version is 6 (before Postfix 2.6 the default version is 2). /etc/postfix/main.cf: - # Postfix >= 2.6 + # Postfix ≥ 2.6 milter_protocol = 6 - # 2.3 <= Postfix <= 2.5 + # 2.3 ≤ Postfix ≤ 2.5 milter_protocol = 2 If the Postfix milter_protocol setting specifies a too low version, the @@ -294,21 +298,21 @@ libmilter library does not expect. See "Different settings for different Milter applications" for advanced configuration options. -MMiilltteerr pprroottooccooll ttiimmeeoouuttss +Milter protocol timeouts Postfix uses different time limits at different Milter protocol stages. The table shows the timeout settings and the corresponding protocol stages (EOH = end of headers; EOM = end of message). - _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ - |PPoossttffiixx ppaarraammeetteerr |TTiimmee lliimmiitt|MMiilltteerr pprroottooccooll ssttaaggee | - |_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ | + _________________________________________________________________ + |Postfix parameter |Time limit|Milter protocol stage | + |______________________|__________|_______________________________| |milter_connect_timeout|30s |CONNECT | - |_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ | + |______________________|__________|_______________________________| |milter_command_timeout|30s |HELO, MAIL, RCPT, DATA, UNKNOWN| - |_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ | + |______________________|__________|_______________________________| |milter_content_timeout|300s |HEADER, EOH, BODY, EOM | - |_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ | + |______________________|__________|_______________________________| Beware: 30s may be too short for Milter applications that do lots of DNS lookups. However, if you increase the above timeouts too much, remote SMTP @@ -318,7 +322,7 @@ inherent problem with before-queue filtering. See "Different settings for different Milter applications" for advanced configuration options. -DDiiffffeerreenntt sseettttiinnggss ffoorr ddiiffffeerreenntt MMiilltteerr aapppplliiccaattiioonnss +Different settings for different Milter applications The previous sections list a number of Postfix main.cf parameters that control time limits and other settings for all Postfix Milter clients. This is @@ -345,11 +349,31 @@ Instead of a server endpoint, we now have a list enclosed in {}. content_timeout, default_action, and protocol. Inside the list, syntax is similar to what we already know from main.cf: items -separated by space or comma. There is one difference: yyoouu mmuusstt eenncclloossee aa -sseettttiinngg iinn ppaarreenntthheesseess,, aass iinn ""{{ nnaammee == vvaalluuee }}"",, iiff yyoouu wwaanntt ttoo hhaavvee ssppaaccee oorr -ccoommmmaa wwiitthhiinn aa vvaalluuee oorr aarroouunndd ""=="". +separated by space or comma. There is one difference: you must enclose a +setting in parentheses, as in "{ name = value }", if you want to have space or +comma within a value or around "=". -SSeennddmmaaiill mmaaccrroo eemmuullaattiioonn +Different settings for different SMTP clients + +The smtpd_milter_maps feature supports different Milter settings for different +client IP addresses. Lookup results override the the global smtpd_milters +setting, and have the same syntax. For example, to disable Milter settings for +local address ranges: + +/etc/postfix/main.cf: + smtpd_milter_maps = cidr:/etc/postfix/smtpd_milter_map + smtpd_milters = inet:host:port, { inet:host:port, ... }, ... + +/etc/postfix/smtpd_milter_map: + # Disable Milters for local clients. + 127.0.0.0/8 DISABLE + 192.168.0.0/16 DISABLE + ::/64 DISABLE + 2001:db8::/32 DISABLE + +This feature is available with Postfix 3.2 and later. + +Sendmail macro emulation Postfix emulates a limited number of Sendmail macros, as shown in the table. Some macro values depend on whether a recipient is rejected (rejected @@ -358,92 +382,70 @@ macros are available at different Milter protocol stages (EOH = end-of-header, EOM = end-of-message); their availability is not always the same as in Sendmail. See the workarounds section below for solutions. - _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ - |SSeennddmmaaiill mmaaccrroo |MMiilltteerr pprroottooccooll ssttaaggee |DDeessccrriippttiioonn | - |_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ | - |i |DATA, EOH, EOM |Queue ID, also Postfix | - | | |queue file name | - |_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ | - |j |Always |Value of myhostname | - |_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ | - |_ |Always |The validated client name | - | | |and address | - |_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ | - |{auth_authen} |MAIL, DATA, EOH, EOM |SASL login name | - |_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ | - |{auth_author} |MAIL, DATA, EOH, EOM |SASL sender | - |_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ | - |{auth_type} |MAIL, DATA, EOH, EOM |SASL login method | - |_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ | - |{client_addr} |Always |Remote client IP address | - |_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ | - | | |Connection concurrency for| - | | |this client (zero if the | - |{client_connections}|CONNECT |client is excluded from | - | | |all smtpd_client_* | - | | |limits). | - |_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ | - | | |Remote client hostname | - | | |When address -> name | - |{client_name} |Always |lookup or name -> address | - | | |verification fails: | - | | |"unknown" | - |_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ | - |{client_port} |Always (Postfix >=2.5) |Remote client TCP port | - |_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ | - | | |Client name from address -| - |{client_ptr} |CONNECT, HELO, MAIL, DATA|> name lookup | - | | |When address -> name | - | | |lookup fails: "unknown" | - |_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ | - |{cert_issuer} |HELO, MAIL, DATA, EOH, |TLS client certificate | - | |EOM |issuer | - |_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ | - |{cert_subject} |HELO, MAIL, DATA, EOH, |TLS client certificate | - | |EOM |subject | - |_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ | - |{cipher_bits} |HELO, MAIL, DATA, EOH, |TLS session key size | - | |EOM | | - |_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ | - |{cipher} |HELO, MAIL, DATA, EOH, |TLS cipher | - | |EOM | | - |_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ | - |{daemon_addr} |Always (Postfix >=3.2) |Local server IP address | - |_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ | - |{daemon_name} |Always |value of | - | | |milter_macro_daemon_name | - |_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ | - |{daemon_port} |Always (Postfix >=3.2) |Local server TCP port | - |_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ | - |{mail_addr} |MAIL |Sender address | - |_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ | - |{mail_host} |MAIL (Postfix >= 2.6, |Sender next-hop | - | |only with smtpd_milters) |destination | - |_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ | - |{mail_mailer} |MAIL (Postfix >= 2.6, |Sender mail delivery | - | |only with smtpd_milters) |transport | - |_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ | - | | |Recipient address | - |{rcpt_addr} |RCPT |With rejected recipient: | - | | |descriptive text | - |_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ | - | | |Recipient next-hop | - |{rcpt_host} |RCPT (Postfix >= 2.6, |destination | - | |only with smtpd_milters) |With rejected recipient: | - | | |enhanced status code | - |_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ | - | | |Recipient mail delivery | - |{rcpt_mailer} |RCPT (Postfix >= 2.6, |transport | - | |only with smtpd_milters) |With rejected recipient: | - | | |"error" | - |_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ | - |{tls_version} |HELO, MAIL, DATA, EOH, |TLS protocol version | - | |EOM | | - |_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ | - |v |Always |value of milter_macro_v | - |_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ | + _________________________________________________________________________________________________________________________________________ + |Sendmail macro |Milter protocol stage |Description | + |____________________|_______________________________________________|____________________________________________________________________| + |i |DATA, EOH, EOM |Queue ID, also Postfix queue file name | + |____________________|_______________________________________________|____________________________________________________________________| + |j |Always |Value of myhostname | + |____________________|_______________________________________________|____________________________________________________________________| + |_ |Always |The validated client name and address | + |____________________|_______________________________________________|____________________________________________________________________| + |{auth_authen} |MAIL, DATA, EOH, EOM |SASL login name | + |____________________|_______________________________________________|____________________________________________________________________| + |{auth_author} |MAIL, DATA, EOH, EOM |SASL sender | + |____________________|_______________________________________________|____________________________________________________________________| + |{auth_type} |MAIL, DATA, EOH, EOM |SASL login method | + |____________________|_______________________________________________|____________________________________________________________________| + |{client_addr} |Always |Remote client IP address | + |____________________|_______________________________________________|____________________________________________________________________| + |{client_connections}|CONNECT |Connection concurrency for this client (zero if the client is | + | | |excluded from all smtpd_client_* limits). | + |____________________|_______________________________________________|____________________________________________________________________| + | | |Remote client hostname | + |{client_name} |Always |When address → name lookup or name → address verification fails:| + | | |"unknown" | + |____________________|_______________________________________________|____________________________________________________________________| + |{client_port} |Always (Postfix ≥2.5) |Remote client TCP port | + |____________________|_______________________________________________|____________________________________________________________________| + |{client_ptr} |CONNECT, HELO, MAIL, DATA |Client name from address → name lookup | + | | |When address → name lookup fails: "unknown" | + |____________________|_______________________________________________|____________________________________________________________________| + |{cert_issuer} |HELO, MAIL, DATA, EOH, EOM |TLS client certificate issuer | + |____________________|_______________________________________________|____________________________________________________________________| + |{cert_subject} |HELO, MAIL, DATA, EOH, EOM |TLS client certificate subject | + |____________________|_______________________________________________|____________________________________________________________________| + |{cipher_bits} |HELO, MAIL, DATA, EOH, EOM |TLS session key size | + |____________________|_______________________________________________|____________________________________________________________________| + |{cipher} |HELO, MAIL, DATA, EOH, EOM |TLS cipher | + |____________________|_______________________________________________|____________________________________________________________________| + |{daemon_addr} |Always (Postfix ≥3.2) |Local server IP address | + |____________________|_______________________________________________|____________________________________________________________________| + |{daemon_name} |Always |value of milter_macro_daemon_name | + |____________________|_______________________________________________|____________________________________________________________________| + |{daemon_port} |Always (Postfix ≥3.2) |Local server TCP port | + |____________________|_______________________________________________|____________________________________________________________________| + |{mail_addr} |MAIL |Sender address | + |____________________|_______________________________________________|____________________________________________________________________| + |{mail_host} |MAIL (Postfix ≥ 2.6, only with smtpd_milters)|Sender next-hop destination | + |____________________|_______________________________________________|____________________________________________________________________| + |{mail_mailer} |MAIL (Postfix ≥ 2.6, only with smtpd_milters)|Sender mail delivery transport | + |____________________|_______________________________________________|____________________________________________________________________| + |{rcpt_addr} |RCPT |Recipient address | + | | |With rejected recipient: descriptive text | + |____________________|_______________________________________________|____________________________________________________________________| + |{rcpt_host} |RCPT (Postfix ≥ 2.6, only with smtpd_milters)|Recipient next-hop destination | + | | |With rejected recipient: enhanced status code | + |____________________|_______________________________________________|____________________________________________________________________| + |{rcpt_mailer} |RCPT (Postfix ≥ 2.6, only with smtpd_milters)|Recipient mail delivery transport | + | | |With rejected recipient: "error" | + |____________________|_______________________________________________|____________________________________________________________________| + |{tls_version} |HELO, MAIL, DATA, EOH, EOM |TLS protocol version | + |____________________|_______________________________________________|____________________________________________________________________| + |v |Always |value of milter_macro_v | + |____________________|_______________________________________________|____________________________________________________________________| -WWhhaatt mmaaccrrooss wwiillll PPoossttffiixx sseenndd ttoo MMiilltteerrss?? +What macros will Postfix send to Milters? Postfix sends specific sets of macros at different Milter protocol stages. The sets are configured with the parameters as shown in the table below (EOH = end @@ -454,26 +456,26 @@ As of Sendmail 8.14.0, Milter applications can specify what macros they want to receive at different Milter protocol stages. An application-specified list takes precedence over a Postfix-specified list. - _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ - |PPoossttffiixx ppaarraammeetteerr |MMiilltteerr pprroottooccooll|MMiilltteerr pprroottooccooll ssttaaggee| - | |vveerrssiioonn | | - |_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ | + ___________________________________________________________________ + |Postfix parameter |Milter protocol|Milter protocol stage| + | |version | | + |_____________________________|_______________|_____________________| |milter_connect_macros |2 or higher |CONNECT | - |_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ | + |_____________________________|_______________|_____________________| |milter_helo_macros |2 or higher |HELO/EHLO | - |_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ | + |_____________________________|_______________|_____________________| |milter_mail_macros |2 or higher |MAIL FROM | - |_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ | + |_____________________________|_______________|_____________________| |milter_rcpt_macros |2 or higher |RCPT TO | - |_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ | + |_____________________________|_______________|_____________________| |milter_data_macros |4 or higher |DATA | - |_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ | + |_____________________________|_______________|_____________________| |milter_end_of_header_macros |6 or higher |EOH | - |_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ | + |_____________________________|_______________|_____________________| |milter_end_of_data_macros |2 or higher |EOM | - |_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ | + |_____________________________|_______________|_____________________| |milter_unknown_command_macros|3 or higher |unknown command | - |_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ | + |_____________________________|_______________|_____________________| By default, Postfix will send only macros whose values have been updated with information from main.cf or master.cf, from an SMTP session (for example; SASL @@ -485,7 +487,7 @@ specify macro default values with the milter_macro_defaults parameter. Specify zero or more name=value pairs separated by comma or whitespace; you may even specify macro names that Postfix does know about! -WWoorrkkaarroouunnddss +Workarounds * To avoid breaking DKIM etc. signatures with an SMTP-based content filter, update the before-filter SMTP client in master.cf, and add a line with "- @@ -504,7 +506,7 @@ WWoorrkkaarroouunnddss * Some Milter applications use the "{if_addr}" macro to recognize local mail; this macro does not exist in Postfix. Workaround: use the "{daemon_addr}" - (Postfix >= 3.2) or "{client_addr}" macro instead. + (Postfix ≥ 3.2) or "{client_addr}" macro instead. * Some Milter applications log a warning that looks like this: @@ -533,19 +535,19 @@ WWoorrkkaarroouunnddss o Edit the filter source file (typically named xxx-filter/xxx-filter.c or similar). - o Look up the mlfi_eom() function and add code near the top shown as bboolldd + o Look up the mlfi_eom() function and add code near the top shown as bold text below: dfc = cc->cctx_msg; assert(dfc != NULL); - //** DDeetteerrmmiinnee tthhee jjoobb IIDD ffoorr llooggggiinngg.. **// - iiff ((ddffcc-->>mmccttxx__jjoobbiidd ==== 00 |||| ssttrrccmmpp((ddffcc-->>mmccttxx__jjoobbiidd,, JJOOBBIIDDUUNNKKNNOOWWNN)) ==== 00)) - {{ - cchhaarr **jjoobbiidd == ssmmffii__ggeettssyymmvvaall((ccttxx,, ""ii""));; - iiff ((jjoobbiidd !!== 00)) - ddffcc-->>mmccttxx__jjoobbiidd == jjoobbiidd;; - }} + /* Determine the job ID for logging. */ + if (dfc->mctx_jobid == 0 || strcmp(dfc->mctx_jobid, JOBIDUNKNOWN) == 0) + { + char *jobid = smfi_getsymval(ctx, "i"); + if (jobid != 0) + dfc->mctx_jobid = jobid; + } NOTES: @@ -557,7 +559,7 @@ WWoorrkkaarroouunnddss o This change fixes only the ugly message header, but not the WARNING message. Fortunately, many Milters log that message only once. -LLiimmiittaattiioonnss +Limitations This section lists limitations of the Postfix Milter implementation. Some limitations will be removed as the implementation is extended over time. Of @@ -567,22 +569,22 @@ the CONTENT_INSPECTION_README document for a discussion. * The Milter protocol has evolved over time. Therefore, different Postfix versions implement different feature sets. - _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ - |PPoossttffiixx|SSuuppppoorrtteedd MMiilltteerr rreeqquueessttss | - |_ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ | + ________________________________________________________________________ + |Postfix|Supported Milter requests | + |_______|________________________________________________________________| | 2.6 |All Milter requests of Sendmail 8.14.0 (see notes below). | - |_ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ | + |_______|________________________________________________________________| | |All Milter requests of Sendmail 8.14.0, except: | | |SMFIP_RCPT_REJ (report rejected recipients to the mail filter), | | 2.5 |SMFIR_CHGFROM (replace sender, with optional ESMTP parameters), | | |SMFIR_ADDRCPT_PAR (add recipient, with optional ESMTP | | |parameters). | - |_ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ | + |_______|________________________________________________________________| | 2.4 |All Milter requests of Sendmail 8.13.0. | - |_ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ | + |_______|________________________________________________________________| | 2.3 |All Milter requests of Sendmail 8.13.0, except: | | |SMFIR_REPLBODY (replace message body). | - |_ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ | + |_______|________________________________________________________________| * For Milter applications that are written in C, you need to use the Sendmail libmilter library. diff --git a/postfix/RELEASE_NOTES b/postfix/RELEASE_NOTES index 03bc062b7..c083b20b5 100644 --- a/postfix/RELEASE_NOTES +++ b/postfix/RELEASE_NOTES @@ -16,6 +16,13 @@ specifies the release date of a stable release or snapshot release. If you upgrade from Postfix 3.0 or earlier, read RELEASE_NOTES-3.1 before proceeding. +Major changes with snapshot 20161031 +==================================== + +The smtpd_milter_maps feature supports per-client Milter configuration. +This overrides the global smtpd_milters setting and has the same syntax. A +lookup result of "DISABLE" turns off Milter support. + Incompatible changes with snapshot 20160925 =========================================== diff --git a/postfix/html/MILTER_README.html b/postfix/html/MILTER_README.html index ee46ad452..99af63a12 100644 --- a/postfix/html/MILTER_README.html +++ b/postfix/html/MILTER_README.html @@ -259,6 +259,9 @@ support per-Milter timeouts, per-Milter error handling, etc.
For advanced configuration see "Different +settings for different SMTP clients" and "Different settings for different Milter +applications".
+The non-SMTP Milter applications handle mail that arrives via @@ -564,6 +572,29 @@ and protocol.
}", if you want to have space or comma within a value or around "=". +The smtpd_milter_maps feature supports different Milter settings +for different client IP addresses. Lookup results override the the +global smtpd_milters setting, and have the same syntax. For example, +to disable Milter settings for local address ranges:
+ ++/etc/postfix/main.cf: + smtpd_milter_maps = cidr:/etc/postfix/smtpd_milter_map + smtpd_milters = inet:host:port, { inet:host:port, ... }, ... + +/etc/postfix/smtpd_milter_map: + # Disable Milters for local clients. + 127.0.0.0/8 DISABLE + 192.168.0.0/16 DISABLE + ::/64 DISABLE + 2001:db8::/32 DISABLE ++ +
This feature is available with Postfix 3.2 and later.
+Postfix emulates a limited number of Sendmail macros, as shown diff --git a/postfix/html/postconf.5.html b/postfix/html/postconf.5.html index 166c8073f..9163af9f9 100644 --- a/postfix/html/postconf.5.html +++ b/postfix/html/postconf.5.html @@ -14637,6 +14637,39 @@ from the list.
This feature is available in Postfix 2.10 and later.
+ + +Lookup tables with Milter settings per remote SMTP client IP +address. The lookup result overrides the smtpd_milters setting, +and has the same syntax.
+ +Note: lookup tables cannot return empty responses. Specify a +lookup result of DISABLE (case does not matter) to indicate that +Milter support should be disabled.
+ +Example to disable Milters for local clients:
+ ++/etc/postfix/main.cf: + smtpd_milter_maps = cidr:/etc/postfix/smtpd_milter_map + smtpd_milters = inet:host:port, { inet:host:port, ... }, ... ++ +
+/etc/postfix/smtpd_milter_map: + # Disable Milters for local clients. + 127.0.0.0/8 DISABLE + 192.168.0.0/16 DISABLE + ::/64 DISABLE + 2001:db8::/32 DISABLE ++ +
This feature is available in Postfix 3.2 and later.
+ +For advanced configuration see "Different +settings for different SMTP clients" and "Different settings for different Milter +applications".
+The non-SMTP Milter applications handle mail that arrives via @@ -564,6 +572,29 @@ main.cf: items separated by space or comma. There is one difference: }", if you want to have space or comma within a value or around "="
The smtpd_milter_maps feature supports different Milter settings +for different client IP addresses. Lookup results override the the +global smtpd_milters setting, and have the same syntax. For example, +to disable Milter settings for local address ranges:
+ ++/etc/postfix/main.cf: + smtpd_milter_maps = cidr:/etc/postfix/smtpd_milter_map + smtpd_milters = inet:host:port, { inet:host:port, ... }, ... + +/etc/postfix/smtpd_milter_map: + # Disable Milters for local clients. + 127.0.0.0/8 DISABLE + 192.168.0.0/16 DISABLE + ::/64 DISABLE + 2001:db8::/32 DISABLE ++ +
This feature is available with Postfix 3.2 and later.
+Postfix emulates a limited number of Sendmail macros, as shown diff --git a/postfix/proto/postconf.proto b/postfix/proto/postconf.proto index 8bc5e6d36..89ffe6cc1 100644 --- a/postfix/proto/postconf.proto +++ b/postfix/proto/postconf.proto @@ -16675,3 +16675,32 @@ the verify(8) daemon automatically refreshes an active address before it expires.
This feature is available in Postfix 3.1 and later.
+ +%PARAM smtpd_milter_maps + +Lookup tables with Milter settings per remote SMTP client IP +address. The lookup result overrides the smtpd_milters setting, +and has the same syntax.
+ +Note: lookup tables cannot return empty responses. Specify a +lookup result of DISABLE (case does not matter) to indicate that +Milter support should be disabled.
+ +Example to disable Milters for local clients:
+ ++/etc/postfix/main.cf: + smtpd_milter_maps = cidr:/etc/postfix/smtpd_milter_map + smtpd_milters = inet:host:port, { inet:host:port, ... }, ... ++ +
+/etc/postfix/smtpd_milter_map: + # Disable Milters for local clients. + 127.0.0.0/8 DISABLE + 192.168.0.0/16 DISABLE + ::/64 DISABLE + 2001:db8::/32 DISABLE ++ +
This feature is available in Postfix 3.2 and later.
diff --git a/postfix/src/global/mail_params.h b/postfix/src/global/mail_params.h index b4b51eb6d..c7ccc7f04 100644 --- a/postfix/src/global/mail_params.h +++ b/postfix/src/global/mail_params.h @@ -3250,6 +3250,11 @@ extern bool var_tls_dane_taa_dgst; #define DEF_SMTPD_MILTERS "" extern char *var_smtpd_milters; +#define VAR_SMTPD_MILTER_MAPS "smtpd_milter_maps" +#define DEF_SMTPD_MILTER_MAPS "" +extern char *var_smtpd_milter_maps; +#define SMTPD_MILTERS_DISABLE "DISABLE" + #define VAR_CLEANUP_MILTERS "non_smtpd_milters" #define DEF_CLEANUP_MILTERS "" extern char *var_cleanup_milters; diff --git a/postfix/src/global/mail_version.h b/postfix/src/global/mail_version.h index 03afe4a55..d24f7c293 100644 --- a/postfix/src/global/mail_version.h +++ b/postfix/src/global/mail_version.h @@ -20,7 +20,7 @@ * Patches change both the patchlevel and the release date. Snapshots have no * patchlevel; they change the release date only. */ -#define MAIL_RELEASE_DATE "20161008" +#define MAIL_RELEASE_DATE "20161101" #define MAIL_VERSION_NUMBER "3.2" #ifdef SNAPSHOT diff --git a/postfix/src/smtpd/smtpd.c b/postfix/src/smtpd/smtpd.c index 6e2a194f8..d94d585f3 100644 --- a/postfix/src/smtpd/smtpd.c +++ b/postfix/src/smtpd/smtpd.c @@ -258,6 +258,11 @@ /* Optional list of \fIname=value\fR pairs that specify default /* values for arbitrary macros that Postfix may send to Milter /* applications. +/* .PP +/* Available in Postfix version 3.2 and later: +/* .IP "\fBsmtpd_milter_maps (empty)\fR" +/* Lookup tables with Milter settings per remote SMTP client IP +/* address. /* GENERAL CONTENT INSPECTION CONTROLS /* .ad /* .fi @@ -1355,6 +1360,7 @@ bool var_smtpd_peername_lookup; int var_plaintext_code; bool var_smtpd_delay_open; char *var_smtpd_milters; +char *var_smtpd_milter_maps; int var_milt_conn_time; int var_milt_cmd_time; int var_milt_msg_time; @@ -1402,6 +1408,13 @@ int var_smtpd_uproxy_tmout; */ static MAPS *ehlo_discard_maps; + /* + * Per-client Milter support. + */ +static MAPS *smtpd_milter_maps; +static void setup_milters(SMTPD_STATE *); +static void teardown_milters(SMTPD_STATE *); + /* * VERP command name. */ @@ -1459,11 +1472,6 @@ static void tls_reset(SMTPD_STATE *); #define REASON_LOST_CONNECTION "lost connection" #define REASON_ERROR_LIMIT "too many errors" - /* - * Mail filter initialization status. - */ -MILTERS *smtpd_milters; - #ifdef USE_TLS /* @@ -1640,10 +1648,9 @@ static int helo_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv) #define PUSH_STRING(old, curr, new) { char *old = (curr); (curr) = (new); #define POP_STRING(old, curr) (curr) = old; } - if (smtpd_milters != 0 - && SMTPD_STAND_ALONE(state) == 0 + if (state->milters != 0 && (state->saved_flags & MILTER_SKIP_FLAGS) == 0 - && (err = milter_helo_event(smtpd_milters, argv[1].strval, 0)) != 0) { + && (err = milter_helo_event(state->milters, argv[1].strval, 0)) != 0) { /* Log reject etc. with correct HELO information. */ PUSH_STRING(saved_helo, state->helo_name, argv[1].strval); err = check_milter_reply(state, err); @@ -1726,10 +1733,9 @@ static int ehlo_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv) * other commands such as AUTH, STARTTLS, and VRFY. */ err = 0; - if (smtpd_milters != 0 - && SMTPD_STAND_ALONE(state) == 0 + if (state->milters != 0 && (state->saved_flags & MILTER_SKIP_FLAGS) == 0 - && (err = milter_helo_event(smtpd_milters, argv[1].strval, 1)) != 0) { + && (err = milter_helo_event(state->milters, argv[1].strval, 1)) != 0) { /* Log reject etc. with correct HELO information. */ PUSH_STRING(saved_helo, state->helo_name, argv[1].strval); err = check_milter_reply(state, err); @@ -1904,8 +1910,8 @@ static void helo_reset(SMTPD_STATE *state) if (state->helo_name) { myfree(state->helo_name); state->helo_name = 0; - if (SMTPD_STAND_ALONE(state) == 0 && smtpd_milters != 0) - milter_abort(smtpd_milters); + if (state->milters != 0) + milter_abort(state->milters); } if (state->ehlo_argv) { argv_free(state->ehlo_argv); @@ -2036,10 +2042,10 @@ static int mail_open_stream(SMTPD_STATE *state) state->cleanup = state->dest->stream; state->queue_id = mystrdup(state->dest->id); if (SMTPD_STAND_ALONE(state) == 0) { - if (smtpd_milters != 0 + if (state->milters != 0 && (state->saved_flags & MILTER_SKIP_FLAGS) == 0) /* Send place-holder smtpd_milters list. */ - (void) milter_dummy(smtpd_milters, state->cleanup); + (void) milter_dummy(state->milters, state->cleanup); rec_fprintf(state->cleanup, REC_TYPE_TIME, REC_TYPE_TIME_FORMAT, REC_TYPE_TIME_ARG(state->arrival_time)); if (*var_filter_xport) @@ -2533,11 +2539,10 @@ static int mail_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv) smtpd_chat_reply(state, "%s", err); return (-1); } - if (smtpd_milters != 0 - && SMTPD_STAND_ALONE(state) == 0 + if (state->milters != 0 && (state->saved_flags & MILTER_SKIP_FLAGS) == 0) { PUSH_STRING(saved_sender, state->sender, STR(state->addr_buf)); - err = milter_mail_event(smtpd_milters, + err = milter_mail_event(state->milters, milter_argv(state, argc - 2, argv + 2)); if (err != 0) { /* Log reject etc. with correct sender information. */ @@ -2653,8 +2658,8 @@ static void mail_reset(SMTPD_STATE *state) state->queue_id = 0; } if (state->sender) { - if (SMTPD_STAND_ALONE(state) == 0 && smtpd_milters != 0) - milter_abort(smtpd_milters); + if (state->milters != 0) + milter_abort(state->milters); myfree(state->sender); state->sender = 0; } @@ -2868,11 +2873,11 @@ static int rcpt_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv) } else { err = smtpd_check_rcpt(state, STR(state->addr_buf)); } - if (smtpd_milters != 0 + if (state->milters != 0 && (state->saved_flags & MILTER_SKIP_FLAGS) == 0) { PUSH_STRING(saved_rcpt, state->recipient, STR(state->addr_buf)); state->milter_reject_text = err; - milter_err = milter_rcpt_event(smtpd_milters, + milter_err = milter_rcpt_event(state->milters, err == 0 ? MILTER_FLAG_NONE : MILTER_FLAG_WANT_RCPT_REJ, milter_argv(state, argc - 2, argv + 2)); @@ -3143,10 +3148,9 @@ static int data_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *unused_argv) smtpd_chat_reply(state, "%s", err); return (-1); } - if (smtpd_milters != 0 - && SMTPD_STAND_ALONE(state) == 0 + if (state->milters != 0 && (state->saved_flags & MILTER_SKIP_FLAGS) == 0 - && (err = milter_data_event(smtpd_milters)) != 0 + && (err = milter_data_event(state->milters)) != 0 && (err = check_milter_reply(state, err)) != 0) { smtpd_chat_reply(state, "%s", err); return (-1); @@ -3186,10 +3190,10 @@ static int data_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *unused_argv) */ if (state->cleanup) { if (SMTPD_STAND_ALONE(state) == 0) { - if (smtpd_milters != 0 + if (state->milters != 0 && (state->saved_flags & MILTER_SKIP_FLAGS) == 0) /* Send actual smtpd_milters list. */ - (void) milter_send(smtpd_milters, state->cleanup); + (void) milter_send(state->milters, state->cleanup); if (state->saved_flags) rec_fprintf(state->cleanup, REC_TYPE_FLGS, "%d", state->saved_flags); @@ -3437,7 +3441,7 @@ static int data_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *unused_argv) * XXX See exception below in code that overrides state->access_denied for * compliance with RFC 2821 Sec 3.1. */ - if (smtpd_milters != 0 && (state->err & CLEANUP_STAT_WRITE) != 0) + if (state->milters != 0 && (state->err & CLEANUP_STAT_WRITE) != 0) state->access_denied = mystrdup("421 4.3.0 Mail system error"); /* @@ -3658,7 +3662,7 @@ static int vrfy_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv) state->addr); return (-1); } - if (smtpd_milters != 0 && (err = milter_other_event(smtpd_milters)) != 0 + if (state->milters != 0 && (err = milter_other_event(state->milters)) != 0 && (err[0] == '5' || err[0] == '4')) { state->error_mask |= MAIL_ERROR_POLICY; smtpd_chat_reply(state, "%s", err); @@ -3713,7 +3717,7 @@ static int etrn_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv) smtpd_chat_reply(state, "503 Error: send HELO/EHLO first"); return (-1); } - if (smtpd_milters != 0 && (err = milter_other_event(smtpd_milters)) != 0 + if (state->milters != 0 && (err = milter_other_event(state->milters)) != 0 && (err[0] == '5' || err[0] == '4')) { state->error_mask |= MAIL_ERROR_POLICY; smtpd_chat_reply(state, "%s", err); @@ -4154,8 +4158,11 @@ static int xclient_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv) chat_reset(state, 0); mail_reset(state); rcpt_reset(state); - if (smtpd_milters) - milter_disc_event(smtpd_milters); + if (state->milters) + milter_disc_event(state->milters); + /* Following duplicates the top-level connect/disconnect handler. */ + teardown_milters(state); + setup_milters(state); vstream_longjmp(state->client, SMTP_ERR_NONE); return (0); } @@ -4634,7 +4641,7 @@ static int starttls_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *unused_argv) smtpd_chat_reply(state, "501 5.5.4 Syntax: STARTTLS"); return (-1); } - if (smtpd_milters != 0 && (err = milter_other_event(smtpd_milters)) != 0) { + if (state->milters != 0 && (err = milter_other_event(state->milters)) != 0) { if (err[0] == '5') { state->error_mask |= MAIL_ERROR_POLICY; smtpd_chat_reply(state, "%s", err); @@ -5035,10 +5042,10 @@ static void smtpd_proto(SMTPD_STATE *state) */ else { err = 0; - if (smtpd_milters != 0 && SMTPD_STAND_ALONE(state) == 0) { - milter_macro_callback(smtpd_milters, smtpd_milter_eval, + if (state->milters != 0) { + milter_macro_callback(state->milters, smtpd_milter_eval, (void *) state); - if ((err = milter_conn_event(smtpd_milters, state->name, + if ((err = milter_conn_event(state->milters, state->name, state->addr, strcmp(state->port, CLIENT_PORT_UNKNOWN) ? state->port : "0", @@ -5163,9 +5170,8 @@ static void smtpd_proto(SMTPD_STATE *state) } /* state->access_denied == 0 || cmdp->action == quit_cmd */ if (cmdp->name == 0) { - if (smtpd_milters != 0 - && SMTPD_STAND_ALONE(state) == 0 - && (err = milter_unknown_event(smtpd_milters, + if (state->milters != 0 + && (err = milter_unknown_event(state->milters, argv[0].strval)) != 0 && (err = check_milter_reply(state, err)) != 0) { smtpd_chat_reply(state, "%s", err); @@ -5270,8 +5276,8 @@ static void smtpd_proto(SMTPD_STATE *state) chat_reset(state, 0); mail_reset(state); rcpt_reset(state); - if (smtpd_milters) - milter_disc_event(smtpd_milters); + if (state->milters) + milter_disc_event(state->milters); } /* smtpd_format_cmd_stats - format per-command statistics */ @@ -5313,6 +5319,59 @@ static char *smtpd_format_cmd_stats(VSTRING *buf) return (lowercase(STR(buf))); } +/* setup_milters - set up Milters after a connection is established */ + +static void setup_milters(SMTPD_STATE *state) +{ + const char *milter_string; + + /* + * Postcondition: either state->milters is set, or the + * INPUT_TRANSP_MILTER flag is passed down-stream. + */ + if (SMTPD_STAND_ALONE(state) == 0 + && (smtpd_input_transp_mask & INPUT_TRANSP_MILTER) == 0 + && ((smtpd_milter_maps + && (milter_string = + maps_find(smtpd_milter_maps, state->addr, 0)) != 0) + || *(milter_string = var_smtpd_milters) != 0) + && strcasecmp(milter_string, SMTPD_MILTERS_DISABLE) != 0) { + state->milters = milter_create(milter_string, + var_milt_conn_time, + var_milt_cmd_time, + var_milt_msg_time, + var_milt_protocol, + var_milt_def_action, + var_milt_conn_macros, + var_milt_helo_macros, + var_milt_mail_macros, + var_milt_rcpt_macros, + var_milt_data_macros, + var_milt_eoh_macros, + var_milt_eod_macros, + var_milt_unk_macros, + var_milt_macro_deflts); + } + + /* + * Safety: disable non_smtpd_milters when not sending our own mail filter + * list. Otherwise the next stage could handle this message as a local + * submission. + */ + if (state->milters == 0) + smtpd_input_transp_mask |= INPUT_TRANSP_MILTER; +} + +/* teardown_milters - release resources */ + +static void teardown_milters(SMTPD_STATE *state) +{ + if (state->milters) { + milter_free(state->milters); + state->milters = 0; + } +} + /* smtpd_service - service one client */ @@ -5374,6 +5433,11 @@ static void smtpd_service(VSTREAM *stream, char *service, char **argv) */ debug_peer_check(state.name, state.addr); + /* + * Set up Milters, or disable Milters down-stream. + */ + setup_milters(&state); /* duplicates xclient_cmd */ + /* * Provide the SMTP service. */ @@ -5386,6 +5450,7 @@ static void smtpd_service(VSTREAM *stream, char *service, char **argv) */ msg_info("disconnect from %s%s", state.namaddr, smtpd_format_cmd_stats(state.buffer)); + teardown_milters(&state); /* duplicates xclient_cmd */ smtpd_state_reset(&state); debug_peer_restore(); } @@ -5598,6 +5663,14 @@ static void pre_jail_init(char *unused_name, char **unused_argv) var_smtpd_ehlo_dis_maps, DICT_FLAG_LOCK); + /* + * Per-client Milter support. + */ + if (*var_smtpd_milter_maps) + smtpd_milter_maps = maps_create(VAR_SMTPD_MILTER_MAPS, + var_smtpd_milter_maps, + DICT_FLAG_LOCK); + /* * DNS reply filter. */ @@ -5627,35 +5700,6 @@ static void post_jail_init(char *unused_name, char **unused_argv) smtpd_proxy_opts = smtpd_proxy_parse_opts(VAR_SMTPD_PROXY_OPTS, var_smtpd_proxy_opts); - /* - * Sendmail mail filters. - * - * XXX Should not do this when running in stand-alone mode. But that test - * looks at VSTREAM_IN which is not available at this point. - * - * XXX Disable non_smtpd_milters when not sending our own mail filter list. - */ - if ((smtpd_input_transp_mask & INPUT_TRANSP_MILTER) == 0) { - if (*var_smtpd_milters) - smtpd_milters = milter_create(var_smtpd_milters, - var_milt_conn_time, - var_milt_cmd_time, - var_milt_msg_time, - var_milt_protocol, - var_milt_def_action, - var_milt_conn_macros, - var_milt_helo_macros, - var_milt_mail_macros, - var_milt_rcpt_macros, - var_milt_data_macros, - var_milt_eoh_macros, - var_milt_eod_macros, - var_milt_unk_macros, - var_milt_macro_deflts); - else - smtpd_input_transp_mask |= INPUT_TRANSP_MILTER; - } - /* * Sanity checks. The queue_minfree value should be at least as large as * (process_limit * message_size_limit) but that is unpractical, so we @@ -5865,6 +5909,7 @@ int main(int argc, char **argv) VAR_MILT_DAEMON_NAME, DEF_MILT_DAEMON_NAME, &var_milt_daemon_name, 1, 0, VAR_MILT_V, DEF_MILT_V, &var_milt_v, 1, 0, VAR_MILT_MACRO_DEFLTS, DEF_MILT_MACRO_DEFLTS, &var_milt_macro_deflts, 0, 0, + VAR_SMTPD_MILTER_MAPS, DEF_SMTPD_MILTER_MAPS, &var_smtpd_milter_maps, 0, 0, VAR_STRESS, DEF_STRESS, &var_stress, 0, 0, VAR_UNV_FROM_WHY, DEF_UNV_FROM_WHY, &var_unv_from_why, 0, 0, VAR_UNV_RCPT_WHY, DEF_UNV_RCPT_WHY, &var_unv_rcpt_why, 0, 0, diff --git a/postfix/src/smtpd/smtpd.h b/postfix/src/smtpd/smtpd.h index fdce24929..4facfb080 100644 --- a/postfix/src/smtpd/smtpd.h +++ b/postfix/src/smtpd/smtpd.h @@ -182,6 +182,7 @@ typedef struct { const char **milter_argv; /* SMTP command vector */ ssize_t milter_argc; /* SMTP command vector */ const char *milter_reject_text; /* input to call-back from Milter */ + MILTERS *milters; /* Milter initialization status.*/ /* * EHLO temporary space. diff --git a/postfix/src/smtpd/smtpd_sasl_proto.c b/postfix/src/smtpd/smtpd_sasl_proto.c index a04d9daf6..5a11a87bd 100644 --- a/postfix/src/smtpd/smtpd_sasl_proto.c +++ b/postfix/src/smtpd/smtpd_sasl_proto.c @@ -163,7 +163,7 @@ int smtpd_sasl_auth_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv) smtpd_chat_reply(state, "503 5.5.1 Error: MAIL transaction in progress"); return (-1); } - if (smtpd_milters != 0 && (err = milter_other_event(smtpd_milters)) != 0) { + if (state->milters != 0 && (err = milter_other_event(state->milters)) != 0) { if (err[0] == '5') { state->error_mask |= MAIL_ERROR_POLICY; smtpd_chat_reply(state, "%s", err); diff --git a/postfix/src/smtpd/smtpd_state.c b/postfix/src/smtpd/smtpd_state.c index c03dfbef8..7a117a8b2 100644 --- a/postfix/src/smtpd/smtpd_state.c +++ b/postfix/src/smtpd/smtpd_state.c @@ -159,6 +159,7 @@ void smtpd_state_init(SMTPD_STATE *state, VSTREAM *stream, state->milter_argv = 0; state->milter_argc = 0; + state->milters = 0; /* * Initialize peer information.