diff --git a/postfix/HISTORY b/postfix/HISTORY index 1a06f19e7..693057866 100644 --- a/postfix/HISTORY +++ b/postfix/HISTORY @@ -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 diff --git a/postfix/README_FILES/XCLIENT_README b/postfix/README_FILES/XCLIENT_README index 3077aed91..62ea99ad0 100644 --- a/postfix/README_FILES/XCLIENT_README +++ b/postfix/README_FILES/XCLIENT_README @@ -1,182 +1,98 @@ 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. +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. -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 -syntax details are given in the next section. +The PROTO attribute specifies either SMTP or ESMTP. -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 HELO attribute specifies a HELO parameter value, or the value +[unavailable] when the information is unavailable. -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 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 +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 index 000000000..6c051b5f7 --- /dev/null +++ b/postfix/README_FILES/XFORWARD_README @@ -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. diff --git a/postfix/conf/postfix-files b/postfix/conf/postfix-files index fcdcb9968..a2487e575 100644 --- a/postfix/conf/postfix-files +++ b/postfix/conf/postfix-files @@ -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 diff --git a/postfix/conf/sample-lmtp.cf b/postfix/conf/sample-lmtp.cf index 9e2699ccc..916527712 100644 --- a/postfix/conf/sample-lmtp.cf +++ b/postfix/conf/sample-lmtp.cf @@ -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. diff --git a/postfix/html/lmtp.8.html b/postfix/html/lmtp.8.html index 1d368f761..9d461d09a 100644 --- a/postfix/html/lmtp.8.html +++ b/postfix/html/lmtp.8.html @@ -107,6 +107,13 @@ LMTP(8) LMTP(8) server. Used as backup if the lmtp service is not found in services(4). + lmtp_send_xforward_command + 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. + Authentication controls lmtp_sasl_auth_enable Enable per-session authentication as per RFC 2554 @@ -206,16 +213,20 @@ LMTP(8) LMTP(8) Timeout for sending the LHLO command, and for receiving the server response. + lmtp_xforward_timeout + Timeout for sending the XFORWARD command, and for + receiving the server response. + lmtp_mail_timeout - Timeout for sending the MAIL FROM command, and for + Timeout for sending the MAIL FROM command, and for receiving the server response. lmtp_rcpt_timeout - Timeout for sending the RCPT TO command, and for + Timeout for sending the RCPT TO command, and for receiving the server response. lmtp_data_init_timeout - Timeout for sending the DATA command, and for + Timeout for sending the DATA command, and for receiving the server response. lmtp_data_xfer_timeout @@ -223,16 +234,16 @@ LMTP(8) LMTP(8) lmtp_data_done_timeout Timeout for sending the "." 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. lmtp_rset_timeout - Timeout for sending the RSET command, and for + Timeout for sending the RSET command, and for receiving the server response. lmtp_quit_timeout - Timeout for sending the QUIT command, and for + Timeout for sending the QUIT command, and for receiving the server response. SEE ALSO @@ -245,7 +256,7 @@ LMTP(8) LMTP(8) syslogd(8) system logging LICENSE - The Secure Mailer license must be distributed with this + The Secure Mailer license must be distributed with this software. AUTHOR(S) diff --git a/postfix/html/smtp.8.html b/postfix/html/smtp.8.html index 0a3c3287a..47a6f67a2 100644 --- a/postfix/html/smtp.8.html +++ b/postfix/html/smtp.8.html @@ -135,6 +135,13 @@ SMTP(8) SMTP(8) Numerical source network address to bind to when making a connection. + smtp_defer_if_no_mx_address_found + 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. + smtp_line_length_limit 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. + smtp_send_xforward_command + 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. + Authentication controls smtp_sasl_auth_enable Enable per-session authentication as per RFC 2554 @@ -274,20 +288,6 @@ SMTP(8) SMTP(8) received, a warning is logged that the mail may be delivered multiple times. - smtp_defer_if_no_mx_address_found - 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. - - smtp_send_xforward_command - 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. - smtp_rset_timeout Timeout for sending the RSET command. diff --git a/postfix/man/man8/lmtp.8 b/postfix/man/man8/lmtp.8 index 75e42c57a..0b60c687b 100644 --- a/postfix/man/man8/lmtp.8 +++ b/postfix/man/man8/lmtp.8 @@ -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. diff --git a/postfix/man/man8/smtp.8 b/postfix/man/man8/smtp.8 index d830dab2b..f805b7b1b 100644 --- a/postfix/man/man8/smtp.8 +++ b/postfix/man/man8/smtp.8 @@ -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 diff --git a/postfix/src/global/mail_params.h b/postfix/src/global/mail_params.h index 0a7aa988d..8c0f6f1f6 100644 --- a/postfix/src/global/mail_params.h +++ b/postfix/src/global/mail_params.h @@ -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. diff --git a/postfix/src/global/mail_proto.h b/postfix/src/global/mail_proto.h index 96bbd1cab..144ee9acc 100644 --- a/postfix/src/global/mail_proto.h +++ b/postfix/src/global/mail_proto.h @@ -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 diff --git a/postfix/src/global/mail_version.h b/postfix/src/global/mail_version.h index 65279a01c..5cbd66697 100644 --- a/postfix/src/global/mail_version.h +++ b/postfix/src/global/mail_version.h @@ -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 diff --git a/postfix/src/lmtp/lmtp.c b/postfix/src/lmtp/lmtp.c index 8eb40b7e0..c587d030c 100644 --- a/postfix/src/lmtp/lmtp.c +++ b/postfix/src/lmtp/lmtp.c @@ -88,6 +88,11 @@ /* .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). @@ -169,6 +174,9 @@ /* .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, diff --git a/postfix/src/lmtp/lmtp.h b/postfix/src/lmtp/lmtp.h index 2f9643970..edbabd3b0 100644 --- a/postfix/src/lmtp/lmtp.h +++ b/postfix/src/lmtp/lmtp.h @@ -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 diff --git a/postfix/src/lmtp/lmtp_proto.c b/postfix/src/lmtp/lmtp_proto.c index 97b53690d..ce2694d9a 100644 --- a/postfix/src/lmtp/lmtp_proto.c +++ b/postfix/src/lmtp/lmtp_proto.c @@ -100,6 +100,7 @@ #include #include #include +#include /* Global library. */ @@ -141,48 +142,58 @@ * 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 */ diff --git a/postfix/src/pipe/pipe.c b/postfix/src/pipe/pipe.c index 92bf1e3b9..64bc15e15 100644 --- a/postfix/src/pipe/pipe.c +++ b/postfix/src/pipe/pipe.c @@ -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. diff --git a/postfix/src/smtp/Makefile.in b/postfix/src/smtp/Makefile.in index 7249c3eff..dceecd09c 100644 --- a/postfix/src/smtp/Makefile.in +++ b/postfix/src/smtp/Makefile.in @@ -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 diff --git a/postfix/src/smtp/smtp.c b/postfix/src/smtp/smtp.c index 256bab47a..f7352287c 100644 --- a/postfix/src/smtp/smtp.c +++ b/postfix/src/smtp/smtp.c @@ -109,6 +109,12 @@ /* 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. @@ -142,6 +148,11 @@ /* 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). @@ -212,17 +223,6 @@ /* 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 @@ -283,7 +283,7 @@ */ 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, diff --git a/postfix/src/smtp/smtp.h b/postfix/src/smtp/smtp.h index f591b0cc3..96a6bafcf 100644 --- a/postfix/src/smtp/smtp.h +++ b/postfix/src/smtp/smtp.h @@ -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 diff --git a/postfix/src/smtp/smtp_proto.c b/postfix/src/smtp/smtp_proto.c index cca3983a7..8a86ab4eb 100644 --- a/postfix/src/smtp/smtp_proto.c +++ b/postfix/src/smtp/smtp_proto.c @@ -104,7 +104,6 @@ #include #include #include -#include /* Application-specific. */ @@ -125,8 +124,8 @@ * 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 @@ -136,8 +135,8 @@ #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; diff --git a/postfix/src/smtpd/Makefile.in b/postfix/src/smtpd/Makefile.in index ba9c6bcbc..91fb331a4 100644 --- a/postfix/src/smtpd/Makefile.in +++ b/postfix/src/smtpd/Makefile.in @@ -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 diff --git a/postfix/src/smtpd/smtpd.c b/postfix/src/smtpd/smtpd.c index b2e3db103..fe2a7c05b 100644 --- a/postfix/src/smtpd/smtpd.c +++ b/postfix/src/smtpd/smtpd.c @@ -464,7 +464,6 @@ #include #include #include -#include /* 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); diff --git a/postfix/src/smtpd/smtpd.h b/postfix/src/smtpd/smtpd.h index 831fa72a6..26a8cf878 100644 --- a/postfix/src/smtpd/smtpd.h +++ b/postfix/src/smtpd/smtpd.h @@ -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) ? \ diff --git a/postfix/src/smtpd/smtpd_proxy.c b/postfix/src/smtpd/smtpd_proxy.c index 074e4e14c..f307b201f 100644 --- a/postfix/src/smtpd/smtpd_proxy.c +++ b/postfix/src/smtpd/smtpd_proxy.c @@ -156,7 +156,6 @@ #include #include #include -#include #include /* 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); /* diff --git a/postfix/src/util/Makefile.in b/postfix/src/util/Makefile.in index 112c7d766..440f26864 100644 --- a/postfix/src/util/Makefile.in +++ b/postfix/src/util/Makefile.in @@ -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 diff --git a/postfix/src/util/stringops.h b/postfix/src/util/stringops.h index 1f05045fc..223a8845f 100644 --- a/postfix/src/util/stringops.h +++ b/postfix/src/util/stringops.h @@ -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 index 000000000..9c6162262 --- /dev/null +++ b/postfix/src/util/uppercase.c @@ -0,0 +1,43 @@ +/*++ +/* NAME +/* uppercase 3 +/* SUMMARY +/* map lowercase characters to uppercase +/* SYNOPSIS +/* #include +/* +/* 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 + +/* 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); +}