2
0
mirror of https://github.com/vdukhovni/postfix synced 2025-08-30 21:55:20 +00:00

postfix-2.0.16-20031130

This commit is contained in:
Wietse Venema
2003-11-30 00:00:00 -05:00
committed by Viktor Dukhovni
parent 196cfcd300
commit edb9945f66
12 changed files with 453 additions and 477 deletions

View File

@@ -11,53 +11,51 @@ the SMTP client hostname, network address, and other information.
2 - Logging after content filter. With Internet->MTA1->filter->MTA2 2 - Logging after content filter. With Internet->MTA1->filter->MTA2
style content filter applications, remote client information is style content filter applications, remote client information is
lost when MTA1 gives the mail to the content filter. This complicates lost when MTA1 gives the mail to the content filter. To simplify
the interpretation of the audit trail. In order maintain audit the interpretation of MTA2 logging, it would help if MTA1 could
trail continuity, MTA1 needs the ability to forward client information forward client information through the content filter to MTA2.
through the content filter to MTA2.
3 - Post-filter access control and logging. With Internet->filter->MTA 3 - Post-filter access control and logging. With Internet->filter->MTA
style content filter applications, the content filter can be greatly style content filter applications, the filter can be simplified if
simplified if it can delegate all decisions concerning mail relay it can delegate decisions concerning mail relay and other access
and other access control to the MTA. This requires that the filter control to the MTA. As in the first example, this requires that
can forward client information to the MTA for access control the filter can override the MTA's idea of the SMTP client hostname,
purposes. network address, and other information.
The preceding suggests that there is a need for two modes of The preceding suggests that there is a need for two functions:
operation:
- Operation mode 1: override the SMTP server's idea of SMTP 1 - Override the MTA's idea of SMTP client information for access
client information for access control and audit trail purposes. control and other purposes. This function is generally useful
Attributes that one may want to override are: for trouble shooting. The implementation can be relatively
straightforward because it updates already existing attributes.
client network address 2 - Forward remote client information for logging purposes. This
client hostname function is limited mainly to environments that use SMTP-based
hostname lookup failure type (permanent or temporary) content filters. The implementation requires more invasive
client protocol (e.g., SMTP or ESMTP) 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 Command overview
trail purposes only. Examples of attributes are: ================
client network address The EHLO keyword associated with this extension is XCLIENT.
client hostname
client protocol (e.g., SMTP or ESMTP)
client SMTP HELO parameter
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 The general command syntax is described below. Upper case and
client information. The general XCLIENT command syntax is described quoted strings specify terminals, lowercase strings specify meta
below. Upper case and quoted strings specify terminals, lowercase terminals, SP is whitespace, and descriptive text is enclosed in
strings specify meta terminals, SP is whitespace, and descriptive {}. Although command and attribute names are shown below in upper
text is in {}. Although shown below in upper case, command and case, they are in fact case insensitive.
attribute names are in fact case insensitive.
xclient-command = XCLIENT *( SP argument ) xclient-command = XCLIENT SP function SP 1*( attribute )
argument = ( request | attribute ) function = ( OVERRIDE | FORWARD )
request = ( RST | ACL | LOG )
attribute = name"="value attribute = name"="value
@@ -67,10 +65,10 @@ attribute names are in fact case insensitive.
xtext = { attribute value encoded as per RFC 1891 } xtext = { attribute value encoded as per RFC 1891 }
The XCLIENT command is typically sent immediately before or after The XCLIENT command can be sent at any time except in the middle
the EHLO command, may be pipelined after the server announces ESMTP of a mail delivery transaction (i.e. between MAIL and DOT). The
pipelining support, and must not be used in the middle of an SMTP command may be pipelined after the server EHLO reply announces
transaction (i.e. between MAIL and DOT). ESMTP pipelining support.
The server reply codes are as follows: The server reply codes are as follows:
@@ -79,96 +77,94 @@ The server reply codes are as follows:
250 | success 250 | success
501 | command syntax error 501 | command syntax error
502 | unrecognized request name 502 | unrecognized request name
503 | command out of order (name=value without prior ACL or LOG request)
421 | unable to proceed 421 | unable to proceed
The server must report success in case of an unrecognized attribute The server must report success in case of an unrecognized attribute
name, although it may log a warning. name, although it may log a warning.
Specific XCLIENT usage scenarios Specific usage scenarios
================================ ========================
This section discusses the semantics of XCLIENT requests. Specific 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 The XCLIENT OVERRIDE request modifies the attributes that the MTA
override of access control or audit trail attributes. Example: 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 XCLIENT OVERRIDE CLIENT_NAME=spike.porcupine.org
before sending surrogate attributes for access control and audit XCLIENT OVERRIDE CLIENT_ADDR=168.100.189.2
trail purposes. Attributes that are not explicitly specified will
default to their actual value. Example:
XCLIENT ACL CLIENT_NAME=spike.porcupine.org The XCLIENT FORWARD request specifies surrogate client attributes for
XCLIENT CLIENT_ADDR=168.100.189.2 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 If only a subset of all possible XCLIENT FORWARD attributes is
none of the other client attributes. 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 The following example updates all forwarded client attributes that
before sending surrogate attributes for audit trail purposes. are defined in this document, leaving none at their default unknown
Attributes that are not explicitly specified will default to the value:
unknown value. Example:
XCLIENT LOG CLIENT_NAME=spike.porcupine.org CLIENT_ADDR=168.100.189.2 XCLIENT FORWARD CLIENT_NAME=spike.porcupine.org CLIENT_ADDR=168.100.189.2
XCLIENT HELO_NAME=spike.porcupine.org PROTOCOL=ESMTP XCLIENT FORWARD HELO_NAME=spike.porcupine.org PROTOCOL=ESMTP
This overrides all client attributes that are defined in this Note 1: attributes specified with successive XCLIENT commands
document, leaving none at their default unknown value. accumulate.
Note 1: it is an error to specify name=value pairs without prior Note 2: XCLIENT FORWARD attributes take precedence over XCLIENT
ACL or LOG request. OVERRIDE attributes.
Note 2: after an ACL or LOG request, attributes specified with Attribute value details
successive XCLIENT commands accumulate until the next RST, ACL or =======================
LOG request.
Note 3: if one XCLIENT command specifies multiple requests (e.g.,
both ACL and LOG), only the last request takes effect.
XCLIENT attribute value details
===============================
Attribute values are encoded as RFC 1891 xtext strings. To explicitly Attribute values are encoded as RFC 1891 xtext strings. To explicitly
specify that an attribute value is unknown, the value must be empty; specify that an attribute value is unknown, the value must be empty;
the client is not allowed to send its own internal representation the client must not send its own internal representation of unknown
for unknown information. information.
CLIENT_CODE specifies CLIENT_NAME hostname lookup status information. CLIENT_CODE specifies CLIENT_NAME hostname lookup status information.
Values are OK (success), TEMP (temporary lookup failure) or PERM Values are OK (success), TEMP (temporary lookup failure) or PERM
(permanent lookup failure). When CLIENT_CODE is set to any value (permanent lookup failure). When CLIENT_CODE is set to any value
other than OK, the CLIENT_NAME attribute is set to the unknown other than OK, the CLIENT_NAME attribute is automatically set to
value. the unknown value.
CLIENT_NAME should specify a syntactically valid domain name and CLIENT_NAME should specify a syntactically valid domain name and
not a numerical address. When a null client name is specified not a numerical address. When a null client name is specified
(i.e. the client name is unknown), the CLIENT_CODE attribute is (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 implicitly set to PERM. When a valid domain name is specified,
set to OK. The server may process a syntactically invalid domain CLIENT_CODE is implicitly set to OK. The server may process a
name as if it were unknown. syntactically invalid domain name as if it were unknown.
CLIENT_ADDR must specify a numerical network address without []. 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 Note 3: syntactically valid CLIENT_NAME and HELO_NAME attributes
can be up to 255 characters long. The client must not send XCLIENT can be up to 255 characters long. The client must not send XCLIENT OVERRIDE
commands that exceed the 512 character limit of SMTP commands. 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 Note 4: attribute values may end up in Received: or other message
headers. The server may substitute any characters that are special headers. The receiving MTA may substitute characters in order to
according to RFC 822 or RFC 2822. not violate RFC 822 or RFC 2822.
Security Security
======== ========
The XCLIENT command changes audit trails and changes client access The XCLIENT command changes audit trails and/or client access
permissions. For these reasons, use of the XCLIENT command must be permissions. For these reasons, use of these commands must be
restricted to authorized clients only. restricted to authorized clients only.
The examples in this document assume that XCLIENT does not override The examples in this document assume that XCLIENT does not override
its own access control mechanism. its own access control mechanism.
@@ -179,7 +175,6 @@ SMTP connection caching
SMTP connection caching makes it possible to deliver multiple SMTP connection caching makes it possible to deliver multiple
messages within the same SMTP session. Thus, one persistent SMTP messages within the same SMTP session. Thus, one persistent SMTP
session with a content filter can carry messages from unrelated session with a content filter can carry messages from unrelated
clients. Attributes from one remote client should not affect the clients. Applications should ensure that XCLIENT information from
delivery of mail from a different remote client. In order to one remote client is properly updated before commencing delivery
prevent such information leakage, use the XCLIENT RST, ACL or LOG of mail from a different remote client.
requests as appropriate.

View File

@@ -151,6 +151,18 @@ extern char *mail_pathname(const char *, const char *);
#define MAIL_ATTR_ORG_NONE "unknown" /* origin unknown */ #define MAIL_ATTR_ORG_NONE "unknown" /* origin unknown */
#define MAIL_ATTR_ORG_LOCAL "local" /* local submission */ #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. * Internal forms for unknown XCLIENT information.
*/ */

View File

@@ -20,7 +20,7 @@
* Patches change the patchlevel and the release date. Snapshots change the * Patches change the patchlevel and the release date. Snapshots change the
* release date only, unless they include the same bugfix as a patch release. * release date only, unless they include the same bugfix as a patch release.
*/ */
#define MAIL_RELEASE_DATE "20031128" #define MAIL_RELEASE_DATE "20031130"
#define VAR_MAIL_VERSION "mail_version" #define VAR_MAIL_VERSION "mail_version"
#define DEF_MAIL_VERSION "2.0.16-" MAIL_RELEASE_DATE #define DEF_MAIL_VERSION "2.0.16-" MAIL_RELEASE_DATE

View File

@@ -385,8 +385,6 @@ int smtp_xfer(SMTP_STATE *state)
int mail_from_rejected; int mail_from_rejected;
int downgrading; int downgrading;
int mime_errs; int mime_errs;
int send_xclient_addr = 0;
int send_xclient_helo = 0;
/* /*
* Macros for readability. * Macros for readability.
@@ -486,21 +484,13 @@ int smtp_xfer(SMTP_STATE *state)
* commands rejected, DATA rejected) it forces the sender to abort the * commands rejected, DATA rejected) it forces the sender to abort the
* SMTP dialog with RSET and QUIT. * SMTP dialog with RSET and QUIT.
* *
* Send "XCLIENT LOG" information only if we have a surrogate remote client * Update the server's remote client information to avoid leakage of past
* name and address, i.e. the mail was actually received from the * client attributes into an unrelated mail delivery.
* network. Since "XCLIENT LOG" overrides all remote client logging
* attributes, there is no need to send helo or protocol information that
* we do not have.
*/ */
nrcpt = 0; nrcpt = 0;
send_xclient_addr = (state->features & SMTP_FEATURE_XCLIENT) if (var_smtp_send_xclient && (state->features & SMTP_FEATURE_XCLIENT))
&& !IS_UNK_CLNT_NAME(request->client_name)
&& !IS_UNK_CLNT_ADDR(request->client_addr);
if (send_xclient_addr) {
send_xclient_helo = !IS_UNK_HELO_NAME(request->client_helo)
|| !IS_UNK_PROTOCOL(request->client_proto);
recv_state = send_state = SMTP_STATE_XCLIENT_ADDR; recv_state = send_state = SMTP_STATE_XCLIENT_ADDR;
} else else
recv_state = send_state = SMTP_STATE_MAIL; recv_state = send_state = SMTP_STATE_MAIL;
next_rcpt = send_rcpt = recv_rcpt = 0; next_rcpt = send_rcpt = recv_rcpt = 0;
mail_from_rejected = 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); msg_panic("%s: bad sender state %d", myname, send_state);
/* /*
* Build the XCLIENT command. Send what we know, converting * Build the XCLIENT command. With properly sanitized
* internal form to external form. With properly sanitized * information, the command length stays within the 512 byte
* information, this stays within the 512 byte command line * command line length limit.
* length limit.
*/ */
case SMTP_STATE_XCLIENT_ADDR: case SMTP_STATE_XCLIENT_ADDR:
vstring_sprintf(next_command, "XCLIENT LOG"); vstring_strcpy(next_command,
if (!IS_UNK_CLNT_NAME(request->client_name)) { XCLIENT_CMD " " XCLIENT_FORWARD " " XCLIENT_NAME "=");
vstring_strcat(next_command, " CLIENT_NAME="); if (!IS_UNK_CLNT_NAME(request->client_name))
xtext_quote_append(next_command, request->client_name, ""); xtext_quote_append(next_command, request->client_name, "");
} vstring_strcat(next_command, " " XCLIENT_ADDR "=");
if (!IS_UNK_CLNT_ADDR(request->client_addr)) { if (!IS_UNK_CLNT_ADDR(request->client_addr))
vstring_strcat(next_command, " CLIENT_ADDR=");
xtext_quote_append(next_command, request->client_addr, ""); xtext_quote_append(next_command, request->client_addr, "");
} next_state = SMTP_STATE_XCLIENT_HELO;
if (send_xclient_helo)
next_state = SMTP_STATE_XCLIENT_HELO;
else
next_state = SMTP_STATE_MAIL;
break; break;
case SMTP_STATE_XCLIENT_HELO: case SMTP_STATE_XCLIENT_HELO:
vstring_sprintf(next_command, "XCLIENT"); vstring_strcpy(next_command,
if (!IS_UNK_HELO_NAME(request->client_helo)) { XCLIENT_CMD " " XCLIENT_FORWARD " " XCLIENT_HELO "=");
vstring_strcat(next_command, " HELO_NAME="); if (!IS_UNK_HELO_NAME(request->client_helo))
xtext_quote_append(next_command, request->client_helo, ""); xtext_quote_append(next_command, request->client_helo, "");
} vstring_strcat(next_command, " " XCLIENT_PROTO "=");
if (!IS_UNK_PROTOCOL(request->client_proto)) { if (!IS_UNK_PROTOCOL(request->client_proto))
vstring_strcat(next_command, " PROTOCOL=");
xtext_quote_append(next_command, request->client_proto, ""); xtext_quote_append(next_command, request->client_proto, "");
}
next_state = SMTP_STATE_MAIL; next_state = SMTP_STATE_MAIL;
break; break;
@@ -684,13 +666,10 @@ int smtp_xfer(SMTP_STATE *state)
switch (recv_state) { switch (recv_state) {
/* /*
* Ignore the XCLIENT response. No Duff device needed. * Process the XCLIENT response.
*/ */
case SMTP_STATE_XCLIENT_ADDR: case SMTP_STATE_XCLIENT_ADDR:
if (send_xclient_helo) recv_state = SMTP_STATE_XCLIENT_HELO;
recv_state = SMTP_STATE_XCLIENT_HELO;
else
recv_state = SMTP_STATE_MAIL;
break; break;
case SMTP_STATE_XCLIENT_HELO: case SMTP_STATE_XCLIENT_HELO:

View File

@@ -410,6 +410,7 @@
#include <errno.h> #include <errno.h>
#include <ctype.h> #include <ctype.h>
#include <signal.h> #include <signal.h>
#include <stddef.h>
#ifdef STRCASECMP_IN_STRINGS_H #ifdef STRCASECMP_IN_STRINGS_H
#include <strings.h> #include <strings.h>
@@ -574,6 +575,7 @@ static NAMADR_LIST *verp_clients;
* XCLIENT command. * XCLIENT command.
*/ */
static NAMADR_LIST *xclient_hosts; static NAMADR_LIST *xclient_hosts;
static int xclient_allowed;
/* /*
* Client connection and rate limiting. * Client connection and rate limiting.
@@ -616,10 +618,10 @@ static int sasl_client_exception(SMTPD_STATE *state)
return (0); return (0);
match = namadr_list_match(sasl_exceptions_networks, match = namadr_list_match(sasl_exceptions_networks,
ACL_NAME(state), ACL_ADDR(state)); state->name, state->addr);
if (msg_verbose) 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); 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); smtpd_chat_reply(state, "250-AUTH=%s", state->sasl_mechanism_list);
} }
#endif #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); smtpd_chat_reply(state, "250-%s", VERP_CMD);
/* XCLIENT must not override its own access control. */ /* 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-%s", XCLIENT_CMD);
smtpd_chat_reply(state, "250 8BITMIME"); smtpd_chat_reply(state, "250 8BITMIME");
return (0); return (0);
@@ -802,7 +804,7 @@ static void mail_open_stream(SMTPD_STATE *state, SMTPD_TOKEN *argv)
smtpd_sasl_mail_log(state); smtpd_sasl_mail_log(state);
else else
#endif #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 * 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) { if (SMTPD_STAND_ALONE(state) == 0) {
rec_fprintf(state->cleanup, REC_TYPE_ATTR, "%s=%s", 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", 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", 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", rec_fprintf(state->cleanup, REC_TYPE_ATTR, "%s=%s",
MAIL_ATTR_HELO_NAME, MAIL_ATTR_HELO_NAME,
IS_UNK_HELO_NAME(LOG_HELO_NAME(state)) ? IS_UNK_HELO_NAME(FORWARD_HELO(state)) ?
HELO_NAME_UNKNOWN : LOG_HELO_NAME(state)); HELO_NAME_UNKNOWN : FORWARD_HELO(state));
rec_fprintf(state->cleanup, REC_TYPE_ATTR, "%s=%s", rec_fprintf(state->cleanup, REC_TYPE_ATTR, "%s=%s",
MAIL_ATTR_PROTO_NAME, LOG_PROTOCOL(state)); MAIL_ATTR_PROTO_NAME, FORWARD_PROTO(state));
} }
if (state->verp_delims) if (state->verp_delims)
rec_fputs(state->cleanup, REC_TYPE_VERP, 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); return (-1);
} }
#endif #endif
} else if (namadr_list_match(verp_clients, ACL_NAME(state), } else if (namadr_list_match(verp_clients, state->name, state->addr)
ACL_ADDR(state))
&& strncasecmp(arg, VERP_CMD, VERP_CMD_LEN) == 0 && strncasecmp(arg, VERP_CMD, VERP_CMD_LEN) == 0
&& (arg[VERP_CMD_LEN] == '=' || arg[VERP_CMD_LEN] == 0)) { && (arg[VERP_CMD_LEN] == '=' || arg[VERP_CMD_LEN] == 0)) {
if (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); 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 */ /* xclient_cmd - process XCLIENT */
static int xclient_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv) 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 *cooked_value;
char *arg_val; char *arg_val;
int update_namaddr = 0; int update_namaddr = 0;
int function;
/* /*
* Sanity checks. The XCLIENT command does not override its own access * Sanity checks. The XCLIENT command does not override its own access
* control. * 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; state->error_mask |= MAIL_ERROR_POLICY;
smtpd_chat_reply(state, "554 Error: insufficient authorization"); smtpd_chat_reply(state, "554 Error: insufficient authorization");
return (-1); return (-1);
} }
#define STREQ(x,y) (strcasecmp((x), (y)) == 0) #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; arg_val = argv[arg_no].strval;
/* /*
* Request name: what should happen with the stored attributes. * Decode the attribute value and for safety's sake mask
* Complain about unrecognized request names. The set of requests is * non-printable characters in the raw and decoded values; we don't
* unlikely to change. * want to handle unexploded munitions. Do not complain about
*/
if ((raw_value = split_at(arg_val, '=')) == 0) {
printable(arg_val, '?');
if (STREQ(arg_val, "RST")) { /* blow them away */
smtpd_xclient_reset(state, XCLIENT_OVER_NONE);
} else if (STREQ(arg_val, "ACL")) { /* access control and logging */
smtpd_xclient_reset(state, XCLIENT_OVER_ACL | XCLIENT_OVER_LOG);
} else if (STREQ(arg_val, "LOG")) { /* logging only */
smtpd_xclient_reset(state, XCLIENT_OVER_LOG);
} else { /* error */
state->error_mask |= MAIL_ERROR_PROTOCOL;
smtpd_chat_reply(state, "501 Bad request: %s", arg_val);
return (-1);
}
}
/*
* NAME=VALUE attribute. Decode the attribute and for safety's sake
* mask non-printable characters in the raw and decoded values; we
* don't want to handle unexploded munitions. Do not complain about
* unrecognized attribute names. The set of attributes may change * unrecognized attribute names. The set of attributes may change
* over time. * over time.
* *
* The client can send multiple XCLIENT attributes in a single command, * The client can send multiple XCLIENT attributes in a single command,
* or multiple XCLIENT commands with fewer attributes. * or multiple XCLIENT commands with fewer attributes.
* *
* Note: XCLIENT ACL overrides only specific logging and access control * Note: XCLIENT OVERRIDE overrides only the specified logging and
* attributes (desirable for testing), while XCLIENT LOG overrides * access control attributes (desirable for testing), while XCLIENT
* all logging attributes (for audit trail consistency). * FORWARD overrides all logging attributes (for audit trail
* consistency).
*/ */
else { if ((raw_value = split_at(arg_val, '=')) == 0) {
if (state->xclient.mode == 0) { state->error_mask |= MAIL_ERROR_PROTOCOL;
state->error_mask |= MAIL_ERROR_PROTOCOL; smtpd_chat_reply(state, "503 Error: name=value expected");
smtpd_chat_reply(state, "503 Error: send %s ACL or LOG first", return (-1);
XCLIENT_CMD); }
return (-1); if (xtext_unquote(state->buffer, raw_value) == 0) {
} state->error_mask |= MAIL_ERROR_PROTOCOL;
if (xtext_unquote(state->buffer, raw_value) == 0) { smtpd_chat_reply(state, "501 Bad attribute value syntax: %s",
state->error_mask |= MAIL_ERROR_PROTOCOL; printable(raw_value, '?'));
smtpd_chat_reply(state, "501 Bad attribute value syntax: %s", return (-1);
printable(raw_value, '?')); }
return (-1); cooked_value = printable(STR(state->buffer), '?');
} (void) printable(raw_value, '?');
cooked_value = printable(STR(state->buffer), '?');
(void) printable(raw_value, '?');
/* /*
* CLIENT_NAME=hostname. Also updates the client hostname lookup * CLIENT_NAME=hostname. Also updates the client hostname lookup
* status code. Treat a numerical hostname as an unavailable * status code. Treat a numerical hostname as an unavailable name.
* name. */
*/ if (STREQ(arg_val, XCLIENT_NAME)) {
if (STREQ(arg_val, "CLIENT_NAME")) { if (*raw_value && !valid_hostaddr(cooked_value, DONT_GRIPE)) {
if (*raw_value && !valid_hostaddr(cooked_value, DONT_GRIPE)) { if (!valid_hostname(cooked_value, DONT_GRIPE)) {
if (!valid_hostname(cooked_value, DONT_GRIPE)) {
state->error_mask |= MAIL_ERROR_PROTOCOL;
smtpd_chat_reply(state, "501 Bad hostname syntax: %s",
cooked_value);
return (-1);
}
UPDATE_STR(state->xclient.name, cooked_value);
state->xclient.peer_code = SMTPD_PEER_CODE_OK;
} else {
UPDATE_STR(state->xclient.name, CLIENT_NAME_UNKNOWN);
state->xclient.peer_code = SMTPD_PEER_CODE_PERM;
}
update_namaddr = 1;
}
/*
* CLIENT_ADDR=client network address.
*/
else if (STREQ(arg_val, "CLIENT_ADDR")) {
if (*raw_value) {
if (!valid_hostaddr(cooked_value, DONT_GRIPE)) {
state->error_mask |= MAIL_ERROR_PROTOCOL;
smtpd_chat_reply(state, "501 Bad address syntax: %s",
cooked_value);
return (-1);
}
UPDATE_STR(state->xclient.addr, cooked_value);
} else {
UPDATE_STR(state->xclient.name, CLIENT_NAME_UNKNOWN);
}
update_namaddr = 1;
}
/*
* CLIENT_CODE=status. Reset the client hostname if the hostname
* lookup status is not OK.
*/
else if (STREQ(arg_val, "CLIENT_CODE")) {
if (STREQ(cooked_value, "OK")) {
state->xclient.peer_code = SMTPD_PEER_CODE_OK;
} else if (STREQ(cooked_value, "TEMP")) {
state->xclient.peer_code = SMTPD_PEER_CODE_TEMP;
UPDATE_STR(state->xclient.name, CLIENT_NAME_UNKNOWN);
update_namaddr = 1;
} else if (STREQ(cooked_value, "PERM")) {
state->xclient.peer_code = SMTPD_PEER_CODE_PERM;
UPDATE_STR(state->xclient.name, CLIENT_NAME_UNKNOWN);
update_namaddr = 1;
} else {
state->error_mask |= MAIL_ERROR_PROTOCOL; 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); cooked_value);
return (-1); 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 * CLIENT_ADDR=client network address.
* not provided by the client and that we must not fall back to */
* the non-XCLIENT value. Disallow characters that could mess up else if (STREQ(arg_val, "CLIENT_ADDR")) {
* our own Received: message headers but allow []. if (*raw_value) {
*/ if (!valid_hostaddr(cooked_value, DONT_GRIPE)) {
else if (STREQ(arg_val, "HELO_NAME")) { state->error_mask |= MAIL_ERROR_PROTOCOL;
if (*raw_value) { smtpd_chat_reply(state, "501 Bad address syntax: %s",
if (strlen(cooked_value) > VALID_HOSTNAME_LEN) { cooked_value);
state->error_mask |= MAIL_ERROR_PROTOCOL; return (-1);
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);
} }
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 * CLIENT_CODE=status. Reset the client hostname if the hostname
* our own Received: message headers. * lookup status is not OK.
*/ */
else if (STREQ(arg_val, "PROTOCOL")) { else if (STREQ(arg_val, "CLIENT_CODE")) {
if (*raw_value) { if (STREQ(cooked_value, "OK")) {
if (*cooked_value == 0 || strlen(cooked_value) > 64) { UPDATE_INT(state, function, peer_code, SMTPD_PEER_CODE_OK);
state->error_mask |= MAIL_ERROR_PROTOCOL; } else if (STREQ(cooked_value, "TEMP")) {
smtpd_chat_reply(state, "501 Bad protocol syntax: %s", UPDATE_INT(state, function, peer_code, SMTPD_PEER_CODE_TEMP);
cooked_value); UPDATE_STR(state, function, name, CLIENT_NAME_UNKNOWN);
return (-1); update_namaddr = 1;
} } else if (STREQ(cooked_value, "PERM")) {
neuter(cooked_value, "[]<>()\\\";:@", '?'); UPDATE_INT(state, function, peer_code, SMTPD_PEER_CODE_PERM);
UPDATE_STR(state->xclient.protocol, cooked_value); UPDATE_STR(state, function, name, CLIENT_NAME_UNKNOWN);
} else { update_namaddr = 1;
UPDATE_STR(state->xclient.protocol, PROTOCOL_UNKNOWN); } 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. * PROTOCOL=protocol name. Disallow characters that could mess up our
* Logging is safe because only authorized clients can issue * own Received: message headers.
* XCLIENT commands. */
*/ else if (STREQ(arg_val, "PROTOCOL")) {
else { if (*raw_value) {
msg_warn("unknown %s attribute from %s: %s=%s", if (*cooked_value == 0 || strlen(cooked_value) > 64) {
XCLIENT_CMD, state->namaddr, arg_val, cooked_value); 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. * 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 (update_namaddr) {
if (state->xclient.namaddr) if (STR_ATTR(state, function, namaddr))
myfree(state->xclient.namaddr); myfree(STR_ATTR(state, function, namaddr));
state->xclient.namaddr = STR_ATTR(state, function, namaddr) =
concatenate(MAYBE_OVERRIDE(state, name), "[", concatenate(STR_ATTR(state, function, name), "[",
MAYBE_OVERRIDE(state, addr), "]", STR_ATTR(state, function, addr), "]",
(char *) 0); (char *) 0);
} }
smtpd_chat_reply(state, "250 Ok"); 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); smtpd_state_init(&state, stream);
msg_info("connect from %s[%s]", state.name, state.addr); 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. * See if we need to turn on verbose logging for this client.
*/ */

View File

@@ -46,7 +46,7 @@ typedef struct SMTPD_DEFER {
} SMTPD_DEFER; } SMTPD_DEFER;
typedef struct SMTPD_XCLIENT_ATTR { typedef struct SMTPD_XCLIENT_ATTR {
int mode; /* none, log, acl */ int used; /* status */
char *name; /* name for access control */ char *name; /* name for access control */
char *addr; /* address for access control */ char *addr; /* address for access control */
char *namaddr; /* name[address] */ 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 * makes no sense to maintain separate attribute sets for XCLIENT LOG or
* XCLIENT ACL, so we set a flag to distinguish purpose. * XCLIENT ACL, so we set a flag to distinguish purpose.
*/ */
#define XCLIENT_CMD "XCLIENT" /* XCLIENT command */ #define SMTPD_FEATURE_XCLIENT (1<<0) /* XCLIENT supported */
#define XCLIENT_EHLO "XCLIENT" /* ESMTP advertisement */
#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 FORWARD_ADDR(s) MAYBE_FORWARD((s), addr)
#define XCLIENT_OVER_ACL (1<<0) /* override access control */ #define FORWARD_NAME(s) MAYBE_FORWARD((s), name)
#define XCLIENT_OVER_LOG (1<<1) /* override logging */ #define FORWARD_NAMADDR(s) MAYBE_FORWARD((s), namaddr)
#define FORWARD_CODE(s) MAYBE_FORWARD((s), peer_code)
#define XCLIENT_OVER(s, m, a) \ #define FORWARD_PROTO(s) MAYBE_FORWARD((s), protocol)
(((s)->xclient.mode & (m)) && (s)->xclient.a ? (s)->xclient.a : (s)->a) #define FORWARD_HELO(s) MAYBE_FORWARD((s), helo_name)
#define ACL_ADDR(s) XCLIENT_OVER((s), XCLIENT_OVER_ACL, addr)
#define ACL_NAME(s) XCLIENT_OVER((s), XCLIENT_OVER_ACL, name)
#define ACL_NAMADDR(s) XCLIENT_OVER((s), XCLIENT_OVER_ACL, namaddr)
#define ACL_PEER_CODE(s) XCLIENT_OVER((s), XCLIENT_OVER_ACL, peer_code)
#define ACL_PROTOCOL(s) XCLIENT_OVER((s), XCLIENT_OVER_ACL, protocol)
#define ACL_HELO_NAME(s) XCLIENT_OVER((s), XCLIENT_OVER_ACL, helo_name)
#define LOG_ADDR(s) XCLIENT_OVER((s), XCLIENT_OVER_LOG, addr)
#define LOG_NAME(s) XCLIENT_OVER((s), XCLIENT_OVER_LOG, name)
#define LOG_NAMADDR(s) XCLIENT_OVER((s), XCLIENT_OVER_LOG, namaddr)
#define LOG_PEER_CODE(s) XCLIENT_OVER((s), XCLIENT_OVER_LOG, peer_code)
#define LOG_PROTOCOL(s) XCLIENT_OVER((s), XCLIENT_OVER_LOG, protocol)
#define LOG_HELO_NAME(s) XCLIENT_OVER((s), XCLIENT_OVER_LOG, helo_name)
extern void smtpd_xclient_init(SMTPD_STATE *state); extern void smtpd_xclient_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, * Transparency: before mail is queued, do we check for unknown recipients,

View File

@@ -809,15 +809,15 @@ static void log_whatsup(SMTPD_STATE *state, const char *whatsup,
vstring_sprintf(buf, "%s: %s: %s from %s: %s;", vstring_sprintf(buf, "%s: %s: %s from %s: %s;",
state->queue_id ? state->queue_id : "NOQUEUE", state->queue_id ? state->queue_id : "NOQUEUE",
whatsup, state->where, LOG_NAMADDR(state), text); whatsup, state->where, state->namaddr, text);
if (state->sender) if (state->sender)
vstring_sprintf_append(buf, " from=<%s>", state->sender); vstring_sprintf_append(buf, " from=<%s>", state->sender);
if (state->recipient) if (state->recipient)
vstring_sprintf_append(buf, " to=<%s>", state->recipient); vstring_sprintf_append(buf, " to=<%s>", state->recipient);
if (!IS_UNK_PROTOCOL(ACL_PROTOCOL(state))) if (state->protocol)
vstring_sprintf_append(buf, " proto=%s", ACL_PROTOCOL(state)); vstring_sprintf_append(buf, " proto=%s", state->protocol);
if (!IS_UNK_HELO_NAME(ACL_HELO_NAME(state))) if (state->helo_name)
vstring_sprintf_append(buf, " helo=<%s>", ACL_HELO_NAME(state)); vstring_sprintf_append(buf, " helo=<%s>", state->helo_name);
msg_info("%s", STR(buf)); msg_info("%s", STR(buf));
vstring_free(buf); vstring_free(buf);
} }
@@ -968,14 +968,14 @@ static int reject_unknown_client(SMTPD_STATE *state)
char *myname = "reject_unknown_client"; char *myname = "reject_unknown_client";
if (msg_verbose) 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, return (smtpd_check_reject(state, MAIL_ERROR_POLICY,
"%d Client host rejected: cannot find your hostname, [%s]", "%d Client host rejected: cannot find your hostname, [%s]",
ACL_PEER_CODE(state) == SMTPD_PEER_CODE_PERM ? state->peer_code == SMTPD_PEER_CODE_PERM ?
var_unk_client_code : 450, var_unk_client_code : 450,
ACL_ADDR(state))); state->addr));
return (SMTPD_CHECK_DUNNO); return (SMTPD_CHECK_DUNNO);
} }
@@ -986,9 +986,9 @@ static int permit_mynetworks(SMTPD_STATE *state)
char *myname = "permit_mynetworks"; char *myname = "permit_mynetworks";
if (msg_verbose) 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_OK);
return (SMTPD_CHECK_DUNNO); 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. * 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); return (SMTPD_CHECK_OK);
/* /*
@@ -1309,7 +1309,7 @@ static int reject_unauth_pipelining(SMTPD_STATE *state,
if (state->client != 0 if (state->client != 0
&& SMTPD_STAND_ALONE(state) == 0 && SMTPD_STAND_ALONE(state) == 0
&& vstream_peek(state->client) > 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)) { || strcasecmp(state->where, "DATA") == 0)) {
return (smtpd_check_reject(state, MAIL_ERROR_PROTOCOL, return (smtpd_check_reject(state, MAIL_ERROR_PROTOCOL,
"503 <%s>: %s rejected: Improper use of SMTP command pipelining", "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. * Return NULL only for non-existent names.
*/ */
if (STREQ(name, MAIL_ATTR_CLIENT)) { if (STREQ(name, MAIL_ATTR_CLIENT)) {
return (ACL_NAMADDR(state)); return (state->namaddr);
} else if (STREQ(name, MAIL_ATTR_CLIENT_ADDR)) { } else if (STREQ(name, MAIL_ATTR_CLIENT_ADDR)) {
return (ACL_ADDR(state)); return (state->addr);
} else if (STREQ(name, MAIL_ATTR_CLIENT_NAME)) { } else if (STREQ(name, MAIL_ATTR_CLIENT_NAME)) {
return (ACL_NAME(state)); return (state->name);
} else if (STREQ(name, MAIL_ATTR_HELO_NAME)) { } else if (STREQ(name, MAIL_ATTR_HELO_NAME)) {
return (IS_UNK_HELO_NAME(ACL_HELO_NAME(state)) ? return (state->helo_name ? state->helo_name : "");
"" : ACL_HELO_NAME(state));
} else if (STREQN(name, MAIL_ATTR_SENDER, CONST_LEN(MAIL_ATTR_SENDER))) { } else if (STREQN(name, MAIL_ATTR_SENDER, CONST_LEN(MAIL_ATTR_SENDER))) {
return (smtpd_expand_addr(state->expand_buf, state->sender, return (smtpd_expand_addr(state->expand_buf, state->sender,
name, CONST_LEN(MAIL_ATTR_SENDER))); name, CONST_LEN(MAIL_ATTR_SENDER)));
@@ -2821,7 +2820,7 @@ static int reject_maps_rbl(SMTPD_STATE *state)
static int warned; static int warned;
if (msg_verbose) if (msg_verbose)
msg_info("%s: %s", myname, ACL_ADDR(state)); msg_info("%s: %s", myname, state->addr);
if (warned == 0) { if (warned == 0) {
warned++; warned++;
@@ -2830,7 +2829,7 @@ static int reject_maps_rbl(SMTPD_STATE *state)
REJECT_MAPS_RBL, var_mail_name, REJECT_RBL_CLIENT); REJECT_MAPS_RBL, var_mail_name, REJECT_RBL_CLIENT);
} }
while ((rbl_domain = mystrtok(&bp, " \t\r\n,")) != 0) { 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); SMTPD_NAME_CLIENT);
if (result != SMTPD_CHECK_DUNNO) if (result != SMTPD_CHECK_DUNNO)
break; break;
@@ -2907,12 +2906,11 @@ static int check_policy_service(SMTPD_STATE *state, const char *server,
ATTR_FLAG_NONE, /* Query attributes. */ ATTR_FLAG_NONE, /* Query attributes. */
ATTR_TYPE_STR, MAIL_ATTR_REQ, "smtpd_access_policy", ATTR_TYPE_STR, MAIL_ATTR_REQ, "smtpd_access_policy",
ATTR_TYPE_STR, MAIL_ATTR_PROTO_STATE, state->where, ATTR_TYPE_STR, MAIL_ATTR_PROTO_STATE, state->where,
ATTR_TYPE_STR, MAIL_ATTR_PROTO_NAME, ACL_PROTOCOL(state), ATTR_TYPE_STR, MAIL_ATTR_PROTO_NAME, state->protocol,
ATTR_TYPE_STR, MAIL_ATTR_CLIENT_ADDR, ACL_ADDR(state), ATTR_TYPE_STR, MAIL_ATTR_CLIENT_ADDR, state->addr,
ATTR_TYPE_STR, MAIL_ATTR_CLIENT_NAME, ACL_NAME(state), ATTR_TYPE_STR, MAIL_ATTR_CLIENT_NAME, state->name,
ATTR_TYPE_STR, MAIL_ATTR_HELO_NAME, ATTR_TYPE_STR, MAIL_ATTR_HELO_NAME,
IS_UNK_HELO_NAME(ACL_HELO_NAME(state)) ? state->helo_name ? state->helo_name : "",
"" : ACL_HELO_NAME(state),
ATTR_TYPE_STR, MAIL_ATTR_SENDER, ATTR_TYPE_STR, MAIL_ATTR_SENDER,
state->sender ? state->sender : "", state->sender ? state->sender : "",
ATTR_TYPE_STR, MAIL_ATTR_RECIP, 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) { } else if (strcasecmp(name, PERMIT_MYNETWORKS) == 0) {
status = permit_mynetworks(state); status = permit_mynetworks(state);
} else if (is_map_command(state, name, CHECK_CLIENT_ACL, &cpp)) { } else if (is_map_command(state, name, CHECK_CLIENT_ACL, &cpp)) {
status = check_namadr_access(state, *cpp, ACL_NAME(state), ACL_ADDR(state), status = check_namadr_access(state, *cpp, state->name, state->addr,
FULL, &found, ACL_NAMADDR(state), FULL, &found, state->namaddr,
SMTPD_NAME_CLIENT, def_acl); SMTPD_NAME_CLIENT, def_acl);
} else if (strcasecmp(name, REJECT_MAPS_RBL) == 0) { } else if (strcasecmp(name, REJECT_MAPS_RBL) == 0) {
status = reject_maps_rbl(state); status = reject_maps_rbl(state);
@@ -3087,7 +3085,7 @@ static int generic_checks(SMTPD_STATE *state, ARGV *restrictions,
if (cpp[1] == 0) if (cpp[1] == 0)
msg_warn("restriction %s requires domain name argument", name); msg_warn("restriction %s requires domain name argument", name);
else else
status = reject_rbl_addr(state, *(cpp += 1), ACL_ADDR(state), status = reject_rbl_addr(state, *(cpp += 1), state->addr,
SMTPD_NAME_CLIENT); SMTPD_NAME_CLIENT);
} else if (strcasecmp(name, REJECT_RHSBL_CLIENT) == 0) { } else if (strcasecmp(name, REJECT_RHSBL_CLIENT) == 0) {
if (cpp[1] == 0) if (cpp[1] == 0)
@@ -3095,73 +3093,69 @@ static int generic_checks(SMTPD_STATE *state, ARGV *restrictions,
name); name);
else { else {
cpp += 1; cpp += 1;
if (!IS_UNK_CLNT_NAME(ACL_NAME(state))) if (!IS_UNK_CLNT_NAME(state->name))
status = reject_rbl_domain(state, *cpp, ACL_NAME(state), status = reject_rbl_domain(state, *cpp, state->name,
SMTPD_NAME_CLIENT); SMTPD_NAME_CLIENT);
} }
} }
/* /*
* HELO/EHLO parameter restrictions. * 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)) { else if (is_map_command(state, name, CHECK_HELO_ACL, &cpp)) {
if (!IS_UNK_HELO_NAME(ACL_HELO_NAME(state))) if (state->helo_name)
status = check_domain_access(state, *cpp, ACL_HELO_NAME(state), status = check_domain_access(state, *cpp, state->helo_name,
FULL, &found, ACL_HELO_NAME(state), FULL, &found, state->helo_name,
SMTPD_NAME_HELO, def_acl); SMTPD_NAME_HELO, def_acl);
} else if (strcasecmp(name, REJECT_INVALID_HOSTNAME) == 0) { } else if (strcasecmp(name, REJECT_INVALID_HOSTNAME) == 0) {
if (!IS_UNK_HELO_NAME(ACL_HELO_NAME(state))) { if (state->helo_name) {
if (*ACL_HELO_NAME(state) != '[') if (*state->helo_name != '[')
status = reject_invalid_hostname(state, ACL_HELO_NAME(state), status = reject_invalid_hostname(state, state->helo_name,
ACL_HELO_NAME(state), SMTPD_NAME_HELO); state->helo_name, SMTPD_NAME_HELO);
else else
status = reject_invalid_hostaddr(state, ACL_HELO_NAME(state), status = reject_invalid_hostaddr(state, state->helo_name,
ACL_HELO_NAME(state), SMTPD_NAME_HELO); state->helo_name, SMTPD_NAME_HELO);
} }
} else if (strcasecmp(name, REJECT_UNKNOWN_HOSTNAME) == 0) { } else if (strcasecmp(name, REJECT_UNKNOWN_HOSTNAME) == 0) {
if (!IS_UNK_HELO_NAME(ACL_HELO_NAME(state))) { if (state->helo_name) {
if (*ACL_HELO_NAME(state) != '[') if (*state->helo_name != '[')
status = reject_unknown_hostname(state, ACL_HELO_NAME(state), status = reject_unknown_hostname(state, state->helo_name,
ACL_HELO_NAME(state), SMTPD_NAME_HELO); state->helo_name, SMTPD_NAME_HELO);
else else
status = reject_invalid_hostaddr(state, ACL_HELO_NAME(state), status = reject_invalid_hostaddr(state, state->helo_name,
ACL_HELO_NAME(state), SMTPD_NAME_HELO); state->helo_name, SMTPD_NAME_HELO);
} }
} else if (strcasecmp(name, PERMIT_NAKED_IP_ADDR) == 0) { } else if (strcasecmp(name, PERMIT_NAKED_IP_ADDR) == 0) {
msg_warn("restriction %s is deprecated. Use %s instead", msg_warn("restriction %s is deprecated. Use %s instead",
PERMIT_NAKED_IP_ADDR, PERMIT_MYNETWORKS); PERMIT_NAKED_IP_ADDR, PERMIT_MYNETWORKS);
if (!IS_UNK_HELO_NAME(ACL_HELO_NAME(state))) { if (state->helo_name) {
if (ACL_HELO_NAME(state)[strspn(ACL_HELO_NAME(state), "0123456789.")] == 0 if (state->helo_name[strspn(state->helo_name, "0123456789.")] == 0
&& (status = reject_invalid_hostaddr(state, ACL_HELO_NAME(state), && (status = reject_invalid_hostaddr(state, state->helo_name,
ACL_HELO_NAME(state), SMTPD_NAME_HELO)) == 0) state->helo_name, SMTPD_NAME_HELO)) == 0)
status = SMTPD_CHECK_OK; status = SMTPD_CHECK_OK;
} }
} else if (is_map_command(state, name, CHECK_HELO_NS_ACL, &cpp)) { } else if (is_map_command(state, name, CHECK_HELO_NS_ACL, &cpp)) {
if (!IS_UNK_HELO_NAME(ACL_HELO_NAME(state))) { if (state->helo_name) {
status = check_server_access(state, *cpp, ACL_HELO_NAME(state), status = check_server_access(state, *cpp, state->helo_name,
T_NS, ACL_HELO_NAME(state), T_NS, state->helo_name,
SMTPD_NAME_HELO, def_acl); 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)) { } else if (is_map_command(state, name, CHECK_HELO_MX_ACL, &cpp)) {
if (!IS_UNK_HELO_NAME(ACL_HELO_NAME(state))) { if (state->helo_name) {
status = check_server_access(state, *cpp, ACL_HELO_NAME(state), status = check_server_access(state, *cpp, state->helo_name,
T_MX, ACL_HELO_NAME(state), T_MX, state->helo_name,
SMTPD_NAME_HELO, def_acl); 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) { } else if (strcasecmp(name, REJECT_NON_FQDN_HOSTNAME) == 0) {
if (!IS_UNK_HELO_NAME(ACL_HELO_NAME(state))) { if (state->helo_name) {
if (*ACL_HELO_NAME(state) != '[') if (*state->helo_name != '[')
status = reject_non_fqdn_hostname(state, ACL_HELO_NAME(state), status = reject_non_fqdn_hostname(state, state->helo_name,
ACL_HELO_NAME(state), SMTPD_NAME_HELO); state->helo_name, SMTPD_NAME_HELO);
else else
status = reject_invalid_hostaddr(state, ACL_HELO_NAME(state), status = reject_invalid_hostaddr(state, state->helo_name,
ACL_HELO_NAME(state), SMTPD_NAME_HELO); state->helo_name, SMTPD_NAME_HELO);
} }
} else if (strcasecmp(name, REJECT_RHSBL_HELO) == 0) { } else if (strcasecmp(name, REJECT_RHSBL_HELO) == 0) {
if (cpp[1] == 0) if (cpp[1] == 0)
@@ -3169,8 +3163,8 @@ static int generic_checks(SMTPD_STATE *state, ARGV *restrictions,
name); name);
else { else {
cpp += 1; cpp += 1;
if (!IS_UNK_HELO_NAME(ACL_HELO_NAME(state))) if (state->helo_name)
status = reject_rbl_domain(state, *cpp, ACL_HELO_NAME(state), status = reject_rbl_domain(state, *cpp, state->helo_name,
SMTPD_NAME_HELO); SMTPD_NAME_HELO);
} }
} }
@@ -3367,7 +3361,7 @@ char *smtpd_check_client(SMTPD_STATE *state)
/* /*
* Initialize. * Initialize.
*/ */
if (ACL_NAME(state) == 0 || ACL_ADDR(state) == 0) if (state->name == 0 || state->addr == 0)
return (0); return (0);
#define SMTPD_CHECK_RESET() { \ #define SMTPD_CHECK_RESET() { \
@@ -3387,7 +3381,7 @@ char *smtpd_check_client(SMTPD_STATE *state)
SMTPD_CHECK_RESET(); SMTPD_CHECK_RESET();
status = setjmp(smtpd_check_buf); status = setjmp(smtpd_check_buf);
if (status == 0 && client_restrctions->argc) 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); SMTPD_NAME_CLIENT, CHECK_CLIENT_ACL);
state->defer_if_permit_client = state->defer_if_permit.active; 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(); SMTPD_CHECK_RESET();
status = setjmp(smtpd_check_buf); status = setjmp(smtpd_check_buf);
if (status == 0 && helo_restrctions->argc) 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); SMTPD_NAME_HELO, CHECK_HELO_ACL);
state->defer_if_permit_helo = state->defer_if_permit.active; 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 (var_smtpd_delay_reject)
if ((err = smtpd_check_client(state)) != 0 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) || (err = smtpd_check_mail(state, state->sender)) != 0)
SMTPD_CHECK_RCPT_RETURN(err); SMTPD_CHECK_RCPT_RETURN(err);
@@ -3622,7 +3616,7 @@ char *smtpd_check_etrn(SMTPD_STATE *state, char *domain)
*/ */
if (var_smtpd_delay_reject) if (var_smtpd_delay_reject)
if ((err = smtpd_check_client(state)) != 0 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); SMTPD_CHECK_ETRN_RETURN(err);
/* /*

View File

@@ -241,29 +241,31 @@ int smtpd_proxy_open(SMTPD_STATE *state, const char *service,
while ((line = mystrtok(&lines, "\n")) != 0) while ((line = mystrtok(&lines, "\n")) != 0)
if (ISDIGIT(line[0]) && ISDIGIT(line[1]) && ISDIGIT(line[2]) if (ISDIGIT(line[0]) && ISDIGIT(line[1]) && ISDIGIT(line[2])
&& (line[3] == ' ' || line[3] == '-') && (line[3] == ' ' || line[3] == '-')
&& strcmp(line + 4, XCLIENT_EHLO) == 0) && strcmp(line + 4, XCLIENT_CMD) == 0)
state->proxy_features |= SMTPD_FEATURE_XCLIENT; 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. * forms and encode the result as xtext.
*/ */
if (state->proxy_features & SMTPD_FEATURE_XCLIENT) { if (state->proxy_features & SMTPD_FEATURE_XCLIENT) {
buf = vstring_alloc(100); buf = vstring_alloc(100);
vstring_sprintf(buf, "%s LOG CLIENT_NAME=", XCLIENT_CMD); vstring_strcpy(buf, XCLIENT_CMD " " XCLIENT_FORWARD
if (!IS_UNK_CLNT_NAME(LOG_NAME(state))) " " XCLIENT_NAME "=");
xtext_quote_append(buf, LOG_NAME(state), ""); if (!IS_UNK_CLNT_NAME(FORWARD_NAME(state)))
vstring_strcat(buf, " CLIENT_ADDR="); xtext_quote_append(buf, FORWARD_NAME(state), "");
if (!IS_UNK_CLNT_ADDR(LOG_ADDR(state))) vstring_strcat(buf, " " XCLIENT_ADDR "=");
xtext_quote_append(buf, LOG_ADDR(state), ""); 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)); bad = smtpd_proxy_cmd(state, SMTPD_PROX_WANT_ANY, "%s", STR(buf));
if (bad == 0) { if (bad == 0) {
vstring_sprintf(buf, "%s HELO_NAME=", XCLIENT_CMD); vstring_strcpy(buf, XCLIENT_CMD " " XCLIENT_FORWARD
if (!IS_UNK_HELO_NAME(LOG_HELO_NAME(state))) " " XCLIENT_HELO "=");
xtext_quote_append(buf, LOG_HELO_NAME(state), ""); if (!IS_UNK_HELO_NAME(FORWARD_HELO(state)))
vstring_strcat(buf, " PROTOCOL="); xtext_quote_append(buf, FORWARD_HELO(state), "");
if (!IS_UNK_PROTOCOL(LOG_PROTOCOL(state))) vstring_strcat(buf, " " XCLIENT_PROTO "=");
xtext_quote_append(buf, LOG_PROTOCOL(state), ""); 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)); bad = smtpd_proxy_cmd(state, SMTPD_PROX_WANT_ANY, "%s", STR(buf));
} }
vstring_free(buf); vstring_free(buf);

