mirror of
https://github.com/vdukhovni/postfix
synced 2025-08-30 21:55:20 +00:00
postfix-2.3-20060611
This commit is contained in:
committed by
Viktor Dukhovni
parent
635c9e37f2
commit
ee5f55f12a
@@ -12182,8 +12182,57 @@ Apologies for any names omitted.
|
||||
master/master_spawn.c, pickup/pickup.c, util/match_ops.c,
|
||||
util/safe_open.c, xsasl/xsasl_cyrus_client.c.
|
||||
|
||||
20060606
|
||||
|
||||
Bugfix: qmgr panic after queue file corruption by Mailscanner.
|
||||
Files: *qmgr/qmgr_message.c.
|
||||
|
||||
Bugfix: XCLIENT didn't work with smtpd_delay_reject=no
|
||||
(problem reported by Joshua Goodall). To make XCLIENT work
|
||||
correctly with built-in restrictions and with Milter
|
||||
applications, the SMTP server now jumps back to the very
|
||||
start (the 220 phase) of an SMTP session. File: smtpd/smtpd.c.
|
||||
|
||||
20060610
|
||||
|
||||
Cleanup: XCLIENT and XFORWARD attribute values are now sent
|
||||
as xtext encoded strings. For backwards compatibility,
|
||||
Postfix will still accept unencoded attribute values. Files:
|
||||
smtpd/smtpd.c, smtpd/smtpd_proxy.c, smtp/smtp_proto.c.
|
||||
|
||||
20060611
|
||||
|
||||
Robustness: additional sanity checks for common database
|
||||
routines. Viktor Dukhovni. File: global/db_common.c.
|
||||
|
||||
Portability: LDAP 2.3 API support. Viktor Dukhovni. File:
|
||||
global/dict_ldap.c.
|
||||
|
||||
Security: the PostgreSQL client was updated after the
|
||||
PostgreSQL developers made major database API changes in
|
||||
response to PostgreSQL security issues. This breaks support
|
||||
for PGSQL versions prior to 8.1.4, 8.0.8, 7.4.13, and 7.3.15.
|
||||
Support for these requires major code changes which are not
|
||||
possible in the time that is left for the Postfix 2.3 stable
|
||||
release.
|
||||
|
||||
Specific PostgreSQL client changes: use connection-aware
|
||||
quoting, and more robust PQexec() result handling. Previous
|
||||
versions of the dict_pgsql driver didn't check the status
|
||||
of the result pointer, and certain exceptional events can
|
||||
be mis-interpreted as an empty result set. Fixes by Leandro
|
||||
Santi. File: global/dict_pgsql.c.
|
||||
|
||||
Wish list:
|
||||
|
||||
With (non)delivery notifications, prepend an "Auto-Submitted:
|
||||
auto-replied" header, as per RFC 3834.
|
||||
|
||||
Defer delivery when a SASL password exists but the server
|
||||
does not offer SASL authentication, as mail might otherwise
|
||||
be bounced. Make this configurable so people can get the
|
||||
old behavior.
|
||||
|
||||
Don't lose bits when converting st_dev into maildir file
|
||||
name. It's 64 bits on Linux. Found with the BEAM source
|
||||
code analyzer.
|
||||
|
@@ -194,8 +194,12 @@ http://www.t29.dk/antiantivirus.txt.
|
||||
DISCARD virus notification
|
||||
/^Content-Disposition:.*VirusWarning.txt/ DISCARD virus notification
|
||||
|
||||
Note: these documents haven't been updated since 2004, so they are useful only
|
||||
as a starting point.
|
||||
|
||||
A plea to virus or spam scanner operators: please do not make the problem worse
|
||||
by sending return mail to forged sender addresses. You're only harassing
|
||||
innocent people. If you must return mail to the purported sender, please return
|
||||
the full message headers, so that the sender can defend against forgeries.
|
||||
the full message headers, so that the sender can filter out the obvious
|
||||
forgeries.
|
||||
|
||||
|
@@ -102,4 +102,7 @@ CCrreeddiittss
|
||||
* Liviu Daia with further refinements from Jose Luis Tallon and Victor
|
||||
Duchovni developed the common query, result_format, domain and
|
||||
expansion_limit interface for LDAP, MySQL and PosgreSQL.
|
||||
* Leandro Santi updated the PostgreSQL client after the PostgreSQL developers
|
||||
made major database API changes in response to SQL injection problems, and
|
||||
made PQexec() handling more robust.
|
||||
|
||||
|
@@ -29,15 +29,17 @@ The XCLIENT command targets the following problems:
|
||||
|
||||
XXCCLLIIEENNTT CCoommmmaanndd ssyynnttaaxx
|
||||
|
||||
Examples of client-server conversations are given at the end of this document.
|
||||
An example client-server conversation is given at the end of this document.
|
||||
|
||||
In SMTP server EHLO replies, the keyword associated with this extension is
|
||||
XCLIENT. It is followed by the names of the attributes that the XCLIENT
|
||||
implementation supports.
|
||||
|
||||
The XCLIENT command may be sent at any time except in the middle of a mail
|
||||
delivery transaction (i.e. between MAIL and DOT). The XCLIENT command may be
|
||||
pipelined when the server supports ESMTP command pipelining.
|
||||
The XCLIENT command may be sent at any time, except in the middle of a mail
|
||||
delivery transaction (i.e. between MAIL and DOT, or MAIL and RSET). The XCLIENT
|
||||
command may be pipelined when the server supports ESMTP command pipelining. To
|
||||
avoid triggering spamware detectors, the command should be sent at the end of a
|
||||
command group.
|
||||
|
||||
The syntax of XCLIENT requests is described below. Upper case and quoted
|
||||
strings specify terminals, lowercase strings specify meta terminals, and SP is
|
||||
@@ -48,6 +50,10 @@ are in fact case insensitive.
|
||||
|
||||
attribute-name = ( NAME | ADDR | PROTO | HELO )
|
||||
|
||||
attribute-value = xtext
|
||||
|
||||
* Attribute values are xtext encoded as per RFC 1891.
|
||||
|
||||
* The NAME attribute specifies an SMTP client hostname (not an SMTP client
|
||||
address), [UNAVAILABLE] when client hostname lookup failed due to a
|
||||
permanent error, or [TEMPUNAVAIL] when the lookup error condition was
|
||||
@@ -62,33 +68,65 @@ are in fact case insensitive.
|
||||
* The HELO attribute specifies an SMTP HELO parameter value, or the value
|
||||
[UNAVAILABLE] when the information is unavailable.
|
||||
|
||||
Note 1: syntactically valid NAME and HELO attributes can be up to 255
|
||||
characters long. The client must not send XCLIENT commands that exceed the 512
|
||||
character limit for SMTP commands. To avoid exceeding the limit the client
|
||||
should send the information in multiple XCLIENT commands.
|
||||
Note 1: syntactically valid NAME and HELO attribute-value elements can be up to
|
||||
255 characters long. The client must not send XCLIENT commands that exceed the
|
||||
512 character limit for SMTP commands. To avoid exceeding the limit the client
|
||||
should send the information in multiple XCLIENT commands; for example, send
|
||||
NAME and ADDR first, then HELO and PROTO.
|
||||
|
||||
Note 2: [UNAVAILABLE], [TEMPUNAVAIL] and IPV6: may be specified in upper case,
|
||||
lower case or mixed case.
|
||||
|
||||
The XCLIENT server reply codes are as follows:
|
||||
Note 3: Postfix implementations prior to version 2.3 do not xtext encode
|
||||
attribute values. Servers that wish to interoperate with these older
|
||||
implementations should be prepared to receive unencoded information.
|
||||
|
||||
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
|
||||
XXCCLLIIEENNTT SSeerrvveerr rreessppoonnssee
|
||||
|
||||
Upon receipt of a correctly formatted XCLIENT command, the server resets state
|
||||
to the initial SMTP greeting protocol stage. Depending on the outcome of
|
||||
optional access decisions, the server responds with 220 or with a suitable
|
||||
rejection code.
|
||||
|
||||
For practical reasons it is not always possible to reset the complete server
|
||||
state to the initial SMTP greeting protocol stage:
|
||||
|
||||
* TLS session information may not be reset, because turning off TLS leaves
|
||||
the connection in an undefined state. Consequently, the server may not
|
||||
announce STARTTLS when TLS is already active, and access decisions may be
|
||||
influenced by client certificate information that was received prior to the
|
||||
XCLIENT command.
|
||||
|
||||
* The SMTP server must not reset attributes that were received with the last
|
||||
XCLIENT command. This includes HELO or PROTO attributes.
|
||||
|
||||
NOTE: Postfix implementations prior to version 2.3 do not jump back to the
|
||||
initial SMTP greeting protocol stage. These older implementations will not
|
||||
correctly simulate connection-level access decisions under some conditions.
|
||||
|
||||
XXCCLLIIEENNTT sseerrvveerr rreeppllyy ccooddeess
|
||||
|
||||
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
|
||||
|CCooddee |MMeeaanniinngg |
|
||||
|_ _ _ _ _|_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ |
|
||||
|250 |success |
|
||||
|_ _ _ _ _|_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ |
|
||||
|501 |bad command parameter syntax |
|
||||
|_ _ _ _ _|_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ |
|
||||
|503 |mail transaction in progress |
|
||||
|_ _ _ _ _|_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ |
|
||||
|_ _ _ _ _ _|_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ |
|
||||
|220 |success |
|
||||
|_ _ _ _ _ _|_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ |
|
||||
|421 |unable to proceed, disconnecting |
|
||||
|_ _ _ _ _|_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ |
|
||||
|_ _ _ _ _ _|_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ |
|
||||
|501 |bad command parameter syntax |
|
||||
|_ _ _ _ _ _|_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ |
|
||||
|503 |mail transaction in progress |
|
||||
|_ _ _ _ _ _|_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ |
|
||||
|550 |insufficient authorization |
|
||||
|_ _ _ _ _ _|_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ |
|
||||
|other|connection rejected by connection-level access decision|
|
||||
|_ _ _ _ _ _|_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ |
|
||||
|
||||
XXCCLLIIEENNTT EExxaammpplleess
|
||||
XXCCLLIIEENNTT EExxaammppllee
|
||||
|
||||
In the first example, the client impersonates a mail originating system by
|
||||
passing all SMTP session information via XCLIENT commands. Information sent by
|
||||
the client is shown in bold font.
|
||||
In the example, the client impersonates a mail originating system by passing
|
||||
all SMTP client information via the XCLIENT command. Information sent by the
|
||||
client is shown in bold font.
|
||||
|
||||
220 server.example.com ESMTP Postfix
|
||||
EEHHLLOO cclliieenntt..eexxaammppllee..ccoomm
|
||||
@@ -99,10 +137,16 @@ the client is shown in bold font.
|
||||
250-ETRN
|
||||
250-XCLIENT NAME ADDR PROTO HELO
|
||||
250 8BITMIME
|
||||
XXCCLLIIEENNTT NNAAMMEE==ssppiikkee..ppoorrccuuppiinnee..oorrgg AADDDDRR==116688..110000..118899..22 PPRROOTTOO==EESSMMTTPP
|
||||
250 Ok
|
||||
XXCCLLIIEENNTT HHEELLOO==ssppiikkee..ppoorrccuuppiinnee..oorrgg
|
||||
250 Ok
|
||||
XXCCLLIIEENNTT NNAAMMEE==ssppiikkee..ppoorrccuuppiinnee..oorrgg AADDDDRR==116688..110000..118899..22
|
||||
220 server.example.com ESMTP Postfix
|
||||
EEHHLLOO ssppiikkee..ppoorrccuuppiinnee..oorrgg
|
||||
250-server.example.com
|
||||
250-PIPELINING
|
||||
250-SIZE 10240000
|
||||
250-VRFY
|
||||
250-ETRN
|
||||
250-XCLIENT NAME ADDR PROTO HELO
|
||||
250 8BITMIME
|
||||
MMAAIILL FFRROOMM::<<wwiieettssee@@ppoorrccuuppiinnee..oorrgg>>
|
||||
250 Ok
|
||||
RRCCPPTT TTOO::<<uusseerr@@eexxaammppllee..ccoomm>>
|
||||
@@ -115,33 +159,10 @@ the client is shown in bold font.
|
||||
QQUUIITT
|
||||
221 Bye
|
||||
|
||||
In the second example, the client impersonates a mail originating system by
|
||||
sending the XCLIENT command before the EHLO or HELO command. This increases the
|
||||
realism of impersonation, but requires that the client knows ahead of time what
|
||||
XCLIENT options the server supports.
|
||||
|
||||
220 server.example.com ESMTP Postfix
|
||||
XXCCLLIIEENNTT NNAAMMEE==ssppiikkee..ppoorrccuuppiinnee..oorrgg AADDDDRR==116688..110000..118899..22
|
||||
250 Ok
|
||||
HHEELLOO ssppiikkee..ppoorrccuuppiinnee..oorrgg
|
||||
250 server.example.com
|
||||
MMAAIILL FFRROOMM::<<wwiieettssee@@ppoorrccuuppiinnee..oorrgg>>
|
||||
250 Ok
|
||||
RRCCPPTT TTOO::<<uusseerr@@eexxaammppllee..ccoomm>>
|
||||
250 Ok
|
||||
DDAATTAA
|
||||
354 End data with <CR><LF>.<CR><LF>
|
||||
.. .. ..mmeessssaaggee ccoonntteenntt.. .. ..
|
||||
..
|
||||
250 Ok: queued as CF1E52AAE7
|
||||
QQUUIITT
|
||||
221 Bye
|
||||
|
||||
SSeeccuurriittyy
|
||||
|
||||
The XCLIENT command changes audit trails and/or SMTP client access permissions.
|
||||
Use of this command must be restricted to authorized SMTP clients. However, the
|
||||
XCLIENT command should not override its own access control mechanism.
|
||||
Use of this command must be restricted to authorized SMTP clients.
|
||||
|
||||
SSMMTTPP ccoonnnneeccttiioonn ccaacchhiinngg
|
||||
|
||||
@@ -149,3 +170,8 @@ XCLIENT attributes persist until the end of an SMTP session. If one session is
|
||||
used to deliver mail on behalf of different SMTP clients, the XCLIENT
|
||||
attributes need to be reset as appropriate before each MAIL FROM command.
|
||||
|
||||
RReeffeerreenncceess
|
||||
|
||||
Moore, K, "SMTP Service Extension for Delivery Status Notifications", RFC 1891,
|
||||
January 1996.
|
||||
|
||||
|
@@ -14,12 +14,12 @@ The XFORWARD command targets the following problem:
|
||||
information through the content filter to MTA2, so that the information
|
||||
could be logged as part of mail handling transactions.
|
||||
|
||||
This extension is implemented as a separate command, and can be used to
|
||||
This extension is implemented as a separate EMSTP command, and can be used to
|
||||
transmit client or message attributes incrementally. It is not implemented by
|
||||
passing additional parameters via the MAIL FROM command, because doing so would
|
||||
require extending the MAIL FROM command length limit by another 600 or more
|
||||
characters beyond the space that is already needed in order to support other
|
||||
extensions such as AUTH.
|
||||
characters beyond the space that is already needed to support other extensions
|
||||
such as AUTH.
|
||||
|
||||
XXFFOORRWWAARRDD CCoommmmaanndd ssyynnttaaxx
|
||||
|
||||
@@ -43,6 +43,10 @@ are in fact case insensitive.
|
||||
|
||||
attribute-name = ( NAME | ADDR | PROTO | HELO | SOURCE )
|
||||
|
||||
attribute-value = xtext
|
||||
|
||||
* Attribute values are xtext encoded as per RFC 1891.
|
||||
|
||||
* The NAME attribute specifies the up-stream hostname, or [UNAVAILABLE] when
|
||||
the information is unavailable. The hostname may be a non-DNS hostname.
|
||||
|
||||
@@ -51,7 +55,7 @@ are in fact case insensitive.
|
||||
not enclosed with []. The address may be a non-IP address.
|
||||
|
||||
* The PROTO attribute specifies the mail protocol for receiving mail from the
|
||||
up-stream host. This may be an SMTP non-SMTP protocol name of up to 64
|
||||
up-stream host. This may be an SMTP or non-SMTP protocol name of up to 64
|
||||
characters, or [UNAVAILABLE] when the information is unavailable.
|
||||
|
||||
* The HELO attribute specifies the hostname that the up-stream host announced
|
||||
@@ -66,11 +70,10 @@ are in fact case insensitive.
|
||||
MTA may decide to enable features such as header munging or address
|
||||
qualification with mail from local sources but not other sources.
|
||||
|
||||
Note 1: Attribute values must not be longer than 255 characters (specific
|
||||
attributes may impose shorter lengths), must not contain control characters,
|
||||
non-ASCII characters, whitespace, or other characters that are special in
|
||||
message headers. Future attributes that may violate this should use xtext
|
||||
encoding as described in RFC 1891.
|
||||
Note 1: an attribute-value element must not be longer than 255 characters
|
||||
(specific attributes may impose shorter lengths). After xtext decoding,
|
||||
attribute values must not contain control characters, non-ASCII characters,
|
||||
whitespace, or other characters that are special in message headers.
|
||||
|
||||
Note 2: DNS hostnames can be up to 255 characters long. The XFORWARD client
|
||||
implementation must not send XFORWARD commands that exceed the 512 character
|
||||
@@ -81,18 +84,31 @@ Note 3: [UNAVAILABLE] may be specified in upper case, lower case or mixed case.
|
||||
Note 4: the XFORWARD server implementation must not mix information from the
|
||||
current SMTP session with forwarded information from an up-stream session.
|
||||
|
||||
The XFORWARD server reply codes are as follows:
|
||||
Note 5: Postfix implementations prior to version 2.3 do not xtext encode
|
||||
attribute values. Servers that wish to interoperate with these older
|
||||
implementations should be prepared to receive unencoded information.
|
||||
|
||||
XXFFOORRWWAARRDD SSeerrvveerr rreessppoonnssee
|
||||
|
||||
Upon receipt of a correctly formatted XFORWARD command, the server stores the
|
||||
specified attribute values, and erases the attributes whose value was specified
|
||||
as [UNAVAILABLE]. All XFORWARD attributes are reset to the real client
|
||||
information after the MAIL FROM command completes.
|
||||
|
||||
XXFFOORRWWAARRDD SSeerrvveerr rreeppllyy ccooddeess
|
||||
|
||||
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
|
||||
|CCooddee|MMeeaanniinngg |
|
||||
|_ _ _ _ _|_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ |
|
||||
|250 |success |
|
||||
|_ _ _ _ _|_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ |
|
||||
|421 |unable to proceed, disconnecting|
|
||||
|_ _ _ _ _|_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ |
|
||||
|501 |bad command parameter syntax |
|
||||
|_ _ _ _ _|_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ |
|
||||
|503 |mail transaction in progress |
|
||||
|_ _ _ _ _|_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ |
|
||||
|421 |unable to proceed, disconnecting|
|
||||
|550 |insufficient authorization |
|
||||
|_ _ _ _ _|_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ |
|
||||
|
||||
XXFFOORRWWAARRDD EExxaammppllee
|
||||
@@ -135,3 +151,8 @@ SMTP connection caching makes it possible to deliver multiple messages within
|
||||
the same SMTP session. The XFORWARD attributes are reset after the MAIL FROM
|
||||
command completes, so there is no risk of information leakage.
|
||||
|
||||
RReeffeerreenncceess
|
||||
|
||||
Moore, K, "SMTP Service Extension for Delivery Status Notifications", RFC 1891,
|
||||
January 1996.
|
||||
|
||||
|
@@ -17,6 +17,32 @@ Incompatibility with Postfix 2.1 and earlier
|
||||
If you upgrade from Postfix 2.1 or earlier, read RELEASE_NOTES-2.2
|
||||
before proceeding.
|
||||
|
||||
Incompatibility with snapshot 20060611
|
||||
======================================
|
||||
|
||||
The PostgreSQL client was updated after the PostgreSQL developers
|
||||
made major database API changes in response to SQL injection problems.
|
||||
This breaks support for PGSQL versions prior to 8.1.4, 8.0.8, 7.4.13,
|
||||
and 7.3.15. Support for these requires major code changes which are
|
||||
not possible in the time that is left for completing the Postfix
|
||||
2.3 stable release.
|
||||
|
||||
The SMTP server XCLIENT implementation has changed. The SMTP server
|
||||
now resets state to the initial server greeting stage, so that it
|
||||
can accurately simulate the effect of connection-level access
|
||||
restrictions. Without this change, XCLIENT will not work at all
|
||||
with Milter applications.
|
||||
|
||||
The SMTP server XCLIENT and XFORWARD commands now expect that
|
||||
attributes are xtext encoded (RFC 1891). For backwards compatibility
|
||||
they will accept unencoded attribute values. The XFORWARD client
|
||||
code in the SMTP client and in the SMTPD_PROXY client will always
|
||||
encode attribute values. This change will have effect only for
|
||||
malformed hostname and helo parameter values.
|
||||
|
||||
For more details, see the XCLIENT_README and XFORWARD_README
|
||||
documents.
|
||||
|
||||
Incompatibility with snapshot 20060207
|
||||
======================================
|
||||
|
||||
|
@@ -74,7 +74,7 @@ stress then it should not waste time. </p>
|
||||
|
||||
<blockquote>
|
||||
<pre>
|
||||
/etc/postfix/main.cf:
|
||||
/etc/postfix/<a href="postconf.5.html">main.cf</a>:
|
||||
# Not needed with Postfix 2.1 and later.
|
||||
<a href="postconf.5.html#smtpd_error_sleep_time">smtpd_error_sleep_time</a> = 0
|
||||
</pre>
|
||||
@@ -105,7 +105,8 @@ Received: from porcupine.org ...
|
||||
</blockquote>
|
||||
|
||||
<p> Then I know that this is almost certainly forged mail (almost;
|
||||
see next section for the fly in the ointment). Mail that is really
|
||||
see <a href="#caveats">next section</a> for the fly in the ointment).
|
||||
Mail that is really
|
||||
sent by my systems looks like this: </p>
|
||||
|
||||
<blockquote>
|
||||
@@ -143,7 +144,7 @@ patterns like this: </p>
|
||||
|
||||
<blockquote>
|
||||
<pre>
|
||||
/etc/postfix/main.cf:
|
||||
/etc/postfix/<a href="postconf.5.html">main.cf</a>:
|
||||
<a href="postconf.5.html#header_checks">header_checks</a> = <a href="regexp_table.5.html">regexp</a>:/etc/postfix/header_checks
|
||||
<a href="postconf.5.html#body_checks">body_checks</a> = <a href="regexp_table.5.html">regexp</a>:/etc/postfix/body_checks
|
||||
|
||||
@@ -182,7 +183,7 @@ and "<tt>)</tt>" would be grouping operators. </p>
|
||||
|
||||
</ul>
|
||||
|
||||
<p><strong>Caveats</strong></p>
|
||||
<p><a name="caveats"><strong>Caveats</strong></a></p>
|
||||
|
||||
<p> Netscape Messenger (and reportedly, Mozilla) sends a HELO name
|
||||
that is identical to the sender address domain part. If you have
|
||||
@@ -197,7 +198,7 @@ mapping translates this temporary address into user@porcupine.org.
|
||||
|
||||
<blockquote>
|
||||
<pre>
|
||||
/etc/postfix/main.cf:
|
||||
/etc/postfix/<a href="postconf.5.html">main.cf</a>:
|
||||
<a href="postconf.5.html#canonical_maps">canonical_maps</a> = hash:/etc/postfix/canonical
|
||||
|
||||
/etc/postfix/canonical:
|
||||
@@ -225,7 +226,7 @@ and is very easy to stop.
|
||||
|
||||
<blockquote>
|
||||
<pre>
|
||||
/etc/postfix/main.cf:
|
||||
/etc/postfix/<a href="postconf.5.html">main.cf</a>:
|
||||
<a href="postconf.5.html#header_checks">header_checks</a> = <a href="regexp_table.5.html">regexp</a>:/etc/postfix/header_checks
|
||||
<a href="postconf.5.html#body_checks">body_checks</a> = <a href="regexp_table.5.html">regexp</a>:/etc/postfix/body_checks
|
||||
|
||||
@@ -294,11 +295,14 @@ or <a href="http://www.t29.dk/antiantivirus.txt">http://www.t29.dk/antiantivirus
|
||||
</pre>
|
||||
</blockquote>
|
||||
|
||||
<p> Note: these documents haven't been updated since 2004, so they
|
||||
are useful only as a starting point. </p>
|
||||
|
||||
<p> A plea to virus or spam scanner operators: please do not make
|
||||
the problem worse by sending return mail to forged sender addresses.
|
||||
You're only harassing innocent people. If you must return mail to
|
||||
the purported sender, please return the full message headers, so
|
||||
that the sender can defend against forgeries. </p>
|
||||
that the sender can filter out the obvious forgeries. </p>
|
||||
|
||||
</body>
|
||||
|
||||
|
@@ -57,11 +57,11 @@ the location of the libpq library file. </p>
|
||||
<h2>Configuring PostgreSQL lookup tables</h2>
|
||||
|
||||
<p> Once Postfix is built with pgsql support, you can specify a
|
||||
map type in main.cf like this: </p>
|
||||
map type in <a href="postconf.5.html">main.cf</a> like this: </p>
|
||||
|
||||
<blockquote>
|
||||
<pre>
|
||||
/etc/postfix/main.cf:
|
||||
/etc/postfix/<a href="postconf.5.html">main.cf</a>:
|
||||
<a href="postconf.5.html#alias_maps">alias_maps</a> = <a href="pgsql_table.5.html">pgsql</a>:/etc/postfix/pgsql-aliases.cf
|
||||
</pre>
|
||||
</blockquote>
|
||||
@@ -130,15 +130,19 @@ calling stored procedures were added by Philip Warner.</li>
|
||||
<li> LaMont Jones was the initial Postfix pgsql maintainer.</li>
|
||||
|
||||
<li> Liviu Daia revised the configuration interface and added the
|
||||
main.cf configuration feature.</li>
|
||||
<a href="postconf.5.html">main.cf</a> configuration feature.</li>
|
||||
|
||||
<li> Liviu Daia revised the configuration interface and added the main.cf
|
||||
<li> Liviu Daia revised the configuration interface and added the <a href="postconf.5.html">main.cf</a>
|
||||
configuration feature.</li>
|
||||
|
||||
<li> Liviu Daia with further refinements from Jose Luis Tallon and
|
||||
Victor Duchovni developed the common query, result_format, domain and
|
||||
expansion_limit interface for LDAP, MySQL and PosgreSQL.</li>
|
||||
|
||||
<li> Leandro Santi updated the PostgreSQL client after the PostgreSQL
|
||||
developers made major database API changes in response to SQL
|
||||
injection problems, and made PQexec() handling more robust. </li>
|
||||
|
||||
</ul>
|
||||
|
||||
</body>
|
||||
|
@@ -52,17 +52,19 @@
|
||||
|
||||
<h2>XCLIENT Command syntax</h2>
|
||||
|
||||
<p> Examples of client-server conversations are given at the end
|
||||
<p> An example client-server conversation is given at the end
|
||||
of this document. </p>
|
||||
|
||||
<p> In SMTP server EHLO replies, the keyword associated with this
|
||||
extension is XCLIENT. It is followed by the names of the attributes
|
||||
that the XCLIENT implementation supports. </p>
|
||||
|
||||
<p> The XCLIENT command may be sent at any time except in the middle
|
||||
of a mail delivery transaction (i.e. between MAIL and DOT). The
|
||||
XCLIENT command may be pipelined when the server supports ESMTP
|
||||
command pipelining. </p>
|
||||
<p> The XCLIENT command may be sent at any time, except in the
|
||||
middle of a mail delivery transaction (i.e. between MAIL and DOT,
|
||||
or MAIL and RSET). The XCLIENT command may be pipelined when the
|
||||
server supports ESMTP command pipelining. To avoid triggering
|
||||
spamware detectors, the command should be sent at the end of a
|
||||
command group. </p>
|
||||
|
||||
<p> The syntax of XCLIENT requests is described below. Upper case
|
||||
and quoted strings specify terminals, lowercase strings specify
|
||||
@@ -77,10 +79,16 @@ names are shown in upper case, they are in fact case insensitive.
|
||||
<p>
|
||||
attribute-name = ( NAME | ADDR | PROTO | HELO )
|
||||
</p>
|
||||
<p>
|
||||
attribute-value = xtext
|
||||
</p>
|
||||
</blockquote>
|
||||
|
||||
<ul>
|
||||
|
||||
<li> <p> Attribute values are xtext encoded as per <a href="http://www.faqs.org/rfcs/rfc1891.html">RFC 1891</a>.
|
||||
</p>
|
||||
|
||||
<li> <p> The NAME attribute specifies an SMTP client hostname
|
||||
(not an SMTP client address), [UNAVAILABLE] when client hostname
|
||||
lookup failed due to a permanent error, or [TEMPUNAVAIL] when
|
||||
@@ -100,16 +108,52 @@ names are shown in upper case, they are in fact case insensitive.
|
||||
|
||||
</ul>
|
||||
|
||||
<p> Note 1: syntactically valid NAME and HELO attributes can be up
|
||||
to 255 characters long. The client must not send XCLIENT commands
|
||||
that exceed the 512 character limit for SMTP commands. To avoid
|
||||
exceeding the limit the client should send the information in
|
||||
multiple XCLIENT commands. </p>
|
||||
<p> Note 1: syntactically valid NAME and HELO attribute-value
|
||||
elements can be up to 255 characters long. The client must not send
|
||||
XCLIENT commands that exceed the 512 character limit for SMTP
|
||||
commands. To avoid exceeding the limit the client should send the
|
||||
information in multiple XCLIENT commands; for example, send NAME
|
||||
and ADDR first, then HELO and PROTO. </p>
|
||||
|
||||
<p> Note 2: [UNAVAILABLE], [TEMPUNAVAIL] and IPV6: may be specified
|
||||
in upper case, lower case or mixed case. </p>
|
||||
|
||||
<p> The XCLIENT server reply codes are as follows: </p>
|
||||
<p> Note 3: Postfix implementations prior to version 2.3 do not
|
||||
xtext encode attribute values. Servers that wish to interoperate
|
||||
with these older implementations should be prepared to receive
|
||||
unencoded information. </p>
|
||||
|
||||
<h2>XCLIENT Server response</h2>
|
||||
|
||||
<p> Upon receipt of a correctly formatted XCLIENT command, the
|
||||
server resets state to the initial SMTP greeting protocol stage.
|
||||
Depending on the outcome of optional access decisions, the server
|
||||
responds with 220 or with a suitable rejection code.
|
||||
|
||||
<p> For practical reasons it is not always possible to reset the
|
||||
complete server state to the initial SMTP greeting protocol stage:
|
||||
</p>
|
||||
|
||||
<ul>
|
||||
|
||||
<li> <p> TLS session information may not be reset, because turning off
|
||||
TLS leaves the connection in an undefined state. Consequently, the
|
||||
server may not announce STARTTLS when TLS is already active, and
|
||||
access decisions may be influenced by client certificate information
|
||||
that was received prior to the XCLIENT command. </p>
|
||||
|
||||
<li> <p> The SMTP server must not reset attributes that were received
|
||||
with the last XCLIENT command. This includes HELO or PROTO attributes.
|
||||
</p>
|
||||
|
||||
</ul>
|
||||
|
||||
<p> NOTE: Postfix implementations prior to version 2.3 do not jump
|
||||
back to the initial SMTP greeting protocol stage. These older
|
||||
implementations will not correctly simulate connection-level access
|
||||
decisions under some conditions. </p>
|
||||
|
||||
<h2> XCLIENT server reply codes </h2>
|
||||
|
||||
<blockquote>
|
||||
|
||||
@@ -117,23 +161,28 @@ in upper case, lower case or mixed case. </p>
|
||||
|
||||
<tr> <th> Code </th> <th> Meaning </th> </tr>
|
||||
|
||||
<tr> <td> 250 </td> <td> success </td> </tr>
|
||||
<tr> <td> 220 </td> <td> success </td> </tr>
|
||||
|
||||
<tr> <td> 421 </td> <td> unable to proceed, disconnecting </td> </tr>
|
||||
|
||||
<tr> <td> 501 </td> <td> bad command parameter syntax </td> </tr>
|
||||
|
||||
<tr> <td> 503 </td> <td> mail transaction in progress </td> </tr>
|
||||
|
||||
<tr> <td> 421 </td> <td> unable to proceed, disconnecting </td> </tr>
|
||||
<tr> <td> 550 </td> <td> insufficient authorization </td> </tr>
|
||||
|
||||
<tr> <td> other </td> <td> connection rejected by connection-level
|
||||
access decision </td> </tr>
|
||||
|
||||
</table>
|
||||
|
||||
</blockquote>
|
||||
|
||||
<h2>XCLIENT Examples</h2>
|
||||
<h2>XCLIENT Example</h2>
|
||||
|
||||
<p> In the first example, the client impersonates a mail originating
|
||||
system by passing all SMTP session information via XCLIENT commands.
|
||||
Information sent by the client is shown in bold font.
|
||||
<p> In the example, the client impersonates a mail originating
|
||||
system by passing all SMTP client information via the XCLIENT
|
||||
command. Information sent by the client is shown in bold font.
|
||||
</p>
|
||||
|
||||
<blockquote>
|
||||
@@ -147,10 +196,16 @@ Information sent by the client is shown in bold font.
|
||||
250-ETRN
|
||||
250-XCLIENT NAME ADDR PROTO HELO
|
||||
250 8BITMIME
|
||||
<b>XCLIENT NAME=spike.porcupine.org ADDR=168.100.189.2 PROTO=ESMTP </b>
|
||||
250 Ok
|
||||
<b>XCLIENT HELO=spike.porcupine.org</b>
|
||||
250 Ok
|
||||
<b>XCLIENT NAME=spike.porcupine.org ADDR=168.100.189.2</b>
|
||||
220 server.example.com ESMTP Postfix
|
||||
<b>EHLO spike.porcupine.org</b>
|
||||
250-server.example.com
|
||||
250-PIPELINING
|
||||
250-SIZE 10240000
|
||||
250-VRFY
|
||||
250-ETRN
|
||||
250-XCLIENT NAME ADDR PROTO HELO
|
||||
250 8BITMIME
|
||||
<b>MAIL FROM:<wietse@porcupine.org></b>
|
||||
250 Ok
|
||||
<b>RCPT TO:<user@example.com></b>
|
||||
@@ -165,39 +220,11 @@ Information sent by the client is shown in bold font.
|
||||
</pre>
|
||||
</blockquote>
|
||||
|
||||
<p> In the second example, the client impersonates a mail originating
|
||||
system by sending the XCLIENT command before the EHLO or HELO command.
|
||||
This increases the realism of impersonation, but requires that the
|
||||
client knows ahead of time what XCLIENT options the server supports.
|
||||
</p>
|
||||
|
||||
<blockquote>
|
||||
<pre>
|
||||
220 server.example.com ESMTP Postfix
|
||||
<b>XCLIENT NAME=spike.porcupine.org ADDR=168.100.189.2</b>
|
||||
250 Ok
|
||||
<b>HELO spike.porcupine.org</b>
|
||||
250 server.example.com
|
||||
<b>MAIL FROM:<wietse@porcupine.org></b>
|
||||
250 Ok
|
||||
<b>RCPT TO:<user@example.com></b>
|
||||
250 Ok
|
||||
<b>DATA</b>
|
||||
354 End data with <CR><LF>.<CR><LF>
|
||||
<b>. . .<i>message content</i>. . .</b>
|
||||
<b>.</b>
|
||||
250 Ok: queued as CF1E52AAE7
|
||||
<b>QUIT</b>
|
||||
221 Bye
|
||||
</pre>
|
||||
</blockquote>
|
||||
|
||||
<h2>Security</h2>
|
||||
|
||||
<p> The XCLIENT command changes audit trails and/or SMTP client
|
||||
access permissions. Use of this command must be restricted to
|
||||
authorized SMTP clients. However, the XCLIENT command should not
|
||||
override its own access control mechanism. </p>
|
||||
authorized SMTP clients. </p>
|
||||
|
||||
<h2>SMTP connection caching</h2>
|
||||
|
||||
@@ -206,6 +233,11 @@ If one session is used to deliver mail on behalf of different SMTP
|
||||
clients, the XCLIENT attributes need to be reset as appropriate
|
||||
before each MAIL FROM command. </p>
|
||||
|
||||
<h2> References </h2>
|
||||
|
||||
<p> Moore, K, "SMTP Service Extension for Delivery Status Notifications",
|
||||
<a href="http://www.faqs.org/rfcs/rfc1891.html">RFC 1891</a>, January 1996. </p>
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
||||
|
@@ -35,13 +35,13 @@
|
||||
|
||||
</ul>
|
||||
|
||||
<p> This extension is implemented as a separate command, and can
|
||||
be used to transmit client or message attributes incrementally.
|
||||
<p> This extension is implemented as a separate EMSTP command, and
|
||||
can be used to transmit client or message attributes incrementally.
|
||||
It is not implemented by passing additional parameters via the MAIL
|
||||
FROM command, because doing so would require extending the MAIL
|
||||
FROM command length limit by another 600 or more characters beyond
|
||||
the space that is already needed in order to support other extensions
|
||||
such as AUTH. </p>
|
||||
the space that is already needed to support other extensions such
|
||||
as AUTH. </p>
|
||||
|
||||
<h2>XFORWARD Command syntax</h2>
|
||||
|
||||
@@ -71,10 +71,16 @@ names are shown in upper case, they are in fact case insensitive.
|
||||
<p>
|
||||
attribute-name = ( NAME | ADDR | PROTO | HELO | SOURCE )
|
||||
</p>
|
||||
<p>
|
||||
attribute-value = xtext
|
||||
</p>
|
||||
</blockquote>
|
||||
|
||||
<ul>
|
||||
|
||||
<li> <p> Attribute values are xtext encoded as per <a href="http://www.faqs.org/rfcs/rfc1891.html">RFC 1891</a>.
|
||||
</p>
|
||||
|
||||
<li> <p> The NAME attribute specifies the up-stream hostname,
|
||||
or [UNAVAILABLE] when the information is unavailable. The
|
||||
hostname may be a non-DNS hostname. </p>
|
||||
@@ -85,7 +91,7 @@ names are shown in upper case, they are in fact case insensitive.
|
||||
be a non-IP address. </p>
|
||||
|
||||
<li> <p> The PROTO attribute specifies the mail protocol for
|
||||
receiving mail from the up-stream host. This may be an SMTP
|
||||
receiving mail from the up-stream host. This may be an SMTP or
|
||||
non-SMTP protocol name of up to 64 characters, or [UNAVAILABLE]
|
||||
when the information is unavailable. </p>
|
||||
|
||||
@@ -105,12 +111,11 @@ names are shown in upper case, they are in fact case insensitive.
|
||||
|
||||
</ul>
|
||||
|
||||
<p> Note 1: Attribute values must not be longer than 255 characters
|
||||
(specific attributes may impose shorter lengths), must not contain
|
||||
control characters, non-ASCII characters, whitespace, or other
|
||||
characters that are special in message headers. Future attributes
|
||||
that may violate this should use xtext encoding as described in
|
||||
<a href="http://www.faqs.org/rfcs/rfc1891.html">RFC 1891</a>. </p>
|
||||
<p> Note 1: an attribute-value element must not be longer than
|
||||
255 characters (specific attributes may impose shorter lengths).
|
||||
After xtext decoding, attribute values must not contain control
|
||||
characters, non-ASCII characters, whitespace, or other characters
|
||||
that are special in message headers. </p>
|
||||
|
||||
<p> Note 2: DNS hostnames can be up to 255 characters long. The
|
||||
XFORWARD client implementation must not send XFORWARD commands that
|
||||
@@ -123,7 +128,20 @@ case or mixed case. </p>
|
||||
information from the current SMTP session with forwarded information
|
||||
from an up-stream session. </p>
|
||||
|
||||
<p> The XFORWARD server reply codes are as follows: </p>
|
||||
<p> Note 5: Postfix implementations prior to version 2.3 do not
|
||||
xtext encode attribute values. Servers that wish to interoperate
|
||||
with these older implementations should be prepared to receive
|
||||
unencoded information. </p>
|
||||
|
||||
<h2> XFORWARD Server response </h2>
|
||||
|
||||
<p> Upon receipt of a correctly formatted XFORWARD command, the
|
||||
server stores the specified attribute values, and erases the
|
||||
attributes whose value was specified as [UNAVAILABLE]. All XFORWARD
|
||||
attributes are reset to the real client information after the MAIL
|
||||
FROM command completes. </p>
|
||||
|
||||
<h2> XFORWARD Server reply codes </h2>
|
||||
|
||||
<blockquote>
|
||||
|
||||
@@ -133,11 +151,13 @@ from an up-stream session. </p>
|
||||
|
||||
<tr> <td> 250 </td> <td> success </td> </tr>
|
||||
|
||||
<tr> <td> 421 </td> <td> unable to proceed, disconnecting </td> </tr>
|
||||
|
||||
<tr> <td> 501 </td> <td> bad command parameter syntax </td> </tr>
|
||||
|
||||
<tr> <td> 503 </td> <td> mail transaction in progress </td> </tr>
|
||||
|
||||
<tr> <td> 421 </td> <td> unable to proceed, disconnecting </td> </tr>
|
||||
<tr> <td> 550 </td> <td> insufficient authorization </td> </tr>
|
||||
|
||||
</table>
|
||||
|
||||
@@ -189,6 +209,11 @@ messages within the same SMTP session. The XFORWARD attributes are
|
||||
reset after the MAIL FROM command completes, so there is no risk
|
||||
of information leakage. </p>
|
||||
|
||||
<h2> References </h2>
|
||||
|
||||
<p> Moore, K, "SMTP Service Extension for Delivery Status Notifications",
|
||||
<a href="http://www.faqs.org/rfcs/rfc1891.html">RFC 1891</a>, January 1996. </p>
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
||||
|
@@ -105,7 +105,8 @@ Received: from porcupine.org ...
|
||||
</blockquote>
|
||||
|
||||
<p> Then I know that this is almost certainly forged mail (almost;
|
||||
see next section for the fly in the ointment). Mail that is really
|
||||
see <a href="#caveats">next section</a> for the fly in the ointment).
|
||||
Mail that is really
|
||||
sent by my systems looks like this: </p>
|
||||
|
||||
<blockquote>
|
||||
@@ -182,7 +183,7 @@ and "<tt>)</tt>" would be grouping operators. </p>
|
||||
|
||||
</ul>
|
||||
|
||||
<p><strong>Caveats</strong></p>
|
||||
<p><a name="caveats"><strong>Caveats</strong></a></p>
|
||||
|
||||
<p> Netscape Messenger (and reportedly, Mozilla) sends a HELO name
|
||||
that is identical to the sender address domain part. If you have
|
||||
@@ -294,11 +295,14 @@ or http://www.t29.dk/antiantivirus.txt. </p>
|
||||
</pre>
|
||||
</blockquote>
|
||||
|
||||
<p> Note: these documents haven't been updated since 2004, so they
|
||||
are useful only as a starting point. </p>
|
||||
|
||||
<p> A plea to virus or spam scanner operators: please do not make
|
||||
the problem worse by sending return mail to forged sender addresses.
|
||||
You're only harassing innocent people. If you must return mail to
|
||||
the purported sender, please return the full message headers, so
|
||||
that the sender can defend against forgeries. </p>
|
||||
that the sender can filter out the obvious forgeries. </p>
|
||||
|
||||
</body>
|
||||
|
||||
|
@@ -139,6 +139,10 @@ configuration feature.</li>
|
||||
Victor Duchovni developed the common query, result_format, domain and
|
||||
expansion_limit interface for LDAP, MySQL and PosgreSQL.</li>
|
||||
|
||||
<li> Leandro Santi updated the PostgreSQL client after the PostgreSQL
|
||||
developers made major database API changes in response to SQL
|
||||
injection problems, and made PQexec() handling more robust. </li>
|
||||
|
||||
</ul>
|
||||
|
||||
</body>
|
||||
|
@@ -52,17 +52,19 @@
|
||||
|
||||
<h2>XCLIENT Command syntax</h2>
|
||||
|
||||
<p> Examples of client-server conversations are given at the end
|
||||
<p> An example client-server conversation is given at the end
|
||||
of this document. </p>
|
||||
|
||||
<p> In SMTP server EHLO replies, the keyword associated with this
|
||||
extension is XCLIENT. It is followed by the names of the attributes
|
||||
that the XCLIENT implementation supports. </p>
|
||||
|
||||
<p> The XCLIENT command may be sent at any time except in the middle
|
||||
of a mail delivery transaction (i.e. between MAIL and DOT). The
|
||||
XCLIENT command may be pipelined when the server supports ESMTP
|
||||
command pipelining. </p>
|
||||
<p> The XCLIENT command may be sent at any time, except in the
|
||||
middle of a mail delivery transaction (i.e. between MAIL and DOT,
|
||||
or MAIL and RSET). The XCLIENT command may be pipelined when the
|
||||
server supports ESMTP command pipelining. To avoid triggering
|
||||
spamware detectors, the command should be sent at the end of a
|
||||
command group. </p>
|
||||
|
||||
<p> The syntax of XCLIENT requests is described below. Upper case
|
||||
and quoted strings specify terminals, lowercase strings specify
|
||||
@@ -77,10 +79,16 @@ names are shown in upper case, they are in fact case insensitive.
|
||||
<p>
|
||||
attribute-name = ( NAME | ADDR | PROTO | HELO )
|
||||
</p>
|
||||
<p>
|
||||
attribute-value = xtext
|
||||
</p>
|
||||
</blockquote>
|
||||
|
||||
<ul>
|
||||
|
||||
<li> <p> Attribute values are xtext encoded as per RFC 1891.
|
||||
</p>
|
||||
|
||||
<li> <p> The NAME attribute specifies an SMTP client hostname
|
||||
(not an SMTP client address), [UNAVAILABLE] when client hostname
|
||||
lookup failed due to a permanent error, or [TEMPUNAVAIL] when
|
||||
@@ -100,16 +108,52 @@ names are shown in upper case, they are in fact case insensitive.
|
||||
|
||||
</ul>
|
||||
|
||||
<p> Note 1: syntactically valid NAME and HELO attributes can be up
|
||||
to 255 characters long. The client must not send XCLIENT commands
|
||||
that exceed the 512 character limit for SMTP commands. To avoid
|
||||
exceeding the limit the client should send the information in
|
||||
multiple XCLIENT commands. </p>
|
||||
<p> Note 1: syntactically valid NAME and HELO attribute-value
|
||||
elements can be up to 255 characters long. The client must not send
|
||||
XCLIENT commands that exceed the 512 character limit for SMTP
|
||||
commands. To avoid exceeding the limit the client should send the
|
||||
information in multiple XCLIENT commands; for example, send NAME
|
||||
and ADDR first, then HELO and PROTO. </p>
|
||||
|
||||
<p> Note 2: [UNAVAILABLE], [TEMPUNAVAIL] and IPV6: may be specified
|
||||
in upper case, lower case or mixed case. </p>
|
||||
|
||||
<p> The XCLIENT server reply codes are as follows: </p>
|
||||
<p> Note 3: Postfix implementations prior to version 2.3 do not
|
||||
xtext encode attribute values. Servers that wish to interoperate
|
||||
with these older implementations should be prepared to receive
|
||||
unencoded information. </p>
|
||||
|
||||
<h2>XCLIENT Server response</h2>
|
||||
|
||||
<p> Upon receipt of a correctly formatted XCLIENT command, the
|
||||
server resets state to the initial SMTP greeting protocol stage.
|
||||
Depending on the outcome of optional access decisions, the server
|
||||
responds with 220 or with a suitable rejection code.
|
||||
|
||||
<p> For practical reasons it is not always possible to reset the
|
||||
complete server state to the initial SMTP greeting protocol stage:
|
||||
</p>
|
||||
|
||||
<ul>
|
||||
|
||||
<li> <p> TLS session information may not be reset, because turning off
|
||||
TLS leaves the connection in an undefined state. Consequently, the
|
||||
server may not announce STARTTLS when TLS is already active, and
|
||||
access decisions may be influenced by client certificate information
|
||||
that was received prior to the XCLIENT command. </p>
|
||||
|
||||
<li> <p> The SMTP server must not reset attributes that were received
|
||||
with the last XCLIENT command. This includes HELO or PROTO attributes.
|
||||
</p>
|
||||
|
||||
</ul>
|
||||
|
||||
<p> NOTE: Postfix implementations prior to version 2.3 do not jump
|
||||
back to the initial SMTP greeting protocol stage. These older
|
||||
implementations will not correctly simulate connection-level access
|
||||
decisions under some conditions. </p>
|
||||
|
||||
<h2> XCLIENT server reply codes </h2>
|
||||
|
||||
<blockquote>
|
||||
|
||||
@@ -117,23 +161,28 @@ in upper case, lower case or mixed case. </p>
|
||||
|
||||
<tr> <th> Code </th> <th> Meaning </th> </tr>
|
||||
|
||||
<tr> <td> 250 </td> <td> success </td> </tr>
|
||||
<tr> <td> 220 </td> <td> success </td> </tr>
|
||||
|
||||
<tr> <td> 421 </td> <td> unable to proceed, disconnecting </td> </tr>
|
||||
|
||||
<tr> <td> 501 </td> <td> bad command parameter syntax </td> </tr>
|
||||
|
||||
<tr> <td> 503 </td> <td> mail transaction in progress </td> </tr>
|
||||
|
||||
<tr> <td> 421 </td> <td> unable to proceed, disconnecting </td> </tr>
|
||||
<tr> <td> 550 </td> <td> insufficient authorization </td> </tr>
|
||||
|
||||
<tr> <td> other </td> <td> connection rejected by connection-level
|
||||
access decision </td> </tr>
|
||||
|
||||
</table>
|
||||
|
||||
</blockquote>
|
||||
|
||||
<h2>XCLIENT Examples</h2>
|
||||
<h2>XCLIENT Example</h2>
|
||||
|
||||
<p> In the first example, the client impersonates a mail originating
|
||||
system by passing all SMTP session information via XCLIENT commands.
|
||||
Information sent by the client is shown in bold font.
|
||||
<p> In the example, the client impersonates a mail originating
|
||||
system by passing all SMTP client information via the XCLIENT
|
||||
command. Information sent by the client is shown in bold font.
|
||||
</p>
|
||||
|
||||
<blockquote>
|
||||
@@ -147,10 +196,16 @@ Information sent by the client is shown in bold font.
|
||||
250-ETRN
|
||||
250-XCLIENT NAME ADDR PROTO HELO
|
||||
250 8BITMIME
|
||||
<b>XCLIENT NAME=spike.porcupine.org ADDR=168.100.189.2 PROTO=ESMTP </b>
|
||||
250 Ok
|
||||
<b>XCLIENT HELO=spike.porcupine.org</b>
|
||||
250 Ok
|
||||
<b>XCLIENT NAME=spike.porcupine.org ADDR=168.100.189.2</b>
|
||||
220 server.example.com ESMTP Postfix
|
||||
<b>EHLO spike.porcupine.org</b>
|
||||
250-server.example.com
|
||||
250-PIPELINING
|
||||
250-SIZE 10240000
|
||||
250-VRFY
|
||||
250-ETRN
|
||||
250-XCLIENT NAME ADDR PROTO HELO
|
||||
250 8BITMIME
|
||||
<b>MAIL FROM:<wietse@porcupine.org></b>
|
||||
250 Ok
|
||||
<b>RCPT TO:<user@example.com></b>
|
||||
@@ -165,39 +220,11 @@ Information sent by the client is shown in bold font.
|
||||
</pre>
|
||||
</blockquote>
|
||||
|
||||
<p> In the second example, the client impersonates a mail originating
|
||||
system by sending the XCLIENT command before the EHLO or HELO command.
|
||||
This increases the realism of impersonation, but requires that the
|
||||
client knows ahead of time what XCLIENT options the server supports.
|
||||
</p>
|
||||
|
||||
<blockquote>
|
||||
<pre>
|
||||
220 server.example.com ESMTP Postfix
|
||||
<b>XCLIENT NAME=spike.porcupine.org ADDR=168.100.189.2</b>
|
||||
250 Ok
|
||||
<b>HELO spike.porcupine.org</b>
|
||||
250 server.example.com
|
||||
<b>MAIL FROM:<wietse@porcupine.org></b>
|
||||
250 Ok
|
||||
<b>RCPT TO:<user@example.com></b>
|
||||
250 Ok
|
||||
<b>DATA</b>
|
||||
354 End data with <CR><LF>.<CR><LF>
|
||||
<b>. . .<i>message content</i>. . .</b>
|
||||
<b>.</b>
|
||||
250 Ok: queued as CF1E52AAE7
|
||||
<b>QUIT</b>
|
||||
221 Bye
|
||||
</pre>
|
||||
</blockquote>
|
||||
|
||||
<h2>Security</h2>
|
||||
|
||||
<p> The XCLIENT command changes audit trails and/or SMTP client
|
||||
access permissions. Use of this command must be restricted to
|
||||
authorized SMTP clients. However, the XCLIENT command should not
|
||||
override its own access control mechanism. </p>
|
||||
authorized SMTP clients. </p>
|
||||
|
||||
<h2>SMTP connection caching</h2>
|
||||
|
||||
@@ -206,6 +233,11 @@ If one session is used to deliver mail on behalf of different SMTP
|
||||
clients, the XCLIENT attributes need to be reset as appropriate
|
||||
before each MAIL FROM command. </p>
|
||||
|
||||
<h2> References </h2>
|
||||
|
||||
<p> Moore, K, "SMTP Service Extension for Delivery Status Notifications",
|
||||
RFC 1891, January 1996. </p>
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
||||
|
@@ -35,13 +35,13 @@
|
||||
|
||||
</ul>
|
||||
|
||||
<p> This extension is implemented as a separate command, and can
|
||||
be used to transmit client or message attributes incrementally.
|
||||
<p> This extension is implemented as a separate EMSTP command, and
|
||||
can be used to transmit client or message attributes incrementally.
|
||||
It is not implemented by passing additional parameters via the MAIL
|
||||
FROM command, because doing so would require extending the MAIL
|
||||
FROM command length limit by another 600 or more characters beyond
|
||||
the space that is already needed in order to support other extensions
|
||||
such as AUTH. </p>
|
||||
the space that is already needed to support other extensions such
|
||||
as AUTH. </p>
|
||||
|
||||
<h2>XFORWARD Command syntax</h2>
|
||||
|
||||
@@ -71,10 +71,16 @@ names are shown in upper case, they are in fact case insensitive.
|
||||
<p>
|
||||
attribute-name = ( NAME | ADDR | PROTO | HELO | SOURCE )
|
||||
</p>
|
||||
<p>
|
||||
attribute-value = xtext
|
||||
</p>
|
||||
</blockquote>
|
||||
|
||||
<ul>
|
||||
|
||||
<li> <p> Attribute values are xtext encoded as per RFC 1891.
|
||||
</p>
|
||||
|
||||
<li> <p> The NAME attribute specifies the up-stream hostname,
|
||||
or [UNAVAILABLE] when the information is unavailable. The
|
||||
hostname may be a non-DNS hostname. </p>
|
||||
@@ -85,7 +91,7 @@ names are shown in upper case, they are in fact case insensitive.
|
||||
be a non-IP address. </p>
|
||||
|
||||
<li> <p> The PROTO attribute specifies the mail protocol for
|
||||
receiving mail from the up-stream host. This may be an SMTP
|
||||
receiving mail from the up-stream host. This may be an SMTP or
|
||||
non-SMTP protocol name of up to 64 characters, or [UNAVAILABLE]
|
||||
when the information is unavailable. </p>
|
||||
|
||||
@@ -105,12 +111,11 @@ names are shown in upper case, they are in fact case insensitive.
|
||||
|
||||
</ul>
|
||||
|
||||
<p> Note 1: Attribute values must not be longer than 255 characters
|
||||
(specific attributes may impose shorter lengths), must not contain
|
||||
control characters, non-ASCII characters, whitespace, or other
|
||||
characters that are special in message headers. Future attributes
|
||||
that may violate this should use xtext encoding as described in
|
||||
RFC 1891. </p>
|
||||
<p> Note 1: an attribute-value element must not be longer than
|
||||
255 characters (specific attributes may impose shorter lengths).
|
||||
After xtext decoding, attribute values must not contain control
|
||||
characters, non-ASCII characters, whitespace, or other characters
|
||||
that are special in message headers. </p>
|
||||
|
||||
<p> Note 2: DNS hostnames can be up to 255 characters long. The
|
||||
XFORWARD client implementation must not send XFORWARD commands that
|
||||
@@ -123,7 +128,20 @@ case or mixed case. </p>
|
||||
information from the current SMTP session with forwarded information
|
||||
from an up-stream session. </p>
|
||||
|
||||
<p> The XFORWARD server reply codes are as follows: </p>
|
||||
<p> Note 5: Postfix implementations prior to version 2.3 do not
|
||||
xtext encode attribute values. Servers that wish to interoperate
|
||||
with these older implementations should be prepared to receive
|
||||
unencoded information. </p>
|
||||
|
||||
<h2> XFORWARD Server response </h2>
|
||||
|
||||
<p> Upon receipt of a correctly formatted XFORWARD command, the
|
||||
server stores the specified attribute values, and erases the
|
||||
attributes whose value was specified as [UNAVAILABLE]. All XFORWARD
|
||||
attributes are reset to the real client information after the MAIL
|
||||
FROM command completes. </p>
|
||||
|
||||
<h2> XFORWARD Server reply codes </h2>
|
||||
|
||||
<blockquote>
|
||||
|
||||
@@ -133,11 +151,13 @@ from an up-stream session. </p>
|
||||
|
||||
<tr> <td> 250 </td> <td> success </td> </tr>
|
||||
|
||||
<tr> <td> 421 </td> <td> unable to proceed, disconnecting </td> </tr>
|
||||
|
||||
<tr> <td> 501 </td> <td> bad command parameter syntax </td> </tr>
|
||||
|
||||
<tr> <td> 503 </td> <td> mail transaction in progress </td> </tr>
|
||||
|
||||
<tr> <td> 421 </td> <td> unable to proceed, disconnecting </td> </tr>
|
||||
<tr> <td> 550 </td> <td> insufficient authorization </td> </tr>
|
||||
|
||||
</table>
|
||||
|
||||
@@ -189,6 +209,11 @@ messages within the same SMTP session. The XFORWARD attributes are
|
||||
reset after the MAIL FROM command completes, so there is no risk
|
||||
of information leakage. </p>
|
||||
|
||||
<h2> References </h2>
|
||||
|
||||
<p> Moore, K, "SMTP Service Extension for Delivery Status Notifications",
|
||||
RFC 1891, January 1996. </p>
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
||||
|
@@ -281,6 +281,8 @@ int db_common_expand(void *ctxArg, const char *format, const char *value,
|
||||
DB_COMMON_CTX *ctx = (DB_COMMON_CTX *) ctxArg;
|
||||
const char *vdomain = 0;
|
||||
const char *kdomain = 0;
|
||||
const char *domain = 0;
|
||||
int dflag = key ? DB_COMMON_VALUE_DOMAIN : DB_COMMON_KEY_DOMAIN;
|
||||
char *vuser = 0;
|
||||
char *kuser = 0;
|
||||
ARGV *parts = 0;
|
||||
@@ -397,6 +399,12 @@ int db_common_expand(void *ctxArg, const char *format, const char *value,
|
||||
break;
|
||||
|
||||
case 'd':
|
||||
if (!(ctx->flags & dflag))
|
||||
msg_panic("%s: %s: %s: bad query/result template context",
|
||||
myname, ctx->dict->name, format);
|
||||
if (!vdomain)
|
||||
msg_panic("%s: %s: %s: expanding domain-less key or value",
|
||||
myname, ctx->dict->name, format);
|
||||
QUOTE_VAL(ctx->dict, quote_func, vdomain, result);
|
||||
break;
|
||||
|
||||
@@ -426,10 +434,13 @@ int db_common_expand(void *ctxArg, const char *format, const char *value,
|
||||
break;
|
||||
|
||||
case 'D':
|
||||
if (key)
|
||||
QUOTE_VAL(ctx->dict, quote_func, kdomain, result);
|
||||
else
|
||||
QUOTE_VAL(ctx->dict, quote_func, vdomain, result);
|
||||
if (!(ctx->flags & DB_COMMON_KEY_DOMAIN))
|
||||
msg_panic("%s: %s: %s: bad query/result template context",
|
||||
myname, ctx->dict->name, format);
|
||||
if ((domain = key ? kdomain : vdomain) == 0)
|
||||
msg_panic("%s: %s: %s: expanding domain-less key or value",
|
||||
myname, ctx->dict->name, format);
|
||||
QUOTE_VAL(ctx->dict, quote_func, domain, result);
|
||||
break;
|
||||
|
||||
case '1':
|
||||
@@ -450,6 +461,13 @@ int db_common_expand(void *ctxArg, const char *format, const char *value,
|
||||
* guaranteed to be initialized and hold enough elements to
|
||||
* satisfy the query template.
|
||||
*/
|
||||
if (!(ctx->flags & DB_COMMON_KEY_DOMAIN)
|
||||
|| ctx->nparts < *cp - '0')
|
||||
msg_panic("%s: %s: %s: bad query/result template context",
|
||||
myname, ctx->dict->name, format);
|
||||
if (!parts || parts->argc < ctx->nparts)
|
||||
msg_panic("%s: %s: %s: key has too few domain labels",
|
||||
myname, ctx->dict->name, format);
|
||||
QUOTE_VAL(ctx->dict, quote_func,
|
||||
parts->argv[parts->argc - (*cp - '0')], result);
|
||||
break;
|
||||
|
@@ -351,31 +351,78 @@ static int dict_ldap_set_errno(LDAP * ld, int rc)
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
* We need a version of ldap_bind that times out, otherwise all
|
||||
* of Postfix can get wedged during daemon initialization.
|
||||
*/
|
||||
static int dict_ldap_bind_st(DICT_LDAP *dict_ldap)
|
||||
/* dict_ldap_result - Read and parse LDAP result */
|
||||
|
||||
static int dict_ldap_result(LDAP *ld, int msgid, int timeout, LDAPMessage **res)
|
||||
{
|
||||
int msgid;
|
||||
LDAPMessage *res;
|
||||
int rc;
|
||||
struct timeval mytimeval;
|
||||
|
||||
if ((msgid = ldap_bind(dict_ldap->ld, dict_ldap->bind_dn,
|
||||
dict_ldap->bind_pw, LDAP_AUTH_SIMPLE)) == -1)
|
||||
return (dict_ldap_get_errno(dict_ldap->ld));
|
||||
|
||||
mytimeval.tv_sec = dict_ldap->timeout;
|
||||
mytimeval.tv_sec = timeout;
|
||||
mytimeval.tv_usec = 0;
|
||||
|
||||
if (ldap_result(dict_ldap->ld, msgid, 1, &mytimeval, &res) == -1)
|
||||
return (dict_ldap_get_errno(dict_ldap->ld));
|
||||
#define GET_ALL 1
|
||||
if (ldap_result(ld, msgid, GET_ALL, &mytimeval, res) == -1)
|
||||
return (dict_ldap_get_errno(ld));
|
||||
|
||||
if (dict_ldap_get_errno(dict_ldap->ld) == LDAP_TIMEOUT) {
|
||||
(void) ldap_abandon(dict_ldap->ld, msgid);
|
||||
return (dict_ldap_set_errno(dict_ldap->ld, LDAP_TIMEOUT));
|
||||
if (dict_ldap_get_errno(ld) == LDAP_TIMEOUT) {
|
||||
(void) ldap_abandon_ext(ld, msgid, 0, 0);
|
||||
return (dict_ldap_set_errno(ld, LDAP_TIMEOUT));
|
||||
}
|
||||
return (ldap_result2error(dict_ldap->ld, res, 1));
|
||||
|
||||
return LDAP_SUCCESS;
|
||||
}
|
||||
|
||||
/* dict_ldap_bind_st - Synchronous simple auth with timeout */
|
||||
|
||||
static int dict_ldap_bind_st(DICT_LDAP *dict_ldap)
|
||||
{
|
||||
int rc;
|
||||
int msgid;
|
||||
LDAPMessage *res;
|
||||
struct berval cred;
|
||||
|
||||
cred.bv_val = dict_ldap->bind_pw;
|
||||
cred.bv_len = strlen(cred.bv_val);
|
||||
if ((rc = ldap_sasl_bind(dict_ldap->ld, dict_ldap->bind_dn,
|
||||
LDAP_SASL_SIMPLE, &cred,
|
||||
0, 0, &msgid)) != LDAP_SUCCESS)
|
||||
return (rc);
|
||||
if ((rc = dict_ldap_result(dict_ldap->ld, msgid, dict_ldap->timeout,
|
||||
&res)) != LDAP_SUCCESS)
|
||||
return (rc);
|
||||
|
||||
#define FREE_RESULT 1
|
||||
return (ldap_parse_sasl_bind_result(dict_ldap->ld, res, 0, FREE_RESULT));
|
||||
}
|
||||
|
||||
/* search_st - Synchronous search with timeout */
|
||||
|
||||
static int search_st(LDAP *ld, char *base, int scope, char *query,
|
||||
char **attrs, int timeout, LDAPMessage **res)
|
||||
{
|
||||
struct timeval mytimeval;
|
||||
int msgid;
|
||||
int rc;
|
||||
int err;
|
||||
|
||||
mytimeval.tv_sec = timeout;
|
||||
mytimeval.tv_usec = 0;
|
||||
|
||||
#define WANTVALS 0
|
||||
#define USE_SIZE_LIM_OPT -1 /* Any negative value will do */
|
||||
|
||||
if ((rc = ldap_search_ext(ld, base, scope, query, attrs, WANTVALS, 0, 0,
|
||||
&mytimeval, USE_SIZE_LIM_OPT,
|
||||
&msgid)) != LDAP_SUCCESS)
|
||||
return rc;
|
||||
|
||||
if ((rc = dict_ldap_result(ld, msgid, timeout, res)) != LDAP_SUCCESS)
|
||||
return (rc);
|
||||
|
||||
#define DONT_FREE_RESULT 0
|
||||
rc = ldap_parse_result(ld, *res, &err, 0, 0, 0, 0, DONT_FREE_RESULT);
|
||||
return (err != LDAP_SUCCESS ? err : rc);
|
||||
}
|
||||
|
||||
#ifdef LDAP_API_FEATURE_X_OPENLDAP
|
||||
@@ -715,14 +762,11 @@ static void dict_ldap_get_values(DICT_LDAP *dict_ldap, LDAPMessage * res,
|
||||
LDAPMessage *resloop = 0;
|
||||
LDAPMessage *entry = 0;
|
||||
BerElement *ber;
|
||||
char **vals;
|
||||
char *attr;
|
||||
char *myname = "dict_ldap_get_values";
|
||||
struct timeval tv;
|
||||
struct berval **vals;
|
||||
int valcount;
|
||||
LDAPURLDesc *url;
|
||||
|
||||
tv.tv_sec = dict_ldap->timeout;
|
||||
tv.tv_usec = 0;
|
||||
char *myname = "dict_ldap_get_values";
|
||||
|
||||
if (++recursion == 1)
|
||||
expansion = 0;
|
||||
@@ -751,7 +795,7 @@ static void dict_ldap_get_values(DICT_LDAP *dict_ldap, LDAPMessage * res,
|
||||
attr != NULL;
|
||||
ldap_memfree(attr), attr = ldap_next_attribute(dict_ldap->ld,
|
||||
entry, ber)) {
|
||||
vals = ldap_get_values(dict_ldap->ld, entry, attr);
|
||||
vals = ldap_get_values_len(dict_ldap->ld, entry, attr);
|
||||
if (vals == NULL) {
|
||||
if (msg_verbose)
|
||||
msg_info("%s[%d]: Entry doesn't have any values for %s",
|
||||
@@ -759,6 +803,8 @@ static void dict_ldap_get_values(DICT_LDAP *dict_ldap, LDAPMessage * res,
|
||||
continue;
|
||||
}
|
||||
|
||||
valcount = ldap_count_values_len(vals);
|
||||
|
||||
/*
|
||||
* If we previously encountered an error, we still continue
|
||||
* through the loop, to avoid memory leaks, but we don't waste
|
||||
@@ -768,8 +814,8 @@ static void dict_ldap_get_values(DICT_LDAP *dict_ldap, LDAPMessage * res,
|
||||
* leaks, but it will likely be more fragile and not worth the
|
||||
* extra code.
|
||||
*/
|
||||
if (dict_errno != 0 || vals[0] == 0) {
|
||||
ldap_value_free(vals);
|
||||
if (dict_errno != 0 || valcount == 0) {
|
||||
ldap_value_free_len(vals);
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -794,9 +840,10 @@ static void dict_ldap_get_values(DICT_LDAP *dict_ldap, LDAPMessage * res,
|
||||
*/
|
||||
if (i < dict_ldap->num_attributes) {
|
||||
/* Ordinary result attribute */
|
||||
for (i = 0; vals[i] != NULL; i++) {
|
||||
for (i = 0; i < valcount; i++) {
|
||||
if (db_common_expand(dict_ldap->ctx,
|
||||
dict_ldap->result_format, vals[i],
|
||||
dict_ldap->result_format,
|
||||
vals[i]->bv_val,
|
||||
name, result, 0)
|
||||
&& dict_ldap->expansion_limit > 0
|
||||
&& ++expansion > dict_ldap->expansion_limit) {
|
||||
@@ -815,27 +862,27 @@ static void dict_ldap_get_values(DICT_LDAP *dict_ldap, LDAPMessage * res,
|
||||
} else if (recursion < dict_ldap->recursion_limit
|
||||
&& dict_ldap->result_attributes->argv[i]) {
|
||||
/* Special result attribute */
|
||||
for (i = 0; vals[i] != NULL; i++) {
|
||||
if (ldap_is_ldap_url(vals[i])) {
|
||||
for (i = 0; i < valcount; i++) {
|
||||
if (ldap_is_ldap_url(vals[i]->bv_val)) {
|
||||
if (msg_verbose)
|
||||
msg_info("%s[%d]: looking up URL %s", myname,
|
||||
recursion, vals[i]);
|
||||
rc = ldap_url_parse(vals[i], &url);
|
||||
recursion, vals[i]->bv_val);
|
||||
rc = ldap_url_parse(vals[i]->bv_val, &url);
|
||||
if (rc == 0) {
|
||||
rc = ldap_search_st(dict_ldap->ld, url->lud_dn,
|
||||
rc = search_st(dict_ldap->ld, url->lud_dn,
|
||||
url->lud_scope, url->lud_filter,
|
||||
url->lud_attrs, 0, &tv,
|
||||
url->lud_attrs, dict_ldap->timeout,
|
||||
&resloop);
|
||||
ldap_free_urldesc(url);
|
||||
}
|
||||
} else {
|
||||
if (msg_verbose)
|
||||
msg_info("%s[%d]: looking up DN %s",
|
||||
myname, recursion, vals[i]);
|
||||
rc = ldap_search_st(dict_ldap->ld, vals[i],
|
||||
myname, recursion, vals[i]->bv_val);
|
||||
rc = search_st(dict_ldap->ld, vals[i]->bv_val,
|
||||
LDAP_SCOPE_BASE, "objectclass=*",
|
||||
dict_ldap->result_attributes->argv,
|
||||
0, &tv, &resloop);
|
||||
dict_ldap->timeout, &resloop);
|
||||
}
|
||||
switch (rc) {
|
||||
case LDAP_SUCCESS:
|
||||
@@ -848,7 +895,7 @@ static void dict_ldap_get_values(DICT_LDAP *dict_ldap, LDAPMessage * res,
|
||||
* and just didn't have any result attributes.
|
||||
*/
|
||||
msg_warn("%s[%d]: DN %s not found, skipping ", myname,
|
||||
recursion, vals[i]);
|
||||
recursion, vals[i]->bv_val);
|
||||
break;
|
||||
default:
|
||||
msg_warn("%s[%d]: search error %d: %s ", myname,
|
||||
@@ -873,10 +920,10 @@ static void dict_ldap_get_values(DICT_LDAP *dict_ldap, LDAPMessage * res,
|
||||
&& dict_ldap->result_attributes->argv[i]) {
|
||||
msg_warn("%s[%d]: %s: Recursion limit exceeded"
|
||||
" for special attribute %s=%s", myname, recursion,
|
||||
dict_ldap->parser->name, attr, vals[0]);
|
||||
dict_ldap->parser->name, attr, vals[0]->bv_val);
|
||||
dict_errno = DICT_ERR_RETRY;
|
||||
}
|
||||
ldap_value_free(vals);
|
||||
ldap_value_free_len(vals);
|
||||
}
|
||||
if (ber)
|
||||
ber_free(ber, 0);
|
||||
@@ -897,7 +944,6 @@ static const char *dict_ldap_lookup(DICT *dict, const char *name)
|
||||
static VSTRING *base;
|
||||
static VSTRING *query;
|
||||
static VSTRING *result;
|
||||
struct timeval tv;
|
||||
int rc = 0;
|
||||
int sizelimit;
|
||||
|
||||
@@ -1001,12 +1047,6 @@ static const char *dict_ldap_lookup(DICT *dict, const char *name)
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Prepare the query.
|
||||
*/
|
||||
tv.tv_sec = dict_ldap->timeout;
|
||||
tv.tv_usec = 0;
|
||||
|
||||
/*
|
||||
* On to the search.
|
||||
*/
|
||||
@@ -1014,17 +1054,16 @@ static const char *dict_ldap_lookup(DICT *dict, const char *name)
|
||||
msg_info("%s: %s: Searching with filter %s", myname,
|
||||
dict_ldap->parser->name, vstring_str(query));
|
||||
|
||||
rc = ldap_search_st(dict_ldap->ld, vstring_str(base),
|
||||
dict_ldap->scope, vstring_str(query),
|
||||
dict_ldap->result_attributes->argv,
|
||||
0, &tv, &res);
|
||||
rc = search_st(dict_ldap->ld, vstring_str(base), dict_ldap->scope,
|
||||
vstring_str(query), dict_ldap->result_attributes->argv,
|
||||
dict_ldap->timeout, &res);
|
||||
|
||||
if (rc == LDAP_SERVER_DOWN) {
|
||||
if (msg_verbose)
|
||||
msg_info("%s: Lost connection for LDAP source %s, reopening",
|
||||
myname, dict_ldap->parser->name);
|
||||
|
||||
ldap_unbind(dict_ldap->ld);
|
||||
ldap_unbind_ext(dict_ldap->ld, 0, 0);
|
||||
dict_ldap->ld = DICT_LDAP_CONN(dict_ldap)->conn_ld = 0;
|
||||
dict_ldap_connect(dict_ldap);
|
||||
|
||||
@@ -1034,10 +1073,9 @@ static const char *dict_ldap_lookup(DICT *dict, const char *name)
|
||||
if (dict_errno)
|
||||
return (0);
|
||||
|
||||
rc = ldap_search_st(dict_ldap->ld, vstring_str(base),
|
||||
dict_ldap->scope, vstring_str(query),
|
||||
dict_ldap->result_attributes->argv,
|
||||
0, &tv, &res);
|
||||
rc = search_st(dict_ldap->ld, vstring_str(base), dict_ldap->scope,
|
||||
vstring_str(query), dict_ldap->result_attributes->argv,
|
||||
dict_ldap->timeout, &res);
|
||||
|
||||
}
|
||||
|
||||
@@ -1093,7 +1131,7 @@ static const char *dict_ldap_lookup(DICT *dict, const char *name)
|
||||
* Tear down the connection so it gets set up from scratch on the
|
||||
* next lookup.
|
||||
*/
|
||||
ldap_unbind(dict_ldap->ld);
|
||||
ldap_unbind_ext(dict_ldap->ld, 0, 0);
|
||||
dict_ldap->ld = DICT_LDAP_CONN(dict_ldap)->conn_ld = 0;
|
||||
|
||||
/*
|
||||
@@ -1130,7 +1168,7 @@ static void dict_ldap_close(DICT *dict)
|
||||
if (msg_verbose)
|
||||
msg_info("%s: Closed connection handle for LDAP source %s",
|
||||
myname, dict_ldap->parser->name);
|
||||
ldap_unbind(conn->conn_ld);
|
||||
ldap_unbind_ext(conn->conn_ld, 0, 0);
|
||||
}
|
||||
binhash_delete(conn_hash, ht->key, ht->key_len, myfree);
|
||||
}
|
||||
|
@@ -217,6 +217,7 @@ typedef struct {
|
||||
char *table;
|
||||
ARGV *hosts;
|
||||
PLPGSQL *pldb;
|
||||
HOST *active_host;
|
||||
} DICT_PGSQL;
|
||||
|
||||
|
||||
@@ -225,7 +226,8 @@ typedef struct {
|
||||
|
||||
/* internal function declarations */
|
||||
static PLPGSQL *plpgsql_init(ARGV *);
|
||||
static PGSQL_RES *plpgsql_query(PLPGSQL *, const char *, char *, char *, char *);
|
||||
static PGSQL_RES *plpgsql_query(DICT_PGSQL *, const char *, VSTRING *, char *,
|
||||
char *, char *);
|
||||
static void plpgsql_dealloc(PLPGSQL *);
|
||||
static void plpgsql_close_host(HOST *);
|
||||
static void plpgsql_down_host(HOST *);
|
||||
@@ -235,42 +237,84 @@ DICT *dict_pgsql_open(const char *, int, int);
|
||||
static void dict_pgsql_close(DICT *);
|
||||
static HOST *host_init(const char *);
|
||||
|
||||
|
||||
/* dict_pgsql_quote - escape SQL metacharacters in input string */
|
||||
|
||||
static void dict_pgsql_quote(DICT *unused, const char *name, VSTRING *result)
|
||||
static void dict_pgsql_quote(DICT *dict, const char *name, VSTRING *result)
|
||||
{
|
||||
const char *sub;
|
||||
DICT_PGSQL *dict_pgsql = (DICT_PGSQL *) dict;
|
||||
HOST *active_host = dict_pgsql->active_host;
|
||||
char *myname = "dict_pgsql_quote";
|
||||
size_t len = strlen(name);
|
||||
size_t buflen = 2*len + 1;
|
||||
int err = 1;
|
||||
|
||||
if (active_host == 0)
|
||||
msg_panic("%s: bogus dict_pgsql->active_host", myname);
|
||||
|
||||
/*
|
||||
* XXX We really should be using an escaper that is provided by the PGSQL
|
||||
* library. The code below seems to be over-kill (see RUS-CERT Advisory
|
||||
* 2001-08:01), but it's better to be safe than to be sorry -- Wietse
|
||||
* We won't get arithmetic overflows in 2*len + 1, because Postfix
|
||||
* input keys have reasonable size limits, better safe than sorry.
|
||||
*/
|
||||
for (sub = name; *sub; sub++) {
|
||||
switch(*sub) {
|
||||
case '\n':
|
||||
vstring_strcat(result, "\\n");
|
||||
break;
|
||||
case '\r':
|
||||
vstring_strcat(result, "\\r");
|
||||
break;
|
||||
case '\'':
|
||||
vstring_strcat(result, "\\'");
|
||||
break;
|
||||
case '"':
|
||||
vstring_strcat(result, "\\\"");
|
||||
break;
|
||||
case 0:
|
||||
vstring_strcat(result, "\\0");
|
||||
break;
|
||||
default:
|
||||
VSTRING_ADDCH(result, *sub);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (buflen <= len)
|
||||
msg_panic("%s: arithmetic overflow in 2*%lu+1",
|
||||
myname, (unsigned long) len);
|
||||
|
||||
/*
|
||||
* XXX Workaround: stop further processing when PQescapeStringConn()
|
||||
* (below) fails. A more proper fix requires invasive changes, not
|
||||
* suitable for a stable release.
|
||||
*/
|
||||
if (active_host->stat == STATFAIL)
|
||||
return;
|
||||
|
||||
/*
|
||||
* Escape the input string, using PQescapeStringConn(), because
|
||||
* the older PQescapeString() is not safe anymore, as stated by the
|
||||
* documentation.
|
||||
*
|
||||
* From current libpq (8.1.4) documentation:
|
||||
*
|
||||
* PQescapeStringConn writes an escaped version of the from string
|
||||
* to the to buffer, escaping special characters so that they cannot
|
||||
* cause any harm, and adding a terminating zero byte.
|
||||
*
|
||||
* ...
|
||||
*
|
||||
* The parameter from points to the first character of the string
|
||||
* that is to be escaped, and the length parameter gives the number
|
||||
* of bytes in this string. A terminating zero byte is not required,
|
||||
* and should not be counted in length.
|
||||
*
|
||||
* ...
|
||||
*
|
||||
* (The parameter) to shall point to a buffer that is able to hold
|
||||
* at least one more byte than twice the value of length, otherwise
|
||||
* the behavior is undefined.
|
||||
*
|
||||
* ...
|
||||
*
|
||||
* If the error parameter is not NULL, then *error is set to zero on
|
||||
* success, nonzero on error ... The output string is still generated
|
||||
* on error, but it can be expected that the server will reject it as
|
||||
* malformed. On error, a suitable message is stored in the conn
|
||||
* object, whether or not error is NULL.
|
||||
*/
|
||||
VSTRING_SPACE(result, buflen);
|
||||
PQescapeStringConn(active_host->db, vstring_end(result), name, len, &err);
|
||||
if (err == 0) {
|
||||
VSTRING_SKIP(result);
|
||||
} else {
|
||||
/*
|
||||
* PQescapeStringConn() failed. According to the docs, we still
|
||||
* have a valid, null-terminated output string, but we need not
|
||||
* rely on this behavior.
|
||||
*/
|
||||
msg_warn("dict pgsql: (host %s) cannot escape input string: %s",
|
||||
active_host->hostname, PQerrorMessage(active_host->db));
|
||||
active_host->stat = STATFAIL;
|
||||
VSTRING_TERMINATE(result);
|
||||
}
|
||||
}
|
||||
|
||||
/* dict_pgsql_lookup - find database entry */
|
||||
|
||||
@@ -324,14 +368,19 @@ static const char *dict_pgsql_lookup(DICT *dict, const char *name)
|
||||
}
|
||||
|
||||
/*
|
||||
* Suppress the actual lookup if the expansion is empty
|
||||
* Suppress the actual lookup if the expansion is empty.
|
||||
*
|
||||
* This initial expansion is outside the context of any
|
||||
* specific host connection, we just want to check the
|
||||
* key pre-requisites, so when quoting happens separately
|
||||
* for each connection, we don't bother with quoting...
|
||||
*/
|
||||
if (!db_common_expand(dict_pgsql->ctx, dict_pgsql->query,
|
||||
name, 0, query, dict_pgsql_quote))
|
||||
name, 0, query, 0))
|
||||
return (0);
|
||||
|
||||
/* do the query - set dict_errno & cleanup if there's an error */
|
||||
if ((query_res = plpgsql_query(pldb, vstring_str(query),
|
||||
if ((query_res = plpgsql_query(dict_pgsql, name, query,
|
||||
dict_pgsql->dbname,
|
||||
dict_pgsql->username,
|
||||
dict_pgsql->password)) == 0) {
|
||||
@@ -466,28 +515,104 @@ static void dict_pgsql_event(int unused_event, char *context)
|
||||
* close unnecessary active connections
|
||||
*/
|
||||
|
||||
static PGSQL_RES *plpgsql_query(PLPGSQL *PLDB,
|
||||
const char *query,
|
||||
static PGSQL_RES *plpgsql_query(DICT_PGSQL *dict_pgsql,
|
||||
const char *name,
|
||||
VSTRING *query,
|
||||
char *dbname,
|
||||
char *username,
|
||||
char *password)
|
||||
{
|
||||
PLPGSQL *PLDB = dict_pgsql->pldb;
|
||||
HOST *host;
|
||||
PGSQL_RES *res = 0;
|
||||
ExecStatusType status;
|
||||
|
||||
while ((host = dict_pgsql_get_active(PLDB, dbname, username, password)) != NULL) {
|
||||
if ((res = PQexec(host->db, query)) == 0) {
|
||||
msg_warn("pgsql query failed: %s", PQerrorMessage(host->db));
|
||||
/*
|
||||
* The active host is used to escape strings in the
|
||||
* context of the active connection's character encoding.
|
||||
*/
|
||||
dict_pgsql->active_host = host;
|
||||
VSTRING_RESET(query);
|
||||
VSTRING_TERMINATE(query);
|
||||
db_common_expand(dict_pgsql->ctx, dict_pgsql->query,
|
||||
name, 0, query, dict_pgsql_quote);
|
||||
dict_pgsql->active_host = 0;
|
||||
|
||||
/* Check for potential dict_pgsql_quote() failure. */
|
||||
if (host->stat == STATFAIL) {
|
||||
plpgsql_down_host(host);
|
||||
} else {
|
||||
if (msg_verbose)
|
||||
msg_info("dict_pgsql: successful query from host %s", host->hostname);
|
||||
event_request_timer(dict_pgsql_event, (char *) host, IDLE_CONN_INTV);
|
||||
break;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
return res;
|
||||
/*
|
||||
* Submit a command to the server. Be paranoid when processing
|
||||
* the result set: try to enumerate every successful case, and
|
||||
* reject everything else.
|
||||
*
|
||||
* From PostgreSQL 8.1.4 docs: (PQexec) returns a PGresult
|
||||
* pointer or possibly a null pointer. A non-null pointer will
|
||||
* generally be returned except in out-of-memory conditions or
|
||||
* serious errors such as inability to send the command to the
|
||||
* server.
|
||||
*/
|
||||
if ((res = PQexec(host->db, vstring_str(query))) != 0) {
|
||||
/*
|
||||
* XXX Because non-null result pointer does not imply success,
|
||||
* we need to check the command's result status.
|
||||
*
|
||||
* Section 28.3.1: A result of status PGRES_NONFATAL_ERROR
|
||||
* will never be returned directly by PQexec or other query
|
||||
* execution functions; results of this kind are instead
|
||||
* passed to the notice processor.
|
||||
*
|
||||
* PGRES_EMPTY_QUERY is being sent by the server when the
|
||||
* query string is empty. The sanity-checking done by
|
||||
* the Postfix infrastructure makes this case impossible,
|
||||
* so we need not handle this situation explicitly.
|
||||
*/
|
||||
switch ((status = PQresultStatus(res))) {
|
||||
case PGRES_TUPLES_OK:
|
||||
case PGRES_COMMAND_OK:
|
||||
/* Success. */
|
||||
if (msg_verbose)
|
||||
msg_info("dict_pgsql: successful query from host %s",
|
||||
host->hostname);
|
||||
event_request_timer(dict_pgsql_event, (char *) host,
|
||||
IDLE_CONN_INTV);
|
||||
return (res);
|
||||
case PGRES_FATAL_ERROR:
|
||||
msg_warn("pgsql query failed: fatal error from host %s: %s",
|
||||
host->hostname, PQresultErrorMessage(res));
|
||||
break;
|
||||
case PGRES_BAD_RESPONSE:
|
||||
msg_warn("pgsql query failed: protocol error, host %s",
|
||||
host->hostname);
|
||||
break;
|
||||
default:
|
||||
msg_warn("pgsql query failed: unknown code 0x%lx from host %s",
|
||||
(unsigned long) status, host->hostname);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
* This driver treats null pointers like fatal, non-null
|
||||
* result pointer errors, as suggested by the PostgreSQL
|
||||
* 8.1.4 documentation.
|
||||
*/
|
||||
msg_warn("pgsql query failed: fatal error from host %s: %s",
|
||||
host->hostname, PQerrorMessage(host->db));
|
||||
}
|
||||
|
||||
/*
|
||||
* XXX An error occurred. Clean up memory and skip this connection.
|
||||
*/
|
||||
if (res != 0)
|
||||
PQclear(res);
|
||||
plpgsql_down_host(host);
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -498,22 +623,33 @@ static PGSQL_RES *plpgsql_query(PLPGSQL *PLDB,
|
||||
static void plpgsql_connect_single(HOST *host, char *dbname, char *username, char *password)
|
||||
{
|
||||
if ((host->db = PQsetdbLogin(host->name, host->port, NULL, NULL,
|
||||
dbname, username, password)) != NULL) {
|
||||
if (PQstatus(host->db) == CONNECTION_OK) {
|
||||
dbname, username, password)) == NULL
|
||||
|| PQstatus(host->db) != CONNECTION_OK) {
|
||||
msg_warn("connect to pgsql server %s: %s",
|
||||
host->hostname, PQerrorMessage(host->db));
|
||||
plpgsql_down_host(host);
|
||||
return;
|
||||
}
|
||||
|
||||
if (msg_verbose)
|
||||
msg_info("dict_pgsql: successful connection to host %s",
|
||||
host->hostname);
|
||||
|
||||
/*
|
||||
* XXX Postfix does not send multi-byte characters. The following
|
||||
* piece of code is an explicit statement of this fact, and the
|
||||
* database server should not accept multi-byte information after
|
||||
* this point.
|
||||
*/
|
||||
if (PQsetClientEncoding(host->db, "LATIN1") != 0) {
|
||||
msg_warn("dict_pgsql: cannot set the encoding to LATIN1, skipping %s",
|
||||
host->hostname);
|
||||
plpgsql_down_host(host);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Success. */
|
||||
host->stat = STATACTIVE;
|
||||
} else {
|
||||
msg_warn("connect to pgsql server %s: %s",
|
||||
host->hostname, PQerrorMessage(host->db));
|
||||
plpgsql_down_host(host);
|
||||
}
|
||||
} else {
|
||||
msg_warn("connect to pgsql server %s: %s",
|
||||
host->hostname, PQerrorMessage(host->db));
|
||||
plpgsql_down_host(host);
|
||||
}
|
||||
}
|
||||
|
||||
/* plpgsql_close_host - close an established PostgreSQL connection */
|
||||
@@ -546,7 +682,6 @@ static void pgsql_parse_config(DICT_PGSQL *dict_pgsql, const char *pgsqlcf)
|
||||
{
|
||||
const char *myname = "pgsql_parse_config";
|
||||
CFG_PARSER *p;
|
||||
int i;
|
||||
char *hosts;
|
||||
VSTRING *query;
|
||||
char *select_function;
|
||||
@@ -627,6 +762,7 @@ DICT *dict_pgsql_open(const char *name, int open_flags, int dict_flags)
|
||||
dict_pgsql->dict.close = dict_pgsql_close;
|
||||
dict_pgsql->dict.flags = dict_flags;
|
||||
pgsql_parse_config(dict_pgsql, name);
|
||||
dict_pgsql->active_host = 0;
|
||||
dict_pgsql->pldb = plpgsql_init(dict_pgsql->hosts);
|
||||
if (dict_pgsql->pldb == NULL)
|
||||
msg_fatal("couldn't intialize pldb!\n");
|
||||
@@ -689,7 +825,6 @@ static HOST *host_init(const char *hostname)
|
||||
|
||||
static void dict_pgsql_close(DICT *dict)
|
||||
{
|
||||
int i;
|
||||
DICT_PGSQL *dict_pgsql = (DICT_PGSQL *) dict;
|
||||
|
||||
plpgsql_dealloc(dict_pgsql->pldb);
|
||||
|
@@ -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 "20060604"
|
||||
#define MAIL_RELEASE_DATE "20060611"
|
||||
#define MAIL_VERSION_NUMBER "2.3"
|
||||
|
||||
#ifdef SNAPSHOT
|
||||
|
@@ -95,11 +95,16 @@
|
||||
/* An I/O error happened, or the peer has disconnected unexpectedly.
|
||||
/* .IP SMTP_ERR_TIME
|
||||
/* The time limit specified to smtp_timeout_setup() was exceeded.
|
||||
/* .PP
|
||||
/* Additional error codes that may be used by applications:
|
||||
/* .IP SMTP_ERR_QUIET
|
||||
/* Perform silent cleanup; the error was already reported by
|
||||
/* the application.
|
||||
/* This error is never generated by the smtp_stream(3) module, but
|
||||
/* is defined for application-specific use.
|
||||
/* .IP SMTP_ERR_NONE
|
||||
/* A non-error code that makes setjmp()/longjmp() convenient
|
||||
/* to use.
|
||||
/* BUGS
|
||||
/* The timeout deadline affects all I/O on the named stream, not
|
||||
/* just the I/O done on behalf of this module.
|
||||
|
@@ -24,11 +24,13 @@
|
||||
#include <vstream.h>
|
||||
|
||||
/*
|
||||
* External interface.
|
||||
* External interface. The following codes are meant for use in longjmp(),
|
||||
* so they must all be non-zero.
|
||||
*/
|
||||
#define SMTP_ERR_EOF 1 /* unexpected client disconnect */
|
||||
#define SMTP_ERR_TIME 2 /* time out */
|
||||
#define SMTP_ERR_QUIET 4 /* silent cleanup (application) */
|
||||
#define SMTP_ERR_QUIET 3 /* silent cleanup (application) */
|
||||
#define SMTP_ERR_NONE 4 /* non-error case */
|
||||
|
||||
extern void smtp_timeout_setup(VSTREAM *, int);
|
||||
extern void PRINTFLIKE(2, 3) smtp_printf(VSTREAM *, const char *,...);
|
||||
|
@@ -11,9 +11,10 @@
|
||||
/* const char *unquoted;
|
||||
/* const char *special;
|
||||
/*
|
||||
/* VSTRING *xtext_unquote_append(unquoted, quoted)
|
||||
/* VSTRING *xtext_quote_append(unquoted, quoted, special)
|
||||
/* VSTRING *unquoted;
|
||||
/* const char *quoted;
|
||||
/* const char *special;
|
||||
/*
|
||||
/* VSTRING *xtext_unquote(unquoted, quoted)
|
||||
/* VSTRING *unquoted;
|
||||
|
@@ -711,7 +711,7 @@ static int qmgr_message_read(QMGR_MESSAGE *message)
|
||||
if (rec_type > 0)
|
||||
msg_warn("%s: ignoring out-of-order DSN original recipient <%.200s>",
|
||||
message->queue_id, dsn_orcpt);
|
||||
myfree(orig_rcpt);
|
||||
myfree(dsn_orcpt);
|
||||
}
|
||||
if (orig_rcpt != 0) {
|
||||
if (rec_type > 0)
|
||||
|
@@ -1002,14 +1002,18 @@ static int smtp_loop(SMTP_STATE *state, NOCLOBBER int send_state,
|
||||
*/
|
||||
case SMTP_STATE_XFORWARD_NAME_ADDR:
|
||||
vstring_strcpy(next_command, XFORWARD_CMD);
|
||||
if (session->features & SMTP_FEATURE_XFORWARD_NAME)
|
||||
vstring_sprintf_append(next_command, " %s=%s",
|
||||
XFORWARD_NAME, DEL_REQ_ATTR_AVAIL(request->client_name) ?
|
||||
request->client_name : XFORWARD_UNAVAILABLE);
|
||||
if (session->features & SMTP_FEATURE_XFORWARD_ADDR)
|
||||
vstring_sprintf_append(next_command, " %s=%s",
|
||||
XFORWARD_ADDR, DEL_REQ_ATTR_AVAIL(request->client_addr) ?
|
||||
request->client_addr : XFORWARD_UNAVAILABLE);
|
||||
if (session->features & SMTP_FEATURE_XFORWARD_NAME) {
|
||||
vstring_strcat(next_command, " " XFORWARD_NAME "=");
|
||||
xtext_quote_append(next_command,
|
||||
DEL_REQ_ATTR_AVAIL(request->client_name) ?
|
||||
request->client_name : XFORWARD_UNAVAILABLE, "");
|
||||
}
|
||||
if (session->features & SMTP_FEATURE_XFORWARD_ADDR) {
|
||||
vstring_strcat(next_command, " " XFORWARD_ADDR "=");
|
||||
xtext_quote_append(next_command,
|
||||
DEL_REQ_ATTR_AVAIL(request->client_addr) ?
|
||||
request->client_addr : XFORWARD_UNAVAILABLE, "");
|
||||
}
|
||||
if (session->send_proto_helo)
|
||||
next_state = SMTP_STATE_XFORWARD_PROTO_HELO;
|
||||
else
|
||||
@@ -1018,20 +1022,26 @@ static int smtp_loop(SMTP_STATE *state, NOCLOBBER int send_state,
|
||||
|
||||
case SMTP_STATE_XFORWARD_PROTO_HELO:
|
||||
vstring_strcpy(next_command, XFORWARD_CMD);
|
||||
if (session->features & SMTP_FEATURE_XFORWARD_PROTO)
|
||||
vstring_sprintf_append(next_command, " %s=%s",
|
||||
XFORWARD_PROTO, DEL_REQ_ATTR_AVAIL(request->client_proto) ?
|
||||
request->client_proto : XFORWARD_UNAVAILABLE);
|
||||
if (session->features & SMTP_FEATURE_XFORWARD_HELO)
|
||||
vstring_sprintf_append(next_command, " %s=%s",
|
||||
XFORWARD_HELO, DEL_REQ_ATTR_AVAIL(request->client_helo) ?
|
||||
request->client_helo : XFORWARD_UNAVAILABLE);
|
||||
if (session->features & SMTP_FEATURE_XFORWARD_DOMAIN)
|
||||
vstring_sprintf_append(next_command, " %s=%s", XFORWARD_DOMAIN,
|
||||
if (session->features & SMTP_FEATURE_XFORWARD_PROTO) {
|
||||
vstring_strcat(next_command, " " XFORWARD_PROTO "=");
|
||||
xtext_quote_append(next_command,
|
||||
DEL_REQ_ATTR_AVAIL(request->client_proto) ?
|
||||
request->client_proto : XFORWARD_UNAVAILABLE, "");
|
||||
}
|
||||
if (session->features & SMTP_FEATURE_XFORWARD_HELO) {
|
||||
vstring_strcat(next_command, " " XFORWARD_HELO "=");
|
||||
xtext_quote_append(next_command,
|
||||
DEL_REQ_ATTR_AVAIL(request->client_helo) ?
|
||||
request->client_helo : XFORWARD_UNAVAILABLE, "");
|
||||
}
|
||||
if (session->features & SMTP_FEATURE_XFORWARD_DOMAIN) {
|
||||
vstring_strcat(next_command, " " XFORWARD_DOMAIN "=");
|
||||
xtext_quote_append(next_command,
|
||||
DEL_REQ_ATTR_AVAIL(request->rewrite_context) == 0 ?
|
||||
XFORWARD_UNAVAILABLE :
|
||||
strcmp(request->rewrite_context, MAIL_ATTR_RWR_LOCAL) ?
|
||||
XFORWARD_DOM_REMOTE : XFORWARD_DOM_LOCAL);
|
||||
XFORWARD_DOM_REMOTE : XFORWARD_DOM_LOCAL, "");
|
||||
}
|
||||
next_state = SMTP_STATE_MAIL;
|
||||
break;
|
||||
|
||||
|
@@ -329,6 +329,7 @@ smtpd_proxy.o: ../../include/tls.h
|
||||
smtpd_proxy.o: ../../include/vbuf.h
|
||||
smtpd_proxy.o: ../../include/vstream.h
|
||||
smtpd_proxy.o: ../../include/vstring.h
|
||||
smtpd_proxy.o: ../../include/xtext.h
|
||||
smtpd_proxy.o: smtpd.h
|
||||
smtpd_proxy.o: smtpd_proxy.c
|
||||
smtpd_proxy.o: smtpd_proxy.h
|
||||
|
@@ -2662,6 +2662,7 @@ static int quit_cmd(SMTPD_STATE *state, int unused_argc, SMTPD_TOKEN *unused_arg
|
||||
static int xclient_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv)
|
||||
{
|
||||
SMTPD_TOKEN *argp;
|
||||
char *raw_value;
|
||||
char *attr_value;
|
||||
const char *bare_value;
|
||||
char *attr_name;
|
||||
@@ -2677,10 +2678,14 @@ static int xclient_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv)
|
||||
MAIL_PROTO_ESMTP, 2,
|
||||
0, -1,
|
||||
};
|
||||
int got_helo = 0;
|
||||
int got_proto = 0;
|
||||
|
||||
/*
|
||||
* Sanity checks. The XCLIENT command does not override its own access
|
||||
* control.
|
||||
* Sanity checks.
|
||||
*
|
||||
* XXX The XCLIENT command will override its own access control, so that
|
||||
* connection count/rate restrictions can be correctly simulated.
|
||||
*/
|
||||
if (IN_MAIL_TRANSACTION(state)) {
|
||||
state->error_mask |= MAIL_ERROR_PROTOCOL;
|
||||
@@ -2705,21 +2710,40 @@ static int xclient_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv)
|
||||
s = (_v) ? mystrdup(_v) : 0; \
|
||||
} while(0)
|
||||
|
||||
/*
|
||||
* Initialize.
|
||||
*/
|
||||
if (state->expand_buf == 0)
|
||||
state->expand_buf = vstring_alloc(100);
|
||||
|
||||
/*
|
||||
* Iterate over all attribute=value elements.
|
||||
*/
|
||||
for (argp = argv + 1; argp < argv + argc; argp++) {
|
||||
attr_name = argp->strval;
|
||||
|
||||
/*
|
||||
* For safety's sake mask non-printable characters. We'll do more
|
||||
* specific censoring later.
|
||||
*/
|
||||
if ((attr_value = split_at(attr_name, '=')) == 0 || *attr_value == 0) {
|
||||
if ((raw_value = split_at(attr_name, '=')) == 0 || *raw_value == 0) {
|
||||
state->error_mask |= MAIL_ERROR_PROTOCOL;
|
||||
smtpd_chat_reply(state, "501 5.5.4 Error: attribute=value expected");
|
||||
return (-1);
|
||||
}
|
||||
if (strlen(raw_value) > 255) {
|
||||
state->error_mask |= MAIL_ERROR_PROTOCOL;
|
||||
smtpd_chat_reply(state, "501 5.5.4 Error: attribute value too long");
|
||||
return (-1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Backwards compatibility: Postfix prior to version 2.3 does not
|
||||
* xtext encode attribute values.
|
||||
*/
|
||||
attr_value = xtext_unquote(state->expand_buf, raw_value) ?
|
||||
STR(state->expand_buf) : raw_value;
|
||||
|
||||
/*
|
||||
* For safety's sake mask non-printable characters. We'll do more
|
||||
* specific censoring later.
|
||||
*/
|
||||
printable(attr_value, '?');
|
||||
|
||||
/*
|
||||
@@ -2805,6 +2829,7 @@ static int xclient_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv)
|
||||
neuter(attr_value, NEUTER_CHARACTERS, '?');
|
||||
}
|
||||
UPDATE_STR(state->helo_name, attr_value);
|
||||
got_helo = 1;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -2818,6 +2843,7 @@ static int xclient_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv)
|
||||
return (-1);
|
||||
}
|
||||
UPDATE_STR(state->protocol, uppercase(attr_value));
|
||||
got_proto = 1;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -2840,7 +2866,41 @@ static int xclient_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv)
|
||||
state->namaddr =
|
||||
concatenate(state->name, "[", state->addr, "]", (char *) 0);
|
||||
}
|
||||
smtpd_chat_reply(state, "250 2.0.0 Ok");
|
||||
|
||||
/*
|
||||
* XXX Compatibility: when the client issues XCLIENT then we have to go
|
||||
* back to initial server greeting stage, otherwise we can't correctly
|
||||
* simulate smtpd_client_restrictions (with smtpd_delay_reject=0) and
|
||||
* Milter connect restrictions.
|
||||
*
|
||||
* XXX Compatibility: for accurate simulation we must also reset the HELO
|
||||
* information. We keep the information if it was specified in the
|
||||
* XCLIENT command.
|
||||
*
|
||||
* XXX The client connection count/rate control must be consistent in its
|
||||
* use of client address information in connect and disconnect events. We
|
||||
* re-evaluate xclient so that we correctly simulate connection
|
||||
* concurrency and connection rate restrictions.
|
||||
*
|
||||
* XXX Duplicated from smtpd_proto().
|
||||
*/
|
||||
xclient_allowed =
|
||||
namadr_list_match(xclient_hosts, state->name, state->addr);
|
||||
/* NOT: tls_reset() */
|
||||
if (got_helo == 0)
|
||||
helo_reset(state);
|
||||
if (got_proto == 0 && strcasecmp(state->protocol, MAIL_PROTO_SMTP) != 0) {
|
||||
myfree(state->protocol);
|
||||
state->protocol = mystrdup(MAIL_PROTO_SMTP);
|
||||
}
|
||||
#ifdef USE_SASL_AUTH
|
||||
if (var_smtpd_sasl_enable)
|
||||
smtpd_sasl_auth_reset(state);
|
||||
#endif
|
||||
chat_reset(state, 0);
|
||||
mail_reset(state);
|
||||
rcpt_reset(state);
|
||||
vstream_longjmp(state->client, SMTP_ERR_NONE);
|
||||
return (0);
|
||||
}
|
||||
|
||||
@@ -2849,6 +2909,7 @@ static int xclient_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv)
|
||||
static int xforward_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv)
|
||||
{
|
||||
SMTPD_TOKEN *argp;
|
||||
char *raw_value;
|
||||
char *attr_value;
|
||||
const char *bare_value;
|
||||
char *attr_name;
|
||||
@@ -2898,6 +2959,8 @@ static int xforward_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv)
|
||||
*/
|
||||
if (state->xforward.flags == 0)
|
||||
smtpd_xforward_preset(state);
|
||||
if (state->expand_buf == 0)
|
||||
state->expand_buf = vstring_alloc(100);
|
||||
|
||||
/*
|
||||
* Iterate over all attribute=value elements.
|
||||
@@ -2905,20 +2968,28 @@ static int xforward_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv)
|
||||
for (argp = argv + 1; argp < argv + argc; argp++) {
|
||||
attr_name = argp->strval;
|
||||
|
||||
/*
|
||||
* For safety's sake mask non-printable characters. We'll do more
|
||||
* specific censoring later.
|
||||
*/
|
||||
if ((attr_value = split_at(attr_name, '=')) == 0 || *attr_value == 0) {
|
||||
if ((raw_value = split_at(attr_name, '=')) == 0 || *raw_value == 0) {
|
||||
state->error_mask |= MAIL_ERROR_PROTOCOL;
|
||||
smtpd_chat_reply(state, "501 5.5.4 Error: attribute=value expected");
|
||||
return (-1);
|
||||
}
|
||||
if (strlen(attr_value) > 255) {
|
||||
if (strlen(raw_value) > 255) {
|
||||
state->error_mask |= MAIL_ERROR_PROTOCOL;
|
||||
smtpd_chat_reply(state, "501 5.5.4 Error: attribute value too long");
|
||||
return (-1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Backwards compatibility: Postfix prior to version 2.3 does not
|
||||
* xtext encode attribute values.
|
||||
*/
|
||||
attr_value = xtext_unquote(state->expand_buf, raw_value) ?
|
||||
STR(state->expand_buf) : raw_value;
|
||||
|
||||
/*
|
||||
* For safety's sake mask non-printable characters. We'll do more
|
||||
* specific censoring later.
|
||||
*/
|
||||
printable(attr_value, '?');
|
||||
|
||||
flag = name_code(xforward_flags, NAME_CODE_FLAG_NONE, attr_name);
|
||||
@@ -3268,7 +3339,7 @@ static STRING_LIST *smtpd_forbid_cmds;
|
||||
|
||||
/* smtpd_proto - talk the SMTP protocol */
|
||||
|
||||
static void smtpd_proto(SMTPD_STATE *state, const char *service)
|
||||
static void smtpd_proto(SMTPD_STATE *state)
|
||||
{
|
||||
int argc;
|
||||
SMTPD_TOKEN *argv;
|
||||
@@ -3276,6 +3347,7 @@ static void smtpd_proto(SMTPD_STATE *state, const char *service)
|
||||
int count;
|
||||
int crate;
|
||||
const char *ehlo_words;
|
||||
int status;
|
||||
|
||||
/*
|
||||
* Print a greeting banner and run the state machine. Read SMTP commands
|
||||
@@ -3297,7 +3369,9 @@ static void smtpd_proto(SMTPD_STATE *state, const char *service)
|
||||
*/
|
||||
smtp_timeout_setup(state->client, var_smtpd_tmout);
|
||||
|
||||
switch (vstream_setjmp(state->client)) {
|
||||
while ((status = vstream_setjmp(state->client)) == SMTP_ERR_NONE)
|
||||
/* void */ ;
|
||||
switch (status) {
|
||||
|
||||
default:
|
||||
msg_panic("smtpd_proto: unknown error reading from %s[%s]",
|
||||
@@ -3371,21 +3445,21 @@ static void smtpd_proto(SMTPD_STATE *state, const char *service)
|
||||
&& !xclient_allowed
|
||||
&& anvil_clnt
|
||||
&& !namadr_list_match(hogger_list, state->name, state->addr)
|
||||
&& anvil_clnt_connect(anvil_clnt, service, state->addr,
|
||||
&& anvil_clnt_connect(anvil_clnt, state->service, state->addr,
|
||||
&count, &crate) == ANVIL_STAT_OK) {
|
||||
if (var_smtpd_cconn_limit > 0 && count > var_smtpd_cconn_limit) {
|
||||
state->error_mask |= MAIL_ERROR_POLICY;
|
||||
smtpd_chat_reply(state, "421 4.7.0 %s Error: too many connections from %s",
|
||||
var_myhostname, state->addr);
|
||||
msg_warn("Connection concurrency limit exceeded: %d from %s for service %s",
|
||||
count, state->namaddr, service);
|
||||
count, state->namaddr, state->service);
|
||||
break;
|
||||
}
|
||||
if (var_smtpd_crate_limit > 0 && crate > var_smtpd_crate_limit) {
|
||||
smtpd_chat_reply(state, "421 4.7.0 %s Error: too many connections from %s",
|
||||
var_myhostname, state->addr);
|
||||
msg_warn("Connection rate limit exceeded: %d from %s for service %s",
|
||||
crate, state->namaddr, service);
|
||||
crate, state->namaddr, state->service);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -3499,7 +3573,7 @@ static void smtpd_proto(SMTPD_STATE *state, const char *service)
|
||||
&& !xclient_allowed
|
||||
&& anvil_clnt
|
||||
&& !namadr_list_match(hogger_list, state->name, state->addr))
|
||||
anvil_clnt_disconnect(anvil_clnt, service, state->addr);
|
||||
anvil_clnt_disconnect(anvil_clnt, state->service, state->addr);
|
||||
|
||||
/*
|
||||
* Log abnormal session termination, in case postmaster notification has
|
||||
@@ -3516,6 +3590,8 @@ static void smtpd_proto(SMTPD_STATE *state, const char *service)
|
||||
/*
|
||||
* Cleanup whatever information the client gave us during the SMTP
|
||||
* dialog.
|
||||
*
|
||||
* XXX Duplicated in xclient_cmd().
|
||||
*/
|
||||
#ifdef USE_TLS
|
||||
tls_reset(state);
|
||||
@@ -3596,7 +3672,7 @@ static void smtpd_service(VSTREAM *stream, char *service, char **argv)
|
||||
/*
|
||||
* Provide the SMTP service.
|
||||
*/
|
||||
smtpd_proto(&state, service);
|
||||
smtpd_proto(&state);
|
||||
|
||||
/*
|
||||
* After the client has gone away, clean up whatever we have set up at
|
||||
|
@@ -162,6 +162,7 @@
|
||||
#include <rec_type.h>
|
||||
#include <mail_proto.h>
|
||||
#include <mail_params.h> /* null_format_string */
|
||||
#include <xtext.h>
|
||||
|
||||
/* Application-specific. */
|
||||
|
||||
@@ -212,12 +213,20 @@ static int smtpd_xforward(SMTPD_STATE *state, VSTRING *buf, const char *name,
|
||||
#define CONSTR_LEN(s) (sizeof(s) - 1)
|
||||
#define PAYLOAD_LIMIT (512 - CONSTR_LEN("250 " XFORWARD_CMD "\r\n"))
|
||||
|
||||
/*
|
||||
* How much space does this attribute need?
|
||||
*/
|
||||
if (!value_available)
|
||||
value = XFORWARD_UNAVAILABLE;
|
||||
new_len = strlen(name) + strlen(value) + 2; /* SPACE name = value */
|
||||
|
||||
/*
|
||||
* Encode the attribute value.
|
||||
*/
|
||||
if (state->expand_buf == 0)
|
||||
state->expand_buf = vstring_alloc(100);
|
||||
xtext_quote(state->expand_buf, value, "");
|
||||
|
||||
/*
|
||||
* How much space does this attribute need? SPACE name = value.
|
||||
*/
|
||||
new_len = strlen(name) + strlen(STR(state->expand_buf)) + 2;
|
||||
if (new_len > PAYLOAD_LIMIT)
|
||||
msg_warn("%s command payload %s=%.10s... exceeds SMTP protocol limit",
|
||||
XFORWARD_CMD, name, value);
|
||||
@@ -228,7 +237,7 @@ static int smtpd_xforward(SMTPD_STATE *state, VSTRING *buf, const char *name,
|
||||
if (VSTRING_LEN(buf) > 0 && VSTRING_LEN(buf) + new_len > PAYLOAD_LIMIT)
|
||||
if ((ret = smtpd_xforward_flush(state, buf)) < 0)
|
||||
return (ret);
|
||||
vstring_sprintf_append(buf, " %s=%s", name, value);
|
||||
vstring_sprintf_append(buf, " %s=%s", name, STR(state->expand_buf));
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
Reference in New Issue
Block a user