]> git.ipfire.org Git - thirdparty/postfix.git/commitdiff
postfix-2.0.16-20031214
authorWietse Venema <wietse@porcupine.org>
Sun, 14 Dec 2003 05:00:00 +0000 (00:00 -0500)
committerViktor Dukhovni <viktor@dukhovni.org>
Tue, 5 Feb 2013 06:29:19 +0000 (06:29 +0000)
27 files changed:
postfix/HISTORY
postfix/README_FILES/XCLIENT_README
postfix/README_FILES/XFORWARD_README [new file with mode: 0644]
postfix/conf/postfix-files
postfix/conf/sample-lmtp.cf
postfix/html/lmtp.8.html
postfix/html/smtp.8.html
postfix/man/man8/lmtp.8
postfix/man/man8/smtp.8
postfix/src/global/mail_params.h
postfix/src/global/mail_proto.h
postfix/src/global/mail_version.h
postfix/src/lmtp/lmtp.c
postfix/src/lmtp/lmtp.h
postfix/src/lmtp/lmtp_proto.c
postfix/src/pipe/pipe.c
postfix/src/smtp/Makefile.in
postfix/src/smtp/smtp.c
postfix/src/smtp/smtp.h
postfix/src/smtp/smtp_proto.c
postfix/src/smtpd/Makefile.in
postfix/src/smtpd/smtpd.c
postfix/src/smtpd/smtpd.h
postfix/src/smtpd/smtpd_proxy.c
postfix/src/util/Makefile.in
postfix/src/util/stringops.h
postfix/src/util/uppercase.c [new file with mode: 0644]

index 1a06f19e7ac0e6e0853808df0d2faac3db702a79..69305786679aa9c68ec40bee3ab9d5258cc65ff6 100644 (file)
@@ -8832,6 +8832,29 @@ Apologies for any names omitted.
        because the deliver_pass.c module was not updated for the
        changed message delivery protocol.
 
+20031211
+
+       Safety: in dynamically growing data structures, update the
+       length info after (instead of before) updating the data
+       size. Files:  util/argv.c, util/inet_addrlist.c, util/intv.c,
+       util/mvect.c, util/vstring.c, global/recipient_list.c,
+       *qmgr/qmgr_rcpt_list.c.
+
+20031212
+
+       Cleanup: separate extensions XCLIENT (impersonate SMTP
+       client) and XFORWARD (down-stream logging of up-stream
+       session information, not necessarily SMTP related). The
+       protocol is extensible: the server advertises what attributes
+       XCLIENT or XFORWARD will accept.  The requirement for xtext
+       encoding is dropped as no attribute currently needs it.
+       All errors are reported by the server and are logged by
+       the client.  See also: XCLIENT_README and XFORWARD_README.
+
+20031214
+
+       Feature: XCLIENT and XFORWARD support in the LMTP client.
+
 Open problems:
 
        High: when virtual aliasing is turned off after content
index 3077aed91c3164b4ad3b2418f2f76cf40c2a2319..62ea99ad091999b7f2efb2b2b3988364f805edf4 100644 (file)
 Purpose of the XCLIENT extension to SMTP
 ========================================
 
-The XCLIENT command targets problems in the following areas:
+The XCLIENT command targets the following problems:
 
 1 - Access control tests. SMTP server access rules are difficult
 to verify when decisions can be triggered only by remote clients.
 In order to facilitate access rule testing, an authorized SMTP
 client test program needs the ability to override the SMTP server's
-idea of the SMTP client hostname, network address, and other
+idea of the SMTP client hostname, network address, and other client
 information, for the entire duration of an SMTP session.
 
-2 - Logging after SMTP-based content filter. With the deployment
-of Internet->MTA1->filter->MTA2 style content filter applications,
-remote client information is lost when MTA1 gives the mail to the
-content filter.  To simplify the interpretation of MTA2 logging,
-it would help if MTA1 could forward client information through the
-content filter to MTA2.
+2 - Client software that downloads mail from an up-stream mail
+server and injects it into a local MTA via SMTP. In order to take
+advantage of the local MTA's access rules, the client software
+needs the ability to override the SMTP server's idea of the remote
+client name, client address and other information.  Such information
+can typically be extracted from the up-stream mail server's Received:
+message header.
 
 3 - Post-filter access control and logging. With Internet->filter->MTA
 style content filter applications, the filter can be simplified if
 it can delegate decisions concerning mail relay and other access
-control to the MTA. As in the first example, this requires that
-the filter can override the MTA's idea of the SMTP client hostname,
-network address, and other information, for the entire duration of
-an SMTP session.
+control to the MTA. This is especially useful when the filter acts
+as a transparent proxy for SMTP commands. As in the first example,
+this requires that the filter can override the MTA's idea of the
+SMTP client hostname, network address, and other information.
 
-4 - Fetchmail.
+Command syntax
+==============
 
-Command overview
-================
-
-The EHLO keyword associated with this extension is XCLIENT. In EHLO
-replies, XCLIENT is followed by the names of the supported XCLIENT
-functions.
-
-The XCLIENT OVERRIDE function updates remote client attributes that
-the MTA normally uses for access control, message headers, logging
-and so on, for the duration of an entire SMTP session.
-
-The XCLIENT FORWARD function updates temporary remote client
-attributes that the MTA uses for transaction logging. These attributes
-are valid for only one message delivery attempt.  In the absence
-of forwarded attributes the MTA must use the normal remote client
-attribute values.
+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 general command syntax is described below.  Upper case and
 quoted strings specify terminals, lowercase strings specify meta
-terminals, SP is whitespace, and descriptive text is enclosed in
-{}.  Although command and attribute names are shown below in upper
-case, they are in fact case insensitive.
+terminals, and SP is whitespace.  Although command and attribute
+names are shown in upper case, they are in fact case insensitive.
 
-    xclient-command = XCLIENT SP function SP 1*( attribute )
-
-    function = ( OVERRIDE | FORWARD )
+    xclient-command = XCLIENT 1*( SP attribute )
 
     attribute = name"="value
 
-    name = ( NAME|ADDR|CODE|PROTO|HELO )
-
-    value = ( { empty } | xtext )
-
-    xtext = { attribute value encoded as per RFC 1891 }
+    name = ( NAME | ADDR | PROTO | HELO )
 
 The XCLIENT command can be sent at any time except in the middle
 of a mail delivery transaction (i.e.  between MAIL and DOT).  The
-command may be pipelined after the server EHLO reply announces
-ESMTP pipelining support.
+command may be pipelined if the server EHLO reply announces ESMTP
+pipelining support.
 
-The server reply codes are as follows:
+The XCLIENT reply codes are as follows:
 
    Code | Meaning
    -----|------------
     250 | success 
-    501 | bad command parameter
+    501 | bad command parameter syntax
     503 | mail transaction in progress
     421 | unable to proceed
 
-The server must report success in case of an unrecognized attribute
-name, although it may log a warning.
-
-Specific usage scenarios
-========================
-
-This section discusses the semantics of XCLIENT requests.  Specific
-syntax details are given in the next section.
-
-The XCLIENT OVERRIDE request modifies remote client attributes that
-the MTA normally uses for access control, message headers, logging,
-and for other purposes, for the duraction of the entire SMTP session.
-Attributes that are not specified in XCLIENT OVERRIDE requests are
-not modified.
-
-The following example overrides only the client hostname and network
-address, leaving unchanged all other client attributes such as the
-mail protocol or the hostname given in the HELO command:
-
-    XCLIENT OVERRIDE NAME=spike.porcupine.org
-    XCLIENT OVERRIDE ADDR=168.100.189.2
-
-The XCLIENT FORWARD request specifies remote client attributes that
-are logged with one message delivery attempt. The attributes are
-discarded after the MAIL FROM transaction finishes. In the absence
-of any XCLIENT FORWARD attributes, the MTA must use the normal
-client attributes.
-
-If only a subset of all possible XCLIENT FORWARD attributes is
-specified, the unspecified attributes must be treated as if they
-are unknown. The implementation must not replace missing XCLIENT
-FORWARD attributes by normal attributes.
-
-The following example updates all forwarded client attributes that
-are defined in this document, leaving none at their default unknown
-value:
-
-    XCLIENT FORWARD NAME=spike.porcupine.org ADDR=168.100.189.2
-    XCLIENT FORWARD HELO=spike.porcupine.org PROTO=ESMTP
-
-Note 1: attributes specified with successive XCLIENT commands
-accumulate.
-
-Note 2: XCLIENT FORWARD attributes take precedence over XCLIENT
-OVERRIDE attributes.
-
-Attribute value details
-=======================
-
-Attribute values are encoded as RFC 1891 xtext strings. To explicitly
-specify that an attribute value is unavailable, the value must be
-empty; the client must not send its own internal representation of
-unavailable information.
-
-The NAME_CODE attribute specifies NAME hostname lookup status
-information.  Values are OK (success), TEMP (temporary lookup
-failure) or PERM (permanent lookup failure). When CODE is set to
-any value other than OK, the NAME attribute is automatically set
-to the unknown value.
-
-The NAME attribute specifies a name space (typically, DNS) and
-an MTA name within that name space.
-and not a numerical address.  When a null client name is specified
-(i.e.  the client name is unknown), the CODE attribute is implicitly
-set to PERM. When a valid domain name is specified, CODE is implicitly
-set to OK. The server may process a syntactically invalid domain
-name as if it were unknown.
+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 [temporary] when the lookup error
+condition was transient.
 
-The ADDR attribute must specify a numerical network address without
-[].
+The ADDR attribute specifies an SMTP client numerical IPv4 network
+address, an IPv6 address prefixed with IPV6:, or [unavailable]
+when the address information is unavailable.  Address information
+is not enclosed with [].
 
-The PROTO attribute should be a string of up to 64 printable
-characters, where printable is defined by the ANSI C isascii() and
-isprint() predicates.
+The PROTO attribute specifies either SMTP or ESMTP.
 
-The HELO attribute should be a syntactically valid HELO
-parameter value.
+The HELO attribute specifies a HELO parameter value, or the value
+[unavailable] when the information is unavailable.
 
-Note 3: syntactically valid NAME and HELO attributes can be up to
+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 of SMTP commands.
+exceed the 512 character limit for SMTP commands.
 
-Note 4: attribute values may end up in Received: or other message
-headers.  The receiving MTA may substitute characters in order to
-not violate RFC 822 or RFC 2822.
+Note 2: [UNAVAILABLE], [TEMPORARY] and IPV6:  may be specified in
+upper case, lower case or mixed case.
 
 Security
 ========
 
 The XCLIENT command changes audit trails and/or client access
