2
0
mirror of https://github.com/vdukhovni/postfix synced 2025-08-29 13:18:12 +00:00

postfix-2.0.16-20031201

This commit is contained in:
Wietse Venema 2003-12-01 00:00:00 -05:00 committed by Viktor Dukhovni
parent edb9945f66
commit e0c65a2f44
16 changed files with 278 additions and 197 deletions

View File

@ -8778,13 +8778,13 @@ Apologies for any names omitted.
logs more specific information. File: master/master_ent.c.
Reported by several people.
20031125-8
20031125-20031201
Feature: XCLIENT support to override the SMTP server's
client information for logging and/or access control. This
replaces the short-lived XADDR and XLOGINFO extensions.
Based on code by Victor Duchovni, with major simplifications.
Files: smtpd/{smtpd,smtpd_check,smtpd_proxy,smtpd_xclient}.c
Remotely based on code by Victor Duchovni. Files:
smtpd/{smtpd,smtpd_check,smtpd_proxy,smtpd_xclient}.c
smtp/smtp_smtp_proto.c, *qmgr/qmgr_message.c,
global/deliver_request.c.

View File

@ -3,49 +3,42 @@ Purpose of the XCLIENT extension to SMTP
The XCLIENT command targets problems in the following areas:
1 - Access control tests. SMTP server access rules are difficult
to verify when decisions can be triggered only by remote clients.
1 - Access control tests. SMTP server access rules can be difficult
to verify when decisions can be triggered by remote clients only.
In order to facilitate access rule testing, an SMTP client test
program needs the ability to override the SMTP server's idea of
the SMTP client hostname, network address, and other information.
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
style content filter applications, remote client information is
lost when MTA1 gives the mail to the content filter. To simplify
the interpretation of MTA2 logging, it would help if MTA1 could
forward client information through the content filter to MTA2.
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
style content filter applications, the filter can be simplified if
it can delegate decisions concerning mail relay and other access
control to the MTA. As in the first example, this requires that
the filter can override the MTA's idea of the SMTP client hostname,
network address, and other information.
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.
network address, and other information, for the entire duration of
an SMTP session.
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
that the MTA normally uses for access control, message headers,
logging and so on, while the XCLIENT FORWARD command maintains an
additional set of attributes that is meant to be used for logging
purposes. In the absence of forwarded attributes the MTA must use
the normal remote client attribute values.
logging and so on, for the duration of an entire SMTP session.
The XCLIENT FORWARD command maintains an additional set of attributes
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
quoted strings specify terminals, lowercase strings specify meta
@ -59,7 +52,7 @@ case, they are in fact case insensitive.
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 )
@ -88,10 +81,11 @@ Specific usage scenarios
This section discusses the semantics of XCLIENT requests. Specific
syntax details are given in the next section.
The XCLIENT OVERRIDE request modifies the attributes that the MTA
normally uses for access control, message headers, logging, and
for other purposes. Attributes that are not specified in XCLIENT
OVERRIDE requests are not modified.
The XCLIENT OVERRIDE request modifies remote client attributes that
the MTA normally uses for access control, message headers, logging,
and for other purposes, for the duraction of the entire SMTP session.
Attributes that are not specified in XCLIENT OVERRIDE requests are
not modified.
The following example overrides only the client hostname and network
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_ADDR=168.100.189.2
The XCLIENT FORWARD request specifies surrogate client attributes for
logging purposes. In the absence of any XCLIENT FORWARD attributes, the
MTA must use the normal client attributes.
The XCLIENT FORWARD request specifies remote client attributes
concerning only one message delivery attempt. The attributes are
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
specified, the unspecified attributes must either not be logged at
all, or they must be logged as if they are unknown. This avoids
the logging of attributes from mixed origins.
specified, the unspecified attributes must be treated as if they
are unknown. The implementation must not replace missing XCLIENT
FORWARD attributes by normal attributes.
The following example updates all forwarded client attributes that
are defined in this document, leaving none at their default unknown
value:
XCLIENT FORWARD 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
accumulate.
@ -126,34 +122,36 @@ Attribute value details
=======================
Attribute values are encoded as RFC 1891 xtext strings. To explicitly
specify that an attribute value is unknown, the value must be empty;
the client must not send its own internal representation of unknown
information.
specify that an attribute value is unavailable, the value must be
empty; the client must not send its own internal representation of
unavailable information.
CLIENT_CODE specifies CLIENT_NAME hostname lookup status information.
Values are OK (success), TEMP (temporary lookup failure) or PERM
(permanent lookup failure). When CLIENT_CODE is set to any value
other than OK, the CLIENT_NAME attribute is automatically set to
the unknown value.
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.
CLIENT_NAME should specify a syntactically valid domain name and
not a numerical address. When a null client name is specified
(i.e. the client name is unknown), the CLIENT_CODE attribute is
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 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.
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
printable is defined by the ANSI C isascii() and isprint() predicates.
The CLIENT_PROTO attribute should be a string of up to 64 printable
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
can be up to 255 characters long. The client must not send XCLIENT OVERRIDE
or XCLIENT FORWARD commands that exceed the 512 character limit of SMTP
commands.
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 4: attribute values may end up in Received: or other message
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
messages within the same SMTP session. Thus, one persistent SMTP
session with a content filter can carry messages from unrelated
clients. Applications should ensure that XCLIENT information from
one remote client is properly updated before commencing delivery
of mail from a different remote client.
clients. The XCLIENT FORWARD attributes are reset after the MAIL
FROM command completes, so there is no risk of information leakage.

