]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
Support cross-realm krb5 authentication. Based on patch by Zachary Kotlarek.
authorTimo Sirainen <tss@iki.fi>
Sun, 4 May 2008 01:27:41 +0000 (04:27 +0300)
committerTimo Sirainen <tss@iki.fi>
Sun, 4 May 2008 01:27:41 +0000 (04:27 +0300)
--HG--
branch : HEAD

src/auth/mech-gssapi.c

index c4307a287fd314f062f5ec4916972709d2215ac0..4c5765f95ac16632571f99e45f75b7834af84cef 100644 (file)
 
 #ifdef HAVE_GSSAPI
 
+#ifndef HAVE___GSS_USEROK
+#  define USE_KRB5_USEROK
+#  include <krb5.h>
+#endif
+
 #ifdef HAVE_GSSAPI_GSSAPI_H
 #  include <gssapi/gssapi.h>
+#  ifdef USE_KRB5_USEROK
+#    include <gssapi/gssapi_krb5.h>
+#  endif
 #elif defined (HAVE_GSSAPI_H)
 #  include <gssapi.h>
+#  ifdef USE_KRB5_USEROK
+#    include <gssapi_krb5.h>
+#  endif
 #endif
 
 #ifdef HAVE_GSSAPI_GSSAPI_EXT_H
@@ -156,6 +167,7 @@ static OM_uint32 obtain_service_credentials(struct auth_request *request,
        return major_status;
 }
 
+#ifndef HAVE___GSS_USEROK
 static gss_name_t
 import_name(struct auth_request *request, void *str, size_t len)
 {
@@ -177,6 +189,7 @@ import_name(struct auth_request *request, void *str, size_t len)
 
        return name;
 }
+#endif
 
 static void gssapi_sec_context(struct gssapi_auth_request *request,
                               gss_buffer_desc inbuf)
@@ -271,6 +284,58 @@ static void gssapi_wrap(struct gssapi_auth_request *request,
        request->sasl_gssapi_state = GSS_STATE_UNWRAP;
 }
 
+#ifdef USE_KRB5_USEROK
+static bool gssapi_krb5_userok(struct gssapi_auth_request *request)
+{
+       krb5_context ctx;
+       krb5_principal princ;
+       krb5_error_code krb5_err;
+       OM_uint32 major_status, minor_status;
+       gss_buffer_desc princ_name;
+       gss_OID name_type;
+       const char *princ_display_name;
+       bool ret = FALSE;
+
+       /* Parse out the principal's username */
+       major_status = gss_display_name(&minor_status, request->authn_name,
+                                       &princ_name, &name_type);
+       if (major_status != GSS_S_COMPLETE) {
+               auth_request_log_gss_error(&request->auth_request, major_status,
+                                          GSS_C_GSS_CODE,
+                                          "gssapi_krb5_userok");
+               return FALSE;
+       }
+       if (name_type != GSS_KRB5_NT_PRINCIPAL_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);
+
+       /* Init a krb5 context and parse the principal username */
+       krb5_err = krb5_init_context(&ctx);
+       if (krb5_err != 0) {
+               auth_request_log_error(&request->auth_request, "gssapi",
+                       "krb5_init_context() failed: %d", (int)krb5_err);
+               return FALSE;
+       }
+       krb5_err = krb5_parse_name(ctx, princ_display_name, &princ);
+       if (krb5_err != 0) {
+               auth_request_log_error(&request->auth_request, "gssapi",
+                                      "krb5_parse_name() failed: %s",
+                                      krb5_get_error_message(ctx, krb5_err));
+       } else {
+               /* See if the principal is authorized to act as the
+                  specified user */
+               ret = krb5_kuserok(ctx, princ, request->auth_request.user);
+               krb5_free_principal(ctx, princ);
+       }
+       krb5_free_context(ctx);
+       return ret;
+}
+#endif
+
 static void gssapi_unwrap(struct gssapi_auth_request *request,
                          gss_buffer_desc inbuf)
 {
@@ -344,6 +409,10 @@ static void gssapi_unwrap(struct gssapi_auth_request *request,
                                        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) {
                auth_request_log_error(&request->auth_request, "gssapi",
                        "authn_name and authz_name differ: not supported");