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