From e86807b58c67a607bceb568d206af3b3abc03dea Mon Sep 17 00:00:00 2001 From: Alexander Bokovoy Date: Tue, 6 Sep 2022 15:53:41 +0300 Subject: [PATCH] ipa-kdb: handle empty S4U proxy in allowed_to_delegate With krb5 1.20, S4U processing code uses a special case of passing an empty S4U proxy to allowed_to_delegate() callback to identify if the server cannot get forwardable S4U2Self tickets according to [MS-PAC] 3.2.5.1.2. This means we need to ensure NULL proxy is a valid one and return an appropriate response to that. Fixes: https://pagure.io/freeipa/issue/9083 Signed-off-by: Alexander Bokovoy Reviewed-By: Julien Rische Reviewed-By: Rob Crittenden --- daemons/ipa-kdb/ipa_kdb_delegation.c | 96 +++++++++++++++++++--------- 1 file changed, 65 insertions(+), 31 deletions(-) diff --git a/daemons/ipa-kdb/ipa_kdb_delegation.c b/daemons/ipa-kdb/ipa_kdb_delegation.c index cd717a9e0..56fc8b565 100644 --- a/daemons/ipa-kdb/ipa_kdb_delegation.c +++ b/daemons/ipa-kdb/ipa_kdb_delegation.c @@ -106,6 +106,8 @@ static krb5_error_code ipadb_match_acl(krb5_context kcontext, bool client_missing; bool client_found; bool target_found; + bool is_constraint_delegation = false; + size_t nrules = 0; int ret; ipactx = ipadb_get_context(kcontext); @@ -113,13 +115,17 @@ static krb5_error_code ipadb_match_acl(krb5_context kcontext, return KRB5_KDB_DBNOTINITED; } - kerr = krb5_unparse_name(kcontext, client, &client_princ); - if (kerr != 0) { - goto done; - } - kerr = krb5_unparse_name(kcontext, target, &target_princ); - if (kerr != 0) { - goto done; + if ((client != NULL) && (target != NULL)) { + kerr = krb5_unparse_name(kcontext, client, &client_princ); + if (kerr != 0) { + goto done; + } + kerr = krb5_unparse_name(kcontext, target, &target_princ); + if (kerr != 0) { + goto done; + } + } else { + is_constraint_delegation = true; } lentry = ldap_first_entry(ipactx->lcontext, results); @@ -142,6 +148,25 @@ static krb5_error_code ipadb_match_acl(krb5_context kcontext, switch (ret) { case 0: for (dres = deref_results; dres; dres = dres->next) { + nrules++; + if (is_constraint_delegation) { + /* + Microsoft revised the S4U2Proxy rules for forwardable + tickets. All S4U2Proxy operations require forwardable + evidence tickets, but S4U2Self should issue a + forwardable ticket if the requesting service has no + ok-to-auth-as-delegate bit but also no constrained + delegation privileges for traditional S4U2Proxy. + Implement these rules, extending the + check_allowed_to_delegate() DAL method so that the KDC + can ask if a principal has any delegation privileges. + + Since target principal is NULL and client principal is + NULL in this case, we simply calculate number of rules associated + with the server principal to decide whether to deny forwardable bit + */ + continue; + } if (client_found == false && strcasecmp(dres->derefAttr, "ipaAllowToImpersonate") == 0) { /* NOTE: client_missing is used to signal that the @@ -175,6 +200,10 @@ static krb5_error_code ipadb_match_acl(krb5_context kcontext, lentry = ldap_next_entry(ipactx->lcontext, lentry); } + if (nrules > 0) { + kerr = 0; + } + done: krb5_free_unparsed_name(kcontext, client_princ); krb5_free_unparsed_name(kcontext, target_princ); @@ -196,33 +225,35 @@ krb5_error_code ipadb_check_allowed_to_delegate(krb5_context kcontext, struct ipadb_e_data *ied_server, *ied_proxy; LDAPMessage *res = NULL; - /* Handle the case where server == proxy, this is allowed in S4U*/ - kerr = ipadb_get_principal(kcontext, proxy, - CLIENT_REFERRALS_FLAGS, - &proxy_entry); - if (kerr) { - goto done; - } - - ied_server = (struct ipadb_e_data *) server->e_data; - ied_proxy = (struct ipadb_e_data *) proxy_entry->e_data; - - /* If we have SIDs for both entries, compare SIDs */ - if ((ied_server->has_sid && ied_server->sid != NULL) && - (ied_proxy->has_sid && ied_proxy->sid != NULL)) { - - if (dom_sid_check(ied_server->sid, ied_proxy->sid, true)) { - kerr = 0; + if (proxy != NULL) { + /* Handle the case where server == proxy, this is allowed in S4U */ + kerr = ipadb_get_principal(kcontext, proxy, + CLIENT_REFERRALS_FLAGS, + &proxy_entry); + if (kerr) { goto done; } - } - /* Otherwise, compare entry DNs */ - kerr = ulc_casecmp(ied_server->entry_dn, strlen(ied_server->entry_dn), - ied_proxy->entry_dn, strlen(ied_proxy->entry_dn), - NULL, NULL, &result); - if (kerr == 0 && result == 0) { - goto done; + ied_server = (struct ipadb_e_data *) server->e_data; + ied_proxy = (struct ipadb_e_data *) proxy_entry->e_data; + + /* If we have SIDs for both entries, compare SIDs */ + if ((ied_server->has_sid && ied_server->sid != NULL) && + (ied_proxy->has_sid && ied_proxy->sid != NULL)) { + + if (dom_sid_check(ied_server->sid, ied_proxy->sid, true)) { + kerr = 0; + goto done; + } + } + + /* Otherwise, compare entry DNs */ + kerr = ulc_casecmp(ied_server->entry_dn, strlen(ied_server->entry_dn), + ied_proxy->entry_dn, strlen(ied_proxy->entry_dn), + NULL, NULL, &result); + if (kerr == 0 && result == 0) { + goto done; + } } kerr = krb5_unparse_name(kcontext, server->princ, &srv_principal); @@ -241,6 +272,9 @@ krb5_error_code ipadb_check_allowed_to_delegate(krb5_context kcontext, } done: + if (kerr) { + kerr = KRB5KDC_ERR_BADOPTION; + } ipadb_free_principal(kcontext, proxy_entry); krb5_free_unparsed_name(kcontext, srv_principal); ldap_msgfree(res);