diff -Nrbu dovecot-1.0.1/src/auth/Makefile.am dovecot-1.0.1-OK/src/auth/Makefile.am
--- dovecot-1.0.1/src/auth/Makefile.am	2007-05-19 15:14:04.000000000 +0400
+++ dovecot-1.0.1-OK/src/auth/Makefile.am	2007-07-03 17:53:14.000000000 +0400
@@ -56,6 +56,7 @@
 	mech-cram-md5.c \
 	mech-digest-md5.c \
 	mech-ntlm.c \
+	mech-winbind.c \
 	mech-gssapi.c \
 	mech-rpa.c \
 	mech-apop.c \
diff -Nrbu dovecot-1.0.1/src/auth/Makefile.in dovecot-1.0.1-OK/src/auth/Makefile.in
--- dovecot-1.0.1/src/auth/Makefile.in	2007-06-14 16:02:13.000000000 +0400
+++ dovecot-1.0.1-OK/src/auth/Makefile.in	2007-07-03 17:53:41.000000000 +0400
@@ -78,6 +78,7 @@
 	mech.$(OBJEXT) mech-anonymous.$(OBJEXT) mech-plain.$(OBJEXT) \
 	mech-login.$(OBJEXT) mech-cram-md5.$(OBJEXT) \
 	mech-digest-md5.$(OBJEXT) mech-ntlm.$(OBJEXT) \
+	mech-winbind.$(OBJEXT) \
 	mech-gssapi.$(OBJEXT) mech-rpa.$(OBJEXT) mech-apop.$(OBJEXT) \
 	passdb.$(OBJEXT) passdb-blocking.$(OBJEXT) \
 	passdb-bsdauth.$(OBJEXT) passdb-cache.$(OBJEXT) \
@@ -325,6 +326,7 @@
 	mech-cram-md5.c \
 	mech-digest-md5.c \
 	mech-ntlm.c \
+	mech-winbind.c \
 	mech-gssapi.c \
 	mech-rpa.c \
 	mech-apop.c \
