diff -urN cyrus-sasl-2.1.18.orig/configure.in cyrus-sasl-2.1.18/configure.in
--- cyrus-sasl-2.1.18.orig/configure.in	2004-03-09 19:54:13 +0300
+++ cyrus-sasl-2.1.18/configure.in	2004-07-13 19:40:12 +0400
@@ -528,26 +528,60 @@
   ntlm=$enableval,
   ntlm=no)
 
-if test "$with_openssl" = no; then
+AC_ARG_WITH(ntlm_impl, [  --with-ntlm_impl={cyrus|samba}          Choose specific NTLMSSP implementation [cyrus] ],
+  ntlm_impl=$withval,
+  ntlm_impl=cyrus)
+
+if test "$with_openssl" = no -a "$ntlm_impl" = cyrus; then
   AC_WARN([OpenSSL not found -- NTLM will be disabled])
   ntlm=no
 fi
 
 AC_MSG_CHECKING(NTLM)
 if test "$ntlm" != no; then
-  AC_MSG_RESULT(enabled)
-  NTLM_LIBS="-lcrypto $LIB_RSAREF"
+  AC_MSG_RESULT(with implementation ${ntlm_impl})
+
+  if test "$ntlm_impl" = samba; then
+    NTLM_LIBS=""
+    NTLM_OBJS="ntlm_samba.lo"
+    NTLM_STATIC_OBJS="ntlm_samba.o"
+  else
+    NTLM_LIBS="-lcrypto $LIB_RSAREF"
+    NTLM_OBJS="ntlm.lo"
+    NTLM_STATIC_OBJS="ntlm.o"
+  fi
+
   AC_SUBST(NTLM_LIBS)
+  AC_SUBST(NTLM_OBJS)
 
   SASL_MECHS="$SASL_MECHS libntlm.la"
   if test "$enable_static" = yes; then
-    SASL_STATIC_OBJS="$SASL_STATIC_OBJS ../plugins/ntlm.o"
+    SASL_STATIC_OBJS="$SASL_STATIC_OBJS ../plugins/$NTLM_STATIC_OBJS"
     AC_DEFINE(STATIC_NTLM,[],[Link NTLM Staticly])
   fi
 else
   AC_MSG_RESULT(disabled)
 fi
 
+dnl GSSSPNEGO
+AC_ARG_ENABLE(gssspnego, [  --enable-gssspnego           enable unsupported GSSSPNEGO authentication [no] ],
+  gssspnego=$enableval,
+  gssspnego=no)
+
+AC_MSG_CHECKING(GSSSPNEGO)
+if test "$gssspnego" != no; then
+  AC_MSG_RESULT(enabled)
+  AC_SUBST(GSSSPNEGO_LIBS)
+
+  SASL_MECHS="$SASL_MECHS libgssspnego.la"
+  if test "$enable_static" = yes; then
+    SASL_STATIC_OBJS="$SASL_STATIC_OBJS ../plugins/gssspnego.o"
+    AC_DEFINE(STATIC_GSSSPNEGO,[],[Link GSSSPNEGO Staticly])
+  fi
+else
+  AC_MSG_RESULT(disabled)
+fi
+
 
 # make the option show up so people don't whine that it is only in the
 # saslauthd configure script --help
