2b37c0
From fe59e6a0b06926a3d71c6b6f361714d1422d5b0f Mon Sep 17 00:00:00 2001
2b37c0
From: Alexander Bokovoy <abokovoy@redhat.com>
2b37c0
Date: Thu, 11 Nov 2021 09:58:09 +0200
2b37c0
Subject: [PATCH 1/2] ipa-kdb: honor SID from the host or service entry
2b37c0
2b37c0
If the SID was explicitly set for the host or service entry, honor it
2b37c0
when issuing PAC. For normal services and hosts we don't allocate
2b37c0
individual SIDs but for cifs/... principals on domain members we do as
2b37c0
they need to login to Samba domain controller.
2b37c0
2b37c0
Related: https://pagure.io/freeipa/issue/9031
2b37c0
2b37c0
Signed-off-by: Alexander Bokovoy <abokovoy@redhat.com>
2b37c0
---
2b37c0
 daemons/ipa-kdb/ipa_kdb_mspac.c | 46 ++++++++++++++++++++-------------
2b37c0
 1 file changed, 28 insertions(+), 18 deletions(-)
2b37c0
2b37c0
diff --git a/daemons/ipa-kdb/ipa_kdb_mspac.c b/daemons/ipa-kdb/ipa_kdb_mspac.c
2b37c0
index 0e0ee3616..6f272f9fe 100644
2b37c0
--- a/daemons/ipa-kdb/ipa_kdb_mspac.c
2b37c0
+++ b/daemons/ipa-kdb/ipa_kdb_mspac.c
2b37c0
@@ -653,6 +653,28 @@ static krb5_error_code ipadb_fill_info3(struct ipadb_context *ipactx,
2b37c0
      * clear it after detecting the changes */
2b37c0
     info3->base.acct_flags = ACB_USE_AES_KEYS;
2b37c0
 
2b37c0
+    ret = ipadb_ldap_attr_to_str(ipactx->lcontext, lentry,
2b37c0
+                                 "ipaNTSecurityIdentifier", &strres);
2b37c0
+    if (ret) {
2b37c0
+        /* SID is mandatory for all but host/services */
2b37c0
+        if (!(is_host || is_service)) {
2b37c0
+            return ret;
2b37c0
+        }
2b37c0
+        info3->base.rid = 0;
2b37c0
+    } else {
2b37c0
+        ret = ipadb_string_to_sid(strres, &sid;;
2b37c0
+        free(strres);
2b37c0
+        if (ret) {
2b37c0
+            return ret;
2b37c0
+        }
2b37c0
+        ret = sid_split_rid(&sid, &info3->base.rid);
2b37c0
+        if (ret) {
2b37c0
+            return ret;
2b37c0
+        }
2b37c0
+    }
2b37c0
+
2b37c0
+    /* If SID was present prefer using it even for hosts and services
2b37c0
+     * but we still need to set the account flags correctly */
2b37c0
     if ((is_host || is_service)) {
2b37c0
         /* it is either host or service, so get the hostname first */
2b37c0
         char *sep = strchr(info3->base.account_name.string, '/');
2b37c0
@@ -661,29 +683,17 @@ static krb5_error_code ipadb_fill_info3(struct ipadb_context *ipactx,
2b37c0
                             sep ? sep + 1 : info3->base.account_name.string);
2b37c0
         if (is_master) {
2b37c0
             /* Well known RID of domain controllers group */
2b37c0
-            info3->base.rid = 516;
2b37c0
+            if (info3->base.rid == 0) {
2b37c0
+                info3->base.rid = 516;
2b37c0
+            }
2b37c0
             info3->base.acct_flags |= ACB_SVRTRUST;
2b37c0
         } else {
2b37c0
             /* Well known RID of domain computers group */
2b37c0
-            info3->base.rid = 515;
2b37c0
+            if (info3->base.rid == 0) {
2b37c0
+                info3->base.rid = 515;
2b37c0
+            }
2b37c0
             info3->base.acct_flags |= ACB_WSTRUST;
2b37c0
         }
2b37c0
-    } else {
2b37c0
-        ret = ipadb_ldap_attr_to_str(ipactx->lcontext, lentry,
2b37c0
-                                     "ipaNTSecurityIdentifier", &strres);
2b37c0
-        if (ret) {
2b37c0
-            /* SID is mandatory */
2b37c0
-            return ret;
2b37c0
-        }
2b37c0
-        ret = ipadb_string_to_sid(strres, &sid;;
2b37c0
-        free(strres);
2b37c0
-        if (ret) {
2b37c0
-            return ret;
2b37c0
-        }
2b37c0
-        ret = sid_split_rid(&sid, &info3->base.rid);
2b37c0
-        if (ret) {
2b37c0
-            return ret;
2b37c0
-        }
2b37c0
     }
2b37c0
 
2b37c0
     ret = ipadb_ldap_deref_results(ipactx->lcontext, lentry, &deref_results);
2b37c0
-- 
2b37c0
2.33.1
2b37c0
2b37c0
2b37c0
From 21af43550aa0a31e1ec5240578bd64fcbdd4ee24 Mon Sep 17 00:00:00 2001
2b37c0
From: Alexander Bokovoy <abokovoy@redhat.com>
2b37c0
Date: Thu, 11 Nov 2021 10:16:47 +0200
2b37c0
Subject: [PATCH 2/2] ipa-kdb: validate domain SID in incoming PAC for trusted
2b37c0
 domains for S4U
2b37c0
2b37c0
Previously, ipadb_check_logon_info() was called only for cross-realm
2b37c0
case. Now we call it for both in-realm and cross-realm cases. In case of
2b37c0
the S4U2Proxy, we would be passed a PAC of the original caller which
2b37c0
might be a principal from the trusted realm. We cannot validate that PAC
2b37c0
against our local client DB entry because this is the proxy entry which
2b37c0
is guaranteed to have different SID.
2b37c0
2b37c0
In such case, validate the SID of the domain in PAC against our realm
2b37c0
and any trusted doman but skip an additional check of the DB entry in
2b37c0
the S4U2Proxy case.
2b37c0
2b37c0
Related: https://pagure.io/freeipa/issue/9031
2b37c0
2b37c0
Signed-off-by: Alexander Bokovoy <abokovoy@redhat.com>
2b37c0
---
2b37c0
 daemons/ipa-kdb/ipa_kdb_mspac.c | 54 ++++++++++++++++++++++++++-------
2b37c0
 1 file changed, 43 insertions(+), 11 deletions(-)
2b37c0
2b37c0
diff --git a/daemons/ipa-kdb/ipa_kdb_mspac.c b/daemons/ipa-kdb/ipa_kdb_mspac.c
2b37c0
index 6f272f9fe..6f7d1ac15 100644
2b37c0
--- a/daemons/ipa-kdb/ipa_kdb_mspac.c
2b37c0
+++ b/daemons/ipa-kdb/ipa_kdb_mspac.c
2b37c0
@@ -1637,11 +1637,13 @@ static void filter_logon_info_log_message_rid(struct dom_sid *sid, uint32_t rid)
2b37c0
 static krb5_error_code check_logon_info_consistent(krb5_context context,
2b37c0
                                                    TALLOC_CTX *memctx,
2b37c0
                                                    krb5_const_principal client_princ,
2b37c0
+                                                   krb5_boolean is_s4u,
2b37c0
                                                    struct PAC_LOGON_INFO_CTR *info)
2b37c0
 {
2b37c0
     krb5_error_code kerr = 0;
2b37c0
     struct ipadb_context *ipactx;
2b37c0
     bool result;
2b37c0
+    bool is_from_trusted_domain = false;
2b37c0
     krb5_db_entry *client_actual = NULL;
2b37c0
     struct ipadb_e_data *ied = NULL;
2b37c0
     int flags = 0;
2b37c0
@@ -1671,14 +1673,36 @@ static krb5_error_code check_logon_info_consistent(krb5_context context,
2b37c0
     result = dom_sid_check(&ipactx->mspac->domsid,
2b37c0
                            info->info->info3.base.domain_sid, true);
2b37c0
     if (!result) {
2b37c0
-        /* memctx is freed by the caller */
2b37c0
-        char *sid = dom_sid_string(memctx, info->info->info3.base.domain_sid);
2b37c0
-        char *dom = dom_sid_string(memctx, &ipactx->mspac->domsid);
2b37c0
-        krb5_klog_syslog(LOG_ERR, "PAC issue: PAC record claims domain SID different "
2b37c0
-                                  "to local domain SID: local [%s], PAC [%s]",
2b37c0
-                                  dom ? dom : "<failed to display>",
2b37c0
-                                  sid ? sid : "<failed to display>");
2b37c0
-        return KRB5KDC_ERR_POLICY;
2b37c0
+        /* In S4U case we might be dealing with the PAC issued by the trusted domain */
2b37c0
+        if (is_s4u && (ipactx->mspac->trusts != NULL)) {
2b37c0
+            /* Iterate through list of trusts and check if this SID belongs to
2b37c0
+             * one of the domains we trust */
2b37c0
+            for(int i = 0 ; i < ipactx->mspac->num_trusts ; i++) {
2b37c0
+                result = dom_sid_check(&ipactx->mspac->trusts[i].domsid,
2b37c0
+                                       info->info->info3.base.domain_sid, true);
2b37c0
+                if (result) {
2b37c0
+                    is_from_trusted_domain = true;
2b37c0
+                    break;
2b37c0
+                }
2b37c0
+            }
2b37c0
+        }
2b37c0
+
2b37c0
+        if (!result) {
2b37c0
+            /* memctx is freed by the caller */
2b37c0
+            char *sid = dom_sid_string(memctx, info->info->info3.base.domain_sid);
2b37c0
+            char *dom = dom_sid_string(memctx, &ipactx->mspac->domsid);
2b37c0
+            krb5_klog_syslog(LOG_ERR, "PAC issue: PAC record claims domain SID different "
2b37c0
+                                      "to local domain SID or any trusted domain SID: "
2b37c0
+                                      "local [%s], PAC [%s]",
2b37c0
+                                      dom ? dom : "<failed to display>",
2b37c0
+                                      sid ? sid : "<failed to display>");
2b37c0
+            return KRB5KDC_ERR_POLICY;
2b37c0
+        }
2b37c0
+    }
2b37c0
+
2b37c0
+    if (is_s4u && is_from_trusted_domain) {
2b37c0
+        /* If the PAC belongs to a user from the trusted domain, we cannot compare SIDs */
2b37c0
+        return 0;
2b37c0
     }
2b37c0
 
2b37c0
     kerr = ipadb_get_principal(context, client_princ, flags, &client_actual);
2b37c0
@@ -1703,6 +1727,7 @@ static krb5_error_code check_logon_info_consistent(krb5_context context,
2b37c0
         goto done;
2b37c0
     }
2b37c0
 
2b37c0
+
2b37c0
     kerr = ipadb_get_sid_from_pac(memctx, info->info, &client_sid);
2b37c0
     if (kerr) {
2b37c0
         goto done;
2b37c0
@@ -1956,6 +1981,7 @@ krb5_error_code filter_logon_info(krb5_context context,
2b37c0
 static krb5_error_code ipadb_check_logon_info(krb5_context context,
2b37c0
                                               krb5_const_principal client_princ,
2b37c0
                                               krb5_boolean is_cross_realm,
2b37c0
+                                              krb5_boolean is_s4u,
2b37c0
                                               krb5_data *pac_blob,
2b37c0
                                               struct dom_sid *requester_sid)
2b37c0
 {
2b37c0
@@ -1999,8 +2025,11 @@ static krb5_error_code ipadb_check_logon_info(krb5_context context,
2b37c0
 
2b37c0
     if (!is_cross_realm) {
2b37c0
         /* For local realm case we need to check whether the PAC is for our user
2b37c0
-         * but we don't need to process further */
2b37c0
-        kerr = check_logon_info_consistent(context, tmpctx, client_princ, &info;;
2b37c0
+         * but we don't need to process further. In S4U2Proxy case when the client
2b37c0
+         * is ours but operates on behalf of the cross-realm principal, we will
2b37c0
+         * search through the trusted domains but otherwise skip the exact SID check
2b37c0
+         * as we are not responsible for the principal from the trusted domain */
2b37c0
+        kerr = check_logon_info_consistent(context, tmpctx, client_princ, is_s4u, &info;;
2b37c0
         goto done;
2b37c0
     }
2b37c0
 
2b37c0
@@ -2251,7 +2280,10 @@ static krb5_error_code ipadb_verify_pac(krb5_context context,
2b37c0
 #endif
2b37c0
 
2b37c0
     kerr = ipadb_check_logon_info(context,
2b37c0
-                                  client_princ, is_cross_realm, &pac_blob,
2b37c0
+                                  client_princ,
2b37c0
+                                  is_cross_realm,
2b37c0
+                                  (flags & KRB5_KDB_FLAGS_S4U),
2b37c0
+                                  &pac_blob,
2b37c0
                                   requester_sid);
2b37c0
     if (kerr != 0) {
2b37c0
         goto done;
2b37c0
-- 
2b37c0
2.33.1
2b37c0