View File

@ -1,4 +1,4 @@
<html> <head> </head> <body> <pre>
<html> <body> <pre>
QMQPD(8) QMQPD(8)
<b>NAME</b>
@ -44,72 +44,72 @@ QMQPD(8) QMQPD(8)
command after a configuration change.
<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
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.
<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
host matches a pattern, increase the verbose log-
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.
<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
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
receive a client request.
<b>soft</b><i>_</i><b>bounce</b>
<b>soft_bounce</b>
Change hard (D) reject responses into soft (Z)
reject responses. This can be useful for testing
purposes.
<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
mail and that either bounces mail or re-injects the
result back into Postfix. This parameter uses the
same syntax as the right-hand side of a Postfix
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 options are passed on to the downstream cleanup
server.
<b>no</b><i>_</i><b>address</b><i>_</i><b>mappings</b>
<b>no_address_mappings</b>
Disable canonical address mapping, virtual
alias map expansion, address masquerading,
and automatic BCC recipients. Specify this
if address mapping etc. are to be done <b>after</b>
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
header/body_checks are to be done <b>after</b> an
external content filter.
<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
handling of partial input lines, and the length of
sender and recipient addresses that are received
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-
ing on-disk storage for sender and recipient
address information.
<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
of a problem. This slows down run-away errors.

View File

@ -46,6 +46,15 @@ typedef struct DELIVER_REQUEST {
char *client_helo; /* helo parameter */
} 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_SUCCESS (1<<0) /* delete successful recipients */
#define DEL_REQ_FLAG_BOUNCE (1<<1) /* unimplemented */

View File

