zbyszek / rpms / krb5

Forked from rpms/krb5 2 years ago
Clone
Blob Blame History Raw
From ed87237cdd70f72b309960a294a2bed26cef1579 Mon Sep 17 00:00:00 2001
From: Isaac Boukris <iboukris@gmail.com>
Date: Fri, 4 Sep 2020 14:05:50 +0300
Subject: [PATCH] Improve KDC alias checking for S4U requests

When processing an S4U2Self request, check for DB aliases when
matching the TGT client against the request server.  When processing
an S4U2Proxy request, check for DB aliases when matching the TGT
client against the evidence ticket server.

[ghudson@mit.edu: minor edits; rewrote commit message]

ticket: 8946 (new)
(cherry picked from commit 05deeebfc096970b5d9aa67a48b14106cf1b9b56)
---
 src/kdc/kdc_util.c | 74 ++++++++++++++++------------------------------
 1 file changed, 25 insertions(+), 49 deletions(-)

diff --git a/src/kdc/kdc_util.c b/src/kdc/kdc_util.c
index e3352f9cc..dcb2df8dc 100644
--- a/src/kdc/kdc_util.c
+++ b/src/kdc/kdc_util.c
@@ -1463,6 +1463,25 @@ cleanup:
     return code;
 }
 
+/* Return true if princ canonicalizes to the same principal as canon. */
+static krb5_boolean
+is_client_alias(krb5_context context, krb5_const_principal canon,
+                krb5_const_principal princ)
+{
+    krb5_error_code ret;
+    krb5_db_entry *self;
+    krb5_boolean is_self = FALSE;
+
+    ret = krb5_db_get_principal(context, princ,
+                                KRB5_KDB_FLAG_CLIENT_REFERRALS_ONLY, &self);
+    if (!ret) {
+        is_self = krb5_principal_compare(context, canon, self->princ);
+        krb5_db_free_principal(context, self);
+    }
+
+    return is_self;
+}
+
 /*
  * Protocol transition (S4U2Self)
  */
@@ -1481,7 +1500,6 @@ kdc_process_s4u2self_req(kdc_realm_t *kdc_active_realm,
 {
     krb5_error_code             code;
     krb5_pa_data                *pa_data;
-    int                         flags;
     krb5_db_entry               *princ;
     krb5_s4u_userid             *id;
 
@@ -1515,51 +1533,11 @@ kdc_process_s4u2self_req(kdc_realm_t *kdc_active_realm,
     }
     id = &(*s4u_x509_user)->user_id;
 
-    /*
-     * We need to compare the client name in the TGT with the requested
-     * server name. Supporting server name aliases without assuming a
-     * global name service makes this difficult to do.
-     *
-     * The comparison below handles the following cases (note that the
-     * term "principal name" below excludes the realm).
-     *
-     * (1) The requested service is a host-based service with two name
-     *     components, in which case we assume the principal name to
-     *     contain sufficient qualifying information. The realm is
-     *     ignored for the purpose of comparison.
-     *
-     * (2) The requested service name is an enterprise principal name:
-     *     the service principal name is compared with the unparsed
-     *     form of the client name (including its realm).
-     *
-     * (3) The requested service is some other name type: an exact
-     *     match is required.
-     *
-     * An alternative would be to look up the server once again with
-     * FLAG_CANONICALIZE | FLAG_CLIENT_REFERRALS_ONLY set, do an exact
-     * match between the returned name and client_princ. However, this
-     * assumes that the client set FLAG_CANONICALIZE when requesting
-     * the TGT and that we have a global name service.
-     */
-    flags = 0;
-    switch (krb5_princ_type(kdc_context, request->server)) {
-    case KRB5_NT_SRV_HST:                   /* (1) */
-        if (krb5_princ_size(kdc_context, request->server) == 2)
-            flags |= KRB5_PRINCIPAL_COMPARE_IGNORE_REALM;
-        break;
-    case KRB5_NT_ENTERPRISE_PRINCIPAL:      /* (2) */
-        flags |= KRB5_PRINCIPAL_COMPARE_ENTERPRISE;
-        break;
-    default:                                /* (3) */
-        break;
-    }
-
-    if (!krb5_principal_compare_flags(kdc_context,
-                                      request->server,
-                                      client_princ,
-                                      flags)) {
-        *status = "INVALID_S4U2SELF_REQUEST";
-        return KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN; /* match Windows error code */
+    /* If the server is local, check that the request is for self. */
+    if (!isflagset(c_flags, KRB5_KDB_FLAG_ISSUING_REFERRAL) &&
+        !is_client_alias(kdc_context, server->princ, client_princ)) {
+        *status = "INVALID_S4U2SELF_REQUEST_SERVER_MISMATCH";
+        return KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN; /* match Windows error */
     }
 
     /*
@@ -1750,9 +1728,7 @@ kdc_process_s4u2proxy_req(kdc_realm_t *kdc_active_realm, unsigned int flags,
         }
 
         client_princ = *stkt_authdata_client;
-    } else if (!krb5_principal_compare(kdc_context,
-                                       server->princ, /* after canon */
-                                       server_princ)) {
+    } else if (!is_client_alias(kdc_context, server->princ, server_princ)) {
         *status = "EVIDENCE_TICKET_MISMATCH";
         return KRB5KDC_ERR_SERVER_NOMATCH;
     }