]> git.ipfire.org Git - thirdparty/postfix.git/commitdiff
postfix-2.3-20060611
authorWietse Venema <wietse@porcupine.org>
Sun, 11 Jun 2006 05:00:00 +0000 (00:00 -0500)
committerViktor Dukhovni <viktor@dukhovni.org>
Tue, 5 Feb 2013 06:32:20 +0000 (06:32 +0000)
26 files changed:
postfix/HISTORY
postfix/README_FILES/BACKSCATTER_README
postfix/README_FILES/PGSQL_README
postfix/README_FILES/XCLIENT_README
postfix/README_FILES/XFORWARD_README
postfix/RELEASE_NOTES
postfix/html/BACKSCATTER_README.html
postfix/html/PGSQL_README.html
postfix/html/XCLIENT_README.html
postfix/html/XFORWARD_README.html
postfix/proto/BACKSCATTER_README.html
postfix/proto/PGSQL_README.html
postfix/proto/XCLIENT_README.html
postfix/proto/XFORWARD_README.html
postfix/src/global/db_common.c
postfix/src/global/dict_ldap.c
postfix/src/global/dict_pgsql.c
postfix/src/global/mail_version.h
postfix/src/global/smtp_stream.c
postfix/src/global/smtp_stream.h
postfix/src/global/xtext.c
postfix/src/qmgr/qmgr_message.c
postfix/src/smtp/smtp_proto.c
postfix/src/smtpd/Makefile.in
postfix/src/smtpd/smtpd.c
postfix/src/smtpd/smtpd_proxy.c

index 0f0b58c1617f38f8a7a5a2de1f86bf7342dd7dcb..f8b6f3d4e866dab996a02a7c4a29850a6e38d893 100644 (file)
@@ -12182,8 +12182,57 @@ Apologies for any names omitted.
        master/master_spawn.c, pickup/pickup.c, util/match_ops.c,
        util/safe_open.c, xsasl/xsasl_cyrus_client.c.
 
+20060606
+
+       Bugfix: qmgr panic after queue file corruption by Mailscanner.
+       Files: *qmgr/qmgr_message.c.
+
+       Bugfix: XCLIENT didn't work with smtpd_delay_reject=no
+       (problem reported by Joshua Goodall).  To make XCLIENT work
+       correctly with built-in restrictions and with Milter
+       applications, the SMTP server now jumps back to the very
+       start (the 220 phase) of an SMTP session.  File: smtpd/smtpd.c.
+
+20060610
+
+       Cleanup: XCLIENT and XFORWARD attribute values are now sent
+       as xtext encoded strings. For backwards compatibility,
+       Postfix will still accept unencoded attribute values.  Files:
+       smtpd/smtpd.c, smtpd/smtpd_proxy.c, smtp/smtp_proto.c.
+
+20060611
+
+       Robustness: additional sanity checks for common database
+       routines. Viktor Dukhovni. File: global/db_common.c.
+
+       Portability: LDAP 2.3 API support. Viktor Dukhovni. File:
+       global/dict_ldap.c.
+
+       Security: the PostgreSQL client was updated after the
+       PostgreSQL developers made major database API changes in
+       response to PostgreSQL security issues. This breaks support
+       for PGSQL versions prior to 8.1.4, 8.0.8, 7.4.13, and 7.3.15.
+       Support for these requires major code changes which are not
+       possible in the time that is left for the Postfix 2.3 stable
+       release.
+
+       Specific PostgreSQL client changes: use connection-aware
+       quoting, and more robust PQexec() result handling.  Previous
+       versions of the dict_pgsql driver didn't check the status
+       of the result pointer, and certain exceptional events can
+       be mis-interpreted as an empty result set.  Fixes by Leandro
+       Santi. File: global/dict_pgsql.c.
+
 Wish list:
 
+       With (non)delivery notifications, prepend an "Auto-Submitted:
+       auto-replied" header, as per RFC 3834.
+
+       Defer delivery when a SASL password exists but the server
+       does not offer SASL authentication, as mail might otherwise
+       be bounced. Make this configurable so people can get the
+       old behavior.
+
        Don't lose bits when converting st_dev into maildir file
        name. It's 64 bits on Linux. Found with the BEAM source
        code analyzer.
index b13457e480b25dfb121650b7e051d9b86693a531..78646f22d135b6e35bd2cb63d5bcbf2ba3ba232a 100644 (file)
@@ -194,8 +194,12 @@ http://www.t29.dk/antiantivirus.txt.
             DISCARD virus notification
         /^Content-Disposition:.*VirusWarning.txt/ DISCARD virus notification
 
+Note: these documents haven't been updated since 2004, so they are useful only
+as a starting point.
+
 A plea to virus or spam scanner operators: please do not make the problem worse
 by sending return mail to forged sender addresses. You're only harassing
 innocent people. If you must return mail to the purported sender, please return
-the full message headers, so that the sender can defend against forgeries.
+the full message headers, so that the sender can filter out the obvious
+forgeries.
 
index c7d8c279fcd2c6977afcd387107ca6bdd7d1036d..152d6a3f0c3f6cfa419358ab442dbced798033ec 100644 (file)
@@ -102,4 +102,7 @@ C\bCr\bre\bed\bdi\bit\bts\bs
   * Liviu Daia with further refinements from Jose Luis Tallon and Victor
     Duchovni developed the common query, result_format, domain and
     expansion_limit interface for LDAP, MySQL and PosgreSQL.
+  * Leandro Santi updated the PostgreSQL client after the PostgreSQL developers
+    made major database API changes in response to SQL injection problems, and
+    made PQexec() handling more robust.
 
index fc2f3a0a5808d3d0073840d096f334561c4db7e5..f9b084eefeb2f466a8413a560d31d9bc9f717c63 100644 (file)
@@ -29,15 +29,17 @@ The XCLIENT command targets the following problems:
 
 X\bXC\bCL\bLI\bIE\bEN\bNT\bT C\bCo\bom\bmm\bma\ban\bnd\bd s\bsy\byn\bnt\bta\bax\bx
 
-Examples of client-server conversations are given at the end of this document.
+An example client-server conversation is given at the end of this document.
 
 In SMTP server EHLO replies, the keyword associated with this extension is
 XCLIENT. It is followed by the names of the attributes that the XCLIENT
 implementation supports.
 
-The XCLIENT command may be sent at any time except in the middle of a mail
-delivery transaction (i.e. between MAIL and DOT). The XCLIENT command may be
-pipelined when the server supports ESMTP command pipelining.
+The XCLIENT command may be sent at any time, except in the middle of a mail
+delivery transaction (i.e. between MAIL and DOT, or MAIL and RSET). The XCLIENT
+command may be pipelined when the server supports ESMTP command pipelining. To
+avoid triggering spamware detectors, the command should be sent at the end of a
+command group.
 
 The syntax of XCLIENT requests is described below. Upper case and quoted
 strings specify terminals, lowercase strings specify meta terminals, and SP is
@@ -48,6 +50,10 @@ are in fact case insensitive.
 
     attribute-name = ( NAME | ADDR | PROTO | HELO )
 
+    attribute-value = xtext
+
+  * Attribute values are xtext encoded as per RFC 1891.
+
   * The NAME attribute specifies an SMTP client hostname (not an SMTP client
     address), [UNAVAILABLE] when client hostname lookup failed due to a
     permanent error, or [TEMPUNAVAIL] when the lookup error condition was
@@ -62,33 +68,65 @@ are in fact case insensitive.
   * The HELO attribute specifies an SMTP HELO parameter value, or the value
     [UNAVAILABLE] when the information is unavailable.
 
-Note 1: syntactically valid NAME and HELO attributes can be up to 255
-characters long. The client must not send XCLIENT commands that exceed the 512
-character limit for SMTP commands. To avoid exceeding the limit the client
-should send the information in multiple XCLIENT commands.
+Note 1: syntactically valid NAME and HELO attribute-value elements can be up to
+255 characters long. The client must not send XCLIENT commands that exceed the
+512 character limit for SMTP commands. To avoid exceeding the limit the client
+should send the information in multiple XCLIENT commands; for example, send
+NAME and ADDR first, then HELO and PROTO.
 
 Note 2: [UNAVAILABLE], [TEMPUNAVAIL] and IPV6: may be specified in upper case,
 lower case or mixed case.
 
-The XCLIENT server reply codes are as follows:
-
-     _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b 
-    |C\bCo\bod\bde\be|M\bMe\bea\ban\bni\bin\bng\bg                         |
-    |_\b _\b _\b _\b _\b|_\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b |
-    |250 |success                         |
-    |_\b _\b _\b _\b _\b|_\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b |
-    |501 |bad command parameter syntax    |
-    |_\b _\b _\b _\b _\b|_\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b |
-    |503 |mail transaction in progress    |
-    |_\b _\b _\b _\b _\b|_\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b |
-    |421 |unable to proceed, disconnecting|
-    |_\b _\b _\b _\b _\b|_\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b |
-
-X\bXC\bCL\bLI\bIE\bEN\bNT\bT E\bEx\bxa\bam\bmp\bpl\ble\bes\bs
-
-In the first example, the client impersonates a mail originating system by
-passing all SMTP session information via XCLIENT commands. Information sent by
-the client is shown in bold font.
+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.
+
+X\bXC\bCL\bLI\bIE\bEN\bNT\bT S\bSe\ber\brv\bve\ber\br r\bre\bes\bsp\bpo\bon\bns\bse\be
+
+Upon receipt of a correctly formatted XCLIENT command, the server resets state
+to the initial SMTP greeting protocol stage. Depending on the outcome of
+optional access decisions, the server responds with 220 or with a suitable
+rejection code.
+
+For practical reasons it is not always possible to reset the complete server
+state to the initial SMTP greeting protocol stage:
+
+  * TLS session information may not be reset, because turning off TLS leaves
+    the connection in an undefined state. Consequently, the server may not
+    announce STARTTLS when TLS is already active, and access decisions may be
+    influenced by client certificate information that was received prior to the
+    XCLIENT command.
+
+  * The SMTP server must not reset attributes that were received with the last
+    XCLIENT command. This includes HELO or PROTO attributes.
+
+NOTE: Postfix implementations prior to version 2.3 do not jump back to the
+initial SMTP greeting protocol stage. These older implementations will not
+correctly simulate connection-level access decisions under some conditions.
+
+X\bXC\bCL\bLI\bIE\bEN\bNT\bT s\bse\ber\brv\bve\ber\br r\bre\bep\bpl\bly\by c\bco\bod\bde\bes\bs
+
+     _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b 
+    |C\bCo\bod\bde\be |M\bMe\bea\ban\bni\bin\bng\bg                                                |
+    |_\b _\b _\b _\b _\b _\b|_\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b |
+    |220  |success                                                |
+    |_\b _\b _\b _\b _\b _\b|_\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b |
+    |421  |unable to proceed, disconnecting                       |
+    |_\b _\b _\b _\b _\b _\b|_\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b |
+    |501  |bad command parameter syntax                           |
+    |_\b _\b _\b _\b _\b _\b|_\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b |
+    |503  |mail transaction in progress                           |
+    |_\b _\b _\b _\b _\b _\b|_\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b |
+    |550  |insufficient authorization                             |
+    |_\b _\b _\b _\b _\b _\b|_\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b |
+    |other|connection rejected by connection-level access decision|
+    |_\b _\b _\b _\b _\b _\b|_\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b |
+
+X\bXC\bCL\bLI\bIE\bEN\bNT\bT E\bEx\bxa\bam\bmp\bpl\ble\be
+
+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
     E\bEH\bHL\bLO\bO c\bcl\bli\bie\ben\bnt\bt.\b.e\bex\bxa\bam\bmp\bpl\ble\be.\b.c\bco\bom\bm
@@ -99,32 +137,16 @@ the client is shown in bold font.
     250-ETRN
     250-XCLIENT NAME ADDR PROTO HELO
     250 8BITMIME
