]> git.ipfire.org Git - thirdparty/postfix.git/commitdiff
postfix-3.6-20201025
authorWietse Venema <wietse@porcupine.org>
Sun, 25 Oct 2020 05:00:00 +0000 (00:00 -0500)
committerViktor Dukhovni <postfix-users@dukhovni.org>
Sun, 25 Oct 2020 21:05:22 +0000 (19:05 -0200)
38 files changed:
postfix/.indent.pro
postfix/HISTORY
postfix/README_FILES/SASL_README
postfix/README_FILES/SOHO_README
postfix/README_FILES/TLS_README
postfix/WISHLIST
postfix/html/SASL_README.html
postfix/html/SOHO_README.html
postfix/html/TLS_README.html
postfix/html/postconf.5.html
postfix/html/postdrop.1.html
postfix/html/smtpd.8.html
postfix/man/man1/postdrop.1
postfix/man/man5/postconf.5
postfix/man/man8/smtpd.8
postfix/mantools/postlink
postfix/proto/SASL_README.html
postfix/proto/TLS_README.html
postfix/proto/postconf.proto
postfix/src/global/Makefile.in
postfix/src/global/cleanup_strerror.c
postfix/src/global/cleanup_user.h
postfix/src/global/login_sender_match.c [new file with mode: 0644]
postfix/src/global/login_sender_match.h [new file with mode: 0644]
postfix/src/global/login_sender_match.ref [new file with mode: 0644]
postfix/src/global/mail_params.h
postfix/src/global/mail_stream.c
postfix/src/global/mail_version.h
postfix/src/global/quote_822_local.c
postfix/src/global/quote_822_local.in
postfix/src/global/quote_822_local.ref
postfix/src/oqmgr/qmgr_deliver.c
postfix/src/postdrop/Makefile.in
postfix/src/postdrop/postdrop.c
postfix/src/postscreen/postscreen_dnsbl.c
postfix/src/sendmail/sendmail.c
postfix/src/smtpd/smtpd.c
postfix/src/util/dict_static.c

index 736227a07e1d7ea3b23eda515ba66984504b075d..4ea4616eaf88d63a2e083ce272dba711e7530afb 100644 (file)
@@ -20,6 +20,7 @@
 -TBH_TABLE
 -TBINATTR
 -TBINATTR_INFO
+-Tbind_props
 -TBINHASH
 -TBINHASH_INFO
 -TBIO
 -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
 -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
 -TEVP_PKEY
 -TEXPAND_ATTR
 -TFILE
+-Tfilter_ctx
 -TFORWARD_INFO
+-Tgeneral_name_stack_t
 -THBC_ACTION_CALL_BACKS
 -THBC_CALL_BACKS
 -THBC_CHECKS
 -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
 -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
 -TMDB_val
 -TMILTER
 -TMILTER8
--TMILTERS
 -TMILTER_MACROS
 -TMILTER_MSG_CONTEXT
+-TMILTERS
 -TMIME_ENCODING
 -TMIME_INFO
 -TMIME_STACK
 -TNAME_CODE
 -TNAME_MASK
 -TNBBIO
+-Toff_t
 -TOPTIONS
 -TPCF_DBMS_INFO
 -TPCF_EVAL_CTX
 -TPCF_SERVICE_PATTERN
 -TPCF_STRING_NV
 -TPEER_NAME
+-Tpem_load_state_t
 -TPGSQL_NAME
 -TPICKUP_INFO
 -TPIPE_ATTR
 -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
 -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
 -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
 -TSMTPD_STATE
 -TSMTPD_TOKEN
 -TSMTPD_XFORWARD_ATTR
--TSMTP_ADDR
--TSMTP_CLI_ATTR
--TSMTP_CMD
 -TSMTP_ITERATOR
 -TSMTP_RESP
 -TSMTP_SASL_AUTH_CACHE
 -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
 -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
 -TTLS_TLSA
 -TTLS_USAGE
 -TTLS_VINFO
--TTLScontext_t
 -TTOK822
 -TTRANSPORT_INFO
 -TTRIGGER_SERVER
+-Tuint16_t
+-Tuint32_t
+-Tuint8_t
 -TUSER_ATTR
 -TVBUF
 -TVSTREAM
 -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
 -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
