From 8a2afcafee977675fc289acab50cc808b469a2b3 Mon Sep 17 00:00:00 2001 From: Matt Rogers Date: May 02 2016 17:15:45 +0000 Subject: ipa_kdb: add krbPrincipalAuthInd handling Store and retrieve the authentication indicator "require_auth" string in the krbPrincipalAuthInd attribute. Skip storing auth indicators to krbExtraData. https://fedorahosted.org/freeipa/ticket/5782 Reviewed-By: Sumit Bose --- diff --git a/daemons/ipa-kdb/ipa_kdb_principals.c b/daemons/ipa-kdb/ipa_kdb_principals.c index e32be85..5027810 100644 --- a/daemons/ipa-kdb/ipa_kdb_principals.c +++ b/daemons/ipa-kdb/ipa_kdb_principals.c @@ -54,6 +54,7 @@ static char *std_principal_attrs[] = { "krbLastSuccessfulAuth", "krbLastFailedAuth", "krbLoginFailedCount", + "krbPrincipalAuthInd", "krbExtraData", "krbLastAdminUnlock", "krbObjectReferences", @@ -428,6 +429,85 @@ done: return kerr; } +static void strv_free(char **strv) +{ + int i; + + if (strv == NULL) { + return; + } + + for (i = 0; strv[i] != NULL; i++) { + free(strv[i]); + } + + free(strv); +} + +static krb5_error_code ipadb_get_ldap_auth_ind(krb5_context kcontext, + LDAP *lcontext, + LDAPMessage *lentry, + krb5_db_entry *entry) +{ + krb5_error_code ret = 0; + char **authinds = NULL; + char *aistr = NULL; + char *ap = NULL; + size_t len = 0; + size_t l = 0; + int count = 0; + int i = 0; + + ret = ipadb_ldap_attr_to_strlist(lcontext, lentry, "krbPrincipalAuthInd", + &authinds); + switch (ret) { + case 0: + break; + case ENOENT: + return 0; + default: + return ret; + } + + for (count = 0; authinds != NULL && authinds[count] != NULL; count++) { + len += strlen(authinds[count]) + 1; + } + + if (len == 0) { + strv_free(authinds); + return 0; + } + + aistr = malloc(len); + if (aistr == NULL) { + ret = errno; + goto cleanup; + } + + /* Create a space-separated string of authinds. */ + ap = aistr; + l = len; + for (i = 0; i < count; i++) { + ret = snprintf(ap, l, "%s ", authinds[i]); + if (ret <= 0 || ret > l) { + ret = ENOMEM; + goto cleanup; + } + ap += ret; + l -= ret; + } + aistr[len - 1] = '\0'; + + ret = krb5_dbe_set_string(kcontext, entry, "require_auth", + aistr); + +cleanup: + strv_free(authinds); + free(aistr); + + return ret; +} + static krb5_error_code ipadb_parse_ldap_entry(krb5_context kcontext, char *principal, LDAPMessage *lentry, @@ -611,6 +691,10 @@ static krb5_error_code ipadb_parse_ldap_entry(krb5_context kcontext, goto done; } + ret = ipadb_get_ldap_auth_ind(kcontext, lcontext, lentry, entry); + if (ret) + goto done; + ret = ipadb_ldap_attr_to_key_data(lcontext, lentry, "krbPrincipalKey", &res_key_data, &result, &mkvno); @@ -1668,6 +1752,62 @@ done: return kerr; } +static krb5_error_code ipadb_get_ldap_mod_auth_ind(krb5_context kcontext, + struct ipadb_mods *imods, + krb5_db_entry *entry, + int mod_op) +{ + krb5_error_code ret = 0; + char **strlist = NULL; + char *ais = NULL; + char *ai = NULL; + char *s = NULL; + size_t ai_size = 0; + int cnt = 0; + int i = 0; + + ret = krb5_dbe_get_string(kcontext, entry, "require_auth", &ais); + if (ret) { + return ret; + } + if (ais == NULL) { + return 0; + } + + ai_size = strlen(ais) + 1; + + for (i = 0; i < ai_size; i++) { + if (ais[i] != ' ') { + continue; + } + if (i > 0 && ais[i - 1] != ' ') { + cnt++; + } + } + + strlist = calloc(cnt + 2, sizeof(*strlist)); + if (strlist == NULL) { + free(ais); + return errno; + } + + cnt = 0; + ai = strtok_r(ais, " ", &s); + while (ai != NULL) { + if (ai[0] != '\0') { + strlist[cnt++] = ai; + } + ai = strtok_r(NULL, " ", &s); + } + + ret = ipadb_get_ldap_mod_str_list(imods, "krbPrincipalAuthInd", + strlist, cnt, mod_op); + + free(ais); + free(strlist); + return ret; +} + static krb5_error_code ipadb_entry_to_mods(krb5_context kcontext, struct ipadb_mods *imods, krb5_db_entry *entry, @@ -1676,6 +1816,7 @@ static krb5_error_code ipadb_entry_to_mods(krb5_context kcontext, krb5_error_code kerr; krb5_int32 time32le; int mkvno; + char *req_auth_str = NULL; /* check each mask flag in order */ @@ -1854,6 +1995,10 @@ static krb5_error_code ipadb_entry_to_mods(krb5_context kcontext, } } + kerr = ipadb_get_ldap_mod_auth_ind(kcontext, imods, entry, mod_op); + if (kerr) + goto done; + /* KADM5_TL_DATA */ if (entry->mask & KMASK_TL_DATA) { kerr = ipadb_get_tl_data(entry, @@ -1873,12 +2018,36 @@ static krb5_error_code ipadb_entry_to_mods(krb5_context kcontext, } } + kerr = krb5_dbe_get_string(kcontext, entry, "require_auth", + &req_auth_str); + if (kerr) { + goto done; + } + + /* Do not store auth indicators from the string attribute in + * krbExtraData. Remove require_auth value from the entry temporarily. */ + if (req_auth_str != NULL) { + kerr = krb5_dbe_set_string(kcontext, entry, "require_auth", NULL); + if (kerr) { + goto done; + } + } + kerr = ipadb_get_ldap_mod_extra_data(imods, entry->tl_data, mod_op); if (kerr && kerr != ENOENT) { goto done; } + + /* Restore require_auth value */ + if (req_auth_str != NULL) { + kerr = krb5_dbe_set_string(kcontext, entry, "require_auth", + req_auth_str); + if (kerr) { + goto done; + } + } } /* KADM5_LOAD */ @@ -1956,6 +2125,7 @@ static krb5_error_code ipadb_entry_to_mods(krb5_context kcontext, kerr = 0; done: + free(req_auth_str); return kerr; } diff --git a/install/share/60kerberos.ldif b/install/share/60kerberos.ldif index 8698e3a..45bea2a 100644 --- a/install/share/60kerberos.ldif +++ b/install/share/60kerberos.ldif @@ -266,7 +266,9 @@ attributetypes: ( 2.16.840.1.113719.1.301.4.53.1 NAME 'krbPrincContainerRef' EQU attributetypes: ( 1.3.6.1.4.1.5322.21.2.5 NAME 'krbLastAdminUnlock' EQUALITY generalizedTimeMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 SINGLE-VALUE) ##### A list of services to which a service principal can delegate. attributetypes: ( 1.3.6.1.4.1.5322.21.2.4 NAME 'krbAllowedToDelegateTo' EQUALITY caseExactIA5Match SUBSTR caseExactSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.26) -######################################################################## +##### A list of authentication indicator strings, one of which must be satisfied +##### to authenticate to the principal as a service. +attributetypes: ( 2.16.840.1.113730.3.8.15.2.1 NAME 'krbPrincipalAuthInd' EQUALITY caseExactMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15) ######################################################################## # Object Class Definitions # ######################################################################## @@ -294,7 +296,7 @@ objectClasses: ( 2.16.840.1.113719.1.301.6.4.1 NAME 'krbKdcService' SUP ( krbSer objectClasses: ( 2.16.840.1.113719.1.301.6.5.1 NAME 'krbPwdService' SUP ( krbService ) ) ###### The principal data auxiliary class. Holds principal information ###### and is used to store principal information for Person, Service objects. -objectClasses: ( 2.16.840.1.113719.1.301.6.8.1 NAME 'krbPrincipalAux' AUXILIARY MAY ( krbPrincipalName $ krbCanonicalName $ krbUPEnabled $ krbPrincipalKey $ krbTicketPolicyReference $ krbPrincipalExpiration $ krbPasswordExpiration $ krbPwdPolicyReference $ krbPrincipalType $ krbPwdHistory $ krbLastPwdChange $ krbPrincipalAliases $ krbLastSuccessfulAuth $ krbLastFailedAuth $ krbLoginFailedCount $ krbExtraData $ krbLastAdminUnlock $ krbAllowedToDelegateTo ) ) +objectClasses: ( 2.16.840.1.113719.1.301.6.8.1 NAME 'krbPrincipalAux' AUXILIARY MAY ( krbPrincipalName $ krbCanonicalName $ krbUPEnabled $ krbPrincipalKey $ krbTicketPolicyReference $ krbPrincipalExpiration $ krbPasswordExpiration $ krbPwdPolicyReference $ krbPrincipalType $ krbPwdHistory $ krbLastPwdChange $ krbPrincipalAliases $ krbLastSuccessfulAuth $ krbLastFailedAuth $ krbLoginFailedCount $ krbExtraData $ krbLastAdminUnlock $ krbAllowedToDelegateTo $ krbPrincipalAuthInd ) ) ###### This class is used to create additional principals and stand alone principals. objectClasses: ( 2.16.840.1.113719.1.301.6.9.1 NAME 'krbPrincipal' SUP ( top ) MUST ( krbPrincipalName ) MAY ( krbObjectReferences ) ) ###### The principal references auxiliary class. Holds all principals referred