From: Wietse Venema Date: Sat, 13 Dec 2003 05:00:00 +0000 (-0500) Subject: postfix-2.0.16-20031213 X-Git-Tag: v2.1-RC1-20040331~23 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=7a646f52bf58ab2bb14bb4c2ab5749803fce1916;p=thirdparty%2Fpostfix.git postfix-2.0.16-20031213 --- diff --git a/postfix/HISTORY b/postfix/HISTORY index d11a0b4ae..1a06f19e7 100644 --- a/postfix/HISTORY +++ b/postfix/HISTORY @@ -8812,11 +8812,26 @@ Apologies for any names omitted. Minor cleanups of the xclient error messages; xclient command lookup tables. File: smtpd/smtpd.c. +20031206 + + Feature: reject_sender_login_mismatch allows multiple owners + of a sender address. Code by Liviu Daia. Files: + smtpd/smtpd_check.c and documentation. + + The reject_sender_login_mismatch feature is now implemented + by elementary features reject_unauth_sender_login_mismatch + (reject if the client is not SASL logged in but the sender + address has an owner in smtpd_sender_login_maps) and + reject_auth_sender_login_mismatch (reject if the client is + SASL logged in but does not own the sender address). Code + by Liviu Daia. Files: smtpd/smtpd_check.c and documentation. + 20031207 Bugfix: fallback_transport and mailbox_transport were broken because the deliver_pass.c module was not updated for the changed message delivery protocol. + Open problems: High: when virtual aliasing is turned off after content @@ -8884,3 +8899,6 @@ Open problems: Low: with quoted-printable, perhaps use =46rom instead of >From. + + virtual_mailbox_path expression like forward_path, so that + people can specify prefix and suffix. diff --git a/postfix/README_FILES/XCLIENT_README b/postfix/README_FILES/XCLIENT_README index 258048b47..3077aed91 100644 --- a/postfix/README_FILES/XCLIENT_README +++ b/postfix/README_FILES/XCLIENT_README @@ -25,19 +25,23 @@ the filter can override the MTA's idea of the SMTP client hostname, network address, and other information, for the entire duration of an SMTP session. +4 - Fetchmail. + Command overview ================ -The EHLO keyword associated with this extension is XCLIENT. +The EHLO keyword associated with this extension is XCLIENT. In EHLO +replies, XCLIENT is followed by the names of the supported XCLIENT +functions. -The XCLIENT OVERRIDE command updates remote client attributes that +The XCLIENT OVERRIDE function updates remote client attributes that the MTA normally uses for access control, message headers, logging and so on, for the duration of an entire SMTP session. -The XCLIENT FORWARD command updates temporary remote client attributes -that the MTA uses for transaction logging. These attributes are -valid for only one message delivery attempt. In the absence of -forwarded attributes the MTA must use the normal remote client +The XCLIENT FORWARD function updates temporary remote client +attributes that the MTA uses for transaction logging. These attributes +are valid for only one message delivery attempt. In the absence +of forwarded attributes the MTA must use the normal remote client attribute values. The general command syntax is described below. Upper case and @@ -52,7 +56,7 @@ case, they are in fact case insensitive. attribute = name"="value - name = ( CLIENT_NAME|CLIENT_ADDR|CLIENT_CODE|CLIENT_PROTO|CLIENT_HELO ) + name = ( NAME|ADDR|CODE|PROTO|HELO ) value = ( { empty } | xtext ) @@ -91,8 +95,8 @@ The following example overrides only the client hostname and network address, leaving unchanged all other client attributes such as the mail protocol or the hostname given in the HELO command: - XCLIENT OVERRIDE CLIENT_NAME=spike.porcupine.org - XCLIENT OVERRIDE CLIENT_ADDR=168.100.189.2 + XCLIENT OVERRIDE NAME=spike.porcupine.org + XCLIENT OVERRIDE ADDR=168.100.189.2 The XCLIENT FORWARD request specifies remote client attributes that are logged with one message delivery attempt. The attributes are @@ -109,8 +113,8 @@ The following example updates all forwarded client attributes that are defined in this document, leaving none at their default unknown value: - XCLIENT FORWARD CLIENT_NAME=spike.porcupine.org CLIENT_ADDR=168.100.189.2 - XCLIENT FORWARD CLIENT_HELO=spike.porcupine.org CLIENT_PROTO=ESMTP + XCLIENT FORWARD NAME=spike.porcupine.org ADDR=168.100.189.2 + XCLIENT FORWARD HELO=spike.porcupine.org PROTO=ESMTP Note 1: attributes specified with successive XCLIENT commands accumulate. @@ -126,32 +130,33 @@ specify that an attribute value is unavailable, the value must be empty; the client must not send its own internal representation of unavailable information. -The CLIENT_CODE attribute 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 -automatically set to the unknown value. +The NAME_CODE attribute specifies NAME hostname lookup status +information. Values are OK (success), TEMP (temporary lookup +failure) or PERM (permanent lookup failure). When CODE is set to +any value other than OK, the NAME attribute is automatically set +to the unknown value. -The CLIENT_NAME attribute 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 implicitly set to PERM. When a valid domain name is -specified, CLIENT_CODE is implicitly set to OK. The server may -process a syntactically invalid domain name as if it were unknown. +The NAME attribute specifies a name space (typically, DNS) and +an MTA name within that name space. +and not a numerical address. When a null client name is specified +(i.e. the client name is unknown), the CODE attribute is implicitly +set to PERM. When a valid domain name is specified, CODE is implicitly +set to OK. The server may process a syntactically invalid domain +name as if it were unknown. -The CLIENT_ADDR attribute must specify a numerical network address -without []. +The ADDR attribute must specify a numerical network address without +[]. -The CLIENT_PROTO attribute should be a string of up to 64 printable +The PROTO attribute should be a string of up to 64 printable characters, where printable is defined by the ANSI C isascii() and isprint() predicates. -The CLIENT_HELO attribute should be a syntactically valid HELO +The HELO attribute should be a syntactically valid HELO parameter value. -Note 3: syntactically valid CLIENT_NAME and CLIENT_HELO attributes -can be up to 255 characters long. The client must not send XCLIENT -commands that exceed the 512 character limit of SMTP commands. +Note 3: syntactically valid NAME and HELO attributes can be up to +255 characters long. The client must not send XCLIENT commands that +exceed the 512 character limit of SMTP commands. Note 4: attribute values may end up in Received: or other message headers. The receiving MTA may substitute characters in order to diff --git a/postfix/conf/sample-auth.cf b/postfix/conf/sample-auth.cf index 7d3943241..e44ec0abc 100644 --- a/postfix/conf/sample-auth.cf +++ b/postfix/conf/sample-auth.cf @@ -19,7 +19,7 @@ # To reject all SMTP connections from unauthenticated clients, # specify smtpd_delay_reject=yes (which is the default) and use: # -# smtpd_client_restrictions = permit_sasl_authenticated +# smtpd_client_restrictions = permit_sasl_authenticated, reject # # In order to enable server-side authentication, build Postfix with # SASL support, and install a configuration file /usr/lib/sasl/smtpd.conf diff --git a/postfix/conf/sample-smtp.cf b/postfix/conf/sample-smtp.cf index e55b5ca20..6812f14aa 100644 --- a/postfix/conf/sample-smtp.cf +++ b/postfix/conf/sample-smtp.cf @@ -76,16 +76,16 @@ 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. +# The smtp_send_xforward_command parameter controls whether the Postfix +# SMTP client will send an XFORWARD command to the SMTP server, when +# the ESMTP HELO response of the remote host indicates XFORWARD support. # This allows an "smtp" delivery agent, used for content filter # message injection, to forward the name, address, protocol and HELO # name of the original client to the content filter and downstream # queuing 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 +smtp_send_xforward_command = no # The smtp_line_length_limit parameter controls the length of # message header and body lines that Postfix will send via SMTP. @@ -237,10 +237,9 @@ smtp_connect_timeout = 30s # smtp_helo_timeout = 300s -# The smtp_xclient_timeout parameter specifies the SMTP client timeout -# for sending the SMTP XCLIENT command, and for receiving the server +# The smtp_xforward_timeout parameter specifies the SMTP client timeout +# for sending the SMTP XFORWARD command, and for receiving the server # response. -# for receiving the SMTP greeting banner. # # In case of problems the client does NOT try the next address on # the mail exchanger list. @@ -248,7 +247,7 @@ smtp_helo_timeout = 300s # Time units: s (seconds), m (minutes), h (hours), d (days), w (weeks). # The default time unit is s (seconds). # -smtp_xclient_timeout = 300s +smtp_xforward_timeout = 300s # The smtp_mail_timeout parameter specifies the SMTP client timeout # for sending the SMTP MAIL FROM command, and for receiving the server diff --git a/postfix/conf/sample-smtpd.cf b/postfix/conf/sample-smtpd.cf index 077076502..720d3d99d 100644 --- a/postfix/conf/sample-smtpd.cf +++ b/postfix/conf/sample-smtpd.cf @@ -78,25 +78,25 @@ unknown_local_recipient_reject_code = 550 # # The smtpd_sender_login_maps parameter specifies the (SASL) login -# name that owns a sender (MAIL FROM) address. +# names that own sender (MAIL FROM) addresses. # # Specify zero or more maptype:mapname entries. Maps are created with # postmap(1) or with equivalent means. The maps are searched in the # specified order. Regexp tables are allowed. # -# Each map entry specifies a sender address and the login name that -# owns the address. The search order is: +# Each map entry specifies a sender address and a list of login names +# that owns the address. The search order is: # -# 1) user@domain owner +# 1) user@domain owner, owner, ... # # This form has the highest precedence. # -# 2) user owner +# 2) user owner, owner, ... # # This matches user@site when site is equal to $myorigin, when site # is listed in $mydestination, or when it is listed in $inet_interfaces. # -# 3) @domain owner +# 3) @domain owner, owner, ... # # This matches every address in the specified domain, and has the # lowest precedence. @@ -158,8 +158,8 @@ smtpd_client_connection_limit_exceptions = $mynetworks # are allowed to specify the XCLIENT extension to SMTP. # # 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. +# logging and access control. Typical use is for SMTP-based content +# filters, fetchmail-like programs, or SMTP server access rule testing. # # By default, no clients are allowed to specify XCLIENT. # @@ -174,6 +174,25 @@ smtpd_client_connection_limit_exceptions = $mynetworks # smtpd_authorized_xclient_hosts = +# The smtpd_authorized_xforward_hosts parameter specifies what clients +# are allowed to specify the XFORWARD extension to SMTP. +# +# This command forwards information that is used to improve logging +# after SMTP-based content filters. +# +# By default, no clients are allowed to specify XFORWARD. +# +# 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_xforward_hosts = + # The smtpd_authorized_verp_clients parameter specifies what clients # are allowed to specify the SMTP XVERP command. This command requests # that mail be delivered one recipient at a time with a per recipient @@ -487,11 +506,22 @@ smtpd_helo_restrictions = # look up sender address MX hosts (or name servers) and apply the # specified access table to those hosts. # Note: the OK result is not allowed here for security reasons. -# reject_sender_login_mismatch: reject if $smtpd_sender_login_maps specifies -# a MAIL FROM address owner, but the client is not (SASL) logged in as -# that MAIL FROM address owner; or if the client is (SASL) logged in, but -# the client login name doesn't own the MAIL FROM address according to -# $smtpd_sender_login_maps (see above). +# reject_sender_login_mismatch: +# reject if $smtpd_sender_login_maps specifies a MAIL FROM +# address owner, but the client is not (SASL) logged in as +# that MAIL FROM address owner; or if the client is (SASL) +# logged in, but the client login name doesn't own the MAIL +# FROM address. +# reject_authenticated_sender_login_mismatch: +# reject if the client is (SASL) logged in, but the client +# login name doesn't own the MAIL FROM address according to +# $smtpd_sender_login_maps (see above). This still allows +# unauthenticated clients to impersonate the sender. +# reject_unauthenticated_sender_login_mismatch: +# reject if $smtpd_sender_login_maps specifies a MAIL FROM +# address owner, but the client is not (SASL) logged in. +# This prevents unauthenticated clients from impersonating +# the sender. # reject_non_fqdn_sender: reject sender address that is not in FQDN form # check_policy_service transport:endpoint: delegate the decision to # an external policy server. See SMTPD_POLICY_README for details. @@ -545,7 +575,7 @@ smtpd_sender_restrictions = # $virtual_alias_domains, or $virtual_mailbox_domains. # - to destinations matching $relay_domains or subdomain thereof, # except for addresses with sender-specified routing. -# reject_unauth_destination: reject mail unless it is sent +# *reject_unauth_destination: reject mail unless it is sent # - to destinations matching $inet_interfaces, $mydestination, # $virtual_alias_domains, or $virtual_mailbox_domains. # - to destinations matching $relay_domains or subdomain thereof, diff --git a/postfix/html/smtp.8.html b/postfix/html/smtp.8.html index eb8f02874..0a3c3287a 100644 --- a/postfix/html/smtp.8.html +++ b/postfix/html/smtp.8.html @@ -249,8 +249,8 @@ 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 + smtp_xforward_timeout + Timeout for sending the XFORWARD command, and for receiving the server response. smtp_mail_timeout @@ -281,8 +281,8 @@ SMTP(8) SMTP(8) 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 + smtp_send_xforward_command + If the SMTP server announces XFORWARD support, send the name, address, protocol and HELO name of the original client. This can be used to forward client information through a content filter to a down- diff --git a/postfix/html/smtpd.8.html b/postfix/html/smtpd.8.html index 9aefc27f1..160306934 100644 --- a/postfix/html/smtpd.8.html +++ b/postfix/html/smtpd.8.html @@ -163,7 +163,13 @@ SMTPD(8) SMTPD(8) Maps that specify the SASL login name that owns a MAIL FROM sender address. Used by the reject_sender_login_mismatch sender anti-spoofing - restriction. + restriction, as well as by its component restric- + tions reject_authenticated_sender_login_mismatch + (an authenticated client can't use a MAIL FROM + sender address that is owned by someone else) and + reject_unauthenticated_sender_login_mismatch (a + client must be authenticated in order to use the + MAIL FROM sender address). Miscellaneous smtpd_authorized_verp_clients @@ -173,29 +179,35 @@ SMTPD(8) SMTPD(8) smtpd_authorized_xclient_hosts Hostnames, domain names and/or addresses of clients 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. + This command overrides client information for + access control and logging purposes, with the + exception of the smtpd_authorized_xclient_hosts + access control itself. + + smtpd_authorized_xforward_hosts + Hostnames, domain names and/or addresses of clients + that are authorized to use the XFORWARD command. + This command accepts client and message identofying + information for logging purposes. 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 @@ -204,18 +216,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 @@ -223,57 +235,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 @@ -281,9 +293,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 @@ -293,21 +305,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. @@ -318,17 +330,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 @@ -337,17 +349,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 @@ -355,19 +367,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 @@ -375,96 +387,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 @@ -472,7 +484,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 @@ -481,15 +493,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 @@ -500,7 +512,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/html/uce.html b/postfix/html/uce.html index 4392efa21..afa38f2d0 100644 --- a/postfix/html/uce.html +++ b/postfix/html/uce.html @@ -829,11 +829,30 @@ response code to rejected requests (default: 504).
reject_sender_login_mismatch
Reject the request when -$smtpd_sender_owner_maps specifies an owner for the MAIL FROM +$smtpd_sender_login_maps specifies an owner for the MAIL FROM address, but the client is not (SASL) logged in as that MAIL FROM address owner; or when the client is (SASL) logged in, but the -client login name doesn't own the MAIL FROM address according to - $smtpd_sender_login_maps. +client login name doesn't own the MAIL FROM address. + +

