diff -ru postfix-2.1.2/src/smtpd/smtpd.h postfix-2.1.2-dovecot/src/smtpd/smtpd.h
--- postfix-2.1.2/src/smtpd/smtpd.h	2004-04-21 21:23:33.000000000 +0300
+++ postfix-2.1.2-dovecot/src/smtpd/smtpd.h	2004-06-16 22:25:05.000000000 +0300
@@ -14,14 +14,6 @@
 #include <unistd.h>
 
  /*
-  * SASL library.
-  */
-#ifdef USE_SASL_AUTH
-#include <sasl.h>
-#include <saslutil.h>
-#endif
-
- /*
   * Utility library.
   */
 #include <vstream.h>
@@ -91,15 +83,13 @@
      * SASL specific.
      */
 #ifdef USE_SASL_AUTH
-#if SASL_VERSION_MAJOR >= 2
-    const char *sasl_mechanism_list;
-#else
     char   *sasl_mechanism_list;
-#endif
     char   *sasl_method;
     char   *sasl_username;
     char   *sasl_sender;
-    sasl_conn_t *sasl_conn;
+    int    sasl_state;
+    char   *sasl_error;
+    struct auth_client *sasl_conn;
     VSTRING *sasl_encoded;
     VSTRING *sasl_decoded;
 #endif
diff -ru postfix-2.1.2/src/smtpd/smtpd_sasl_glue.c postfix-2.1.2-dovecot/src/smtpd/smtpd_sasl_glue.c
--- postfix-2.1.2/src/smtpd/smtpd_sasl_glue.c	2004-02-01 20:44:55.000000000 +0200
+++ postfix-2.1.2-dovecot/src/smtpd/smtpd_sasl_glue.c	2004-06-16 22:21:10.000000000 +0300
@@ -89,6 +89,7 @@
 
 /* Utility library. */
 
+#include <base64_code.h>
 #include <msg.h>
 #include <mymalloc.h>
 #include <namadr_list.h>
@@ -99,6 +100,18 @@
 #include <mail_params.h>
 #include <smtp_stream.h>
 
+#ifdef USE_SASL_AUTH
+#include <stdint.h>
+#include <mempool.h>
+#include <data-stack.h>
+#include <failures.h>
+#include <strfuncs.h>
+#include <ioloop.h>
+#include <lib-auth/auth-client.h>
+
+void lib_init(void);
+#endif
+
 /* Application-specific. */
 
 #include "smtpd.h"
@@ -107,133 +120,65 @@
 
 #ifdef USE_SASL_AUTH
 
-/*
- * Silly little macros.
- */
-#define STR(s)	vstring_str(s)
-
- /*
-  * Macros to handle API differences between SASLv1 and SASLv2. Specifics:
-  * 
-  * The SASL_LOG_* constants were renamed in SASLv2.
-  * 
-  * SASLv2's sasl_server_new takes two new parameters to specify local and
-  * remote IP addresses for auth mechs that use them.
-  * 
-  * SASLv2's sasl_server_start and sasl_server_step no longer have the errstr
-  * parameter.
-  * 
-  * SASLv2's sasl_decode64 function takes an extra parameter for the length of
-  * the output buffer.
-  * 
-  * The other major change is that SASLv2 now takes more responsibility for
-  * deallocating memory that it allocates internally.  Thus, some of the
-  * function parameters are now 'const', to make sure we don't try to free
-  * them too.  This is dealt with in the code later on.
-  */
-
-#if SASL_VERSION_MAJOR < 2
-/* SASL version 1.x */
-#define SASL_LOG_WARN SASL_LOG_WARNING
-#define SASL_LOG_NOTE SASL_LOG_INFO
-#define SASL_SERVER_NEW(srv, fqdn, rlm, lport, rport, cb, secflags, pconn) \
-	sasl_server_new(srv, fqdn, rlm, cb, secflags, pconn)
-#define SASL_SERVER_START(conn, mech, clin, clinlen, srvout, srvoutlen, err) \
-	sasl_server_start(conn, mech, clin, clinlen, srvout, srvoutlen, err)
-#define SASL_SERVER_STEP(conn, clin, clinlen, srvout, srvoutlen, err) \
-	sasl_server_step(conn, clin, clinlen, srvout, srvoutlen, err)
-#define SASL_DECODE64(in, inlen, out, outmaxlen, outlen) \
-	sasl_decode64(in, inlen, out, outlen)
-#endif
+static struct ioloop *ioloop;
 