@@ -494,6 +496,7 @@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mech-ntlm.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mech-plain.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mech-rpa.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mech-winbind.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mech.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mycrypt.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/passdb-blocking.Po@am__quote@
diff -Nrbu dovecot-1.0.1/src/auth/mech-winbind.c dovecot-1.0.1-OK/src/auth/mech-winbind.c
--- dovecot-1.0.1/src/auth/mech-winbind.c	1970-01-01 03:00:00.000000000 +0300
+++ dovecot-1.0.1-OK/src/auth/mech-winbind.c	2007-07-03 17:53:14.000000000 +0400
@@ -0,0 +1,298 @@
+/*
+ * NTLM and Negotiate authentication mechanisms,
+ * using Samba winbind daemon
+ *
+ * Copyright (c) 2007 Dmitry Butskoy <dmitry@butskoy.name>
+ *
+ * This software is released under the MIT license.
+ */
+
+#include "common.h"
+#include "mech.h"
+#include "str.h"
+#include "buffer.h"
+#include "safe-memset.h"
+#include "base64.h"
+#include "istream.h"
+#include "ostream.h"
+
+#include <stdlib.h>
+#include <unistd.h>
+
+
+#define WINBIND_HELPER_NTLM \
+	"/usr/bin/ntlm_auth --helper-protocol=squid-2.5-ntlmssp"
+#define WINBIND_HELPER_SPNEGO \
+	"/usr/bin/ntlm_auth --helper-protocol=gss-spnego"
+
+
+struct winbind_auth_request {
+	struct auth_request auth_request;
+
+	pool_t pool;
+
+	int continued;
+
+	int negotiate;	/*  1 -- GSS-SPNEGO, 0 -- NTLM   */
+
+};
+
+
+static struct istream *in_pipe = NULL;
+static struct ostream *out_pipe = NULL;
+
+
+static void init_helper (int negotiate) {
+	int infd[2], outfd[2];
+	pid_t pid;
+
+	if (in_pipe)  i_stream_destroy (&in_pipe);
+	if (out_pipe)  o_stream_destroy (&out_pipe);
+
+
+	if (pipe (infd) < 0 || pipe (outfd) < 0)
+		i_fatal ("pipe creation failed");
+
+	pid = fork ();
+	if (pid < 0)  i_fatal ("fork() failed");
+
+	if (pid == 0) {	/*  child   */
+	    const char *helper;
+	    const char **args;
+
+	    close (infd[0]);
+	    close (outfd[1]);
+
+	    if (dup2 (outfd[0], 0) < 0 ||
+		dup2 (infd[1], 1) < 0
+	    )  i_fatal ("dup2 failed after fork()");
+
+	    if (negotiate) {
+		helper = getenv ("WINBIND_HELPER_SPNEGO");
+		if (!helper)  helper = WINBIND_HELPER_SPNEGO;
+	    } else {
+		helper = getenv ("WINBIND_HELPER_NTLM");
+		if (!helper)  helper = WINBIND_HELPER_NTLM;
+	    }
+
+	    args = t_strsplit_spaces (helper, " ");
+	    if (!args || !args[0])
+		    i_fatal ("bad helper `%s' specified", helper);
+
+	    execv (args[0], (char **) args);
+	    i_fatal ("execv of %s failed", args[0]);
+	    _exit (127);	/*  paranoia   */
+	}
+
+	/*  parent   */
+
+	close (infd[1]);
+	close (outfd[0]);
+
+	in_pipe = i_stream_create_file (infd[0], default_pool, 
+				     AUTH_CLIENT_MAX_LINE_LENGTH, FALSE);
+	out_pipe = o_stream_create_file (outfd[1], default_pool,
+						(size_t) -1, FALSE);
+
+	return;
+}
+
+
+static void mech_winbind_auth_continue(struct auth_request *auth_request,
+				const unsigned char *data, size_t data_size) {
+	struct winbind_auth_request *request =
+				(struct winbind_auth_request *) auth_request;
+	string_t *str;
+	char *answer;
+	const char **token;
+
+	str = t_str_new (MAX_BASE64_ENCODED_SIZE (data_size + 1) + 4);
+
+	str_printfa (str, "%s ", request->continued ? "KK" : "YR");
+	base64_encode (data, data_size, str);
+	str_append_c (str, '\n');
+
+	if (o_stream_send_str (out_pipe, str_c (str)) < 0 ||
+	    o_stream_flush (out_pipe) < 0
+	) {
+	    auth_request_log_info (auth_request, "winbind",
+					"cannot write to helper pipe");
+	    goto restart;
+	}
+
+	request->continued = 0;
+
+
+	answer = i_stream_read_next_line (in_pipe);
+	if (!answer) {
+	    auth_request_log_info (auth_request, "winbind",
+					"cannot read from helper pipe");
+	    goto restart;
+	}
+
+	token = t_strsplit_spaces (answer, " \n");
+	if (!token || !token[0] ||
+	    (!token[1] && strcmp (token[0], "BH") != 0) ||
+	    (request->negotiate && !token[2])
+	) {
+	    auth_request_log_info (auth_request, "winbind",
+			    "could not parse `%s' helper callback", answer);
+	    goto restart;
+	}
+
+	/*
+	 *  NTLM:
+	 *  The child's reply contains 2 parts:
+	 *   - The code: TT, AF or NA
+	 *   - The argument:
+	 *        For TT it's the blob to send to the client, coded in base64
+	 *        For AF it's user or DOMAIN\user
+	 *        For NA it's the NT error code
+	 *
+	 *  GSS-SPNEGO:
+	 *  The child's reply contains 3 parts:
+	 *   - The code: TT, AF or NA
+	 *   - The blob to send to the client, coded in base64
+	 *   - The argument:
+	 *        For TT it's a dummy '*'
+	 *        For AF it's DOMAIN\user
+	 *        For NA it's the NT error code
+	 */
+	
+	if (!strcmp (token[0], "TT")) {
+	    buffer_t *buf;
+	    size_t len = strlen (token[1]);
+
+	    buf = buffer_create_dynamic (pool_datastack_create(),
+					    MAX_BASE64_DECODED_SIZE (len));
+	    base64_decode (token[1], len, NULL, buf);
+
+	    auth_request->callback (auth_request,
+					AUTH_CLIENT_RESULT_CONTINUE,
+					buf->data, buf->used);
+	    request->continued = 1;
+	    return;
+	}
+	else if (!strcmp (token[0], "NA")) {
+	    const char *error = request->negotiate ? token[2] : token[1];
+
+	    auth_request_log_info (auth_request, "winbind",
+				"user not authenticated: %s", error);
+
+	    auth_request_fail (auth_request);
+	    return;
+	}
+	else if (!strcmp (token[0], "AF")) {
+	    const char *user, *p, *error;
+
+	    user = request->negotiate ? token[2] : token[1];
+
+	    p = strchr (user, '\\');
+	    if (p) {
+		/*  change "DOMAIN\user" to uniform style "user@DOMAIN"   */
+		user = t_strconcat (p+1, "@", t_strdup_until (user, p), NULL);
+	    }
+
+	    if (!auth_request_set_username (auth_request, user, &error)) {
+		auth_request_log_info (auth_request, "winbind", "%s", error);
+
+		auth_request_fail (auth_request);
+		return;
+	    }
+ 
+	    if (request->negotiate && strcmp (token[1], "*") != 0) {
+		buffer_t *buf;
+		size_t len = strlen (token[1]);
+
+		buf = buffer_create_dynamic (pool_datastack_create(),
+						MAX_BASE64_DECODED_SIZE (len));
+		base64_decode (token[1], len, NULL, buf);
+
+		auth_request_success (&request->auth_request,
+						buf->data, buf->used);
+	    } else
+		auth_request_success (&request->auth_request, NULL, 0);
+
+	    return;
+	}
+	else if (!strcmp (token[0], "BH")) {
+	    auth_request_log_info (auth_request, "winbind",
+			"ntlm_auth reports broken helper: %s",
+			token[1] ? token[1] : "");
+	    auth_request_fail (auth_request);
+	    return;
+	}
+	else {
+	    auth_request_log_info (auth_request, "winbind",
+			    "could not parse `%s' helper callback", answer);
+	    auth_request_fail (auth_request);
+	    return;
+	}
+
+
+restart:
+	init_helper (request->negotiate);	/*   try to restart   */
+
+	auth_request_fail (auth_request);
+	return;
+}
+
+
+static struct auth_request *do_auth_new (int negotiate) {
+	struct winbind_auth_request *request;
+	pool_t pool;
+
+	pool = pool_alloconly_create("winbind_auth_request", 1024);
+	request = p_new(pool, struct winbind_auth_request, 1);
+	request->pool = pool;
+
+	request->negotiate = negotiate;
+
+	request->continued = 0;
+
+	if (!in_pipe || !out_pipe)
+		init_helper (negotiate);
+
+	request->auth_request.pool = pool;
+	return &request->auth_request;
+}
+
+static struct auth_request *mech_winbind_ntlm_auth_new (void) {
+
+	return  do_auth_new (0);
+}
+
+static struct auth_request *mech_winbind_spnego_auth_new (void) {
+
+	return  do_auth_new (1);
+}
+
+
+const struct mech_module mech_winbind_ntlm = {
+	"NTLM",
+
+	MEMBER(flags) MECH_SEC_DICTIONARY | MECH_SEC_ACTIVE,
+
+	MEMBER(passdb_need_plain) FALSE,
+	MEMBER(passdb_need_credentials) FALSE,
+
+	mech_winbind_ntlm_auth_new,
+	mech_generic_auth_initial,
+	mech_winbind_auth_continue,
+	mech_generic_auth_free
+};
+
+const struct mech_module mech_winbind_spnego = {
+	"GSS-SPNEGO",
+
+	MEMBER(flags) 0,
+
+	MEMBER(passdb_need_plain) FALSE,
+	MEMBER(passdb_need_credentials) FALSE,
+
+	mech_winbind_spnego_auth_new,
+	mech_generic_auth_initial,
+	mech_winbind_auth_continue,
+	mech_generic_auth_free
+};
+
diff -Nrbu dovecot-1.0.1/src/auth/mech.c dovecot-1.0.1-OK/src/auth/mech.c
--- dovecot-1.0.1/src/auth/mech.c	2007-05-19 15:14:04.000000000 +0400
+++ dovecot-1.0.1-OK/src/auth/mech.c	2007-07-03 17:53:14.000000000 +0400
@@ -73,6 +73,8 @@
 #ifdef HAVE_GSSAPI
 extern struct mech_module mech_gssapi;
 #endif