diff -urN cyrus-sasl-2.1.18.orig/plugins/gssspnego.c cyrus-sasl-2.1.18/plugins/gssspnego.c
--- cyrus-sasl-2.1.18.orig/plugins/gssspnego.c	1970-01-01 03:00:00 +0300
+++ cyrus-sasl-2.1.18/plugins/gssspnego.c	2004-07-14 12:31:55 +0400
@@ -0,0 +1,557 @@
+/* GSS SPNEGO plugin
+ * Volker Lendecke
+ */
+/* 
+ * Copyright (c) 1998-2003 Carnegie Mellon University.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer. 
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * 3. The name "Carnegie Mellon University" must not be used to
+ *    endorse or promote products derived from this software without
+ *    prior written permission. For permission or any other legal
+ *    details, please contact  
+ *      Office of Technology Transfer
+ *      Carnegie Mellon University
+ *      5000 Forbes Avenue
+ *      Pittsburgh, PA  15213-3890
+ *      (412) 268-4387, fax: (412) 268-7395
+ *      tech-transfer@andrew.cmu.edu
+ *
+ * 4. Redistributions of any form whatsoever must retain the following
+ *    acknowledgment:
+ *    "This product includes software developed by Computing Services
+ *     at Carnegie Mellon University (http://www.cmu.edu/computing/)."
+ *
+ * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
+ * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE
+ * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
+ * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
+ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <string.h> 
+#include <sasl.h>
+#include <saslplug.h>
+#include <syslog.h>
+
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#include "plugin_common.h"
+#include "smb_helper.h"
+
+#ifdef macintosh 
+#include <sasl_gssspnego_plugin_decl.h> 
+#endif 
+
+/*****************************  Common Section  *****************************/
+
+static const char plugin_id[] = "$Id: gssspnego.c,v 1.61 2003/03/26 17:18:04 rjs3 Exp $";
+
+/*****************************  Server Section  *****************************/
+
+struct gssspnego_context {
+	struct smb_helper *helper;
+};
+
+static int gssspnego_server_mech_new(void *glob_context __attribute__((unused)), 
+				 sasl_server_params_t *sparams,
+				 const char *challenge __attribute__((unused)),
+				 unsigned challen __attribute__((unused)),
+				 void **conn_context)
+{
+	char * argv[] = { "ntlm_auth",
+			  "--helper-protocol=gss-spnego",
+			  NULL };
+
+	struct gssspnego_context *context =
+		malloc(sizeof(struct gssspnego_context));
+
+	if (context == NULL) {
+		syslog(LOG_DEBUG, "gssspnego_server_mech_new: No memory\n");
+		MEMERROR(sparams->utils);
+		return SASL_NOMEM;
+	}
+
+	memset(context, 0, sizeof(struct gssspnego_context));
+
+	*conn_context = context;
+
+	return fork_helper(&context->helper, "ntlm_auth",
+				argv, sparams->utils);
+}
+
+static int gssspnego_server_mech_step(void *conn_context,
+				      sasl_server_params_t *params,
+				      const char *clientin,
+				      unsigned clientinlen,
+				      const char **serverout,
+				      unsigned *serveroutlen,
+				      sasl_out_params_t *oparams)
+{
+	struct gssspnego_context *context =
+		(struct gssspnego_context *)conn_context;
+
+	unsigned char childbuf[1025];
+	unsigned childbuflen;
+
+	unsigned char *childarg;
+	unsigned base64len;
+
+	static unsigned char bin[1025];
+
+	int result;
+
+	if (clientinlen == 0) {
+
+		/* This should only happen on the first request, we
+                   need the initial mechanism offer from the child. */
+
+		strncpy(childbuf, "YR", sizeof(childbuf)-1);
+		childbuflen = strlen(childbuf);
+
+	} else {
+
+		strncpy(childbuf, "KK ", sizeof(childbuf)-1);
+
+		if (params->utils->encode64(clientin, clientinlen,
+					    childbuf+3, sizeof(childbuf)-4,
+					    &childbuflen) != SASL_OK) {
+			syslog(LOG_DEBUG,
+			       "Could not convert clientin to base64\n");
+			return SASL_FAIL;
+		}
+	}
+
+	if ((result = interact_helper(context->helper,
+					childbuf,
+					sizeof(childbuf),
+					&childbuflen)) != SASL_OK)
+		return result;
+
+	/* 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
+	*/
+
+	childarg = strchr(childbuf+3, ' ');
+
+	if (childarg == NULL) {
+		syslog(LOG_DEBUG, "Got invalid response from child\n");
+		return SASL_FAIL;
+	}
+
+	base64len = (childarg - childbuf) - 3;
+
+	if (params->utils->decode64(childbuf+3, base64len,
+				    bin, sizeof(bin)-1,
+				    serveroutlen) != SASL_OK) {
+		syslog(LOG_DEBUG, "Could not decode child's base64\n");
+		return SASL_FAIL;
+	}
+	*serverout = bin;
+	childarg++;
+
+	if ( strncmp(childbuf, "TT ", 3) == 0) {
+		/* Next round */
+		return SASL_CONTINUE;
+	}
+	if (strncmp(childbuf, "NA ", 3) == 0) {
+		/* Not Authenticated */
+		kill_helper(context->helper);
+		return SASL_BADAUTH;
+	}
+
+	if (strncmp(childbuf, "AF ", 3) == 0) {
+		/* Authentication Fine */
+		char *domain = childarg;
+		char *user = strchr(domain, '\\');
+		int status;
+
+		kill_helper(context->helper);
+
+		if (user == NULL) {
+			syslog(LOG_DEBUG,
+			       "Could not find user/domain in AF\n");
+			return SASL_FAIL;
+		}
+		*user++ = 0;
+		if ( (status = params->canon_user(params->utils->conn,
+						  user, 0, SASL_CU_AUTHID,
+						  oparams)) != SASL_OK ) {
+			syslog(LOG_DEBUG, "canon_user for AUTHID failed\n");
+			return status;
+		}
+
+		if ( (status = params->canon_user(params->utils->conn,
+						  user, 0, SASL_CU_AUTHZID,
+						  oparams)) != SASL_OK ) {
+			syslog(LOG_DEBUG, "canon_user for AUTHZID failed\n");
+			return status;
+		}
+					    
+		oparams->doneflag = 1;
+		oparams->mech_ssf = 0;
+		oparams->maxoutbuf = 0;
+		oparams->encode_context = NULL;
+		oparams->encode = NULL;
+		oparams->decode_context = NULL;
+		oparams->decode = NULL;
+
+		return SASL_OK;
+	}
+
+	syslog(LOG_DEBUG, "Child's response unknown\n");
+	return SASL_FAIL;
+}
+
+static void gssspnego_server_mech_dispose(void *conn_context,
+					  const sasl_utils_t *utils __attribute__((unused)))
+{
+	struct gssspnego_context *context =
+		(struct gssspnego_context *)conn_context;
+
+	kill_helper(context->helper);
+
+	return;
+}
+
+static sasl_server_plug_t gssspnego_server_plugins[] = 
+{
+    {
+	"GSS-SPNEGO",			/* mech_name */
+	0,				/* max_ssf */
+	SASL_SEC_NOANONYMOUS
+	| SASL_SEC_NOPLAINTEXT,		/* security_flags */
+	SASL_FEAT_SERVER_FIRST,		/* features */
+	NULL,				/* glob_context */
+	&gssspnego_server_mech_new,		/* mech_new */
+	&gssspnego_server_mech_step,	/* mech_step */
+	&gssspnego_server_mech_dispose,	/* mech_dispose */
+	NULL,				/* mech_free */
+	NULL,				/* setpass */
+	NULL,				/* user_query */
+	NULL,				/* idle */
+	NULL,				/* mech_avail */
+	NULL				/* spare */
+    }
+};
+
+int gssspnego_server_plug_init(const sasl_utils_t *utils,
+			   int maxversion,
+			   int *out_version,
+			   sasl_server_plug_t **pluglist,
+			   int *plugcount)
+{
+    if (maxversion < SASL_SERVER_PLUG_VERSION) {
+	SETERROR(utils, "GSSSPNEGO version mismatch");
+	return SASL_BADVERS;
+    }
+    
+    *out_version = SASL_SERVER_PLUG_VERSION;
+    *pluglist = gssspnego_server_plugins;
+    *plugcount = 1;  
+    
+    return SASL_OK;
+}
+
+/*****************************  Client Section  *****************************/
+
+static int gssspnego_new_client_helper(struct gssspnego_context *context,
+				       sasl_client_params_t *params,
+				       sasl_interact_t **prompt_need,
+				       sasl_out_params_t *oparams)
+{
+	int auth_result = SASL_OK;
+	int domain_result = SASL_OK;
+	static const char *authid = NULL;
+	static const char *domain = NULL;
+
+	char child_user_arg[512];
+	char child_domain_arg[512];
+
+	int result;
+
+	char *argv[] = { "ntlm_auth",
+			 "--helper-protocol=gss-spnego-client",
+			 child_user_arg,
+			 child_domain_arg,
+			 NULL };
+
+	if (authid == NULL) {
+		auth_result = _plug_get_authid(params->utils,
+					       &authid, prompt_need);
+
+		if ( (auth_result != SASL_OK) &&
+		     (auth_result != SASL_INTERACT) &&
+		     (authid == NULL) )
+			return auth_result;
+	}
+
+	if (domain == NULL) {
+		domain_result = _plug_get_realm(params->utils, NULL,
+						&domain, prompt_need);
+		if ( (domain_result != SASL_OK) &&
+		     (domain_result != SASL_INTERACT) &&
+		     (domain == NULL) )
+			return domain_result;
+	}
+
+	/* free prompts we got */
+	if (prompt_need && *prompt_need) {
+		params->utils->free(*prompt_need);
+		*prompt_need = NULL;
+	}
+
+	if ( (auth_result == SASL_INTERACT) ||
+	     (domain_result == SASL_INTERACT) ) {
+		result = _plug_make_prompts(params->utils, prompt_need,
+					    NULL, NULL,
+					    (auth_result == SASL_INTERACT) ?
+					    "Username" : NULL, NULL,
+					    NULL, NULL,
+					    NULL, NULL, NULL,
+					    NULL,
+					    (domain_result == SASL_INTERACT) ?
+					    "Realm (Domain)" : NULL, NULL);
+
+		if (result != SASL_OK)
+			return result;
+		return SASL_INTERACT;
+	}
+
+	oparams->user   = strdup(authid);
+	oparams->ulen   = strlen(authid);
+	oparams->authid = strdup(authid);
+	oparams->alen   = oparams->ulen;
+
+	snprintf(child_user_arg, sizeof(child_user_arg)-1,
+		 "--username=%s", authid);
+	snprintf(child_domain_arg, sizeof(child_domain_arg)-1,
+		 "--domain=%s", domain);
+
+	return fork_helper(&context->helper, "ntlm_auth",
+				argv, params->utils);
+}
+
+static int gssspnego_client_mech_new(void *glob_context __attribute__((unused)),
+				     sasl_client_params_t *params,
+				     void **conn_context)
+{
+	struct gssspnego_context *context =
+		malloc(sizeof(struct gssspnego_context));
+
+	if (context == NULL) {
+		MEMERROR(params->utils);
+		return SASL_NOMEM;
+	}
+
+	memset(context, 0, sizeof(struct gssspnego_context));
+
+	*conn_context = context;
+
+	return SASL_OK;
+}
+
+static int gssspnego_client_mech_step(void *conn_context,
+				  sasl_client_params_t *params,
+				  const char *serverin,
+				  unsigned serverinlen,
+				  sasl_interact_t **prompt_need,
+				  const char **clientout,
+				  unsigned *clientoutlen,
+				  sasl_out_params_t *oparams)
+{
+	struct gssspnego_context *context =
+		(struct gssspnego_context *)conn_context;
+
+	unsigned char childbuf[1025];
+	unsigned childbuflen;
+
+	int result;
+
+	static sasl_secret_t *password;
+	static int must_free_password;
+	static int must_send_password = 0;
+
+	if (context->helper == NULL) {
+		result = gssspnego_new_client_helper(context, params,
+						     prompt_need, oparams);
+
+		if (result != SASL_OK)
+			return result;
+	}
+
+	if (must_send_password != 0) {
+
+		must_send_password = 0;
+
+	send_password:
+
+		strncpy(childbuf, "PW ", sizeof(childbuf)-1);
+
+		if (params->utils->encode64(password->data, password->len,
+					    childbuf+3, sizeof(childbuf)-3,
+					    &childbuflen) != SASL_OK) {
+			syslog(LOG_DEBUG,
+			       "Could not convert password to base64\n");
+			return SASL_FAIL;
+		}
+
+		if ((result = interact_helper(context->helper,
+						childbuf,
+						sizeof(childbuf),
+						&childbuflen)) != SASL_OK)
+			return result;
+
+		if (strncmp(childbuf, "OK", 2) != 0) {
+			syslog(LOG_DEBUG, "Child did not accept our password\n");
+			return SASL_FAIL;
+		}
+	}
+
+	strncpy(childbuf, "TT ", sizeof(childbuf)-1);
+
+	if (params->utils->encode64(serverin, serverinlen,
+				    childbuf+3, sizeof(childbuf)-4,
+				    &childbuflen) != SASL_OK) {
+		syslog(LOG_DEBUG,
+		       "Could not convert serverin to base64\n");
+		return SASL_FAIL;
+	}
+
+	if ((result = interact_helper(context->helper,
+					childbuf,
+					sizeof(childbuf),
+					&childbuflen)) != SASL_OK)
+		return result;
+
+	/* The child's reply can be:
+	   "PW" -> It wants a password
+	   "KK <base64>" -> Send <base64> to the server
+	   "AF" -> Authenticated
+	   "NA" -> Not Authenticated
+	*/
+
+	if (strncmp(childbuf, "PW", 2) == 0) {
+
+		result = _plug_get_password(params->utils, &password,
+					    &must_free_password, prompt_need);
+
+		if ( (result != SASL_OK) &&
+		     (result != SASL_INTERACT) )
+			return result;
+
+		/* free prompts we got */
+		if (prompt_need && *prompt_need) {
+			params->utils->free(*prompt_need);
+			*prompt_need = NULL;
+		}
+
+		if (result == SASL_OK)
+			goto send_password;
+
+		result = _plug_make_prompts(params->utils, prompt_need,
+					    NULL, NULL,
+					    NULL, NULL,
+					    "Password", NULL,
+					    NULL, NULL, NULL,
+					    NULL, NULL, NULL);
+		if (result != SASL_OK)
+			return result;
+		return SASL_INTERACT;
+
+	}
+
+	if (strncmp(childbuf, "KK ", 3) == 0) {
+		static char bin[2048];
+
+		if (params->utils->decode64(childbuf+3, childbuflen-3,
+					    bin, sizeof(bin)-1,
+					    clientoutlen) != SASL_OK) {
+			syslog(LOG_DEBUG, "Could not decode child's base64\n");
+			return SASL_FAIL;
+		}
+		*clientout = bin;
+		return SASL_CONTINUE;
+	}
+
+	if ( (strncmp(childbuf, "AF", 2) == 0) ||
+	     (strncmp(childbuf, "NA", 2) == 0) ) {
+		
+		kill_helper(context->helper);
+
+		*clientout = NULL;
+		*clientoutlen = 0;
+
+		/* set oparams */
+		oparams->doneflag = 1;
+		oparams->mech_ssf = 0;
+		oparams->maxoutbuf = 0;
+		oparams->encode_context = NULL;
+		oparams->encode = NULL;
+		oparams->decode_context = NULL;
+		oparams->decode = NULL;
+
+		return (strncmp(childbuf, "AF", 2) == 0) ?
+			SASL_OK : SASL_BADAUTH;
+	}
+
+	return SASL_FAIL;
+}
+
+static sasl_client_plug_t gssspnego_client_plugins[] = 
+{
+    {
+	"GSS-SPNEGO",			/* mech_name */
+	0,				/* max_ssf */
+	SASL_SEC_NOANONYMOUS | SASL_SEC_NOPLAINTEXT,		/* security_flags */
+	SASL_FEAT_SERVER_FIRST, /* features */
+	NULL,				/* required_prompts */
+	NULL,				/* glob_context */
+	&gssspnego_client_mech_new,	/* mech_new */
+	&gssspnego_client_mech_step,	/* mech_step */
+	NULL,				/* mech_dispose */
+	NULL,				/* mech_free */
+	NULL,				/* idle */
+	NULL,				/* spare */
+	NULL				/* spare */
+    }
+};
+
+int gssspnego_client_plug_init(sasl_utils_t *utils,
+			   int maxversion,
+			   int *out_version,
+			   sasl_client_plug_t **pluglist,
+			   int *plugcount)
+{
+    if (maxversion < SASL_CLIENT_PLUG_VERSION) {
+	SETERROR(utils, "GSSSPNEGO version mismatch");
+	return SASL_BADVERS;
+    }
+    
+    *out_version = SASL_CLIENT_PLUG_VERSION;
+    *pluglist = gssspnego_client_plugins;
+    *plugcount = 1;
+    
+    return SASL_OK;
+}
diff -urN cyrus-sasl-2.1.18.orig/plugins/Makefile.am cyrus-sasl-2.1.18/plugins/Makefile.am
--- cyrus-sasl-2.1.18.orig/plugins/Makefile.am	2004-03-09 19:54:18 +0300
+++ cyrus-sasl-2.1.18/plugins/Makefile.am	2004-07-13 18:45:05 +0400
@@ -55,6 +55,7 @@
 login_version = 2:19:0
 plain_version = 2:19:0
 ntlm_version = 2:19:0
