]> git.ipfire.org Git - thirdparty/postfix.git/commitdiff
postfix-2.9-20111218
authorWietse Venema <wietse@porcupine.org>
Sun, 18 Dec 2011 05:00:00 +0000 (00:00 -0500)
committerViktor Dukhovni <viktor@dukhovni.org>
Tue, 5 Feb 2013 06:37:47 +0000 (06:37 +0000)
20 files changed:
postfix/HISTORY
postfix/README_FILES/XCLIENT_README
postfix/RELEASE_NOTES
postfix/WISHLIST
postfix/html/XCLIENT_README.html
postfix/html/memcache_table.5.html
postfix/man/man5/memcache_table.5
postfix/proto/XCLIENT_README.html
postfix/proto/memcache_table
postfix/src/global/dict_memcache.c
postfix/src/global/mail_proto.h
postfix/src/global/mail_version.h
postfix/src/smtpd/smtpd.c
postfix/src/smtpd/smtpd.h
postfix/src/smtpd/smtpd_check.c
postfix/src/smtpd/smtpd_sasl_glue.c
postfix/src/smtpd/smtpd_sasl_glue.h
postfix/src/smtpd/smtpd_sasl_proto.c
postfix/src/smtpd/smtpd_sasl_proto.h
postfix/src/smtpd/smtpd_state.c

index 7ee65cf81333b0760da5d2d3d6e7a6cc93ef9527..6afc09ae0f948d36d328e0278f8faf2da652bbf7 100644 (file)
@@ -17353,3 +17353,22 @@ Apologies for any names omitted.
        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.
index e524e82bf741035d9e712bdcacdca44a867ae6c5..54258d6caa8ef13f07b907cd664593b434ac1d61 100644 (file)
@@ -50,7 +50,7 @@ are in fact case insensitive.
 
     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
 
@@ -73,6 +73,9 @@ are in fact case insensitive.
   * 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
@@ -86,8 +89,8 @@ Note 3: Postfix implementations prior to version 2.3 do not xtext encode
 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
 
index 5bc1f69da2ce47ba7a21bee3b514b94ea1f3bd40..ab67e1f7513b953fdfaa7528ff9067fac6fbcd06 100644 (file)
@@ -14,6 +14,21 @@ specifies the release date of a stable release or snapshot release.
 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
 ====================================
 
index 0daf6339904dcbfcde51696f397f8c6ab1ab9e72..c38f721db1736bda5ac47f533b9a94f1b9edc107 100644 (file)
@@ -2,6 +2,11 @@ Wish list:
 
        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.
@@ -25,8 +30,6 @@ Wish list:
        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)
index 7b1f278ea25c8fa5f555b3a05d86c524f4ce93a3..db2df625084048640dc4dcccabb6b6442449c8a2 100644 (file)
@@ -80,7 +80,7 @@ names are shown in upper case, they are in fact case insensitive.
     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
@@ -113,6 +113,10 @@ names are shown in upper case, they are in fact case insensitive.
     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
@@ -130,8 +134,8 @@ xtext encode attribute values. Servers that wish to interoperate
 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>
 
index a2042e7c2786a03946b12f28b28c973a17142a18..1dd8ba15f27d3ac5b11e2e60b09c680b4390ebb0 100644 (file)
@@ -34,11 +34,29 @@ MEMCACHE_TABLE(5)                                            MEMCACHE_TABLE(5)
        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:
 
@@ -51,40 +69,49 @@ MEMCACHE_TABLE(5)                                            MEMCACHE_TABLE(5)
               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
@@ -144,25 +171,24 @@ MEMCACHE_TABLE(5)                                            MEMCACHE_TABLE(5)
 
                   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-
@@ -178,7 +204,7 @@ MEMCACHE_TABLE(5)                                            MEMCACHE_TABLE(5)
        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
index 87de7eccd69ce4763feca0265c2c826e35cba97e..5ceb73d1d3e0fd44b285120fb9a566217b09baf7 100644 (file)
@@ -34,12 +34,30 @@ The Postfix memcache client supports the lookup, update,
 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