-permissions. For these reasons, use of these commands must be
-restricted to authorized clients only.
+permissions. Use of this command must be restricted to authorized
+clients.
 
-The examples in this document assume that XCLIENT does not override
-its own access control mechanism.
+The XCLIENT should not override its own access control mechanism.
 
 SMTP connection caching
 =======================
 
 SMTP connection caching makes it possible to deliver multiple
-messages within the same SMTP session. Thus, one persistent SMTP
-session with a content filter can carry messages from unrelated
-clients.  The XCLIENT FORWARD attributes are reset after the MAIL
-FROM command completes, so there is no risk of information leakage.
+messages within the same SMTP session. The XCLIENT attributes are 
+persistent across deliveries, and need to be reset as appropriate
+in order to avoid information leakage.
diff --git a/postfix/README_FILES/XFORWARD_README b/postfix/README_FILES/XFORWARD_README
new file mode 100644 (file)
index 0000000..6c051b5
--- /dev/null
@@ -0,0 +1,95 @@
+Purpose of the XFORWARD extension to SMTP
+========================================
+
+The XFORWARD command targets the following problem:
+
+- Logging after SMTP-based content filter. With the deployment of
+Internet->MTA1->filter->MTA2 style content filter applications,
+the logging of client and message identifying information changes
+when MTA1 gives the mail to the content filter.  To simplify the
+interpretation of MTA2 logging, it would help if MTA1 could forward
+remote client and/or message identifying information through the
+content filter to MTA2, so that the information could be logged as
+part of mail handling transactions.
+
+Command syntax
+==============
+
+In SMTP server EHLO replies, the keyword associated with this
+extension is XFORWARD. The keyword is followed by the names of the
+attributes that the XFORWARD implementation supports.
+
+The general command syntax is described below.  Upper case and
+quoted strings specify terminals, lowercase strings specify meta
+terminals, and SP is whitespace.  Although command and attribute
+names are shown in upper case, they are in fact case insensitive.
+
+    xclient-command = XFORWARD 1*( SP attribute )
+
+    attribute = name"="value
+
+    name = ( NAME | ADDR | PROTO | HELO | IDENT )
+
+The XFORWARD command can be sent at any time except in the middle
+of a mail delivery transaction (i.e.  between MAIL and DOT).  The
+command may be pipelined if the server EHLO reply announces ESMTP
+pipelining support.
+
+The XFORWARD reply codes are as follows:
+
+   Code | Meaning
+   -----|------------
+    250 | success 
+    501 | bad command parameter syntax
+    503 | mail transaction in progress
+    421 | unable to proceed
+
+The information specified with XFORWARD attribues is not limited
+to DNS hostnames, IP addresses or SMTP protocol names.  Attribute
+values may contain arbitrary text, but must not contain control
+characters, non-ASCII characters, whitespace, or other characters
+that are special in message headers.
+
+The NAME attribute specifies an up-stream client hostname, or
+[UNAVAILABLE] when the information is unavailable. The hostname
+may be a non-DNS hostname.
+
+The ADDR attribute specifies an up-stream client network address,
+or [UNAVAILABLE] when the information is unavailable.  Address
+information is not enclosed with []. The address may be a non-IP
+address.
+
+The PROTO attribute specifies the mail protocol that was used by
+the up-stream client. This may be an SMTP 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 client
+host introduced itself with (for example, via the SMTP HELO command),
+or [UNAVAILABLE] when the information is unavailable. The hostname
+may be a non-DNS hostname.
+
+Note 1: DNS hostnames can be up to 255 characters long. The XFORWARD
+client implementation must not send XFORWARD commands that exceed
+the 512 character limit for SMTP commands.
+
+Note 2: [UNAVAILABLE] may be specified in upper case, lower case
+or mixed case.
+
+Note 3: the XFORWARD server implementation must not mix information
+from the current SMTP session with forwarded information from an
+up-stream session.
+
+Security
+========
+
+The XFORWARD command changes audit trails.  Use of this command
+must be restricted to authorized clients.
+
+SMTP connection caching
+=======================
+
+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.
index fcdcb99681c7b788e2abfc10acbad71a5a59e716..a2487e5754bbd8c2be690faad7d79570d9b1455b 100644 (file)
@@ -217,3 +217,5 @@ $readme_directory/ULTRIX_README:f:root:-:644
 $readme_directory/UUCP_README:f:root:-:644
 $readme_directory/VERP_README:f:root:-:644
 $readme_directory/VIRTUAL_README:f:root:-:644
+$readme_directory/XCLIENT_README:f:root:-:644
+$readme_directory/XFORWARD_README:f:root:-:644
index 9e2699cccbd3b0e46d12a47149350f3ced8beccf..91652771286085cfa0a5045faa337f68f0ebd68a 100644 (file)
@@ -21,6 +21,17 @@ lmtp_skip_quit_response = yes
 #
 lmtp_tcp_port = 24
 
+# The lmtp_send_xforward_command parameter controls whether the Postfix
+# LMTP client will send an XFORWARD command to the SMTP server, when
+# the ELMTP HELO response of the remote host indicates XFORWARD support.
+# This allows an "smtp" delivery agent, used for content filter
+# message injection, to forward the name, address, protocol and HELO
+# name of the original client to the content filter and downstream
+# queuing LMTP server. Before you change the value to yes, it is best
+# to make sure your content filter supports this command.
+# 
+lmtp_send_xforward_command = no
+
 #
 # RESOURCE AND RATE CONTROLS
 #
@@ -83,6 +94,18 @@ lmtp_connect_timeout = 0s
 #
 lmtp_lhlo_timeout = 300s
 
+# The lmtp_xforward_timeout parameter specifies the LMTP client timeout
+# for sending the LMTP XFORWARD command, and for receiving the server
+# response.
+#
+# In case of problems the client does NOT try the next address on
+# the mail exchanger list.
+#
+# Time units: s (seconds), m (minutes), h (hours), d (days), w (weeks).
+# The default time unit is s (seconds).
+#
+lmtp_xforward_timeout = 300s
+
 # The lmtp_mail_timeout parameter specifies the LMTP client timeout
 # for sending the LMTP MAIL FROM command, and for receiving the server
 # response.
index 1d368f7618562947bf1ea9735e4af110b7cb16b2..9d461d09ac5739cc6c1377a7e2a1df48fbd9359a 100644 (file)
@@ -107,6 +107,13 @@ LMTP(8)                                                   LMTP(8)
               server.  Used as backup if the <b>lmtp</b> service is  not
               found in <b>services</b>(4).
 
+       <b>lmtp_send_xforward_command</b>
+              If the LMTP server announces XFORWARD support, send
+              the name, address, protocol and HELO  name  of  the
+              original client. This can be used to forward client
+              information through a content  filter  to  a  down-
+              stream queuing LMTP server.
+
 <b>Authentication controls</b>
        <b>lmtp_sasl_auth_enable</b>
               Enable  per-session  authentication as per <a href="http://www.faqs.org/rfcs/rfc2554.html">RFC 2554</a>
@@ -206,16 +213,20 @@ LMTP(8)                                                   LMTP(8)
               Timeout  for  sending  the  <b>LHLO</b>  command,  and for
               receiving the server response.
 
+       <b>lmtp_xforward_timeout</b>
+              Timeout for sending the <b>XFORWARD</b> command,  and  for
+              receiving the server response.
+
        <b>lmtp_mail_timeout</b>
-              Timeout for sending the <b>MAIL FROM</b> command, and  for
+              Timeout  for sending the <b>MAIL FROM</b> command, and for
               receiving the server response.
 
        <b>lmtp_rcpt_timeout</b>
-              Timeout  for  sending  the <b>RCPT TO</b> command, and for
+              Timeout for sending the <b>RCPT TO</b>  command,  and  for
               receiving the server response.
 
        <b>lmtp_data_init_timeout</b>
-              Timeout for  sending  the  <b>DATA</b>  command,  and  for
+              Timeout  for  sending  the  <b>DATA</b>  command,  and for
               receiving the server response.
 
        <b>lmtp_data_xfer_timeout</b>
@@ -223,16 +234,16 @@ LMTP(8)                                                   LMTP(8)
 
        <b>lmtp_data_done_timeout</b>
               Timeout  for  sending  the  "<b>.</b>"  command,  and  for
-              receiving the server response. When no response  is
-              received,  a warning is logged that the mail may be
+              receiving  the server response. When no response is
+              received, a warning is logged that the mail may  be
               delivered multiple times.
 
        <b>lmtp_rset_timeout</b>
-              Timeout for  sending  the  <b>RSET</b>  command,  and  for
+              Timeout  for  sending  the  <b>RSET</b>  command,  and for
               receiving the server response.
 
        <b>lmtp_quit_timeout</b>
-              Timeout  for  sending  the  <b>QUIT</b>  command,  and for
+              Timeout for  sending  the  <b>QUIT</b>  command,  and  for
               receiving the server response.
 
 <b>SEE ALSO</b>
@@ -245,7 +256,7 @@ LMTP(8)                                                   LMTP(8)
        syslogd(8) system logging
 
 <b>LICENSE</b>
-       The Secure Mailer license must be  distributed  with  this
+       The  Secure  Mailer  license must be distributed with this
        software.
 
 <b>AUTHOR(S)</b>
index 0a3c3287aa04c4d732bfda9de3700084292c1245..47a6f67a2ca28cb88aff6ec2e867438ad26833d8 100644 (file)
@@ -135,6 +135,13 @@ SMTP(8)                                                   SMTP(8)
               Numerical  source  network  address to bind to when
               making a connection.
 
+       <b>smtp_defer_if_no_mx_address_found</b>
+              If no, bounce mail when no MX host resolves  to  an
+              address (Postfix always ignores MX hosts with equal
+              or worse preference than the local MTA).   If  yes,
+              keep  trying  until  a suitable MX host resolves or
+              until the mail is too old.
+
        <b>smtp_line_length_limit</b>
               Length limit for SMTP message content  lines.  Zero
               means  no  limit.   Some  SMTP servers misbehave on
@@ -186,6 +193,13 @@ SMTP(8)                                                   SMTP(8)
               nested deeper, when converting from 8BITMIME format
               to 7BIT format.
 
+       <b>smtp_send_xforward_command</b>
+              If the SMTP server announces XFORWARD support, send
+              the  name,  address,  protocol and HELO name of the
+              original client. This can be used to forward client
+              information  through  a  content  filter to a down-
+              stream queuing SMTP server.
+
 <b>Authentication controls</b>
        <b>smtp_sasl_auth_enable</b>
               Enable per-session authentication as per  <a href="http://www.faqs.org/rfcs/rfc2554.html">RFC  2554</a>
