kdc: add referral_policy callback to windc plugin
authorLuke Howard <lukeh@padl.com>
Sun, 2 Jan 2022 10:51:43 +0000 (21:51 +1100)
committerLuke Howard <lukeh@padl.com>
Mon, 3 Jan 2022 05:17:01 +0000 (16:17 +1100)
Add a referral policy hook to the TGS as a more elegant way of resolving
referral detection for Samba). The hook can either rewrite the server_princ in
the request, or it can return an error to disable built-in referral processing.

kdc/krb5tgs.c
kdc/windc.c
kdc/windc_plugin.h
tests/plugin/windc.c

index 66a28edd3104962fb4a4931ad3969ee963f01d8d..534eae564cbed8365d5909ed01b37f7f4aede4e0 100644 (file)
@@ -1518,6 +1518,7 @@ tgs_build_reply(astgs_request_t priv,
 
 server_lookup:
     priv->server = NULL;
+    priv->server_princ = sp;
     if (server)
         _kdc_free_ent(context, server);
     server = NULL;
@@ -1560,7 +1561,25 @@ server_lookup:
        Realm req_rlm;
        krb5_realm *realms;
 
-       if ((req_rlm = get_krbtgt_realm(&sp->name)) != NULL) {
+       priv->ret = ret; /* advise policy plugin of failure reason */
+       ret2 = _kdc_referral_policy(priv);
+       if (ret2 == 0) {
+           heim_assert(priv->server_princ != sp,
+                       "Referral policy plugin must update server principal");
+
+           krb5_free_principal(context, sp);
+           sp = priv->server_princ;
+
+           krb5_xfree(priv->sname);
+           priv->sname = NULL;
+           ret = krb5_unparse_name(context, sp, &priv->sname);
+           if (ret)
+               goto out;
+           spn = priv->sname;
+           goto server_lookup;
+       } else if (ret2 != KRB5_PLUGIN_NO_HANDLE) {
+           ret = ret2;
+       } else if ((req_rlm = get_krbtgt_realm(&sp->name)) != NULL) {
             if (capath == NULL) {
                 /* With referalls, hierarchical capaths are always enabled */
                 ret2 = _krb5_find_capath(context, tgt->crealm, our_realm,
index a63fadcfb27d45ff686b3d1fc7fc085f12736fc6..e7e2b9d4d98b05d37cad883c9e0f359ccea4812e 100644 (file)
@@ -234,6 +234,27 @@ _kdc_finalize_reply(astgs_request_t r)
     return ret;
 }
 
+static krb5_error_code KRB5_LIB_CALL
+referral_policy(krb5_context context, const void *plug, void *plugctx, void *userctx)
+{
+    krb5plugin_windc_ftable *ft = (krb5plugin_windc_ftable *)plug;
+
+    if (ft->referral_policy == NULL)
+       return KRB5_PLUGIN_NO_HANDLE;
+    return ft->referral_policy((void *)plug, userctx);
+}
+
+krb5_error_code
+_kdc_referral_policy(astgs_request_t r)
+{
+    krb5_error_code ret = KRB5_PLUGIN_NO_HANDLE;
+
+    if (have_plugin)
+        ret = _krb5_plugin_run_f(r->context, &windc_plugin_data, 0, r, referral_policy);
+
+    return ret;
+}
+
 uintptr_t KRB5_CALLCONV
 kdc_get_instance(const char *libname)
 {
index b5ff8af432b87dfead06cce2949555cff64f3b49..2ecfe70fc40c53b4764ca529ce7e6a2aa6bf4416 100644 (file)
@@ -84,6 +84,20 @@ typedef krb5_error_code
 typedef krb5_error_code
 (KRB5_CALLCONV *krb5plugin_windc_finalize_reply)(void *, astgs_request_t r);
 
+/*
+ * A referral policy plugin can either rewrite the server principal
+ * by resetting priv->server_princ, or it can disable referral
+ * processing entirely by returning an error.
+ *
+ * The error code from the previous server lookup is available as r->ret.
+ *
+ * If the function returns KRB5_PLUGIN_NO_HANDLE, the TGS will continue
+ * with its default referral handling.
+ */
+
+typedef krb5_error_code
+(KRB5_CALLCONV *krb5plugin_windc_referral_policy)(void *, astgs_request_t r);
+
 #define KRB5_WINDC_PLUGIN_MINOR                        8
 #define KRB5_WINDC_PLUGING_MINOR KRB5_WINDC_PLUGIN_MINOR
 
@@ -94,6 +108,7 @@ typedef struct krb5plugin_windc_ftable {
     krb5plugin_windc_pac_generate      pac_generate;
     krb5plugin_windc_pac_verify                pac_verify;
     krb5plugin_windc_client_access     client_access;
+    krb5plugin_windc_referral_policy   referral_policy;
     krb5plugin_windc_finalize_reply    finalize_reply;
 } krb5plugin_windc_ftable;
 
index 357148019ae84cdcb46e642a0446968a9376a97f..3168291cea20d6a64f31bbce9acf47733b28b0a7 100644 (file)
@@ -123,6 +123,7 @@ static krb5plugin_windc_ftable windc = {
     pac_generate,
     pac_verify,
     client_access,
+    NULL, /* referral_policy */
     finalize_reply
 };