-    X\bXC\bCL\bLI\bIE\bEN\bNT\bT N\bNA\bAM\bME\bE=\b=s\bsp\bpi\bik\bke\be.\b.p\bpo\bor\brc\bcu\bup\bpi\bin\bne\be.\b.o\bor\brg\bg A\bAD\bDD\bDR\bR=\b=1\b16\b68\b8.\b.1\b10\b00\b0.\b.1\b18\b89\b9.\b.2\b2 P\bPR\bRO\bOT\bTO\bO=\b=E\bES\bSM\bMT\bTP\bP
-    250 Ok
-    X\bXC\bCL\bLI\bIE\bEN\bNT\bT H\bHE\bEL\bLO\bO=\b=s\bsp\bpi\bik\bke\be.\b.p\bpo\bor\brc\bcu\bup\bpi\bin\bne\be.\b.o\bor\brg\bg
-    250 Ok
-    M\bMA\bAI\bIL\bL F\bFR\bRO\bOM\bM:\b:<\b<w\bwi\bie\bet\bts\bse\be@\b@p\bpo\bor\brc\bcu\bup\bpi\bin\bne\be.\b.o\bor\brg\bg>\b>
-    250 Ok
-    R\bRC\bCP\bPT\bT T\bTO\bO:\b:<\b<u\bus\bse\ber\br@\b@e\bex\bxa\bam\bmp\bpl\ble\be.\b.c\bco\bom\bm>\b>
-    250 Ok
-    D\bDA\bAT\bTA\bA
-    354 End data with <CR><LF>.<CR><LF>
-    .\b. .\b. .\b.m\bme\bes\bss\bsa\bag\bge\be c\bco\bon\bnt\bte\ben\bnt\bt.\b. .\b. .\b.
-    .\b.
-    250 Ok: queued as 763402AAE6
-    Q\bQU\bUI\bIT\bT
-    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
     X\bXC\bCL\bLI\bIE\bEN\bNT\bT N\bNA\bAM\bME\bE=\b=s\bsp\bpi\bik\bke\be.\b.p\bpo\bor\brc\bcu\bup\bpi\bin\bne\be.\b.o\bor\brg\bg A\bAD\bDD\bDR\bR=\b=1\b16\b68\b8.\b.1\b10\b00\b0.\b.1\b18\b89\b9.\b.2\b2
-    250 Ok
-    H\bHE\bEL\bLO\bO s\bsp\bpi\bik\bke\be.\b.p\bpo\bor\brc\bcu\bup\bpi\bin\bne\be.\b.o\bor\brg\bg
-    250 server.example.com
+    220 server.example.com ESMTP Postfix
+    E\bEH\bHL\bLO\bO s\bsp\bpi\bik\bke\be.\b.p\bpo\bor\brc\bcu\bup\bpi\bin\bne\be.\b.o\bor\brg\bg
+    250-server.example.com
+    250-PIPELINING
+    250-SIZE 10240000
+    250-VRFY
+    250-ETRN
+    250-XCLIENT NAME ADDR PROTO HELO
+    250 8BITMIME
     M\bMA\bAI\bIL\bL F\bFR\bRO\bOM\bM:\b:<\b<w\bwi\bie\bet\bts\bse\be@\b@p\bpo\bor\brc\bcu\bup\bpi\bin\bne\be.\b.o\bor\brg\bg>\b>
     250 Ok
     R\bRC\bCP\bPT\bT T\bTO\bO:\b:<\b<u\bus\bse\ber\br@\b@e\bex\bxa\bam\bmp\bpl\ble\be.\b.c\bco\bom\bm>\b>
@@ -133,15 +155,14 @@ XCLIENT options the server supports.
     354 End data with <CR><LF>.<CR><LF>
     .\b. .\b. .\b.m\bme\bes\bss\bsa\bag\bge\be c\bco\bon\bnt\bte\ben\bnt\bt.\b. .\b. .\b.
     .\b.
-    250 Ok: queued as CF1E52AAE7
+    250 Ok: queued as 763402AAE6
     Q\bQU\bUI\bIT\bT
     221 Bye
 
 S\bSe\bec\bcu\bur\bri\bit\bty\by
 
 The XCLIENT command changes audit trails and/or SMTP client access permissions.
-Use of this command must be restricted to authorized SMTP clients. However, the
-XCLIENT command should not override its own access control mechanism.
+Use of this command must be restricted to authorized SMTP clients.
 
 S\bSM\bMT\bTP\bP c\bco\bon\bnn\bne\bec\bct\bti\bio\bon\bn c\bca\bac\bch\bhi\bin\bng\bg
 
@@ -149,3 +170,8 @@ XCLIENT attributes persist until the end of an SMTP session. If one session is
 used to deliver mail on behalf of different SMTP clients, the XCLIENT
 attributes need to be reset as appropriate before each MAIL FROM command.
 
+R\bRe\bef\bfe\ber\bre\ben\bnc\bce\bes\bs
+
+Moore, K, "SMTP Service Extension for Delivery Status Notifications", RFC 1891,
+January 1996.
+
index c11ea991fe4440cd699c7a1ada0302f5c192d98b..47b12fe099c3c9bb056548c74872081021a87e6d 100644 (file)
@@ -14,12 +14,12 @@ The XFORWARD command targets the following problem:
     information through the content filter to MTA2, so that the information
     could be logged as part of mail handling transactions.
 
-This extension is implemented as a separate command, and can be used to
+This extension is implemented as a separate EMSTP command, and can be used to
 transmit client or message attributes incrementally. It is not implemented by
 passing additional parameters via the MAIL FROM command, because doing so would
 require extending the MAIL FROM command length limit by another 600 or more
-characters beyond the space that is already needed in order to support other
-extensions such as AUTH.
+characters beyond the space that is already needed to support other extensions
+such as AUTH.
 
 X\bXF\bFO\bOR\bRW\bWA\bAR\bRD\bD C\bCo\bom\bmm\bma\ban\bnd\bd s\bsy\byn\bnt\bta\bax\bx
 
@@ -43,6 +43,10 @@ are in fact case insensitive.
 
     attribute-name = ( NAME | ADDR | PROTO | HELO | SOURCE )
 
+    attribute-value = xtext
+
+  * Attribute values are xtext encoded as per RFC 1891.
+
   * The NAME attribute specifies the up-stream hostname, or [UNAVAILABLE] when
     the information is unavailable. The hostname may be a non-DNS hostname.
 
@@ -51,7 +55,7 @@ are in fact case insensitive.
     not enclosed with []. The address may be a non-IP address.
 
   * The PROTO attribute specifies the mail protocol for receiving mail from the
-    up-stream host. This may be an SMTP non-SMTP protocol name of up to 64
+    up-stream host. This may be an SMTP or non-SMTP protocol name of up to 64
     characters, or [UNAVAILABLE] when the information is unavailable.
 
   * The HELO attribute specifies the hostname that the up-stream host announced
@@ -66,11 +70,10 @@ are in fact case insensitive.
     MTA may decide to enable features such as header munging or address
     qualification with mail from local sources but not other sources.
 
-Note 1: Attribute values must not be longer than 255 characters (specific
-attributes may impose shorter lengths), must not contain control characters,
-non-ASCII characters, whitespace, or other characters that are special in
-message headers. Future attributes that may violate this should use xtext
-encoding as described in RFC 1891.
+Note 1: an attribute-value element must not be longer than 255 characters
+(specific attributes may impose shorter lengths). After xtext decoding,
+attribute values must not contain control characters, non-ASCII characters,
+whitespace, or other characters that are special in message headers.
 
 Note 2: DNS hostnames can be up to 255 characters long. The XFORWARD client
 implementation must not send XFORWARD commands that exceed the 512 character
@@ -81,18 +84,31 @@ Note 3: [UNAVAILABLE] may be specified in upper case, lower case or mixed case.
 Note 4: the XFORWARD server implementation must not mix information from the
 current SMTP session with forwarded information from an up-stream session.
 
-The XFORWARD server reply codes are as follows:
+Note 5: Postfix implementations prior to version 2.3 do not xtext encode
+attribute values. Servers that wish to interoperate with these older
+implementations should be prepared to receive unencoded information.
+
+X\bXF\bFO\bOR\bRW\bWA\bAR\bRD\bD S\bSe\ber\brv\bve\ber\br r\bre\bes\bsp\bpo\bon\bns\bse\be
+
+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.
+
+X\bXF\bFO\bOR\bRW\bWA\bAR\bRD\bD S\bSe\ber\brv\bve\ber\br r\bre\bep\bpl\bly\by c\bco\bod\bde\bes\bs
 
      _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b 
     |C\bCo\bod\bde\be|M\bMe\bea\ban\bni\bin\bng\bg                         |
     |_\b _\b _\b _\b _\b|_\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b |
     |250 |success                         |
     |_\b _\b _\b _\b _\b|_\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b |
+    |421 |unable to proceed, disconnecting|
+    |_\b _\b _\b _\b _\b|_\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b |
     |501 |bad command parameter syntax    |
     |_\b _\b _\b _\b _\b|_\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b |
     |503 |mail transaction in progress    |
     |_\b _\b _\b _\b _\b|_\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b |
-    |421 |unable to proceed, disconnecting|
+    |550 |insufficient authorization      |
     |_\b _\b _\b _\b _\b|_\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b |
 
 X\bXF\bFO\bOR\bRW\bWA\bAR\bRD\bD E\bEx\bxa\bam\bmp\bpl\ble\be
@@ -135,3 +151,8 @@ SMTP connection caching makes it possible to deliver multiple messages within
 the same SMTP session. The XFORWARD attributes are reset after the MAIL FROM
 command completes, so there is no risk of information leakage.
 
+R\bRe\bef\bfe\ber\bre\ben\bnc\bce\bes\bs
+
+Moore, K, "SMTP Service Extension for Delivery Status Notifications", RFC 1891,
+January 1996.
+
index e4ea548cccfb2be157f62b93ba09e6d0e43c2b38..f5186e1318d26c8fac30f16da7a65c20f00ad74b 100644 (file)
@@ -17,6 +17,32 @@ Incompatibility with Postfix 2.1 and earlier
 If you upgrade from Postfix 2.1 or earlier, read RELEASE_NOTES-2.2
 before proceeding.
 
+Incompatibility with snapshot 20060611
+======================================
+
+The PostgreSQL client was updated after the PostgreSQL developers
+made major database API changes in response to SQL injection problems.
+This breaks support for PGSQL versions prior to 8.1.4, 8.0.8, 7.4.13,
+and 7.3.15. Support for these requires major code changes which are
+not possible in the time that is left for completing the Postfix
+2.3 stable release.
+
+The SMTP server XCLIENT implementation has changed. The SMTP server
+now resets state to the initial server greeting stage, so that it
+can accurately simulate the effect of connection-level access
+restrictions.  Without this change, XCLIENT will not work at all
+with Milter applications.
+
+The SMTP server XCLIENT and XFORWARD commands now expect that
+attributes are xtext encoded (RFC 1891). For backwards compatibility
+they will accept unencoded attribute values. The XFORWARD client
+code in the SMTP client and in the SMTPD_PROXY client will always
+encode attribute values. This change will have effect only for
+malformed hostname and helo parameter values.
+
+For more details, see the XCLIENT_README and XFORWARD_README
+documents.
+
 Incompatibility with snapshot 20060207
 ======================================
 
index 26892192621e4873b368c321f0cc3a6cccbe7f05..a007603bdfae217de7bdab09136905da657c22b6 100644 (file)
@@ -74,7 +74,7 @@ stress then it should not waste time. </p>
 
 <blockquote>
 <pre>
-/etc/postfix/main.cf:
+/etc/postfix/<a href="postconf.5.html">main.cf</a>:
     # Not needed with Postfix 2.1 and later.
     <a href="postconf.5.html#smtpd_error_sleep_time">smtpd_error_sleep_time</a> = 0
 </pre>
@@ -105,7 +105,8 @@ Received: from porcupine.org ...
 </blockquote>
 
 <p> Then I know that this is almost certainly forged mail (almost;
-see next section for the fly in the ointment). Mail that is really
+see <a href="#caveats">next section</a> for the fly in the ointment).
+Mail that is really
 sent by my systems looks like this: </p>
 
 <blockquote>
@@ -143,7 +144,7 @@ patterns like this: </p>
 
 <blockquote>
 <pre>
-/etc/postfix/main.cf:
+/etc/postfix/<a href="postconf.5.html">main.cf</a>:
     <a href="postconf.5.html#header_checks">header_checks</a> = <a href="regexp_table.5.html">regexp</a>:/etc/postfix/header_checks
     <a href="postconf.5.html#body_checks">body_checks</a> = <a href="regexp_table.5.html">regexp</a>:/etc/postfix/body_checks
 
@@ -182,7 +183,7 @@ and "<tt>)</tt>" would be grouping operators.  </p>
 
 </ul>
 
-<p><strong>Caveats</strong></p>
+<p><a name="caveats"><strong>Caveats</strong></a></p>
 
 <p> Netscape Messenger (and reportedly, Mozilla) sends a HELO name
 that is identical to the sender address domain part. If you have
@@ -197,7 +198,7 @@ mapping translates this temporary address into user@porcupine.org.
 
 <blockquote>
 <pre>
-/etc/postfix/main.cf:
+/etc/postfix/<a href="postconf.5.html">main.cf</a>:
     <a href="postconf.5.html#canonical_maps">canonical_maps</a> = hash:/etc/postfix/canonical
 
 /etc/postfix/canonical:
