2
0
mirror of https://github.com/vdukhovni/postfix synced 2025-08-31 22:25:24 +00:00

postfix-2.0.16-20031214

This commit is contained in:
Wietse Venema
2003-12-14 00:00:00 -05:00
committed by Viktor Dukhovni
parent 7a646f52bf
commit 0b73da41c8
27 changed files with 630 additions and 390 deletions

View File

@@ -8832,6 +8832,29 @@ Apologies for any names omitted.
because the deliver_pass.c module was not updated for the because the deliver_pass.c module was not updated for the
changed message delivery protocol. 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: Open problems:
High: when virtual aliasing is turned off after content High: when virtual aliasing is turned off after content

View File

@@ -1,182 +1,98 @@
Purpose of the XCLIENT extension to SMTP 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 1 - Access control tests. SMTP server access rules are difficult
to verify when decisions can be triggered only by remote clients. to verify when decisions can be triggered only by remote clients.
In order to facilitate access rule testing, an authorized SMTP In order to facilitate access rule testing, an authorized SMTP
client test program needs the ability to override the SMTP server's 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. information, for the entire duration of an SMTP session.
2 - Logging after SMTP-based content filter. With the deployment 2 - Client software that downloads mail from an up-stream mail
of Internet->MTA1->filter->MTA2 style content filter applications, server and injects it into a local MTA via SMTP. In order to take
remote client information is lost when MTA1 gives the mail to the advantage of the local MTA's access rules, the client software
content filter. To simplify the interpretation of MTA2 logging, needs the ability to override the SMTP server's idea of the remote
it would help if MTA1 could forward client information through the client name, client address and other information. Such information
content filter to MTA2. 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 3 - Post-filter access control and logging. With Internet->filter->MTA
style content filter applications, the filter can be simplified if style content filter applications, the filter can be simplified if
it can delegate decisions concerning mail relay and other access it can delegate decisions concerning mail relay and other access
control to the MTA. As in the first example, this requires that control to the MTA. This is especially useful when the filter acts
the filter can override the MTA's idea of the SMTP client hostname, as a transparent proxy for SMTP commands. As in the first example,
network address, and other information, for the entire duration of this requires that the filter can override the MTA's idea of the
an SMTP session. SMTP client hostname, network address, and other information.
4 - Fetchmail. Command syntax
==============
Command overview 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 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.
The general command syntax is described below. Upper case and The general command syntax is described below. Upper case and
quoted strings specify terminals, lowercase strings specify meta quoted strings specify terminals, lowercase strings specify meta
terminals, SP is whitespace, and descriptive text is enclosed in terminals, and SP is whitespace. Although command and attribute
{}. Although command and attribute names are shown below in upper names are shown in upper case, they are in fact case insensitive.
case, they are in fact case insensitive.
xclient-command = XCLIENT SP function SP 1*( attribute ) xclient-command = XCLIENT 1*( SP attribute )
function = ( OVERRIDE | FORWARD )
attribute = name"="value attribute = name"="value
name = ( NAME|ADDR|CODE|PROTO|HELO ) name = ( NAME | ADDR | PROTO | HELO )
value = ( { empty } | xtext )
xtext = { attribute value encoded as per RFC 1891 }
The XCLIENT command can be sent at any time except in the middle 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 of a mail delivery transaction (i.e. between MAIL and DOT). The
command may be pipelined after the server EHLO reply announces command may be pipelined if the server EHLO reply announces ESMTP
ESMTP pipelining support. pipelining support.
The server reply codes are as follows: The XCLIENT reply codes are as follows:
Code | Meaning Code | Meaning
-----|------------ -----|------------
250 | success 250 | success
501 | bad command parameter 501 | bad command parameter syntax
503 | mail transaction in progress 503 | mail transaction in progress
421 | unable to proceed 421 | unable to proceed
The server must report success in case of an unrecognized attribute The NAME attribute specifies an SMTP client hostname (not an SMTP
name, although it may log a warning. client address), [unavailable] when client hostname lookup failed
due to a permanent error, or [temporary] when the lookup error
condition was transient.
Specific usage scenarios 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 [].
This section discusses the semantics of XCLIENT requests. Specific The PROTO attribute specifies either SMTP or ESMTP.
syntax details are given in the next section.
The XCLIENT OVERRIDE request modifies remote client attributes that The HELO attribute specifies a HELO parameter value, or the value
the MTA normally uses for access control, message headers, logging, [unavailable] when the information is unavailable.
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 Note 1: syntactically valid NAME and HELO attributes can be up to
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 ADDR attribute must specify a numerical network address without
[].
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 HELO attribute should be a syntactically valid HELO
parameter value.
Note 3: syntactically valid NAME and HELO attributes can be up to
255 characters long. The client must not send XCLIENT commands that 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 Note 2: [UNAVAILABLE], [TEMPORARY] and IPV6: may be specified in
headers. The receiving MTA may substitute characters in order to upper case, lower case or mixed case.
not violate RFC 822 or RFC 2822.
Security Security
======== ========
The XCLIENT command changes audit trails and/or client access The XCLIENT command changes audit trails and/or client access
permissions. For these reasons, use of these commands must be permissions. Use of this command must be restricted to authorized
restricted to authorized clients only. clients.
The examples in this document assume that XCLIENT does not override The XCLIENT should not override its own access control mechanism.
its own access control mechanism.
SMTP connection caching SMTP connection caching
======================= =======================
SMTP connection caching makes it possible to deliver multiple SMTP connection caching makes it possible to deliver multiple
messages within the same SMTP session. Thus, one persistent SMTP messages within the same SMTP session. The XCLIENT attributes are
session with a content filter can carry messages from unrelated persistent across deliveries, and need to be reset as appropriate
clients. The XCLIENT FORWARD attributes are reset after the MAIL in order to avoid information leakage.
FROM command completes, so there is no risk of information leakage.

View File

@@ -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.

View File

@@ -217,3 +217,5 @@ $readme_directory/ULTRIX_README:f:root:-:644
$readme_directory/UUCP_README:f:root:-:644 $readme_directory/UUCP_README:f:root:-:644
$readme_directory/VERP_README:f:root:-:644 $readme_directory/VERP_README:f:root:-:644
$readme_directory/VIRTUAL_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

View File

@@ -21,6 +21,17 @@ lmtp_skip_quit_response = yes
# #
lmtp_tcp_port = 24 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 # RESOURCE AND RATE CONTROLS
# #
@@ -83,6 +94,18 @@ lmtp_connect_timeout = 0s
# #
lmtp_lhlo_timeout = 300s 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 # The lmtp_mail_timeout parameter specifies the LMTP client timeout
# for sending the LMTP MAIL FROM command, and for receiving the server # for sending the LMTP MAIL FROM command, and for receiving the server
# response. # response.

View File