+gssspnego_version = 2:19:0
 otp_version = 2:19:0
 sql_version = 2:19:0
 srp_version = 2:19:0
@@ -77,7 +78,7 @@
 sasl_LTLIBRARIES = @SASL_MECHS@
 EXTRA_LTLIBRARIES = libplain.la libanonymous.la libkerberos4.la libcrammd5.la \
 	libgssapiv2.la libdigestmd5.la liblogin.la libsrp.la libotp.la \
-	libntlm.la libsasldb.la libsql.la
+	libntlm.la libgssspnego.la libsasldb.la libsql.la
 
 libplain_la_SOURCES = plain.c plain_init.c $(common_sources)
 libplain_la_LDFLAGS = -version-info $(plain_version)
@@ -124,10 +125,16 @@
 libotp_la_DEPENDENCIES = $(COMPAT_OBJS)
 libotp_la_LIBADD = $(OTP_LIBS) $(COMPAT_OBJS)
 
-libntlm_la_SOURCES = ntlm.c ntlm_init.c $(common_sources)
+libntlm_la_SOURCES = smb_helper.c smb_helper.h ntlm_init.c $(common_sources)
+EXTRA_libntlm_la_SOURCES = ntlm.c ntlm_samba.c
 libntlm_la_LDFLAGS = -version-info $(ntlm_version)