-#if SASL_VERSION_MAJOR >= 2
-/* SASL version > 2.x */
-#define SASL_SERVER_NEW(srv, fqdn, rlm, lport, rport, cb, secflags, pconn) \
-	sasl_server_new(srv, fqdn, rlm, lport, rport, cb, secflags, pconn)
-#define SASL_SERVER_START(conn, mech, clin, clinlen, srvout, srvoutlen, err) \
-	sasl_server_start(conn, mech, clin, clinlen, srvout, srvoutlen)
-#define SASL_SERVER_STEP(conn, clin, clinlen, srvout, srvoutlen, err) \
-	sasl_server_step(conn, clin, clinlen, srvout, srvoutlen)
-#define SASL_DECODE64(in, inlen, out, outmaxlen, outlen) \
-	sasl_decode64(in, inlen, out, outmaxlen, outlen)
-#endif
+static void panic_handler(const char *fmt, va_list args) __attr_noreturn__;
+static void fatal_handler(int unused_status, const char *fmt, va_list args)
+    __attr_noreturn__;
 
-/* smtpd_sasl_log - SASL logging callback */
+static void panic_handler(const char *fmt, va_list args)
+{
+    msg_panic("%s", t_strdup_vprintf(fmt, args));
+}
 
-static int smtpd_sasl_log(void *unused_context, int priority,
-			          const char *message)
+static void fatal_handler(int unused_status, const char *fmt, va_list args)
 {
-    switch (priority) {
-	case SASL_LOG_ERR:
-	case SASL_LOG_WARN:
-	msg_warn("SASL authentication problem: %s", message);
-	break;
-    case SASL_LOG_NOTE:
-	if (msg_verbose)
-	    msg_info("SASL authentication info: %s", message);
-	break;
-#if SASL_VERSION_MAJOR >= 2
-    case SASL_LOG_FAIL:
-	msg_warn("SASL authentication failure: %s", message);
-	break;
-#endif
-    }
-    return SASL_OK;
+    msg_fatal("%s", t_strdup_vprintf(fmt, args));
 }
 
- /*
-  * SASL callback interface structure. These call-backs have no per-session
-  * context.
-  */
-#define NO_CALLBACK_CONTEXT	0
-
-static sasl_callback_t callbacks[] = {
-    {SASL_CB_LOG, &smtpd_sasl_log, NO_CALLBACK_CONTEXT},
-    {SASL_CB_LIST_END, 0, 0}
-};
-
-static NAME_MASK smtpd_sasl_mask[] = {
-    "noplaintext", SASL_SEC_NOPLAINTEXT,
-    "noactive", SASL_SEC_NOACTIVE,
-    "nodictionary", SASL_SEC_NODICTIONARY,
-    "noanonymous", SASL_SEC_NOANONYMOUS,
-#if SASL_VERSION_MAJOR >= 2
-    "mutual_auth", SASL_SEC_MUTUAL_AUTH,
-#endif
-    0,
-};
+static void error_handler(const char *fmt, va_list args)
+{
+    t_push();
+    msg_error("%s", t_strdup_vprintf(fmt, args));
+    t_pop();
+}
 
-/* smtpd_sasl_initialize - per-process initialization */
+static void warning_handler(const char *fmt, va_list args)
+{
+    t_push();
+    msg_warn("%s", t_strdup_vprintf(fmt, args));
+    t_pop();
+}
 
