-TSMTPD_RBL_STATE
-TSMTPD_STATE
-TSMTPD_TOKEN
--TSMTPD_XCLIENT_ATTR
+-TSMTPD_XFORWARD_ATTR
-TSMTP_ADDR
-TSMTP_CMD
-TSMTP_RESP
20031212
Cleanup: separate extensions XCLIENT (impersonate SMTP
- client) and XFORWARD (down-stream logging of up-stream
- session information, not necessarily SMTP related). The
- protocol is extensible: the server advertises what attributes
- XCLIENT or XFORWARD will accept. The requirement for xtext
- encoding is dropped as no attribute currently needs it.
- All errors are reported by the server and are logged by
- the client. See also: XCLIENT_README and XFORWARD_README.
+ client) and XFORWARD (down-stream logging of up-stream MTA
+ and/or message information, not necessarily SMTP related).
+ The protocol is extensible: the server advertises what
+ attributes XCLIENT or XFORWARD will accept, and it is an
+ error to send an unsupported attribute. No xtext encoding
+ is used, since no attribute currently needs it. See also:
+ XCLIENT_README and XFORWARD_README.
20031214
- Feature: XCLIENT and XFORWARD support in the LMTP client.
+ Feature: XFORWARD support in the LMTP client.
+
+20031215
+
+ Safety: updated mail_queue_id_ok() for long fast flush
+ logfile names. File: global/mail_queue.c.
+
+ Robustness: save and restore the resolver _res.options
+ settings before and after DNS lookup, to avoid surprises
+ in third-party code. File: dns/dns_lookup.c.
Open problems:
2 - Client software that downloads mail from an up-stream mail
server and injects it into a local MTA via SMTP. In order to take
-advantage of the local MTA's access rules, the client software
-needs the ability to override the SMTP server's idea of the remote
-client name, client address and other information. Such information
-can typically be extracted from the up-stream mail server's Received:
-message header.
+advantage of the local MTA's SMTP server access rules, the client
+software needs the ability to override the SMTP server's idea of
+the remote client name, client address and other information. Such
+information can typically be extracted from the up-stream mail
+server's Received: message header.
3 - Post-filter access control and logging. With Internet->filter->MTA
style content filter applications, the filter can be simplified if
terminals, and SP is whitespace. Although command and attribute
names are shown in upper case, they are in fact case insensitive.
- xclient-command = XCLIENT 1*( SP attribute )
-
- attribute = name"="value
+ xclient-command = XCLIENT 1*( SP name"="value )
name = ( NAME | ADDR | PROTO | HELO )
421 | unable to proceed
The NAME attribute specifies an SMTP client hostname (not an SMTP
-client address), [unavailable] when client hostname lookup failed
-due to a permanent error, or [temporary] when the lookup error
+client address), [UNAVAILABLE] when client hostname lookup failed
+due to a permanent error, or [TEMPUNAVAIL] when the lookup error
condition was transient.
The ADDR attribute specifies an SMTP client numerical IPv4 network
-address, an IPv6 address prefixed with IPV6:, or [unavailable]
+address, an IPv6 address prefixed with IPV6:, or [UNAVAILABLE]
when the address information is unavailable. Address information
is not enclosed with [].
The PROTO attribute specifies either SMTP or ESMTP.
The HELO attribute specifies a HELO parameter value, or the value
-[unavailable] when the information is unavailable.
+[UNAVAILABLE] when the information is unavailable.
Note 1: syntactically valid NAME and HELO attributes can be up to
255 characters long. The client must not send XCLIENT commands that
exceed the 512 character limit for SMTP commands.
-Note 2: [UNAVAILABLE], [TEMPORARY] and IPV6: may be specified in
+Note 2: [UNAVAILABLE], [TEMPUNAVAIL] and IPV6: may be specified in
upper case, lower case or mixed case.
Security
=======================
SMTP connection caching makes it possible to deliver multiple
-messages within the same SMTP session. The XCLIENT attributes are
-persistent across deliveries, and need to be reset as appropriate
-in order to avoid information leakage.
+messages within the same SMTP session. The XCLIENT attributes are
+persistent across an SMTP session, and need to be reset as appropriate
+in between deliveries.
content filter to MTA2, so that the information could be logged as
part of mail handling transactions.
+This extension is implemented as a separate command, so that it
+can be used to transmit client or message attributes incrementally.
+It is not implemented by passing additional parameters via the MAIL
+FROM command, because doing so would require extending the MAIL
+FROM command length limit by another 600 or more characters beyond.
+
Command syntax
==============
terminals, and SP is whitespace. Although command and attribute
names are shown in upper case, they are in fact case insensitive.
- xclient-command = XFORWARD 1*( SP attribute )
-
- attribute = name"="value
+ xforward-command = XFORWARD 1*( SP name"="value )
name = ( NAME | ADDR | PROTO | HELO | IDENT )
503 | mail transaction in progress
421 | unable to proceed
-The information specified with XFORWARD attribues is not limited
+The information specified with XFORWARD attributes is not limited
to DNS hostnames, IP addresses or SMTP protocol names. Attribute
-values may contain arbitrary text, but must not contain control
-characters, non-ASCII characters, whitespace, or other characters
-that are special in message headers.
+values may contain arbitrary text, must not be longer than 255
+characters (specific attributes may imposer shorter lengths), must
+not contain control characters, non-ASCII characters, whitespace,
+or other characters that are special in message headers.
-The NAME attribute specifies an up-stream client hostname, or
-[UNAVAILABLE] when the information is unavailable. The hostname
-may be a non-DNS hostname.
+The NAME attribute specifies the up-stream hostname, or [UNAVAILABLE]
+when the information is unavailable. The hostname may be a non-DNS
+hostname.
-The ADDR attribute specifies an up-stream client network address,
-or [UNAVAILABLE] when the information is unavailable. Address
+The ADDR attribute specifies the up-stream network address, or
+[UNAVAILABLE] when the information is unavailable. Address
information is not enclosed with []. The address may be a non-IP
address.
-The PROTO attribute specifies the mail protocol that was used by
-the up-stream client. This may be an SMTP non-SMTP protocol name
+The PROTO attribute specifies the mail protocol for receiving mail
+from the up-stream host. This may be an SMTP non-SMTP protocol name
of up to 64 characters, or [UNAVAILABLE] when the information is
unavailable.
-The HELO attribute specifies the hostname that the up-stream client
-host introduced itself with (for example, via the SMTP HELO command),
+The HELO attribute specifies the hostname that the up-stream host
+announced itself with (not necessarily via the SMTP HELO command),
or [UNAVAILABLE] when the information is unavailable. The hostname
may be a non-DNS hostname.
===============================================================
WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING
===============================================================
-The XCLIENT feature for content filter logging is still changing
-and the design details have already changed again.
-
The sender/recipient address verification code is lightly documented
and has been tested lightly. The code is proof-of-concept quality
and must not be used on high-volume sites. Use at your own risk.
date. Snapshots change only the release date, unless they include
the same bugfixes as a patch release.
+Incompatible changes with Postfix snapshot 2.0.16-20031215
+==========================================================
+
+XCLIENT is approaching completion.
+
+Major changes with Postfix snapshot 2.0.16-20031215
+===================================================
+
+The XCLIENT extension to SMTP implements SMTP client impersonation
+for SMTP server access rule testing. Send "xclient name=xxx addr=yyy"
+in SMTP sessions and pretend that you are connecting as the specified
+client. More details are in the XCLIENT_README file.
+
+The XFORWARD extension to SMTP forwards up-stream MTA information
+(and in the future, message identifying information) to improve
+the logging by down-stream mail software. Send "xclient name=xxx
+addr=yyy proto=aaa helo=bbb" to specify the original SMTP client
+information that should be recorded with the next MAIL FROM
+transaction. More details are in the XFORWARD_README file.
+
+The reject_sender_login_mismatch feature is now implemented in
+terms of more basic restrictions: reject_unauth_sender_login_mismatch
+(reject mail when $sender_login_maps lists an owner for the sender
+address but the SMTP client is not SASL authenticated) and
+reject_auth_sender_login_mismatch (reject mail when the sender
+address is not owned by the SASL authenticated user). The
+sender_login_maps now support multiple owners per sender address.
+
Incompatible changes with Postfix snapshot 2.0.16-20031203
==========================================================
# The lmtp_send_xforward_command parameter controls whether the Postfix
# LMTP client will send an XFORWARD command to the SMTP server, when
-# the ELMTP HELO response of the remote host indicates XFORWARD support.
-# This allows an "smtp" delivery agent, used for content filter
+# the LMTP LHLO response of the remote host indicates XFORWARD support.
+# This allows an "lmtp" delivery agent, used for content filter
# message injection, to forward the name, address, protocol and HELO
# name of the original client to the content filter and downstream
# queuing LMTP server. Before you change the value to yes, it is best
# specified order. Regexp tables are allowed.
#
# Each map entry specifies a sender address and a list of login names
-# that owns the address. The search order is:
+# that own the address. The search order is:
#
# 1) user@domain owner, owner, ...
#
# are allowed to specify the XCLIENT extension to SMTP.
#
# This command overrides SMTP client information that is used for
-# logging and access control. Typical use is for SMTP-based content
-# filters, fetchmail-like programs, or SMTP server access rule testing.
+# access control. Typical use is for SMTP-based content filters,
+# fetchmail-like programs, or SMTP server access rule testing.
#
# By default, no clients are allowed to specify XCLIENT.
#
# specified access table to those hosts.
# Note: the OK result is not allowed here for security reasons.
# reject_sender_login_mismatch:
-# reject if $smtpd_sender_login_maps specifies a MAIL FROM
-# address owner, but the client is not (SASL) logged in as
-# that MAIL FROM address owner; or if the client is (SASL)
-# logged in, but the client login name doesn't own the MAIL
-# FROM address.
+# reject if $smtpd_sender_login_maps specifies one or more
+# owners for the MAIL FROM address, but the client is not
+# (SASL) logged in as one of the owners.
# reject_authenticated_sender_login_mismatch:
# reject if the client is (SASL) logged in, but the client
# login name doesn't own the MAIL FROM address according to
Disallow anonymous logins.
<b>smtpd_sender_login_maps</b>
- Maps that specify the SASL login name that owns a
+ Maps that specify the SASL login names that own a
MAIL FROM sender address. Used by the
<b>reject_sender_login_mismatch</b> sender anti-spoofing
restriction, as well as by its component restric-
.IP \fB-c\fR
Display a running counter that is updated whenever an SMTP
QUIT command is executed.
+.IP \fB-C\fR
+Disable XCLIENT support.
.IP \fB-e\fR
Do not announce ESMTP support.
.IP "\fB-f \fIcommand,command,...\fR"
Reject the specified commands with a hard (5xx) error code.
+.IP \fB-F\fR
+Disable XFORWARD support.
.IP \fB-h\fI hostname\fR
Use \fIhostname\fR in the SMTP greeting, in the HELO response,
and in the EHLO response. The default hostname is "smtp-sink".
Disallow anonymous logins.
.RE
.IP \fBsmtpd_sender_login_maps\fR
-Maps that specify the SASL login name that owns a MAIL FROM sender
+Maps that specify the SASL login names that own a MAIL FROM sender
address. Used by the \fBreject_sender_login_mismatch\fR sender
anti-spoofing restriction, as well as by its component restrictions
\fBreject_authenticated_sender_login_mismatch\fR (an authenticated
{
HEADER *reply_header;
int len;
+ int saved_options = _res.options;
/*
* Initialize the name service.
* only if the name server told us so.
*/
len = res_search((char *) name, C_IN, type, reply->buf, sizeof(reply->buf));
+ _res.options = saved_options;
if (len < 0) {
if (why)
vstring_sprintf(why, "Host or domain name not found. "
{
const char *cp;
+ /*
+ * A file name is either a queue ID (short alphanumeric string in
+ * time+inum form) or a fast flush service logfile name (destination
+ * domain name with non-alphanumeric characters replaced by "_").
+ */
if (*queue_id == 0 || strlen(queue_id) > VALID_HOSTNAME_LEN)
return (0);
/*
- * OK if in in time+inum form or in host-name_domain_tld form.
+ * OK if in time+inum form or in host_domain_tld form.
*/
for (cp = queue_id; *cp; cp++)
- if (!ISALNUM(*cp) && *cp != '_' && *cp != '-')
+ if (!ISALNUM(*cp) && *cp != '_')
return (0);
return (1);
}
* 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 "20031214"
+#define MAIL_RELEASE_DATE "20031215"
#define VAR_MAIL_VERSION "mail_version"
#define DEF_MAIL_VERSION "2.0.16-" MAIL_RELEASE_DATE
VAR_LMTP_CACHE_CONN, DEF_LMTP_CACHE_CONN, &var_lmtp_cache_conn,
VAR_LMTP_SKIP_QUIT_RESP, DEF_LMTP_SKIP_QUIT_RESP, &var_lmtp_skip_quit_resp,
VAR_LMTP_SASL_ENABLE, DEF_LMTP_SASL_ENABLE, &var_lmtp_sasl_enable,
+ VAR_LMTP_SEND_XFORWARD, DEF_LMTP_SEND_XFORWARD, &var_lmtp_send_xforward,
0,
};
#define LMTP_FEATURE_XFORWARD_PROTO (1<<8)
#define LMTP_FEATURE_XFORWARD_HELO (1<<9)
-#define LMTP_FEATURE_XFORWARD_NAME_ADDR \
- (LMTP_FEATURE_XFORWARD_NAME | LMTP_FEATURE_XFORWARD_ADDR)
-
-#define LMTP_FEATURE_XFORWARD_PROTO_HELO \
- (LMTP_FEATURE_XFORWARD_PROTO | LMTP_FEATURE_XFORWARD_HELO)
-
/*
* lmtp.c
*/
* minimal amount of information is available.
*/
send_name_addr =
- (var_lmtp_send_xforward
- && (state->features & LMTP_FEATURE_XFORWARD_NAME_ADDR)
- && (DEL_REQ_ATTR_AVAIL(request->client_name)
- || DEL_REQ_ATTR_AVAIL(request->client_addr)));
+ var_lmtp_send_xforward
+ && (((state->features & LMTP_FEATURE_XFORWARD_NAME)
+ && DEL_REQ_ATTR_AVAIL(request->client_name))
+ || ((state->features & LMTP_FEATURE_XFORWARD_ADDR)
+ && DEL_REQ_ATTR_AVAIL(request->client_addr)));
lmtp_send_proto_helo =
- (var_lmtp_send_xforward
- && (state->features & LMTP_FEATURE_XFORWARD_PROTO_HELO)
- && (DEL_REQ_ATTR_AVAIL(request->client_proto)
- || DEL_REQ_ATTR_AVAIL(request->client_helo)));
+ var_lmtp_send_xforward
+ && (((state->features & LMTP_FEATURE_XFORWARD_PROTO)
+ && DEL_REQ_ATTR_AVAIL(request->client_proto))
+ || ((state->features & LMTP_FEATURE_XFORWARD_HELO)
+ && DEL_REQ_ATTR_AVAIL(request->client_helo)));
if (send_name_addr)
start = LMTP_STATE_XFORWARD_NAME_ADDR;
else if (lmtp_send_proto_helo)
} QMQPD_STATE;
/*
- * Postfix representation unknown client information within qmqpd processes.
- * This is not the representation that Postfix uses in queue files, in queue
- * manager delivery requests, nor is it the representation of information in
- * XCLIENT/XFORWARD commands!
+ * Representation of unknown upstream client or message information within
+ * qmqpd processes. This is not the representation that Postfix uses in
+ * queue files, in queue manager delivery requests, or in XCLIENT/XFORWARD
+ * commands!
*/
#define CLIENT_ATTR_UNKNOWN "unknown"
#define SMTP_FEATURE_XFORWARD_PROTO (1<<9)
#define SMTP_FEATURE_XFORWARD_HELO (1<<10)
-#define SMTP_FEATURE_XFORWARD_NAME_ADDR \
- (SMTP_FEATURE_XFORWARD_NAME | SMTP_FEATURE_XFORWARD_ADDR)
-
-#define SMTP_FEATURE_XFORWARD_PROTO_HELO \
- (SMTP_FEATURE_XFORWARD_PROTO | SMTP_FEATURE_XFORWARD_HELO)
-
/*
* smtp.c
*/
*/
nrcpt = 0;
send_name_addr =
- (var_smtp_send_xforward
- && (state->features & SMTP_FEATURE_XFORWARD_NAME_ADDR)
- && (DEL_REQ_ATTR_AVAIL(request->client_name)
- || DEL_REQ_ATTR_AVAIL(request->client_addr)));
+ var_smtp_send_xforward
+ && (((state->features & SMTP_FEATURE_XFORWARD_NAME)
+ && DEL_REQ_ATTR_AVAIL(request->client_name))
+ || ((state->features & SMTP_FEATURE_XFORWARD_ADDR)
+ && DEL_REQ_ATTR_AVAIL(request->client_addr)));
send_proto_helo =
- (var_smtp_send_xforward
- && (state->features & SMTP_FEATURE_XFORWARD_PROTO_HELO)
- && (DEL_REQ_ATTR_AVAIL(request->client_proto)
- || DEL_REQ_ATTR_AVAIL(request->client_helo)));
+ var_smtp_send_xforward
+ && (((state->features & SMTP_FEATURE_XFORWARD_PROTO)
+ && DEL_REQ_ATTR_AVAIL(request->client_proto))
+ || ((state->features & SMTP_FEATURE_XFORWARD_HELO)
+ && DEL_REQ_ATTR_AVAIL(request->client_helo)));
if (send_name_addr)
recv_state = send_state = SMTP_STATE_XFORWARD_NAME_ADDR;
else if (send_proto_helo)
msg_warn("host %s said: %s (in reply to %s)",
session->namaddr,
translit(resp->str, "\n", " "),
- xfer_request[SMTP_STATE_XFORWARD_NAME_ADDR]);
+ xfer_request[SMTP_STATE_XFORWARD_NAME_ADDR]);
if (send_proto_helo)
recv_state = SMTP_STATE_XFORWARD_PROTO_HELO;
else
msg_warn("host %s said: %s (in reply to %s)",
session->namaddr,
translit(resp->str, "\n", " "),
- xfer_request[SMTP_STATE_XFORWARD_PROTO_HELO]);
+ xfer_request[SMTP_STATE_XFORWARD_PROTO_HELO]);
recv_state = SMTP_STATE_MAIL;
break;
/* Disallow anonymous logins.
/* .RE
/* .IP \fBsmtpd_sender_login_maps\fR
-/* Maps that specify the SASL login name that owns a MAIL FROM sender
+/* Maps that specify the SASL login names that own a MAIL FROM sender
/* address. Used by the \fBreject_sender_login_mismatch\fR sender
/* anti-spoofing restriction, as well as by its component restrictions
/* \fBreject_authenticated_sender_login_mismatch\fR (an authenticated
char *attr_name;
int updated = 0;
static NAME_CODE xforward_flags[] = {
- XFORWARD_NAME, SMTPD_XFORWARD_FLAG_NAME,
- XFORWARD_ADDR, SMTPD_XFORWARD_FLAG_ADDR,
- XFORWARD_PROTO, SMTPD_XFORWARD_FLAG_PROTO,
- XFORWARD_HELO, SMTPD_XFORWARD_FLAG_HELO,
+ XFORWARD_NAME, SMTPD_STATE_XFORWARD_NAME,
+ XFORWARD_ADDR, SMTPD_STATE_XFORWARD_ADDR,
+ XFORWARD_PROTO, SMTPD_STATE_XFORWARD_PROTO,
+ XFORWARD_HELO, SMTPD_STATE_XFORWARD_HELO,
0, 0,
};
int flag;
smtpd_chat_reply(state, "501 Error: attribute=value expected");
return (-1);
}
+ if (strlen(attr_value) > 255) {
+ state->error_mask |= MAIL_ERROR_PROTOCOL;
+ smtpd_chat_reply(state, "501 Error: attribute value too long");
+ return (-1);
+ }
printable(attr_value, '?');
flag = name_code(xforward_flags, NAME_CODE_FLAG_NONE, attr_name);
switch (flag) {
/*
- * NAME=host name, not necessarily in the DNS. Censor special
- * characters that could mess up message headers.
+ * NAME=up-stream host name, not necessarily in the DNS. Censor
+ * special characters that could mess up message headers.
*/
- case SMTPD_XFORWARD_FLAG_NAME:
+ case SMTPD_STATE_XFORWARD_NAME:
if (STREQ(attr_value, XFORWARD_UNAVAILABLE)) {
attr_value = CLIENT_NAME_UNKNOWN;
} else {
break;
/*
- * ADDR=host network address, not necessarily on the Internet.
- * Censor special characters that could mess up message headers.
+ * ADDR=up-stream host network address, not necessarily on the
+ * Internet. Censor special characters that could mess up message
+ * headers.
*/
- case SMTPD_XFORWARD_FLAG_ADDR:
+ case SMTPD_STATE_XFORWARD_ADDR:
if (STREQ(attr_value, XFORWARD_UNAVAILABLE)) {
attr_value = CLIENT_ADDR_UNKNOWN;
} else {
break;
/*
- * HELO=hostname that the host introduced itself with (not
- * necessarily SMTP HELO). Censor special characters that could
- * mess up message headers.
+ * HELO=hostname that the up-stream MTA introduced itself with
+ * (not necessarily SMTP HELO). Censor special characters that
+ * could mess up message headers.
*/
- case SMTPD_XFORWARD_FLAG_HELO:
+ case SMTPD_STATE_XFORWARD_HELO:
if (STREQ(attr_value, XFORWARD_UNAVAILABLE)) {
attr_value = CLIENT_HELO_UNKNOWN;
} else {
break;
/*
- * PROTO=protocol name, not necessarily SMTP or ESMTP. Censor
- * special characters that could mess up message headers.
+ * PROTO=up-stream protocol, not necessarily SMTP or ESMTP.
+ * Censor special characters that could mess up message headers.
*/
- case SMTPD_XFORWARD_FLAG_PROTO:
+ case SMTPD_STATE_XFORWARD_PROTO:
if (STREQ(attr_value, XFORWARD_UNAVAILABLE)) {
attr_value = CLIENT_PROTO_UNKNOWN;
} else {
state->xforward.flags |= updated;
/*
- * Update the combined name and address when either has changed.
+ * Update the combined name and address when either has changed. Use only
+ * the name when no address is available.
*/
- if (updated & (SMTPD_XFORWARD_FLAG_NAME | SMTPD_XFORWARD_FLAG_ADDR)) {
+ if (updated & (SMTPD_STATE_XFORWARD_NAME | SMTPD_STATE_XFORWARD_ADDR)) {
if (state->xforward.namaddr)
myfree(state->xforward.namaddr);
state->xforward.namaddr =
int class; /* error notification class */
} SMTPD_DEFER;
-typedef struct SMTPD_XFORWARD_ATTR {
- int flags; /* see below */
+typedef struct {
+ int flags; /* XFORWARD server state */
char *name; /* name for access control */
char *addr; /* address for access control */
char *namaddr; /* name[address] */
char *ident; /* message identifier */
} SMTPD_XFORWARD_ATTR;
-#define SMTPD_XFORWARD_FLAG_INIT (1<<0) /* preset done */
-#define SMTPD_XFORWARD_FLAG_NAME (1<<1) /* client name received */
-#define SMTPD_XFORWARD_FLAG_ADDR (1<<2) /* client address received */
-#define SMTPD_XFORWARD_FLAG_PROTO (1<<3)/* protocol received */
-#define SMTPD_XFORWARD_FLAG_HELO (1<<4) /* client helo received */
-#define SMTPD_XFORWARD_FLAG_IDENT (1<<5)/* message identifier received */
-
-#define SMTPD_XFORWARD_FLAG_CLIENT_MASK \
- (SMTPD_XFORWARD_FLAG_NAME | SMTPD_XFORWARD_FLAG_ADDR \
- | SMTPD_XFORWARD_FLAG_PROTO | SMTPD_XFORWARD_FLAG_HELO)
-
typedef struct SMTPD_STATE {
int err;
VSTREAM *client;
char *saved_redirect; /* postponed redirect action */
int saved_flags; /* postponed hold/discard */
VSTRING *expand_buf; /* scratch space for $name expansion */
+
+ /* Pass-through proxy client. */
VSTREAM *proxy; /* proxy handle */
VSTRING *proxy_buffer; /* proxy query/reply buffer */
char *proxy_mail; /* owned by mail_cmd() */
- int proxy_xforward_features; /* proxy XFORWARD features */
- SMTPD_XFORWARD_ATTR xforward; /* override access control */
+ int proxy_xforward_features; /* XFORWARD proxy state */
+
+ /* XFORWARD server state. */
+ SMTPD_XFORWARD_ATTR xforward; /* up-stream logging info */
} SMTPD_STATE;
+#define SMTPD_STATE_XFORWARD_INIT (1<<0) /* xforward preset done */
+#define SMTPD_STATE_XFORWARD_NAME (1<<1) /* client name received */
+#define SMTPD_STATE_XFORWARD_ADDR (1<<2) /* client address received */
+#define SMTPD_STATE_XFORWARD_PROTO (1<<3) /* protocol received */
+#define SMTPD_STATE_XFORWARD_HELO (1<<4) /* client helo received */
+#define SMTPD_STATE_XFORWARD_IDENT (1<<5) /* message identifier */
+
+#define SMTPD_STATE_XFORWARD_CLIENT_MASK \
+ (SMTPD_STATE_XFORWARD_NAME | SMTPD_STATE_XFORWARD_ADDR \
+ | SMTPD_STATE_XFORWARD_PROTO | SMTPD_STATE_XFORWARD_HELO)
+
extern void smtpd_state_init(SMTPD_STATE *, VSTREAM *);
extern void smtpd_state_reset(SMTPD_STATE *);
#define SMTPD_AFTER_DOT "END-OF-MESSAGE"
/*
- * Postfix representation of unknown client information within smtpd
- * processes. This is not the representation that Postfix uses in queue
- * files, in queue manager delivery requests, nor is it the representation
- * of information in XCLIENT/XFORWARD commands!
+ * Representation of unknown client information within smtpd processes. This
+ * is not the representation that Postfix uses in queue files, in queue
+ * manager delivery requests, or in XCLIENT/XFORWARD commands!
*/
#define CLIENT_ATTR_UNKNOWN "unknown"
* Note 2: outside the SMTP server, the representation of unknown/known
* attribute values is different in queue files, in queue manager delivery
* requests, and in over-the-network XFORWARD commands.
- */
-#define SMTPD_PROXY_XFORWARD_NAME (1<<0) /* client name */
-#define SMTPD_PROXY_XFORWARD_ADDR (1<<1) /* client address */
-#define SMTPD_PROXY_XFORWARD_PROTO (1<<2) /* protocol */
-#define SMTPD_PROXY_XFORWARD_HELO (1<<3) /* client helo */
-#define SMTPD_PROXY_XFORWARD_IDENT (1<<4) /* message identifier */
-
- /*
- * If forwarding client information, don't mix information from the current
- * SMTP session with forwarded information from an up-stream session.
+ *
+ * Note 3: if forwarding client information, don't mix information from the
+ * current SMTP session with forwarded information from an up-stream
+ * session.
*/
#define FORWARD_CLIENT_ATTR(s, a) \
- (((s)->xforward.flags & SMTPD_XFORWARD_FLAG_CLIENT_MASK) ? \
+ (((s)->xforward.flags & SMTPD_STATE_XFORWARD_CLIENT_MASK) ? \
(s)->xforward.a : (s)->a)
#define FORWARD_IDENT_ATTR(s) \
- (((s)->xforward.flags & SMTPD_XFORWARD_FLAG_IDENT) ? \
+ (((s)->xforward.flags & SMTPD_STATE_XFORWARD_IDENT) ? \
(s)->queue_id : (s)->ident)
#define FORWARD_ADDR(s) FORWARD_CLIENT_ATTR((s), addr)
return (result);
}
-#ifdef USE_SASL
+#ifdef USE_SASL_AUTH
/* reject_auth_sender_login_mismatch - logged in client must own sender address */
status = reject_non_fqdn_address(state, state->sender,
state->sender, SMTPD_NAME_SENDER);
} else if (strcasecmp(name, REJECT_AUTH_SENDER_LOGIN_MISMATCH) == 0) {
-#ifdef USE_SASL
+#ifdef USE_SASL_AUTH
if (var_smtpd_sasl_enable) {
if (state->sender && *state->sender)
status = reject_auth_sender_login_mismatch(state, state->sender);
#endif
msg_warn("restriction `%s' ignored: no SASL support", name);
} else if (strcasecmp(name, REJECT_UNAUTH_SENDER_LOGIN_MISMATCH) == 0) {
-#ifdef USE_SASL
+#ifdef USE_SASL_AUTH
if (var_smtpd_sasl_enable) {
if (state->sender && *state->sender)
status = reject_unauth_sender_login_mismatch(state, state->sender);
#include <smtpd.h>
#include <smtpd_proxy.h>
+ /*
+ * XFORWARD server features, recognized by the pass-through proxy client.
+ */
+#define SMTPD_PROXY_XFORWARD_NAME (1<<0) /* client name */
+#define SMTPD_PROXY_XFORWARD_ADDR (1<<1) /* client address */
+#define SMTPD_PROXY_XFORWARD_PROTO (1<<2) /* protocol */
+#define SMTPD_PROXY_XFORWARD_HELO (1<<3) /* client helo */
+#define SMTPD_PROXY_XFORWARD_IDENT (1<<4) /* message identifier */
+
/*
* SLMs.
*/
* same values as unknown normal attributes, so that we don't break
* assumptions in pre-existing code.
*/
- state->xforward.flags = SMTPD_XFORWARD_FLAG_INIT;
+ state->xforward.flags = SMTPD_STATE_XFORWARD_INIT;
state->xforward.name = mystrdup(CLIENT_NAME_UNKNOWN);
state->xforward.addr = mystrdup(CLIENT_ADDR_UNKNOWN);
state->xforward.namaddr = mystrdup(CLIENT_NAMADDR_UNKNOWN);
/* .IP \fB-c\fR
/* Display a running counter that is updated whenever an SMTP
/* QUIT command is executed.
+/* .IP \fB-C\fR
+/* Disable XCLIENT support.
/* .IP \fB-e\fR
/* Do not announce ESMTP support.
/* .IP "\fB-f \fIcommand,command,...\fR"
/* Reject the specified commands with a hard (5xx) error code.
+/* .IP \fB-F\fR
+/* Disable XFORWARD support.
/* .IP \fB-h\fI hostname\fR
/* Use \fIhostname\fR in the SMTP greeting, in the HELO response,
/* and in the EHLO response. The default hostname is "smtp-sink".
static int enable_lmtp;
static int pretend_pix;
static int disable_saslauth;
+static int disable_xclient;
+static int disable_xforward;
/* ehlo_response - respond to EHLO command */
smtp_printf(state->stream, "250-8BITMIME");
if (!disable_saslauth)
smtp_printf(state->stream, "250-AUTH PLAIN LOGIN");
+ if (!disable_xclient)
+ smtp_printf(state->stream, "250-XCLIENT NAME HELO");
+ if (!disable_xforward)
+ smtp_printf(state->stream, "250-XFORWARD NAME ADDR PROTO HELO");
smtp_printf(state->stream, "250 ");
smtp_flush(state->stream);
}
"helo", helo_response, 0,
"ehlo", ehlo_response, 0,
"lhlo", ehlo_response, 0,
+ "xclient", ok_response, FLAG_ENABLE,
+ "xforward", ok_response, FLAG_ENABLE,
"auth", ok_response, FLAG_ENABLE,
"mail", mail_response, FLAG_ENABLE,
"rcpt", rcpt_response, FLAG_ENABLE,
0,
};
+/* reset_cmd_flags - reset per-command command flags */
+
+static void reset_cmd_flags(const char *cmd, int flags)
+{
+ SINK_COMMAND *cmdp;
+
+ for (cmdp = command_table; cmdp->name != 0; cmdp++)
+ if (strcasecmp(cmd, cmdp->name) == 0)
+ break;
+ if (cmdp->name == 0)
+ msg_fatal("unknown command: %s", cmd);
+ cmdp->flags &= ~flags;
+}
+
/* set_cmd_flags - set per-command command flags */
static void set_cmd_flags(const char *cmd, int flags)
/*
* Parse JCL.
*/
- while ((ch = GETOPT(argc, argv, "acef:h:Ln:pPr:s:vw:8")) > 0) {
+ while ((ch = GETOPT(argc, argv, "acCef:Fh:Ln:pPr:s:vw:8")) > 0) {
switch (ch) {
case 'a':
disable_saslauth = 1;
case 'c':
count++;
break;
+ case 'C':
+ disable_xclient = 1;
+ reset_cmd_flags("xclient", FLAG_ENABLE);
+ break;
case 'e':
disable_esmtp = 1;
break;
case 'f':
set_cmds_flags(optarg, FLAG_HARD_ERR);
break;
+ case 'F':
+ disable_xforward = 1;
+ reset_cmd_flags("xforward", FLAG_ENABLE);
+ break;
case 'h':
var_myhostname = optarg;
break;
enable_lmtp = 1;
break;
case 'n':
- max_count = atoi(optarg);
+ if ((max_count = atoi(optarg)) <= 0)
+ msg_fatal("bad count: %s", optarg);
break;
case 'p':
disable_pipelining = 1;
linger.l_onoff = 1;
linger.l_linger = 0;
if (setsockopt(fd, SOL_SOCKET, SO_LINGER, (char *) &linger,
- sizeof(linger)) < 0)
- msg_warn("setsockopt SO_LINGER %d: %m", linger.l_linger);
+ sizeof(linger)) < 0)
+ msg_warn("setsockopt SO_LINGER %d: %m", linger.l_linger);
session->stream = vstream_fdopen(fd, O_RDWR);
event_enable_write(fd, connect_done, (char *) session);
smtp_timeout_setup(session->stream, var_timeout);
count++;
break;
case 'C':
- if ((connect_count = atoi(optarg)) <= 0) {
- msg_error("bad connection count: %s", optarg);
- usage(argv[0]);
- }
+ if ((connect_count = atoi(optarg)) <= 0)
+ msg_fatal("bad connection count: %s", optarg);
break;
case 'd':
disconnect = 0;
sender = optarg;
break;
case 'l':
- if ((message_length = atoi(optarg)) <= 0) {
- msg_error("bad message length: %s", optarg);
- usage(argv[0]);
- }
+ if ((message_length = atoi(optarg)) <= 0)
+ msg_fatal("bad message length: %s", optarg);
message_data = mymalloc(message_length);
memset(message_data, 'X', message_length);
for (i = 80; i < message_length; i += 80) {
talk_lmtp = 1;
break;
case 'm':
- if ((message_count = atoi(optarg)) <= 0) {
- msg_error("bad message count: %s", optarg);
- usage(argv[0]);
- }
+ if ((message_count = atoi(optarg)) <= 0)
+ msg_fatal("bad message count: %s", optarg);
break;
case 'o':
send_helo_first = 0;
send_headers = 0;
break;
case 'r':
- if ((recipients = atoi(optarg)) <= 0) {
- msg_error("bad recipient count: %s", optarg);
- usage(argv[0]);
- }
+ if ((recipients = atoi(optarg)) <= 0)
+ msg_fatal("bad recipient count: %s", optarg);
break;
case 'R':
- if (fixed_delay > 0) {
- msg_error("do not use -w and -R options at the same time");
- usage(argv[0]);
- }
- if ((random_delay = atoi(optarg)) <= 0) {
- msg_error("bad random delay: %s", optarg);
- usage(argv[0]);
- }
+ if (fixed_delay > 0)
+ msg_fatal("do not use -w and -R options at the same time");
+ if ((random_delay = atoi(optarg)) <= 0)
+ msg_fatal("bad random delay: %s", optarg);
break;
case 's':
- if ((sessions = atoi(optarg)) <= 0) {
- msg_error("bad session count: %s", optarg);
- usage(argv[0]);
- }
+ if ((sessions = atoi(optarg)) <= 0)
+ msg_fatal("bad session count: %s", optarg);
break;
case 'S':
subject = optarg;
msg_verbose++;
break;
case 'w':
- if (random_delay > 0) {
- msg_error("do not use -w and -R options at the same time");
- usage(argv[0]);
- }
- if ((fixed_delay = atoi(optarg)) <= 0) {
- msg_error("bad fixed delay: %s", optarg);
- usage(argv[0]);
- }
+ if (random_delay > 0)
+ msg_fatal("do not use -w and -R options at the same time");
+ if ((fixed_delay = atoi(optarg)) <= 0)
+ msg_fatal("bad fixed delay: %s", optarg);
break;
default:
usage(argv[0]);
fifo_trigger.c file_limit.c find_inet.c fsspace.c fullname.c \
get_domainname.c get_hostname.c hex_quote.c host_port.c htable.c \
inet_addr_host.c inet_addr_list.c inet_addr_local.c inet_connect.c \
- inet_listen.c inet_trigger.c inet_util.c intv.c line_wrap.c \
+ inet_listen.c inet_trigger.c inet_util.c line_wrap.c \
lowercase.c lstat_as.c mac_expand.c mac_parse.c make_dirs.c \
match_list.c match_ops.c msg.c msg_output.c msg_syslog.c \
msg_vstream.c mvect.c myflock.c mymalloc.c myrand.c mystrtok.c \
fifo_trigger.o file_limit.o find_inet.o fsspace.o fullname.o \
get_domainname.o get_hostname.o hex_quote.o host_port.o htable.o \
inet_addr_host.o inet_addr_list.o inet_addr_local.o inet_connect.o \
- inet_listen.o inet_trigger.o inet_util.o intv.o line_wrap.o \
+ inet_listen.o inet_trigger.o inet_util.o line_wrap.o \
lowercase.o lstat_as.o mac_expand.o mac_parse.o make_dirs.o \
match_list.o match_ops.o msg.o msg_output.o msg_syslog.o \
msg_vstream.o mvect.o myflock.o mymalloc.o myrand.o mystrtok.o \
dict_static.h dict_tcp.h dict_unix.h dir_forest.h events.h \
exec_command.h find_inet.h fsspace.h fullname.h get_domainname.h \
get_hostname.h hex_quote.h host_port.h htable.h inet_addr_host.h \
- inet_addr_list.h inet_addr_local.h inet_util.h intv.h iostuff.h \
+ inet_addr_list.h inet_addr_local.h inet_util.h iostuff.h \
line_wrap.h listen.h lstat_as.h mac_expand.h mac_parse.h \
make_dirs.h match_list.h match_ops.h msg.h msg_output.h \
msg_syslog.h msg_vstream.h mvect.h myflock.h mymalloc.h myrand.h \
inet_util.o: mymalloc.h
inet_util.o: split_at.h
inet_util.o: inet_util.h
-intv.o: intv.c
-intv.o: sys_defs.h
-intv.o: mymalloc.h
-intv.o: msg.h
-intv.o: intv.h
line_wrap.o: line_wrap.c
line_wrap.o: sys_defs.h
line_wrap.o: line_wrap.h
}
server_host = parser.get_str(ldapsource, "server_host",
- "localhost", 0, 0);
+ "localhost", 1, 0);
if (msg_verbose)
msg_info("%s: %s server_host is %s", myname, ldapsource,
server_host);
vstring_sprintf_append(url_list, " %s", h);
#endif
}
- dict_ldap->server_host = mystrdup(vstring_str(url_list) + 1);
+ dict_ldap->server_host =
+ mystrdup(VSTRING_LEN(url_list) > 0 ? vstring_str(url_list) + 1 : "");
#if defined(LDAP_API_FEATURE_X_OPENLDAP)
+++ /dev/null
-/*++
-/* NAME
-/* intv 3
-/* SUMMARY
-/* integer array utilities
-/* SYNOPSIS
-/* #include <intv.h>
-/*
-/* INTV *intv_alloc(len)
-/* int len;
-/*
-/* INTV *intv_free(intvp)
-/* INTV *intvp;
-/*
-/* void intv_add(intvp, count, arg, ...)
-/* INTV *intvp;
-/* int count;
-/* int *arg;
-/* DESCRIPTION
-/* The functions in this module manipulate arrays of integers.
-/* An INTV structure contains the following members:
-/* .IP len
-/* The actual length of the \fIintv\fR array.
-/* .IP intc
-/* The number of \fIintv\fR elements used.
-/* .IP intv
-/* An array of integer values.
-/* .PP
-/* intv_alloc() returns an empty integer array of the requested
-/* length. The result is ready for use by intv_add().
-/*
-/* intv_add() copies zero or more integers and adds them to the
-/* specified integer array.
-/*
-/* intv_free() releases storage for an integer array, and conveniently
-/* returns a null pointer.
-/* SEE ALSO
-/* msg(3) diagnostics interface
-/* DIAGNOSTICS
-/* Fatal errors: memory allocation problem.
-/* LICENSE
-/* .ad
-/* .fi
-/* The Secure Mailer license must be distributed with this software.
-/* AUTHOR(S)
-/* Wietse Venema
-/* IBM T.J. Watson Research
-/* P.O. Box 704
-/* Yorktown Heights, NY 10598, USA
-/*--*/
-
-/* System libraries. */
-
-#include <sys_defs.h>
-#include <stdlib.h> /* 44BSD stdarg.h uses abort() */
-#include <stdarg.h>
-
-/* Application-specific. */
-
-#include "mymalloc.h"
-#include "msg.h"
-#include "intv.h"
-
-/* intv_free - destroy integer array */
-
-INTV *intv_free(INTV *intvp)
-{
- myfree((char *) intvp->intv);
- myfree((char *) intvp);
- return (0);
-}
-
-/* intv_alloc - initialize integer array */
-
-INTV *intv_alloc(int len)
-{
- INTV *intvp;
-
- /*
- * Sanity check.
- */
- if (len < 1)
- msg_panic("intv_alloc: bad array length %d", len);
-
- /*
- * Initialize.
- */
- intvp = (INTV *) mymalloc(sizeof(*intvp));
- intvp->len = 0;
- intvp->intv = (int *) mymalloc(len * sizeof(intvp->intv[0]));
- intvp->len = len;
- intvp->intc = 0;
- return (intvp);
-}
-
-/* intv_add - add integer to vector */
-
-void intv_add(INTV *intvp, int count,...)
-{
- va_list ap;
- int new_len;
-
- /*
- * Make sure that always intvp->intc < intvp->len.
- */
- va_start(ap, count);
- while (count-- > 0) {
- if (intvp->intc >= intvp->len) {
- new_len = intvp->len * 2;
- intvp->intv = (int *) myrealloc((char *) intvp->intv,
- new_len * sizeof(int));
- intvp->len = new_len;
- }
- intvp->intv[intvp->intc++] = va_arg(ap, int);
- }
- va_end(ap);
-}
+++ /dev/null
-#ifndef _INTV_H_INCLUDED_
-#define _INTV_H_INCLUDED_
-
-/*++
-/* NAME
-/* intv 3h
-/* SUMMARY
-/* string array utilities
-/* SYNOPSIS
-/* #include "intv.h"
- DESCRIPTION
- .nf
-
- /*
- * External interface.
- */
-typedef struct INTV {
- int len; /* number of array elements */
- int intc; /* array elements in use */
- int *intv; /* integer array */
-} INTV;
-
-extern INTV *intv_alloc(int);
-extern void intv_add(INTV *, int,...);
-extern INTV *intv_free(INTV *);
-
-/* LICENSE
-/* .ad
-/* .fi
-/* The Secure Mailer license must be distributed with this software.
-/* AUTHOR(S)
-/* Wietse Venema
-/* IBM T.J. Watson Research
-/* P.O. Box 704
-/* Yorktown Heights, NY 10598, USA
-/*--*/
-
-#endif