@ -159,27 +159,33 @@ extern char *mail_pathname(const char *, const char *);
#define XCLIENT_FORWARD "FORWARD" /* forward function */
#define XCLIENT_NAME "CLIENT_NAME" /* client name */
#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_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_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_ATTR_UNKNOWN "unknown"
/*
* Internal forms: recognizing unknown XCLIENT information.
*/
#define IS_UNK_CLNT_NAME(v) (!(v) || !strcmp((v), CLIENT_NAME_UNKNOWN))
#define IS_UNK_CLNT_ADDR(v) (!(v) || !strcmp((v), CLIENT_ADDR_UNKNOWN))
#define IS_UNK_CLNT_NAMADDR(v) (!(v) || !strcmp((v), CLIENT_NAMADDR_UNKNOWN))
#define IS_UNK_HELO_NAME(v) (!(v) || !*(v))
#define IS_UNK_PROTOCOL(v) (!(v) || !strcmp((v), PROTOCOL_UNKNOWN))
#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_UNK_CLIENT_ATTR(v) (!(v) || !strcmp((v), CLIENT_ATTR_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
/* .ad

View File

@ -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 "20031130"
#define MAIL_RELEASE_DATE "20031201"
#define VAR_MAIL_VERSION "mail_version"
#define DEF_MAIL_VERSION "2.0.16-" MAIL_RELEASE_DATE

View File

@ -612,13 +612,13 @@ static int qmgr_message_read(QMGR_MESSAGE *message)
if (message->encoding == 0)
message->encoding = mystrdup(MAIL_ATTR_ENC_NONE);
if (message->client_name == 0)
message->client_name = mystrdup(CLIENT_NAME_UNKNOWN);
message->client_name = mystrdup("");
if (message->client_addr == 0)
message->client_addr = mystrdup(CLIENT_ADDR_UNKNOWN);
message->client_addr = mystrdup("");
if (message->client_proto == 0)
message->client_proto = mystrdup(PROTOCOL_UNKNOWN);
message->client_proto = mystrdup("");
if (message->client_helo == 0)
message->client_helo = mystrdup(HELO_NAME_UNKNOWN);
message->client_helo = mystrdup("");
/*
* Clean up.
@ -1130,6 +1130,14 @@ void qmgr_message_free(QMGR_MESSAGE *message)
myfree(message->inspect_xport);
if (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_message_count--;
myfree((char *) message);

View File

@ -577,13 +577,13 @@ static int qmgr_message_read(QMGR_MESSAGE *message)
if (message->encoding == 0)
message->encoding = mystrdup(MAIL_ATTR_ENC_NONE);
if (message->client_name == 0)
message->client_name = mystrdup(CLIENT_NAME_UNKNOWN);
message->client_name = mystrdup("");
if (message->client_addr == 0)
message->client_addr = mystrdup(CLIENT_ADDR_UNKNOWN);
message->client_addr = mystrdup("");
if (message->client_proto == 0)
message->client_proto = mystrdup(PROTOCOL_UNKNOWN);
message->client_proto = mystrdup("");
if (message->client_helo == 0)
message->client_helo = mystrdup(HELO_NAME_UNKNOWN);
message->client_helo = mystrdup("");
/*
* Clean up.
@ -1024,6 +1024,14 @@ void qmgr_message_free(QMGR_MESSAGE *message)
myfree(message->inspect_xport);
if (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_message_count--;
myfree((char *) message);

View File

@ -285,10 +285,12 @@ static void qmqpd_copy_sender(QMQPD_STATE *state)
static void qmqpd_write_attributes(QMQPD_STATE *state)
{
rec_fprintf(state->cleanup, REC_TYPE_ATTR, "%s=%s",
MAIL_ATTR_CLIENT_NAME, state->name);
rec_fprintf(state->cleanup, REC_TYPE_ATTR, "%s=%s",
MAIL_ATTR_CLIENT_ADDR, state->addr);
if (!IS_UNK_CLIENT_NAME(state->name))
rec_fprintf(state->cleanup, REC_TYPE_ATTR, "%s=%s",
MAIL_ATTR_CLIENT_NAME, state->name);
if (!IS_UNK_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);
rec_fprintf(state->cleanup, REC_TYPE_ATTR, "%s=%s",

View File

@ -484,11 +484,14 @@ int smtp_xfer(SMTP_STATE *state)
* commands rejected, DATA rejected) it forces the sender to abort the
* SMTP dialog with RSET and QUIT.
*
* Update the server's remote client information to avoid leakage of past
* client attributes into an unrelated mail delivery.
* Use the XCLIENT 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_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;
else
recv_state = send_state = SMTP_STATE_MAIL;
@ -516,10 +519,10 @@ int smtp_xfer(SMTP_STATE *state)
case SMTP_STATE_XCLIENT_ADDR:
vstring_strcpy(next_command,
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, "");
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, "");
next_state = SMTP_STATE_XCLIENT_HELO;
break;
@ -527,10 +530,10 @@ int smtp_xfer(SMTP_STATE *state)
case SMTP_STATE_XCLIENT_HELO:
vstring_strcpy(next_command,
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, "");
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, "");
next_state = SMTP_STATE_MAIL;
break;

View File

@ -667,9 +667,12 @@ static int helo_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv)
rcpt_reset(state);
state->helo_name = mystrdup(printable(argv[1].strval, '?'));
neuter(state->helo_name, "<>()\\\";:@", '?');
/* Changing the protocol name breaks the unauthorized pipelining check. */
if (strcmp(state->protocol, MAIL_PROTO_ESMTP) != 0)
state->protocol = MAIL_PROTO_SMTP;
/* Downgrading the protocol name breaks the unauthorized pipelining test. */
if (strcasecmp(state->protocol, MAIL_PROTO_ESMTP) != 0
&& strcasecmp(state->protocol, MAIL_PROTO_SMTP) != 0) {
myfree(state->protocol);
state->protocol = mystrdup(MAIL_PROTO_SMTP);
}
smtpd_chat_reply(state, "250 %s", var_myhostname);
return (0);
}
@ -705,7 +708,10 @@ static int ehlo_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv)
rcpt_reset(state);
state->helo_name = mystrdup(printable(argv[1].strval, '?'));
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-PIPELINING");
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 */
static void mail_open_stream(SMTPD_STATE *state, SMTPD_TOKEN *argv)
static void mail_open_stream(SMTPD_STATE *state)
{
char *postdrop_command;
int cleanup_flags;
@ -815,7 +821,7 @@ static void mail_open_stream(SMTPD_STATE *state, SMTPD_TOKEN *argv)
if (*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)
rec_fprintf(state->cleanup, REC_TYPE_ATTR, "%s=%s",
MAIL_ATTR_ENCODING, state->encoding);
@ -824,18 +830,21 @@ static void mail_open_stream(SMTPD_STATE *state, SMTPD_TOKEN *argv)
* Store the client attributes for logging purposes.
*/
if (SMTPD_STAND_ALONE(state) == 0) {
rec_fprintf(state->cleanup, REC_TYPE_ATTR, "%s=%s",
MAIL_ATTR_CLIENT_NAME, FORWARD_NAME(state));
rec_fprintf(state->cleanup, REC_TYPE_ATTR, "%s=%s",
MAIL_ATTR_CLIENT_ADDR, FORWARD_ADDR(state));
rec_fprintf(state->cleanup, REC_TYPE_ATTR, "%s=%s",
MAIL_ATTR_ORIGIN, FORWARD_NAMADDR(state));
rec_fprintf(state->cleanup, REC_TYPE_ATTR, "%s=%s",
MAIL_ATTR_HELO_NAME,
IS_UNK_HELO_NAME(FORWARD_HELO(state)) ?
HELO_NAME_UNKNOWN : FORWARD_HELO(state));
rec_fprintf(state->cleanup, REC_TYPE_ATTR, "%s=%s",
MAIL_ATTR_PROTO_NAME, FORWARD_PROTO(state));
if (!IS_UNK_CLIENT_NAME(FORWARD_NAME(state)))
rec_fprintf(state->cleanup, REC_TYPE_ATTR, "%s=%s",
MAIL_ATTR_CLIENT_NAME, FORWARD_NAME(state));
if (!IS_UNK_CLIENT_ADDR(FORWARD_ADDR(state)))
rec_fprintf(state->cleanup, REC_TYPE_ATTR, "%s=%s",
MAIL_ATTR_CLIENT_ADDR, FORWARD_ADDR(state));
if (!IS_UNK_CLIENT_NAMADDR(FORWARD_NAMADDR(state)))
rec_fprintf(state->cleanup, REC_TYPE_ATTR, "%s=%s",
MAIL_ATTR_ORIGIN, FORWARD_NAMADDR(state));
if (!IS_UNK_CLIENT_HELO(FORWARD_HELO(state)))
rec_fprintf(state->cleanup, REC_TYPE_ATTR, "%s=%s",
MAIL_ATTR_HELO_NAME, FORWARD_HELO(state));
if (!IS_UNK_CLIENT_PROTO(FORWARD_PROTO(state)))
rec_fprintf(state->cleanup, REC_TYPE_ATTR, "%s=%s",
MAIL_ATTR_PROTO_NAME, FORWARD_PROTO(state));
}
if (state->verp_delims)
rec_fputs(state->cleanup, REC_TYPE_VERP, state->verp_delims);
@ -1129,6 +1138,8 @@ static void mail_reset(SMTPD_STATE *state)
myfree(state->proxy_mail);
state->proxy_mail = 0;
}
if (state->xclient.used)
smtpd_xclient_reset(state);
}
/* rcpt_cmd - process RCPT TO command */
@ -1201,7 +1212,7 @@ static int rcpt_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv)
return (-1);
}
} 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,
"%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 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)) \
myfree(STR_ATTR(state, func, attr)); \
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); \
}
@ -1755,7 +1772,8 @@ static int xclient_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv)
function = FUNC_OVERRIDE;
} else if (STREQ(arg_val, XCLIENT_FORWARD)) {
function = FUNC_FORWARD;
state->xclient.used = 1;
if (state->xclient.used == 0)
smtpd_xclient_preset(state);
} else { /* error */
state->error_mask |= MAIL_ERROR_PROTOCOL;
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++) {
arg_val = argv[arg_no].strval;
@ -1810,11 +1830,11 @@ static int xclient_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv)
cooked_value);
return (-1);
}
UPDATE_STR(state, function, name, cooked_value);
UPDATE_INT(state, function, peer_code, SMTPD_PEER_CODE_OK);
UPD_STR_ATTR(state, function, name, cooked_value);
UPD_INT_ATTR(state, function, peer_code, SMTPD_PEER_CODE_OK);
} else {
UPDATE_STR(state, function, name, CLIENT_NAME_UNKNOWN);
UPDATE_INT(state, function, peer_code, SMTPD_PEER_CODE_PERM);
UPD_STR_ATTR(state, function, name, CLIENT_NAME_UNKNOWN);
UPD_INT_ATTR(state, function, peer_code, SMTPD_PEER_CODE_PERM);
}
update_namaddr = 1;
}
@ -1822,7 +1842,7 @@ static int xclient_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv)
/*
* CLIENT_ADDR=client network address.
*/
else if (STREQ(arg_val, "CLIENT_ADDR")) {
else if (STREQ(arg_val, XCLIENT_ADDR)) {
if (*raw_value) {
if (!valid_hostaddr(cooked_value, DONT_GRIPE)) {
state->error_mask |= MAIL_ERROR_PROTOCOL;
@ -1830,9 +1850,9 @@ static int xclient_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv)
cooked_value);
return (-1);
}
UPDATE_STR(state, function, addr, cooked_value);
UPD_STR_ATTR(state, function, addr, cooked_value);
} else {
UPDATE_STR(state, function, name, CLIENT_ADDR_UNKNOWN);
UPD_STR_ATTR(state, function, addr, CLIENT_ADDR_UNKNOWN);
}
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
* lookup status is not OK.
*/
else if (STREQ(arg_val, "CLIENT_CODE")) {
else if (STREQ(arg_val, XCLIENT_CODE)) {
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")) {
UPDATE_INT(state, function, peer_code, SMTPD_PEER_CODE_TEMP);
UPDATE_STR(state, function, name, CLIENT_NAME_UNKNOWN);
UPD_INT_ATTR(state, function, peer_code, SMTPD_PEER_CODE_TEMP);
UPD_STR_ATTR(state, function, name, CLIENT_NAME_UNKNOWN);
update_namaddr = 1;
} else if (STREQ(cooked_value, "PERM")) {
UPDATE_INT(state, function, peer_code, SMTPD_PEER_CODE_PERM);
UPDATE_STR(state, function, name, CLIENT_NAME_UNKNOWN);
UPD_INT_ATTR(state, function, peer_code, SMTPD_PEER_CODE_PERM);
UPD_STR_ATTR(state, function, name, CLIENT_NAME_UNKNOWN);
update_namaddr = 1;
} else {
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
* provided by the client and that we must not fall back to the
* non-XCLIENT value. Disallow characters that could mess up our own
* Received: message headers but allow [].
* CLIENT_HELO=hostname. 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 (strlen(cooked_value) > VALID_HOSTNAME_LEN) {
state->error_mask |= MAIL_ERROR_PROTOCOL;
@ -1875,17 +1893,17 @@ static int xclient_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv)
return (-1);
}
neuter(cooked_value, "<>()\\\";:@", '?');
UPDATE_STR(state, function, helo_name, cooked_value);
UPD_STR_ATTR(state, function, helo_name, cooked_value);
} 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
* own Received: message headers.
* CLIENT_PROTO=protocol name. Disallow characters that could mess up
* our own Received: message headers.
*/
else if (STREQ(arg_val, "PROTOCOL")) {
else if (STREQ(arg_val, XCLIENT_PROTO)) {
if (*raw_value) {
if (*cooked_value == 0 || strlen(cooked_value) > 64) {
state->error_mask |= MAIL_ERROR_PROTOCOL;
@ -1894,9 +1912,9 @@ static int xclient_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv)
return (-1);
}
neuter(cooked_value, "[]<>()\\\";:@", '?');
UPDATE_STR(state, function, protocol, cooked_value);
UPD_STR_ATTR(state, function, protocol, cooked_value);
} 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:
/*
* XXX The client connection count/rate control uses the real client
* name/address to maintain consistency between connect and
* disconnect events.
* XXX The client connection count/rate control must be consistent in
* its use of client address information in connect and disconnect
* events. For now we exclude xclient authorized hosts from
* connection count/rate control.
*/
if (SMTPD_STAND_ALONE(state) == 0
&& !xclient_allowed
&& anvil_clnt
&& !namadr_list_match(hogger_list, state->name, 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
* name/address to maintain consistency between connect and disconnect
* events.
* XXX The client connection count/rate control must be consistent in its
* use of client address information in connect and disconnect events.
* For now we exclude xclient authorized hosts from connection count/rate
* control.
*/
if (SMTPD_STAND_ALONE(state) == 0
&& !xclient_allowed
&& anvil_clnt
&& !namadr_list_match(hogger_list, state->name, state->addr))
anvil_clnt_disconnect(anvil_clnt, service, state->addr);

View File

@ -142,9 +142,7 @@ extern void smtpd_peer_reset(SMTPD_STATE *state);
#define SMTPD_PEER_CODE_PERM 5
/*
* XCLIENT support to override logging and/or access control attributes. It
* makes no sense to maintain separate attribute sets for XCLIENT LOG or
* XCLIENT ACL, so we set a flag to distinguish purpose.
* Choose between normal or forwarded attributes.
*/
#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)
extern void smtpd_xclient_init(SMTPD_STATE *state);
extern void smtpd_xclient_preset(SMTPD_STATE *state);
extern void smtpd_xclient_reset(SMTPD_STATE *state);
/*

View File

@ -970,7 +970,7 @@ static int reject_unknown_client(SMTPD_STATE *state)
if (msg_verbose)
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,
"%d Client host rejected: cannot find your hostname, [%s]",
state->peer_code == SMTPD_PEER_CODE_PERM ?
@ -2524,7 +2524,7 @@ static const char *smtpd_expand_lookup(const char *name, int unused_mode,
} else if (STREQ(name, MAIL_ATTR_CLIENT_NAME)) {
return (state->name);
} else if (STREQ(name, MAIL_ATTR_HELO_NAME)) {
return (state->helo_name ? state->helo_name : "");
return (state->helo_name ? state->helo_name : "");
} else if (STREQN(name, MAIL_ATTR_SENDER, CONST_LEN(MAIL_ATTR_SENDER))) {
return (smtpd_expand_addr(state->expand_buf, state->sender,
name, CONST_LEN(MAIL_ATTR_SENDER)));
@ -2910,7 +2910,7 @@ static int check_policy_service(SMTPD_STATE *state, const char *server,
ATTR_TYPE_STR, MAIL_ATTR_CLIENT_ADDR, state->addr,
ATTR_TYPE_STR, MAIL_ATTR_CLIENT_NAME, state->name,
ATTR_TYPE_STR, MAIL_ATTR_HELO_NAME,
state->helo_name ? state->helo_name : "",
state->helo_name ? state->helo_name : "",
ATTR_TYPE_STR, MAIL_ATTR_SENDER,
state->sender ? state->sender : "",
ATTR_TYPE_STR, MAIL_ATTR_RECIP,
@ -3093,7 +3093,7 @@ static int generic_checks(SMTPD_STATE *state, ARGV *restrictions,
name);
else {
cpp += 1;
if (!IS_UNK_CLNT_NAME(state->name))
if (strcasecmp(state->name, "unknown") != 0)
status = reject_rbl_domain(state, *cpp, state->name,
SMTPD_NAME_CLIENT);
}

View File

@ -245,26 +245,29 @@ int smtpd_proxy_open(SMTPD_STATE *state, const char *service,
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.
*/
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);
vstring_strcpy(buf, XCLIENT_CMD " " XCLIENT_FORWARD
" " 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), "");
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), "");
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_UNK_HELO_NAME(FORWARD_HELO(state)))
if (!IS_UNK_CLIENT_HELO(FORWARD_HELO(state)))
xtext_quote_append(buf, FORWARD_HELO(state), "");
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), "");
bad = smtpd_proxy_cmd(state, SMTPD_PROX_WANT_ANY, "%s", STR(buf));
}

