mirror of
https://github.com/vdukhovni/postfix
synced 2025-08-30 05:38:06 +00:00
postfix-2.0.16-20031201
This commit is contained in:
parent
edb9945f66
commit
e0c65a2f44
@ -8778,13 +8778,13 @@ Apologies for any names omitted.
|
|||||||
logs more specific information. File: master/master_ent.c.
|
logs more specific information. File: master/master_ent.c.
|
||||||
Reported by several people.
|
Reported by several people.
|
||||||
|
|
||||||
20031125-8
|
20031125-20031201
|
||||||
|
|
||||||
Feature: XCLIENT support to override the SMTP server's
|
Feature: XCLIENT support to override the SMTP server's
|
||||||
client information for logging and/or access control. This
|
client information for logging and/or access control. This
|
||||||
replaces the short-lived XADDR and XLOGINFO extensions.
|
replaces the short-lived XADDR and XLOGINFO extensions.
|
||||||
Based on code by Victor Duchovni, with major simplifications.
|
Remotely based on code by Victor Duchovni. Files:
|
||||||
Files: smtpd/{smtpd,smtpd_check,smtpd_proxy,smtpd_xclient}.c
|
smtpd/{smtpd,smtpd_check,smtpd_proxy,smtpd_xclient}.c
|
||||||
smtp/smtp_smtp_proto.c, *qmgr/qmgr_message.c,
|
smtp/smtp_smtp_proto.c, *qmgr/qmgr_message.c,
|
||||||
global/deliver_request.c.
|
global/deliver_request.c.
|
||||||
|
|
||||||
|
@ -3,49 +3,42 @@ Purpose of the XCLIENT extension to SMTP
|
|||||||
|
|
||||||
The XCLIENT command targets problems in the following areas:
|
The XCLIENT command targets problems in the following areas:
|
||||||
|
|
||||||
1 - Access control tests. SMTP server access rules are difficult
|
1 - Access control tests. SMTP server access rules can be difficult
|
||||||
to verify when decisions can be triggered only by remote clients.
|
to verify when decisions can be triggered by remote clients only.
|
||||||
In order to facilitate access rule testing, an SMTP client test
|
In order to facilitate access rule testing, an SMTP client test
|
||||||
program needs the ability to override the SMTP server's idea of
|
program needs the ability to override the SMTP server's idea of
|
||||||
the SMTP client hostname, network address, and other information.
|
the SMTP client hostname, network address, and other information,
|
||||||
|
for the entire duration of an SMTP session.
|
||||||
|
|
||||||
2 - Logging after content filter. With Internet->MTA1->filter->MTA2
|
2 - Logging after content filter. With Internet->MTA1->filter->MTA2
|
||||||
style content filter applications, remote client information is
|
style content filter applications, remote client information is
|
||||||
lost when MTA1 gives the mail to the content filter. To simplify
|
lost when MTA1 gives the mail to the content filter. To simplify
|
||||||
the interpretation of MTA2 logging, it would help if MTA1 could
|
the interpretation of MTA2 logging, it would help if MTA1 could
|
||||||
forward client information through the content filter to MTA2.
|
forward client information through the content filter to MTA2, for
|
||||||
|
a single message delivery.
|
||||||
|
|
||||||
3 - Post-filter access control and logging. With Internet->filter->MTA
|
3 - Post-filter access control and logging. With Internet->filter->MTA
|
||||||
style content filter applications, the filter can be simplified if
|
style content filter applications, the filter can be simplified if
|
||||||
it can delegate decisions concerning mail relay and other access
|
it can delegate decisions concerning mail relay and other access
|
||||||
control to the MTA. As in the first example, this requires that
|
control to the MTA. As in the first example, this requires that
|
||||||
the filter can override the MTA's idea of the SMTP client hostname,
|
the filter can override the MTA's idea of the SMTP client hostname,
|
||||||
network address, and other information.
|
network address, and other information, for the entire duration of
|
||||||
|
an SMTP session.
|
||||||
The preceding suggests that there is a need for two functions:
|
|
||||||
|
|
||||||
1 - Override the MTA's idea of SMTP client information for access
|
|
||||||
control and other purposes. This function is generally useful
|
|
||||||
for trouble shooting. The implementation can be relatively
|
|
||||||
straightforward because it updates already existing attributes.
|
|
||||||
|
|
||||||
2 - Forward remote client information for logging purposes. This
|
|
||||||
function is limited mainly to environments that use SMTP-based
|
|
||||||
content filters. The implementation requires more invasive
|
|
||||||
changes to the MTA to store the additional attributes and to
|
|
||||||
choose between the normal attributes and the forwarded ones.
|
|
||||||
|
|
||||||
Command overview
|
Command overview
|
||||||
================
|
================
|
||||||
|
|
||||||
The EHLO keyword associated with this extension is XCLIENT.
|
XCLIENT is an extension to SMTP. The EHLO keyword associated with
|
||||||
|
this extension is XCLIENT.
|
||||||
|
|
||||||
The XCLIENT OVERRIDE command updates the remote client attributes
|
The XCLIENT OVERRIDE command updates the remote client attributes
|
||||||
that the MTA normally uses for access control, message headers,
|
that the MTA normally uses for access control, message headers,
|
||||||
logging and so on, while the XCLIENT FORWARD command maintains an
|
logging and so on, for the duration of an entire SMTP session.
|
||||||
additional set of attributes that is meant to be used for logging
|
|
||||||
purposes. In the absence of forwarded attributes the MTA must use
|
The XCLIENT FORWARD command maintains an additional set of attributes
|
||||||
the normal remote client attribute values.
|
that concern only one message delivery attempt. In the absence of
|
||||||
|
forwarded attributes the MTA must use the normal remote client
|
||||||
|
attribute values.
|
||||||
|
|
||||||
The general command syntax is described below. Upper case and
|
The general command syntax is described below. Upper case and
|
||||||
quoted strings specify terminals, lowercase strings specify meta
|
quoted strings specify terminals, lowercase strings specify meta
|
||||||
@ -59,7 +52,7 @@ case, they are in fact case insensitive.
|
|||||||
|
|
||||||
attribute = name"="value
|
attribute = name"="value
|
||||||
|
|
||||||
name = ( CLIENT_NAME | CLIENT_ADDR | CLIENT_CODE | PROTOCOL | HELO_NAME )
|
name = ( CLIENT_NAME|CLIENT_ADDR|CLIENT_CODE|CLIENT_PROTO|CLIENT_HELO )
|
||||||
|
|
||||||
value = ( { empty } | xtext )
|
value = ( { empty } | xtext )
|
||||||
|
|
||||||
@ -88,10 +81,11 @@ Specific usage scenarios
|
|||||||
This section discusses the semantics of XCLIENT requests. Specific
|
This section discusses the semantics of XCLIENT requests. Specific
|
||||||
syntax details are given in the next section.
|
syntax details are given in the next section.
|
||||||
|
|
||||||
The XCLIENT OVERRIDE request modifies the attributes that the MTA
|
The XCLIENT OVERRIDE request modifies remote client attributes that
|
||||||
normally uses for access control, message headers, logging, and
|
the MTA normally uses for access control, message headers, logging,
|
||||||
for other purposes. Attributes that are not specified in XCLIENT
|
and for other purposes, for the duraction of the entire SMTP session.
|
||||||
OVERRIDE requests are not modified.
|
Attributes that are not specified in XCLIENT OVERRIDE requests are
|
||||||
|
not modified.
|
||||||
|
|
||||||
The following example overrides only the client hostname and network
|
The following example overrides only the client hostname and network
|
||||||
address, leaving unchanged all other client attributes such as the
|
address, leaving unchanged all other client attributes such as the
|
||||||
@ -100,21 +94,23 @@ mail protocol or the hostname given in the HELO command:
|
|||||||
XCLIENT OVERRIDE CLIENT_NAME=spike.porcupine.org
|
XCLIENT OVERRIDE CLIENT_NAME=spike.porcupine.org
|
||||||
XCLIENT OVERRIDE CLIENT_ADDR=168.100.189.2
|
XCLIENT OVERRIDE CLIENT_ADDR=168.100.189.2
|
||||||
|
|
||||||
The XCLIENT FORWARD request specifies surrogate client attributes for
|
The XCLIENT FORWARD request specifies remote client attributes
|
||||||
logging purposes. In the absence of any XCLIENT FORWARD attributes, the
|
concerning only one message delivery attempt. The attributes are
|
||||||
MTA must use the normal client attributes.
|
discarded after the next MAIL FROM transaction finishes. In the
|
||||||
|
absence of any XCLIENT FORWARD attributes, the MTA must use the
|
||||||
|
normal client attributes.
|
||||||
|
|
||||||
If only a subset of all possible XCLIENT FORWARD attributes is
|
If only a subset of all possible XCLIENT FORWARD attributes is
|
||||||
specified, the unspecified attributes must either not be logged at
|
specified, the unspecified attributes must be treated as if they
|
||||||
all, or they must be logged as if they are unknown. This avoids
|
are unknown. The implementation must not replace missing XCLIENT
|
||||||
the logging of attributes from mixed origins.
|
FORWARD attributes by normal attributes.
|
||||||
|
|
||||||
The following example updates all forwarded client attributes that
|
The following example updates all forwarded client attributes that
|
||||||
are defined in this document, leaving none at their default unknown
|
are defined in this document, leaving none at their default unknown
|
||||||
value:
|
value:
|
||||||
|
|
||||||
XCLIENT FORWARD CLIENT_NAME=spike.porcupine.org CLIENT_ADDR=168.100.189.2
|
XCLIENT FORWARD CLIENT_NAME=spike.porcupine.org CLIENT_ADDR=168.100.189.2
|
||||||
XCLIENT FORWARD HELO_NAME=spike.porcupine.org PROTOCOL=ESMTP
|
XCLIENT FORWARD CLIENT_HELO=spike.porcupine.org CLIENT_PROTO=ESMTP
|
||||||
|
|
||||||
Note 1: attributes specified with successive XCLIENT commands
|
Note 1: attributes specified with successive XCLIENT commands
|
||||||
accumulate.
|
accumulate.
|
||||||
@ -126,34 +122,36 @@ Attribute value details
|
|||||||
=======================
|
=======================
|
||||||
|
|
||||||
Attribute values are encoded as RFC 1891 xtext strings. To explicitly
|
Attribute values are encoded as RFC 1891 xtext strings. To explicitly
|
||||||
specify that an attribute value is unknown, the value must be empty;
|
specify that an attribute value is unavailable, the value must be
|
||||||
the client must not send its own internal representation of unknown
|
empty; the client must not send its own internal representation of
|
||||||
information.
|
unavailable information.
|
||||||
|
|
||||||
CLIENT_CODE specifies CLIENT_NAME hostname lookup status information.
|
The CLIENT_CODE attribute specifies CLIENT_NAME hostname lookup
|
||||||
Values are OK (success), TEMP (temporary lookup failure) or PERM
|
status information. Values are OK (success), TEMP (temporary lookup
|
||||||
(permanent lookup failure). When CLIENT_CODE is set to any value
|
failure) or PERM (permanent lookup failure). When CLIENT_CODE is
|
||||||
other than OK, the CLIENT_NAME attribute is automatically set to
|
set to any value other than OK, the CLIENT_NAME attribute is
|
||||||
the unknown value.
|
automatically set to the unknown value.
|
||||||
|
|
||||||
CLIENT_NAME should specify a syntactically valid domain name and
|
The CLIENT_NAME attribute should specify a syntactically valid
|
||||||
not a numerical address. When a null client name is specified
|
domain name and not a numerical address. When a null client name
|
||||||
(i.e. the client name is unknown), the CLIENT_CODE attribute is
|
is specified (i.e. the client name is unknown), the CLIENT_CODE
|
||||||
implicitly set to PERM. When a valid domain name is specified,
|
attribute is implicitly set to PERM. When a valid domain name is
|
||||||
CLIENT_CODE is implicitly set to OK. The server may process a
|
specified, CLIENT_CODE is implicitly set to OK. The server may
|
||||||
syntactically invalid domain name as if it were unknown.
|
process a syntactically invalid domain name as if it were unknown.
|
||||||
|
|
||||||
CLIENT_ADDR must specify a numerical network address without [].
|
The CLIENT_ADDR attribute must specify a numerical network address
|
||||||
|
without [].
|
||||||
|
|
||||||
PROTOCOL is a string of up to 64 printable characters, where
|
The CLIENT_PROTO attribute should be a string of up to 64 printable
|
||||||
printable is defined by the ANSI C isascii() and isprint() predicates.
|
characters, where printable is defined by the ANSI C isascii() and
|
||||||
|
isprint() predicates.
|
||||||
|
|
||||||
HELO_NAME should be a syntactically valid HELO parameter value.
|
The CLIENT_HELO attribute should be a syntactically valid HELO
|
||||||
|
parameter value.
|
||||||
|
|
||||||
Note 3: syntactically valid CLIENT_NAME and HELO_NAME attributes
|
Note 3: syntactically valid CLIENT_NAME and CLIENT_HELO attributes
|
||||||
can be up to 255 characters long. The client must not send XCLIENT OVERRIDE
|
can be up to 255 characters long. The client must not send XCLIENT
|
||||||
or XCLIENT FORWARD commands that exceed the 512 character limit of SMTP
|
commands that exceed the 512 character limit of SMTP commands.
|
||||||
commands.
|
|
||||||
|
|
||||||
Note 4: attribute values may end up in Received: or other message
|
Note 4: attribute values may end up in Received: or other message
|
||||||
headers. The receiving MTA may substitute characters in order to
|
headers. The receiving MTA may substitute characters in order to
|
||||||
@ -175,6 +173,5 @@ SMTP connection caching
|
|||||||
SMTP connection caching makes it possible to deliver multiple
|
SMTP connection caching makes it possible to deliver multiple
|
||||||
messages within the same SMTP session. Thus, one persistent SMTP
|
messages within the same SMTP session. Thus, one persistent SMTP
|
||||||
session with a content filter can carry messages from unrelated
|
session with a content filter can carry messages from unrelated
|
||||||
clients. Applications should ensure that XCLIENT information from
|
clients. The XCLIENT FORWARD attributes are reset after the MAIL
|
||||||
one remote client is properly updated before commencing delivery
|
FROM command completes, so there is no risk of information leakage.
|
||||||
of mail from a different remote client.
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
<html> <head> </head> <body> <pre>
|
<html> <body> <pre>
|
||||||
QMQPD(8) QMQPD(8)
|
QMQPD(8) QMQPD(8)
|
||||||
|
|
||||||
<b>NAME</b>
|
<b>NAME</b>
|
||||||
@ -44,72 +44,72 @@ QMQPD(8) QMQPD(8)
|
|||||||
command after a configuration change.
|
command after a configuration change.
|
||||||
|
|
||||||
<b>Miscellaneous</b>
|
<b>Miscellaneous</b>
|
||||||
<b>debug</b><i>_</i><b>peer</b><i>_</i><b>level</b>
|
<b>debug_peer_level</b>
|
||||||
Increment in verbose logging level when a remote
|
Increment in verbose logging level when a remote
|
||||||
host matches a pattern in the <b>debug</b><i>_</i><b>peer</b><i>_</i><b>list</b>
|
host matches a pattern in the <b>debug_peer_list</b>
|
||||||
parameter.
|
parameter.
|
||||||
|
|
||||||
<b>debug</b><i>_</i><b>peer</b><i>_</i><b>list</b>
|
<b>debug_peer_list</b>
|
||||||
List of domain or network patterns. When a remote
|
List of domain or network patterns. When a remote
|
||||||
host matches a pattern, increase the verbose log-
|
host matches a pattern, increase the verbose log-
|
||||||
ging level by the amount specified in the
|
ging level by the amount specified in the
|
||||||
<b>debug</b><i>_</i><b>peer</b><i>_</i><b>level</b> parameter.
|
<b>debug_peer_level</b> parameter.
|
||||||
|
|
||||||
<b>hopcount</b><i>_</i><b>limit</b>
|
<b>hopcount_limit</b>
|
||||||
Limit the number of <b>Received:</b> message headers.
|
Limit the number of <b>Received:</b> message headers.
|
||||||
|
|
||||||
<b>qmqpd</b><i>_</i><b>authorized</b><i>_</i><b>clients</b>
|
<b>qmqpd_authorized_clients</b>
|
||||||
A list of domain or network patterns that specifies
|
A list of domain or network patterns that specifies
|
||||||
what clients are allowed to use the service.
|
what clients are allowed to use the service.
|
||||||
|
|
||||||
<b>qmqpd</b><i>_</i><b>timeout</b>
|
<b>qmqpd_timeout</b>
|
||||||
Limit the time to send a server response and to
|
Limit the time to send a server response and to
|
||||||
receive a client request.
|
receive a client request.
|
||||||
|
|
||||||
<b>soft</b><i>_</i><b>bounce</b>
|
<b>soft_bounce</b>
|
||||||
Change hard (D) reject responses into soft (Z)
|
Change hard (D) reject responses into soft (Z)
|
||||||
reject responses. This can be useful for testing
|
reject responses. This can be useful for testing
|
||||||
purposes.
|
purposes.
|
||||||
|
|
||||||
<b>Content inspection controls</b>
|
<b>Content inspection controls</b>
|
||||||
<b>content</b><i>_</i><b>filter</b>
|
<b>content_filter</b>
|
||||||
The name of a mail delivery transport that filters
|
The name of a mail delivery transport that filters
|
||||||
mail and that either bounces mail or re-injects the
|
mail and that either bounces mail or re-injects the
|
||||||
result back into Postfix. This parameter uses the
|
result back into Postfix. This parameter uses the
|
||||||
same syntax as the right-hand side of a Postfix
|
same syntax as the right-hand side of a Postfix
|
||||||
transport table.
|
transport table.
|
||||||
|
|
||||||
<b>receive</b><i>_</i><b>override</b><i>_</i><b>options</b>
|
<b>receive_override_options</b>
|
||||||
The following options override <b>main.cf</b> settings.
|
The following options override <b>main.cf</b> settings.
|
||||||
The options are passed on to the downstream cleanup
|
The options are passed on to the downstream cleanup
|
||||||
server.
|
server.
|
||||||
|
|
||||||
<b>no</b><i>_</i><b>address</b><i>_</i><b>mappings</b>
|
<b>no_address_mappings</b>
|
||||||
Disable canonical address mapping, virtual
|
Disable canonical address mapping, virtual
|
||||||
alias map expansion, address masquerading,
|
alias map expansion, address masquerading,
|
||||||
and automatic BCC recipients. Specify this
|
and automatic BCC recipients. Specify this
|
||||||
if address mapping etc. are to be done <b>after</b>
|
if address mapping etc. are to be done <b>after</b>
|
||||||
an external content filter.
|
an external content filter.
|
||||||
|
|
||||||
<b>no</b><i>_</i><b>header</b><i>_</i><b>body</b><i>_</i><b>checks</b>
|
<b>no_header_body_checks</b>
|
||||||
Disable header/body_checks. Specify this if
|
Disable header/body_checks. Specify this if
|
||||||
header/body_checks are to be done <b>after</b> an
|
header/body_checks are to be done <b>after</b> an
|
||||||
external content filter.
|
external content filter.
|
||||||
|
|
||||||
<b>Resource controls</b>
|
<b>Resource controls</b>
|
||||||
<b>line</b><i>_</i><b>length</b><i>_</i><b>limit</b>
|
<b>line_length_limit</b>
|
||||||
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, and the length of
|
handling of partial input lines, and the length of
|
||||||
sender and recipient addresses that are received
|
sender and recipient addresses that are received
|
||||||
from client.
|
from client.
|
||||||
|
|
||||||
<b>message</b><i>_</i><b>size</b><i>_</i><b>limit</b>
|
<b>message_size_limit</b>
|
||||||
Limit the total size in bytes of a message, includ-
|
Limit the total size in bytes of a message, includ-
|
||||||
ing on-disk storage for sender and recipient
|
ing on-disk storage for sender and recipient
|
||||||
address information.
|
address information.
|
||||||
|
|
||||||
<b>Tarpitting</b>
|
<b>Tarpitting</b>
|
||||||
<b>qmqpd</b><i>_</i><b>error</b><i>_</i><b>delay</b>
|
<b>qmqpd_error_delay</b>
|
||||||
Time to wait in seconds before informing the client
|
Time to wait in seconds before informing the client
|
||||||
of a problem. This slows down run-away errors.
|
of a problem. This slows down run-away errors.
|
||||||
|
|
||||||
|
@ -46,6 +46,15 @@ typedef struct DELIVER_REQUEST {
|
|||||||
char *client_helo; /* helo parameter */
|
char *client_helo; /* helo parameter */
|
||||||
} DELIVER_REQUEST;
|
} DELIVER_REQUEST;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Since we can't send null pointers, null strings represent unavailable
|
||||||
|
* attributes instead. They're less likely to explode in our face, too.
|
||||||
|
*/
|
||||||
|
#define DEL_REQ_ATTR_UNAVAIL(a) (*(a))
|
||||||
|
|
||||||
|
/*
|
||||||
|
* How to deliver, really?
|
||||||
|
*/
|
||||||
#define DEL_REQ_FLAG_DEFLT (DEL_REQ_FLAG_SUCCESS | DEL_REQ_FLAG_BOUNCE)
|
#define DEL_REQ_FLAG_DEFLT (DEL_REQ_FLAG_SUCCESS | DEL_REQ_FLAG_BOUNCE)
|
||||||
#define DEL_REQ_FLAG_SUCCESS (1<<0) /* delete successful recipients */
|
#define DEL_REQ_FLAG_SUCCESS (1<<0) /* delete successful recipients */
|
||||||
#define DEL_REQ_FLAG_BOUNCE (1<<1) /* unimplemented */
|
#define DEL_REQ_FLAG_BOUNCE (1<<1) /* unimplemented */
|
||||||
|
@ -159,27 +159,33 @@ extern char *mail_pathname(const char *, const char *);
|
|||||||
#define XCLIENT_FORWARD "FORWARD" /* forward function */
|
#define XCLIENT_FORWARD "FORWARD" /* forward function */
|
||||||
#define XCLIENT_NAME "CLIENT_NAME" /* client name */
|
#define XCLIENT_NAME "CLIENT_NAME" /* client name */
|
||||||
#define XCLIENT_ADDR "CLIENT_ADDR" /* client address */
|
#define XCLIENT_ADDR "CLIENT_ADDR" /* client address */
|
||||||
#define XCLIENT_PROTO "PROTOCOL" /* client protocol */
|
#define XCLIENT_PROTO "CLIENT_PROTO" /* client protocol */
|
||||||
#define XCLIENT_CODE "CLIENT_CODE" /* client name status */
|
#define XCLIENT_CODE "CLIENT_CODE" /* client name status */
|
||||||
#define XCLIENT_HELO "HELO_NAME" /* client helo */
|
#define XCLIENT_HELO "CLIENT_HELO" /* client helo */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Internal forms for unknown XCLIENT information.
|
* 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_NAME_UNKNOWN "unknown"
|
#define CLIENT_ATTR_UNKNOWN "unknown"
|
||||||
#define CLIENT_ADDR_UNKNOWN "unknown"
|
|
||||||
#define CLIENT_NAMADDR_UNKNOWN CLIENT_NAME_UNKNOWN "[" CLIENT_ADDR_UNKNOWN "]"
|
|
||||||
#define HELO_NAME_UNKNOWN "" /* or NULL */
|
|
||||||
#define PROTOCOL_UNKNOWN "unknown"
|
|
||||||
|
|
||||||
/*
|
#define CLIENT_NAME_UNKNOWN CLIENT_ATTR_UNKNOWN
|
||||||
* Internal forms: recognizing unknown XCLIENT information.
|
#define CLIENT_ADDR_UNKNOWN CLIENT_ATTR_UNKNOWN
|
||||||
*/
|
#define CLIENT_NAMADDR_UNKNOWN CLIENT_ATTR_UNKNOWN
|
||||||
#define IS_UNK_CLNT_NAME(v) (!(v) || !strcmp((v), CLIENT_NAME_UNKNOWN))
|
#define CLIENT_HELO_UNKNOWN 0
|
||||||
#define IS_UNK_CLNT_ADDR(v) (!(v) || !strcmp((v), CLIENT_ADDR_UNKNOWN))
|
#define CLIENT_PROTO_UNKNOWN CLIENT_ATTR_UNKNOWN
|
||||||
#define IS_UNK_CLNT_NAMADDR(v) (!(v) || !strcmp((v), CLIENT_NAMADDR_UNKNOWN))
|
|
||||||
#define IS_UNK_HELO_NAME(v) (!(v) || !*(v))
|
#define IS_UNK_CLIENT_ATTR(v) (!(v) || !strcmp((v), CLIENT_ATTR_UNKNOWN))
|
||||||
#define IS_UNK_PROTOCOL(v) (!(v) || !strcmp((v), PROTOCOL_UNKNOWN))
|
|
||||||
|
#define IS_UNK_CLIENT_NAME(v) IS_UNK_CLIENT_ATTR(v)
|
||||||
|
#define IS_UNK_CLIENT_ADDR(v) IS_UNK_CLIENT_ATTR(v)
|
||||||
|
#define IS_UNK_CLIENT_NAMADDR(v) IS_UNK_CLIENT_ATTR(v)
|
||||||
|
#define IS_UNK_CLIENT_HELO(v) (!(v))
|
||||||
|
#define IS_UNK_CLIENT_PROTO(v) IS_UNK_CLIENT_ATTR(v)
|
||||||
|
|
||||||
/* LICENSE
|
/* LICENSE
|
||||||
/* .ad
|
/* .ad
|
||||||
|
@ -20,7 +20,7 @@
|
|||||||
* Patches change the patchlevel and the release date. Snapshots change the
|
* Patches change the patchlevel and the release date. Snapshots change the
|
||||||
* release date only, unless they include the same bugfix as a patch release.
|
* release date only, unless they include the same bugfix as a patch release.
|
||||||
*/
|
*/
|
||||||
#define MAIL_RELEASE_DATE "20031130"
|
#define MAIL_RELEASE_DATE "20031201"
|
||||||
|
|
||||||
#define VAR_MAIL_VERSION "mail_version"
|
#define VAR_MAIL_VERSION "mail_version"
|
||||||
#define DEF_MAIL_VERSION "2.0.16-" MAIL_RELEASE_DATE
|
#define DEF_MAIL_VERSION "2.0.16-" MAIL_RELEASE_DATE
|
||||||
|
@ -612,13 +612,13 @@ static int qmgr_message_read(QMGR_MESSAGE *message)
|
|||||||
if (message->encoding == 0)
|
if (message->encoding == 0)
|
||||||
message->encoding = mystrdup(MAIL_ATTR_ENC_NONE);
|
message->encoding = mystrdup(MAIL_ATTR_ENC_NONE);
|
||||||
if (message->client_name == 0)
|
if (message->client_name == 0)
|
||||||
message->client_name = mystrdup(CLIENT_NAME_UNKNOWN);
|
message->client_name = mystrdup("");
|
||||||
if (message->client_addr == 0)
|
if (message->client_addr == 0)
|
||||||
message->client_addr = mystrdup(CLIENT_ADDR_UNKNOWN);
|
message->client_addr = mystrdup("");
|
||||||
if (message->client_proto == 0)
|
if (message->client_proto == 0)
|
||||||
message->client_proto = mystrdup(PROTOCOL_UNKNOWN);
|
message->client_proto = mystrdup("");
|
||||||
if (message->client_helo == 0)
|
if (message->client_helo == 0)
|
||||||
message->client_helo = mystrdup(HELO_NAME_UNKNOWN);
|
message->client_helo = mystrdup("");
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Clean up.
|
* Clean up.
|
||||||
@ -1130,6 +1130,14 @@ void qmgr_message_free(QMGR_MESSAGE *message)
|
|||||||
myfree(message->inspect_xport);
|
myfree(message->inspect_xport);
|
||||||
if (message->redirect_addr)
|
if (message->redirect_addr)
|
||||||
myfree(message->redirect_addr);
|
myfree(message->redirect_addr);
|
||||||
|
if (message->client_name)
|
||||||
|
myfree(message->client_name);
|
||||||
|
if (message->client_addr)
|
||||||
|
myfree(message->client_addr);
|
||||||
|
if (message->client_proto)
|
||||||
|
myfree(message->client_proto);
|
||||||
|
if (message->client_helo)
|
||||||
|
myfree(message->client_helo);
|
||||||
qmgr_rcpt_list_free(&message->rcpt_list);
|
qmgr_rcpt_list_free(&message->rcpt_list);
|
||||||
qmgr_message_count--;
|
qmgr_message_count--;
|
||||||
myfree((char *) message);
|
myfree((char *) message);
|
||||||
|
@ -577,13 +577,13 @@ static int qmgr_message_read(QMGR_MESSAGE *message)
|
|||||||
if (message->encoding == 0)
|
if (message->encoding == 0)
|
||||||
message->encoding = mystrdup(MAIL_ATTR_ENC_NONE);
|
message->encoding = mystrdup(MAIL_ATTR_ENC_NONE);
|
||||||
if (message->client_name == 0)
|
if (message->client_name == 0)
|
||||||
message->client_name = mystrdup(CLIENT_NAME_UNKNOWN);
|
message->client_name = mystrdup("");
|
||||||
if (message->client_addr == 0)
|
if (message->client_addr == 0)
|
||||||
message->client_addr = mystrdup(CLIENT_ADDR_UNKNOWN);
|
message->client_addr = mystrdup("");
|
||||||
if (message->client_proto == 0)
|
if (message->client_proto == 0)
|
||||||
message->client_proto = mystrdup(PROTOCOL_UNKNOWN);
|
message->client_proto = mystrdup("");
|
||||||
if (message->client_helo == 0)
|
if (message->client_helo == 0)
|
||||||
message->client_helo = mystrdup(HELO_NAME_UNKNOWN);
|
message->client_helo = mystrdup("");
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Clean up.
|
* Clean up.
|
||||||
@ -1024,6 +1024,14 @@ void qmgr_message_free(QMGR_MESSAGE *message)
|
|||||||
myfree(message->inspect_xport);
|
myfree(message->inspect_xport);
|
||||||
if (message->redirect_addr)
|
if (message->redirect_addr)
|
||||||
myfree(message->redirect_addr);
|
myfree(message->redirect_addr);
|
||||||
|
if (message->client_name)
|
||||||
|
myfree(message->client_name);
|
||||||
|
if (message->client_addr)
|
||||||
|
myfree(message->client_addr);
|
||||||
|
if (message->client_proto)
|
||||||
|
myfree(message->client_proto);
|
||||||
|
if (message->client_helo)
|
||||||
|
myfree(message->client_helo);
|
||||||
qmgr_rcpt_list_free(&message->rcpt_list);
|
qmgr_rcpt_list_free(&message->rcpt_list);
|
||||||
qmgr_message_count--;
|
qmgr_message_count--;
|
||||||
myfree((char *) message);
|
myfree((char *) message);
|
||||||
|
@ -285,8 +285,10 @@ static void qmqpd_copy_sender(QMQPD_STATE *state)
|
|||||||
|
|
||||||
static void qmqpd_write_attributes(QMQPD_STATE *state)
|
static void qmqpd_write_attributes(QMQPD_STATE *state)
|
||||||
{
|
{
|
||||||
|
if (!IS_UNK_CLIENT_NAME(state->name))
|
||||||
rec_fprintf(state->cleanup, REC_TYPE_ATTR, "%s=%s",
|
rec_fprintf(state->cleanup, REC_TYPE_ATTR, "%s=%s",
|
||||||
MAIL_ATTR_CLIENT_NAME, state->name);
|
MAIL_ATTR_CLIENT_NAME, state->name);
|
||||||
|
if (!IS_UNK_CLIENT_ADDR(state->addr))
|
||||||
rec_fprintf(state->cleanup, REC_TYPE_ATTR, "%s=%s",
|
rec_fprintf(state->cleanup, REC_TYPE_ATTR, "%s=%s",
|
||||||
MAIL_ATTR_CLIENT_ADDR, state->addr);
|
MAIL_ATTR_CLIENT_ADDR, state->addr);
|
||||||
rec_fprintf(state->cleanup, REC_TYPE_ATTR, "%s=%s",
|
rec_fprintf(state->cleanup, REC_TYPE_ATTR, "%s=%s",
|
||||||
|
@ -484,11 +484,14 @@ int smtp_xfer(SMTP_STATE *state)
|
|||||||
* commands rejected, DATA rejected) it forces the sender to abort the
|
* commands rejected, DATA rejected) it forces the sender to abort the
|
||||||
* SMTP dialog with RSET and QUIT.
|
* SMTP dialog with RSET and QUIT.
|
||||||
*
|
*
|
||||||
* Update the server's remote client information to avoid leakage of past
|
* Use the XCLIENT command to forward client attributes only when a minimal
|
||||||
* client attributes into an unrelated mail delivery.
|
* amount of information is available.
|
||||||
*/
|
*/
|
||||||
nrcpt = 0;
|
nrcpt = 0;
|
||||||
if (var_smtp_send_xclient && (state->features & SMTP_FEATURE_XCLIENT))
|
if (var_smtp_send_xclient
|
||||||
|
&& (state->features & SMTP_FEATURE_XCLIENT)
|
||||||
|
&& !DEL_REQ_ATTR_UNAVAIL(request->client_name)
|
||||||
|
&& !DEL_REQ_ATTR_UNAVAIL(request->client_addr))
|
||||||
recv_state = send_state = SMTP_STATE_XCLIENT_ADDR;
|
recv_state = send_state = SMTP_STATE_XCLIENT_ADDR;
|
||||||
else
|
else
|
||||||
recv_state = send_state = SMTP_STATE_MAIL;
|
recv_state = send_state = SMTP_STATE_MAIL;
|
||||||
@ -516,10 +519,10 @@ int smtp_xfer(SMTP_STATE *state)
|
|||||||
case SMTP_STATE_XCLIENT_ADDR:
|
case SMTP_STATE_XCLIENT_ADDR:
|
||||||
vstring_strcpy(next_command,
|
vstring_strcpy(next_command,
|
||||||
XCLIENT_CMD " " XCLIENT_FORWARD " " XCLIENT_NAME "=");
|
XCLIENT_CMD " " XCLIENT_FORWARD " " XCLIENT_NAME "=");
|
||||||
if (!IS_UNK_CLNT_NAME(request->client_name))
|
if (!DEL_REQ_ATTR_UNAVAIL(request->client_name))
|
||||||
xtext_quote_append(next_command, request->client_name, "");
|
xtext_quote_append(next_command, request->client_name, "");
|
||||||
vstring_strcat(next_command, " " XCLIENT_ADDR "=");
|
vstring_strcat(next_command, " " XCLIENT_ADDR "=");
|
||||||
if (!IS_UNK_CLNT_ADDR(request->client_addr))
|
if (!DEL_REQ_ATTR_UNAVAIL(request->client_addr))
|
||||||
xtext_quote_append(next_command, request->client_addr, "");
|
xtext_quote_append(next_command, request->client_addr, "");
|
||||||
next_state = SMTP_STATE_XCLIENT_HELO;
|
next_state = SMTP_STATE_XCLIENT_HELO;
|
||||||
break;
|
break;
|
||||||
@ -527,10 +530,10 @@ int smtp_xfer(SMTP_STATE *state)
|
|||||||
case SMTP_STATE_XCLIENT_HELO:
|
case SMTP_STATE_XCLIENT_HELO:
|
||||||
vstring_strcpy(next_command,
|
vstring_strcpy(next_command,
|
||||||
XCLIENT_CMD " " XCLIENT_FORWARD " " XCLIENT_HELO "=");
|
XCLIENT_CMD " " XCLIENT_FORWARD " " XCLIENT_HELO "=");
|
||||||
if (!IS_UNK_HELO_NAME(request->client_helo))
|
if (!DEL_REQ_ATTR_UNAVAIL(request->client_helo))
|
||||||
xtext_quote_append(next_command, request->client_helo, "");
|
xtext_quote_append(next_command, request->client_helo, "");
|
||||||
vstring_strcat(next_command, " " XCLIENT_PROTO "=");
|
vstring_strcat(next_command, " " XCLIENT_PROTO "=");
|
||||||
if (!IS_UNK_PROTOCOL(request->client_proto))
|
if (!DEL_REQ_ATTR_UNAVAIL(request->client_proto))
|
||||||
xtext_quote_append(next_command, request->client_proto, "");
|
xtext_quote_append(next_command, request->client_proto, "");
|
||||||
next_state = SMTP_STATE_MAIL;
|
next_state = SMTP_STATE_MAIL;
|
||||||
break;
|
break;
|
||||||
|
@ -667,9 +667,12 @@ static int helo_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv)
|
|||||||
rcpt_reset(state);
|
rcpt_reset(state);
|
||||||
state->helo_name = mystrdup(printable(argv[1].strval, '?'));
|
state->helo_name = mystrdup(printable(argv[1].strval, '?'));
|
||||||
neuter(state->helo_name, "<>()\\\";:@", '?');
|
neuter(state->helo_name, "<>()\\\";:@", '?');
|
||||||
/* Changing the protocol name breaks the unauthorized pipelining check. */
|
/* Downgrading the protocol name breaks the unauthorized pipelining test. */
|
||||||
if (strcmp(state->protocol, MAIL_PROTO_ESMTP) != 0)
|
if (strcasecmp(state->protocol, MAIL_PROTO_ESMTP) != 0
|
||||||
state->protocol = MAIL_PROTO_SMTP;
|
&& strcasecmp(state->protocol, MAIL_PROTO_SMTP) != 0) {
|
||||||
|
myfree(state->protocol);
|
||||||
|
state->protocol = mystrdup(MAIL_PROTO_SMTP);
|
||||||
|
}
|
||||||
smtpd_chat_reply(state, "250 %s", var_myhostname);
|
smtpd_chat_reply(state, "250 %s", var_myhostname);
|
||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
@ -705,7 +708,10 @@ static int ehlo_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv)
|
|||||||
rcpt_reset(state);
|
rcpt_reset(state);
|
||||||
state->helo_name = mystrdup(printable(argv[1].strval, '?'));
|
state->helo_name = mystrdup(printable(argv[1].strval, '?'));
|
||||||
neuter(state->helo_name, "<>()\\\";:@", '?');
|
neuter(state->helo_name, "<>()\\\";:@", '?');
|
||||||
state->protocol = MAIL_PROTO_ESMTP;
|
if (strcasecmp(state->protocol, MAIL_PROTO_ESMTP) != 0) {
|
||||||
|
myfree(state->protocol);
|
||||||
|
state->protocol = mystrdup(MAIL_PROTO_ESMTP);
|
||||||
|
}
|
||||||
smtpd_chat_reply(state, "250-%s", var_myhostname);
|
smtpd_chat_reply(state, "250-%s", var_myhostname);
|
||||||
smtpd_chat_reply(state, "250-PIPELINING");
|
smtpd_chat_reply(state, "250-PIPELINING");
|
||||||
if (var_message_limit)
|
if (var_message_limit)
|
||||||
@ -743,7 +749,7 @@ static void helo_reset(SMTPD_STATE *state)
|
|||||||
|
|
||||||
/* mail_open_stream - open mail queue file or IPC stream */
|
/* mail_open_stream - open mail queue file or IPC stream */
|
||||||
|
|
||||||
static void mail_open_stream(SMTPD_STATE *state, SMTPD_TOKEN *argv)
|
static void mail_open_stream(SMTPD_STATE *state)
|
||||||
{
|
{
|
||||||
char *postdrop_command;
|
char *postdrop_command;
|
||||||
int cleanup_flags;
|
int cleanup_flags;
|
||||||
@ -815,7 +821,7 @@ static void mail_open_stream(SMTPD_STATE *state, SMTPD_TOKEN *argv)
|
|||||||
if (*var_filter_xport)
|
if (*var_filter_xport)
|
||||||
rec_fprintf(state->cleanup, REC_TYPE_FILT, "%s", var_filter_xport);
|
rec_fprintf(state->cleanup, REC_TYPE_FILT, "%s", var_filter_xport);
|
||||||
}
|
}
|
||||||
rec_fputs(state->cleanup, REC_TYPE_FROM, argv[2].strval);
|
rec_fputs(state->cleanup, REC_TYPE_FROM, state->sender);
|
||||||
if (state->encoding != 0)
|
if (state->encoding != 0)
|
||||||
rec_fprintf(state->cleanup, REC_TYPE_ATTR, "%s=%s",
|
rec_fprintf(state->cleanup, REC_TYPE_ATTR, "%s=%s",
|
||||||
MAIL_ATTR_ENCODING, state->encoding);
|
MAIL_ATTR_ENCODING, state->encoding);
|
||||||
@ -824,16 +830,19 @@ static void mail_open_stream(SMTPD_STATE *state, SMTPD_TOKEN *argv)
|
|||||||
* Store the client attributes for logging purposes.
|
* Store the client attributes for logging purposes.
|
||||||
*/
|
*/
|
||||||
if (SMTPD_STAND_ALONE(state) == 0) {
|
if (SMTPD_STAND_ALONE(state) == 0) {
|
||||||
|
if (!IS_UNK_CLIENT_NAME(FORWARD_NAME(state)))
|
||||||
rec_fprintf(state->cleanup, REC_TYPE_ATTR, "%s=%s",
|
rec_fprintf(state->cleanup, REC_TYPE_ATTR, "%s=%s",
|
||||||
MAIL_ATTR_CLIENT_NAME, FORWARD_NAME(state));
|
MAIL_ATTR_CLIENT_NAME, FORWARD_NAME(state));
|
||||||
|
if (!IS_UNK_CLIENT_ADDR(FORWARD_ADDR(state)))
|
||||||
rec_fprintf(state->cleanup, REC_TYPE_ATTR, "%s=%s",
|
rec_fprintf(state->cleanup, REC_TYPE_ATTR, "%s=%s",
|
||||||
MAIL_ATTR_CLIENT_ADDR, FORWARD_ADDR(state));
|
MAIL_ATTR_CLIENT_ADDR, FORWARD_ADDR(state));
|
||||||
|
if (!IS_UNK_CLIENT_NAMADDR(FORWARD_NAMADDR(state)))
|
||||||
rec_fprintf(state->cleanup, REC_TYPE_ATTR, "%s=%s",
|
rec_fprintf(state->cleanup, REC_TYPE_ATTR, "%s=%s",
|
||||||
MAIL_ATTR_ORIGIN, FORWARD_NAMADDR(state));
|
MAIL_ATTR_ORIGIN, FORWARD_NAMADDR(state));
|
||||||
|
if (!IS_UNK_CLIENT_HELO(FORWARD_HELO(state)))
|
||||||
rec_fprintf(state->cleanup, REC_TYPE_ATTR, "%s=%s",
|
rec_fprintf(state->cleanup, REC_TYPE_ATTR, "%s=%s",
|
||||||
MAIL_ATTR_HELO_NAME,
|
MAIL_ATTR_HELO_NAME, FORWARD_HELO(state));
|
||||||
IS_UNK_HELO_NAME(FORWARD_HELO(state)) ?
|
if (!IS_UNK_CLIENT_PROTO(FORWARD_PROTO(state)))
|
||||||
HELO_NAME_UNKNOWN : FORWARD_HELO(state));
|
|
||||||
rec_fprintf(state->cleanup, REC_TYPE_ATTR, "%s=%s",
|
rec_fprintf(state->cleanup, REC_TYPE_ATTR, "%s=%s",
|
||||||
MAIL_ATTR_PROTO_NAME, FORWARD_PROTO(state));
|
MAIL_ATTR_PROTO_NAME, FORWARD_PROTO(state));
|
||||||
}
|
}
|
||||||
@ -1129,6 +1138,8 @@ static void mail_reset(SMTPD_STATE *state)
|
|||||||
myfree(state->proxy_mail);
|
myfree(state->proxy_mail);
|
||||||
state->proxy_mail = 0;
|
state->proxy_mail = 0;
|
||||||
}
|
}
|
||||||
|
if (state->xclient.used)
|
||||||
|
smtpd_xclient_reset(state);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* rcpt_cmd - process RCPT TO command */
|
/* rcpt_cmd - process RCPT TO command */
|
||||||
@ -1201,7 +1212,7 @@ static int rcpt_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv)
|
|||||||
return (-1);
|
return (-1);
|
||||||
}
|
}
|
||||||
} else if (state->cleanup == 0) {
|
} else if (state->cleanup == 0) {
|
||||||
mail_open_stream(state, argv);
|
mail_open_stream(state);
|
||||||
}
|
}
|
||||||
if (state->proxy && smtpd_proxy_cmd(state, SMTPD_PROX_WANT_OK,
|
if (state->proxy && smtpd_proxy_cmd(state, SMTPD_PROX_WANT_OK,
|
||||||
"%s", STR(state->buffer)) != 0) {
|
"%s", STR(state->buffer)) != 0) {
|
||||||
@ -1702,13 +1713,19 @@ static const struct attr_offset attr_offset = {
|
|||||||
#define STR_ATTR(state, func, attr) *((char **) PTR_ATTR(state, func, attr))
|
#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 INT_ATTR(state, func, attr) *((int *) PTR_ATTR(state, func, attr))
|
||||||
|
|
||||||
#define UPDATE_STR(state, func, attr, value) { \
|
#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)) \
|
if (STR_ATTR(state, func, attr)) \
|
||||||
myfree(STR_ATTR(state, func, attr)); \
|
myfree(STR_ATTR(state, func, attr)); \
|
||||||
STR_ATTR(state, func, attr) = mystrdup(value); \
|
STR_ATTR(state, func, attr) = mystrdup(value); \
|
||||||
}
|
}
|
||||||
|
|
||||||
#define UPDATE_INT(state, func, attr, value) { \
|
#define UPD_INT_ATTR(state, func, attr, value) { \
|
||||||
INT_ATTR(state, func, attr) = (value); \
|
INT_ATTR(state, func, attr) = (value); \
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1755,7 +1772,8 @@ static int xclient_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv)
|
|||||||
function = FUNC_OVERRIDE;
|
function = FUNC_OVERRIDE;
|
||||||
} else if (STREQ(arg_val, XCLIENT_FORWARD)) {
|
} else if (STREQ(arg_val, XCLIENT_FORWARD)) {
|
||||||
function = FUNC_FORWARD;
|
function = FUNC_FORWARD;
|
||||||
state->xclient.used = 1;
|
if (state->xclient.used == 0)
|
||||||
|
smtpd_xclient_preset(state);
|
||||||
} else { /* error */
|
} else { /* error */
|
||||||
state->error_mask |= MAIL_ERROR_PROTOCOL;
|
state->error_mask |= MAIL_ERROR_PROTOCOL;
|
||||||
smtpd_chat_reply(state, "501 Bad %s function: %s",
|
smtpd_chat_reply(state, "501 Bad %s function: %s",
|
||||||
@ -1764,7 +1782,9 @@ static int xclient_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Iterate over all NAME=VALUE attributes.
|
* 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++) {
|
for (arg_no = 2; arg_no < argc; arg_no++) {
|
||||||
arg_val = argv[arg_no].strval;
|
arg_val = argv[arg_no].strval;
|
||||||
@ -1810,11 +1830,11 @@ static int xclient_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv)
|
|||||||
cooked_value);
|
cooked_value);
|
||||||
return (-1);
|
return (-1);
|
||||||
}
|
}
|
||||||
UPDATE_STR(state, function, name, cooked_value);
|
UPD_STR_ATTR(state, function, name, cooked_value);
|
||||||
UPDATE_INT(state, function, peer_code, SMTPD_PEER_CODE_OK);
|
UPD_INT_ATTR(state, function, peer_code, SMTPD_PEER_CODE_OK);
|
||||||
} else {
|
} else {
|
||||||
UPDATE_STR(state, function, name, CLIENT_NAME_UNKNOWN);
|
UPD_STR_ATTR(state, function, name, CLIENT_NAME_UNKNOWN);
|
||||||
UPDATE_INT(state, function, peer_code, SMTPD_PEER_CODE_PERM);
|
UPD_INT_ATTR(state, function, peer_code, SMTPD_PEER_CODE_PERM);
|
||||||
}
|
}
|
||||||
update_namaddr = 1;
|
update_namaddr = 1;
|
||||||
}
|
}
|
||||||
@ -1822,7 +1842,7 @@ static int xclient_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv)
|
|||||||
/*
|
/*
|
||||||
* CLIENT_ADDR=client network address.
|
* CLIENT_ADDR=client network address.
|
||||||
*/
|
*/
|
||||||
else if (STREQ(arg_val, "CLIENT_ADDR")) {
|
else if (STREQ(arg_val, XCLIENT_ADDR)) {
|
||||||
if (*raw_value) {
|
if (*raw_value) {
|
||||||
if (!valid_hostaddr(cooked_value, DONT_GRIPE)) {
|
if (!valid_hostaddr(cooked_value, DONT_GRIPE)) {
|
||||||
state->error_mask |= MAIL_ERROR_PROTOCOL;
|
state->error_mask |= MAIL_ERROR_PROTOCOL;
|
||||||
@ -1830,9 +1850,9 @@ static int xclient_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv)
|
|||||||
cooked_value);
|
cooked_value);
|
||||||
return (-1);
|
return (-1);
|
||||||
}
|
}
|
||||||
UPDATE_STR(state, function, addr, cooked_value);
|
UPD_STR_ATTR(state, function, addr, cooked_value);
|
||||||
} else {
|
} else {
|
||||||
UPDATE_STR(state, function, name, CLIENT_ADDR_UNKNOWN);
|
UPD_STR_ATTR(state, function, addr, CLIENT_ADDR_UNKNOWN);
|
||||||
}
|
}
|
||||||
update_namaddr = 1;
|
update_namaddr = 1;
|
||||||
}
|
}
|
||||||
@ -1841,16 +1861,16 @@ static int xclient_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv)
|
|||||||
* CLIENT_CODE=status. Reset the client hostname if the hostname
|
* CLIENT_CODE=status. Reset the client hostname if the hostname
|
||||||
* lookup status is not OK.
|
* lookup status is not OK.
|
||||||
*/
|
*/
|
||||||
else if (STREQ(arg_val, "CLIENT_CODE")) {
|
else if (STREQ(arg_val, XCLIENT_CODE)) {
|
||||||
if (STREQ(cooked_value, "OK")) {
|
if (STREQ(cooked_value, "OK")) {
|
||||||
UPDATE_INT(state, function, peer_code, SMTPD_PEER_CODE_OK);
|
UPD_INT_ATTR(state, function, peer_code, SMTPD_PEER_CODE_OK);
|
||||||
} else if (STREQ(cooked_value, "TEMP")) {
|
} else if (STREQ(cooked_value, "TEMP")) {
|
||||||
UPDATE_INT(state, function, peer_code, SMTPD_PEER_CODE_TEMP);
|
UPD_INT_ATTR(state, function, peer_code, SMTPD_PEER_CODE_TEMP);
|
||||||
UPDATE_STR(state, function, name, CLIENT_NAME_UNKNOWN);
|
UPD_STR_ATTR(state, function, name, CLIENT_NAME_UNKNOWN);
|
||||||
update_namaddr = 1;
|
update_namaddr = 1;
|
||||||
} else if (STREQ(cooked_value, "PERM")) {
|
} else if (STREQ(cooked_value, "PERM")) {
|
||||||
UPDATE_INT(state, function, peer_code, SMTPD_PEER_CODE_PERM);
|
UPD_INT_ATTR(state, function, peer_code, SMTPD_PEER_CODE_PERM);
|
||||||
UPDATE_STR(state, function, name, CLIENT_NAME_UNKNOWN);
|
UPD_STR_ATTR(state, function, name, CLIENT_NAME_UNKNOWN);
|
||||||
update_namaddr = 1;
|
update_namaddr = 1;
|
||||||
} else {
|
} else {
|
||||||
state->error_mask |= MAIL_ERROR_PROTOCOL;
|
state->error_mask |= MAIL_ERROR_PROTOCOL;
|
||||||
@ -1861,12 +1881,10 @@ static int xclient_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* HELO_NAME=hostname. An empty value means the information was not
|
* CLIENT_HELO=hostname. Disallow characters that could mess up our
|
||||||
* provided by the client and that we must not fall back to the
|
* own Received: message headers but allow [].
|
||||||
* non-XCLIENT value. Disallow characters that could mess up our own
|
|
||||||
* Received: message headers but allow [].
|
|
||||||
*/
|
*/
|
||||||
else if (STREQ(arg_val, "HELO_NAME")) {
|
else if (STREQ(arg_val, XCLIENT_HELO)) {
|
||||||
if (*raw_value) {
|
if (*raw_value) {
|
||||||
if (strlen(cooked_value) > VALID_HOSTNAME_LEN) {
|
if (strlen(cooked_value) > VALID_HOSTNAME_LEN) {
|
||||||
state->error_mask |= MAIL_ERROR_PROTOCOL;
|
state->error_mask |= MAIL_ERROR_PROTOCOL;
|
||||||
@ -1875,17 +1893,17 @@ static int xclient_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv)
|
|||||||
return (-1);
|
return (-1);
|
||||||
}
|
}
|
||||||
neuter(cooked_value, "<>()\\\";:@", '?');
|
neuter(cooked_value, "<>()\\\";:@", '?');
|
||||||
UPDATE_STR(state, function, helo_name, cooked_value);
|
UPD_STR_ATTR(state, function, helo_name, cooked_value);
|
||||||
} else {
|
} else {
|
||||||
UPDATE_STR(state, function, helo_name, HELO_NAME_UNKNOWN);
|
RST_STR_ATTR(state, function, helo_name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* PROTOCOL=protocol name. Disallow characters that could mess up our
|
* CLIENT_PROTO=protocol name. Disallow characters that could mess up
|
||||||
* own Received: message headers.
|
* our own Received: message headers.
|
||||||
*/
|
*/
|
||||||
else if (STREQ(arg_val, "PROTOCOL")) {
|
else if (STREQ(arg_val, XCLIENT_PROTO)) {
|
||||||
if (*raw_value) {
|
if (*raw_value) {
|
||||||
if (*cooked_value == 0 || strlen(cooked_value) > 64) {
|
if (*cooked_value == 0 || strlen(cooked_value) > 64) {
|
||||||
state->error_mask |= MAIL_ERROR_PROTOCOL;
|
state->error_mask |= MAIL_ERROR_PROTOCOL;
|
||||||
@ -1894,9 +1912,9 @@ static int xclient_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv)
|
|||||||
return (-1);
|
return (-1);
|
||||||
}
|
}
|
||||||
neuter(cooked_value, "[]<>()\\\";:@", '?');
|
neuter(cooked_value, "[]<>()\\\";:@", '?');
|
||||||
UPDATE_STR(state, function, protocol, cooked_value);
|
UPD_STR_ATTR(state, function, protocol, cooked_value);
|
||||||
} else {
|
} else {
|
||||||
UPDATE_STR(state, function, protocol, PROTOCOL_UNKNOWN);
|
UPD_STR_ATTR(state, function, protocol, CLIENT_PROTO_UNKNOWN);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2039,11 +2057,13 @@ static void smtpd_proto(SMTPD_STATE *state, const char *service)
|
|||||||
case 0:
|
case 0:
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* XXX The client connection count/rate control uses the real client
|
* XXX The client connection count/rate control must be consistent in
|
||||||
* name/address to maintain consistency between connect and
|
* its use of client address information in connect and disconnect
|
||||||
* disconnect events.
|
* events. For now we exclude xclient authorized hosts from
|
||||||
|
* connection count/rate control.
|
||||||
*/
|
*/
|
||||||
if (SMTPD_STAND_ALONE(state) == 0
|
if (SMTPD_STAND_ALONE(state) == 0
|
||||||
|
&& !xclient_allowed
|
||||||
&& anvil_clnt
|
&& anvil_clnt
|
||||||
&& !namadr_list_match(hogger_list, state->name, state->addr)
|
&& !namadr_list_match(hogger_list, state->name, state->addr)
|
||||||
&& anvil_clnt_connect(anvil_clnt, service, state->addr,
|
&& anvil_clnt_connect(anvil_clnt, service, state->addr,
|
||||||
@ -2129,11 +2149,13 @@ static void smtpd_proto(SMTPD_STATE *state, const char *service)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* XXX The client connection count/rate control uses the real client
|
* XXX The client connection count/rate control must be consistent in its
|
||||||
* name/address to maintain consistency between connect and disconnect
|
* use of client address information in connect and disconnect events.
|
||||||
* events.
|
* For now we exclude xclient authorized hosts from connection count/rate
|
||||||
|
* control.
|
||||||
*/
|
*/
|
||||||
if (SMTPD_STAND_ALONE(state) == 0
|
if (SMTPD_STAND_ALONE(state) == 0
|
||||||
|
&& !xclient_allowed
|
||||||
&& anvil_clnt
|
&& anvil_clnt
|
||||||
&& !namadr_list_match(hogger_list, state->name, state->addr))
|
&& !namadr_list_match(hogger_list, state->name, state->addr))
|
||||||
anvil_clnt_disconnect(anvil_clnt, service, state->addr);
|
anvil_clnt_disconnect(anvil_clnt, service, state->addr);
|
||||||
|
@ -142,9 +142,7 @@ extern void smtpd_peer_reset(SMTPD_STATE *state);
|
|||||||
#define SMTPD_PEER_CODE_PERM 5
|
#define SMTPD_PEER_CODE_PERM 5
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* XCLIENT support to override logging and/or access control attributes. It
|
* Choose between normal or forwarded attributes.
|
||||||
* makes no sense to maintain separate attribute sets for XCLIENT LOG or
|
|
||||||
* XCLIENT ACL, so we set a flag to distinguish purpose.
|
|
||||||
*/
|
*/
|
||||||
#define SMTPD_FEATURE_XCLIENT (1<<0) /* XCLIENT supported */
|
#define SMTPD_FEATURE_XCLIENT (1<<0) /* XCLIENT supported */
|
||||||
|
|
||||||
@ -159,6 +157,7 @@ extern void smtpd_peer_reset(SMTPD_STATE *state);
|
|||||||
#define FORWARD_HELO(s) MAYBE_FORWARD((s), helo_name)
|
#define FORWARD_HELO(s) MAYBE_FORWARD((s), helo_name)
|
||||||
|
|
||||||
extern void smtpd_xclient_init(SMTPD_STATE *state);
|
extern void smtpd_xclient_init(SMTPD_STATE *state);
|
||||||
|
extern void smtpd_xclient_preset(SMTPD_STATE *state);
|
||||||
extern void smtpd_xclient_reset(SMTPD_STATE *state);
|
extern void smtpd_xclient_reset(SMTPD_STATE *state);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -970,7 +970,7 @@ static int reject_unknown_client(SMTPD_STATE *state)
|
|||||||
if (msg_verbose)
|
if (msg_verbose)
|
||||||
msg_info("%s: %s %s", myname, state->name, state->addr);
|
msg_info("%s: %s %s", myname, state->name, state->addr);
|
||||||
|
|
||||||
if (IS_UNK_CLNT_NAME(state->name))
|
if (strcasecmp(state->name, "unknown") == 0)
|
||||||
return (smtpd_check_reject(state, MAIL_ERROR_POLICY,
|
return (smtpd_check_reject(state, MAIL_ERROR_POLICY,
|
||||||
"%d Client host rejected: cannot find your hostname, [%s]",
|
"%d Client host rejected: cannot find your hostname, [%s]",
|
||||||
state->peer_code == SMTPD_PEER_CODE_PERM ?
|
state->peer_code == SMTPD_PEER_CODE_PERM ?
|
||||||
@ -3093,7 +3093,7 @@ static int generic_checks(SMTPD_STATE *state, ARGV *restrictions,
|
|||||||
name);
|
name);
|
||||||
else {
|
else {
|
||||||
cpp += 1;
|
cpp += 1;
|
||||||
if (!IS_UNK_CLNT_NAME(state->name))
|
if (strcasecmp(state->name, "unknown") != 0)
|
||||||
status = reject_rbl_domain(state, *cpp, state->name,
|
status = reject_rbl_domain(state, *cpp, state->name,
|
||||||
SMTPD_NAME_CLIENT);
|
SMTPD_NAME_CLIENT);
|
||||||
}
|
}
|
||||||
|
@ -245,26 +245,29 @@ int smtpd_proxy_open(SMTPD_STATE *state, const char *service,
|
|||||||
state->proxy_features |= SMTPD_FEATURE_XCLIENT;
|
state->proxy_features |= SMTPD_FEATURE_XCLIENT;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Send all XCLIENT attributes. Transform internal forms to external
|
* 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.
|
* forms and encode the result as xtext.
|
||||||
*/
|
*/
|
||||||
if (state->proxy_features & SMTPD_FEATURE_XCLIENT) {
|
if ((state->proxy_features & SMTPD_FEATURE_XCLIENT)
|
||||||
|
&& (!IS_UNK_CLIENT_NAME(FORWARD_NAME(state))
|
||||||
|
|| !IS_UNK_CLIENT_ADDR(FORWARD_ADDR(state)))) {
|
||||||
buf = vstring_alloc(100);
|
buf = vstring_alloc(100);
|
||||||
vstring_strcpy(buf, XCLIENT_CMD " " XCLIENT_FORWARD
|
vstring_strcpy(buf, XCLIENT_CMD " " XCLIENT_FORWARD
|
||||||
" " XCLIENT_NAME "=");
|
" " XCLIENT_NAME "=");
|
||||||
if (!IS_UNK_CLNT_NAME(FORWARD_NAME(state)))
|
if (!IS_UNK_CLIENT_NAME(FORWARD_NAME(state)))
|
||||||
xtext_quote_append(buf, FORWARD_NAME(state), "");
|
xtext_quote_append(buf, FORWARD_NAME(state), "");
|
||||||
vstring_strcat(buf, " " XCLIENT_ADDR "=");
|
vstring_strcat(buf, " " XCLIENT_ADDR "=");
|
||||||
if (!IS_UNK_CLNT_ADDR(FORWARD_ADDR(state)))
|
if (!IS_UNK_CLIENT_ADDR(FORWARD_ADDR(state)))
|
||||||
xtext_quote_append(buf, FORWARD_ADDR(state), "");
|
xtext_quote_append(buf, FORWARD_ADDR(state), "");
|
||||||
bad = smtpd_proxy_cmd(state, SMTPD_PROX_WANT_ANY, "%s", STR(buf));
|
bad = smtpd_proxy_cmd(state, SMTPD_PROX_WANT_ANY, "%s", STR(buf));
|
||||||
if (bad == 0) {
|
if (bad == 0) {
|
||||||
vstring_strcpy(buf, XCLIENT_CMD " " XCLIENT_FORWARD
|
vstring_strcpy(buf, XCLIENT_CMD " " XCLIENT_FORWARD
|
||||||
" " XCLIENT_HELO "=");
|
" " XCLIENT_HELO "=");
|
||||||
if (!IS_UNK_HELO_NAME(FORWARD_HELO(state)))
|
if (!IS_UNK_CLIENT_HELO(FORWARD_HELO(state)))
|
||||||
xtext_quote_append(buf, FORWARD_HELO(state), "");
|
xtext_quote_append(buf, FORWARD_HELO(state), "");
|
||||||
vstring_strcat(buf, " " XCLIENT_PROTO "=");
|
vstring_strcat(buf, " " XCLIENT_PROTO "=");
|
||||||
if (!IS_UNK_PROTOCOL(FORWARD_PROTO(state)))
|
if (!IS_UNK_CLIENT_PROTO(FORWARD_PROTO(state)))
|
||||||
xtext_quote_append(buf, FORWARD_PROTO(state), "");
|
xtext_quote_append(buf, FORWARD_PROTO(state), "");
|
||||||
bad = smtpd_proxy_cmd(state, SMTPD_PROX_WANT_ANY, "%s", STR(buf));
|
bad = smtpd_proxy_cmd(state, SMTPD_PROX_WANT_ANY, "%s", STR(buf));
|
||||||
}
|
}
|
||||||
|
@ -88,7 +88,7 @@ void smtpd_state_init(SMTPD_STATE *state, VSTREAM *stream)
|
|||||||
state->verp_delims = 0;
|
state->verp_delims = 0;
|
||||||
state->recipient = 0;
|
state->recipient = 0;
|
||||||
state->etrn_name = 0;
|
state->etrn_name = 0;
|
||||||
state->protocol = MAIL_PROTO_SMTP;
|
state->protocol = mystrdup(MAIL_PROTO_SMTP);
|
||||||
state->where = SMTPD_AFTER_CONNECT;
|
state->where = SMTPD_AFTER_CONNECT;
|
||||||
state->recursion = 0;
|
state->recursion = 0;
|
||||||
state->msg_size = 0;
|
state->msg_size = 0;
|
||||||
@ -140,6 +140,8 @@ void smtpd_state_reset(SMTPD_STATE *state)
|
|||||||
*/
|
*/
|
||||||
if (state->buffer)
|
if (state->buffer)
|
||||||
vstring_free(state->buffer);
|
vstring_free(state->buffer);
|
||||||
|
if (state->protocol)
|
||||||
|
myfree(state->protocol);
|
||||||
smtpd_peer_reset(state);
|
smtpd_peer_reset(state);
|
||||||
smtpd_xclient_reset(state);
|
smtpd_xclient_reset(state);
|
||||||
if (state->defer_if_permit.reason)
|
if (state->defer_if_permit.reason)
|
||||||
|
@ -12,13 +12,14 @@
|
|||||||
/* void smtpd_xclient_reset(state)
|
/* void smtpd_xclient_reset(state)
|
||||||
/* SMTPD_STATE *state;
|
/* SMTPD_STATE *state;
|
||||||
/* DESCRIPTION
|
/* DESCRIPTION
|
||||||
/* smtpd_xclient_init() initializes state variables that are
|
/* smtpd_xclient_init() zeroes the attributes for storage of XCLIENT
|
||||||
/* used for storage of XCLIENT command parameters.
|
/* FORWARD command parameters.
|
||||||
/* These variables override specific members of the global state
|
|
||||||
/* structure for access control or logging purposes.
|
|
||||||
/*
|
/*
|
||||||
/* smtpd_xclient_reset() releases memory allocated after the return
|
/* smtpd_xclient_preset() takes the result from smtpd_xclient_init()
|
||||||
/* 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
|
/* LICENSE
|
||||||
/* .ad
|
/* .ad
|
||||||
/* .fi
|
/* .fi
|
||||||
@ -52,21 +53,42 @@
|
|||||||
void smtpd_xclient_init(SMTPD_STATE *state)
|
void smtpd_xclient_init(SMTPD_STATE *state)
|
||||||
{
|
{
|
||||||
state->xclient.used = 0;
|
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.name = mystrdup(CLIENT_NAME_UNKNOWN);
|
||||||
state->xclient.addr = mystrdup(CLIENT_ADDR_UNKNOWN);
|
state->xclient.addr = mystrdup(CLIENT_ADDR_UNKNOWN);
|
||||||
state->xclient.namaddr = mystrdup(CLIENT_NAMADDR_UNKNOWN);
|
state->xclient.namaddr = mystrdup(CLIENT_NAMADDR_UNKNOWN);
|
||||||
state->xclient.peer_code = 0;
|
state->xclient.protocol = mystrdup(CLIENT_PROTO_UNKNOWN);
|
||||||
state->xclient.protocol = mystrdup(PROTOCOL_UNKNOWN);
|
|
||||||
state->xclient.helo_name = mystrdup(HELO_NAME_UNKNOWN);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* smtpd_xclient_reset - reset XCLIENT attributes */
|
/* smtpd_xclient_reset - reset XCLIENT attributes */
|
||||||
|
|
||||||
void smtpd_xclient_reset(SMTPD_STATE *state)
|
void smtpd_xclient_reset(SMTPD_STATE *state)
|
||||||
{
|
{
|
||||||
myfree(state->xclient.name);
|
#define FREE_AND_WIPE(s) { if (s) myfree(s); s = 0; }
|
||||||
myfree(state->xclient.addr);
|
|
||||||
myfree(state->xclient.namaddr);
|
state->xclient.used = 0;
|
||||||
myfree(state->xclient.protocol);
|
FREE_AND_WIPE(state->xclient.name);
|
||||||
myfree(state->xclient.helo_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);
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user