Only in cyrus-sasl-2.1.22: autom4te.cache
diff -ur cyrus-sasl-2.1.22~/config.h.in cyrus-sasl-2.1.22/config.h.in
--- cyrus-sasl-2.1.22~/config.h.in	Thu May 18 15:38:02 2006
+++ cyrus-sasl-2.1.22/config.h.in	Mon Dec 17 14:07:18 2007
@@ -416,6 +416,9 @@
 /* use the doors IPC API for saslauthd? */
 #undef USE_DOORS
 
+/* Use KCRAP support */
+#undef USE_KCRAP
+
 /* Version number of package */
 #undef VERSION
 
Only in cyrus-sasl-2.1.22: config.h.in~
diff -ur cyrus-sasl-2.1.22~/configure.in cyrus-sasl-2.1.22/configure.in
--- cyrus-sasl-2.1.22~/configure.in	Thu May 18 15:06:13 2006
+++ cyrus-sasl-2.1.22/configure.in	Mon Dec 17 14:06:10 2007
@@ -608,6 +608,33 @@
   AC_MSG_RESULT(disabled)
 fi
 
+dnl KCRAP
+AC_ARG_ENABLE(kcrap, [  --enable-kcrap          enable experimental NTLM through KCRAP authentication [[auto]] ],
+  kcrap=$enableval,
+  kcrap=auto)
+
+if test "$kcrap" != auto; then
+  AC_CHECK_HEADER(kcrap.h,[
+    AC_CHECK_LIB(kcrap, kcrap_try, [
+      kcrap=yes
+    ], [ kcrap=no ])
+  ], [ kcrap=no ])
+fi
+
+AC_MSG_CHECKING(KCRAP)
+if test "$kcrap" != no; then
+  AC_MSG_RESULT(enabled)
+  if test "$ntlm" = no; then
+    AC_MSG_ERROR(Must enable NTLM for KCRAP)
+  fi
+  NTLM_LIBS="$NTLM_LIBS -lkcrap"
+  AC_SUBST(NTLM_LIBS)
+  AC_DEFINE(USE_KCRAP,[],[Use KCRAP support])
+else
+  AC_MSG_RESULT(disabled)
+fi
+
+
 dnl PASSDSS
 AC_ARG_ENABLE(passdss, [  --enable-passdss        enable PASSDSS authentication (experimental) [[no]] ],
   passdss=$enableval,
diff -ur cyrus-sasl-2.1.22~/plugins/ntlm.c cyrus-sasl-2.1.22/plugins/ntlm.c
--- cyrus-sasl-2.1.22~/plugins/ntlm.c	Thu Jul  7 12:10:14 2005
+++ cyrus-sasl-2.1.22/plugins/ntlm.c	Mon Dec 17 14:46:36 2007
@@ -91,6 +92,10 @@
 	 DES_ecb_encrypt((i),(o),&(k),(e))
 #endif /* OpenSSL 0.9.7+ w/o old DES support */
 
+#ifdef USE_KCRAP
+# include <kcrap.h>
+#endif
+
 #include <sasl.h>
 #define MD5_H  /* suppress internal MD5 */
 #include <saslplug.h>
@@ -464,6 +469,8 @@
 
 /*****************************  Server Section  *****************************/
 
+struct kcrap_context;
+
 typedef struct server_context {
     int state;
 
@@ -476,6 +483,7 @@
 
     /* socket to remote authentication host */
     SOCKET sock;
+    struct kcrap_context *kcrap;
 
 } server_context_t;
 
@@ -1364,6 +1372,10 @@
     server_context_t *text;
     const char *serv;
     unsigned int len;
+#ifdef USE_KCRAP
+    const char *keytab_file;
+    unsigned int ktlen;
+#endif
     SOCKET sock = (SOCKET) -1;
 
     sparams->utils->getopt(sparams->utils->getopt_context,
@@ -1385,6 +1397,17 @@
     
     text->state = 1;
     text->sock = sock;
+
+#ifdef USE_KCRAP
+    sparams->utils->getopt(sparams->utils->getopt_context,
+			   "KCRAP", "keytab_file", &keytab_file, &ktlen);
+    text->kcrap = kcrap_init(keytab_file, NULL);
+    if (text->kcrap == NULL) {
+	sparams->utils->log(NULL, SASL_LOG_WARN, "Cannot initialize KCRAP: %s", kcrap_errmsg());
+    }
+#else
+    text->kcrap = NULL;
+#endif
     
     *conn_context = text;
     
@@ -1514,7 +1537,68 @@
     if (domain) sparams->utils->log(NULL, SASL_LOG_DEBUG,
 				    "client domain: %s", domain);
 
-    if (text->sock == -1) {
+#ifdef USE_KCRAP
+# define KCRAP_SDATA(VAR,VAL) (VAR).data = (VAL), (VAR).length = strlen((VAR).data)
+    if (text->kcrap && nt_resp) {
+	struct kcrap_auth_req_data req;
+	static const unsigned char zeros[16] = { 0, };
+	int auth_status;
+
+	bzero(&req, sizeof(req));
+	if (nt_resp_len > NTLM_RESP_LENGTH) {
+	    /* NTLM V2 */
+	    KCRAP_SDATA(req.chal_type, "NTLM2");
+	    req.principal.length = authid_len;
+	    req.principal.data = authid;
+	    req.alt_username.length = domain_len;
+	    req.alt_username.data = domain;
+	    req.server_challenge.length = NTLM_NONCE_LENGTH;
+	    req.server_challenge.data = text->nonce;
+	    req.client_challenge.length = nt_resp_len - MD5_DIGEST_LENGTH;
+	    req.client_challenge.data = nt_resp + MD5_DIGEST_LENGTH;
+	    req.response.length = MD5_DIGEST_LENGTH;
+	    req.response.data = nt_resp;
+	} else if (lm_resp && memcmp(lm_resp+8, zeros, 16) == 0 &&
+		   memcmp(lm_resp, zeros, 8) != 0) {
+	    KCRAP_SDATA(req.chal_type, "NTLM2S");
+	    req.principal.length = authid_len;
+	    req.principal.data = authid;
+	    req.server_challenge.length = NTLM_NONCE_LENGTH;
+	    req.server_challenge.data = text->nonce;
+	    req.client_challenge.length = 8;
+	    req.client_challenge.data = lm_resp;
+	    req.response.length = nt_resp_len;
+	    req.response.data = nt_resp;
+	} else {
+	    /* NTLM V1 */
+	    KCRAP_SDATA(req.chal_type, "NTLM");
+	    req.principal.length = authid_len;
+	    req.principal.data = authid;
+	    req.server_challenge.length = NTLM_NONCE_LENGTH;
+	    req.server_challenge.data = text->nonce;
+	    req.response.length = nt_resp_len;
+	    req.response.data = nt_resp;
+	}
+	result = kcrap_try(text->kcrap, &req, &auth_status);
+	if (result != 0) {
+	    sparams->utils->log(NULL, SASL_LOG_WARN, "NTLM: KCRAP error: %s\n", kcrap_errmsg());
+	    SETERROR(sparams->utils, "internal error authenticating with KCRAP");
+	    result = SASL_FAIL;
+	    goto cleanup;
+	} else if (auth_status == 0) {
+	    SETERROR(sparams->utils, "incorrect NTLM response");                                                                
+	    result = SASL_BADAUTH;
+	    goto cleanup;
+	} else {
+	    sparams->utils->log(NULL, SASL_LOG_DEBUG, "NTLM: KCRAP ok\n");
+
+	    result = sparams->canon_user(sparams->utils->conn, authid, authid_len,
+					 SASL_CU_AUTHID | SASL_CU_AUTHZID, oparams);
+	    if (result != SASL_OK) goto cleanup;
+	}
+    } else
+#endif
+     if (text->sock == -1) {
 	/* verify the response internally */
 
 	sasl_secret_t *password = NULL;
@@ -1697,6 +1781,9 @@
     
     if (text->out_buf) utils->free(text->out_buf);
     if (text->sock != -1) closesocket(text->sock);
+#ifdef USE_KCRAP
+    if (text->kcrap) kcrap_free(text->kcrap);
+#endif
 
     utils->free(text);
 }