@@ -274,20 +288,6 @@ SMTP(8)                                                   SMTP(8)
               received,  a warning is logged that the mail may be
               delivered multiple times.
 
-       <b>smtp_defer_if_no_mx_address_found</b>
-              If no, bounce mail when no MX host resolves  to  an
-              address (Postfix always ignores MX hosts with equal
-              or worse preference than the local MTA).   If  yes,
-              keep  trying  until  a suitable MX host resolves or
-              until the mail is too old.
-
-       <b>smtp_send_xforward_command</b>
-              If the SMTP server announces XFORWARD support, send
-              the  name,  address,  protocol and HELO name of the
-              original client. This can be used to forward client
-              information  through  a  content  filter to a down-
-              stream queuing SMTP server.
-
        <b>smtp_rset_timeout</b>
               Timeout for sending the <b>RSET</b> command.
 
index 75e42c57aad8ef0dea89b4ff045ea726733d6e86..0b60c687bffc4632724b570195b61abfded925f8 100644 (file)
@@ -104,6 +104,11 @@ Do not wait for the server response after sending QUIT.
 .IP \fBlmtp_tcp_port\fR
 The TCP port to be used when connecting to a LMTP server.  Used as
 backup if the \fBlmtp\fR service is not found in \fBservices\fR(4).
+.IP \fBlmtp_send_xforward_command\fR
+If the LMTP server announces XFORWARD support, send the name,
+address, protocol and HELO name of the original client. This
+can be used to forward client information through a content
+filter to a downstream queuing LMTP server.
 .SH "Authentication controls"
 .IP \fBlmtp_sasl_auth_enable\fR
 Enable per-session authentication as per RFC 2554 (SASL).
@@ -185,6 +190,9 @@ is deferred.
 .IP \fBlmtp_lhlo_timeout\fR
 Timeout for sending the \fBLHLO\fR command, and for
 receiving the server response.
+.IP \fBlmtp_xforward_timeout\fR
+Timeout for sending the \fBXFORWARD\fR command, and for
+receiving the server response.
 .IP \fBlmtp_mail_timeout\fR
 Timeout for sending the \fBMAIL FROM\fR command, and for
 receiving the server response.
index d830dab2be8d85b85e91377579ebf0f13820759f..f805b7b1b7ae4a8eaf0d92206bba68476bf23012 100644 (file)
@@ -125,6 +125,12 @@ Always send EHLO at the start of a connection.
 Never send EHLO at the start of a connection.
 .IP \fBsmtp_bind_address\fR
 Numerical source network address to bind to when making a connection.
+.IP \fBsmtp_defer_if_no_mx_address_found\fR
+If no, bounce mail when no MX host resolves to an address
+(Postfix always ignores MX hosts with equal or worse preference
+than the local MTA).
+If yes, keep trying until a suitable MX host resolves or until
+the mail is too old.
 .IP \fBsmtp_line_length_limit\fR
 Length limit for SMTP message content lines. Zero means no limit.
 Some SMTP servers misbehave on long lines.
@@ -158,6 +164,11 @@ between boundary strings that do not differ in the first
 The maximal nesting level of multipart mail that the MIME
 processor can handle. Refuse mail that is nested deeper,
 when converting from 8BITMIME format to 7BIT format.
+.IP \fBsmtp_send_xforward_command\fR
+If the SMTP server announces XFORWARD support, send the name,
+address, protocol and HELO name of the original client. This
+can be used to forward client information through a content
+filter to a downstream queuing SMTP server.
 .SH "Authentication controls"
 .IP \fBsmtp_sasl_auth_enable\fR
 Enable per-session authentication as per RFC 2554 (SASL).
@@ -228,17 +239,6 @@ Timeout for sending the message content.
 Timeout for sending the "\fB.\fR" command, and for
 receiving the server response. When no response is received, a
 warning is logged that the mail may be delivered multiple times.
-.IP \fBsmtp_defer_if_no_mx_address_found\fR
-If no, bounce mail when no MX host resolves to an address
-(Postfix always ignores MX hosts with equal or worse preference
-than the local MTA).
-If yes, keep trying until a suitable MX host resolves or until
-the mail is too old.
-.IP \fBsmtp_send_xforward_command\fR
-If the SMTP server announces XFORWARD support, send the name,
-address, protocol and HELO name of the original client. This
-can be used to forward client information through a content
-filter to a downstream queuing SMTP server.
 .IP \fBsmtp_rset_timeout\fR
 Timeout for sending the \fBRSET\fR command.
 .IP \fBsmtp_quit_timeout\fR
index 0a7aa988ded7eba9e2c2f851cdfdd17d0b73427f..8c0f6f1f68d395c99b3cbfbab3256880483181ab 100644 (file)
@@ -753,9 +753,9 @@ extern int var_smtp_conn_tmout;
 #define DEF_SMTP_HELO_TMOUT    "300s"
 extern int var_smtp_helo_tmout;
 
-#define VAR_SMTP_XCLNT_TMOUT   "smtp_xclient_timeout"
-#define DEF_SMTP_XCLNT_TMOUT   "300s"
-extern int var_smtp_xclnt_tmout;
+#define VAR_SMTP_XFWD_TMOUT    "smtp_xforward_timeout"
+#define DEF_SMTP_XFWD_TMOUT    "300s"
+extern int var_smtp_xfwd_tmout;
 
 #define VAR_SMTP_MAIL_TMOUT    "smtp_mail_timeout"
 #define DEF_SMTP_MAIL_TMOUT    "300s"
@@ -1032,6 +1032,10 @@ extern int var_lmtp_rset_tmout;
 #define DEF_LMTP_LHLO_TMOUT    "300s"
 extern int var_lmtp_lhlo_tmout;
 
+#define VAR_LMTP_XFWD_TMOUT    "lmtp_xforward_timeout"
+#define DEF_LMTP_XFWD_TMOUT    "300s"
+extern int var_lmtp_xfwd_tmout;
+
 #define VAR_LMTP_MAIL_TMOUT    "lmtp_mail_timeout"
 #define DEF_LMTP_MAIL_TMOUT    "300s"
 extern int var_lmtp_mail_tmout;
@@ -1056,6 +1060,10 @@ extern int var_lmtp_data2_tmout;
 #define DEF_LMTP_QUIT_TMOUT    "300s"
 extern int var_lmtp_quit_tmout;
 
+#define VAR_LMTP_SEND_XFORWARD "lmtp_send_xforward_command"
+#define DEF_LMTP_SEND_XFORWARD 0
+extern bool var_lmtp_send_xforward;
+
  /*
   * Cleanup service. Header info that exceeds $header_size_limit bytes forces
   * the start of the message body.
index 96bbd1cab783093b0b6221f23d86da25db0e140f..144ee9acce47f519bef343266027adc251bae8fa 100644 (file)
@@ -152,15 +152,17 @@ extern char *mail_pathname(const char *, const char *);
 #define MAIL_ATTR_ORG_LOCAL    "local" /* local submission */
 
  /*
-  * XCLIENT in SMTP.
+  * XCLIENT/XFORWARD in SMTP.
   */
 #define XCLIENT_CMD            "XCLIENT"       /* XCLIENT command */
 #define XCLIENT_NAME           "NAME"          /* client name */
 #define XCLIENT_ADDR           "ADDR"          /* client address */
 #define XCLIENT_PROTO          "PROTO"         /* client protocol */
-#define XCLIENT_CODE           "NAME_CODE"     /* client name status */
 #define XCLIENT_HELO           "HELO"          /* client helo */
 
+#define XCLIENT_UNAVAILABLE    "[UNAVAILABLE]" /* permanently unavailable */
+#define XCLIENT_TEMPORARY      "[TEMPUNAVAIL]" /* temporarily unavailable */
+
 #define XFORWARD_CMD           "XFORWARD"      /* XFORWARD command */
 #define XFORWARD_NAME          "NAME"          /* client name */
 #define XFORWARD_ADDR          "ADDR"          /* client address */
@@ -168,6 +170,8 @@ extern char *mail_pathname(const char *, const char *);
 #define XFORWARD_HELO          "HELO"          /* client helo */
 #define XFORWARD_IDENT         "IDENT"         /* message identifier */
 
+#define XFORWARD_UNAVAILABLE   "[UNAVAILABLE]" /* attribute unavailable */
+
 /* LICENSE
 /* .ad
 /* .fi
index 65279a01ccceca86fc75ef32d71939ea1b8bbecb..5cbd66697ec1157e451173e068e53c6a3c93072a 100644 (file)
@@ -20,7 +20,7 @@
   * Patches change the patchlevel and the release date. Snapshots change the
   * release date only, unless they include the same bugfix as a patch release.
   */
-#define MAIL_RELEASE_DATE      "20031213"
+#define MAIL_RELEASE_DATE      "20031214"
 
 #define VAR_MAIL_VERSION       "mail_version"
 #define DEF_MAIL_VERSION       "2.0.16-" MAIL_RELEASE_DATE
