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,
|
master/master_spawn.c, pickup/pickup.c, util/match_ops.c,
|
||||||
util/safe_open.c, xsasl/xsasl_cyrus_client.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:
|
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
|
Don't lose bits when converting st_dev into maildir file
|
||||||
name. It's 64 bits on Linux. Found with the BEAM source
|
name. It's 64 bits on Linux. Found with the BEAM source
|
||||||
code analyzer.
|
code analyzer.
|
||||||
|
@@ -194,8 +194,12 @@ http://www.t29.dk/antiantivirus.txt.
|
|||||||
DISCARD virus notification
|
DISCARD virus notification
|
||||||
/^Content-Disposition:.*VirusWarning.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
|
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
|
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
|
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
|
* Liviu Daia with further refinements from Jose Luis Tallon and Victor
|
||||||
Duchovni developed the common query, result_format, domain and
|
Duchovni developed the common query, result_format, domain and
|
||||||
expansion_limit interface for LDAP, MySQL and PosgreSQL.
|
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
|
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
|
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
|
XCLIENT. It is followed by the names of the attributes that the XCLIENT
|
||||||
implementation supports.
|
implementation supports.
|
||||||
|
|
||||||
The XCLIENT command may be sent at any time except in the middle of a mail
|
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
|
delivery transaction (i.e. between MAIL and DOT, or MAIL and RSET). The XCLIENT
|
||||||
pipelined when the server supports ESMTP command pipelining.
|
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
|
The syntax of XCLIENT requests is described below. Upper case and quoted
|
||||||
strings specify terminals, lowercase strings specify meta terminals, and SP is
|
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-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
|
* The NAME attribute specifies an SMTP client hostname (not an SMTP client
|
||||||
address), [UNAVAILABLE] when client hostname lookup failed due to a
|
address), [UNAVAILABLE] when client hostname lookup failed due to a
|
||||||
permanent error, or [TEMPUNAVAIL] when the lookup error condition was
|
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
|
* The HELO attribute specifies an SMTP HELO parameter value, or the value
|
||||||
[UNAVAILABLE] when the information is unavailable.
|
[UNAVAILABLE] when the information is unavailable.
|
||||||
|
|
||||||
Note 1: syntactically valid NAME and HELO attributes can be up to 255
|
Note 1: syntactically valid NAME and HELO attribute-value elements can be up to
|
||||||
characters long. The client must not send XCLIENT commands that exceed the 512
|
255 characters long. The client must not send XCLIENT commands that exceed the
|
||||||
character limit for SMTP commands. To avoid exceeding the limit the client
|
512 character limit for SMTP commands. To avoid exceeding the limit the client
|
||||||
should send the information in multiple XCLIENT commands.
|
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,
|
Note 2: [UNAVAILABLE], [TEMPUNAVAIL] and IPV6: may be specified in upper case,
|
||||||
lower case or mixed 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
|
||||||
|CCooddee|MMeeaanniinngg |
|
|
||||||
|_ _ _ _ _|_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ |
|
|
||||||
|250 |success |
|
|
||||||
|_ _ _ _ _|_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ |
|
|
||||||
|501 |bad command parameter syntax |
|
|
||||||
|_ _ _ _ _|_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ |
|
|
||||||
|503 |mail transaction in progress |
|
|
||||||
|_ _ _ _ _|_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ |
|
|
||||||
|421 |unable to proceed, disconnecting|
|
|
||||||
|_ _ _ _ _|_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ |
|
|
||||||
|
|
||||||
XXCCLLIIEENNTT EExxaammpplleess
|
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.
|
||||||
|
|
||||||
In the first example, the client impersonates a mail originating system by
|
For practical reasons it is not always possible to reset the complete server
|
||||||
passing all SMTP session information via XCLIENT commands. Information sent by
|
state to the initial SMTP greeting protocol stage:
|
||||||
the client is shown in bold font.
|
|
||||||
|
* 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 |
|
||||||
|
|_ _ _ _ _ _|_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ |
|
||||||
|
|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 EExxaammppllee
|
||||||
|
|
||||||
|
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
|
220 server.example.com ESMTP Postfix
|
||||||
EEHHLLOO cclliieenntt..eexxaammppllee..ccoomm
|
EEHHLLOO cclliieenntt..eexxaammppllee..ccoomm
|
||||||
@@ -99,10 +137,16 @@ the client is shown in bold font.
|
|||||||
250-ETRN
|
250-ETRN
|
||||||
250-XCLIENT NAME ADDR PROTO HELO
|
250-XCLIENT NAME ADDR PROTO HELO
|
||||||
250 8BITMIME
|
250 8BITMIME
|
||||||
XXCCLLIIEENNTT NNAAMMEE==ssppiikkee..ppoorrccuuppiinnee..oorrgg AADDDDRR==116688..110000..118899..22 PPRROOTTOO==EESSMMTTPP
|
XXCCLLIIEENNTT NNAAMMEE==ssppiikkee..ppoorrccuuppiinnee..oorrgg AADDDDRR==116688..110000..118899..22
|
||||||
250 Ok
|
220 server.example.com ESMTP Postfix
|
||||||
XXCCLLIIEENNTT HHEELLOO==ssppiikkee..ppoorrccuuppiinnee..oorrgg
|
EEHHLLOO ssppiikkee..ppoorrccuuppiinnee..oorrgg
|
||||||
250 Ok
|
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>>
|
MMAAIILL FFRROOMM::<<wwiieettssee@@ppoorrccuuppiinnee..oorrgg>>
|
||||||
250 Ok
|
250 Ok
|
||||||
RRCCPPTT TTOO::<<uusseerr@@eexxaammppllee..ccoomm>>
|
RRCCPPTT TTOO::<<uusseerr@@eexxaammppllee..ccoomm>>
|
||||||
@@ -115,33 +159,10 @@ the client is shown in bold font.
|
|||||||
QQUUIITT
|
QQUUIITT
|
||||||
221 Bye
|
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
|
SSeeccuurriittyy
|
||||||
|
|
||||||
The XCLIENT command changes audit trails and/or SMTP client access permissions.
|
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
|
Use of this command must be restricted to authorized SMTP clients.
|
||||||
XCLIENT command should not override its own access control mechanism.
|
|
||||||
|
|
||||||
SSMMTTPP ccoonnnneeccttiioonn ccaacchhiinngg
|
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
|
used to deliver mail on behalf of different SMTP clients, the XCLIENT
|
||||||
attributes need to be reset as appropriate before each MAIL FROM command.
|
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
|
information through the content filter to MTA2, so that the information
|
||||||
could be logged as part of mail handling transactions.
|
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
|
transmit client or message attributes incrementally. It is not implemented by
|
||||||
passing additional parameters via the MAIL FROM command, because doing so would
|
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
|
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
|
characters beyond the space that is already needed to support other extensions
|
||||||
extensions such as AUTH.
|
such as AUTH.
|
||||||
|
|
||||||
XXFFOORRWWAARRDD CCoommmmaanndd ssyynnttaaxx
|
XXFFOORRWWAARRDD CCoommmmaanndd ssyynnttaaxx
|
||||||
|
|
||||||
@@ -43,6 +43,10 @@ are in fact case insensitive.
|
|||||||
|
|
||||||
attribute-name = ( NAME | ADDR | PROTO | HELO | SOURCE )
|
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 NAME attribute specifies the up-stream hostname, or [UNAVAILABLE] when
|
||||||
the information is unavailable. The hostname may be a non-DNS hostname.
|
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.
|
not enclosed with []. The address may be a non-IP address.
|
||||||
|
|
||||||
* The PROTO attribute specifies the mail protocol for receiving mail from the
|
* 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.
|
characters, or [UNAVAILABLE] when the information is unavailable.
|
||||||
|
|
||||||
* The HELO attribute specifies the hostname that the up-stream host announced
|
* 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
|
MTA may decide to enable features such as header munging or address
|
||||||
qualification with mail from local sources but not other sources.
|
qualification with mail from local sources but not other sources.
|
||||||
|
|
||||||
Note 1: Attribute values must not be longer than 255 characters (specific
|
Note 1: an attribute-value element must not be longer than 255 characters
|
||||||
attributes may impose shorter lengths), must not contain control characters,
|
(specific attributes may impose shorter lengths). After xtext decoding,
|
||||||
non-ASCII characters, whitespace, or other characters that are special in
|
attribute values must not contain control characters, non-ASCII characters,
|
||||||
message headers. Future attributes that may violate this should use xtext
|
whitespace, or other characters that are special in message headers.
|
||||||
encoding as described in RFC 1891.
|
|
||||||
|
|
||||||
Note 2: DNS hostnames can be up to 255 characters long. The XFORWARD client
|
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
|
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
|
Note 4: the XFORWARD server implementation must not mix information from the
|
||||||
current SMTP session with forwarded information from an up-stream session.
|
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 |
|
|CCooddee|MMeeaanniinngg |
|
||||||
|_ _ _ _ _|_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ |
|
|_ _ _ _ _|_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ |
|
||||||
|250 |success |
|
|250 |success |
|
||||||
|_ _ _ _ _|_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ |
|
|_ _ _ _ _|_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ |
|
||||||
|
|421 |unable to proceed, disconnecting|
|
||||||
|
|_ _ _ _ _|_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ |
|
||||||
|501 |bad command parameter syntax |
|
|501 |bad command parameter syntax |
|
||||||
|_ _ _ _ _|_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ |
|
|_ _ _ _ _|_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ |
|
||||||
|503 |mail transaction in progress |
|
|503 |mail transaction in progress |
|
||||||
|_ _ _ _ _|_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ |
|
|_ _ _ _ _|_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ |
|
||||||
|421 |unable to proceed, disconnecting|
|
|550 |insufficient authorization |
|
||||||
|_ _ _ _ _|_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ |
|
|_ _ _ _ _|_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ |
|
||||||
|
|
||||||
XXFFOORRWWAARRDD EExxaammppllee
|
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
|
the same SMTP session. The XFORWARD attributes are reset after the MAIL FROM
|
||||||
command completes, so there is no risk of information leakage.
|
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
|
If you upgrade from Postfix 2.1 or earlier, read RELEASE_NOTES-2.2
|
||||||
before proceeding.
|
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
|
Incompatibility with snapshot 20060207
|
||||||
======================================
|
======================================
|
||||||
|
|
||||||
|
@@ -74,7 +74,7 @@ stress then it should not waste time. </p>
|
|||||||
|
|
||||||
<blockquote>
|
<blockquote>
|
||||||
<pre>
|
<pre>
|
||||||
/etc/postfix/main.cf:
|
/etc/postfix/<a href="postconf.5.html">main.cf</a>:
|
||||||
# Not needed with Postfix 2.1 and later.
|
# Not needed with Postfix 2.1 and later.
|
||||||
<a href="postconf.5.html#smtpd_error_sleep_time">smtpd_error_sleep_time</a> = 0
|
<a href="postconf.5.html#smtpd_error_sleep_time">smtpd_error_sleep_time</a> = 0
|
||||||
</pre>
|
</pre>
|
||||||
@@ -105,7 +105,8 @@ Received: from porcupine.org ...
|
|||||||
</blockquote>
|
</blockquote>
|
||||||
|
|
||||||
<p> Then I know that this is almost certainly forged mail (almost;
|
<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>
|
sent by my systems looks like this: </p>
|
||||||
|
|
||||||
<blockquote>
|
<blockquote>
|
||||||
@@ -143,7 +144,7 @@ patterns like this: </p>
|
|||||||
|
|
||||||
<blockquote>
|
<blockquote>
|
||||||
<pre>
|
<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#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
|
<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>
|
</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
|
<p> Netscape Messenger (and reportedly, Mozilla) sends a HELO name
|
||||||
that is identical to the sender address domain part. If you have
|
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>
|
<blockquote>
|
||||||
<pre>
|
<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
|
<a href="postconf.5.html#canonical_maps">canonical_maps</a> = hash:/etc/postfix/canonical
|
||||||
|
|
||||||
/etc/postfix/canonical:
|
/etc/postfix/canonical:
|
||||||
@@ -225,7 +226,7 @@ and is very easy to stop.
|
|||||||
|
|
||||||
<blockquote>
|
<blockquote>
|
||||||
<pre>
|
<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#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
|
<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>
|
</pre>
|
||||||
</blockquote>
|
</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
|
<p> A plea to virus or spam scanner operators: please do not make
|
||||||
the problem worse by sending return mail to forged sender addresses.
|
the problem worse by sending return mail to forged sender addresses.
|
||||||
You're only harassing innocent people. If you must return mail to
|
You're only harassing innocent people. If you must return mail to
|
||||||
the purported sender, please return the full message headers, so
|
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>
|
</body>
|
||||||
|
|
||||||
|
@@ -57,11 +57,11 @@ the location of the libpq library file. </p>
|
|||||||
<h2>Configuring PostgreSQL lookup tables</h2>
|
<h2>Configuring PostgreSQL lookup tables</h2>
|
||||||
|
|
||||||
<p> Once Postfix is built with pgsql support, you can specify a
|
<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>
|
<blockquote>
|
||||||
<pre>
|
<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
|
<a href="postconf.5.html#alias_maps">alias_maps</a> = <a href="pgsql_table.5.html">pgsql</a>:/etc/postfix/pgsql-aliases.cf
|
||||||
</pre>
|
</pre>
|
||||||
</blockquote>
|
</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> LaMont Jones was the initial Postfix pgsql maintainer.</li>
|
||||||
|
|
||||||
<li> Liviu Daia revised the configuration interface and added the
|
<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>
|
configuration feature.</li>
|
||||||
|
|
||||||
<li> Liviu Daia with further refinements from Jose Luis Tallon and
|
<li> Liviu Daia with further refinements from Jose Luis Tallon and
|
||||||
Victor Duchovni developed the common query, result_format, domain and
|
Victor Duchovni developed the common query, result_format, domain and
|
||||||
expansion_limit interface for LDAP, MySQL and PosgreSQL.</li>
|
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>
|
</ul>
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
|
@@ -52,17 +52,19 @@
|
|||||||
|
|
||||||
<h2>XCLIENT Command syntax</h2>
|
<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>
|
of this document. </p>
|
||||||
|
|
||||||
<p> In SMTP server EHLO replies, the keyword associated with this
|
<p> In SMTP server EHLO replies, the keyword associated with this
|
||||||
extension is XCLIENT. It is followed by the names of the attributes
|
extension is XCLIENT. It is followed by the names of the attributes
|
||||||
that the XCLIENT implementation supports. </p>
|
that the XCLIENT implementation supports. </p>
|
||||||
|
|
||||||
<p> The XCLIENT command may be sent at any time except in the middle
|
<p> The XCLIENT command may be sent at any time, except in the
|
||||||
of a mail delivery transaction (i.e. between MAIL and DOT). The
|
middle of a mail delivery transaction (i.e. between MAIL and DOT,
|
||||||
XCLIENT command may be pipelined when the server supports ESMTP
|
or MAIL and RSET). The XCLIENT command may be pipelined when the
|
||||||
command pipelining. </p>
|
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
|
<p> The syntax of XCLIENT requests is described below. Upper case
|
||||||
and quoted strings specify terminals, lowercase strings specify
|
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>
|
<p>
|
||||||
attribute-name = ( NAME | ADDR | PROTO | HELO )
|
attribute-name = ( NAME | ADDR | PROTO | HELO )
|
||||||
</p>
|
</p>
|
||||||
|
<p>
|
||||||
|
attribute-value = xtext
|
||||||
|
</p>
|
||||||
</blockquote>
|
</blockquote>
|
||||||
|
|
||||||
<ul>
|
<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
|
<li> <p> The NAME attribute specifies an SMTP client hostname
|
||||||
(not an SMTP client address), [UNAVAILABLE] when client hostname
|
(not an SMTP client address), [UNAVAILABLE] when client hostname
|
||||||
lookup failed due to a permanent error, or [TEMPUNAVAIL] when
|
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>
|
</ul>
|
||||||
|
|
||||||
<p> Note 1: syntactically valid NAME and HELO attributes can be up
|
<p> Note 1: syntactically valid NAME and HELO attribute-value
|
||||||
to 255 characters long. The client must not send XCLIENT commands
|
elements can be up to 255 characters long. The client must not send
|
||||||
that exceed the 512 character limit for SMTP commands. To avoid
|
XCLIENT commands that exceed the 512 character limit for SMTP
|
||||||
exceeding the limit the client should send the information in
|
commands. To avoid exceeding the limit the client should send the
|
||||||
multiple XCLIENT commands. </p>
|
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
|
<p> Note 2: [UNAVAILABLE], [TEMPUNAVAIL] and IPV6: may be specified
|
||||||
in upper case, lower case or mixed case. </p>
|
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>
|
<blockquote>
|
||||||
|
|
||||||
@@ -117,23 +161,28 @@ in upper case, lower case or mixed case. </p>
|
|||||||
|
|
||||||
<tr> <th> Code </th> <th> Meaning </th> </tr>
|
<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> 501 </td> <td> bad command parameter syntax </td> </tr>
|
||||||
|
|
||||||
<tr> <td> 503 </td> <td> mail transaction in progress </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>
|
</table>
|
||||||
|
|
||||||
</blockquote>
|
</blockquote>
|
||||||
|
|
||||||
<h2>XCLIENT Examples</h2>
|
<h2>XCLIENT Example</h2>
|
||||||
|
|
||||||
<p> In the first example, the client impersonates a mail originating
|
<p> In the example, the client impersonates a mail originating
|
||||||
system by passing all SMTP session information via XCLIENT commands.
|
system by passing all SMTP client information via the XCLIENT
|
||||||
Information sent by the client is shown in bold font.
|
command. Information sent by the client is shown in bold font.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<blockquote>
|
<blockquote>
|
||||||
@@ -147,10 +196,16 @@ Information sent by the client is shown in bold font.
|
|||||||
250-ETRN
|
250-ETRN
|
||||||
250-XCLIENT NAME ADDR PROTO HELO
|
250-XCLIENT NAME ADDR PROTO HELO
|
||||||
250 8BITMIME
|
250 8BITMIME
|
||||||
<b>XCLIENT NAME=spike.porcupine.org ADDR=168.100.189.2 PROTO=ESMTP </b>
|
<b>XCLIENT NAME=spike.porcupine.org ADDR=168.100.189.2</b>
|
||||||
250 Ok
|
220 server.example.com ESMTP Postfix
|
||||||
<b>XCLIENT HELO=spike.porcupine.org</b>
|
<b>EHLO spike.porcupine.org</b>
|
||||||
250 Ok
|
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>
|
<b>MAIL FROM:<wietse@porcupine.org></b>
|
||||||
250 Ok
|
250 Ok
|
||||||
<b>RCPT TO:<user@example.com></b>
|
<b>RCPT TO:<user@example.com></b>
|
||||||
@@ -165,39 +220,11 @@ Information sent by the client is shown in bold font.
|
|||||||
</pre>
|
</pre>
|
||||||
</blockquote>
|
</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>
|
<h2>Security</h2>
|
||||||
|
|
||||||
<p> The XCLIENT command changes audit trails and/or SMTP client
|
<p> The XCLIENT command changes audit trails and/or SMTP client
|
||||||
access permissions. Use of this command must be restricted to
|
access permissions. Use of this command must be restricted to
|
||||||
authorized SMTP clients. However, the XCLIENT command should not
|
authorized SMTP clients. </p>
|
||||||
override its own access control mechanism. </p>
|
|
||||||
|
|
||||||
<h2>SMTP connection caching</h2>
|
<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
|
clients, the XCLIENT attributes need to be reset as appropriate
|
||||||
before each MAIL FROM command. </p>
|
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>
|
</body>
|
||||||
|
|
||||||
</html>
|
</html>
|
||||||
|
@@ -35,13 +35,13 @@
|
|||||||
|
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
<p> This extension is implemented as a separate command, and can
|
<p> This extension is implemented as a separate EMSTP command, and
|
||||||
be used to transmit client or message attributes incrementally.
|
can be used to transmit client or message attributes incrementally.
|
||||||
It is not implemented by passing additional parameters via the MAIL
|
It is not implemented by passing additional parameters via the MAIL
|
||||||
FROM command, because doing so would require extending the MAIL
|
FROM command, because doing so would require extending the MAIL
|
||||||
FROM command length limit by another 600 or more characters beyond
|
FROM command length limit by another 600 or more characters beyond
|
||||||
the space that is already needed in order to support other extensions
|
the space that is already needed to support other extensions such
|
||||||
such as AUTH. </p>
|
as AUTH. </p>
|
||||||
|
|
||||||
<h2>XFORWARD Command syntax</h2>
|
<h2>XFORWARD Command syntax</h2>
|
||||||
|
|
||||||
@@ -71,10 +71,16 @@ names are shown in upper case, they are in fact case insensitive.
|
|||||||
<p>
|
<p>
|
||||||
attribute-name = ( NAME | ADDR | PROTO | HELO | SOURCE )
|
attribute-name = ( NAME | ADDR | PROTO | HELO | SOURCE )
|
||||||
</p>
|
</p>
|
||||||
|
<p>
|
||||||
|
attribute-value = xtext
|
||||||
|
</p>
|
||||||
</blockquote>
|
</blockquote>
|
||||||
|
|
||||||
<ul>
|
<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,
|
<li> <p> The NAME attribute specifies the up-stream hostname,
|
||||||
or [UNAVAILABLE] when the information is unavailable. The
|
or [UNAVAILABLE] when the information is unavailable. The
|
||||||
hostname may be a non-DNS hostname. </p>
|
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>
|
be a non-IP address. </p>
|
||||||
|
|
||||||
<li> <p> The PROTO attribute specifies the mail protocol for
|
<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]
|
non-SMTP protocol name of up to 64 characters, or [UNAVAILABLE]
|
||||||
when the information is unavailable. </p>
|
when the information is unavailable. </p>
|
||||||
|
|
||||||
@@ -105,12 +111,11 @@ names are shown in upper case, they are in fact case insensitive.
|
|||||||
|
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
<p> Note 1: Attribute values must not be longer than 255 characters
|
<p> Note 1: an attribute-value element must not be longer than
|
||||||
(specific attributes may impose shorter lengths), must not contain
|
255 characters (specific attributes may impose shorter lengths).
|
||||||
control characters, non-ASCII characters, whitespace, or other
|
After xtext decoding, attribute values must not contain control
|
||||||
characters that are special in message headers. Future attributes
|
characters, non-ASCII characters, whitespace, or other characters
|
||||||
that may violate this should use xtext encoding as described in
|
that are special in message headers. </p>
|
||||||
<a href="http://www.faqs.org/rfcs/rfc1891.html">RFC 1891</a>. </p>
|
|
||||||
|
|
||||||
<p> Note 2: DNS hostnames can be up to 255 characters long. The
|
<p> Note 2: DNS hostnames can be up to 255 characters long. The
|
||||||
XFORWARD client implementation must not send XFORWARD commands that
|
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
|
information from the current SMTP session with forwarded information
|
||||||
from an up-stream session. </p>
|
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>
|
<blockquote>
|
||||||
|
|
||||||
@@ -133,11 +151,13 @@ from an up-stream session. </p>
|
|||||||
|
|
||||||
<tr> <td> 250 </td> <td> success </td> </tr>
|
<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> 501 </td> <td> bad command parameter syntax </td> </tr>
|
||||||
|
|
||||||
<tr> <td> 503 </td> <td> mail transaction in progress </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>
|
</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
|
reset after the MAIL FROM command completes, so there is no risk
|
||||||
of information leakage. </p>
|
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>
|
</body>
|
||||||
|
|
||||||
</html>
|
</html>
|
||||||
|
@@ -105,7 +105,8 @@ Received: from porcupine.org ...
|
|||||||
</blockquote>
|
</blockquote>
|
||||||
|
|
||||||
<p> Then I know that this is almost certainly forged mail (almost;
|
<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>
|
sent by my systems looks like this: </p>
|
||||||
|
|
||||||
<blockquote>
|
<blockquote>
|
||||||
@@ -182,7 +183,7 @@ and "<tt>)</tt>" would be grouping operators. </p>
|
|||||||
|
|
||||||
</ul>
|
</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
|
<p> Netscape Messenger (and reportedly, Mozilla) sends a HELO name
|
||||||
that is identical to the sender address domain part. If you have
|
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>
|
</pre>
|
||||||
</blockquote>
|
</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
|
<p> A plea to virus or spam scanner operators: please do not make
|
||||||
the problem worse by sending return mail to forged sender addresses.
|
the problem worse by sending return mail to forged sender addresses.
|
||||||
You're only harassing innocent people. If you must return mail to
|
You're only harassing innocent people. If you must return mail to
|
||||||
the purported sender, please return the full message headers, so
|
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>
|
</body>
|
||||||
|
|
||||||
|
@@ -139,6 +139,10 @@ configuration feature.</li>
|
|||||||
Victor Duchovni developed the common query, result_format, domain and
|
Victor Duchovni developed the common query, result_format, domain and
|
||||||
expansion_limit interface for LDAP, MySQL and PosgreSQL.</li>
|
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>
|
</ul>
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
|
@@ -52,17 +52,19 @@
|
|||||||
|
|
||||||
<h2>XCLIENT Command syntax</h2>
|
<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>
|
of this document. </p>
|
||||||
|
|
||||||
<p> In SMTP server EHLO replies, the keyword associated with this
|
<p> In SMTP server EHLO replies, the keyword associated with this
|
||||||
extension is XCLIENT. It is followed by the names of the attributes
|
extension is XCLIENT. It is followed by the names of the attributes
|
||||||
that the XCLIENT implementation supports. </p>
|
that the XCLIENT implementation supports. </p>
|
||||||
|
|
||||||
<p> The XCLIENT command may be sent at any time except in the middle
|
<p> The XCLIENT command may be sent at any time, except in the
|
||||||
of a mail delivery transaction (i.e. between MAIL and DOT). The
|
middle of a mail delivery transaction (i.e. between MAIL and DOT,
|
||||||
XCLIENT command may be pipelined when the server supports ESMTP
|
or MAIL and RSET). The XCLIENT command may be pipelined when the
|
||||||
command pipelining. </p>
|
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
|
<p> The syntax of XCLIENT requests is described below. Upper case
|
||||||
and quoted strings specify terminals, lowercase strings specify
|
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>
|
<p>
|
||||||
attribute-name = ( NAME | ADDR | PROTO | HELO )
|
attribute-name = ( NAME | ADDR | PROTO | HELO )
|
||||||
</p>
|
</p>
|
||||||
|
<p>
|
||||||
|
attribute-value = xtext
|
||||||
|
</p>
|
||||||
</blockquote>
|
</blockquote>
|
||||||
|
|
||||||
<ul>
|
<ul>
|
||||||
|
|
||||||
|
<li> <p> Attribute values are xtext encoded as per RFC 1891.
|
||||||
|
</p>
|
||||||
|
|
||||||
<li> <p> The NAME attribute specifies an SMTP client hostname
|
<li> <p> The NAME attribute specifies an SMTP client hostname
|
||||||
(not an SMTP client address), [UNAVAILABLE] when client hostname
|
(not an SMTP client address), [UNAVAILABLE] when client hostname
|
||||||
lookup failed due to a permanent error, or [TEMPUNAVAIL] when
|
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>
|
</ul>
|
||||||
|
|
||||||
<p> Note 1: syntactically valid NAME and HELO attributes can be up
|
<p> Note 1: syntactically valid NAME and HELO attribute-value
|
||||||
to 255 characters long. The client must not send XCLIENT commands
|
elements can be up to 255 characters long. The client must not send
|
||||||
that exceed the 512 character limit for SMTP commands. To avoid
|
XCLIENT commands that exceed the 512 character limit for SMTP
|
||||||
exceeding the limit the client should send the information in
|
commands. To avoid exceeding the limit the client should send the
|
||||||
multiple XCLIENT commands. </p>
|
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
|
<p> Note 2: [UNAVAILABLE], [TEMPUNAVAIL] and IPV6: may be specified
|
||||||
in upper case, lower case or mixed case. </p>
|
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>
|
<blockquote>
|
||||||
|
|
||||||
@@ -117,23 +161,28 @@ in upper case, lower case or mixed case. </p>
|
|||||||
|
|
||||||
<tr> <th> Code </th> <th> Meaning </th> </tr>
|
<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> 501 </td> <td> bad command parameter syntax </td> </tr>
|
||||||
|
|
||||||
<tr> <td> 503 </td> <td> mail transaction in progress </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>
|
</table>
|
||||||
|
|
||||||
</blockquote>
|
</blockquote>
|
||||||
|
|
||||||
<h2>XCLIENT Examples</h2>
|
<h2>XCLIENT Example</h2>
|
||||||
|
|
||||||
<p> In the first example, the client impersonates a mail originating
|
<p> In the example, the client impersonates a mail originating
|
||||||
system by passing all SMTP session information via XCLIENT commands.
|
system by passing all SMTP client information via the XCLIENT
|
||||||
Information sent by the client is shown in bold font.
|
command. Information sent by the client is shown in bold font.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<blockquote>
|
<blockquote>
|
||||||
@@ -147,10 +196,16 @@ Information sent by the client is shown in bold font.
|
|||||||
250-ETRN
|
250-ETRN
|
||||||
250-XCLIENT NAME ADDR PROTO HELO
|
250-XCLIENT NAME ADDR PROTO HELO
|
||||||
250 8BITMIME
|
250 8BITMIME
|
||||||
<b>XCLIENT NAME=spike.porcupine.org ADDR=168.100.189.2 PROTO=ESMTP </b>
|
<b>XCLIENT NAME=spike.porcupine.org ADDR=168.100.189.2</b>
|
||||||
250 Ok
|
220 server.example.com ESMTP Postfix
|
||||||
<b>XCLIENT HELO=spike.porcupine.org</b>
|
<b>EHLO spike.porcupine.org</b>
|
||||||
250 Ok
|
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>
|
<b>MAIL FROM:<wietse@porcupine.org></b>
|
||||||
250 Ok
|
250 Ok
|
||||||
<b>RCPT TO:<user@example.com></b>
|
<b>RCPT TO:<user@example.com></b>
|
||||||
@@ -165,39 +220,11 @@ Information sent by the client is shown in bold font.
|
|||||||
</pre>
|
</pre>
|
||||||
</blockquote>
|
</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>
|
<h2>Security</h2>
|
||||||
|
|
||||||
<p> The XCLIENT command changes audit trails and/or SMTP client
|
<p> The XCLIENT command changes audit trails and/or SMTP client
|
||||||
access permissions. Use of this command must be restricted to
|
access permissions. Use of this command must be restricted to
|
||||||
authorized SMTP clients. However, the XCLIENT command should not
|
authorized SMTP clients. </p>
|
||||||
override its own access control mechanism. </p>
|
|
||||||
|
|
||||||
<h2>SMTP connection caching</h2>
|
<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
|
clients, the XCLIENT attributes need to be reset as appropriate
|
||||||
before each MAIL FROM command. </p>
|
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>
|
</body>
|
||||||
|
|
||||||
</html>
|
</html>
|
||||||
|
@@ -35,13 +35,13 @@
|
|||||||
|
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
<p> This extension is implemented as a separate command, and can
|
<p> This extension is implemented as a separate EMSTP command, and
|
||||||
be used to transmit client or message attributes incrementally.
|
can be used to transmit client or message attributes incrementally.
|
||||||
It is not implemented by passing additional parameters via the MAIL
|
It is not implemented by passing additional parameters via the MAIL
|
||||||
FROM command, because doing so would require extending the MAIL
|
FROM command, because doing so would require extending the MAIL
|
||||||
FROM command length limit by another 600 or more characters beyond
|
FROM command length limit by another 600 or more characters beyond
|
||||||
the space that is already needed in order to support other extensions
|
the space that is already needed to support other extensions such
|
||||||
such as AUTH. </p>
|
as AUTH. </p>
|
||||||
|
|
||||||
<h2>XFORWARD Command syntax</h2>
|
<h2>XFORWARD Command syntax</h2>
|
||||||
|
|
||||||
@@ -71,10 +71,16 @@ names are shown in upper case, they are in fact case insensitive.
|
|||||||
<p>
|
<p>
|
||||||
attribute-name = ( NAME | ADDR | PROTO | HELO | SOURCE )
|
attribute-name = ( NAME | ADDR | PROTO | HELO | SOURCE )
|
||||||
</p>
|
</p>
|
||||||
|
<p>
|
||||||
|
attribute-value = xtext
|
||||||
|
</p>
|
||||||
</blockquote>
|
</blockquote>
|
||||||
|
|
||||||
<ul>
|
<ul>
|
||||||
|
|
||||||
|
<li> <p> Attribute values are xtext encoded as per RFC 1891.
|
||||||
|
</p>
|
||||||
|
|
||||||
<li> <p> The NAME attribute specifies the up-stream hostname,
|
<li> <p> The NAME attribute specifies the up-stream hostname,
|
||||||
or [UNAVAILABLE] when the information is unavailable. The
|
or [UNAVAILABLE] when the information is unavailable. The
|
||||||
hostname may be a non-DNS hostname. </p>
|
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>
|
be a non-IP address. </p>
|
||||||
|
|
||||||
<li> <p> The PROTO attribute specifies the mail protocol for
|
<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]
|
non-SMTP protocol name of up to 64 characters, or [UNAVAILABLE]
|
||||||
when the information is unavailable. </p>
|
when the information is unavailable. </p>
|
||||||
|
|
||||||
@@ -105,12 +111,11 @@ names are shown in upper case, they are in fact case insensitive.
|
|||||||
|
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
<p> Note 1: Attribute values must not be longer than 255 characters
|
<p> Note 1: an attribute-value element must not be longer than
|
||||||
(specific attributes may impose shorter lengths), must not contain
|
255 characters (specific attributes may impose shorter lengths).
|
||||||
control characters, non-ASCII characters, whitespace, or other
|
After xtext decoding, attribute values must not contain control
|
||||||
characters that are special in message headers. Future attributes
|
characters, non-ASCII characters, whitespace, or other characters
|
||||||
that may violate this should use xtext encoding as described in
|
that are special in message headers. </p>
|
||||||
RFC 1891. </p>
|
|
||||||
|
|
||||||
<p> Note 2: DNS hostnames can be up to 255 characters long. The
|
<p> Note 2: DNS hostnames can be up to 255 characters long. The
|
||||||
XFORWARD client implementation must not send XFORWARD commands that
|
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
|
information from the current SMTP session with forwarded information
|
||||||
from an up-stream session. </p>
|
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>
|
<blockquote>
|
||||||
|
|
||||||
@@ -133,11 +151,13 @@ from an up-stream session. </p>
|
|||||||
|
|
||||||
<tr> <td> 250 </td> <td> success </td> </tr>
|
<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> 501 </td> <td> bad command parameter syntax </td> </tr>
|
||||||
|
|
||||||
<tr> <td> 503 </td> <td> mail transaction in progress </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>
|
</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
|
reset after the MAIL FROM command completes, so there is no risk
|
||||||
of information leakage. </p>
|
of information leakage. </p>
|
||||||
|
|
||||||
|
<h2> References </h2>
|
||||||
|
|
||||||
|
<p> Moore, K, "SMTP Service Extension for Delivery Status Notifications",
|
||||||
|
RFC 1891, January 1996. </p>
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
</html>
|
</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;
|
DB_COMMON_CTX *ctx = (DB_COMMON_CTX *) ctxArg;
|
||||||
const char *vdomain = 0;
|
const char *vdomain = 0;
|
||||||
const char *kdomain = 0;
|
const char *kdomain = 0;
|
||||||
|
const char *domain = 0;
|
||||||
|
int dflag = key ? DB_COMMON_VALUE_DOMAIN : DB_COMMON_KEY_DOMAIN;
|
||||||
char *vuser = 0;
|
char *vuser = 0;
|
||||||
char *kuser = 0;
|
char *kuser = 0;
|
||||||
ARGV *parts = 0;
|
ARGV *parts = 0;
|
||||||
@@ -397,6 +399,12 @@ int db_common_expand(void *ctxArg, const char *format, const char *value,
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case 'd':
|
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);
|
QUOTE_VAL(ctx->dict, quote_func, vdomain, result);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -426,10 +434,13 @@ int db_common_expand(void *ctxArg, const char *format, const char *value,
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case 'D':
|
case 'D':
|
||||||
if (key)
|
if (!(ctx->flags & DB_COMMON_KEY_DOMAIN))
|
||||||
QUOTE_VAL(ctx->dict, quote_func, kdomain, result);
|
msg_panic("%s: %s: %s: bad query/result template context",
|
||||||
else
|
myname, ctx->dict->name, format);
|
||||||
QUOTE_VAL(ctx->dict, quote_func, vdomain, result);
|
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;
|
break;
|
||||||
|
|
||||||
case '1':
|
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
|
* guaranteed to be initialized and hold enough elements to
|
||||||
* satisfy the query template.
|
* 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,
|
QUOTE_VAL(ctx->dict, quote_func,
|
||||||
parts->argv[parts->argc - (*cp - '0')], result);
|
parts->argv[parts->argc - (*cp - '0')], result);
|
||||||
break;
|
break;
|
||||||
|
@@ -351,31 +351,78 @@ static int dict_ldap_set_errno(LDAP * ld, int rc)
|
|||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/* dict_ldap_result - Read and parse LDAP result */
|
||||||
* We need a version of ldap_bind that times out, otherwise all
|
|
||||||
* of Postfix can get wedged during daemon initialization.
|
static int dict_ldap_result(LDAP *ld, int msgid, int timeout, LDAPMessage **res)
|
||||||
*/
|
|
||||||
static int dict_ldap_bind_st(DICT_LDAP *dict_ldap)
|
|
||||||
{
|
{
|
||||||
int msgid;
|
int rc;
|
||||||
LDAPMessage *res;
|
|
||||||
struct timeval mytimeval;
|
struct timeval mytimeval;
|
||||||
|
|
||||||
if ((msgid = ldap_bind(dict_ldap->ld, dict_ldap->bind_dn,
|
mytimeval.tv_sec = timeout;
|
||||||
dict_ldap->bind_pw, LDAP_AUTH_SIMPLE)) == -1)
|
|
||||||
return (dict_ldap_get_errno(dict_ldap->ld));
|
|
||||||
|
|
||||||
mytimeval.tv_sec = dict_ldap->timeout;
|
|
||||||
mytimeval.tv_usec = 0;
|
mytimeval.tv_usec = 0;
|
||||||
|
|
||||||
if (ldap_result(dict_ldap->ld, msgid, 1, &mytimeval, &res) == -1)
|
#define GET_ALL 1
|
||||||
return (dict_ldap_get_errno(dict_ldap->ld));
|
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) {
|
if (dict_ldap_get_errno(ld) == LDAP_TIMEOUT) {
|
||||||
(void) ldap_abandon(dict_ldap->ld, msgid);
|
(void) ldap_abandon_ext(ld, msgid, 0, 0);
|
||||||
return (dict_ldap_set_errno(dict_ldap->ld, LDAP_TIMEOUT));
|
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
|
#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 *resloop = 0;
|
||||||
LDAPMessage *entry = 0;
|
LDAPMessage *entry = 0;
|
||||||
BerElement *ber;
|
BerElement *ber;
|
||||||
char **vals;
|
|
||||||
char *attr;
|
char *attr;
|
||||||
char *myname = "dict_ldap_get_values";
|
struct berval **vals;
|
||||||
struct timeval tv;
|
int valcount;
|
||||||
LDAPURLDesc *url;
|
LDAPURLDesc *url;
|
||||||
|
char *myname = "dict_ldap_get_values";
|
||||||
tv.tv_sec = dict_ldap->timeout;
|
|
||||||
tv.tv_usec = 0;
|
|
||||||
|
|
||||||
if (++recursion == 1)
|
if (++recursion == 1)
|
||||||
expansion = 0;
|
expansion = 0;
|
||||||
@@ -751,7 +795,7 @@ static void dict_ldap_get_values(DICT_LDAP *dict_ldap, LDAPMessage * res,
|
|||||||
attr != NULL;
|
attr != NULL;
|
||||||
ldap_memfree(attr), attr = ldap_next_attribute(dict_ldap->ld,
|
ldap_memfree(attr), attr = ldap_next_attribute(dict_ldap->ld,
|
||||||
entry, ber)) {
|
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 (vals == NULL) {
|
||||||
if (msg_verbose)
|
if (msg_verbose)
|
||||||
msg_info("%s[%d]: Entry doesn't have any values for %s",
|
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;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
valcount = ldap_count_values_len(vals);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If we previously encountered an error, we still continue
|
* If we previously encountered an error, we still continue
|
||||||
* through the loop, to avoid memory leaks, but we don't waste
|
* 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
|
* leaks, but it will likely be more fragile and not worth the
|
||||||
* extra code.
|
* extra code.
|
||||||
*/
|
*/
|
||||||
if (dict_errno != 0 || vals[0] == 0) {
|
if (dict_errno != 0 || valcount == 0) {
|
||||||
ldap_value_free(vals);
|
ldap_value_free_len(vals);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -794,9 +840,10 @@ static void dict_ldap_get_values(DICT_LDAP *dict_ldap, LDAPMessage * res,
|
|||||||
*/
|
*/
|
||||||
if (i < dict_ldap->num_attributes) {
|
if (i < dict_ldap->num_attributes) {
|
||||||
/* Ordinary result attribute */
|
/* Ordinary result attribute */
|
||||||
for (i = 0; vals[i] != NULL; i++) {
|
for (i = 0; i < valcount; i++) {
|
||||||
if (db_common_expand(dict_ldap->ctx,
|
if (db_common_expand(dict_ldap->ctx,
|
||||||
dict_ldap->result_format, vals[i],
|
dict_ldap->result_format,
|
||||||
|
vals[i]->bv_val,
|
||||||
name, result, 0)
|
name, result, 0)
|
||||||
&& dict_ldap->expansion_limit > 0
|
&& dict_ldap->expansion_limit > 0
|
||||||
&& ++expansion > dict_ldap->expansion_limit) {
|
&& ++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
|
} else if (recursion < dict_ldap->recursion_limit
|
||||||
&& dict_ldap->result_attributes->argv[i]) {
|
&& dict_ldap->result_attributes->argv[i]) {
|
||||||
/* Special result attribute */
|
/* Special result attribute */
|
||||||
for (i = 0; vals[i] != NULL; i++) {
|
for (i = 0; i < valcount; i++) {
|
||||||
if (ldap_is_ldap_url(vals[i])) {
|
if (ldap_is_ldap_url(vals[i]->bv_val)) {
|
||||||
if (msg_verbose)
|
if (msg_verbose)
|
||||||
msg_info("%s[%d]: looking up URL %s", myname,
|
msg_info("%s[%d]: looking up URL %s", myname,
|
||||||
recursion, vals[i]);
|
recursion, vals[i]->bv_val);
|
||||||
rc = ldap_url_parse(vals[i], &url);
|
rc = ldap_url_parse(vals[i]->bv_val, &url);
|
||||||
if (rc == 0) {
|
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_scope, url->lud_filter,
|
||||||
url->lud_attrs, 0, &tv,
|
url->lud_attrs, dict_ldap->timeout,
|
||||||
&resloop);
|
&resloop);
|
||||||
ldap_free_urldesc(url);
|
ldap_free_urldesc(url);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (msg_verbose)
|
if (msg_verbose)
|
||||||
msg_info("%s[%d]: looking up DN %s",
|
msg_info("%s[%d]: looking up DN %s",
|
||||||
myname, recursion, vals[i]);
|
myname, recursion, vals[i]->bv_val);
|
||||||
rc = ldap_search_st(dict_ldap->ld, vals[i],
|
rc = search_st(dict_ldap->ld, vals[i]->bv_val,
|
||||||
LDAP_SCOPE_BASE, "objectclass=*",
|
LDAP_SCOPE_BASE, "objectclass=*",
|
||||||
dict_ldap->result_attributes->argv,
|
dict_ldap->result_attributes->argv,
|
||||||
0, &tv, &resloop);
|
dict_ldap->timeout, &resloop);
|
||||||
}
|
}
|
||||||
switch (rc) {
|
switch (rc) {
|
||||||
case LDAP_SUCCESS:
|
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.
|
* and just didn't have any result attributes.
|
||||||
*/
|
*/
|
||||||
msg_warn("%s[%d]: DN %s not found, skipping ", myname,
|
msg_warn("%s[%d]: DN %s not found, skipping ", myname,
|
||||||
recursion, vals[i]);
|
recursion, vals[i]->bv_val);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
msg_warn("%s[%d]: search error %d: %s ", myname,
|
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]) {
|
&& dict_ldap->result_attributes->argv[i]) {
|
||||||
msg_warn("%s[%d]: %s: Recursion limit exceeded"
|
msg_warn("%s[%d]: %s: Recursion limit exceeded"
|
||||||
" for special attribute %s=%s", myname, recursion,
|
" 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;
|
dict_errno = DICT_ERR_RETRY;
|
||||||
}
|
}
|
||||||
ldap_value_free(vals);
|
ldap_value_free_len(vals);
|
||||||
}
|
}
|
||||||
if (ber)
|
if (ber)
|
||||||
ber_free(ber, 0);
|
ber_free(ber, 0);
|
||||||
@@ -897,7 +944,6 @@ static const char *dict_ldap_lookup(DICT *dict, const char *name)
|
|||||||
static VSTRING *base;
|
static VSTRING *base;
|
||||||
static VSTRING *query;
|
static VSTRING *query;
|
||||||
static VSTRING *result;
|
static VSTRING *result;
|
||||||
struct timeval tv;
|
|
||||||
int rc = 0;
|
int rc = 0;
|
||||||
int sizelimit;
|
int sizelimit;
|
||||||
|
|
||||||
@@ -1001,12 +1047,6 @@ static const char *dict_ldap_lookup(DICT *dict, const char *name)
|
|||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Prepare the query.
|
|
||||||
*/
|
|
||||||
tv.tv_sec = dict_ldap->timeout;
|
|
||||||
tv.tv_usec = 0;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* On to the search.
|
* 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,
|
msg_info("%s: %s: Searching with filter %s", myname,
|
||||||
dict_ldap->parser->name, vstring_str(query));
|
dict_ldap->parser->name, vstring_str(query));
|
||||||
|
|
||||||
rc = ldap_search_st(dict_ldap->ld, vstring_str(base),
|
rc = search_st(dict_ldap->ld, vstring_str(base), dict_ldap->scope,
|
||||||
dict_ldap->scope, vstring_str(query),
|
vstring_str(query), dict_ldap->result_attributes->argv,
|
||||||
dict_ldap->result_attributes->argv,
|
dict_ldap->timeout, &res);
|
||||||
0, &tv, &res);
|
|
||||||
|
|
||||||
if (rc == LDAP_SERVER_DOWN) {
|
if (rc == LDAP_SERVER_DOWN) {
|
||||||
if (msg_verbose)
|
if (msg_verbose)
|
||||||
msg_info("%s: Lost connection for LDAP source %s, reopening",
|
msg_info("%s: Lost connection for LDAP source %s, reopening",
|
||||||
myname, dict_ldap->parser->name);
|
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->ld = DICT_LDAP_CONN(dict_ldap)->conn_ld = 0;
|
||||||
dict_ldap_connect(dict_ldap);
|
dict_ldap_connect(dict_ldap);
|
||||||
|
|
||||||
@@ -1034,10 +1073,9 @@ static const char *dict_ldap_lookup(DICT *dict, const char *name)
|
|||||||
if (dict_errno)
|
if (dict_errno)
|
||||||
return (0);
|
return (0);
|
||||||
|
|
||||||
rc = ldap_search_st(dict_ldap->ld, vstring_str(base),
|
rc = search_st(dict_ldap->ld, vstring_str(base), dict_ldap->scope,
|
||||||
dict_ldap->scope, vstring_str(query),
|
vstring_str(query), dict_ldap->result_attributes->argv,
|
||||||
dict_ldap->result_attributes->argv,
|
dict_ldap->timeout, &res);
|
||||||
0, &tv, &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
|
* Tear down the connection so it gets set up from scratch on the
|
||||||
* next lookup.
|
* 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;
|
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)
|
if (msg_verbose)
|
||||||
msg_info("%s: Closed connection handle for LDAP source %s",
|
msg_info("%s: Closed connection handle for LDAP source %s",
|
||||||
myname, dict_ldap->parser->name);
|
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);
|
binhash_delete(conn_hash, ht->key, ht->key_len, myfree);
|
||||||
}
|
}
|
||||||
|
@@ -217,6 +217,7 @@ typedef struct {
|
|||||||
char *table;
|
char *table;
|
||||||
ARGV *hosts;
|
ARGV *hosts;
|
||||||
PLPGSQL *pldb;
|
PLPGSQL *pldb;
|
||||||
|
HOST *active_host;
|
||||||
} DICT_PGSQL;
|
} DICT_PGSQL;
|
||||||
|
|
||||||
|
|
||||||
@@ -225,7 +226,8 @@ typedef struct {
|
|||||||
|
|
||||||
/* internal function declarations */
|
/* internal function declarations */
|
||||||
static PLPGSQL *plpgsql_init(ARGV *);
|
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_dealloc(PLPGSQL *);
|
||||||
static void plpgsql_close_host(HOST *);
|
static void plpgsql_close_host(HOST *);
|
||||||
static void plpgsql_down_host(HOST *);
|
static void plpgsql_down_host(HOST *);
|
||||||
@@ -235,41 +237,83 @@ DICT *dict_pgsql_open(const char *, int, int);
|
|||||||
static void dict_pgsql_close(DICT *);
|
static void dict_pgsql_close(DICT *);
|
||||||
static HOST *host_init(const char *);
|
static HOST *host_init(const char *);
|
||||||
|
|
||||||
|
|
||||||
/* dict_pgsql_quote - escape SQL metacharacters in input string */
|
/* 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
|
* We won't get arithmetic overflows in 2*len + 1, because Postfix
|
||||||
* library. The code below seems to be over-kill (see RUS-CERT Advisory
|
* input keys have reasonable size limits, better safe than sorry.
|
||||||
* 2001-08:01), but it's better to be safe than to be sorry -- Wietse
|
|
||||||
*/
|
*/
|
||||||
for (sub = name; *sub; sub++) {
|
if (buflen <= len)
|
||||||
switch(*sub) {
|
msg_panic("%s: arithmetic overflow in 2*%lu+1",
|
||||||
case '\n':
|
myname, (unsigned long) len);
|
||||||
vstring_strcat(result, "\\n");
|
|
||||||
break;
|
/*
|
||||||
case '\r':
|
* XXX Workaround: stop further processing when PQescapeStringConn()
|
||||||
vstring_strcat(result, "\\r");
|
* (below) fails. A more proper fix requires invasive changes, not
|
||||||
break;
|
* suitable for a stable release.
|
||||||
case '\'':
|
*/
|
||||||
vstring_strcat(result, "\\'");
|
if (active_host->stat == STATFAIL)
|
||||||
break;
|
return;
|
||||||
case '"':
|
|
||||||
vstring_strcat(result, "\\\"");
|
/*
|
||||||
break;
|
* Escape the input string, using PQescapeStringConn(), because
|
||||||
case 0:
|
* the older PQescapeString() is not safe anymore, as stated by the
|
||||||
vstring_strcat(result, "\\0");
|
* documentation.
|
||||||
break;
|
*
|
||||||
default:
|
* From current libpq (8.1.4) documentation:
|
||||||
VSTRING_ADDCH(result, *sub);
|
*
|
||||||
break;
|
* 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);
|
||||||
}
|
}
|
||||||
VSTRING_TERMINATE(result);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* dict_pgsql_lookup - find database entry */
|
/* 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,
|
if (!db_common_expand(dict_pgsql->ctx, dict_pgsql->query,
|
||||||
name, 0, query, dict_pgsql_quote))
|
name, 0, query, 0))
|
||||||
return (0);
|
return (0);
|
||||||
|
|
||||||
/* do the query - set dict_errno & cleanup if there's an error */
|
/* 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->dbname,
|
||||||
dict_pgsql->username,
|
dict_pgsql->username,
|
||||||
dict_pgsql->password)) == 0) {
|
dict_pgsql->password)) == 0) {
|
||||||
@@ -466,28 +515,104 @@ static void dict_pgsql_event(int unused_event, char *context)
|
|||||||
* close unnecessary active connections
|
* close unnecessary active connections
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static PGSQL_RES *plpgsql_query(PLPGSQL *PLDB,
|
static PGSQL_RES *plpgsql_query(DICT_PGSQL *dict_pgsql,
|
||||||
const char *query,
|
const char *name,
|
||||||
|
VSTRING *query,
|
||||||
char *dbname,
|
char *dbname,
|
||||||
char *username,
|
char *username,
|
||||||
char *password)
|
char *password)
|
||||||
{
|
{
|
||||||
|
PLPGSQL *PLDB = dict_pgsql->pldb;
|
||||||
HOST *host;
|
HOST *host;
|
||||||
PGSQL_RES *res = 0;
|
PGSQL_RES *res = 0;
|
||||||
|
ExecStatusType status;
|
||||||
|
|
||||||
while ((host = dict_pgsql_get_active(PLDB, dbname, username, password)) != NULL) {
|
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);
|
plpgsql_down_host(host);
|
||||||
} else {
|
continue;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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 res;
|
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)
|
static void plpgsql_connect_single(HOST *host, char *dbname, char *username, char *password)
|
||||||
{
|
{
|
||||||
if ((host->db = PQsetdbLogin(host->name, host->port, NULL, NULL,
|
if ((host->db = PQsetdbLogin(host->name, host->port, NULL, NULL,
|
||||||
dbname, username, password)) != NULL) {
|
dbname, username, password)) == NULL
|
||||||
if (PQstatus(host->db) == CONNECTION_OK) {
|
|| PQstatus(host->db) != CONNECTION_OK) {
|
||||||
if (msg_verbose)
|
|
||||||
msg_info("dict_pgsql: successful connection to host %s",
|
|
||||||
host->hostname);
|
|
||||||
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",
|
msg_warn("connect to pgsql server %s: %s",
|
||||||
host->hostname, PQerrorMessage(host->db));
|
host->hostname, PQerrorMessage(host->db));
|
||||||
plpgsql_down_host(host);
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* plpgsql_close_host - close an established PostgreSQL connection */
|
/* 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";
|
const char *myname = "pgsql_parse_config";
|
||||||
CFG_PARSER *p;
|
CFG_PARSER *p;
|
||||||
int i;
|
|
||||||
char *hosts;
|
char *hosts;
|
||||||
VSTRING *query;
|
VSTRING *query;
|
||||||
char *select_function;
|
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.close = dict_pgsql_close;
|
||||||
dict_pgsql->dict.flags = dict_flags;
|
dict_pgsql->dict.flags = dict_flags;
|
||||||
pgsql_parse_config(dict_pgsql, name);
|
pgsql_parse_config(dict_pgsql, name);
|
||||||
|
dict_pgsql->active_host = 0;
|
||||||
dict_pgsql->pldb = plpgsql_init(dict_pgsql->hosts);
|
dict_pgsql->pldb = plpgsql_init(dict_pgsql->hosts);
|
||||||
if (dict_pgsql->pldb == NULL)
|
if (dict_pgsql->pldb == NULL)
|
||||||
msg_fatal("couldn't intialize pldb!\n");
|
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)
|
static void dict_pgsql_close(DICT *dict)
|
||||||
{
|
{
|
||||||
int i;
|
|
||||||
DICT_PGSQL *dict_pgsql = (DICT_PGSQL *) dict;
|
DICT_PGSQL *dict_pgsql = (DICT_PGSQL *) dict;
|
||||||
|
|
||||||
plpgsql_dealloc(dict_pgsql->pldb);
|
plpgsql_dealloc(dict_pgsql->pldb);
|
||||||
|
@@ -20,7 +20,7 @@
|
|||||||
* Patches change both the patchlevel and the release date. Snapshots have no
|
* Patches change both the patchlevel and the release date. Snapshots have no
|
||||||
* patchlevel; they change the release date only.
|
* patchlevel; they change the release date only.
|
||||||
*/
|
*/
|
||||||
#define MAIL_RELEASE_DATE "20060604"
|
#define MAIL_RELEASE_DATE "20060611"
|
||||||
#define MAIL_VERSION_NUMBER "2.3"
|
#define MAIL_VERSION_NUMBER "2.3"
|
||||||
|
|
||||||
#ifdef SNAPSHOT
|
#ifdef SNAPSHOT
|
||||||
|
@@ -95,11 +95,16 @@
|
|||||||
/* An I/O error happened, or the peer has disconnected unexpectedly.
|
/* An I/O error happened, or the peer has disconnected unexpectedly.
|
||||||
/* .IP SMTP_ERR_TIME
|
/* .IP SMTP_ERR_TIME
|
||||||
/* The time limit specified to smtp_timeout_setup() was exceeded.
|
/* The time limit specified to smtp_timeout_setup() was exceeded.
|
||||||
|
/* .PP
|
||||||
|
/* Additional error codes that may be used by applications:
|
||||||
/* .IP SMTP_ERR_QUIET
|
/* .IP SMTP_ERR_QUIET
|
||||||
/* Perform silent cleanup; the error was already reported by
|
/* Perform silent cleanup; the error was already reported by
|
||||||
/* the application.
|
/* the application.
|
||||||
/* This error is never generated by the smtp_stream(3) module, but
|
/* This error is never generated by the smtp_stream(3) module, but
|
||||||
/* is defined for application-specific use.
|
/* is defined for application-specific use.
|
||||||
|
/* .IP SMTP_ERR_NONE
|
||||||
|
/* A non-error code that makes setjmp()/longjmp() convenient
|
||||||
|
/* to use.
|
||||||
/* BUGS
|
/* BUGS
|
||||||
/* The timeout deadline affects all I/O on the named stream, not
|
/* The timeout deadline affects all I/O on the named stream, not
|
||||||
/* just the I/O done on behalf of this module.
|
/* just the I/O done on behalf of this module.
|
||||||
|
@@ -24,11 +24,13 @@
|
|||||||
#include <vstream.h>
|
#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_EOF 1 /* unexpected client disconnect */
|
||||||
#define SMTP_ERR_TIME 2 /* time out */
|
#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 smtp_timeout_setup(VSTREAM *, int);
|
||||||
extern void PRINTFLIKE(2, 3) smtp_printf(VSTREAM *, const char *,...);
|
extern void PRINTFLIKE(2, 3) smtp_printf(VSTREAM *, const char *,...);
|
||||||
|
@@ -11,9 +11,10 @@
|
|||||||
/* const char *unquoted;
|
/* const char *unquoted;
|
||||||
/* const char *special;
|
/* const char *special;
|
||||||
/*
|
/*
|
||||||
/* VSTRING *xtext_unquote_append(unquoted, quoted)
|
/* VSTRING *xtext_quote_append(unquoted, quoted, special)
|
||||||
/* VSTRING *unquoted;
|
/* VSTRING *unquoted;
|
||||||
/* const char *quoted;
|
/* const char *quoted;
|
||||||
|
/* const char *special;
|
||||||
/*
|
/*
|
||||||
/* VSTRING *xtext_unquote(unquoted, quoted)
|
/* VSTRING *xtext_unquote(unquoted, quoted)
|
||||||
/* VSTRING *unquoted;
|
/* VSTRING *unquoted;
|
||||||
|
@@ -711,7 +711,7 @@ static int qmgr_message_read(QMGR_MESSAGE *message)
|
|||||||
if (rec_type > 0)
|
if (rec_type > 0)
|
||||||
msg_warn("%s: ignoring out-of-order DSN original recipient <%.200s>",
|
msg_warn("%s: ignoring out-of-order DSN original recipient <%.200s>",
|
||||||
message->queue_id, dsn_orcpt);
|
message->queue_id, dsn_orcpt);
|
||||||
myfree(orig_rcpt);
|
myfree(dsn_orcpt);
|
||||||
}
|
}
|
||||||
if (orig_rcpt != 0) {
|
if (orig_rcpt != 0) {
|
||||||
if (rec_type > 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:
|
case SMTP_STATE_XFORWARD_NAME_ADDR:
|
||||||
vstring_strcpy(next_command, XFORWARD_CMD);
|
vstring_strcpy(next_command, XFORWARD_CMD);
|
||||||
if (session->features & SMTP_FEATURE_XFORWARD_NAME)
|
if (session->features & SMTP_FEATURE_XFORWARD_NAME) {
|
||||||
vstring_sprintf_append(next_command, " %s=%s",
|
vstring_strcat(next_command, " " XFORWARD_NAME "=");
|
||||||
XFORWARD_NAME, DEL_REQ_ATTR_AVAIL(request->client_name) ?
|
xtext_quote_append(next_command,
|
||||||
request->client_name : XFORWARD_UNAVAILABLE);
|
DEL_REQ_ATTR_AVAIL(request->client_name) ?
|
||||||
if (session->features & SMTP_FEATURE_XFORWARD_ADDR)
|
request->client_name : XFORWARD_UNAVAILABLE, "");
|
||||||
vstring_sprintf_append(next_command, " %s=%s",
|
}
|
||||||
XFORWARD_ADDR, DEL_REQ_ATTR_AVAIL(request->client_addr) ?
|
if (session->features & SMTP_FEATURE_XFORWARD_ADDR) {
|
||||||
request->client_addr : XFORWARD_UNAVAILABLE);
|
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)
|
if (session->send_proto_helo)
|
||||||
next_state = SMTP_STATE_XFORWARD_PROTO_HELO;
|
next_state = SMTP_STATE_XFORWARD_PROTO_HELO;
|
||||||
else
|
else
|
||||||
@@ -1018,20 +1022,26 @@ static int smtp_loop(SMTP_STATE *state, NOCLOBBER int send_state,
|
|||||||
|
|
||||||
case SMTP_STATE_XFORWARD_PROTO_HELO:
|
case SMTP_STATE_XFORWARD_PROTO_HELO:
|
||||||
vstring_strcpy(next_command, XFORWARD_CMD);
|
vstring_strcpy(next_command, XFORWARD_CMD);
|
||||||
if (session->features & SMTP_FEATURE_XFORWARD_PROTO)
|
if (session->features & SMTP_FEATURE_XFORWARD_PROTO) {
|
||||||
vstring_sprintf_append(next_command, " %s=%s",
|
vstring_strcat(next_command, " " XFORWARD_PROTO "=");
|
||||||
XFORWARD_PROTO, DEL_REQ_ATTR_AVAIL(request->client_proto) ?
|
xtext_quote_append(next_command,
|
||||||
request->client_proto : XFORWARD_UNAVAILABLE);
|
DEL_REQ_ATTR_AVAIL(request->client_proto) ?
|
||||||
if (session->features & SMTP_FEATURE_XFORWARD_HELO)
|
request->client_proto : XFORWARD_UNAVAILABLE, "");
|
||||||
vstring_sprintf_append(next_command, " %s=%s",
|
}
|
||||||
XFORWARD_HELO, DEL_REQ_ATTR_AVAIL(request->client_helo) ?
|
if (session->features & SMTP_FEATURE_XFORWARD_HELO) {
|
||||||
request->client_helo : XFORWARD_UNAVAILABLE);
|
vstring_strcat(next_command, " " XFORWARD_HELO "=");
|
||||||
if (session->features & SMTP_FEATURE_XFORWARD_DOMAIN)
|
xtext_quote_append(next_command,
|
||||||
vstring_sprintf_append(next_command, " %s=%s", XFORWARD_DOMAIN,
|
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 ?
|
DEL_REQ_ATTR_AVAIL(request->rewrite_context) == 0 ?
|
||||||
XFORWARD_UNAVAILABLE :
|
XFORWARD_UNAVAILABLE :
|
||||||
strcmp(request->rewrite_context, MAIL_ATTR_RWR_LOCAL) ?
|
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;
|
next_state = SMTP_STATE_MAIL;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@@ -329,6 +329,7 @@ smtpd_proxy.o: ../../include/tls.h
|
|||||||
smtpd_proxy.o: ../../include/vbuf.h
|
smtpd_proxy.o: ../../include/vbuf.h
|
||||||
smtpd_proxy.o: ../../include/vstream.h
|
smtpd_proxy.o: ../../include/vstream.h
|
||||||
smtpd_proxy.o: ../../include/vstring.h
|
smtpd_proxy.o: ../../include/vstring.h
|
||||||
|
smtpd_proxy.o: ../../include/xtext.h
|
||||||
smtpd_proxy.o: smtpd.h
|
smtpd_proxy.o: smtpd.h
|
||||||
smtpd_proxy.o: smtpd_proxy.c
|
smtpd_proxy.o: smtpd_proxy.c
|
||||||
smtpd_proxy.o: smtpd_proxy.h
|
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)
|
static int xclient_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv)
|
||||||
{
|
{
|
||||||
SMTPD_TOKEN *argp;
|
SMTPD_TOKEN *argp;
|
||||||
|
char *raw_value;
|
||||||
char *attr_value;
|
char *attr_value;
|
||||||
const char *bare_value;
|
const char *bare_value;
|
||||||
char *attr_name;
|
char *attr_name;
|
||||||
@@ -2677,10 +2678,14 @@ static int xclient_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv)
|
|||||||
MAIL_PROTO_ESMTP, 2,
|
MAIL_PROTO_ESMTP, 2,
|
||||||
0, -1,
|
0, -1,
|
||||||
};
|
};
|
||||||
|
int got_helo = 0;
|
||||||
|
int got_proto = 0;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Sanity checks. The XCLIENT command does not override its own access
|
* Sanity checks.
|
||||||
* control.
|
*
|
||||||
|
* 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)) {
|
if (IN_MAIL_TRANSACTION(state)) {
|
||||||
state->error_mask |= MAIL_ERROR_PROTOCOL;
|
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; \
|
s = (_v) ? mystrdup(_v) : 0; \
|
||||||
} while(0)
|
} while(0)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Initialize.
|
||||||
|
*/
|
||||||
|
if (state->expand_buf == 0)
|
||||||
|
state->expand_buf = vstring_alloc(100);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Iterate over all attribute=value elements.
|
* Iterate over all attribute=value elements.
|
||||||
*/
|
*/
|
||||||
for (argp = argv + 1; argp < argv + argc; argp++) {
|
for (argp = argv + 1; argp < argv + argc; argp++) {
|
||||||
attr_name = argp->strval;
|
attr_name = argp->strval;
|
||||||
|
|
||||||
/*
|
if ((raw_value = split_at(attr_name, '=')) == 0 || *raw_value == 0) {
|
||||||
* 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) {
|
|
||||||
state->error_mask |= MAIL_ERROR_PROTOCOL;
|
state->error_mask |= MAIL_ERROR_PROTOCOL;
|
||||||
smtpd_chat_reply(state, "501 5.5.4 Error: attribute=value expected");
|
smtpd_chat_reply(state, "501 5.5.4 Error: attribute=value expected");
|
||||||
return (-1);
|
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, '?');
|
printable(attr_value, '?');
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -2805,6 +2829,7 @@ static int xclient_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv)
|
|||||||
neuter(attr_value, NEUTER_CHARACTERS, '?');
|
neuter(attr_value, NEUTER_CHARACTERS, '?');
|
||||||
}
|
}
|
||||||
UPDATE_STR(state->helo_name, attr_value);
|
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);
|
return (-1);
|
||||||
}
|
}
|
||||||
UPDATE_STR(state->protocol, uppercase(attr_value));
|
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 =
|
state->namaddr =
|
||||||
concatenate(state->name, "[", state->addr, "]", (char *) 0);
|
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);
|
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)
|
static int xforward_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv)
|
||||||
{
|
{
|
||||||
SMTPD_TOKEN *argp;
|
SMTPD_TOKEN *argp;
|
||||||
|
char *raw_value;
|
||||||
char *attr_value;
|
char *attr_value;
|
||||||
const char *bare_value;
|
const char *bare_value;
|
||||||
char *attr_name;
|
char *attr_name;
|
||||||
@@ -2898,6 +2959,8 @@ static int xforward_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv)
|
|||||||
*/
|
*/
|
||||||
if (state->xforward.flags == 0)
|
if (state->xforward.flags == 0)
|
||||||
smtpd_xforward_preset(state);
|
smtpd_xforward_preset(state);
|
||||||
|
if (state->expand_buf == 0)
|
||||||
|
state->expand_buf = vstring_alloc(100);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Iterate over all attribute=value elements.
|
* 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++) {
|
for (argp = argv + 1; argp < argv + argc; argp++) {
|
||||||
attr_name = argp->strval;
|
attr_name = argp->strval;
|
||||||
|
|
||||||
/*
|
if ((raw_value = split_at(attr_name, '=')) == 0 || *raw_value == 0) {
|
||||||
* 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) {
|
|
||||||
state->error_mask |= MAIL_ERROR_PROTOCOL;
|
state->error_mask |= MAIL_ERROR_PROTOCOL;
|
||||||
smtpd_chat_reply(state, "501 5.5.4 Error: attribute=value expected");
|
smtpd_chat_reply(state, "501 5.5.4 Error: attribute=value expected");
|
||||||
return (-1);
|
return (-1);
|
||||||
}
|
}
|
||||||
if (strlen(attr_value) > 255) {
|
if (strlen(raw_value) > 255) {
|
||||||
state->error_mask |= MAIL_ERROR_PROTOCOL;
|
state->error_mask |= MAIL_ERROR_PROTOCOL;
|
||||||
smtpd_chat_reply(state, "501 5.5.4 Error: attribute value too long");
|
smtpd_chat_reply(state, "501 5.5.4 Error: attribute value too long");
|
||||||
return (-1);
|
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, '?');
|
printable(attr_value, '?');
|
||||||
|
|
||||||
flag = name_code(xforward_flags, NAME_CODE_FLAG_NONE, attr_name);
|
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 */
|
/* 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;
|
int argc;
|
||||||
SMTPD_TOKEN *argv;
|
SMTPD_TOKEN *argv;
|
||||||
@@ -3276,6 +3347,7 @@ static void smtpd_proto(SMTPD_STATE *state, const char *service)
|
|||||||
int count;
|
int count;
|
||||||
int crate;
|
int crate;
|
||||||
const char *ehlo_words;
|
const char *ehlo_words;
|
||||||
|
int status;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Print a greeting banner and run the state machine. Read SMTP commands
|
* 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);
|
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:
|
default:
|
||||||
msg_panic("smtpd_proto: unknown error reading from %s[%s]",
|
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
|
&& !xclient_allowed
|
||||||
&& anvil_clnt
|
&& anvil_clnt
|
||||||
&& !namadr_list_match(hogger_list, state->name, state->addr)
|
&& !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) {
|
&count, &crate) == ANVIL_STAT_OK) {
|
||||||
if (var_smtpd_cconn_limit > 0 && count > var_smtpd_cconn_limit) {
|
if (var_smtpd_cconn_limit > 0 && count > var_smtpd_cconn_limit) {
|
||||||
state->error_mask |= MAIL_ERROR_POLICY;
|
state->error_mask |= MAIL_ERROR_POLICY;
|
||||||
smtpd_chat_reply(state, "421 4.7.0 %s Error: too many connections from %s",
|
smtpd_chat_reply(state, "421 4.7.0 %s Error: too many connections from %s",
|
||||||
var_myhostname, state->addr);
|
var_myhostname, state->addr);
|
||||||
msg_warn("Connection concurrency limit exceeded: %d from %s for service %s",
|
msg_warn("Connection concurrency limit exceeded: %d from %s for service %s",
|
||||||
count, state->namaddr, service);
|
count, state->namaddr, state->service);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (var_smtpd_crate_limit > 0 && crate > var_smtpd_crate_limit) {
|
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",
|
smtpd_chat_reply(state, "421 4.7.0 %s Error: too many connections from %s",
|
||||||
var_myhostname, state->addr);
|
var_myhostname, state->addr);
|
||||||
msg_warn("Connection rate limit exceeded: %d from %s for service %s",
|
msg_warn("Connection rate limit exceeded: %d from %s for service %s",
|
||||||
crate, state->namaddr, service);
|
crate, state->namaddr, state->service);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -3499,7 +3573,7 @@ static void smtpd_proto(SMTPD_STATE *state, const char *service)
|
|||||||
&& !xclient_allowed
|
&& !xclient_allowed
|
||||||
&& anvil_clnt
|
&& anvil_clnt
|
||||||
&& !namadr_list_match(hogger_list, state->name, state->addr))
|
&& !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
|
* 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
|
* Cleanup whatever information the client gave us during the SMTP
|
||||||
* dialog.
|
* dialog.
|
||||||
|
*
|
||||||
|
* XXX Duplicated in xclient_cmd().
|
||||||
*/
|
*/
|
||||||
#ifdef USE_TLS
|
#ifdef USE_TLS
|
||||||
tls_reset(state);
|
tls_reset(state);
|
||||||
@@ -3596,7 +3672,7 @@ static void smtpd_service(VSTREAM *stream, char *service, char **argv)
|
|||||||
/*
|
/*
|
||||||
* Provide the SMTP service.
|
* 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
|
* After the client has gone away, clean up whatever we have set up at
|
||||||
|
@@ -162,6 +162,7 @@
|
|||||||
#include <rec_type.h>
|
#include <rec_type.h>
|
||||||
#include <mail_proto.h>
|
#include <mail_proto.h>
|
||||||
#include <mail_params.h> /* null_format_string */
|
#include <mail_params.h> /* null_format_string */
|
||||||
|
#include <xtext.h>
|
||||||
|
|
||||||
/* Application-specific. */
|
/* 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 CONSTR_LEN(s) (sizeof(s) - 1)
|
||||||
#define PAYLOAD_LIMIT (512 - CONSTR_LEN("250 " XFORWARD_CMD "\r\n"))
|
#define PAYLOAD_LIMIT (512 - CONSTR_LEN("250 " XFORWARD_CMD "\r\n"))
|
||||||
|
|
||||||
/*
|
|
||||||
* How much space does this attribute need?
|
|
||||||
*/
|
|
||||||
if (!value_available)
|
if (!value_available)
|
||||||
value = XFORWARD_UNAVAILABLE;
|
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)
|
if (new_len > PAYLOAD_LIMIT)
|
||||||
msg_warn("%s command payload %s=%.10s... exceeds SMTP protocol limit",
|
msg_warn("%s command payload %s=%.10s... exceeds SMTP protocol limit",
|
||||||
XFORWARD_CMD, name, value);
|
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 (VSTRING_LEN(buf) > 0 && VSTRING_LEN(buf) + new_len > PAYLOAD_LIMIT)
|
||||||
if ((ret = smtpd_xforward_flush(state, buf)) < 0)
|
if ((ret = smtpd_xforward_flush(state, buf)) < 0)
|
||||||
return (ret);
|
return (ret);
|
||||||
vstring_sprintf_append(buf, " %s=%s", name, value);
|
vstring_sprintf_append(buf, " %s=%s", name, STR(state->expand_buf));
|
||||||
|
|
||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user