In addition to the names listed below, the following people provided
+
+20160618
+
+ Bugfix:
useful inputs on many occasions: Paul D. Robertson, Simon J. Mudd.
Apologies for any names omitted.
20140612
- Bugfix: missing server address/port conversion. File:
+ Bugfix (introduced: 20090211): missing server address
+ conversion for non-proxy, non-postscreen connections. File:
smtpd/smtpd_peer.c.
+
+ Bugfix (introduced: 20160611) missing server port conversion
+ for non-proxy, non-postscreen connections, because there was
+ no server address conversion. File: smtpd/smtpd_peer.c.
+
+20160618
+
+ Bugfix(introduced: 20091121): with the introduction of
+ sender_dependent_default_transport_maps, the SMTP daemon
+ was not updated. This resulted in false rejects with
+ sender-dependent "error" transports. Based on a fix by
+ Russell Yanofsky. Files: global/resolve_clnt.c,
+ global/resolve_clnt.h, smtpd/smtpd_check.c, smtpd/smtpd_check.h,
+ smtpd/smtpd_milter.c, smtpd/smtpd_resolve.c, smtpd/smtpd_resolve.h.
+
+20160619
+
+ Refinements to the 20160618 fix. For more consistent results
+ with sender address validation, use the recipient address
+ (if available) as the sender-dependent address resolver
+ context. For better caching, pass sender context with all
+ attempts to resolve an email address. File: smtpd/smtpd.c,
+ smtpd/smtpd_check.c, smtpd/smtpd_milter.c.
+
+20160625
+
+ Cleanup: the Postfix SMTP server now passes network address
+ and port information to the Cyrus SASL library. Build with
+ ``make makefiles "CCARGS=$CCARGS -DNO_IP_CYRUS_SASL_AUTH"''
+ for backwards compatibility. Files: makedefs,
+ smtpd/smtpd_sasl_glue.c, xsasl/xsasl.h, xsasl/xsasl_cyrus_server.c,
+ xsasl/xsasl_server.c.
+
+ Cleanup: dnsblog manpage. File: dnsblog/dnsblog.c.
Propagate SMTPD_PEER_CODE_XXX from smtpd(8) to cleanup(8),
so that {client_resolve} and {_} produce consistent results.
+ NO_IP_CYRUS_SASL_AUTH should be a main.cf parameter.
+
Modeline support in config files to enable/disable trailing
#comment, and to give hints about how to handle an LHS or
RHS.
match and replies with the query arguments plus an address list with
the resulting IP addresses, separated by whitespace, and the reply TTL.
Otherwise it replies with the query arguments plus an empty address
- list and the reply TTL; the reply TTL is -1 if there is no reply, or if
- a negative reply contains no SOA record. Finally, The <a href="dnsblog.8.html"><b>dnsblog</b>(8)</a>
+ list and the reply TTL; the reply TTL is -1 if there is no reply, or a
+ negative reply that contains no SOA record. Finally, the <a href="dnsblog.8.html"><b>dnsblog</b>(8)</a>
server closes the connection.
<b>DIAGNOSTICS</b>
#
# Note: this directive is for debugging and testing only. It
# is not guaranteed to work on all platforms.
+# .IP \fB-DNO_IP_CYRUS_SASL_AUTH\fR
+# Don't pass remote SMTP client and Postfix SMTP server IP
+# address and port information to the Cyrus SASL library.
+# This is compatible with Postfix < 3.2.
# .IP \fB-DNO_KQUEUE\fR
# Do not build with FreeBSD/NetBSD/OpenBSD/MacOSX KQUEUE support.
# By default, KQUEUE support is compiled in on platforms that
addresses, separated by whitespace, and the reply TTL.
Otherwise it replies with the query arguments plus an empty
address list and the reply TTL; the reply TTL is \-1 if there
-is no reply, or if a negative reply contains no SOA record.
-Finally, The \fBdnsblog\fR(8) server closes the connection.
+is no reply, or a negative reply that contains no SOA record.
+Finally, the \fBdnsblog\fR(8) server closes the connection.
.SH DIAGNOSTICS
.ad
.fi
/* addresses, separated by whitespace, and the reply TTL.
/* Otherwise it replies with the query arguments plus an empty
/* address list and the reply TTL; the reply TTL is -1 if there
-/* is no reply, or if a negative reply contains no SOA record.
-/* Finally, The \fBdnsblog\fR(8) server closes the connection.
+/* is no reply, or a negative reply that contains no SOA record.
+/* Finally, the \fBdnsblog\fR(8) server closes the connection.
/* DIAGNOSTICS
/* Problems and transactions are logged to \fBsyslogd\fR(8).
/* CONFIGURATION PARAMETERS
* We won't get integer overflows in 2*len + 1, because Postfix input
* keys have reasonable size limits, better safe than sorry.
*/
- if (len > (INT_MAX - 1) / 2)
- msg_panic("dict_mysql_quote: integer overflow in 2*%d+1", len);
+ if (len > (INT_MAX - VSTRING_LEN(result) - 1) / 2)
+ msg_panic("dict_mysql_quote: integer overflow in %lu+2*%d+1",
+ (unsigned long) VSTRING_LEN(result), len);
buflen = 2 * len + 1;
VSTRING_SPACE(result, buflen);
* Patches change both the patchlevel and the release date. Snapshots have no
* patchlevel; they change the release date only.
*/
-#define MAIL_RELEASE_DATE "20160612"
+#define MAIL_RELEASE_DATE "20160625"
#define MAIL_VERSION_NUMBER "3.2"
#ifdef SNAPSHOT
/* void resolve_clnt_init(reply)
/* RESOLVE_REPLY *reply;
/*
-/* void resolve_clnt_query(address, reply)
-/* const char *address;
-/* RESOLVE_REPLY *reply;
-/*
/* void resolve_clnt_query_from(sender, address, reply)
/* const char *sender;
/* const char *address;
/* RESOLVE_REPLY *reply;
/*
-/* void resolve_clnt_verify(address, reply)
-/* const char *address;
-/* RESOLVE_REPLY *reply;
-/*
/* void resolve_clnt_verify_from(sender, address, reply)
/* const char *sender;
/* const char *address;
/* by resolve_clnt_query(). The structure is destroyed by passing
/* it to resolve_clnt_free().
/*
-/* resolve_clnt_query() sends an internal-form recipient address
+/* resolve_clnt_query_from() sends an internal-form recipient address
/* (user@domain) to the resolver daemon and returns the resulting
/* transport name, next_hop host name, and internal-form recipient
/* address. In case of communication failure the program keeps trying
-/* until the mail system goes down.
+/* until the mail system goes down. The internal-form sender
+/* information is used for sender-dependent relayhost lookup.
+/* Specify RESOLVE_NULL_FROM when the sender is unavailable.
/*
-/* resolve_clnt_verify() implements an alternative version that can
+/* resolve_clnt_verify_from() implements an alternative version that can
/* be used for address verification.
/*
-/* resolve_clnt_query_from() and resolve_clnt_verify_from()
-/* allow the caller to supply sender context that will be used
-/* for sender-dependent relayhost lookup.
-/*
/* In the resolver reply, the flags member is the bit-wise OR of
/* zero or more of the following:
/* .IP RESOLVE_FLAG_FINAL
#define RESOLVE_NULL_FROM ""
-#define resolve_clnt_query(a, r) \
- resolve_clnt(RESOLVE_REGULAR, RESOLVE_NULL_FROM, (a), (r))
-#define resolve_clnt_verify(a, r) \
- resolve_clnt(RESOLVE_VERIFY, RESOLVE_NULL_FROM, (a), (r))
-
#define resolve_clnt_query_from(f, a, r) \
resolve_clnt(RESOLVE_REGULAR, (f), (a), (r))
#define resolve_clnt_verify_from(f, a, r) \
smtpd_resolve.o: ../../include/nvtable.h
smtpd_resolve.o: ../../include/resolve_clnt.h
smtpd_resolve.o: ../../include/rewrite_clnt.h
+smtpd_resolve.o: ../../include/split_at.h
smtpd_resolve.o: ../../include/stringops.h
smtpd_resolve.o: ../../include/sys_defs.h
smtpd_resolve.o: ../../include/vbuf.h
if ((STR(state->addr_buf)[0] == 0 && !allow_empty_addr)
|| (strict_rfc821 && STR(state->addr_buf)[0] == '@')
|| (SMTPD_STAND_ALONE(state) == 0
- && smtpd_check_addr(STR(state->addr_buf), smtputf8) != 0)) {
+ && smtpd_check_addr(strcmp(state->where, SMTPD_CMD_MAIL) == 0 ?
+ state->recipient : state->sender,
+ STR(state->addr_buf), smtputf8) != 0)) {
msg_warn("Illegal address syntax from %s in %s command: %s",
state->namaddr, state->where,
printable(STR(arg->vstrval), '?'));
/*
/* void smtpd_check_init()
/*
-/* int smtpd_check_addr(address, smtputf8)
+/* int smtpd_check_addr(sender, address, smtputf8)
+/* const char *sender;
/* const char *address;
/* int smtputf8;
/*
/* once during the process life time.
/*
/* smtpd_check_addr() sanity checks an email address and returns
-/* non-zero in case of badness.
+/* non-zero in case of badness. The sender argument provides sender
+/* context for address resolution and caching, or a null pointer
+/* if information is unavailable.
/*
/* smtpd_check_rewrite() should be called before opening a queue
/* file or proxy connection, in order to establish the proper
*/
static int check_sender_rcpt_maps(SMTPD_STATE *, const char *);
static int check_recipient_rcpt_maps(SMTPD_STATE *, const char *);
-static int check_rcpt_maps(SMTPD_STATE *, const char *, const char *);
+static int check_rcpt_maps(SMTPD_STATE *, const char *, const char *,
+ const char *);
/*
* Tempfail actions;
/*
* Resolve the address.
*/
- reply = smtpd_resolve_addr(recipient);
+ reply = smtpd_resolve_addr(state->sender, recipient);
if (reply->flags & RESOLVE_FLAG_FAIL)
reject_dict_retry(state, recipient);
/*
* Resolve the address.
*/
- reply = smtpd_resolve_addr(recipient);
+ reply = smtpd_resolve_addr(state->sender, recipient);
if (reply->flags & RESOLVE_FLAG_FAIL)
reject_dict_retry(state, recipient);
/*
* Resolve the address.
*/
- reply = smtpd_resolve_addr(addr);
+ reply = smtpd_resolve_addr(strcmp(reply_class, SMTPD_NAME_SENDER) == 0 ?
+ state->recipient : state->sender, addr);
if (reply->flags & RESOLVE_FLAG_FAIL)
reject_dict_retry(state, addr);
/*
* Resolve the address.
*/
- reply = smtpd_resolve_addr(addr);
+ reply = smtpd_resolve_addr(strcmp(reply_class, SMTPD_NAME_SENDER) == 0 ?
+ state->recipient : state->sender, addr);
if (reply->flags & RESOLVE_FLAG_FAIL)
reject_dict_retry(state, addr);
* Reject if the client is logged in and does not own the sender address.
*/
if (smtpd_sender_login_maps && state->sasl_username) {
- reply = smtpd_resolve_addr(sender);
+ reply = smtpd_resolve_addr(state->recipient, sender);
if (reply->flags & RESOLVE_FLAG_FAIL)
reject_dict_retry(state, sender);
if ((owners = check_mail_addr_find(state, sender, smtpd_sender_login_maps,
* owner.
*/
if (smtpd_sender_login_maps && !state->sasl_username) {
- reply = smtpd_resolve_addr(sender);
+ reply = smtpd_resolve_addr(state->recipient, sender);
if (reply->flags & RESOLVE_FLAG_FAIL)
reject_dict_retry(state, sender);
if (check_mail_addr_find(state, sender, smtpd_sender_login_maps,
/* smtpd_check_addr - address sanity check */
-int smtpd_check_addr(const char *addr, int smtputf8)
+int smtpd_check_addr(const char *sender, const char *addr, int smtputf8)
{
const RESOLVE_REPLY *resolve_reply;
const char *myname = "smtpd_check_addr";
*/
if (addr == 0 || *addr == 0)
return (0);
- resolve_reply = smtpd_resolve_addr(addr);
+ resolve_reply = smtpd_resolve_addr(sender, addr);
if (resolve_reply->flags & RESOLVE_FLAG_ERROR)
return (-1);
if (state->warn_if_reject == 0)
/* We really validate the recipient address. */
state->recipient_rcptmap_checked = 1;
- return (check_rcpt_maps(state, recipient, SMTPD_NAME_RECIPIENT));
+ return (check_rcpt_maps(state, state->sender, recipient,
+ SMTPD_NAME_RECIPIENT));
}
/* check_sender_rcpt_maps - generic_checks() sender table check */
if (state->warn_if_reject == 0)
/* We really validate the sender address. */
state->sender_rcptmap_checked = 1;
- return (check_rcpt_maps(state, sender, SMTPD_NAME_SENDER));
+ return (check_rcpt_maps(state, state->recipient, sender,
+ SMTPD_NAME_SENDER));
}
/* check_rcpt_maps - generic_checks() interface for recipient table check */
-static int check_rcpt_maps(SMTPD_STATE *state, const char *recipient,
+static int check_rcpt_maps(SMTPD_STATE *state, const char *sender,
+ const char *recipient,
const char *reply_class)
{
const RESOLVE_REPLY *reply;
/*
* Resolve the address.
*/
- reply = smtpd_resolve_addr(recipient);
+ reply = smtpd_resolve_addr(sender, recipient);
if (reply->flags & RESOLVE_FLAG_FAIL)
reject_dict_retry(state, recipient);
* External interface.
*/
extern void smtpd_check_init(void);
-extern int smtpd_check_addr(const char *, int);
+extern int smtpd_check_addr(const char *, const char *, int);
extern char *smtpd_check_rewrite(SMTPD_STATE *);
extern char *smtpd_check_client(SMTPD_STATE *);
extern char *smtpd_check_helo(SMTPD_STATE *, char *);
return (0);
if (state->sender[0] == 0)
return ("");
- reply = smtpd_resolve_addr(state->sender);
+ reply = smtpd_resolve_addr(state->recipient, state->sender);
/* Sendmail 8.13 does not externalize the null string. */
if (STR(reply->recipient)[0])
quote_821_local(state->expand_buf, STR(reply->recipient));
if (strcmp(name, S8_MAC_MAIL_HOST) == 0) {
if (state->sender == 0)
return (0);
- reply = smtpd_resolve_addr(state->sender);
+ reply = smtpd_resolve_addr(state->recipient, state->sender);
return (STR(reply->nexthop));
}
if (strcmp(name, S8_MAC_MAIL_MAILER) == 0) {
if (state->sender == 0)
return (0);
- reply = smtpd_resolve_addr(state->sender);
+ reply = smtpd_resolve_addr(state->recipient, state->sender);
return (STR(reply->transport));
}
cp = split_at(STR(state->expand_buf), ' ');
return (cp ? split_at(cp, ' ') : cp);
}
- reply = smtpd_resolve_addr(state->recipient);
+ reply = smtpd_resolve_addr(state->sender, state->recipient);
/* Sendmail 8.13 does not externalize the null string. */
if (STR(reply->recipient)[0])
quote_821_local(state->expand_buf, STR(reply->recipient));
(void) split_at(STR(state->expand_buf), ' ');
return (STR(state->expand_buf));
}
- reply = smtpd_resolve_addr(state->recipient);
+ reply = smtpd_resolve_addr(state->sender, state->recipient);
return (STR(reply->nexthop));
}
if (strcmp(name, S8_MAC_RCPT_MAILER) == 0) {
return (0);
if (state->milter_reject_text)
return (S8_RCPT_MAILER_ERROR);
- reply = smtpd_resolve_addr(state->recipient);
+ reply = smtpd_resolve_addr(state->sender, state->recipient);
return (STR(reply->transport));
}
return (0);
/* void smtpd_resolve_init(cache_size)
/* int cache_size;
/*
-/* const RESOLVE_REPLY *smtpd_resolve_addr(addr)
+/* const RESOLVE_REPLY *smtpd_resolve_addr(sender, addr)
+/* const char *sender;
/* const char *addr;
/* DESCRIPTION
/* This module maintains a resolve client cache that persists
/* Arguments:
/* .IP cache_size
/* The requested cache size.
+/* .IP sender
+/* The message sender, or null pointer.
/* .IP addr
/* The address to resolve.
/* DIAGNOSTICS
#include <vstring.h>
#include <ctable.h>
#include <stringops.h>
+#include <split_at.h>
/* Global library. */
static CTABLE *smtpd_resolve_cache;
#define STR(x) vstring_str(x)
+#define SENDER_ADDR_JOIN_CHAR '\n'
/* resolve_pagein - page in an address resolver result */
-static void *resolve_pagein(const char *addr, void *unused_context)
+static void *resolve_pagein(const char *sender_plus_addr, void *unused_context)
{
+ const char myname[] = "resolve_pagein";
static VSTRING *query;
+ static VSTRING *junk;
+ static VSTRING *sender_buf;
RESOLVE_REPLY *reply;
- char *tmp;
+ const char *sender;
+ const char *addr;
/*
* Initialize on the fly.
*/
- if (query == 0)
+ if (query == 0) {
query = vstring_alloc(10);
+ junk = vstring_alloc(10);
+ sender_buf = vstring_alloc(10);
+ }
/*
* Initialize.
reply = (RESOLVE_REPLY *) mymalloc(sizeof(*reply));
resolve_clnt_init(reply);
+ /*
+ * Split the sender and address.
+ */
+ vstring_strcpy(junk, sender_plus_addr);
+ sender = STR(junk);
+ if ((addr = split_at(STR(junk), SENDER_ADDR_JOIN_CHAR)) == 0)
+ msg_panic("%s: bad search key: \"%s\"", myname, sender_plus_addr);
+
/*
* Resolve the address.
*/
+ rewrite_clnt_internal(MAIL_ATTR_RWR_LOCAL, sender, sender_buf);
rewrite_clnt_internal(MAIL_ATTR_RWR_LOCAL, addr, query);
- resolve_clnt_query(STR(query), reply);
- tmp = mystrdup(STR(reply->recipient));
- casefold(reply->recipient, tmp); /* XXX */
- myfree(tmp);
+ resolve_clnt_query_from(STR(sender_buf), STR(query), reply);
+ vstring_strcpy(junk, STR(reply->recipient));
+ casefold(reply->recipient, STR(junk)); /* XXX */
/*
* Save the result.
resolve_pageout, (void *) 0);
}
-/* smtpd_resolve_addr - resolve cached addres */
+/* smtpd_resolve_addr - resolve cached address */
-const RESOLVE_REPLY *smtpd_resolve_addr(const char *addr)
+const RESOLVE_REPLY *smtpd_resolve_addr(const char *sender, const char *addr)
{
+ static VSTRING *sender_plus_addr_buf;
+
+ /*
+ * Initialize on the fly.
+ */
+ if (sender_plus_addr_buf == 0)
+ sender_plus_addr_buf = vstring_alloc(10);
/*
* Sanity check.
/*
* Reply from the read-through cache.
*/
- return (const RESOLVE_REPLY *) ctable_locate(smtpd_resolve_cache, addr);
+ vstring_sprintf(sender_plus_addr_buf, "%s%c%s",
+ sender ? sender : RESOLVE_NULL_FROM,
+ SENDER_ADDR_JOIN_CHAR, addr);
+ return (const RESOLVE_REPLY *)
+ ctable_locate(smtpd_resolve_cache, STR(sender_plus_addr_buf));
}
* External interface.
*/
extern void smtpd_resolve_init(int);
-extern const RESOLVE_REPLY *smtpd_resolve_addr(const char *);
+extern const RESOLVE_REPLY *smtpd_resolve_addr(const char*, const char *);
/* LICENSE
/* .ad
if ((state->sasl_server =
XSASL_SERVER_CREATE(smtpd_sasl_impl, &create_args,
stream = state->client,
- server_addr = (state->dest_addr ?
- state->dest_addr : ""),
+ addr_family = state->addr_family,
+ server_addr = ADDR_OR_EMPTY(state->dest_addr,
+ SERVER_ADDR_UNKNOWN),
+ server_port = ADDR_OR_EMPTY(state->dest_port,
+ SERVER_PORT_UNKNOWN),
client_addr = ADDR_OR_EMPTY(state->addr,
CLIENT_ADDR_UNKNOWN),
+ client_port = ADDR_OR_EMPTY(state->port,
+ CLIENT_PORT_UNKNOWN),
service = var_smtpd_sasl_service,
user_realm = REALM_OR_NULL(var_smtpd_sasl_realm),
security_options = sasl_opts_val,
*/
typedef struct XSASL_SERVER_CREATE_ARGS {
VSTREAM *stream;
+ int addr_family;
const char *server_addr;
+ const char *server_port;
const char *client_addr;
+ const char *client_port;
const char *service;
const char *user_realm;
const char *security_options;
#define xsasl_server_create(impl, args) \
(impl)->create((impl), (args))
-#define XSASL_SERVER_CREATE(impl, args, a1, a2, a3, a4, a5, a6, a7) \
+#define XSASL_SERVER_CREATE(impl, args, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10) \
xsasl_server_create((impl), (((args)->a1), ((args)->a2), ((args)->a3), \
- ((args)->a4), ((args)->a5), ((args)->a6), ((args)->a7), (args)))
+ ((args)->a4), ((args)->a5), ((args)->a6), ((args)->a7), ((args)->a8), \
+ ((args)->a9), ((args)->a10), (args)))
#define xsasl_server_done(impl) (impl)->done((impl));
/*
/* System library. */
#include <sys_defs.h>
+#include <sys/socket.h>
#include <stdlib.h>
#include <string.h>
typedef const char *SERVEROUT_TYPE;
typedef const void *VOID_SERVEROUT_TYPE;
+#endif
+
+#ifndef NO_IP_CYRUS_SASL_AUTH
+#define USE_IP_CYRUS_SASL_AUTH
#endif
/*
XSASL_SERVER_CREATE_ARGS *args)
{
const char *myname = "xsasl_cyrus_server_create";
- char *server_address;
- char *client_address;
+ char *server_addr_port = 0;
+ char *client_addr_port = 0;
sasl_conn_t *sasl_conn = 0;
XSASL_CYRUS_SERVER *server = 0;
int sasl_status;
if (sasl_conn) \
sasl_dispose(&sasl_conn); \
} \
+ XSASL_CYRUS_SERVER_CREATE_RETURN(x); \
+ } while (0)
+
+#define XSASL_CYRUS_SERVER_CREATE_RETURN(x) \
+ do { \
+ if (server_addr_port) \
+ myfree(server_addr_port); \
+ if (client_addr_port) \
+ myfree(client_addr_port); \
return (x); \
} while (0)
#define NO_SESSION_CALLBACKS ((sasl_callback_t *) 0)
#define NO_AUTH_REALM ((char *) 0)
-#if SASL_VERSION_MAJOR >= 2 && defined(USE_SASL_IP_AUTH)
+#if SASL_VERSION_MAJOR >= 2 && defined(USE_IP_CYRUS_SASL_AUTH)
/*
- * Get IP addresses of local and remote endpoints for SASL.
+ * Get IP address and port of local and remote endpoints for SASL. Some
+ * implementation supports "[ipv6addr]:port" and "ipv4addr:port" (e.g.,
+ * https://illumos.org/man/3sasl/sasl_server_new), They still support the
+ * historical "address;port" syntax, so we stick with that for now.
*/
-#error "USE_SASL_IP_AUTH is not implemented"
-
+ server_addr_port = (*args->server_addr && *args->server_port ?
+ concatenate(args->server_addr, ";",
+ args->server_port, (char *) 0) : 0);
+ client_addr_port = (*args->client_addr && *args->client_port ?
+ concatenate(args->client_addr, ";",
+ args->client_port, (char *) 0) : 0);
#else
/*
- * Don't give any IP address information to SASL. SASLv1 doesn't use it,
- * and in SASLv2 this will disable any mechanisms that do.
+ * Don't give any IP address information to SASL.
*/
- server_address = 0;
- client_address = 0;
#endif
if ((sasl_status =
SASL_SERVER_NEW(args->service, var_myhostname,
args->user_realm ? args->user_realm : NO_AUTH_REALM,
- server_address, client_address,
+ server_addr_port, client_addr_port,
NO_SESSION_CALLBACKS, NO_SECURITY_LAYERS,
&sasl_conn)) != SASL_OK) {
msg_warn("SASL per-connection server initialization: %s",
!= XSASL_AUTH_OK)
XSASL_CYRUS_SERVER_CREATE_ERROR_RETURN(0);
- return (&server->xsasl);
+ XSASL_CYRUS_SERVER_CREATE_RETURN(&server->xsasl);
}
/* xsasl_cyrus_server_set_security - set security properties */
/* after successful authentication.
/*
/* Arguments:
+/* .IP addr_family
+/* The network address family: AF_INET6 or AF_INET.
/* .IP auth_method
/* AUTH command authentication method.
/* .IP client_addr
/* IPv4 or IPv6 address (no surrounding [] or ipv6: prefix),
/* or zero-length string if unavailable.
+/* .IP client_port
+/* TCP port or zero-length string if unavailable.
/* .IP init_resp
/* AUTH command initial response or null pointer.
/* .IP implementation
/* .IP server_addr
/* IPv4 or IPv6 address (no surrounding [] or ipv6: prefix),
/* or zero-length string if unavailable.
+/* .IP server_port
+/* TCP port or zero-length string if unavailable.
/* .IP server_reply
/* BASE64 encoded server non-error reply (without SMTP reply
/* code or enhanced status code), or ASCII error description.