@@ -67,25 +85,36 @@ name (including the "proxy:" prefix) must be specified in
 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
@@ -141,23 +170,22 @@ are skipped with a warning).  Example:
 .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
@@ -175,7 +203,7 @@ unprivileged Postfix user.
 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
index 97692c0db1c979e111c0c598e734fb3c7bacf05c..daf0109b9471f34e356a70bbb11db72fbed989ff 100644 (file)
@@ -80,7 +80,7 @@ names are shown in upper case, they are in fact case insensitive.
     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
@@ -113,6 +113,10 @@ names are shown in upper case, they are in fact case insensitive.
     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
@@ -130,8 +134,8 @@ xtext encode attribute values. Servers that wish to interoperate
 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>
 
index 129e7d4382e19c855afb5d6efe91e453006f8073..45dbe2942502bd5cb4cf008ec617da0780d363db 100644 (file)
 #      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
index f140ee7df20ddca36edfd072c1b498e836d88670..3fc6101c0d643474e77b538dedc010490d4fbcd6 100644 (file)
@@ -44,6 +44,7 @@
 /* System library. */
 
 #include <sys_defs.h>
+#include <errno.h>
 #include <string.h>
 #include <ctype.h>
 #include <stdio.h>                     /* XXX sscanf() */
@@ -77,10 +78,12 @@ typedef struct {
     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 */
@@ -91,7 +94,7 @@ typedef struct {
 } DICT_MC;
 
  /*
-  * Default memcache options.
+  * Memcache option defaults and names.
   */
 #define DICT_MC_DEF_HOST       "localhost"
 #define DICT_MC_DEF_PORT       "11211"
@@ -100,8 +103,21 @@ typedef struct {
 #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.
@@ -117,35 +133,48 @@ static void dict_memcache_set(DICT_MC *dict_mc, const char *value, int ttl)
 {
     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);
     }
 }
 
@@ -160,41 +189,89 @@ static const char *dict_memcache_get(DICT_MC *dict_mc)
 
     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);
 }
@@ -298,12 +375,12 @@ static void dict_memcache_update(DICT *dict, const char *name,
     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 */
@@ -340,12 +417,13 @@ static const char *dict_memcache_lookup(DICT *dict, const char *name)
            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);
 }
 
@@ -355,9 +433,9 @@ static int dict_memcache_delete(DICT *dict, const char *name)
 {
     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
@@ -377,21 +455,19 @@ static int dict_memcache_delete(DICT *dict, const char *name)
     }
 
     /*
-     * 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 */
@@ -467,19 +543,23 @@ DICT   *dict_memcache_open(const char *name, int open_flags, int dict_flags)
      * 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);
 
     /*
@@ -491,7 +571,8 @@ DICT   *dict_memcache_open(const char *name, int open_flags, int dict_flags)
     /*
      * 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);
index 66f6ff521b8717c8be8ad592dbc726cec9c78f5c..538b01e57bed5f15630ba42553071ff3aa78d627 100644 (file)
@@ -210,6 +210,7 @@ extern char *mail_pathname(const char *, const char *);
 #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 */
index 032b403aa5506cd8b47c2e34215803190fea94b3..a4e1808e147a3c81274410c03d30eca6778bf309 100644 (file)
@@ -20,7 +20,7 @@
   * 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
index 6dee4fbcb6177fda455beaab5c7d17a4669eca2a..d42fefbf5dd9634cdac7582c4487e07fd197d8cc 100644 (file)
@@ -1690,6 +1690,9 @@ static int ehlo_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv)
                                  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))
@@ -1700,7 +1703,8 @@ static int ehlo_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv)
            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