@@ -107,6 +107,13 @@ LMTP(8) LMTP(8)
server. Used as backup if the <b>lmtp</b> service is not server. Used as backup if the <b>lmtp</b> service is not
found in <b>services</b>(4). 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>Authentication controls</b>
<b>lmtp_sasl_auth_enable</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> 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 Timeout for sending the <b>LHLO</b> command, and for
receiving the server response. 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> <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. receiving the server response.
<b>lmtp_rcpt_timeout</b> <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. receiving the server response.
<b>lmtp_data_init_timeout</b> <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. receiving the server response.
<b>lmtp_data_xfer_timeout</b> <b>lmtp_data_xfer_timeout</b>
@@ -223,16 +234,16 @@ LMTP(8) LMTP(8)
<b>lmtp_data_done_timeout</b> <b>lmtp_data_done_timeout</b>
Timeout for sending the "<b>.</b>" command, and for Timeout for sending the "<b>.</b>" command, and for
receiving the server response. When no response is receiving the server response. When no response is
received, a warning is logged that the mail may be received, a warning is logged that the mail may be
delivered multiple times. delivered multiple times.
<b>lmtp_rset_timeout</b> <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. receiving the server response.
<b>lmtp_quit_timeout</b> <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. receiving the server response.
<b>SEE ALSO</b> <b>SEE ALSO</b>
@@ -245,7 +256,7 @@ LMTP(8) LMTP(8)
syslogd(8) system logging syslogd(8) system logging
<b>LICENSE</b> <b>LICENSE</b>
The Secure Mailer license must be distributed with this The Secure Mailer license must be distributed with this
software. software.
<b>AUTHOR(S)</b> <b>AUTHOR(S)</b>

View File

@@ -135,6 +135,13 @@ SMTP(8) SMTP(8)
Numerical source network address to bind to when Numerical source network address to bind to when
making a connection. 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> <b>smtp_line_length_limit</b>
Length limit for SMTP message content lines. Zero Length limit for SMTP message content lines. Zero
means no limit. Some SMTP servers misbehave on means no limit. Some SMTP servers misbehave on
@@ -186,6 +193,13 @@ SMTP(8) SMTP(8)
nested deeper, when converting from 8BITMIME format nested deeper, when converting from 8BITMIME format
to 7BIT 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>Authentication controls</b>
<b>smtp_sasl_auth_enable</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> 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 received, a warning is logged that the mail may be
delivered multiple times. 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> <b>smtp_rset_timeout</b>
Timeout for sending the <b>RSET</b> command. Timeout for sending the <b>RSET</b> command.

View File

@@ -104,6 +104,11 @@ Do not wait for the server response after sending QUIT.
.IP \fBlmtp_tcp_port\fR .IP \fBlmtp_tcp_port\fR
The TCP port to be used when connecting to a LMTP server. Used as 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). 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" .SH "Authentication controls"
.IP \fBlmtp_sasl_auth_enable\fR .IP \fBlmtp_sasl_auth_enable\fR
Enable per-session authentication as per RFC 2554 (SASL). Enable per-session authentication as per RFC 2554 (SASL).
@@ -185,6 +190,9 @@ is deferred.
.IP \fBlmtp_lhlo_timeout\fR .IP \fBlmtp_lhlo_timeout\fR
Timeout for sending the \fBLHLO\fR command, and for Timeout for sending the \fBLHLO\fR command, and for
receiving the server response. 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 .IP \fBlmtp_mail_timeout\fR
Timeout for sending the \fBMAIL FROM\fR command, and for Timeout for sending the \fBMAIL FROM\fR command, and for
receiving the server response. receiving the server response.

View File

@@ -125,6 +125,12 @@ Always send EHLO at the start of a connection.
Never send EHLO at the start of a connection. Never send EHLO at the start of a connection.
.IP \fBsmtp_bind_address\fR .IP \fBsmtp_bind_address\fR
Numerical source network address to bind to when making a connection. 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 .IP \fBsmtp_line_length_limit\fR
Length limit for SMTP message content lines. Zero means no limit. Length limit for SMTP message content lines. Zero means no limit.
Some SMTP servers misbehave on long lines. 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 The maximal nesting level of multipart mail that the MIME
processor can handle. Refuse mail that is nested deeper, processor can handle. Refuse mail that is nested deeper,
when converting from 8BITMIME format to 7BIT format. 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" .SH "Authentication controls"
.IP \fBsmtp_sasl_auth_enable\fR .IP \fBsmtp_sasl_auth_enable\fR
Enable per-session authentication as per RFC 2554 (SASL). 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 Timeout for sending the "\fB.\fR" command, and for
receiving the server response. When no response is received, a receiving the server response. When no response is received, a
warning is logged that the mail may be delivered multiple times. 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 .IP \fBsmtp_rset_timeout\fR
Timeout for sending the \fBRSET\fR command. Timeout for sending the \fBRSET\fR command.
.IP \fBsmtp_quit_timeout\fR .IP \fBsmtp_quit_timeout\fR

View File

@@ -753,9 +753,9 @@ extern int var_smtp_conn_tmout;
#define DEF_SMTP_HELO_TMOUT "300s" #define DEF_SMTP_HELO_TMOUT "300s"
extern int var_smtp_helo_tmout; extern int var_smtp_helo_tmout;
#define VAR_SMTP_XCLNT_TMOUT "smtp_xclient_timeout" #define VAR_SMTP_XFWD_TMOUT "smtp_xforward_timeout"
#define DEF_SMTP_XCLNT_TMOUT "300s" #define DEF_SMTP_XFWD_TMOUT "300s"
extern int var_smtp_xclnt_tmout; extern int var_smtp_xfwd_tmout;
#define VAR_SMTP_MAIL_TMOUT "smtp_mail_timeout" #define VAR_SMTP_MAIL_TMOUT "smtp_mail_timeout"
#define DEF_SMTP_MAIL_TMOUT "300s" #define DEF_SMTP_MAIL_TMOUT "300s"
@@ -1032,6 +1032,10 @@ extern int var_lmtp_rset_tmout;
#define DEF_LMTP_LHLO_TMOUT "300s" #define DEF_LMTP_LHLO_TMOUT "300s"
extern int var_lmtp_lhlo_tmout; 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 VAR_LMTP_MAIL_TMOUT "lmtp_mail_timeout"
#define DEF_LMTP_MAIL_TMOUT "300s" #define DEF_LMTP_MAIL_TMOUT "300s"
extern int var_lmtp_mail_tmout; extern int var_lmtp_mail_tmout;
@@ -1056,6 +1060,10 @@ extern int var_lmtp_data2_tmout;
#define DEF_LMTP_QUIT_TMOUT "300s" #define DEF_LMTP_QUIT_TMOUT "300s"
extern int var_lmtp_quit_tmout; 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 * Cleanup service. Header info that exceeds $header_size_limit bytes forces
* the start of the message body. * the start of the message body.

View File