@@ -225,7 +226,7 @@ and is very easy to stop.
 
 <blockquote>
 <pre>
-/etc/postfix/main.cf:
+/etc/postfix/<a href="postconf.5.html">main.cf</a>:
     <a href="postconf.5.html#header_checks">header_checks</a> = <a href="regexp_table.5.html">regexp</a>:/etc/postfix/header_checks
     <a href="postconf.5.html#body_checks">body_checks</a> = <a href="regexp_table.5.html">regexp</a>:/etc/postfix/body_checks
 
@@ -294,11 +295,14 @@ or <a href="http://www.t29.dk/antiantivirus.txt">http://www.t29.dk/antiantivirus
 </pre>
 </blockquote>
 
+<p> Note: these documents haven't been updated since 2004, so they
+are useful only as a starting point. </p>
+
 <p> A plea to virus or spam scanner operators: please do not make
 the problem worse by sending return mail to forged sender addresses.
 You're only harassing innocent people. If you must return mail to
 the purported sender, please return the full message headers, so
-that the sender can defend against forgeries. </p>
+that the sender can filter out the obvious forgeries. </p>
 
 </body>
 
index 254f580dd3291e55bf3d9ceca2921b0272c053e5..021d64175bd2889c6944f7322f8ecef8c4df1850 100644 (file)
@@ -57,11 +57,11 @@ the location of the libpq library file. </p>
 <h2>Configuring PostgreSQL lookup tables</h2>
 
 <p> Once Postfix is built with pgsql support, you can specify a
-map type in main.cf like this: </p>
+map type in <a href="postconf.5.html">main.cf</a> like this: </p>
 
 <blockquote>
 <pre>
-/etc/postfix/main.cf:
+/etc/postfix/<a href="postconf.5.html">main.cf</a>:
     <a href="postconf.5.html#alias_maps">alias_maps</a> = <a href="pgsql_table.5.html">pgsql</a>:/etc/postfix/pgsql-aliases.cf
 </pre>
 </blockquote>
@@ -130,15 +130,19 @@ calling stored procedures were added by Philip Warner.</li>
 <li> LaMont Jones was the initial Postfix pgsql maintainer.</li>
 
 <li> Liviu Daia revised the configuration interface and added the
-main.cf configuration feature.</li>
+<a href="postconf.5.html">main.cf</a> configuration feature.</li>
 
-<li> Liviu Daia revised the configuration interface and added the main.cf
+<li> Liviu Daia revised the configuration interface and added the <a href="postconf.5.html">main.cf</a>
 configuration feature.</li>
 
 <li> Liviu Daia with further refinements from Jose Luis Tallon and
 Victor Duchovni developed the common query, result_format, domain and
 expansion_limit interface for LDAP, MySQL and PosgreSQL.</li>
 
+<li> Leandro Santi updated the PostgreSQL client after the PostgreSQL
+developers made major database API changes in response to SQL
+injection problems, and made PQexec() handling more robust. </li>
+
 </ul>
 
 </body>
index 2f228a2d3b112ea9984095c67639667818f25086..09425094ee8f0db67684baa06195f9da7cd78a76 100644 (file)
 
 <h2>XCLIENT Command syntax</h2>
 
-<p> Examples of client-server conversations are given at the end
+<p> An example client-server conversation is given at the end
 of this document. </p>
 
 <p> In SMTP server EHLO replies, the keyword associated with this
 extension is XCLIENT. It is followed by the names of the attributes
 that the XCLIENT implementation supports.  </p>
 
-<p> The XCLIENT command may be sent at any time except in the middle
-of a mail delivery transaction (i.e.  between MAIL and DOT).  The
-XCLIENT command may be pipelined when the server supports ESMTP
-command pipelining.  </p>
+<p> The XCLIENT command may be sent at any time, except in the
+middle of a mail delivery transaction (i.e.  between MAIL and DOT,
+or MAIL and RSET).  The XCLIENT command may be pipelined when the
+server supports ESMTP command pipelining. To avoid triggering
+spamware detectors, the command should be sent at the end of a
+command group.  </p>
 
 <p> The syntax of XCLIENT requests is described below.  Upper case
 and quoted strings specify terminals, lowercase strings specify
@@ -77,10 +79,16 @@ names are shown in upper case, they are in fact case insensitive.
 <p>
     attribute-name = ( NAME | ADDR | PROTO | HELO )
 </p>
+<p>
+    attribute-value = xtext
+</p>
 </blockquote>
 
 <ul>
 
+    <li> <p> Attribute values are xtext encoded as per <a href="http://www.faqs.org/rfcs/rfc1891.html">RFC 1891</a>.
+    </p>
+
     <li> <p> The NAME attribute specifies an SMTP client hostname
     (not an SMTP client address), [UNAVAILABLE] when client hostname
     lookup failed due to a permanent error, or [TEMPUNAVAIL] when
@@ -100,16 +108,52 @@ names are shown in upper case, they are in fact case insensitive.
 
 </ul>
 
-<p> Note 1: syntactically valid NAME and HELO attributes can be up
-to 255 characters long. The client must not send XCLIENT commands
-that exceed the 512 character limit for SMTP commands. To avoid
-exceeding the limit the client should send the information in
-multiple XCLIENT commands. </p>
+<p> Note 1: syntactically valid NAME and HELO attribute-value
+elements can be up to 255 characters long. The client must not send
+XCLIENT commands that exceed the 512 character limit for SMTP
+commands. To avoid exceeding the limit the client should send the
+information in multiple XCLIENT commands; for example, send NAME
+and ADDR first, then HELO and PROTO. </p>
 
 <p> Note 2: [UNAVAILABLE], [TEMPUNAVAIL] and IPV6:  may be specified
 in upper case, lower case or mixed case. </p>
 
-<p> The XCLIENT server reply codes are as follows: </p>
+<p> Note 3: Postfix implementations prior to version 2.3 do not
+xtext encode attribute values. Servers that wish to interoperate
+with these older implementations should be prepared to receive
+unencoded information. </p>
+
+<h2>XCLIENT Server response</h2>
+
+<p> Upon receipt of a correctly formatted XCLIENT command, the
+server resets state to the initial SMTP greeting protocol stage.
+Depending on the outcome of optional access decisions, the server
+responds with 220 or with a suitable rejection code.
+
+<p> For practical reasons it is not always possible to reset the
+complete server state to the initial SMTP greeting protocol stage:
+</p>
+
+<ul>
+
+<li> <p> TLS session information may not be reset, because turning off
+TLS leaves the connection in an undefined state.  Consequently, the
+server may not announce STARTTLS when TLS is already active, and
+access decisions may be influenced by client certificate information
+that was received prior to the XCLIENT command. </p>
+
+<li> <p> The SMTP server must not reset attributes that were received
+with the last XCLIENT command. This includes HELO or PROTO attributes.
+</p>
+
+</ul>
+
+<p> NOTE: Postfix implementations prior to version 2.3 do not jump
+back to the initial SMTP greeting protocol stage.  These older
+implementations will not correctly simulate connection-level access
+decisions under some conditions.  </p>
+
+<h2> XCLIENT server reply codes </h2>
 
 <blockquote>
 
@@ -117,23 +161,28 @@ in upper case, lower case or mixed case. </p>
 
 <tr> <th> Code </th> <th> Meaning </th> </tr>
 
-<tr> <td> 250 </td> <td> success  </td> </tr>
+<tr> <td> 220 </td> <td> success  </td> </tr>
+
+<tr> <td> 421 </td> <td> unable to proceed, disconnecting </td> </tr>
 
 <tr> <td> 501 </td> <td> bad command parameter syntax </td> </tr>
 
 <tr> <td> 503 </td> <td> mail transaction in progress </td> </tr>
 
-<tr> <td> 421 </td> <td> unable to proceed, disconnecting </td> </tr>
+<tr> <td> 550 </td> <td> insufficient authorization </td> </tr>
+
+<tr> <td> other </td> <td> connection rejected by connection-level
+access decision </td> </tr>
 
 </table>
 
 </blockquote>
 
-<h2>XCLIENT Examples</h2>
+<h2>XCLIENT Example</h2>
 
-<p> In the first example, the client impersonates a mail originating
-system by passing all SMTP session information via XCLIENT commands.
-Information sent by the client is shown in bold font.
+<p> In the example, the client impersonates a mail originating
+system by passing all SMTP client information via the XCLIENT
+command.  Information sent by the client is shown in bold font.
 </p>
 
 <blockquote>
@@ -147,37 +196,16 @@ Information sent by the client is shown in bold font.
 250-ETRN
 250-XCLIENT NAME ADDR PROTO HELO
 250 8BITMIME
-<b>XCLIENT NAME=spike.porcupine.org ADDR=168.100.189.2 PROTO=ESMTP </b>
-250 Ok
-<b>XCLIENT HELO=spike.porcupine.org</b>
-250 Ok
-<b>MAIL FROM:&lt;wietse@porcupine.org&gt;</b>
-250 Ok
-<b>RCPT TO:&lt;user@example.com&gt;</b>
-250 Ok
-<b>DATA</b>
-354 End data with &lt;CR&gt;&lt;LF&gt;.&lt;CR&gt;&lt;LF&gt;
-<b>. . .<i>message content</i>. . .</b>
-<b>.</b>
-250 Ok: queued as 763402AAE6
-<b>QUIT</b>
-221 Bye
-</pre>
-</blockquote>
-
-<p> In the second example, the client impersonates a mail originating
-system by sending the XCLIENT command before the EHLO or HELO command.
-This increases the realism of impersonation, but requires that the
-client knows ahead of time what XCLIENT options the server supports.
-</p>
-
-<blockquote>
-<pre>
-220 server.example.com ESMTP Postfix
 <b>XCLIENT NAME=spike.porcupine.org ADDR=168.100.189.2</b>
-250 Ok
-<b>HELO spike.porcupine.org</b>
-250 server.example.com
+220 server.example.com ESMTP Postfix
+<b>EHLO spike.porcupine.org</b>
+250-server.example.com
+250-PIPELINING
+250-SIZE 10240000
+250-VRFY
+250-ETRN
+250-XCLIENT NAME ADDR PROTO HELO
+250 8BITMIME
 <b>MAIL FROM:&lt;wietse@porcupine.org&gt;</b>
 250 Ok
 <b>RCPT TO:&lt;user@example.com&gt;</b>
@@ -186,7 +214,7 @@ client knows ahead of time what XCLIENT options the server supports.
 354 End data with &lt;CR&gt;&lt;LF&gt;.&lt;CR&gt;&lt;LF&gt;
 <b>. . .<i>message content</i>. . .</b>
 <b>.</b>
-250 Ok: queued as CF1E52AAE7
+250 Ok: queued as 763402AAE6
 <b>QUIT</b>
 221 Bye
 </pre>
@@ -196,8 +224,7 @@ client knows ahead of time what XCLIENT options the server supports.
 
 <p> The XCLIENT command changes audit trails and/or SMTP client
 access permissions. Use of this command must be restricted to
-authorized SMTP clients. However, the XCLIENT command should not
-override its own access control mechanism. </p>
+authorized SMTP clients. </p>
 
 <h2>SMTP connection caching</h2>
 
@@ -206,6 +233,11 @@ If one session is used to deliver mail on behalf of different SMTP
 clients, the XCLIENT attributes need to be reset as appropriate 
 before each MAIL FROM command. </p>
 
+<h2> References </h2>
+
+<p> Moore, K, "SMTP Service Extension for Delivery Status Notifications",
+<a href="http://www.faqs.org/rfcs/rfc1891.html">RFC 1891</a>, January 1996. </p>
+
 </body>
 
 </html>
index 11a26b40f8deed8e983f8c5b5cc11b5cb9cf6257..8f6677eff76ad045aa24063b565a061c51f0f3eb 100644 (file)
 
 </ul>
 
-<p> This extension is implemented as a separate command, and can
-be used to transmit client or message attributes incrementally.
+<p> This extension is implemented as a separate EMSTP command, and
+can be used to transmit client or message attributes incrementally.
 It is not implemented by passing additional parameters via the MAIL
 FROM command, because doing so would require extending the MAIL
 FROM command length limit by another 600 or more characters beyond
-the space that is already needed in order to support other extensions
-such as AUTH. </p>
+the space that is already needed to support other extensions such
+as AUTH. </p>
 
 <h2>XFORWARD Command syntax</h2>
 
@@ -71,10 +71,16 @@ names are shown in upper case, they are in fact case insensitive.
 <p>
     attribute-name = ( NAME | ADDR | PROTO | HELO | SOURCE )
 </p>
+<p>
+    attribute-value = xtext
+</p>
 </blockquote>
 
 <ul>
 
