diff --git a/daemons/ipa-kdb/ipa_kdb.h b/daemons/ipa-kdb/ipa_kdb.h index f2f21c6e0..08c24ae64 100644 --- a/daemons/ipa-kdb/ipa_kdb.h +++ b/daemons/ipa-kdb/ipa_kdb.h @@ -141,6 +141,7 @@ struct ipadb_e_data { time_t last_admin_unlock; char **authz_data; bool has_tktpolaux; + enum ipadb_user_auth user_auth; }; struct ipadb_context *ipadb_get_context(krb5_context kcontext); diff --git a/daemons/ipa-kdb/ipa_kdb_kdcpolicy.c b/daemons/ipa-kdb/ipa_kdb_kdcpolicy.c index 66e49d637..6b61f162e 100644 --- a/daemons/ipa-kdb/ipa_kdb_kdcpolicy.c +++ b/daemons/ipa-kdb/ipa_kdb_kdcpolicy.c @@ -18,12 +18,82 @@ ipa_kdcpolicy_check_as(krb5_context context, krb5_kdcpolicy_moddata moddata, const char **status, krb5_deltat *lifetime_out, krb5_deltat *renew_lifetime_out) { + krb5_error_code kerr; + enum ipadb_user_auth ua; + struct ipadb_e_data *ied; + int valid_auth_indicators = 0; + *status = NULL; *lifetime_out = 0; *renew_lifetime_out = 0; krb5_klog_syslog(LOG_INFO, "IPA kdcpolicy: checking AS-REQ."); + ied = (struct ipadb_e_data *)client->e_data; + if (ied == NULL || ied->magic != IPA_E_DATA_MAGIC) { + /* e-data is not availble, getting user auth from LDAP */ + krb5_klog_syslog(LOG_INFO, "IPA kdcpolicy: client e_data not availble. Try fetching..."); + kerr = ipadb_get_principal(context, request->client, KRB5_KDB_FLAG_ALIAS_OK, &client); + if (kerr != 0) { + krb5_klog_syslog(LOG_ERR, "IPA kdcpolicy: ipadb_find_principal failed."); + return kerr; + } + + ied = (struct ipadb_e_data *)client->e_data; + if (ied == NULL && ied->magic != IPA_E_DATA_MAGIC) { + krb5_klog_syslog(LOG_ERR, "IPA kdcpolicy: client e_data fetching failed."); + return EINVAL; + } + } + + ua = ied->user_auth; + + /* If no mechanisms are set, allow every auth method */ + if (ua == IPADB_USER_AUTH_NONE) { + return 0; + } + + /* For each auth indicator, see if it is allowed for that user */ + for (int i = 0; auth_indicators[i] != NULL; i++) { + const char *auth_indicator = auth_indicators[i]; + + if (strcmp(auth_indicator, "otp") == 0) { + valid_auth_indicators++; + if (!(ua & IPADB_USER_AUTH_OTP)) { + *status = "OTP pre-authentication not allowed for this user."; + return KRB5KDC_ERR_POLICY; + } + } else if (strcmp(auth_indicator, "radius") == 0) { + valid_auth_indicators++; + if (!(ua & IPADB_USER_AUTH_RADIUS)) { + *status = "OTP pre-authentication not allowed for this user."; + return KRB5KDC_ERR_POLICY; + } + } else if (strcmp(auth_indicator, "pkinit") == 0) { + valid_auth_indicators++; + if (!(ua & IPADB_USER_AUTH_PKINIT)) { + *status = "PKINIT pre-authentication not allowed for this user."; + return KRB5KDC_ERR_POLICY; + } + } else if (strcmp(auth_indicator, "hardened") == 0) { + valid_auth_indicators++; + /* Allow hardened even if only password pre-auth is allowed */ + if (!(ua & (IPADB_USER_AUTH_HARDENED | IPADB_USER_AUTH_PASSWORD))) { + *status = "Password pre-authentication not not allowed for this user."; + return KRB5KDC_ERR_POLICY; + } + } + } + + /* There is no auth indicator assigned for non-hardened password authentication + * so we assume password is used when no supported indicator exists */ + if (!valid_auth_indicators) { + if (!(ua & IPADB_USER_AUTH_PASSWORD)) { + *status = "Non-hardened password authentication not allowed for this user."; + return KRB5KDC_ERR_POLICY; + } + } + return 0; } diff --git a/daemons/ipa-kdb/ipa_kdb_principals.c b/daemons/ipa-kdb/ipa_kdb_principals.c index 731348e01..58f462f8a 100644 --- a/daemons/ipa-kdb/ipa_kdb_principals.c +++ b/daemons/ipa-kdb/ipa_kdb_principals.c @@ -318,15 +318,6 @@ static void ipadb_validate_radius(struct ipadb_context *ipactx, ldap_value_free_len(vals); } -static void ipadb_validate_password(struct ipadb_context *ipactx, - LDAPMessage *lentry, - enum ipadb_user_auth *ua) -{ - /* If no mechanisms are set, use password. */ - if (*ua == IPADB_USER_AUTH_NONE) - *ua |= IPADB_USER_AUTH_PASSWORD; -} - static enum ipadb_user_auth ipadb_get_user_auth(struct ipadb_context *ipactx, LDAPMessage *lentry) { @@ -354,7 +345,6 @@ static enum ipadb_user_auth ipadb_get_user_auth(struct ipadb_context *ipactx, /* Perform flag validation. */ ipadb_validate_otp(ipactx, lentry, &ua); ipadb_validate_radius(ipactx, lentry, &ua); - ipadb_validate_password(ipactx, lentry, &ua); return ua; } @@ -708,13 +698,6 @@ static krb5_error_code ipadb_parse_ldap_entry(krb5_context kcontext, &res_key_data, &result, &mkvno); switch (ret) { case 0: - /* Only set a principal's key if password auth should be used. */ - if (!(ua & IPADB_USER_AUTH_PASSWORD)) { - /* This is the same behavior as ENOENT below. */ - ipa_krb5_free_key_data(res_key_data, result); - break; - } - entry->key_data = res_key_data; entry->n_key_data = result; if (mkvno) { @@ -851,6 +834,8 @@ static krb5_error_code ipadb_parse_ldap_entry(krb5_context kcontext, ied->authz_data = authz_data_list; } + ied->user_auth = ua; + /* If enabled, set the otp user string, enabling otp. */ if (ua & IPADB_USER_AUTH_OTP) { kerr = ipadb_set_tl_data(entry, KRB5_TL_STRING_ATTRS,