index f4810b3254285b8267610475414c76f3c342659a..2986dbb26231499df342c508ba133e1f0a01cef3 100644 (file)
@@ -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.
index 0c42480382fd11b4e8d89715c0635e73a0240fac..d9561d7f354a1386d9b31008d8d21720cf2e5fa8 100644 (file)
@@ -1058,9 +1058,9 @@ username/password information.
     standard "AUTH=m\bme\bet\bth\bho\bod\bd.\b...." 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
index 722bece706e4365de0fc28d73c2def397c92566b..3804b9da2574d5bf80c44950d920cada313f913c 100644 (file)
@@ -200,9 +200,9 @@ username/password information.
     standard "AUTH=m\bme\bet\bth\bho\bod\bd.\b...." 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
index 282ea2b649f3b01ba335ef7c91e04574d42e2295..864e7ae03318f2cef479501e7e925b999995e62c 100644 (file)
@@ -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:
 C\bCl\bli\bie\ben\bnt\bt-\b-s\bsi\bid\bde\be S\bSM\bMT\bTP\bPS\bS s\bsu\bup\bpp\bpo\bor\brt\bt
 
 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.
 
 P\bPo\bos\bst\btf\bfi\bix\bx >\b>=\b= 3\b3.\b.0\b0
 
index 36aef38babdad65effd59581eb3ce7ca428ad2b9..3ff40b112de507b538e2d0b8be01ea0db9af1e53 100644 (file)
@@ -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.
index df98b11f0bfa37a7adb8b37d1d3a9ff41f1d26ca..1f4bfdf4a7999599fd403e26b5858954dcdef539 100644 (file)
@@ -1697,10 +1697,9 @@ that use the non-standard "<code>AUTH=<em>method.</em>...</code>"
 syntax in response to the EHLO command; this requires no additional
 Postfix client configuration. </p> </li>
 
-<li> <p> The Postfix SMTP client does not support the obsolete
-"wrappermode" protocol, which uses TCP port <code>465</code> on the
-SMTP server.  See <a href="TLS_README.html">TLS_README</a> for a solution that uses the
-<code>stunnel</code> command.  </p> </li>
+<li> <p> With the setting "<a href="postconf.5.html#smtp_tls_wrappermode">smtp_tls_wrappermode</a> = yes", the Postfix
+SMTP client supports the "wrappermode" protocol, which uses TCP
+port 465 on the SMTP server (Postfix 3.0 and later). </p> </li>
 
 <li> <p> With the <code><a href="postconf.5.html#smtp_sasl_password_maps">smtp_sasl_password_maps</a></code> parameter,
 we configure the Postfix SMTP client to send username and password
index 775d93e8600bd49bc00efcf061cf4746e01db069..c3a7a10aee32e080b55648dc2eb18f7f660aea94 100644 (file)
@@ -288,10 +288,9 @@ that use the non-standard "<code>AUTH=<em>method.</em>...</code>"
 syntax in response to the EHLO command; this requires no additional
 Postfix client configuration. </p> </li>
 
-<li> <p> The Postfix SMTP client does not support the obsolete
-"wrappermode" protocol, which uses TCP port <code>465</code> on the
-SMTP server.  See <a href="TLS_README.html">TLS_README</a> for a solution that uses the
-<code>stunnel</code> command.  </p> </li>
+<li> <p> With the setting "<a href="postconf.5.html#smtp_tls_wrappermode">smtp_tls_wrappermode</a> = yes", the Postfix
+SMTP client supports the "wrappermode" protocol, which uses TCP
+port 465 on the SMTP server (Postfix 3.0 and later). </p> </li>
 
 <li> <p> With the <code><a href="postconf.5.html#smtp_sasl_password_maps">smtp_sasl_password_maps</a></code> parameter,
 we configure the Postfix SMTP client to send username and password
index 7b12d2a1a0c37db7f4d8daa75d9a23279d3479b6..915beded9acccff9315c110d241ba3048eb48b5e 100644 (file)
@@ -540,7 +540,7 @@ by default and should only seldom be used. </p>
 </pre>
 </blockquote>
 
-<p> TLS is sometimes used in the non-standard "wrapper" mode where
+<p> 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. </p>
 <h3> <a name="client_smtps">Client-side SMTPS support </a> </h3>
 
 <p> 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. </p>
 