+    <li> <p> Attribute values are xtext encoded as per <a href="http://www.faqs.org/rfcs/rfc1891.html">RFC 1891</a>.
+    </p>
+
     <li> <p> The NAME attribute specifies the up-stream hostname,
     or [UNAVAILABLE] when the information is unavailable. The
     hostname may be a non-DNS hostname. </p>
@@ -85,7 +91,7 @@ names are shown in upper case, they are in fact case insensitive.
     be a non-IP address. </p>
 
     <li> <p> The PROTO attribute specifies the mail protocol for
-    receiving mail from the up-stream host. This may be an SMTP
+    receiving mail from the up-stream host. This may be an SMTP or
     non-SMTP protocol name of up to 64 characters, or [UNAVAILABLE]
     when the information is unavailable. </p>
 
@@ -105,12 +111,11 @@ names are shown in upper case, they are in fact case insensitive.
 
 </ul>
 
-<p> Note 1: Attribute values must not be longer than 255 characters
-(specific attributes may impose shorter lengths), must not contain
-control characters, non-ASCII characters, whitespace, or other
-characters that are special in message headers. Future attributes
-that may violate this should use xtext encoding as described in
-<a href="http://www.faqs.org/rfcs/rfc1891.html">RFC 1891</a>.  </p>
+<p> Note 1: an attribute-value element must not be longer than
+255 characters (specific attributes may impose shorter lengths).
+After xtext decoding, attribute values must not contain control
+characters, non-ASCII characters, whitespace, or other characters
+that are special in message headers.  </p>
 
 <p> Note 2: DNS hostnames can be up to 255 characters long. The
 XFORWARD client implementation must not send XFORWARD commands that
@@ -123,7 +128,20 @@ case or mixed case. </p>
 information from the current SMTP session with forwarded information
 from an up-stream session. </p>
 
-<p> The XFORWARD server reply codes are as follows: </p>
+<p> Note 5: Postfix implementations prior to version 2.3 do not
+xtext encode attribute values. Servers that wish to interoperate
+with these older implementations should be prepared to receive
+unencoded information. </p>
+
+<h2> XFORWARD Server response </h2>
+
+<p> Upon receipt of a correctly formatted XFORWARD command, the
+server stores the specified attribute values, and erases the
+attributes whose value was specified as [UNAVAILABLE]. All XFORWARD
+attributes are reset to the real client information after the MAIL
+FROM command completes. </p>
+
+<h2> XFORWARD Server reply codes </h2>
 
 <blockquote>
 
@@ -133,11 +151,13 @@ from an up-stream session. </p>
 
 <tr> <td> 250 </td> <td> success  </td> </tr>
 
+<tr> <td> 421 </td> <td> unable to proceed, disconnecting </td> </tr>
+
 <tr> <td> 501 </td> <td> bad command parameter syntax </td> </tr>
 
 <tr> <td> 503 </td> <td> mail transaction in progress </td> </tr>
 
-<tr> <td> 421 </td> <td> unable to proceed, disconnecting </td> </tr>
+<tr> <td> 550 </td> <td> insufficient authorization </td> </tr>
 
 </table>
 
@@ -189,6 +209,11 @@ messages within the same SMTP session. The XFORWARD attributes are
 reset after the MAIL FROM command completes, so there is no risk
 of information leakage. </p>
 
+<h2> References </h2>
+
+<p> Moore, K, "SMTP Service Extension for Delivery Status Notifications",
+<a href="http://www.faqs.org/rfcs/rfc1891.html">RFC 1891</a>, January 1996. </p>
+
 </body>
 
 </html>
index 6c0bb061d1cb00a289586b7c6560423b87d11400..1b9a7864e87410251439b12fddbed3710a1bf980 100644 (file)
@@ -105,7 +105,8 @@ Received: from porcupine.org ...
 </blockquote>
 
 <p> Then I know that this is almost certainly forged mail (almost;
-see next section for the fly in the ointment). Mail that is really
+see <a href="#caveats">next section</a> for the fly in the ointment).
+Mail that is really
 sent by my systems looks like this: </p>
 
 <blockquote>
@@ -182,7 +183,7 @@ and "<tt>)</tt>" would be grouping operators.  </p>
 
 </ul>
 
-<p><strong>Caveats</strong></p>
+<p><a name="caveats"><strong>Caveats</strong></a></p>
 
 <p> Netscape Messenger (and reportedly, Mozilla) sends a HELO name
 that is identical to the sender address domain part. If you have
@@ -294,11 +295,14 @@ or http://www.t29.dk/antiantivirus.txt.  </p>
 </pre>
 </blockquote>
 
+<p> Note: these documents haven't been updated since 2004, so they
+are useful only as a starting point. </p>
+
 <p> A plea to virus or spam scanner operators: please do not make
 the problem worse by sending return mail to forged sender addresses.
 You're only harassing innocent people. If you must return mail to
 the purported sender, please return the full message headers, so
-that the sender can defend against forgeries. </p>
+that the sender can filter out the obvious forgeries. </p>
 
 </body>
 
index 167c45b9520ad35d9cc1f0bd7f8a961fa0b2d780..60929e6b00987e551baaa9ccef0656da45afeb0a 100644 (file)
@@ -139,6 +139,10 @@ configuration feature.</li>
 Victor Duchovni developed the common query, result_format, domain and
 expansion_limit interface for LDAP, MySQL and PosgreSQL.</li>
 
+<li> Leandro Santi updated the PostgreSQL client after the PostgreSQL
+developers made major database API changes in response to SQL
+injection problems, and made PQexec() handling more robust. </li>
+
 </ul>
 
 </body>
index 2f228a2d3b112ea9984095c67639667818f25086..3fe786047a28deefd205b7da737fff08acc1fece 100644 (file)
 
 <h2>XCLIENT Command syntax</h2>
 
-<p> Examples of client-server conversations are given at the end
+<p> An example client-server conversation is given at the end
 of this document. </p>
 
 <p> In SMTP server EHLO replies, the keyword associated with this
 extension is XCLIENT. It is followed by the names of the attributes
 that the XCLIENT implementation supports.  </p>
 
-<p> The XCLIENT command may be sent at any time except in the middle
-of a mail delivery transaction (i.e.  between MAIL and DOT).  The
-XCLIENT command may be pipelined when the server supports ESMTP
-command pipelining.  </p>
+<p> The XCLIENT command may be sent at any time, except in the
+middle of a mail delivery transaction (i.e.  between MAIL and DOT,
+or MAIL and RSET).  The XCLIENT command may be pipelined when the
+server supports ESMTP command pipelining. To avoid triggering
+spamware detectors, the command should be sent at the end of a
+command group.  </p>
 
 <p> The syntax of XCLIENT requests is described below.  Upper case
 and quoted strings specify terminals, lowercase strings specify
@@ -77,10 +79,16 @@ names are shown in upper case, they are in fact case insensitive.
 <p>
     attribute-name = ( NAME | ADDR | PROTO | HELO )
 </p>
+<p>
+    attribute-value = xtext
+</p>
 </blockquote>
 
 <ul>
 
+    <li> <p> Attribute values are xtext encoded as per RFC 1891.
+    </p>
+
     <li> <p> The NAME attribute specifies an SMTP client hostname
     (not an SMTP client address), [UNAVAILABLE] when client hostname
     lookup failed due to a permanent error, or [TEMPUNAVAIL] when
@@ -100,16 +108,52 @@ names are shown in upper case, they are in fact case insensitive.
 
 </ul>
 
-<p> Note 1: syntactically valid NAME and HELO attributes can be up
-to 255 characters long. The client must not send XCLIENT commands
-that exceed the 512 character limit for SMTP commands. To avoid
-exceeding the limit the client should send the information in
-multiple XCLIENT commands. </p>
+<p> Note 1: syntactically valid NAME and HELO attribute-value
+elements can be up to 255 characters long. The client must not send
+XCLIENT commands that exceed the 512 character limit for SMTP
+commands. To avoid exceeding the limit the client should send the
+information in multiple XCLIENT commands; for example, send NAME
+and ADDR first, then HELO and PROTO. </p>
 
 <p> Note 2: [UNAVAILABLE], [TEMPUNAVAIL] and IPV6:  may be specified
 in upper case, lower case or mixed case. </p>
 
-<p> The XCLIENT server reply codes are as follows: </p>
+<p> Note 3: Postfix implementations prior to version 2.3 do not
+xtext encode attribute values. Servers that wish to interoperate
+with these older implementations should be prepared to receive
+unencoded information. </p>
+
+<h2>XCLIENT Server response</h2>
+
+<p> Upon receipt of a correctly formatted XCLIENT command, the
+server resets state to the initial SMTP greeting protocol stage.
+Depending on the outcome of optional access decisions, the server
+responds with 220 or with a suitable rejection code.
+
+<p> For practical reasons it is not always possible to reset the
+complete server state to the initial SMTP greeting protocol stage:
+</p>
+
+<ul>
+
+<li> <p> TLS session information may not be reset, because turning off
+TLS leaves the connection in an undefined state.  Consequently, the
+server may not announce STARTTLS when TLS is already active, and
+access decisions may be influenced by client certificate information
+that was received prior to the XCLIENT command. </p>
+
+<li> <p> The SMTP server must not reset attributes that were received
+with the last XCLIENT command. This includes HELO or PROTO attributes.
+</p>
+
+</ul>
+
+<p> NOTE: Postfix implementations prior to version 2.3 do not jump
+back to the initial SMTP greeting protocol stage.  These older
+implementations will not correctly simulate connection-level access
+decisions under some conditions.  </p>
+
+<h2> XCLIENT server reply codes </h2>
 
 <blockquote>
 
@@ -117,23 +161,28 @@ in upper case, lower case or mixed case. </p>
 
 <tr> <th> Code </th> <th> Meaning </th> </tr>
 
-<tr> <td> 250 </td> <td> success  </td> </tr>
+<tr> <td> 220 </td> <td> success  </td> </tr>
+
+<tr> <td> 421 </td> <td> unable to proceed, disconnecting </td> </tr>
 
 <tr> <td> 501 </td> <td> bad command parameter syntax </td> </tr>
 
 <tr> <td> 503 </td> <td> mail transaction in progress </td> </tr>
 
-<tr> <td> 421 </td> <td> unable to proceed, disconnecting </td> </tr>
+<tr> <td> 550 </td> <td> insufficient authorization </td> </tr>
+
+<tr> <td> other </td> <td> connection rejected by connection-level
+access decision </td> </tr>
 
 </table>
 
 </blockquote>
 
-<h2>XCLIENT Examples</h2>
+<h2>XCLIENT Example</h2>
 
-<p> In the first example, the client impersonates a mail originating
-system by passing all SMTP session information via XCLIENT commands.
-Information sent by the client is shown in bold font.
+<p> In the example, the client impersonates a mail originating
+system by passing all SMTP client information via the XCLIENT
+command.  Information sent by the client is shown in bold font.
 </p>
 
 <blockquote>
@@ -147,37 +196,16 @@ Information sent by the client is shown in bold font.
 250-ETRN
 250-XCLIENT NAME ADDR PROTO HELO
 250 8BITMIME
-<b>XCLIENT NAME=spike.porcupine.org ADDR=168.100.189.2 PROTO=ESMTP </b>
-250 Ok
-<b>XCLIENT HELO=spike.porcupine.org</b>
-250 Ok
-<b>MAIL FROM:&lt;wietse@porcupine.org&gt;</b>
-250 Ok
-<b>RCPT TO:&lt;user@example.com&gt;</b>
-250 Ok
-<b>DATA</b>
-354 End data with &lt;CR&gt;&lt;LF&gt;.&lt;CR&gt;&lt;LF&gt;
-<b>. . .<i>message content</i>. . .</b>
-<b>.</b>
-250 Ok: queued as 763402AAE6
-<b>QUIT</b>
-221 Bye
-</pre>
-</blockquote>
-
-<p> In the second example, the client impersonates a mail originating
-system by sending the XCLIENT command before the EHLO or HELO command.
-This increases the realism of impersonation, but requires that the
-client knows ahead of time what XCLIENT options the server supports.
-</p>
-
-<blockquote>
-<pre>
-220 server.example.com ESMTP Postfix
 <b>XCLIENT NAME=spike.porcupine.org ADDR=168.100.189.2</b>
-250 Ok
-<b>HELO spike.porcupine.org</b>
-250 server.example.com
+220 server.example.com ESMTP Postfix
+<b>EHLO spike.porcupine.org</b>
+250-server.example.com
+250-PIPELINING
+250-SIZE 10240000
+250-VRFY
+250-ETRN
+250-XCLIENT NAME ADDR PROTO HELO
+250 8BITMIME
 <b>MAIL FROM:&lt;wietse@porcupine.org&gt;</b>
 250 Ok
 <b>RCPT TO:&lt;user@example.com&gt;</b>
