From: Wietse Venema Date: Sun, 25 Oct 2020 05:00:00 +0000 (-0500) Subject: postfix-3.6-20201025 X-Git-Tag: v3.6.0-RC1~19 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=1bf53d4b287c444fc6bcadc131ca69d488ee7d62;p=thirdparty%2Fpostfix.git postfix-3.6-20201025 --- diff --git a/postfix/.indent.pro b/postfix/.indent.pro index 736227a07..4ea4616ea 100644 --- a/postfix/.indent.pro +++ b/postfix/.indent.pro @@ -20,6 +20,7 @@ -TBH_TABLE -TBINATTR -TBINATTR_INFO +-Tbind_props -TBINHASH -TBINHASH_INFO -TBIO @@ -37,9 +38,10 @@ -TBYTE_MASK -TCFG_PARSER -TCIDR_MATCH +-Tcipher_probe_t -TCLEANUP_REGION --TCLEANUP_STATE -TCLEANUP_STAT_DETAIL +-TCLEANUP_STATE -TCLIENT_LIST -TCLNT_STREAM -TCONFIG_BOOL_FN_TABLE @@ -63,9 +65,12 @@ -TCRYPTO_EX_DATA -TCTABLE -TCTABLE_ENTRY +-Td2i_X509_t +-Tdane_digest +-Tdane_mtype -TDB_COMMON_CTX --TDELIVERED_HDR_INFO -TDELIVER_ATTR +-TDELIVERED_HDR_INFO -TDELIVER_REQUEST -TDELTA_TIME -TDICT @@ -148,7 +153,9 @@ -TEVP_PKEY -TEXPAND_ATTR -TFILE +-Tfilter_ctx -TFORWARD_INFO +-Tgeneral_name_stack_t -THBC_ACTION_CALL_BACKS -THBC_CALL_BACKS -THBC_CHECKS @@ -160,17 +167,18 @@ -THOST -THTABLE -THTABLE_INFO +-Tiana_digest -TINET_ADDR_LIST -TINET_PROTO_INFO -TINSTANCE -TINST_SELECTION -TINT32_TYPE --TINTV -TINT_TABLE +-TINTV -TJMP_BUF_WRAPPER -TLDAP --TLDAPMessage -TLDAP_CONN +-TLDAPMessage -TLIB_DP -TLIB_FN -TLMTP_ATTR @@ -179,20 +187,21 @@ -TLMTP_STATE -TLOCAL_EXP -TLOCAL_STATE +-TLOGIN_SENDER_MATCH -TLOGWRITER -TLONG_NAME_MASK -TMAC_EXP_CONTEXT -TMAC_EXP_OP_INFO -TMAC_HEAD -TMAC_PARSE +-TMAI_HOSTADDR_STR +-TMAI_HOSTNAME_STR -TMAIL_ADDR_FORMATTER -TMAIL_ADDR_MAP_TEST -TMAIL_PRINT -TMAIL_SCAN -TMAIL_STREAM -TMAIL_VERSION --TMAI_HOSTADDR_STR --TMAI_HOSTNAME_STR -TMAI_SERVNAME_STR -TMAI_SERVPORT_STR -TMAPS @@ -211,9 +220,9 @@ -TMDB_val -TMILTER -TMILTER8 --TMILTERS -TMILTER_MACROS -TMILTER_MSG_CONTEXT +-TMILTERS -TMIME_ENCODING -TMIME_INFO -TMIME_STACK @@ -238,6 +247,7 @@ -TNAME_CODE -TNAME_MASK -TNBBIO +-Toff_t -TOPTIONS -TPCF_DBMS_INFO -TPCF_EVAL_CTX @@ -251,6 +261,7 @@ -TPCF_SERVICE_PATTERN -TPCF_STRING_NV -TPEER_NAME +-Tpem_load_state_t -TPGSQL_NAME -TPICKUP_INFO -TPIPE_ATTR @@ -258,9 +269,9 @@ -TPIPE_STATE -TPLMYSQL -TPLPGSQL --TPOSTMAP_KEY_STATE -TPOST_MAIL_FCLOSE_STATE -TPOST_MAIL_STATE +-TPOSTMAP_KEY_STATE -TPRIVATE_STR_TABLE -TPSC_CALL_BACK_ENTRY -TPSC_CLIENT_INFO @@ -288,11 +299,15 @@ -TRECIPIENT -TRECIPIENT_LIST -TREC_TYPE_NAME +-Tregex_t +-Tregmatch_t +-TRES_CONTEXT -TRESOLVE_REPLY -TRESPONSE -TREST_TABLE --TRES_CONTEXT -TRWR_CONTEXT +-Tsasl_conn_t +-Tsasl_secret_t -TSCACHE -TSCACHE_CLNT -TSCACHE_MULTI @@ -306,13 +321,21 @@ -TSCAN_DIR -TSCAN_INFO -TSCAN_OBJ +-TSENDER_LOGIN_MATCH -TSESSION +-Tsfsistat -TSHARED_PATH +-Tsigset_t -TSINGLE_SERVER -TSINK_COMMAND -TSINK_STATE +-Tsize_t -TSLMDB -TSMFICTX +-TSM_STATE +-TSMTP_ADDR +-TSMTP_CLI_ATTR +-TSMTP_CMD -TSMTPD_CMD -TSMTPD_DEFER -TSMTPD_ENDPT_LOOKUP_INFO @@ -324,9 +347,6 @@ -TSMTPD_STATE -TSMTPD_TOKEN -TSMTPD_XFORWARD_ATTR --TSMTP_ADDR --TSMTP_CLI_ATTR --TSMTP_CMD -TSMTP_ITERATOR -TSMTP_RESP -TSMTP_SASL_AUTH_CACHE @@ -335,10 +355,13 @@ -TSMTP_TLS_POLICY -TSMTP_TLS_SESS -TSMTP_TLS_SITE_POLICY --TSM_STATE +-Tsockaddr -TSOCKADDR_SIZE -TSPAWN_ATTR +-Tssize_t -TSSL +-Tssl_cipher_stack_t +-Tssl_comp_stack_t -TSSL_CTX -TSSL_SESSION -TSTATE @@ -346,17 +369,20 @@ -TSTRING_TABLE -TSYS_EXITS_DETAIL -TTEST_CASE --TTLSMGR_SCACHE --TTLSP_STATE +-Ttime_t +-Ttlsa_filter -TTLS_APPL_STATE -TTLS_CERTS -TTLS_CLIENT_INIT_PROPS -TTLS_CLIENT_PARAMS -TTLS_CLIENT_START_PROPS +-TTLScontext_t -TTLS_DANE +-TTLSMGR_SCACHE -TTLS_PKEYS -TTLS_PRNG_SEED_INFO -TTLS_PRNG_SRC +-TTLSP_STATE -TTLS_ROLE -TTLS_SCACHE -TTLS_SCACHE_ENTRY @@ -367,10 +393,12 @@ -TTLS_TLSA -TTLS_USAGE -TTLS_VINFO --TTLScontext_t -TTOK822 -TTRANSPORT_INFO -TTRIGGER_SERVER +-Tuint16_t +-Tuint32_t +-Tuint8_t -TUSER_ATTR -TVBUF -TVSTREAM @@ -380,10 +408,11 @@ -TWATCHDOG -TWATCH_FD -TX509 --TX509V3_CTX -TX509_EXTENSION -TX509_NAME +-Tx509_stack_t -TX509_STORE_CTX +-TX509V3_CTX -TXSASL_CLIENT -TXSASL_CLIENT_CREATE_ARGS -TXSASL_CLIENT_IMPL @@ -400,30 +429,3 @@ -TXSASL_SERVER_CREATE_ARGS -TXSASL_SERVER_IMPL -TXSASL_SERVER_IMPL_INFO --Tbind_props --Tcipher_probe_t --Td2i_X509_t --Tdane_digest --Tdane_mtype --Tfilter_ctx --Tgeneral_name_stack_t --Tiana_digest --Toff_t --Tpem_load_state_t --Tregex_t --Tregmatch_t --Tsasl_conn_t --Tsasl_secret_t --Tsfsistat --Tsigset_t --Tsize_t --Tsockaddr --Tssize_t --Tssl_cipher_stack_t --Tssl_comp_stack_t --Ttime_t --Ttlsa_filter --Tuint16_t --Tuint32_t --Tuint8_t --Tx509_stack_t diff --git a/postfix/HISTORY b/postfix/HISTORY index f4810b325..2986dbb26 100644 --- a/postfix/HISTORY +++ b/postfix/HISTORY @@ -25195,7 +25195,7 @@ Apologies for any names omitted. Cleanup: some wordsmithing of warnings when DNSSEC validation is unavailable. File: dns/dns_sec.c. - Clenaup: add missing warnings for libpostfix version + Cleanup: add missing warnings for libpostfix version mismatches. This will help folks with build processes that mistakenly run newly-built Postfix installation commands with previously-installed libpostfix files. Files: @@ -25204,3 +25204,44 @@ Apologies for any names omitted. Documentation: hyperlink occurrences of the info_log_address_format parameter name in daemon manpages. + +20201005 + + Cleanup: move the submit_users check after the postdrop + initializations that strip the environment, set up signal + handlers, etc. File: postdrop/postdrop.c. + + Documentation: descriptions of Postfix TLS wrappermode + support. File: proto/TLS_README.html, proto/SASL_README.html. + +20201011 + + Cleanup: save a copy of the postscreen_dnsbl_reply_map + lookup result. This has no effect when the recommended + texthash: look table is used, but it may avoid stale data + with other lookup tables. File: postscreen/postscreen_dnsbl.c. + +20201015 + + Documentation: simplified the recipient_delimiter + description. File: proto/postconf.proto. + +20201022 + + Bugfix (introduced: Postfix 2.2): after processing an + XCCLIENT command, the smtps service was waiting for a TLS + handshake. Found by Aki Tuomi. File: smtpd/smtpd.c. + +20201025 + + Feature: local_login_sender_maps to lock down the envelope + sender addresses that the postdrop command will accept. The + default is backwards compatible. Files: postdrop/postdrop.c, + global/mail_params.h, global/local_sender_login_match.[hc], + global/local_sender_login_match.in, + global/local_sender_login_match.ref, global/quote_822_local.c, + global/quote_822_local.in, global/quote_822_local.ref, + mantools/postlink, proto/postconf.proto. + + Bugfix (introduced: Postfix 2.3): static maps did not free + their casefolding buffer. File: util/dict_static.c. diff --git a/postfix/README_FILES/SASL_README b/postfix/README_FILES/SASL_README index 0c4248038..d9561d7f3 100644 --- a/postfix/README_FILES/SASL_README +++ b/postfix/README_FILES/SASL_README @@ -1058,9 +1058,9 @@ username/password information. standard "AUTH=mmeetthhoodd....." syntax in response to the EHLO command; this requires no additional Postfix client configuration. - * The Postfix SMTP client does not support the obsolete "wrappermode" - protocol, which uses TCP port 465 on the SMTP server. See TLS_README for a - solution that uses the stunnel command. + * With the setting "smtp_tls_wrappermode = yes", the Postfix SMTP client + supports the "wrappermode" protocol, which uses TCP port 465 on the SMTP + server (Postfix 3.0 and later). * With the smtp_sasl_password_maps parameter, we configure the Postfix SMTP client to send username and password information to the mail gateway diff --git a/postfix/README_FILES/SOHO_README b/postfix/README_FILES/SOHO_README index 722bece70..3804b9da2 100644 --- a/postfix/README_FILES/SOHO_README +++ b/postfix/README_FILES/SOHO_README @@ -200,9 +200,9 @@ username/password information. standard "AUTH=mmeetthhoodd....." syntax in response to the EHLO command; this requires no additional Postfix client configuration. - * The Postfix SMTP client does not support the obsolete "wrappermode" - protocol, which uses TCP port 465 on the SMTP server. See TLS_README for a - solution that uses the stunnel command. + * With the setting "smtp_tls_wrappermode = yes", the Postfix SMTP client + supports the "wrappermode" protocol, which uses TCP port 465 on the SMTP + server (Postfix 3.0 and later). * With the smtp_sasl_password_maps parameter, we configure the Postfix SMTP client to send username and password information to the mail gateway diff --git a/postfix/README_FILES/TLS_README b/postfix/README_FILES/TLS_README index 282ea2b64..864e7ae03 100644 --- a/postfix/README_FILES/TLS_README +++ b/postfix/README_FILES/TLS_README @@ -364,11 +364,11 @@ Example: /etc/postfix/main.cf: smtpd_tls_security_level = encrypt -TLS is sometimes used in the non-standard "wrapper" mode where a server always -uses TLS, instead of announcing STARTTLS support and waiting for remote SMTP -clients to request TLS service. Some clients, namely Outlook [Express] prefer -the "wrapper" mode. This is true for OE (Win32 < 5.0 and Win32 >=5.0 when run -on a port<>25 and OE (5.01 Mac on all ports). +TLS is also used in the "wrapper" mode where a server always uses TLS, instead +of announcing STARTTLS support and waiting for remote SMTP clients to request +TLS service. Some clients, namely Outlook [Express] prefer the "wrapper" mode. +This is true for OE (Win32 < 5.0 and Win32 >=5.0 when run on a port<>25 and OE +(5.01 Mac on all ports). It is strictly discouraged to use this mode from main.cf. If you want to support this service, enable a special port in master.cf and specify "- @@ -1932,8 +1932,8 @@ Example: CClliieenntt--ssiiddee SSMMTTPPSS ssuuppppoorrtt These sections show how to send mail to a server that does not support -STARTTLS, but that provides the deprecated SMTPS service on TCP port 465. -Depending on the Postfix version, some additional tooling may be required. +STARTTLS, but that provides the SMTPS service on TCP port 465. Depending on the +Postfix version, some additional tooling may be required. PPoossttffiixx >>== 33..00 diff --git a/postfix/WISHLIST b/postfix/WISHLIST index 36aef38ba..3ff40b112 100644 --- a/postfix/WISHLIST +++ b/postfix/WISHLIST @@ -2,6 +2,12 @@ Wish list: Does tlsproxy terminate to soon after 'postfix reload'? + Eliminate duplicate user_acl check from sendmail, and pass + the result through the postdrop-to-sendmail protocol. This + requires that postdrop reads all inputs before responding. + Then we can also consider to save input to dead.letter (drop + setgid privilege, use safe_open() to avoid clobbering files). + Understand what happens with DNSSEC related status fields in posttls-finger when resolv.conf points to a host that runs no DNS server. diff --git a/postfix/html/SASL_README.html b/postfix/html/SASL_README.html index df98b11f0..1f4bfdf4a 100644 --- a/postfix/html/SASL_README.html +++ b/postfix/html/SASL_README.html @@ -1697,10 +1697,9 @@ that use the non-standard "AUTH=method...." syntax in response to the EHLO command; this requires no additional Postfix client configuration.

-
  • The Postfix SMTP client does not support the obsolete -"wrappermode" protocol, which uses TCP port 465 on the -SMTP server. See TLS_README for a solution that uses the -stunnel command.

  • +
  • With the setting "smtp_tls_wrappermode = yes", the Postfix +SMTP client supports the "wrappermode" protocol, which uses TCP +port 465 on the SMTP server (Postfix 3.0 and later).

  • With the smtp_sasl_password_maps parameter, we configure the Postfix SMTP client to send username and password diff --git a/postfix/html/SOHO_README.html b/postfix/html/SOHO_README.html index 775d93e86..c3a7a10ae 100644 --- a/postfix/html/SOHO_README.html +++ b/postfix/html/SOHO_README.html @@ -288,10 +288,9 @@ that use the non-standard "AUTH=method...." syntax in response to the EHLO command; this requires no additional Postfix client configuration.

  • -
  • The Postfix SMTP client does not support the obsolete -"wrappermode" protocol, which uses TCP port 465 on the -SMTP server. See TLS_README for a solution that uses the -stunnel command.

  • +
  • With the setting "smtp_tls_wrappermode = yes", the Postfix +SMTP client supports the "wrappermode" protocol, which uses TCP +port 465 on the SMTP server (Postfix 3.0 and later).

  • With the smtp_sasl_password_maps parameter, we configure the Postfix SMTP client to send username and password diff --git a/postfix/html/TLS_README.html b/postfix/html/TLS_README.html index 7b12d2a1a..915beded9 100644 --- a/postfix/html/TLS_README.html +++ b/postfix/html/TLS_README.html @@ -540,7 +540,7 @@ by default and should only seldom be used.

    -

    TLS is sometimes used in the non-standard "wrapper" mode where +

    TLS is also used in the "wrapper" mode where a server always uses TLS, instead of announcing STARTTLS support and waiting for remote SMTP clients to request TLS service. Some clients, namely @@ -2520,7 +2520,7 @@ the TLS protocols used with opportunistic TLS.

    Client-side SMTPS support

    These sections show how to send mail to a server that does not -support STARTTLS, but that provides the deprecated SMTPS service +support STARTTLS, but that provides the SMTPS service on TCP port 465. Depending on the Postfix version, some additional tooling may be required.

    diff --git a/postfix/html/postconf.5.html b/postfix/html/postconf.5.html index c672fa4ef..1fa04137e 100644 --- a/postfix/html/postconf.5.html +++ b/postfix/html/postconf.5.html @@ -3137,6 +3137,19 @@ will be used instead of the null sender address.

    This feature is available in Postfix 2.7 and later.

    + + +
    empty_address_local_login_sender_maps_lookup_key +(default: <>)
    + +

    +The lookup key to be used in local_login_sender_maps tables, instead +of the null sender address. +

    + +

    This feature is available in Postfix 3.6 and later.

    + +
    empty_address_recipient @@ -5845,6 +5858,62 @@ system.

    + + +
    local_login_sender_maps +(default: static:*)
    + +

    A list of lookup tables that are searched by the UNIX login name, +and that return a list of allowed envelope sender patterns separated +by space or comma. These sender patterns are enforced by the Postfix +postdrop(1) command. The default is backwards-compatible: +every user may specify any envelope information.

    + +

    When no UNIX login name is available, the postdrop command will +prepend '#' to the numerical UID and use that instead.

    + +

    Before checking a sender address against local_login_sender_maps, +Postfix will strip an address extension based on the current +recipient_delimiter value. + +

    The following sender patterns are special; these cannot be used +as part of a longer pattern.

    + +
    + +
    *
    This pattern allows everything.
    + +
    <>
    This pattern allows the null sender +address. It is configured with the +empty_address_local_login_sender_maps_lookup_key configuration +parameter.
    + +
    @domain
    This pattern allows a sender +address when the '@' and domain part match.
    + +
    + +

    Examples:

    + +
    +/etc/postfix/main.cf:
    +    # Allow root and postfix full control, anyone else can only
    +    # send mail as themselves. Use # followed by the numerical UID
    +    # when the UID has no entry in the UNIX password file.
    +    local_login_sender_maps =
    +        inline:{ { root = *}, { postfix = * } },
    +        pcre:/etc/postfix/login_senders
    +
    + +
    +/etc/postfix/login_senders:
    +   # Allow both the bare username and the user@domain forms.
    +    /(.+)/ $1 $1@example.com/
    +
    + +

    This feature is available in Postfix 3.6 and later.

    + +
    local_recipient_maps @@ -9529,17 +9598,19 @@ Example:
    recipient_delimiter (default: empty)
    -

    The set of characters that can separate a user name from its -extension (example: user+foo), or a .forward file name from its -extension (example: .forward+foo). Basically, the software tries -user+foo and .forward+foo before trying user and .forward. This -implementation recognizes one delimiter character and one extension -per email address or .forward file name.

    +

    The set of characters that can separate an email address +localpart, user name, or a .forward file name from its extension. +For example, with "recipient_delimiter = +", the software tries +user+foo@example.com before trying user@example.com, user+foo before +trying user, and .forward+foo before trying .forward.

    -

    When the recipient_delimiter set contains multiple characters -(Postfix 2.11 and later), a user name or .forward file name is +

    More formally, an email address localpart or user name is separated from its extension by the first character that matches -the recipient_delimiter set.

    +the recipient_delimiter set. The delimiter character and extension +may then be used to generate an extended .forward file name. This +implementation recognizes one delimiter character and one extension +per email address localpart or email address. With Postfix 2.10 and +earler, the recipient_delimiter specifies a single character.

    See canonical(5), local(8), relocated(5) and virtual(5) for the effects of recipient_delimiter on lookups in aliases, canonical, diff --git a/postfix/html/postdrop.1.html b/postfix/html/postdrop.1.html index 463a3d396..ce25bfbdb 100644 --- a/postfix/html/postdrop.1.html +++ b/postfix/html/postdrop.1.html @@ -94,6 +94,21 @@ POSTDROP(1) POSTDROP(1) mail(1) command (and with the privileged postdrop(1) helper com- mand). + Available in Postfix version 3.6 and later: + + local_login_sender_maps (static:*) + A list of lookup tables that are searched by the UNIX login + name, and that return a list of allowed envelope sender patterns + separated by space or comma. + + empty_address_local_login_sender_maps_lookup_key (<>) + The lookup key to be used in local_login_sender_maps tables, + instead of the null sender address. + + recipient_delimiter (empty) + The set of characters that can separate an email address local- + part, user name, or a .forward file name from its extension. + FILES /var/spool/postfix/maildrop, maildrop queue diff --git a/postfix/html/smtpd.8.html b/postfix/html/smtpd.8.html index 0881ebee2..97c35179a 100644 --- a/postfix/html/smtpd.8.html +++ b/postfix/html/smtpd.8.html @@ -1291,25 +1291,24 @@ SMTPD(8) SMTPD(8) The location of the Postfix top-level queue directory. recipient_delimiter (empty) - The set of characters that can separate a user name from its - extension (example: user+foo), or a .forward file name from its - extension (example: .forward+foo). + The set of characters that can separate an email address local- + part, user name, or a .forward file name from its extension. smtpd_banner ($myhostname ESMTP $mail_name) - The text that follows the 220 status code in the SMTP greeting + The text that follows the 220 status code in the SMTP greeting banner. syslog_facility (mail) The syslog facility of Postfix logging. syslog_name (see 'postconf -d' output) - A prefix that is prepended to the process name in syslog + A prefix that is prepended to the process name in syslog records, so that, for example, "smtpd" becomes "prefix/smtpd". Available in Postfix version 2.2 and later: smtpd_forbidden_commands (CONNECT, GET, POST) - List of commands that cause the Postfix SMTP server to immedi- + List of commands that cause the Postfix SMTP server to immedi- ately terminate the session with a 221 code. Available in Postfix version 2.5 and later: @@ -1326,7 +1325,7 @@ SMTPD(8) SMTPD(8) Available in Postfix 3.4 and later: smtpd_reject_footer_maps (empty) - Lookup tables, indexed by the complete Postfix SMTP server 4xx + Lookup tables, indexed by the complete Postfix SMTP server 4xx or 5xx response, with reject footer templates. SEE ALSO diff --git a/postfix/man/man1/postdrop.1 b/postfix/man/man1/postdrop.1 index 10f638fd1..23d60124a 100644 --- a/postfix/man/man1/postdrop.1 +++ b/postfix/man/man1/postdrop.1 @@ -96,6 +96,18 @@ Available in Postfix version 2.2 and later: .IP "\fBauthorized_submit_users (static:anyone)\fR" List of users who are authorized to submit mail with the \fBsendmail\fR(1) command (and with the privileged \fBpostdrop\fR(1) helper command). +.PP +Available in Postfix version 3.6 and later: +.IP "\fBlocal_login_sender_maps (static:*)\fR" +A list of lookup tables that are searched by the UNIX login name, +and that return a list of allowed envelope sender patterns separated +by space or comma. +.IP "\fBempty_address_local_login_sender_maps_lookup_key (<>)\fR" +The lookup key to be used in local_login_sender_maps tables, instead +of the null sender address. +.IP "\fBrecipient_delimiter (empty)\fR" +The set of characters that can separate an email address +localpart, user name, or a .forward file name from its extension. .SH "FILES" .na .nf diff --git a/postfix/man/man5/postconf.5 b/postfix/man/man5/postconf.5 index 38394bdb3..6ef9b413b 100644 --- a/postfix/man/man5/postconf.5 +++ b/postfix/man/man5/postconf.5 @@ -1972,6 +1972,11 @@ The sender_dependent_default_transport_maps search string that will be used instead of the null sender address. .PP This feature is available in Postfix 2.7 and later. +.SH empty_address_local_login_sender_maps_lookup_key (default: <>) +The lookup key to be used in local_login_sender_maps tables, instead +of the null sender address. +.PP +This feature is available in Postfix 3.6 and later. .SH empty_address_recipient (default: MAILER\-DAEMON) The recipient of mail addressed to the null address. Postfix does not accept such addresses in SMTP commands, but they may still be @@ -3537,6 +3542,64 @@ local_header_rewrite_clients = permit_mynetworks, .ad .ft R .in -4 +.SH local_login_sender_maps (default: static:*) +A list of lookup tables that are searched by the UNIX login name, +and that return a list of allowed envelope sender patterns separated +by space or comma. These sender patterns are enforced by the Postfix +\fBpostdrop\fR(1) command. The default is backwards\-compatible: +every user may specify any envelope information. +.PP +When no UNIX login name is available, the postdrop command will +prepend '#' to the numerical UID and use that instead. +.PP +Before checking a sender address against local_login_sender_maps, +Postfix will strip an address extension based on the current +recipient_delimiter value. +.PP +The following sender patterns are special; these cannot be used +as part of a longer pattern. +.IP "\fB * \fR +This pattern allows everything. +.br +.IP "\fB <> \fR" +This pattern allows the null sender +address. It is configured with the +empty_address_local_login_sender_maps_lookup_key configuration +parameter. +.br +.IP "\fB @\fIdomain\fR\fR" +This pattern allows a sender +address when the '@' and \fIdomain\fR part match. +.br +.br +.PP +Examples: +.PP +.nf +.na +.ft C +/etc/postfix/main.cf: + # Allow root and postfix full control, anyone else can only + # send mail as themselves. Use # followed by the numerical UID + # when the UID has no entry in the UNIX password file. + local_login_sender_maps = + inline:{ { root = *}, { postfix = * } }, + pcre:/etc/postfix/login_senders +.fi +.ad +.ft R +.PP +.nf +.na +.ft C +/etc/postfix/login_senders: + # Allow both the bare username and the user@domain forms. + /(.+)/ $1 $1@example.com/ +.fi +.ad +.ft R +.PP +This feature is available in Postfix 3.6 and later. .SH local_recipient_maps (default: proxy:unix:passwd.byname $alias_maps) Lookup tables with all names or addresses of local recipients: a recipient address is local when its domain matches $mydestination, @@ -5886,17 +5949,19 @@ recipient_canonical_maps = hash:/etc/postfix/recipient_canonical .ad .ft R .SH recipient_delimiter (default: empty) -The set of characters that can separate a user name from its -extension (example: user+foo), or a .forward file name from its -extension (example: .forward+foo). Basically, the software tries -user+foo and .forward+foo before trying user and .forward. This -implementation recognizes one delimiter character and one extension -per email address or .forward file name. +The set of characters that can separate an email address +localpart, user name, or a .forward file name from its extension. +For example, with "recipient_delimiter = +", the software tries +user+foo@example.com before trying user@example.com, user+foo before +trying user, and .forward+foo before trying .forward. .PP -When the recipient_delimiter set contains multiple characters -(Postfix 2.11 and later), a user name or .forward file name is +More formally, an email address localpart or user name is separated from its extension by the first character that matches -the recipient_delimiter set. +the recipient_delimiter set. The delimiter character and extension +may then be used to generate an extended .forward file name. This +implementation recognizes one delimiter character and one extension +per email address localpart or email address. With Postfix 2.10 and +earler, the recipient_delimiter specifies a single character. .PP See \fBcanonical\fR(5), \fBlocal\fR(8), \fBrelocated\fR(5) and \fBvirtual\fR(5) for the effects of recipient_delimiter on lookups in aliases, canonical, diff --git a/postfix/man/man8/smtpd.8 b/postfix/man/man8/smtpd.8 index 299bf33da..547d947f0 100644 --- a/postfix/man/man8/smtpd.8 +++ b/postfix/man/man8/smtpd.8 @@ -1120,9 +1120,8 @@ The process name of a Postfix command or daemon process. .IP "\fBqueue_directory (see 'postconf -d' output)\fR" The location of the Postfix top\-level queue directory. .IP "\fBrecipient_delimiter (empty)\fR" -The set of characters that can separate a user name from its -extension (example: user+foo), or a .forward file name from its -extension (example: .forward+foo). +The set of characters that can separate an email address +localpart, user name, or a .forward file name from its extension. .IP "\fBsmtpd_banner ($myhostname ESMTP $mail_name)\fR" The text that follows the 220 status code in the SMTP greeting banner. diff --git a/postfix/mantools/postlink b/postfix/mantools/postlink index 556b4cde7..3eee53bd5 100755 --- a/postfix/mantools/postlink +++ b/postfix/mantools/postlink @@ -1130,6 +1130,8 @@ while (<>) { s;\bmail[-]*\n*[ ]*log_file_rotate_suffix\b;$&;g; s;\bpostlog_service_name\b;$&;g; s;\bpostlogd_watchdog_timeout\b;$&;g; + s;\blocal_login_sender_maps\b;$&;g; + s;\bempty_address_local_login_sender_maps_lookup_key\b;$&;g; # Service-defined parameters... diff --git a/postfix/proto/SASL_README.html b/postfix/proto/SASL_README.html index 90284b921..404c2c978 100644 --- a/postfix/proto/SASL_README.html +++ b/postfix/proto/SASL_README.html @@ -1697,10 +1697,9 @@ that use the non-standard "AUTH=method...." syntax in response to the EHLO command; this requires no additional Postfix client configuration.

  • -
  • The Postfix SMTP client does not support the obsolete -"wrappermode" protocol, which uses TCP port 465 on the -SMTP server. See TLS_README for a solution that uses the -stunnel command.

  • +
  • With the setting "smtp_tls_wrappermode = yes", the Postfix +SMTP client supports the "wrappermode" protocol, which uses TCP +port 465 on the SMTP server (Postfix 3.0 and later).

  • With the smtp_sasl_password_maps parameter, we configure the Postfix SMTP client to send username and password diff --git a/postfix/proto/TLS_README.html b/postfix/proto/TLS_README.html index fbea1a94d..badd59ad1 100644 --- a/postfix/proto/TLS_README.html +++ b/postfix/proto/TLS_README.html @@ -540,7 +540,7 @@ by default and should only seldom be used.

    -

    TLS is sometimes used in the non-standard "wrapper" mode where +

    TLS is also used in the "wrapper" mode where a server always uses TLS, instead of announcing STARTTLS support and waiting for remote SMTP clients to request TLS service. Some clients, namely @@ -2520,7 +2520,7 @@ the TLS protocols used with opportunistic TLS.

    Client-side SMTPS support

    These sections show how to send mail to a server that does not -support STARTTLS, but that provides the deprecated SMTPS service +support STARTTLS, but that provides the SMTPS service on TCP port 465. Depending on the Postfix version, some additional tooling may be required.

    diff --git a/postfix/proto/postconf.proto b/postfix/proto/postconf.proto index 81cdcad6a..62c0abb8f 100644 --- a/postfix/proto/postconf.proto +++ b/postfix/proto/postconf.proto @@ -3632,17 +3632,19 @@ recipient_canonical_maps = hash:/etc/postfix/recipient_canonical %PARAM recipient_delimiter -

    The set of characters that can separate a user name from its -extension (example: user+foo), or a .forward file name from its -extension (example: .forward+foo). Basically, the software tries -user+foo and .forward+foo before trying user and .forward. This -implementation recognizes one delimiter character and one extension -per email address or .forward file name.

    +

    The set of characters that can separate an email address +localpart, user name, or a .forward file name from its extension. +For example, with "recipient_delimiter = +", the software tries +user+foo@example.com before trying user@example.com, user+foo before +trying user, and .forward+foo before trying .forward.

    -

    When the recipient_delimiter set contains multiple characters -(Postfix 2.11 and later), a user name or .forward file name is +

    More formally, an email address localpart or user name is separated from its extension by the first character that matches -the recipient_delimiter set.

    +the recipient_delimiter set. The delimiter character and extension +may then be used to generate an extended .forward file name. This +implementation recognizes one delimiter character and one extension +per email address localpart or email address. With Postfix 2.10 and +earler, the recipient_delimiter specifies a single character.

    See canonical(5), local(8), relocated(5) and virtual(5) for the effects of recipient_delimiter on lookups in aliases, canonical, @@ -17897,3 +17899,64 @@ reachable, specify a different probe, or specify an empty dnssec_probe value to disable the feature.

    This feature is available in Postfix 3.6 and later.

    + +%PARAM local_login_sender_maps static:* + +

    A list of lookup tables that are searched by the UNIX login name, +and that return a list of allowed envelope sender patterns separated +by space or comma. These sender patterns are enforced by the Postfix +postdrop(1) command. The default is backwards-compatible: +every user may specify any envelope information.

    + +

    When no UNIX login name is available, the postdrop command will +prepend '#' to the numerical UID and use that instead.

    + +

    Before checking a sender address against local_login_sender_maps, +Postfix will strip an address extension based on the current +recipient_delimiter value. + +

    The following sender patterns are special; these cannot be used +as part of a longer pattern.

    + +
    + +
    *
    This pattern allows everything.
    + +
    <>
    This pattern allows the null sender +address. It is configured with the +empty_address_local_login_sender_maps_lookup_key configuration +parameter.
    + +
    @domain
    This pattern allows a sender +address when the '@' and domain part match.
    + +
    + +

    Examples:

    + +
    +/etc/postfix/main.cf:
    +    # Allow root and postfix full control, anyone else can only
    +    # send mail as themselves. Use # followed by the numerical UID
    +    # when the UID has no entry in the UNIX password file.
    +    local_login_sender_maps = 
    +	inline:{ { root = *}, { postfix = * } },
    +	pcre:/etc/postfix/login_senders
    +
    + +
    +/etc/postfix/login_senders:
    +   # Allow both the bare username and the user@domain forms.
    +    /(.+)/ $1 $1@example.com/
    +
    + +

    This feature is available in Postfix 3.6 and later.

    + +%PARAM empty_address_local_login_sender_maps_lookup_key <> + +

    +The lookup key to be used in local_login_sender_maps tables, instead +of the null sender address. +

    + +

    This feature is available in Postfix 3.6 and later.

    diff --git a/postfix/src/global/Makefile.in b/postfix/src/global/Makefile.in index db43f845b..f84aa4f9b 100644 --- a/postfix/src/global/Makefile.in +++ b/postfix/src/global/Makefile.in @@ -36,7 +36,7 @@ SRCS = abounce.c anvil_clnt.c been_here.c bounce.c bounce_log.c \ smtputf8.c mail_conf_over.c mail_parm_split.c midna_adomain.c \ mail_addr_form.c quote_flags.c maillog_client.c \ normalize_mailhost_addr.c map_search.c reject_deliver_request.c \ - info_log_addr_form.c sasl_mech_filter.c + info_log_addr_form.c sasl_mech_filter.c login_sender_match.c OBJS = abounce.o anvil_clnt.o been_here.o bounce.o bounce_log.o \ canon_addr.o cfg_parser.o cleanup_strerror.o cleanup_strflags.o \ clnt_stream.o conv_time.o db_common.o debug_peer.o debug_process.o \ @@ -74,7 +74,7 @@ OBJS = abounce.o anvil_clnt.o been_here.o bounce.o bounce_log.o \ smtputf8.o attr_override.o mail_parm_split.o midna_adomain.o \ $(NON_PLUGIN_MAP_OBJ) mail_addr_form.o quote_flags.o maillog_client.o \ normalize_mailhost_addr.o map_search.o reject_deliver_request.o \ - info_log_addr_form.o sasl_mech_filter.o + info_log_addr_form.o sasl_mech_filter.o login_sender_match.o # MAP_OBJ is for maps that may be dynamically loaded with dynamicmaps.cf. # When hard-linking these maps, makedefs sets NON_PLUGIN_MAP_OBJ=$(MAP_OBJ), # otherwise it sets the PLUGIN_* macros. @@ -109,7 +109,7 @@ HDRS = abounce.h anvil_clnt.h been_here.h bounce.h bounce_log.h \ haproxy_srvr.h dsn_filter.h dynamicmaps.h uxtext.h smtputf8.h \ attr_override.h mail_parm_split.h midna_adomain.h mail_addr_form.h \ maillog_client.h normalize_mailhost_addr.h map_search.h \ - info_log_addr_form.h sasl_mech_filter.h + info_log_addr_form.h sasl_mech_filter.h login_sender_match.h TESTSRC = rec2stream.c stream2rec.c recdump.c DEFS = -I. -I$(INC_DIR) -D$(SYSTYPE) CFLAGS = $(DEBUG) $(OPT) $(DEFS) @@ -125,7 +125,7 @@ TESTPROG= domain_list dot_lockfile mail_addr_crunch mail_addr_find \ data_redirect addr_match_list safe_ultostr verify_sender_addr \ mail_version mail_dict server_acl uxtext mail_parm_split \ fold_addr smtp_reply_footer mail_addr_map normalize_mailhost_addr \ - haproxy_srvr map_search delivered_hdr + haproxy_srvr map_search delivered_hdr login_sender_match LIBS = ../../lib/lib$(LIB_PREFIX)util$(LIB_SUFFIX) LIB_DIR = ../../lib @@ -396,6 +396,9 @@ map_search: map_search.c $(LIB) $(LIBS) delivered_hdr: delivered_hdr.c $(LIB) $(LIBS) $(CC) $(CFLAGS) -DTEST -o $@ $@.c $(LIB) $(LIBS) $(SYSLIBS) +login_sender_match: login_sender_match.c $(LIB) $(LIBS) + $(CC) $(CFLAGS) -DTEST -o $@ $@.c $(LIB) $(LIBS) $(SYSLIBS) + tests: tok822_test mime_tests strip_addr_test tok822_limit_test \ xtext_test scache_multi_test ehlo_mask_test \ namadr_list_test mail_conf_time_test header_body_checks_tests \ @@ -404,7 +407,7 @@ tests: tok822_test mime_tests strip_addr_test tok822_limit_test \ smtp_reply_footer_test off_cvt_test mail_addr_crunch_test \ mail_addr_find_test mail_addr_map_test quote_822_local_test \ normalize_mailhost_addr_test haproxy_srvr_test map_search_test \ - delivered_hdr_test + delivered_hdr_test login_sender_match_test mime_tests: mime_test mime_nest mime_8bit mime_dom mime_trunc mime_cvt \ mime_cvt2 mime_cvt3 mime_garb1 mime_garb2 mime_garb3 mime_garb4 @@ -737,6 +740,11 @@ delivered_hdr_test: update delivered_hdr delivered_hdr.ref diff delivered_hdr.ref delivered_hdr.tmp rm -f delivered_hdr.tmp +login_sender_match_test: update login_sender_match login_sender_match.ref + -$(SHLIB_ENV) $(VALGRIND) ./login_sender_match >login_sender_match.tmp 2>&1 + diff login_sender_match.ref login_sender_match.tmp + rm -f login_sender_match.tmp + printfck: $(OBJS) $(PROG) rm -rf printfck mkdir printfck @@ -1520,6 +1528,24 @@ log_adhoc.o: log_adhoc.h log_adhoc.o: mail_params.h log_adhoc.o: msg_stats.h log_adhoc.o: recipient_list.h +login_sender_match.o: ../../include/argv.h +login_sender_match.o: ../../include/check_arg.h +login_sender_match.o: ../../include/dict.h +login_sender_match.o: ../../include/msg.h +login_sender_match.o: ../../include/myflock.h +login_sender_match.o: ../../include/mymalloc.h +login_sender_match.o: ../../include/stringops.h +login_sender_match.o: ../../include/sys_defs.h +login_sender_match.o: ../../include/vbuf.h +login_sender_match.o: ../../include/vstream.h +login_sender_match.o: ../../include/vstring.h +login_sender_match.o: login_sender_match.c +login_sender_match.o: login_sender_match.h +login_sender_match.o: mail_params.h +login_sender_match.o: maps.h +login_sender_match.o: quote_822_local.h +login_sender_match.o: quote_flags.h +login_sender_match.o: strip_addr.h mail_addr.o: ../../include/check_arg.h mail_addr.o: ../../include/stringops.h mail_addr.o: ../../include/sys_defs.h diff --git a/postfix/src/global/cleanup_strerror.c b/postfix/src/global/cleanup_strerror.c index ce0bb40d0..7e3dfe5d9 100644 --- a/postfix/src/global/cleanup_strerror.c +++ b/postfix/src/global/cleanup_strerror.c @@ -67,6 +67,7 @@ static const CLEANUP_STAT_DETAIL cleanup_stat_map[] = { CLEANUP_STAT_SIZE, 552, "5.3.4", "message file too big", CLEANUP_STAT_CONT, 550, "5.7.1", "message content rejected", CLEANUP_STAT_WRITE, 451, "4.3.0", "queue file write error", + CLEANUP_STAT_NOPERM, 550, "5.7.1", "service denied", }; static CLEANUP_STAT_DETAIL cleanup_stat_success = { diff --git a/postfix/src/global/cleanup_user.h b/postfix/src/global/cleanup_user.h index a4de82a65..3ad4c1b1c 100644 --- a/postfix/src/global/cleanup_user.h +++ b/postfix/src/global/cleanup_user.h @@ -62,6 +62,7 @@ #define CLEANUP_STAT_RCPT (1<<6) /* No recipients found */ #define CLEANUP_STAT_PROXY (1<<7) /* Proxy reject */ #define CLEANUP_STAT_DEFER (1<<8) /* Temporary reject */ +#define CLEANUP_STAT_NOPERM (1<<9) /* Denied by non-content policy */ /* * These are set when we can't bounce even if we were asked to. diff --git a/postfix/src/global/login_sender_match.c b/postfix/src/global/login_sender_match.c new file mode 100644 index 000000000..58f66c599 --- /dev/null +++ b/postfix/src/global/login_sender_match.c @@ -0,0 +1,342 @@ +/*++ +/* NAME +/* login_sender_match 3 +/* SUMMARY +/* match login and sender against (login, sender) patterns +/* SYNOPSIS +/* #include +/* +/* typedef LOGIN_SENDER_MATCH LOGIN_SENDER_MATCH; +/* +/* LOGIN_SENDER_MATCH *login_sender_create( +/* const char *title, +/* const char *map_names, +/* const char *ext_delimiters, +/* const char *null_sender, +/* const char *wildcard) +/* +/* void login_sender_free( +/* LOGIN_SENDER_MATCH *lsm) +/* +/* int login_sender_match( +/* LOGIN_SENDER_MATCH *lsm, +/* const char *login_name, +/* const char *sender_addr) +/* DESCRIPTION +/* This module determines if a login name and internal-form +/* sender address match a (login name, external-form sender +/* patterns) table entry. A login name matches if it matches +/* a lookup table key. A sender address matches the corresponding +/* table entry if it matches a sender pattern. A wildcard +/* sender pattern matches any sender address. A sender pattern +/* that starts with '@' matches the '@' and the domain portion +/* of a sender address. Otherwise, the matcher ignores the +/* extension part of a sender address, and requires a +/* case-insensitive match against a sender pattern. +/* +/* login_sender_create() creates a (login name, sender patterns) +/* matcher. +/* +/* login_sender_free() destroys the specified (login name, +/* sender patterns) matcher. +/* +/* login_sender_match() looks up an entry for the \fBlogin_name\fR +/* argument, and determines if the lookup result matches the +/* \fBsender_adddr\fR argument. +/* +/* Arguments: +/* .IP title +/* The name of the configuration parameter that specifies the +/* map_names value, used for error messages. +/* .IP map_names +r* The lookup table(s) with (login name, sender patterns) entries. +/* .IP ext_delimiters +/* The set of address extension delimiters. +/* .IP null_sender +/* If a sender pattern equals the null_sender pattern, then +/* the empty address is matched. +/* .IP wildcard +/* Null pointer, or non-empty string with a wildcard pattern. +/* If a sender pattern equals the wildcard pattern, then any +/* sender address is matched. +/* .IP login_name +/* The login name (for example, UNIX account, or SASL username) +/* that will be used as a search key to locate a list of senders. +/* .IP sender_addr +/* The sender email address (unquoted form) that will be matched +/* against a (login name, sender patterns) table entry. +/* DIAGNOSTICS +/* login_sender_match() returns LSM_STAT_FOUND if a +/* match was found, LOGIN_STAT_NOTFOUND if no match was found, +/* LSM_STAT_RETRY if the table lookup failed, or +/* LSM_STAT_CONFIG in case of a configuration error. +/* LICENSE +/* .ad +/* .fi +/* The Secure Mailer license must be distributed with this software. +/* AUTHOR(S) +/* Wietse Venema +/* Google, Inc. +/* 111 8th Avenue +/* New York, NY 10011, USA +/*--*/ + + /* + * System library. + */ +#include +#include + + /* + * Utility library. + */ +#include +#include +#include +#include + + /* + * Global library. + */ +#include +#include +#include +#include +#include + + /* + * Private data structure. + */ +struct LOGIN_SENDER_MATCH { + MAPS *maps; + VSTRING *ext_stripped_sender; + char *ext_delimiters; + char *null_sender; + char *wildcard; +}; + + /* + * SLMs. + */ +#define STR(x) vstring_str(x) + +/* login_sender_create - create (login name, sender patterns) matcher */ + +LOGIN_SENDER_MATCH *login_sender_create(const char *title, + const char *map_names, + const char *ext_delimiters, + const char *null_sender, + const char *wildcard) +{ + LOGIN_SENDER_MATCH *lsm = mymalloc(sizeof *lsm); + + lsm->maps = maps_create(title, map_names, DICT_FLAG_LOCK + | DICT_FLAG_FOLD_FIX | DICT_FLAG_UTF8_REQUEST); + lsm->ext_stripped_sender = vstring_alloc(100); + lsm->ext_delimiters = mystrdup(ext_delimiters); + if (null_sender == 0 || *null_sender == 0) + msg_panic("login_sender_create: null or empty null_sender"); + lsm->null_sender = mystrdup(null_sender); + lsm->wildcard = (wildcard && *wildcard) ? mystrdup(wildcard) : 0; + return (lsm); +} + +/* login_sender_free - destroy (login name, sender patterns) matcher */ + +void login_sender_free(LOGIN_SENDER_MATCH *lsm) +{ + maps_free(lsm->maps); + vstring_free(lsm->ext_stripped_sender); + myfree(lsm->ext_delimiters); + myfree(lsm->null_sender); + if (lsm->wildcard) + myfree(lsm->wildcard); + myfree((void *) lsm); +} + +/* strip_externalize_addr - strip address extension and externalize remainder */ + +static VSTRING *strip_externalize_addr(VSTRING *ext_addr, const char *int_addr, + const char *delims) +{ + char *int_stripped_addr; + + if ((int_stripped_addr = strip_addr_internal(int_addr, + /* extension= */ (char **) 0, + delims)) != 0) { + quote_822_local(ext_addr, int_stripped_addr); + myfree(int_stripped_addr); + return (ext_addr); + } else { + return quote_822_local(ext_addr, int_addr); + } +} + +/* login_sender_match - match login and sender against (login, senders) table */ + +int login_sender_match(LOGIN_SENDER_MATCH *lsm, const char *login_name, + const char *sender_addr) +{ + int found_or_error = LSM_STAT_NOTFOUND; + + /* Sender patterns and derived info */ + const char *sender_patterns; + char *saved_sender_patterns; + char *cp; + char *sender_pattern; + + /* Actual sender and derived info */ + const char *ext_stripped_sender = 0; + const char *at_sender_domain; + + /* + * Match the login. + */ + if ((sender_patterns = maps_find(lsm->maps, login_name, + /* flags= */ 0)) != 0) { + + /* + * Match the sender. TODO: don't break a sender pattern on a + * comma/space inside a quoted localpart. + */ + cp = saved_sender_patterns = mystrdup(sender_patterns); + while (found_or_error == LSM_STAT_NOTFOUND + && (sender_pattern = mystrtok(&cp, CHARS_COMMA_SP)) != 0) { + /* Special pattern: @domain. */ + if (*sender_pattern == '@') { + if ((at_sender_domain = strrchr(sender_addr, '@')) != 0 + && strcasecmp_utf8(sender_pattern, at_sender_domain) == 0) + found_or_error = LSM_STAT_FOUND; + } + /* Special pattern: wildcard. */ + else if (strcasecmp(sender_pattern, lsm->wildcard) == 0) { + found_or_error = LSM_STAT_FOUND; + } + /* Special pattern: empty sender. */ + else if (strcasecmp(sender_pattern, lsm->null_sender) == 0) { + if (*sender_addr == 0) + found_or_error = LSM_STAT_FOUND; + } + /* Literal pattern: match the stripped and externalized sender. */ + if (ext_stripped_sender == 0) + ext_stripped_sender = + STR(strip_externalize_addr(lsm->ext_stripped_sender, + sender_addr, + lsm->ext_delimiters)); + if (strcasecmp_utf8(sender_pattern, ext_stripped_sender) == 0) + found_or_error = LSM_STAT_FOUND; + } + myfree(saved_sender_patterns); + } else { + found_or_error = lsm->maps->error; + } + return (found_or_error); +} + +#ifdef TEST + +int main(int argc, char **argv) +{ + struct testcase { + const char *title; + const char *map_names; + const char *ext_delimiters; + const char *null_sender; + const char *wildcard; + const char *login_name; + const char *sender_addr; + int exp_return; + }; + struct testcase testcases[] = { + {"wildcard works", + "inline:{root=*, {foo = foo,foo@example.com}, bar=<>}", + "+-", "<>", "*", "root", "anything", LSM_STAT_FOUND + }, + {"unknown user", + "inline:{root=*, {foo = foo,foo@example.com}, bar=<>}", + "+-", "<>", "*", "toor", "anything", LSM_STAT_NOTFOUND + }, + {"bare user", + "inline:{root=*, {foo = foo,foo@example.com}, bar=<>}", + "+-", "<>", "*", "foo", "foo", LSM_STAT_FOUND + }, + {"user@domain", + "inline:{root=*, {foo = foo,foo@example.com}, bar=<>}", + "+-", "<>", "*", "foo", "foo@example.com", LSM_STAT_FOUND + }, + {"user+ext@domain", + "inline:{root=*, {foo = foo,foo@example.com}, bar=<>}", + "+-", "<>", "*", "foo", "foo+bar@example.com", LSM_STAT_FOUND + }, + {"wrong sender", + "inline:{root=*, {foo = foo,foo@example.com}, bar=<>}", + "+-", "<>", "*", "foo", "bar@example.com", LSM_STAT_NOTFOUND + }, + {"@domain", + "inline:{root=*, {foo = @example.com}, bar=<>}", + "+-", "<>", "*", "foo", "anyone@example.com", LSM_STAT_FOUND + }, + {"wrong @domain", + "inline:{root=*, {foo = @example.com}, bar=<>}", + "+-", "<>", "*", "foo", "anyone@example.org", LSM_STAT_NOTFOUND + }, + {"null sender", + "inline:{root=*, {foo = foo,foo@example.com}, bar=<>}", + "+-", "<>", "*", "bar", "", LSM_STAT_FOUND + }, + {"wrong null sender", + "inline:{root=*, {foo = foo,foo@example.com}, bar=<>}", + "+-", "<>", "*", "baz", "", LSM_STAT_NOTFOUND + }, + {"error", + "inline:{root=*}, fail:sorry", + "+-", "<>", "*", "baz", "whatever", LSM_STAT_RETRY + }, + {"no error", + "inline:{root=*}, fail:sorry", + "+-", "<>", "*", "root", "whatever", LSM_STAT_FOUND + }, + }; + struct testcase *tp; + int act_return; + int pass; + int fail; + LOGIN_SENDER_MATCH *lsm; + + /* + * Fake variable settings. + */ + var_double_bounce_sender = DEF_DOUBLE_BOUNCE; + var_ownreq_special = DEF_OWNREQ_SPECIAL; + +#define NUM_TESTS sizeof(testcases)/sizeof(testcases[0]) + + for (pass = fail = 0, tp = testcases; tp < testcases + NUM_TESTS; tp++) { + msg_info("RUN test case %ld %s", (long) (tp - testcases), tp->title); +#if 0 + msg_info("title=%s", tp->title); + msg_info("map_names=%s", tp->map_names); + msg_info("ext_delimiters=%s", tp->ext_delimiters); + msg_info("null_sender=%s", tp->null_sender); + msg_info("wildcard=%s", tp->wildcard); + msg_info("login_name=%s", tp->login_name); + msg_info("sender_addr=%s", tp->sender_addr); + msg_info("exp_return=%d", tp->exp_return); +#endif + lsm = login_sender_create("test map", tp->map_names, + tp->ext_delimiters, tp->null_sender, + tp->wildcard); + act_return = login_sender_match(lsm, tp->login_name, tp->sender_addr); + if (act_return == tp->exp_return) { + msg_info("PASS test %ld", (long) (tp - testcases)); + pass++; + } else { + msg_info("FAIL test %ld", (long) (tp - testcases)); + fail++; + } + login_sender_free(lsm); + } + return (fail > 0); +} + +#endif /* TEST */ diff --git a/postfix/src/global/login_sender_match.h b/postfix/src/global/login_sender_match.h new file mode 100644 index 000000000..eec0ba91d --- /dev/null +++ b/postfix/src/global/login_sender_match.h @@ -0,0 +1,49 @@ +#ifndef _LOGIN_SENDER_MATCH_H_INCLUDED_ +#define _LOGIN_SENDER_MATCH_H_INCLUDED_ + +/*++ +/* NAME +/* login_sender_match 3h +/* SUMMARY +/* oracle for per-login allowed sender addresses +/* SYNOPSIS +/* #include +/* DESCRIPTION +/* .nf + + /* + * Utility library. + */ +#include + + /* + * External interface. + */ +typedef struct LOGIN_SENDER_MATCH LOGIN_SENDER_MATCH; + +extern LOGIN_SENDER_MATCH *login_sender_create(const char *title, + const char *map_names, + const char *ext_delimiters, + const char *null_sender, + const char *wildcard); +extern void login_sender_free(LOGIN_SENDER_MATCH *lsm); +extern int login_sender_match(LOGIN_SENDER_MATCH *lsm, const char *login_name, + const char *sender_addr); + +#define LSM_STAT_FOUND (1) +#define LSM_STAT_NOTFOUND (0) +#define LSM_STAT_RETRY (DICT_ERR_RETRY) +#define LSM_STAT_CONFIG (DICT_ERR_CONFIG) + +/* LICENSE +/* .ad +/* .fi +/* The Secure Mailer license must be distributed with this software. +/* AUTHOR(S) +/* Wietse Venema +/* Google, Inc. +/* 111 8th Avenue +/* New York, NY 10011, USA +/*--*/ + +#endif /* _LOGIN_SENDER_MATCH_H_INCLUDED_ */ diff --git a/postfix/src/global/login_sender_match.ref b/postfix/src/global/login_sender_match.ref new file mode 100644 index 000000000..35b488bb2 --- /dev/null +++ b/postfix/src/global/login_sender_match.ref @@ -0,0 +1,25 @@ +unknown: RUN test case 0 wildcard works +unknown: PASS test 0 +unknown: RUN test case 1 unknown user +unknown: PASS test 1 +unknown: RUN test case 2 bare user +unknown: PASS test 2 +unknown: RUN test case 3 user@domain +unknown: PASS test 3 +unknown: RUN test case 4 user+ext@domain +unknown: PASS test 4 +unknown: RUN test case 5 wrong sender +unknown: PASS test 5 +unknown: RUN test case 6 @domain +unknown: PASS test 6 +unknown: RUN test case 7 wrong @domain +unknown: PASS test 7 +unknown: RUN test case 8 null sender +unknown: PASS test 8 +unknown: RUN test case 9 wrong null sender +unknown: PASS test 9 +unknown: RUN test case 10 error +unknown: warning: fail:sorry lookup error for "baz" +unknown: PASS test 10 +unknown: RUN test case 11 no error +unknown: PASS test 11 diff --git a/postfix/src/global/mail_params.h b/postfix/src/global/mail_params.h index e41bffab4..12499f53b 100644 --- a/postfix/src/global/mail_params.h +++ b/postfix/src/global/mail_params.h @@ -125,6 +125,17 @@ extern char *var_showq_acl; #define DEF_SUBMIT_ACL STATIC_ANYONE_ACL extern char *var_submit_acl; + /* + * Local submission, envelope sender ownership. + */ +#define VAR_LOCAL_LOGIN_SND_MAPS "local_login_sender_maps" +#define DEF_LOCAL_LOGIN_SND_MAPS "static:*" +extern char *var_local_login_snd__maps; + +#define VAR_NULL_LOCAL_LOGIN_SND_MAPS_KEY "empty_address_local_login_sender_maps_lookup_key" +#define DEF_NULL_LOCAL_LOGIN_SND_MAPS_KEY "<>" +extern char *var_null_local_login_snd_maps_key; + /* * What goes on the right-hand side of addresses of mail sent from this * machine. diff --git a/postfix/src/global/mail_stream.c b/postfix/src/global/mail_stream.c index 90a1ee084..46cc87e45 100644 --- a/postfix/src/global/mail_stream.c +++ b/postfix/src/global/mail_stream.c @@ -155,7 +155,8 @@ static VSTRING *id_buf; void mail_stream_cleanup(MAIL_STREAM *info) { - FREE_AND_WIPE(info->close, info->stream); + if (info->stream && info->close(info->stream)) + msg_warn("mail_stream_cleanup: close error"); FREE_AND_WIPE(myfree, info->queue); FREE_AND_WIPE(myfree, info->id); FREE_AND_WIPE(myfree, info->class); diff --git a/postfix/src/global/mail_version.h b/postfix/src/global/mail_version.h index d0b5da56a..8269e7ce7 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 "20201003" +#define MAIL_RELEASE_DATE "20201025" #define MAIL_VERSION_NUMBER "3.6" #ifdef SNAPSHOT diff --git a/postfix/src/global/quote_822_local.c b/postfix/src/global/quote_822_local.c index c16db66c0..541e4f721 100644 --- a/postfix/src/global/quote_822_local.c +++ b/postfix/src/global/quote_822_local.c @@ -230,7 +230,8 @@ VSTRING *unquote_822_local(VSTRING *dst, const char *mbox) /* * Proof-of-concept test program. Read an unquoted address from stdin, and - * show the quoted and unquoted results. + * show the quoted and unquoted results. Specify <> to test behavior for an + * empty unquoted adress. */ #include #include @@ -258,7 +259,11 @@ int main(int unused_argc, char **argv) bp++; if (*bp == 0) { msg_warn("missing argument"); - } else if (strcmp(cmd, "quote") == 0) { + continue; + } + if (strcmp(bp, "<>") == 0) + bp = ""; + if (strcmp(cmd, "quote") == 0) { quote_822_local(out, bp); vstream_printf("'%s' quoted '%s'\n", bp, STR(out)); } else if (strcmp(cmd, "quote_with_flags") == 0) { diff --git a/postfix/src/global/quote_822_local.in b/postfix/src/global/quote_822_local.in index 385f4d855..fc811bfc3 100644 --- a/postfix/src/global/quote_822_local.in +++ b/postfix/src/global/quote_822_local.in @@ -3,3 +3,4 @@ quote_with_flags 8bitclean|bare_localpart a@b@c@d unquote "a@b@c"@d unquote "a@b@c" unquote "a@b@c"@d@e +quote <> diff --git a/postfix/src/global/quote_822_local.ref b/postfix/src/global/quote_822_local.ref index ec7591751..3b0fba3c6 100644 --- a/postfix/src/global/quote_822_local.ref +++ b/postfix/src/global/quote_822_local.ref @@ -3,3 +3,4 @@ '"a@b@c"@d' unquoted 'a@b@c@d' '"a@b@c"' unquoted 'a@b@c' '"a@b@c"@d@e' unquoted 'a@b@c@d@e' +'' quoted '""' diff --git a/postfix/src/oqmgr/qmgr_deliver.c b/postfix/src/oqmgr/qmgr_deliver.c index 16fbc9e2a..7a1c8eac3 100644 --- a/postfix/src/oqmgr/qmgr_deliver.c +++ b/postfix/src/oqmgr/qmgr_deliver.c @@ -103,8 +103,6 @@ int qmgr_deliver_concurrency; static int qmgr_deliver_initial_reply(VSTREAM *stream) { - int stat; - if (peekfd(vstream_fileno(stream)) < 0) { msg_warn("%s: premature disconnect", VSTREAM_PATH(stream)); return (DELIVER_STAT_CRASH); diff --git a/postfix/src/postdrop/Makefile.in b/postfix/src/postdrop/Makefile.in index 6ae3f7a9f..cd60a943d 100644 --- a/postfix/src/postdrop/Makefile.in +++ b/postfix/src/postdrop/Makefile.in @@ -63,8 +63,10 @@ postdrop.o: ../../include/attr.h postdrop.o: ../../include/check_arg.h postdrop.o: ../../include/clean_env.h postdrop.o: ../../include/cleanup_user.h +postdrop.o: ../../include/dict.h postdrop.o: ../../include/htable.h postdrop.o: ../../include/iostuff.h +postdrop.o: ../../include/login_sender_match.h postdrop.o: ../../include/mail_conf.h postdrop.o: ../../include/mail_dict.h postdrop.o: ../../include/mail_params.h @@ -77,7 +79,9 @@ postdrop.o: ../../include/mail_version.h postdrop.o: ../../include/maillog_client.h postdrop.o: ../../include/msg.h postdrop.o: ../../include/msg_vstream.h +postdrop.o: ../../include/myflock.h postdrop.o: ../../include/mymalloc.h +postdrop.o: ../../include/mypwd.h postdrop.o: ../../include/nvtable.h postdrop.o: ../../include/rec_attr_map.h postdrop.o: ../../include/rec_type.h diff --git a/postfix/src/postdrop/postdrop.c b/postfix/src/postdrop/postdrop.c index 7f32c95f2..f8b588c33 100644 --- a/postfix/src/postdrop/postdrop.c +++ b/postfix/src/postdrop/postdrop.c @@ -82,6 +82,18 @@ /* .IP "\fBauthorized_submit_users (static:anyone)\fR" /* List of users who are authorized to submit mail with the \fBsendmail\fR(1) /* command (and with the privileged \fBpostdrop\fR(1) helper command). +/* .PP +/* Available in Postfix version 3.6 and later: +/* .IP "\fBlocal_login_sender_maps (static:*)\fR" +/* A list of lookup tables that are searched by the UNIX login name, +/* and that return a list of allowed envelope sender patterns separated +/* by space or comma. +/* .IP "\fBempty_address_local_login_sender_maps_lookup_key (<>)\fR" +/* The lookup key to be used in local_login_sender_maps tables, instead +/* of the null sender address. +/* .IP "\fBrecipient_delimiter (empty)\fR" +/* The set of characters that can separate an email address +/* localpart, user name, or a .forward file name from its extension. /* FILES /* /var/spool/postfix/maildrop, maildrop queue /* SEE ALSO @@ -128,6 +140,7 @@ #include #include #include +#include /* Global library. */ @@ -147,6 +160,7 @@ #include #include #include +#include /* Application-specific. */ @@ -167,9 +181,13 @@ * Local mail submission access list. */ char *var_submit_acl; +char *var_local_login_snd_maps; +char *var_null_local_login_snd_maps_key; static const CONFIG_STR_TABLE str_table[] = { VAR_SUBMIT_ACL, DEF_SUBMIT_ACL, &var_submit_acl, 0, 0, + VAR_LOCAL_LOGIN_SND_MAPS, DEF_LOCAL_LOGIN_SND_MAPS, &var_local_login_snd_maps, 0, 0, + VAR_NULL_LOCAL_LOGIN_SND_MAPS_KEY, DEF_NULL_LOCAL_LOGIN_SND_MAPS_KEY, &var_null_local_login_snd_maps_key, 0, 0, 0, }; @@ -220,6 +238,72 @@ static void postdrop_cleanup(void) postdrop_sig(0); } +/* check_login_sender_acl - check if a user is authorized to use this sender */ + +static int check_login_sender_acl(uid_t uid, VSTRING *sender_buf, + VSTRING *reason) +{ + const char myname[] = "check_login_sender_acl"; + struct mypasswd *user_info; + char *user_name; + VSTRING *user_name_buf = 0; + LOGIN_SENDER_MATCH *lsm; + int res; + + /* + * Sanity checks. + */ + if (vstring_memchr(sender_buf, '\0') != 0) { + vstring_sprintf(reason, "NUL in FROM record"); + return (CLEANUP_STAT_BAD); + } + + /* + * Optimization. + */ + if (strcmp(var_local_login_snd_maps, DEF_LOCAL_LOGIN_SND_MAPS) == 0) + return (CLEANUP_STAT_OK); + + /* + * Get the username. + */ + if ((user_info = mypwuid(uid)) != 0) { + user_name = user_info->pw_name; + } else { + user_name_buf = vstring_alloc(10); + vstring_sprintf(user_name_buf, "#%ld", (long) uid); + user_name = vstring_str(user_name_buf); + } + + + /* + * Apply the a login-sender matcher. TODO: add DICT flags. + */ + lsm = login_sender_create(VAR_LOCAL_LOGIN_SND_MAPS, + var_local_login_snd_maps, + var_rcpt_delim, + var_null_local_login_snd_maps_key, "*"); + res = login_sender_match(lsm, user_name, vstring_str(sender_buf)); + login_sender_free(lsm); + if (user_name_buf) + vstring_free(user_name_buf); + switch (res) { + case LSM_STAT_FOUND: + return (CLEANUP_STAT_OK); + case LSM_STAT_NOTFOUND: + vstring_sprintf(reason, "not authorized to use sender='%s'", + vstring_str(sender_buf)); + return (CLEANUP_STAT_NOPERM); + case LSM_STAT_RETRY: + case LSM_STAT_CONFIG: + vstring_sprintf(reason, "%s table lookup error for '%s'", + VAR_LOCAL_LOGIN_SND_MAPS, var_local_login_snd_maps); + return (CLEANUP_STAT_WRITE); + default: + msg_panic("%s: bad login_sender_match() result: %d", myname, res); + } +} + MAIL_VERSION_STAMP_DECLARE; /* main - the main program */ @@ -230,7 +314,8 @@ int main(int argc, char **argv) int fd; int c; VSTRING *buf; - int status; + int status = CLEANUP_STAT_OK; + VSTRING *reason = vstring_alloc(100); MAIL_STREAM *dst; int rec_type; static char *segment_info[] = { @@ -315,16 +400,6 @@ int main(int argc, char **argv) maillog_client_init(mail_task("postdrop"), MAILLOG_CLIENT_FLAG_NONE); get_mail_conf_str_table(str_table); - /* - * Mail submission access control. Should this be in the user-land gate, - * or in the daemon process? - */ - mail_dict_init(); - if ((errstr = check_user_acl_byuid(VAR_SUBMIT_ACL, var_submit_acl, - uid)) != 0) - msg_fatal("User %s(%ld) is not allowed to submit mail", - errstr, (long) uid); - /* * Stop run-away process accidents by limiting the queue file size. This * is not a defense against DOS attack. @@ -368,6 +443,16 @@ int main(int argc, char **argv) /* End of initializations. */ + /* + * Mail submission access control. Should this be in the user-land gate, + * or in the daemon process? + */ + mail_dict_init(); + if ((errstr = check_user_acl_byuid(VAR_SUBMIT_ACL, var_submit_acl, + uid)) != 0) + msg_fatal("User %s(%ld) is not allowed to submit mail", + errstr, (long) uid); + /* * Don't trust the caller's time information. */ @@ -430,8 +515,10 @@ int main(int argc, char **argv) if (rec_type == REC_TYPE_TIME) continue; /* Check these at submission time instead of pickup time. */ - if (rec_type == REC_TYPE_FROM) + if (rec_type == REC_TYPE_FROM) { + status |= check_login_sender_acl(uid, buf, reason); from_count++; + } if (rec_type == REC_TYPE_RCPT) rcpt_count++; /* Limit the attribute types that users may specify. */ @@ -463,7 +550,8 @@ int main(int argc, char **argv) } continue; } - if (REC_PUT_BUF(dst->stream, rec_type, buf) < 0) { + if (status != CLEANUP_STAT_OK + || REC_PUT_BUF(dst->stream, rec_type, buf) < 0) { /* rec_get() errors must not clobber errno. */ saved_errno = errno; while ((rec_type = rec_get_raw(VSTREAM_IN, buf, var_line_limit, @@ -496,16 +584,20 @@ int main(int argc, char **argv) * reporting (report at submission time instead of pickup time). Besides * the segment terminator records, there aren't any other mandatory * records in a Postfix submission queue file. + * + * TODO: return an informative reason for missing sender, too many senders, + * or missing recipient. */ - if (validate_input && (from_count == 0 || rcpt_count == 0)) { - status = CLEANUP_STAT_BAD; + if (validate_input && (from_count == 0 || rcpt_count == 0)) + status |= CLEANUP_STAT_BAD; + if (status != CLEANUP_STAT_OK) { mail_stream_cleanup(dst); } /* * Finish the file. */ - else if ((status = mail_stream_finish(dst, (VSTRING *) 0)) != 0) { + else if ((status = mail_stream_finish(dst, reason)) != 0) { msg_warn("uid=%ld: %m", (long) uid); postdrop_cleanup(); } @@ -525,7 +617,9 @@ int main(int argc, char **argv) */ attr_print(VSTREAM_OUT, ATTR_FLAG_NONE, SEND_ATTR_INT(MAIL_ATTR_STATUS, status), - SEND_ATTR_STR(MAIL_ATTR_WHY, ""), + SEND_ATTR_STR(MAIL_ATTR_WHY, status != CLEANUP_STAT_OK + && VSTRING_LEN(reason) > 0 ? + vstring_str(reason) : ""), ATTR_TYPE_END); vstream_fflush(VSTREAM_OUT); exit(status); diff --git a/postfix/src/postscreen/postscreen_dnsbl.c b/postfix/src/postscreen/postscreen_dnsbl.c index 32eec4bea..0142dd3fc 100644 --- a/postfix/src/postscreen/postscreen_dnsbl.c +++ b/postfix/src/postscreen/postscreen_dnsbl.c @@ -231,6 +231,7 @@ static void psc_dnsbl_add_site(const char *site) int weight; HTABLE_INFO *ht; char *parse_err; + const char *safe_dnsbl; /* * Parse the required DNSBL domain name, the optional reply filter and @@ -271,8 +272,9 @@ static void psc_dnsbl_add_site(const char *site) ht = htable_enter(dnsbl_site_cache, saved_site, (void *) head); /* Translate the DNSBL name into a safe name if available. */ if (psc_dnsbl_reply == 0 - || (head->safe_dnsbl = dict_get(psc_dnsbl_reply, saved_site)) == 0) - head->safe_dnsbl = ht->key; + || (safe_dnsbl = dict_get(psc_dnsbl_reply, saved_site)) == 0) + safe_dnsbl = ht->key; + head->safe_dnsbl = mystrdup(safe_dnsbl); if (psc_dnsbl_reply && psc_dnsbl_reply->error) msg_fatal("%s:%s lookup error", psc_dnsbl_reply->type, psc_dnsbl_reply->name); diff --git a/postfix/src/sendmail/sendmail.c b/postfix/src/sendmail/sendmail.c index 40e2d26d4..e060e58b4 100644 --- a/postfix/src/sendmail/sendmail.c +++ b/postfix/src/sendmail/sendmail.c @@ -694,6 +694,7 @@ static void enqueue(const int flags, const char *encoding, VSTRING *postdrop_command; uid_t uid = getuid(); int status; + VSTRING *why; /* postdrop status message */ int naddr; int prev_type; MIME_STATE *mime_state = 0; @@ -987,11 +988,15 @@ static void enqueue(const int flags, const char *encoding, if (vstream_ferror(VSTREAM_IN)) msg_fatal_status(EX_DATAERR, "%s(%ld): error reading input: %m", saved_sender, (long) uid); - if ((status = mail_stream_finish(handle, (VSTRING *) 0)) != 0) + why = vstring_alloc(100); + if ((status = mail_stream_finish(handle, why)) != CLEANUP_STAT_OK) msg_fatal_status((status & CLEANUP_STAT_BAD) ? EX_SOFTWARE : (status & CLEANUP_STAT_WRITE) ? EX_TEMPFAIL : + (status & CLEANUP_STAT_NOPERM) ? EX_NOPERM : EX_UNAVAILABLE, "%s(%ld): %s", saved_sender, - (long) uid, cleanup_strerror(status)); + (long) uid, VSTRING_LEN(why) ? + STR(why) : cleanup_strerror(status)); + vstring_free(why); /* * Don't leave them in the dark. diff --git a/postfix/src/smtpd/smtpd.c b/postfix/src/smtpd/smtpd.c index bcd285c13..6751dbf73 100644 --- a/postfix/src/smtpd/smtpd.c +++ b/postfix/src/smtpd/smtpd.c @@ -1062,9 +1062,8 @@ /* .IP "\fBqueue_directory (see 'postconf -d' output)\fR" /* The location of the Postfix top-level queue directory. /* .IP "\fBrecipient_delimiter (empty)\fR" -/* The set of characters that can separate a user name from its -/* extension (example: user+foo), or a .forward file name from its -/* extension (example: .forward+foo). +/* The set of characters that can separate an email address +/* localpart, user name, or a .forward file name from its extension. /* .IP "\fBsmtpd_banner ($myhostname ESMTP $mail_name)\fR" /* The text that follows the 220 status code in the SMTP greeting /* banner. @@ -5464,7 +5463,8 @@ static void smtpd_proto(SMTPD_STATE *state) * obsolete, so we don't have to provide perfect support. */ #ifdef USE_TLS - if (SMTPD_STAND_ALONE(state) == 0 && var_smtpd_tls_wrappermode) { + if (SMTPD_STAND_ALONE(state) == 0 && var_smtpd_tls_wrappermode + && state->tls_context == 0) { #ifdef USE_TLSPROXY /* We garbage-collect the VSTREAM in smtpd_state_reset() */ state->tlsproxy = diff --git a/postfix/src/util/dict_static.c b/postfix/src/util/dict_static.c index 9141f8661..448dde0c7 100644 --- a/postfix/src/util/dict_static.c +++ b/postfix/src/util/dict_static.c @@ -73,6 +73,8 @@ static void dict_static_close(DICT *dict) if (dict_static->value) myfree(dict_static->value); + if (dict->fold_buf) + vstring_free(dict->fold_buf); dict_free(dict); }