mirror of
https://github.com/vdukhovni/postfix
synced 2025-08-30 05:38:06 +00:00
postfix-2.0.16-20031130
This commit is contained in:
parent
196cfcd300
commit
edb9945f66
@ -11,53 +11,51 @@ the SMTP client hostname, network address, and other information.
|
||||
|
||||
2 - Logging after content filter. With Internet->MTA1->filter->MTA2
|
||||
style content filter applications, remote client information is
|
||||
lost when MTA1 gives the mail to the content filter. This complicates
|
||||
the interpretation of the audit trail. In order maintain audit
|
||||
trail continuity, MTA1 needs the ability to forward client information
|
||||
through the content filter to MTA2.
|
||||
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.
|
||||
|
||||
3 - Post-filter access control and logging. With Internet->filter->MTA
|
||||
style content filter applications, the content filter can be greatly
|
||||
simplified if it can delegate all decisions concerning mail relay
|
||||
and other access control to the MTA. This requires that the filter
|
||||
can forward client information to the MTA for access control
|
||||
purposes.
|
||||
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 modes of
|
||||
operation:
|
||||
The preceding suggests that there is a need for two functions:
|
||||
|
||||
- Operation mode 1: override the SMTP server's idea of SMTP
|
||||
client information for access control and audit trail purposes.
|
||||
Attributes that one may want to override are:
|
||||
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.
|
||||
|
||||
client network address
|
||||
client hostname
|
||||
hostname lookup failure type (permanent or temporary)
|
||||
client protocol (e.g., SMTP or ESMTP)
|
||||
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.
|
||||
|
||||
- Operation mode 2: forward remote client information for audit
|
||||
trail purposes only. Examples of attributes are:
|
||||
Command overview
|
||||
================
|
||||
|
||||
client network address
|
||||
client hostname
|
||||
client protocol (e.g., SMTP or ESMTP)
|
||||
client SMTP HELO parameter
|
||||
The EHLO keyword associated with this extension is XCLIENT.
|
||||
|
||||
General XCLIENT command syntax
|
||||
==============================
|
||||
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.
|
||||
|
||||
The XCLIENT command maintains one set of attributes with surrogate
|
||||
client information. The general XCLIENT command syntax is described
|
||||
below. Upper case and quoted strings specify terminals, lowercase
|
||||
strings specify meta terminals, SP is whitespace, and descriptive
|
||||
text is in {}. Although shown below in upper case, command and
|
||||
attribute names are in fact case insensitive.
|
||||
The general command syntax is described below. Upper case and
|
||||
quoted strings specify terminals, lowercase strings specify meta
|
||||
terminals, SP is whitespace, and descriptive text is enclosed in
|
||||
{}. Although command and attribute names are shown below in upper
|
||||
case, they are in fact case insensitive.
|
||||
|
||||
xclient-command = XCLIENT *( SP argument )
|
||||
xclient-command = XCLIENT SP function SP 1*( attribute )
|
||||
|
||||
argument = ( request | attribute )
|
||||
|
||||
request = ( RST | ACL | LOG )
|
||||
function = ( OVERRIDE | FORWARD )
|
||||
|
||||
attribute = name"="value
|
||||
|
||||
@ -67,10 +65,10 @@ attribute names are in fact case insensitive.
|
||||
|
||||
xtext = { attribute value encoded as per RFC 1891 }
|
||||
|
||||
The XCLIENT command is typically sent immediately before or after
|
||||
the EHLO command, may be pipelined after the server announces ESMTP
|
||||
pipelining support, and must not be used in the middle of an SMTP
|
||||
transaction (i.e. between MAIL and DOT).
|
||||
The XCLIENT command can be sent at any time except in the middle
|
||||
of a mail delivery transaction (i.e. between MAIL and DOT). The
|
||||
command may be pipelined after the server EHLO reply announces
|
||||
ESMTP pipelining support.
|
||||
|
||||
The server reply codes are as follows:
|
||||
|
||||
@ -79,96 +77,94 @@ The server reply codes are as follows:
|
||||
250 | success
|
||||
501 | command syntax error
|
||||
502 | unrecognized request name
|
||||
503 | command out of order (name=value without prior ACL or LOG request)
|
||||
421 | unable to proceed
|
||||
|
||||
The server must report success in case of an unrecognized attribute
|
||||
name, although it may log a warning.
|
||||
|
||||
Specific XCLIENT usage scenarios
|
||||
================================
|
||||
Specific usage scenarios
|
||||
========================
|
||||
|
||||
This section discusses the semantics of XCLIENT requests. Specific
|
||||
syntax information is given in the next section.
|
||||
syntax details are given in the next section.
|
||||
|
||||
The RST request resets all XCLIENT attributes and disables any
|
||||
override of access control or audit trail attributes. Example:
|
||||
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.
|
||||
|
||||
XCLIENT RST
|
||||
The following example overrides only the client hostname and network
|
||||
address, leaving unchanged all other client attributes such as the
|
||||
mail protocol or the hostname given in the HELO command:
|
||||
|
||||
The ACL request resets all XCLIENT attributes and must be specified
|
||||
before sending surrogate attributes for access control and audit
|
||||
trail purposes. Attributes that are not explicitly specified will
|
||||
default to their actual value. Example:
|
||||
XCLIENT OVERRIDE CLIENT_NAME=spike.porcupine.org
|
||||
XCLIENT OVERRIDE CLIENT_ADDR=168.100.189.2
|
||||
|
||||
XCLIENT ACL CLIENT_NAME=spike.porcupine.org
|
||||
XCLIENT 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.
|
||||
|
||||
This overrides only the client hostname and network address, but
|
||||
none of the other 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.
|
||||
|
||||
The LOG request resets all XCLIENT attributes and must be specified
|
||||
before sending surrogate attributes for audit trail purposes.
|
||||
Attributes that are not explicitly specified will default to the
|
||||
unknown value. Example:
|
||||
The following example updates all forwarded client attributes that
|
||||
are defined in this document, leaving none at their default unknown
|
||||
value:
|
||||
|
||||
XCLIENT LOG CLIENT_NAME=spike.porcupine.org CLIENT_ADDR=168.100.189.2
|
||||
XCLIENT HELO_NAME=spike.porcupine.org PROTOCOL=ESMTP
|
||||
XCLIENT FORWARD CLIENT_NAME=spike.porcupine.org CLIENT_ADDR=168.100.189.2
|
||||
XCLIENT FORWARD HELO_NAME=spike.porcupine.org PROTOCOL=ESMTP
|
||||
|
||||
This overrides all client attributes that are defined in this
|
||||
document, leaving none at their default unknown value.
|
||||
Note 1: attributes specified with successive XCLIENT commands
|
||||
accumulate.
|
||||
|
||||
Note 1: it is an error to specify name=value pairs without prior
|
||||
ACL or LOG request.
|
||||
Note 2: XCLIENT FORWARD attributes take precedence over XCLIENT
|
||||
OVERRIDE attributes.
|
||||
|
||||
Note 2: after an ACL or LOG request, attributes specified with
|
||||
successive XCLIENT commands accumulate until the next RST, ACL or
|
||||
LOG request.
|
||||
|
||||
Note 3: if one XCLIENT command specifies multiple requests (e.g.,
|
||||
both ACL and LOG), only the last request takes effect.
|
||||
|
||||
XCLIENT attribute value details
|
||||
===============================
|
||||
Attribute value details
|
||||
=======================
|
||||
|
||||
Attribute values are encoded as RFC 1891 xtext strings. To explicitly
|
||||
specify that an attribute value is unknown, the value must be empty;
|
||||
the client is not allowed to send its own internal representation
|
||||
for unknown information.
|
||||
the client must not send its own internal representation of unknown
|
||||
information.
|
||||
|
||||
CLIENT_CODE specifies CLIENT_NAME hostname lookup status information.
|
||||
Values are OK (success), TEMP (temporary lookup failure) or PERM
|
||||
(permanent lookup failure). When CLIENT_CODE is set to any value
|
||||
other than OK, the CLIENT_NAME attribute is set to the unknown
|
||||
value.
|
||||
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
|
||||
set to PERM. When a valid domain name is specified, CLIENT_CODE is
|
||||
set to OK. The server may process a syntactically invalid domain
|
||||
name as if it were unknown.
|
||||
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 [].
|
||||
|
||||
PROTOCOL is a string of up to 64 printable characters.
|
||||
PROTOCOL is 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 domain name.
|
||||
HELO_NAME should be a syntactically valid HELO parameter value.
|
||||
|
||||
Note 4: syntactically valid CLIENT_NAME and HELO_NAME attributes
|
||||
can be up to 255 characters long. The client must not send XCLIENT
|
||||
commands that exceed the 512 character limit of SMTP commands.
|
||||
Note 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 5: attribute values may end up in Received: or other message
|
||||
headers. The server may substitute any characters that are special
|
||||
according to RFC 822 or RFC 2822.
|
||||
Note 4: attribute values may end up in Received: or other message
|
||||
headers. The receiving MTA may substitute characters in order to
|
||||
not violate RFC 822 or RFC 2822.
|
||||
|
||||
Security
|
||||
========
|
||||
|
||||
The XCLIENT command changes audit trails and changes client access
|
||||
permissions. For these reasons, use of the XCLIENT command must be
|
||||
restricted to authorized clients only.
|
||||
The XCLIENT command changes audit trails and/or client access
|
||||
permissions. For these reasons, use of these commands must be
|
||||
restricted to authorized clients only.
|
||||
|
||||
The examples in this document assume that XCLIENT does not override
|
||||
its own access control mechanism.
|
||||
@ -179,7 +175,6 @@ SMTP connection caching
|
||||
SMTP connection caching makes it possible to deliver multiple
|
||||
messages within the same SMTP session. Thus, one persistent SMTP
|
||||
session with a content filter can carry messages from unrelated
|
||||
clients. Attributes from one remote client should not affect the
|
||||
delivery of mail from a different remote client. In order to
|
||||
prevent such information leakage, use the XCLIENT RST, ACL or LOG
|
||||
requests as appropriate.
|
||||
clients. Applications should ensure that XCLIENT information from
|
||||
one remote client is properly updated before commencing delivery
|
||||
of mail from a different remote client.
|
||||
|
@ -151,6 +151,18 @@ extern char *mail_pathname(const char *, const char *);
|
||||
#define MAIL_ATTR_ORG_NONE "unknown" /* origin unknown */
|
||||
#define MAIL_ATTR_ORG_LOCAL "local" /* local submission */
|
||||
|
||||
/*
|
||||
* XCLIENT in SMTP.
|
||||
*/
|
||||
#define XCLIENT_CMD "XCLIENT" /* XCLIENT command */
|
||||
#define XCLIENT_OVERRIDE "OVERRIDE" /* override function */
|
||||
#define XCLIENT_FORWARD "FORWARD" /* forward function */
|
||||
#define XCLIENT_NAME "CLIENT_NAME" /* client name */
|
||||
#define XCLIENT_ADDR "CLIENT_ADDR" /* client address */
|
||||
#define XCLIENT_PROTO "PROTOCOL" /* client protocol */
|
||||
#define XCLIENT_CODE "CLIENT_CODE" /* client name status */
|
||||
#define XCLIENT_HELO "HELO_NAME" /* client helo */
|
||||
|
||||
/*
|
||||
* Internal forms for unknown XCLIENT information.
|
||||
*/
|
||||
|
@ -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 "20031128"
|
||||
#define MAIL_RELEASE_DATE "20031130"
|
||||
|
||||
#define VAR_MAIL_VERSION "mail_version"
|
||||
#define DEF_MAIL_VERSION "2.0.16-" MAIL_RELEASE_DATE
|
||||
|
@ -385,8 +385,6 @@ int smtp_xfer(SMTP_STATE *state)
|
||||
int mail_from_rejected;
|
||||
int downgrading;
|
||||
int mime_errs;
|
||||
int send_xclient_addr = 0;
|
||||
int send_xclient_helo = 0;
|
||||
|
||||
/*
|
||||
* Macros for readability.
|
||||
@ -486,21 +484,13 @@ int smtp_xfer(SMTP_STATE *state)
|
||||
* commands rejected, DATA rejected) it forces the sender to abort the
|
||||
* SMTP dialog with RSET and QUIT.
|
||||
*
|
||||
* Send "XCLIENT LOG" information only if we have a surrogate remote client
|
||||
* name and address, i.e. the mail was actually received from the
|
||||
* network. Since "XCLIENT LOG" overrides all remote client logging
|
||||
* attributes, there is no need to send helo or protocol information that
|
||||
* we do not have.
|
||||
* Update the server's remote client information to avoid leakage of past
|
||||
* client attributes into an unrelated mail delivery.
|
||||
*/
|
||||
nrcpt = 0;
|
||||
send_xclient_addr = (state->features & SMTP_FEATURE_XCLIENT)
|
||||
&& !IS_UNK_CLNT_NAME(request->client_name)
|
||||
&& !IS_UNK_CLNT_ADDR(request->client_addr);
|
||||
if (send_xclient_addr) {
|
||||
send_xclient_helo = !IS_UNK_HELO_NAME(request->client_helo)
|
||||
|| !IS_UNK_PROTOCOL(request->client_proto);
|
||||
if (var_smtp_send_xclient && (state->features & SMTP_FEATURE_XCLIENT))
|
||||
recv_state = send_state = SMTP_STATE_XCLIENT_ADDR;
|
||||
} else
|
||||
else
|
||||
recv_state = send_state = SMTP_STATE_MAIL;
|
||||
next_rcpt = send_rcpt = recv_rcpt = 0;
|
||||
mail_from_rejected = 0;
|
||||
@ -519,37 +509,29 @@ int smtp_xfer(SMTP_STATE *state)
|
||||
msg_panic("%s: bad sender state %d", myname, send_state);
|
||||
|
||||
/*
|
||||
* Build the XCLIENT command. Send what we know, converting
|
||||
* internal form to external form. With properly sanitized
|
||||
* information, this stays within the 512 byte command line
|
||||
* length limit.
|
||||
* Build the XCLIENT command. With properly sanitized
|
||||
* information, the command length stays within the 512 byte
|
||||
* command line length limit.
|
||||
*/
|
||||
case SMTP_STATE_XCLIENT_ADDR:
|
||||
vstring_sprintf(next_command, "XCLIENT LOG");
|
||||
if (!IS_UNK_CLNT_NAME(request->client_name)) {
|
||||
vstring_strcat(next_command, " CLIENT_NAME=");
|
||||
vstring_strcpy(next_command,
|
||||
XCLIENT_CMD " " XCLIENT_FORWARD " " XCLIENT_NAME "=");
|
||||
if (!IS_UNK_CLNT_NAME(request->client_name))
|
||||
xtext_quote_append(next_command, request->client_name, "");
|
||||
}
|
||||
if (!IS_UNK_CLNT_ADDR(request->client_addr)) {
|
||||
vstring_strcat(next_command, " CLIENT_ADDR=");
|
||||
vstring_strcat(next_command, " " XCLIENT_ADDR "=");
|
||||
if (!IS_UNK_CLNT_ADDR(request->client_addr))
|
||||
xtext_quote_append(next_command, request->client_addr, "");
|
||||
}
|
||||
if (send_xclient_helo)
|
||||
next_state = SMTP_STATE_XCLIENT_HELO;
|
||||
else
|
||||
next_state = SMTP_STATE_MAIL;
|
||||
next_state = SMTP_STATE_XCLIENT_HELO;
|
||||
break;
|
||||
|
||||
case SMTP_STATE_XCLIENT_HELO:
|
||||
vstring_sprintf(next_command, "XCLIENT");
|
||||
if (!IS_UNK_HELO_NAME(request->client_helo)) {
|
||||
vstring_strcat(next_command, " HELO_NAME=");
|
||||
vstring_strcpy(next_command,
|
||||
XCLIENT_CMD " " XCLIENT_FORWARD " " XCLIENT_HELO "=");
|
||||
if (!IS_UNK_HELO_NAME(request->client_helo))
|
||||
xtext_quote_append(next_command, request->client_helo, "");
|
||||
}
|
||||
if (!IS_UNK_PROTOCOL(request->client_proto)) {
|
||||
vstring_strcat(next_command, " PROTOCOL=");
|
||||
vstring_strcat(next_command, " " XCLIENT_PROTO "=");
|
||||
if (!IS_UNK_PROTOCOL(request->client_proto))
|
||||
xtext_quote_append(next_command, request->client_proto, "");
|
||||
}
|
||||
next_state = SMTP_STATE_MAIL;
|
||||
break;
|
||||
|
||||
@ -684,13 +666,10 @@ int smtp_xfer(SMTP_STATE *state)
|
||||
switch (recv_state) {
|
||||
|
||||
/*
|
||||
* Ignore the XCLIENT response. No Duff device needed.
|
||||
* Process the XCLIENT response.
|
||||
*/
|
||||
case SMTP_STATE_XCLIENT_ADDR:
|
||||
if (send_xclient_helo)
|
||||
recv_state = SMTP_STATE_XCLIENT_HELO;
|
||||
else
|
||||
recv_state = SMTP_STATE_MAIL;
|
||||
recv_state = SMTP_STATE_XCLIENT_HELO;
|
||||
break;
|
||||
|
||||
case SMTP_STATE_XCLIENT_HELO:
|
||||
|
@ -410,6 +410,7 @@
|
||||
#include <errno.h>
|
||||
#include <ctype.h>
|
||||
#include <signal.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#ifdef STRCASECMP_IN_STRINGS_H
|
||||
#include <strings.h>
|
||||
@ -574,6 +575,7 @@ static NAMADR_LIST *verp_clients;
|
||||
* XCLIENT command.
|
||||
*/
|
||||
static NAMADR_LIST *xclient_hosts;
|
||||
static int xclient_allowed;
|
||||
|
||||
/*
|
||||
* Client connection and rate limiting.
|
||||
@ -616,10 +618,10 @@ static int sasl_client_exception(SMTPD_STATE *state)
|
||||
return (0);
|
||||
|
||||
match = namadr_list_match(sasl_exceptions_networks,
|
||||
ACL_NAME(state), ACL_ADDR(state));
|
||||
state->name, state->addr);
|
||||
|
||||
if (msg_verbose)
|
||||
msg_info("sasl_exceptions: %s, match=%d", ACL_NAMADDR(state), match);
|
||||
msg_info("sasl_exceptions: %s, match=%d", state->namaddr, match);
|
||||
|
||||
return (match);
|
||||
}
|
||||
@ -721,10 +723,10 @@ static int ehlo_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv)
|
||||
smtpd_chat_reply(state, "250-AUTH=%s", state->sasl_mechanism_list);
|
||||
}
|
||||
#endif
|
||||
if (namadr_list_match(verp_clients, ACL_NAME(state), ACL_ADDR(state)))
|
||||
if (namadr_list_match(verp_clients, state->name, state->addr))
|
||||
smtpd_chat_reply(state, "250-%s", VERP_CMD);
|
||||
/* XCLIENT must not override its own access control. */
|
||||
if (namadr_list_match(xclient_hosts, state->name, state->addr))
|
||||
if (xclient_allowed)
|
||||
smtpd_chat_reply(state, "250-%s", XCLIENT_CMD);
|
||||
smtpd_chat_reply(state, "250 8BITMIME");
|
||||
return (0);
|
||||
@ -802,7 +804,7 @@ static void mail_open_stream(SMTPD_STATE *state, SMTPD_TOKEN *argv)
|
||||
smtpd_sasl_mail_log(state);
|
||||
else
|
||||
#endif
|
||||
msg_info("%s: client=%s", state->queue_id, LOG_NAMADDR(state));
|
||||
msg_info("%s: client=%s", state->queue_id, FORWARD_NAMADDR(state));
|
||||
|
||||
/*
|
||||
* Record the time of arrival, the sender envelope address, some session
|
||||
@ -823,17 +825,17 @@ static void mail_open_stream(SMTPD_STATE *state, SMTPD_TOKEN *argv)
|
||||
*/
|
||||
if (SMTPD_STAND_ALONE(state) == 0) {
|
||||
rec_fprintf(state->cleanup, REC_TYPE_ATTR, "%s=%s",
|
||||
MAIL_ATTR_CLIENT_NAME, LOG_NAME(state));
|
||||
MAIL_ATTR_CLIENT_NAME, FORWARD_NAME(state));
|
||||
rec_fprintf(state->cleanup, REC_TYPE_ATTR, "%s=%s",
|
||||
MAIL_ATTR_CLIENT_ADDR, LOG_ADDR(state));
|
||||
MAIL_ATTR_CLIENT_ADDR, FORWARD_ADDR(state));
|
||||
rec_fprintf(state->cleanup, REC_TYPE_ATTR, "%s=%s",
|
||||
MAIL_ATTR_ORIGIN, LOG_NAMADDR(state));
|
||||
MAIL_ATTR_ORIGIN, FORWARD_NAMADDR(state));
|
||||
rec_fprintf(state->cleanup, REC_TYPE_ATTR, "%s=%s",
|
||||
MAIL_ATTR_HELO_NAME,
|
||||
IS_UNK_HELO_NAME(LOG_HELO_NAME(state)) ?
|
||||
HELO_NAME_UNKNOWN : LOG_HELO_NAME(state));
|
||||
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, LOG_PROTOCOL(state));
|
||||
MAIL_ATTR_PROTO_NAME, FORWARD_PROTO(state));
|
||||
}
|
||||
if (state->verp_delims)
|
||||
rec_fputs(state->cleanup, REC_TYPE_VERP, state->verp_delims);
|
||||
@ -1023,8 +1025,7 @@ static int mail_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv)
|
||||
return (-1);
|
||||
}
|
||||
#endif
|
||||
} else if (namadr_list_match(verp_clients, ACL_NAME(state),
|
||||
ACL_ADDR(state))
|
||||
} else if (namadr_list_match(verp_clients, state->name, state->addr)
|
||||
&& strncasecmp(arg, VERP_CMD, VERP_CMD_LEN) == 0
|
||||
&& (arg[VERP_CMD_LEN] == '=' || arg[VERP_CMD_LEN] == 0)) {
|
||||
if (arg[VERP_CMD_LEN] == 0) {
|
||||
@ -1669,6 +1670,48 @@ static int quit_cmd(SMTPD_STATE *state, int unused_argc, SMTPD_TOKEN *unused_arg
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Lookup tables with xclient/normal attribute offsets. Maybe we should not
|
||||
* try so hard to make XOVERRIDE and XFORWARD attribute lists identical.
|
||||
*/
|
||||
#define FUNC_OVERRIDE 0
|
||||
#define FUNC_FORWARD 1
|
||||
|
||||
struct attr_offset {
|
||||
int name[2];
|
||||
int addr[2];
|
||||
int namaddr[2];
|
||||
int peer_code[2];
|
||||
int protocol[2];
|
||||
int helo_name[2];
|
||||
};
|
||||
|
||||
#define ATTR_OFFSETS(member) \
|
||||
offsetof(SMTPD_STATE, member), offsetof(SMTPD_STATE, xclient.member)
|
||||
|
||||
static const struct attr_offset attr_offset = {
|
||||
ATTR_OFFSETS(name),
|
||||
ATTR_OFFSETS(addr),
|
||||
ATTR_OFFSETS(namaddr),
|
||||
ATTR_OFFSETS(peer_code),
|
||||
ATTR_OFFSETS(protocol),
|
||||
ATTR_OFFSETS(helo_name)
|
||||
};
|
||||
|
||||
#define PTR_ATTR(state, func, attr) (((char *) state) + attr_offset.attr[func])
|
||||
#define STR_ATTR(state, func, attr) *((char **) PTR_ATTR(state, func, attr))
|
||||
#define INT_ATTR(state, func, attr) *((int *) PTR_ATTR(state, func, attr))
|
||||
|
||||
#define UPDATE_STR(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) { \
|
||||
INT_ATTR(state, func, attr) = (value); \
|
||||
}
|
||||
|
||||
/* xclient_cmd - process XCLIENT */
|
||||
|
||||
static int xclient_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv)
|
||||
@ -1678,202 +1721,205 @@ static int xclient_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv)
|
||||
char *cooked_value;
|
||||
char *arg_val;
|
||||
int update_namaddr = 0;
|
||||
int function;
|
||||
|
||||
/*
|
||||
* Sanity checks. The XCLIENT command does not override its own access
|
||||
* control.
|
||||
*/
|
||||
if (namadr_list_match(xclient_hosts, state->name, state->addr) == 0) {
|
||||
if (IN_MAIL_TRANSACTION(state)) {
|
||||
state->error_mask |= MAIL_ERROR_PROTOCOL;
|
||||
smtpd_chat_reply(state, "503 Error: MAIL transaction in progress");
|
||||
return (-1);
|
||||
}
|
||||
if (argc < 3) {
|
||||
state->error_mask |= MAIL_ERROR_PROTOCOL;
|
||||
smtpd_chat_reply(state, "501 Syntax: %s function name=value...",
|
||||
XCLIENT_CMD);
|
||||
return (-1);
|
||||
}
|
||||
if (!xclient_allowed) {
|
||||
state->error_mask |= MAIL_ERROR_POLICY;
|
||||
smtpd_chat_reply(state, "554 Error: insufficient authorization");
|
||||
return (-1);
|
||||
}
|
||||
#define STREQ(x,y) (strcasecmp((x), (y)) == 0)
|
||||
#define UPDATE_STR(s, v) { if (s) myfree(s); s = mystrdup(v); }
|
||||
|
||||
/*
|
||||
* Iterate over all XCLIENT arguments.
|
||||
* Function name: what attributes to update. Complain about unrecognized
|
||||
* request names. The set of requests is unlikely to change.
|
||||
*/
|
||||
for (arg_no = 1; arg_no < argc; arg_no++) {
|
||||
arg_val = argv[1].strval;
|
||||
printable(arg_val, '?');
|
||||
if (STREQ(arg_val, XCLIENT_OVERRIDE)) {
|
||||
function = FUNC_OVERRIDE;
|
||||
} else if (STREQ(arg_val, XCLIENT_FORWARD)) {
|
||||
function = FUNC_FORWARD;
|
||||
state->xclient.used = 1;
|
||||
} else { /* error */
|
||||
state->error_mask |= MAIL_ERROR_PROTOCOL;
|
||||
smtpd_chat_reply(state, "501 Bad %s function: %s",
|
||||
XCLIENT_CMD, arg_val);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Iterate over all NAME=VALUE attributes.
|
||||
*/
|
||||
for (arg_no = 2; arg_no < argc; arg_no++) {
|
||||
arg_val = argv[arg_no].strval;
|
||||
|
||||
/*
|
||||
* Request name: what should happen with the stored attributes.
|
||||
* Complain about unrecognized request names. The set of requests is
|
||||
* unlikely to change.
|
||||
*/
|
||||
if ((raw_value = split_at(arg_val, '=')) == 0) {
|
||||
printable(arg_val, '?');
|
||||
if (STREQ(arg_val, "RST")) { /* blow them away */
|
||||
smtpd_xclient_reset(state, XCLIENT_OVER_NONE);
|
||||
} else if (STREQ(arg_val, "ACL")) { /* access control and logging */
|
||||
smtpd_xclient_reset(state, XCLIENT_OVER_ACL | XCLIENT_OVER_LOG);
|
||||
} else if (STREQ(arg_val, "LOG")) { /* logging only */
|
||||
smtpd_xclient_reset(state, XCLIENT_OVER_LOG);
|
||||
} else { /* error */
|
||||
state->error_mask |= MAIL_ERROR_PROTOCOL;
|
||||
smtpd_chat_reply(state, "501 Bad request: %s", arg_val);
|
||||
return (-1);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* NAME=VALUE attribute. Decode the attribute and for safety's sake
|
||||
* mask non-printable characters in the raw and decoded values; we
|
||||
* don't want to handle unexploded munitions. Do not complain about
|
||||
* Decode the attribute value and for safety's sake mask
|
||||
* non-printable characters in the raw and decoded values; we don't
|
||||
* want to handle unexploded munitions. Do not complain about
|
||||
* unrecognized attribute names. The set of attributes may change
|
||||
* over time.
|
||||
*
|
||||
* The client can send multiple XCLIENT attributes in a single command,
|
||||
* or multiple XCLIENT commands with fewer attributes.
|
||||
*
|
||||
* Note: XCLIENT ACL overrides only specific logging and access control
|
||||
* attributes (desirable for testing), while XCLIENT LOG overrides
|
||||
* all logging attributes (for audit trail consistency).
|
||||
* Note: XCLIENT OVERRIDE overrides only the specified logging and
|
||||
* access control attributes (desirable for testing), while XCLIENT
|
||||
* FORWARD overrides all logging attributes (for audit trail
|
||||
* consistency).
|
||||
*/
|
||||
else {
|
||||
if (state->xclient.mode == 0) {
|
||||
state->error_mask |= MAIL_ERROR_PROTOCOL;
|
||||
smtpd_chat_reply(state, "503 Error: send %s ACL or LOG first",
|
||||
XCLIENT_CMD);
|
||||
return (-1);
|
||||
}
|
||||
if (xtext_unquote(state->buffer, raw_value) == 0) {
|
||||
state->error_mask |= MAIL_ERROR_PROTOCOL;
|
||||
smtpd_chat_reply(state, "501 Bad attribute value syntax: %s",
|
||||
printable(raw_value, '?'));
|
||||
return (-1);
|
||||
}
|
||||
cooked_value = printable(STR(state->buffer), '?');
|
||||
(void) printable(raw_value, '?');
|
||||
if ((raw_value = split_at(arg_val, '=')) == 0) {
|
||||
state->error_mask |= MAIL_ERROR_PROTOCOL;
|
||||
smtpd_chat_reply(state, "503 Error: name=value expected");
|
||||
return (-1);
|
||||
}
|
||||
if (xtext_unquote(state->buffer, raw_value) == 0) {
|
||||
state->error_mask |= MAIL_ERROR_PROTOCOL;
|
||||
smtpd_chat_reply(state, "501 Bad attribute value syntax: %s",
|
||||
printable(raw_value, '?'));
|
||||
return (-1);
|
||||
}
|
||||
cooked_value = printable(STR(state->buffer), '?');
|
||||
(void) printable(raw_value, '?');
|
||||
|
||||
/*
|
||||
* CLIENT_NAME=hostname. Also updates the client hostname lookup
|
||||
* status code. Treat a numerical hostname as an unavailable
|
||||
* name.
|
||||
*/
|
||||
if (STREQ(arg_val, "CLIENT_NAME")) {
|
||||
if (*raw_value && !valid_hostaddr(cooked_value, DONT_GRIPE)) {
|
||||
if (!valid_hostname(cooked_value, DONT_GRIPE)) {
|
||||
state->error_mask |= MAIL_ERROR_PROTOCOL;
|
||||
smtpd_chat_reply(state, "501 Bad hostname syntax: %s",
|
||||
cooked_value);
|
||||
return (-1);
|
||||
}
|
||||
UPDATE_STR(state->xclient.name, cooked_value);
|
||||
state->xclient.peer_code = SMTPD_PEER_CODE_OK;
|
||||
} else {
|
||||
UPDATE_STR(state->xclient.name, CLIENT_NAME_UNKNOWN);
|
||||
state->xclient.peer_code = SMTPD_PEER_CODE_PERM;
|
||||
}
|
||||
update_namaddr = 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* CLIENT_ADDR=client network address.
|
||||
*/
|
||||
else if (STREQ(arg_val, "CLIENT_ADDR")) {
|
||||
if (*raw_value) {
|
||||
if (!valid_hostaddr(cooked_value, DONT_GRIPE)) {
|
||||
state->error_mask |= MAIL_ERROR_PROTOCOL;
|
||||
smtpd_chat_reply(state, "501 Bad address syntax: %s",
|
||||
cooked_value);
|
||||
return (-1);
|
||||
}
|
||||
UPDATE_STR(state->xclient.addr, cooked_value);
|
||||
} else {
|
||||
UPDATE_STR(state->xclient.name, CLIENT_NAME_UNKNOWN);
|
||||
}
|
||||
update_namaddr = 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* CLIENT_CODE=status. Reset the client hostname if the hostname
|
||||
* lookup status is not OK.
|
||||
*/
|
||||
else if (STREQ(arg_val, "CLIENT_CODE")) {
|
||||
if (STREQ(cooked_value, "OK")) {
|
||||
state->xclient.peer_code = SMTPD_PEER_CODE_OK;
|
||||
} else if (STREQ(cooked_value, "TEMP")) {
|
||||
state->xclient.peer_code = SMTPD_PEER_CODE_TEMP;
|
||||
UPDATE_STR(state->xclient.name, CLIENT_NAME_UNKNOWN);
|
||||
update_namaddr = 1;
|
||||
} else if (STREQ(cooked_value, "PERM")) {
|
||||
state->xclient.peer_code = SMTPD_PEER_CODE_PERM;
|
||||
UPDATE_STR(state->xclient.name, CLIENT_NAME_UNKNOWN);
|
||||
update_namaddr = 1;
|
||||
} else {
|
||||
/*
|
||||
* CLIENT_NAME=hostname. Also updates the client hostname lookup
|
||||
* status code. Treat a numerical hostname as an unavailable name.
|
||||
*/
|
||||
if (STREQ(arg_val, XCLIENT_NAME)) {
|
||||
if (*raw_value && !valid_hostaddr(cooked_value, DONT_GRIPE)) {
|
||||
if (!valid_hostname(cooked_value, DONT_GRIPE)) {
|
||||
state->error_mask |= MAIL_ERROR_PROTOCOL;
|
||||
smtpd_chat_reply(state, "501 Bad hostname status: %s",
|
||||
smtpd_chat_reply(state, "501 Bad hostname syntax: %s",
|
||||
cooked_value);
|
||||
return (-1);
|
||||
}
|
||||
UPDATE_STR(state, function, name, cooked_value);
|
||||
UPDATE_INT(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);
|
||||
}
|
||||
update_namaddr = 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* HELO_NAME=hostname. An empty value means the information was
|
||||
* not provided by the client and that we must not fall back to
|
||||
* the non-XCLIENT value. Disallow characters that could mess up
|
||||
* our own Received: message headers but allow [].
|
||||
*/
|
||||
else if (STREQ(arg_val, "HELO_NAME")) {
|
||||
if (*raw_value) {
|
||||
if (strlen(cooked_value) > VALID_HOSTNAME_LEN) {
|
||||
state->error_mask |= MAIL_ERROR_PROTOCOL;
|
||||
smtpd_chat_reply(state, "501 Bad HELO syntax: %s",
|
||||
cooked_value);
|
||||
return (-1);
|
||||
}
|
||||
neuter(cooked_value, "<>()\\\";:@", '?');
|
||||
UPDATE_STR(state->xclient.helo_name, cooked_value);
|
||||
} else {
|
||||
UPDATE_STR(state->xclient.helo_name, HELO_NAME_UNKNOWN);
|
||||
/*
|
||||
* CLIENT_ADDR=client network address.
|
||||
*/
|
||||
else if (STREQ(arg_val, "CLIENT_ADDR")) {
|
||||
if (*raw_value) {
|
||||
if (!valid_hostaddr(cooked_value, DONT_GRIPE)) {
|
||||
state->error_mask |= MAIL_ERROR_PROTOCOL;
|
||||
smtpd_chat_reply(state, "501 Bad address syntax: %s",
|
||||
cooked_value);
|
||||
return (-1);
|
||||
}
|
||||
UPDATE_STR(state, function, addr, cooked_value);
|
||||
} else {
|
||||
UPDATE_STR(state, function, name, CLIENT_ADDR_UNKNOWN);
|
||||
}
|
||||
update_namaddr = 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* PROTOCOL=protocol name. Disallow characters that could mess up
|
||||
* our own Received: message headers.
|
||||
*/
|
||||
else if (STREQ(arg_val, "PROTOCOL")) {
|
||||
if (*raw_value) {
|
||||
if (*cooked_value == 0 || strlen(cooked_value) > 64) {
|
||||
state->error_mask |= MAIL_ERROR_PROTOCOL;
|
||||
smtpd_chat_reply(state, "501 Bad protocol syntax: %s",
|
||||
cooked_value);
|
||||
return (-1);
|
||||
}
|
||||
neuter(cooked_value, "[]<>()\\\";:@", '?');
|
||||
UPDATE_STR(state->xclient.protocol, cooked_value);
|
||||
} else {
|
||||
UPDATE_STR(state->xclient.protocol, PROTOCOL_UNKNOWN);
|
||||
/*
|
||||
* CLIENT_CODE=status. Reset the client hostname if the hostname
|
||||
* lookup status is not OK.
|
||||
*/
|
||||
else if (STREQ(arg_val, "CLIENT_CODE")) {
|
||||
if (STREQ(cooked_value, "OK")) {
|
||||
UPDATE_INT(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);
|
||||
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);
|
||||
update_namaddr = 1;
|
||||
} else {
|
||||
state->error_mask |= MAIL_ERROR_PROTOCOL;
|
||||
smtpd_chat_reply(state, "501 Bad hostname status: %s",
|
||||
cooked_value);
|
||||
return (-1);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* HELO_NAME=hostname. An empty value means the information was not
|
||||
* provided by the client and that we must not fall back to the
|
||||
* non-XCLIENT value. Disallow characters that could mess up our own
|
||||
* Received: message headers but allow [].
|
||||
*/
|
||||
else if (STREQ(arg_val, "HELO_NAME")) {
|
||||
if (*raw_value) {
|
||||
if (strlen(cooked_value) > VALID_HOSTNAME_LEN) {
|
||||
state->error_mask |= MAIL_ERROR_PROTOCOL;
|
||||
smtpd_chat_reply(state, "501 Bad HELO syntax: %s",
|
||||
cooked_value);
|
||||
return (-1);
|
||||
}
|
||||
neuter(cooked_value, "<>()\\\";:@", '?');
|
||||
UPDATE_STR(state, function, helo_name, cooked_value);
|
||||
} else {
|
||||
UPDATE_STR(state, function, helo_name, HELO_NAME_UNKNOWN);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Unknown attribute name. Don't complain, and log a warning.
|
||||
* Logging is safe because only authorized clients can issue
|
||||
* XCLIENT commands.
|
||||
*/
|
||||
else {
|
||||
msg_warn("unknown %s attribute from %s: %s=%s",
|
||||
XCLIENT_CMD, state->namaddr, arg_val, cooked_value);
|
||||
/*
|
||||
* PROTOCOL=protocol name. Disallow characters that could mess up our
|
||||
* own Received: message headers.
|
||||
*/
|
||||
else if (STREQ(arg_val, "PROTOCOL")) {
|
||||
if (*raw_value) {
|
||||
if (*cooked_value == 0 || strlen(cooked_value) > 64) {
|
||||
state->error_mask |= MAIL_ERROR_PROTOCOL;
|
||||
smtpd_chat_reply(state, "501 Bad protocol syntax: %s",
|
||||
cooked_value);
|
||||
return (-1);
|
||||
}
|
||||
neuter(cooked_value, "[]<>()\\\";:@", '?');
|
||||
UPDATE_STR(state, function, protocol, cooked_value);
|
||||
} else {
|
||||
UPDATE_STR(state, function, protocol, PROTOCOL_UNKNOWN);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Unknown attribute name. Don't complain, and log a warning. Logging
|
||||
* is safe because only authorized clients can issue XCLIENT
|
||||
* commands.
|
||||
*/
|
||||
else {
|
||||
msg_warn("unknown %s attribute from %s: %s=%s",
|
||||
XCLIENT_CMD, state->namaddr, arg_val, cooked_value);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Update the combined name and address when either has changed.
|
||||
*/
|
||||
#define MAYBE_OVERRIDE(state, attr) \
|
||||
((state)->xclient.attr ? (state)->xclient.attr : (state)->attr)
|
||||
|
||||
if (update_namaddr) {
|
||||
if (state->xclient.namaddr)
|
||||
myfree(state->xclient.namaddr);
|
||||
state->xclient.namaddr =
|
||||
concatenate(MAYBE_OVERRIDE(state, name), "[",
|
||||
MAYBE_OVERRIDE(state, addr), "]",
|
||||
if (STR_ATTR(state, function, namaddr))
|
||||
myfree(STR_ATTR(state, function, namaddr));
|
||||
STR_ATTR(state, function, namaddr) =
|
||||
concatenate(STR_ATTR(state, function, name), "[",
|
||||
STR_ATTR(state, function, addr), "]",
|
||||
(char *) 0);
|
||||
}
|
||||
smtpd_chat_reply(state, "250 Ok");
|
||||
@ -2142,6 +2188,12 @@ static void smtpd_service(VSTREAM *stream, char *service, char **argv)
|
||||
smtpd_state_init(&state, stream);
|
||||
msg_info("connect from %s[%s]", state.name, state.addr);
|
||||
|
||||
/*
|
||||
* XCLIENT must not override its own access control.
|
||||
*/
|
||||
xclient_allowed =
|
||||
namadr_list_match(xclient_hosts, state.name, state.addr);
|
||||
|
||||
/*
|
||||
* See if we need to turn on verbose logging for this client.
|
||||
*/
|
||||
|
@ -46,7 +46,7 @@ typedef struct SMTPD_DEFER {
|
||||
} SMTPD_DEFER;
|
||||
|
||||
typedef struct SMTPD_XCLIENT_ATTR {
|
||||
int mode; /* none, log, acl */
|
||||
int used; /* status */
|
||||
char *name; /* name for access control */
|
||||
char *addr; /* address for access control */
|
||||
char *namaddr; /* name[address] */
|
||||
@ -146,34 +146,20 @@ extern void smtpd_peer_reset(SMTPD_STATE *state);
|
||||
* makes no sense to maintain separate attribute sets for XCLIENT LOG or
|
||||
* XCLIENT ACL, so we set a flag to distinguish purpose.
|
||||
*/
|
||||
#define XCLIENT_CMD "XCLIENT" /* XCLIENT command */
|
||||
#define XCLIENT_EHLO "XCLIENT" /* ESMTP advertisement */
|
||||
#define SMTPD_FEATURE_XCLIENT (1<<0) /* XCLIENT supported */
|
||||
|
||||
#define SMTPD_FEATURE_XCLIENT (1<<0) /* server supports XCLIENT */
|
||||
#define MAYBE_FORWARD(s, a) \
|
||||
((s)->xclient.used ? (s)->xclient.a : (s)->a)
|
||||
|
||||
#define XCLIENT_OVER_NONE (0) /* override reset */
|
||||
#define XCLIENT_OVER_ACL (1<<0) /* override access control */
|
||||
#define XCLIENT_OVER_LOG (1<<1) /* override logging */
|
||||
|
||||
#define XCLIENT_OVER(s, m, a) \
|
||||
(((s)->xclient.mode & (m)) && (s)->xclient.a ? (s)->xclient.a : (s)->a)
|
||||
|
||||
#define ACL_ADDR(s) XCLIENT_OVER((s), XCLIENT_OVER_ACL, addr)
|
||||
#define ACL_NAME(s) XCLIENT_OVER((s), XCLIENT_OVER_ACL, name)
|
||||
#define ACL_NAMADDR(s) XCLIENT_OVER((s), XCLIENT_OVER_ACL, namaddr)
|
||||
#define ACL_PEER_CODE(s) XCLIENT_OVER((s), XCLIENT_OVER_ACL, peer_code)
|
||||
#define ACL_PROTOCOL(s) XCLIENT_OVER((s), XCLIENT_OVER_ACL, protocol)
|
||||
#define ACL_HELO_NAME(s) XCLIENT_OVER((s), XCLIENT_OVER_ACL, helo_name)
|
||||
|
||||
#define LOG_ADDR(s) XCLIENT_OVER((s), XCLIENT_OVER_LOG, addr)
|
||||
#define LOG_NAME(s) XCLIENT_OVER((s), XCLIENT_OVER_LOG, name)
|
||||
#define LOG_NAMADDR(s) XCLIENT_OVER((s), XCLIENT_OVER_LOG, namaddr)
|
||||
#define LOG_PEER_CODE(s) XCLIENT_OVER((s), XCLIENT_OVER_LOG, peer_code)
|
||||
#define LOG_PROTOCOL(s) XCLIENT_OVER((s), XCLIENT_OVER_LOG, protocol)
|
||||
#define LOG_HELO_NAME(s) XCLIENT_OVER((s), XCLIENT_OVER_LOG, helo_name)
|
||||
#define FORWARD_ADDR(s) MAYBE_FORWARD((s), addr)
|
||||
#define FORWARD_NAME(s) MAYBE_FORWARD((s), name)
|
||||
#define FORWARD_NAMADDR(s) MAYBE_FORWARD((s), namaddr)
|
||||
#define FORWARD_CODE(s) MAYBE_FORWARD((s), peer_code)
|
||||
#define FORWARD_PROTO(s) MAYBE_FORWARD((s), protocol)
|
||||
#define FORWARD_HELO(s) MAYBE_FORWARD((s), helo_name)
|
||||
|
||||
extern void smtpd_xclient_init(SMTPD_STATE *state);
|
||||
extern void smtpd_xclient_reset(SMTPD_STATE *state, int);
|
||||
extern void smtpd_xclient_reset(SMTPD_STATE *state);
|
||||
|
||||
/*
|
||||
* Transparency: before mail is queued, do we check for unknown recipients,
|
||||
|
@ -809,15 +809,15 @@ static void log_whatsup(SMTPD_STATE *state, const char *whatsup,
|
||||
|
||||
vstring_sprintf(buf, "%s: %s: %s from %s: %s;",
|
||||
state->queue_id ? state->queue_id : "NOQUEUE",
|
||||
whatsup, state->where, LOG_NAMADDR(state), text);
|
||||
whatsup, state->where, state->namaddr, text);
|
||||
if (state->sender)
|
||||
vstring_sprintf_append(buf, " from=<%s>", state->sender);
|
||||
if (state->recipient)
|
||||
vstring_sprintf_append(buf, " to=<%s>", state->recipient);
|
||||
if (!IS_UNK_PROTOCOL(ACL_PROTOCOL(state)))
|
||||
vstring_sprintf_append(buf, " proto=%s", ACL_PROTOCOL(state));
|
||||
if (!IS_UNK_HELO_NAME(ACL_HELO_NAME(state)))
|
||||
vstring_sprintf_append(buf, " helo=<%s>", ACL_HELO_NAME(state));
|
||||
if (state->protocol)
|
||||
vstring_sprintf_append(buf, " proto=%s", state->protocol);
|
||||
if (state->helo_name)
|
||||
vstring_sprintf_append(buf, " helo=<%s>", state->helo_name);
|
||||
msg_info("%s", STR(buf));
|
||||
vstring_free(buf);
|
||||
}
|
||||
@ -968,14 +968,14 @@ static int reject_unknown_client(SMTPD_STATE *state)
|
||||
char *myname = "reject_unknown_client";
|
||||
|
||||
if (msg_verbose)
|
||||
msg_info("%s: %s %s", myname, ACL_NAME(state), ACL_ADDR(state));
|
||||
msg_info("%s: %s %s", myname, state->name, state->addr);
|
||||
|
||||
if (IS_UNK_CLNT_NAME(ACL_NAME(state)))
|
||||
if (IS_UNK_CLNT_NAME(state->name))
|
||||
return (smtpd_check_reject(state, MAIL_ERROR_POLICY,
|
||||
"%d Client host rejected: cannot find your hostname, [%s]",
|
||||
ACL_PEER_CODE(state) == SMTPD_PEER_CODE_PERM ?
|
||||
state->peer_code == SMTPD_PEER_CODE_PERM ?
|
||||
var_unk_client_code : 450,
|
||||
ACL_ADDR(state)));
|
||||
state->addr));
|
||||
return (SMTPD_CHECK_DUNNO);
|
||||
}
|
||||
|
||||
@ -986,9 +986,9 @@ static int permit_mynetworks(SMTPD_STATE *state)
|
||||
char *myname = "permit_mynetworks";
|
||||
|
||||
if (msg_verbose)
|
||||
msg_info("%s: %s %s", myname, ACL_NAME(state), ACL_ADDR(state));
|
||||
msg_info("%s: %s %s", myname, state->name, state->addr);
|
||||
|
||||
if (namadr_list_match(mynetworks, ACL_NAME(state), ACL_ADDR(state)))
|
||||
if (namadr_list_match(mynetworks, state->name, state->addr))
|
||||
return (SMTPD_CHECK_OK);
|
||||
return (SMTPD_CHECK_DUNNO);
|
||||
}
|
||||
@ -1207,7 +1207,7 @@ static int check_relay_domains(SMTPD_STATE *state, char *recipient,
|
||||
/*
|
||||
* Permit if the client matches the relay_domains list.
|
||||
*/
|
||||
if (domain_list_match(relay_domains, ACL_NAME(state)))
|
||||
if (domain_list_match(relay_domains, state->name))
|
||||
return (SMTPD_CHECK_OK);
|
||||
|
||||
/*
|
||||
@ -1309,7 +1309,7 @@ static int reject_unauth_pipelining(SMTPD_STATE *state,
|
||||
if (state->client != 0
|
||||
&& SMTPD_STAND_ALONE(state) == 0
|
||||
&& vstream_peek(state->client) > 0
|
||||
&& (strcasecmp(ACL_PROTOCOL(state), MAIL_PROTO_ESMTP) != 0
|
||||
&& (strcasecmp(state->protocol, MAIL_PROTO_ESMTP) != 0
|
||||
|| strcasecmp(state->where, "DATA") == 0)) {
|
||||
return (smtpd_check_reject(state, MAIL_ERROR_PROTOCOL,
|
||||
"503 <%s>: %s rejected: Improper use of SMTP command pipelining",
|
||||
@ -2518,14 +2518,13 @@ static const char *smtpd_expand_lookup(const char *name, int unused_mode,
|
||||
* Return NULL only for non-existent names.
|
||||
*/
|
||||
if (STREQ(name, MAIL_ATTR_CLIENT)) {
|
||||
return (ACL_NAMADDR(state));
|
||||
return (state->namaddr);
|
||||
} else if (STREQ(name, MAIL_ATTR_CLIENT_ADDR)) {
|
||||
return (ACL_ADDR(state));
|
||||
return (state->addr);
|
||||
} else if (STREQ(name, MAIL_ATTR_CLIENT_NAME)) {
|
||||
return (ACL_NAME(state));
|
||||
return (state->name);
|
||||
} else if (STREQ(name, MAIL_ATTR_HELO_NAME)) {
|
||||
return (IS_UNK_HELO_NAME(ACL_HELO_NAME(state)) ?
|
||||
"" : ACL_HELO_NAME(state));
|
||||
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)));
|
||||
@ -2821,7 +2820,7 @@ static int reject_maps_rbl(SMTPD_STATE *state)
|
||||
static int warned;
|
||||
|
||||
if (msg_verbose)
|
||||
msg_info("%s: %s", myname, ACL_ADDR(state));
|
||||
msg_info("%s: %s", myname, state->addr);
|
||||
|
||||
if (warned == 0) {
|
||||
warned++;
|
||||
@ -2830,7 +2829,7 @@ static int reject_maps_rbl(SMTPD_STATE *state)
|
||||
REJECT_MAPS_RBL, var_mail_name, REJECT_RBL_CLIENT);
|
||||
}
|
||||
while ((rbl_domain = mystrtok(&bp, " \t\r\n,")) != 0) {
|
||||
result = reject_rbl_addr(state, rbl_domain, ACL_ADDR(state),
|
||||
result = reject_rbl_addr(state, rbl_domain, state->addr,
|
||||
SMTPD_NAME_CLIENT);
|
||||
if (result != SMTPD_CHECK_DUNNO)
|
||||
break;
|
||||
@ -2907,12 +2906,11 @@ static int check_policy_service(SMTPD_STATE *state, const char *server,
|
||||
ATTR_FLAG_NONE, /* Query attributes. */
|
||||
ATTR_TYPE_STR, MAIL_ATTR_REQ, "smtpd_access_policy",
|
||||
ATTR_TYPE_STR, MAIL_ATTR_PROTO_STATE, state->where,
|
||||
ATTR_TYPE_STR, MAIL_ATTR_PROTO_NAME, ACL_PROTOCOL(state),
|
||||
ATTR_TYPE_STR, MAIL_ATTR_CLIENT_ADDR, ACL_ADDR(state),
|
||||
ATTR_TYPE_STR, MAIL_ATTR_CLIENT_NAME, ACL_NAME(state),
|
||||
ATTR_TYPE_STR, MAIL_ATTR_PROTO_NAME, state->protocol,
|
||||
ATTR_TYPE_STR, MAIL_ATTR_CLIENT_ADDR, state->addr,
|
||||
ATTR_TYPE_STR, MAIL_ATTR_CLIENT_NAME, state->name,
|
||||
ATTR_TYPE_STR, MAIL_ATTR_HELO_NAME,
|
||||
IS_UNK_HELO_NAME(ACL_HELO_NAME(state)) ?
|
||||
"" : ACL_HELO_NAME(state),
|
||||
state->helo_name ? state->helo_name : "",
|
||||
ATTR_TYPE_STR, MAIL_ATTR_SENDER,
|
||||
state->sender ? state->sender : "",
|
||||
ATTR_TYPE_STR, MAIL_ATTR_RECIP,
|
||||
@ -3077,8 +3075,8 @@ static int generic_checks(SMTPD_STATE *state, ARGV *restrictions,
|
||||
} else if (strcasecmp(name, PERMIT_MYNETWORKS) == 0) {
|
||||
status = permit_mynetworks(state);
|
||||
} else if (is_map_command(state, name, CHECK_CLIENT_ACL, &cpp)) {
|
||||
status = check_namadr_access(state, *cpp, ACL_NAME(state), ACL_ADDR(state),
|
||||
FULL, &found, ACL_NAMADDR(state),
|
||||
status = check_namadr_access(state, *cpp, state->name, state->addr,
|
||||
FULL, &found, state->namaddr,
|
||||
SMTPD_NAME_CLIENT, def_acl);
|
||||
} else if (strcasecmp(name, REJECT_MAPS_RBL) == 0) {
|
||||
status = reject_maps_rbl(state);
|
||||
@ -3087,7 +3085,7 @@ static int generic_checks(SMTPD_STATE *state, ARGV *restrictions,
|
||||
if (cpp[1] == 0)
|
||||
msg_warn("restriction %s requires domain name argument", name);
|
||||
else
|
||||
status = reject_rbl_addr(state, *(cpp += 1), ACL_ADDR(state),
|
||||
status = reject_rbl_addr(state, *(cpp += 1), state->addr,
|
||||
SMTPD_NAME_CLIENT);
|
||||
} else if (strcasecmp(name, REJECT_RHSBL_CLIENT) == 0) {
|
||||
if (cpp[1] == 0)
|
||||
@ -3095,73 +3093,69 @@ static int generic_checks(SMTPD_STATE *state, ARGV *restrictions,
|
||||
name);
|
||||
else {
|
||||
cpp += 1;
|
||||
if (!IS_UNK_CLNT_NAME(ACL_NAME(state)))
|
||||
status = reject_rbl_domain(state, *cpp, ACL_NAME(state),
|
||||
if (!IS_UNK_CLNT_NAME(state->name))
|
||||
status = reject_rbl_domain(state, *cpp, state->name,
|
||||
SMTPD_NAME_CLIENT);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* HELO/EHLO parameter restrictions.
|
||||
*
|
||||
* XXX With XCLIENT overrides, a zero-length name means the client did
|
||||
* not send a HELO/EHLO command. Do not fall back to the non-XCLIENT
|
||||
* HELO/EHLO value.
|
||||
*/
|
||||
else if (is_map_command(state, name, CHECK_HELO_ACL, &cpp)) {
|
||||
if (!IS_UNK_HELO_NAME(ACL_HELO_NAME(state)))
|
||||
status = check_domain_access(state, *cpp, ACL_HELO_NAME(state),
|
||||
FULL, &found, ACL_HELO_NAME(state),
|
||||
if (state->helo_name)
|
||||
status = check_domain_access(state, *cpp, state->helo_name,
|
||||
FULL, &found, state->helo_name,
|
||||
SMTPD_NAME_HELO, def_acl);
|
||||
} else if (strcasecmp(name, REJECT_INVALID_HOSTNAME) == 0) {
|
||||
if (!IS_UNK_HELO_NAME(ACL_HELO_NAME(state))) {
|
||||
if (*ACL_HELO_NAME(state) != '[')
|
||||
status = reject_invalid_hostname(state, ACL_HELO_NAME(state),
|
||||
ACL_HELO_NAME(state), SMTPD_NAME_HELO);
|
||||
if (state->helo_name) {
|
||||
if (*state->helo_name != '[')
|
||||
status = reject_invalid_hostname(state, state->helo_name,
|
||||
state->helo_name, SMTPD_NAME_HELO);
|
||||
else
|
||||
status = reject_invalid_hostaddr(state, ACL_HELO_NAME(state),
|
||||
ACL_HELO_NAME(state), SMTPD_NAME_HELO);
|
||||
status = reject_invalid_hostaddr(state, state->helo_name,
|
||||
state->helo_name, SMTPD_NAME_HELO);
|
||||
}
|
||||
} else if (strcasecmp(name, REJECT_UNKNOWN_HOSTNAME) == 0) {
|
||||
if (!IS_UNK_HELO_NAME(ACL_HELO_NAME(state))) {
|
||||
if (*ACL_HELO_NAME(state) != '[')
|
||||
status = reject_unknown_hostname(state, ACL_HELO_NAME(state),
|
||||
ACL_HELO_NAME(state), SMTPD_NAME_HELO);
|
||||
if (state->helo_name) {
|
||||
if (*state->helo_name != '[')
|
||||
status = reject_unknown_hostname(state, state->helo_name,
|
||||
state->helo_name, SMTPD_NAME_HELO);
|
||||
else
|
||||
status = reject_invalid_hostaddr(state, ACL_HELO_NAME(state),
|
||||
ACL_HELO_NAME(state), SMTPD_NAME_HELO);
|
||||
status = reject_invalid_hostaddr(state, state->helo_name,
|
||||
state->helo_name, SMTPD_NAME_HELO);
|
||||
}
|
||||
} else if (strcasecmp(name, PERMIT_NAKED_IP_ADDR) == 0) {
|
||||
msg_warn("restriction %s is deprecated. Use %s instead",
|
||||
PERMIT_NAKED_IP_ADDR, PERMIT_MYNETWORKS);
|
||||
if (!IS_UNK_HELO_NAME(ACL_HELO_NAME(state))) {
|
||||
if (ACL_HELO_NAME(state)[strspn(ACL_HELO_NAME(state), "0123456789.")] == 0
|
||||
&& (status = reject_invalid_hostaddr(state, ACL_HELO_NAME(state),
|
||||
ACL_HELO_NAME(state), SMTPD_NAME_HELO)) == 0)
|
||||
if (state->helo_name) {
|
||||
if (state->helo_name[strspn(state->helo_name, "0123456789.")] == 0
|
||||
&& (status = reject_invalid_hostaddr(state, state->helo_name,
|
||||
state->helo_name, SMTPD_NAME_HELO)) == 0)
|
||||
status = SMTPD_CHECK_OK;
|
||||
}
|
||||
} else if (is_map_command(state, name, CHECK_HELO_NS_ACL, &cpp)) {
|
||||
if (!IS_UNK_HELO_NAME(ACL_HELO_NAME(state))) {
|
||||
status = check_server_access(state, *cpp, ACL_HELO_NAME(state),
|
||||
T_NS, ACL_HELO_NAME(state),
|
||||
if (state->helo_name) {
|
||||
status = check_server_access(state, *cpp, state->helo_name,
|
||||
T_NS, state->helo_name,
|
||||
SMTPD_NAME_HELO, def_acl);
|
||||
forbid_whitelist(state, name, status, ACL_HELO_NAME(state));
|
||||
forbid_whitelist(state, name, status, state->helo_name);
|
||||
}
|
||||
} else if (is_map_command(state, name, CHECK_HELO_MX_ACL, &cpp)) {
|
||||
if (!IS_UNK_HELO_NAME(ACL_HELO_NAME(state))) {
|
||||
status = check_server_access(state, *cpp, ACL_HELO_NAME(state),
|
||||
T_MX, ACL_HELO_NAME(state),
|
||||
if (state->helo_name) {
|
||||
status = check_server_access(state, *cpp, state->helo_name,
|
||||
T_MX, state->helo_name,
|
||||
SMTPD_NAME_HELO, def_acl);
|
||||
forbid_whitelist(state, name, status, ACL_HELO_NAME(state));
|
||||
forbid_whitelist(state, name, status, state->helo_name);
|
||||
}
|
||||
} else if (strcasecmp(name, REJECT_NON_FQDN_HOSTNAME) == 0) {
|
||||
if (!IS_UNK_HELO_NAME(ACL_HELO_NAME(state))) {
|
||||
if (*ACL_HELO_NAME(state) != '[')
|
||||
status = reject_non_fqdn_hostname(state, ACL_HELO_NAME(state),
|
||||
ACL_HELO_NAME(state), SMTPD_NAME_HELO);
|
||||
if (state->helo_name) {
|
||||
if (*state->helo_name != '[')
|
||||
status = reject_non_fqdn_hostname(state, state->helo_name,
|
||||
state->helo_name, SMTPD_NAME_HELO);
|
||||
else
|
||||
status = reject_invalid_hostaddr(state, ACL_HELO_NAME(state),
|
||||
ACL_HELO_NAME(state), SMTPD_NAME_HELO);
|
||||
status = reject_invalid_hostaddr(state, state->helo_name,
|
||||
state->helo_name, SMTPD_NAME_HELO);
|
||||
}
|
||||
} else if (strcasecmp(name, REJECT_RHSBL_HELO) == 0) {
|
||||
if (cpp[1] == 0)
|
||||
@ -3169,8 +3163,8 @@ static int generic_checks(SMTPD_STATE *state, ARGV *restrictions,
|
||||
name);
|
||||
else {
|
||||
cpp += 1;
|
||||
if (!IS_UNK_HELO_NAME(ACL_HELO_NAME(state)))
|
||||
status = reject_rbl_domain(state, *cpp, ACL_HELO_NAME(state),
|
||||
if (state->helo_name)
|
||||
status = reject_rbl_domain(state, *cpp, state->helo_name,
|
||||
SMTPD_NAME_HELO);
|
||||
}
|
||||
}
|
||||
@ -3367,7 +3361,7 @@ char *smtpd_check_client(SMTPD_STATE *state)
|
||||
/*
|
||||
* Initialize.
|
||||
*/
|
||||
if (ACL_NAME(state) == 0 || ACL_ADDR(state) == 0)
|
||||
if (state->name == 0 || state->addr == 0)
|
||||
return (0);
|
||||
|
||||
#define SMTPD_CHECK_RESET() { \
|
||||
@ -3387,7 +3381,7 @@ char *smtpd_check_client(SMTPD_STATE *state)
|
||||
SMTPD_CHECK_RESET();
|
||||
status = setjmp(smtpd_check_buf);
|
||||
if (status == 0 && client_restrctions->argc)
|
||||
status = generic_checks(state, client_restrctions, ACL_NAMADDR(state),
|
||||
status = generic_checks(state, client_restrctions, state->namaddr,
|
||||
SMTPD_NAME_CLIENT, CHECK_CLIENT_ACL);
|
||||
state->defer_if_permit_client = state->defer_if_permit.active;
|
||||
|
||||
@ -3441,7 +3435,7 @@ char *smtpd_check_helo(SMTPD_STATE *state, char *helohost)
|
||||
SMTPD_CHECK_RESET();
|
||||
status = setjmp(smtpd_check_buf);
|
||||
if (status == 0 && helo_restrctions->argc)
|
||||
status = generic_checks(state, helo_restrctions, ACL_HELO_NAME(state),
|
||||
status = generic_checks(state, helo_restrctions, state->helo_name,
|
||||
SMTPD_NAME_HELO, CHECK_HELO_ACL);
|
||||
state->defer_if_permit_helo = state->defer_if_permit.active;
|
||||
|
||||
@ -3553,7 +3547,7 @@ char *smtpd_check_rcpt(SMTPD_STATE *state, char *recipient)
|
||||
*/
|
||||
if (var_smtpd_delay_reject)
|
||||
if ((err = smtpd_check_client(state)) != 0
|
||||
|| (err = smtpd_check_helo(state, ACL_HELO_NAME(state))) != 0
|
||||
|| (err = smtpd_check_helo(state, state->helo_name)) != 0
|
||||
|| (err = smtpd_check_mail(state, state->sender)) != 0)
|
||||
SMTPD_CHECK_RCPT_RETURN(err);
|
||||
|
||||
@ -3622,7 +3616,7 @@ char *smtpd_check_etrn(SMTPD_STATE *state, char *domain)
|
||||
*/
|
||||
if (var_smtpd_delay_reject)
|
||||
if ((err = smtpd_check_client(state)) != 0
|
||||
|| (err = smtpd_check_helo(state, ACL_HELO_NAME(state))) != 0)
|
||||
|| (err = smtpd_check_helo(state, state->helo_name)) != 0)
|
||||
SMTPD_CHECK_ETRN_RETURN(err);
|
||||
|
||||
/*
|
||||
|
@ -241,29 +241,31 @@ int smtpd_proxy_open(SMTPD_STATE *state, const char *service,
|
||||
while ((line = mystrtok(&lines, "\n")) != 0)
|
||||
if (ISDIGIT(line[0]) && ISDIGIT(line[1]) && ISDIGIT(line[2])
|
||||
&& (line[3] == ' ' || line[3] == '-')
|
||||
&& strcmp(line + 4, XCLIENT_EHLO) == 0)
|
||||
&& strcmp(line + 4, XCLIENT_CMD) == 0)
|
||||
state->proxy_features |= SMTPD_FEATURE_XCLIENT;
|
||||
|
||||
/*
|
||||
* Send our XCLIENT attributes. Transform internal forms to external
|
||||
* Send all XCLIENT attributes. Transform internal forms to external
|
||||
* forms and encode the result as xtext.
|
||||
*/
|
||||
if (state->proxy_features & SMTPD_FEATURE_XCLIENT) {
|
||||
buf = vstring_alloc(100);
|
||||
vstring_sprintf(buf, "%s LOG CLIENT_NAME=", XCLIENT_CMD);
|
||||
if (!IS_UNK_CLNT_NAME(LOG_NAME(state)))
|
||||
xtext_quote_append(buf, LOG_NAME(state), "");
|
||||
vstring_strcat(buf, " CLIENT_ADDR=");
|
||||
if (!IS_UNK_CLNT_ADDR(LOG_ADDR(state)))
|
||||
xtext_quote_append(buf, LOG_ADDR(state), "");
|
||||
vstring_strcpy(buf, XCLIENT_CMD " " XCLIENT_FORWARD
|
||||
" " XCLIENT_NAME "=");
|
||||
if (!IS_UNK_CLNT_NAME(FORWARD_NAME(state)))
|
||||
xtext_quote_append(buf, FORWARD_NAME(state), "");
|
||||
vstring_strcat(buf, " " XCLIENT_ADDR "=");
|
||||
if (!IS_UNK_CLNT_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_sprintf(buf, "%s HELO_NAME=", XCLIENT_CMD);
|
||||
if (!IS_UNK_HELO_NAME(LOG_HELO_NAME(state)))
|
||||
xtext_quote_append(buf, LOG_HELO_NAME(state), "");
|
||||
vstring_strcat(buf, " PROTOCOL=");
|
||||
if (!IS_UNK_PROTOCOL(LOG_PROTOCOL(state)))
|
||||
xtext_quote_append(buf, LOG_PROTOCOL(state), "");
|
||||
vstring_strcpy(buf, XCLIENT_CMD " " XCLIENT_FORWARD
|
||||
" " XCLIENT_HELO "=");
|
||||
if (!IS_UNK_HELO_NAME(FORWARD_HELO(state)))
|
||||
xtext_quote_append(buf, FORWARD_HELO(state), "");
|
||||
vstring_strcat(buf, " " XCLIENT_PROTO "=");
|
||||
if (!IS_UNK_PROTOCOL(FORWARD_PROTO(state)))
|
||||
xtext_quote_append(buf, FORWARD_PROTO(state), "");
|
||||
bad = smtpd_proxy_cmd(state, SMTPD_PROX_WANT_ANY, "%s", STR(buf));
|
||||
}
|
||||
vstring_free(buf);
|
||||
|
@ -198,7 +198,7 @@ void smtpd_sasl_mail_log(SMTPD_STATE *state)
|
||||
#define IFELSE(e1,e2,e3) ((e1) ? (e2) : (e3))
|
||||
|
||||
msg_info("%s: client=%s%s%s%s%s%s%s",
|
||||
state->queue_id, LOG_NAMADDR(state),
|
||||
state->queue_id, FORWARD_NAMADDR(state),
|
||||
IFELSE(state->sasl_method, ", sasl_method=", ""),
|
||||
IFELSE(state->sasl_method, state->sasl_method, ""),
|
||||
IFELSE(state->sasl_username, ", sasl_username=", ""),
|
||||
|
@ -141,7 +141,7 @@ void smtpd_state_reset(SMTPD_STATE *state)
|
||||
if (state->buffer)
|
||||
vstring_free(state->buffer);
|
||||
smtpd_peer_reset(state);
|
||||
smtpd_xclient_reset(state, XCLIENT_OVER_NONE);
|
||||
smtpd_xclient_reset(state);
|
||||
if (state->defer_if_permit.reason)
|
||||
vstring_free(state->defer_if_permit.reason);
|
||||
if (state->defer_if_reject.reason)
|
||||
|
@ -9,9 +9,8 @@
|
||||
/* void smtpd_xclient_init(state)
|
||||
/* SMTPD_STATE *state;
|
||||
/*
|
||||
/* void smtpd_xclient_reset(state, mode)
|
||||
/* void smtpd_xclient_reset(state)
|
||||
/* SMTPD_STATE *state;
|
||||
/* int mode;
|
||||
/* DESCRIPTION
|
||||
/* smtpd_xclient_init() initializes state variables that are
|
||||
/* used for storage of XCLIENT command parameters.
|
||||
@ -19,14 +18,7 @@
|
||||
/* structure for access control or logging purposes.
|
||||
/*
|
||||
/* smtpd_xclient_reset() releases memory allocated after the return
|
||||
/* from smtpd_xclient_init() and optionally presets the state variables
|
||||
/* to defaults that are suitable for the specified mode:
|
||||
/* .IP XCLIENT_OVER_NONE
|
||||
/* This should be used after the XCLIENT RST request.
|
||||
/* .IP XCLIENT_OVER_ACL|XCLIENT_OVER_LOG
|
||||
/* This should be used after the XCLIENT ACL request.
|
||||
/* .IP XCLIENT_OVER_LOG
|
||||
/* This should be used after the XCLIENT LOG request.
|
||||
/* from smtpd_xclient_init().
|
||||
/* LICENSE
|
||||
/* .ad
|
||||
/* .fi
|
||||
@ -59,58 +51,22 @@
|
||||
|
||||
void smtpd_xclient_init(SMTPD_STATE *state)
|
||||
{
|
||||
state->xclient.mode = 0;
|
||||
state->xclient.name = 0;
|
||||
state->xclient.addr = 0;
|
||||
state->xclient.namaddr = 0;
|
||||
state->xclient.used = 0;
|
||||
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 = 0;
|
||||
state->xclient.helo_name = 0;
|
||||
state->xclient.protocol = mystrdup(PROTOCOL_UNKNOWN);
|
||||
state->xclient.helo_name = mystrdup(HELO_NAME_UNKNOWN);
|
||||
}
|
||||
|
||||
/* smtpd_xclient_reset - reset XCLIENT attributes */
|
||||
|
||||
void smtpd_xclient_reset(SMTPD_STATE *state, int mode)
|
||||
void smtpd_xclient_reset(SMTPD_STATE *state)
|
||||
{
|
||||
switch (mode) {
|
||||
|
||||
/*
|
||||
* Can't happen.
|
||||
*/
|
||||
default:
|
||||
msg_panic("smtpd_xclient_reset: unknown mode 0x%x", mode);
|
||||
|
||||
/*
|
||||
* Restore smtpd_xclient_init() result. Allow selective override.
|
||||
* This is desirable for access rule testing.
|
||||
*/
|
||||
#define FREE_AND_WIPE(s) { if (s) { myfree(s); s = 0; } }
|
||||
|
||||
case XCLIENT_OVER_NONE:
|
||||
case XCLIENT_OVER_ACL | XCLIENT_OVER_LOG:
|
||||
FREE_AND_WIPE(state->xclient.name);
|
||||
FREE_AND_WIPE(state->xclient.addr);
|
||||
FREE_AND_WIPE(state->xclient.namaddr);
|
||||
state->xclient.peer_code = 0;
|
||||
FREE_AND_WIPE(state->xclient.protocol);
|
||||
FREE_AND_WIPE(state->xclient.helo_name);
|
||||
break;
|
||||
|
||||
/*
|
||||
* Non-selective override. Set all attributes to "unknown". This is
|
||||
* desirable to avoid polluting the audit trail with data from mixed
|
||||
* origins.
|
||||
*/
|
||||
#define FREE_AND_DUP(s,v) { if (s) { myfree(s); s = mystrdup(v); } }
|
||||
|
||||
case XCLIENT_OVER_LOG:
|
||||
FREE_AND_DUP(state->xclient.name, CLIENT_NAME_UNKNOWN);
|
||||
FREE_AND_DUP(state->xclient.addr, CLIENT_ADDR_UNKNOWN);
|
||||
FREE_AND_DUP(state->xclient.namaddr, CLIENT_NAMADDR_UNKNOWN);
|
||||
state->xclient.peer_code = 0;
|
||||
FREE_AND_DUP(state->xclient.protocol, PROTOCOL_UNKNOWN);
|
||||
FREE_AND_DUP(state->xclient.helo_name, HELO_NAME_UNKNOWN);
|
||||
break;
|
||||
}
|
||||
state->xclient.mode = mode;
|
||||
myfree(state->xclient.name);
|
||||
myfree(state->xclient.addr);
|
||||
myfree(state->xclient.namaddr);
|
||||
myfree(state->xclient.protocol);
|
||||
myfree(state->xclient.helo_name);
|
||||
}
|
||||
|
@ -1129,7 +1129,7 @@ typedef int pid_t;
|
||||
* that works as long as off_t is some two's complement number.
|
||||
*/
|
||||
#include <limits.h>
|
||||
#define __MAXINT__(T) ((T) (((T)1 << ((sizeof(T) * CHAR_BIT) - 1) ^ ((T) -1))))
|
||||
#define __MAXINT__(T) ((T) (((((T) 1) << ((sizeof(T) * CHAR_BIT) - 1)) ^ ((T) -1))))
|
||||
#ifndef OFF_T_MAX
|
||||
#define OFF_T_MAX __MAXINT__(off_t)
|
||||
#endif
|
||||
|
Loading…
x
Reference in New Issue
Block a user