index 8eb40b7e0238852307f6ab4de30121910a2f610d..c587d030c8a19131c890c6efb677179900e03f40 100644 (file)
 /* .IP \fBlmtp_tcp_port\fR
 /*     The TCP port to be used when connecting to a LMTP server.  Used as
 /*     backup if the \fBlmtp\fR service is not found in \fBservices\fR(4).
+/* .IP \fBlmtp_send_xforward_command\fR
+/*     If the LMTP server announces XFORWARD support, send the name,
+/*     address, protocol and HELO name of the original client. This
+/*     can be used to forward client information through a content
+/*     filter to a downstream queuing LMTP server.
 /* .SH "Authentication controls"
 /* .IP \fBlmtp_sasl_auth_enable\fR
 /*     Enable per-session authentication as per RFC 2554 (SASL).
 /* .IP \fBlmtp_lhlo_timeout\fR
 /*     Timeout for sending the \fBLHLO\fR command, and for
 /*     receiving the server response.
+/* .IP \fBlmtp_xforward_timeout\fR
+/*     Timeout for sending the \fBXFORWARD\fR command, and for
+/*     receiving the server response.
 /* .IP \fBlmtp_mail_timeout\fR
 /*     Timeout for sending the \fBMAIL FROM\fR command, and for
 /*     receiving the server response.
@@ -263,6 +271,7 @@ int     var_lmtp_tcp_port;
 int     var_lmtp_conn_tmout;
 int     var_lmtp_rset_tmout;
 int     var_lmtp_lhlo_tmout;
+int     var_lmtp_xfwd_tmout;
 int     var_lmtp_mail_tmout;
 int     var_lmtp_rcpt_tmout;
 int     var_lmtp_data0_tmout;
@@ -276,6 +285,7 @@ char   *var_error_rcpt;
 char   *var_lmtp_sasl_opts;
 char   *var_lmtp_sasl_passwd;
 bool    var_lmtp_sasl_enable;
+bool    var_lmtp_send_xforward;
 
  /*
   * Global variables.
@@ -538,6 +548,7 @@ int     main(int argc, char **argv)
        VAR_LMTP_CONN_TMOUT, DEF_LMTP_CONN_TMOUT, &var_lmtp_conn_tmout, 0, 0,
        VAR_LMTP_RSET_TMOUT, DEF_LMTP_RSET_TMOUT, &var_lmtp_rset_tmout, 1, 0,
        VAR_LMTP_LHLO_TMOUT, DEF_LMTP_LHLO_TMOUT, &var_lmtp_lhlo_tmout, 1, 0,
+       VAR_LMTP_XFWD_TMOUT, DEF_LMTP_XFWD_TMOUT, &var_lmtp_xfwd_tmout, 1, 0,
        VAR_LMTP_MAIL_TMOUT, DEF_LMTP_MAIL_TMOUT, &var_lmtp_mail_tmout, 1, 0,
        VAR_LMTP_RCPT_TMOUT, DEF_LMTP_RCPT_TMOUT, &var_lmtp_rcpt_tmout, 1, 0,
        VAR_LMTP_DATA0_TMOUT, DEF_LMTP_DATA0_TMOUT, &var_lmtp_data0_tmout, 1, 0,
index 2f9643970121d160f14bb9aabedef5fb65307cec..edbabd3b09db1c810d290ddce23fcbeb477c9ef1 100644 (file)
@@ -61,6 +61,16 @@ typedef struct LMTP_STATE {
 #define LMTP_FEATURE_PIPELINING        (1<<2)
 #define LMTP_FEATURE_SIZE      (1<<3)
 #define LMTP_FEATURE_AUTH      (1<<5)
+#define LMTP_FEATURE_XFORWARD_NAME (1<<6)
+#define LMTP_FEATURE_XFORWARD_ADDR (1<<7)
+#define LMTP_FEATURE_XFORWARD_PROTO (1<<8)
+#define LMTP_FEATURE_XFORWARD_HELO (1<<9)
+
+#define LMTP_FEATURE_XFORWARD_NAME_ADDR \
+       (LMTP_FEATURE_XFORWARD_NAME | LMTP_FEATURE_XFORWARD_ADDR)
+
+#define LMTP_FEATURE_XFORWARD_PROTO_HELO \
+       (LMTP_FEATURE_XFORWARD_PROTO | LMTP_FEATURE_XFORWARD_HELO)
 
  /*
   * lmtp.c
index 97b53690d9e16df826e3cc01fee4f997906ea218..ce2694d9add2f56e08423d3f1e96fa8e0497c0d8 100644 (file)
 #include <vstring_vstream.h>
 #include <stringops.h>
 #include <mymalloc.h>
+#include <name_code.h>
 
 /* Global library. */
 
   * the existing code for exception handling and error reporting.
   * 
   * Client states that are associated with sending mail (up to and including
-  * SMTP_STATE_DOT) must have smaller numerical values than the non-sending
-  * states (SMTP_STATE_ABORT .. SMTP_STATE_LAST).
+  * LMTP_STATE_DOT) must have smaller numerical values than the non-sending
+  * states (LMTP_STATE_ABORT .. LMTP_STATE_LAST).
   */
-#define LMTP_STATE_MAIL                0
-#define LMTP_STATE_RCPT                1
-#define LMTP_STATE_DATA                2
-#define LMTP_STATE_DOT         3
-#define LMTP_STATE_ABORT       4
-#define LMTP_STATE_RSET                5
-#define LMTP_STATE_QUIT                6
-#define LMTP_STATE_LAST                7
+#define LMTP_STATE_XFORWARD_NAME_ADDR 0
+#define LMTP_STATE_XFORWARD_PROTO_HELO 1
+#define LMTP_STATE_MAIL                2
+#define LMTP_STATE_RCPT                3
+#define LMTP_STATE_DATA                4
+#define LMTP_STATE_DOT         5
+#define LMTP_STATE_ABORT       6
+#define LMTP_STATE_RSET                7
+#define LMTP_STATE_QUIT                8
+#define LMTP_STATE_LAST                9
 
 int    *xfer_timeouts[LMTP_STATE_LAST] = {
+    &var_lmtp_xfwd_tmout,              /* name/addr */
+    &var_lmtp_xfwd_tmout,              /* helo/proto */
     &var_lmtp_mail_tmout,
     &var_lmtp_rcpt_tmout,
     &var_lmtp_data0_tmout,
     &var_lmtp_data2_tmout,
-    &var_lmtp_rset_tmout,
-    &var_lmtp_rset_tmout,
+    &var_lmtp_rset_tmout,              /* abort */
+    &var_lmtp_rset_tmout,              /* rset */
     &var_lmtp_quit_tmout,
 };
 
 char   *xfer_states[LMTP_STATE_LAST] = {
+    "sending XFORWARD name/address",
+    "sending XFORWARD protocol/helo_name",
     "sending MAIL FROM",
     "sending RCPT TO",
     "sending DATA command",
     "sending end of data -- message may be sent more than once",
-    "sending RSET",
-    "sending RSET",
+    "sending RSET",                    /* abort */
+    "sending RSET",                    /* rset */
     "sending QUIT",
 };
 
 char   *xfer_request[LMTP_STATE_LAST] = {
+    "XFORWARD name/address command",
+    "XFORWARD helo/protocol command",
     "MAIL FROM command",
     "RCPT TO command",
     "DATA command",
     "end of DATA command",
-    "RSET command",
-    "RSET command",
+    "RSET command",                    /* abort */
+    "RSET command",                    /* rset */
     "QUIT command",
 };
 
+static int lmtp_send_proto_helo;
+
 /* lmtp_lhlo - perform initial handshake with LMTP server */
 
 int     lmtp_lhlo(LMTP_STATE *state)
@@ -193,6 +204,13 @@ int     lmtp_lhlo(LMTP_STATE *state)
     char   *lines;
     char   *words;
     char   *word;