View File

@ -88,7 +88,7 @@ void smtpd_state_init(SMTPD_STATE *state, VSTREAM *stream)
state->verp_delims = 0;
state->recipient = 0;
state->etrn_name = 0;
state->protocol = MAIL_PROTO_SMTP;
state->protocol = mystrdup(MAIL_PROTO_SMTP);
state->where = SMTPD_AFTER_CONNECT;
state->recursion = 0;
state->msg_size = 0;
@ -140,6 +140,8 @@ void smtpd_state_reset(SMTPD_STATE *state)
*/
if (state->buffer)
vstring_free(state->buffer);
if (state->protocol)
myfree(state->protocol);
smtpd_peer_reset(state);
smtpd_xclient_reset(state);
if (state->defer_if_permit.reason)

View File

@ -12,13 +12,14 @@
/* void smtpd_xclient_reset(state)
/* SMTPD_STATE *state;
/* DESCRIPTION
/* smtpd_xclient_init() initializes state variables that are
/* used for storage of XCLIENT command parameters.
/* These variables override specific members of the global state
/* structure for access control or logging purposes.
/* smtpd_xclient_init() zeroes the attributes for storage of XCLIENT
/* FORWARD command parameters.
/*
/* smtpd_xclient_reset() releases memory allocated after the return
/* from smtpd_xclient_init().
/* 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
@ -52,21 +53,42 @@
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.peer_code = 0;
state->xclient.protocol = mystrdup(PROTOCOL_UNKNOWN);
state->xclient.helo_name = mystrdup(HELO_NAME_UNKNOWN);
state->xclient.protocol = mystrdup(CLIENT_PROTO_UNKNOWN);
}
/* smtpd_xclient_reset - reset XCLIENT attributes */
void smtpd_xclient_reset(SMTPD_STATE *state)
{
myfree(state->xclient.name);
myfree(state->xclient.addr);
myfree(state->xclient.namaddr);
myfree(state->xclient.protocol);
myfree(state->xclient.helo_name);
#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);
}