index c672fa4ef3c6a3a4d7c74f27129ca131adb57a36..1fa04137e026e065e1ef68b8a1e03a6bafbf4418 100644 (file)
@@ -3137,6 +3137,19 @@ will be used instead of the null sender address. </p>
 <p> This feature is available in Postfix 2.7 and later.  </p>
 
 
+</DD>
+
+<DT><b><a name="empty_address_local_login_sender_maps_lookup_key">empty_address_local_login_sender_maps_lookup_key</a>
+(default: &lt;&gt;)</b></DT><DD>
+
+<p>
+The lookup key to be used in <a href="postconf.5.html#local_login_sender_maps">local_login_sender_maps</a> tables, instead
+of the null sender address.
+</p>
+
+<p> This feature is available in Postfix 3.6 and later. </p>
+
+
 </DD>
 
 <DT><b><a name="empty_address_recipient">empty_address_recipient</a>
@@ -5845,6 +5858,62 @@ system.  </p>
 </blockquote>
 
 
+</DD>
+
+<DT><b><a name="local_login_sender_maps">local_login_sender_maps</a>
+(default: <a href="DATABASE_README.html#types">static</a>:*)</b></DT><DD>
+
+<p> 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
+<a href="postdrop.1.html">postdrop(1)</a> command. The default is backwards-compatible:
+every user may specify any envelope information.  </p>
+
+<p> When no UNIX login name is available, the postdrop command will
+prepend '#' to the numerical UID and use that instead. </p>
+
+<p> Before checking a sender address against <a href="postconf.5.html#local_login_sender_maps">local_login_sender_maps</a>,
+Postfix will strip an address extension based on the current
+<a href="postconf.5.html#recipient_delimiter">recipient_delimiter</a> value.
+
+<p> The following sender patterns are special; these cannot be used
+as part of a longer pattern. </p>
+
+<dl>
+
+<dt> <b> * </b> <dd> This pattern allows everything. </dd>
+
+<dt> <b> &lt;&gt; </b> </dt> <dd> This pattern allows the null sender
+address. It is configured with the
+<a href="postconf.5.html#empty_address_local_login_sender_maps_lookup_key">empty_address_local_login_sender_maps_lookup_key</a> configuration
+parameter. </dd>
+
+<dt> <b> @<i>domain</i></b> </dt> <dd> This pattern allows a sender
+address when the '@' and <i>domain</i> part match. </dd>
+
+</dl>
+
+<p> Examples: </p>
+
+<pre>
+/etc/postfix/<a href="postconf.5.html">main.cf</a>:
+    # 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.
+    <a href="postconf.5.html#local_login_sender_maps">local_login_sender_maps</a> =
+        <a href="DATABASE_README.html#types">inline</a>:{ { root = *}, { postfix = * } },
+        <a href="pcre_table.5.html">pcre</a>:/etc/postfix/login_senders
+</pre>
+
+<pre>
+/etc/postfix/login_senders:
+   # Allow both the bare username and the user@domain forms.
+    /(.+)/ $1 $1@example.com/
+</pre>
+
+<p> This feature is available in Postfix 3.6 and later. </p>
+
+
 </DD>
 
 <DT><b><a name="local_recipient_maps">local_recipient_maps</a>
@@ -9529,17 +9598,19 @@ Example:
 <DT><b><a name="recipient_delimiter">recipient_delimiter</a>
 (default: empty)</b></DT><DD>
 
-<p> 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. </p>
+<p> The set of characters that can separate an email address
+localpart, user name, or a .forward file name from its extension.
+For example, with "<a href="postconf.5.html#recipient_delimiter">recipient_delimiter</a> = +", the software tries
+user+foo@example.com before trying user@example.com, user+foo before
+trying user, and .forward+foo before trying .forward. </p>
 
-<p> When the <a href="postconf.5.html#recipient_delimiter">recipient_delimiter</a> set contains multiple characters
-(Postfix 2.11 and later), a user name or .forward file name is
+<p> More formally, an email address localpart or user name is
 separated from its extension by the first character that matches