+extern struct mech_module mech_winbind_ntlm;
+extern struct mech_module mech_winbind_spnego;
 
 void mech_init(void)
 {
@@ -81,12 +83,16 @@
 	mech_register_module(&mech_apop);
 	mech_register_module(&mech_cram_md5);
 	mech_register_module(&mech_digest_md5);
+	if (getenv("NTLM_USE_WINBIND") != NULL)
+	    mech_register_module(&mech_winbind_ntlm);
+	else
 	mech_register_module(&mech_ntlm);
 	mech_register_module(&mech_rpa);
 	mech_register_module(&mech_anonymous);
 #ifdef HAVE_GSSAPI
 	mech_register_module(&mech_gssapi);
 #endif
+	mech_register_module(&mech_winbind_spnego);
 }
 
 void mech_deinit(void)
@@ -96,10 +102,14 @@
 	mech_unregister_module(&mech_apop);
 	mech_unregister_module(&mech_cram_md5);
 	mech_unregister_module(&mech_digest_md5);
+	if (getenv("NTLM_USE_WINBIND") != NULL)
+	    mech_unregister_module(&mech_winbind_ntlm);
+	else
 	mech_unregister_module(&mech_ntlm);
 	mech_unregister_module(&mech_rpa);
 	mech_unregister_module(&mech_anonymous);
 #ifdef HAVE_GSSAPI
 	mech_unregister_module(&mech_gssapi);
 #endif
