Attached is a patch which in my environment (Linux/Heimdal 1.2.1) fixes cross-realm GSSAPI authentication.
Changes it makes: 1. When using krb5_kuserok, do not call gss_compare_name to check that authn_name and authz_name are the same. Instead, make TWO calls to krb5_kuserok, one for each ID. If both IDs are acceptable, allow the login. 2. Disable checking that the name is a GSS_KRB5_PRINCIPAL_NAME, as this doesn't appear to be always the case for the authz_name. If I create a .k5login listing both usern...@realm1 and usern...@realm2, and make that file follow the appropriate security restrictions (world read, user only write permissions), this lets me use GSSAPI logins with principals from either REALM1 or REALM2. This leaves untouched the behavior in the case where krb5_kuserok is not available. Bryan Jacobs
Index: dovecot-1.1.11/src/auth/mech-gssapi.c =================================================================== --- dovecot-1.1.11.orig/src/auth/mech-gssapi.c +++ dovecot-1.1.11/src/auth/mech-gssapi.c @@ -310,7 +310,7 @@ static void gssapi_wrap(struct gssapi_au } #ifdef USE_KRB5_USEROK -static bool gssapi_krb5_userok(struct gssapi_auth_request *request) +static bool gssapi_krb5_userok(struct gssapi_auth_request *request, gss_name_t name) { krb5_context ctx; krb5_principal princ; @@ -322,7 +322,7 @@ static bool gssapi_krb5_userok(struct gs bool ret = FALSE; /* Parse out the principal's username */ - major_status = gss_display_name(&minor_status, request->authn_name, + major_status = gss_display_name(&minor_status, name, &princ_name, &name_type); if (major_status != GSS_S_COMPLETE) { auth_request_log_gss_error(&request->auth_request, major_status, @@ -330,11 +330,11 @@ static bool gssapi_krb5_userok(struct gs "gssapi_krb5_userok"); return FALSE; } - if (name_type != GSS_KRB5_NT_PRINCIPAL_NAME) { + /*if (name_type != GSS_KRB5_NT_PRINCIPAL_NAME && name_type != GSS_KRB5_NT_USER_NAME) { auth_request_log_error(&request->auth_request, "gssapi", "OID not kerberos principal name"); return FALSE; - } + }*/ princ_display_name = t_strndup(princ_name.value, princ_name.length); gss_release_buffer(&minor_status, &princ_name); @@ -433,21 +433,35 @@ static void gssapi_unwrap(struct gssapi_ (unsigned char *)outbuf.value + 4, outbuf.length - 4); +#ifdef USE_KRB5_USEROK + equal_authn_authz = gssapi_krb5_userok(request, request->authn_name); + if (equal_authn_authz == 0) { + auth_request_log_error(&request->auth_request, "gssapi", + "authn_name not authorized"); + auth_request_fail(&request->auth_request); + return; + } + + equal_authn_authz = gssapi_krb5_userok(request, request->authz_name); + if (equal_authn_authz == 0) { + auth_request_log_error(&request->auth_request, "gssapi", + "authz_name not authorized"); + auth_request_fail(&request->auth_request); + return; + } +#else major_status = gss_compare_name(&minor_status, request->authn_name, request->authz_name, &equal_authn_authz); -#ifdef USE_KRB5_USEROK - if (equal_authn_authz == 0) - equal_authn_authz = gssapi_krb5_userok(request); -#endif - if (equal_authn_authz == 0) { + if (equal_authn_authz != 0) { auth_request_log_error(&request->auth_request, "gssapi", "authn_name and authz_name differ: not supported"); auth_request_fail(&request->auth_request); return; } #endif +#endif auth_request_success(&request->auth_request, NULL, 0); }
signature.asc
Description: PGP signature