-the <a href="postconf.5.html#recipient_delimiter">recipient_delimiter</a> set. </p>
+the <a href="postconf.5.html#recipient_delimiter">recipient_delimiter</a> 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 <a href="postconf.5.html#recipient_delimiter">recipient_delimiter</a> specifies a single character. </p>
 
 <p> See <a href="canonical.5.html">canonical(5)</a>, <a href="local.8.html">local(8)</a>, <a href="relocated.5.html">relocated(5)</a> and <a href="virtual.5.html">virtual(5)</a> for the
 effects of <a href="postconf.5.html#recipient_delimiter">recipient_delimiter</a> on lookups in aliases, canonical,
index 463a3d3968fb2a3c9dbda3d36c483acb05888381..ce25bfbdb0a28952173a0f188a472070a124c1df 100644 (file)
@@ -94,6 +94,21 @@ POSTDROP(1)                                                        POSTDROP(1)
               <a href="sendmail.1.html"><b>mail</b>(1)</a> command (and with the privileged <a href="postdrop.1.html"><b>postdrop</b>(1)</a> helper com-
               mand).
 
+       Available in Postfix version 3.6 and later:
+
+       <b><a href="postconf.5.html#local_login_sender_maps">local_login_sender_maps</a> (<a href="DATABASE_README.html#types">static</a>:*)</b>
+              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.
+
+       <b><a href="postconf.5.html#empty_address_local_login_sender_maps_lookup_key">empty_address_local_login_sender_maps_lookup_key</a> (</b>&lt;&gt;<b>)</b>
+              The lookup key to be  used  in  <a href="postconf.5.html#local_login_sender_maps">local_login_sender_maps</a>  tables,
+              instead of the null sender address.
+
+       <b><a href="postconf.5.html#recipient_delimiter">recipient_delimiter</a> (empty)</b>
+              The  set of characters that can separate an email address local-
+              part, user name, or a .forward file name from its extension.
+
 <b>FILES</b>
        /var/spool/postfix/<a href="QSHAPE_README.html#maildrop_queue">maildrop</a>, <a href="QSHAPE_README.html#maildrop_queue">maildrop queue</a>
 
index 0881ebee29816713ee94e8b2913f4e448897ded0..97c35179acc8758a52751f95a1d1a658606ec851 100644 (file)
@@ -1291,25 +1291,24 @@ SMTPD(8)                                                              SMTPD(8)
               The location of the Postfix top-level queue directory.
 
        <b><a href="postconf.5.html#recipient_delimiter">recipient_delimiter</a> (empty)</b>
-              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.
 
        <b><a href="postconf.5.html#smtpd_banner">smtpd_banner</a> ($<a href="postconf.5.html#myhostname">myhostname</a> ESMTP $<a href="postconf.5.html#mail_name">mail_name</a>)</b>
-              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.
 
        <b><a href="postconf.5.html#syslog_facility">syslog_facility</a> (mail)</b>
               The syslog facility of Postfix logging.
 
        <b><a href="postconf.5.html#syslog_name">syslog_name</a> (see 'postconf -d' output)</b>
-              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:
 
        <b><a href="postconf.5.html#smtpd_forbidden_commands">smtpd_forbidden_commands</a> (CONNECT, GET, POST)</b>
-              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:
 
        <b><a href="postconf.5.html#smtpd_reject_footer_maps">smtpd_reject_footer_maps</a> (empty)</b>
-              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.
 
 <b>SEE ALSO</b>