+ + + +

reject_authenticated_sender_login_mismatch + +
Reject the request when the client is (SASL) logged in but +the client login name doesn't own the MAIL FROM address according +to $smtpd_sender_login_maps. + +

+ + + +

reject_unauthenticated_sender_login_mismatch + +
Reject the request when +$smtpd_sender_login_maps specifies an owner for the address, +but the client is not (SASL) logged in.

@@ -1583,8 +1602,13 @@ tables listed in $relay_domains.

smtpd_sender_login_maps
This parameter specifies ownership of MAIL FROM addresses, as -used by the -reject_sender_login_mismatch sender address restriction. +used by the reject_sender_login_mismatch +anti-spoofing restriction and by its component sender address +restrictions: +reject_authenticated_sender_login_mismatch and +reject_unauthenticated_sender_login_mismatch.

@@ -1604,30 +1628,31 @@ specified order. Regexp tables are allowed.

-Each map entry specifies a sender address and the login name that -owns the address. The search order is: +Each map entry specifies a sender address and a list of login names +(separated by whitespace and/or commas) that owns the address. The +search order is:

-
user@domain owner +
user@domain   owner, owner, ...
This form has the highest precedence.

-

user owner +
user   owner, owner, ... -
This matches user@site when site is equal to $myorigin, when site is +
This matches user@site when site is equal to + $myorigin, when site is listed in $mydestination, or when it is listed in $inet_interfaces.

-