@@ -152,15 +152,17 @@ extern char *mail_pathname(const char *, const char *);
#define MAIL_ATTR_ORG_LOCAL "local" /* local submission */ #define MAIL_ATTR_ORG_LOCAL "local" /* local submission */
/* /*
* XCLIENT in SMTP. * XCLIENT/XFORWARD in SMTP.
*/ */
#define XCLIENT_CMD "XCLIENT" /* XCLIENT command */ #define XCLIENT_CMD "XCLIENT" /* XCLIENT command */
#define XCLIENT_NAME "NAME" /* client name */ #define XCLIENT_NAME "NAME" /* client name */
#define XCLIENT_ADDR "ADDR" /* client address */ #define XCLIENT_ADDR "ADDR" /* client address */
#define XCLIENT_PROTO "PROTO" /* client protocol */ #define XCLIENT_PROTO "PROTO" /* client protocol */
#define XCLIENT_CODE "NAME_CODE" /* client name status */
#define XCLIENT_HELO "HELO" /* client helo */ #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_CMD "XFORWARD" /* XFORWARD command */
#define XFORWARD_NAME "NAME" /* client name */ #define XFORWARD_NAME "NAME" /* client name */
#define XFORWARD_ADDR "ADDR" /* client address */ #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_HELO "HELO" /* client helo */
#define XFORWARD_IDENT "IDENT" /* message identifier */ #define XFORWARD_IDENT "IDENT" /* message identifier */
#define XFORWARD_UNAVAILABLE "[UNAVAILABLE]" /* attribute unavailable */
/* LICENSE /* LICENSE
/* .ad /* .ad
/* .fi /* .fi

View File

@@ -20,7 +20,7 @@
* Patches change the patchlevel and the release date. Snapshots change the * Patches change the patchlevel and the release date. Snapshots change the
* release date only, unless they include the same bugfix as a patch release. * 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 VAR_MAIL_VERSION "mail_version"
#define DEF_MAIL_VERSION "2.0.16-" MAIL_RELEASE_DATE #define DEF_MAIL_VERSION "2.0.16-" MAIL_RELEASE_DATE

View File

@@ -88,6 +88,11 @@
/* .IP \fBlmtp_tcp_port\fR /* .IP \fBlmtp_tcp_port\fR
/* The TCP port to be used when connecting to a LMTP server. Used as /* 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). /* 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" /* .SH "Authentication controls"
/* .IP \fBlmtp_sasl_auth_enable\fR /* .IP \fBlmtp_sasl_auth_enable\fR
/* Enable per-session authentication as per RFC 2554 (SASL). /* Enable per-session authentication as per RFC 2554 (SASL).
@@ -169,6 +174,9 @@
/* .IP \fBlmtp_lhlo_timeout\fR /* .IP \fBlmtp_lhlo_timeout\fR
/* Timeout for sending the \fBLHLO\fR command, and for /* Timeout for sending the \fBLHLO\fR command, and for
/* receiving the server response. /* 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 /* .IP \fBlmtp_mail_timeout\fR
/* Timeout for sending the \fBMAIL FROM\fR command, and for /* Timeout for sending the \fBMAIL FROM\fR command, and for
/* receiving the server response. /* receiving the server response.
@@ -263,6 +271,7 @@ int var_lmtp_tcp_port;
int var_lmtp_conn_tmout; int var_lmtp_conn_tmout;
int var_lmtp_rset_tmout; int var_lmtp_rset_tmout;
int var_lmtp_lhlo_tmout; int var_lmtp_lhlo_tmout;
int var_lmtp_xfwd_tmout;
int var_lmtp_mail_tmout; int var_lmtp_mail_tmout;
int var_lmtp_rcpt_tmout; int var_lmtp_rcpt_tmout;
int var_lmtp_data0_tmout; int var_lmtp_data0_tmout;
@@ -276,6 +285,7 @@ char *var_error_rcpt;
char *var_lmtp_sasl_opts; char *var_lmtp_sasl_opts;
char *var_lmtp_sasl_passwd; char *var_lmtp_sasl_passwd;
bool var_lmtp_sasl_enable; bool var_lmtp_sasl_enable;
bool var_lmtp_send_xforward;
/* /*
* Global variables. * 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_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_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_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_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_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, VAR_LMTP_DATA0_TMOUT, DEF_LMTP_DATA0_TMOUT, &var_lmtp_data0_tmout, 1, 0,

View File

@@ -61,6 +61,16 @@ typedef struct LMTP_STATE {
#define LMTP_FEATURE_PIPELINING (1<<2) #define LMTP_FEATURE_PIPELINING (1<<2)
#define LMTP_FEATURE_SIZE (1<<3) #define LMTP_FEATURE_SIZE (1<<3)
#define LMTP_FEATURE_AUTH (1<<5) #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 * lmtp.c

View File

@@ -100,6 +100,7 @@
#include <vstring_vstream.h> #include <vstring_vstream.h>
#include <stringops.h> #include <stringops.h>
#include <mymalloc.h> #include <mymalloc.h>
#include <name_code.h>
/* Global library. */ /* Global library. */
@@ -141,48 +142,58 @@
* the existing code for exception handling and error reporting. * the existing code for exception handling and error reporting.
* *
* Client states that are associated with sending mail (up to and including * Client states that are associated with sending mail (up to and including
* SMTP_STATE_DOT) must have smaller numerical values than the non-sending * LMTP_STATE_DOT) must have smaller numerical values than the non-sending
* states (SMTP_STATE_ABORT .. SMTP_STATE_LAST). * states (LMTP_STATE_ABORT .. LMTP_STATE_LAST).
*/ */
#define LMTP_STATE_MAIL 0 #define LMTP_STATE_XFORWARD_NAME_ADDR 0
#define LMTP_STATE_RCPT 1 #define LMTP_STATE_XFORWARD_PROTO_HELO 1
#define LMTP_STATE_DATA 2 #define LMTP_STATE_MAIL 2
#define LMTP_STATE_DOT 3 #define LMTP_STATE_RCPT 3
#define LMTP_STATE_ABORT 4 #define LMTP_STATE_DATA 4
#define LMTP_STATE_RSET 5 #define LMTP_STATE_DOT 5
#define LMTP_STATE_QUIT 6 #define LMTP_STATE_ABORT 6
#define LMTP_STATE_LAST 7 #define LMTP_STATE_RSET 7
#define LMTP_STATE_QUIT 8
#define LMTP_STATE_LAST 9
int *xfer_timeouts[LMTP_STATE_LAST] = { int *xfer_timeouts[LMTP_STATE_LAST] = {
&var_lmtp_xfwd_tmout, /* name/addr */
&var_lmtp_xfwd_tmout, /* helo/proto */
&var_lmtp_mail_tmout, &var_lmtp_mail_tmout,
&var_lmtp_rcpt_tmout, &var_lmtp_rcpt_tmout,
&var_lmtp_data0_tmout, &var_lmtp_data0_tmout,
&var_lmtp_data2_tmout, &var_lmtp_data2_tmout,
&var_lmtp_rset_tmout, &var_lmtp_rset_tmout, /* abort */
&var_lmtp_rset_tmout, &var_lmtp_rset_tmout, /* rset */
&var_lmtp_quit_tmout, &var_lmtp_quit_tmout,
}; };
char *xfer_states[LMTP_STATE_LAST] = { char *xfer_states[LMTP_STATE_LAST] = {
"sending XFORWARD name/address",
"sending XFORWARD protocol/helo_name",
"sending MAIL FROM", "sending MAIL FROM",
"sending RCPT TO", "sending RCPT TO",
"sending DATA command", "sending DATA command",
"sending end of data -- message may be sent more than once", "sending end of data -- message may be sent more than once",
"sending RSET", "sending RSET", /* abort */
"sending RSET", "sending RSET", /* rset */
"sending QUIT", "sending QUIT",
}; };
char *xfer_request[LMTP_STATE_LAST] = { char *xfer_request[LMTP_STATE_LAST] = {
"XFORWARD name/address command",
"XFORWARD helo/protocol command",
"MAIL FROM command", "MAIL FROM command",
"RCPT TO command", "RCPT TO command",
"DATA command", "DATA command",
"end of DATA command", "end of DATA command",
"RSET command", "RSET command", /* abort */
"RSET command", "RSET command", /* rset */
"QUIT command", "QUIT command",
}; };
static int lmtp_send_proto_helo;
/* lmtp_lhlo - perform initial handshake with LMTP server */ /* lmtp_lhlo - perform initial handshake with LMTP server */
int lmtp_lhlo(LMTP_STATE *state) int lmtp_lhlo(LMTP_STATE *state)
@@ -193,6 +204,13 @@ int lmtp_lhlo(LMTP_STATE *state)
char *lines; char *lines;
char *words; char *words;
char *word; 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. * Prepare for disaster.
@@ -235,6 +253,10 @@ int lmtp_lhlo(LMTP_STATE *state)
state->features |= LMTP_FEATURE_8BITMIME; state->features |= LMTP_FEATURE_8BITMIME;
else if (strcasecmp(word, "PIPELINING") == 0) else if (strcasecmp(word, "PIPELINING") == 0)
state->features |= LMTP_FEATURE_PIPELINING; 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) else if (strcasecmp(word, "SIZE") == 0)
state->features |= LMTP_FEATURE_SIZE; state->features |= LMTP_FEATURE_SIZE;
#ifdef USE_SASL_AUTH #ifdef USE_SASL_AUTH
@@ -364,6 +386,40 @@ static int lmtp_loop(LMTP_STATE *state, int send_state, int recv_state)
default: default:
msg_panic("%s: bad sender state %d", myname, send_state); 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. * Build the MAIL FROM command.
*/ */
@@ -478,7 +534,7 @@ static int lmtp_loop(LMTP_STATE *state, int send_state, int recv_state)
/* /*
* Sanity check. * Sanity check.
*/ */
if (recv_state < LMTP_STATE_MAIL if (recv_state < LMTP_STATE_XFORWARD_NAME_ADDR
|| recv_state > LMTP_STATE_QUIT) || recv_state > LMTP_STATE_QUIT)
msg_panic("%s: bad receiver state %d (sender state %d)", msg_panic("%s: bad receiver state %d (sender state %d)",
myname, recv_state, send_state); 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) { 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 * Process the MAIL FROM response. When the server
* rejects the sender, set the mail_from_rejected flag so * 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), && sent(DEL_REQ_TRACE_FLAGS(request->flags),
request->queue_id, rcpt->orig_addr, request->queue_id, rcpt->orig_addr,
rcpt->address, rcpt->offset, rcpt->address, rcpt->offset,
session->namaddr, request->arrival_time, session->namaddr, request->arrival_time,
"%s", "%s",
translit(resp->str, "\n", " ")) == 0) { translit(resp->str, "\n", " ")) == 0) {
if (request->flags & DEL_REQ_FLAG_SUCCESS) 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) 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 */ /* lmtp_rset - send a lone RSET command and wait for response */