View File

@@ -198,7 +198,7 @@ void smtpd_sasl_mail_log(SMTPD_STATE *state)
#define IFELSE(e1,e2,e3) ((e1) ? (e2) : (e3)) #define IFELSE(e1,e2,e3) ((e1) ? (e2) : (e3))
msg_info("%s: client=%s%s%s%s%s%s%s", 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, ", sasl_method=", ""),
IFELSE(state->sasl_method, state->sasl_method, ""), IFELSE(state->sasl_method, state->sasl_method, ""),
IFELSE(state->sasl_username, ", sasl_username=", ""), IFELSE(state->sasl_username, ", sasl_username=", ""),

View File

@@ -141,7 +141,7 @@ void smtpd_state_reset(SMTPD_STATE *state)
if (state->buffer) if (state->buffer)
vstring_free(state->buffer); vstring_free(state->buffer);
smtpd_peer_reset(state); smtpd_peer_reset(state);
smtpd_xclient_reset(state, XCLIENT_OVER_NONE); smtpd_xclient_reset(state);
if (state->defer_if_permit.reason) if (state->defer_if_permit.reason)
vstring_free(state->defer_if_permit.reason); vstring_free(state->defer_if_permit.reason);
if (state->defer_if_reject.reason) if (state->defer_if_reject.reason)

