Index: dovecot-2.0.15/src/auth/auth-request.c
===================================================================
--- dovecot-2.0.15.orig/src/auth/auth-request.c	2012-03-06 11:01:03.000000000 +0000
+++ dovecot-2.0.15/src/auth/auth-request.c	2012-03-06 15:20:38.000000000 +0000
@@ -45,6 +45,8 @@ auth_request_new(const struct mech_modul
 	request->refcount = 1;
 	request->last_access = ioloop_time;
 
+	p_array_init (&request->gssapi_k5principals, request->pool, 0);
+
 	request->set = global_auth_settings;
 	request->mech = mech;
 	request->mech_name = mech == NULL ? NULL : mech->mech_name;
@@ -63,6 +65,8 @@ struct auth_request *auth_request_new_du
 	request->state = AUTH_REQUEST_STATE_NEW;
 	auth_request_state_count[AUTH_REQUEST_STATE_NEW]++;
 
+	p_array_init (&request->gssapi_k5principals, request->pool, 0);
+
 	request->refcount = 1;
 	request->last_access = ioloop_time;
 	request->set = global_auth_settings;
@@ -1157,6 +1161,17 @@ auth_request_try_update_username(struct
 	return TRUE;
 }
 
+static void
+auth_request_store_k5principals(struct auth_request *request,
+                                const char* value)
+{
+	for (const char* const* pr = t_strsplit_spaces (value, ","); *pr != NULL; ++pr) {
+		char* pr_in_pool = p_strdup(request->pool, *pr);
+		auth_request_log_debug(request, "auth", "k5 principal: %s may access %s", pr_in_pool, request->user);
+		array_append(&request->gssapi_k5principals, &pr_in_pool, 1);
+	}
+}
+
 void auth_request_set_field(struct auth_request *request,
 			    const char *name, const char *value,
 			    const char *default_scheme)
@@ -1203,6 +1218,9 @@ void auth_request_set_field(struct auth_
 		if (request->userdb_reply == NULL)
 			auth_request_init_userdb_reply(request);
 		auth_request_set_userdb_field(request, name + 7, value);
+	} else if (strcmp(name, "k5principals") == 0) {
+		auth_request_log_debug(request, "auth", "k5 principal: storing");
+		auth_request_store_k5principals(request, value);
 	} else {
 		/* these fields are returned to client */
 		auth_request_set_reply_field(request, name, value);
Index: dovecot-2.0.15/src/auth/auth-request.h
===================================================================
--- dovecot-2.0.15.orig/src/auth/auth-request.h	2012-03-06 11:01:03.000000000 +0000
+++ dovecot-2.0.15/src/auth/auth-request.h	2012-03-06 15:20:38.000000000 +0000
@@ -1,6 +1,8 @@
 #ifndef AUTH_REQUEST_H
 #define AUTH_REQUEST_H
 
+#include "../lib/array.h"
+
 #include "network.h"
 #include "mech.h"
 #include "userdb.h"
@@ -114,6 +116,8 @@ struct auth_request {
 	unsigned int removed_from_handler:1;
 
 	/* ... mechanism specific data ... */
+	//char* gssapi_k5principals[];
+	ARRAY_DEFINE(gssapi_k5principals, char*);
 };
 
 extern unsigned int auth_request_state_count[AUTH_REQUEST_STATE_MAX];
Index: dovecot-2.0.15/src/auth/mech-gssapi.c
===================================================================
--- dovecot-2.0.15.orig/src/auth/mech-gssapi.c	2012-03-06 11:01:03.000000000 +0000
+++ dovecot-2.0.15/src/auth/mech-gssapi.c	2012-03-06 17:59:30.000000000 +0000
@@ -419,9 +419,23 @@ mech_gssapi_krb5_userok(struct gssapi_au
 				      "krb5_parse_name() failed: %d",
 				      (int)krb5_err);
 	} else {
+		/* See if the principal is in the list of authorized
+		 * principals for the user */
+		auth_request_log_debug(&request->auth_request, "gssapi", "%u authorized princpals", array_count_i(&request->auth_request.gssapi_k5principals));
+		const char* const* authorized_principal;
+		array_foreach(&request->auth_request.gssapi_k5principals, authorized_principal) {
+			if (strcmp (princ_display_name, *authorized_principal) == 0) {
+				auth_request_log_debug(&request->auth_request, "gssapi", "authorized principal: %s", *authorized_principal);
+				ret = TRUE;
+				break;
+			}
+		}
+
 		/* See if the principal is authorized to act as the
-		   specified user */
-		ret = krb5_kuserok(ctx, princ, login_user);
+		   specified (UNIX) user */
+		if (!ret)
+			ret = krb5_kuserok(ctx, princ, login_user);
+
 		krb5_free_principal(ctx, princ);
 	}
 	krb5_free_context(ctx);
@@ -483,11 +497,30 @@ mech_gssapi_userok(struct gssapi_auth_re
 #else
 	auth_request_log_info(auth_request, "gssapi",
 			      "Cross-realm authentication not supported "
-			      "(authz_name=%s)", login_user);
+			      "(authn_name=%s, authz_name=%s)", request->auth_request.original_username, login_user);
 	return -1;
 #endif
 }
 
+static void
+gssapi_credentials_callback (enum passdb_result result,
+		             const unsigned char* credentials,
+			     size_t size,
+			     struct auth_request* request)
+{
+	/* We don't care whether the lookup succeeded or not because GSSAPI
+	 * does not strictly require a passdb. But if a passdb is configured,
+	 * now the k5principals field will have been filled in. */
+	struct gssapi_auth_request *gssapi_request =
+		(struct gssapi_auth_request *)request;
+
+	if (mech_gssapi_userok(gssapi_request, request->user) == 0) {
+		auth_request_success(request, NULL, 0);
+	} else {
+		auth_request_fail(request);
+	}
+}
+
 static int
 mech_gssapi_unwrap(struct gssapi_auth_request *request, gss_buffer_desc inbuf)
 {
@@ -531,16 +564,19 @@ mech_gssapi_unwrap(struct gssapi_auth_re
 		return -1;
 	}
 
-	if (mech_gssapi_userok(request, login_user) < 0)
-		return -1;
-
+	/* Set username early, so that the credential lookup is for the
+	 * authorizing user. This means the user name in subsequent log
+	 * messagess will be the authorization name, not the authentication
+	 * name, which may mean that future log messages should be adjusted
+	 * to log the right thing. */
 	if (!auth_request_set_username(auth_request, login_user, &error)) {
 		auth_request_log_info(auth_request, "gssapi",
 				      "authz_name: %s", error);
 		return -1;
 	}
 
-	auth_request_success(auth_request, NULL, 0);
+	/* Continue in callback once auth_request is populated with passdb information. */
+	auth_request_lookup_credentials(&request->auth_request, "", gssapi_credentials_callback);
 	return 0;
 }
 
