On Mon, 2012-03-05 at 20:52 +0200, Timo Sirainen wrote: > On 5.3.2012, at 20.45, Sam Morris wrote: > > > 3. The credentials lookup triggers an info log message saying that > > credentials for GSSAPI were requested, "but we have only (e.g.) > > MD5-CRYPT". The authplugin doesn't actually want the credential, > > but I think that the only way the authplugin can trigger a > > passdb lookup is by requesting it. > > I'll look at the rest more closely later, but this should be an easy fix: > request "" instead of "GSSAPI".
Thanks for pointing that out. Here's a newer version of the patch with that change. I also realised that the gss_buffer is not required in the code that runs once the passdb lookup is complete, so I removed the code that stashes it in struct gssapi_auth_request. Regards, -- Sam Morris <s...@robots.org.uk>
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; }