dovecot-2.2: gssapi: Allow logging in as users listed in "k5prin...

dovecot at dovecot.org dovecot at dovecot.org
Wed Jun 27 12:04:01 EEST 2012


details:   http://hg.dovecot.org/dovecot-2.2/rev/183adc90781c
changeset: 14690:183adc90781c
user:      Timo Sirainen <tss at iki.fi>
date:      Wed Jun 27 12:03:51 2012 +0300
description:
gssapi: Allow logging in as users listed in "k5principals" extra field.
This also enables other passdb extra fields for gssapi mechanism.

Based on patch by Sam Morris.

diffstat:

 src/auth/mech-gssapi.c |  87 ++++++++++++++++++++++++++++++++++++++++++++-----
 1 files changed, 78 insertions(+), 9 deletions(-)

diffs (139 lines):

diff -r 096e4c4d62bb -r 183adc90781c src/auth/mech-gssapi.c
--- a/src/auth/mech-gssapi.c	Wed Jun 27 04:24:53 2012 +0300
+++ b/src/auth/mech-gssapi.c	Wed Jun 27 12:03:51 2012 +0300
@@ -380,6 +380,29 @@
 
 #ifdef USE_KRB5_USEROK
 static bool
+k5_principal_is_authorized(struct auth_request *request, const char *name)
+{
+	const char *value, *const *authorized_names, *const *tmp;
+
+	if (request->extra_fields == NULL)
+		return FALSE;
+
+	value = auth_stream_reply_find(request->extra_fields, "k5principals");
+	if (value == NULL)
+		return FALSE;
+
+	authorized_names = t_strsplit_spaces(value, ",");
+	for (tmp = authorized_names; *tmp != NULL; tmp++) {
+		if (strcmp(*tmp, name) == 0) {
+			auth_request_log_debug(request, "gssapi",
+				"authorized by k5principals field: %s", name);
+			return TRUE;
+		}
+	}
+	return FALSE;
+}
+
+static bool
 mech_gssapi_krb5_userok(struct gssapi_auth_request *request,
 			gss_name_t name, const char *login_user,
 			bool check_name_type)
@@ -389,7 +412,7 @@
 	krb5_error_code krb5_err;
 	gss_OID name_type;
 	const char *princ_display_name;
-	bool ret = FALSE;
+	bool authorized = FALSE;
 
 	/* Parse out the principal's username */
 	if (!get_display_name(&request->auth_request, name, &name_type,
@@ -419,13 +442,20 @@
 				      "krb5_parse_name() failed: %d",
 				      (int)krb5_err);
 	} else {
+		/* See if the principal is in the list of authorized
+		 * principals for the user */
+		authorized = k5_principal_is_authorized(&request->auth_request,
+							princ_display_name);
+
 		/* See if the principal is authorized to act as the
-		   specified user */
-		ret = krb5_kuserok(ctx, princ, login_user);
+		   specified (UNIX) user */
+		if (!authorized)
+			authorized = krb5_kuserok(ctx, princ, login_user);
+
 		krb5_free_principal(ctx, princ);
 	}
 	krb5_free_context(ctx);
-	return ret;
+	return authorized;
 }
 #endif
 
@@ -483,11 +513,45 @@
 #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 ATTR_UNUSED,
+			    size_t size ATTR_UNUSED,
+			    struct auth_request *request)
+{
+	struct gssapi_auth_request *gssapi_request =
+		(struct gssapi_auth_request *)request;
+
+	/* We don't care much 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. */
+	switch (result) {
+	case PASSDB_RESULT_INTERNAL_FAILURE:
+		auth_request_internal_failure(request);
+		return;
+	case PASSDB_RESULT_USER_DISABLED:
+	case PASSDB_RESULT_PASS_EXPIRED:
+		/* user is explicitly disabled, don't allow it to log in */
+		auth_request_fail(request);
+		return;
+	case PASSDB_RESULT_SCHEME_NOT_AVAILABLE:
+	case PASSDB_RESULT_USER_UNKNOWN:
+	case PASSDB_RESULT_PASSWORD_MISMATCH:
+	case PASSDB_RESULT_OK:
+		break;
+	}
+
+	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 +595,21 @@
 		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 username 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;
 }
 


More information about the dovecot-cvs mailing list