-libntlm_la_DEPENDENCIES = $(COMPAT_OBJS)
-libntlm_la_LIBADD = $(NTLM_LIBS) $(COMPAT_OBJS)
+libntlm_la_DEPENDENCIES = $(COMPAT_OBJS) $(NTLM_OBJS)
+libntlm_la_LIBADD = $(NTLM_LIBS) $(COMPAT_OBJS) $(NTLM_OBJS)
+
+libgssspnego_la_SOURCES = smb_helper.c smb_helper.h gssspnego.c gssspnego_init.c $(common_sources)
+libgssspnego_la_LDFLAGS = -version-info $(gssspnego_version)
+libgssspnego_la_DEPENDENCIES = $(COMPAT_OBJS)
+libgssspnego_la_LIBADD = $(GSSSPNEGO_LIBS) $(COMPAT_OBJS)
 
 # Auxprop Plugins
 libsasldb_la_SOURCES = sasldb.c sasldb_init.c $(common_sources)
@@ -145,7 +152,7 @@
 
 init_src=anonymous_init.c crammd5_init.c digestmd5_init.c gssapiv2_init.c \
 kerberos4_init.c login_init.c plain_init.c srp_init.c otp_init.c ntlm_init.c \
-sasldb_init.c sql_init.c
+gssspnego_init.c sasldb_init.c sql_init.c
 
 
 CLEANFILES=$(init_src)
diff -urN cyrus-sasl-2.1.18.orig/plugins/makeinit.sh cyrus-sasl-2.1.18/plugins/makeinit.sh
--- cyrus-sasl-2.1.18.orig/plugins/makeinit.sh	2003-07-15 21:38:59 +0400
+++ cyrus-sasl-2.1.18/plugins/makeinit.sh	2004-06-30 13:34:36 +0400
@@ -1,4 +1,4 @@
-for mech in anonymous crammd5 digestmd5 gssapiv2 kerberos4 login ntlm otp plain srp; do
+for mech in anonymous crammd5 digestmd5 gssapiv2 kerberos4 login ntlm gssspnego otp plain srp; do
 
 echo "
 #include <config.h>
