From 196cfcd300103aea10f2c37d8475a9f93b54a73b Mon Sep 17 00:00:00 2001 From: Wietse Venema Date: Fri, 28 Nov 2003 00:00:00 -0500 Subject: [PATCH] postfix-2.0.16-20031128 --- postfix/.indent.pro | 1 + postfix/HISTORY | 33 ++ .../README_FILES/ADDRESS_VERIFICATION_README | 20 +- postfix/README_FILES/FILTER_README | 7 + postfix/README_FILES/SMTPD_PROXY_README | 48 +- postfix/README_FILES/XCLIENT_README | 185 +++++++ postfix/conf/sample-smtp.cf | 11 + postfix/conf/sample-smtpd.cf | 34 +- postfix/html/smtp.8.html | 31 +- postfix/html/smtpd.8.html | 190 ++++--- postfix/makedefs | 11 +- postfix/man/man8/smtp.8 | 8 + postfix/man/man8/smtpd.8 | 18 +- postfix/src/anvil/Makefile.in | 3 - postfix/src/bounce/Makefile.in | 3 - postfix/src/cleanup/Makefile.in | 3 - postfix/src/dns/Makefile.in | 3 - postfix/src/error/Makefile.in | 3 - postfix/src/flush/Makefile.in | 3 - postfix/src/fsstone/Makefile.in | 3 - postfix/src/global/Makefile.in | 3 - postfix/src/global/deliver_request.c | 34 +- postfix/src/global/deliver_request.h | 4 + postfix/src/global/mail_params.h | 20 +- postfix/src/global/mail_proto.h | 19 + postfix/src/global/mail_stream.c | 1 + postfix/src/global/mail_version.h | 2 +- postfix/src/global/mime_state.c | 6 +- postfix/src/global/rewrite_clnt.c | 5 +- postfix/src/global/xtext.c | 27 +- postfix/src/global/xtext.h | 3 +- postfix/src/lmtp/Makefile.in | 3 - postfix/src/local/Makefile.in | 3 - postfix/src/master/Makefile.in | 3 - postfix/src/master/master_ent.c | 4 +- postfix/src/nqmgr/Makefile.in | 3 - postfix/src/nqmgr/qmgr.h | 4 + postfix/src/nqmgr/qmgr_active.c | 5 +- postfix/src/nqmgr/qmgr_deliver.c | 4 + postfix/src/nqmgr/qmgr_message.c | 33 ++ postfix/src/pickup/Makefile.in | 3 - postfix/src/pipe/Makefile.in | 3 - postfix/src/postalias/Makefile.in | 3 - postfix/src/postcat/Makefile.in | 3 - postfix/src/postconf/Makefile.in | 3 - postfix/src/postdrop/Makefile.in | 3 - postfix/src/postfix/Makefile.in | 3 - postfix/src/postkick/Makefile.in | 3 - postfix/src/postlock/Makefile.in | 3 - postfix/src/postlog/Makefile.in | 3 - postfix/src/postmap/Makefile.in | 3 - postfix/src/postqueue/Makefile.in | 3 - postfix/src/postsuper/Makefile.in | 3 - postfix/src/proxymap/Makefile.in | 3 - postfix/src/qmgr/Makefile.in | 3 - postfix/src/qmgr/qmgr.h | 4 + postfix/src/qmgr/qmgr_active.c | 5 +- postfix/src/qmgr/qmgr_deliver.c | 4 + postfix/src/qmgr/qmgr_message.c | 33 ++ postfix/src/qmqpd/Makefile.in | 3 - postfix/src/sendmail/Makefile.in | 3 - postfix/src/sendmail/sendmail.c | 2 +- postfix/src/showq/Makefile.in | 3 - postfix/src/smtp/Makefile.in | 4 +- postfix/src/smtp/smtp.c | 12 + postfix/src/smtp/smtp.h | 1 + postfix/src/smtp/smtp_proto.c | 94 +++- postfix/src/smtpd/Makefile.in | 32 +- postfix/src/smtpd/smtpd.c | 474 ++++++++++++------ postfix/src/smtpd/smtpd.h | 60 ++- postfix/src/smtpd/smtpd_check.c | 144 +++--- postfix/src/smtpd/smtpd_peer.c | 33 +- postfix/src/smtpd/smtpd_proxy.c | 63 ++- postfix/src/smtpd/smtpd_sasl_proto.c | 2 +- postfix/src/smtpd/smtpd_state.c | 9 + postfix/src/smtpd/smtpd_xclient.c | 116 +++++ postfix/src/smtpstone/Makefile.in | 3 - postfix/src/spawn/Makefile.in | 3 - postfix/src/trivial-rewrite/Makefile.in | 3 - postfix/src/util/Makefile.in | 12 +- postfix/src/util/neuter.c | 56 +++ postfix/src/util/stringops.h | 1 + postfix/src/util/sys_defs.h | 46 +- postfix/src/verify/Makefile.in | 3 - postfix/src/virtual/Makefile.in | 3 - 85 files changed, 1497 insertions(+), 583 deletions(-) create mode 100644 postfix/README_FILES/XCLIENT_README create mode 100644 postfix/src/smtpd/smtpd_xclient.c create mode 100644 postfix/src/util/neuter.c diff --git a/postfix/.indent.pro b/postfix/.indent.pro index 64210d687..6c4de13ef 100644 --- a/postfix/.indent.pro +++ b/postfix/.indent.pro @@ -153,6 +153,7 @@ -TSMTPD_RBL_STATE -TSMTPD_STATE -TSMTPD_TOKEN +-TSMTPD_XCLIENT_ATTR -TSMTP_ADDR -TSMTP_CMD -TSMTP_RESP diff --git a/postfix/HISTORY b/postfix/HISTORY index ae0da92eb..0f63bfe14 100644 --- a/postfix/HISTORY +++ b/postfix/HISTORY @@ -8755,6 +8755,39 @@ Apologies for any names omitted. controls periodic logging of maximal connection counts or rates. The default logging interval is 10 minutes. + Feature: "make makefiles WARN=stuff..." overrides the + built-in GCC warning options that are used when "make" is + invoked from within a source subdirectory. Files: makedefs, + */Makefile.in. + +20031125 + + Feature: qmgr logs "queueid: deleted", just like postsuper, + when it removes a message from the mail queue. + + Performance: smtpd connects to the cleanup or proxy server + AFTER the first valid RCPT TO command, instead of after + the first valid MAIL FROM command. This avoid wasting + real-time proxy filter resources when mail is stopped by + the SMTP server's access blocks. File: smtpd/smtpd.c. + +20031126 + + Bugfix: "panic: mymalloc: requested length 0" when master.cf + specified an invalid host name or address. Postfix now + logs more specific information. File: master/master_ent.c. + Reported by several people. + +20031125-8 + + Feature: XCLIENT support to override the SMTP server's + client information for logging and/or access control. This + replaces the short-lived XADDR and XLOGINFO extensions. + Based on code by Victor Duchovni, with major simplifications. + Files: smtpd/{smtpd,smtpd_check,smtpd_proxy,smtpd_xclient}.c + smtp/smtp_smtp_proto.c, *qmgr/qmgr_message.c, + global/deliver_request.c. + Open problems: High: when virtual aliasing is turned off after content diff --git a/postfix/README_FILES/ADDRESS_VERIFICATION_README b/postfix/README_FILES/ADDRESS_VERIFICATION_README index 4abd3bba5..e14ec7ec4 100644 --- a/postfix/README_FILES/ADDRESS_VERIFICATION_README +++ b/postfix/README_FILES/ADDRESS_VERIFICATION_README @@ -9,7 +9,9 @@ normal mail, but are discarded instead of being deferred or bounced. The same technique may be useful to block mail for undeliverable recipients, for example on mail relay hosts that do not have a copy -of all the relayed recipient addresses. +of all the relayed recipient addresses. This prevents undeliverable +junk mail from entering the queue, so that Postfix doesn't have to +waste resources trying to send mailer-daemon messages back. With address verification turned on, normal mail will suffer only a short delay of up to 6 seconds while an address is verified for @@ -95,6 +97,8 @@ specific domains that often appear in forged email. /etc/postfix/main.cf: smtpd_sender_restrictions = hash:/etc/postfix/sender_access unverified_sender_reject_code = 550 + # Be sure to read the "Caching" section below! + address_verify_map = btree:/var/mta/verify /etc/postfix/sender_access: aol.com reject_unverified_sender @@ -120,6 +124,7 @@ To find out how sender address verification would affect your mail, specify "warn_if_reject reject_unverified_sender" so that you can see what mail would be blocked: +/etc/postfix/main.cf: smtpd_sender_restrictions = permit_mynetworks ... @@ -127,6 +132,8 @@ see what mail would be blocked: reject_unknown_sender_domain warn_if_reject reject_unverified_sender ... + # Be sure to read the "Caching" section below! + address_verify_map = btree:/var/mta/verify This is also a good way to populate your cache with address verification results before you start to actually reject mail. @@ -160,7 +167,7 @@ Caching NOTE: By default, address verification information is not stored in a persistent file. You have to specify one in main.cf (see below). Persistent storage is off by default because it may need -more disk space than is available in your root file system. +more disk space than is available in your file system. Address verification information is cached by the Postfix verify daemon. Postfix has a bunch of parameters that control the caching @@ -173,9 +180,9 @@ verification results. If you don't specify a file, all address verification information is lost after "postfix reload" or "postfix stop". -If your root file system has sufficient space, try: +If your /var file system has sufficient space, try: - address_verify_map = btree:/etc/postfix/verify + address_verify_map = btree:/var/mta/verify NOTE: Do not put this file in a file system that fills up. When the address verification table gets corrupted the world comes to @@ -197,8 +204,8 @@ accepted) and for negative results (address was rejected). Right now, no tools are provided to manage the address verification database. If the file gets too big, or if it gets corrupted, you -can manually delete the file and run "postfix reload". The new -verify daemon process will then create a new, empty, database. +can manually rename or delete the file and run "postfix reload". +The new verify daemon process will then create a new database. Controlling the routing of address verification probes ====================================================== @@ -249,6 +256,7 @@ for address verification probes and leave everything else alone: /etc/postfix/main.cf: relayhost = $mydomain address_verify_relayhost = + ... Sites behind an address translation relay might have to use a different SMTP client that sends the correct hostname information: diff --git a/postfix/README_FILES/FILTER_README b/postfix/README_FILES/FILTER_README index 6c377b0fd..b973c97cf 100644 --- a/postfix/README_FILES/FILTER_README +++ b/postfix/README_FILES/FILTER_README @@ -233,12 +233,19 @@ one would set up the service in the Postfix master.cf file: /etc/postfix/master.cf: scan unix - - n - 10 smtp + # -o smtp_send_xclient_command=yes Instead of a limit of 10 concurrent processes, use whatever process limit is feasible for your machine. Content inspection software can gobble up a lot of system resources, so you don't want to have too much of it running at the same time. +Uncomment (but keep the leading white-space) the option setting: +"smtp_send_xclient_command=yes", if you would like the scan transport +to forward the original client name and IP address to the backend smtpd +so that mail transaction logs show the real client name IP address. +See sample-smtp.cf and smtp(8). + The content filter can be set up with the Postfix spawn service, which is the Postfix equivalent of inetd. For example, to instantiate up to 10 content filtering processes on demand: diff --git a/postfix/README_FILES/SMTPD_PROXY_README b/postfix/README_FILES/SMTPD_PROXY_README index d39e64cfc..c6f63acbf 100644 --- a/postfix/README_FILES/SMTPD_PROXY_README +++ b/postfix/README_FILES/SMTPD_PROXY_README @@ -68,7 +68,7 @@ How Postfix talks to the before-queue content filter The before-filter Postfix SMTP server connects to the content filter, delivers one message, and disconnects. While sending mail into the content filter, Postfix speaks ESMTP but uses no command -pipelining. Postfix generates its own EHLO, XLOGINFO (for logging +pipelining. Postfix generates its own EHLO, XCLIENT (for logging the remote client IP address instead of localhost[127.0.0.1]), DATA and QUIT commands, and forwards unmodified copies of all the MAIL FROM and RCPT TO commands that the before-filter Postfix SMTP server @@ -85,6 +85,9 @@ the connection with the after-filter Postfix SMTP server without completing the SMTP conversation with the after-filter Postfix SMTP server. +More details on the postfix-to-proxy interaction is at the end of +this document, in the section titled "Transparency". + Configuration parameters ======================== @@ -119,7 +122,7 @@ for testing, of course. smtp inet n - n - - smtpd -o smtpd_proxy_filter=26 :26 inet n - n - - smtpd - -o smtpd_authorized_xloginfo_clients=127.0.0.0/8 + -o smtpd_authorized_xclient_hosts=127.0.0.0/8 -o smtpd_client_restrictions= -o smtpd_helo_restrictions= -o smtpd_sender_restrictions= @@ -132,10 +135,10 @@ Note: do not specify spaces around the "=" or "," characters. The ":26" causes Postfix to listen on the localhost address only. DO NOT expose the secondary SMTP server to the Internet :-) -The smtpd_authorized_xloginfo_clients parameter allows the before -filter SMTP server to pass the remote SMTP client name and address -to the after-filter SMTP server, so that the after-filter Postfix -daemons log the remote client name and address instead of logging +The smtpd_authorized_xclient_hosts parameter allows the before +filter SMTP server to forward remote SMTP client information to +the after-filter SMTP server, so that the after-filter Postfix +daemons log the remote SMTP client information instead of logging localhost[127.0.0.1]. The other parameter settings avoid duplication of effort that is @@ -149,3 +152,36 @@ This configuration is sufficient for stress testing. Other suggestions for test configurations: use the Postfix smtp-sink command as the proxy, or something as basic as netcat. + +Transparency +============ + +The before-filter Postfix SMTP server forwards the MAIL FROM, RCPT +TO and DATA commands that it has approved, but it does not forward +other commands such as TLS or SASL commands. It can therefore not +be transparent. + +The real-time content filter, on the other hand, has to be transparent. +In order to support non-transparent real-time content filters, +Postfix would have to reconcile the before-filter Postfix ESMTP +feature set with the feature set that Postfix receives from the +real-time content filter. + +- When a future Postfix version supports DSN, but the content filter +does not announce DSN support in the EHLO reply, then the before-filter +SMTP server would have to either 1) suppress the DSN feature in +its EHLO announcement, or 2) duplicate all the work that needs to +be done when delivering DSN-aware mail to a non-DSN destination. + +- When the content filter does not announce 8BITMIME support in +the EHLO reply, then the before-filter SMTP server would have to +either 1) suppress the 8BITMIME feature in its EHLO announcement, +or 2) convert the content to quoted-printable before giving it to +the content filter. + +- Performance: when Postfix has to suppress elements from the +before-filter EHLO reply because they are incompatible with the +real-time content filter, then Postfix has to connect to the content +filter as soon as the client sends a valid EHLO command. This wastes +a lot of resources when all the MAIL FROM or RCPT TO commands are +rejected. diff --git a/postfix/README_FILES/XCLIENT_README b/postfix/README_FILES/XCLIENT_README new file mode 100644 index 000000000..3624bc89a --- /dev/null +++ b/postfix/README_FILES/XCLIENT_README @@ -0,0 +1,185 @@ +Purpose of the XCLIENT extension to SMTP +======================================== + +The XCLIENT command targets problems in the following areas: + +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 SMTP client test +program needs the ability to override the SMTP server's idea of +the SMTP client hostname, network address, and other information. + +2 - Logging after content filter. With Internet->MTA1->filter->MTA2 +style content filter applications, remote client information is +lost when MTA1 gives the mail to the content filter. This complicates +the interpretation of the audit trail. In order maintain audit +trail continuity, MTA1 needs the ability to forward client information +through the content filter to MTA2. + +3 - Post-filter access control and logging. With Internet->filter->MTA +style content filter applications, the content filter can be greatly +simplified if it can delegate all decisions concerning mail relay +and other access control to the MTA. This requires that the filter +can forward client information to the MTA for access control +purposes. + +The preceding suggests that there is a need for two modes of +operation: + + - Operation mode 1: override the SMTP server's idea of SMTP + client information for access control and audit trail purposes. + Attributes that one may want to override are: + + client network address + client hostname + hostname lookup failure type (permanent or temporary) + client protocol (e.g., SMTP or ESMTP) + + - Operation mode 2: forward remote client information for audit + trail purposes only. Examples of attributes are: + + client network address + client hostname + client protocol (e.g., SMTP or ESMTP) + client SMTP HELO parameter + +General XCLIENT command syntax +============================== + +The XCLIENT command maintains one set of attributes with surrogate +client information. The general XCLIENT command syntax is described +below. Upper case and quoted strings specify terminals, lowercase +strings specify meta terminals, SP is whitespace, and descriptive +text is in {}. Although shown below in upper case, command and +attribute names are in fact case insensitive. + + xclient-command = XCLIENT *( SP argument ) + + argument = ( request | attribute ) + + request = ( RST | ACL | LOG ) + + attribute = name"="value + + name = ( CLIENT_NAME | CLIENT_ADDR | CLIENT_CODE | PROTOCOL | HELO_NAME ) + + value = ( { empty } | xtext ) + + xtext = { attribute value encoded as per RFC 1891 } + +The XCLIENT command is typically sent immediately before or after +the EHLO command, may be pipelined after the server announces ESMTP +pipelining support, and must not be used in the middle of an SMTP +transaction (i.e. between MAIL and DOT). + +The server reply codes are as follows: + + Code | Meaning + -----|------------ + 250 | success + 501 | command syntax error + 502 | unrecognized request name + 503 | command out of order (name=value without prior ACL or LOG request) + 421 | unable to proceed + +The server must report success in case of an unrecognized attribute +name, although it may log a warning. + +Specific XCLIENT usage scenarios +================================ + +This section discusses the semantics of XCLIENT requests. Specific +syntax information is given in the next section. + +The RST request resets all XCLIENT attributes and disables any +override of access control or audit trail attributes. Example: + + XCLIENT RST + +The ACL request resets all XCLIENT attributes and must be specified +before sending surrogate attributes for access control and audit +trail purposes. Attributes that are not explicitly specified will +default to their actual value. Example: + + XCLIENT ACL CLIENT_NAME=spike.porcupine.org + XCLIENT CLIENT_ADDR=168.100.189.2 + +This overrides only the client hostname and network address, but +none of the other client attributes. + +The LOG request resets all XCLIENT attributes and must be specified +before sending surrogate attributes for audit trail purposes. +Attributes that are not explicitly specified will default to the +unknown value. Example: + + XCLIENT LOG CLIENT_NAME=spike.porcupine.org CLIENT_ADDR=168.100.189.2 + XCLIENT HELO_NAME=spike.porcupine.org PROTOCOL=ESMTP + +This overrides all client attributes that are defined in this +document, leaving none at their default unknown value. + +Note 1: it is an error to specify name=value pairs without prior +ACL or LOG request. + +Note 2: after an ACL or LOG request, attributes specified with +successive XCLIENT commands accumulate until the next RST, ACL or +LOG request. + +Note 3: if one XCLIENT command specifies multiple requests (e.g., +both ACL and LOG), only the last request takes effect. + +XCLIENT attribute value details +=============================== + +Attribute values are encoded as RFC 1891 xtext strings. To explicitly +specify that an attribute value is unknown, the value must be empty; +the client is not allowed to send its own internal representation +for unknown information. + +CLIENT_CODE specifies CLIENT_NAME hostname lookup status information. +Values are OK (success), TEMP (temporary lookup failure) or PERM +(permanent lookup failure). When CLIENT_CODE is set to any value +other than OK, the CLIENT_NAME attribute is set to the unknown +value. + +CLIENT_NAME should specify a syntactically valid domain name and +not a numerical address. When a null client name is specified +(i.e. the client name is unknown), the CLIENT_CODE attribute is +set to PERM. When a valid domain name is specified, CLIENT_CODE is +set to OK. The server may process a syntactically invalid domain +name as if it were unknown. + +CLIENT_ADDR must specify a numerical network address without []. + +PROTOCOL is a string of up to 64 printable characters. + +HELO_NAME should be a syntactically valid domain name. + +Note 4: syntactically valid CLIENT_NAME and HELO_NAME attributes +can be up to 255 characters long. The client must not send XCLIENT +commands that exceed the 512 character limit of SMTP commands. + +Note 5: attribute values may end up in Received: or other message +headers. The server may substitute any characters that are special +according to RFC 822 or RFC 2822. + +Security +======== + +The XCLIENT command changes audit trails and changes client access +permissions. For these reasons, use of the XCLIENT command must be +restricted to authorized clients only. + +The examples in this document assume that XCLIENT does 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. Attributes from one remote client should not affect the +delivery of mail from a different remote client. In order to +prevent such information leakage, use the XCLIENT RST, ACL or LOG +requests as appropriate. diff --git a/postfix/conf/sample-smtp.cf b/postfix/conf/sample-smtp.cf index ca85a151a..0d6e9cf11 100644 --- a/postfix/conf/sample-smtp.cf +++ b/postfix/conf/sample-smtp.cf @@ -76,6 +76,17 @@ smtp_never_send_ehlo = no # smtp_defer_if_no_mx_address_found = no +# The smtp_send_xclient_command parameter controls whether the Postfix +# SMTP client will send an XCLIENT command to the SMTP server, when +# the ESMTP HELO response of the remote host indicates XCLIENT 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 SMTP server. Before you change the value to yes, it is best +# to make sure your content filter supports this command. +# +smtp_send_xclient_command = no + # The smtp_line_length_limit parameter controls the length of # message header and body lines that Postfix will send via SMTP. # Lines that are longer are broken by inserting . diff --git a/postfix/conf/sample-smtpd.cf b/postfix/conf/sample-smtpd.cf index 8f93a3631..077076502 100644 --- a/postfix/conf/sample-smtpd.cf +++ b/postfix/conf/sample-smtpd.cf @@ -154,13 +154,14 @@ smtpd_client_connection_limit_exceptions = $mynetworks # #disable_vrfy_command = no -# The smtpd_authorized_xaddr_clients parameter specifies what clients -# are allowed to specify the SMTP "XADDR client-address client-name" -# command. This command changes Postfix's idea of the client hostname -# and IP address for logging and for access control. Typical use is -# for SMTPD access testing. +# The smtpd_authorized_xclient_hosts parameter specifies what clients +# are allowed to specify the XCLIENT extension to SMTP. # -# By default, no clients are allowed to specify XADDR. +# This command overrides SMTP client information that is used for +# logging or access control. Typical use is for SMTP-based content +# filters or for SMTP server access rule testing. +# +# By default, no clients are allowed to specify XCLIENT. # # Specify an explicit list of network/netmask patterns, where the # mask specifies the number of bits in the network part of a host @@ -171,26 +172,7 @@ smtpd_client_connection_limit_exceptions = $mynetworks # of listing the patterns here. Specify type:table for table-based lookups # (the value on the table right-hand side is not used). # -smtpd_authorized_xaddr_clients = - -# The smtpd_authorized_xloginfo_clients parameter specifies what -# clients are allowed to specify the SMTP "XLOGINFO client-address -# client-name" command. This command changes Postfix's idea of the -# client hostname and IP address for logging but not for access -# control. Typical use is for SMTP-based content filters. -# -# By default, no clients are allowed to specify XLOGINFO. -# -# Specify an explicit list of network/netmask patterns, where the -# mask specifies the number of bits in the network part of a host -# address. You can also specify hostnames or .domain names (the -# initial dot causes the domain to match any name below it). -# -# You can also specify the absolute pathname of a pattern file instead -# of listing the patterns here. Specify type:table for table-based lookups -# (the value on the table right-hand side is not used). -# -smtpd_authorized_xloginfo_clients = +smtpd_authorized_xclient_hosts = # The smtpd_authorized_verp_clients parameter specifies what clients # are allowed to specify the SMTP XVERP command. This command requests diff --git a/postfix/html/smtp.8.html b/postfix/html/smtp.8.html index f9fe0ab72..eb8f02874 100644 --- a/postfix/html/smtp.8.html +++ b/postfix/html/smtp.8.html @@ -249,16 +249,20 @@ SMTP(8) SMTP(8) Timeout for sending the HELO command, and for receiving the server response. + smtp_xclient_timeout + Timeout for sending the XCLIENT command, and for + receiving the server response. + smtp_mail_timeout - Timeout for sending the MAIL FROM command, and for + Timeout for sending the MAIL FROM command, and for receiving the server response. smtp_rcpt_timeout - Timeout for sending the RCPT TO command, and for + Timeout for sending the RCPT TO command, and for receiving the server response. smtp_data_init_timeout - Timeout for sending the DATA command, and for + Timeout for sending the DATA command, and for receiving the server response. smtp_data_xfer_timeout @@ -266,22 +270,29 @@ SMTP(8) SMTP(8) smtp_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. smtp_defer_if_no_mx_address_found - If no, bounce mail when no MX host resolves to an + 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 + 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_xclient_command + If the SMTP server announces XCLIENT 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. smtp_quit_timeout - Timeout for sending the QUIT command, and for + Timeout for sending the QUIT command, and for receiving the server response. SEE ALSO @@ -291,7 +302,7 @@ SMTP(8) SMTP(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/smtpd.8.html b/postfix/html/smtpd.8.html index da940a734..9aefc27f1 100644 --- a/postfix/html/smtpd.8.html +++ b/postfix/html/smtpd.8.html @@ -170,42 +170,32 @@ SMTPD(8) SMTPD(8) Hostnames, domain names and/or addresses of clients that are authorized to use the XVERP extension. - smtpd_authorized_xaddr_clients + smtpd_authorized_xclient_hosts Hostnames, domain names and/or addresses of clients - that are authorized to use the "XADDR client- - address client-name" command. This changes Post- - fix's idea of the SMTP client IP address and host- - name for access control and for logging purposes. - - smtpd_authorized_xloginfo_clients - Hostnames, domain names and/or addresses of clients - that are authorized to use the "XLOGINFO client- - address client-name" command. This changes the - client name and address that are used for logging, - without affecting the client IP address and host- - name that are used for access control. XLOGINFO is - typically used to propagate remote client informa- - tion through an SMTP-based content filter to the - after-filter SMTP server. + that are authorized to use the XCLIENT command. + This command changes client information for access + control and/or logging purposes, with the exception + of the smtpd_authorized_xclient_hosts access con- + trol itself. debug_peer_level - Increment in verbose logging level when a remote + Increment in verbose logging level when a remote host matches a pattern in the debug_peer_list parameter. debug_peer_list - List of domain or network patterns. When a remote - host matches a pattern, increase the verbose log- - ging level by the amount specified in the + List of domain or network patterns. When a remote + host matches a pattern, increase the verbose log- + ging level by the amount specified in the debug_peer_level parameter. default_verp_delimiters The default VERP delimiter characters that are used - when the XVERP command is specified without + when the XVERP command is specified without explicit delimiters. error_notice_recipient - Recipient of protocol/policy/resource/software + Recipient of protocol/policy/resource/software error notices. hopcount_limit @@ -214,18 +204,18 @@ SMTPD(8) SMTPD(8) notify_classes List of error classes. Of special interest are: - policy When a client violates any policy, mail a + policy When a client violates any policy, mail a transcript of the entire SMTP session to the postmaster. protocol - When a client violates the SMTP protocol or + When a client violates the SMTP protocol or issues an unimplemented command, mail a transcript of the entire SMTP session to the postmaster. smtpd_banner - Text that follows the 220 status code in the SMTP + Text that follows the 220 status code in the SMTP greeting banner. smtpd_expansion_filter @@ -233,57 +223,57 @@ SMTPD(8) SMTPD(8) expansion of rbl template responses and other text. smtpd_recipient_limit - Restrict the number of recipients that the SMTP + Restrict the number of recipients that the SMTP server accepts per message delivery. smtpd_timeout - Limit the time to send a server response and to + Limit the time to send a server response and to receive a client request. soft_bounce - Change hard (5xx) reject responses into soft (4xx) - reject responses. This can be useful for testing + Change hard (5xx) reject responses into soft (4xx) + reject responses. This can be useful for testing purposes. verp_delimiter_filter - The characters that Postfix accepts as VERP delim- + The characters that Postfix accepts as VERP delim- iter characters. Known versus unknown recipients show_user_unknown_table_name - Whether or not to reveal the table name in the - "User unknown" responses. The extra detail makes - trouble shooting easier but also reveals informa- + Whether or not to reveal the table name in the + "User unknown" responses. The extra detail makes + trouble shooting easier but also reveals informa- tion that is nobody elses business. unknown_local_recipient_reject_code The response code when a client specifies a recipi- - ent whose domain matches $mydestination or + ent whose domain matches $mydestination or $inet_interfaces, while $local_recipient_maps is - non-empty and does not list the recipient address + non-empty and does not list the recipient address or address local-part. unknown_relay_recipient_reject_code The response code when a client specifies a recipi- ent whose domain matches $relay_domains, while - $relay_recipient_maps is non-empty and does not + $relay_recipient_maps is non-empty and does not list the recipient address. unknown_virtual_alias_reject_code The response code when a client specifies a recipi- - ent whose domain matches $virtual_alias_domains, - while the recipient is not listed in $vir- + ent whose domain matches $virtual_alias_domains, + while the recipient is not listed in $vir- tual_alias_maps. unknown_virtual_mailbox_reject_code The response code when a client specifies a recipi- - ent whose domain matches $virtual_mailbox_domains, + ent whose domain matches $virtual_mailbox_domains, while the recipient is not listed in $virtual_mail- box_maps. Resource controls line_length_limit - Limit the amount of memory in bytes used for the + Limit the amount of memory in bytes used for the handling of partial input lines. message_size_limit @@ -291,9 +281,9 @@ SMTPD(8) SMTPD(8) ing on-disk storage for envelope information. queue_minfree - Minimal amount of free space in bytes in the queue - file system for the SMTP server to accept any mail - at all (default: twice the message_size_limit + Minimal amount of free space in bytes in the queue + file system for the SMTP server to accept any mail + at all (default: twice the message_size_limit value). smtpd_history_flush_threshold @@ -303,21 +293,21 @@ SMTPD(8) SMTPD(8) smtpd_client_connection_count_limit The maximal number of simultaneous connections that - any client is allowed to make to this service. - When a client exceeds the limit, the SMTP server + any client is allowed to make to this service. + When a client exceeds the limit, the SMTP server logs a warning with the client name/address and the service name as configured in master.cf. smtpd_client_connection_rate_limit - The maximal number of connections per unit time + The maximal number of connections per unit time (specified with connection_rate_time_unit) that any - client is allowed to make to this service. When a - client exceeds the limit, the SMTP server logs a - warning with the client name/address and the ser- + client is allowed to make to this service. When a + client exceeds the limit, the SMTP server logs a + warning with the client name/address and the ser- vice name as configured in master.cf. smtpd_client_connection_limit_exceptions - Hostnames, .domain names and/or network address + Hostnames, .domain names and/or network address blocks of clients that are excluded from connection count or rate limits. @@ -328,17 +318,17 @@ SMTPD(8) SMTPD(8) smtpd_soft_error_limit When an SMTP client has made this number of errors, - wait error_count seconds before responding to any + wait error_count seconds before responding to any client request. smtpd_hard_error_limit - Disconnect after a client has made this number of + Disconnect after a client has made this number of errors. smtpd_junk_command_limit Limit the number of times a client can issue a junk - command such as NOOP, VRFY, ETRN or RSET in one - SMTP session before it is penalized with tarpit + command such as NOOP, VRFY, ETRN or RSET in one + SMTP session before it is penalized with tarpit delays. Delegated policy @@ -347,17 +337,17 @@ SMTPD(8) SMTPD(8) receiving from a delegated SMTPD policy server. smtpd_policy_service_max_idle - Time after which an unused SMTPD policy service + Time after which an unused SMTPD policy service connection is closed. smtpd_policy_service_timeout - Time after which an active SMTPD policy service + Time after which an active SMTPD policy service connection is closed. UCE control restrictions parent_domain_matches_subdomains - List of Postfix features that use domain.tld pat- - terns to match sub.domain.tld (as opposed to + List of Postfix features that use domain.tld pat- + terns to match sub.domain.tld (as opposed to requiring .domain.tld patterns). smtpd_client_restrictions @@ -365,19 +355,19 @@ SMTPD(8) SMTPD(8) tem. smtpd_helo_required - Require that clients introduce themselves at the + Require that clients introduce themselves at the beginning of an SMTP session. smtpd_helo_restrictions - Restrict what client hostnames are allowed in HELO + Restrict what client hostnames are allowed in HELO and EHLO commands. smtpd_sender_restrictions - Restrict what sender addresses are allowed in MAIL + Restrict what sender addresses are allowed in MAIL FROM commands. smtpd_recipient_restrictions - Restrict what recipient addresses are allowed in + Restrict what recipient addresses are allowed in RCPT TO commands. smtpd_etrn_restrictions @@ -385,96 +375,96 @@ SMTPD(8) SMTPD(8) mands, and what clients may issue ETRN commands. smtpd_data_restrictions - Restrictions on the DATA command. Currently, the - only restriction that makes sense here is + Restrictions on the DATA command. Currently, the + only restriction that makes sense here is reject_unauth_pipelining. allow_untrusted_routing - Allow untrusted clients to specify addresses with - sender-specified routing. Enabling this opens up - nasty relay loopholes involving trusted backup MX + Allow untrusted clients to specify addresses with + sender-specified routing. Enabling this opens up + nasty relay loopholes involving trusted backup MX hosts. smtpd_restriction_classes - Declares the name of zero or more parameters that - contain a list of UCE restrictions. The names of - these parameters can then be used instead of the + Declares the name of zero or more parameters that + contain a list of UCE restrictions. The names of + these parameters can then be used instead of the restriction lists that they represent. smtpd_null_access_lookup_key - The lookup key to be used in SMTPD access tables - instead of the null sender address. A null sender + The lookup key to be used in SMTPD access tables + instead of the null sender address. A null sender address cannot be looked up. maps_rbl_domains (deprecated) - List of DNS domains that publish the addresses of + List of DNS domains that publish the addresses of blacklisted hosts. This is used with the deprecated reject_maps_rbl restriction. permit_mx_backup_networks - Only domains whose primary MX hosts match the - listed networks are eligible for the per- + Only domains whose primary MX hosts match the + listed networks are eligible for the per- mit_mx_backup feature. relay_domains - Restrict what domains this mail system will relay - mail to. The domains are routed to the delivery + Restrict what domains this mail system will relay + mail to. The domains are routed to the delivery agent specified with the relay_transport setting. Sender/recipient address verification Address verification is implemented by sending probe email - messages that are not actually delivered, and is enabled - via the reject_unverified_{sender,recipient} access - restriction. The status of verification probes is main- + messages that are not actually delivered, and is enabled + via the reject_unverified_{sender,recipient} access + restriction. The status of verification probes is main- tained by the address verification service. address_verify_poll_count - How many times to query the address verification - service for completion of an address verification - request. Specify 1 to implement a simple form of - greylisting, that is, always defer the request for + How many times to query the address verification + service for completion of an address verification + request. Specify 1 to implement a simple form of + greylisting, that is, always defer the request for a new sender or recipient address. address_verify_poll_delay - Time to wait after querying the address verifica- + Time to wait after querying the address verifica- tion service for completion of an address verifica- tion request. UCE control responses access_map_reject_code - Response code when a client violates an access + Response code when a client violates an access database restriction. default_rbl_reply Default template reply when a request is RBL black- - listed. This template is used by the reject_rbl_* - and reject_rhsbl_* restrictions. See also: + listed. This template is used by the reject_rbl_* + and reject_rhsbl_* restrictions. See also: rbl_reply_maps and smtpd_expansion_filter. defer_code - Response code when a client request is rejected by + Response code when a client request is rejected by the defer restriction. invalid_hostname_reject_code - Response code when a client violates the + Response code when a client violates the reject_invalid_hostname restriction. maps_rbl_reject_code Response code when a request is RBL blacklisted. multi_recipient_bounce_reject_code - Response code when a multi-recipient bounce is + Response code when a multi-recipient bounce is blocked. rbl_reply_maps - Table with template responses for RBL blacklisted - requests, indexed by RBL domain name. These tem- + Table with template responses for RBL blacklisted + requests, indexed by RBL domain name. These tem- plates are used by the reject_rbl_* and - reject_rhsbl_* restrictions. See also: + reject_rhsbl_* restrictions. See also: default_rbl_reply and smtpd_expansion_filter. reject_code - Response code when the client matches a reject + Response code when the client matches a reject restriction. relay_domains_reject_code @@ -482,7 +472,7 @@ SMTPD(8) SMTPD(8) mail relay policy. unknown_address_reject_code - Response code when a client violates the + Response code when a client violates the reject_unknown_address restriction. unknown_client_reject_code @@ -491,15 +481,15 @@ SMTPD(8) SMTPD(8) tion. unknown_hostname_reject_code - Response code when a client violates the + Response code when a client violates the reject_unknown_hostname restriction. unverified_sender_reject_code - Response code when a sender address is known to be + Response code when a sender address is known to be undeliverable. unverified_recipient_reject_code - Response code when a recipient address is known to + Response code when a recipient address is known to be undeliverable. SEE ALSO @@ -510,7 +500,7 @@ SMTPD(8) SMTPD(8) verify(8) address verification service 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/makedefs b/postfix/makedefs index 0827f00e3..1d0d2f428 100644 --- a/postfix/makedefs +++ b/postfix/makedefs @@ -6,7 +6,7 @@ # SUMMARY # makefile configuration utility # SYNOPSIS -# \fBmakedefs\fR +# \fBmake makefiles \fIname=value...\fR # DESCRIPTION # The \fBmakedefs\fR command identifies the program compilation # environment, and emits macro definitions on the standard output @@ -29,6 +29,9 @@ # .IP \fBOPT=\fIoptimization_level\fR # Specifies a non-default optimization level. The default is \fB-O\fR. # Specify \fBOPT=\fR to turn off optimization. +# .IP \fBWARN=\fIwarning_flags\fR +# Specifies non-default gcc compiler warning options for use when +# "make" is invoked in a source subdirectory only. # LICENSE # .ad # .fi @@ -320,7 +323,10 @@ case "$CC" in *) : ${OPT='-O'};; esac -: ${CC='gcc $(WARN)'} ${OPT='-O'} ${DEBUG='-g'} ${AWK=awk} +: ${CC='gcc $(WARN)'} ${OPT='-O'} ${DEBUG='-g'} ${AWK=awk} \ +${WARN='-W -Wformat -Wimplicit -Wmissing-prototypes \ + -Wparentheses -Wstrict-prototypes -Wswitch -Wuninitialized \ + -Wunused'} export SYSTYPE AR ARFL RANLIB SYSLIBS CC OPT DEBUG AWK OPTS @@ -336,4 +342,5 @@ DEBUG = $DEBUG AWK = $AWK STRCASE = $STRCASE EXPORT = AUXLIBS='$AUXLIBS' CCARGS='$CCARGS' OPT='$OPT' DEBUG='$DEBUG' +WARN = $WARN EOF diff --git a/postfix/man/man8/smtp.8 b/postfix/man/man8/smtp.8 index 4d5495fcf..c585f4945 100644 --- a/postfix/man/man8/smtp.8 +++ b/postfix/man/man8/smtp.8 @@ -210,6 +210,9 @@ exchanger list. .IP \fBsmtp_helo_timeout\fR Timeout for sending the \fBHELO\fR command, and for receiving the server response. +.IP \fBsmtp_xclient_timeout\fR +Timeout for sending the \fBXCLIENT\fR command, and for +receiving the server response. .IP \fBsmtp_mail_timeout\fR Timeout for sending the \fBMAIL FROM\fR command, and for receiving the server response. @@ -231,6 +234,11 @@ If no, bounce mail when no MX host resolves to an address than the local MTA). If yes, keep trying until a suitable MX host resolves or until the mail is too old. +.IP \fBsmtp_send_xclient_command\fR +If the SMTP server announces XCLIENT 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/man/man8/smtpd.8 b/postfix/man/man8/smtpd.8 index a93f533ba..f4466b7b6 100644 --- a/postfix/man/man8/smtpd.8 +++ b/postfix/man/man8/smtpd.8 @@ -157,20 +157,12 @@ anti-spoofing restriction. .IP \fBsmtpd_authorized_verp_clients\fR Hostnames, domain names and/or addresses of clients that are authorized to use the XVERP extension. -.IP \fBsmtpd_authorized_xaddr_clients\fR +.IP \fBsmtpd_authorized_xclient_hosts\fR Hostnames, domain names and/or addresses of clients that are -authorized to use the "XADDR client-address client-name" command. -This changes Postfix's -idea of the SMTP client IP address and hostname for access -control and for logging purposes. -.IP \fBsmtpd_authorized_xloginfo_clients\fR -Hostnames, domain names and/or addresses of clients that are -authorized to use the "XLOGINFO client-address client-name" command. -This changes the client -name and address that are used for logging, without affecting the -client IP address and hostname that are used for access control. -XLOGINFO is typically used to propagate remote client information -through an SMTP-based content filter to the after-filter SMTP server. +authorized to use the XCLIENT command. This command changes +client information for access control and/or logging purposes, +with the exception of the +\fBsmtpd_authorized_xclient_hosts\fR access control itself. .IP \fBdebug_peer_level\fR Increment in verbose logging level when a remote host matches a pattern in the \fBdebug_peer_list\fR parameter. diff --git a/postfix/src/anvil/Makefile.in b/postfix/src/anvil/Makefile.in index 7f4ea06b1..189f14ec0 100644 --- a/postfix/src/anvil/Makefile.in +++ b/postfix/src/anvil/Makefile.in @@ -3,9 +3,6 @@ SRCS = anvil.c OBJS = anvil.o HDRS = TESTSRC = -WARN = -W -Wformat -Wimplicit -Wmissing-prototypes \ - -Wparentheses -Wstrict-prototypes -Wswitch -Wuninitialized \ - -Wunused DEFS = -I. -I$(INC_DIR) -D$(SYSTYPE) CFLAGS = $(DEBUG) $(OPT) $(DEFS) TESTPROG= diff --git a/postfix/src/bounce/Makefile.in b/postfix/src/bounce/Makefile.in index abd9067b9..6a3f352b3 100644 --- a/postfix/src/bounce/Makefile.in +++ b/postfix/src/bounce/Makefile.in @@ -7,9 +7,6 @@ OBJS = bounce.o bounce_append_service.o bounce_notify_service.o \ bounce_one_service.o bounce_warn_service.o bounce_trace_service.o HDRS = TESTSRC = -WARN = -W -Wformat -Wimplicit -Wmissing-prototypes \ - -Wparentheses -Wstrict-prototypes -Wswitch -Wuninitialized \ - -Wunused DEFS = -I. -I$(INC_DIR) -D$(SYSTYPE) CFLAGS = $(DEBUG) $(OPT) $(DEFS) TESTPROG= diff --git a/postfix/src/cleanup/Makefile.in b/postfix/src/cleanup/Makefile.in index 8eb9a8807..c390e5ae0 100644 --- a/postfix/src/cleanup/Makefile.in +++ b/postfix/src/cleanup/Makefile.in @@ -11,9 +11,6 @@ OBJS = cleanup.o cleanup_out.o cleanup_envelope.o cleanup_message.o \ cleanup_addr.o HDRS = TESTSRC = -WARN = -W -Wformat -Wimplicit -Wmissing-prototypes \ - -Wparentheses -Wstrict-prototypes -Wswitch -Wuninitialized \ - -Wunused DEFS = -I. -I$(INC_DIR) -D$(SYSTYPE) CFLAGS = $(DEBUG) $(OPT) $(DEFS) TESTPROG= cleanup_masquerade diff --git a/postfix/src/dns/Makefile.in b/postfix/src/dns/Makefile.in index 9948582e7..c96f67256 100644 --- a/postfix/src/dns/Makefile.in +++ b/postfix/src/dns/Makefile.in @@ -3,9 +3,6 @@ SRCS = dns_lookup.c dns_rr.c dns_strerror.c dns_strtype.c OBJS = dns_lookup.o dns_rr.o dns_strerror.o dns_strtype.o HDRS = dns.h TESTSRC = test_dns_lookup.c test_alias_token.c -WARN = -W -Wformat -Wimplicit -Wmissing-prototypes \ - -Wparentheses -Wstrict-prototypes -Wswitch -Wuninitialized \ - -Wunused DEFS = -I. -I$(INC_DIR) -D$(SYSTYPE) CFLAGS = $(DEBUG) $(OPT) $(DEFS) INCL = diff --git a/postfix/src/error/Makefile.in b/postfix/src/error/Makefile.in index 4ba674db5..a6559a48b 100644 --- a/postfix/src/error/Makefile.in +++ b/postfix/src/error/Makefile.in @@ -3,9 +3,6 @@ SRCS = error.c OBJS = error.o HDRS = TESTSRC = -WARN = -W -Wformat -Wimplicit -Wmissing-prototypes \ - -Wparentheses -Wstrict-prototypes -Wswitch -Wuninitialized \ - -Wunused DEFS = -I. -I$(INC_DIR) -D$(SYSTYPE) CFLAGS = $(DEBUG) $(OPT) $(DEFS) TESTPROG= diff --git a/postfix/src/flush/Makefile.in b/postfix/src/flush/Makefile.in index 266254d91..4708bb12c 100644 --- a/postfix/src/flush/Makefile.in +++ b/postfix/src/flush/Makefile.in @@ -3,9 +3,6 @@ SRCS = flush.c OBJS = flush.o HDRS = TESTSRC = -WARN = -W -Wformat -Wimplicit -Wmissing-prototypes \ - -Wparentheses -Wstrict-prototypes -Wswitch -Wuninitialized \ - -Wunused DEFS = -I. -I$(INC_DIR) -D$(SYSTYPE) CFLAGS = $(DEBUG) $(OPT) $(DEFS) TESTPROG= diff --git a/postfix/src/fsstone/Makefile.in b/postfix/src/fsstone/Makefile.in index e5f76b76f..d22b4bc55 100644 --- a/postfix/src/fsstone/Makefile.in +++ b/postfix/src/fsstone/Makefile.in @@ -3,9 +3,6 @@ SRCS = fsstone.c OBJS = fsstone.o HDRS = TESTSRC = -WARN = -W -Wformat -Wimplicit -Wmissing-prototypes \ - -Wparentheses -Wstrict-prototypes -Wswitch -Wuninitialized \ - -Wunused DEFS = -I. -I$(INC_DIR) -D$(SYSTYPE) CFLAGS = $(DEBUG) $(OPT) $(DEFS) TESTPROG= diff --git a/postfix/src/global/Makefile.in b/postfix/src/global/Makefile.in index c6da6f946..dc95fda33 100644 --- a/postfix/src/global/Makefile.in +++ b/postfix/src/global/Makefile.in @@ -68,9 +68,6 @@ HDRS = been_here.h bounce.h canon_addr.h cleanup_user.h clnt_stream.h \ trace.h log_adhoc.h verify.h dict_proxy.h mail_dict.h qmgr_user.h \ input_transp.h anvil_clnt.h TESTSRC = rec2stream.c stream2rec.c recdump.c -WARN = -W -Wformat -Wimplicit -Wmissing-prototypes \ - -Wparentheses -Wstrict-prototypes -Wswitch -Wuninitialized \ - -Wunused DEFS = -I. -I$(INC_DIR) -D$(SYSTYPE) CFLAGS = $(DEBUG) $(OPT) $(DEFS) INCL = diff --git a/postfix/src/global/deliver_request.c b/postfix/src/global/deliver_request.c index 08a95f326..1ad6defb2 100644 --- a/postfix/src/global/deliver_request.c +++ b/postfix/src/global/deliver_request.c @@ -22,6 +22,10 @@ /* long arrival_time; /* RECIPIENT_LIST rcpt_list; /* char *hop_status; +/* char *client_name; +/* char *client_addr; +/* char *client_proto; +/* char *client_helo; /* .in -5 /* } DELIVER_REQUEST; /* @@ -175,6 +179,10 @@ static int deliver_request_get(VSTREAM *stream, DELIVER_REQUEST *request) static VSTRING *address; static VSTRING *errors_to; static VSTRING *return_receipt; + static VSTRING *client_name; + static VSTRING *client_addr; + static VSTRING *client_proto; + static VSTRING *client_helo; long offset; /* @@ -191,6 +199,10 @@ static int deliver_request_get(VSTREAM *stream, DELIVER_REQUEST *request) address = vstring_alloc(10); errors_to = vstring_alloc(10); return_receipt = vstring_alloc(10); + client_name = vstring_alloc(10); + client_addr = vstring_alloc(10); + client_proto = vstring_alloc(10); + client_helo = vstring_alloc(10); } /* @@ -209,7 +221,11 @@ static int deliver_request_get(VSTREAM *stream, DELIVER_REQUEST *request) ATTR_TYPE_STR, MAIL_ATTR_ERRTO, errors_to, ATTR_TYPE_STR, MAIL_ATTR_RRCPT, return_receipt, ATTR_TYPE_LONG, MAIL_ATTR_TIME, &request->arrival_time, - ATTR_TYPE_END) != 11) { + ATTR_TYPE_STR, MAIL_ATTR_CLIENT_NAME, client_name, + ATTR_TYPE_STR, MAIL_ATTR_CLIENT_ADDR, client_addr, + ATTR_TYPE_STR, MAIL_ATTR_PROTO_NAME, client_proto, + ATTR_TYPE_STR, MAIL_ATTR_HELO_NAME, client_helo, + ATTR_TYPE_END) != 15) { msg_warn("%s: error receiving common attributes", myname); return (-1); } @@ -224,6 +240,10 @@ static int deliver_request_get(VSTREAM *stream, DELIVER_REQUEST *request) request->sender = mystrdup(vstring_str(address)); request->errors_to = mystrdup(vstring_str(errors_to)); request->return_receipt = mystrdup(vstring_str(return_receipt)); + request->client_name = mystrdup(vstring_str(client_name)); + request->client_addr = mystrdup(vstring_str(client_addr)); + request->client_proto = mystrdup(vstring_str(client_proto)); + request->client_helo = mystrdup(vstring_str(client_helo)); /* * Extract the recipient offset and address list. Skip over any @@ -298,6 +318,10 @@ static DELIVER_REQUEST *deliver_request_alloc(void) request->data_size = 0; recipient_list_init(&request->rcpt_list); request->hop_status = 0; + request->client_name = 0; + request->client_addr = 0; + request->client_proto = 0; + request->client_helo = 0; return (request); } @@ -324,6 +348,14 @@ static void deliver_request_free(DELIVER_REQUEST *request) recipient_list_free(&request->rcpt_list); if (request->hop_status) myfree(request->hop_status); + if (request->client_name) + myfree(request->client_name); + if (request->client_addr) + myfree(request->client_addr); + if (request->client_proto) + myfree(request->client_proto); + if (request->client_helo) + myfree(request->client_helo); myfree((char *) request); } diff --git a/postfix/src/global/deliver_request.h b/postfix/src/global/deliver_request.h index 124204a60..2264a28d7 100644 --- a/postfix/src/global/deliver_request.h +++ b/postfix/src/global/deliver_request.h @@ -40,6 +40,10 @@ typedef struct DELIVER_REQUEST { long arrival_time; /* arrival time */ RECIPIENT_LIST rcpt_list; /* envelope recipients */ char *hop_status; /* reason if unavailable */ + char *client_name; /* client hostname */ + char *client_addr; /* client address */ + char *client_proto; /* client protocol */ + char *client_helo; /* helo parameter */ } DELIVER_REQUEST; #define DEL_REQ_FLAG_DEFLT (DEL_REQ_FLAG_SUCCESS | DEL_REQ_FLAG_BOUNCE) diff --git a/postfix/src/global/mail_params.h b/postfix/src/global/mail_params.h index b41f969c7..260e61ecf 100644 --- a/postfix/src/global/mail_params.h +++ b/postfix/src/global/mail_params.h @@ -753,6 +753,10 @@ 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_MAIL_TMOUT "smtp_mail_timeout" #define DEF_SMTP_MAIL_TMOUT "300s" extern int var_smtp_mail_tmout; @@ -841,6 +845,10 @@ extern int var_smtp_pix_delay; #define DEF_SMTP_DEFER_MXADDR 0 extern bool var_smtp_defer_mxaddr; +#define VAR_SMTP_SEND_XCLIENT "smtp_send_xclient_command" +#define DEF_SMTP_SEND_XCLIENT 0 +extern bool var_smtp_send_xclient; + /* * SMTP server. The soft error limit determines how many errors an SMTP * client may make before we start to slow down; the hard error limit @@ -1567,15 +1575,11 @@ extern bool var_verp_bounce_off; extern char *var_verp_clients; /* - * XADDR. + * XCLIENT, for rule testing and improved post-filter logging. */ -#define VAR_XADDR_CLIENTS "smtpd_authorized_xaddr_clients" -#define DEF_XADDR_CLIENTS "" -extern char *var_xaddr_clients; - -#define VAR_XLOGINFO_CLIENTS "smtpd_authorized_xloginfo_clients" -#define DEF_XLOGINFO_CLIENTS "" -extern char *var_xloginfo_clients; +#define VAR_XCLIENT_HOSTS "smtpd_authorized_xclient_hosts" +#define DEF_XCLIENT_HOSTS "" +extern char *var_xclient_hosts; /* * Inbound mail flow control. This allows for a stiffer coupling between diff --git a/postfix/src/global/mail_proto.h b/postfix/src/global/mail_proto.h index 04ad9bda4..10718cfd1 100644 --- a/postfix/src/global/mail_proto.h +++ b/postfix/src/global/mail_proto.h @@ -15,6 +15,7 @@ * System library. */ #include +#include /* * Utility library. @@ -150,6 +151,24 @@ extern char *mail_pathname(const char *, const char *); #define MAIL_ATTR_ORG_NONE "unknown" /* origin unknown */ #define MAIL_ATTR_ORG_LOCAL "local" /* local submission */ + /* + * Internal forms for unknown XCLIENT information. + */ +#define CLIENT_NAME_UNKNOWN "unknown" +#define CLIENT_ADDR_UNKNOWN "unknown" +#define CLIENT_NAMADDR_UNKNOWN CLIENT_NAME_UNKNOWN "[" CLIENT_ADDR_UNKNOWN "]" +#define HELO_NAME_UNKNOWN "" /* or NULL */ +#define PROTOCOL_UNKNOWN "unknown" + + /* + * Internal forms: recognizing unknown XCLIENT information. + */ +#define IS_UNK_CLNT_NAME(v) (!(v) || !strcmp((v), CLIENT_NAME_UNKNOWN)) +#define IS_UNK_CLNT_ADDR(v) (!(v) || !strcmp((v), CLIENT_ADDR_UNKNOWN)) +#define IS_UNK_CLNT_NAMADDR(v) (!(v) || !strcmp((v), CLIENT_NAMADDR_UNKNOWN)) +#define IS_UNK_HELO_NAME(v) (!(v) || !*(v)) +#define IS_UNK_PROTOCOL(v) (!(v) || !strcmp((v), PROTOCOL_UNKNOWN)) + /* LICENSE /* .ad /* .fi diff --git a/postfix/src/global/mail_stream.c b/postfix/src/global/mail_stream.c index 094cb00b0..19c822911 100644 --- a/postfix/src/global/mail_stream.c +++ b/postfix/src/global/mail_stream.c @@ -84,6 +84,7 @@ #include #include #include +#include /* Utility library. */ diff --git a/postfix/src/global/mail_version.h b/postfix/src/global/mail_version.h index 6b0b71f10..ce00d7d18 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 "20031113" +#define MAIL_RELEASE_DATE "20031128" #define VAR_MAIL_VERSION "mail_version" #define DEF_MAIL_VERSION "2.0.16-" MAIL_RELEASE_DATE diff --git a/postfix/src/global/mime_state.c b/postfix/src/global/mime_state.c index eb7bfc4ba..5c9630d35 100644 --- a/postfix/src/global/mime_state.c +++ b/postfix/src/global/mime_state.c @@ -387,7 +387,7 @@ static MIME_ENCODING mime_encoding_map[] = { /* RFC 2045 */ * Outputs and state changes are interleaved, so we must maintain separate * offsets for header and body segments. */ -#define HEAD_OUT(ptr, info) do { \ +#define HEAD_OUT(ptr, info, len) do { \ (ptr)->head_out((ptr)->app_context, (ptr)->curr_state, \ (info), (ptr)->output_buffer, (ptr)->head_offset); \ (ptr)->head_offset += (len) + 1; \ @@ -805,7 +805,7 @@ int mime_state_update(MIME_STATE *state, int rec_type, || header_info->type != HDR_CONTENT_TRANSFER_ENCODING || (state->static_flags & MIME_OPT_DOWNGRADE) == 0 || state->curr_domain == MIME_ENC_7BIT) - HEAD_OUT(state, header_info); + HEAD_OUT(state, header_info, len); state->prev_rec_type = 0; VSTRING_RESET(state->output_buffer); } @@ -855,7 +855,7 @@ int mime_state_update(MIME_STATE *state, int rec_type, cp = CU_CHAR_PTR("quoted-printable"); vstring_sprintf(state->output_buffer, "Content-Transfer-Encoding: %s", cp); - HEAD_OUT(state, (HEADER_OPTS *) 0); + HEAD_OUT(state, (HEADER_OPTS *) 0, len); VSTRING_RESET(state->output_buffer); } diff --git a/postfix/src/global/rewrite_clnt.c b/postfix/src/global/rewrite_clnt.c index 4a20c7cee..1eaca0eec 100644 --- a/postfix/src/global/rewrite_clnt.c +++ b/postfix/src/global/rewrite_clnt.c @@ -182,6 +182,7 @@ VSTRING *rewrite_clnt_internal(const char *ruleset, const char *addr, VSTRING *r #include #include #include +#include #include #include #include @@ -237,8 +238,8 @@ int main(int argc, char **argv) VSTRING *buffer = vstring_alloc(1); while (vstring_fgets_nonl(buffer, VSTREAM_IN)) { - if ((rule = strtok(STR(buffer), " \t,")) == 0 - || (addr = strtok((char *) 0, " \t,")) == 0) + if ((addr = split_at(STR(buffer), ' ')) == 0 + || *(rule = STR(buffer)) == 0) usage(argv[0]); rewrite(rule, addr, reply); } diff --git a/postfix/src/global/xtext.c b/postfix/src/global/xtext.c index 14806e46e..959dd1aef 100644 --- a/postfix/src/global/xtext.c +++ b/postfix/src/global/xtext.c @@ -2,7 +2,7 @@ /* NAME /* xtext 3 /* SUMMARY -/* quote/unquote text, HTTP style. +/* quote/unquote text, xtext style. /* SYNOPSIS /* #include /* @@ -11,6 +11,10 @@ /* const char *unquoted; /* const char *special; /* +/* VSTRING *xtext_unquote_append(unquoted, quoted) +/* VSTRING *unquoted; +/* const char *quoted; +/* /* VSTRING *xtext_unquote(unquoted, quoted) /* VSTRING *unquoted; /* const char *quoted; @@ -19,6 +23,9 @@ /* +, <33(10) and >126(10), as well as characters specified with "special" /* by +XX, XX being the two-digit uppercase hexadecimal equivalent. /* +/* xtext_quote_append() is like xtext_quote(), but appends the conversion +/* result to the result buffer. +/* /* xtext_unquote() performs the opposite transformation. This function /* understands lowercase, uppercase, and mixed case +XX sequences. The /* result value is the unquoted argument in case of success, a null pointer @@ -53,16 +60,17 @@ #define STR(x) vstring_str(x) #define LEN(x) VSTRING_LEN(x) -/* xtext_quote - unquoted data to quoted */ +/* xtext_quote_append - append unquoted data to quoted data */ -VSTRING *xtext_quote(VSTRING *quoted, const char *unquoted, const char *special) +VSTRING *xtext_quote_append(VSTRING *quoted, const char *unquoted, + const char *special) { const char *cp; int ch; - VSTRING_RESET(quoted); for (cp = unquoted; (ch = *(unsigned const char *) cp) != 0; cp++) { - if (ch != '+' && ch > 32 && ch < 127 && strchr(special, ch) == 0) { + if (ch != '+' && ch > 32 && ch < 127 + && (*special == 0 || strchr(special, ch) == 0)) { VSTRING_ADDCH(quoted, ch); } else { vstring_sprintf_append(quoted, "+%02X", ch); @@ -72,6 +80,15 @@ VSTRING *xtext_quote(VSTRING *quoted, const char *unquoted, const char *special) return (quoted); } +/* xtext_quote - unquoted data to quoted */ + +VSTRING *xtext_quote(VSTRING *quoted, const char *unquoted, const char *special) +{ + VSTRING_RESET(quoted); + xtext_quote_append(quoted, unquoted, special); + return (quoted); +} + /* xtext_unquote - quoted data to unquoted */ VSTRING *xtext_unquote(VSTRING *unquoted, const char *quoted) diff --git a/postfix/src/global/xtext.h b/postfix/src/global/xtext.h index 8b924c6bc..1515242d3 100644 --- a/postfix/src/global/xtext.h +++ b/postfix/src/global/xtext.h @@ -13,13 +13,14 @@ /* * Utility library. - */ + */ #include /* * External interface. */ extern VSTRING *xtext_quote(VSTRING *, const char *, const char *); +extern VSTRING *xtext_quote_append(VSTRING *, const char *, const char *); extern VSTRING *xtext_unquote(VSTRING *, const char *); /* LICENSE diff --git a/postfix/src/lmtp/Makefile.in b/postfix/src/lmtp/Makefile.in index 4b86772e8..baf5db8d4 100644 --- a/postfix/src/lmtp/Makefile.in +++ b/postfix/src/lmtp/Makefile.in @@ -7,9 +7,6 @@ OBJS = lmtp.o lmtp_connect.o lmtp_proto.o lmtp_chat.o lmtp_session.o \ lmtp_sasl_proto.o HDRS = lmtp.h TESTSRC = -WARN = -W -Wformat -Wimplicit -Wmissing-prototypes \ - -Wparentheses -Wstrict-prototypes -Wswitch -Wuninitialized \ - -Wunused DEFS = -I. -I$(INC_DIR) -D$(SYSTYPE) CFLAGS = $(DEBUG) $(OPT) $(DEFS) TESTPROG= diff --git a/postfix/src/local/Makefile.in b/postfix/src/local/Makefile.in index 038e81edc..28dc05001 100644 --- a/postfix/src/local/Makefile.in +++ b/postfix/src/local/Makefile.in @@ -9,9 +9,6 @@ OBJS = alias.o command.o delivered.o dotforward.o file.o forward.o \ local_expand.o HDRS = local.h TESTSRC = -WARN = -W -Wformat -Wimplicit -Wmissing-prototypes \ - -Wparentheses -Wstrict-prototypes -Wswitch -Wuninitialized \ - -Wunused DEFS = -I. -I$(INC_DIR) -D$(SYSTYPE) CFLAGS = $(DEBUG) $(OPT) $(DEFS) PROG = local diff --git a/postfix/src/master/Makefile.in b/postfix/src/master/Makefile.in index eeb2ce986..3bca0e03d 100644 --- a/postfix/src/master/Makefile.in +++ b/postfix/src/master/Makefile.in @@ -10,9 +10,6 @@ LIB_OBJ = single_server.o multi_server.o trigger_server.o master_proto.o \ mail_flow.o HDRS = mail_server.h master_proto.h mail_flow.h INT_HDR = master.h -WARN = -W -Wformat -Wimplicit -Wmissing-prototypes \ - -Wparentheses -Wstrict-prototypes -Wswitch -Wuninitialized \ - -Wunused DEFS = -I. -I$(INC_DIR) -D$(SYSTYPE) CFLAGS = $(DEBUG) $(OPT) $(DEFS) LIB = libmaster.a diff --git a/postfix/src/master/master_ent.c b/postfix/src/master/master_ent.c index 11ff16cc9..8c22bb91c 100644 --- a/postfix/src/master/master_ent.c +++ b/postfix/src/master/master_ent.c @@ -303,7 +303,9 @@ MASTER_SERV *get_master_ent() MASTER_INET_ADDRLIST(serv) = (INET_ADDR_LIST *) mymalloc(sizeof(*MASTER_INET_ADDRLIST(serv))); inet_addr_list_init(MASTER_INET_ADDRLIST(serv)); - inet_addr_host(MASTER_INET_ADDRLIST(serv), host); + if (inet_addr_host(MASTER_INET_ADDRLIST(serv), host) == 0) + msg_fatal("%s: line %d: bad hostname or network address: %s", + VSTREAM_PATH(master_fp), master_line, host); inet_addr_list_uniq(MASTER_INET_ADDRLIST(serv)); serv->listen_fd_count = MASTER_INET_ADDRLIST(serv)->used; } else if (strcasecmp(saved_interfaces, DEF_INET_INTERFACES) == 0) { diff --git a/postfix/src/nqmgr/Makefile.in b/postfix/src/nqmgr/Makefile.in index c5f6254e7..35f34f1ee 100644 --- a/postfix/src/nqmgr/Makefile.in +++ b/postfix/src/nqmgr/Makefile.in @@ -9,9 +9,6 @@ OBJS = qmgr.o qmgr_active.o qmgr_transport.o qmgr_queue.o qmgr_entry.o \ qmgr_defer.o qmgr_enable.o qmgr_scan.o qmgr_bounce.o HDRS = qmgr.h TESTSRC = -WARN = -W -Wformat -Wimplicit -Wmissing-prototypes \ - -Wparentheses -Wstrict-prototypes -Wswitch -Wuninitialized \ - -Wunused DEFS = -I. -I$(INC_DIR) -D$(SYSTYPE) CFLAGS = $(DEBUG) $(OPT) $(DEFS) TESTPROG= diff --git a/postfix/src/nqmgr/qmgr.h b/postfix/src/nqmgr/qmgr.h index e3fbd9ac0..8a8f5a925 100644 --- a/postfix/src/nqmgr/qmgr.h +++ b/postfix/src/nqmgr/qmgr.h @@ -276,6 +276,10 @@ struct QMGR_MESSAGE { char *redirect_addr; /* info@spammer.tld */ long data_size; /* message content size */ long rcpt_offset; /* more recipients here */ + char *client_name; /* client hostname */ + char *client_addr; /* client address */ + char *client_proto; /* client protocol */ + char *client_helo; /* helo parameter */ QMGR_RCPT_LIST rcpt_list; /* complete addresses */ int rcpt_count; /* used recipient slots */ int rcpt_limit; /* maximum read in-core */ diff --git a/postfix/src/nqmgr/qmgr_active.c b/postfix/src/nqmgr/qmgr_active.c index 67f574253..198bd4492 100644 --- a/postfix/src/nqmgr/qmgr_active.c +++ b/postfix/src/nqmgr/qmgr_active.c @@ -489,8 +489,9 @@ static void qmgr_active_done_3_generic(QMGR_MESSAGE *message) message->queue_id, message->queue_name); msg_warn("%s: remove %s from %s: %m", myname, message->queue_id, message->queue_name); - } else if (msg_verbose) { - msg_info("%s: remove %s", myname, message->queue_id); + } else { + /* Same format as logged by postsuper. */ + msg_info("%s: removed", message->queue_id); } } diff --git a/postfix/src/nqmgr/qmgr_deliver.c b/postfix/src/nqmgr/qmgr_deliver.c index 3f7e78bb5..cfdf635ff 100644 --- a/postfix/src/nqmgr/qmgr_deliver.c +++ b/postfix/src/nqmgr/qmgr_deliver.c @@ -161,6 +161,10 @@ static int qmgr_deliver_send_request(QMGR_ENTRY *entry, VSTREAM *stream) ATTR_TYPE_STR, MAIL_ATTR_ERRTO, message->errors_to, ATTR_TYPE_STR, MAIL_ATTR_RRCPT, message->return_receipt, ATTR_TYPE_LONG, MAIL_ATTR_TIME, message->arrival_time, + ATTR_TYPE_STR, MAIL_ATTR_CLIENT_NAME, message->client_name, + ATTR_TYPE_STR, MAIL_ATTR_CLIENT_ADDR, message->client_addr, + ATTR_TYPE_STR, MAIL_ATTR_PROTO_NAME, message->client_proto, + ATTR_TYPE_STR, MAIL_ATTR_HELO_NAME, message->client_helo, ATTR_TYPE_END); if (sender_buf != 0) vstring_free(sender_buf); diff --git a/postfix/src/nqmgr/qmgr_message.c b/postfix/src/nqmgr/qmgr_message.c index b2951133c..1dc1e410e 100644 --- a/postfix/src/nqmgr/qmgr_message.c +++ b/postfix/src/nqmgr/qmgr_message.c @@ -168,6 +168,10 @@ static QMGR_MESSAGE *qmgr_message_create(const char *queue_name, message->warn_time = 0; message->rcpt_offset = 0; message->verp_delims = 0; + message->client_name = 0; + message->client_addr = 0; + message->client_proto = 0; + message->client_helo = 0; qmgr_rcpt_list_init(&message->rcpt_list); message->rcpt_count = 0; message->rcpt_limit = var_qmgr_msg_rcpt_limit; @@ -525,6 +529,27 @@ static int qmgr_message_read(QMGR_MESSAGE *message) myfree(message->encoding); message->encoding = mystrdup(value); } + /* Original client attributes. */ + if (strcmp(name, MAIL_ATTR_CLIENT_NAME) == 0) { + if (message->client_name != 0) + myfree(message->client_name); + message->client_name = mystrdup(value); + } + if (strcmp(name, MAIL_ATTR_CLIENT_ADDR) == 0) { + if (message->client_addr != 0) + myfree(message->client_addr); + message->client_addr = mystrdup(value); + } + if (strcmp(name, MAIL_ATTR_PROTO_NAME) == 0) { + if (message->client_proto != 0) + myfree(message->client_proto); + message->client_proto = mystrdup(value); + } + if (strcmp(name, MAIL_ATTR_HELO_NAME) == 0) { + if (message->client_helo != 0) + myfree(message->client_helo); + message->client_helo = mystrdup(value); + } /* Optional tracing flags. */ else if (strcmp(name, MAIL_ATTR_TRACE_FLAGS) == 0) { message->tflags = DEL_REQ_TRACE_FLAGS(atoi(value)); @@ -586,6 +611,14 @@ static int qmgr_message_read(QMGR_MESSAGE *message) message->return_receipt = mystrdup(""); if (message->encoding == 0) message->encoding = mystrdup(MAIL_ATTR_ENC_NONE); + if (message->client_name == 0) + message->client_name = mystrdup(CLIENT_NAME_UNKNOWN); + if (message->client_addr == 0) + message->client_addr = mystrdup(CLIENT_ADDR_UNKNOWN); + if (message->client_proto == 0) + message->client_proto = mystrdup(PROTOCOL_UNKNOWN); + if (message->client_helo == 0) + message->client_helo = mystrdup(HELO_NAME_UNKNOWN); /* * Clean up. diff --git a/postfix/src/pickup/Makefile.in b/postfix/src/pickup/Makefile.in index 44847920d..c007503af 100644 --- a/postfix/src/pickup/Makefile.in +++ b/postfix/src/pickup/Makefile.in @@ -3,9 +3,6 @@ SRCS = pickup.c OBJS = pickup.o HDRS = TESTSRC = -WARN = -W -Wformat -Wimplicit -Wmissing-prototypes \ - -Wparentheses -Wstrict-prototypes -Wswitch -Wuninitialized \ - -Wunused DEFS = -I. -I$(INC_DIR) -D$(SYSTYPE) CFLAGS = $(DEBUG) $(OPT) $(DEFS) TESTPROG= diff --git a/postfix/src/pipe/Makefile.in b/postfix/src/pipe/Makefile.in index 7f0c13f38..d1063fcb2 100644 --- a/postfix/src/pipe/Makefile.in +++ b/postfix/src/pipe/Makefile.in @@ -3,9 +3,6 @@ SRCS = pipe.c OBJS = pipe.o HDRS = TESTSRC = -WARN = -W -Wformat -Wimplicit -Wmissing-prototypes \ - -Wparentheses -Wstrict-prototypes -Wswitch -Wuninitialized \ - -Wunused DEFS = -I. -I$(INC_DIR) -D$(SYSTYPE) CFLAGS = $(DEBUG) $(OPT) $(DEFS) TESTPROG= diff --git a/postfix/src/postalias/Makefile.in b/postfix/src/postalias/Makefile.in index acb8e86b9..702551a52 100644 --- a/postfix/src/postalias/Makefile.in +++ b/postfix/src/postalias/Makefile.in @@ -3,9 +3,6 @@ SRCS = postalias.c OBJS = postalias.o HDRS = TESTSRC = -WARN = -W -Wformat -Wimplicit -Wmissing-prototypes \ - -Wparentheses -Wstrict-prototypes -Wswitch -Wuninitialized \ - -Wunused DEFS = -I. -I$(INC_DIR) -D$(SYSTYPE) CFLAGS = $(DEBUG) $(OPT) $(DEFS) TESTPROG= diff --git a/postfix/src/postcat/Makefile.in b/postfix/src/postcat/Makefile.in index dca610880..e1ba3bdc9 100644 --- a/postfix/src/postcat/Makefile.in +++ b/postfix/src/postcat/Makefile.in @@ -3,9 +3,6 @@ SRCS = postcat.c OBJS = postcat.o HDRS = TESTSRC = -WARN = -W -Wformat -Wimplicit -Wmissing-prototypes \ - -Wparentheses -Wstrict-prototypes -Wswitch -Wuninitialized \ - -Wunused DEFS = -I. -I$(INC_DIR) -D$(SYSTYPE) CFLAGS = $(DEBUG) $(OPT) $(DEFS) TESTPROG= diff --git a/postfix/src/postconf/Makefile.in b/postfix/src/postconf/Makefile.in index 198be229e..6597e31ce 100644 --- a/postfix/src/postconf/Makefile.in +++ b/postfix/src/postconf/Makefile.in @@ -3,9 +3,6 @@ SRCS = postconf.c OBJS = postconf.o HDRS = TESTSRC = -WARN = -W -Wformat -Wimplicit -Wmissing-prototypes \ - -Wparentheses -Wstrict-prototypes -Wswitch -Wuninitialized \ - -Wunused DEFS = -I. -I$(INC_DIR) -D$(SYSTYPE) CFLAGS = $(DEBUG) $(OPT) $(DEFS) TESTPROG= diff --git a/postfix/src/postdrop/Makefile.in b/postfix/src/postdrop/Makefile.in index 846e70fde..cb914ad96 100644 --- a/postfix/src/postdrop/Makefile.in +++ b/postfix/src/postdrop/Makefile.in @@ -3,9 +3,6 @@ SRCS = postdrop.c OBJS = postdrop.o HDRS = TESTSRC = -WARN = -W -Wformat -Wimplicit -Wmissing-prototypes \ - -Wparentheses -Wstrict-prototypes -Wswitch -Wuninitialized \ - -Wunused DEFS = -I. -I$(INC_DIR) -D$(SYSTYPE) CFLAGS = $(DEBUG) $(OPT) $(DEFS) TESTPROG= diff --git a/postfix/src/postfix/Makefile.in b/postfix/src/postfix/Makefile.in index bd1e8f5e3..ac53549d3 100644 --- a/postfix/src/postfix/Makefile.in +++ b/postfix/src/postfix/Makefile.in @@ -3,9 +3,6 @@ SRCS = postfix.c OBJS = postfix.o HDRS = TESTSRC = -WARN = -W -Wformat -Wimplicit -Wmissing-prototypes \ - -Wparentheses -Wstrict-prototypes -Wswitch -Wuninitialized \ - -Wunused DEFS = -I. -I$(INC_DIR) -D$(SYSTYPE) CFLAGS = $(DEBUG) $(OPT) $(DEFS) FILES = Makefile $(SRCS) $(HDRS) diff --git a/postfix/src/postkick/Makefile.in b/postfix/src/postkick/Makefile.in index ce8b4a485..38c0fba9a 100644 --- a/postfix/src/postkick/Makefile.in +++ b/postfix/src/postkick/Makefile.in @@ -3,9 +3,6 @@ SRCS = postkick.c OBJS = postkick.o HDRS = TESTSRC = -WARN = -W -Wformat -Wimplicit -Wmissing-prototypes \ - -Wparentheses -Wstrict-prototypes -Wswitch -Wuninitialized \ - -Wunused DEFS = -I. -I$(INC_DIR) -D$(SYSTYPE) CFLAGS = $(DEBUG) $(OPT) $(DEFS) TESTPROG= diff --git a/postfix/src/postlock/Makefile.in b/postfix/src/postlock/Makefile.in index 3e95260c3..4e4ea3ad0 100644 --- a/postfix/src/postlock/Makefile.in +++ b/postfix/src/postlock/Makefile.in @@ -3,9 +3,6 @@ SRCS = postlock.c OBJS = postlock.o HDRS = TESTSRC = -WARN = -W -Wformat -Wimplicit -Wmissing-prototypes \ - -Wparentheses -Wstrict-prototypes -Wswitch -Wuninitialized \ - -Wunused DEFS = -I. -I$(INC_DIR) -D$(SYSTYPE) CFLAGS = $(DEBUG) $(OPT) $(DEFS) TESTPROG= diff --git a/postfix/src/postlog/Makefile.in b/postfix/src/postlog/Makefile.in index 5feba3056..8e57470ac 100644 --- a/postfix/src/postlog/Makefile.in +++ b/postfix/src/postlog/Makefile.in @@ -3,9 +3,6 @@ SRCS = postlog.c OBJS = postlog.o HDRS = TESTSRC = -WARN = -W -Wformat -Wimplicit -Wmissing-prototypes \ - -Wparentheses -Wstrict-prototypes -Wswitch -Wuninitialized \ - -Wunused DEFS = -I. -I$(INC_DIR) -D$(SYSTYPE) CFLAGS = $(DEBUG) $(OPT) $(DEFS) FILES = Makefile $(SRCS) $(HDRS) diff --git a/postfix/src/postmap/Makefile.in b/postfix/src/postmap/Makefile.in index 5dbb4ccfe..21cf87be5 100644 --- a/postfix/src/postmap/Makefile.in +++ b/postfix/src/postmap/Makefile.in @@ -3,9 +3,6 @@ SRCS = postmap.c OBJS = postmap.o HDRS = TESTSRC = -WARN = -W -Wformat -Wimplicit -Wmissing-prototypes \ - -Wparentheses -Wstrict-prototypes -Wswitch -Wuninitialized \ - -Wunused DEFS = -I. -I$(INC_DIR) -D$(SYSTYPE) CFLAGS = $(DEBUG) $(OPT) $(DEFS) TESTPROG= diff --git a/postfix/src/postqueue/Makefile.in b/postfix/src/postqueue/Makefile.in index 29ba1bff4..ba9e66f16 100644 --- a/postfix/src/postqueue/Makefile.in +++ b/postfix/src/postqueue/Makefile.in @@ -3,9 +3,6 @@ SRCS = postqueue.c OBJS = postqueue.o HDRS = TESTSRC = -WARN = -W -Wformat -Wimplicit -Wmissing-prototypes \ - -Wparentheses -Wstrict-prototypes -Wswitch -Wuninitialized \ - -Wunused DEFS = -I. -I$(INC_DIR) -D$(SYSTYPE) CFLAGS = $(DEBUG) $(OPT) $(DEFS) TESTPROG= diff --git a/postfix/src/postsuper/Makefile.in b/postfix/src/postsuper/Makefile.in index aacc1841a..1b9d8079d 100644 --- a/postfix/src/postsuper/Makefile.in +++ b/postfix/src/postsuper/Makefile.in @@ -3,9 +3,6 @@ SRCS = postsuper.c OBJS = postsuper.o HDRS = TESTSRC = -WARN = -W -Wformat -Wimplicit -Wmissing-prototypes \ - -Wparentheses -Wstrict-prototypes -Wswitch -Wuninitialized \ - -Wunused DEFS = -I. -I$(INC_DIR) -D$(SYSTYPE) CFLAGS = $(DEBUG) $(OPT) $(DEFS) TESTPROG= diff --git a/postfix/src/proxymap/Makefile.in b/postfix/src/proxymap/Makefile.in index 91d20d838..e42f4389c 100644 --- a/postfix/src/proxymap/Makefile.in +++ b/postfix/src/proxymap/Makefile.in @@ -3,9 +3,6 @@ SRCS = proxymap.c OBJS = proxymap.o HDRS = TESTSRC = -WARN = -W -Wformat -Wimplicit -Wmissing-prototypes \ - -Wparentheses -Wstrict-prototypes -Wswitch -Wuninitialized \ - -Wunused DEFS = -I. -I$(INC_DIR) -D$(SYSTYPE) CFLAGS = $(DEBUG) $(OPT) $(DEFS) TESTPROG= diff --git a/postfix/src/qmgr/Makefile.in b/postfix/src/qmgr/Makefile.in index 06ead6374..a640af3dc 100644 --- a/postfix/src/qmgr/Makefile.in +++ b/postfix/src/qmgr/Makefile.in @@ -7,9 +7,6 @@ OBJS = qmgr.o qmgr_active.o qmgr_transport.o qmgr_queue.o qmgr_entry.o \ qmgr_defer.o qmgr_enable.o qmgr_scan.o qmgr_bounce.o HDRS = qmgr.h TESTSRC = -WARN = -W -Wformat -Wimplicit -Wmissing-prototypes \ - -Wparentheses -Wstrict-prototypes -Wswitch -Wuninitialized \ - -Wunused DEFS = -I. -I$(INC_DIR) -D$(SYSTYPE) CFLAGS = $(DEBUG) $(OPT) $(DEFS) TESTPROG= diff --git a/postfix/src/qmgr/qmgr.h b/postfix/src/qmgr/qmgr.h index 638639714..2981b4b54 100644 --- a/postfix/src/qmgr/qmgr.h +++ b/postfix/src/qmgr/qmgr.h @@ -236,6 +236,10 @@ struct QMGR_MESSAGE { char *redirect_addr; /* info@spammer.tld */ long data_size; /* message content size */ long rcpt_offset; /* more recipients here */ + char *client_name; /* client hostname */ + char *client_addr; /* client address */ + char *client_proto; /* client protocol */ + char *client_helo; /* helo parameter */ QMGR_RCPT_LIST rcpt_list; /* complete addresses */ }; diff --git a/postfix/src/qmgr/qmgr_active.c b/postfix/src/qmgr/qmgr_active.c index 3e25b6323..6d4a248c1 100644 --- a/postfix/src/qmgr/qmgr_active.c +++ b/postfix/src/qmgr/qmgr_active.c @@ -489,8 +489,9 @@ static void qmgr_active_done_3_generic(QMGR_MESSAGE *message) message->queue_id, message->queue_name); msg_warn("%s: remove %s from %s: %m", myname, message->queue_id, message->queue_name); - } else if (msg_verbose) { - msg_info("%s: remove %s", myname, message->queue_id); + } else { + /* Same format as logged by postsuper. */ + msg_info("%s: removed", message->queue_id); } } diff --git a/postfix/src/qmgr/qmgr_deliver.c b/postfix/src/qmgr/qmgr_deliver.c index c1e6ab749..d41064ad5 100644 --- a/postfix/src/qmgr/qmgr_deliver.c +++ b/postfix/src/qmgr/qmgr_deliver.c @@ -156,6 +156,10 @@ static int qmgr_deliver_send_request(QMGR_ENTRY *entry, VSTREAM *stream) ATTR_TYPE_STR, MAIL_ATTR_ERRTO, message->errors_to, ATTR_TYPE_STR, MAIL_ATTR_RRCPT, message->return_receipt, ATTR_TYPE_LONG, MAIL_ATTR_TIME, message->arrival_time, + ATTR_TYPE_STR, MAIL_ATTR_CLIENT_NAME, message->client_name, + ATTR_TYPE_STR, MAIL_ATTR_CLIENT_ADDR, message->client_addr, + ATTR_TYPE_STR, MAIL_ATTR_PROTO_NAME, message->client_proto, + ATTR_TYPE_STR, MAIL_ATTR_HELO_NAME, message->client_helo, ATTR_TYPE_END); if (sender_buf != 0) vstring_free(sender_buf); diff --git a/postfix/src/qmgr/qmgr_message.c b/postfix/src/qmgr/qmgr_message.c index a860e384c..70fa555db 100644 --- a/postfix/src/qmgr/qmgr_message.c +++ b/postfix/src/qmgr/qmgr_message.c @@ -158,6 +158,10 @@ static QMGR_MESSAGE *qmgr_message_create(const char *queue_name, message->warn_time = 0; message->rcpt_offset = 0; message->verp_delims = 0; + message->client_name = 0; + message->client_addr = 0; + message->client_proto = 0; + message->client_helo = 0; qmgr_rcpt_list_init(&message->rcpt_list); return (message); } @@ -490,6 +494,27 @@ static int qmgr_message_read(QMGR_MESSAGE *message) myfree(message->encoding); message->encoding = mystrdup(value); } + /* Original client attributes. */ + if (strcmp(name, MAIL_ATTR_CLIENT_NAME) == 0) { + if (message->client_name != 0) + myfree(message->client_name); + message->client_name = mystrdup(value); + } + if (strcmp(name, MAIL_ATTR_CLIENT_ADDR) == 0) { + if (message->client_addr != 0) + myfree(message->client_addr); + message->client_addr = mystrdup(value); + } + if (strcmp(name, MAIL_ATTR_PROTO_NAME) == 0) { + if (message->client_proto != 0) + myfree(message->client_proto); + message->client_proto = mystrdup(value); + } + if (strcmp(name, MAIL_ATTR_HELO_NAME) == 0) { + if (message->client_helo != 0) + myfree(message->client_helo); + message->client_helo = mystrdup(value); + } /* Optional tracing flags. */ else if (strcmp(name, MAIL_ATTR_TRACE_FLAGS) == 0) { message->tflags = DEL_REQ_TRACE_FLAGS(atoi(value)); @@ -551,6 +576,14 @@ static int qmgr_message_read(QMGR_MESSAGE *message) message->return_receipt = mystrdup(""); if (message->encoding == 0) message->encoding = mystrdup(MAIL_ATTR_ENC_NONE); + if (message->client_name == 0) + message->client_name = mystrdup(CLIENT_NAME_UNKNOWN); + if (message->client_addr == 0) + message->client_addr = mystrdup(CLIENT_ADDR_UNKNOWN); + if (message->client_proto == 0) + message->client_proto = mystrdup(PROTOCOL_UNKNOWN); + if (message->client_helo == 0) + message->client_helo = mystrdup(HELO_NAME_UNKNOWN); /* * Clean up. diff --git a/postfix/src/qmqpd/Makefile.in b/postfix/src/qmqpd/Makefile.in index 2ccd7d449..e3fdf333c 100644 --- a/postfix/src/qmqpd/Makefile.in +++ b/postfix/src/qmqpd/Makefile.in @@ -3,9 +3,6 @@ SRCS = qmqpd.c qmqpd_state.c qmqpd_peer.c OBJS = qmqpd.o qmqpd_state.o qmqpd_peer.o HDRS = TESTSRC = -WARN = -W -Wformat -Wimplicit -Wmissing-prototypes \ - -Wparentheses -Wstrict-prototypes -Wswitch -Wuninitialized \ - -Wunused DEFS = -I. -I$(INC_DIR) -D$(SYSTYPE) CFLAGS = $(DEBUG) $(OPT) $(DEFS) TESTPROG= diff --git a/postfix/src/sendmail/Makefile.in b/postfix/src/sendmail/Makefile.in index 7fdaae232..fbbb60600 100644 --- a/postfix/src/sendmail/Makefile.in +++ b/postfix/src/sendmail/Makefile.in @@ -3,9 +3,6 @@ SRCS = sendmail.c OBJS = sendmail.o HDRS = TESTSRC = -WARN = -W -Wformat -Wimplicit -Wmissing-prototypes \ - -Wparentheses -Wstrict-prototypes -Wswitch -Wuninitialized \ - -Wunused DEFS = -I. -I$(INC_DIR) -D$(SYSTYPE) CFLAGS = $(DEBUG) $(OPT) $(DEFS) TESTPROG= diff --git a/postfix/src/sendmail/sendmail.c b/postfix/src/sendmail/sendmail.c index a59957c01..2dc1ed9e9 100644 --- a/postfix/src/sendmail/sendmail.c +++ b/postfix/src/sendmail/sendmail.c @@ -740,7 +740,7 @@ int main(int argc, char **argv) for (fd = 0; fd < 3; fd++) if (fstat(fd, &st) == -1 && (close(fd), open("/dev/null", O_RDWR, 0)) != fd) - msg_fatal_status(EX_UNAVAILABLE, "open /dev/null: %m"); + msg_fatal_status(EX_OSERR, "open /dev/null: %m"); /* * The CDE desktop calendar manager leaks a parent file descriptor into diff --git a/postfix/src/showq/Makefile.in b/postfix/src/showq/Makefile.in index 2001e4df3..a8cba0c1f 100644 --- a/postfix/src/showq/Makefile.in +++ b/postfix/src/showq/Makefile.in @@ -3,9 +3,6 @@ SRCS = showq.c OBJS = showq.o HDRS = TESTSRC = -WARN = -W -Wformat -Wimplicit -Wmissing-prototypes \ - -Wparentheses -Wstrict-prototypes -Wswitch -Wuninitialized \ - -Wunused DEFS = -I. -I$(INC_DIR) -D$(SYSTYPE) CFLAGS = $(DEBUG) $(OPT) $(DEFS) TESTPROG= diff --git a/postfix/src/smtp/Makefile.in b/postfix/src/smtp/Makefile.in index d51009814..7249c3eff 100644 --- a/postfix/src/smtp/Makefile.in +++ b/postfix/src/smtp/Makefile.in @@ -7,9 +7,6 @@ OBJS = smtp.o smtp_connect.o smtp_proto.o smtp_chat.o smtp_session.o \ smtp_sasl_proto.o smtp_sasl_glue.o HDRS = smtp.h smtp_sasl.h TESTSRC = -WARN = -W -Wformat -Wimplicit -Wmissing-prototypes \ - -Wparentheses -Wstrict-prototypes -Wswitch -Wuninitialized \ - -Wunused DEFS = -I. -I$(INC_DIR) -D$(SYSTYPE) CFLAGS = $(DEBUG) $(OPT) $(DEFS) TESTPROG= smtp_unalias @@ -176,6 +173,7 @@ 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 b1324c835..3400b7df3 100644 --- a/postfix/src/smtp/smtp.c +++ b/postfix/src/smtp/smtp.c @@ -194,6 +194,9 @@ /* .IP \fBsmtp_helo_timeout\fR /* Timeout for sending the \fBHELO\fR command, and for /* receiving the server response. +/* .IP \fBsmtp_xclient_timeout\fR +/* Timeout for sending the \fBXCLIENT\fR command, and for +/* receiving the server response. /* .IP \fBsmtp_mail_timeout\fR /* Timeout for sending the \fBMAIL FROM\fR command, and for /* receiving the server response. @@ -215,6 +218,11 @@ /* than the local MTA). /* If yes, keep trying until a suitable MX host resolves or until /* the mail is too old. +/* .IP \fBsmtp_send_xclient_command\fR +/* If the SMTP server announces XCLIENT 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 @@ -275,6 +283,7 @@ */ int var_smtp_conn_tmout; int var_smtp_helo_tmout; +int var_smtp_xclnt_tmout; int var_smtp_mail_tmout; int var_smtp_rcpt_tmout; int var_smtp_data0_tmout; @@ -305,6 +314,7 @@ char *var_smtp_helo_name; char *var_smtp_host_lookup; bool var_smtp_quote_821_env; bool var_smtp_defer_mxaddr; +bool var_smtp_send_xclient; /* * Global variables. smtp_errno is set by the address lookup routines and by @@ -492,6 +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_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, @@ -518,6 +529,7 @@ int main(int argc, char **argv) VAR_SMTP_RAND_ADDR, DEF_SMTP_RAND_ADDR, &var_smtp_rand_addr, VAR_SMTP_QUOTE_821_ENV, DEF_SMTP_QUOTE_821_ENV, &var_smtp_quote_821_env, VAR_SMTP_DEFER_MXADDR, DEF_SMTP_DEFER_MXADDR, &var_smtp_defer_mxaddr, + VAR_SMTP_SEND_XCLIENT, DEF_SMTP_SEND_XCLIENT, &var_smtp_send_xclient, 0, }; diff --git a/postfix/src/smtp/smtp.h b/postfix/src/smtp/smtp.h index c4500d1d1..8c9d04074 100644 --- a/postfix/src/smtp/smtp.h +++ b/postfix/src/smtp/smtp.h @@ -64,6 +64,7 @@ typedef struct SMTP_STATE { #define SMTP_FEATURE_STARTTLS (1<<4) #define SMTP_FEATURE_AUTH (1<<5) #define SMTP_FEATURE_MAYBEPIX (1<<6) /* PIX smtp fixup mode */ +#define SMTP_FEATURE_XCLIENT (1<<7) /* server supports XCLIENT */ /* * smtp.c diff --git a/postfix/src/smtp/smtp_proto.c b/postfix/src/smtp/smtp_proto.c index 024d78e19..243f1fab6 100644 --- a/postfix/src/smtp/smtp_proto.c +++ b/postfix/src/smtp/smtp_proto.c @@ -103,6 +103,7 @@ #include #include #include +#include /* Application-specific. */ @@ -123,15 +124,19 @@ * SMTP_STATE_DOT) must have smaller numerical values than the non-sending * states (SMTP_STATE_ABORT .. SMTP_STATE_LAST). */ -#define SMTP_STATE_MAIL 0 -#define SMTP_STATE_RCPT 1 -#define SMTP_STATE_DATA 2 -#define SMTP_STATE_DOT 3 -#define SMTP_STATE_ABORT 4 -#define SMTP_STATE_QUIT 5 -#define SMTP_STATE_LAST 6 +#define SMTP_STATE_XCLIENT_ADDR 0 +#define SMTP_STATE_XCLIENT_HELO 1 +#define SMTP_STATE_MAIL 2 +#define SMTP_STATE_RCPT 3 +#define SMTP_STATE_DATA 4 +#define SMTP_STATE_DOT 5 +#define SMTP_STATE_ABORT 6 +#define SMTP_STATE_QUIT 7 +#define SMTP_STATE_LAST 8 int *xfer_timeouts[SMTP_STATE_LAST] = { + &var_smtp_xclnt_tmout, + &var_smtp_xclnt_tmout, &var_smtp_mail_tmout, &var_smtp_rcpt_tmout, &var_smtp_data0_tmout, @@ -141,6 +146,8 @@ int *xfer_timeouts[SMTP_STATE_LAST] = { }; char *xfer_states[SMTP_STATE_LAST] = { + "sending XCLIENT address and name", + "sending XCLIENT helo_name and protocol", "sending MAIL FROM", "sending RCPT TO", "sending DATA command", @@ -150,6 +157,8 @@ char *xfer_states[SMTP_STATE_LAST] = { }; char *xfer_request[SMTP_STATE_LAST] = { + "XCLIENT command", + "XCLIENT command", "MAIL FROM command", "RCPT TO command", "DATA command", @@ -250,6 +259,8 @@ 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, "XCLIENT") == 0) + state->features |= SMTP_FEATURE_XCLIENT; else if (strcasecmp(word, "SIZE") == 0) { state->features |= SMTP_FEATURE_SIZE; if ((word = mystrtok(&words, " \t")) != 0) { @@ -374,6 +385,8 @@ int smtp_xfer(SMTP_STATE *state) int mail_from_rejected; int downgrading; int mime_errs; + int send_xclient_addr = 0; + int send_xclient_helo = 0; /* * Macros for readability. @@ -472,9 +485,23 @@ int smtp_xfer(SMTP_STATE *state) * receiver detects a serious problem (MAIL FROM rejected, all RCPT TO * commands rejected, DATA rejected) it forces the sender to abort the * SMTP dialog with RSET and QUIT. + * + * Send "XCLIENT LOG" information only if we have a surrogate remote client + * name and address, i.e. the mail was actually received from the + * network. Since "XCLIENT LOG" overrides all remote client logging + * attributes, there is no need to send helo or protocol information that + * we do not have. */ nrcpt = 0; - recv_state = send_state = SMTP_STATE_MAIL; + send_xclient_addr = (state->features & SMTP_FEATURE_XCLIENT) + && !IS_UNK_CLNT_NAME(request->client_name) + && !IS_UNK_CLNT_ADDR(request->client_addr); + if (send_xclient_addr) { + send_xclient_helo = !IS_UNK_HELO_NAME(request->client_helo) + || !IS_UNK_PROTOCOL(request->client_proto); + recv_state = send_state = SMTP_STATE_XCLIENT_ADDR; + } else + recv_state = send_state = SMTP_STATE_MAIL; next_rcpt = send_rcpt = recv_rcpt = 0; mail_from_rejected = 0; @@ -491,6 +518,41 @@ int smtp_xfer(SMTP_STATE *state) default: msg_panic("%s: bad sender state %d", myname, send_state); + /* + * Build the XCLIENT command. Send what we know, converting + * internal form to external form. With properly sanitized + * information, this stays within the 512 byte command line + * length limit. + */ + case SMTP_STATE_XCLIENT_ADDR: + vstring_sprintf(next_command, "XCLIENT LOG"); + if (!IS_UNK_CLNT_NAME(request->client_name)) { + vstring_strcat(next_command, " CLIENT_NAME="); + xtext_quote_append(next_command, request->client_name, ""); + } + if (!IS_UNK_CLNT_ADDR(request->client_addr)) { + vstring_strcat(next_command, " CLIENT_ADDR="); + xtext_quote_append(next_command, request->client_addr, ""); + } + if (send_xclient_helo) + next_state = SMTP_STATE_XCLIENT_HELO; + else + next_state = SMTP_STATE_MAIL; + break; + + case SMTP_STATE_XCLIENT_HELO: + vstring_sprintf(next_command, "XCLIENT"); + if (!IS_UNK_HELO_NAME(request->client_helo)) { + vstring_strcat(next_command, " HELO_NAME="); + xtext_quote_append(next_command, request->client_helo, ""); + } + if (!IS_UNK_PROTOCOL(request->client_proto)) { + vstring_strcat(next_command, " PROTOCOL="); + xtext_quote_append(next_command, request->client_proto, ""); + } + next_state = SMTP_STATE_MAIL; + break; + /* * Build the MAIL FROM command. */ @@ -600,7 +662,7 @@ int smtp_xfer(SMTP_STATE *state) /* * Sanity check. */ - if (recv_state < SMTP_STATE_MAIL + if (recv_state < SMTP_STATE_XCLIENT_ADDR || recv_state > SMTP_STATE_QUIT) msg_panic("%s: bad receiver state %d (sender state %d)", myname, recv_state, send_state); @@ -621,6 +683,20 @@ int smtp_xfer(SMTP_STATE *state) */ switch (recv_state) { + /* + * Ignore the XCLIENT response. No Duff device needed. + */ + case SMTP_STATE_XCLIENT_ADDR: + if (send_xclient_helo) + recv_state = SMTP_STATE_XCLIENT_HELO; + else + recv_state = SMTP_STATE_MAIL; + break; + + case SMTP_STATE_XCLIENT_HELO: + recv_state = SMTP_STATE_MAIL; + break; + /* * Process the MAIL FROM response. When the server * rejects the sender, set the mail_from_rejected flag so diff --git a/postfix/src/smtpd/Makefile.in b/postfix/src/smtpd/Makefile.in index 2ddf62ae8..7161b3fff 100644 --- a/postfix/src/smtpd/Makefile.in +++ b/postfix/src/smtpd/Makefile.in @@ -1,14 +1,13 @@ SHELL = /bin/sh SRCS = smtpd.c smtpd_token.c smtpd_check.c smtpd_chat.c smtpd_state.c \ - smtpd_peer.c smtpd_sasl_proto.c smtpd_sasl_glue.c smtpd_proxy.c + smtpd_peer.c smtpd_sasl_proto.c smtpd_sasl_glue.c smtpd_proxy.c \ + smtpd_xclient.c OBJS = smtpd.o smtpd_token.o smtpd_check.o smtpd_chat.o smtpd_state.o \ - smtpd_peer.o smtpd_sasl_proto.o smtpd_sasl_glue.o smtpd_proxy.o + smtpd_peer.o smtpd_sasl_proto.o smtpd_sasl_glue.o smtpd_proxy.o \ + smtpd_xclient.o HDRS = smtpd_token.h smtpd_check.h smtpd_chat.h smtpd_sasl_proto.h \ smtpd_sasl_glue.h smtpd_proxy.h TESTSRC = smtpd_token_test.c -WARN = -W -Wformat -Wimplicit -Wmissing-prototypes \ - -Wparentheses -Wstrict-prototypes -Wswitch -Wuninitialized \ - -Wunused DEFS = -I. -I$(INC_DIR) -D$(SYSTYPE) CFLAGS = $(DEBUG) $(OPT) $(DEFS) TESTPROG= smtpd_token smtpd_check @@ -122,6 +121,7 @@ smtpd.o: ../../include/dict.h smtpd.o: ../../include/argv.h smtpd.o: ../../include/watchdog.h smtpd.o: ../../include/iostuff.h +smtpd.o: ../../include/split_at.h smtpd.o: ../../include/mail_params.h smtpd.o: ../../include/record.h smtpd.o: ../../include/rec_type.h @@ -150,6 +150,7 @@ 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 @@ -243,8 +244,11 @@ smtpd_peer.o: ../../include/valid_hostname.h smtpd_peer.o: ../../include/stringops.h smtpd_peer.o: ../../include/vstring.h smtpd_peer.o: ../../include/vbuf.h -smtpd_peer.o: smtpd.h +smtpd_peer.o: ../../include/mail_proto.h smtpd_peer.o: ../../include/vstream.h +smtpd_peer.o: ../../include/iostuff.h +smtpd_peer.o: ../../include/attr.h +smtpd_peer.o: smtpd.h smtpd_peer.o: ../../include/argv.h smtpd_peer.o: ../../include/mail_stream.h smtpd_proxy.o: smtpd_proxy.c @@ -262,6 +266,9 @@ 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 smtpd_proxy.o: ../../include/argv.h smtpd_proxy.o: ../../include/mail_stream.h @@ -331,3 +338,16 @@ smtpd_token.o: ../../include/mvect.h smtpd_token.o: smtpd_token.h smtpd_token.o: ../../include/vstring.h smtpd_token.o: ../../include/vbuf.h +smtpd_xclient.o: smtpd_xclient.c +smtpd_xclient.o: ../../include/sys_defs.h +smtpd_xclient.o: ../../include/mymalloc.h +smtpd_xclient.o: ../../include/msg.h +smtpd_xclient.o: ../../include/mail_proto.h +smtpd_xclient.o: ../../include/vstream.h +smtpd_xclient.o: ../../include/vbuf.h +smtpd_xclient.o: ../../include/iostuff.h +smtpd_xclient.o: ../../include/attr.h +smtpd_xclient.o: smtpd.h +smtpd_xclient.o: ../../include/vstring.h +smtpd_xclient.o: ../../include/argv.h +smtpd_xclient.o: ../../include/mail_stream.h diff --git a/postfix/src/smtpd/smtpd.c b/postfix/src/smtpd/smtpd.c index 54555dc40..301ebf39f 100644 --- a/postfix/src/smtpd/smtpd.c +++ b/postfix/src/smtpd/smtpd.c @@ -143,20 +143,12 @@ /* .IP \fBsmtpd_authorized_verp_clients\fR /* Hostnames, domain names and/or addresses of clients that are /* authorized to use the XVERP extension. -/* .IP \fBsmtpd_authorized_xaddr_clients\fR +/* .IP \fBsmtpd_authorized_xclient_hosts\fR /* Hostnames, domain names and/or addresses of clients that are -/* authorized to use the "XADDR client-address client-name" command. -/* This changes Postfix's -/* idea of the SMTP client IP address and hostname for access -/* control and for logging purposes. -/* .IP \fBsmtpd_authorized_xloginfo_clients\fR -/* Hostnames, domain names and/or addresses of clients that are -/* authorized to use the "XLOGINFO client-address client-name" command. -/* This changes the client -/* name and address that are used for logging, without affecting the -/* client IP address and hostname that are used for access control. -/* XLOGINFO is typically used to propagate remote client information -/* through an SMTP-based content filter to the after-filter SMTP server. +/* authorized to use the XCLIENT command. This command changes +/* client information for access control and/or logging purposes, +/* with the exception of the +/* \fBsmtpd_authorized_xclient_hosts\fR access control itself. /* .IP \fBdebug_peer_level\fR /* Increment in verbose logging level when a remote host matches a /* pattern in the \fBdebug_peer_list\fR parameter. @@ -437,6 +429,7 @@ #include #include #include +#include /* Global library. */ @@ -461,6 +454,7 @@ #include #include #include +#include /* Single-threaded server skeleton. */ @@ -557,8 +551,7 @@ char *var_input_transp; int var_smtpd_policy_tmout; int var_smtpd_policy_idle; int var_smtpd_policy_ttl; -char *var_xaddr_clients; -char *var_xloginfo_clients; +char *var_xclient_hosts; int var_smtpd_crate_limit; int var_smtpd_cconn_limit; char *var_smtpd_hoggers; @@ -578,16 +571,9 @@ char *var_smtpd_hoggers; static NAMADR_LIST *verp_clients; /* - * XADDR command. + * XCLIENT command. */ -#define XADDR_CMD "XADDR" - -static NAMADR_LIST *xaddr_clients; - - /* - * XLOGINFO command. - */ -static NAMADR_LIST *xloginfo_clients; +static NAMADR_LIST *xclient_hosts; /* * Client connection and rate limiting. @@ -630,11 +616,10 @@ static int sasl_client_exception(SMTPD_STATE *state) return (0); match = namadr_list_match(sasl_exceptions_networks, - state->name, state->addr); + ACL_NAME(state), ACL_ADDR(state)); if (msg_verbose) - msg_info("sasl_exceptions: %s[%s], match=%d", - state->name, state->addr, match); + msg_info("sasl_exceptions: %s, match=%d", ACL_NAMADDR(state), match); return (match); } @@ -679,6 +664,8 @@ static int helo_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv) mail_reset(state); rcpt_reset(state); state->helo_name = mystrdup(printable(argv[1].strval, '?')); + neuter(state->helo_name, "<>()\\\";:@", '?'); + /* Changing the protocol name breaks the unauthorized pipelining check. */ if (strcmp(state->protocol, MAIL_PROTO_ESMTP) != 0) state->protocol = MAIL_PROTO_SMTP; smtpd_chat_reply(state, "250 %s", var_myhostname); @@ -715,6 +702,7 @@ static int ehlo_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv) mail_reset(state); rcpt_reset(state); state->helo_name = mystrdup(printable(argv[1].strval, '?')); + neuter(state->helo_name, "<>()\\\";:@", '?'); state->protocol = MAIL_PROTO_ESMTP; smtpd_chat_reply(state, "250-%s", var_myhostname); smtpd_chat_reply(state, "250-PIPELINING"); @@ -733,12 +721,11 @@ static int ehlo_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv) smtpd_chat_reply(state, "250-AUTH=%s", state->sasl_mechanism_list); } #endif - if (namadr_list_match(verp_clients, state->name, state->addr)) + if (namadr_list_match(verp_clients, ACL_NAME(state), ACL_ADDR(state))) smtpd_chat_reply(state, "250-%s", VERP_CMD); - if (namadr_list_match(xaddr_clients, state->name, state->addr)) - smtpd_chat_reply(state, "250-%s", XADDR_CMD); - if (namadr_list_match(xloginfo_clients, state->name, state->addr)) - smtpd_chat_reply(state, "250-%s", XLOGINFO_CMD); + /* XCLIENT must not override its own access control. */ + if (namadr_list_match(xclient_hosts, state->name, state->addr)) + smtpd_chat_reply(state, "250-%s", XCLIENT_CMD); smtpd_chat_reply(state, "250 8BITMIME"); return (0); } @@ -754,8 +741,7 @@ static void helo_reset(SMTPD_STATE *state) /* mail_open_stream - open mail queue file or IPC stream */ -static void mail_open_stream(SMTPD_STATE *state, SMTPD_TOKEN *argv, - const char *encoding, const char *verp_delims) +static void mail_open_stream(SMTPD_STATE *state, SMTPD_TOKEN *argv) { char *postdrop_command; int cleanup_flags; @@ -816,7 +802,7 @@ static void mail_open_stream(SMTPD_STATE *state, SMTPD_TOKEN *argv, smtpd_sasl_mail_log(state); else #endif - msg_info("%s: client=%s", state->queue_id, state->namaddr); + msg_info("%s: client=%s", state->queue_id, LOG_NAMADDR(state)); /* * Record the time of arrival, the sender envelope address, some session @@ -828,24 +814,29 @@ static void mail_open_stream(SMTPD_STATE *state, SMTPD_TOKEN *argv, rec_fprintf(state->cleanup, REC_TYPE_FILT, "%s", var_filter_xport); } rec_fputs(state->cleanup, REC_TYPE_FROM, argv[2].strval); - if (encoding != 0) + if (state->encoding != 0) rec_fprintf(state->cleanup, REC_TYPE_ATTR, "%s=%s", - MAIL_ATTR_ENCODING, encoding); + MAIL_ATTR_ENCODING, state->encoding); + + /* + * Store the client attributes for logging purposes. + */ if (SMTPD_STAND_ALONE(state) == 0) { rec_fprintf(state->cleanup, REC_TYPE_ATTR, "%s=%s", - MAIL_ATTR_CLIENT_NAME, state->name); + MAIL_ATTR_CLIENT_NAME, LOG_NAME(state)); rec_fprintf(state->cleanup, REC_TYPE_ATTR, "%s=%s", - MAIL_ATTR_CLIENT_ADDR, state->addr); + MAIL_ATTR_CLIENT_ADDR, LOG_ADDR(state)); rec_fprintf(state->cleanup, REC_TYPE_ATTR, "%s=%s", - MAIL_ATTR_ORIGIN, state->namaddr); - if (state->helo_name != 0) - rec_fprintf(state->cleanup, REC_TYPE_ATTR, "%s=%s", - MAIL_ATTR_HELO_NAME, state->helo_name); + MAIL_ATTR_ORIGIN, LOG_NAMADDR(state)); rec_fprintf(state->cleanup, REC_TYPE_ATTR, "%s=%s", - MAIL_ATTR_PROTO_NAME, state->protocol); + MAIL_ATTR_HELO_NAME, + IS_UNK_HELO_NAME(LOG_HELO_NAME(state)) ? + HELO_NAME_UNKNOWN : LOG_HELO_NAME(state)); + rec_fprintf(state->cleanup, REC_TYPE_ATTR, "%s=%s", + MAIL_ATTR_PROTO_NAME, LOG_PROTOCOL(state)); } - if (verp_delims) - rec_fputs(state->cleanup, REC_TYPE_VERP, verp_delims); + if (state->verp_delims) + rec_fputs(state->cleanup, REC_TYPE_VERP, state->verp_delims); } /* extract_addr - extract address from rubble */ @@ -965,8 +956,8 @@ static int mail_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv) int narg; char *arg; char *verp_delims = 0; - char *encoding = 0; + state->encoding = 0; state->msg_size = 0; /* @@ -983,7 +974,7 @@ static int mail_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv) smtpd_chat_reply(state, "503 Error: send HELO/EHLO first"); return (-1); } -#define IN_MAIL_TRANSACTION(state) ((state)->cleanup || (state)->proxy) +#define IN_MAIL_TRANSACTION(state) ((state)->sender != 0) if (IN_MAIL_TRANSACTION(state)) { state->error_mask |= MAIL_ERROR_PROTOCOL; @@ -998,7 +989,7 @@ static int mail_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv) } if (argv[2].tokval == SMTPD_TOK_ERROR) { state->error_mask |= MAIL_ERROR_PROTOCOL; - smtpd_chat_reply(state, "501 Bad address syntax"); + smtpd_chat_reply(state, "501 Bad sender address syntax"); return (-1); } if ((err = extract_addr(state, argv + 2, PERMIT_EMPTY_ADDR, var_strict_rfc821_env)) != 0) { @@ -1009,9 +1000,9 @@ static int mail_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv) for (narg = 3; narg < argc; narg++) { arg = argv[narg].strval; if (strcasecmp(arg, "BODY=8BITMIME") == 0) { /* RFC 1652 */ - encoding = MAIL_ATTR_ENC_8BIT; + state->encoding = MAIL_ATTR_ENC_8BIT; } else if (strcasecmp(arg, "BODY=7BIT") == 0) { /* RFC 1652 */ - encoding = MAIL_ATTR_ENC_7BIT; + state->encoding = MAIL_ATTR_ENC_7BIT; } else if (strncasecmp(arg, "SIZE=", 5) == 0) { /* RFC 1870 */ /* Reject non-numeric size. */ if (!alldig(arg + 5)) { @@ -1032,11 +1023,13 @@ static int mail_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv) return (-1); } #endif - } else if (namadr_list_match(verp_clients, state->name, state->addr)) { - if (strcasecmp(arg, VERP_CMD) == 0) { + } else if (namadr_list_match(verp_clients, ACL_NAME(state), + ACL_ADDR(state)) + && strncasecmp(arg, VERP_CMD, VERP_CMD_LEN) == 0 + && (arg[VERP_CMD_LEN] == '=' || arg[VERP_CMD_LEN] == 0)) { + if (arg[VERP_CMD_LEN] == 0) { verp_delims = var_verp_delims; - } else if (strncasecmp(arg, VERP_CMD, VERP_CMD_LEN) == 0 - && arg[VERP_CMD_LEN] == '=') { + } else { verp_delims = arg + VERP_CMD_LEN + 1; if (verp_delims_verify(verp_delims) != 0) { state->error_mask |= MAIL_ERROR_PROTOCOL; @@ -1065,28 +1058,26 @@ static int mail_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv) state->time = time((time_t *) 0); /* - * Open connection to SMTP proxy server. + * Check the queue file space, if applicable. */ - if (SMTPD_STAND_ALONE(state) == 0 && *var_smtpd_proxy_filt) { - if (smtpd_proxy_open(state, var_smtpd_proxy_filt, var_smtpd_proxy_tmout, - var_smtpd_proxy_ehlo, STR(state->buffer)) != 0) { - smtpd_chat_reply(state, "%s", STR(state->proxy_buffer)); +#define USE_SMTPD_PROXY(state) \ + (SMTPD_STAND_ALONE(state) == 0 && *var_smtpd_proxy_filt) + + if (!USE_SMTPD_PROXY(state)) { + if ((err = smtpd_check_size(state, state->msg_size)) != 0) { + smtpd_chat_reply(state, "%s", err); return (-1); } } /* - * Open queue file, or open connection to queue file writing process. - * Check for queue file space first. + * No more early returns. The mail transaction is in progress. */ - else { - if ((err = smtpd_check_size(state, state->msg_size)) != 0) { - smtpd_chat_reply(state, "%s", err); - return (-1); - } - mail_open_stream(state, argv, encoding, verp_delims); - } state->sender = mystrdup(argv[2].strval); + if (verp_delims) + state->verp_delims = mystrdup(verp_delims); + if (USE_SMTPD_PROXY(state)) + state->proxy_mail = mystrdup(STR(state->buffer)); smtpd_chat_reply(state, "250 Ok"); return (0); } @@ -1115,6 +1106,10 @@ static void mail_reset(SMTPD_STATE *state) myfree(state->sender); state->sender = 0; } + if (state->verp_delims) { + myfree(state->verp_delims); + state->verp_delims = 0; + } #ifdef USE_SASL_AUTH if (var_smtpd_sasl_enable) smtpd_sasl_mail_reset(state); @@ -1129,6 +1124,10 @@ static void mail_reset(SMTPD_STATE *state) (void) smtpd_proxy_cmd(state, SMTPD_PROX_WANT_NONE, "QUIT"); smtpd_proxy_close(state); } + if (state->proxy_mail) { + myfree(state->proxy_mail); + state->proxy_mail = 0; + } } /* rcpt_cmd - process RCPT TO command */ @@ -1161,7 +1160,7 @@ static int rcpt_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv) } if (argv[2].tokval == SMTPD_TOK_ERROR) { state->error_mask |= MAIL_ERROR_PROTOCOL; - smtpd_chat_reply(state, "501 Bad address syntax"); + smtpd_chat_reply(state, "501 Bad recipient address syntax"); return (-1); } if ((err = extract_addr(state, argv + 2, REJECT_EMPTY_ADDR, var_strict_rfc821_env)) != 0) { @@ -1188,6 +1187,21 @@ static int rcpt_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv) return (-1); } } + + /* + * Don't access the proxy, queue file, or queue file writer process until + * we have a valid recipient address. + */ + if (state->proxy == 0 && state->proxy_mail) { + if (smtpd_proxy_open(state, var_smtpd_proxy_filt, + var_smtpd_proxy_tmout, var_smtpd_proxy_ehlo, + state->proxy_mail) != 0) { + smtpd_chat_reply(state, "%s", STR(state->proxy_buffer)); + return (-1); + } + } else if (state->cleanup == 0) { + mail_open_stream(state, argv); + } if (state->proxy && smtpd_proxy_cmd(state, SMTPD_PROX_WANT_OK, "%s", STR(state->buffer)) != 0) { smtpd_chat_reply(state, "%s", STR(state->proxy_buffer)); @@ -1284,36 +1298,41 @@ static int data_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *unused_argv) * Terminate the message envelope segment. Start the message content * segment, and prepend our own Received: header. If there is only one * recipient, list the recipient address. + * + * Suppress our own Received: header in the unlikely case that we are an + * intermediate proxy. */ if (state->cleanup) rec_fputs(state->cleanup, REC_TYPE_MESG, ""); - out_fprintf(out_stream, REC_TYPE_NORM, - "Received: from %s (%s [%s])", - state->helo_name ? state->helo_name : state->name, - state->name, state->addr); - if (state->rcpt_count == 1 && state->recipient) { - out_fprintf(out_stream, REC_TYPE_NORM, - state->cleanup ? "\tby %s (%s) with %s id %s" : - "\tby %s (%s) with %s", - var_myhostname, var_mail_name, - state->protocol, state->queue_id); - quote_822_local(state->buffer, state->recipient); + if (!state->proxy || state->xclient.addr == 0) { out_fprintf(out_stream, REC_TYPE_NORM, + "Received: from %s (%s [%s])", + state->helo_name ? state->helo_name : state->name, + state->name, state->addr); + if (state->rcpt_count == 1 && state->recipient) { + out_fprintf(out_stream, REC_TYPE_NORM, + state->cleanup ? "\tby %s (%s) with %s id %s" : + "\tby %s (%s) with %s", + var_myhostname, var_mail_name, + state->protocol, state->queue_id); + quote_822_local(state->buffer, state->recipient); + out_fprintf(out_stream, REC_TYPE_NORM, "\tfor <%s>; %s", STR(state->buffer), mail_date(state->time)); - } else { - out_fprintf(out_stream, REC_TYPE_NORM, - state->cleanup ? "\tby %s (%s) with %s id %s;" : - "\tby %s (%s) with %s;", - var_myhostname, var_mail_name, - state->protocol, state->queue_id); - out_fprintf(out_stream, REC_TYPE_NORM, - "\t%s", mail_date(state->time)); - } + } else { + out_fprintf(out_stream, REC_TYPE_NORM, + state->cleanup ? "\tby %s (%s) with %s id %s;" : + "\tby %s (%s) with %s;", + var_myhostname, var_mail_name, + state->protocol, state->queue_id); + out_fprintf(out_stream, REC_TYPE_NORM, + "\t%s", mail_date(state->time)); + } #ifdef RECEIVED_ENVELOPE_FROM - quote_822_local(state->buffer, state->sender); - out_fprintf(out_stream, REC_TYPE_NORM, - "\t(envelope-from %s)", STR(state->buffer)); + quote_822_local(state->buffer, state->sender); + out_fprintf(out_stream, REC_TYPE_NORM, + "\t(envelope-from %s)", STR(state->buffer)); #endif + } smtpd_chat_reply(state, "354 End data with ."); /* @@ -1650,75 +1669,213 @@ static int quit_cmd(SMTPD_STATE *state, int unused_argc, SMTPD_TOKEN *unused_arg return (0); } -/* xaddr_cmd - process XADDR */ +/* xclient_cmd - process XCLIENT */ -static int xaddr_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv) +static int xclient_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv) { + int arg_no; + char *raw_value; + char *cooked_value; + char *arg_val; + int update_namaddr = 0; /* - * Sanity checks. + * Sanity checks. The XCLIENT command does not override its own access + * control. */ - if (namadr_list_match(xaddr_clients, state->name, state->addr) == 0) { + if (namadr_list_match(xclient_hosts, state->name, state->addr) == 0) { state->error_mask |= MAIL_ERROR_POLICY; smtpd_chat_reply(state, "554 Error: insufficient authorization"); return (-1); } - /* Todo: "XADDR address" to let Postfix look up the client name. */ - if (argc != 3 - || !valid_hostaddr(argv[1].strval, DONT_GRIPE) - || !valid_hostname(argv[2].strval, DONT_GRIPE)) { - state->error_mask |= MAIL_ERROR_PROTOCOL; - smtpd_chat_reply(state, "501 Syntax: %s address hostname", XADDR_CMD); - return (-1); +#define STREQ(x,y) (strcasecmp((x), (y)) == 0) +#define UPDATE_STR(s, v) { if (s) myfree(s); s = mystrdup(v); } + + /* + * Iterate over all XCLIENT arguments. + */ + for (arg_no = 1; arg_no < argc; arg_no++) { + arg_val = argv[arg_no].strval; + + /* + * Request name: what should happen with the stored attributes. + * Complain about unrecognized request names. The set of requests is + * unlikely to change. + */ + if ((raw_value = split_at(arg_val, '=')) == 0) { + printable(arg_val, '?'); + if (STREQ(arg_val, "RST")) { /* blow them away */ + smtpd_xclient_reset(state, XCLIENT_OVER_NONE); + } else if (STREQ(arg_val, "ACL")) { /* access control and logging */ + smtpd_xclient_reset(state, XCLIENT_OVER_ACL | XCLIENT_OVER_LOG); + } else if (STREQ(arg_val, "LOG")) { /* logging only */ + smtpd_xclient_reset(state, XCLIENT_OVER_LOG); + } else { /* error */ + state->error_mask |= MAIL_ERROR_PROTOCOL; + smtpd_chat_reply(state, "501 Bad request: %s", arg_val); + return (-1); + } + } + + /* + * NAME=VALUE attribute. Decode the attribute and for safety's sake + * mask non-printable characters in the raw and decoded values; we + * don't want to handle unexploded munitions. Do not complain about + * unrecognized attribute names. The set of attributes may change + * over time. + * + * The client can send multiple XCLIENT attributes in a single command, + * or multiple XCLIENT commands with fewer attributes. + * + * Note: XCLIENT ACL overrides only specific logging and access control + * attributes (desirable for testing), while XCLIENT LOG overrides + * all logging attributes (for audit trail consistency). + */ + else { + if (state->xclient.mode == 0) { + state->error_mask |= MAIL_ERROR_PROTOCOL; + smtpd_chat_reply(state, "503 Error: send %s ACL or LOG first", + XCLIENT_CMD); + return (-1); + } + if (xtext_unquote(state->buffer, raw_value) == 0) { + state->error_mask |= MAIL_ERROR_PROTOCOL; + smtpd_chat_reply(state, "501 Bad attribute value syntax: %s", + printable(raw_value, '?')); + return (-1); + } + cooked_value = printable(STR(state->buffer), '?'); + (void) printable(raw_value, '?'); + + /* + * CLIENT_NAME=hostname. Also updates the client hostname lookup + * status code. Treat a numerical hostname as an unavailable + * name. + */ + if (STREQ(arg_val, "CLIENT_NAME")) { + if (*raw_value && !valid_hostaddr(cooked_value, DONT_GRIPE)) { + if (!valid_hostname(cooked_value, DONT_GRIPE)) { + state->error_mask |= MAIL_ERROR_PROTOCOL; + smtpd_chat_reply(state, "501 Bad hostname syntax: %s", + cooked_value); + return (-1); + } + UPDATE_STR(state->xclient.name, cooked_value); + state->xclient.peer_code = SMTPD_PEER_CODE_OK; + } else { + UPDATE_STR(state->xclient.name, CLIENT_NAME_UNKNOWN); + state->xclient.peer_code = SMTPD_PEER_CODE_PERM; + } + update_namaddr = 1; + } + + /* + * CLIENT_ADDR=client network address. + */ + else if (STREQ(arg_val, "CLIENT_ADDR")) { + if (*raw_value) { + if (!valid_hostaddr(cooked_value, DONT_GRIPE)) { + state->error_mask |= MAIL_ERROR_PROTOCOL; + smtpd_chat_reply(state, "501 Bad address syntax: %s", + cooked_value); + return (-1); + } + UPDATE_STR(state->xclient.addr, cooked_value); + } else { + UPDATE_STR(state->xclient.name, CLIENT_NAME_UNKNOWN); + } + update_namaddr = 1; + } + + /* + * CLIENT_CODE=status. Reset the client hostname if the hostname + * lookup status is not OK. + */ + else if (STREQ(arg_val, "CLIENT_CODE")) { + if (STREQ(cooked_value, "OK")) { + state->xclient.peer_code = SMTPD_PEER_CODE_OK; + } else if (STREQ(cooked_value, "TEMP")) { + state->xclient.peer_code = SMTPD_PEER_CODE_TEMP; + UPDATE_STR(state->xclient.name, CLIENT_NAME_UNKNOWN); + update_namaddr = 1; + } else if (STREQ(cooked_value, "PERM")) { + state->xclient.peer_code = SMTPD_PEER_CODE_PERM; + UPDATE_STR(state->xclient.name, CLIENT_NAME_UNKNOWN); + update_namaddr = 1; + } else { + state->error_mask |= MAIL_ERROR_PROTOCOL; + smtpd_chat_reply(state, "501 Bad hostname status: %s", + cooked_value); + return (-1); + } + } + + /* + * HELO_NAME=hostname. An empty value means the information was + * not provided by the client and that we must not fall back to + * the non-XCLIENT value. Disallow characters that could mess up + * our own Received: message headers but allow []. + */ + else if (STREQ(arg_val, "HELO_NAME")) { + if (*raw_value) { + if (strlen(cooked_value) > VALID_HOSTNAME_LEN) { + state->error_mask |= MAIL_ERROR_PROTOCOL; + smtpd_chat_reply(state, "501 Bad HELO syntax: %s", + cooked_value); + return (-1); + } + neuter(cooked_value, "<>()\\\";:@", '?'); + UPDATE_STR(state->xclient.helo_name, cooked_value); + } else { + UPDATE_STR(state->xclient.helo_name, HELO_NAME_UNKNOWN); + } + } + + /* + * PROTOCOL=protocol name. Disallow characters that could mess up + * our own Received: message headers. + */ + else if (STREQ(arg_val, "PROTOCOL")) { + if (*raw_value) { + if (*cooked_value == 0 || strlen(cooked_value) > 64) { + state->error_mask |= MAIL_ERROR_PROTOCOL; + smtpd_chat_reply(state, "501 Bad protocol syntax: %s", + cooked_value); + return (-1); + } + neuter(cooked_value, "[]<>()\\\";:@", '?'); + UPDATE_STR(state->xclient.protocol, cooked_value); + } else { + UPDATE_STR(state->xclient.protocol, PROTOCOL_UNKNOWN); + } + } + + /* + * Unknown attribute name. Don't complain, and log a warning. + * Logging is safe because only authorized clients can issue + * XCLIENT commands. + */ + else { + msg_warn("unknown %s attribute from %s: %s=%s", + XCLIENT_CMD, state->namaddr, arg_val, cooked_value); + } + } } /* - * Change peer information for logging and for access control. Change a - * numerical hostname into "unknown", to make it easy to extract client - * information from Received: headers. + * Update the combined name and address when either has changed. */ -#define FIX_NUMERICAL_NAME(s) \ - (valid_hostaddr((s), DONT_GRIPE) ? "unknown" : (s)) +#define MAYBE_OVERRIDE(state, attr) \ + ((state)->xclient.attr ? (state)->xclient.attr : (state)->attr) - smtpd_peer_reset(state); - state->name = mystrdup(FIX_NUMERICAL_NAME(argv[2].strval)); - state->addr = mystrdup(argv[1].strval); - state->namaddr = - concatenate(state->name, "[", state->addr, "]", (char *) 0); - state->peer_code = strcmp(state->name, "unknown") ? 2 : 5; - smtpd_chat_reply(state, "250 Ok"); - return (0); -} - -/* xloginfo_cmd - process XLOGINFO */ - -static int xloginfo_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv) -{ - - /* - * Sanity checks. - */ - if (namadr_list_match(xloginfo_clients, state->name, state->addr) == 0) { - state->error_mask |= MAIL_ERROR_POLICY; - smtpd_chat_reply(state, "554 Error: insufficient authorization"); - return (-1); + if (update_namaddr) { + if (state->xclient.namaddr) + myfree(state->xclient.namaddr); + state->xclient.namaddr = + concatenate(MAYBE_OVERRIDE(state, name), "[", + MAYBE_OVERRIDE(state, addr), "]", + (char *) 0); } - if (argc != 3 - || !valid_hostaddr(argv[1].strval, DONT_GRIPE) - || !valid_hostname(argv[2].strval, DONT_GRIPE)) { - state->error_mask |= MAIL_ERROR_PROTOCOL; - smtpd_chat_reply(state, "501 Syntax: %s address hostname", XLOGINFO_CMD); - return (-1); - } - - /* - * Change peer information for logging but not for access control. Change - * a numerical hostname into "unknown", for consistency with XADDR. - */ - myfree(state->namaddr); - state->namaddr = - concatenate(FIX_NUMERICAL_NAME(argv[2].strval), - "[", argv[1].strval, "]", (char *) 0); smtpd_chat_reply(state, "250 Ok"); return (0); } @@ -1774,8 +1931,7 @@ static SMTPD_CMD smtpd_cmd_table[] = { "VRFY", vrfy_cmd, SMTPD_CMD_FLAG_LIMIT, "ETRN", etrn_cmd, SMTPD_CMD_FLAG_LIMIT, "QUIT", quit_cmd, 0, - "XADDR", xaddr_cmd, SMTPD_CMD_FLAG_LIMIT, - "XLOGINFO", xloginfo_cmd, SMTPD_CMD_FLAG_LIMIT, + "XCLIENT", xclient_cmd, SMTPD_CMD_FLAG_LIMIT, "Received:", 0, SMTPD_CMD_FLAG_FORBIDDEN, "Reply-To:", 0, SMTPD_CMD_FLAG_FORBIDDEN, "Message-ID:", 0, SMTPD_CMD_FLAG_FORBIDDEN, @@ -1835,6 +1991,12 @@ static void smtpd_proto(SMTPD_STATE *state, const char *service) break; case 0: + + /* + * XXX The client connection count/rate control uses the real client + * name/address to maintain consistency between connect and + * disconnect events. + */ if (SMTPD_STAND_ALONE(state) == 0 && anvil_clnt && !namadr_list_match(hogger_list, state->name, state->addr) @@ -1855,6 +2017,7 @@ static void smtpd_proto(SMTPD_STATE *state, const char *service) break; } } + /* XXX We use the real client for connect access control. */ if (SMTPD_STAND_ALONE(state) == 0 && var_smtpd_delay_reject == 0 && (state->access_denied = smtpd_check_client(state)) != 0) { @@ -1900,6 +2063,7 @@ static void smtpd_proto(SMTPD_STATE *state, const char *service) smtpd_chat_reply(state, "221 Error: I can break rules, too. Goodbye."); break; } + /* XXX We use the real client for connect access control. */ if (state->access_denied && cmdp->action != quit_cmd) { smtpd_chat_reply(state, "503 Error: access denied for %s", state->namaddr); /* RFC 2821 Sec 3.1 */ @@ -1917,6 +2081,12 @@ static void smtpd_proto(SMTPD_STATE *state, const char *service) } break; } + + /* + * XXX The client connection count/rate control uses the real client + * name/address to maintain consistency between connect and disconnect + * events. + */ if (SMTPD_STAND_ALONE(state) == 0 && anvil_clnt && !namadr_list_match(hogger_list, state->name, state->addr)) @@ -2014,8 +2184,7 @@ static void pre_jail_init(char *unused_name, char **unused_argv) */ smtpd_noop_cmds = string_list_init(MATCH_FLAG_NONE, var_smtpd_noop_cmds); verp_clients = namadr_list_init(MATCH_FLAG_NONE, var_verp_clients); - xaddr_clients = namadr_list_init(MATCH_FLAG_NONE, var_xaddr_clients); - xloginfo_clients = namadr_list_init(MATCH_FLAG_NONE, var_xloginfo_clients); + xclient_hosts = namadr_list_init(MATCH_FLAG_NONE, var_xclient_hosts); hogger_list = namadr_list_init(MATCH_FLAG_NONE, var_smtpd_hoggers); if (getuid() == 0 || getuid() == var_owner_uid) smtpd_check_init(); @@ -2153,8 +2322,7 @@ int main(int argc, char **argv) VAR_SMTPD_PROXY_FILT, DEF_SMTPD_PROXY_FILT, &var_smtpd_proxy_filt, 0, 0, VAR_SMTPD_PROXY_EHLO, DEF_SMTPD_PROXY_EHLO, &var_smtpd_proxy_ehlo, 0, 0, VAR_INPUT_TRANSP, DEF_INPUT_TRANSP, &var_input_transp, 0, 0, - VAR_XADDR_CLIENTS, DEF_XADDR_CLIENTS, &var_xaddr_clients, 0, 0, - VAR_XLOGINFO_CLIENTS, DEF_XLOGINFO_CLIENTS, &var_xloginfo_clients, 0, 0, + VAR_XCLIENT_HOSTS, DEF_XCLIENT_HOSTS, &var_xclient_hosts, 0, 0, VAR_SMTPD_HOGGERS, DEF_SMTPD_HOGGERS, &var_smtpd_hoggers, 0, 0, 0, }; diff --git a/postfix/src/smtpd/smtpd.h b/postfix/src/smtpd/smtpd.h index 40438248a..0b418f59c 100644 --- a/postfix/src/smtpd/smtpd.h +++ b/postfix/src/smtpd/smtpd.h @@ -45,6 +45,16 @@ typedef struct SMTPD_DEFER { int class; /* error notification class */ } SMTPD_DEFER; +typedef struct SMTPD_XCLIENT_ATTR { + int mode; /* none, log, acl */ + char *name; /* name for access control */ + char *addr; /* address for access control */ + char *namaddr; /* name[address] */ + int peer_code; /* name status */ + char *protocol; /* email protocol */ + char *helo_name; /* helo/ehlo parameter */ +} SMTPD_XCLIENT_ATTR; + typedef struct SMTPD_STATE { int err; VSTREAM *client; @@ -66,6 +76,8 @@ typedef struct SMTPD_STATE { ARGV *history; char *reason; char *sender; + char *encoding; + char *verp_delims; char *recipient; char *etrn_name; char *protocol; @@ -97,6 +109,9 @@ typedef struct SMTPD_STATE { VSTRING *expand_buf; /* scratch space for $name expansion */ VSTREAM *proxy; /* proxy handle */ VSTRING *proxy_buffer; /* proxy query/reply buffer */ + char *proxy_mail; /* proxy MAIL FROM command */ + int proxy_features; /* proxy ESMTP features */ + SMTPD_XCLIENT_ATTR xclient; /* override access control */ } SMTPD_STATE; extern void smtpd_state_init(SMTPD_STATE *, VSTREAM *); @@ -117,22 +132,55 @@ extern void smtpd_state_reset(SMTPD_STATE *); (state->client == VSTREAM_IN && getuid() != var_owner_uid) /* - * SMPTD peer information lookup. + * SMTPD peer information lookup. */ extern void smtpd_peer_init(SMTPD_STATE *state); extern void smtpd_peer_reset(SMTPD_STATE *state); +#define SMTPD_PEER_CODE_OK 2 +#define SMTPD_PEER_CODE_TEMP 4 +#define SMTPD_PEER_CODE_PERM 5 + + /* + * XCLIENT support to override logging and/or access control attributes. It + * makes no sense to maintain separate attribute sets for XCLIENT LOG or + * XCLIENT ACL, so we set a flag to distinguish purpose. + */ +#define XCLIENT_CMD "XCLIENT" /* XCLIENT command */ +#define XCLIENT_EHLO "XCLIENT" /* ESMTP advertisement */ + +#define SMTPD_FEATURE_XCLIENT (1<<0) /* server supports XCLIENT */ + +#define XCLIENT_OVER_NONE (0) /* override reset */ +#define XCLIENT_OVER_ACL (1<<0) /* override access control */ +#define XCLIENT_OVER_LOG (1<<1) /* override logging */ + +#define XCLIENT_OVER(s, m, a) \ + (((s)->xclient.mode & (m)) && (s)->xclient.a ? (s)->xclient.a : (s)->a) + +#define ACL_ADDR(s) XCLIENT_OVER((s), XCLIENT_OVER_ACL, addr) +#define ACL_NAME(s) XCLIENT_OVER((s), XCLIENT_OVER_ACL, name) +#define ACL_NAMADDR(s) XCLIENT_OVER((s), XCLIENT_OVER_ACL, namaddr) +#define ACL_PEER_CODE(s) XCLIENT_OVER((s), XCLIENT_OVER_ACL, peer_code) +#define ACL_PROTOCOL(s) XCLIENT_OVER((s), XCLIENT_OVER_ACL, protocol) +#define ACL_HELO_NAME(s) XCLIENT_OVER((s), XCLIENT_OVER_ACL, helo_name) + +#define LOG_ADDR(s) XCLIENT_OVER((s), XCLIENT_OVER_LOG, addr) +#define LOG_NAME(s) XCLIENT_OVER((s), XCLIENT_OVER_LOG, name) +#define LOG_NAMADDR(s) XCLIENT_OVER((s), XCLIENT_OVER_LOG, namaddr) +#define LOG_PEER_CODE(s) XCLIENT_OVER((s), XCLIENT_OVER_LOG, peer_code) +#define LOG_PROTOCOL(s) XCLIENT_OVER((s), XCLIENT_OVER_LOG, protocol) +#define LOG_HELO_NAME(s) XCLIENT_OVER((s), XCLIENT_OVER_LOG, helo_name) + +extern void smtpd_xclient_init(SMTPD_STATE *state); +extern void smtpd_xclient_reset(SMTPD_STATE *state, int); + /* * Transparency: before mail is queued, do we check for unknown recipients, * do we allow address mapping, automatic bcc, header/body checks? */ extern int smtpd_input_transp_mask; - /* - * XLOGINFO command. - */ -#define XLOGINFO_CMD "XLOGINFO" - /* LICENSE /* .ad /* .fi diff --git a/postfix/src/smtpd/smtpd_check.c b/postfix/src/smtpd/smtpd_check.c index da755fc8e..b1688b59a 100644 --- a/postfix/src/smtpd/smtpd_check.c +++ b/postfix/src/smtpd/smtpd_check.c @@ -809,15 +809,15 @@ static void log_whatsup(SMTPD_STATE *state, const char *whatsup, vstring_sprintf(buf, "%s: %s: %s from %s: %s;", state->queue_id ? state->queue_id : "NOQUEUE", - whatsup, state->where, state->namaddr, text); + whatsup, state->where, LOG_NAMADDR(state), text); if (state->sender) vstring_sprintf_append(buf, " from=<%s>", state->sender); if (state->recipient) vstring_sprintf_append(buf, " to=<%s>", state->recipient); - if (state->protocol) - vstring_sprintf_append(buf, " proto=%s", state->protocol); - if (state->helo_name) - vstring_sprintf_append(buf, " helo=<%s>", state->helo_name); + if (!IS_UNK_PROTOCOL(ACL_PROTOCOL(state))) + vstring_sprintf_append(buf, " proto=%s", ACL_PROTOCOL(state)); + if (!IS_UNK_HELO_NAME(ACL_HELO_NAME(state))) + vstring_sprintf_append(buf, " helo=<%s>", ACL_HELO_NAME(state)); msg_info("%s", STR(buf)); vstring_free(buf); } @@ -968,14 +968,14 @@ static int reject_unknown_client(SMTPD_STATE *state) char *myname = "reject_unknown_client"; if (msg_verbose) - msg_info("%s: %s %s", myname, state->name, state->addr); + msg_info("%s: %s %s", myname, ACL_NAME(state), ACL_ADDR(state)); - if (strcasecmp(state->name, "unknown") == 0) + if (IS_UNK_CLNT_NAME(ACL_NAME(state))) return (smtpd_check_reject(state, MAIL_ERROR_POLICY, "%d Client host rejected: cannot find your hostname, [%s]", - state->peer_code == 5 ? + ACL_PEER_CODE(state) == SMTPD_PEER_CODE_PERM ? var_unk_client_code : 450, - state->addr)); + ACL_ADDR(state))); return (SMTPD_CHECK_DUNNO); } @@ -986,9 +986,9 @@ static int permit_mynetworks(SMTPD_STATE *state) char *myname = "permit_mynetworks"; if (msg_verbose) - msg_info("%s: %s %s", myname, state->name, state->addr); + msg_info("%s: %s %s", myname, ACL_NAME(state), ACL_ADDR(state)); - if (namadr_list_match(mynetworks, state->name, state->addr)) + if (namadr_list_match(mynetworks, ACL_NAME(state), ACL_ADDR(state))) return (SMTPD_CHECK_OK); return (SMTPD_CHECK_DUNNO); } @@ -1207,7 +1207,7 @@ static int check_relay_domains(SMTPD_STATE *state, char *recipient, /* * Permit if the client matches the relay_domains list. */ - if (domain_list_match(relay_domains, state->name)) + if (domain_list_match(relay_domains, ACL_NAME(state))) return (SMTPD_CHECK_OK); /* @@ -1309,7 +1309,7 @@ static int reject_unauth_pipelining(SMTPD_STATE *state, if (state->client != 0 && SMTPD_STAND_ALONE(state) == 0 && vstream_peek(state->client) > 0 - && (strcasecmp(state->protocol, "ESMTP") != 0 + && (strcasecmp(ACL_PROTOCOL(state), MAIL_PROTO_ESMTP) != 0 || strcasecmp(state->where, "DATA") == 0)) { return (smtpd_check_reject(state, MAIL_ERROR_PROTOCOL, "503 <%s>: %s rejected: Improper use of SMTP command pipelining", @@ -2518,13 +2518,14 @@ static const char *smtpd_expand_lookup(const char *name, int unused_mode, * Return NULL only for non-existent names. */ if (STREQ(name, MAIL_ATTR_CLIENT)) { - return (state->namaddr); + return (ACL_NAMADDR(state)); } else if (STREQ(name, MAIL_ATTR_CLIENT_ADDR)) { - return (state->addr); + return (ACL_ADDR(state)); } else if (STREQ(name, MAIL_ATTR_CLIENT_NAME)) { - return (state->name); + return (ACL_NAME(state)); } else if (STREQ(name, MAIL_ATTR_HELO_NAME)) { - return (state->helo_name ? state->helo_name : ""); + return (IS_UNK_HELO_NAME(ACL_HELO_NAME(state)) ? + "" : ACL_HELO_NAME(state)); } else if (STREQN(name, MAIL_ATTR_SENDER, CONST_LEN(MAIL_ATTR_SENDER))) { return (smtpd_expand_addr(state->expand_buf, state->sender, name, CONST_LEN(MAIL_ATTR_SENDER))); @@ -2820,7 +2821,7 @@ static int reject_maps_rbl(SMTPD_STATE *state) static int warned; if (msg_verbose) - msg_info("%s: %s", myname, state->addr); + msg_info("%s: %s", myname, ACL_ADDR(state)); if (warned == 0) { warned++; @@ -2829,7 +2830,7 @@ static int reject_maps_rbl(SMTPD_STATE *state) REJECT_MAPS_RBL, var_mail_name, REJECT_RBL_CLIENT); } while ((rbl_domain = mystrtok(&bp, " \t\r\n,")) != 0) { - result = reject_rbl_addr(state, rbl_domain, state->addr, + result = reject_rbl_addr(state, rbl_domain, ACL_ADDR(state), SMTPD_NAME_CLIENT); if (result != SMTPD_CHECK_DUNNO) break; @@ -2906,11 +2907,12 @@ static int check_policy_service(SMTPD_STATE *state, const char *server, ATTR_FLAG_NONE, /* Query attributes. */ ATTR_TYPE_STR, MAIL_ATTR_REQ, "smtpd_access_policy", ATTR_TYPE_STR, MAIL_ATTR_PROTO_STATE, state->where, - ATTR_TYPE_STR, MAIL_ATTR_PROTO_NAME, state->protocol, - ATTR_TYPE_STR, MAIL_ATTR_CLIENT_ADDR, state->addr, - ATTR_TYPE_STR, MAIL_ATTR_CLIENT_NAME, state->name, + ATTR_TYPE_STR, MAIL_ATTR_PROTO_NAME, ACL_PROTOCOL(state), + ATTR_TYPE_STR, MAIL_ATTR_CLIENT_ADDR, ACL_ADDR(state), + ATTR_TYPE_STR, MAIL_ATTR_CLIENT_NAME, ACL_NAME(state), ATTR_TYPE_STR, MAIL_ATTR_HELO_NAME, - state->helo_name ? state->helo_name : "", + IS_UNK_HELO_NAME(ACL_HELO_NAME(state)) ? + "" : ACL_HELO_NAME(state), ATTR_TYPE_STR, MAIL_ATTR_SENDER, state->sender ? state->sender : "", ATTR_TYPE_STR, MAIL_ATTR_RECIP, @@ -3075,8 +3077,8 @@ static int generic_checks(SMTPD_STATE *state, ARGV *restrictions, } else if (strcasecmp(name, PERMIT_MYNETWORKS) == 0) { status = permit_mynetworks(state); } else if (is_map_command(state, name, CHECK_CLIENT_ACL, &cpp)) { - status = check_namadr_access(state, *cpp, state->name, state->addr, - FULL, &found, state->namaddr, + status = check_namadr_access(state, *cpp, ACL_NAME(state), ACL_ADDR(state), + FULL, &found, ACL_NAMADDR(state), SMTPD_NAME_CLIENT, def_acl); } else if (strcasecmp(name, REJECT_MAPS_RBL) == 0) { status = reject_maps_rbl(state); @@ -3085,7 +3087,7 @@ static int generic_checks(SMTPD_STATE *state, ARGV *restrictions, if (cpp[1] == 0) msg_warn("restriction %s requires domain name argument", name); else - status = reject_rbl_addr(state, *(cpp += 1), state->addr, + status = reject_rbl_addr(state, *(cpp += 1), ACL_ADDR(state), SMTPD_NAME_CLIENT); } else if (strcasecmp(name, REJECT_RHSBL_CLIENT) == 0) { if (cpp[1] == 0) @@ -3093,69 +3095,73 @@ static int generic_checks(SMTPD_STATE *state, ARGV *restrictions, name); else { cpp += 1; - if (strcasecmp(state->name, "unknown") != 0) - status = reject_rbl_domain(state, *cpp, state->name, + if (!IS_UNK_CLNT_NAME(ACL_NAME(state))) + status = reject_rbl_domain(state, *cpp, ACL_NAME(state), SMTPD_NAME_CLIENT); } } /* * HELO/EHLO parameter restrictions. + * + * XXX With XCLIENT overrides, a zero-length name means the client did + * not send a HELO/EHLO command. Do not fall back to the non-XCLIENT + * HELO/EHLO value. */ else if (is_map_command(state, name, CHECK_HELO_ACL, &cpp)) { - if (state->helo_name) - status = check_domain_access(state, *cpp, state->helo_name, - FULL, &found, state->helo_name, + if (!IS_UNK_HELO_NAME(ACL_HELO_NAME(state))) + status = check_domain_access(state, *cpp, ACL_HELO_NAME(state), + FULL, &found, ACL_HELO_NAME(state), SMTPD_NAME_HELO, def_acl); } else if (strcasecmp(name, REJECT_INVALID_HOSTNAME) == 0) { - if (state->helo_name) { - if (*state->helo_name != '[') - status = reject_invalid_hostname(state, state->helo_name, - state->helo_name, SMTPD_NAME_HELO); + if (!IS_UNK_HELO_NAME(ACL_HELO_NAME(state))) { + if (*ACL_HELO_NAME(state) != '[') + status = reject_invalid_hostname(state, ACL_HELO_NAME(state), + ACL_HELO_NAME(state), SMTPD_NAME_HELO); else - status = reject_invalid_hostaddr(state, state->helo_name, - state->helo_name, SMTPD_NAME_HELO); + status = reject_invalid_hostaddr(state, ACL_HELO_NAME(state), + ACL_HELO_NAME(state), SMTPD_NAME_HELO); } } else if (strcasecmp(name, REJECT_UNKNOWN_HOSTNAME) == 0) { - if (state->helo_name) { - if (*state->helo_name != '[') - status = reject_unknown_hostname(state, state->helo_name, - state->helo_name, SMTPD_NAME_HELO); + if (!IS_UNK_HELO_NAME(ACL_HELO_NAME(state))) { + if (*ACL_HELO_NAME(state) != '[') + status = reject_unknown_hostname(state, ACL_HELO_NAME(state), + ACL_HELO_NAME(state), SMTPD_NAME_HELO); else - status = reject_invalid_hostaddr(state, state->helo_name, - state->helo_name, SMTPD_NAME_HELO); + status = reject_invalid_hostaddr(state, ACL_HELO_NAME(state), + ACL_HELO_NAME(state), SMTPD_NAME_HELO); } } else if (strcasecmp(name, PERMIT_NAKED_IP_ADDR) == 0) { msg_warn("restriction %s is deprecated. Use %s instead", PERMIT_NAKED_IP_ADDR, PERMIT_MYNETWORKS); - if (state->helo_name) { - if (state->helo_name[strspn(state->helo_name, "0123456789.")] == 0 - && (status = reject_invalid_hostaddr(state, state->helo_name, - state->helo_name, SMTPD_NAME_HELO)) == 0) + if (!IS_UNK_HELO_NAME(ACL_HELO_NAME(state))) { + if (ACL_HELO_NAME(state)[strspn(ACL_HELO_NAME(state), "0123456789.")] == 0 + && (status = reject_invalid_hostaddr(state, ACL_HELO_NAME(state), + ACL_HELO_NAME(state), SMTPD_NAME_HELO)) == 0) status = SMTPD_CHECK_OK; } } else if (is_map_command(state, name, CHECK_HELO_NS_ACL, &cpp)) { - if (state->helo_name) { - status = check_server_access(state, *cpp, state->helo_name, - T_NS, state->helo_name, + if (!IS_UNK_HELO_NAME(ACL_HELO_NAME(state))) { + status = check_server_access(state, *cpp, ACL_HELO_NAME(state), + T_NS, ACL_HELO_NAME(state), SMTPD_NAME_HELO, def_acl); - forbid_whitelist(state, name, status, state->helo_name); + forbid_whitelist(state, name, status, ACL_HELO_NAME(state)); } } else if (is_map_command(state, name, CHECK_HELO_MX_ACL, &cpp)) { - if (state->helo_name) { - status = check_server_access(state, *cpp, state->helo_name, - T_MX, state->helo_name, + if (!IS_UNK_HELO_NAME(ACL_HELO_NAME(state))) { + status = check_server_access(state, *cpp, ACL_HELO_NAME(state), + T_MX, ACL_HELO_NAME(state), SMTPD_NAME_HELO, def_acl); - forbid_whitelist(state, name, status, state->helo_name); + forbid_whitelist(state, name, status, ACL_HELO_NAME(state)); } } else if (strcasecmp(name, REJECT_NON_FQDN_HOSTNAME) == 0) { - if (state->helo_name) { - if (*state->helo_name != '[') - status = reject_non_fqdn_hostname(state, state->helo_name, - state->helo_name, SMTPD_NAME_HELO); + if (!IS_UNK_HELO_NAME(ACL_HELO_NAME(state))) { + if (*ACL_HELO_NAME(state) != '[') + status = reject_non_fqdn_hostname(state, ACL_HELO_NAME(state), + ACL_HELO_NAME(state), SMTPD_NAME_HELO); else - status = reject_invalid_hostaddr(state, state->helo_name, - state->helo_name, SMTPD_NAME_HELO); + status = reject_invalid_hostaddr(state, ACL_HELO_NAME(state), + ACL_HELO_NAME(state), SMTPD_NAME_HELO); } } else if (strcasecmp(name, REJECT_RHSBL_HELO) == 0) { if (cpp[1] == 0) @@ -3163,8 +3169,8 @@ static int generic_checks(SMTPD_STATE *state, ARGV *restrictions, name); else { cpp += 1; - if (state->helo_name) - status = reject_rbl_domain(state, *cpp, state->helo_name, + if (!IS_UNK_HELO_NAME(ACL_HELO_NAME(state))) + status = reject_rbl_domain(state, *cpp, ACL_HELO_NAME(state), SMTPD_NAME_HELO); } } @@ -3361,7 +3367,7 @@ char *smtpd_check_client(SMTPD_STATE *state) /* * Initialize. */ - if (state->name == 0 || state->addr == 0) + if (ACL_NAME(state) == 0 || ACL_ADDR(state) == 0) return (0); #define SMTPD_CHECK_RESET() { \ @@ -3381,7 +3387,7 @@ char *smtpd_check_client(SMTPD_STATE *state) SMTPD_CHECK_RESET(); status = setjmp(smtpd_check_buf); if (status == 0 && client_restrctions->argc) - status = generic_checks(state, client_restrctions, state->namaddr, + status = generic_checks(state, client_restrctions, ACL_NAMADDR(state), SMTPD_NAME_CLIENT, CHECK_CLIENT_ACL); state->defer_if_permit_client = state->defer_if_permit.active; @@ -3435,7 +3441,7 @@ char *smtpd_check_helo(SMTPD_STATE *state, char *helohost) SMTPD_CHECK_RESET(); status = setjmp(smtpd_check_buf); if (status == 0 && helo_restrctions->argc) - status = generic_checks(state, helo_restrctions, state->helo_name, + status = generic_checks(state, helo_restrctions, ACL_HELO_NAME(state), SMTPD_NAME_HELO, CHECK_HELO_ACL); state->defer_if_permit_helo = state->defer_if_permit.active; @@ -3547,7 +3553,7 @@ char *smtpd_check_rcpt(SMTPD_STATE *state, char *recipient) */ if (var_smtpd_delay_reject) if ((err = smtpd_check_client(state)) != 0 - || (err = smtpd_check_helo(state, state->helo_name)) != 0 + || (err = smtpd_check_helo(state, ACL_HELO_NAME(state))) != 0 || (err = smtpd_check_mail(state, state->sender)) != 0) SMTPD_CHECK_RCPT_RETURN(err); @@ -3616,7 +3622,7 @@ char *smtpd_check_etrn(SMTPD_STATE *state, char *domain) */ if (var_smtpd_delay_reject) if ((err = smtpd_check_client(state)) != 0 - || (err = smtpd_check_helo(state, state->helo_name)) != 0) + || (err = smtpd_check_helo(state, ACL_HELO_NAME(state))) != 0) SMTPD_CHECK_ETRN_RETURN(err); /* @@ -4316,7 +4322,7 @@ int main(int argc, char **argv) if (args->argc == 4) state.peer_code = atoi(args->argv[3]); else - state.peer_code = 2; + state.peer_code = SMTPD_PEER_CODE_OK; if (state.namaddr) myfree(state.namaddr); state.namaddr = concatenate(state.name, "[", state.addr, diff --git a/postfix/src/smtpd/smtpd_peer.c b/postfix/src/smtpd/smtpd_peer.c index 583c6ebcc..28c127f2a 100644 --- a/postfix/src/smtpd/smtpd_peer.c +++ b/postfix/src/smtpd/smtpd_peer.c @@ -93,6 +93,7 @@ static int h_errno = TRY_AGAIN; /* Global library. */ +#include /* Application-specific. */ @@ -124,9 +125,9 @@ void smtpd_peer_init(SMTPD_STATE *state) * If peer went away, give up. */ if (errno == ECONNRESET || errno == ECONNABORTED) { - state->name = mystrdup("unknown"); - state->addr = mystrdup("unknown"); - state->peer_code = 5; + state->name = mystrdup(CLIENT_NAME_UNKNOWN); + state->addr = mystrdup(CLIENT_ADDR_UNKNOWN); + state->peer_code = SMTPD_PEER_CODE_PERM; } /* @@ -137,26 +138,27 @@ void smtpd_peer_init(SMTPD_STATE *state) hp = gethostbyaddr((char *) &(sin.sin_addr), sizeof(sin.sin_addr), AF_INET); if (hp == 0) { - state->name = mystrdup("unknown"); - state->peer_code = (h_errno == TRY_AGAIN ? 4 : 5); + state->name = mystrdup(CLIENT_NAME_UNKNOWN); + state->peer_code = (h_errno == TRY_AGAIN ? + SMTPD_PEER_CODE_TEMP : SMTPD_PEER_CODE_PERM); } else if (valid_hostaddr(hp->h_name, DONT_GRIPE)) { msg_warn("numeric result %s in address->name lookup for %s", hp->h_name, state->addr); - state->name = mystrdup("unknown"); - state->peer_code = 5; + state->name = mystrdup(CLIENT_NAME_UNKNOWN); + state->peer_code = SMTPD_PEER_CODE_PERM; } else if (!valid_hostname(hp->h_name, DONT_GRIPE)) { - state->name = mystrdup("unknown"); - state->peer_code = 5; + state->name = mystrdup(CLIENT_NAME_UNKNOWN); + state->peer_code = SMTPD_PEER_CODE_PERM; } else { state->name = mystrdup(hp->h_name); /* hp->name is clobbered!! */ - state->peer_code = 2; + state->peer_code = SMTPD_PEER_CODE_OK; /* * Reject the hostname if it does not list the peer address. */ #define REJECT_PEER_NAME(state, code) { \ myfree(state->name); \ - state->name = mystrdup("unknown"); \ + state->name = mystrdup(CLIENT_NAME_UNKNOWN); \ state->peer_code = code; \ } @@ -164,17 +166,18 @@ void smtpd_peer_init(SMTPD_STATE *state) if (hp == 0) { msg_warn("%s: hostname %s verification failed: %s", state->addr, state->name, HSTRERROR(h_errno)); - REJECT_PEER_NAME(state, (h_errno == TRY_AGAIN ? 4 : 5)); + REJECT_PEER_NAME(state, (h_errno == TRY_AGAIN ? + SMTPD_PEER_CODE_TEMP : SMTPD_PEER_CODE_PERM)); } else if (hp->h_length != sizeof(sin.sin_addr)) { msg_warn("%s: hostname %s verification failed: bad address size %d", state->addr, state->name, hp->h_length); - REJECT_PEER_NAME(state, 5); + REJECT_PEER_NAME(state, SMTPD_PEER_CODE_PERM); } else { for (i = 0; /* void */ ; i++) { if (hp->h_addr_list[i] == 0) { msg_warn("%s: address not listed for hostname %s", state->addr, state->name); - REJECT_PEER_NAME(state, 5); + REJECT_PEER_NAME(state, SMTPD_PEER_CODE_PERM); break; } if (memcmp(hp->h_addr_list[i], @@ -193,7 +196,7 @@ void smtpd_peer_init(SMTPD_STATE *state) else { state->name = mystrdup("localhost"); state->addr = mystrdup("127.0.0.1"); /* XXX bogus. */ - state->peer_code = 2; + state->peer_code = SMTPD_PEER_CODE_OK; } /* diff --git a/postfix/src/smtpd/smtpd_proxy.c b/postfix/src/smtpd/smtpd_proxy.c index ec532dddd..3999c993b 100644 --- a/postfix/src/smtpd/smtpd_proxy.c +++ b/postfix/src/smtpd/smtpd_proxy.c @@ -51,12 +51,12 @@ /* have the same interface as the routines that are used for non-proxied /* mail. /* -/* smtpd_proxy_open() should be called after receiving the MAIL FROM -/* command. It connects to the proxy service, sends EHLO, sends the -/* MAIL FROM command, and receives the reply. A non-zero result means +/* smtpd_proxy_open() connects to the proxy service, sends EHLO, sends +/* client information with the XCLIENT command if possible, sends +/* the MAIL FROM command, and receives the reply. A non-zero result means /* trouble: either the proxy is unavailable, or it did not send the /* expected reply. -/* All results are reported via the state->proxy_buffer field in a form +/* The result is reported via the state->proxy_buffer field in a form /* that can be sent to the SMTP client. In case of error, the /* state->error_mask and state->err fields are updated. /* A state->proxy_buffer field is created automatically; this field @@ -155,6 +155,8 @@ #include #include #include +#include +#include /* Application-specific. */ @@ -168,7 +170,7 @@ #define LEN(x) VSTRING_LEN(x) #define SMTPD_PROXY_CONNECT ((char *) 0) -/* smtpd_proxy_open - open proxy connection after MAIL FROM */ +/* smtpd_proxy_open - open proxy connection */ int smtpd_proxy_open(SMTPD_STATE *state, const char *service, int timeout, const char *ehlo_name, @@ -177,6 +179,8 @@ int smtpd_proxy_open(SMTPD_STATE *state, const char *service, int fd; char *lines; char *line; + VSTRING *buf; + int bad; /* * This buffer persists beyond the end of a proxy session so we can @@ -205,7 +209,8 @@ int smtpd_proxy_open(SMTPD_STATE *state, const char *service, * * If this fails then we have a problem because the proxy should always * accept our connection. Make up our own response instead of passing - * back the greeting banner: the client expects a MAIL FROM reply. + * back the greeting banner: the proxy open might be delayed to the point + * that the client expects a MAIL FROM or RCPT TO reply. */ if (smtpd_proxy_cmd(state, SMTPD_PROX_WANT_OK, SMTPD_PROXY_CONNECT) != 0) { vstring_sprintf(state->proxy_buffer, @@ -217,8 +222,9 @@ int smtpd_proxy_open(SMTPD_STATE *state, const char *service, /* * Send our own EHLO command. If this fails then we have a problem * because the proxy should always accept our EHLO command. Make up our - * own response instead of passing back the EHLO reply: the client - * expects a MAIL FROM reply. + * own response instead of passing back the EHLO reply: the proxy open + * might be delayed to the point that the client expects a MAIL FROM or + * RCPT TO reply. */ if (smtpd_proxy_cmd(state, SMTPD_PROX_WANT_OK, "EHLO %s", ehlo_name) != 0) { vstring_sprintf(state->proxy_buffer, @@ -228,17 +234,46 @@ int smtpd_proxy_open(SMTPD_STATE *state, const char *service, } /* - * Parse the EHLO reply and see if we can forward the client hostname and - * address info for logging purposes. If the command fails, then proceed. - * It is not the end of the world. + * Parse the EHLO reply and see if we can forward logging information. */ + state->proxy_features = 0; lines = STR(state->proxy_buffer); while ((line = mystrtok(&lines, "\n")) != 0) if (ISDIGIT(line[0]) && ISDIGIT(line[1]) && ISDIGIT(line[2]) && (line[3] == ' ' || line[3] == '-') - && strcmp(line + 4, XLOGINFO_CMD) == 0) - (void) smtpd_proxy_cmd(state, SMTPD_PROX_WANT_ANY, "%s %s %s", - XLOGINFO_CMD, state->addr, state->name); + && strcmp(line + 4, XCLIENT_EHLO) == 0) + state->proxy_features |= SMTPD_FEATURE_XCLIENT; + + /* + * Send our XCLIENT attributes. Transform internal forms to external + * forms and encode the result as xtext. + */ + if (state->proxy_features & SMTPD_FEATURE_XCLIENT) { + buf = vstring_alloc(100); + vstring_sprintf(buf, "%s LOG CLIENT_NAME=", XCLIENT_CMD); + if (!IS_UNK_CLNT_NAME(LOG_NAME(state))) + xtext_quote_append(buf, LOG_NAME(state), ""); + vstring_strcat(buf, " CLIENT_ADDR="); + if (!IS_UNK_CLNT_ADDR(LOG_ADDR(state))) + xtext_quote_append(buf, LOG_ADDR(state), ""); + bad = smtpd_proxy_cmd(state, SMTPD_PROX_WANT_ANY, "%s", STR(buf)); + if (bad == 0) { + vstring_sprintf(buf, "%s HELO_NAME=", XCLIENT_CMD); + if (!IS_UNK_HELO_NAME(LOG_HELO_NAME(state))) + xtext_quote_append(buf, LOG_HELO_NAME(state), ""); + vstring_strcat(buf, " PROTOCOL="); + if (!IS_UNK_PROTOCOL(LOG_PROTOCOL(state))) + xtext_quote_append(buf, LOG_PROTOCOL(state), ""); + bad = smtpd_proxy_cmd(state, SMTPD_PROX_WANT_ANY, "%s", STR(buf)); + } + vstring_free(buf); + if (bad) { + vstring_sprintf(state->proxy_buffer, + "451 Error: queue file write error"); + smtpd_proxy_close(state); + return (-1); + } + } /* * Pass-through the client's MAIL FROM command. If this fails, then we diff --git a/postfix/src/smtpd/smtpd_sasl_proto.c b/postfix/src/smtpd/smtpd_sasl_proto.c index a0654384e..4e412c50b 100644 --- a/postfix/src/smtpd/smtpd_sasl_proto.c +++ b/postfix/src/smtpd/smtpd_sasl_proto.c @@ -198,7 +198,7 @@ void smtpd_sasl_mail_log(SMTPD_STATE *state) #define IFELSE(e1,e2,e3) ((e1) ? (e2) : (e3)) msg_info("%s: client=%s%s%s%s%s%s%s", - state->queue_id, state->namaddr, + state->queue_id, LOG_NAMADDR(state), IFELSE(state->sasl_method, ", sasl_method=", ""), IFELSE(state->sasl_method, state->sasl_method, ""), IFELSE(state->sasl_username, ", sasl_username=", ""), diff --git a/postfix/src/smtpd/smtpd_state.c b/postfix/src/smtpd/smtpd_state.c index 53e805794..d5988b416 100644 --- a/postfix/src/smtpd/smtpd_state.c +++ b/postfix/src/smtpd/smtpd_state.c @@ -85,6 +85,7 @@ void smtpd_state_init(SMTPD_STATE *state, VSTREAM *stream) state->history = 0; state->reason = 0; state->sender = 0; + state->verp_delims = 0; state->recipient = 0; state->etrn_name = 0; state->protocol = MAIL_PROTO_SMTP; @@ -101,6 +102,8 @@ void smtpd_state_init(SMTPD_STATE *state, VSTREAM *stream) state->expand_buf = 0; state->proxy = 0; state->proxy_buffer = 0; + state->proxy_mail = 0; + state->proxy_features = 0; #ifdef USE_SASL_AUTH if (SMTPD_STAND_ALONE(state)) @@ -114,6 +117,11 @@ void smtpd_state_init(SMTPD_STATE *state, VSTREAM *stream) */ smtpd_peer_init(state); + /* + * Initialize xclient information. + */ + smtpd_xclient_init(state); + /* * Initialize the conversation history. */ @@ -133,6 +141,7 @@ void smtpd_state_reset(SMTPD_STATE *state) if (state->buffer) vstring_free(state->buffer); smtpd_peer_reset(state); + smtpd_xclient_reset(state, XCLIENT_OVER_NONE); if (state->defer_if_permit.reason) vstring_free(state->defer_if_permit.reason); if (state->defer_if_reject.reason) diff --git a/postfix/src/smtpd/smtpd_xclient.c b/postfix/src/smtpd/smtpd_xclient.c new file mode 100644 index 000000000..75c92d946 --- /dev/null +++ b/postfix/src/smtpd/smtpd_xclient.c @@ -0,0 +1,116 @@ +/*++ +/* NAME +/* smtpd_xclient 3 +/* SUMMARY +/* maintain XCLIENT information +/* SYNOPSIS +/* #include "smtpd.h" +/* +/* void smtpd_xclient_init(state) +/* SMTPD_STATE *state; +/* +/* void smtpd_xclient_reset(state, mode) +/* SMTPD_STATE *state; +/* int mode; +/* DESCRIPTION +/* smtpd_xclient_init() initializes state variables that are +/* used for storage of XCLIENT command parameters. +/* These variables override specific members of the global state +/* structure for access control or logging purposes. +/* +/* smtpd_xclient_reset() releases memory allocated after the return +/* from smtpd_xclient_init() and optionally presets the state variables +/* to defaults that are suitable for the specified mode: +/* .IP XCLIENT_OVER_NONE +/* This should be used after the XCLIENT RST request. +/* .IP XCLIENT_OVER_ACL|XCLIENT_OVER_LOG +/* This should be used after the XCLIENT ACL request. +/* .IP XCLIENT_OVER_LOG +/* This should be used after the XCLIENT LOG request. +/* 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 + +/* Utility library. */ + +#include +#include + +/* Global library. */ + +#include + +/* Application-specific. */ + +#include + +/* smtpd_xclient_init - initialize XCLIENT attributes */ + +void smtpd_xclient_init(SMTPD_STATE *state) +{ + state->xclient.mode = 0; + state->xclient.name = 0; + state->xclient.addr = 0; + state->xclient.namaddr = 0; + state->xclient.peer_code = 0; + state->xclient.protocol = 0; + state->xclient.helo_name = 0; +} + +/* smtpd_xclient_reset - reset XCLIENT attributes */ + +void smtpd_xclient_reset(SMTPD_STATE *state, int mode) +{ + switch (mode) { + + /* + * Can't happen. + */ + default: + msg_panic("smtpd_xclient_reset: unknown mode 0x%x", mode); + + /* + * Restore smtpd_xclient_init() result. Allow selective override. + * This is desirable for access rule testing. + */ +#define FREE_AND_WIPE(s) { if (s) { myfree(s); s = 0; } } + + case XCLIENT_OVER_NONE: + case XCLIENT_OVER_ACL | XCLIENT_OVER_LOG: + FREE_AND_WIPE(state->xclient.name); + FREE_AND_WIPE(state->xclient.addr); + FREE_AND_WIPE(state->xclient.namaddr); + state->xclient.peer_code = 0; + FREE_AND_WIPE(state->xclient.protocol); + FREE_AND_WIPE(state->xclient.helo_name); + break; + + /* + * Non-selective override. Set all attributes to "unknown". This is + * desirable to avoid polluting the audit trail with data from mixed + * origins. + */ +#define FREE_AND_DUP(s,v) { if (s) { myfree(s); s = mystrdup(v); } } + + case XCLIENT_OVER_LOG: + FREE_AND_DUP(state->xclient.name, CLIENT_NAME_UNKNOWN); + FREE_AND_DUP(state->xclient.addr, CLIENT_ADDR_UNKNOWN); + FREE_AND_DUP(state->xclient.namaddr, CLIENT_NAMADDR_UNKNOWN); + state->xclient.peer_code = 0; + FREE_AND_DUP(state->xclient.protocol, PROTOCOL_UNKNOWN); + FREE_AND_DUP(state->xclient.helo_name, HELO_NAME_UNKNOWN); + break; + } + state->xclient.mode = mode; +} diff --git a/postfix/src/smtpstone/Makefile.in b/postfix/src/smtpstone/Makefile.in index c541cdbaa..d8dbd5ceb 100644 --- a/postfix/src/smtpstone/Makefile.in +++ b/postfix/src/smtpstone/Makefile.in @@ -3,9 +3,6 @@ SRCS = smtp-source.c smtp-sink.c qmqp-source.c qmqp-sink.c OBJS = smtp-source.o smtp-sink.o qmqp-source.o qmqp-sink.o HDRS = TESTSRC = -WARN = -W -Wformat -Wimplicit -Wmissing-prototypes \ - -Wparentheses -Wstrict-prototypes -Wswitch -Wuninitialized \ - -Wunused DEFS = -I. -I$(INC_DIR) -D$(SYSTYPE) CFLAGS = $(DEBUG) $(OPT) $(DEFS) TESTPROG= diff --git a/postfix/src/spawn/Makefile.in b/postfix/src/spawn/Makefile.in index 95fcb3e31..3a1cdb12e 100644 --- a/postfix/src/spawn/Makefile.in +++ b/postfix/src/spawn/Makefile.in @@ -3,9 +3,6 @@ SRCS = spawn.c OBJS = spawn.o HDRS = TESTSRC = -WARN = -W -Wformat -Wimplicit -Wmissing-prototypes \ - -Wparentheses -Wstrict-prototypes -Wswitch -Wuninitialized \ - -Wunused DEFS = -I. -I$(INC_DIR) -D$(SYSTYPE) CFLAGS = $(DEBUG) $(OPT) $(DEFS) TESTPROG= diff --git a/postfix/src/trivial-rewrite/Makefile.in b/postfix/src/trivial-rewrite/Makefile.in index 556aaf047..94f6d89aa 100644 --- a/postfix/src/trivial-rewrite/Makefile.in +++ b/postfix/src/trivial-rewrite/Makefile.in @@ -3,9 +3,6 @@ SRCS = trivial-rewrite.c rewrite.c resolve.c transport.c OBJS = trivial-rewrite.o rewrite.o resolve.o transport.o HDRS = TESTSRC = -WARN = -W -Wformat -Wimplicit -Wmissing-prototypes \ - -Wparentheses -Wstrict-prototypes -Wswitch -Wuninitialized \ - -Wunused DEFS = -I. -I$(INC_DIR) -D$(SYSTYPE) CFLAGS = $(DEBUG) $(OPT) $(DEFS) LIB = diff --git a/postfix/src/util/Makefile.in b/postfix/src/util/Makefile.in index 5dc045801..efdd532e4 100644 --- a/postfix/src/util/Makefile.in +++ b/postfix/src/util/Makefile.in @@ -27,7 +27,7 @@ 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 + attr_print_plain.c sane_connect.c neuter.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 +56,7 @@ 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) + attr_print_plain.o sane_connect.o $(STRCASE) neuter.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 \ @@ -78,9 +78,6 @@ HDRS = argv.h attr.h base64_code.h binhash.h chroot_uid.h clean_env.h \ auto_clnt.h attr_clnt.h sane_connect.h TESTSRC = fifo_open.c fifo_rdwr_bug.c fifo_rdonly_bug.c select_bug.c \ stream_test.c dup2_pass_on_exec.c -WARN = -W -Wformat -Wimplicit -Wmissing-prototypes \ - -Wparentheses -Wstrict-prototypes -Wswitch -Wuninitialized \ - -Wunused DEFS = -I. -D$(SYSTYPE) CFLAGS = $(DEBUG) $(OPT) $(DEFS) FILES = Makefile $(SRCS) $(HDRS) @@ -1046,6 +1043,11 @@ netstring.o: vstream.h netstring.o: vbuf.h netstring.o: vstring.h netstring.o: netstring.h +neuter.o: neuter.c +neuter.o: sys_defs.h +neuter.o: stringops.h +neuter.o: vstring.h +neuter.o: vbuf.h non_blocking.o: non_blocking.c non_blocking.o: sys_defs.h non_blocking.o: msg.h diff --git a/postfix/src/util/neuter.c b/postfix/src/util/neuter.c new file mode 100644 index 000000000..1d0279e9e --- /dev/null +++ b/postfix/src/util/neuter.c @@ -0,0 +1,56 @@ +/*++ +/* NAME +/* neuter 3 +/* SUMMARY +/* mask non-neuter characters +/* SYNOPSIS +/* #include +/* +/* char *neuter(buffer, bad, replacement) +/* char *buffer; +/* const char *bad; +/* int replacement; +/* DESCRIPTION +/* neuter() replaces bad characters in its input +/* by the given replacement. +/* +/* Arguments: +/* .IP buffer +/* The null-terminated input string. +/* .IP bad +/* The null-terminated bad character string. +/* .IP replacement +/* Replacement value for characters in \fIbuffer\fR that do not +/* pass the bad character test. +/* 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 +#include + +/* Utility library. */ + +#include + +/* neuter - neutralize bad characters */ + +char *neuter(char *string, const char *bad, int replacement) +{ + char *cp; + int ch; + + for (cp = string; (ch = *(unsigned char *) cp) != 0; cp++) + if (strchr(bad, ch) != 0) + *cp = replacement; + return (string); +} diff --git a/postfix/src/util/stringops.h b/postfix/src/util/stringops.h index 0cd80c797..1f05045fc 100644 --- a/postfix/src/util/stringops.h +++ b/postfix/src/util/stringops.h @@ -20,6 +20,7 @@ * External interface. */ extern char *printable(char *, int); +extern char *neuter(char *, const char *, int); extern char *lowercase(char *); extern char *skipblanks(const char *); extern char *trimblanks(char *, int); diff --git a/postfix/src/util/sys_defs.h b/postfix/src/util/sys_defs.h index 4ea98c931..6d556e257 100644 --- a/postfix/src/util/sys_defs.h +++ b/postfix/src/util/sys_defs.h @@ -59,18 +59,39 @@ #define NATIVE_DAEMON_DIR "/usr/libexec/postfix" #endif -#if defined(FREEBSD2) || defined(FREEBSD3) || defined(FREEBSD4) -#define HAS_DUPLEX_PIPE -#endif +/* __FreeBSD_version version is major+minor */ -#if defined(OPENBSD2) || defined(OPENBSD3) \ - || defined(FREEBSD3) || defined(FREEBSD4) +#if __FreeBSD_version >= 200000 +#define HAS_DUPLEX_PIPE #define HAS_ISSETUGID #endif -#if defined(NETBSD1) +#if __FreeBSD_version >= 400000 +#define SOCKADDR_SIZE socklen_t +#define SOCKOPT_SIZE socklen_t +#endif + +/* OpenBSD version is year+month */ + +#if OpenBSD >= 200000 /* XXX */ +#define HAS_ISSETUGID +#endif + +#if OpenBSD >= 200200 /* XXX */ +#define SOCKADDR_SIZE socklen_t +#define SOCKOPT_SIZE socklen_t +#endif + +/* __NetBSD_Version__ is major+minor */ + +#if __NetBSD_Version__ >= 103000000 /* XXX */ #undef DEF_MAILBOX_LOCK #define DEF_MAILBOX_LOCK "flock, dotlock" +#endif + +#if __NetBSD_Version__ >= 106000000 /* XXX */ +#define SOCKADDR_SIZE socklen_t +#define SOCKOPT_SIZE socklen_t #endif /* @@ -493,6 +514,7 @@ extern int initgroups(const char *, int); #ifdef LINUX2 #define SUPPORTED #include +#include #define USE_PATHS_H #define HAS_FLOCK_LOCK #define HAS_FCNTL_LOCK @@ -516,6 +538,10 @@ extern int initgroups(const char *, int); #define NATIVE_NEWALIAS_PATH "/usr/bin/newaliases" #define NATIVE_COMMAND_DIR "/usr/sbin" #define NATIVE_DAEMON_DIR "/usr/libexec/postfix" +#if __GLIBC__ >= 2 && __GLIBC_MINOR__ >= 1 +#define SOCKADDR_SIZE socklen_t +#define SOCKOPT_SIZE socklen_t +#endif #endif #ifdef LINUX1 @@ -908,6 +934,9 @@ extern int dup2_pass_on_exec(int oldd, int newd); #endif #define OPTIND (optind > 0 ? optind : 1) + /* + * Check for required but missing definitions. + */ #if !defined(HAS_FCNTL_LOCK) && !defined(HAS_FLOCK_LOCK) #error "define HAS_FCNTL_LOCK and/or HAS_FLOCK_LOCK" #endif @@ -929,7 +958,7 @@ extern int dup2_pass_on_exec(int oldd, int newd); #endif /* - * Defaults for normal systems. + * Defaults for systems that pre-date POSIX socklen_t. */ #ifndef SOCKADDR_SIZE #define SOCKADDR_SIZE int @@ -939,6 +968,9 @@ extern int dup2_pass_on_exec(int oldd, int newd); #define SOCKOPT_SIZE int #endif + /* + * Defaults for normal systems. + */ #ifndef LOCAL_LISTEN #define LOCAL_LISTEN unix_listen #define LOCAL_ACCEPT unix_accept diff --git a/postfix/src/verify/Makefile.in b/postfix/src/verify/Makefile.in index 169affba0..2daf6659e 100644 --- a/postfix/src/verify/Makefile.in +++ b/postfix/src/verify/Makefile.in @@ -3,9 +3,6 @@ SRCS = verify.c OBJS = verify.o HDRS = TESTSRC = -WARN = -W -Wformat -Wimplicit -Wmissing-prototypes \ - -Wparentheses -Wstrict-prototypes -Wswitch -Wuninitialized \ - -Wunused DEFS = -I. -I$(INC_DIR) -D$(SYSTYPE) CFLAGS = $(DEBUG) $(OPT) $(DEFS) TESTPROG= diff --git a/postfix/src/virtual/Makefile.in b/postfix/src/virtual/Makefile.in index 7ab030855..e439102f9 100644 --- a/postfix/src/virtual/Makefile.in +++ b/postfix/src/virtual/Makefile.in @@ -3,9 +3,6 @@ SRCS = virtual.c mailbox.c recipient.c deliver_attr.c maildir.c unknown.c OBJS = virtual.o mailbox.o recipient.o deliver_attr.o maildir.o unknown.o HDRS = virtual.h TESTSRC = -WARN = -W -Wformat -Wimplicit -Wmissing-prototypes \ - -Wparentheses -Wstrict-prototypes -Wswitch -Wuninitialized \ - -Wunused DEFS = -I. -I$(INC_DIR) -D$(SYSTYPE) CFLAGS = $(DEBUG) $(OPT) $(DEFS) PROG = virtual