Index: configure.in
===================================================================
RCS file: /home/cvs/dovecot/configure.in,v
retrieving revision 1.214
diff -u -r1.214 configure.in
--- configure.in	23 Sep 2005 13:28:40 -0000	1.214
+++ configure.in	19 Oct 2005 08:25:31 -0000
@@ -118,6 +118,15 @@
 	fi,
 	want_bsdauth=yes)
 
+AC_ARG_WITH(gssapi,
+[  --with-gssapi           Build with GSSAPI authentication support (default)],
+    if test x$withval = xno; then
+		want_gssapi=no
+	else
+		want_gssapi_yes
+	fi,
+	want_gssapi=yes)
+
 AC_ARG_WITH(ldap,
 [  --with-ldap             Build with LDAP support],
 	if test x$withval = xno; then
@@ -1192,6 +1201,17 @@
 	])
 fi
 
+have_gssapi=no
+if test $want_gssapi = yes; then
+	AC_CHECK_PROG(KRB5CONFIG, krb5-config, YES, NO)
+	if test $KRB5CONFIG = YES; then
+		AUTH_LIBS="$AUTH_LIBS `krb5-config --libs gssapi`"
+		AUTH_CFLAGS="$AUTH_CFLAGS `krb5-config --cflags gssapi`"
+		AC_DEFINE(MECH_GSSAPI,, Build with GSSAPI support)
+		have_gssapi=yes
+	fi
+fi
+
 if test $want_ldap = yes; then
 	AC_CHECK_LIB(ldap, ldap_init, [
 		AC_CHECK_HEADER(ldap.h, [
@@ -1486,5 +1506,6 @@
 echo "Building with IPv6 support .......... : $want_ipv6"
 echo "Building with pop3 server ........... : $want_pop3d"
 echo "Building with mail delivery agent  .. : $want_deliver"
+echo "Building with GSSAPI support ........ : $have_gssapi"
 echo "Building with user database modules . :$userdb"
 echo "Building with password lookup modules :$passdb"
Index: dovecot-example.conf
===================================================================
RCS file: /home/cvs/dovecot/dovecot-example.conf,v
retrieving revision 1.155
diff -u -r1.155 dovecot-example.conf
--- dovecot-example.conf	16 Oct 2005 14:59:12 -0000	1.155
+++ dovecot-example.conf	19 Oct 2005 08:25:31 -0000
@@ -568,9 +568,13 @@
 # automatically created and destroyed as needed.
 #auth_worker_max_count = 30
 
+# Kerberos keytab to use for the GSSAPI mechanism. Will use the system 
+# default (usually /etc/krb5.keytab) if not specified.
+#auth_krb5_keytab = 
+
 auth default {
   # Space separated list of wanted authentication mechanisms:
-  #   plain digest-md5 cram-md5 apop anonymous
+  #   plain digest-md5 cram-md5 apop anonymous gssapi
   mechanisms = plain
 
   #
Index: src/auth/Makefile.am
===================================================================
RCS file: /home/cvs/dovecot/src/auth/Makefile.am,v
retrieving revision 1.47
diff -u -r1.47 Makefile.am
--- src/auth/Makefile.am	7 Aug 2005 11:41:19 -0000	1.47
+++ src/auth/Makefile.am	19 Oct 2005 08:25:31 -0000
@@ -54,6 +54,7 @@
 	mech-cram-md5.c \
 	mech-digest-md5.c \
 	mech-ntlm.c \
+	mech-gssapi.c \
 	mech-rpa.c \
 	mech-apop.c \
 	passdb.c \
Index: src/auth/auth.c
===================================================================
RCS file: /home/cvs/dovecot/src/auth/auth.c,v
retrieving revision 1.19
diff -u -r1.19 auth.c
--- src/auth/auth.c	16 Oct 2005 14:06:59 -0000	1.19
+++ src/auth/auth.c	19 Oct 2005 08:25:31 -0000
@@ -56,8 +56,6 @@
 	}
 	t_pop();
 
-	if (auth->passdbs == NULL)
-		i_fatal("No password databases set");
 	if (auth->userdbs == NULL)
 		i_fatal("No user databases set");
 	return auth;
@@ -130,6 +128,9 @@
 	struct mech_module_list *list;
 
 	for (list = auth->mech_modules; list != NULL; list = list->next) {
+		if (list->module.need_passdb &&
+			!auth->passdbs)
+			break;
 		if (list->module.passdb_need_plain &&
 		    !auth_passdb_list_have_plain(auth))
 			break;
Index: src/auth/mech-anonymous.c
===================================================================
RCS file: /home/cvs/dovecot/src/auth/mech-anonymous.c,v
retrieving revision 1.13
diff -u -r1.13 mech-anonymous.c
--- src/auth/mech-anonymous.c	23 Apr 2005 09:11:49 -0000	1.13
+++ src/auth/mech-anonymous.c	19 Oct 2005 08:25:31 -0000
@@ -57,6 +57,7 @@
 
 	MEMBER(flags) MECH_SEC_ANONYMOUS,
 
+	MEMBER(need_passdb) TRUE,
 	MEMBER(passdb_need_plain) FALSE,
 	MEMBER(passdb_need_credentials) FALSE,
 
Index: src/auth/mech-apop.c
===================================================================
RCS file: /home/cvs/dovecot/src/auth/mech-apop.c,v
retrieving revision 1.16
diff -u -r1.16 mech-apop.c
--- src/auth/mech-apop.c	23 Apr 2005 09:11:49 -0000	1.16
+++ src/auth/mech-apop.c	19 Oct 2005 08:25:31 -0000
@@ -162,6 +162,7 @@
 
 	MEMBER(flags) MECH_SEC_PRIVATE | MECH_SEC_DICTIONARY | MECH_SEC_ACTIVE,
 
+	MEMBER(need_passdb) TRUE,
 	MEMBER(passdb_need_plain) FALSE,
 	MEMBER(passdb_need_credentials) TRUE,
 
Index: src/auth/mech-cram-md5.c
===================================================================
RCS file: /home/cvs/dovecot/src/auth/mech-cram-md5.c,v
retrieving revision 1.20
diff -u -r1.20 mech-cram-md5.c
--- src/auth/mech-cram-md5.c	8 Jan 2005 21:37:32 -0000	1.20
+++ src/auth/mech-cram-md5.c	19 Oct 2005 08:25:32 -0000
@@ -191,6 +191,7 @@
 
 	MEMBER(flags) MECH_SEC_DICTIONARY | MECH_SEC_ACTIVE,
 
+	MEMBER(need_passdb) TRUE,
 	MEMBER(passdb_need_plain) FALSE,
 	MEMBER(passdb_need_credentials) TRUE,
 
Index: src/auth/mech-digest-md5.c
===================================================================
RCS file: /home/cvs/dovecot/src/auth/mech-digest-md5.c,v
retrieving revision 1.34
diff -u -r1.34 mech-digest-md5.c
--- src/auth/mech-digest-md5.c	8 Jan 2005 21:37:32 -0000	1.34
+++ src/auth/mech-digest-md5.c	19 Oct 2005 08:25:32 -0000
@@ -619,6 +619,7 @@
 	MEMBER(flags) MECH_SEC_DICTIONARY | MECH_SEC_ACTIVE |
 		MECH_SEC_MUTUAL_AUTH,
 
+	MEMBER(need_passdb) TRUE,
 	MEMBER(passdb_need_plain) FALSE,
 	MEMBER(passdb_need_credentials) TRUE,
 
Index: src/auth/mech-login.c
===================================================================
RCS file: /home/cvs/dovecot/src/auth/mech-login.c,v
retrieving revision 1.12
diff -u -r1.12 mech-login.c
--- src/auth/mech-login.c	23 Apr 2005 09:11:49 -0000	1.12
+++ src/auth/mech-login.c	19 Oct 2005 08:25:32 -0000
@@ -87,6 +87,7 @@
 
 	MEMBER(flags) MECH_SEC_PLAINTEXT,
 
+	MEMBER(need_passdb) TRUE,
 	MEMBER(passdb_need_plain) TRUE,
 	MEMBER(passdb_need_credentials) FALSE,
 
Index: src/auth/mech-ntlm.c
===================================================================
RCS file: /home/cvs/dovecot/src/auth/mech-ntlm.c,v
retrieving revision 1.19
diff -u -r1.19 mech-ntlm.c
--- src/auth/mech-ntlm.c	23 Apr 2005 09:11:49 -0000	1.19
+++ src/auth/mech-ntlm.c	19 Oct 2005 08:25:32 -0000
@@ -281,6 +281,7 @@
 
 	MEMBER(flags) MECH_SEC_DICTIONARY | MECH_SEC_ACTIVE,
 
+	MEMBER(need_passdb) TRUE,
 	MEMBER(passdb_need_plain) FALSE,
 	MEMBER(passdb_need_credentials) TRUE,
 
Index: src/auth/mech-plain.c
===================================================================
RCS file: /home/cvs/dovecot/src/auth/mech-plain.c,v
retrieving revision 1.31
diff -u -r1.31 mech-plain.c
--- src/auth/mech-plain.c	23 Apr 2005 09:11:49 -0000	1.31
+++ src/auth/mech-plain.c	19 Oct 2005 08:25:32 -0000
@@ -103,6 +103,7 @@
 
 	MEMBER(flags) MECH_SEC_PLAINTEXT,
 
+	MEMBER(need_passdb) TRUE,
 	MEMBER(passdb_need_plain) TRUE,
 	MEMBER(passdb_need_credentials) FALSE,
 
Index: src/auth/mech-rpa.c
===================================================================
RCS file: /home/cvs/dovecot/src/auth/mech-rpa.c,v
retrieving revision 1.19
diff -u -r1.19 mech-rpa.c
--- src/auth/mech-rpa.c	23 Apr 2005 09:11:49 -0000	1.19
+++ src/auth/mech-rpa.c	19 Oct 2005 08:25:32 -0000
@@ -614,6 +614,7 @@
 	MEMBER(flags) MECH_SEC_DICTIONARY | MECH_SEC_ACTIVE |
 		MECH_SEC_MUTUAL_AUTH,
 
+	MEMBER(need_passdb) TRUE,
 	MEMBER(passdb_need_plain) FALSE,
 	MEMBER(passdb_need_credentials) TRUE,
 
Index: src/auth/mech.c
===================================================================
RCS file: /home/cvs/dovecot/src/auth/mech.c,v
retrieving revision 1.54
diff -u -r1.54 mech.c
--- src/auth/mech.c	7 Jan 2005 19:55:50 -0000	1.54
+++ src/auth/mech.c	19 Oct 2005 08:25:32 -0000
@@ -54,6 +54,9 @@
 extern struct mech_module mech_ntlm;
 extern struct mech_module mech_rpa;
 extern struct mech_module mech_anonymous;
+#ifdef MECH_GSSAPI
+extern struct mech_module mech_gssapi;
+#endif
 
 void mech_init(void)
 {
@@ -65,6 +68,9 @@
 	mech_register_module(&mech_ntlm);
 	mech_register_module(&mech_rpa);
 	mech_register_module(&mech_anonymous);
+#ifdef MECH_GSSAPI
+	mech_register_module(&mech_gssapi);
+#endif
 }
 
 void mech_deinit(void)
@@ -77,4 +83,7 @@
 	mech_unregister_module(&mech_ntlm);
 	mech_unregister_module(&mech_rpa);
 	mech_unregister_module(&mech_anonymous);
+#ifdef MECH_GSSAPI
+	mech_unregister_module(&mech_gssapi);
+#endif
 }
Index: src/auth/mech.h
===================================================================
RCS file: /home/cvs/dovecot/src/auth/mech.h,v
retrieving revision 1.35
diff -u -r1.35 mech.h
--- src/auth/mech.h	9 Jan 2005 16:54:48 -0000	1.35
+++ src/auth/mech.h	19 Oct 2005 08:25:32 -0000
@@ -24,6 +24,7 @@
 	const char *mech_name;
 
         enum mech_security_flags flags;
+	unsigned int need_passdb:1;
 	unsigned int passdb_need_plain:1;
 	unsigned int passdb_need_credentials:1;
 
Index: src/master/auth-process.c
===================================================================
RCS file: /home/cvs/dovecot/src/master/auth-process.c,v
retrieving revision 1.82
diff -u -r1.82 auth-process.c
--- src/master/auth-process.c	1 Oct 2005 10:52:16 -0000	1.82
+++ src/master/auth-process.c	19 Oct 2005 08:25:33 -0000
@@ -458,6 +458,8 @@
 		env_put("SSL_REQUIRE_CLIENT_CERT=1");
 	if (set->ssl_username_from_cert)
 		env_put("SSL_USERNAME_FROM_CERT=1");
+	if (set->krb5_keytab)
+		env_put(t_strconcat("KRB5_KTNAME=", set->krb5_keytab, NULL));
 
 	restrict_process_size(set->process_size, (unsigned int)-1);
 }
Index: src/master/master-settings.c
===================================================================
RCS file: /home/cvs/dovecot/src/master/master-settings.c,v
retrieving revision 1.92
diff -u -r1.92 master-settings.c
--- src/master/master-settings.c	16 Oct 2005 14:59:17 -0000	1.92
+++ src/master/master-settings.c	19 Oct 2005 08:25:33 -0000
@@ -155,6 +155,7 @@
 	DEF(SET_STR, username_chars),
 	DEF(SET_STR, username_translation),
 	DEF(SET_STR, anonymous_username),
+	DEF(SET_STR, krb5_keytab),
 
 	DEF(SET_BOOL, verbose),
 	DEF(SET_BOOL, debug),
@@ -353,6 +354,7 @@
 	MEMBER(username_chars) "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890.-_@",
 	MEMBER(username_translation) "",
 	MEMBER(anonymous_username) "anonymous",
+	MEMBER(krb5_keytab) NULL,
 
 	MEMBER(verbose) FALSE,
 	MEMBER(debug) FALSE,
Index: src/master/master-settings.h
===================================================================
RCS file: /home/cvs/dovecot/src/master/master-settings.h,v
retrieving revision 1.60
diff -u -r1.60 master-settings.h
--- src/master/master-settings.h	1 Oct 2005 10:52:16 -0000	1.60
+++ src/master/master-settings.h	19 Oct 2005 08:25:33 -0000
@@ -162,6 +162,7 @@
 	const char *username_chars;
 	const char *username_translation;
 	const char *anonymous_username;
+	const char *krb5_keytab;
 
 	int verbose, debug;
 	int ssl_require_client_cert;
--- /dev/null	2005-10-17 12:49:06.896857000 +0200
+++ src/auth/mech-gssapi.c	2005-10-19 10:17:45.000000000 +0200
@@ -0,0 +1,321 @@
+/*
+ * GSSAPI Module
+ *
+ * Copyright (c) 2005 Jelmer Vernooij <jelmer@samba.org>
+ *
+ * Related standards:
+ * - draft-ietf-sasl-gssapi-03 
+ * - RFC2222
+ *
+ * Some parts inspired by an older patch from Colin Walters
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published 
+ * by the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include "common.h"
+#include "mech.h"
+#include "passdb.h"
+#include "str.h"
+#include "buffer.h"
+#include "hex-binary.h"
+#include "safe-memset.h"
+#include "hostpid.h"
+
+#ifdef MECH_GSSAPI
+
+#include <gssapi/gssapi.h>
+
+struct gssapi_auth_request {
+	struct auth_request auth_request;
+	gss_ctx_id_t gss_ctx;
+	gss_cred_id_t service_cred;
+
+	enum { 
+		GSS_STATE_SEC_CONTEXT, 
+		GSS_STATE_WRAP, 
+		GSS_STATE_UNWRAP
+	} sasl_gssapi_state;
+
+	gss_name_t src_name;
+		
+	pool_t pool;
+};
+
+static void auth_request_log_gss_error(struct auth_request *request, OM_uint32 status_value, int status_type, const char *description)
+{
+	OM_uint32 message_context = 0;
+	OM_uint32 major_status, minor_status;
+	gss_buffer_desc status_string;
+
+	do {
+		major_status = gss_display_status(&minor_status, status_value, 
+							status_type, GSS_C_NO_OID, &message_context, 
+							&status_string);
+	
+		auth_request_log_error(request, "gssapi", "While %s: %s", 
+							   description, (char *)status_string.value);
+
+		major_status = gss_release_buffer(&minor_status, &status_string);
+	} while (message_context != 0);
+}
+
+static struct auth_request *mech_gssapi_auth_new(void)
+{
+	struct gssapi_auth_request *request;
+	pool_t pool;
+
+	pool = pool_alloconly_create("gssapi_auth_request", 512);
+	request = p_new(pool, struct gssapi_auth_request, 1);
+	request->pool = pool;
+
+	request->gss_ctx = GSS_C_NO_CONTEXT;
+
+	request->auth_request.pool = pool;
+	return &request->auth_request;
+}
+
+static OM_uint32 obtain_service_credentials(struct auth_request *request, gss_cred_id_t *ret)
+{
+	OM_uint32 major_status, minor_status;
+	string_t *principal_name;
+	gss_buffer_desc inbuf;
+	gss_name_t gss_principal;
+
+	principal_name = t_str_new(40);
+	str_append(principal_name, t_str_lcase(request->service));
+	str_append(principal_name, "@");
+	str_append(principal_name, my_hostname); 
+
+	auth_request_log_info(request, "gssapi",
+			"Obtaining credentials for %s", str_c(principal_name));
+
+	inbuf.length = str_len(principal_name);
+	inbuf.value = (void*) str_c(principal_name);
+
+	major_status = gss_import_name(&minor_status, &inbuf, 
+						GSS_C_NT_HOSTBASED_SERVICE, &gss_principal);
+
+	str_free(principal_name);
+
+	if (GSS_ERROR(major_status)) {
+		auth_request_log_gss_error(request, major_status, GSS_C_GSS_CODE,
+				"importing principal name");
+		return major_status;
+	}
+
+	major_status = gss_acquire_cred(&minor_status, gss_principal, 0, 
+						GSS_C_NULL_OID_SET, GSS_C_ACCEPT, ret, NULL, NULL);
+
+	if (GSS_ERROR(major_status)) {
+		auth_request_log_gss_error(request, major_status, GSS_C_GSS_CODE,
+				"acquiring service credentials");
+		auth_request_log_gss_error(request, minor_status, GSS_C_MECH_CODE,
+				"acquiring service credentials");
+		return major_status;
+	}
+
+	gss_release_name(&minor_status, gss_principal);
+
+	return major_status;
+}
+
+static void gssapi_sec_context(struct gssapi_auth_request *request,
+				  gss_buffer_desc inbuf)
+{
+	OM_uint32 major_status, minor_status;
+	gss_buffer_desc outbuf;
+
+	major_status = gss_accept_sec_context (
+		&minor_status,
+		&request->gss_ctx,
+		request->service_cred,
+		&inbuf,
+		GSS_C_NO_CHANNEL_BINDINGS,
+		&request->src_name, 
+		NULL, /* mech_type */
+		&outbuf,
+		NULL, /* ret_flags */
+		NULL, /* time_rec */
+		NULL  /* delegated_cred_handle */
+	);
+	
+	if (GSS_ERROR(major_status)) {
+		auth_request_log_gss_error(&request->auth_request, major_status, GSS_C_GSS_CODE,
+				"processing incoming data");
+		auth_request_log_gss_error(&request->auth_request, minor_status, GSS_C_MECH_CODE,
+				"processing incoming data");
+
+		auth_request_fail(&request->auth_request);
+		return;
+	} 
+
+	if (major_status == GSS_S_COMPLETE) {
+		request->sasl_gssapi_state = GSS_STATE_WRAP;
+		auth_request_log_info(&request->auth_request, "gssapi", 
+				"security context state completed.");
+	} else {
+		auth_request_log_info(&request->auth_request, "gssapi", 
+				"Processed incoming packet correctly, waiting for another.");
+	}
+
+	request->auth_request.callback(&request->auth_request,
+			AUTH_CLIENT_RESULT_CONTINUE,
+		   outbuf.value, outbuf.length);
+
+	major_status = gss_release_buffer(&minor_status, &outbuf);
+}
+
+static void gssapi_wrap(struct gssapi_auth_request *request,
+				  gss_buffer_desc inbuf)
+{
+	OM_uint32 major_status, minor_status;
+	gss_buffer_desc outbuf;
+	char ret[4];
+
+	/* The clients return data should be empty here */
+	
+	ret[0] = 0x01; /* Only authentication, no integrity or confidentiality protection (yet?) */
+	ret[1] = 0xFF;
+	ret[2] = 0xFF;
+	ret[3] = 0xFF;
+
+	inbuf.length = 4;
+	inbuf.value = ret;
+	
+	major_status = gss_wrap(&minor_status, request->gss_ctx, 0,
+								GSS_C_QOP_DEFAULT,
+								&inbuf, NULL, &outbuf);
+
+	if (GSS_ERROR(major_status)) {
+		auth_request_log_gss_error(&request->auth_request, major_status, GSS_C_GSS_CODE,
+				"sending security layer negotiation");
+		auth_request_log_gss_error(&request->auth_request, minor_status, GSS_C_MECH_CODE,
+				"sending security layer negotiation");
+		auth_request_fail(&request->auth_request);
+		return;
+	} 
+
+	auth_request_log_info(&request->auth_request, "gssapi", 
+				"Negotiated security layer");
+
+	request->auth_request.callback(&request->auth_request,
+			AUTH_CLIENT_RESULT_CONTINUE,
+		   outbuf.value, outbuf.length);
+
+	major_status = gss_release_buffer(&minor_status, &outbuf);
+
+	request->sasl_gssapi_state = GSS_STATE_UNWRAP;
+}
+
+static void gssapi_unwrap(struct gssapi_auth_request *request,
+				  gss_buffer_desc inbuf)
+{
+	OM_uint32 major_status, minor_status;
+	gss_buffer_desc outbuf;
+
+	major_status = gss_unwrap(&minor_status, request->gss_ctx, 
+							  &inbuf, &outbuf, NULL, NULL);
+	
+	if (GSS_ERROR(major_status)) {
+		auth_request_log_gss_error(&request->auth_request, major_status, GSS_C_GSS_CODE,
+				"final negotiation: gss_unwrap");
+		auth_request_fail(&request->auth_request);
+		return;
+	} 
+
+	if (outbuf.length <= 4) {
+		auth_request_log_error(&request->auth_request, "gssapi",
+							 "Invalid response length");
+		auth_request_fail(&request->auth_request);
+		return;
+	}
+
+	request->auth_request.user = p_strndup(request->auth_request.pool,
+			((unsigned char*) outbuf.value)+4,
+			outbuf.length-4);
+
+	auth_request_success(&request->auth_request, NULL, 0);
+}
+
+static void
+mech_gssapi_auth_continue(struct auth_request *request,
+		       const unsigned char *data, size_t data_size)
+{
+	struct gssapi_auth_request *gssapi_request = 
+						(struct gssapi_auth_request *)request;
+	gss_buffer_desc inbuf;
+
+	inbuf.value = (char*) data;
+	inbuf.length = data_size;
+
+	switch (gssapi_request->sasl_gssapi_state) {
+	case GSS_STATE_SEC_CONTEXT: gssapi_sec_context(gssapi_request, inbuf); break;
+	case GSS_STATE_WRAP: gssapi_wrap(gssapi_request, inbuf); break;
+	case GSS_STATE_UNWRAP: gssapi_unwrap(gssapi_request, inbuf); break;
+	} 
+}
+
+static void
+mech_gssapi_auth_initial(struct auth_request *request,
+		       const unsigned char *data, size_t data_size)
+{
+	OM_uint32 major_status;
+	struct gssapi_auth_request *gssapi_request = 
+						(struct gssapi_auth_request *)request;
+	
+	major_status = obtain_service_credentials(request, &gssapi_request->service_cred);
+
+	if (GSS_ERROR(major_status)) {
+		auth_request_internal_failure(request);
+		return;
+	}
+	gssapi_request->src_name = GSS_C_NO_NAME;
+
+	gssapi_request->sasl_gssapi_state = GSS_STATE_SEC_CONTEXT;
+
+	if (data_size == 0) {
+		/* The client should go first */
+		request->callback(request,
+			AUTH_CLIENT_RESULT_CONTINUE,
+		   NULL, 0);
+	} else {
+		mech_gssapi_auth_continue(request, data, data_size);
+	}
+}
+
+
+static void
+mech_gssapi_auth_free(struct auth_request *request)
+{
+	OM_uint32 major_status, minor_status;
+	struct gssapi_auth_request *gssapi_request = 
+						(struct gssapi_auth_request *)request;
+
+	major_status = gss_delete_sec_context(&minor_status, 
+										  &gssapi_request->gss_ctx,
+										  GSS_C_NO_BUFFER);
+
+	major_status = gss_release_cred(&minor_status, &gssapi_request->service_cred);
+
+	pool_unref(request->pool);
+}
+
+const struct mech_module mech_gssapi = {
+	"GSSAPI",
+
+	MEMBER(flags) 0,
+
+	MEMBER(need_passdb) FALSE,
+	MEMBER(passdb_need_plain) FALSE, 
+	MEMBER(passdb_need_credentials) FALSE, 
+
+	mech_gssapi_auth_new,
+	mech_gssapi_auth_initial,
+	mech_gssapi_auth_continue,
+	mech_gssapi_auth_free
+};
+
+#endif
Index: AUTHORS
===================================================================
RCS file: /home/cvs/dovecot/AUTHORS,v
retrieving revision 1.11
diff -u -r1.11 AUTHORS
--- AUTHORS	19 Aug 2004 03:56:01 -0000	1.11
+++ AUTHORS	19 Oct 2005 08:38:49 -0000
@@ -12,6 +12,8 @@
 Joshua Goodall <joshua@roughtrade.net> (src/auth/password-scheme-cram-md5.c,
   src/util/dovecotpw.c)
 
+Jelmer Vernooij <jelmer@samba.org> (src/auth/mech-gssapi.c)
+
 This product includes software developed by Computing Services
 at Carnegie Mellon University (http://www.cmu.edu/computing/).
 (src/lib/base64.c, src/lib/mkgmtime.c)