@@ -1837,17 +1841,16 @@ static int mail_open_stream(SMTPD_STATE *state)
            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
 
            /*
@@ -1947,7 +1950,7 @@ static int mail_open_stream(SMTPD_STATE *state)
      * 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
@@ -2203,8 +2206,7 @@ static int mail_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv)
                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);
@@ -2390,7 +2392,7 @@ static void mail_reset(SMTPD_STATE *state)
     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;
@@ -2928,8 +2930,7 @@ static int data_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *unused_argv)
 #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,
@@ -2937,7 +2938,7 @@ static int data_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *unused_argv)
            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
@@ -3460,6 +3461,7 @@ static int xclient_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv)
     };
     int     got_helo = 0;
     int     got_proto = 0;
+    int     got_login = 0;
 
     /*
      * Sanity checks.
@@ -3652,6 +3654,20 @@ static int xclient_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv)
            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.
         */
@@ -3700,7 +3716,7 @@ static int xclient_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv)
        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);
@@ -4767,8 +4783,8 @@ static void smtpd_proto(SMTPD_STATE *state)
 #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
@@ -4815,13 +4831,13 @@ static void smtpd_service(VSTREAM *stream, char *service, char **argv)
     /*
      * 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);
 
     /*
index 73f15ffbeb089eb874ac7196ba7cfd62680bcd14..2d6c46c9250478b66bd39b76df5c5adc1875ec80 100644 (file)
@@ -267,6 +267,7 @@ extern void smtpd_state_reset(SMTPD_STATE *);
 #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))
 
index 45c4a53e6862387203f30b0c32533e859e329dbb..f53741f825bf607b10e22ae11b78dcfe000fe1e0 100644 (file)
@@ -2668,6 +2668,7 @@ static int check_ccert_access(SMTPD_STATE *state, const char *table,
                                      const char *def_acl)
 {
     int     result = SMTPD_CHECK_DUNNO;
+
 #ifdef USE_TLS
     const char *myname = "check_ccert_access";
     int     found;
@@ -3354,16 +3355,10 @@ static int reject_auth_sender_login_mismatch(SMTPD_STATE *state, const char *sen
     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);
@@ -3396,7 +3391,7 @@ static int reject_unauth_sender_login_mismatch(SMTPD_STATE *state, const char *s
      * 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);
@@ -3489,14 +3484,11 @@ static int check_policy_service(SMTPD_STATE *state, const char *server,
                          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))
index da37c4f9a7ae7d319649b1f89b36ba442b07fb3a..5062ee9acb31783519b4e782468cd03c71d71fd4 100644 (file)
@@ -6,6 +6,9 @@
 /* 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.
 /*
@@ -181,9 +198,6 @@ void    smtpd_sasl_activate(SMTPD_STATE *state, const char *sasl_opts_name,
      */
     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.
@@ -204,7 +218,7 @@ void    smtpd_sasl_activate(SMTPD_STATE *state, const char *sasl_opts_name,
                             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");
@@ -218,6 +232,16 @@ void    smtpd_sasl_activate(SMTPD_STATE *state, const char *sasl_opts_name,
     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)
@@ -322,4 +346,17 @@ void    smtpd_sasl_logout(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
index c6e76e3f5bafa54df29357d9685fade79dd1b8ac..d81eec1bb497485f9454d9bfd50e7c313e9c9c83 100644 (file)
  /*
   * 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);
 
index 823e988863a58403e65031d17c11f5c0882fe326..297a445a690d38f63adb9539537f00d8b9ee0e3d 100644 (file)
 /*     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
@@ -183,7 +195,6 @@ int     smtpd_sasl_auth_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv)
        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"
@@ -212,13 +223,6 @@ int     smtpd_sasl_auth_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv)
     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)
@@ -227,10 +231,6 @@ 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;
index bd326be5891bd1683ad659186cce5db8290585a5..7f8ac3d4b53f19dd6d5838158c24a463072a0798 100644 (file)
@@ -17,6 +17,9 @@ extern char *smtpd_sasl_mail_opt(SMTPD_STATE *, const char *);
 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
index 12bca30255fa785597a0d090d4c532e9dea61cec..43baa74bca3207f267642b03714a1479a175fd47 100644 (file)
@@ -145,10 +145,16 @@ void    smtpd_state_init(SMTPD_STATE *state, VSTREAM *stream,
     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;