index 10f638fd16c4e0a0d7530d7f89ffd4f054ee9159..23d60124aa28902e7abbebdb7e1385ebab0e5f15 100644 (file)
@@ -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
index 38394bdb380536183f6e9fc75be1567256097b56..6ef9b413bc343a69261b8b21463d96ea799264a4 100644 (file)
@@ -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,
index 299bf33dab541cf117c0c69d0c82cb5bc4e837ff..547d947f0edb780015eb3db8fc99c489a7711a3f 100644 (file)
@@ -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.
index 556b4cde7461d339943d28c1510e8cdc23106093..3eee53bd58c130f74b64c114f5952b85190d71ce 100755 (executable)
@@ -1130,6 +1130,8 @@ while (<>) {
     s;\bmail[-</bB>]*\n*[ <bB>]*log_file_rotate_suffix\b;<a href="postconf.5.html#maillog_file_rotate_suffix">$&</a>;g;
     s;\bpostlog_service_name\b;<a href="postconf.5.html#postlog_service_name">$&</a>;g;
     s;\bpostlogd_watchdog_timeout\b;<a href="postconf.5.html#postlogd_watchdog_timeout">$&</a>;g;
+    s;\blocal_login_sender_maps\b;<a href="postconf.5.html#local_login_sender_maps">$&</a>;g;
+    s;\bempty_address_local_login_sender_maps_lookup_key\b;<a href="postconf.5.html#empty_address_local_login_sender_maps_lookup_key">$&</a>;g;
 
     # Service-defined parameters...
 
index 90284b9210fe303fdbf4f81e3188eb7ec970c20d..404c2c978281062fd3b21ec51b0b0067ff18f09f 100644 (file)
@@ -1697,10 +1697,9 @@ that use the non-standard "<code>AUTH=<em>method.</em>...</code>"
 syntax in response to the EHLO command; this requires no additional
 Postfix client configuration. </p> </li>
 
-<li> <p> The Postfix SMTP client does not support the obsolete
-"wrappermode" protocol, which uses TCP port <code>465</code> on the
-SMTP server.  See TLS_README for a solution that uses the
-<code>stunnel</code> command.  </p> </li>
+<li> <p> 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). </p> </li>
 
 <li> <p> With the <code>smtp_sasl_password_maps</code> parameter,
 we configure the Postfix SMTP client to send username and password
index fbea1a94d248635ae70c8700c9609014ddfb4b85..badd59ad189242cb4c541bda09e5fcbeaf5cb8ac 100644 (file)
@@ -540,7 +540,7 @@ by default and should only seldom be used. </p>
 </pre>
 </blockquote>
 
-<p> TLS is sometimes used in the non-standard "wrapper" mode where
+<p> 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. </p>
 <h3> <a name="client_smtps">Client-side SMTPS support </a> </h3>
 
 <p> 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. </p>
 
index 81cdcad6a085dec00de795cb48779f1cd7dea967..62c0abb8fda41171bba2cafeafffe4c2e5e97a0b 100644 (file)
@@ -3632,17 +3632,19 @@ recipient_canonical_maps = hash:/etc/postfix/recipient_canonical
 
 %PARAM recipient_delimiter
 
-<p> 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. </p>
+<p> 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. </p>
 
-<p> When the recipient_delimiter set contains multiple characters
-(Postfix 2.11 and later), a user name or .forward file name is
+<p> More formally, an email address localpart or user name is
 separated from its extension by the first character that matches
-the recipient_delimiter set. </p>
+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. </p>
 
 <p> 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. </p>
 
 <p> This feature is available in Postfix 3.6 and later. </p>