+	mech_unregister_module(&mech_winbind_spnego);
 }
diff -Nrbu dovecot-1.0.1/src/master/auth-process.c dovecot-1.0.1-OK/src/master/auth-process.c
--- dovecot-1.0.1/src/master/auth-process.c	2007-06-12 20:43:46.000000000 +0400
+++ dovecot-1.0.1-OK/src/master/auth-process.c	2007-07-03 17:53:14.000000000 +0400
@@ -474,6 +474,8 @@
 		env_put("SSL_REQUIRE_CLIENT_CERT=1");
 	if (set->ssl_username_from_cert)
 		env_put("SSL_USERNAME_FROM_CERT=1");
+	if (set->ntlm_use_winbind)
+		env_put("NTLM_USE_WINBIND=1");
 	if (*set->krb5_keytab != '\0') {
 		/* Environment used by Kerberos 5 library directly */
 		env_put(t_strconcat("KRB5_KTNAME=", set->krb5_keytab, NULL));
@@ -482,6 +484,14 @@
 		env_put(t_strconcat("GSSAPI_HOSTNAME=",
 				    set->gssapi_hostname, NULL));
 	}
+	if (*set->winbind_helper_ntlm != '\0') {
+		env_put(t_strconcat("WINBIND_HELPER_NTLM=",
+				    set->winbind_helper_ntlm, NULL));
+	}
+	if (*set->winbind_helper_spnego != '\0') {
+		env_put(t_strconcat("WINBIND_HELPER_SPNEGO=",
+				    set->winbind_helper_spnego, NULL));
+	}
 
 	restrict_process_size(set->process_size, (unsigned int)-1);
 }
diff -Nrbu dovecot-1.0.1/src/master/master-settings.c dovecot-1.0.1-OK/src/master/master-settings.c
--- dovecot-1.0.1/src/master/master-settings.c	2007-06-12 20:43:06.000000000 +0400
+++ dovecot-1.0.1-OK/src/master/master-settings.c	2007-07-03 17:53:14.000000000 +0400
@@ -72,12 +72,15 @@
 	DEF(SET_STR, anonymous_username),
 	DEF(SET_STR, krb5_keytab),
 	DEF(SET_STR, gssapi_hostname),
+	DEF(SET_STR, winbind_helper_ntlm),
+	DEF(SET_STR, winbind_helper_spnego),
 
 	DEF(SET_BOOL, verbose),
 	DEF(SET_BOOL, debug),
 	DEF(SET_BOOL, debug_passwords),
 	DEF(SET_BOOL, ssl_require_client_cert),
 	DEF(SET_BOOL, ssl_username_from_cert),
+	DEF(SET_BOOL, ntlm_use_winbind),
 
 	DEF(SET_INT, count),
 	DEF(SET_INT, worker_max_count),
@@ -291,12 +294,15 @@
 	MEMBER(anonymous_username) "anonymous",
 	MEMBER(krb5_keytab) "",
 	MEMBER(gssapi_hostname) "",
+	MEMBER(winbind_helper_ntlm) "",
+	MEMBER(winbind_helper_spnego) "",
 
 	MEMBER(verbose) FALSE,
 	MEMBER(debug) FALSE,
 	MEMBER(debug_passwords) FALSE,
 	MEMBER(ssl_require_client_cert) FALSE,
 	MEMBER(ssl_username_from_cert) FALSE,
+	MEMBER(ntlm_use_winbind) FALSE,
 
 	MEMBER(count) 1,
 	MEMBER(worker_max_count) 30,
diff -Nrbu dovecot-1.0.1/src/master/master-settings.h dovecot-1.0.1-OK/src/master/master-settings.h
--- dovecot-1.0.1/src/master/master-settings.h	2007-06-12 20:42:52.000000000 +0400
+++ dovecot-1.0.1-OK/src/master/master-settings.h	2007-07-03 17:53:14.000000000 +0400
@@ -191,10 +191,13 @@
 	const char *anonymous_username;
 	const char *krb5_keytab;
 	const char *gssapi_hostname;
+	const char *winbind_helper_ntlm;
+	const char *winbind_helper_spnego;
 
 	bool verbose, debug, debug_passwords;
 	bool ssl_require_client_cert;
 	bool ssl_username_from_cert;
+	bool ntlm_use_winbind;
 
 	unsigned int count;
 	unsigned int worker_max_count;