@@ -186,7 +214,7 @@ client knows ahead of time what XCLIENT options the server supports.
 354 End data with &lt;CR&gt;&lt;LF&gt;.&lt;CR&gt;&lt;LF&gt;
 <b>. . .<i>message content</i>. . .</b>
 <b>.</b>
-250 Ok: queued as CF1E52AAE7
+250 Ok: queued as 763402AAE6
 <b>QUIT</b>
 221 Bye
 </pre>
@@ -196,8 +224,7 @@ client knows ahead of time what XCLIENT options the server supports.
 
 <p> The XCLIENT command changes audit trails and/or SMTP client
 access permissions. Use of this command must be restricted to
-authorized SMTP clients. However, the XCLIENT command should not
-override its own access control mechanism. </p>
+authorized SMTP clients. </p>
 
 <h2>SMTP connection caching</h2>
 
@@ -206,6 +233,11 @@ If one session is used to deliver mail on behalf of different SMTP
 clients, the XCLIENT attributes need to be reset as appropriate 
 before each MAIL FROM command. </p>
 
+<h2> References </h2>
+
+<p> Moore, K, "SMTP Service Extension for Delivery Status Notifications",
+RFC 1891, January 1996. </p>
+
 </body>
 
 </html>
index f8b14793f39c95890f674c875033b038c96bbf15..2fb064e6ce924875867f9e03a17d1b2078cc25f7 100644 (file)
 
 </ul>
 
-<p> This extension is implemented as a separate command, and can
-be used to transmit client or message attributes incrementally.
+<p> This extension is implemented as a separate EMSTP command, and
+can be used to transmit client or message attributes incrementally.
 It is not implemented by passing additional parameters via the MAIL
 FROM command, because doing so would require extending the MAIL
 FROM command length limit by another 600 or more characters beyond
-the space that is already needed in order to support other extensions
-such as AUTH. </p>
+the space that is already needed to support other extensions such
+as AUTH. </p>
 
 <h2>XFORWARD Command syntax</h2>
 
@@ -71,10 +71,16 @@ names are shown in upper case, they are in fact case insensitive.
 <p>
     attribute-name = ( NAME | ADDR | PROTO | HELO | SOURCE )
 </p>
+<p>
+    attribute-value = xtext
+</p>
 </blockquote>
 
 <ul>
 
+    <li> <p> Attribute values are xtext encoded as per RFC 1891.
+    </p>
+
     <li> <p> The NAME attribute specifies the up-stream hostname,
     or [UNAVAILABLE] when the information is unavailable. The
     hostname may be a non-DNS hostname. </p>
@@ -85,7 +91,7 @@ names are shown in upper case, they are in fact case insensitive.
     be a non-IP address. </p>
 
     <li> <p> The PROTO attribute specifies the mail protocol for
-    receiving mail from the up-stream host. This may be an SMTP
+    receiving mail from the up-stream host. This may be an SMTP or
     non-SMTP protocol name of up to 64 characters, or [UNAVAILABLE]
     when the information is unavailable. </p>
 
@@ -105,12 +111,11 @@ names are shown in upper case, they are in fact case insensitive.
 
 </ul>
 
-<p> Note 1: Attribute values must not be longer than 255 characters
-(specific attributes may impose shorter lengths), must not contain
-control characters, non-ASCII characters, whitespace, or other
-characters that are special in message headers. Future attributes
-that may violate this should use xtext encoding as described in
-RFC 1891.  </p>
+<p> Note 1: an attribute-value element must not be longer than
+255 characters (specific attributes may impose shorter lengths).
+After xtext decoding, attribute values must not contain control
+characters, non-ASCII characters, whitespace, or other characters
+that are special in message headers.  </p>
 
 <p> Note 2: DNS hostnames can be up to 255 characters long. The
 XFORWARD client implementation must not send XFORWARD commands that
@@ -123,7 +128,20 @@ case or mixed case. </p>
 information from the current SMTP session with forwarded information
 from an up-stream session. </p>
 
-<p> The XFORWARD server reply codes are as follows: </p>
+<p> Note 5: Postfix implementations prior to version 2.3 do not
+xtext encode attribute values. Servers that wish to interoperate
+with these older implementations should be prepared to receive
+unencoded information. </p>
+
+<h2> XFORWARD Server response </h2>
+
+<p> Upon receipt of a correctly formatted XFORWARD command, the
+server stores the specified attribute values, and erases the
+attributes whose value was specified as [UNAVAILABLE]. All XFORWARD
+attributes are reset to the real client information after the MAIL
+FROM command completes. </p>
+
+<h2> XFORWARD Server reply codes </h2>
 
 <blockquote>
 
@@ -133,11 +151,13 @@ from an up-stream session. </p>
 
 <tr> <td> 250 </td> <td> success  </td> </tr>
 
+<tr> <td> 421 </td> <td> unable to proceed, disconnecting </td> </tr>
+
 <tr> <td> 501 </td> <td> bad command parameter syntax </td> </tr>
 
 <tr> <td> 503 </td> <td> mail transaction in progress </td> </tr>
 
-<tr> <td> 421 </td> <td> unable to proceed, disconnecting </td> </tr>
+<tr> <td> 550 </td> <td> insufficient authorization </td> </tr>
 
 </table>
 
@@ -189,6 +209,11 @@ messages within the same SMTP session. The XFORWARD attributes are
 reset after the MAIL FROM command completes, so there is no risk
 of information leakage. </p>
 
+<h2> References </h2>
+
+<p> Moore, K, "SMTP Service Extension for Delivery Status Notifications",
+RFC 1891, January 1996. </p>
+
 </body>
 
 </html>
index 811dd847cd4e37d807c6d85985ecbe26dc881397..7adaf9ca2fa514c3e1f4d5d76e556cf529ad980a 100644 (file)
@@ -281,6 +281,8 @@ int db_common_expand(void *ctxArg, const char *format, const char *value,
     DB_COMMON_CTX *ctx = (DB_COMMON_CTX *) ctxArg;
     const char *vdomain = 0;
     const char *kdomain = 0;
+    const char *domain = 0;
+    int     dflag = key ? DB_COMMON_VALUE_DOMAIN : DB_COMMON_KEY_DOMAIN;
     char   *vuser = 0;
     char   *kuser = 0;
     ARGV   *parts = 0;
@@ -397,6 +399,12 @@ int db_common_expand(void *ctxArg, const char *format, const char *value,
                break;
 
            case 'd':
+               if (!(ctx->flags & dflag))
+                   msg_panic("%s: %s: %s: bad query/result template context",
+                             myname, ctx->dict->name, format);
+               if (!vdomain)
+                   msg_panic("%s: %s: %s: expanding domain-less key or value",
+                             myname, ctx->dict->name, format);
                QUOTE_VAL(ctx->dict, quote_func, vdomain, result);
                break;
 
@@ -426,10 +434,13 @@ int db_common_expand(void *ctxArg, const char *format, const char *value,
                break;
 
            case 'D':
-               if (key)
-                   QUOTE_VAL(ctx->dict, quote_func, kdomain, result);
-               else
-                   QUOTE_VAL(ctx->dict, quote_func, vdomain, result);
+               if (!(ctx->flags & DB_COMMON_KEY_DOMAIN))
+                   msg_panic("%s: %s: %s: bad query/result template context",
+                             myname, ctx->dict->name, format);
+               if ((domain = key ? kdomain : vdomain) == 0)
+                   msg_panic("%s: %s: %s: expanding domain-less key or value",
+                             myname, ctx->dict->name, format);
+               QUOTE_VAL(ctx->dict, quote_func, domain, result);
                break;
 
            case '1':
@@ -450,6 +461,13 @@ int db_common_expand(void *ctxArg, const char *format, const char *value,
                 * guaranteed to be initialized and hold enough elements to
                 * satisfy the query template.
                 */
+               if (!(ctx->flags & DB_COMMON_KEY_DOMAIN)
+                   || ctx->nparts < *cp - '0')
+                   msg_panic("%s: %s: %s: bad query/result template context",
+                             myname, ctx->dict->name, format);
+               if (!parts || parts->argc <  ctx->nparts)
+                   msg_panic("%s: %s: %s: key has too few domain labels",
+                             myname, ctx->dict->name, format);
                QUOTE_VAL(ctx->dict, quote_func,
                          parts->argv[parts->argc - (*cp - '0')], result);
                break;
index 27f9bd603190fd9284a591150a3012d2a787141b..2888ac5d4cd92641498b2598b5b2b14d7a220dd1 100644 (file)
@@ -351,31 +351,78 @@ static int dict_ldap_set_errno(LDAP * ld, int rc)
     return rc;
 }
 
-/*
- * We need a version of ldap_bind that times out, otherwise all
- * of Postfix can get wedged during daemon initialization.
- */
+/* dict_ldap_result - Read and parse LDAP result */
+
+static int dict_ldap_result(LDAP *ld, int msgid, int timeout, LDAPMessage **res)
+{
+    int     rc;
+    struct timeval mytimeval;
+
+    mytimeval.tv_sec = timeout;
+    mytimeval.tv_usec = 0;
+
+#define GET_ALL 1
+    if (ldap_result(ld, msgid, GET_ALL, &mytimeval, res) == -1)
+       return (dict_ldap_get_errno(ld));
+
+    if (dict_ldap_get_errno(ld) == LDAP_TIMEOUT) {
+       (void) ldap_abandon_ext(ld, msgid, 0, 0);
+       return (dict_ldap_set_errno(ld, LDAP_TIMEOUT));
+    }
+
+    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 timeval mytimeval;
+    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));
+}
 
-    if ((msgid = ldap_bind(dict_ldap->ld, dict_ldap->bind_dn,
-                          dict_ldap->bind_pw, LDAP_AUTH_SIMPLE)) == -1)
-       return (dict_ldap_get_errno(dict_ldap->ld));
+/* search_st - Synchronous search with timeout */
 
-    mytimeval.tv_sec = dict_ldap->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;
 
-    if (ldap_result(dict_ldap->ld, msgid, 1, &mytimeval, &res) == -1)
-       return (dict_ldap_get_errno(dict_ldap->ld));
+#define WANTVALS 0
+#define USE_SIZE_LIM_OPT -1            /* Any negative value will do */
 
-    if (dict_ldap_get_errno(dict_ldap->ld) == LDAP_TIMEOUT) {
-       (void) ldap_abandon(dict_ldap->ld, msgid);
-       return (dict_ldap_set_errno(dict_ldap->ld, LDAP_TIMEOUT));
-    }
-    return (ldap_result2error(dict_ldap->ld, res, 1));
+    if ((rc = ldap_search_ext(ld, base, scope, query, attrs, WANTVALS, 0, 0,
+                             &mytimeval, USE_SIZE_LIM_OPT,
+                             &msgid)) != LDAP_SUCCESS)
+       return rc;
+
+    if ((rc = dict_ldap_result(ld, msgid, timeout, res)) != LDAP_SUCCESS)
+       return (rc);
+
+#define DONT_FREE_RESULT 0
+    rc = ldap_parse_result(ld, *res, &err, 0, 0, 0, 0, DONT_FREE_RESULT);
+    return (err != LDAP_SUCCESS ? err : rc);
 }
 
 #ifdef LDAP_API_FEATURE_X_OPENLDAP