diff -urN cyrus-sasl-2.1.18.orig/plugins/ntlm_samba.c cyrus-sasl-2.1.18/plugins/ntlm_samba.c
--- cyrus-sasl-2.1.18.orig/plugins/ntlm_samba.c	1970-01-01 03:00:00 +0300
+++ cyrus-sasl-2.1.18/plugins/ntlm_samba.c	2004-07-13 19:30:52 +0400
@@ -0,0 +1,561 @@
+/* NTLM (via ntlm_auth) plugin
+ * Volker Lendecke, Andrew Bartlett
+ */
+/* 
+ * Copyright (c) 1998-2003 Carnegie Mellon University.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer. 
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * 3. The name "Carnegie Mellon University" must not be used to
+ *    endorse or promote products derived from this software without
+ *    prior written permission. For permission or any other legal
+ *    details, please contact  
+ *      Office of Technology Transfer
+ *      Carnegie Mellon University
+ *      5000 Forbes Avenue
+ *      Pittsburgh, PA  15213-3890
+ *      (412) 268-4387, fax: (412) 268-7395
+ *      tech-transfer@andrew.cmu.edu
+ *
+ * 4. Redistributions of any form whatsoever must retain the following
+ *    acknowledgment:
+ *    "This product includes software developed by Computing Services
+ *     at Carnegie Mellon University (http://www.cmu.edu/computing/)."
+ *
+ * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
+ * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE
+ * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
+ * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
+ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <string.h> 
+#include <sasl.h>
+#include <saslplug.h>
+#include <syslog.h>
+
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#include "plugin_common.h"
+#include "smb_helper.h"
+
+#ifdef macintosh 
+#include <sasl_ntlm_plugin_decl.h> 
+#endif 
+
+/*****************************  Common Section  *****************************/
+
+static const char plugin_id[] = "$Id: ntlm.c,v 1.61 2003/03/26 17:18:04 rjs3 Exp $";
+
+/*****************************  Server Section  *****************************/
+
+struct ntlm_context {
+	struct smb_helper *helper;
+	int first;
+	sasl_secret_t *password;	/* user password */
+	unsigned int free_password; /* set if we need to free password */
+	unsigned int sent_password; /* set if we have told ntlm_auth the password already */
+	const char *authid;
+	const char *domain;
+};
+
+static int ntlm_server_mech_new(void *glob_context __attribute__((unused)), 
+				 sasl_server_params_t *sparams,
+				 const char *challenge __attribute__((unused)),
+				 unsigned challen __attribute__((unused)),
+				 void **conn_context)
+{
+	char * argv[] = { "ntlm_auth",
+			  "--helper-protocol=squid-2.5-ntlmssp",
+			  NULL };
+
+	struct ntlm_context *context =
+		malloc(sizeof(struct ntlm_context));
+	
+	if (context == NULL) {
+		syslog(LOG_DEBUG, "ntlm_server_mech_new: No memory\n");
+		MEMERROR(sparams->utils);
+		return SASL_NOMEM;
+	}
+
+	memset(context, 0, sizeof(struct ntlm_context));
+	context->first = 1;
+
+	*conn_context = context;
+
+	return fork_helper(&context->helper, "ntlm_auth",
+				argv, sparams->utils);
+}
+
+static int ntlm_server_mech_step(void *conn_context,
+				      sasl_server_params_t *params,
+				      const char *clientin,
+				      unsigned clientinlen,
+				      const char **serverout,
+				      unsigned *serveroutlen,
+				      sasl_out_params_t *oparams)
+{
+	struct ntlm_context *context =
+		(struct ntlm_context *)conn_context;
+
+	unsigned char childbuf[1025];
+	unsigned childbuflen;
+
+	unsigned base64len;
+
+	static unsigned char bin[1025];
+
+	int result;
+
+	if (context->first) {
+		strncpy(childbuf, "YR ", sizeof(childbuf)-1);
+		context->first = 0;
+	} else {
+		strncpy(childbuf, "KK ", sizeof(childbuf)-1);
+	}
+
+	if (params->utils->encode64(clientin, clientinlen,
+				    childbuf+3, sizeof(childbuf)-4,
+				    &childbuflen) != SASL_OK) {
+		syslog(LOG_DEBUG,
+		       "Could not convert clientin to base64\n");
+		return SASL_FAIL;
+	}
+
+	if ((result = interact_helper(context->helper,
+					childbuf,
+					sizeof(childbuf),
+					&childbuflen)) != SASL_OK)
+		return result;
+	
+	/* The child's reply contains 3 parts:
+	   - The code: TT, AF or NA
+	   - The blob to send to the client, coded in base64
+	   - or for AF it's domain\\user
+	        for NA it's the NT error code
+	*/
+
+	if (strlen(childbuf) < 3) {
+		syslog(LOG_DEBUG, "Got invalid response from child (parse of ntlm_auth output failure)\n");
+		return SASL_FAIL;
+	}
+
+	base64len = strlen(childbuf) - 3;
+
+	if ( strncmp(childbuf, "TT ", 3) == 0) {
+		if (params->utils->decode64(childbuf+3, base64len,
+					    bin, sizeof(bin)-1,
+					    serveroutlen) != SASL_OK) {
+			syslog(LOG_DEBUG, "Could not decode child's base64\n");
+			return SASL_FAIL;
+		}
+		*serverout = bin;
+
+		/* Next round */
+		return SASL_CONTINUE;
+	}
+	if (strncmp(childbuf, "NA ", 3) == 0) {
+		/* Not Authenticated */
+		kill_helper(context->helper);
+		return SASL_BADAUTH;
+	}
+
+	if (strncmp(childbuf, "AF ", 3) == 0) {
+		/* Authentication Fine */
+		char *user = childbuf + 3;
+		int status;
+
+		kill_helper(context->helper);
+
+		if ( (status = params->canon_user(params->utils->conn,
+						  user, 0, SASL_CU_AUTHID,
+						  oparams)) != SASL_OK ) {
+			syslog(LOG_DEBUG, "canon_user for AUTHID [%s] failed\n", user);
+			return status;
+		}
+
+		if ( (status = params->canon_user(params->utils->conn,
+						  user, 0, SASL_CU_AUTHZID,
+						  oparams)) != SASL_OK ) {
+			syslog(LOG_DEBUG, "canon_user for AUTHZID [%s] failed\n", user);
+			return status;
+		}
+					    
+		oparams->doneflag = 1;
+		oparams->mech_ssf = 0;
+		oparams->maxoutbuf = 0;
+		oparams->encode_context = NULL;
+		oparams->encode = NULL;
+		oparams->decode_context = NULL;
+		oparams->decode = NULL;
+
+		return SASL_OK;
+	}
+
+	syslog(LOG_DEBUG, "Child's response unknown\n");
+	return SASL_FAIL;
+}
+
+static void ntlm_server_mech_dispose(void *conn_context,
+					  const sasl_utils_t *utils __attribute__((unused)))
+{
+	struct ntlm_context *context =
+		(struct ntlm_context *)conn_context;
+
+	kill_helper(context->helper);
+
+	return;
+}
+
+static sasl_server_plug_t ntlm_server_plugins[] = 
+{
+    {
+	"NTLM",			/* mech_name */
+	0,				/* max_ssf */
+	SASL_SEC_NOANONYMOUS
+	| SASL_SEC_NOPLAINTEXT,		/* security_flags */
+	SASL_FEAT_WANT_CLIENT_FIRST,		/* features */
+	NULL,				/* glob_context */
+	&ntlm_server_mech_new,		/* mech_new */
+	&ntlm_server_mech_step,	/* mech_step */
+	&ntlm_server_mech_dispose,	/* mech_dispose */
+	NULL,				/* mech_free */
+	NULL,				/* setpass */
+	NULL,				/* user_query */
+	NULL,				/* idle */
+	NULL,				/* mech_avail */
+	NULL				/* spare */
+    }
+};
+
+int ntlm_server_plug_init(const sasl_utils_t *utils,
+			   int maxversion,
+			   int *out_version,
+			   sasl_server_plug_t **pluglist,
+			   int *plugcount)
+{
+    if (maxversion < SASL_SERVER_PLUG_VERSION) {
+	SETERROR(utils, "NTLM version mismatch");
+	return SASL_BADVERS;
+    }
+    
+    *out_version = SASL_SERVER_PLUG_VERSION;
+    *pluglist = ntlm_server_plugins;
+    *plugcount = 1;  
+    
+    return SASL_OK;
+}
+
+/*****************************  Client Section  *****************************/
+
+static int ntlm_new_client_helper(struct ntlm_context *context,
+				       sasl_client_params_t *params,
+				       sasl_interact_t **prompt_need,
+				       sasl_out_params_t *oparams)
+{
+	int auth_result = SASL_OK;
+	int domain_result = SASL_OK;
+
+	int pass_result = SASL_OK;
+	int result;
+
+	char child_user_arg[512];
+	char child_domain_arg[512];
+
+	const char *domains[] = {
+		"",
+		NULL
+	};
+
+	char *argv[] = { "ntlm_auth",
+			 "--helper-protocol=ntlmssp-client-1",
+			 child_user_arg,
+			 child_domain_arg,
+			 NULL };
+
+	if (context->authid == NULL) {
+		auth_result = _plug_get_authid(params->utils,
+					       &context->authid, prompt_need);
+
+		if ( (auth_result != SASL_OK) &&
+		     (auth_result != SASL_INTERACT) &&
+		     (context->authid == NULL) )
+			return auth_result;
+	}
+
+	if (context->domain == NULL) {
+		domain_result = _plug_get_realm(params->utils, domains,
+						&context->domain, prompt_need);
+		if ( (domain_result != SASL_OK) &&
+		     (domain_result != SASL_INTERACT) &&
+		     (context->domain == NULL) )
+			return domain_result;
+	}
+	
+	if (context->password == NULL) {
+		pass_result = _plug_get_password(params->utils, &context->password,
+					    &context->free_password, prompt_need);
+		
+		if ( (pass_result != SASL_OK) &&
+		     (pass_result != SASL_INTERACT) 
+		     && (context->password == NULL))
+			return pass_result;
+	}
+		
+	/* free prompts we got */
+	if (prompt_need && *prompt_need) {
+		params->utils->free(*prompt_need);
+		*prompt_need = NULL;
+	}
+
+	if ( (auth_result == SASL_INTERACT) ||
+	     (domain_result == SASL_INTERACT) ) {
+		result = _plug_make_prompts(params->utils, prompt_need,
+					    NULL, NULL,
+					    (auth_result == SASL_INTERACT) ?
+					    "Username" : NULL, NULL,
+					    pass_result == SASL_INTERACT ?
+					    "Password" : NULL, NULL,
+					    NULL, NULL, NULL,
+					    NULL,
+					    (domain_result == SASL_INTERACT) ?
+					    "Realm (Domain)" : NULL, NULL);
+
+		if (result != SASL_OK)
+			return result;
+		return SASL_INTERACT;
+	}
+
+	if (!context->password) {
+	    PARAMERROR(params->utils);
+	    return SASL_BADPARAM;
+	}
+
+	oparams->user   = strdup(context->authid);
+	oparams->ulen   = strlen(context->authid);
+	oparams->authid = strdup(context->authid);
+	oparams->alen   = oparams->ulen;
+
+	snprintf(child_user_arg, sizeof(child_user_arg)-1,
+		 "--username=%s", context->authid);
+	snprintf(child_domain_arg, sizeof(child_domain_arg)-1,
+		 "--domain=%s", context->domain);
+
+	return fork_helper(&context->helper, "ntlm_auth",
+				argv, params->utils);
+}
+
+static int ntlm_client_mech_new(void *glob_context __attribute__((unused)),
+				     sasl_client_params_t *params,
+				     void **conn_context)
+{
+	struct ntlm_context *context =
+		malloc(sizeof(struct ntlm_context));
+
+	if (context == NULL) {
+		MEMERROR(params->utils);
+		return SASL_NOMEM;
+	}
+
+	memset(context, 0, sizeof(struct ntlm_context));
+	context->first = 1;
+
+	*conn_context = context;
+
+	return SASL_OK;
+}
+
+static int ntlm_client_mech_step(void *conn_context,
+				  sasl_client_params_t *params,
+				  const char *serverin,
+				  unsigned serverinlen,
+				  sasl_interact_t **prompt_need,
+				  const char **clientout,
+				  unsigned *clientoutlen,
+				  sasl_out_params_t *oparams)
+{
+	struct ntlm_context *context =
+		(struct ntlm_context *)conn_context;
+
+	unsigned char childbuf[1025];
+	unsigned childbuflen;
+
+	int result;
+
+	if (context->helper == NULL) {
+		result = ntlm_new_client_helper(context, params,
+						prompt_need, oparams);
+
+		if (result != SASL_OK)
+			return result;
+	}
+
+	if (!context->sent_password) {
+
+		strncpy(childbuf, "PW ", sizeof(childbuf)-1);
+		
+		if (params->utils->encode64(context->password->data, context->password->len,
+					    childbuf+3, sizeof(childbuf)-3,
+					    &childbuflen) != SASL_OK) {
+			syslog(LOG_DEBUG,
+			       "Could not convert password to base64\n");
+			return SASL_FAIL;
+		}
+		
+		if ((result = interact_helper(context->helper,
+						childbuf,
+						sizeof(childbuf),
+						&childbuflen)) != SASL_OK)
+			return result;
+		
+		if (strncmp(childbuf, "OK", 2) != 0) {
+			syslog(LOG_DEBUG, "Child did not accept our password\n");
+			return SASL_FAIL;
+		}
+		context->sent_password = 1;
+	}
+
+	if (context->first) {
+		strncpy(childbuf, "YR", sizeof(childbuf)-1);
+		context->first = 0;
+	} else {
+		strncpy(childbuf, "TT", sizeof(childbuf)-1);
+	}
+
+	if (serverinlen) {
+		strncpy(childbuf+2, " ", sizeof(childbuf)-3);
+		if (params->utils->encode64(serverin, serverinlen,
+					    childbuf+3, sizeof(childbuf)-4,
+					    &childbuflen) != SASL_OK) {
+			syslog(LOG_DEBUG,
+			       "Could not convert serverin to base64\n");
+			return SASL_FAIL;
+		}
+	}
+
+	if ((result = interact_helper(context->helper,
+					childbuf,
+					sizeof(childbuf),
+					&childbuflen)) != SASL_OK)
+		return result;
+
+	/* The child's reply can be:
+	   "PW" -> It wants a password (but we premptivly deal with that above)
+	   "YR <base64>" -> Send (initial) <base64> to the server
+	   "KK <base64>" -> Send <base64> to the server
+	   "AF" -> Authenticated
+	   "NA" -> Not Authenticated
+	*/
+
+	if ((strncmp(childbuf, "YR ", 3) == 0) || (strncmp(childbuf, "KK ", 3) == 0)) {
+		static char bin[2048];
+
+		if (params->utils->decode64(childbuf+3, childbuflen-3,
+					    bin, sizeof(bin)-1,
+					    clientoutlen) != SASL_OK) {
+			syslog(LOG_DEBUG, "Could not decode child's base64\n");
+			return SASL_FAIL;
+		}
+		*clientout = bin;
+		return SASL_CONTINUE;
+	}
+
+	if ( (strncmp(childbuf, "AF", 2) == 0) ||
+	     (strncmp(childbuf, "NA", 2) == 0) ) {
+		
+		kill_helper(context->helper);
+
+		*clientout = NULL;
+		*clientoutlen = 0;
+
+		/* set oparams */
+		oparams->doneflag = 1;
+		oparams->mech_ssf = 0;
+		oparams->maxoutbuf = 0;
+		oparams->encode_context = NULL;
+		oparams->encode = NULL;
+		oparams->decode_context = NULL;
+		oparams->decode = NULL;
+
+		return (strncmp(childbuf, "AF", 2) == 0) ?
+			SASL_OK : SASL_BADAUTH;
+	}
+
+	return SASL_FAIL;
+}
+
+static void ntlm_client_mech_dispose(void *conn_context,
+				     const sasl_utils_t *utils __attribute__((unused)))
+{
+	struct ntlm_context *context =
+		(struct ntlm_context *)conn_context;
+
+	kill_helper(context->helper);
+
+	return;
+}
+
+static void ntlm_client_mech_free(void *conn_context,
+				  const sasl_utils_t *utils __attribute__((unused)))
+{
+	struct ntlm_context *context =
+		(struct ntlm_context *)conn_context;
+
+	if (context->free_password)
+		_plug_free_secret(utils, &context->password);
+
+	return;
+}
+
+static sasl_client_plug_t ntlm_client_plugins[] = 
+{
+    {
+	"NTLM", 			/* mech_name */
+	0,				/* max_ssf */
+	SASL_SEC_NOANONYMOUS | SASL_SEC_NOPLAINTEXT,		/* security_flags */
+	SASL_FEAT_WANT_CLIENT_FIRST, /* features */
+	NULL,				/* required_prompts */
+	NULL,				/* glob_context */
+	&ntlm_client_mech_new,	        /* mech_new */
+	&ntlm_client_mech_step,	        /* mech_step */
+	&ntlm_client_mech_dispose,	/* mech_dispose */
+        &ntlm_client_mech_free, 	/* mech_free */
+	NULL,				/* idle */
+	NULL,				/* spare */
+	NULL				/* spare */
+    }
+};
+
+int ntlm_client_plug_init(sasl_utils_t *utils,
+			   int maxversion,
+			   int *out_version,
+			   sasl_client_plug_t **pluglist,
+			   int *plugcount)
+{
+    if (maxversion < SASL_CLIENT_PLUG_VERSION) {
+	SETERROR(utils, "NTLM version mismatch");
+	return SASL_BADVERS;
+    }
+    
+    *out_version = SASL_CLIENT_PLUG_VERSION;
+    *pluglist = ntlm_client_plugins;
+    *plugcount = 1;
+    
+    return SASL_OK;
+}
diff -urN cyrus-sasl-2.1.18.orig/plugins/smb_helper.c cyrus-sasl-2.1.18/plugins/smb_helper.c
--- cyrus-sasl-2.1.18.orig/plugins/smb_helper.c	1970-01-01 03:00:00 +0300
+++ cyrus-sasl-2.1.18/plugins/smb_helper.c	2004-07-13 22:07:51 +0400
@@ -0,0 +1,168 @@
+/* Interface functions to samba's ntlm_auth helper
+ * Volker Lendecke, Andrew Bartlett
+ *
+ * $Id:$
+ */
+/* 
+ * Copyright (c) 1998-2003 Carnegie Mellon University.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer. 
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * 3. The name "Carnegie Mellon University" must not be used to
+ *    endorse or promote products derived from this software without
+ *    prior written permission. For permission or any other legal
+ *    details, please contact  
+ *      Office of Technology Transfer
+ *      Carnegie Mellon University
+ *      5000 Forbes Avenue
+ *      Pittsburgh, PA  15213-3890
+ *      (412) 268-4387, fax: (412) 268-7395
+ *      tech-transfer@andrew.cmu.edu
+ *
+ * 4. Redistributions of any form whatsoever must retain the following
+ *    acknowledgment:
+ *    "This product includes software developed by Computing Services
+ *     at Carnegie Mellon University (http://www.cmu.edu/computing/)."
+ *
+ * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
+ * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE
+ * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
+ * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
+ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/types.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <syslog.h>
+
+#include <sasl.h>
+#include <saslplug.h>
+
+#include "plugin_common.h"
+#include "smb_helper.h"
+
+int fork_helper(struct smb_helper **new_helper,
+		      const char *prog,
+		      char * const argv[],
+		      const sasl_utils_t *utils)
+{
+	int pipe_in[2];
+	int pipe_out[2];
+
+	struct smb_helper *helper = malloc(sizeof(struct smb_helper));
+
+	if (helper == NULL) {
+		syslog(LOG_DEBUG, "fork_helper: No memory\n");
+		MEMERROR(utils);
+		return SASL_NOMEM;
+	}
+	
+	*new_helper = helper;
+
+	if ( (pipe(pipe_in) < 0) || (pipe(pipe_out) < 0) ) {
+		syslog(LOG_DEBUG, "fork_helper: could not open pipes\n");
+		utils->seterror(utils->conn, 0, "Could not allocate pipe\n");
+		return SASL_FAIL;
+	}
+
+	helper->child_pid = fork();
+
+	if (helper->child_pid == -1) {
+		syslog(LOG_DEBUG, "fork_helper: Could not fork\n");
+		utils->seterror(utils->conn, 0, "Could not fork\n");
+		return SASL_FAIL;
+	}
+
+	if (helper->child_pid == 0) {
+
+		/* Set up the pipes correctly */
+
+		close(0);
+		close(1);
+		dup2(pipe_out[0], 0);
+		close(pipe_out[0]);
+		close(pipe_out[1]);
+		dup2(pipe_in[1], 1);
+		close(pipe_in[0]);
+		close(pipe_in[1]);
+
+		execvp(prog, argv);
+
+		/* We should never get here ... */
+		exit(1);
+
+	} else {
+
+		helper->pipe_in = fdopen(pipe_in[0], "r");
+		close(pipe_in[1]);
+		helper->pipe_out = fdopen(pipe_out[1], "w");
+		close(pipe_out[0]);
+	}
+
+	return SASL_OK;
+}
+
+int interact_helper(struct smb_helper *helper,
+				unsigned char *childbuf,
+				unsigned max_childbuflen,
+				unsigned *childbuflen)
+{
+	syslog(LOG_DEBUG, "interact_helper: Sending %d bytes do child: %s\n",
+	       *childbuflen, childbuf);
+
+	fprintf(helper->pipe_out, "%s\n", childbuf);
+	fflush(helper->pipe_out);
+
+	if (fgets(childbuf, max_childbuflen-1, helper->pipe_in) == NULL) {
+		syslog(LOG_DEBUG, "interact_helper: Did not get a response from helper\n");
+		return SASL_FAIL;
+	}
+	
+	*childbuflen = strlen(childbuf)-1;
+	childbuf[*childbuflen] = '\0'; /* Strip trailing \n */
+
+	syslog(LOG_DEBUG, "interact_helper: Got %d bytes from helper: %s\n",
+	       *childbuflen, childbuf);
+
+	if ( *childbuflen < 2 ) {
+		syslog(LOG_DEBUG, "interact_helper: Got invalid response from helper\n");
+		return SASL_FAIL;
+	}
+
+	if ((*childbuflen <= 3) && (strncmp(childbuf, "BH", 2) == 0)) {
+		syslog(LOG_DEBUG, "interact_helper: Broke Helper somehow...\n");
+		return SASL_FAIL;
+	}
+	return SASL_OK;
+}
+
+void kill_helper(struct smb_helper *helper)
+{
+	int status;
+	
+	if ((helper == NULL) || (helper->child_pid == 0))
+		return;
+
+	fclose(helper->pipe_out);
+	fclose(helper->pipe_in);
+
+	waitpid(helper->child_pid, &status, 0);
+	syslog(LOG_DEBUG, "kill_helper: Helper died with status %d\n", status);
+
+	helper->child_pid = 0;
+	free(helper);
+}
diff -urN cyrus-sasl-2.1.18.orig/plugins/smb_helper.h cyrus-sasl-2.1.18/plugins/smb_helper.h
--- cyrus-sasl-2.1.18.orig/plugins/smb_helper.h	1970-01-01 03:00:00 +0300
+++ cyrus-sasl-2.1.18/plugins/smb_helper.h	2004-07-13 22:08:00 +0400
@@ -0,0 +1,73 @@
+/* Interface functions to samba's ntlm_auth helper
+ * Volker Lendecke, Andrew Bartlett
+ *
+ * $Id:$
+ */
+/* 
+ * Copyright (c) 1998-2003 Carnegie Mellon University.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer. 
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * 3. The name "Carnegie Mellon University" must not be used to
+ *    endorse or promote products derived from this software without
+ *    prior written permission. For permission or any other legal
+ *    details, please contact  
+ *      Office of Technology Transfer
+ *      Carnegie Mellon University
+ *      5000 Forbes Avenue
+ *      Pittsburgh, PA  15213-3890
+ *      (412) 268-4387, fax: (412) 268-7395
+ *      tech-transfer@andrew.cmu.edu
+ *
+ * 4. Redistributions of any form whatsoever must retain the following
+ *    acknowledgment:
+ *    "This product includes software developed by Computing Services
+ *     at Carnegie Mellon University (http://www.cmu.edu/computing/)."
+ *
+ * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
+ * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE
+ * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
+ * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
+ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef _SMB_HELPER_H_
+#define _SMB_HELPER_H_
+
+#include <sys/types.h>
+#include <stdio.h>
+
+#include <sasl.h>
+#include <saslplug.h>
+
+struct smb_helper {
+	pid_t child_pid;
+	FILE *pipe_in;
+	FILE *pipe_out;
+};
+
+int fork_helper(struct smb_helper **helper,
+			const char *prog,
+			char * const argv[],
+			const sasl_utils_t *utils);
+
+int interact_helper(struct smb_helper *helper,
+				unsigned char *childbuf,
+				unsigned max_childbuflen,
+				unsigned *childbuflen);
+
+void kill_helper(struct smb_helper *helper);
+
+#endif
