Human factors: the postscreen/verify cache manager now logs
the full database name including the proxy: prefix, to avoid
WTF surprises. File: util/dict_cache.c.
+
+20111218
+
+ Cleanup: more configurable memcache client error handling.
+ Files: global/dict_memcache.c, proto/memcache_table.
+
+ Feature: the Postfix SMTP server XCLIENT command now supports
+ the LOGIN attribute (e.g., login information from nginx).
+ Based on the nginx:xclient-login-patch from citrin.ru (Anton
+ Yuzhis). The patch was further enhanced to support SASL
+ login information everywhere in the Postfix SMTP server
+ without having to specify "smtpd_sasl_auth_enable = yes"
+ in main.cf. Files: smtpd.[hc], smtpd_sasl_glue.[hc],
+ smtpd_check.c, smtpd_sasl_proto.[hc], smtpd_state.c,
+ proto/XCLIENT_README.html.
+
+ Incompatibility: the Postfix SMTP server now always checks
+ the smtpd_sender_login_maps table, even without having
+ "smtpd_sasl_auth_enable = yes" in main.cf.
xclient-command = XCLIENT 1*( SP attribute-name"="attribute-value )
- attribute-name = ( NAME | ADDR | PORT | PROTO | HELO )
+ attribute-name = ( NAME | ADDR | PORT | PROTO | HELO | LOGIN )
attribute-value = xtext
* The HELO attribute specifies an SMTP HELO parameter value, or the value
[UNAVAILABLE] when the information is unavailable.
+ * The LOGIN attribute specifies a SASL login name, or the value [UNAVAILABLE]
+ when the information is unavailable.
+
Note 1: syntactically valid NAME and HELO attribute-value elements can be up to
255 characters long. The client must not send XCLIENT commands that exceed the
512 character limit for SMTP commands. To avoid exceeding the limit the client
attribute values. Servers that wish to interoperate with these older
implementations should be prepared to receive unencoded information.
-Note 4: Postfix implementations prior to version 2.5 do not implement the PORT
-attribute.
+Note 4: Some Postfix implementations do not implement the PORT or LOGIN
+attributes.
X\bXC\bCL\bLI\bIE\bEN\bNT\bT S\bSe\ber\brv\bve\ber\br r\bre\bes\bsp\bpo\bon\bns\bse\be
If you upgrade from Postfix 2.7 or earlier, read RELEASE_NOTES-2.8
before proceeding.
+Incompatible changes with snapshot 201112XX
+===========================================
+
+To support external SASL authentication, the Postfix SMTP server
+now always checks the smtpd_sender_login_maps table, even without
+having "smtpd_sasl_auth_enable = yes" in main.cf.
+
+Major changes with snapshot 201112XX
+====================================
+
+Support for external SASL authentication via the XCLIENT command.
+This is used to accept SASL authentication from an SMTP proxy such
+as nginx. This support works even without having to specify
+"smtpd_sasl_auth_enable = yes" in main.cf.
+
Major changes with snapshot 20111213
====================================
Things to do before the stable release:
+ Remove this file from the stable release.
+
+ limits on attribute string length in IPC protocols. 10-20KB
+ seems OK. We could start with limits enabled only in proxymap.
+
Either make all void dict_* operations return an error code,
or require that they reset dict_errno on entry, either exit
with a fatal error or set dict_errno on error.
by msg_warn and longjmp? The callers will have to specify
if they want the code to return instead of terminate.
- Remove this file from the stable release.
-
Things to do after the stable release:
What is the feasibility of adding an mta_name (personality)
xclient-command = XCLIENT 1*( SP attribute-name"="attribute-value )
</p>
<p>
- attribute-name = ( NAME | ADDR | PORT | PROTO | HELO )
+ attribute-name = ( NAME | ADDR | PORT | PROTO | HELO | LOGIN )
</p>
<p>
attribute-value = xtext
value, or the value [UNAVAILABLE] when the information is
unavailable. </p>
+ <li> <p> The LOGIN attribute specifies a SASL login name, or
+ the value [UNAVAILABLE] when the information is unavailable.
+ </p>
+
</ul>
<p> Note 1: syntactically valid NAME and HELO attribute-value
with these older implementations should be prepared to receive
unencoded information. </p>
-<p> Note 4: Postfix implementations prior to version 2.5 do not
-implement the PORT attribute. </p>
+<p> Note 4: Some Postfix implementations do not implement the PORT
+or LOGIN attributes. </p>
<h2>XCLIENT Server response</h2>
operation requires a backup database that supports the
operation.
-<b>MEMCACHE PARAMETERS</b>
- <b>backup</b> An optional Postfix database that provides persis-
- tent backup for the memcache database. The Postfix
- memcache client will update the memcache database
- whenever it looks up or changes information in the
+<b>MEMCACHE MAIN PARAMETERS</b>
+ <b>memcache (default: inet:localhost:11211)</b>
+ The memcache server (note: singular) that Postfix
+ will try to connect to. For a TCP server specify
+ "inet:" followed by a hostname or address, ":", and
+ a port name or number. Specify an IPv6 address
+ inside "[]". For a UNIX-domain server specify
+ "unix:" followed by the socket pathname. Examples:
+
+ memcache = inet:memcache.example.com:11211
+ memcache = inet:127.0.0.1:11211
+ memcache = inet:[fc00:8d00:189::3]:11211
+ memcache = unix:/path/to/socket
+
+ NOTE: to access a UNIX-domain socket with the <a href="proxymap.8.html">prox-</a>
+ <a href="proxymap.8.html">ymap(8)</a> server, the socket must be accessible by
+ the unprivileged postfix user.
+
+ <b>backup (default: undefined)</b>
+ An optional Postfix database that provides persis-
+ tent backup for the memcache database. The Postfix
+ memcache client will update the memcache database
+ whenever it looks up or changes information in the
persistent database. Specify a Postfix "<a href="DATABASE_README.html">type:table</a>"
database. Examples:
Access to remote proxymap servers is under develop-
ment.
- NOTE 1: When using memcache with persistent backup
- as <a href="postscreen.8.html"><b>postscreen</b>(8)</a> or <a href="verify.8.html"><b>verify</b>(8)</a> cache, disable auto-
- matic cache cleanup (*_cache_cleanup_interval = 0)
- in all Postfix instances except for one instance
+ NOTE 1: When using memcache with persistent backup
+ as <a href="postscreen.8.html"><b>postscreen</b>(8)</a> or <a href="verify.8.html"><b>verify</b>(8)</a> cache, disable auto-
+ matic cache cleanup (*_cache_cleanup_interval = 0)
+ in all Postfix instances except for one instance
that will be responsible for cache cleanup.
NOTE 2: In the case of a proxied database, the full
- database name (including the "<a href="proxymap.8.html">proxy</a>:" prefix) must
- be specified in the proxymap server's
- <a href="postconf.5.html#proxy_read_maps">proxy_read_maps</a> or <a href="postconf.5.html#proxy_write_maps">proxy_write_maps</a> setting
- (depending on whether the access is read-only or
+ database name (including the "<a href="proxymap.8.html">proxy</a>:" prefix) must
+ be specified in the proxymap server's
+ <a href="postconf.5.html#proxy_read_maps">proxy_read_maps</a> or <a href="postconf.5.html#proxy_write_maps">proxy_write_maps</a> setting
+ (depending on whether the access is read-only or
read-write).
- <b>memcache (default: inet:localhost:11211)</b>
- The memcache server (note: singular) that Postfix
- will try to connect to. For a TCP server specify
- "inet:" followed by a hostname or address, ":", and
- a port name or number. For a UNIX-domain server
- specify "unix:" followed by the socket pathname.
- Examples:
+ <b>flags (default: 0)</b>
+ Optional flags that should be stored along with a
+ memcache update.
- memcache = inet:memcache.example.com
- memcache = unix:/path/to/socket
+ <b>ttl (default: 3600)</b>
+ The expiration time in seconds of memcache updates.
+
+ NOTE 1: When using a memcache table as
+ <a href="postscreen.8.html"><b>postscreen</b>(8)</a> or <a href="verify.8.html"><b>verify</b>(8)</a> cache without persistent
+ backup, specify a zero *_cache_cleanup_interval
+ value with all Postfix instances that use the mem-
+ cache, and specify the largest <a href="postscreen.8.html"><b>postscreen</b>(8)</a> *_ttl
+ value or <a href="verify.8.html"><b>verify</b>(8)</a> *_expire_time value as the mem-
+ cache table's <b>ttl</b> value.
- NOTE: In the case of a UNIX-domain socket, it must
- be accessible by the unprivileged postfix user and
- by the memcached process.
+ NOTE 2: According to memcache protocol documenta-
+ tion, a value greater than 30 days (2592000 sec-
+ onds) specifies absolute UNIX time. Smaller values
+ are relative to the time of the update.
+<b>MEMCACHE KEY PARAMETERS</b>
<b>key_format (default: %s)</b>
- Format of the lookup and update keys in memcache
- queries. By default, these are the same as the
- lookup and update keys that are given to the Post-
+ Format of the lookup and update keys in memcache
+ requests. By default, these are the same as the
+ lookup and update keys that are given to the Post-
fix memcache client.
+ NOTE: The <b>key_format</b> feature is not used for <b>backup</b>
+ database requests.
+
When the same memcache database is used to cache
information from multiple tables, you can use the
<b>key_format</b> feature to avoid name collisions by
domain = example.com, hash:/etc/postfix/searchdomains
- <b>flags (default: 0)</b>
- Optional flags that should be stored along with a
- memcache update.
+<b>MEMCACHE ERROR CONTROLS</b>
+ <b>data_size_limit (default: 10240)</b>
+ The maximal memcache reply data length in bytes.
- <b>ttl (default: 3600)</b>
- The expiration time in seconds of memcache updates.
+ <b>line_size_limit (default: 1024)</b>
+ The maximal memcache reply line length in bytes.
- NOTE 1: When using a memcache table as
- <a href="postscreen.8.html"><b>postscreen</b>(8)</a> or <a href="verify.8.html"><b>verify</b>(8)</a> cache without persistent
- backup, specify a zero *_cache_cleanup_interval
- value with all Postfix instances that use the mem-
- cache, and specify the largest <a href="postscreen.8.html"><b>postscreen</b>(8)</a> *_ttl
- value or <a href="verify.8.html"><b>verify</b>(8)</a> *_expire_time value as the mem-
- cache table's <b>ttl</b> value.
+ <b>max_try (default: 2)</b>
+ The number of times to try a memcache command
+ before giving up.
- NOTE 2: According to memcache protocol documenta-
- tion, a value greater than 30 days (2592000 sec-
- onds) specifies absolute UNIX time. Smaller values
- are relative to the time of the update.
+ <b>retry_pause (default: 1)</b>
+ The time in seconds to wait after a memcache com-
+ mand fails.
+
+ <b>timeout (default: 2)</b>
+ The time limit for sending a memcache command and
+ for receiving a memcache reply.
<b>BUGS</b>
The Postfix memcache client cannot be used for security-
The Postfix memcache client requires additional configura-
tion when used as <a href="postscreen.8.html"><b>postscreen</b>(8)</a> or <a href="verify.8.html"><b>verify</b>(8)</a> cache. For
details see the <b>backup</b> and <b>ttl</b> parameter discussions in
- the MEMCACHE PARAMETERS section above.
+ the MEMCACHE MAIN PARAMETERS section above.
<b>SEE ALSO</b>
<a href="postmap.1.html">postmap(1)</a>, Postfix lookup table manager
delete and sequence (first/next) operations. The sequence
operation requires a backup database that supports the
operation.
-.SH "MEMCACHE PARAMETERS"
+.SH "MEMCACHE MAIN PARAMETERS"
.na
.nf
.ad
.fi
-.IP \fBbackup\fR
+.IP "\fBmemcache (default: inet:localhost:11211)\fR"
+The memcache server (note: singular) that Postfix will try
+to connect to. For a TCP server specify "inet:" followed by
+a hostname or address, ":", and a port name or number.
+Specify an IPv6 address inside "[]".
+For a UNIX-domain server specify "unix:" followed by the
+socket pathname. Examples:
+
+.nf
+ memcache = inet:memcache.example.com:11211
+ memcache = inet:127.0.0.1:11211
+ memcache = inet:[fc00:8d00:189::3]:11211
+ memcache = unix:/path/to/socket
+.fi
+
+NOTE: to access a UNIX-domain socket with the proxymap(8)
+server, the socket must be accessible by the unprivileged
+postfix user.
+.IP "\fBbackup (default: undefined)\fR"
An optional Postfix database that provides persistent backup
for the memcache database. The Postfix memcache client will
update the memcache database whenever it looks up or changes
the proxymap server's proxy_read_maps or proxy_write_maps
setting (depending on whether the access is read-only or
read-write).
-.IP "\fBmemcache (default: inet:localhost:11211)\fR"
-The memcache server (note: singular) that Postfix will try
-to connect to. For a TCP server specify "inet:" followed by
-a hostname or address, ":", and a port name or number.
-For a UNIX-domain server specify "unix:" followed by the
-socket pathname. Examples:
+.IP "\fBflags (default: 0)\fR"
+Optional flags that should be stored along with a memcache
+update.
+.IP "\fBttl (default: 3600)\fR"
+The expiration time in seconds of memcache updates.
+NOTE 1: When using a memcache table as \fBpostscreen\fR(8)
+or \fBverify\fR(8) cache without persistent backup, specify
+a zero *_cache_cleanup_interval value with all Postfix
+instances that use the memcache, and specify the largest
+\fBpostscreen\fR(8) *_ttl value or \fBverify\fR(8) *_expire_time
+value as the memcache table's \fBttl\fR value.
+
+NOTE 2: According to memcache protocol documentation, a
+value greater than 30 days (2592000 seconds) specifies
+absolute UNIX
+time. Smaller values are relative to the time of the update.
+.SH "MEMCACHE KEY PARAMETERS"
+.na
.nf
- memcache = inet:memcache.example.com
- memcache = unix:/path/to/socket
+.ad
.fi
-
-NOTE: In the case of a UNIX-domain socket, it must be accessible
-by the unprivileged postfix user and by the memcached process.
.IP "\fBkey_format (default: %s)\fB"
-Format of the lookup and update keys in memcache queries.
+Format of the lookup and update keys in memcache requests.
By default, these are the same as the lookup and update
keys that are given to the Postfix memcache client.
+NOTE: The \fBkey_format\fR feature is not used for \fBbackup\fR
+database requests.
+
When the same memcache database is used to cache information
from multiple tables, you can use the \fBkey_format\fR
feature to avoid name collisions by prepending a fixed
.nf
domain = example.com, hash:/etc/postfix/searchdomains
.fi
-.IP "\fBflags (default: 0)\fR"
-Optional flags that should be stored along with a memcache
-update.
-.IP "\fBttl (default: 3600)\fR"
-The expiration time in seconds of memcache updates.
-
-NOTE 1: When using a memcache table as \fBpostscreen\fR(8)
-or \fBverify\fR(8) cache without persistent backup, specify
-a zero *_cache_cleanup_interval value with all Postfix
-instances that use the memcache, and specify the largest
-\fBpostscreen\fR(8) *_ttl value or \fBverify\fR(8) *_expire_time
-value as the memcache table's \fBttl\fR value.
-
-NOTE 2: According to memcache protocol documentation, a
-value greater than 30 days (2592000 seconds) specifies
-absolute UNIX
-time. Smaller values are relative to the time of the update.
+.SH "MEMCACHE ERROR CONTROLS"
+.na
+.nf
+.ad
+.fi
+.IP "\fBdata_size_limit (default: 10240)\fR"
+The maximal memcache reply data length in bytes.
+.IP "\fBline_size_limit (default: 1024)\fR"
+The maximal memcache reply line length in bytes.
+.IP "\fBmax_try (default: 2)\fR"
+The number of times to try a memcache command before giving up.
+.IP "\fBretry_pause (default: 1)\fR"
+The time in seconds to wait after a memcache command fails.
+.IP "\fBtimeout (default: 2)\fR"
+The time limit for sending a memcache command and for
+receiving a memcache reply.
.SH BUGS
.ad
.fi
The Postfix memcache client requires additional configuration
when used as \fBpostscreen\fR(8) or \fBverify\fR(8) cache.
For details see the \fBbackup\fR and \fBttl\fR parameter
-discussions in the MEMCACHE PARAMETERS section above.
+discussions in the MEMCACHE MAIN PARAMETERS section above.
.SH "SEE ALSO"
.na
.nf
xclient-command = XCLIENT 1*( SP attribute-name"="attribute-value )
</p>
<p>
- attribute-name = ( NAME | ADDR | PORT | PROTO | HELO )
+ attribute-name = ( NAME | ADDR | PORT | PROTO | HELO | LOGIN )
</p>
<p>
attribute-value = xtext
value, or the value [UNAVAILABLE] when the information is
unavailable. </p>
+ <li> <p> The LOGIN attribute specifies a SASL login name, or
+ the value [UNAVAILABLE] when the information is unavailable.
+ </p>
+
</ul>
<p> Note 1: syntactically valid NAME and HELO attribute-value
with these older implementations should be prepared to receive
unencoded information. </p>
-<p> Note 4: Postfix implementations prior to version 2.5 do not
-implement the PORT attribute. </p>
+<p> Note 4: Some Postfix implementations do not implement the PORT
+or LOGIN attributes. </p>
<h2>XCLIENT Server response</h2>
# delete and sequence (first/next) operations. The sequence
# operation requires a backup database that supports the
# operation.
-# MEMCACHE PARAMETERS
+# MEMCACHE MAIN PARAMETERS
# .ad
# .fi
-# .IP \fBbackup\fR
+# .IP "\fBmemcache (default: inet:localhost:11211)\fR"
+# The memcache server (note: singular) that Postfix will try
+# to connect to. For a TCP server specify "inet:" followed by
+# a hostname or address, ":", and a port name or number.
+# Specify an IPv6 address inside "[]".
+# For a UNIX-domain server specify "unix:" followed by the
+# socket pathname. Examples:
+#
+# .nf
+# memcache = inet:memcache.example.com:11211
+# memcache = inet:127.0.0.1:11211
+# memcache = inet:[fc00:8d00:189::3]:11211
+# memcache = unix:/path/to/socket
+# .fi
+#
+# NOTE: to access a UNIX-domain socket with the proxymap(8)
+# server, the socket must be accessible by the unprivileged
+# postfix user.
+# .IP "\fBbackup (default: undefined)\fR"
# An optional Postfix database that provides persistent backup
# for the memcache database. The Postfix memcache client will
# update the memcache database whenever it looks up or changes
# the proxymap server's proxy_read_maps or proxy_write_maps
# setting (depending on whether the access is read-only or
# read-write).
-# .IP "\fBmemcache (default: inet:localhost:11211)\fR"
-# The memcache server (note: singular) that Postfix will try
-# to connect to. For a TCP server specify "inet:" followed by
-# a hostname or address, ":", and a port name or number.
-# For a UNIX-domain server specify "unix:" followed by the
-# socket pathname. Examples:
+# .IP "\fBflags (default: 0)\fR"
+# Optional flags that should be stored along with a memcache
+# update.
+# .IP "\fBttl (default: 3600)\fR"
+# The expiration time in seconds of memcache updates.
#
-# .nf
-# memcache = inet:memcache.example.com
-# memcache = unix:/path/to/socket
-# .fi
+# NOTE 1: When using a memcache table as \fBpostscreen\fR(8)
+# or \fBverify\fR(8) cache without persistent backup, specify
+# a zero *_cache_cleanup_interval value with all Postfix
+# instances that use the memcache, and specify the largest
+# \fBpostscreen\fR(8) *_ttl value or \fBverify\fR(8) *_expire_time
+# value as the memcache table's \fBttl\fR value.
#
-# NOTE: In the case of a UNIX-domain socket, it must be accessible
-# by the unprivileged postfix user and by the memcached process.
+# NOTE 2: According to memcache protocol documentation, a
+# value greater than 30 days (2592000 seconds) specifies
+# absolute UNIX
+# time. Smaller values are relative to the time of the update.
+# MEMCACHE KEY PARAMETERS
+# .ad
+# .fi
# .IP "\fBkey_format (default: %s)\fB"
-# Format of the lookup and update keys in memcache queries.
+# Format of the lookup and update keys in memcache requests.
# By default, these are the same as the lookup and update
# keys that are given to the Postfix memcache client.
#
+# NOTE: The \fBkey_format\fR feature is not used for \fBbackup\fR
+# database requests.
+#
# When the same memcache database is used to cache information
# from multiple tables, you can use the \fBkey_format\fR
# feature to avoid name collisions by prepending a fixed
# .nf
# domain = example.com, hash:/etc/postfix/searchdomains
# .fi
-# .IP "\fBflags (default: 0)\fR"
-# Optional flags that should be stored along with a memcache
-# update.
-# .IP "\fBttl (default: 3600)\fR"
-# The expiration time in seconds of memcache updates.
-#
-# NOTE 1: When using a memcache table as \fBpostscreen\fR(8)
-# or \fBverify\fR(8) cache without persistent backup, specify
-# a zero *_cache_cleanup_interval value with all Postfix
-# instances that use the memcache, and specify the largest
-# \fBpostscreen\fR(8) *_ttl value or \fBverify\fR(8) *_expire_time
-# value as the memcache table's \fBttl\fR value.
-#
-# NOTE 2: According to memcache protocol documentation, a
-# value greater than 30 days (2592000 seconds) specifies
-# absolute UNIX
-# time. Smaller values are relative to the time of the update.
+# MEMCACHE ERROR CONTROLS
+# .ad
+# .fi
+# .IP "\fBdata_size_limit (default: 10240)\fR"
+# The maximal memcache reply data length in bytes.
+# .IP "\fBline_size_limit (default: 1024)\fR"
+# The maximal memcache reply line length in bytes.
+# .IP "\fBmax_try (default: 2)\fR"
+# The number of times to try a memcache command before giving up.
+# .IP "\fBretry_pause (default: 1)\fR"
+# The time in seconds to wait after a memcache command fails.
+# .IP "\fBtimeout (default: 2)\fR"
+# The time limit for sending a memcache command and for
+# receiving a memcache reply.
# BUGS
# The Postfix memcache client cannot be used for security-sensitive
# tables such as \fBalias_maps\fR (these may contain
# The Postfix memcache client requires additional configuration
# when used as \fBpostscreen\fR(8) or \fBverify\fR(8) cache.
# For details see the \fBbackup\fR and \fBttl\fR parameter
-# discussions in the MEMCACHE PARAMETERS section above.
+# discussions in the MEMCACHE MAIN PARAMETERS section above.
# SEE ALSO
# postmap(1), Postfix lookup table manager
# postconf(5), configuration parameters
/* System library. */
#include <sys_defs.h>
+#include <errno.h>
#include <string.h>
#include <ctype.h>
#include <stdio.h> /* XXX sscanf() */
void *dbc_ctxt; /* db_common context */
char *key_format; /* query key translation */
int timeout; /* client timeout */
- int mc_ttl; /* memcache expiration */
- int mc_flags; /* memcache flags */
- int mc_pause; /* sleep between errors */
- int mc_maxtry; /* number of tries */
+ int mc_ttl; /* memcache update expiration */
+ int mc_flags; /* memcache update flags */
+ int err_pause; /* delay between errors */
+ int max_tries; /* number of tries */
+ int max_line; /* reply line limit */
+ int max_data; /* reply data limit */
char *memcache; /* memcache server spec */
AUTO_CLNT *clnt; /* memcache client stream */
VSTRING *clnt_buf; /* memcache client buffer */
} DICT_MC;
/*
- * Default memcache options.
+ * Memcache option defaults and names.
*/
#define DICT_MC_DEF_HOST "localhost"
#define DICT_MC_DEF_PORT "11211"
#define DICT_MC_DEF_MC_TTL 3600
#define DICT_MC_DEF_MC_TIMEOUT 2
#define DICT_MC_DEF_MC_FLAGS 0
-#define DICT_MC_DEF_MC_MAXTRY 2
-#define DICT_MC_DEF_MC_PAUSE 1
+#define DICT_MC_DEF_MAX_TRY 2
+#define DICT_MC_DEF_MAX_LINE 1024
+#define DICT_MC_DEF_MAX_DATA 10240
+#define DICT_MC_DEF_ERR_PAUSE 1
+
+#define DICT_MC_NAME_MEMCACHE "memcache"
+#define DICT_MC_NAME_BACKUP "backup"
+#define DICT_MC_NAME_KEY_FMT "key_format"
+#define DICT_MC_NAME_MC_TTL "ttl"
+#define DICT_MC_NAME_MC_TIMEOUT "timeout"
+#define DICT_MC_NAME_MC_FLAGS "flags"
+#define DICT_MC_NAME_MAX_TRY "max_try"
+#define DICT_MC_NAME_MAX_LINE "line_size_limit"
+#define DICT_MC_NAME_MAX_DATA "data_size_limit"
+#define DICT_MC_NAME_ERR_PAUSE "retry_pause"
/*
* SLMs.
{
VSTREAM *fp;
int count;
+ int data_len = strlen(value);
-#define MC_LINE_LIMIT 1024
-
- dict_mc->mc_errno = DICT_ERR_RETRY;
- for (count = 0; count < dict_mc->mc_maxtry; count++) {
+ /*
+ * If we can't retrieve it, then we must not store it.
+ */
+ dict_mc->mc_errno = DICT_ERR_RETRY; /* XXX */
+ if (data_len > dict_mc->max_data) {
+ msg_warn("database %s:%s: data for key %s is too long (%s=%d) "
+ "-- not stored", DICT_TYPE_MEMCACHE, dict_mc->dict.name,
+ STR(dict_mc->key_buf), DICT_MC_NAME_MAX_DATA,
+ dict_mc->max_data);
+ return;
+ }
+ for (count = 0; count < dict_mc->max_tries; count++) {
if (count > 0)
- sleep(1);
- if ((fp = auto_clnt_access(dict_mc->clnt)) != 0) {
+ sleep(dict_mc->err_pause);
+ if ((fp = auto_clnt_access(dict_mc->clnt)) == 0) {
+ if (errno == ECONNREFUSED)
+ break;
+ } else {
if (memcache_printf(fp, "set %s %d %d %ld",
STR(dict_mc->key_buf), dict_mc->mc_flags,
- ttl, strlen(value)) < 0
+ ttl, data_len) < 0
|| memcache_fwrite(fp, value, strlen(value)) < 0
- || memcache_get(fp, dict_mc->clnt_buf, MC_LINE_LIMIT) < 0) {
+ || memcache_get(fp, dict_mc->clnt_buf,
+ dict_mc->max_line) < 0) {
if (count > 0)
- msg_warn("database %s:%s: I/O error: %m",
+ msg_warn(errno ? "database %s:%s: I/O error: %m" :
+ "database %s:%s: I/O error",
DICT_TYPE_MEMCACHE, dict_mc->dict.name);
- auto_clnt_recover(dict_mc->clnt);
} else if (strcmp(STR(dict_mc->clnt_buf), "STORED") != 0) {
if (count > 0)
msg_warn("database %s:%s: update failed: %.30s",
DICT_TYPE_MEMCACHE, dict_mc->dict.name,
STR(dict_mc->clnt_buf));
- auto_clnt_recover(dict_mc->clnt);
} else {
/* Victory! */
dict_mc->mc_errno = 0;
break;
}
}
+ auto_clnt_recover(dict_mc->clnt);
}
}
dict_mc->mc_errno = DICT_ERR_RETRY;
retval = 0;
- for (count = 0; count < dict_mc->mc_maxtry; count++) {
+ for (count = 0; count < dict_mc->max_tries; count++) {
if (count > 0)
- sleep(1);
- if ((fp = auto_clnt_access(dict_mc->clnt)) != 0) {
+ sleep(dict_mc->err_pause);
+ if ((fp = auto_clnt_access(dict_mc->clnt)) == 0) {
+ if (errno == ECONNREFUSED)
+ break;
+ } else {
if (memcache_printf(fp, "get %s", STR(dict_mc->key_buf)) < 0
- || memcache_get(fp, dict_mc->clnt_buf, MC_LINE_LIMIT) < 0) {
+ || memcache_get(fp, dict_mc->clnt_buf, dict_mc->max_line) < 0) {
if (count > 0)
- msg_warn("database %s:%s: I/O error: %m",
+ msg_warn(errno ? "database %s:%s: I/O error: %m" :
+ "database %s:%s: I/O error",
DICT_TYPE_MEMCACHE, dict_mc->dict.name);
- auto_clnt_recover(dict_mc->clnt);
} else if (strcmp(STR(dict_mc->clnt_buf), "END") == 0) {
/* Not found. */
dict_mc->mc_errno = 0;
break;
} else if (sscanf(STR(dict_mc->clnt_buf),
- "VALUE %*s %*s %ld", &todo) != 1 || todo < 0) {
+ "VALUE %*s %*s %ld", &todo) != 1
+ || todo < 0 || todo > dict_mc->max_data) {
if (count > 0)
msg_warn("%s: unexpected memcache server reply: %.30s",
dict_mc->dict.name, STR(dict_mc->clnt_buf));
- auto_clnt_recover(dict_mc->clnt);
} else if (memcache_fread(fp, dict_mc->res_buf, todo) < 0) {
if (count > 0)
msg_warn("%s: EOF receiving memcache server reply",
dict_mc->dict.name);
- auto_clnt_recover(dict_mc->clnt);
} else {
/* Victory! */
retval = STR(dict_mc->res_buf);
dict_mc->mc_errno = 0;
- if (memcache_get(fp, dict_mc->clnt_buf, MC_LINE_LIMIT) < 0
+ if (memcache_get(fp, dict_mc->clnt_buf, dict_mc->max_line) < 0
|| strcmp(STR(dict_mc->clnt_buf), "END") != 0)
auto_clnt_recover(dict_mc->clnt);
break;
}
}
+ auto_clnt_recover(dict_mc->clnt);
+ }
+ return (retval);
+}
+
+/* dict_memcache_del - delete memcache key/value */
+
+static int dict_memcache_del(DICT_MC *dict_mc)
+{
+ VSTREAM *fp;
+ int count;
+ int retval = -1;
+
+ dict_mc->mc_errno = DICT_ERR_RETRY;
+ for (count = 0; count < dict_mc->max_tries; count++) {
+ if (count > 0)
+ sleep(dict_mc->err_pause);
+ if ((fp = auto_clnt_access(dict_mc->clnt)) == 0) {
+ if (errno == ECONNREFUSED)
+ break;
+ } else {
+ if (memcache_printf(fp, "delete %s", STR(dict_mc->key_buf)) < 0
+ || memcache_get(fp, dict_mc->clnt_buf,
+ dict_mc->max_line) < 0) {
+ if (count > 0)
+ msg_warn(errno ? "database %s:%s: I/O error: %m" :
+ "database %s:%s: I/O error",
+ DICT_TYPE_MEMCACHE, dict_mc->dict.name);
+ } else if (strcmp(STR(dict_mc->clnt_buf), "DELETED") == 0) {
+ /* Victory! */
+ dict_mc->mc_errno = 0;
+ retval = 0;
+ break;
+ } else if (strcmp(STR(dict_mc->clnt_buf), "NOT_FOUND") == 0) {
+ /* Not found! */
+ dict_mc->mc_errno = 0;
+ retval = 1;
+ break;
+ } else {
+ if (count > 0)
+ msg_warn("database %s:%s: delete failed: %.30s",
+ DICT_TYPE_MEMCACHE, dict_mc->dict.name,
+ STR(dict_mc->clnt_buf));
+ }
+ }
+ auto_clnt_recover(dict_mc->clnt);
}
return (retval);
}
dict_memcache_set(dict_mc, value, dict_mc->mc_ttl);
if (msg_verbose)
- msg_info("%s: %s: update key \"%s\" => \"%s\" %s",
- myname, dict_mc->dict.name, STR(dict_mc->key_buf), value,
- dict_mc->mc_errno ? "(memcache error)" :
+ msg_info("%s: %s: update key \"%s\"(%s) => \"%s\" %s",
+ myname, dict_mc->dict.name, name, STR(dict_mc->key_buf),
+ value, dict_mc->mc_errno ? "(memcache error)" :
backup_errno ? "(backup error)" : "(no error)");
- dict_errno = (backup_errno ? backup_errno : dict_mc->mc_errno);
+ dict_errno = (dict_mc->backup ? backup_errno : dict_mc->mc_errno);
}
/* dict_memcache_lookup - lookup memcache */
dict_memcache_set(dict_mc, retval, dict_mc->mc_ttl);
}
if (msg_verbose)
- msg_info("%s: %s: key %s => %s",
- myname, dict_mc->dict.name, STR(dict_mc->key_buf),
- retval ? retval :
- dict_mc->mc_errno ? "(memcache error)" :
+ msg_info("%s: %s: key \"%s\"(%s) => %s",
+ myname, dict_mc->dict.name, name, STR(dict_mc->key_buf),
+ retval ? retval : dict_mc->mc_errno ? "(memcache error)" :
backup_errno ? "(backup error)" : "(not found)");
+ dict_errno = (dict_mc->backup ? backup_errno : dict_mc->mc_errno);
+
return (retval);
}
{
const char *myname = "dict_memcache_delete";
DICT_MC *dict_mc = (DICT_MC *) dict;
- const char *retval;
int backup_errno = 0;
int del_res = 0;
+ int mem_res;
/*
* Skip lookups with an inapplicable key, silently. This is just deleting
}
/*
- * Update the memcache last. There is no memcache delete operation.
- * Instead, we set a short expiration time if the data exists.
+ * Update the memcache last.
*/
- if ((retval = dict_memcache_get(dict_mc)) != 0)
- dict_memcache_set(dict_mc, retval, 1);
+ mem_res = dict_memcache_del(dict_mc);
if (msg_verbose)
- msg_info("%s: %s: delete key %s => %s",
- myname, dict_mc->dict.name, STR(dict_mc->key_buf),
+ msg_info("%s: %s: delete key \"%s\"(%s) => %s",
+ myname, dict_mc->dict.name, name, STR(dict_mc->key_buf),
dict_mc->mc_errno ? "(memcache error)" :
backup_errno ? "(backup error)" : "(no error)");
- dict_errno = (backup_errno ? backup_errno : dict_mc->mc_errno);
+ dict_errno = (dict_mc->backup ? backup_errno : dict_mc->mc_errno);
- return (del_res);
+ return (dict_mc->backup ? del_res : mem_res);
}
/* dict_memcache_sequence - first/next lookup */
* Parse the configuration file.
*/
dict_mc->parser = cfg_parser_alloc(name);
- dict_mc->key_format = cfg_get_str(dict_mc->parser, "key_format",
+ dict_mc->key_format = cfg_get_str(dict_mc->parser, DICT_MC_NAME_KEY_FMT,
DICT_MC_DEF_KEY_FMT, 0, 0);
- dict_mc->timeout = cfg_get_int(dict_mc->parser, "timeout",
+ dict_mc->timeout = cfg_get_int(dict_mc->parser, DICT_MC_NAME_MC_TIMEOUT,
DICT_MC_DEF_MC_TIMEOUT, 0, 0);
- dict_mc->mc_ttl = cfg_get_int(dict_mc->parser, "ttl",
+ dict_mc->mc_ttl = cfg_get_int(dict_mc->parser, DICT_MC_NAME_MC_TTL,
DICT_MC_DEF_MC_TTL, 0, 0);
- dict_mc->mc_flags = cfg_get_int(dict_mc->parser, "flags",
+ dict_mc->mc_flags = cfg_get_int(dict_mc->parser, DICT_MC_NAME_MC_FLAGS,
DICT_MC_DEF_MC_FLAGS, 0, 0);
- dict_mc->mc_pause = cfg_get_int(dict_mc->parser, "error_pause",
- DICT_MC_DEF_MC_PAUSE, 1, 0);
- dict_mc->mc_maxtry = cfg_get_int(dict_mc->parser, "maxtry",
- DICT_MC_DEF_MC_MAXTRY, 1, 0);
- dict_mc->memcache = cfg_get_str(dict_mc->parser, "memcache",
+ dict_mc->err_pause = cfg_get_int(dict_mc->parser, DICT_MC_NAME_ERR_PAUSE,
+ DICT_MC_DEF_ERR_PAUSE, 1, 0);
+ dict_mc->max_tries = cfg_get_int(dict_mc->parser, DICT_MC_NAME_MAX_TRY,
+ DICT_MC_DEF_MAX_TRY, 1, 0);
+ dict_mc->max_line = cfg_get_int(dict_mc->parser, DICT_MC_NAME_MAX_LINE,
+ DICT_MC_DEF_MAX_LINE, 1, 0);
+ dict_mc->max_data = cfg_get_int(dict_mc->parser, DICT_MC_NAME_MAX_DATA,
+ DICT_MC_DEF_MAX_DATA, 1, 0);
+ dict_mc->memcache = cfg_get_str(dict_mc->parser, DICT_MC_NAME_MEMCACHE,
DICT_MC_DEF_MEMCACHE, 0, 0);
/*
/*
* Open the optional backup database.
*/
- backup = cfg_get_str(dict_mc->parser, "backup", (char *) 0, 0, 0);
+ backup = cfg_get_str(dict_mc->parser, DICT_MC_NAME_BACKUP,
+ (char *) 0, 0, 0);
if (backup) {
dict_mc->backup = dict_open(backup, open_flags, dict_flags);
myfree(backup);
#define XCLIENT_PORT "PORT" /* client port */
#define XCLIENT_PROTO "PROTO" /* client protocol */
#define XCLIENT_HELO "HELO" /* client helo */
+#define XCLIENT_LOGIN "LOGIN" /* SASL login name */
#define XCLIENT_UNAVAILABLE "[UNAVAILABLE]" /* permanently unavailable */
#define XCLIENT_TEMPORARY "[TEMPUNAVAIL]" /* temporarily unavailable */
* Patches change both the patchlevel and the release date. Snapshots have no
* patchlevel; they change the release date only.
*/
-#define MAIL_RELEASE_DATE "20111217"
+#define MAIL_RELEASE_DATE "20111218"
#define MAIL_VERSION_NUMBER "2.9"
#ifdef SNAPSHOT
state->sasl_mechanism_list);
}
}
+#define XCLIENT_LOGIN_KLUDGE " " XCLIENT_LOGIN
+#else
+#define XCLIENT_LOGIN_KLUDGE ""
#endif
if ((discard_mask & EHLO_MASK_VERP) == 0)
if (namadr_list_match(verp_clients, state->name, state->addr))
ENQUEUE_FIX_REPLY(state, reply_buf, XCLIENT_CMD
" " XCLIENT_NAME " " XCLIENT_ADDR
" " XCLIENT_PROTO " " XCLIENT_HELO
- " " XCLIENT_REVERSE_NAME " " XCLIENT_PORT);
+ " " XCLIENT_REVERSE_NAME " " XCLIENT_PORT
+ XCLIENT_LOGIN_KLUDGE);
if ((discard_mask & EHLO_MASK_XFORWARD) == 0)
if (xforward_allowed)
ENQUEUE_FIX_REPLY(state, reply_buf, XFORWARD_CMD
rec_fprintf(state->cleanup, REC_TYPE_ATTR, "%s=%s",
MAIL_ATTR_RWR_CONTEXT, FORWARD_DOMAIN(state));
#ifdef USE_SASL_AUTH
- if (smtpd_sasl_is_active(state)) {
- if (state->sasl_method)
- rec_fprintf(state->cleanup, REC_TYPE_ATTR, "%s=%s",
- MAIL_ATTR_SASL_METHOD, state->sasl_method);
- if (state->sasl_username)
- rec_fprintf(state->cleanup, REC_TYPE_ATTR, "%s=%s",
- MAIL_ATTR_SASL_USERNAME, state->sasl_username);
- if (state->sasl_sender)
- rec_fprintf(state->cleanup, REC_TYPE_ATTR, "%s=%s",
- MAIL_ATTR_SASL_SENDER, state->sasl_sender);
- }
+ /* Make external authentication painless (e.g., XCLIENT). */
+ if (state->sasl_method)
+ rec_fprintf(state->cleanup, REC_TYPE_ATTR, "%s=%s",
+ MAIL_ATTR_SASL_METHOD, state->sasl_method);
+ if (state->sasl_username)
+ rec_fprintf(state->cleanup, REC_TYPE_ATTR, "%s=%s",
+ MAIL_ATTR_SASL_USERNAME, state->sasl_username);
+ if (state->sasl_sender)
+ rec_fprintf(state->cleanup, REC_TYPE_ATTR, "%s=%s",
+ MAIL_ATTR_SASL_SENDER, state->sasl_sender);
#endif
/*
* Log the queue ID with the message origin.
*/
#ifdef USE_SASL_AUTH
- if (smtpd_sasl_is_active(state))
+ if (state->sasl_username)
smtpd_sasl_mail_log(state);
else
#endif
return (-1);
}
#ifdef USE_SASL_AUTH
- } else if (smtpd_sasl_is_active(state)
- && strncasecmp(arg, "AUTH=", 5) == 0) {
+ } else if (strncasecmp(arg, "AUTH=", 5) == 0) {
if ((err = smtpd_sasl_mail_opt(state, arg + 5)) != 0) {
smtpd_chat_reply(state, "%s", err);
return (-1);
state->saved_delay = 0;
#endif
#ifdef USE_SASL_AUTH
- if (smtpd_sasl_is_active(state))
+ if (state->sasl_sender)
smtpd_sasl_mail_reset(state);
#endif
state->discard = 0;
#endif
rfc3848_sess = "";
#ifdef USE_SASL_AUTH
- if (smtpd_sasl_is_active(state) && var_smtpd_sasl_auth_hdr
- && state->sasl_username) {
+ if (var_smtpd_sasl_auth_hdr && state->sasl_username) {
username = VSTRING_STRDUP(state->sasl_username);
comment_sanitize(username);
out_fprintf(out_stream, REC_TYPE_NORM,
vstring_free(username);
}
/* RFC 3848 is defined for ESMTP only. */
- if (smtpd_sasl_is_active(state) && state->sasl_username
+ if (state->sasl_username
&& strcmp(state->protocol, MAIL_PROTO_ESMTP) == 0)
rfc3848_auth = "A";
else
};
int got_helo = 0;
int got_proto = 0;
+ int got_login = 0;
/*
* Sanity checks.
got_proto = 1;
}
+ /*
+ * LOGIN=sasl_username. Sets the authentication method as XCLIENT.
+ * This can be used even if SASL authentication is turned off in
+ * main.cf. We can't make it easier than that.
+ */
+#ifdef USE_SASL_AUTH
+ else if (STREQ(attr_name, XCLIENT_LOGIN)) {
+ if (STREQ(attr_value, XCLIENT_UNAVAILABLE) == 0) {
+ smtpd_sasl_auth_extern(state, attr_value, XCLIENT_CMD);
+ got_login = 1;
+ }
+ }
+#endif
+
/*
* Unknown attribute name. Complain.
*/
state->protocol = mystrdup(MAIL_PROTO_SMTP);
}
#ifdef USE_SASL_AUTH
- if (smtpd_sasl_is_active(state))
+ if (got_login == 0)
smtpd_sasl_auth_reset(state);
#endif
chat_reset(state, 0);
#endif
helo_reset(state);
#ifdef USE_SASL_AUTH
+ smtpd_sasl_auth_reset(state);
if (smtpd_sasl_is_active(state)) {
- smtpd_sasl_auth_reset(state);
smtpd_sasl_deactivate(state);
}
#endif
/*
* XCLIENT must not override its own access control.
*/
- xclient_allowed =
+ xclient_allowed = SMTPD_STAND_ALONE((&state)) == 0 &&
namadr_list_match(xclient_hosts, state.name, state.addr);
/*
* Overriding XFORWARD access control makes no sense, either.
*/
- xforward_allowed =
+ xforward_allowed = SMTPD_STAND_ALONE((&state)) == 0 &&
namadr_list_match(xforward_hosts, state.name, state.addr);
/*
#define CLIENT_PROTO_UNKNOWN CLIENT_ATTR_UNKNOWN
#define CLIENT_IDENT_UNKNOWN 0
#define CLIENT_DOMAIN_UNKNOWN 0
+#define CLIENT_LOGIN_UNKNOWN 0
#define IS_AVAIL_CLIENT_ATTR(v) ((v) && strcmp((v), CLIENT_ATTR_UNKNOWN))
const char *def_acl)
{
int result = SMTPD_CHECK_DUNNO;
+
#ifdef USE_TLS
const char *myname = "check_ccert_access";
int found;
char *name;
int found = 0;
- /*
- * Replace obscure code by self-evident code.
- */
-#define SMTPD_SASL_AUTHENTICATED(state) \
- (smtpd_sasl_is_active(state) && state->sasl_username != 0)
-
/*
* Reject if the client is logged in and does not own the sender address.
*/
- if (var_smtpd_sasl_enable && SMTPD_SASL_AUTHENTICATED(state)) {
+ if (smtpd_sender_login_maps && state->sasl_username) {
reply = smtpd_resolve_addr(sender);
if (reply->flags & RESOLVE_FLAG_FAIL)
reject_dict_retry(state, sender);
* Reject if the client is not logged in and the sender address has an
* owner.
*/
- if (var_smtpd_sasl_enable && !SMTPD_SASL_AUTHENTICATED(state)) {
+ if (smtpd_sender_login_maps && !state->sasl_username) {
reply = smtpd_resolve_addr(sender);
if (reply->flags & RESOLVE_FLAG_FAIL)
reject_dict_retry(state, sender);
ATTR_TYPE_STR, MAIL_ATTR_STRESS, var_stress,
#ifdef USE_SASL_AUTH
ATTR_TYPE_STR, MAIL_ATTR_SASL_METHOD,
- smtpd_sasl_is_active(state) && state->sasl_method ?
- state->sasl_method : "",
+ state->sasl_method ? state->sasl_method : "",
ATTR_TYPE_STR, MAIL_ATTR_SASL_USERNAME,
- smtpd_sasl_is_active(state) && state->sasl_username ?
- state->sasl_username : "",
+ state->sasl_username ? state->sasl_username : "",
ATTR_TYPE_STR, MAIL_ATTR_SASL_SENDER,
- smtpd_sasl_is_active(state) && state->sasl_sender ?
- state->sasl_sender : "",
+ state->sasl_sender ? state->sasl_sender : "",
#endif
#ifdef USE_TLS
#define IF_ENCRYPTED(x, y) ((state->tls_context && ((x) != 0)) ? (x) : (y))
/* SYNOPSIS
/* #include "smtpd_sasl_glue.h"
/*
+/* void smtpd_sasl_state_init(state)
+/* SMTPD_STATE *state;
+/*
/* void smtpd_sasl_initialize()
/*
/* void smtpd_sasl_activate(state, sasl_opts_name, sasl_opts_val)
/* void smtpd_sasl_logout(state)
/* SMTPD_STATE *state;
/*
+/* void smtpd_sasl_login(state, sasl_username, sasl_method)
+/* SMTPD_STATE *state;
+/* const char *sasl_username;
+/* const char *sasl_method;
+/*
/* void smtpd_sasl_deactivate(state)
/* SMTPD_STATE *state;
/*
/* This module encapsulates most of the detail specific to SASL
/* authentication.
/*
+/* smtpd_sasl_state_init() performs minimal server state
+/* initialization to support external authentication (e.g.,
+/* XCLIENT) without having to enable SASL in main.cf. This
+/* should always be called at process startup.
+/*
/* smtpd_sasl_initialize() initializes the SASL library. This
/* routine should be called once at process start-up. It may
/* need access to the file system for run-time loading of
/* This member is a null pointer in the absence of successful
/* authentication.
/* .PP
+/* smtpd_sasl_login() records the result of successful external
+/* authentication, i.e. without invoking smtpd_sasl_authenticate(),
+/* but produces an otherwise equivalent result.
+/*
/* smtpd_sasl_logout() cleans up after smtpd_sasl_authenticate().
/* This routine exists for the sake of symmetry.
/*
*/
state->sasl_reply = vstring_alloc(20);
state->sasl_mechanism_list = 0;
- state->sasl_username = 0;
- state->sasl_method = 0;
- state->sasl_sender = 0;
/*
* Set up a new server context for this connection.
client_addr = ADDR_OR_EMPTY(state->addr,
CLIENT_ADDR_UNKNOWN),
service = SMTPD_SASL_SERVICE,
- user_realm = REALM_OR_NULL(var_smtpd_sasl_realm),
+ user_realm = REALM_OR_NULL(var_smtpd_sasl_realm),
security_options = sasl_opts_val,
tls_flag = tls_flag)) == 0)
msg_fatal("SASL per-connection initialization failed");
state->sasl_mechanism_list = mystrdup(mechanism_list);
}
+/* smtpd_sasl_state_init - initialize state to allow extern authentication. */
+
+void smtpd_sasl_state_init(SMTPD_STATE *state)
+{
+ /* Initialization to support external authentication (e.g., XCLIENT). */
+ state->sasl_username = 0;
+ state->sasl_method = 0;
+ state->sasl_sender = 0;
+}
+
/* smtpd_sasl_deactivate - per-connection cleanup */
void smtpd_sasl_deactivate(SMTPD_STATE *state)
}
}
+/* smtpd_sasl_login - set login information */
+
+void smtpd_sasl_login(SMTPD_STATE *state, const char *sasl_username,
+ const char *sasl_method)
+{
+ if (state->sasl_username)
+ myfree(state->sasl_username);
+ state->sasl_username = mystrdup(sasl_username);
+ if (state->sasl_method)
+ myfree(state->sasl_method);
+ state->sasl_method = mystrdup(sasl_method);
+}
+
#endif
/*
* SASL protocol interface
*/
+extern void smtpd_sasl_state_init(SMTPD_STATE *);
extern void smtpd_sasl_initialize(void);
extern void smtpd_sasl_activate(SMTPD_STATE *, const char *, const char *);
extern void smtpd_sasl_deactivate(SMTPD_STATE *);
extern int smtpd_sasl_authenticate(SMTPD_STATE *, const char *, const char *);
+extern void smtpd_sasl_login(SMTPD_STATE *, const char *, const char *);
extern void smtpd_sasl_logout(SMTPD_STATE *);
extern int permit_sasl_auth(SMTPD_STATE *, int, int);
/* int argc;
/* SMTPD_TOKEN *argv;
/*
+/* void smtpd_sasl_auth_extern(state, username, method)
+/* SMTPD_STATE *state;
+/* const char *username;
+/* const char *method;
+/*
/* void smtpd_sasl_auth_reset(state)
/* SMTPD_STATE *state;
/*
/* .PP
/* smtpd_sasl_auth_reset() cleans up after the AUTH command.
/* This is required before smtpd_sasl_auth_cmd() can be used again.
+/* This may be called even if SASL authentication is turned off
+/* in main.cf.
+/*
+/* smtpd_sasl_auth_extern() records authentication information
+/* that is received from an external source.
+/* This may be called even if SASL authentication is turned off
+/* in main.cf.
/*
/* smtpd_sasl_mail_opt() implements the SASL-specific AUTH=sender
/* option to the MAIL FROM command. The result is an error response
smtpd_chat_reply(state, "501 5.5.4 Syntax: AUTH mechanism");
return (-1);
}
-
/* Don't reuse the SASL handle after authentication failure. */
#ifndef XSASL_TYPE_CYRUS
#define XSASL_TYPE_CYRUS "cyrus"
return (smtpd_sasl_authenticate(state, auth_mechanism, initial_response));
}
-/* smtpd_sasl_auth_reset - clean up after AUTH command */
-
-void smtpd_sasl_auth_reset(SMTPD_STATE *state)
-{
- smtpd_sasl_logout(state);
-}
-
/* smtpd_sasl_mail_opt - SASL-specific MAIL FROM option */
char *smtpd_sasl_mail_opt(SMTPD_STATE *state, const char *addr)
/*
* Do not store raw RFC2554 protocol data.
*/
- if (!smtpd_sasl_is_active(state)) {
- state->error_mask |= MAIL_ERROR_PROTOCOL;
- return ("503 5.5.4 Error: authentication disabled");
- }
#if 0
if (state->sasl_username == 0) {
state->error_mask |= MAIL_ERROR_PROTOCOL;
extern void smtpd_sasl_mail_log(SMTPD_STATE *);
extern void smtpd_sasl_mail_reset(SMTPD_STATE *);
+#define smtpd_sasl_auth_extern smtpd_sasl_login
+#define smtpd_sasl_auth_reset smtpd_sasl_logout
+
/* LICENSE
/* .ad
/* .fi
state->tls_context = 0;
#endif
+
+ /*
+ * Minimal initialization to support external authentication (e.g.,
+ * XCLIENT) without having to enable SASL in main.cf.
+ */
#ifdef USE_SASL_AUTH
if (SMTPD_STAND_ALONE(state))
var_smtpd_sasl_enable = 0;
smtpd_sasl_set_inactive(state);
+ smtpd_sasl_state_init(state);
#endif
state->milter_argv = 0;