+static void info_handler(const char *fmt, va_list args)
+{
+    t_push();
+    msg_info("%s", t_strdup_vprintf(fmt, args));
+    t_pop();
+}
+
+/* smtpd_sasl_initialize - per-process initialization */
 void    smtpd_sasl_initialize(void)
 {
+    lib_init();
 
-    /*
-     * Initialize the library: load SASL plug-in routines, etc.
-     */
-    if (msg_verbose)
-	msg_info("smtpd_sasl_initialize: SASL config file is %s.conf",
-		 var_smtpd_sasl_appname);
-    if (sasl_server_init(callbacks, var_smtpd_sasl_appname) != SASL_OK)
-	msg_fatal("SASL per-process initialization failed");
+    i_set_panic_handler(panic_handler);
+    i_set_fatal_handler(fatal_handler);
+    i_set_error_handler(error_handler);
+    i_set_warning_handler(warning_handler);
+    i_set_info_handler(info_handler);
 
+    ioloop = io_loop_create(system_pool);
 }
 
 /* smtpd_sasl_connect - per-connection initialization */
 
 void    smtpd_sasl_connect(SMTPD_STATE *state, const char *sasl_opts_name,
-			           const char *sasl_opts_val)
+			   const char *sasl_opts_var)
 {
-#if SASL_VERSION_MAJOR < 2
-    unsigned sasl_mechanism_count;
-
-#else
-    int     sasl_mechanism_count;
-
-#endif
-    sasl_security_properties_t sec_props;
-    char   *server_address;
-    char   *client_address;
+    const struct auth_mech_desc *mech;
+    unsigned i, mech_count;
+    VSTRING *str;
 
     /*
      * Initialize SASL-specific state variables. Use long-lived storage for
@@ -249,71 +194,26 @@
     state->sasl_decoded = vstring_alloc(10);
     state->sasl_encoded = vstring_alloc(10);
 
-    /*
-     * Set up a new server context for this connection.
-     */
-#define NO_SECURITY_LAYERS	(0)
-#define NO_SESSION_CALLBACKS	((sasl_callback_t *) 0)
-#define NO_AUTH_REALM		((char *) 0)
-
-#if SASL_VERSION_MAJOR >= 2 && defined(USE_SASL_IP_AUTH)
-
-    /*
-     * Get IP addresses of local and remote endpoints for SASL.
-     */
-#error "USE_SASL_IP_AUTH is not implemented"
-
-#else
-
-    /*
-     * Don't give any IP address information to SASL.  SASLv1 doesn't use it,
-     * and in SASLv2 this will disable any mechaniams that do.
-     */
-    server_address = 0;
-    client_address = 0;
-#endif
-
-    if (SASL_SERVER_NEW("smtp", var_myhostname, *var_smtpd_sasl_realm ?
-			var_smtpd_sasl_realm : NO_AUTH_REALM,
-			server_address, client_address,
-			NO_SESSION_CALLBACKS, NO_SECURITY_LAYERS,
-			&state->sasl_conn) != SASL_OK)
-	msg_fatal("SASL per-connection server initialization");
-
-    /*
-     * Security options. Some information can be found in the sasl.h include
-     * file. Disallow anonymous authentication; this is because the
-     * permit_sasl_authenticated feature is restricted to authenticated
-     * clients only.
-     */
-    memset(&sec_props, 0, sizeof(sec_props));
-    sec_props.min_ssf = 0;
-    sec_props.max_ssf = 1;			/* don't allow real SASL
-						 * security layer */
-    sec_props.security_flags = name_mask(sasl_opts_name, smtpd_sasl_mask,
-					 sasl_opts_val);
-    sec_props.maxbufsize = 0;
-    sec_props.property_names = 0;
-    sec_props.property_values = 0;
-
-    if (sasl_setprop(state->sasl_conn, SASL_SEC_PROPS,
-		     &sec_props) != SASL_OK)
-	msg_fatal("SASL per-connection security setup");
-
-    /*
-     * Get the list of authentication mechanisms.
-     */
-#define UNSUPPORTED_USER	((char *) 0)
-#define IGNORE_MECHANISM_LEN	((unsigned *) 0)
-
-    if (sasl_listmech(state->sasl_conn, UNSUPPORTED_USER,
-		      "", " ", "",
-		      &state->sasl_mechanism_list,
-		      IGNORE_MECHANISM_LEN,
-		      &sasl_mechanism_count) != SASL_OK)
-	msg_fatal("cannot lookup SASL authentication mechanisms");
-    if (sasl_mechanism_count <= 0)
-	msg_fatal("no SASL authentication mechanisms");
+    state->sasl_conn = auth_client_new_external(getpid(),
+						"/etc/dovecot-auth",
+						NULL, NULL);
+
+    io_loop_set_running(ioloop);
+    while (!auth_client_is_connected(state->sasl_conn))
+	io_loop_handler_run(ioloop);
+
+    str = vstring_alloc(20);
+    mech = auth_client_get_available_mechs(state->sasl_conn, &mech_count);
+
+    if (mech_count <= 0)
+	msg_fatal("No SASL authentication mechanisms");
+
+    for (i = 0; i < mech_count; i++) {
+        if (VSTRING_LEN(str) > 0)
+            VSTRING_ADDCH(str, ' ');
+	vstring_strcat(str, mech[i].name);
+    }
+    state->sasl_mechanism_list = vstring_export(str);
 }
 
 /* smtpd_sasl_disconnect - per-connection cleanup */
