Hi, The attached patch is a part of the authentication indicator enhancements, adding indicator value storage and retrieval for the KDB driver.
https://fedorahosted.org/freeipa/ticket/5782 Regards, --- Matt Rogers Red Hat, Inc
From 4aedaf64320b52485407f6798788ecd367c3a002 Mon Sep 17 00:00:00 2001 From: Matt Rogers <mrog...@redhat.com> Date: Fri, 25 Mar 2016 17:01:40 -0400 Subject: [PATCH] ipa_kdb: add krbPrincipalAuthInd handling Store and retrieve the authentication indicator "require_auth" string in the krbPrincipalAuthInd attribute. Skip storing auth indicators to krbExtraData. --- daemons/ipa-kdb/ipa_kdb_principals.c | 277 +++++++++++++++++++++++++++++++++++ install/share/60kerberos.ldif | 6 +- 2 files changed, 281 insertions(+), 2 deletions(-) diff --git a/daemons/ipa-kdb/ipa_kdb_principals.c b/daemons/ipa-kdb/ipa_kdb_principals.c index 629f8193223c924267f6d5f39d258cfbc51c7f63..f12339579e5a4127947fd9a9d6cebf7c0f80e1e2 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); @@ -1422,12 +1506,121 @@ done: return kerr; } +/* Find the next key and value pair in *pos and update *pos. */ +static bool next_attr(const char **pos, const char *end, + const char **key_out, const char **val_out) +{ + const char *key, *key_end, *val, *val_end; + + *key_out = *val_out = NULL; + if (*pos == end) + return false; + key = *pos; + key_end = memchr(key, '\0', end - key); + if (key_end == NULL) /* Malformed representation; give up. */ + return false; + val = key_end + 1; + val_end = memchr(val, '\0', end - val); + if (val_end == NULL) /* Malformed representation; give up. */ + return false; + + *key_out = key; + *val_out = val; + *pos = val_end + 1; + return true; +} + +static krb5_error_code filter_authind_str_attrs(krb5_tl_data *data, + krb5_tl_data **data_out) +{ + krb5_error_code ret = 0; + krb5_tl_data *new_data = NULL; + char *new_content = NULL; + char *new_cp = NULL; + const char *pos = NULL; + const char *end = NULL; + const char *key = NULL; + const char *val = NULL; + size_t data_len = 0; + size_t new_len = 0; + + *data_out = NULL; + + if (data->tl_data_type != KRB5_TL_STRING_ATTRS) { + return 0; + } + + pos = (const char *)data->tl_data_contents; + data_len = data->tl_data_length; + end = pos + data_len; + + new_data = malloc(sizeof(*new_data)); + if (new_data == NULL) { + return errno; + } + new_content = malloc(data_len); + if (new_content == NULL) { + ret = errno; + goto done; + } + + new_cp = new_content; + while (next_attr(&pos, end, &key, &val)) { + if (strcmp(key, "require_auth") == 0) { + continue; + } + + ret = snprintf(new_cp, data_len, "%s", key); + if (ret <= 0 || ret > data_len) { + ret = ENOMEM; + goto done; + } + new_cp += (ret + 1); + data_len -= (ret + 1); + + ret = snprintf(new_cp, data_len, "%s", val); + if (ret <= 0 || ret > data_len) { + ret = ENOMEM; + goto done; + } + new_cp += (ret + 1); + data_len -= (ret + 1); + } + + if (data_len > 0) { + new_len = data->tl_data_length - data_len; + } else { + new_len = data->tl_data_length; + } + + /* "require_auth" was the only entry, return empty contents */ + if (new_len == 0) { + free(new_content); + new_content = NULL; + } + + new_data->tl_data_type = data->tl_data_type; + new_data->tl_data_next = data->tl_data_next; + new_data->tl_data_contents = new_content; + new_data->tl_data_length = new_len; + *data_out = new_data; + ret = 0; + +done: + if (ret) { + free(new_content); + free(new_data); + } + return ret; +} + static krb5_error_code ipadb_get_ldap_mod_extra_data(struct ipadb_mods *imods, krb5_tl_data *tl_data, int mod_op) { krb5_error_code kerr; krb5_tl_data *data; + krb5_tl_data *data_tmp = NULL; struct berval **bvs = NULL; krb5_int16 be_type; int n, i; @@ -1463,6 +1656,20 @@ static krb5_error_code ipadb_get_ldap_mod_extra_data(struct ipadb_mods *imods, continue; } + /* Exclude any auth indicators from krbExtraData */ + kerr = filter_authind_str_attrs(data, &data_tmp); + if (kerr) { + goto done; + } + if (data_tmp != NULL) { + if (data_tmp->tl_data_contents == NULL) { + free(data_tmp); + data_tmp = NULL; + continue; + } + data = data_tmp; + } + be_type = htons(data->tl_data_type); bvs[i] = calloc(1, sizeof(struct berval)); @@ -1497,6 +1704,10 @@ done: free(bvs[i]); } } + if (data_tmp != NULL) { + free(data_tmp->tl_data_contents); + free(data_tmp); + } free(bvs); return kerr; } @@ -1649,6 +1860,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, @@ -1835,6 +2102,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, @@ -1854,6 +2125,12 @@ static krb5_error_code ipadb_entry_to_mods(krb5_context kcontext, } } + /* Delete authinds from tl_data so it is not included in krbExtraData. */ + 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); diff --git a/install/share/60kerberos.ldif b/install/share/60kerberos.ldif index 8698e3a0538fd42443f4a3221fccfb739d4c104d..45bea2aefd3993a521e8ea732f902279622f8cb8 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 -- 2.4.3
-- Manage your subscription for the Freeipa-devel mailing list: https://www.redhat.com/mailman/listinfo/freeipa-devel Contribute to FreeIPA: http://www.freeipa.org/page/Contribute/Code