@domain owner +
@domain   owner, owner, ...
This matches every address in the specified domain, and has the lowest precedence. diff --git a/postfix/man/man8/smtp.8 b/postfix/man/man8/smtp.8 index c585f4945..d830dab2b 100644 --- a/postfix/man/man8/smtp.8 +++ b/postfix/man/man8/smtp.8 @@ -210,8 +210,8 @@ 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 +.IP \fBsmtp_xforward_timeout\fR +Timeout for sending the \fBXFORWARD\fR command, and for receiving the server response. .IP \fBsmtp_mail_timeout\fR Timeout for sending the \fBMAIL FROM\fR command, and for @@ -234,8 +234,8 @@ 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, +.IP \fBsmtp_send_xforward_command\fR +If the SMTP server announces XFORWARD support, send the name, address, protocol and HELO name of the original client. This can be used to forward client information through a content filter to a downstream queuing SMTP server. diff --git a/postfix/man/man8/smtpd.8 b/postfix/man/man8/smtpd.8 index f4466b7b6..c96da0507 100644 --- a/postfix/man/man8/smtpd.8 +++ b/postfix/man/man8/smtpd.8 @@ -150,7 +150,11 @@ Disallow anonymous logins. .IP \fBsmtpd_sender_login_maps\fR Maps that specify the SASL login name that owns a MAIL FROM sender address. Used by the \fBreject_sender_login_mismatch\fR sender -anti-spoofing restriction. +anti-spoofing restriction, as well as by its component restrictions +\fBreject_authenticated_sender_login_mismatch\fR (an authenticated +client can't use a MAIL FROM sender address that is owned by someone +else) and \fBreject_unauthenticated_sender_login_mismatch\fR (a client +must be authenticated in order to use the MAIL FROM sender address). .SH Miscellaneous .ad .fi @@ -159,10 +163,14 @@ Hostnames, domain names and/or addresses of clients that are authorized to use the XVERP extension. .IP \fBsmtpd_authorized_xclient_hosts\fR Hostnames, domain names and/or addresses of clients that are -authorized to use the XCLIENT command. This command changes -client information for access control and/or logging purposes, +authorized to use the XCLIENT command. This command overrides +client information for access control and logging purposes, with the exception of the \fBsmtpd_authorized_xclient_hosts\fR access control itself. +.IP \fBsmtpd_authorized_xforward_hosts\fR +Hostnames, domain names and/or addresses of clients that are +authorized to use the XFORWARD command. This command accepts +client and message identofying information for logging purposes. .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/global/Makefile.in b/postfix/src/global/Makefile.in index dc95fda33..951071b95 100644 --- a/postfix/src/global/Makefile.in +++ b/postfix/src/global/Makefile.in @@ -210,11 +210,6 @@ local_transport: $(LIB) $(LIBS) quote_821_local: quote_821_local.c $(LIBS) $(CC) $(CFLAGS) -DTEST -o $@ $@.c $(LIBS) $(SYSLIBS) -peer_name: $(LIB) - mv $@.o junk - $(CC) $(CFLAGS) -DTEST -o $@ $@.c $(LIB) $(SYSLIBS) - mv junk $@.o - mail_conf_time: $(LIB) $(LIBS) mv $@.o junk $(CC) -DTEST $(CFLAGS) -o $@ $@.c $(LIB) $(LIBS) $(SYSLIBS) @@ -1079,11 +1074,6 @@ own_inet_addr.o: ../../include/vstring.h own_inet_addr.o: ../../include/vbuf.h own_inet_addr.o: mail_params.h own_inet_addr.o: own_inet_addr.h -peer_name.o: peer_name.c -peer_name.o: ../../include/sys_defs.h -peer_name.o: ../../include/msg.h -peer_name.o: ../../include/valid_hostname.h -peer_name.o: peer_name.h pipe_command.o: pipe_command.c pipe_command.o: ../../include/sys_defs.h pipe_command.o: ../../include/msg.h diff --git a/postfix/src/global/mail_params.c b/postfix/src/global/mail_params.c index aa81791d0..1bd415a1c 100644 --- a/postfix/src/global/mail_params.c +++ b/postfix/src/global/mail_params.c @@ -608,18 +608,19 @@ void mail_params_init() * I have seen this happen just too often. */ if (strcasecmp(var_myhostname, var_relayhost) == 0) - msg_fatal("myhostname == relayhost"); + msg_fatal("%s and %s parameter settings must not be identical: %s", + VAR_MYHOSTNAME, VAR_RELAYHOST, var_myhostname); /* * XXX These should be caught by a proper parameter parsing algorithm. */ if (var_myorigin[strcspn(var_myorigin, ", \t\r\n")]) - msg_fatal("myorigin parameter setting contains multiple values: %s", - var_myorigin); + msg_fatal("%s parameter setting must not contain multiple values: %s", + VAR_MYORIGIN, var_myorigin); if (var_relayhost[strcspn(var_relayhost, ", \t\r\n")]) - msg_fatal("relayhost parameter setting contains multiple values: %s", - var_relayhost); + msg_fatal("%s parameter setting must not contain multiple values: %s", + VAR_RELAYHOST, var_relayhost); /* * One more sanity check. diff --git a/postfix/src/global/mail_params.h b/postfix/src/global/mail_params.h index 260e61ecf..0a7aa988d 100644 --- a/postfix/src/global/mail_params.h +++ b/postfix/src/global/mail_params.h @@ -845,9 +845,9 @@ 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; +#define VAR_SMTP_SEND_XFORWARD "smtp_send_xforward_command" +#define DEF_SMTP_SEND_XFORWARD 0 +extern bool var_smtp_send_xforward; /* * SMTP server. The soft error limit determines how many errors an SMTP @@ -910,6 +910,10 @@ extern char *var_smtpd_sasl_realm; extern char *var_smtpd_snd_auth_maps; #define REJECT_SENDER_LOGIN_MISMATCH "reject_sender_login_mismatch" +#define REJECT_AUTH_SENDER_LOGIN_MISMATCH \ + "reject_authenticated_sender_login_mismatch" +#define REJECT_UNAUTH_SENDER_LOGIN_MISMATCH \ + "reject_unauthenticated_sender_login_mismatch" /* * SASL authentication support, SMTP client side. @@ -1575,12 +1579,19 @@ extern bool var_verp_bounce_off; extern char *var_verp_clients; /* - * XCLIENT, for rule testing and improved post-filter logging. + * XCLIENT, for rule testing and fetchmail like apps. */ #define VAR_XCLIENT_HOSTS "smtpd_authorized_xclient_hosts" #define DEF_XCLIENT_HOSTS "" extern char *var_xclient_hosts; + /* + * XFORWARD, for improved post-filter logging. + */ +#define VAR_XFORWARD_HOSTS "smtpd_authorized_xforward_hosts" +#define DEF_XFORWARD_HOSTS "" +extern char *var_xforward_hosts; + /* * Inbound mail flow control. This allows for a stiffer coupling between * receiving mail and sending mail. A sending process produces one token for diff --git a/postfix/src/global/mail_proto.h b/postfix/src/global/mail_proto.h index d6018d006..96bbd1cab 100644 --- a/postfix/src/global/mail_proto.h +++ b/postfix/src/global/mail_proto.h @@ -155,37 +155,18 @@ extern char *mail_pathname(const char *, const char *); * XCLIENT in SMTP. */ #define XCLIENT_CMD "XCLIENT" /* XCLIENT command */ -#define XCLIENT_OVERRIDE "OVERRIDE" /* override function */ -#define XCLIENT_FORWARD "FORWARD" /* forward function */ -#define XCLIENT_NAME "CLIENT_NAME" /* client name */ -#define XCLIENT_ADDR "CLIENT_ADDR" /* client address */ -#define XCLIENT_PROTO "CLIENT_PROTO" /* client protocol */ -#define XCLIENT_CODE "CLIENT_CODE" /* client name status */ -#define XCLIENT_HELO "CLIENT_HELO" /* client helo */ - - /* - * This is how Postfix represents unknown client information within smtpd or - * qmqpd processes. - * - * This is not the representation that Postfix uses in queue files, in queue - * manager delivery requests, nor is it the representation of information in - * XCLIENT commands! - */ -#define CLIENT_ATTR_UNKNOWN "unknown" - -#define CLIENT_NAME_UNKNOWN CLIENT_ATTR_UNKNOWN -#define CLIENT_ADDR_UNKNOWN CLIENT_ATTR_UNKNOWN -#define CLIENT_NAMADDR_UNKNOWN CLIENT_ATTR_UNKNOWN -#define CLIENT_HELO_UNKNOWN 0 -#define CLIENT_PROTO_UNKNOWN CLIENT_ATTR_UNKNOWN - -#define IS_AVAIL_CLIENT_ATTR(v) ((v) && strcmp((v), CLIENT_ATTR_UNKNOWN)) - -#define IS_AVAIL_CLIENT_NAME(v) IS_AVAIL_CLIENT_ATTR(v) -#define IS_AVAIL_CLIENT_ADDR(v) IS_AVAIL_CLIENT_ATTR(v) -#define IS_AVAIL_CLIENT_NAMADDR(v) IS_AVAIL_CLIENT_ATTR(v) -#define IS_AVAIL_CLIENT_HELO(v) (v) -#define IS_AVAIL_CLIENT_PROTO(v) IS_AVAIL_CLIENT_ATTR(v) +#define XCLIENT_NAME "NAME" /* client name */ +#define XCLIENT_ADDR "ADDR" /* client address */ +#define XCLIENT_PROTO "PROTO" /* client protocol */ +#define XCLIENT_CODE "NAME_CODE" /* client name status */ +#define XCLIENT_HELO "HELO" /* client helo */ + +#define XFORWARD_CMD "XFORWARD" /* XFORWARD command */ +#define XFORWARD_NAME "NAME" /* client name */ +#define XFORWARD_ADDR "ADDR" /* client address */ +#define XFORWARD_PROTO "PROTO" /* client protocol */ +#define XFORWARD_HELO "HELO" /* client helo */ +#define XFORWARD_IDENT "IDENT" /* message identifier */ /* LICENSE /* .ad diff --git a/postfix/src/global/mail_queue.c b/postfix/src/global/mail_queue.c index bb00522fc..192f01d38 100644 --- a/postfix/src/global/mail_queue.c +++ b/postfix/src/global/mail_queue.c @@ -285,33 +285,16 @@ int mail_queue_id_ok(const char *queue_id) { const char *cp; - if (*queue_id == 0 || strlen(queue_id) > 100) + if (*queue_id == 0 || strlen(queue_id) > VALID_HOSTNAME_LEN) return (0); /* - * OK if in in time+inum form. + * OK if in in time+inum form or in host-name_domain_tld form. */ - for (cp = queue_id; /* void */ ; cp++) { - if (*cp == 0) - return (1); - if (!ISALNUM(*cp)) - break; - } - - /* - * BAD if in time.pid form. - */ - for (cp = queue_id; /* void */ ; cp++) { - if (*cp == 0) + for (cp = queue_id; *cp; cp++) + if (!ISALNUM(*cp) && *cp != '_' && *cp != '-') return (0); - if (!ISDIGIT(*cp) && *cp != '.') - break; - } - - /* - * OK if in valid hostname form. - */ - return (valid_hostname(queue_id, DONT_GRIPE)); + return (1); } /* mail_queue_enter - make mail queue entry with locally-unique name */ diff --git a/postfix/src/global/mail_version.h b/postfix/src/global/mail_version.h index acb4ee8bc..65279a01c 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 "20031207" +#define MAIL_RELEASE_DATE "20031213" #define VAR_MAIL_VERSION "mail_version" #define DEF_MAIL_VERSION "2.0.16-" MAIL_RELEASE_DATE diff --git a/postfix/src/global/peer_name.c b/postfix/src/global/peer_name.c deleted file mode 100644 index 5e3affa5a..000000000 --- a/postfix/src/global/peer_name.c +++ /dev/null @@ -1,113 +0,0 @@ -/*++ -/* NAME -/* peer_name 3 -/* SUMMARY -/* produce printable peer name and address -/* SYNOPSIS -/* #include -/* -/* typedef struct { -/* .in +4 -/* int type; -/* char name; -/* char addr; -/* .in -4 -/* } PEER_NAME; -/* -/* PEER_NAME *peer_name(sock) -/* int sock; -/* DESCRIPTION -/* The \fIpeer_name\fR() routine attempts to produce a printable -/* version of the peer name and address of the specified socket. -/* The result is in static memory that will be overwritten. -/* Make a copy if the result is to be used for an appreciable -/* amount of time. -/* -/* Where information is unavailable, the name and/or address -/* are set to "unknown". -/* The \fItype\fR result field specifies how the name and address -/* should be interpreted: -/* .IP PEER_TYPE_INET -/* The socket specifies a TCP/IP endpoint. -/* The result is a hostname (from the DNS, a local hosts file or -/* other); the address a dotted quad. -/* .IP PEER_TYPE_LOCAL -/* The socket argument specifies a local transport. -/* The result name is "localhost"; the result address is "127.0.0.1". -/* .IP PEER_TYPE_UNKNOWN -/* The socket argument does not specify a socket. -/* The result name is "localhost"; the result address is "127.0.0.1". -/* 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 -#include -#include -#include -#include -#include - -/* Utility library. */ - -#include -#include -#include - -/* peer_name - produce printable peer name and address */ - -PEER_NAME *peer_name(int sock) -{ - static PEER_NAME peer; - struct sockaddr_in sin; - SOCKADDR_SIZE len = sizeof(sin); - struct hostent *hp; - - if (getpeername(sock, (struct sockaddr *) & sin, &len) == 0) { - switch (sin.sin_family) { - case AF_INET: - peer.type = PEER_TYPE_INET; - hp = gethostbyaddr((char *) &(sin.sin_addr), - sizeof(sin.sin_addr), AF_INET); - peer.name = (hp && valid_hostname(hp->h_name, DO_GRIPE) ? - hp->h_name : "unknown"); - peer.addr = inet_ntoa(sin.sin_addr); - return (&peer); - case AF_UNSPEC: - case AF_UNIX: - peer.type = PEER_TYPE_LOCAL; - peer.name = "localhost"; - peer.addr = "127.0.0.1"; - return (&peer); - } - } - peer.type = PEER_TYPE_UNKNOWN; - peer.name = "localhost"; - peer.addr = "127.0.0.1"; - return (&peer); - -} - -#ifdef TEST - -#include - -int main(int unused_argc, char **unused_argv) -{ - PEER_NAME *peer; - - peer = peer_name(STDIN_FILENO); - msg_info("name %s addr %s", peer->name, peer->addr); -} - -#endif diff --git a/postfix/src/global/peer_name.h b/postfix/src/global/peer_name.h deleted file mode 100644 index f1c96374a..000000000 --- a/postfix/src/global/peer_name.h +++ /dev/null @@ -1,39 +0,0 @@ -#ifndef _PEER_NAME_H_INCLUDED_ -#define _PEER_NAME_H_INCLUDED_ - -/*++ -/* NAME -/* peer_name 3h -/* SUMMARY -/* produce printable peer name and address -/* SYNOPSIS -/* #include -/* DESCRIPTION - - /* - * External interface. - */ -typedef struct { - int type; /* IPC type, see below */ - char *name; /* peer official name */ - char *addr; /* peer address */ -} PEER_NAME; - -#define PEER_TYPE_UNKNOWN 0 -#define PEER_TYPE_INET 1 -#define PEER_TYPE_LOCAL 2 - -extern PEER_NAME *peer_name(int); - -/* 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 -/*--*/ - -#endif diff --git a/postfix/src/global/recipient_list.c b/postfix/src/global/recipient_list.c index 3228c09b9..92d37f597 100644 --- a/postfix/src/global/recipient_list.c +++ b/postfix/src/global/recipient_list.c @@ -95,10 +95,13 @@ void recipient_list_init(RECIPIENT_LIST *list) void recipient_list_add(RECIPIENT_LIST *list, long offset, const char *orig_rcpt, const char *rcpt) { + int new_avail; + if (list->len >= list->avail) { - list->avail *= 2; + new_avail = list->avail * 2; list->info = (RECIPIENT *) - myrealloc((char *) list->info, list->avail * sizeof(RECIPIENT)); + myrealloc((char *) list->info, new_avail * sizeof(RECIPIENT)); + list->avail = new_avail; } list->info[list->len].orig_addr = mystrdup(orig_rcpt); list->info[list->len].address = mystrdup(rcpt); diff --git a/postfix/src/nqmgr/qmgr_rcpt_list.c b/postfix/src/nqmgr/qmgr_rcpt_list.c index 9868c9fca..ebe566243 100644 --- a/postfix/src/nqmgr/qmgr_rcpt_list.c +++ b/postfix/src/nqmgr/qmgr_rcpt_list.c @@ -75,10 +75,13 @@ void qmgr_rcpt_list_init(QMGR_RCPT_LIST *list) void qmgr_rcpt_list_add(QMGR_RCPT_LIST *list, long offset, const char *orcpt, const char *rcpt) { + int new_avail; + if (list->len >= list->avail) { - list->avail *= 2; + new_avail = list->avail * 2; list->info = (QMGR_RCPT *) - myrealloc((char *) list->info, list->avail * sizeof(QMGR_RCPT)); + myrealloc((char *) list->info, new_avail * sizeof(QMGR_RCPT)); + list->avail = new_avail; } list->info[list->len].orig_rcpt = mystrdup(orcpt); list->info[list->len].address = mystrdup(rcpt); diff --git a/postfix/src/qmgr/qmgr_rcpt_list.c b/postfix/src/qmgr/qmgr_rcpt_list.c index 9868c9fca..ebe566243 100644 --- a/postfix/src/qmgr/qmgr_rcpt_list.c +++ b/postfix/src/qmgr/qmgr_rcpt_list.c @@ -75,10 +75,13 @@ void qmgr_rcpt_list_init(QMGR_RCPT_LIST *list) void qmgr_rcpt_list_add(QMGR_RCPT_LIST *list, long offset, const char *orcpt, const char *rcpt) { + int new_avail; + if (list->len >= list->avail) { - list->avail *= 2; + new_avail = list->avail * 2; list->info = (QMGR_RCPT *) - myrealloc((char *) list->info, list->avail * sizeof(QMGR_RCPT)); + myrealloc((char *) list->info, new_avail * sizeof(QMGR_RCPT)); + list->avail = new_avail; } list->info[list->len].orig_rcpt = mystrdup(orcpt); list->info[list->len].address = mystrdup(rcpt); diff --git a/postfix/src/qmqpd/qmqpd.c b/postfix/src/qmqpd/qmqpd.c index 1fcc75ca6..483c6e138 100644 --- a/postfix/src/qmqpd/qmqpd.c +++ b/postfix/src/qmqpd/qmqpd.c @@ -291,8 +291,9 @@ static void qmqpd_write_attributes(QMQPD_STATE *state) if (IS_AVAIL_CLIENT_ADDR(state->addr)) rec_fprintf(state->cleanup, REC_TYPE_ATTR, "%s=%s", MAIL_ATTR_CLIENT_ADDR, state->addr); - rec_fprintf(state->cleanup, REC_TYPE_ATTR, "%s=%s", - MAIL_ATTR_ORIGIN, state->namaddr); + if (IS_AVAIL_CLIENT_NAMADDR(state->namaddr)) + rec_fprintf(state->cleanup, REC_TYPE_ATTR, "%s=%s", + MAIL_ATTR_ORIGIN, state->namaddr); rec_fprintf(state->cleanup, REC_TYPE_ATTR, "%s=%s", MAIL_ATTR_PROTO_NAME, state->protocol); } diff --git a/postfix/src/qmqpd/qmqpd.h b/postfix/src/qmqpd/qmqpd.h index aaacb4242..7e5c2471b 100644 --- a/postfix/src/qmqpd/qmqpd.h +++ b/postfix/src/qmqpd/qmqpd.h @@ -48,6 +48,24 @@ typedef struct { VSTRING *why_rejected; /* REJECT reason */ } QMQPD_STATE; + /* + * Postfix representation unknown client information within qmqpd processes. + * This is not the representation that Postfix uses in queue files, in queue + * manager delivery requests, nor is it the representation of information in + * XCLIENT/XFORWARD commands! + */ +#define CLIENT_ATTR_UNKNOWN "unknown" + +#define CLIENT_NAME_UNKNOWN CLIENT_ATTR_UNKNOWN +#define CLIENT_ADDR_UNKNOWN CLIENT_ATTR_UNKNOWN +#define CLIENT_NAMADDR_UNKNOWN CLIENT_ATTR_UNKNOWN + +#define IS_AVAIL_CLIENT_ATTR(v) ((v) && strcmp((v), CLIENT_ATTR_UNKNOWN)) + +#define IS_AVAIL_CLIENT_NAME(v) IS_AVAIL_CLIENT_ATTR(v) +#define IS_AVAIL_CLIENT_ADDR(v) IS_AVAIL_CLIENT_ATTR(v) +#define IS_AVAIL_CLIENT_NAMADDR(v) IS_AVAIL_CLIENT_ATTR(v) + /* * QMQP protocol status codes. */ diff --git a/postfix/src/qmqpd/qmqpd_peer.c b/postfix/src/qmqpd/qmqpd_peer.c index 9f0e9f2f5..84c878dcb 100644 --- a/postfix/src/qmqpd/qmqpd_peer.c +++ b/postfix/src/qmqpd/qmqpd_peer.c @@ -105,8 +105,8 @@ void qmqpd_peer_init(QMQPD_STATE *state) * If peer went away, give up. */ if (errno == ECONNRESET || errno == ECONNABORTED) { - state->name = mystrdup("unknown"); - state->addr = mystrdup("unknown"); + state->name = mystrdup(CLIENT_ATTR_UNKNOWN); + state->addr = mystrdup(CLIENT_ATTR_UNKNOWN); } /* @@ -117,9 +117,9 @@ void qmqpd_peer_init(QMQPD_STATE *state) hp = gethostbyaddr((char *) &(sin.sin_addr), sizeof(sin.sin_addr), AF_INET); if (hp == 0) { - state->name = mystrdup("unknown"); + state->name = mystrdup(CLIENT_ATTR_UNKNOWN); } else if (!valid_hostname(hp->h_name, DONT_GRIPE)) { - state->name = mystrdup("unknown"); + state->name = mystrdup(CLIENT_ATTR_UNKNOWN); } else { state->name = mystrdup(hp->h_name); /* hp->name is clobbered!! */ @@ -128,7 +128,7 @@ void qmqpd_peer_init(QMQPD_STATE *state) */ #define REJECT_PEER_NAME(state) { \ myfree(state->name); \ - state->name = mystrdup("unknown"); \ + state->name = mystrdup(CLIENT_ATTR_UNKNOWN); \ } hp = gethostbyname(state->name); /* clobbers hp->name!! */ diff --git a/postfix/src/smtp/smtp.c b/postfix/src/smtp/smtp.c index 3400b7df3..256bab47a 100644 --- a/postfix/src/smtp/smtp.c +++ b/postfix/src/smtp/smtp.c @@ -194,8 +194,8 @@ /* .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 +/* .IP \fBsmtp_xforward_timeout\fR +/* Timeout for sending the \fBXFORWARD\fR command, and for /* receiving the server response. /* .IP \fBsmtp_mail_timeout\fR /* Timeout for sending the \fBMAIL FROM\fR command, and for @@ -218,8 +218,8 @@ /* 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, +/* .IP \fBsmtp_send_xforward_command\fR +/* If the SMTP server announces XFORWARD support, send the name, /* address, protocol and HELO name of the original client. This /* can be used to forward client information through a content /* filter to a downstream queuing SMTP server. @@ -314,7 +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; +bool var_smtp_send_xforward; /* * Global variables. smtp_errno is set by the address lookup routines and by @@ -529,7 +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, + VAR_SMTP_SEND_XFORWARD, DEF_SMTP_SEND_XFORWARD, &var_smtp_send_xforward, 0, }; diff --git a/postfix/src/smtp/smtp.h b/postfix/src/smtp/smtp.h index 8c9d04074..f591b0cc3 100644 --- a/postfix/src/smtp/smtp.h +++ b/postfix/src/smtp/smtp.h @@ -64,7 +64,14 @@ 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 */ +#define SMTP_FEATURE_XFORWARD_NAME (1<<7) +#define SMTP_FEATURE_XFORWARD_ADDR (1<<8) +#define SMTP_FEATURE_XFORWARD_PROTO (1<<9) +#define SMTP_FEATURE_XFORWARD_HELO (1<<10) + +#define SMTP_FEATURE_XFORWARD_MASK \ + (SMTP_FEATURE_XFORWARD_NAME | SMTP_FEATURE_XFORWARD_ADDR \ + | SMTP_FEATURE_XFORWARD_PROTO | SMTP_FEATURE_XFORWARD_HELO) /* * smtp.c diff --git a/postfix/src/smtp/smtp_proto.c b/postfix/src/smtp/smtp_proto.c index 6471014ba..cca3983a7 100644 --- a/postfix/src/smtp/smtp_proto.c +++ b/postfix/src/smtp/smtp_proto.c @@ -84,6 +84,7 @@ #include #include #include +#include /* Global library. */ @@ -124,8 +125,8 @@ * SMTP_STATE_DOT) must have smaller numerical values than the non-sending * states (SMTP_STATE_ABORT .. SMTP_STATE_LAST). */ -#define SMTP_STATE_XCLIENT_ADDR 0 -#define SMTP_STATE_XCLIENT_HELO 1 +#define SMTP_STATE_XFORWARD_ADDR 0 +#define SMTP_STATE_XFORWARD_HELO 1 #define SMTP_STATE_MAIL 2 #define SMTP_STATE_RCPT 3 #define SMTP_STATE_DATA 4 @@ -146,8 +147,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 XFORWARD address and name", + "sending XFORWARD helo_name and protocol", "sending MAIL FROM", "sending RCPT TO", "sending DATA command", @@ -157,8 +158,8 @@ char *xfer_states[SMTP_STATE_LAST] = { }; char *xfer_request[SMTP_STATE_LAST] = { - "XCLIENT command", - "XCLIENT command", + "XFORWARD name/address command", + "XFORWARD helo/protocol command", "MAIL FROM command", "RCPT TO command", "DATA command", @@ -179,6 +180,13 @@ int smtp_helo(SMTP_STATE *state) char *words; char *word; int n; + static NAME_CODE xforward_features[] = { + XFORWARD_NAME, SMTP_FEATURE_XFORWARD_NAME, + XFORWARD_ADDR, SMTP_FEATURE_XFORWARD_ADDR, + XFORWARD_PROTO, SMTP_FEATURE_XFORWARD_PROTO, + XFORWARD_HELO, SMTP_FEATURE_XFORWARD_HELO, + 0, 0, + }; /* * Prepare for disaster. @@ -259,9 +267,11 @@ int smtp_helo(SMTP_STATE *state) state->features |= SMTP_FEATURE_8BITMIME; else if (strcasecmp(word, "PIPELINING") == 0) state->features |= SMTP_FEATURE_PIPELINING; - else if (strcasecmp(word, "XCLIENT") == 0) - state->features |= SMTP_FEATURE_XCLIENT; - else if (strcasecmp(word, "SIZE") == 0) { + else if (strcasecmp(word, "XFORWARD") == 0) { + while ((word = mystrtok(&words, " \t")) != 0) + state->features |= name_code(xforward_features, + NAME_CODE_FLAG_NONE, word); + } else if (strcasecmp(word, "SIZE") == 0) { state->features |= SMTP_FEATURE_SIZE; if ((word = mystrtok(&words, " \t")) != 0) { if (!alldig(word)) @@ -484,15 +494,15 @@ int smtp_xfer(SMTP_STATE *state) * commands rejected, DATA rejected) it forces the sender to abort the * SMTP dialog with RSET and QUIT. * - * Use the XCLIENT command to forward client attributes only when a minimal + * Use the XFORWARD command to forward client attributes only when a minimal * amount of information is available. */ nrcpt = 0; - if (var_smtp_send_xclient - && (state->features & SMTP_FEATURE_XCLIENT) + if (var_smtp_send_xforward + && (state->features & SMTP_FEATURE_XFORWARD_MASK) && (DEL_REQ_ATTR_AVAIL(request->client_name) || DEL_REQ_ATTR_AVAIL(request->client_addr))) - recv_state = send_state = SMTP_STATE_XCLIENT_ADDR; + recv_state = send_state = SMTP_STATE_XFORWARD_ADDR; else recv_state = send_state = SMTP_STATE_MAIL; next_rcpt = send_rcpt = recv_rcpt = 0; @@ -512,29 +522,37 @@ int smtp_xfer(SMTP_STATE *state) msg_panic("%s: bad sender state %d", myname, send_state); /* - * Build the XCLIENT command. With properly sanitized + * Build the XFORWARD command. With properly sanitized * information, the command length stays within the 512 byte * command line length limit. */ - case SMTP_STATE_XCLIENT_ADDR: - vstring_strcpy(next_command, - XCLIENT_CMD " " XCLIENT_FORWARD " " XCLIENT_NAME "="); - if (DEL_REQ_ATTR_AVAIL(request->client_name)) - xtext_quote_append(next_command, request->client_name, ""); - vstring_strcat(next_command, " " XCLIENT_ADDR "="); - if (DEL_REQ_ATTR_AVAIL(request->client_addr)) - xtext_quote_append(next_command, request->client_addr, ""); - next_state = SMTP_STATE_XCLIENT_HELO; + case SMTP_STATE_XFORWARD_ADDR: + vstring_strcpy(next_command, XFORWARD_CMD); + if (state->features & SMTP_FEATURE_XFORWARD_NAME) { + vstring_strcat(next_command, " " XCLIENT_NAME "="); + if (DEL_REQ_ATTR_AVAIL(request->client_name)) + xtext_quote_append(next_command, request->client_name, ""); + } + if (state->features & SMTP_FEATURE_XFORWARD_ADDR) { + vstring_strcat(next_command, " " XFORWARD_ADDR "="); + if (DEL_REQ_ATTR_AVAIL(request->client_addr)) + xtext_quote_append(next_command, request->client_addr, ""); + } + next_state = SMTP_STATE_XFORWARD_HELO; break; - case SMTP_STATE_XCLIENT_HELO: - vstring_strcpy(next_command, - XCLIENT_CMD " " XCLIENT_FORWARD " " XCLIENT_HELO "="); - if (DEL_REQ_ATTR_AVAIL(request->client_helo)) - xtext_quote_append(next_command, request->client_helo, ""); - vstring_strcat(next_command, " " XCLIENT_PROTO "="); - if (DEL_REQ_ATTR_AVAIL(request->client_proto)) - xtext_quote_append(next_command, request->client_proto, ""); + case SMTP_STATE_XFORWARD_HELO: + vstring_strcpy(next_command, XFORWARD_CMD); + if (state->features & SMTP_FEATURE_XFORWARD_HELO) { + vstring_strcat(next_command, " " XCLIENT_HELO "="); + if (DEL_REQ_ATTR_AVAIL(request->client_helo)) + xtext_quote_append(next_command, request->client_helo, ""); + } + if (state->features & SMTP_FEATURE_XFORWARD_ADDR) { + vstring_strcat(next_command, " " XFORWARD_PROTO "="); + if (DEL_REQ_ATTR_AVAIL(request->client_proto)) + xtext_quote_append(next_command, request->client_proto, ""); + } next_state = SMTP_STATE_MAIL; break; @@ -647,7 +665,7 @@ int smtp_xfer(SMTP_STATE *state) /* * Sanity check. */ - if (recv_state < SMTP_STATE_XCLIENT_ADDR + if (recv_state < SMTP_STATE_XFORWARD_ADDR || recv_state > SMTP_STATE_QUIT) msg_panic("%s: bad receiver state %d (sender state %d)", myname, recv_state, send_state); @@ -669,13 +687,23 @@ int smtp_xfer(SMTP_STATE *state) switch (recv_state) { /* - * Process the XCLIENT response. + * Process the XFORWARD response. */ - case SMTP_STATE_XCLIENT_ADDR: - recv_state = SMTP_STATE_XCLIENT_HELO; + case SMTP_STATE_XFORWARD_ADDR: + if (resp->code / 100 != 2) + msg_warn("host %s said: %s (in reply to %s)", + session->namaddr, + translit(resp->str, "\n", " "), + xfer_request[SMTP_STATE_MAIL]); + recv_state = SMTP_STATE_XFORWARD_HELO; break; - case SMTP_STATE_XCLIENT_HELO: + case SMTP_STATE_XFORWARD_HELO: + if (resp->code / 100 != 2) + msg_warn("host %s said: %s (in reply to %s)", + session->namaddr, + translit(resp->str, "\n", " "), + xfer_request[SMTP_STATE_MAIL]); recv_state = SMTP_STATE_MAIL; break; diff --git a/postfix/src/smtpd/Makefile.in b/postfix/src/smtpd/Makefile.in index 6014a9f25..ba9c6bcbc 100644 --- a/postfix/src/smtpd/Makefile.in +++ b/postfix/src/smtpd/Makefile.in @@ -1,10 +1,10 @@ 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_xclient.c + smtpd_xforward.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_xclient.o + smtpd_xforward.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 @@ -30,7 +30,7 @@ update: ../../libexec/$(PROG) ../../libexec/$(PROG): $(PROG) cp $(PROG) ../../libexec -SMTPD_CHECK_OBJ = smtpd_state.o smtpd_peer.o smtpd_xclient.o +SMTPD_CHECK_OBJ = smtpd_state.o smtpd_peer.o smtpd_xforward.o smtpd_token: smtpd_token.c $(LIBS) $(CC) $(CFLAGS) -DTEST -o $@ $@.c $(LIBS) $(SYSLIBS) @@ -122,6 +122,7 @@ smtpd.o: ../../include/argv.h smtpd.o: ../../include/watchdog.h smtpd.o: ../../include/iostuff.h smtpd.o: ../../include/split_at.h +smtpd.o: ../../include/name_code.h smtpd.o: ../../include/mail_params.h smtpd.o: ../../include/record.h smtpd.o: ../../include/rec_type.h @@ -338,16 +339,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 +smtpd_xforward.o: smtpd_xforward.c +smtpd_xforward.o: ../../include/sys_defs.h +smtpd_xforward.o: ../../include/mymalloc.h +smtpd_xforward.o: ../../include/msg.h +smtpd_xforward.o: ../../include/mail_proto.h +smtpd_xforward.o: ../../include/vstream.h +smtpd_xforward.o: ../../include/vbuf.h +smtpd_xforward.o: ../../include/iostuff.h +smtpd_xforward.o: ../../include/attr.h +smtpd_xforward.o: smtpd.h +smtpd_xforward.o: ../../include/vstring.h +smtpd_xforward.o: ../../include/argv.h +smtpd_xforward.o: ../../include/mail_stream.h diff --git a/postfix/src/smtpd/smtpd.c b/postfix/src/smtpd/smtpd.c index 07d690802..b2e3db103 100644 --- a/postfix/src/smtpd/smtpd.c +++ b/postfix/src/smtpd/smtpd.c @@ -136,7 +136,11 @@ /* .IP \fBsmtpd_sender_login_maps\fR /* Maps that specify the SASL login name that owns a MAIL FROM sender /* address. Used by the \fBreject_sender_login_mismatch\fR sender -/* anti-spoofing restriction. +/* anti-spoofing restriction, as well as by its component restrictions +/* \fBreject_authenticated_sender_login_mismatch\fR (an authenticated +/* client can't use a MAIL FROM sender address that is owned by someone +/* else) and \fBreject_unauthenticated_sender_login_mismatch\fR (a client +/* must be authenticated in order to use the MAIL FROM sender address). /* .SH Miscellaneous /* .ad /* .fi @@ -145,10 +149,14 @@ /* authorized to use the XVERP extension. /* .IP \fBsmtpd_authorized_xclient_hosts\fR /* Hostnames, domain names and/or addresses of clients that are -/* authorized to use the XCLIENT command. This command changes -/* client information for access control and/or logging purposes, +/* authorized to use the XCLIENT command. This command overrides +/* client information for access control and logging purposes, /* with the exception of the /* \fBsmtpd_authorized_xclient_hosts\fR access control itself. +/* .IP \fBsmtpd_authorized_xforward_hosts\fR +/* Hostnames, domain names and/or addresses of clients that are +/* authorized to use the XFORWARD command. This command accepts +/* client and message identofying information for logging purposes. /* .IP \fBdebug_peer_level\fR /* Increment in verbose logging level when a remote host matches a /* pattern in the \fBdebug_peer_list\fR parameter. @@ -554,6 +562,7 @@ int var_smtpd_policy_tmout; int var_smtpd_policy_idle; int var_smtpd_policy_ttl; char *var_xclient_hosts; +char *var_xforward_hosts; int var_smtpd_crate_limit; int var_smtpd_cconn_limit; char *var_smtpd_hoggers; @@ -579,6 +588,12 @@ static NAMADR_LIST *verp_clients; static NAMADR_LIST *xclient_hosts; static int xclient_allowed; + /* + * XFORWARD command. Access control is cached. + */ +static NAMADR_LIST *xforward_hosts; +static int xforward_allowed; + /* * Client connection and rate limiting. */ @@ -736,7 +751,14 @@ static int ehlo_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv) smtpd_chat_reply(state, "250-%s", VERP_CMD); /* XCLIENT must not override its own access control. */ if (xclient_allowed) - smtpd_chat_reply(state, "250-%s", XCLIENT_CMD); + smtpd_chat_reply(state, "250-" XCLIENT_CMD + " " XCLIENT_NAME " " XCLIENT_ADDR + " " XCLIENT_CODE " " XCLIENT_PROTO + " " XCLIENT_HELO); + if (xforward_allowed) + smtpd_chat_reply(state, "250-" XFORWARD_CMD + " " XFORWARD_NAME " " XFORWARD_ADDR + " " XFORWARD_PROTO " " XFORWARD_HELO); smtpd_chat_reply(state, "250 8BITMIME"); return (0); } @@ -1147,8 +1169,8 @@ static void mail_reset(SMTPD_STATE *state) (void) smtpd_proxy_cmd(state, SMTPD_PROX_WANT_NONE, "QUIT"); smtpd_proxy_close(state); } - if (state->xclient.used) - smtpd_xclient_reset(state); + if (state->xforward.flags) + smtpd_xforward_reset(state); } /* rcpt_cmd - process RCPT TO command */ @@ -1336,7 +1358,7 @@ static int data_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *unused_argv) rec_fprintf(state->cleanup, REC_TYPE_FLGS, "%d", state->saved_flags); rec_fputs(state->cleanup, REC_TYPE_MESG, ""); } - if (!state->proxy || state->xclient.used == 0) { + if (!state->proxy || state->xforward.flags == 0) { out_fprintf(out_stream, REC_TYPE_NORM, "Received: from %s (%s [%s])", state->helo_name ? state->helo_name : state->name, @@ -1701,76 +1723,26 @@ static int quit_cmd(SMTPD_STATE *state, int unused_argc, SMTPD_TOKEN *unused_arg return (0); } - /* - * Lookup tables with xclient/normal attribute offsets. Maybe we should not - * try so hard to make XOVERRIDE and XFORWARD attribute lists identical. - */ -#define FUNC_OVERRIDE 0 -#define FUNC_FORWARD 1 - -struct attr_offset { - int name[2]; - int addr[2]; - int namaddr[2]; - int peer_code[2]; - int protocol[2]; - int helo_name[2]; -}; - -#define ATTR_OFFSETS(member) \ - offsetof(SMTPD_STATE, member), offsetof(SMTPD_STATE, xclient.member) - -static const struct attr_offset attr_offset = { - ATTR_OFFSETS(name), - ATTR_OFFSETS(addr), - ATTR_OFFSETS(namaddr), - ATTR_OFFSETS(peer_code), - ATTR_OFFSETS(protocol), - ATTR_OFFSETS(helo_name) -}; - -#define PTR_ATTR(state, func, attr) (((char *) state) + attr_offset.attr[func]) -#define STR_ATTR(state, func, attr) *((char **) PTR_ATTR(state, func, attr)) -#define INT_ATTR(state, func, attr) *((int *) PTR_ATTR(state, func, attr)) - -#define RST_STR_ATTR(state, func, attr) { \ - if (STR_ATTR(state, func, attr)) \ - myfree(STR_ATTR(state, func, attr)); \ - STR_ATTR(state, func, attr) = 0; \ - } - -#define UPD_STR_ATTR(state, func, attr, value) { \ - if (STR_ATTR(state, func, attr)) \ - myfree(STR_ATTR(state, func, attr)); \ - STR_ATTR(state, func, attr) = mystrdup(value); \ - } - -#define UPD_INT_ATTR(state, func, attr, value) { \ - INT_ATTR(state, func, attr) = (value); \ - } - -/* xclient_cmd - process XCLIENT */ +/* xclient_cmd - override client attributes */ static int xclient_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv) { int arg_no; - char *raw_value; - char *cooked_value; - char *arg_val; + char *attr_value; + char *attr_name; int update_namaddr = 0; - int function; int code; - static NAME_CODE xclient_functions[] = { - XCLIENT_OVERRIDE, FUNC_OVERRIDE, - XCLIENT_FORWARD, FUNC_FORWARD, - 0, -1, - }; static NAME_CODE xclient_codes[] = { "OK", SMTPD_PEER_CODE_OK, "PERM", SMTPD_PEER_CODE_PERM, "TEMP", SMTPD_PEER_CODE_TEMP, 0, -1, }; + static NAME_CODE xclient_proto[] = { + MAIL_PROTO_SMTP, 1, + MAIL_PROTO_ESMTP, 2, + 0, -1, + }; /* * Sanity checks. The XCLIENT command does not override its own access @@ -1781,9 +1753,9 @@ static int xclient_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv) smtpd_chat_reply(state, "503 Error: MAIL transaction in progress"); return (-1); } - if (argc < 3) { + if (argc < 2) { state->error_mask |= MAIL_ERROR_PROTOCOL; - smtpd_chat_reply(state, "501 Syntax: %s function name=value...", + smtpd_chat_reply(state, "501 Syntax: %s name=value...", XCLIENT_CMD); return (-1); } @@ -1792,164 +1764,133 @@ static int xclient_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv) smtpd_chat_reply(state, "554 Error: insufficient authorization"); return (-1); } -#define STREQ(x,y) (strcasecmp((x), (y)) == 0) +#define STREQ(x,y) (strcasecmp((x), (y)) == 0) +#define UPDATE_STR(s, v) do { if (s) myfree(s); s = (v) ? mystrdup(v) : 0; } while(0) /* - * Function name: what attributes to update. Complain about unrecognized - * request names. The set of requests is unlikely to change. + * Iterate over all NAME=VALUE attributes. */ - arg_val = argv[1].strval; - printable(arg_val, '?'); - if ((function = name_code(xclient_functions, arg_val)) < 0) { - state->error_mask |= MAIL_ERROR_PROTOCOL; - smtpd_chat_reply(state, "501 Bad %s function: %s", - XCLIENT_CMD, arg_val); - return (-1); - } - if (function == FUNC_FORWARD && state->xclient.used == 0) - smtpd_xclient_preset(state); - - /* - * Iterate over all NAME=VALUE attributes. An empty value means the - * information was not provided by the client and that we must not fall - * back to the non-XCLIENT value. - */ - for (arg_no = 2; arg_no < argc; arg_no++) { - arg_val = argv[arg_no].strval; + for (arg_no = 1; arg_no < argc; arg_no++) { + attr_name = argv[arg_no].strval; /* - * Decode the attribute value 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. + * For safety's sake mask non-printable characters in the raw and + * decoded values; we don't want to handle unexploded munitions. + * Complain when they send an attribute that we didn't announce. + * + * An implementation must allow clients to send XCLIENT before the + * HELO/EHLO greeting. * * The client can send multiple XCLIENT attributes in a single command, * or multiple XCLIENT commands with fewer attributes. - * - * Note: XCLIENT OVERRIDE overrides only the specified remote client - * attributes (for testing), while XCLIENT FORWARD overrides all - * remote client attributes (for consistency). */ - if ((raw_value = split_at(arg_val, '=')) == 0) { + if ((attr_value = split_at(attr_name, '=')) == 0) { state->error_mask |= MAIL_ERROR_PROTOCOL; smtpd_chat_reply(state, "501 Error: name=value expected"); 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, '?'); + printable(attr_value, '?'); /* - * CLIENT_NAME=hostname. Also updates the client hostname lookup - * status code. Treat a numerical hostname as an unavailable name. + * NAME=hostname. Also updates the client hostname lookup status + * code. Treat a numerical hostname as an unavailable name. */ - if (STREQ(arg_val, XCLIENT_NAME)) { - if (*raw_value && !valid_hostaddr(cooked_value, DONT_GRIPE)) { - if (!valid_hostname(cooked_value, DONT_GRIPE)) { + if (STREQ(attr_name, XCLIENT_NAME)) { + if (*attr_value && !valid_hostaddr(attr_value, DONT_GRIPE)) { + if (!valid_hostname(attr_value, DONT_GRIPE)) { state->error_mask |= MAIL_ERROR_PROTOCOL; smtpd_chat_reply(state, "501 Bad %s syntax: %s", - XCLIENT_NAME, raw_value); + XCLIENT_NAME, attr_value); return (-1); } - UPD_STR_ATTR(state, function, name, cooked_value); - UPD_INT_ATTR(state, function, peer_code, SMTPD_PEER_CODE_OK); + UPDATE_STR(state->name, attr_value); + state->peer_code = SMTPD_PEER_CODE_OK; } else { - UPD_STR_ATTR(state, function, name, CLIENT_NAME_UNKNOWN); - UPD_INT_ATTR(state, function, peer_code, SMTPD_PEER_CODE_PERM); + UPDATE_STR(state->name, CLIENT_NAME_UNKNOWN); + state->peer_code = SMTPD_PEER_CODE_PERM; } update_namaddr = 1; } /* - * CLIENT_ADDR=client network address. + * ADDR=client network address. */ - else if (STREQ(arg_val, XCLIENT_ADDR)) { - if (*raw_value) { - if (!valid_hostaddr(cooked_value, DONT_GRIPE)) { + else if (STREQ(attr_name, XCLIENT_ADDR)) { + if (*attr_value) { + if (!valid_hostaddr(attr_value, DONT_GRIPE)) { state->error_mask |= MAIL_ERROR_PROTOCOL; smtpd_chat_reply(state, "501 Bad %s syntax: %s", - XCLIENT_ADDR, raw_value); + XCLIENT_ADDR, attr_value); return (-1); } - UPD_STR_ATTR(state, function, addr, cooked_value); + UPDATE_STR(state->addr, attr_value); } else { - UPD_STR_ATTR(state, function, addr, CLIENT_ADDR_UNKNOWN); + UPDATE_STR(state->addr, CLIENT_ADDR_UNKNOWN); } update_namaddr = 1; } /* - * CLIENT_CODE=hostname lookup status. Reset the client hostname if - * the hostname lookup status is not OK. + * CODE=hostname lookup status. Reset the client hostname if the + * hostname lookup status is not OK. */ - else if (STREQ(arg_val, XCLIENT_CODE)) { - if (*raw_value) { - if ((code = name_code(xclient_codes, cooked_value)) < 0) { + else if (STREQ(attr_name, XCLIENT_CODE)) { + if (*attr_value) { + if ((code = name_code(xclient_codes, NAME_CODE_FLAG_NONE, attr_value)) < 0) { state->error_mask |= MAIL_ERROR_PROTOCOL; smtpd_chat_reply(state, "501 Bad %s value: %s", - XCLIENT_CODE, raw_value); + XCLIENT_CODE, attr_value); return (-1); } - UPD_INT_ATTR(state, function, peer_code, code); + state->peer_code = code; if (code != SMTPD_PEER_CODE_OK) { - UPD_STR_ATTR(state, function, name, CLIENT_NAME_UNKNOWN); + UPDATE_STR(state->name, CLIENT_NAME_UNKNOWN); update_namaddr = 1; } } } /* - * CLIENT_HELO=hostname. Disallow characters that could mess up our - * own Received: message headers but allow []. + * HELO=hostname. Disallow characters that could mess up our own + * Received: message headers but allow []. */ - else if (STREQ(arg_val, XCLIENT_HELO)) { - if (*raw_value) { - if (strlen(cooked_value) > VALID_HOSTNAME_LEN) { + else if (STREQ(attr_name, XCLIENT_HELO)) { + if (*attr_value) { + if (strlen(attr_value) > VALID_HOSTNAME_LEN) { state->error_mask |= MAIL_ERROR_PROTOCOL; smtpd_chat_reply(state, "501 Bad %s syntax: %s", - XCLIENT_HELO, raw_value); + XCLIENT_HELO, attr_value); return (-1); } - neuter(cooked_value, "<>()\\\";:@", '?'); - UPD_STR_ATTR(state, function, helo_name, cooked_value); + neuter(attr_value, "<>()\\\";:@", '?'); + UPDATE_STR(state->helo_name, attr_value); } else { - RST_STR_ATTR(state, function, helo_name); + UPDATE_STR(state->helo_name, CLIENT_HELO_UNKNOWN); } } /* - * CLIENT_PROTO=protocol name. Disallow characters that could mess up - * our own Received: message headers. + * PROTO=protocol name. Disallow characters that could mess up our + * own Received: message headers. */ - else if (STREQ(arg_val, XCLIENT_PROTO)) { - if (*raw_value) { - if (*cooked_value == 0 || strlen(cooked_value) > 64) { - state->error_mask |= MAIL_ERROR_PROTOCOL; - smtpd_chat_reply(state, "501 Bad %s syntax: %s", - XCLIENT_PROTO, raw_value); - return (-1); - } - neuter(cooked_value, "[]<>()\\\";:@", '?'); - UPD_STR_ATTR(state, function, protocol, cooked_value); - } else { - UPD_STR_ATTR(state, function, protocol, CLIENT_PROTO_UNKNOWN); + else if (STREQ(attr_name, XCLIENT_PROTO)) { + if (name_code(xclient_proto, NAME_CODE_FLAG_NONE, attr_value) < 0) { + state->error_mask |= MAIL_ERROR_PROTOCOL; + smtpd_chat_reply(state, "501 Bad %s syntax: %s", + XCLIENT_PROTO, attr_value); + return (-1); } + UPDATE_STR(state->protocol, attr_value); } /* - * Unknown attribute name. Don't complain, and log a warning. Logging - * is safe because only authorized clients can issue XCLIENT - * commands. + * Unknown attribute name. Complain. */ else { - msg_warn("unknown %s attribute from %s: %s=%s", - XCLIENT_CMD, state->namaddr, arg_val, cooked_value); + state->error_mask |= MAIL_ERROR_PROTOCOL; + smtpd_chat_reply(state, "501 Bad %s attribute name: %s", + XCLIENT_CMD, attr_name); + return (-1); } } @@ -1957,11 +1898,173 @@ static int xclient_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv) * Update the combined name and address when either has changed. */ if (update_namaddr) { - if (STR_ATTR(state, function, namaddr)) - myfree(STR_ATTR(state, function, namaddr)); - STR_ATTR(state, function, namaddr) = - concatenate(STR_ATTR(state, function, name), "[", - STR_ATTR(state, function, addr), "]", + if (state->namaddr) + myfree(state->namaddr); + state->namaddr = + concatenate(state->name, "[", state->addr, "]", (char *) 0); + } + smtpd_chat_reply(state, "250 Ok"); + return (0); +} + +/* xforward_cmd - forward logging attributes */ + +static int xforward_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv) +{ + int arg_no; + char *attr_value; + char *attr_name; + int updated = 0; + static NAME_CODE xforward_flags[] = { + XFORWARD_NAME, SMTPD_XFORWARD_FLAG_NAME, + XFORWARD_ADDR, SMTPD_XFORWARD_FLAG_ADDR, + XFORWARD_PROTO, SMTPD_XFORWARD_FLAG_PROTO, + XFORWARD_HELO, SMTPD_XFORWARD_FLAG_HELO, + 0, 0, + }; + int flag; + + /* + * Sanity checks. + */ + if (IN_MAIL_TRANSACTION(state)) { + state->error_mask |= MAIL_ERROR_PROTOCOL; + smtpd_chat_reply(state, "503 Error: MAIL transaction in progress"); + return (-1); + } + if (argc < 2) { + state->error_mask |= MAIL_ERROR_PROTOCOL; + smtpd_chat_reply(state, "501 Syntax: %s name=value...", + XFORWARD_CMD); + return (-1); + } + if (!xforward_allowed) { + state->error_mask |= MAIL_ERROR_POLICY; + smtpd_chat_reply(state, "554 Error: insufficient authorization"); + return (-1); + } + + /* + * Initialize. + */ + if (state->xforward.flags == 0) + smtpd_xforward_preset(state); + + /* + * Iterate over all NAME=VALUE attributes. + */ + for (arg_no = 1; arg_no < argc; arg_no++) { + attr_name = argv[arg_no].strval; + + /* + * For safety's sake mask non-printable characters in the raw and + * decoded values; we don't want to handle unexploded munitions. + * Complain when they send an attribute that we didn't announce. + * + * The client can send multiple XFORWARD attributes in a single command, + * or multiple XFORWARD commands with fewer attributes. + */ + if ((attr_value = split_at(attr_name, '=')) == 0) { + state->error_mask |= MAIL_ERROR_PROTOCOL; + smtpd_chat_reply(state, "501 Error: name=value expected"); + return (-1); + } + printable(attr_value, '?'); + + flag = name_code(xforward_flags, NAME_CODE_FLAG_NONE, attr_name); + switch (flag) { + + /* + * NAME=hostname. Also updates the client hostname lookup status + * code. Treat a numerical hostname as an unavailable name. + */ + case SMTPD_XFORWARD_FLAG_NAME: + if (*attr_value && !valid_hostaddr(attr_value, DONT_GRIPE)) { + if (!valid_hostname(attr_value, DONT_GRIPE)) { + state->error_mask |= MAIL_ERROR_PROTOCOL; + smtpd_chat_reply(state, "501 Bad %s syntax: %s", + XFORWARD_NAME, attr_value); + return (-1); + } + } else { + attr_value = CLIENT_NAME_UNKNOWN; + } + UPDATE_STR(state->xforward.name, attr_value); + break; + + /* + * ADDR=client network address. + */ + case SMTPD_XFORWARD_FLAG_ADDR: + if (*attr_value) { + if (!valid_hostaddr(attr_value, DONT_GRIPE)) { + state->error_mask |= MAIL_ERROR_PROTOCOL; + smtpd_chat_reply(state, "501 Bad %s syntax: %s", + XFORWARD_ADDR, attr_value); + return (-1); + } + } else { + attr_value = CLIENT_ADDR_UNKNOWN; + } + UPDATE_STR(state->xforward.addr, attr_value); + break; + + /* + * HELO=hostname. Disallow characters that could mess up our own + * Received: message headers but allow []. + */ + case SMTPD_XFORWARD_FLAG_HELO: + if (*attr_value) { + if (strlen(attr_value) > VALID_HOSTNAME_LEN) { + state->error_mask |= MAIL_ERROR_PROTOCOL; + smtpd_chat_reply(state, "501 Bad %s syntax: %s", + XFORWARD_HELO, attr_value); + return (-1); + } + neuter(attr_value, "<>()\\\";:@", '?'); + } else { + attr_value = CLIENT_HELO_UNKNOWN; + } + UPDATE_STR(state->xforward.helo_name, attr_value); + break; + + /* + * PROTO=protocol name. Neutralize characters that could mess up + * our own Received: message headers. + */ + case SMTPD_XFORWARD_FLAG_PROTO: + if (strlen(attr_value) > 64) { + state->error_mask |= MAIL_ERROR_PROTOCOL; + smtpd_chat_reply(state, "501 Bad %s syntax: %s", + XFORWARD_PROTO, attr_value); + return (-1); + } + neuter(attr_value, "<>()\\\";:@", '?'); + UPDATE_STR(state->xforward.protocol, attr_value); + break; + + /* + * Unknown attribute name. Complain. + */ + default: + state->error_mask |= MAIL_ERROR_PROTOCOL; + smtpd_chat_reply(state, "501 Bad %s attribute name: %s", + XFORWARD_CMD, attr_name); + return (-1); + } + updated |= flag; + } + state->xforward.flags |= updated; + + /* + * Update the combined name and address when either has changed. + */ + if (updated & (SMTPD_XFORWARD_FLAG_NAME | SMTPD_XFORWARD_FLAG_ADDR)) { + if (state->xforward.namaddr) + myfree(state->xforward.namaddr); + state->xforward.namaddr = + concatenate(state->xforward.name, "[", + state->xforward.addr, "]", (char *) 0); } smtpd_chat_reply(state, "250 Ok"); @@ -2001,7 +2104,7 @@ typedef struct SMTPD_CMD { } SMTPD_CMD; #define SMTPD_CMD_FLAG_LIMIT (1<<0) /* limit usage */ -#define SMTPD_CMD_FLAG_FORBIDDEN (1<<1) /* RFC 2822 mail header */ +#define SMTPD_CMD_FLAG_FORBID (1<<1) /* RFC 2822 mail header */ static SMTPD_CMD smtpd_cmd_table[] = { "HELO", helo_cmd, SMTPD_CMD_FLAG_LIMIT, @@ -2020,13 +2123,14 @@ static SMTPD_CMD smtpd_cmd_table[] = { "ETRN", etrn_cmd, SMTPD_CMD_FLAG_LIMIT, "QUIT", quit_cmd, 0, "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, - "Subject:", 0, SMTPD_CMD_FLAG_FORBIDDEN, - "From:", 0, SMTPD_CMD_FLAG_FORBIDDEN, - "CONNECT", 0, SMTPD_CMD_FLAG_FORBIDDEN, - "User-Agent:", 0, SMTPD_CMD_FLAG_FORBIDDEN, + "XFORWARD", xforward_cmd, SMTPD_CMD_FLAG_LIMIT, + "Received:", 0, SMTPD_CMD_FLAG_FORBID, + "Reply-To:", 0, SMTPD_CMD_FLAG_FORBID, + "Message-ID:", 0, SMTPD_CMD_FLAG_FORBID, + "Subject:", 0, SMTPD_CMD_FLAG_FORBID, + "From:", 0, SMTPD_CMD_FLAG_FORBID, + "CONNECT", 0, SMTPD_CMD_FLAG_FORBID, + "User-Agent:", 0, SMTPD_CMD_FLAG_FORBID, 0, }; @@ -2147,7 +2251,7 @@ static void smtpd_proto(SMTPD_STATE *state, const char *service) state->error_count++; continue; } - if (cmdp->flags & SMTPD_CMD_FLAG_FORBIDDEN) { + if (cmdp->flags & SMTPD_CMD_FLAG_FORBID) { msg_warn("%s sent non-SMTP command: %.100s", state->namaddr, vstring_str(state->buffer)); smtpd_chat_reply(state, "221 Error: I can break rules, too. Goodbye."); @@ -2240,6 +2344,12 @@ static void smtpd_service(VSTREAM *stream, char *service, char **argv) xclient_allowed = namadr_list_match(xclient_hosts, state.name, state.addr); + /* + * Overriding XFORWARD access control makes no sense, either. + */ + xforward_allowed = + namadr_list_match(xforward_hosts, state.name, state.addr); + /* * See if we need to turn on verbose logging for this client. */ @@ -2283,6 +2393,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); xclient_hosts = namadr_list_init(MATCH_FLAG_NONE, var_xclient_hosts); + xforward_hosts = namadr_list_init(MATCH_FLAG_NONE, var_xforward_hosts); hogger_list = namadr_list_init(MATCH_FLAG_NONE, var_smtpd_hoggers); if (getuid() == 0 || getuid() == var_owner_uid) smtpd_check_init(); @@ -2421,6 +2532,7 @@ int main(int argc, char **argv) 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_XCLIENT_HOSTS, DEF_XCLIENT_HOSTS, &var_xclient_hosts, 0, 0, + VAR_XFORWARD_HOSTS, DEF_XFORWARD_HOSTS, &var_xforward_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 b6bbe5709..831fa72a6 100644 --- a/postfix/src/smtpd/smtpd.h +++ b/postfix/src/smtpd/smtpd.h @@ -45,15 +45,26 @@ typedef struct SMTPD_DEFER { int class; /* error notification class */ } SMTPD_DEFER; -typedef struct SMTPD_XCLIENT_ATTR { - int used; /* status */ +typedef struct SMTPD_XFORWARD_ATTR { + int flags; /* see below */ 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; + char *ident; /* message identifier */ +} SMTPD_XFORWARD_ATTR; + +#define SMTPD_XFORWARD_FLAG_INIT (1<<0) /* preset done */ +#define SMTPD_XFORWARD_FLAG_NAME (1<<1) /* client name received */ +#define SMTPD_XFORWARD_FLAG_ADDR (1<<2) /* client address received */ +#define SMTPD_XFORWARD_FLAG_PROTO (1<<3)/* protocol received */ +#define SMTPD_XFORWARD_FLAG_HELO (1<<4) /* client helo received */ +#define SMTPD_XFORWARD_FLAG_IDENT (1<<5)/* message identifier received */ + +#define SMTPD_XFORWARD_FLAG_CLIENT_MASK \ + (SMTPD_XFORWARD_FLAG_NAME | SMTPD_XFORWARD_FLAG_ADDR \ + | SMTPD_XFORWARD_FLAG_PROTO | SMTPD_XFORWARD_FLAG_HELO) typedef struct SMTPD_STATE { int err; @@ -113,8 +124,8 @@ typedef struct SMTPD_STATE { VSTREAM *proxy; /* proxy handle */ VSTRING *proxy_buffer; /* proxy query/reply buffer */ char *proxy_mail; /* owned by mail_cmd() */ - int proxy_features; /* proxy ESMTP features */ - SMTPD_XCLIENT_ATTR xclient; /* override access control */ + int proxy_xforward_features; /* proxy XFORWARD features */ + SMTPD_XFORWARD_ATTR xforward; /* override access control */ } SMTPD_STATE; extern void smtpd_state_init(SMTPD_STATE *, VSTREAM *); @@ -127,6 +138,30 @@ extern void smtpd_state_reset(SMTPD_STATE *); #define SMTPD_AFTER_CONNECT "CONNECT" #define SMTPD_AFTER_DOT "END-OF-MESSAGE" + /* + * Postfix representation of unknown client information within smtpd + * processes. This is not the representation that Postfix uses in queue + * files, in queue manager delivery requests, nor is it the representation + * of information in XCLIENT/XFORWARD commands! + */ +#define CLIENT_ATTR_UNKNOWN "unknown" + +#define CLIENT_NAME_UNKNOWN CLIENT_ATTR_UNKNOWN +#define CLIENT_ADDR_UNKNOWN CLIENT_ATTR_UNKNOWN +#define CLIENT_NAMADDR_UNKNOWN CLIENT_ATTR_UNKNOWN +#define CLIENT_HELO_UNKNOWN 0 +#define CLIENT_PROTO_UNKNOWN CLIENT_ATTR_UNKNOWN +#define CLIENT_IDENT_UNKNOWN 0 + +#define IS_AVAIL_CLIENT_ATTR(v) ((v) && strcmp((v), CLIENT_ATTR_UNKNOWN)) + +#define IS_AVAIL_CLIENT_NAME(v) IS_AVAIL_CLIENT_ATTR(v) +#define IS_AVAIL_CLIENT_ADDR(v) IS_AVAIL_CLIENT_ATTR(v) +#define IS_AVAIL_CLIENT_NAMADDR(v) IS_AVAIL_CLIENT_ATTR(v) +#define IS_AVAIL_CLIENT_HELO(v) ((v) != 0) +#define IS_AVAIL_CLIENT_PROTO(v) IS_AVAIL_CLIENT_ATTR(v) +#define IS_AVAIL_CLIENT_IDENT(v) ((v) != 0) + /* * If running in stand-alone mode, do not try to talk to Postfix daemons but * write to queue file instead. @@ -162,23 +197,37 @@ extern void smtpd_peer_reset(SMTPD_STATE *state); * * Note 2: outside the SMTP server, the representation of unknown/known * attribute values is different in queue files, in queue manager delivery - * requests, and in over-the-network XCLIENT commands. + * requests, and in over-the-network XFORWARD commands. */ -#define SMTPD_FEATURE_XCLIENT (1<<0) /* proxy announces XCLIENT */ - -#define MAYBE_FORWARD(s, a) \ - ((s)->xclient.used ? (s)->xclient.a : (s)->a) +#define SMTPD_PROXY_XFORWARD_NAME (1<<0) /* client name */ +#define SMTPD_PROXY_XFORWARD_ADDR (1<<1) /* client address */ +#define SMTPD_PROXY_XFORWARD_PROTO (1<<2) /* protocol */ +#define SMTPD_PROXY_XFORWARD_HELO (1<<3) /* client helo */ +#define SMTPD_PROXY_XFORWARD_IDENT (1<<4) /* message identifier */ -#define FORWARD_ADDR(s) MAYBE_FORWARD((s), addr) -#define FORWARD_NAME(s) MAYBE_FORWARD((s), name) -#define FORWARD_NAMADDR(s) MAYBE_FORWARD((s), namaddr) -#define FORWARD_CODE(s) MAYBE_FORWARD((s), peer_code) -#define FORWARD_PROTO(s) MAYBE_FORWARD((s), protocol) -#define FORWARD_HELO(s) MAYBE_FORWARD((s), helo_name) - -extern void smtpd_xclient_init(SMTPD_STATE *state); -extern void smtpd_xclient_preset(SMTPD_STATE *state); -extern void smtpd_xclient_reset(SMTPD_STATE *state); + /* + * If forwarding client information, don't mix direct client information + * from the current SMTP session with forwarded client information from an + * up-stream session. + */ +#define FORWARD_CLIENT_ATTR(s, a) \ + (((s)->xforward.flags & SMTPD_XFORWARD_FLAG_CLIENT_MASK) ? \ + (s)->xforward.a : (s)->a) + +#define FORWARD_IDENT_ATTR(s) \ + (((s)->xforward.flags & SMTPD_XFORWARD_FLAG_IDENT) ? \ + (s)->queue_id : (s)->ident) + +#define FORWARD_ADDR(s) FORWARD_CLIENT_ATTR((s), addr) +#define FORWARD_NAME(s) FORWARD_CLIENT_ATTR((s), name) +#define FORWARD_NAMADDR(s) FORWARD_CLIENT_ATTR((s), namaddr) +#define FORWARD_PROTO(s) FORWARD_CLIENT_ATTR((s), protocol) +#define FORWARD_HELO(s) FORWARD_CLIENT_ATTR((s), helo_name) +#define FORWARD_IDENT(s) FORWARD_IDENT_ATTR(s) + +extern void smtpd_xforward_init(SMTPD_STATE *state); +extern void smtpd_xforward_preset(SMTPD_STATE *state); +extern void smtpd_xforward_reset(SMTPD_STATE *state); /* * Transparency: before mail is queued, do we check for unknown recipients, diff --git a/postfix/src/smtpd/smtpd_check.c b/postfix/src/smtpd/smtpd_check.c index 22da5f045..3bcdcbcaa 100644 --- a/postfix/src/smtpd/smtpd_check.c +++ b/postfix/src/smtpd/smtpd_check.c @@ -784,6 +784,9 @@ void smtpd_check_init(void) htable_enter(smtpd_rest_classes, "check_relay_domains", smtpd_check_parse("permit_mydomain reject_unauth_destination")); #endif + htable_enter(smtpd_rest_classes, REJECT_SENDER_LOGIN_MISMATCH, + (char *) smtpd_check_parse(REJECT_AUTH_SENDER_LOGIN_MISMATCH + " " REJECT_UNAUTH_SENDER_LOGIN_MISMATCH)); /* * People screw up the relay restrictions too often. Require that they @@ -2849,42 +2852,70 @@ static int reject_maps_rbl(SMTPD_STATE *state) return (result); } -/* reject_sender_login_mismatch - reject login/sender ownership mismatch */ +#ifdef USE_SASL -static int reject_sender_login_mismatch(SMTPD_STATE *state, const char *sender) +/* reject_auth_sender_login_mismatch - logged in client must own sender address */ + +static int reject_auth_sender_login_mismatch(SMTPD_STATE *state, const char *sender) { const RESOLVE_REPLY *reply; - const char *login = 0; - const char *owner = 0; + const char *owners; + char *saved_owners; + char *cp; + char *name; + int found = 0; /* - * If the sender address is owned by a login name, or if the client has - * logged in, then require that the client is logged in as the owner of - * the sender address. + * Reject if the client is logged in and does not own the sender address. */ - reply = (const RESOLVE_REPLY *) ctable_locate(smtpd_resolve_cache, sender); - if (reply->flags & RESOLVE_FLAG_FAIL) - reject_dict_retry(state, sender); - owner = check_mail_addr_find(state, sender, smtpd_sender_login_maps, - STR(reply->recipient), (char **) 0); -#ifdef USE_SASL_AUTH - if (var_smtpd_sasl_enable && state->sasl_username != 0) - login = state->sasl_username; -#endif - if (login) { - if (owner == 0 || strcasecmp(login, owner) != 0) + if (var_smtpd_sasl_enable && state->sasl_username != 0) { + reply = (const RESOLVE_REPLY *) ctable_locate(smtpd_resolve_cache, sender); + if (reply->flags & RESOLVE_FLAG_FAIL) + reject_dict_retry(state, sender); + if ((owners = check_mail_addr_find(state, sender, smtpd_sender_login_maps, + STR(reply->recipient), (char **) 0)) != 0) { + cp = saved_owners = mystrdup(owners); + while ((name = mystrtok(&cp, ", \t\r\n")) != 0) { + if (strcasecmp(state->sasl_username, name) == 0) { + found = 1; + break; + } + } + myfree(saved_owners); + } + if (!found) return (smtpd_check_reject(state, MAIL_ERROR_POLICY, "553 <%s>: Sender address rejected: not owned by user %s", - sender, login)); - } else { - if (owner) + sender, state->sasl_username)); + } + return (SMTPD_CHECK_DUNNO); +} + +/* reject_unauth_sender_login_mismatch - sender requires client is logged in */ + +static int reject_unauth_sender_login_mismatch(SMTPD_STATE *state, const char *sender) +{ + const RESOLVE_REPLY *reply; + const char *login = 0; + + /* + * Reject if the client is not logged in and the sender address has an + * owner. + */ + if (var_smtpd_sasl_enable && state->sasl_username == 0) { + reply = (const RESOLVE_REPLY *) ctable_locate(smtpd_resolve_cache, sender); + if (reply->flags & RESOLVE_FLAG_FAIL) + reject_dict_retry(state, sender); + if (check_mail_addr_find(state, sender, smtpd_sender_login_maps, + STR(reply->recipient), (char **) 0) != 0) return (smtpd_check_reject(state, MAIL_ERROR_POLICY, - "553 <%s>: Sender address rejected: not logged in as owner", - sender)); + "553 <%s>: Sender address rejected: not logged in", sender)); } return (SMTPD_CHECK_DUNNO); } +#endif + /* check_policy_service - check delegated policy service */ static int check_policy_service(SMTPD_STATE *state, const char *server, @@ -3204,9 +3235,22 @@ static int generic_checks(SMTPD_STATE *state, ARGV *restrictions, if (state->sender && *state->sender) status = reject_non_fqdn_address(state, state->sender, state->sender, SMTPD_NAME_SENDER); - } else if (strcasecmp(name, REJECT_SENDER_LOGIN_MISMATCH) == 0) { - if (state->sender && *state->sender) - status = reject_sender_login_mismatch(state, state->sender); + } else if (strcasecmp(name, REJECT_AUTH_SENDER_LOGIN_MISMATCH) == 0) { +#ifdef USE_SASL + if (var_smtpd_sasl_enable) { + if (state->sender && *state->sender) + status = reject_auth_sender_login_mismatch(state, state->sender); + } else +#endif + msg_warn("restriction `%s' ignored: no SASL support", name); + } else if (strcasecmp(name, REJECT_UNAUTH_SENDER_LOGIN_MISMATCH) == 0) { +#ifdef USE_SASL + if (var_smtpd_sasl_enable) { + if (state->sender && *state->sender) + status = reject_unauth_sender_login_mismatch(state, state->sender); + } else +#endif + msg_warn("restriction `%s' ignored: no SASL support", name); } else if (is_map_command(state, name, CHECK_SENDER_NS_ACL, &cpp)) { if (state->sender && *state->sender) { status = check_server_access(state, *cpp, state->sender, diff --git a/postfix/src/smtpd/smtpd_proxy.c b/postfix/src/smtpd/smtpd_proxy.c index 103d2080c..074e4e14c 100644 --- a/postfix/src/smtpd/smtpd_proxy.c +++ b/postfix/src/smtpd/smtpd_proxy.c @@ -52,7 +52,7 @@ /* mail. /* /* smtpd_proxy_open() connects to the proxy service, sends EHLO, sends -/* client information with the XCLIENT command if possible, sends +/* client information with the XFORWARD 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. @@ -147,6 +147,7 @@ #include #include #include +#include /* Global library. */ @@ -170,6 +171,53 @@ #define LEN(x) VSTRING_LEN(x) #define SMTPD_PROXY_CONNECT ((char *) 0) +/* smtpd_xforward_flush - flush forwarding information */ + +static int smtpd_xforward_flush(SMTPD_STATE *state, VSTRING *buf) +{ + int ret; + + if (VSTRING_LEN(buf) > 0) { + ret = smtpd_proxy_cmd(state, SMTPD_PROX_WANT_OK, + XFORWARD_CMD "%s", STR(buf)); + VSTRING_RESET(buf); + return (ret); + } + return (0); +} + +/* smtpd_xforward - send forwarding information */ + +static int smtpd_xforward(SMTPD_STATE *state, VSTRING *buf, const char *name, + int value_available, const char *value) +{ + size_t new_len; + int ret; + +#define CONSTR_LEN(s) (sizeof(s) - 1) +#define PAYLOAD_LIMIT (512 - CONSTR_LEN("250 " XFORWARD_CMD "\r\n")) + + /* + * How much space does this attribute need? + */ + if (!value_available) + value = ""; + new_len = strlen(name) + strlen(value) + 2; /* SPACE name = value */ + if (new_len > PAYLOAD_LIMIT) + msg_warn("%s payload %s=%.10s... exceeds SMTP protocol limit", + XFORWARD_CMD, name, value); + + /* + * Flush the buffer if we need to, and store the attribute. + */ + if (VSTRING_LEN(buf) > 0 && VSTRING_LEN(buf) + new_len > PAYLOAD_LIMIT) + if ((ret = smtpd_xforward_flush(state, buf)) < 0) + return (ret); + vstring_sprintf_append(buf, " %s=%s", name, value); + + return (0); +} + /* smtpd_proxy_open - open proxy connection */ int smtpd_proxy_open(SMTPD_STATE *state, const char *service, @@ -178,9 +226,17 @@ int smtpd_proxy_open(SMTPD_STATE *state, const char *service, { int fd; char *lines; - char *line; + char *words; VSTRING *buf; int bad; + char *word; + static NAME_CODE xforward_features[] = { + XFORWARD_NAME, SMTPD_PROXY_XFORWARD_NAME, + XFORWARD_ADDR, SMTPD_PROXY_XFORWARD_ADDR, + XFORWARD_PROTO, SMTPD_PROXY_XFORWARD_PROTO, + XFORWARD_HELO, SMTPD_PROXY_XFORWARD_HELO, + 0, 0, + }; /* * This buffer persists beyond the end of a proxy session so we can @@ -236,41 +292,41 @@ int smtpd_proxy_open(SMTPD_STATE *state, const char *service, /* * Parse the EHLO reply and see if we can forward logging information. */ - state->proxy_features = 0; + state->proxy_xforward_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, XCLIENT_CMD) == 0) - state->proxy_features |= SMTPD_FEATURE_XCLIENT; + while ((words = mystrtok(&lines, "\n")) != 0) { + if (mystrtok(&words, "- ") && (word = mystrtok(&words, " \t")) != 0) { + if (strcasecmp(word, XFORWARD_CMD) == 0) + while ((word = mystrtok(&words, " \t")) != 0) + state->proxy_xforward_features |= + name_code(xforward_features, NAME_CODE_FLAG_NONE, word); + } + } /* - * Send all XCLIENT attributes, but only if we have some minimal amount - * of remote client information. Transform internal forms to external - * forms and encode the result as xtext. + * Send XFORWARD attributes. For robustness, explicitly specify what SMTP + * session attributes are known and unknown. */ - if ((state->proxy_features & SMTPD_FEATURE_XCLIENT) - && (IS_AVAIL_CLIENT_NAME(FORWARD_NAME(state)) - || IS_AVAIL_CLIENT_ADDR(FORWARD_ADDR(state)))) { + if (state->proxy_xforward_features) { buf = vstring_alloc(100); - vstring_strcpy(buf, XCLIENT_CMD " " XCLIENT_FORWARD - " " XCLIENT_NAME "="); - if (IS_AVAIL_CLIENT_NAME(FORWARD_NAME(state))) - xtext_quote_append(buf, FORWARD_NAME(state), ""); - vstring_strcat(buf, " " XCLIENT_ADDR "="); - if (IS_AVAIL_CLIENT_ADDR(FORWARD_ADDR(state))) - xtext_quote_append(buf, FORWARD_ADDR(state), ""); - bad = smtpd_proxy_cmd(state, SMTPD_PROX_WANT_ANY, "%s", STR(buf)); - if (bad == 0) { - vstring_strcpy(buf, XCLIENT_CMD " " XCLIENT_FORWARD - " " XCLIENT_HELO "="); - if (IS_AVAIL_CLIENT_HELO(FORWARD_HELO(state))) - xtext_quote_append(buf, FORWARD_HELO(state), ""); - vstring_strcat(buf, " " XCLIENT_PROTO "="); - if (IS_AVAIL_CLIENT_PROTO(FORWARD_PROTO(state))) - xtext_quote_append(buf, FORWARD_PROTO(state), ""); - bad = smtpd_proxy_cmd(state, SMTPD_PROX_WANT_ANY, "%s", STR(buf)); - } + bad = 0; + if ((state->proxy_xforward_features & SMTPD_PROXY_XFORWARD_NAME) + && !(bad = smtpd_xforward(state, buf, XFORWARD_NAME, + IS_AVAIL_CLIENT_NAME(FORWARD_NAME(state)), + FORWARD_NAME(state))) + && (state->proxy_xforward_features & SMTPD_PROXY_XFORWARD_ADDR) + && !(bad = smtpd_xforward(state, buf, XFORWARD_ADDR, + IS_AVAIL_CLIENT_ADDR(FORWARD_ADDR(state)), + FORWARD_ADDR(state))) + && (state->proxy_xforward_features & SMTPD_PROXY_XFORWARD_HELO) + && !(bad = smtpd_xforward(state, buf, XFORWARD_HELO, + IS_AVAIL_CLIENT_HELO(FORWARD_HELO(state)), + FORWARD_HELO(state))) + && (state->proxy_xforward_features & SMTPD_PROXY_XFORWARD_PROTO) + && !(bad = smtpd_xforward(state, buf, XFORWARD_PROTO, + IS_AVAIL_CLIENT_PROTO(FORWARD_PROTO(state)), + FORWARD_PROTO(state)))) + bad = smtpd_xforward_flush(state, buf); vstring_free(buf); if (bad) { vstring_sprintf(state->proxy_buffer, diff --git a/postfix/src/smtpd/smtpd_state.c b/postfix/src/smtpd/smtpd_state.c index 1071d05b8..d64601dea 100644 --- a/postfix/src/smtpd/smtpd_state.c +++ b/postfix/src/smtpd/smtpd_state.c @@ -103,7 +103,7 @@ void smtpd_state_init(SMTPD_STATE *state, VSTREAM *stream) state->proxy = 0; state->proxy_buffer = 0; state->proxy_mail = 0; - state->proxy_features = 0; + state->proxy_xforward_features = 0; state->saved_filter = 0; state->saved_redirect = 0; state->saved_flags = 0; @@ -121,9 +121,9 @@ void smtpd_state_init(SMTPD_STATE *state, VSTREAM *stream) smtpd_peer_init(state); /* - * Initialize xclient information. + * Initialize xforward information. */ - smtpd_xclient_init(state); + smtpd_xforward_init(state); /* * Initialize the conversation history. diff --git a/postfix/src/smtpd/smtpd_xclient.c b/postfix/src/smtpd/smtpd_xclient.c deleted file mode 100644 index f8688111c..000000000 --- a/postfix/src/smtpd/smtpd_xclient.c +++ /dev/null @@ -1,94 +0,0 @@ -/*++ -/* 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) -/* SMTPD_STATE *state; -/* DESCRIPTION -/* smtpd_xclient_init() zeroes the attributes for storage of XCLIENT -/* FORWARD command parameters. -/* -/* smtpd_xclient_preset() takes the result from smtpd_xclient_init() -/* and sets all fields to the same "unknown" value that regular -/* client attributes would have. -/* -/* smtpd_xclient_reset() restores the state from smtpd_xclient_init(). -/* 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.used = 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_preset - set xclient attributes to "unknown" */ - -void smtpd_xclient_preset(SMTPD_STATE *state) -{ - - /* - * This is a temporary solution. Unknown forwarded attributes get the - * same values as unknown normal attributes, so that we don't break - * assumptions in pre-existing code. - */ - state->xclient.used = 1; - state->xclient.name = mystrdup(CLIENT_NAME_UNKNOWN); - state->xclient.addr = mystrdup(CLIENT_ADDR_UNKNOWN); - state->xclient.namaddr = mystrdup(CLIENT_NAMADDR_UNKNOWN); - state->xclient.protocol = mystrdup(CLIENT_PROTO_UNKNOWN); -} - -/* smtpd_xclient_reset - reset XCLIENT attributes */ - -void smtpd_xclient_reset(SMTPD_STATE *state) -{ -#define FREE_AND_WIPE(s) { if (s) myfree(s); s = 0; } - - state->xclient.used = 0; - 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); -} diff --git a/postfix/src/smtpd/smtpd_xforward.c b/postfix/src/smtpd/smtpd_xforward.c new file mode 100644 index 000000000..280c00aa5 --- /dev/null +++ b/postfix/src/smtpd/smtpd_xforward.c @@ -0,0 +1,103 @@ +/*++ +/* NAME +/* smtpd_xforward 3 +/* SUMMARY +/* maintain XCLIENT information +/* SYNOPSIS +/* #include "smtpd.h" +/* +/* void smtpd_xforward_init(state) +/* SMTPD_STATE *state; +/* +/* void smtpd_xforward_reset(state) +/* SMTPD_STATE *state; +/* DESCRIPTION +/* smtpd_xforward_init() zeroes the attributes for storage of +/* XFORWARD command parameters. +/* +/* smtpd_xforward_preset() takes the result from smtpd_xforward_init() +/* and sets all fields to the same "unknown" value that regular +/* client attributes would have. +/* +/* smtpd_xforward_reset() restores the state from smtpd_xforward_init(). +/* 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_xforward_init - initialize XCLIENT attributes */ + +void smtpd_xforward_init(SMTPD_STATE *state) +{ + state->xforward.flags = 0; + state->xforward.name = 0; + state->xforward.addr = 0; + state->xforward.namaddr = 0; + state->xforward.protocol = 0; + state->xforward.helo_name = 0; + state->xforward.ident = 0; +} + +/* smtpd_xforward_preset - set xforward attributes to "unknown" */ + +void smtpd_xforward_preset(SMTPD_STATE *state) +{ + + /* + * Sanity checks. + */ + if (state->xforward.flags) + msg_panic("smtpd_xforward_preset: bad flags: 0x%x", + state->xforward.flags); + + /* + * This is a temporary solution. Unknown forwarded attributes get the + * same values as unknown normal attributes, so that we don't break + * assumptions in pre-existing code. + */ + state->xforward.flags = SMTPD_XFORWARD_FLAG_INIT; + state->xforward.name = mystrdup(CLIENT_NAME_UNKNOWN); + state->xforward.addr = mystrdup(CLIENT_ADDR_UNKNOWN); + state->xforward.namaddr = mystrdup(CLIENT_NAMADDR_UNKNOWN); + /* Leave helo at zero. */ + state->xforward.protocol = mystrdup(CLIENT_PROTO_UNKNOWN); + /* Leave ident at zero. */ +} + +/* smtpd_xforward_reset - reset XCLIENT attributes */ + +void smtpd_xforward_reset(SMTPD_STATE *state) +{ +#define FREE_AND_WIPE(s) { if (s) myfree(s); s = 0; } + + state->xforward.flags = 0; + FREE_AND_WIPE(state->xforward.name); + FREE_AND_WIPE(state->xforward.addr); + FREE_AND_WIPE(state->xforward.namaddr); + FREE_AND_WIPE(state->xforward.protocol); + FREE_AND_WIPE(state->xforward.helo_name); + FREE_AND_WIPE(state->xforward.ident); +} diff --git a/postfix/src/smtpstone/smtp-source.c b/postfix/src/smtpstone/smtp-source.c index fdb2f8690..cc5062340 100644 --- a/postfix/src/smtpstone/smtp-source.c +++ b/postfix/src/smtpstone/smtp-source.c @@ -793,8 +793,10 @@ int main(int argc, char **argv) count++; break; case 'C': - if ((connect_count = atoi(optarg)) <= 0) + if ((connect_count = atoi(optarg)) <= 0) { + msg_error("bad connection count: %s", optarg); usage(argv[0]); + } break; case 'd': disconnect = 0; @@ -803,8 +805,10 @@ int main(int argc, char **argv) sender = optarg; break; case 'l': - if ((message_length = atoi(optarg)) <= 0) + if ((message_length = atoi(optarg)) <= 0) { + msg_error("bad message length: %s", optarg); usage(argv[0]); + } message_data = mymalloc(message_length); memset(message_data, 'X', message_length); for (i = 80; i < message_length; i += 80) { @@ -817,24 +821,36 @@ int main(int argc, char **argv) talk_lmtp = 1; break; case 'm': - if ((message_count = atoi(optarg)) <= 0) + if ((message_count = atoi(optarg)) <= 0) { + msg_error("bad message count: %s", optarg); usage(argv[0]); + } break; case 'o': send_helo_first = 0; send_headers = 0; break; case 'r': - if ((recipients = atoi(optarg)) <= 0) + if ((recipients = atoi(optarg)) <= 0) { + msg_error("bad recipient count: %s", optarg); usage(argv[0]); + } break; case 'R': - if (fixed_delay > 0 || (random_delay = atoi(optarg)) <= 0) + if (fixed_delay > 0) { + msg_error("do not use -w and -R options at the same time"); + usage(argv[0]); + } + if ((random_delay = atoi(optarg)) <= 0) { + msg_error("bad random delay: %s", optarg); usage(argv[0]); + } break; case 's': - if ((sessions = atoi(optarg)) <= 0) + if ((sessions = atoi(optarg)) <= 0) { + msg_error("bad session count: %s", optarg); usage(argv[0]); + } break; case 'S': subject = optarg; @@ -846,8 +862,14 @@ int main(int argc, char **argv) msg_verbose++; break; case 'w': - if (random_delay > 0 || (fixed_delay = atoi(optarg)) <= 0) + if (random_delay > 0) { + msg_error("do not use -w and -R options at the same time"); usage(argv[0]); + } + if ((fixed_delay = atoi(optarg)) <= 0) { + msg_error("bad fixed delay: %s", optarg); + usage(argv[0]); + } break; default: usage(argv[0]); diff --git a/postfix/src/util/argv.c b/postfix/src/util/argv.c index ff94f0328..bf3fb84ce 100644 --- a/postfix/src/util/argv.c +++ b/postfix/src/util/argv.c @@ -95,13 +95,16 @@ ARGV *argv_free(ARGV *argvp) ARGV *argv_alloc(int len) { ARGV *argvp; + int sane_len; /* * Make sure that always argvp->argc < argvp->len. */ argvp = (ARGV *) mymalloc(sizeof(*argvp)); - argvp->len = (len < 2 ? 2 : len); - argvp->argv = (char **) mymalloc((argvp->len + 1) * sizeof(char *)); + argvp->len = 0; + sane_len = (len < 2 ? 2 : len); + argvp->argv = (char **) mymalloc((sane_len + 1) * sizeof(char *)); + argvp->len = sane_len; argvp->argc = 0; argvp->argv[0] = 0; return (argvp); @@ -111,10 +114,12 @@ ARGV *argv_alloc(int len) static void argv_extend(ARGV *argvp) { - argvp->len *= 2; + int new_len; + + new_len = argvp->len * 2; argvp->argv = (char **) - myrealloc((char *) argvp->argv, - (argvp->len + 1) * sizeof(char *)); + myrealloc((char *) argvp->argv, (new_len + 1) * sizeof(char *)); + argvp->len = new_len; } /* argv_add - add string to vector */ diff --git a/postfix/src/util/inet_addr_list.c b/postfix/src/util/inet_addr_list.c index fa1cbd399..49ae833d5 100644 --- a/postfix/src/util/inet_addr_list.c +++ b/postfix/src/util/inet_addr_list.c @@ -61,10 +61,13 @@ void inet_addr_list_init(INET_ADDR_LIST *list) { + int init_size; + list->used = 0; - list->size = 2; - list->addrs = (struct in_addr *) - mymalloc(sizeof(*list->addrs) * list->size); + list->size = 0; + init_size = 2; + list->addrs = (struct in_addr *) mymalloc(sizeof(*list->addrs) * init_size); + list->size = init_size; } /* inet_addr_list_append - append address to internet address list */ @@ -72,15 +75,17 @@ void inet_addr_list_init(INET_ADDR_LIST *list) void inet_addr_list_append(INET_ADDR_LIST *list, struct in_addr * addr) { char *myname = "inet_addr_list_append"; + int new_size; if (msg_verbose > 1) msg_info("%s: %s", myname, inet_ntoa(*addr)); - if (list->used >= list->size) - list->size *= 2; - list->addrs = (struct in_addr *) - myrealloc((char *) list->addrs, - sizeof(*list->addrs) * list->size); + if (list->used >= list->size) { + new_size = list->size * 2; + list->addrs = (struct in_addr *) + myrealloc((char *) list->addrs, sizeof(*list->addrs) * new_size); + list->size = new_size; + } list->addrs[list->used++] = *addr; } diff --git a/postfix/src/util/intv.c b/postfix/src/util/intv.c index 1d117fe02..774e12d10 100644 --- a/postfix/src/util/intv.c +++ b/postfix/src/util/intv.c @@ -86,8 +86,9 @@ INTV *intv_alloc(int len) * Initialize. */ intvp = (INTV *) mymalloc(sizeof(*intvp)); + intvp->len = 0; + intvp->intv = (int *) mymalloc(len * sizeof(intvp->intv[0])); intvp->len = len; - intvp->intv = (int *) mymalloc(intvp->len * sizeof(intvp->intv[0])); intvp->intc = 0; return (intvp); } @@ -97,6 +98,7 @@ INTV *intv_alloc(int len) void intv_add(INTV *intvp, int count,...) { va_list ap; + int new_len; /* * Make sure that always intvp->intc < intvp->len. @@ -104,9 +106,10 @@ void intv_add(INTV *intvp, int count,...) va_start(ap, count); while (count-- > 0) { if (intvp->intc >= intvp->len) { - intvp->len *= 2; + new_len = intvp->len * 2; intvp->intv = (int *) myrealloc((char *) intvp->intv, - intvp->len * sizeof(int)); + new_len * sizeof(int)); + intvp->len = new_len; } intvp->intv[intvp->intc++] = va_arg(ap, int); } diff --git a/postfix/src/util/mvect.c b/postfix/src/util/mvect.c index fa3df03bd..ed03d2ad0 100644 --- a/postfix/src/util/mvect.c +++ b/postfix/src/util/mvect.c @@ -70,11 +70,12 @@ char *mvect_alloc(MVECT *vect, int elsize, int nelm, void (*init_fn) (char *, int), void (*wipe_fn) (char *, int)) { - vect->nelm = nelm; - vect->elsize = elsize; vect->init_fn = init_fn; vect->wipe_fn = wipe_fn; - vect->ptr = mymalloc(vect->elsize * vect->nelm); + vect->nelm = 0; + vect->ptr = mymalloc(elsize * nelm); + vect->nelm = nelm; + vect->elsize = elsize; if (vect->init_fn) vect->init_fn(vect->ptr, vect->nelm); return (vect->ptr); @@ -86,12 +87,14 @@ char *mvect_realloc(MVECT *vect, int nelm) { int old_len = vect->nelm; int incr = nelm - old_len; + int new_nelm; if (incr > 0) { if (incr < old_len) incr = old_len; - vect->nelm += incr; - vect->ptr = myrealloc(vect->ptr, vect->elsize * vect->nelm); + new_nelm = vect->nelm + incr; + vect->ptr = myrealloc(vect->ptr, vect->elsize * new_nelm); + vect->nelm = new_nelm; if (vect->init_fn) vect->init_fn(vect->ptr + old_len * vect->elsize, incr); } diff --git a/postfix/src/util/name_code.c b/postfix/src/util/name_code.c index ece60c0b3..cf32cc6e9 100644 --- a/postfix/src/util/name_code.c +++ b/postfix/src/util/name_code.c @@ -13,8 +13,9 @@ /* .in -4 /* } NAME_CODE; /* -/* int name_code(table, name) +/* int name_code(table, flags, name) /* NAME_CODE *table; +/* int flags; /* const char *name; /* /* const char *str_name_code(table, code) @@ -27,7 +28,13 @@ /* corresponds to "name not found". /* /* name_code() looks up the code that corresponds with the name. -/* The lookup is case insensitive. +/* The lookup is case insensitive. The flags argument specifies +/* zero or more of the following: +/* .IP NAME_CODE_FLAG_STRICT_CASE +/* String lookups are case sensitive. +/* .PP +/* For convenience the constant NAME_CODE_FLAG_NONE requests +/* no special processing. /* /* str_name_code() translates a number to its equivalend string. /* DIAGNOSTICS @@ -59,12 +66,18 @@ /* name_code - look up code by name */ -int name_code(NAME_CODE *table, const char *name) +int name_code(NAME_CODE *table, int flags, const char *name) { NAME_CODE *np; + int (*lookup) (const char *, const char *); + + if (flags & NAME_CODE_FLAG_STRICT_CASE) + lookup = strcmp; + else + lookup = strcasecmp; for (np = table; np->name; np++) - if (strcasecmp(name, np->name) == 0) + if (lookup(name, np->name) == 0) break; return (np->code); } diff --git a/postfix/src/util/name_code.h b/postfix/src/util/name_code.h index 6722eee6b..dd251b7aa 100644 --- a/postfix/src/util/name_code.h +++ b/postfix/src/util/name_code.h @@ -19,7 +19,10 @@ typedef struct { int code; } NAME_CODE; -extern int name_code(NAME_CODE *, const char *); +#define NAME_CODE_FLAG_NONE 0 +#define NAME_CODE_FLAG_STRICT_CASE (1<<0) + +extern int name_code(NAME_CODE *, int, const char *); extern const char *str_name_code(NAME_CODE *, int); /* LICENSE diff --git a/postfix/src/util/vstring.c b/postfix/src/util/vstring.c index 43ffae1e2..ff926dd81 100644 --- a/postfix/src/util/vstring.c +++ b/postfix/src/util/vstring.c @@ -253,6 +253,7 @@ static void vstring_extend(VBUF *bp, int incr) { unsigned used = bp->ptr - bp->data; + int new_len; /* * Note: vp->vbuf.len is the current buffer size (both on entry and on @@ -261,8 +262,9 @@ static void vstring_extend(VBUF *bp, int incr) * strings we might want to abandon the length doubling strategy, and go * to fixed increments. */ - bp->len += (bp->len > incr ? bp->len : incr); - bp->data = (unsigned char *) myrealloc((char *) bp->data, bp->len); + new_len = bp->len + (bp->len > incr ? bp->len : incr); + bp->data = (unsigned char *) myrealloc((char *) bp->data, new_len); + bp->len = new_len; bp->ptr = bp->data + used; bp->cnt = bp->len - used; } @@ -305,6 +307,7 @@ VSTRING *vstring_alloc(int len) msg_panic("vstring_alloc: bad length %d", len); vp = (VSTRING *) mymalloc(sizeof(*vp)); vp->vbuf.flags = 0; + vp->vbuf.len = 0; vp->vbuf.data = (unsigned char *) mymalloc(len); vp->vbuf.len = len; VSTRING_RESET(vp);