View 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. * Sanity checks. Verify that every member has an acceptable value.
*/ */
if (user == 0) if (user == 0)
msg_fatal("missing user= attribute"); msg_fatal("missing user= command-line attribute");
if (attr->command == 0) if (attr->command == 0)
msg_fatal("missing argv= attribute"); msg_fatal("missing argv= command-line attribute");
if (attr->uid == 0) 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) 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) 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) 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. * Give the poor tester a clue of what is going on.

View File

@@ -154,6 +154,7 @@ smtp_proto.o: ../../include/stringops.h
smtp_proto.o: ../../include/mymalloc.h smtp_proto.o: ../../include/mymalloc.h
smtp_proto.o: ../../include/iostuff.h smtp_proto.o: ../../include/iostuff.h
smtp_proto.o: ../../include/split_at.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/mail_params.h
smtp_proto.o: ../../include/smtp_stream.h smtp_proto.o: ../../include/smtp_stream.h
smtp_proto.o: ../../include/mail_queue.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/attr.h
smtp_proto.o: ../../include/mime_state.h smtp_proto.o: ../../include/mime_state.h
smtp_proto.o: ../../include/header_opts.h smtp_proto.o: ../../include/header_opts.h
smtp_proto.o: ../../include/xtext.h
smtp_proto.o: smtp.h smtp_proto.o: smtp.h
smtp_proto.o: ../../include/argv.h smtp_proto.o: ../../include/argv.h
smtp_proto.o: smtp_sasl.h smtp_proto.o: smtp_sasl.h

View File

