|
|
3615c2 |
From 5b83cb4769a61068ad02cacc455c51fe3cc28b6f Mon Sep 17 00:00:00 2001
|
|
|
3615c2 |
From: Julien Rische <jrische@redhat.com>
|
|
|
3615c2 |
Date: Mon, 25 Mar 2024 18:25:52 +0200
|
|
|
3615c2 |
Subject: [PATCH] kdb: apply combinatorial logic for ticket flags
|
|
|
3615c2 |
|
|
|
3615c2 |
The initial design for ticket flags was implementing this logic:
|
|
|
3615c2 |
* If a ticket policy is defined for the principal entry, use flags from
|
|
|
3615c2 |
this policy if they are set. Otherwise, use default ticket flags.
|
|
|
3615c2 |
* If no ticket policy is defined for the principal entry, but there is a
|
|
|
3615c2 |
global one, use flags from the global ticket policy if they are set.
|
|
|
3615c2 |
Otherwise, use default ticket flags.
|
|
|
3615c2 |
* If no policy (principal nor global) is defined, use default ticket
|
|
|
3615c2 |
flags.
|
|
|
3615c2 |
|
|
|
3615c2 |
However, this logic was broken by a1165ffb which introduced creation of
|
|
|
3615c2 |
a principal-level ticket policy in case the ticket flag set is modified.
|
|
|
3615c2 |
This was typically the case for the -allow_tix flag, which was set
|
|
|
3615c2 |
virtually by the KDB driver when a user was locked until they initialize
|
|
|
3615c2 |
their password on first kinit pre-authentication.
|
|
|
3615c2 |
|
|
|
3615c2 |
This was causing multiple issues, which are mitigated by the new
|
|
|
3615c2 |
approach:
|
|
|
3615c2 |
|
|
|
3615c2 |
Now flags from each level are combined together. There flags like
|
|
|
3615c2 |
+requires_preauth which are set systematically by the KDB diver, as
|
|
|
3615c2 |
well as -allow_tix which is set based on the value of "nsAccountLock".
|
|
|
3615c2 |
This commit also adds the implicit -allow_svr ticket flag for user
|
|
|
3615c2 |
principals to protect users against Kerberoast-type attacks. None of
|
|
|
3615c2 |
these flags are stored in the LDAP database, they are hard-coded in the
|
|
|
3615c2 |
KDB driver.
|
|
|
3615c2 |
|
|
|
3615c2 |
In addition to these "virtual" ticket flags, flags from both global and
|
|
|
3615c2 |
principal ticket policies are applied (if these policies exist).
|
|
|
3615c2 |
|
|
|
3615c2 |
Principal ticket policies are not supported for hosts and services, but
|
|
|
3615c2 |
this is only an HTTP API limitation. The "krbTicketPolicyAux" object
|
|
|
3615c2 |
class is supported for all account types. This is required for ticket
|
|
|
3615c2 |
flags like +ok_to_auth_as_delegate. Such flags can be set using "ipa
|
|
|
3615c2 |
host-mod" and "ipa serivce-mod", or using kadmin's "modprinc".
|
|
|
3615c2 |
|
|
|
3615c2 |
It is possible to ignore flags from the global ticket policy or default
|
|
|
3615c2 |
flags like -allow_svr for a user principal by setting the
|
|
|
3615c2 |
"final_user_tkt_flags" string attribute to "true" in kadmin. In this
|
|
|
3615c2 |
case, any ticket flag can be configured in the principal ticket policy,
|
|
|
3615c2 |
except requires_preauth and allow_tix.
|
|
|
3615c2 |
|
|
|
3615c2 |
When in IPA setup mode (using the "ipa-setup-override-restrictions" KDB
|
|
|
3615c2 |
argument), all the system described above is disabled and ticket flags
|
|
|
3615c2 |
are written in the principal ticket policy as they are provided. This is
|
|
|
3615c2 |
required to initialize the Kerberos LDAP container during IPA server
|
|
|
3615c2 |
installation.
|
|
|
3615c2 |
|
|
|
3615c2 |
This fixes CVE-2024-3183
|
|
|
3615c2 |
|
|
|
3615c2 |
Signed-off-by: Julien Rische <jrische@redhat.com>
|
|
|
3615c2 |
---
|
|
|
3615c2 |
daemons/ipa-kdb/ipa_kdb.h | 43 ++++
|
|
|
3615c2 |
daemons/ipa-kdb/ipa_kdb_principals.c | 352 +++++++++++++++++++++++----
|
|
|
3615c2 |
util/ipa_krb5.c | 18 ++
|
|
|
3615c2 |
util/ipa_krb5.h | 5 +
|
|
|
3615c2 |
4 files changed, 365 insertions(+), 53 deletions(-)
|
|
|
3615c2 |
|
|
|
3615c2 |
diff --git a/daemons/ipa-kdb/ipa_kdb.h b/daemons/ipa-kdb/ipa_kdb.h
|
|
|
3615c2 |
index d187d969f..e7da25875 100644
|
|
|
3615c2 |
--- a/daemons/ipa-kdb/ipa_kdb.h
|
|
|
3615c2 |
+++ b/daemons/ipa-kdb/ipa_kdb.h
|
|
|
3615c2 |
@@ -82,6 +82,34 @@
|
|
|
3615c2 |
#define IPA_KRB_AUTHZ_DATA_ATTR "ipaKrbAuthzData"
|
|
|
3615c2 |
#define IPA_USER_AUTH_TYPE "ipaUserAuthType"
|
|
|
3615c2 |
|
|
|
3615c2 |
+/* Virtual managed ticket flags like "-allow_tix", are always controlled by the
|
|
|
3615c2 |
+ * "nsAccountLock" attribute, such flags should never be set in the database.
|
|
|
3615c2 |
+ * The following expression combine all of them, and is used to filter them
|
|
|
3615c2 |
+ * out. */
|
|
|
3615c2 |
+#define IPA_KDB_TKTFLAGS_VIRTUAL_MANAGED_ALL (KRB5_KDB_DISALLOW_ALL_TIX)
|
|
|
3615c2 |
+
|
|
|
3615c2 |
+/* Virtual static ticket flags are hard-coded in the KDB driver. */
|
|
|
3615c2 |
+/* Virtual static mandatory flags are set systematically and implicitly for all
|
|
|
3615c2 |
+ * principals. They are filtered out from database ticket flags updates.
|
|
|
3615c2 |
+ * (However, "KRB5_KDB_REQUIRES_PRE_AUTH" can still be unset by the
|
|
|
3615c2 |
+ * "KDC:Disable Default Preauth for SPNs" global setting) */
|
|
|
3615c2 |
+#define IPA_KDB_TKTFLAGS_VIRTUAL_STATIC_MANDATORY (KRB5_KDB_REQUIRES_PRE_AUTH)
|
|
|
3615c2 |
+/* Virtual static default ticket flags are implicitly set for user and non-user
|
|
|
3615c2 |
+ * (SPN) principals, and not stored in the database.
|
|
|
3615c2 |
+ * (Except if the "IPA_KDB_STRATTR_FINAL_TKTFLAGS" string attribute is "true"
|
|
|
3615c2 |
+ * the principal) */
|
|
|
3615c2 |
+/* Virtual static default user ticket flags are set for users only. The
|
|
|
3615c2 |
+ * "-allow_svr" flag is set to protect them from CVE-2024-3183. */
|
|
|
3615c2 |
+#define IPA_KDB_TKTFLAGS_VIRTUAL_STATIC_DEFAULTS_USER (KRB5_KDB_DISALLOW_SVR)
|
|
|
3615c2 |
+#define IPA_KDB_TKTFLAGS_VIRTUAL_STATIC_DEFAULTS_SPN (0)
|
|
|
3615c2 |
+
|
|
|
3615c2 |
+/* If this string attribute is set to "true", then only the virtual managed and
|
|
|
3615c2 |
+ * virtual static mandatory ticket flags are applied and filtered out from
|
|
|
3615c2 |
+ * database read and write operations for the concerned user principal.
|
|
|
3615c2 |
+ * Configurable principal ticket flags are applied, but not the configurable
|
|
|
3615c2 |
+ * global ticket policy flags. */
|
|
|
3615c2 |
+#define IPA_KDB_STRATTR_FINAL_USER_TKTFLAGS "final_user_tkt_flags"
|
|
|
3615c2 |
+
|
|
|
3615c2 |
struct ipadb_mspac;
|
|
|
3615c2 |
|
|
|
3615c2 |
enum ipadb_user_auth {
|
|
|
3615c2 |
@@ -141,6 +169,21 @@ struct ipadb_e_data {
|
|
|
3615c2 |
bool has_tktpolaux;
|
|
|
3615c2 |
};
|
|
|
3615c2 |
|
|
|
3615c2 |
+inline static krb5_error_code
|
|
|
3615c2 |
+ipadb_get_edata(krb5_db_entry *entry, struct ipadb_e_data **ied)
|
|
|
3615c2 |
+{
|
|
|
3615c2 |
+ struct ipadb_e_data *in_ied;
|
|
|
3615c2 |
+
|
|
|
3615c2 |
+ in_ied = (struct ipadb_e_data *)entry->e_data;
|
|
|
3615c2 |
+ if (!in_ied || in_ied->magic != IPA_E_DATA_MAGIC)
|
|
|
3615c2 |
+ return EINVAL;
|
|
|
3615c2 |
+
|
|
|
3615c2 |
+ if (ied)
|
|
|
3615c2 |
+ *ied = in_ied;
|
|
|
3615c2 |
+
|
|
|
3615c2 |
+ return 0;
|
|
|
3615c2 |
+}
|
|
|
3615c2 |
+
|
|
|
3615c2 |
struct ipadb_context *ipadb_get_context(krb5_context kcontext);
|
|
|
3615c2 |
int ipadb_get_connection(struct ipadb_context *ipactx);
|
|
|
3615c2 |
|
|
|
3615c2 |
diff --git a/daemons/ipa-kdb/ipa_kdb_principals.c b/daemons/ipa-kdb/ipa_kdb_principals.c
|
|
|
3615c2 |
index e1e86a610..2e522aa39 100644
|
|
|
3615c2 |
--- a/daemons/ipa-kdb/ipa_kdb_principals.c
|
|
|
3615c2 |
+++ b/daemons/ipa-kdb/ipa_kdb_principals.c
|
|
|
3615c2 |
@@ -592,9 +592,12 @@ static krb5_error_code ipadb_parse_ldap_entry(krb5_context kcontext,
|
|
|
3615c2 |
"krbTicketFlags", &result);
|
|
|
3615c2 |
if (ret == 0) {
|
|
|
3615c2 |
entry->attributes = result;
|
|
|
3615c2 |
- } else {
|
|
|
3615c2 |
- *polmask |= TKTFLAGS_BIT;
|
|
|
3615c2 |
}
|
|
|
3615c2 |
+ /* Since principal, global policy, and virtual ticket flags are combined,
|
|
|
3615c2 |
+ * they must always be resolved, except if we are in IPA setup mode (because
|
|
|
3615c2 |
+ * ticket policies and virtual ticket flags are irrelevant in this case). */
|
|
|
3615c2 |
+ if (!ipactx->override_restrictions)
|
|
|
3615c2 |
+ *polmask |= TKTFLAGS_BIT;
|
|
|
3615c2 |
|
|
|
3615c2 |
ret = ipadb_ldap_attr_to_int(lcontext, lentry,
|
|
|
3615c2 |
"krbMaxTicketLife", &result);
|
|
|
3615c2 |
@@ -788,7 +791,11 @@ static krb5_error_code ipadb_parse_ldap_entry(krb5_context kcontext,
|
|
|
3615c2 |
goto done;
|
|
|
3615c2 |
}
|
|
|
3615c2 |
if (ret == 0) {
|
|
|
3615c2 |
- ied->ipa_user = true;
|
|
|
3615c2 |
+ if (1 == krb5_princ_size(kcontext, entry->princ)) {
|
|
|
3615c2 |
+ /* A principal must be a POSIX account AND have only one element to
|
|
|
3615c2 |
+ * be considered a user (this is to filter out CIFS principals). */
|
|
|
3615c2 |
+ ied->ipa_user = true;
|
|
|
3615c2 |
+ }
|
|
|
3615c2 |
}
|
|
|
3615c2 |
|
|
|
3615c2 |
/* check if it has the krbTicketPolicyAux objectclass */
|
|
|
3615c2 |
@@ -1075,23 +1082,150 @@ krb5_error_code ipadb_find_principal(krb5_context kcontext,
|
|
|
3615c2 |
return 0;
|
|
|
3615c2 |
}
|
|
|
3615c2 |
|
|
|
3615c2 |
-static krb5_flags maybe_require_preauth(struct ipadb_context *ipactx,
|
|
|
3615c2 |
- krb5_db_entry *entry)
|
|
|
3615c2 |
+static krb5_error_code
|
|
|
3615c2 |
+are_final_tktflags(struct ipadb_context *ipactx, krb5_db_entry *entry,
|
|
|
3615c2 |
+ bool *final_tktflags)
|
|
|
3615c2 |
{
|
|
|
3615c2 |
- const struct ipadb_global_config *config;
|
|
|
3615c2 |
+ krb5_error_code kerr;
|
|
|
3615c2 |
struct ipadb_e_data *ied;
|
|
|
3615c2 |
+ char *str = NULL;
|
|
|
3615c2 |
+ bool in_final_tktflags = false;
|
|
|
3615c2 |
|
|
|
3615c2 |
- config = ipadb_get_global_config(ipactx);
|
|
|
3615c2 |
- if (config && config->disable_preauth_for_spns) {
|
|
|
3615c2 |
- ied = (struct ipadb_e_data *)entry->e_data;
|
|
|
3615c2 |
- if (ied && ied->ipa_user != true) {
|
|
|
3615c2 |
- /* not a user, assume SPN */
|
|
|
3615c2 |
- return 0;
|
|
|
3615c2 |
- }
|
|
|
3615c2 |
+ kerr = ipadb_get_edata(entry, &ied;;
|
|
|
3615c2 |
+ if (kerr)
|
|
|
3615c2 |
+ goto end;
|
|
|
3615c2 |
+
|
|
|
3615c2 |
+ if (!ied->ipa_user) {
|
|
|
3615c2 |
+ kerr = 0;
|
|
|
3615c2 |
+ goto end;
|
|
|
3615c2 |
+ }
|
|
|
3615c2 |
+
|
|
|
3615c2 |
+ kerr = krb5_dbe_get_string(ipactx->kcontext, entry,
|
|
|
3615c2 |
+ IPA_KDB_STRATTR_FINAL_USER_TKTFLAGS, &str);
|
|
|
3615c2 |
+ if (kerr)
|
|
|
3615c2 |
+ goto end;
|
|
|
3615c2 |
+
|
|
|
3615c2 |
+ in_final_tktflags = str && ipa_krb5_parse_bool(str);
|
|
|
3615c2 |
+
|
|
|
3615c2 |
+end:
|
|
|
3615c2 |
+ if (final_tktflags)
|
|
|
3615c2 |
+ *final_tktflags = in_final_tktflags;
|
|
|
3615c2 |
+
|
|
|
3615c2 |
+ krb5_dbe_free_string(ipactx->kcontext, str);
|
|
|
3615c2 |
+ return kerr;
|
|
|
3615c2 |
+}
|
|
|
3615c2 |
+
|
|
|
3615c2 |
+static krb5_error_code
|
|
|
3615c2 |
+add_virtual_static_tktflags(struct ipadb_context *ipactx, krb5_db_entry *entry,
|
|
|
3615c2 |
+ krb5_flags *tktflags)
|
|
|
3615c2 |
+{
|
|
|
3615c2 |
+ krb5_error_code kerr;
|
|
|
3615c2 |
+ krb5_flags vsflg;
|
|
|
3615c2 |
+ bool final_tktflags;
|
|
|
3615c2 |
+ const struct ipadb_global_config *gcfg;
|
|
|
3615c2 |
+ struct ipadb_e_data *ied;
|
|
|
3615c2 |
+
|
|
|
3615c2 |
+ vsflg = IPA_KDB_TKTFLAGS_VIRTUAL_STATIC_MANDATORY;
|
|
|
3615c2 |
+
|
|
|
3615c2 |
+ kerr = ipadb_get_edata(entry, &ied;;
|
|
|
3615c2 |
+ if (kerr)
|
|
|
3615c2 |
+ goto end;
|
|
|
3615c2 |
+
|
|
|
3615c2 |
+ kerr = are_final_tktflags(ipactx, entry, &final_tktflags);
|
|
|
3615c2 |
+ if (kerr)
|
|
|
3615c2 |
+ goto end;
|
|
|
3615c2 |
+
|
|
|
3615c2 |
+ /* In practice, principal ticket flags cannot be final for SPNs. */
|
|
|
3615c2 |
+ if (!final_tktflags)
|
|
|
3615c2 |
+ vsflg |= ied->ipa_user ? IPA_KDB_TKTFLAGS_VIRTUAL_STATIC_DEFAULTS_USER
|
|
|
3615c2 |
+ : IPA_KDB_TKTFLAGS_VIRTUAL_STATIC_DEFAULTS_SPN;
|
|
|
3615c2 |
+
|
|
|
3615c2 |
+ if (!ied->ipa_user) {
|
|
|
3615c2 |
+ gcfg = ipadb_get_global_config(ipactx);
|
|
|
3615c2 |
+ if (gcfg && gcfg->disable_preauth_for_spns)
|
|
|
3615c2 |
+ vsflg &= ~KRB5_KDB_REQUIRES_PRE_AUTH;
|
|
|
3615c2 |
}
|
|
|
3615c2 |
|
|
|
3615c2 |
- /* By default require preauth for all principals */
|
|
|
3615c2 |
- return KRB5_KDB_REQUIRES_PRE_AUTH;
|
|
|
3615c2 |
+ if (tktflags)
|
|
|
3615c2 |
+ *tktflags |= vsflg;
|
|
|
3615c2 |
+
|
|
|
3615c2 |
+end:
|
|
|
3615c2 |
+ return kerr;
|
|
|
3615c2 |
+}
|
|
|
3615c2 |
+
|
|
|
3615c2 |
+static krb5_error_code
|
|
|
3615c2 |
+get_virtual_static_tktflags_mask(struct ipadb_context *ipactx,
|
|
|
3615c2 |
+ krb5_db_entry *entry, krb5_flags *mask)
|
|
|
3615c2 |
+{
|
|
|
3615c2 |
+ krb5_error_code kerr;
|
|
|
3615c2 |
+ krb5_flags flags = IPA_KDB_TKTFLAGS_VIRTUAL_MANAGED_ALL;
|
|
|
3615c2 |
+
|
|
|
3615c2 |
+ kerr = add_virtual_static_tktflags(ipactx, entry, &flags);
|
|
|
3615c2 |
+ if (kerr)
|
|
|
3615c2 |
+ goto end;
|
|
|
3615c2 |
+
|
|
|
3615c2 |
+ if (mask)
|
|
|
3615c2 |
+ *mask = ~flags;
|
|
|
3615c2 |
+
|
|
|
3615c2 |
+ kerr = 0;
|
|
|
3615c2 |
+
|
|
|
3615c2 |
+end:
|
|
|
3615c2 |
+ return kerr;
|
|
|
3615c2 |
+}
|
|
|
3615c2 |
+
|
|
|
3615c2 |
+/* Add ticket flags from the global ticket policy if it exists, otherwise
|
|
|
3615c2 |
+ * succeed. If the global ticket policy is set, the "exists" parameter is set to
|
|
|
3615c2 |
+ * true. */
|
|
|
3615c2 |
+static krb5_error_code
|
|
|
3615c2 |
+add_global_ticket_policy_flags(struct ipadb_context *ipactx,
|
|
|
3615c2 |
+ bool *gtpol_exists, krb5_flags *tktflags)
|
|
|
3615c2 |
+{
|
|
|
3615c2 |
+ krb5_error_code kerr;
|
|
|
3615c2 |
+ char *policy_dn;
|
|
|
3615c2 |
+ char *tktflags_attr[] = { "krbticketflags", NULL };
|
|
|
3615c2 |
+ LDAPMessage *res = NULL, *first;
|
|
|
3615c2 |
+ int ec, ldap_tktflags;
|
|
|
3615c2 |
+ bool in_gtpol_exists = false;
|
|
|
3615c2 |
+
|
|
|
3615c2 |
+ ec = asprintf(&policy_dn, "cn=%s,cn=kerberos,%s", ipactx->realm,
|
|
|
3615c2 |
+ ipactx->base);
|
|
|
3615c2 |
+ if (-1 == ec) {
|
|
|
3615c2 |
+ kerr = ENOMEM;
|
|
|
3615c2 |
+ goto end;
|
|
|
3615c2 |
+ }
|
|
|
3615c2 |
+
|
|
|
3615c2 |
+ kerr = ipadb_simple_search(ipactx, policy_dn, LDAP_SCOPE_BASE,
|
|
|
3615c2 |
+ "(objectclass=krbticketpolicyaux)",
|
|
|
3615c2 |
+ tktflags_attr, &res;;
|
|
|
3615c2 |
+ if (kerr) {
|
|
|
3615c2 |
+ if (KRB5_KDB_NOENTRY == kerr)
|
|
|
3615c2 |
+ kerr = 0;
|
|
|
3615c2 |
+ goto end;
|
|
|
3615c2 |
+ }
|
|
|
3615c2 |
+
|
|
|
3615c2 |
+ first = ldap_first_entry(ipactx->lcontext, res);
|
|
|
3615c2 |
+ if (!first) {
|
|
|
3615c2 |
+ kerr = 0;
|
|
|
3615c2 |
+ goto end;
|
|
|
3615c2 |
+ }
|
|
|
3615c2 |
+
|
|
|
3615c2 |
+ in_gtpol_exists = true;
|
|
|
3615c2 |
+
|
|
|
3615c2 |
+ ec = ipadb_ldap_attr_to_int(ipactx->lcontext, first, "krbticketflags",
|
|
|
3615c2 |
+ &ldap_tktflags);
|
|
|
3615c2 |
+ if (0 == ec && tktflags) {
|
|
|
3615c2 |
+ *tktflags |= (krb5_flags)ldap_tktflags;
|
|
|
3615c2 |
+ }
|
|
|
3615c2 |
+
|
|
|
3615c2 |
+ kerr = 0;
|
|
|
3615c2 |
+
|
|
|
3615c2 |
+end:
|
|
|
3615c2 |
+ if (gtpol_exists)
|
|
|
3615c2 |
+ *gtpol_exists = in_gtpol_exists;
|
|
|
3615c2 |
+
|
|
|
3615c2 |
+ ldap_msgfree(res);
|
|
|
3615c2 |
+ free(policy_dn);
|
|
|
3615c2 |
+ return kerr;
|
|
|
3615c2 |
}
|
|
|
3615c2 |
|
|
|
3615c2 |
static krb5_error_code ipadb_fetch_tktpolicy(krb5_context kcontext,
|
|
|
3615c2 |
@@ -1104,6 +1238,7 @@ static krb5_error_code ipadb_fetch_tktpolicy(krb5_context kcontext,
|
|
|
3615c2 |
char *policy_dn = NULL;
|
|
|
3615c2 |
LDAPMessage *res = NULL;
|
|
|
3615c2 |
LDAPMessage *first;
|
|
|
3615c2 |
+ bool final_tktflags, has_local_tktpolicy = true;
|
|
|
3615c2 |
int result;
|
|
|
3615c2 |
int ret;
|
|
|
3615c2 |
|
|
|
3615c2 |
@@ -1112,12 +1247,18 @@ static krb5_error_code ipadb_fetch_tktpolicy(krb5_context kcontext,
|
|
|
3615c2 |
return KRB5_KDB_DBNOTINITED;
|
|
|
3615c2 |
}
|
|
|
3615c2 |
|
|
|
3615c2 |
+ kerr = are_final_tktflags(ipactx, entry, &final_tktflags);
|
|
|
3615c2 |
+ if (kerr)
|
|
|
3615c2 |
+ goto done;
|
|
|
3615c2 |
+
|
|
|
3615c2 |
ret = ipadb_ldap_attr_to_str(ipactx->lcontext, lentry,
|
|
|
3615c2 |
"krbticketpolicyreference", &policy_dn);
|
|
|
3615c2 |
switch (ret) {
|
|
|
3615c2 |
case 0:
|
|
|
3615c2 |
break;
|
|
|
3615c2 |
case ENOENT:
|
|
|
3615c2 |
+ /* If no principal ticket policy, fallback to the global one. */
|
|
|
3615c2 |
+ has_local_tktpolicy = false;
|
|
|
3615c2 |
ret = asprintf(&policy_dn, "cn=%s,cn=kerberos,%s",
|
|
|
3615c2 |
ipactx->realm, ipactx->base);
|
|
|
3615c2 |
if (ret == -1) {
|
|
|
3615c2 |
@@ -1159,12 +1300,13 @@ static krb5_error_code ipadb_fetch_tktpolicy(krb5_context kcontext,
|
|
|
3615c2 |
}
|
|
|
3615c2 |
}
|
|
|
3615c2 |
if (polmask & TKTFLAGS_BIT) {
|
|
|
3615c2 |
- ret = ipadb_ldap_attr_to_int(ipactx->lcontext, first,
|
|
|
3615c2 |
- "krbticketflags", &result);
|
|
|
3615c2 |
- if (ret == 0) {
|
|
|
3615c2 |
- entry->attributes |= result;
|
|
|
3615c2 |
- } else {
|
|
|
3615c2 |
- entry->attributes |= maybe_require_preauth(ipactx, entry);
|
|
|
3615c2 |
+ /* If global ticket policy is being applied, set flags only if
|
|
|
3615c2 |
+ * user principal ticket flags are not final. */
|
|
|
3615c2 |
+ if (has_local_tktpolicy || !final_tktflags) {
|
|
|
3615c2 |
+ ret = ipadb_ldap_attr_to_int(ipactx->lcontext, first,
|
|
|
3615c2 |
+ "krbticketflags", &result);
|
|
|
3615c2 |
+ if (ret == 0)
|
|
|
3615c2 |
+ entry->attributes |= result;
|
|
|
3615c2 |
}
|
|
|
3615c2 |
}
|
|
|
3615c2 |
}
|
|
|
3615c2 |
@@ -1179,13 +1321,27 @@ static krb5_error_code ipadb_fetch_tktpolicy(krb5_context kcontext,
|
|
|
3615c2 |
if (polmask & MAXRENEWABLEAGE_BIT) {
|
|
|
3615c2 |
entry->max_renewable_life = 604800;
|
|
|
3615c2 |
}
|
|
|
3615c2 |
- if (polmask & TKTFLAGS_BIT) {
|
|
|
3615c2 |
- entry->attributes |= maybe_require_preauth(ipactx, entry);
|
|
|
3615c2 |
- }
|
|
|
3615c2 |
|
|
|
3615c2 |
kerr = 0;
|
|
|
3615c2 |
}
|
|
|
3615c2 |
|
|
|
3615c2 |
+ if (polmask & TKTFLAGS_BIT) {
|
|
|
3615c2 |
+ /* If the principal ticket flags were applied, then flags from the
|
|
|
3615c2 |
+ * global ticket policy has to be applied atop of them if user principal
|
|
|
3615c2 |
+ * ticket flags are not final. */
|
|
|
3615c2 |
+ if (has_local_tktpolicy && !final_tktflags) {
|
|
|
3615c2 |
+ kerr = add_global_ticket_policy_flags(ipactx, NULL,
|
|
|
3615c2 |
+ &entry->attributes);
|
|
|
3615c2 |
+ if (kerr)
|
|
|
3615c2 |
+ goto done;
|
|
|
3615c2 |
+ }
|
|
|
3615c2 |
+
|
|
|
3615c2 |
+ /* Virtual static ticket flags are set regardless of database content */
|
|
|
3615c2 |
+ kerr = add_virtual_static_tktflags(ipactx, entry, &entry->attributes);
|
|
|
3615c2 |
+ if (kerr)
|
|
|
3615c2 |
+ goto done;
|
|
|
3615c2 |
+ }
|
|
|
3615c2 |
+
|
|
|
3615c2 |
done:
|
|
|
3615c2 |
ldap_msgfree(res);
|
|
|
3615c2 |
free(policy_dn);
|
|
|
3615c2 |
@@ -1512,6 +1668,36 @@ static void ipadb_mods_free_tip(struct ipadb_mods *imods)
|
|
|
3615c2 |
imods->tip--;
|
|
|
3615c2 |
}
|
|
|
3615c2 |
|
|
|
3615c2 |
+/* Use LDAP REPLACE operation to remove an attribute.
|
|
|
3615c2 |
+ * Contrary to the DELETE operation, it will not fail if the attribute does not
|
|
|
3615c2 |
+ * exist. */
|
|
|
3615c2 |
+static krb5_error_code
|
|
|
3615c2 |
+ipadb_ldap_replace_remove(struct ipadb_mods *imods, char *attribute)
|
|
|
3615c2 |
+{
|
|
|
3615c2 |
+ krb5_error_code kerr;
|
|
|
3615c2 |
+ LDAPMod *m = NULL;
|
|
|
3615c2 |
+
|
|
|
3615c2 |
+ kerr = ipadb_mods_new(imods, &m);
|
|
|
3615c2 |
+ if (kerr)
|
|
|
3615c2 |
+ return kerr;
|
|
|
3615c2 |
+
|
|
|
3615c2 |
+ m->mod_op = LDAP_MOD_REPLACE;
|
|
|
3615c2 |
+ m->mod_type = strdup(attribute);
|
|
|
3615c2 |
+ if (!m->mod_type) {
|
|
|
3615c2 |
+ kerr = ENOMEM;
|
|
|
3615c2 |
+ goto end;
|
|
|
3615c2 |
+ }
|
|
|
3615c2 |
+
|
|
|
3615c2 |
+ m->mod_values = NULL;
|
|
|
3615c2 |
+
|
|
|
3615c2 |
+ kerr = 0;
|
|
|
3615c2 |
+
|
|
|
3615c2 |
+end:
|
|
|
3615c2 |
+ if (kerr)
|
|
|
3615c2 |
+ ipadb_mods_free_tip(imods);
|
|
|
3615c2 |
+ return kerr;
|
|
|
3615c2 |
+}
|
|
|
3615c2 |
+
|
|
|
3615c2 |
static krb5_error_code ipadb_get_ldap_mod_str(struct ipadb_mods *imods,
|
|
|
3615c2 |
char *attribute, char *value,
|
|
|
3615c2 |
int mod_op)
|
|
|
3615c2 |
@@ -1923,6 +2109,93 @@ static krb5_error_code ipadb_get_ldap_mod_auth_ind(krb5_context kcontext,
|
|
|
3615c2 |
return ret;
|
|
|
3615c2 |
}
|
|
|
3615c2 |
|
|
|
3615c2 |
+static krb5_error_code
|
|
|
3615c2 |
+update_tktflags(krb5_context kcontext, struct ipadb_mods *imods,
|
|
|
3615c2 |
+ krb5_db_entry *entry, int mod_op)
|
|
|
3615c2 |
+{
|
|
|
3615c2 |
+ krb5_error_code kerr;
|
|
|
3615c2 |
+ struct ipadb_context *ipactx;
|
|
|
3615c2 |
+ struct ipadb_e_data *ied;
|
|
|
3615c2 |
+ bool final_tktflags;
|
|
|
3615c2 |
+ krb5_flags tktflags_mask;
|
|
|
3615c2 |
+ int tktflags;
|
|
|
3615c2 |
+
|
|
|
3615c2 |
+ ipactx = ipadb_get_context(kcontext);
|
|
|
3615c2 |
+ if (!ipactx) {
|
|
|
3615c2 |
+ kerr = KRB5_KDB_DBNOTINITED;
|
|
|
3615c2 |
+ goto end;
|
|
|
3615c2 |
+ }
|
|
|
3615c2 |
+
|
|
|
3615c2 |
+ if (ipactx->override_restrictions) {
|
|
|
3615c2 |
+ /* In IPA setup mode, IPA edata might not be available. In this mode,
|
|
|
3615c2 |
+ * ticket flags are written as they are provided. */
|
|
|
3615c2 |
+ tktflags = (int)entry->attributes;
|
|
|
3615c2 |
+ } else {
|
|
|
3615c2 |
+ kerr = ipadb_get_edata(entry, &ied;;
|
|
|
3615c2 |
+ if (kerr)
|
|
|
3615c2 |
+ goto end;
|
|
|
3615c2 |
+
|
|
|
3615c2 |
+ kerr = get_virtual_static_tktflags_mask(ipactx, entry, &tktflags_mask);
|
|
|
3615c2 |
+ if (kerr)
|
|
|
3615c2 |
+ goto end;
|
|
|
3615c2 |
+
|
|
|
3615c2 |
+ kerr = are_final_tktflags(ipactx, entry, &final_tktflags);
|
|
|
3615c2 |
+ if (kerr)
|
|
|
3615c2 |
+ goto end;
|
|
|
3615c2 |
+
|
|
|
3615c2 |
+ /* Flags from the global ticket policy are filtered out only if the user
|
|
|
3615c2 |
+ * principal flags are not final. */
|
|
|
3615c2 |
+ if (!final_tktflags) {
|
|
|
3615c2 |
+ krb5_flags gbl_tktflags = 0;
|
|
|
3615c2 |
+
|
|
|
3615c2 |
+ kerr = add_global_ticket_policy_flags(ipactx, NULL, &gbl_tktflags);
|
|
|
3615c2 |
+ if (kerr)
|
|
|
3615c2 |
+ goto end;
|
|
|
3615c2 |
+
|
|
|
3615c2 |
+ tktflags_mask &= ~gbl_tktflags;
|
|
|
3615c2 |
+ }
|
|
|
3615c2 |
+
|
|
|
3615c2 |
+ tktflags = (int)(entry->attributes & tktflags_mask);
|
|
|
3615c2 |
+
|
|
|
3615c2 |
+ if (LDAP_MOD_REPLACE == mod_op && ied && !ied->has_tktpolaux) {
|
|
|
3615c2 |
+ if (0 == tktflags) {
|
|
|
3615c2 |
+ /* No point initializing principal ticket policy if there are no
|
|
|
3615c2 |
+ * flags left after filtering out virtual and global ticket
|
|
|
3615c2 |
+ * policy ones. */
|
|
|
3615c2 |
+ kerr = 0;
|
|
|
3615c2 |
+ goto end;
|
|
|
3615c2 |
+ }
|
|
|
3615c2 |
+
|
|
|
3615c2 |
+ /* if the object does not have the krbTicketPolicyAux class
|
|
|
3615c2 |
+ * we need to add it or this will fail, only for modifications.
|
|
|
3615c2 |
+ * We always add this objectclass by default when doing an add
|
|
|
3615c2 |
+ * from scratch. */
|
|
|
3615c2 |
+ kerr = ipadb_get_ldap_mod_str(imods, "objectclass",
|
|
|
3615c2 |
+ "krbTicketPolicyAux", LDAP_MOD_ADD);
|
|
|
3615c2 |
+ if (kerr)
|
|
|
3615c2 |
+ goto end;
|
|
|
3615c2 |
+ }
|
|
|
3615c2 |
+ }
|
|
|
3615c2 |
+
|
|
|
3615c2 |
+ if (tktflags != 0) {
|
|
|
3615c2 |
+ kerr = ipadb_get_ldap_mod_int(imods, "krbTicketFlags", tktflags,
|
|
|
3615c2 |
+ mod_op);
|
|
|
3615c2 |
+ if (kerr)
|
|
|
3615c2 |
+ goto end;
|
|
|
3615c2 |
+ } else if (LDAP_MOD_REPLACE == mod_op) {
|
|
|
3615c2 |
+ /* If the principal is not being created, and there are no custom ticket
|
|
|
3615c2 |
+ * flags to be set, remove the "krbTicketFlags" attribute. */
|
|
|
3615c2 |
+ kerr = ipadb_ldap_replace_remove(imods, "krbTicketFlags");
|
|
|
3615c2 |
+ if (kerr)
|
|
|
3615c2 |
+ goto end;
|
|
|
3615c2 |
+ }
|
|
|
3615c2 |
+
|
|
|
3615c2 |
+ kerr = 0;
|
|
|
3615c2 |
+
|
|
|
3615c2 |
+end:
|
|
|
3615c2 |
+ return kerr;
|
|
|
3615c2 |
+}
|
|
|
3615c2 |
+
|
|
|
3615c2 |
static krb5_error_code ipadb_entry_to_mods(krb5_context kcontext,
|
|
|
3615c2 |
struct ipadb_mods *imods,
|
|
|
3615c2 |
krb5_db_entry *entry,
|
|
|
3615c2 |
@@ -1998,36 +2271,9 @@ static krb5_error_code ipadb_entry_to_mods(krb5_context kcontext,
|
|
|
3615c2 |
|
|
|
3615c2 |
/* KADM5_ATTRIBUTES */
|
|
|
3615c2 |
if (entry->mask & KMASK_ATTRIBUTES) {
|
|
|
3615c2 |
- /* if the object does not have the krbTicketPolicyAux class
|
|
|
3615c2 |
- * we need to add it or this will fail, only for modifications.
|
|
|
3615c2 |
- * We always add this objectclass by default when doing an add
|
|
|
3615c2 |
- * from scratch. */
|
|
|
3615c2 |
- if ((mod_op == LDAP_MOD_REPLACE) && entry->e_data) {
|
|
|
3615c2 |
- struct ipadb_e_data *ied;
|
|
|
3615c2 |
-
|
|
|
3615c2 |
- ied = (struct ipadb_e_data *)entry->e_data;
|
|
|
3615c2 |
- if (ied->magic != IPA_E_DATA_MAGIC) {
|
|
|
3615c2 |
- kerr = EINVAL;
|
|
|
3615c2 |
- goto done;
|
|
|
3615c2 |
- }
|
|
|
3615c2 |
-
|
|
|
3615c2 |
- if (!ied->has_tktpolaux) {
|
|
|
3615c2 |
- kerr = ipadb_get_ldap_mod_str(imods, "objectclass",
|
|
|
3615c2 |
- "krbTicketPolicyAux",
|
|
|
3615c2 |
- LDAP_MOD_ADD);
|
|
|
3615c2 |
- if (kerr) {
|
|
|
3615c2 |
- goto done;
|
|
|
3615c2 |
- }
|
|
|
3615c2 |
- }
|
|
|
3615c2 |
- }
|
|
|
3615c2 |
-
|
|
|
3615c2 |
- kerr = ipadb_get_ldap_mod_int(imods,
|
|
|
3615c2 |
- "krbTicketFlags",
|
|
|
3615c2 |
- (int)entry->attributes,
|
|
|
3615c2 |
- mod_op);
|
|
|
3615c2 |
- if (kerr) {
|
|
|
3615c2 |
+ kerr = update_tktflags(kcontext, imods, entry, mod_op);
|
|
|
3615c2 |
+ if (kerr)
|
|
|
3615c2 |
goto done;
|
|
|
3615c2 |
- }
|
|
|
3615c2 |
}
|
|
|
3615c2 |
|
|
|
3615c2 |
/* KADM5_MAX_LIFE */
|
|
|
3615c2 |
diff --git a/util/ipa_krb5.c b/util/ipa_krb5.c
|
|
|
3615c2 |
index 1ba6d25ee..2e663c506 100644
|
|
|
3615c2 |
--- a/util/ipa_krb5.c
|
|
|
3615c2 |
+++ b/util/ipa_krb5.c
|
|
|
3615c2 |
@@ -38,6 +38,12 @@ const char *ipapwd_password_max_len_errmsg = \
|
|
|
3615c2 |
TOSTR(IPAPWD_PASSWORD_MAX_LEN) \
|
|
|
3615c2 |
" chars)!";
|
|
|
3615c2 |
|
|
|
3615c2 |
+/* Case-insensitive string values to by parsed as boolean true */
|
|
|
3615c2 |
+static const char *const conf_yes[] = {
|
|
|
3615c2 |
+ "y", "yes", "true", "t", "1", "on",
|
|
|
3615c2 |
+ NULL,
|
|
|
3615c2 |
+};
|
|
|
3615c2 |
+
|
|
|
3615c2 |
/* Salt types */
|
|
|
3615c2 |
#define KRB5P_SALT_SIZE 16
|
|
|
3615c2 |
|
|
|
3615c2 |
@@ -1237,3 +1243,15 @@ done:
|
|
|
3615c2 |
}
|
|
|
3615c2 |
return ret;
|
|
|
3615c2 |
}
|
|
|
3615c2 |
+
|
|
|
3615c2 |
+bool ipa_krb5_parse_bool(const char *str)
|
|
|
3615c2 |
+{
|
|
|
3615c2 |
+ const char *const *p;
|
|
|
3615c2 |
+
|
|
|
3615c2 |
+ for (p = conf_yes; *p; p++) {
|
|
|
3615c2 |
+ if (!strcasecmp(*p, str))
|
|
|
3615c2 |
+ return true;
|
|
|
3615c2 |
+ }
|
|
|
3615c2 |
+
|
|
|
3615c2 |
+ return false;
|
|
|
3615c2 |
+}
|
|
|
3615c2 |
diff --git a/util/ipa_krb5.h b/util/ipa_krb5.h
|
|
|
3615c2 |
index 8392a85b6..ba371449e 100644
|
|
|
3615c2 |
--- a/util/ipa_krb5.h
|
|
|
3615c2 |
+++ b/util/ipa_krb5.h
|
|
|
3615c2 |
@@ -4,6 +4,7 @@
|
|
|
3615c2 |
#include <krb5/krb5.h>
|
|
|
3615c2 |
#include <kdb.h>
|
|
|
3615c2 |
#include <syslog.h>
|
|
|
3615c2 |
+#include <stdbool.h>
|
|
|
3615c2 |
|
|
|
3615c2 |
struct krb_key_salt {
|
|
|
3615c2 |
krb5_enctype enctype;
|
|
|
3615c2 |
@@ -86,3 +87,7 @@ int create_keys(krb5_context krbctx,
|
|
|
3615c2 |
char **err_msg);
|
|
|
3615c2 |
|
|
|
3615c2 |
int ipa_kstuples_to_string(krb5_key_salt_tuple *kst, int n_kst, char **str);
|
|
|
3615c2 |
+
|
|
|
3615c2 |
+/* Implement boolean string parsing function from MIT krb5:
|
|
|
3615c2 |
+ * src/lib/krb5/krb/libdef_parse.c:_krb5_conf_boolean() */
|
|
|
3615c2 |
+bool ipa_krb5_parse_bool(const char *str);
|
|
|
3615c2 |
--
|
|
|
3615c2 |
2.44.0
|
|
|
3615c2 |
|