@@ -321,47 +221,109 @@
 void    smtpd_sasl_disconnect(SMTPD_STATE *state)
 {
     if (state->sasl_mechanism_list) {
-#if SASL_VERSION_MAJOR < 2
-	/* SASL version 1 doesn't free memory that it allocates. */
-	free(state->sasl_mechanism_list);
-#endif
+	myfree(state->sasl_mechanism_list);
 	state->sasl_mechanism_list = 0;
     }
     if (state->sasl_conn) {
-	sasl_dispose(&state->sasl_conn);
+	auth_client_free(state->sasl_conn);
 	state->sasl_conn = 0;
     }
     vstring_free(state->sasl_decoded);
     vstring_free(state->sasl_encoded);
 }
 
-/* smtpd_sasl_authenticate - per-session authentication */
-
-char   *smtpd_sasl_authenticate(SMTPD_STATE *state,
-				        const char *sasl_method,
-				        const char *init_response)
+static void auth_callback(struct auth_request *request,
+                          struct auth_client_request_reply *reply,
+                          const unsigned char *data, void *context)
 {
     char   *myname = "smtpd_sasl_authenticate";
-    char   *dec_buffer;
-    unsigned dec_length;
-    unsigned enc_length;
-    unsigned enc_length_out;
-    unsigned reply_len;
-    unsigned serveroutlen;
-    int     result;
+    SMTPD_STATE *state = context;
 
-#if SASL_VERSION_MAJOR < 2
-    char   *serverout = 0;
+    if (reply == NULL) {
+        state->sasl_state = -1;
+        state->sasl_error = "501 Authentication process died";
+        return;
+    }
 
-#else
-    const char *serverout = 0;
+    if (data == NULL)
+	data = "";
 
-#endif
+    switch (reply->result) {
+    case AUTH_CLIENT_RESULT_CONTINUE:
+	/*
+	 * Send a server challenge. Avoid storing the challenge in a local
+	 * variable, because we would leak memory when smtpd_chat_reply()
+	 * does not return due to timeout or I/O error. sasl_encode64()
+	 * null-terminates the result if the result buffer is large enough.
+	 */
+	if (msg_verbose)
+	    msg_info("%s: uncoded challenge: %.*s",
+		     myname, (int) reply->data_size, data);
 
-#if SASL_VERSION_MAJOR < 2
-    const char *errstr = 0;
+        base64_encode(state->sasl_encoded,
+                      (const char *) data + reply->reply_idx,
+                      reply->data_size - reply->reply_idx);
+	smtpd_chat_reply(state, "334 %s", vstring_str(state->sasl_encoded));
 
-#endif
+	/*
+	 * Receive the client response. "*" means that the client gives up.
+	 * XXX For now we ignore the fact that excessively long responses
+	 * will be truncated. To handle such responses, we need to change
+	 * smtpd_chat_query() so that it returns an error indication.
+	 */
+	smtpd_chat_query(state);
+        if (strcmp(vstring_str(state->buffer), "*") == 0) {
+            state->sasl_error = "501 Authentication aborted";
+            break;
+        }
+
+        if (base64_decode(state->sasl_decoded,
+                          vstring_str(state->buffer),
+                          VSTRING_LEN(state->buffer)) == NULL) {
+            state->sasl_error =
+                "501 Authentication failed: malformed initial response";
+            break;
+        }
+
+	if (msg_verbose)
+	    msg_info("%s: decoded response: %.*s",
+                     myname, (int) VSTRING_LEN(state->sasl_decoded),
+                     vstring_str(state->sasl_decoded));
+
+        auth_client_request_continue(request, vstring_str(state->sasl_decoded),
+                                     VSTRING_LEN(state->sasl_decoded));
+        break;
+
+    case AUTH_CLIENT_RESULT_SUCCESS:
+        state->sasl_username = mystrdup((const char *) data + reply->username_idx);
+        state->sasl_state = 1;
+        break;
+
+    case AUTH_CLIENT_RESULT_FAILURE:
+        /* see if we have error message */
+        if (msg_verbose &&
+            reply->data_size > 0 && data[reply->data_size-1] == '\0') {
+            msg_info("%s: Authentication failed: ", myname,
+                     (const char *) data);
+        }
+        state->sasl_state = -1;
+        break;
+    }
+
+    if (state->sasl_error)
+        state->sasl_state = -1;
+}
+
+/* smtpd_sasl_authenticate - per-session authentication */
+
+char   *smtpd_sasl_authenticate(SMTPD_STATE *state,
+				        const char *sasl_method,
+				        const char *init_response)
+{
+    char   *myname = "smtpd_sasl_authenticate";
+    struct auth_request *request;
+    struct auth_request_info info;
+    const char *error;
 
 #define IFELSE(e1,e2,e3) ((e1) ? (e2) : (e3))
 
@@ -381,109 +343,50 @@
      * response that was sent along in the AUTH command.
      */
     if (init_response) {
-	reply_len = strlen(init_response);
-	VSTRING_SPACE(state->sasl_decoded, reply_len);
-	dec_buffer = STR(state->sasl_decoded);
-	if (SASL_DECODE64(init_response, reply_len,
-			  dec_buffer, reply_len, &dec_length) != SASL_OK)
+        if (base64_decode(state->sasl_decoded,
+                          init_response, strlen(init_response)) == NULL)
 	    return ("501 Authentication failed: malformed initial response");
 	if (msg_verbose)
-	    msg_info("%s: decoded initial response %s", myname, dec_buffer);
+            msg_info("%s: decoded initial response %s", myname,
+                     vstring_str(state->sasl_decoded));
     } else {
-	dec_buffer = 0;
-	dec_length = 0;
+	VSTRING_RESET(state->sasl_decoded);
     }
-    result = SASL_SERVER_START(state->sasl_conn, sasl_method, dec_buffer,
-			    dec_length, &serverout, &serveroutlen, &errstr);
 
-    /*
-     * Repeat until done or until the client gives up.
-     */
-    while (result == SASL_CONTINUE) {
-
-	/*
-	 * Send a server challenge. Avoid storing the challenge in a local
-	 * variable, because we would leak memory when smtpd_chat_reply()
-	 * does not return due to timeout or I/O error. sasl_encode64()
-	 * null-terminates the result if the result buffer is large enough.
-	 * 
-	 * Regarding the hairy expression below: output from sasl_encode64()
-	 * comes in multiples of four bytes for each triple of input bytes,
-	 * plus four bytes for any incomplete last triple, plus one byte for
-	 * the null terminator.
-	 * 
-	 * XXX Replace the klunky sasl_encode64() interface by something that
-	 * uses VSTRING buffers.
-	 */
-	if (msg_verbose)
-	    msg_info("%s: uncoded challenge: %.*s",
-		     myname, (int) serveroutlen, serverout);
-	enc_length = ((serveroutlen + 2) / 3) * 4 + 1;
-	VSTRING_SPACE(state->sasl_encoded, enc_length);
-	if (sasl_encode64(serverout, serveroutlen, STR(state->sasl_encoded),
-			  enc_length, &enc_length_out) != SASL_OK)
-	    msg_panic("%s: sasl_encode64 botch", myname);
-#if SASL_VERSION_MAJOR < 2
-	/* SASL version 1 doesn't free memory that it allocates. */
-	free(serverout);
-#endif
-	serverout = 0;
-	smtpd_chat_reply(state, "334 %s", STR(state->sasl_encoded));
-
-	/*
-	 * Receive the client response. "*" means that the client gives up.
-	 * XXX For now we ignore the fact that excessively long responses
-	 * will be truncated. To handle such responses, we need to change
-	 * smtpd_chat_query() so that it returns an error indication.
-	 */
-	smtpd_chat_query(state);
-	if (strcmp(vstring_str(state->buffer), "*") == 0)
-	    return ("501 Authentication aborted");	/* XXX */
-	reply_len = VSTRING_LEN(state->buffer);
-	VSTRING_SPACE(state->sasl_decoded, reply_len);
-	if (SASL_DECODE64(vstring_str(state->buffer), reply_len,
-			  STR(state->sasl_decoded), reply_len,
-			  &dec_length) != SASL_OK)
-	    return ("501 Error: malformed authentication response");
-	if (msg_verbose)
-	    msg_info("%s: decoded response: %.*s",
-		     myname, (int) dec_length, STR(state->sasl_decoded));
-	result = SASL_SERVER_STEP(state->sasl_conn, STR(state->sasl_decoded),
-			    dec_length, &serverout, &serveroutlen, &errstr);
+    memset(&info, 0, sizeof(info));
+    info.mech = sasl_method;
+    info.protocol = var_smtpd_sasl_appname;
+    info.flags = 0; /* FIXME: set TLS */
+    /* FIXME: set local/remote IP */
+    info.initial_resp_data = vstring_str(state->sasl_decoded);
+    info.initial_resp_size = VSTRING_LEN(state->sasl_decoded);
+
+    request = auth_client_request_new(state->sasl_conn, &info,
+                                      auth_callback, state, &error);
+    if (request == NULL) {
+        if (msg_verbose)
+            msg_info("%s: Authentication failed: %s", myname, error);
+        return ("501 Authentication failed");
     }
 
     /*
-     * Cleanup. What an awful interface.
+     * Repeat until done or until the client gives up.
      */
-#if SASL_VERSION_MAJOR < 2
-    if (serverout)
-	free(serverout);
-#endif
+    state->sasl_state = 0;
+    state->sasl_error = NULL;
+    io_loop_set_running(ioloop);
+    while (state->sasl_state == 0)
+	io_loop_handler_run(ioloop);
 
     /*
      * The authentication protocol was completed.
      */
-    if (result != SASL_OK)
-	return ("535 Error: authentication failed");
+    if (state->sasl_state < 0) {
+        return (state->sasl_error ? state->sasl_error :
+                "535 Error: authentication failed");
+    }
 
-    /*
-     * Authentication succeeded. Find out the login name for logging and for
-     * accounting purposes. For the sake of completeness we also record the
-     * authentication method that was used. XXX Do not free(serverout).
-     */
-#if SASL_VERSION_MAJOR >= 2
-    result = sasl_getprop(state->sasl_conn, SASL_USERNAME,
-			  (const void **) &serverout);
-#else
-    result = sasl_getprop(state->sasl_conn, SASL_USERNAME,
-			  (void **) &serverout);
-#endif
-    if (result != SASL_OK || serverout == 0)
-	msg_panic("%s: sasl_getprop SASL_USERNAME botch", myname);
-    state->sasl_username = mystrdup(serverout);
-    printable(state->sasl_username, '?');
     state->sasl_method = mystrdup(sasl_method);
-    printable(state->sasl_method, '?');
 
     return (0);
 }