@@ -715,14 +762,11 @@ static void dict_ldap_get_values(DICT_LDAP *dict_ldap, LDAPMessage * res,
     LDAPMessage *resloop = 0;
     LDAPMessage *entry = 0;
     BerElement *ber;
-    char  **vals;
     char   *attr;
-    char   *myname = "dict_ldap_get_values";
-    struct timeval tv;
+    struct berval **vals;
+    int     valcount;
     LDAPURLDesc *url;
-
-    tv.tv_sec = dict_ldap->timeout;
-    tv.tv_usec = 0;
+    char   *myname = "dict_ldap_get_values";
 
     if (++recursion == 1)
        expansion = 0;
@@ -751,7 +795,7 @@ static void dict_ldap_get_values(DICT_LDAP *dict_ldap, LDAPMessage * res,
             attr != NULL;
             ldap_memfree(attr), attr = ldap_next_attribute(dict_ldap->ld,
                                                            entry, ber)) {
-           vals = ldap_get_values(dict_ldap->ld, entry, attr);
+           vals = ldap_get_values_len(dict_ldap->ld, entry, attr);
            if (vals == NULL) {
                if (msg_verbose)
                    msg_info("%s[%d]: Entry doesn't have any values for %s",
@@ -759,6 +803,8 @@ static void dict_ldap_get_values(DICT_LDAP *dict_ldap, LDAPMessage * res,
                continue;
            }
 
+           valcount = ldap_count_values_len(vals);
+
            /*
             * If we previously encountered an error, we still continue
             * through the loop, to avoid memory leaks, but we don't waste
@@ -768,8 +814,8 @@ static void dict_ldap_get_values(DICT_LDAP *dict_ldap, LDAPMessage * res,
             * leaks, but it will likely be more fragile and not worth the
             * extra code.
             */
-           if (dict_errno != 0 || vals[0] == 0) {
-               ldap_value_free(vals);
+           if (dict_errno != 0 || valcount == 0) {
+               ldap_value_free_len(vals);
                continue;
            }
 
@@ -794,9 +840,10 @@ static void dict_ldap_get_values(DICT_LDAP *dict_ldap, LDAPMessage * res,
             */
            if (i < dict_ldap->num_attributes) {
                /* Ordinary result attribute */
-               for (i = 0; vals[i] != NULL; i++) {
+               for (i = 0; i < valcount; i++) {
                    if (db_common_expand(dict_ldap->ctx,
-                                        dict_ldap->result_format, vals[i],
+                                        dict_ldap->result_format,
+                                        vals[i]->bv_val,
                                         name, result, 0)
                        && dict_ldap->expansion_limit > 0
                        && ++expansion > dict_ldap->expansion_limit) {
@@ -815,27 +862,27 @@ static void dict_ldap_get_values(DICT_LDAP *dict_ldap, LDAPMessage * res,
            } else if (recursion < dict_ldap->recursion_limit
                       && dict_ldap->result_attributes->argv[i]) {
                /* Special result attribute */
-               for (i = 0; vals[i] != NULL; i++) {
-                   if (ldap_is_ldap_url(vals[i])) {
+               for (i = 0; i < valcount; i++) {
+                   if (ldap_is_ldap_url(vals[i]->bv_val)) {
                        if (msg_verbose)
                            msg_info("%s[%d]: looking up URL %s", myname,
-                                    recursion, vals[i]);
-                       rc = ldap_url_parse(vals[i], &url);
+                                    recursion, vals[i]->bv_val);
+                       rc = ldap_url_parse(vals[i]->bv_val, &url);
                        if (rc == 0) {
-                           rc = ldap_search_st(dict_ldap->ld, url->lud_dn,
-                                           url->lud_scope, url->lud_filter,
-                                               url->lud_attrs, 0, &tv,
-                                               &resloop);
+                           rc = search_st(dict_ldap->ld, url->lud_dn,
+                                          url->lud_scope, url->lud_filter,
+                                          url->lud_attrs, dict_ldap->timeout,
+                                          &resloop);
                            ldap_free_urldesc(url);
                        }
                    } else {
                        if (msg_verbose)
                            msg_info("%s[%d]: looking up DN %s",
-                                    myname, recursion, vals[i]);
-                       rc = ldap_search_st(dict_ldap->ld, vals[i],
-                                           LDAP_SCOPE_BASE, "objectclass=*",
-                                        dict_ldap->result_attributes->argv,
-                                           0, &tv, &resloop);
+                                    myname, recursion, vals[i]->bv_val);
+                       rc = search_st(dict_ldap->ld, vals[i]->bv_val,
+                                      LDAP_SCOPE_BASE, "objectclass=*",
+                                      dict_ldap->result_attributes->argv,
+                                      dict_ldap->timeout, &resloop);
                    }
                    switch (rc) {
                    case LDAP_SUCCESS:
@@ -848,7 +895,7 @@ static void dict_ldap_get_values(DICT_LDAP *dict_ldap, LDAPMessage * res,
                         * and just didn't have any result attributes.
                         */
                        msg_warn("%s[%d]: DN %s not found, skipping ", myname,
-                                recursion, vals[i]);
+                                recursion, vals[i]->bv_val);
                        break;
                    default:
                        msg_warn("%s[%d]: search error %d: %s ", myname,
@@ -873,10 +920,10 @@ static void dict_ldap_get_values(DICT_LDAP *dict_ldap, LDAPMessage * res,
                       && dict_ldap->result_attributes->argv[i]) {
                msg_warn("%s[%d]: %s: Recursion limit exceeded"
                         " for special attribute %s=%s", myname, recursion,
-                        dict_ldap->parser->name, attr, vals[0]);
+                        dict_ldap->parser->name, attr, vals[0]->bv_val);
                dict_errno = DICT_ERR_RETRY;
            }
-           ldap_value_free(vals);
+           ldap_value_free_len(vals);
        }
        if (ber)
            ber_free(ber, 0);
@@ -897,7 +944,6 @@ static const char *dict_ldap_lookup(DICT *dict, const char *name)
     static VSTRING *base;
     static VSTRING *query;
     static VSTRING *result;
-    struct timeval tv;
     int     rc = 0;
     int     sizelimit;
 
@@ -1001,12 +1047,6 @@ static const char *dict_ldap_lookup(DICT *dict, const char *name)
         return (0);
     }
 
-    /*
-     * Prepare the query.
-     */
-    tv.tv_sec = dict_ldap->timeout;
-    tv.tv_usec = 0;
-
     /*
      * On to the search.
      */
@@ -1014,17 +1054,16 @@ static const char *dict_ldap_lookup(DICT *dict, const char *name)
        msg_info("%s: %s: Searching with filter %s", myname,
                 dict_ldap->parser->name, vstring_str(query));
 
-    rc = ldap_search_st(dict_ldap->ld, vstring_str(base),
-                       dict_ldap->scope, vstring_str(query),
-                       dict_ldap->result_attributes->argv,
-                       0, &tv, &res);
+    rc = search_st(dict_ldap->ld, vstring_str(base), dict_ldap->scope,
+                  vstring_str(query), dict_ldap->result_attributes->argv,
+                  dict_ldap->timeout, &res);
 
     if (rc == LDAP_SERVER_DOWN) {
        if (msg_verbose)
            msg_info("%s: Lost connection for LDAP source %s, reopening",
                     myname, dict_ldap->parser->name);
 
-       ldap_unbind(dict_ldap->ld);
+       ldap_unbind_ext(dict_ldap->ld, 0, 0);
        dict_ldap->ld = DICT_LDAP_CONN(dict_ldap)->conn_ld = 0;
        dict_ldap_connect(dict_ldap);
 
@@ -1034,10 +1073,9 @@ static const char *dict_ldap_lookup(DICT *dict, const char *name)
        if (dict_errno)
            return (0);
 
-       rc = ldap_search_st(dict_ldap->ld, vstring_str(base),
-                           dict_ldap->scope, vstring_str(query),
-                           dict_ldap->result_attributes->argv,
-                           0, &tv, &res);
+       rc = search_st(dict_ldap->ld, vstring_str(base), dict_ldap->scope,
+                      vstring_str(query), dict_ldap->result_attributes->argv,
+                      dict_ldap->timeout, &res);
 
     }
 
@@ -1093,7 +1131,7 @@ static const char *dict_ldap_lookup(DICT *dict, const char *name)
         * Tear down the connection so it gets set up from scratch on the
         * next lookup.
         */
-       ldap_unbind(dict_ldap->ld);
+       ldap_unbind_ext(dict_ldap->ld, 0, 0);
        dict_ldap->ld = DICT_LDAP_CONN(dict_ldap)->conn_ld = 0;
 
        /*
@@ -1130,7 +1168,7 @@ static void dict_ldap_close(DICT *dict)
            if (msg_verbose)
                msg_info("%s: Closed connection handle for LDAP source %s",
                         myname, dict_ldap->parser->name);
-           ldap_unbind(conn->conn_ld);
+           ldap_unbind_ext(conn->conn_ld, 0, 0);
        }
        binhash_delete(conn_hash, ht->key, ht->key_len, myfree);
     }
index acaf6e7861b0d583c5993c63edf12daa36463dc9..cedeec0bbce5b7300f6a34ef1b0c3b86cdb54edf 100644 (file)
@@ -217,6 +217,7 @@ typedef struct {
     char   *table;
     ARGV   *hosts;
     PLPGSQL *pldb;
+    HOST   *active_host;
 } DICT_PGSQL;
 
 
@@ -225,7 +226,8 @@ typedef struct {
 
 /* internal function declarations */
 static PLPGSQL *plpgsql_init(ARGV *);
-static PGSQL_RES *plpgsql_query(PLPGSQL *, const char *, char *, char *, char *);
+static PGSQL_RES *plpgsql_query(DICT_PGSQL *, const char *, VSTRING *, char *,
+                               char *, char *);
 static void plpgsql_dealloc(PLPGSQL *);
 static void plpgsql_close_host(HOST *);
 static void plpgsql_down_host(HOST *);
@@ -235,41 +237,83 @@ DICT   *dict_pgsql_open(const char *, int, int);
 static void dict_pgsql_close(DICT *);
 static HOST *host_init(const char *);
 
-
 /* dict_pgsql_quote - escape SQL metacharacters in input string */
 
-static void dict_pgsql_quote(DICT *unused, const char *name, VSTRING *result)
+static void dict_pgsql_quote(DICT *dict, const char *name, VSTRING *result)
 {
-    const char *sub;
+    DICT_PGSQL *dict_pgsql = (DICT_PGSQL *) dict;
+    HOST  *active_host = dict_pgsql->active_host;
+    char  *myname = "dict_pgsql_quote";
+    size_t len = strlen(name);
+    size_t buflen = 2*len + 1;
+    int err = 1;
+
+    if (active_host == 0)
+       msg_panic("%s: bogus dict_pgsql->active_host", myname);
 
     /*
-     * XXX We really should be using an escaper that is provided by the PGSQL
-     * library. The code below seems to be over-kill (see RUS-CERT Advisory
-     * 2001-08:01), but it's better to be safe than to be sorry -- Wietse
+     * We won't get arithmetic overflows in 2*len + 1, because Postfix
+     * input keys have reasonable size limits, better safe than sorry.
      */
-     for (sub = name; *sub; sub++) {
-        switch(*sub) {
-       case '\n':
-            vstring_strcat(result, "\\n");
-           break;
-       case '\r':
-           vstring_strcat(result, "\\r");
-           break;
-       case '\'':
-           vstring_strcat(result, "\\'");
-           break;
-       case '"':
-           vstring_strcat(result, "\\\"");
-           break;
-       case 0:
-           vstring_strcat(result, "\\0");
-           break;
-       default:
-           VSTRING_ADDCH(result, *sub);
-           break;
-       }
+    if (buflen <= len)
+       msg_panic("%s: arithmetic overflow in 2*%lu+1", 
+                 myname, (unsigned long) len);
+
+    /*
+     * XXX Workaround: stop further processing when PQescapeStringConn()
+     * (below) fails. A more proper fix requires invasive changes, not
+     * suitable for a stable release.
+     */
+    if (active_host->stat == STATFAIL)
+       return;
+
+    /*
+     * Escape the input string, using PQescapeStringConn(), because
+     * the older PQescapeString() is not safe anymore, as stated by the
+     * documentation.
+     *
+     * From current libpq (8.1.4) documentation:
+     *
+     * PQescapeStringConn writes an escaped version of the from string 
+     * to the to buffer, escaping special characters so that they cannot
+     * cause any harm, and adding a terminating zero byte.
+     *
+     * ...
+     *
+     * The parameter from points to the first character of the string 
+     * that is to be escaped, and the length parameter gives the number 
+     * of bytes in this string. A terminating zero byte is not required,
+     * and should not be counted in length.
+     *
+     * ...
+     *
+     * (The parameter) to shall point to a buffer that is able to hold 
+     * at least one more byte than twice the value of length, otherwise
+     * the behavior is undefined.
+     *
+     * ...
+     *
+     * If the error parameter is not NULL, then *error is set to zero on
+     * success, nonzero on error ... The output string is still generated
+     * on error, but it can be expected that the server will reject it as
+     * malformed. On error, a suitable message is stored in the conn 
+     * object, whether or not error is NULL.
+     */
+    VSTRING_SPACE(result, buflen);
+    PQescapeStringConn(active_host->db, vstring_end(result), name, len, &err);
+    if (err == 0) {
+       VSTRING_SKIP(result);
+    } else {
+       /* 
+        * PQescapeStringConn() failed. According to the docs, we still 
+        * have a valid, null-terminated output string, but we need not
+        * rely on this behavior.
+        */
+       msg_warn("dict pgsql: (host %s) cannot escape input string: %s", 
+                active_host->hostname, PQerrorMessage(active_host->db));
+       active_host->stat = STATFAIL;
+       VSTRING_TERMINATE(result);
     }
-    VSTRING_TERMINATE(result);
 }
 
 /* dict_pgsql_lookup - find database entry */
@@ -324,14 +368,19 @@ static const char *dict_pgsql_lookup(DICT *dict, const char *name)
     }
 
     /*
-     * Suppress the actual lookup if the expansion is empty
+     * Suppress the actual lookup if the expansion is empty.
+     * 
+     * This initial expansion is outside the context of any
+     * specific host connection, we just want to check the
+     * key pre-requisites, so when quoting happens separately
+     * for each connection, we don't bother with quoting...
      */
     if (!db_common_expand(dict_pgsql->ctx, dict_pgsql->query,
-                         name, 0, query, dict_pgsql_quote))
+                         name, 0, query, 0))
        return (0);
     
     /* do the query - set dict_errno & cleanup if there's an error */
-    if ((query_res = plpgsql_query(pldb, vstring_str(query),
+    if ((query_res = plpgsql_query(dict_pgsql, name, query,
                                   dict_pgsql->dbname,
                                   dict_pgsql->username,
                                   dict_pgsql->password)) == 0) {
@@ -466,28 +515,104 @@ static void dict_pgsql_event(int unused_event, char *context)
  *                     close unnecessary active connections
  */
 
-static PGSQL_RES *plpgsql_query(PLPGSQL *PLDB,
-                                       const char *query,
+static PGSQL_RES *plpgsql_query(DICT_PGSQL *dict_pgsql,
+                                       const char *name,
+                                       VSTRING *query,
                                        char *dbname,
                                        char *username,
                                        char *password)
 {
+    PLPGSQL *PLDB = dict_pgsql->pldb;
     HOST   *host;
     PGSQL_RES *res = 0;
+    ExecStatusType status;
 
     while ((host = dict_pgsql_get_active(PLDB, dbname, username, password)) != NULL) {
-       if ((res = PQexec(host->db, query)) == 0) {
-           msg_warn("pgsql query failed: %s", PQerrorMessage(host->db));
+       /*
+        * The active host is used to escape strings in the
+        * context of the active connection's character encoding.
+        */
+       dict_pgsql->active_host = host;
+       VSTRING_RESET(query);
+       VSTRING_TERMINATE(query);
+       db_common_expand(dict_pgsql->ctx, dict_pgsql->query,
+                        name, 0, query, dict_pgsql_quote);
+       dict_pgsql->active_host = 0;
+
+       /* Check for potential dict_pgsql_quote() failure. */
+       if (host->stat == STATFAIL) {
            plpgsql_down_host(host);
+           continue;
+       }
+
+       /* 
+        * 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 {
-           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;
+           /* 
+            * 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)
 {
     if ((host->db = PQsetdbLogin(host->name, host->port, NULL, NULL,
-                                dbname, username, password)) != NULL) {
-       if (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 {
+                                dbname, username, password)) == NULL
+       || PQstatus(host->db) != CONNECTION_OK) {
        msg_warn("connect to pgsql server %s: %s",
                 host->hostname, PQerrorMessage(host->db));
        plpgsql_down_host(host);
+       return;
+    }
+
+    if (msg_verbose)
+       msg_info("dict_pgsql: successful connection to host %s",
+                host->hostname);
+
+    /*
+     * XXX Postfix does not send multi-byte characters. The following
+     * piece of code is an explicit statement of this fact, and the 
+     * database server should not accept multi-byte information after
+     * this point.
+     */
+    if (PQsetClientEncoding(host->db, "LATIN1") != 0) {
+       msg_warn("dict_pgsql: cannot set the encoding to LATIN1, skipping %s",
+                host->hostname);
+       plpgsql_down_host(host);
+       return;
     }
+
+    /* Success. */
+    host->stat = STATACTIVE;
 }
 
 /* plpgsql_close_host - close an established PostgreSQL connection */
@@ -546,7 +682,6 @@ static void pgsql_parse_config(DICT_PGSQL *dict_pgsql, const char *pgsqlcf)
 {
     const char *myname = "pgsql_parse_config";
     CFG_PARSER *p;
-    int     i;
     char   *hosts;
     VSTRING *query;
     char   *select_function;
@@ -627,6 +762,7 @@ DICT   *dict_pgsql_open(const char *name, int open_flags, int dict_flags)
     dict_pgsql->dict.close = dict_pgsql_close;
     dict_pgsql->dict.flags = dict_flags;
     pgsql_parse_config(dict_pgsql, name);
+    dict_pgsql->active_host = 0;
     dict_pgsql->pldb = plpgsql_init(dict_pgsql->hosts);
     if (dict_pgsql->pldb == NULL)
        msg_fatal("couldn't intialize pldb!\n");
@@ -689,7 +825,6 @@ static HOST *host_init(const char *hostname)
 
 static void dict_pgsql_close(DICT *dict)
 {
-    int     i;
     DICT_PGSQL *dict_pgsql = (DICT_PGSQL *) dict;
 
     plpgsql_dealloc(dict_pgsql->pldb);
index 97688435afd3646acd15acbb603f87d77e0feb92..1112b4d395e1c9d28412a4ef7257bb99da18ca90 100644 (file)
@@ -20,7 +20,7 @@
   * Patches change both the patchlevel and the release date. Snapshots have no
   * patchlevel; they change the release date only.
   */
-#define MAIL_RELEASE_DATE      "20060604"
+#define MAIL_RELEASE_DATE      "20060611"
 #define MAIL_VERSION_NUMBER    "2.3"
 
 #ifdef SNAPSHOT
index 24507d5ee6b530b751abd5ab4b6311f47bb36a9e..82d18e513fe3b5134d94ed31435ac1b04d8b0d17 100644 (file)
 /*     An I/O error happened, or the peer has disconnected unexpectedly.
 /* .IP SMTP_ERR_TIME
 /*     The time limit specified to smtp_timeout_setup() was exceeded.
+/* .PP
+/*     Additional error codes that may be used by applications:
 /* .IP SMTP_ERR_QUIET
 /*     Perform silent cleanup; the error was already reported by
 /*     the application.
 /*     This error is never generated by the smtp_stream(3) module, but
 /*     is defined for application-specific use.
+/* .IP SMTP_ERR_NONE
+/*     A non-error code that makes setjmp()/longjmp() convenient
+/*     to use.
 /* BUGS
 /*     The timeout deadline affects all I/O on the named stream, not
 /*     just the I/O done on behalf of this module.
index a09a13f898a869b164b69cc1a94c112227c8952e..5593922164404cf73475565576c3e36b842788c3 100644 (file)
 #include <vstream.h>
 
  /*
-  * External interface.
+  * External interface. The following codes are meant for use in longjmp(),
+  * so they must all be non-zero.
   */
 #define SMTP_ERR_EOF   1               /* unexpected client disconnect */
 #define SMTP_ERR_TIME  2               /* time out */
-#define SMTP_ERR_QUIET 4               /* silent cleanup (application) */
+#define SMTP_ERR_QUIET 3               /* silent cleanup (application) */
+#define SMTP_ERR_NONE  4               /* non-error case */
 
 extern void smtp_timeout_setup(VSTREAM *, int);
 extern void PRINTFLIKE(2, 3) smtp_printf(VSTREAM *, const char *,...);
index a736070f56265cfb0b637452ec9084c59a1a2c15..3bcb8c3d462d32330c57294ef9eda2d1685565a1 100644 (file)
 /*     const char *unquoted;
 /*     const char *special;
 /*
-/*     VSTRING *xtext_unquote_append(unquoted, quoted)
+/*     VSTRING *xtext_quote_append(unquoted, quoted, special)
 /*     VSTRING *unquoted;
 /*     const char *quoted;
+/*     const char *special;
 /*
 /*     VSTRING *xtext_unquote(unquoted, quoted)
 /*     VSTRING *unquoted;
index 778540a015324a854bd9ad514536b98feaa33879..2ff6ee88a4637dc70bebdd465363ff08f26f2744 100644 (file)
@@ -711,7 +711,7 @@ static int qmgr_message_read(QMGR_MESSAGE *message)
        if (rec_type > 0)
            msg_warn("%s: ignoring out-of-order DSN original recipient <%.200s>",
                     message->queue_id, dsn_orcpt);
-       myfree(orig_rcpt);
+       myfree(dsn_orcpt);
     }
     if (orig_rcpt != 0) {
        if (rec_type > 0)
index 1dcdf269daf41cdbbe0e3124bde80f8c9d3bd81f..c0325d093f16b91aa7fd1681ec3da7d38eab4c81 100644 (file)
@@ -1002,14 +1002,18 @@ static int smtp_loop(SMTP_STATE *state, NOCLOBBER int send_state,
             */
        case SMTP_STATE_XFORWARD_NAME_ADDR:
            vstring_strcpy(next_command, XFORWARD_CMD);
-           if (session->features & SMTP_FEATURE_XFORWARD_NAME)
-               vstring_sprintf_append(next_command, " %s=%s",
-                  XFORWARD_NAME, DEL_REQ_ATTR_AVAIL(request->client_name) ?
-                              request->client_name : XFORWARD_UNAVAILABLE);
-           if (session->features & SMTP_FEATURE_XFORWARD_ADDR)
-               vstring_sprintf_append(next_command, " %s=%s",
-                  XFORWARD_ADDR, DEL_REQ_ATTR_AVAIL(request->client_addr) ?
-                              request->client_addr : XFORWARD_UNAVAILABLE);
+           if (session->features & SMTP_FEATURE_XFORWARD_NAME) {
+               vstring_strcat(next_command, " " XFORWARD_NAME "=");
+               xtext_quote_append(next_command,
+                                  DEL_REQ_ATTR_AVAIL(request->client_name) ?
+                          request->client_name : XFORWARD_UNAVAILABLE, "");
+           }
+           if (session->features & SMTP_FEATURE_XFORWARD_ADDR) {
+               vstring_strcat(next_command, " " XFORWARD_ADDR "=");
+               xtext_quote_append(next_command,
+                                  DEL_REQ_ATTR_AVAIL(request->client_addr) ?
+                          request->client_addr : XFORWARD_UNAVAILABLE, "");
+           }
            if (session->send_proto_helo)
                next_state = SMTP_STATE_XFORWARD_PROTO_HELO;
            else
@@ -1018,20 +1022,26 @@ static int smtp_loop(SMTP_STATE *state, NOCLOBBER int send_state,
 
        case SMTP_STATE_XFORWARD_PROTO_HELO:
            vstring_strcpy(next_command, XFORWARD_CMD);
-           if (session->features & SMTP_FEATURE_XFORWARD_PROTO)
-               vstring_sprintf_append(next_command, " %s=%s",
-                XFORWARD_PROTO, DEL_REQ_ATTR_AVAIL(request->client_proto) ?
-                             request->client_proto : XFORWARD_UNAVAILABLE);
-           if (session->features & SMTP_FEATURE_XFORWARD_HELO)
-               vstring_sprintf_append(next_command, " %s=%s",
-                  XFORWARD_HELO, DEL_REQ_ATTR_AVAIL(request->client_helo) ?
-                              request->client_helo : XFORWARD_UNAVAILABLE);
-           if (session->features & SMTP_FEATURE_XFORWARD_DOMAIN)
-               vstring_sprintf_append(next_command, " %s=%s", XFORWARD_DOMAIN,
+           if (session->features & SMTP_FEATURE_XFORWARD_PROTO) {
+               vstring_strcat(next_command, " " XFORWARD_PROTO "=");
+               xtext_quote_append(next_command,
+                                DEL_REQ_ATTR_AVAIL(request->client_proto) ?
+                         request->client_proto : XFORWARD_UNAVAILABLE, "");
+           }
+           if (session->features & SMTP_FEATURE_XFORWARD_HELO) {
+               vstring_strcat(next_command, " " XFORWARD_HELO "=");
+               xtext_quote_append(next_command,
+                                  DEL_REQ_ATTR_AVAIL(request->client_helo) ?
+                          request->client_helo : XFORWARD_UNAVAILABLE, "");
+           }
+           if (session->features & SMTP_FEATURE_XFORWARD_DOMAIN) {
+               vstring_strcat(next_command, " " XFORWARD_DOMAIN "=");
+               xtext_quote_append(next_command,
                         DEL_REQ_ATTR_AVAIL(request->rewrite_context) == 0 ?
-                                      XFORWARD_UNAVAILABLE :
+                                  XFORWARD_UNAVAILABLE :
                     strcmp(request->rewrite_context, MAIL_ATTR_RWR_LOCAL) ?
-                                 XFORWARD_DOM_REMOTE : XFORWARD_DOM_LOCAL);
+                             XFORWARD_DOM_REMOTE : XFORWARD_DOM_LOCAL, "");
+           }
            next_state = SMTP_STATE_MAIL;
            break;
 
index d39c701855ca725ef57a6c87590a8d77a7db2e3a..6dbe2ebf3393e5ea286addffc787f06613056c52 100644 (file)
@@ -329,6 +329,7 @@ smtpd_proxy.o: ../../include/tls.h
 smtpd_proxy.o: ../../include/vbuf.h
 smtpd_proxy.o: ../../include/vstream.h
 smtpd_proxy.o: ../../include/vstring.h
+smtpd_proxy.o: ../../include/xtext.h
 smtpd_proxy.o: smtpd.h
 smtpd_proxy.o: smtpd_proxy.c
 smtpd_proxy.o: smtpd_proxy.h
index e0661dc94f96ac1a0ba9ab796358a5d434cce4ae..5b715cb9347bfc39df1ca51887cfe3816975540d 100644 (file)
@@ -2662,6 +2662,7 @@ static int quit_cmd(SMTPD_STATE *state, int unused_argc, SMTPD_TOKEN *unused_arg
 static int xclient_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv)
 {
     SMTPD_TOKEN *argp;
+    char   *raw_value;
     char   *attr_value;
     const char *bare_value;
     char   *attr_name;
@@ -2677,10 +2678,14 @@ static int xclient_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv)
        MAIL_PROTO_ESMTP, 2,
        0, -1,
     };
+    int     got_helo = 0;
+    int     got_proto = 0;
 
     /*
-     * Sanity checks. The XCLIENT command does not override its own access
-     * control.
+     * Sanity checks.
+     * 
+     * XXX The XCLIENT command will override its own access control, so that
+     * connection count/rate restrictions can be correctly simulated.
      */
     if (IN_MAIL_TRANSACTION(state)) {
        state->error_mask |= MAIL_ERROR_PROTOCOL;
@@ -2705,21 +2710,40 @@ static int xclient_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv)
            s = (_v) ? mystrdup(_v) : 0; \
        } while(0)
 
+    /*
+     * Initialize.
+     */
+    if (state->expand_buf == 0)
+       state->expand_buf = vstring_alloc(100);
+
     /*
      * Iterate over all attribute=value elements.
      */
     for (argp = argv + 1; argp < argv + argc; argp++) {
        attr_name = argp->strval;
 
-       /*
-        * For safety's sake mask non-printable characters. We'll do more
-        * specific censoring later.
-        */
-       if ((attr_value = split_at(attr_name, '=')) == 0 || *attr_value == 0) {
+       if ((raw_value = split_at(attr_name, '=')) == 0 || *raw_value == 0) {
            state->error_mask |= MAIL_ERROR_PROTOCOL;
            smtpd_chat_reply(state, "501 5.5.4 Error: attribute=value expected");
            return (-1);
        }
+       if (strlen(raw_value) > 255) {
+           state->error_mask |= MAIL_ERROR_PROTOCOL;
+           smtpd_chat_reply(state, "501 5.5.4 Error: attribute value too long");
+           return (-1);
+       }
+
+       /*
+        * Backwards compatibility: Postfix prior to version 2.3 does not
+        * xtext encode attribute values.
+        */
+       attr_value = xtext_unquote(state->expand_buf, raw_value) ?
+           STR(state->expand_buf) : raw_value;
+
+       /*
+        * For safety's sake mask non-printable characters. We'll do more
+        * specific censoring later.
+        */
        printable(attr_value, '?');
 
        /*
@@ -2805,6 +2829,7 @@ static int xclient_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv)
                neuter(attr_value, NEUTER_CHARACTERS, '?');
            }
            UPDATE_STR(state->helo_name, attr_value);
+           got_helo = 1;
        }
 
        /*
@@ -2818,6 +2843,7 @@ static int xclient_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv)
                return (-1);
            }
            UPDATE_STR(state->protocol, uppercase(attr_value));
+           got_proto = 1;
        }
 
        /*
@@ -2840,7 +2866,41 @@ static int xclient_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv)
        state->namaddr =
            concatenate(state->name, "[", state->addr, "]", (char *) 0);
     }
-    smtpd_chat_reply(state, "250 2.0.0 Ok");
+
+    /*
+     * XXX Compatibility: when the client issues XCLIENT then we have to go
+     * back to initial server greeting stage, otherwise we can't correctly
+     * simulate smtpd_client_restrictions (with smtpd_delay_reject=0) and
+     * Milter connect restrictions.
+     * 
+     * XXX Compatibility: for accurate simulation we must also reset the HELO
+     * information. We keep the information if it was specified in the
+     * XCLIENT command.
+     * 
+     * XXX The client connection count/rate control must be consistent in its
+     * use of client address information in connect and disconnect events. We
+     * re-evaluate xclient so that we correctly simulate connection
+     * concurrency and connection rate restrictions.
+     * 
+     * XXX Duplicated from smtpd_proto().
+     */
+    xclient_allowed =
+       namadr_list_match(xclient_hosts, state->name, state->addr);
+    /* NOT: tls_reset() */
+    if (got_helo == 0)
+       helo_reset(state);
+    if (got_proto == 0 && strcasecmp(state->protocol, MAIL_PROTO_SMTP) != 0) {
+       myfree(state->protocol);
+        state->protocol = mystrdup(MAIL_PROTO_SMTP);
+    }
+#ifdef USE_SASL_AUTH
+    if (var_smtpd_sasl_enable)
+       smtpd_sasl_auth_reset(state);
+#endif
+    chat_reset(state, 0);
+    mail_reset(state);
+    rcpt_reset(state);
+    vstream_longjmp(state->client, SMTP_ERR_NONE);
     return (0);
 }
 
@@ -2849,6 +2909,7 @@ static int xclient_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv)
 static int xforward_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv)
 {
     SMTPD_TOKEN *argp;
+    char   *raw_value;
     char   *attr_value;
     const char *bare_value;
     char   *attr_name;
@@ -2898,6 +2959,8 @@ static int xforward_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv)
      */
     if (state->xforward.flags == 0)
        smtpd_xforward_preset(state);
+    if (state->expand_buf == 0)
+       state->expand_buf = vstring_alloc(100);
 
     /*
      * Iterate over all attribute=value elements.
@@ -2905,20 +2968,28 @@ static int xforward_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv)
     for (argp = argv + 1; argp < argv + argc; argp++) {
        attr_name = argp->strval;
 
-       /*
-        * For safety's sake mask non-printable characters. We'll do more
-        * specific censoring later.
-        */
-       if ((attr_value = split_at(attr_name, '=')) == 0 || *attr_value == 0) {
+       if ((raw_value = split_at(attr_name, '=')) == 0 || *raw_value == 0) {
            state->error_mask |= MAIL_ERROR_PROTOCOL;
            smtpd_chat_reply(state, "501 5.5.4 Error: attribute=value expected");
            return (-1);
        }
-       if (strlen(attr_value) > 255) {
+       if (strlen(raw_value) > 255) {
            state->error_mask |= MAIL_ERROR_PROTOCOL;
            smtpd_chat_reply(state, "501 5.5.4 Error: attribute value too long");
            return (-1);
        }
+
+       /*
+        * Backwards compatibility: Postfix prior to version 2.3 does not
+        * xtext encode attribute values.
+        */
+       attr_value = xtext_unquote(state->expand_buf, raw_value) ?
+           STR(state->expand_buf) : raw_value;
+
+       /*
+        * For safety's sake mask non-printable characters. We'll do more
+        * specific censoring later.
+        */
        printable(attr_value, '?');
 
        flag = name_code(xforward_flags, NAME_CODE_FLAG_NONE, attr_name);
@@ -3268,7 +3339,7 @@ static STRING_LIST *smtpd_forbid_cmds;
 
 /* smtpd_proto - talk the SMTP protocol */
 
-static void smtpd_proto(SMTPD_STATE *state, const char *service)
+static void smtpd_proto(SMTPD_STATE *state)
 {
     int     argc;
     SMTPD_TOKEN *argv;
@@ -3276,6 +3347,7 @@ static void smtpd_proto(SMTPD_STATE *state, const char *service)
     int     count;
     int     crate;
     const char *ehlo_words;
+    int     status;
 
     /*
      * Print a greeting banner and run the state machine. Read SMTP commands
@@ -3297,7 +3369,9 @@ static void smtpd_proto(SMTPD_STATE *state, const char *service)
      */
     smtp_timeout_setup(state->client, var_smtpd_tmout);
 
-    switch (vstream_setjmp(state->client)) {
+    while ((status = vstream_setjmp(state->client)) == SMTP_ERR_NONE)
+        /* void */ ;
+    switch (status) {
 
     default:
        msg_panic("smtpd_proto: unknown error reading from %s[%s]",
@@ -3371,21 +3445,21 @@ static void smtpd_proto(SMTPD_STATE *state, const char *service)
            && !xclient_allowed
            && anvil_clnt
            && !namadr_list_match(hogger_list, state->name, state->addr)
-           && anvil_clnt_connect(anvil_clnt, service, state->addr,
+           && anvil_clnt_connect(anvil_clnt, state->service, state->addr,
                                  &count, &crate) == ANVIL_STAT_OK) {
            if (var_smtpd_cconn_limit > 0 && count > var_smtpd_cconn_limit) {
                state->error_mask |= MAIL_ERROR_POLICY;
                smtpd_chat_reply(state, "421 4.7.0 %s Error: too many connections from %s",
                                 var_myhostname, state->addr);
                msg_warn("Connection concurrency limit exceeded: %d from %s for service %s",
-                        count, state->namaddr, service);
+                        count, state->namaddr, state->service);
                break;
            }
            if (var_smtpd_crate_limit > 0 && crate > var_smtpd_crate_limit) {
                smtpd_chat_reply(state, "421 4.7.0 %s Error: too many connections from %s",
                                 var_myhostname, state->addr);
                msg_warn("Connection rate limit exceeded: %d from %s for service %s",
-                        crate, state->namaddr, service);
+                        crate, state->namaddr, state->service);
                break;
            }
        }
@@ -3499,7 +3573,7 @@ static void smtpd_proto(SMTPD_STATE *state, const char *service)
        && !xclient_allowed
        && anvil_clnt
        && !namadr_list_match(hogger_list, state->name, state->addr))
-       anvil_clnt_disconnect(anvil_clnt, service, state->addr);
+       anvil_clnt_disconnect(anvil_clnt, state->service, state->addr);
 
     /*
      * Log abnormal session termination, in case postmaster notification has
@@ -3516,6 +3590,8 @@ static void smtpd_proto(SMTPD_STATE *state, const char *service)
     /*
      * Cleanup whatever information the client gave us during the SMTP
      * dialog.
+     * 
+     * XXX Duplicated in xclient_cmd().
      */
 #ifdef USE_TLS
     tls_reset(state);
@@ -3596,7 +3672,7 @@ static void smtpd_service(VSTREAM *stream, char *service, char **argv)
     /*
      * Provide the SMTP service.
      */
-    smtpd_proto(&state, service);
+    smtpd_proto(&state);
 
     /*
      * After the client has gone away, clean up whatever we have set up at
index 9df37e3555e5b5fe16acf754c50ecdcda71ceaca..0f18fffeebcae273ef29f1236f550f56d88203cf 100644 (file)
 #include <rec_type.h>
 #include <mail_proto.h>
 #include <mail_params.h>               /* null_format_string */
+#include <xtext.h>
 
 /* Application-specific. */
 
@@ -212,12 +213,20 @@ static int smtpd_xforward(SMTPD_STATE *state, VSTRING *buf, const char *name,
 #define CONSTR_LEN(s)  (sizeof(s) - 1)
 #define PAYLOAD_LIMIT  (512 - CONSTR_LEN("250 " XFORWARD_CMD "\r\n"))
 
-    /*
-     * How much space does this attribute need?
-     */
     if (!value_available)
        value = XFORWARD_UNAVAILABLE;
-    new_len = strlen(name) + strlen(value) + 2;        /* SPACE name = value */
+
+    /*
+     * Encode the attribute value.
+     */
+    if (state->expand_buf == 0)
+       state->expand_buf = vstring_alloc(100);
+    xtext_quote(state->expand_buf, value, "");
+
+    /*
+     * How much space does this attribute need? SPACE name = value.
+     */
+    new_len = strlen(name) + strlen(STR(state->expand_buf)) + 2;
     if (new_len > PAYLOAD_LIMIT)
        msg_warn("%s command payload %s=%.10s... exceeds SMTP protocol limit",
                 XFORWARD_CMD, name, value);
@@ -228,7 +237,7 @@ static int smtpd_xforward(SMTPD_STATE *state, VSTRING *buf, const char *name,
     if (VSTRING_LEN(buf) > 0 && VSTRING_LEN(buf) + new_len > PAYLOAD_LIMIT)
        if ((ret = smtpd_xforward_flush(state, buf)) < 0)
            return (ret);
-    vstring_sprintf_append(buf, " %s=%s", name, value);
+    vstring_sprintf_append(buf, " %s=%s", name, STR(state->expand_buf));
 
     return (0);
 }