+    static NAME_CODE xforward_features[] = {
+       XFORWARD_NAME, LMTP_FEATURE_XFORWARD_NAME,
+       XFORWARD_ADDR, LMTP_FEATURE_XFORWARD_ADDR,
+       XFORWARD_PROTO, LMTP_FEATURE_XFORWARD_PROTO,
+       XFORWARD_HELO, LMTP_FEATURE_XFORWARD_HELO,
+       0, 0,
+    };
 
     /*
      * Prepare for disaster.
@@ -235,6 +253,10 @@ int     lmtp_lhlo(LMTP_STATE *state)
                state->features |= LMTP_FEATURE_8BITMIME;
            else if (strcasecmp(word, "PIPELINING") == 0)
                state->features |= LMTP_FEATURE_PIPELINING;
+           else if (strcasecmp(word, "XFORWARD") == 0)
+               while ((word = mystrtok(&words, " \t")) != 0)
+                   state->features |= name_code(xforward_features,
+                                                NAME_CODE_FLAG_NONE, word);
            else if (strcasecmp(word, "SIZE") == 0)
                state->features |= LMTP_FEATURE_SIZE;
 #ifdef USE_SASL_AUTH
@@ -364,6 +386,40 @@ static int lmtp_loop(LMTP_STATE *state, int send_state, int recv_state)
        default:
            msg_panic("%s: bad sender state %d", myname, send_state);
 
+           /*
+            * Build the XFORWARD command. With properly sanitized
+            * information, the command length stays within the 512 byte
+            * command line length limit.
+            */
+       case LMTP_STATE_XFORWARD_NAME_ADDR:
+           vstring_strcpy(next_command, XFORWARD_CMD);
+           if (state->features & LMTP_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 (state->features & LMTP_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 (lmtp_send_proto_helo)
+               next_state = LMTP_STATE_XFORWARD_PROTO_HELO;
+           else
+               next_state = LMTP_STATE_MAIL;
+           break;
+
+       case LMTP_STATE_XFORWARD_PROTO_HELO:
+           vstring_strcpy(next_command, XFORWARD_CMD);
+           if (state->features & LMTP_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 (state->features & LMTP_FEATURE_XFORWARD_HELO)
+               vstring_sprintf_append(next_command, " %s=%s",
+                  XFORWARD_HELO, DEL_REQ_ATTR_AVAIL(request->client_helo) ?
+                              request->client_helo : XFORWARD_UNAVAILABLE);
+           next_state = LMTP_STATE_MAIL;
+           break;
+
            /*
             * Build the MAIL FROM command.
             */
@@ -478,7 +534,7 @@ static int lmtp_loop(LMTP_STATE *state, int send_state, int recv_state)
                /*
                 * Sanity check.
                 */
-               if (recv_state < LMTP_STATE_MAIL
+               if (recv_state < LMTP_STATE_XFORWARD_NAME_ADDR
                    || recv_state > LMTP_STATE_QUIT)
                    msg_panic("%s: bad receiver state %d (sender state %d)",
                              myname, recv_state, send_state);
@@ -499,6 +555,30 @@ static int lmtp_loop(LMTP_STATE *state, int send_state, int recv_state)
                 */
                switch (recv_state) {
 
+                   /*
+                    * Process the XFORWARD response.
+                    */
+               case LMTP_STATE_XFORWARD_NAME_ADDR:
+                   if (resp->code / 100 != 2)
+                       msg_warn("host %s said: %s (in reply to %s)",
+                                session->namaddr,
+                                translit(resp->str, "\n", " "),
+                              xfer_request[LMTP_STATE_XFORWARD_NAME_ADDR]);
+                   if (lmtp_send_proto_helo)
+                       recv_state = LMTP_STATE_XFORWARD_PROTO_HELO;
+                   else
+                       recv_state = LMTP_STATE_MAIL;
+                   break;
+
+               case LMTP_STATE_XFORWARD_PROTO_HELO:
+                   if (resp->code / 100 != 2)
+                       msg_warn("host %s said: %s (in reply to %s)",
+                                session->namaddr,
+                                translit(resp->str, "\n", " "),
+                             xfer_request[LMTP_STATE_XFORWARD_PROTO_HELO]);
+                   recv_state = LMTP_STATE_MAIL;
+                   break;
+
                    /*
                     * Process the MAIL FROM response. When the server
                     * rejects the sender, set the mail_from_rejected flag so
@@ -546,7 +626,7 @@ static int lmtp_loop(LMTP_STATE *state, int send_state, int recv_state)
                                && sent(DEL_REQ_TRACE_FLAGS(request->flags),
                                        request->queue_id, rcpt->orig_addr,
                                        rcpt->address, rcpt->offset,
-                                       session->namaddr, request->arrival_time,
+                                   session->namaddr, request->arrival_time,
                                        "%s",
                                     translit(resp->str, "\n", " ")) == 0) {
                                if (request->flags & DEL_REQ_FLAG_SUCCESS)
@@ -746,7 +826,31 @@ static int lmtp_loop(LMTP_STATE *state, int send_state, int recv_state)
 
 int     lmtp_xfer(LMTP_STATE *state)
 {
-    return (lmtp_loop(state, LMTP_STATE_MAIL, LMTP_STATE_MAIL));
+    DELIVER_REQUEST *request = state->request;
+    int     start;
+    int     send_name_addr;
+
+    /*
+     * Use the XFORWARD command to forward client attributes only when a
+     * minimal amount of information is available.
+     */
+    send_name_addr =
+       (var_lmtp_send_xforward
+        && (state->features & LMTP_FEATURE_XFORWARD_NAME_ADDR)
+        && (DEL_REQ_ATTR_AVAIL(request->client_name)
+            || DEL_REQ_ATTR_AVAIL(request->client_addr)));
+    lmtp_send_proto_helo =
+       (var_lmtp_send_xforward
+        && (state->features & LMTP_FEATURE_XFORWARD_PROTO_HELO)
+        && (DEL_REQ_ATTR_AVAIL(request->client_proto)
+            || DEL_REQ_ATTR_AVAIL(request->client_helo)));
+    if (send_name_addr)
+       start = LMTP_STATE_XFORWARD_NAME_ADDR;
+    else if (lmtp_send_proto_helo)
+       start = LMTP_STATE_XFORWARD_PROTO_HELO;
+    else
+       start = LMTP_STATE_MAIL;
+    return (lmtp_loop(state, start, start));
 }
 
 /* lmtp_rset - send a lone RSET command and wait for response */
index 92bf1e3b9488e55af8ff18c533f26eac88b0bb78..64bc15e15e71b93ca449c559655e9c28af4f6576 100644 (file)
@@ -698,17 +698,19 @@ static void get_service_attr(PIPE_ATTR *attr, char **argv)
      * Sanity checks. Verify that every member has an acceptable value.
      */
     if (user == 0)
-       msg_fatal("missing user= attribute");
+       msg_fatal("missing user= command-line attribute");
     if (attr->command == 0)
-       msg_fatal("missing argv= attribute");
+       msg_fatal("missing argv= command-line attribute");
     if (attr->uid == 0)
-       msg_fatal("request to deliver as root");
+       msg_fatal("user= command-line attribute specifies root privileges");
     if (attr->uid == var_owner_uid)
-       msg_fatal("request to deliver as mail system owner");
+       msg_fatal("user= command-line attribute specifies mail system owner %s",
+                 var_mail_owner);
     if (attr->gid == 0)
-       msg_fatal("request to use privileged group id %ld", (long) attr->gid);
+       msg_fatal("user= command-line attribute specifies privileged group id 0");
     if (attr->gid == var_owner_gid)
-       msg_fatal("request to use mail system owner group id %ld", (long) attr->gid);
+       msg_fatal("user= command-line attribute specifies mail system owner %s group id %ld",
+                 var_mail_owner, (long) attr->gid);
 
     /*
      * Give the poor tester a clue of what is going on.
index 7249c3eff27cc8abaabc527d36dda3f473c8d778..dceecd09c902058d328b42fc3a01e7c3c3daff7e 100644 (file)
@@ -154,6 +154,7 @@ smtp_proto.o: ../../include/stringops.h
 smtp_proto.o: ../../include/mymalloc.h
 smtp_proto.o: ../../include/iostuff.h
 smtp_proto.o: ../../include/split_at.h
+smtp_proto.o: ../../include/name_code.h
 smtp_proto.o: ../../include/mail_params.h
 smtp_proto.o: ../../include/smtp_stream.h
 smtp_proto.o: ../../include/mail_queue.h
@@ -173,7 +174,6 @@ smtp_proto.o: ../../include/mail_proto.h
 smtp_proto.o: ../../include/attr.h
 smtp_proto.o: ../../include/mime_state.h
 smtp_proto.o: ../../include/header_opts.h
-smtp_proto.o: ../../include/xtext.h
 smtp_proto.o: smtp.h
 smtp_proto.o: ../../include/argv.h
 smtp_proto.o: smtp_sasl.h
index 256bab47a0190719243fbb348fb91624ece8b1ba..f7352287c90e7c94a21cec4c2a54e1c5ebcb4ce5 100644 (file)
 /*     Never send EHLO at the start of a connection.
 /* .IP \fBsmtp_bind_address\fR
 /*     Numerical source network address to bind to when making a connection.
+/* .IP \fBsmtp_defer_if_no_mx_address_found\fR
+/*     If no, bounce mail when no MX host resolves to an address
+/*     (Postfix always ignores MX hosts with equal or worse preference
+/*     than the local MTA).
+/*     If yes, keep trying until a suitable MX host resolves or until
+/*     the mail is too old.
 /* .IP \fBsmtp_line_length_limit\fR
 /*     Length limit for SMTP message content lines. Zero means no limit.
 /*     Some SMTP servers misbehave on long lines.
 /*     The maximal nesting level of multipart mail that the MIME
 /*     processor can handle. Refuse mail that is nested deeper,
 /*     when converting from 8BITMIME format to 7BIT format.
+/* .IP \fBsmtp_send_xforward_command\fR
+/*     If the SMTP server announces XFORWARD support, send the name,
+/*     address, protocol and HELO name of the original client. This
+/*     can be used to forward client information through a content
+/*     filter to a downstream queuing SMTP server.
 /* .SH "Authentication controls"
 /* .IP \fBsmtp_sasl_auth_enable\fR
 /*     Enable per-session authentication as per RFC 2554 (SASL).
 /*     Timeout for sending the "\fB.\fR" command, and for
 /*     receiving the server response. When no response is received, a
 /*     warning is logged that the mail may be delivered multiple times.
-/* .IP \fBsmtp_defer_if_no_mx_address_found\fR
-/*     If no, bounce mail when no MX host resolves to an address
-/*     (Postfix always ignores MX hosts with equal or worse preference
-/*     than the local MTA).
-/*     If yes, keep trying until a suitable MX host resolves or until
-/*     the mail is too old.
-/* .IP \fBsmtp_send_xforward_command\fR
-/*     If the SMTP server announces XFORWARD support, send the name,
-/*     address, protocol and HELO name of the original client. This
-/*     can be used to forward client information through a content
-/*     filter to a downstream queuing SMTP server.
 /* .IP \fBsmtp_rset_timeout\fR
 /*     Timeout for sending the \fBRSET\fR command.
 /* .IP \fBsmtp_quit_timeout\fR
   */
 int     var_smtp_conn_tmout;
 int     var_smtp_helo_tmout;
-int     var_smtp_xclnt_tmout;
+int     var_smtp_xfwd_tmout;
 int     var_smtp_mail_tmout;
 int     var_smtp_rcpt_tmout;
 int     var_smtp_data0_tmout;
@@ -502,7 +502,7 @@ int     main(int argc, char **argv)
     static CONFIG_TIME_TABLE time_table[] = {
        VAR_SMTP_CONN_TMOUT, DEF_SMTP_CONN_TMOUT, &var_smtp_conn_tmout, 0, 0,
        VAR_SMTP_HELO_TMOUT, DEF_SMTP_HELO_TMOUT, &var_smtp_helo_tmout, 1, 0,
-       VAR_SMTP_XCLNT_TMOUT, DEF_SMTP_XCLNT_TMOUT, &var_smtp_xclnt_tmout, 1, 0,
+       VAR_SMTP_XFWD_TMOUT, DEF_SMTP_XFWD_TMOUT, &var_smtp_xfwd_tmout, 1, 0,
        VAR_SMTP_MAIL_TMOUT, DEF_SMTP_MAIL_TMOUT, &var_smtp_mail_tmout, 1, 0,
        VAR_SMTP_RCPT_TMOUT, DEF_SMTP_RCPT_TMOUT, &var_smtp_rcpt_tmout, 1, 0,
        VAR_SMTP_DATA0_TMOUT, DEF_SMTP_DATA0_TMOUT, &var_smtp_data0_tmout, 1, 0,
index f591b0cc36a2d58699115a3f1d8f56c26acc4c48..96a6bafcfd4026a5406ce677017fcfbf0be48a94 100644 (file)
@@ -69,9 +69,11 @@ typedef struct SMTP_STATE {
 #define SMTP_FEATURE_XFORWARD_PROTO (1<<9)
 #define SMTP_FEATURE_XFORWARD_HELO (1<<10)
 
-#define SMTP_FEATURE_XFORWARD_MASK \
-       (SMTP_FEATURE_XFORWARD_NAME | SMTP_FEATURE_XFORWARD_ADDR \
-       | SMTP_FEATURE_XFORWARD_PROTO | SMTP_FEATURE_XFORWARD_HELO)
+#define SMTP_FEATURE_XFORWARD_NAME_ADDR \
+       (SMTP_FEATURE_XFORWARD_NAME | SMTP_FEATURE_XFORWARD_ADDR)
+
+#define        SMTP_FEATURE_XFORWARD_PROTO_HELO \
+       (SMTP_FEATURE_XFORWARD_PROTO | SMTP_FEATURE_XFORWARD_HELO)
 
  /*
   * smtp.c
index cca3983a751bb8bbaa35b55e50c2846272a8dbf0..8a86ab4ebeff9d70d322487675539936f4fb4ac0 100644 (file)
 #include <quote_821_local.h>
 #include <mail_proto.h>
 #include <mime_state.h>
-#include <xtext.h>
 
 /* Application-specific. */
 
   * SMTP_STATE_DOT) must have smaller numerical values than the non-sending
   * states (SMTP_STATE_ABORT .. SMTP_STATE_LAST).
   */
-#define SMTP_STATE_XFORWARD_ADDR 0
-#define SMTP_STATE_XFORWARD_HELO 1
+#define SMTP_STATE_XFORWARD_NAME_ADDR 0
+#define SMTP_STATE_XFORWARD_PROTO_HELO 1
 #define SMTP_STATE_MAIL                2
 #define SMTP_STATE_RCPT                3
 #define SMTP_STATE_DATA                4
 #define SMTP_STATE_LAST                8
 
 int    *xfer_timeouts[SMTP_STATE_LAST] = {
-    &var_smtp_xclnt_tmout,
-    &var_smtp_xclnt_tmout,
+    &var_smtp_xfwd_tmout,              /* name/addr */
+    &var_smtp_xfwd_tmout,              /* helo/proto */
     &var_smtp_mail_tmout,
     &var_smtp_rcpt_tmout,
     &var_smtp_data0_tmout,
@@ -147,8 +146,8 @@ int    *xfer_timeouts[SMTP_STATE_LAST] = {
 };
 
 char   *xfer_states[SMTP_STATE_LAST] = {
-    "sending XFORWARD address and name",
-    "sending XFORWARD helo_name and protocol",
+    "sending XFORWARD name/address",
+    "sending XFORWARD protocol/helo_name",
     "sending MAIL FROM",
     "sending RCPT TO",
     "sending DATA command",
@@ -267,11 +266,11 @@ int     smtp_helo(SMTP_STATE *state)
                state->features |= SMTP_FEATURE_8BITMIME;
            else if (strcasecmp(word, "PIPELINING") == 0)
                state->features |= SMTP_FEATURE_PIPELINING;
-           else if (strcasecmp(word, "XFORWARD") == 0) {
+           else if (strcasecmp(word, "XFORWARD") == 0)
                while ((word = mystrtok(&words, " \t")) != 0)
                    state->features |= name_code(xforward_features,
                                                 NAME_CODE_FLAG_NONE, word);
-           else if (strcasecmp(word, "SIZE") == 0) {
+           else if (strcasecmp(word, "SIZE") == 0) {
                state->features |= SMTP_FEATURE_SIZE;
                if ((word = mystrtok(&words, " \t")) != 0) {
                    if (!alldig(word))
@@ -395,6 +394,8 @@ int     smtp_xfer(SMTP_STATE *state)
     int     mail_from_rejected;
     int     downgrading;
     int     mime_errs;
+    int     send_name_addr;
+    int     send_proto_helo;
 
     /*
      * Macros for readability.
@@ -498,11 +499,20 @@ int     smtp_xfer(SMTP_STATE *state)
      * amount of information is available.
      */
     nrcpt = 0;
-    if (var_smtp_send_xforward
-       && (state->features & SMTP_FEATURE_XFORWARD_MASK)
-       && (DEL_REQ_ATTR_AVAIL(request->client_name)
-           || DEL_REQ_ATTR_AVAIL(request->client_addr)))
-       recv_state = send_state = SMTP_STATE_XFORWARD_ADDR;
+    send_name_addr =
+       (var_smtp_send_xforward
+        && (state->features & SMTP_FEATURE_XFORWARD_NAME_ADDR)
+        && (DEL_REQ_ATTR_AVAIL(request->client_name)
+            || DEL_REQ_ATTR_AVAIL(request->client_addr)));
+    send_proto_helo =
+       (var_smtp_send_xforward
+        && (state->features & SMTP_FEATURE_XFORWARD_PROTO_HELO)
+        && (DEL_REQ_ATTR_AVAIL(request->client_proto)
+            || DEL_REQ_ATTR_AVAIL(request->client_helo)));
+    if (send_name_addr)
+       recv_state = send_state = SMTP_STATE_XFORWARD_NAME_ADDR;
+    else if (send_proto_helo)
+       recv_state = send_state = SMTP_STATE_XFORWARD_PROTO_HELO;
     else
        recv_state = send_state = SMTP_STATE_MAIL;
     next_rcpt = send_rcpt = recv_rcpt = 0;
@@ -526,33 +536,32 @@ int     smtp_xfer(SMTP_STATE *state)
             * information, the command length stays within the 512 byte
             * command line length limit.
             */
-       case SMTP_STATE_XFORWARD_ADDR:
+       case SMTP_STATE_XFORWARD_NAME_ADDR:
            vstring_strcpy(next_command, XFORWARD_CMD);
-           if (state->features & SMTP_FEATURE_XFORWARD_NAME) {
-               vstring_strcat(next_command, " " XCLIENT_NAME "=");
-               if (DEL_REQ_ATTR_AVAIL(request->client_name))
-                   xtext_quote_append(next_command, request->client_name, "");
-           }
-           if (state->features & SMTP_FEATURE_XFORWARD_ADDR) {
-               vstring_strcat(next_command, " " XFORWARD_ADDR "=");
-               if (DEL_REQ_ATTR_AVAIL(request->client_addr))
-                   xtext_quote_append(next_command, request->client_addr, "");
-           }
-           next_state = SMTP_STATE_XFORWARD_HELO;
+           if (state->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 (state->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 (send_proto_helo)
+               next_state = SMTP_STATE_XFORWARD_PROTO_HELO;
+           else
+               next_state = SMTP_STATE_MAIL;
            break;
 
-       case SMTP_STATE_XFORWARD_HELO:
+       case SMTP_STATE_XFORWARD_PROTO_HELO:
            vstring_strcpy(next_command, XFORWARD_CMD);
-           if (state->features & SMTP_FEATURE_XFORWARD_HELO) {
-               vstring_strcat(next_command, " " XCLIENT_HELO "=");
-               if (DEL_REQ_ATTR_AVAIL(request->client_helo))
-                   xtext_quote_append(next_command, request->client_helo, "");
-           }
-           if (state->features & SMTP_FEATURE_XFORWARD_ADDR) {
-               vstring_strcat(next_command, " " XFORWARD_PROTO "=");
-               if (DEL_REQ_ATTR_AVAIL(request->client_proto))
-                   xtext_quote_append(next_command, request->client_proto, "");
-           }
+           if (state->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 (state->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);
            next_state = SMTP_STATE_MAIL;
            break;
 
@@ -665,7 +674,7 @@ int     smtp_xfer(SMTP_STATE *state)
                /*
                 * Sanity check.
                 */
-               if (recv_state < SMTP_STATE_XFORWARD_ADDR
+               if (recv_state < SMTP_STATE_XFORWARD_NAME_ADDR
                    || recv_state > SMTP_STATE_QUIT)
                    msg_panic("%s: bad receiver state %d (sender state %d)",
                              myname, recv_state, send_state);
@@ -689,21 +698,24 @@ int     smtp_xfer(SMTP_STATE *state)
                    /*
                     * Process the XFORWARD response.
                     */
-               case SMTP_STATE_XFORWARD_ADDR:
+               case SMTP_STATE_XFORWARD_NAME_ADDR:
                    if (resp->code / 100 != 2)
                        msg_warn("host %s said: %s (in reply to %s)",
                                 session->namaddr,
                                 translit(resp->str, "\n", " "),
-                                xfer_request[SMTP_STATE_MAIL]);
-                   recv_state = SMTP_STATE_XFORWARD_HELO;
+                                xfer_request[SMTP_STATE_XFORWARD_NAME_ADDR]);
+                   if (send_proto_helo)
+                       recv_state = SMTP_STATE_XFORWARD_PROTO_HELO;
+                   else
+                       recv_state = SMTP_STATE_MAIL;
                    break;
 
-               case SMTP_STATE_XFORWARD_HELO:
+               case SMTP_STATE_XFORWARD_PROTO_HELO:
                    if (resp->code / 100 != 2)
                        msg_warn("host %s said: %s (in reply to %s)",
                                 session->namaddr,
                                 translit(resp->str, "\n", " "),
-                                xfer_request[SMTP_STATE_MAIL]);
+                                xfer_request[SMTP_STATE_XFORWARD_PROTO_HELO]);
                    recv_state = SMTP_STATE_MAIL;
                    break;
 
index ba9c6bcbc9a6b11c21c76e4f68c304a8a7f3ecc9..91fb331a46d70aa825ba8b41eec4c1871597261a 100644 (file)
@@ -151,7 +151,6 @@ smtpd.o: ../../include/namadr_list.h
 smtpd.o: ../../include/input_transp.h
 smtpd.o: ../../include/anvil_clnt.h
 smtpd.o: ../../include/attr_clnt.h
-smtpd.o: ../../include/xtext.h
 smtpd.o: ../../include/mail_server.h
 smtpd.o: smtpd_token.h
 smtpd.o: smtpd.h
@@ -261,13 +260,13 @@ smtpd_proxy.o: ../../include/vstring.h
 smtpd_proxy.o: ../../include/stringops.h
 smtpd_proxy.o: ../../include/connect.h
 smtpd_proxy.o: ../../include/iostuff.h
+smtpd_proxy.o: ../../include/name_code.h
 smtpd_proxy.o: ../../include/mail_error.h
 smtpd_proxy.o: ../../include/name_mask.h
 smtpd_proxy.o: ../../include/smtp_stream.h
 smtpd_proxy.o: ../../include/cleanup_user.h
 smtpd_proxy.o: ../../include/mail_params.h
 smtpd_proxy.o: ../../include/rec_type.h
-smtpd_proxy.o: ../../include/xtext.h
 smtpd_proxy.o: ../../include/mail_proto.h
 smtpd_proxy.o: ../../include/attr.h
 smtpd_proxy.o: smtpd.h
index b2e3db103f422ce73a4a109c73f1920e04042061..fe2a7c05b5e454ba91068ad269ce899bf792b0e2 100644 (file)
 #include <namadr_list.h>
 #include <input_transp.h>
 #include <anvil_clnt.h>
-#include <xtext.h>
 
 /* Single-threaded server skeleton. */
 
@@ -753,8 +752,7 @@ static int ehlo_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv)
     if (xclient_allowed)
        smtpd_chat_reply(state, "250-" XCLIENT_CMD
                         " " XCLIENT_NAME " " XCLIENT_ADDR
-                        " " XCLIENT_CODE " " XCLIENT_PROTO
-                        " " XCLIENT_HELO);
+                        " " XCLIENT_PROTO " " XCLIENT_HELO);
     if (xforward_allowed)
        smtpd_chat_reply(state, "250-" XFORWARD_CMD
                         " " XFORWARD_NAME " " XFORWARD_ADDR
@@ -1723,22 +1721,21 @@ static int quit_cmd(SMTPD_STATE *state, int unused_argc, SMTPD_TOKEN *unused_arg
     return (0);
 }
 
-/* xclient_cmd - override client attributes */
+/* xclient_cmd - override SMTP client attributes */
 
 static int xclient_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv)
 {
-    int     arg_no;
+    SMTPD_TOKEN *argp;
     char   *attr_value;
     char   *attr_name;
     int     update_namaddr = 0;
-    int     code;
-    static NAME_CODE xclient_codes[] = {
-       "OK", SMTPD_PEER_CODE_OK,
-       "PERM", SMTPD_PEER_CODE_PERM,
-       "TEMP", SMTPD_PEER_CODE_TEMP,
-       0, -1,
+    int     peer_code;
+    static NAME_CODE peer_codes[] = {
+       XCLIENT_UNAVAILABLE, SMTPD_PEER_CODE_PERM,
+       XCLIENT_TEMPORARY, SMTPD_PEER_CODE_TEMP,
+       0, SMTPD_PEER_CODE_OK,
     };
-    static NAME_CODE xclient_proto[] = {
+    static NAME_CODE proto_names[] = {
        MAIL_PROTO_SMTP, 1,
        MAIL_PROTO_ESMTP, 2,
        0, -1,
@@ -1755,7 +1752,7 @@ static int xclient_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv)
     }
     if (argc < 2) {
        state->error_mask |= MAIL_ERROR_PROTOCOL;
-       smtpd_chat_reply(state, "501 Syntax: %s name=value...",
+       smtpd_chat_reply(state, "501 Syntax: %s attribute=value...",
                         XCLIENT_CMD);
        return (-1);
     }
@@ -1765,122 +1762,99 @@ static int xclient_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv)
        return (-1);
     }
 #define STREQ(x,y)     (strcasecmp((x), (y)) == 0)
-#define UPDATE_STR(s, v) do { if (s) myfree(s); s = (v) ? mystrdup(v) : 0; } while(0)
+#define UPDATE_STR(s, v) do { \
+           if (s) myfree(s); \
+           s = (v) ? mystrdup(v) : 0; \
+       } while(0)
+#define NEUTER_CHARACTERS "<>()\\\";:@"
 
     /*
-     * Iterate over all NAME=VALUE attributes.
+     * Iterate over all attribute=value elements.
      */
-    for (arg_no = 1; arg_no < argc; arg_no++) {
-       attr_name = argv[arg_no].strval;
+    for (argp = argv + 1; argp < argv + argc; argp++) {
+       attr_name = argp->strval;
 
        /*
-        * For safety's sake mask non-printable characters in the raw and
-        * decoded values; we don't want to handle unexploded munitions.
-        * Complain when they send an attribute that we didn't announce.
-        * 
-        * An implementation must allow clients to send XCLIENT before the
-        * HELO/EHLO greeting.
-        * 
-        * The client can send multiple XCLIENT attributes in a single command,
-        * or multiple XCLIENT commands with fewer attributes.
+        * For safety's sake mask non-printable characters. We'll do more
+        * specific censoring later.
         */
-       if ((attr_value = split_at(attr_name, '=')) == 0) {
+       if ((attr_value = split_at(attr_name, '=')) == 0 || *attr_value == 0) {
            state->error_mask |= MAIL_ERROR_PROTOCOL;
-           smtpd_chat_reply(state, "501 Error: name=value expected");
+           smtpd_chat_reply(state, "501 Error: attribute=value expected");
            return (-1);
        }
        printable(attr_value, '?');
 
        /*
-        * NAME=hostname. Also updates the client hostname lookup status
-        * code. Treat a numerical hostname as an unavailable name.
+        * NAME=substitute SMTP client hostname. Also updates the client
+        * hostname lookup status code.
         */
        if (STREQ(attr_name, XCLIENT_NAME)) {
-           if (*attr_value && !valid_hostaddr(attr_value, DONT_GRIPE)) {
-               if (!valid_hostname(attr_value, DONT_GRIPE)) {
+           peer_code = name_code(peer_codes, NAME_CODE_FLAG_NONE, attr_value);
+           if (peer_code != SMTPD_PEER_CODE_OK) {
+               attr_value = CLIENT_NAME_UNKNOWN;
+           } else {
+               if (!valid_hostname(attr_value, DONT_GRIPE)
+                   || valid_hostaddr(attr_value, DONT_GRIPE)) {
                    state->error_mask |= MAIL_ERROR_PROTOCOL;
                    smtpd_chat_reply(state, "501 Bad %s syntax: %s",
                                     XCLIENT_NAME, attr_value);
                    return (-1);
                }
-               UPDATE_STR(state->name, attr_value);
-               state->peer_code = SMTPD_PEER_CODE_OK;
-           } else {
-               UPDATE_STR(state->name, CLIENT_NAME_UNKNOWN);
-               state->peer_code = SMTPD_PEER_CODE_PERM;
            }
+           state->peer_code = peer_code;
+           UPDATE_STR(state->name, attr_value);
            update_namaddr = 1;
        }
 
        /*
-        * ADDR=client network address.
+        * ADDR=substitute SMTP client network address.
         */
        else if (STREQ(attr_name, XCLIENT_ADDR)) {
-           if (*attr_value) {
+           if (STREQ(attr_value, XCLIENT_UNAVAILABLE)) {
+               attr_value = CLIENT_ADDR_UNKNOWN;
+           } else {
                if (!valid_hostaddr(attr_value, DONT_GRIPE)) {
                    state->error_mask |= MAIL_ERROR_PROTOCOL;
                    smtpd_chat_reply(state, "501 Bad %s syntax: %s",
                                     XCLIENT_ADDR, attr_value);
                    return (-1);
                }
-               UPDATE_STR(state->addr, attr_value);
-           } else {
-               UPDATE_STR(state->addr, CLIENT_ADDR_UNKNOWN);
            }
+           UPDATE_STR(state->addr, attr_value);
            update_namaddr = 1;
        }
 
        /*
-        * CODE=hostname lookup status. Reset the client hostname if the
-        * hostname lookup status is not OK.
-        */
-       else if (STREQ(attr_name, XCLIENT_CODE)) {
-           if (*attr_value) {
-               if ((code = name_code(xclient_codes, NAME_CODE_FLAG_NONE, attr_value)) < 0) {
-                   state->error_mask |= MAIL_ERROR_PROTOCOL;
-                   smtpd_chat_reply(state, "501 Bad %s value: %s",
-                                    XCLIENT_CODE, attr_value);
-                   return (-1);
-               }
-               state->peer_code = code;
-               if (code != SMTPD_PEER_CODE_OK) {
-                   UPDATE_STR(state->name, CLIENT_NAME_UNKNOWN);
-                   update_namaddr = 1;
-               }
-           }
-       }
-
-       /*
-        * HELO=hostname. Disallow characters that could mess up our own
-        * Received: message headers but allow [].
+        * HELO=substitute SMTP client HELO parameter. Censor special
+        * characters that could mess up message headers.
         */
        else if (STREQ(attr_name, XCLIENT_HELO)) {
-           if (*attr_value) {
+           if (STREQ(attr_value, XCLIENT_UNAVAILABLE)) {
+               attr_value = CLIENT_HELO_UNKNOWN;
+           } else {
                if (strlen(attr_value) > VALID_HOSTNAME_LEN) {
                    state->error_mask |= MAIL_ERROR_PROTOCOL;
                    smtpd_chat_reply(state, "501 Bad %s syntax: %s",
                                     XCLIENT_HELO, attr_value);
                    return (-1);
                }
-               neuter(attr_value, "<>()\\\";:@", '?');
-               UPDATE_STR(state->helo_name, attr_value);
-           } else {
-               UPDATE_STR(state->helo_name, CLIENT_HELO_UNKNOWN);
+               neuter(attr_value, NEUTER_CHARACTERS, '?');
            }
+           UPDATE_STR(state->helo_name, attr_value);
        }
 
        /*
-        * PROTO=protocol name. Disallow characters that could mess up our
-        * own Received: message headers.
+        * PROTO=SMTP protocol name.
         */
        else if (STREQ(attr_name, XCLIENT_PROTO)) {
-           if (name_code(xclient_proto, NAME_CODE_FLAG_NONE, attr_value) < 0) {
+           if (name_code(proto_names, NAME_CODE_FLAG_NONE, attr_value) < 0) {
                state->error_mask |= MAIL_ERROR_PROTOCOL;
                smtpd_chat_reply(state, "501 Bad %s syntax: %s",
                                 XCLIENT_PROTO, attr_value);
                return (-1);
            }
-           UPDATE_STR(state->protocol, attr_value);
+           UPDATE_STR(state->protocol, uppercase(attr_value));
        }
 
        /*
@@ -1911,7 +1885,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)
 {
-    int     arg_no;
+    SMTPD_TOKEN *argp;
     char   *attr_value;
     char   *attr_name;
     int     updated = 0;
@@ -1934,7 +1908,7 @@ static int xforward_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv)
     }
     if (argc < 2) {
        state->error_mask |= MAIL_ERROR_PROTOCOL;
-       smtpd_chat_reply(state, "501 Syntax: %s name=value...",
+       smtpd_chat_reply(state, "501 Syntax: %s attribute=value...",
                         XFORWARD_CMD);
        return (-1);
     }
@@ -1951,22 +1925,18 @@ static int xforward_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv)
        smtpd_xforward_preset(state);
 
     /*
-     * Iterate over all NAME=VALUE attributes.
+     * Iterate over all attribute=value elements.
      */
-    for (arg_no = 1; arg_no < argc; arg_no++) {
-       attr_name = argv[arg_no].strval;
+    for (argp = argv + 1; argp < argv + argc; argp++) {
+       attr_name = argp->strval;
 
        /*
-        * For safety's sake mask non-printable characters in the raw and
-        * decoded values; we don't want to handle unexploded munitions.
-        * Complain when they send an attribute that we didn't announce.
-        * 
-        * The client can send multiple XFORWARD attributes in a single command,
-        * or multiple XFORWARD commands with fewer attributes.
+        * For safety's sake mask non-printable characters. We'll do more
+        * specific censoring later.
         */
-       if ((attr_value = split_at(attr_name, '=')) == 0) {
+       if ((attr_value = split_at(attr_name, '=')) == 0 || *attr_value == 0) {
            state->error_mask |= MAIL_ERROR_PROTOCOL;
-           smtpd_chat_reply(state, "501 Error: name=value expected");
+           smtpd_chat_reply(state, "501 Error: attribute=value expected");
            return (-1);
        }
        printable(attr_value, '?');
@@ -1975,71 +1945,61 @@ static int xforward_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv)
        switch (flag) {
 
            /*
-            * NAME=hostname. Also updates the client hostname lookup status
-            * code. Treat a numerical hostname as an unavailable name.
+            * NAME=host name, not necessarily in the DNS. Censor special
+            * characters that could mess up message headers.
             */
        case SMTPD_XFORWARD_FLAG_NAME:
-           if (*attr_value && !valid_hostaddr(attr_value, DONT_GRIPE)) {
-               if (!valid_hostname(attr_value, DONT_GRIPE)) {
-                   state->error_mask |= MAIL_ERROR_PROTOCOL;
-                   smtpd_chat_reply(state, "501 Bad %s syntax: %s",
-                                    XFORWARD_NAME, attr_value);
-                   return (-1);
-               }
-           } else {
+           if (STREQ(attr_value, XFORWARD_UNAVAILABLE)) {
                attr_value = CLIENT_NAME_UNKNOWN;
+           } else {
+               neuter(attr_value, NEUTER_CHARACTERS, '?');
            }
            UPDATE_STR(state->xforward.name, attr_value);
            break;
 
            /*
-            * ADDR=client network address.
+            * ADDR=host network address, not necessarily on the Internet.
+            * Censor special characters that could mess up message headers.
             */
        case SMTPD_XFORWARD_FLAG_ADDR:
-           if (*attr_value) {
-               if (!valid_hostaddr(attr_value, DONT_GRIPE)) {
-                   state->error_mask |= MAIL_ERROR_PROTOCOL;
-                   smtpd_chat_reply(state, "501 Bad %s syntax: %s",
-                                    XFORWARD_ADDR, attr_value);
-                   return (-1);
-               }
-           } else {
+           if (STREQ(attr_value, XFORWARD_UNAVAILABLE)) {
                attr_value = CLIENT_ADDR_UNKNOWN;
+           } else {
+               neuter(attr_value, NEUTER_CHARACTERS, '?');
            }
            UPDATE_STR(state->xforward.addr, attr_value);
            break;
 
            /*
-            * HELO=hostname. Disallow characters that could mess up our own
-            * Received: message headers but allow [].
+            * HELO=hostname that the host introduced itself with (not
+            * necessarily SMTP HELO). Censor special characters that could
+            * mess up message headers.
             */
        case SMTPD_XFORWARD_FLAG_HELO:
-           if (*attr_value) {
-               if (strlen(attr_value) > VALID_HOSTNAME_LEN) {
-                   state->error_mask |= MAIL_ERROR_PROTOCOL;
-                   smtpd_chat_reply(state, "501 Bad %s syntax: %s",
-                                    XFORWARD_HELO, attr_value);
-                   return (-1);
-               }
-               neuter(attr_value, "<>()\\\";:@", '?');
-           } else {
+           if (STREQ(attr_value, XFORWARD_UNAVAILABLE)) {
                attr_value = CLIENT_HELO_UNKNOWN;
+           } else {
+               neuter(attr_value, NEUTER_CHARACTERS, '?');
            }
            UPDATE_STR(state->xforward.helo_name, attr_value);
            break;
 
            /*
-            * PROTO=protocol name. Neutralize characters that could mess up
-            * our own Received: message headers.
+            * PROTO=protocol name, not necessarily SMTP or ESMTP. Censor
+            * special characters that could mess up message headers.
             */
        case SMTPD_XFORWARD_FLAG_PROTO:
-           if (strlen(attr_value) > 64) {
-               state->error_mask |= MAIL_ERROR_PROTOCOL;
-               smtpd_chat_reply(state, "501 Bad %s syntax: %s",
-                                XFORWARD_PROTO, attr_value);
-               return (-1);
+           if (STREQ(attr_value, XFORWARD_UNAVAILABLE)) {
+               attr_value = CLIENT_PROTO_UNKNOWN;
+           } else {
+               if (strlen(attr_value) > 64) {
+                   state->error_mask |= MAIL_ERROR_PROTOCOL;
+                   smtpd_chat_reply(state, "501 Bad %s syntax: %s",
+                                    XFORWARD_PROTO, attr_value);
+                   return (-1);
+               }
+               neuter(attr_value, NEUTER_CHARACTERS, '?');
            }
-           neuter(attr_value, "<>()\\\";:@", '?');
            UPDATE_STR(state->xforward.protocol, attr_value);
            break;
 
@@ -2063,9 +2023,10 @@ static int xforward_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv)
        if (state->xforward.namaddr)
            myfree(state->xforward.namaddr);
        state->xforward.namaddr =
+           IS_AVAIL_CLIENT_ADDR(state->xforward.addr) ?
            concatenate(state->xforward.name, "[",
                        state->xforward.addr, "]",
-                       (char *) 0);
+                       (char *) 0) : mystrdup(state->xforward.name);
     }
     smtpd_chat_reply(state, "250 Ok");
     return (0);
index 831fa72a646ff54ee9fd4177d7b1d3083c7c03f9..26a8cf878c8a685266948a93886f44087e9c873c 100644 (file)
@@ -206,9 +206,8 @@ extern void smtpd_peer_reset(SMTPD_STATE *state);
 #define SMTPD_PROXY_XFORWARD_IDENT (1<<4)      /* message identifier */
 
  /*
-  * If forwarding client information, don't mix direct client information
-  * from the current SMTP session with forwarded client information from an
-  * up-stream session.
+  * If forwarding client information, don't mix information from the current
+  * SMTP session with forwarded information from an up-stream session.
   */
 #define FORWARD_CLIENT_ATTR(s, a) \
        (((s)->xforward.flags & SMTPD_XFORWARD_FLAG_CLIENT_MASK) ? \
index 074e4e14c342d665f2163696d56d39568a7fafa3..f307b201f8a41b3f7c757968ac50091a675b86d5 100644 (file)
 #include <cleanup_user.h>
 #include <mail_params.h>
 #include <rec_type.h>
-#include <xtext.h>
 #include <mail_proto.h>
 
 /* Application-specific. */
@@ -201,10 +200,10 @@ static int smtpd_xforward(SMTPD_STATE *state, VSTRING *buf, const char *name,
      * How much space does this attribute need?
      */
     if (!value_available)
-       value = "";
+       value = XFORWARD_UNAVAILABLE;
     new_len = strlen(name) + strlen(value) + 2;        /* SPACE name = value */
     if (new_len > PAYLOAD_LIMIT)
-       msg_warn("%s payload %s=%.10s... exceeds SMTP protocol limit",
+       msg_warn("%s command payload %s=%.10s... exceeds SMTP protocol limit",
                 XFORWARD_CMD, name, value);
 
     /*
index 112c7d766a964954fd953ff88f5cee51a3440cc7..440f268641fd9256d40d80d00859b47d2bd5cc8d 100644 (file)
@@ -27,7 +27,8 @@ SRCS  = alldig.c argv.c argv_split.c attr_print0.c attr_print64.c \
        username.c valid_hostname.c vbuf.c vbuf_print.c vstream.c \
        vstream_popen.c vstring.c vstring_vstream.c watchdog.c writable.c \
        write_buf.c write_wait.c auto_clnt.c attr_clnt.c attr_scan_plain.c \
-       attr_print_plain.c sane_connect.c neuter.c name_code.c
+       attr_print_plain.c sane_connect.c neuter.c name_code.c \
+       uppercase.c
 OBJS   = alldig.o argv.o argv_split.o attr_print0.o attr_print64.o \
        attr_scan0.o attr_scan64.o base64_code.o basename.o binhash.o \
        chroot_uid.o clean_env.o close_on_exec.o concatenate.o ctable.o \
@@ -56,7 +57,8 @@ OBJS  = alldig.o argv.o argv_split.o attr_print0.o attr_print64.o \
        username.o valid_hostname.o vbuf.o vbuf_print.o vstream.o \
        vstream_popen.o vstring.o vstring_vstream.o watchdog.o writable.o \
        write_buf.o write_wait.o auto_clnt.o attr_clnt.o attr_scan_plain.o \
-       attr_print_plain.o sane_connect.o $(STRCASE) neuter.o name_code.o
+       attr_print_plain.o sane_connect.o $(STRCASE) neuter.o name_code.o \
+       uppercase.o
 HDRS   = argv.h attr.h base64_code.h binhash.h chroot_uid.h clean_env.h \
        connect.h ctable.h dict.h dict_db.h dict_dbm.h dict_env.h \
        dict_cidr.h dict_ht.h dict_ldap.h dict_mysql.h dict_ni.h dict_nis.h \
@@ -1292,6 +1294,11 @@ unix_trigger.o: trigger.h
 unsafe.o: unsafe.c
 unsafe.o: sys_defs.h
 unsafe.o: safe.h
+uppercase.o: uppercase.c
+uppercase.o: sys_defs.h
+uppercase.o: stringops.h
+uppercase.o: vstring.h
+uppercase.o: vbuf.h
 username.o: username.c
 username.o: sys_defs.h
 username.o: username.h
index 1f05045fcd412f5bea5a5c9b8067e3f9da4da4e5..223a8845fef09216a14bf2b57fb8ecd495180cf1 100644 (file)
@@ -22,6 +22,7 @@
 extern char *printable(char *, int);
 extern char *neuter(char *, const char *, int);
 extern char *lowercase(char *);
+extern char *uppercase(char *);
 extern char *skipblanks(const char *);
 extern char *trimblanks(char *, int);
 extern char *concatenate(const char *,...);
diff --git a/postfix/src/util/uppercase.c b/postfix/src/util/uppercase.c
new file mode 100644 (file)
index 0000000..9c61622
--- /dev/null
@@ -0,0 +1,43 @@
+/*++
+/* NAME
+/*     uppercase 3
+/* SUMMARY
+/*     map lowercase characters to uppercase
+/* SYNOPSIS
+/*     #include <stringops.h>
+/*
+/*     char    *uppercase(buf)
+/*     char    *buf;
+/* DESCRIPTION
+/*     uppercase() replaces lowercase characters in its null-terminated
+/*     input by their uppercase equivalent.
+/* LICENSE
+/* .ad
+/* .fi
+/*     The Secure Mailer license must be distributed with this software.
+/* AUTHOR(S)
+/*     Wietse Venema
+/*     IBM T.J. Watson Research
+/*     P.O. Box 704
+/*     Yorktown Heights, NY 10598, USA
+/*--*/
+
+/* System library. */
+
+#include "sys_defs.h"
+#include <ctype.h>
+
+/* Utility library. */
+
+#include "stringops.h"
+
+char   *uppercase(char *string)
+{
+    char   *cp;
+    int     ch;
+
+    for (cp = string; (ch = *cp) != 0; cp++)
+       if (ISLOWER(ch))
+           *cp = TOUPPER(ch);
+    return (string);
+}