+
+%PARAM local_login_sender_maps static:*
+
+<p> 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.  </p>
+
+<p> When no UNIX login name is available, the postdrop command will 
+prepend '#' to the numerical UID and use that instead. </p>
+
+<p> Before checking a sender address against local_login_sender_maps,
+Postfix will strip an address extension based on the current
+recipient_delimiter value.
+
+<p> The following sender patterns are special; these cannot be used
+as part of a longer pattern. </p>
+
+<dl>
+
+<dt> <b> * </b> <dd> This pattern allows everything. </dd>
+
+<dt> <b> &lt;&gt; </b> </dt> <dd> This pattern allows the null sender
+address. It is configured with the
+empty_address_local_login_sender_maps_lookup_key configuration
+parameter. </dd>
+
+<dt> <b> @<i>domain</i></b> </dt> <dd> This pattern allows a sender
+address when the '@' and <i>domain</i> part match. </dd>
+
+</dl>
+
+<p> Examples: </p>
+
+<pre>
+/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
+</pre>
+
+<pre>
+/etc/postfix/login_senders:
+   # Allow both the bare username and the user@domain forms.
+    /(.+)/ $1 $1@example.com/
+</pre>
+
+<p> This feature is available in Postfix 3.6 and later. </p>
+
+%PARAM empty_address_local_login_sender_maps_lookup_key &lt;&gt;
+
+<p>
+The lookup key to be used in local_login_sender_maps tables, instead
+of the null sender address.
+</p>
+
+<p> This feature is available in Postfix 3.6 and later. </p>
index db43f845bbe6f7635b9332c79d3b243861a5ea76..f84aa4f9b08782682a6e6e7e0ae6c1ccf7897936 100644 (file)
@@ -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
index ce0bb40d05c180102c29d0c8885e0ccd25c885a8..7e3dfe5d9b728dc6753c7ae592685769ff405907 100644 (file)
@@ -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 = {
index a4de82a65e5e37d50a3ef1180d3864a22a014785..3ad4c1b1c1362407402146e835800b4bf705c50c 100644 (file)
@@ -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 (file)
index 0000000..58f66c5
--- /dev/null
@@ -0,0 +1,342 @@
+/*++
+/* NAME
+/*     login_sender_match 3
+/* SUMMARY
+/*     match login and sender against (login, sender) patterns
+/* SYNOPSIS
+/*     #include <login_sender.h>
+/*
+/*     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 <sys_defs.h>
+#include <string.h>
+
+ /*
+  * Utility library.
+  */
+#include <msg.h>
+#include <mymalloc.h>
+#include <stringops.h>
+#include <vstring.h>
+
+ /*
+  * Global library.
+  */
+#include <mail_params.h>
+#include <maps.h>
+#include <quote_822_local.h>
+#include <strip_addr.h>
+#include <login_sender_match.h>
+
+ /*
+  * 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 (file)
index 0000000..eec0ba9
--- /dev/null
@@ -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 <login_sender_match.h>
+/* DESCRIPTION
+/* .nf
+
+ /*
+  * Utility library.
+  */
+#include <dict.h>
+
+ /*
+  * 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 (file)
index 0000000..35b488b
--- /dev/null
@@ -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
index e41bffab4c86e2fc4062381ec4184e3ac528b59c..12499f53b3a1bf6dedc95c4d5f186d5e729ece71 100644 (file)
@@ -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.
index 90a1ee0845d71b732646ce9df5ed7b905883926e..46cc87e45bfeab77e4aa4c9d21c7333ad3c3293c 100644 (file)
@@ -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);
index d0b5da56a5ad2eaab4b5ab76a985b003c2ec97fc..8269e7ce7033d2c6fd8e246e027eb5787a3f01c9 100644 (file)
@@ -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
index c16db66c007aaa74566651570abc11933d2cf2dd..541e4f721bd7f6430fcb3588e2e7b8e560b15794 100644 (file)
@@ -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 <ctype.h>
 #include <string.h>
@@ -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) {
index 385f4d855ac12c2ec38f96a52469b308be57826a..fc811bfc3cee5155ff8f73da621ee6a9edf41d02 100644 (file)
@@ -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 <>
index ec759175152358f79368c6fcd63dcbf97fa708f2..3b0fba3c6d452868d3f4ba5bcb35725214359b42 100644 (file)
@@ -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 '""'
index 16fbc9e2a3f13e3877f32261ae27d7b2703f8ba6..7a1c8eac326d1a8e2e3868ee8158b6be94b0f69e 100644 (file)
@@ -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);
index 6ae3f7a9f7b2653042555938cb268907811f5df2..cd60a943daf8f10595e3b7a622b234766bef2518 100644 (file)
@@ -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
index 7f32c95f27d514eb0baf3cb044bc84dd0a8a7f74..f8b588c331f8b3dca4fa322967aa2600715ac233 100644 (file)
 /* .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
 #include <argv.h>
 #include <iostuff.h>
 #include <stringops.h>
+#include <mypwd.h>
 
 /* Global library. */
 
 #include <rec_attr_map.h>
 #include <mail_parm_split.h>
 #include <maillog_client.h>
+#include <login_sender_match.h>
 
 /* Application-specific. */
 
   * 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);
index 32eec4beafce5aa4179c6159cd14420a4f2b2f3d..0142dd3fccec1f59ae245d7b590087007740430d 100644 (file)
@@ -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);
index 40e2d26d4e07ff8859cff5b7fcaf3979ef1ea923..e060e58b40f3d179a1224a263d4bbb6b9c15b313 100644 (file)
@@ -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.
index bcd285c13be0dcf82a33f3194369c668ed86fc80..6751dbf73d8dd8a624b1e1ea456893111006aecb 100644 (file)
 /* .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 =
index 9141f86611e73d03504dfa445c755efd14addd28..448dde0c75776f417e122cca3f47920bd02d35d4 100644 (file)
@@ -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);
 }