View File

@@ -9,9 +9,8 @@
/* void smtpd_xclient_init(state) /* void smtpd_xclient_init(state)
/* SMTPD_STATE *state; /* SMTPD_STATE *state;
/* /*
/* void smtpd_xclient_reset(state, mode) /* void smtpd_xclient_reset(state)
/* SMTPD_STATE *state; /* SMTPD_STATE *state;
/* int mode;
/* DESCRIPTION /* DESCRIPTION
/* smtpd_xclient_init() initializes state variables that are /* smtpd_xclient_init() initializes state variables that are
/* used for storage of XCLIENT command parameters. /* used for storage of XCLIENT command parameters.
@@ -19,14 +18,7 @@
/* structure for access control or logging purposes. /* structure for access control or logging purposes.
/* /*
/* smtpd_xclient_reset() releases memory allocated after the return /* smtpd_xclient_reset() releases memory allocated after the return
/* from smtpd_xclient_init() and optionally presets the state variables /* from smtpd_xclient_init().
/* to defaults that are suitable for the specified mode:
/* .IP XCLIENT_OVER_NONE
/* This should be used after the XCLIENT RST request.
/* .IP XCLIENT_OVER_ACL|XCLIENT_OVER_LOG
/* This should be used after the XCLIENT ACL request.
/* .IP XCLIENT_OVER_LOG
/* This should be used after the XCLIENT LOG request.
/* LICENSE /* LICENSE
/* .ad /* .ad
/* .fi /* .fi
@@ -59,58 +51,22 @@
void smtpd_xclient_init(SMTPD_STATE *state) void smtpd_xclient_init(SMTPD_STATE *state)
{ {
state->xclient.mode = 0; state->xclient.used = 0;
state->xclient.name = 0; state->xclient.name = mystrdup(CLIENT_NAME_UNKNOWN);
state->xclient.addr = 0; state->xclient.addr = mystrdup(CLIENT_ADDR_UNKNOWN);
state->xclient.namaddr = 0; state->xclient.namaddr = mystrdup(CLIENT_NAMADDR_UNKNOWN);
state->xclient.peer_code = 0; state->xclient.peer_code = 0;
state->xclient.protocol = 0; state->xclient.protocol = mystrdup(PROTOCOL_UNKNOWN);
state->xclient.helo_name = 0; state->xclient.helo_name = mystrdup(HELO_NAME_UNKNOWN);
} }
/* smtpd_xclient_reset - reset XCLIENT attributes */ /* smtpd_xclient_reset - reset XCLIENT attributes */
void smtpd_xclient_reset(SMTPD_STATE *state, int mode) void smtpd_xclient_reset(SMTPD_STATE *state)
{ {
switch (mode) { myfree(state->xclient.name);
myfree(state->xclient.addr);
/* myfree(state->xclient.namaddr);
* Can't happen. myfree(state->xclient.protocol);
*/ myfree(state->xclient.helo_name);
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;
} }

View File

@@ -1129,7 +1129,7 @@ typedef int pid_t;
* that works as long as off_t is some two's complement number. * that works as long as off_t is some two's complement number.
*/ */
#include <limits.h> #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 #ifndef OFF_T_MAX
#define OFF_T_MAX __MAXINT__(off_t) #define OFF_T_MAX __MAXINT__(off_t)
#endif #endif