@@ -109,6 +109,12 @@
/* Never send EHLO at the start of a connection. /* Never send EHLO at the start of a connection.
/* .IP \fBsmtp_bind_address\fR /* .IP \fBsmtp_bind_address\fR
/* Numerical source network address to bind to when making a connection. /* 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 /* .IP \fBsmtp_line_length_limit\fR
/* Length limit for SMTP message content lines. Zero means no limit. /* Length limit for SMTP message content lines. Zero means no limit.
/* Some SMTP servers misbehave on long lines. /* Some SMTP servers misbehave on long lines.
@@ -142,6 +148,11 @@
/* The maximal nesting level of multipart mail that the MIME /* The maximal nesting level of multipart mail that the MIME
/* processor can handle. Refuse mail that is nested deeper, /* processor can handle. Refuse mail that is nested deeper,
/* when converting from 8BITMIME format to 7BIT format. /* 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" /* .SH "Authentication controls"
/* .IP \fBsmtp_sasl_auth_enable\fR /* .IP \fBsmtp_sasl_auth_enable\fR
/* Enable per-session authentication as per RFC 2554 (SASL). /* Enable per-session authentication as per RFC 2554 (SASL).
@@ -212,17 +223,6 @@
/* Timeout for sending the "\fB.\fR" command, and for /* Timeout for sending the "\fB.\fR" command, and for
/* receiving the server response. When no response is received, a /* receiving the server response. When no response is received, a
/* warning is logged that the mail may be delivered multiple times. /* 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 /* .IP \fBsmtp_rset_timeout\fR
/* Timeout for sending the \fBRSET\fR command. /* Timeout for sending the \fBRSET\fR command.
/* .IP \fBsmtp_quit_timeout\fR /* .IP \fBsmtp_quit_timeout\fR
@@ -283,7 +283,7 @@
*/ */
int var_smtp_conn_tmout; int var_smtp_conn_tmout;
int var_smtp_helo_tmout; int var_smtp_helo_tmout;
int var_smtp_xclnt_tmout; int var_smtp_xfwd_tmout;
int var_smtp_mail_tmout; int var_smtp_mail_tmout;
int var_smtp_rcpt_tmout; int var_smtp_rcpt_tmout;
int var_smtp_data0_tmout; int var_smtp_data0_tmout;
@@ -502,7 +502,7 @@ int main(int argc, char **argv)
static CONFIG_TIME_TABLE time_table[] = { static CONFIG_TIME_TABLE time_table[] = {
VAR_SMTP_CONN_TMOUT, DEF_SMTP_CONN_TMOUT, &var_smtp_conn_tmout, 0, 0, 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_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_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_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, VAR_SMTP_DATA0_TMOUT, DEF_SMTP_DATA0_TMOUT, &var_smtp_data0_tmout, 1, 0,

View File

@@ -69,9 +69,11 @@ typedef struct SMTP_STATE {
#define SMTP_FEATURE_XFORWARD_PROTO (1<<9) #define SMTP_FEATURE_XFORWARD_PROTO (1<<9)
#define SMTP_FEATURE_XFORWARD_HELO (1<<10) #define SMTP_FEATURE_XFORWARD_HELO (1<<10)
#define SMTP_FEATURE_XFORWARD_MASK \ #define SMTP_FEATURE_XFORWARD_NAME_ADDR \
(SMTP_FEATURE_XFORWARD_NAME | SMTP_FEATURE_XFORWARD_ADDR \ (SMTP_FEATURE_XFORWARD_NAME | SMTP_FEATURE_XFORWARD_ADDR)
| SMTP_FEATURE_XFORWARD_PROTO | SMTP_FEATURE_XFORWARD_HELO)
#define SMTP_FEATURE_XFORWARD_PROTO_HELO \
(SMTP_FEATURE_XFORWARD_PROTO | SMTP_FEATURE_XFORWARD_HELO)
/* /*
* smtp.c * smtp.c

View File

@@ -104,7 +104,6 @@
#include <quote_821_local.h> #include <quote_821_local.h>
#include <mail_proto.h> #include <mail_proto.h>
#include <mime_state.h> #include <mime_state.h>
#include <xtext.h>
/* Application-specific. */ /* Application-specific. */
@@ -125,8 +124,8 @@
* SMTP_STATE_DOT) must have smaller numerical values than the non-sending * SMTP_STATE_DOT) must have smaller numerical values than the non-sending
* states (SMTP_STATE_ABORT .. SMTP_STATE_LAST). * states (SMTP_STATE_ABORT .. SMTP_STATE_LAST).
*/ */
#define SMTP_STATE_XFORWARD_ADDR 0 #define SMTP_STATE_XFORWARD_NAME_ADDR 0
#define SMTP_STATE_XFORWARD_HELO 1 #define SMTP_STATE_XFORWARD_PROTO_HELO 1
#define SMTP_STATE_MAIL 2 #define SMTP_STATE_MAIL 2
#define SMTP_STATE_RCPT 3 #define SMTP_STATE_RCPT 3
#define SMTP_STATE_DATA 4 #define SMTP_STATE_DATA 4
@@ -136,8 +135,8 @@
#define SMTP_STATE_LAST 8 #define SMTP_STATE_LAST 8
int *xfer_timeouts[SMTP_STATE_LAST] = { int *xfer_timeouts[SMTP_STATE_LAST] = {
&var_smtp_xclnt_tmout, &var_smtp_xfwd_tmout, /* name/addr */
&var_smtp_xclnt_tmout, &var_smtp_xfwd_tmout, /* helo/proto */
&var_smtp_mail_tmout, &var_smtp_mail_tmout,
&var_smtp_rcpt_tmout, &var_smtp_rcpt_tmout,
&var_smtp_data0_tmout, &var_smtp_data0_tmout,
@@ -147,8 +146,8 @@ int *xfer_timeouts[SMTP_STATE_LAST] = {
}; };
char *xfer_states[SMTP_STATE_LAST] = { char *xfer_states[SMTP_STATE_LAST] = {
"sending XFORWARD address and name", "sending XFORWARD name/address",
"sending XFORWARD helo_name and protocol", "sending XFORWARD protocol/helo_name",
"sending MAIL FROM", "sending MAIL FROM",
"sending RCPT TO", "sending RCPT TO",
"sending DATA command", "sending DATA command",
@@ -267,11 +266,11 @@ int smtp_helo(SMTP_STATE *state)
state->features |= SMTP_FEATURE_8BITMIME; state->features |= SMTP_FEATURE_8BITMIME;
else if (strcasecmp(word, "PIPELINING") == 0) else if (strcasecmp(word, "PIPELINING") == 0)
state->features |= SMTP_FEATURE_PIPELINING; state->features |= SMTP_FEATURE_PIPELINING;
else if (strcasecmp(word, "XFORWARD") == 0) { else if (strcasecmp(word, "XFORWARD") == 0)
while ((word = mystrtok(&words, " \t")) != 0) while ((word = mystrtok(&words, " \t")) != 0)
state->features |= name_code(xforward_features, state->features |= name_code(xforward_features,
NAME_CODE_FLAG_NONE, word); NAME_CODE_FLAG_NONE, word);
} else if (strcasecmp(word, "SIZE") == 0) { else if (strcasecmp(word, "SIZE") == 0) {
state->features |= SMTP_FEATURE_SIZE; state->features |= SMTP_FEATURE_SIZE;
if ((word = mystrtok(&words, " \t")) != 0) { if ((word = mystrtok(&words, " \t")) != 0) {
if (!alldig(word)) if (!alldig(word))
@@ -395,6 +394,8 @@ int smtp_xfer(SMTP_STATE *state)
int mail_from_rejected; int mail_from_rejected;
int downgrading; int downgrading;
int mime_errs; int mime_errs;
int send_name_addr;
int send_proto_helo;
/* /*
* Macros for readability. * Macros for readability.
@@ -498,11 +499,20 @@ int smtp_xfer(SMTP_STATE *state)
* amount of information is available. * amount of information is available.
*/ */
nrcpt = 0; nrcpt = 0;
if (var_smtp_send_xforward send_name_addr =
&& (state->features & SMTP_FEATURE_XFORWARD_MASK) (var_smtp_send_xforward
&& (DEL_REQ_ATTR_AVAIL(request->client_name) && (state->features & SMTP_FEATURE_XFORWARD_NAME_ADDR)
|| DEL_REQ_ATTR_AVAIL(request->client_addr))) && (DEL_REQ_ATTR_AVAIL(request->client_name)
recv_state = send_state = SMTP_STATE_XFORWARD_ADDR; || 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 else
recv_state = send_state = SMTP_STATE_MAIL; recv_state = send_state = SMTP_STATE_MAIL;
next_rcpt = send_rcpt = recv_rcpt = 0; 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 * information, the command length stays within the 512 byte
* command line length limit. * command line length limit.
*/ */
case SMTP_STATE_XFORWARD_ADDR: case SMTP_STATE_XFORWARD_NAME_ADDR:
vstring_strcpy(next_command, XFORWARD_CMD); vstring_strcpy(next_command, XFORWARD_CMD);
if (state->features & SMTP_FEATURE_XFORWARD_NAME) { if (state->features & SMTP_FEATURE_XFORWARD_NAME)
vstring_strcat(next_command, " " XCLIENT_NAME "="); vstring_sprintf_append(next_command, " %s=%s",
if (DEL_REQ_ATTR_AVAIL(request->client_name)) XFORWARD_NAME, DEL_REQ_ATTR_AVAIL(request->client_name) ?
xtext_quote_append(next_command, request->client_name, ""); request->client_name : XFORWARD_UNAVAILABLE);
} if (state->features & SMTP_FEATURE_XFORWARD_ADDR)
if (state->features & SMTP_FEATURE_XFORWARD_ADDR) { vstring_sprintf_append(next_command, " %s=%s",
vstring_strcat(next_command, " " XFORWARD_ADDR "="); XFORWARD_ADDR, DEL_REQ_ATTR_AVAIL(request->client_addr) ?
if (DEL_REQ_ATTR_AVAIL(request->client_addr)) request->client_addr : XFORWARD_UNAVAILABLE);
xtext_quote_append(next_command, request->client_addr, ""); if (send_proto_helo)
} next_state = SMTP_STATE_XFORWARD_PROTO_HELO;
next_state = SMTP_STATE_XFORWARD_HELO; else
next_state = SMTP_STATE_MAIL;
break; break;
case SMTP_STATE_XFORWARD_HELO: case SMTP_STATE_XFORWARD_PROTO_HELO:
vstring_strcpy(next_command, XFORWARD_CMD); vstring_strcpy(next_command, XFORWARD_CMD);
if (state->features & SMTP_FEATURE_XFORWARD_HELO) { if (state->features & SMTP_FEATURE_XFORWARD_PROTO)
vstring_strcat(next_command, " " XCLIENT_HELO "="); vstring_sprintf_append(next_command, " %s=%s",
if (DEL_REQ_ATTR_AVAIL(request->client_helo)) XFORWARD_PROTO, DEL_REQ_ATTR_AVAIL(request->client_proto) ?
xtext_quote_append(next_command, request->client_helo, ""); request->client_proto : XFORWARD_UNAVAILABLE);
} if (state->features & SMTP_FEATURE_XFORWARD_HELO)
if (state->features & SMTP_FEATURE_XFORWARD_ADDR) { vstring_sprintf_append(next_command, " %s=%s",
vstring_strcat(next_command, " " XFORWARD_PROTO "="); XFORWARD_HELO, DEL_REQ_ATTR_AVAIL(request->client_helo) ?
if (DEL_REQ_ATTR_AVAIL(request->client_proto)) request->client_helo : XFORWARD_UNAVAILABLE);
xtext_quote_append(next_command, request->client_proto, "");
}
next_state = SMTP_STATE_MAIL; next_state = SMTP_STATE_MAIL;
break; break;
@@ -665,7 +674,7 @@ int smtp_xfer(SMTP_STATE *state)
/* /*
* Sanity check. * Sanity check.
*/ */
if (recv_state < SMTP_STATE_XFORWARD_ADDR if (recv_state < SMTP_STATE_XFORWARD_NAME_ADDR
|| recv_state > SMTP_STATE_QUIT) || recv_state > SMTP_STATE_QUIT)
msg_panic("%s: bad receiver state %d (sender state %d)", msg_panic("%s: bad receiver state %d (sender state %d)",
myname, recv_state, send_state); myname, recv_state, send_state);
@@ -689,21 +698,24 @@ int smtp_xfer(SMTP_STATE *state)
/* /*
* Process the XFORWARD response. * Process the XFORWARD response.
*/ */
case SMTP_STATE_XFORWARD_ADDR: case SMTP_STATE_XFORWARD_NAME_ADDR:
if (resp->code / 100 != 2) if (resp->code / 100 != 2)
msg_warn("host %s said: %s (in reply to %s)", msg_warn("host %s said: %s (in reply to %s)",
session->namaddr, session->namaddr,
translit(resp->str, "\n", " "), translit(resp->str, "\n", " "),
xfer_request[SMTP_STATE_MAIL]); xfer_request[SMTP_STATE_XFORWARD_NAME_ADDR]);
recv_state = SMTP_STATE_XFORWARD_HELO; if (send_proto_helo)
recv_state = SMTP_STATE_XFORWARD_PROTO_HELO;
else
recv_state = SMTP_STATE_MAIL;
break; break;
case SMTP_STATE_XFORWARD_HELO: case SMTP_STATE_XFORWARD_PROTO_HELO:
if (resp->code / 100 != 2) if (resp->code / 100 != 2)
msg_warn("host %s said: %s (in reply to %s)", msg_warn("host %s said: %s (in reply to %s)",
session->namaddr, session->namaddr,
translit(resp->str, "\n", " "), translit(resp->str, "\n", " "),
xfer_request[SMTP_STATE_MAIL]); xfer_request[SMTP_STATE_XFORWARD_PROTO_HELO]);
recv_state = SMTP_STATE_MAIL; recv_state = SMTP_STATE_MAIL;
break; break;

View File

@@ -151,7 +151,6 @@ smtpd.o: ../../include/namadr_list.h
smtpd.o: ../../include/input_transp.h smtpd.o: ../../include/input_transp.h
smtpd.o: ../../include/anvil_clnt.h smtpd.o: ../../include/anvil_clnt.h
smtpd.o: ../../include/attr_clnt.h smtpd.o: ../../include/attr_clnt.h
smtpd.o: ../../include/xtext.h
smtpd.o: ../../include/mail_server.h smtpd.o: ../../include/mail_server.h
smtpd.o: smtpd_token.h smtpd.o: smtpd_token.h
smtpd.o: smtpd.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/stringops.h
smtpd_proxy.o: ../../include/connect.h smtpd_proxy.o: ../../include/connect.h
smtpd_proxy.o: ../../include/iostuff.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/mail_error.h
smtpd_proxy.o: ../../include/name_mask.h smtpd_proxy.o: ../../include/name_mask.h
smtpd_proxy.o: ../../include/smtp_stream.h smtpd_proxy.o: ../../include/smtp_stream.h
smtpd_proxy.o: ../../include/cleanup_user.h smtpd_proxy.o: ../../include/cleanup_user.h
smtpd_proxy.o: ../../include/mail_params.h smtpd_proxy.o: ../../include/mail_params.h
smtpd_proxy.o: ../../include/rec_type.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/mail_proto.h
smtpd_proxy.o: ../../include/attr.h smtpd_proxy.o: ../../include/attr.h
smtpd_proxy.o: smtpd.h smtpd_proxy.o: smtpd.h

View File

@@ -464,7 +464,6 @@
#include <namadr_list.h> #include <namadr_list.h>
#include <input_transp.h> #include <input_transp.h>
#include <anvil_clnt.h> #include <anvil_clnt.h>
#include <xtext.h>
/* Single-threaded server skeleton. */ /* Single-threaded server skeleton. */
@@ -753,8 +752,7 @@ static int ehlo_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv)
if (xclient_allowed) if (xclient_allowed)
smtpd_chat_reply(state, "250-" XCLIENT_CMD smtpd_chat_reply(state, "250-" XCLIENT_CMD
" " XCLIENT_NAME " " XCLIENT_ADDR " " XCLIENT_NAME " " XCLIENT_ADDR
" " XCLIENT_CODE " " XCLIENT_PROTO " " XCLIENT_PROTO " " XCLIENT_HELO);
" " XCLIENT_HELO);
if (xforward_allowed) if (xforward_allowed)
smtpd_chat_reply(state, "250-" XFORWARD_CMD smtpd_chat_reply(state, "250-" XFORWARD_CMD
" " XFORWARD_NAME " " XFORWARD_ADDR " " XFORWARD_NAME " " XFORWARD_ADDR
@@ -1723,22 +1721,21 @@ static int quit_cmd(SMTPD_STATE *state, int unused_argc, SMTPD_TOKEN *unused_arg
return (0); 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) static int xclient_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv)
{ {
int arg_no; SMTPD_TOKEN *argp;
char *attr_value; char *attr_value;
char *attr_name; char *attr_name;
int update_namaddr = 0; int update_namaddr = 0;
int code; int peer_code;
static NAME_CODE xclient_codes[] = { static NAME_CODE peer_codes[] = {
"OK", SMTPD_PEER_CODE_OK, XCLIENT_UNAVAILABLE, SMTPD_PEER_CODE_PERM,
"PERM", SMTPD_PEER_CODE_PERM, XCLIENT_TEMPORARY, SMTPD_PEER_CODE_TEMP,
"TEMP", SMTPD_PEER_CODE_TEMP, 0, SMTPD_PEER_CODE_OK,
0, -1,
}; };
static NAME_CODE xclient_proto[] = { static NAME_CODE proto_names[] = {
MAIL_PROTO_SMTP, 1, MAIL_PROTO_SMTP, 1,
MAIL_PROTO_ESMTP, 2, MAIL_PROTO_ESMTP, 2,
0, -1, 0, -1,
@@ -1755,7 +1752,7 @@ static int xclient_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv)
} }
if (argc < 2) { if (argc < 2) {
state->error_mask |= MAIL_ERROR_PROTOCOL; 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); XCLIENT_CMD);
return (-1); return (-1);
} }
@@ -1765,122 +1762,99 @@ static int xclient_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv)
return (-1); return (-1);
} }
#define STREQ(x,y) (strcasecmp((x), (y)) == 0) #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++) { for (argp = argv + 1; argp < argv + argc; argp++) {
attr_name = argv[arg_no].strval; attr_name = argp->strval;
/* /*
* For safety's sake mask non-printable characters in the raw and * For safety's sake mask non-printable characters. We'll do more
* decoded values; we don't want to handle unexploded munitions. * specific censoring later.
* 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.
*/ */
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; 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); return (-1);
} }
printable(attr_value, '?'); printable(attr_value, '?');
/* /*
* NAME=hostname. Also updates the client hostname lookup status * NAME=substitute SMTP client hostname. Also updates the client
* code. Treat a numerical hostname as an unavailable name. * hostname lookup status code.
*/ */
if (STREQ(attr_name, XCLIENT_NAME)) { if (STREQ(attr_name, XCLIENT_NAME)) {
if (*attr_value && !valid_hostaddr(attr_value, DONT_GRIPE)) { peer_code = name_code(peer_codes, NAME_CODE_FLAG_NONE, attr_value);
if (!valid_hostname(attr_value, DONT_GRIPE)) { 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; state->error_mask |= MAIL_ERROR_PROTOCOL;
smtpd_chat_reply(state, "501 Bad %s syntax: %s", smtpd_chat_reply(state, "501 Bad %s syntax: %s",
XCLIENT_NAME, attr_value); XCLIENT_NAME, attr_value);
return (-1); 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; update_namaddr = 1;
} }
/* /*
* ADDR=client network address. * ADDR=substitute SMTP client network address.
*/ */
else if (STREQ(attr_name, XCLIENT_ADDR)) { 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)) { if (!valid_hostaddr(attr_value, DONT_GRIPE)) {
state->error_mask |= MAIL_ERROR_PROTOCOL; state->error_mask |= MAIL_ERROR_PROTOCOL;
smtpd_chat_reply(state, "501 Bad %s syntax: %s", smtpd_chat_reply(state, "501 Bad %s syntax: %s",
XCLIENT_ADDR, attr_value); XCLIENT_ADDR, attr_value);
return (-1); 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; update_namaddr = 1;
} }
/* /*
* CODE=hostname lookup status. Reset the client hostname if the * HELO=substitute SMTP client HELO parameter. Censor special
* hostname lookup status is not OK. * characters that could mess up message headers.
*/
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 [].
*/ */
else if (STREQ(attr_name, XCLIENT_HELO)) { 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) { if (strlen(attr_value) > VALID_HOSTNAME_LEN) {
state->error_mask |= MAIL_ERROR_PROTOCOL; state->error_mask |= MAIL_ERROR_PROTOCOL;
smtpd_chat_reply(state, "501 Bad %s syntax: %s", smtpd_chat_reply(state, "501 Bad %s syntax: %s",
XCLIENT_HELO, attr_value); XCLIENT_HELO, attr_value);
return (-1); return (-1);
} }
neuter(attr_value, "<>()\\\";:@", '?'); neuter(attr_value, NEUTER_CHARACTERS, '?');
UPDATE_STR(state->helo_name, attr_value);
} else {
UPDATE_STR(state->helo_name, CLIENT_HELO_UNKNOWN);
} }
UPDATE_STR(state->helo_name, attr_value);
} }
/* /*
* PROTO=protocol name. Disallow characters that could mess up our * PROTO=SMTP protocol name.
* own Received: message headers.
*/ */
else if (STREQ(attr_name, XCLIENT_PROTO)) { 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; state->error_mask |= MAIL_ERROR_PROTOCOL;
smtpd_chat_reply(state, "501 Bad %s syntax: %s", smtpd_chat_reply(state, "501 Bad %s syntax: %s",
XCLIENT_PROTO, attr_value); XCLIENT_PROTO, attr_value);
return (-1); 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) static int xforward_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv)
{ {
int arg_no; SMTPD_TOKEN *argp;
char *attr_value; char *attr_value;
char *attr_name; char *attr_name;
int updated = 0; int updated = 0;
@@ -1934,7 +1908,7 @@ static int xforward_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv)
} }
if (argc < 2) { if (argc < 2) {
state->error_mask |= MAIL_ERROR_PROTOCOL; 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); XFORWARD_CMD);
return (-1); return (-1);
} }
@@ -1951,22 +1925,18 @@ static int xforward_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv)
smtpd_xforward_preset(state); 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++) { for (argp = argv + 1; argp < argv + argc; argp++) {
attr_name = argv[arg_no].strval; attr_name = argp->strval;
/* /*
* For safety's sake mask non-printable characters in the raw and * For safety's sake mask non-printable characters. We'll do more
* decoded values; we don't want to handle unexploded munitions. * specific censoring later.
* 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.
*/ */
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; 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); return (-1);
} }
printable(attr_value, '?'); printable(attr_value, '?');
@@ -1975,71 +1945,61 @@ static int xforward_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv)
switch (flag) { switch (flag) {
/* /*
* NAME=hostname. Also updates the client hostname lookup status * NAME=host name, not necessarily in the DNS. Censor special
* code. Treat a numerical hostname as an unavailable name. * characters that could mess up message headers.
*/ */
case SMTPD_XFORWARD_FLAG_NAME: case SMTPD_XFORWARD_FLAG_NAME:
if (*attr_value && !valid_hostaddr(attr_value, DONT_GRIPE)) { if (STREQ(attr_value, XFORWARD_UNAVAILABLE)) {
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 {
attr_value = CLIENT_NAME_UNKNOWN; attr_value = CLIENT_NAME_UNKNOWN;
} else {
neuter(attr_value, NEUTER_CHARACTERS, '?');
} }
UPDATE_STR(state->xforward.name, attr_value); UPDATE_STR(state->xforward.name, attr_value);
break; 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: case SMTPD_XFORWARD_FLAG_ADDR:
if (*attr_value) { if (STREQ(attr_value, XFORWARD_UNAVAILABLE)) {
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 {
attr_value = CLIENT_ADDR_UNKNOWN; attr_value = CLIENT_ADDR_UNKNOWN;
} else {
neuter(attr_value, NEUTER_CHARACTERS, '?');
} }
UPDATE_STR(state->xforward.addr, attr_value); UPDATE_STR(state->xforward.addr, attr_value);
break; break;
/* /*
* HELO=hostname. Disallow characters that could mess up our own * HELO=hostname that the host introduced itself with (not
* Received: message headers but allow []. * necessarily SMTP HELO). Censor special characters that could
* mess up message headers.
*/ */
case SMTPD_XFORWARD_FLAG_HELO: case SMTPD_XFORWARD_FLAG_HELO:
if (*attr_value) { if (STREQ(attr_value, XFORWARD_UNAVAILABLE)) {
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 {
attr_value = CLIENT_HELO_UNKNOWN; attr_value = CLIENT_HELO_UNKNOWN;
} else {
neuter(attr_value, NEUTER_CHARACTERS, '?');
} }
UPDATE_STR(state->xforward.helo_name, attr_value); UPDATE_STR(state->xforward.helo_name, attr_value);
break; break;
/* /*
* PROTO=protocol name. Neutralize characters that could mess up * PROTO=protocol name, not necessarily SMTP or ESMTP. Censor
* our own Received: message headers. * special characters that could mess up message headers.
*/ */
case SMTPD_XFORWARD_FLAG_PROTO: case SMTPD_XFORWARD_FLAG_PROTO:
if (strlen(attr_value) > 64) { if (STREQ(attr_value, XFORWARD_UNAVAILABLE)) {
state->error_mask |= MAIL_ERROR_PROTOCOL; attr_value = CLIENT_PROTO_UNKNOWN;
smtpd_chat_reply(state, "501 Bad %s syntax: %s", } else {
XFORWARD_PROTO, attr_value); if (strlen(attr_value) > 64) {
return (-1); 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); UPDATE_STR(state->xforward.protocol, attr_value);
break; break;
@@ -2063,9 +2023,10 @@ static int xforward_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv)
if (state->xforward.namaddr) if (state->xforward.namaddr)
myfree(state->xforward.namaddr); myfree(state->xforward.namaddr);
state->xforward.namaddr = state->xforward.namaddr =
IS_AVAIL_CLIENT_ADDR(state->xforward.addr) ?
concatenate(state->xforward.name, "[", concatenate(state->xforward.name, "[",
state->xforward.addr, "]", state->xforward.addr, "]",
(char *) 0); (char *) 0) : mystrdup(state->xforward.name);
} }
smtpd_chat_reply(state, "250 Ok"); smtpd_chat_reply(state, "250 Ok");
return (0); return (0);

View File

@@ -206,9 +206,8 @@ extern void smtpd_peer_reset(SMTPD_STATE *state);
#define SMTPD_PROXY_XFORWARD_IDENT (1<<4) /* message identifier */ #define SMTPD_PROXY_XFORWARD_IDENT (1<<4) /* message identifier */
/* /*
* If forwarding client information, don't mix direct client information * If forwarding client information, don't mix information from the current
* from the current SMTP session with forwarded client information from an * SMTP session with forwarded information from an up-stream session.
* up-stream session.
*/ */
#define FORWARD_CLIENT_ATTR(s, a) \ #define FORWARD_CLIENT_ATTR(s, a) \
(((s)->xforward.flags & SMTPD_XFORWARD_FLAG_CLIENT_MASK) ? \ (((s)->xforward.flags & SMTPD_XFORWARD_FLAG_CLIENT_MASK) ? \

View File

@@ -156,7 +156,6 @@
#include <cleanup_user.h> #include <cleanup_user.h>
#include <mail_params.h> #include <mail_params.h>
#include <rec_type.h> #include <rec_type.h>
#include <xtext.h>
#include <mail_proto.h> #include <mail_proto.h>
/* Application-specific. */ /* 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? * How much space does this attribute need?
*/ */
if (!value_available) if (!value_available)
value = ""; value = XFORWARD_UNAVAILABLE;
new_len = strlen(name) + strlen(value) + 2; /* SPACE name = value */ new_len = strlen(name) + strlen(value) + 2; /* SPACE name = value */
if (new_len > PAYLOAD_LIMIT) 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); XFORWARD_CMD, name, value);
/* /*

View 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 \ username.c valid_hostname.c vbuf.c vbuf_print.c vstream.c \
vstream_popen.c vstring.c vstring_vstream.c watchdog.c writable.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 \ 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 \ 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 \ 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 \ 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 \ username.o valid_hostname.o vbuf.o vbuf_print.o vstream.o \
vstream_popen.o vstring.o vstring_vstream.o watchdog.o writable.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 \ 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 \ 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 \ 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 \ 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: unsafe.c
unsafe.o: sys_defs.h unsafe.o: sys_defs.h
unsafe.o: safe.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: username.c
username.o: sys_defs.h username.o: sys_defs.h
username.o: username.h username.o: username.h

View File

@@ -22,6 +22,7 @@
extern char *printable(char *, int); extern char *printable(char *, int);
extern char *neuter(char *, const char *, int); extern char *neuter(char *, const char *, int);
extern char *lowercase(char *); extern char *lowercase(char *);
extern char *uppercase(char *);
extern char *skipblanks(const char *); extern char *skipblanks(const char *);
extern char *trimblanks(char *, int); extern char *trimblanks(char *, int);
extern char *concatenate(const char *,...); extern char *concatenate(const char *,...);

View File

@@ -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);
}