From: Arran Cudbard-Bell Date: Fri, 17 Jul 2026 18:49:49 +0000 (-0400) Subject: rlm_ldap: merge profile DN sources into one pooled allocation X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=5cfee05887886504f5263bd78a2b5f46a94cbde5;p=thirdparty%2Ffreeradius-server.git rlm_ldap: merge profile DN sources into one pooled allocation fr_ldap_str_list_afrom_result gains leading slots the caller fills with borrowed strings, so the default, group and user profile DNs merge into a single pooled array with the user values read in place from the result message. The now unused fr_ldap_berval_to_string_list is removed. --- diff --git a/src/lib/ldap/base.h b/src/lib/ldap/base.h index b75477212e7..40217f38095 100644 --- a/src/lib/ldap/base.h +++ b/src/lib/ldap/base.h @@ -963,15 +963,13 @@ size_t fr_ldap_util_normalise_dn(char *out, char const *in); char *fr_ldap_berval_to_string(TALLOC_CTX *ctx, struct berval const *in); -char const **fr_ldap_berval_to_string_list(TALLOC_CTX *ctx, struct berval **values, int count, size_t extra); - int fr_ldap_result_values_len(size_t *num, size_t *strings_len, LDAP *handle, LDAPMessage *result, char const *attr); int fr_ldap_entry_value_find(struct berval *out, LDAP *handle, LDAPMessage *entry, char const *attr); talloc_str_list_t *fr_ldap_str_list_afrom_result(TALLOC_CTX *ctx, LDAP *handle, LDAPMessage *result, - char const *attr); + char const *attr, size_t extra); uint8_t *fr_ldap_berval_to_bin(TALLOC_CTX *ctx, struct berval const *in); diff --git a/src/lib/ldap/util.c b/src/lib/ldap/util.c index 41c71e2293d..a54d6c12340 100644 --- a/src/lib/ldap/util.c +++ b/src/lib/ldap/util.c @@ -497,48 +497,6 @@ int fr_ldap_parse_url_extensions(LDAPControl **sss, size_t sss_len, char *extens return (sss_end - sss_p); } -/** Convert a list of bervals to a NULL terminated list of talloced strings - * - * A list variant of fr_ldap_berval_to_string. Where talloc_pooled_object is - * available the pointer array and every string are allocated from a single - * talloc pool, so building the list costs one malloc. Zero length values - * are skipped. - * - * @param[in] ctx to parent the list. - * @param[in] values to copy. - * @param[in] count Number of values. - * @param[in] extra Leading pointer array entries to leave NULL, for the - * caller to fill with strings not copied into the pool. - * @return NULL terminated array of \0 terminated strings. - */ -char const **fr_ldap_berval_to_string_list(TALLOC_CTX *ctx, struct berval **values, int count, size_t extra) -{ - char const **list; - size_t num = extra; - int i; - -#ifdef HAVE_TALLOC_ZERO_POOLED_OBJECT - { - size_t strings_size = 0; - - for (i = 0; i < count; i++) { - strings_size += values[i]->bv_len + 1; - } - MEM(list = _talloc_zero_pooled_object(ctx, sizeof(char const *) * (count + extra + 1), - "char const *[]", count, strings_size)); - } -#else - MEM(list = talloc_zero_array(ctx, char const *, count + extra + 1)); -#endif - - for (i = 0; i < count; i++) { - if (values[i]->bv_len == 0) continue; - MEM(list[num++] = fr_ldap_berval_to_string(list, values[i])); - } - - return list; -} - /** Sum the lengths of an attribute's values across every entry of a result * * The values are read in place from the result message, no arrays are @@ -612,22 +570,32 @@ int fr_ldap_result_values_len(size_t *num, size_t *strings_len, LDAP *handle, LD * @param[in] ctx to allocate the list in. * @param[in] handle the result was received on. * @param[in] result Head of the result message chain. - * @param[in] attr whose values to copy. + * @param[in] attr whose values to copy. May be NULL, in which case + * only the extra slots are allocated. + * @param[in] extra Leading pointer array slots to leave NULL, for the + * caller to fill with strings not copied into the pool. * @return * - List of the attribute's values. Empty if the result holds no * values for the attribute. * - NULL if an entry could not be parsed. */ -talloc_str_list_t *fr_ldap_str_list_afrom_result(TALLOC_CTX *ctx, LDAP *handle, LDAPMessage *result, char const *attr) +talloc_str_list_t *fr_ldap_str_list_afrom_result(TALLOC_CTX *ctx, LDAP *handle, LDAPMessage *result, + char const *attr, size_t extra) { talloc_str_list_t *list = NULL; LDAPMessage *entry; BerElement *ber = NULL; - size_t attr_len = strlen(attr), num, strings_len; + size_t attr_len, num = 0, strings_len = 0; + + if (attr) { + if (unlikely(fr_ldap_result_values_len(&num, &strings_len, handle, result, attr) < 0)) return NULL; + } - if (unlikely(fr_ldap_result_values_len(&num, &strings_len, handle, result, attr) < 0)) return NULL; + MEM(list = talloc_str_list_alloc(ctx, num + extra, strings_len)); + list->p += extra; - MEM(list = talloc_str_list_alloc(ctx, num, strings_len)); + if (num == 0) return list; + attr_len = strlen(attr); for (entry = ldap_first_entry(handle, result); entry; entry = ldap_next_entry(handle, entry)) { struct berval dn, name, value; diff --git a/src/modules/rlm_ldap/groups.c b/src/modules/rlm_ldap/groups.c index 245c2b81eb2..9f1ac11954a 100644 --- a/src/modules/rlm_ldap/groups.c +++ b/src/modules/rlm_ldap/groups.c @@ -817,7 +817,7 @@ static unlang_action_t ldap_group_profile_resume(unlang_result_t *p_result, requ fr_assert(!autz_ctx->group_profile_dn_list); autz_ctx->group_profile_dn_list = fr_ldap_str_list_afrom_result(autz_ctx, query->ldap_conn->handle, - query->result, group_ctx->profile_attr); + query->result, group_ctx->profile_attr, 0); if (unlikely(!autz_ctx->group_profile_dn_list)) { RPERROR("Failed parsing profiles from group objects"); rcode = RLM_MODULE_FAIL; diff --git a/src/modules/rlm_ldap/rlm_ldap.c b/src/modules/rlm_ldap/rlm_ldap.c index f12bc3fbcac..85a2659d467 100644 --- a/src/modules/rlm_ldap/rlm_ldap.c +++ b/src/modules/rlm_ldap/rlm_ldap.c @@ -1985,11 +1985,11 @@ static unlang_action_t CC_HINT(nonnull) mod_authorize_resume(unlang_result_t *p_ case LDAP_AUTZ_PROFILES: { - struct berval **values = NULL; - char const *profile_attr; - char const **dn_p; - bool have_default = !fr_box_is_null(&call_env->default_profile); - int count, group_count = 0, i; + talloc_str_list_t *list; + char const *profile_attr; + char const **dn_p; + bool have_default = !fr_box_is_null(&call_env->default_profile); + size_t count = 0, strings_len = 0, group_count = 0, i; /* * Which set of profiles to apply depends on the user's @@ -1998,20 +1998,22 @@ static unlang_action_t CC_HINT(nonnull) mod_authorize_resume(unlang_result_t *p_ profile_attr = rlm_ldap_profile_attr_select(inst->user.profile_attr, inst->user.profile_attr_suspend, autz_ctx->access_state); if (profile_attr) { - values = ldap_get_values_len(handle, autz_ctx->entry, profile_attr); - count = ldap_count_values_len(values); + if (unlikely(fr_ldap_result_values_len(&count, &strings_len, handle, + autz_ctx->query->result, profile_attr) < 0)) { + RPERROR("Failed parsing user object"); + p_result->rcode = RLM_MODULE_FAIL; + goto finish; + } if (count > 0) { - RDEBUG2("Processing %i profile(s) found in attribute \"%s\"", count, profile_attr); + RDEBUG2("Processing %zu profile(s) found in attribute \"%s\"", count, profile_attr); } else { RDEBUG2("No profile(s) found in attribute \"%s\"", profile_attr); } - } else { - count = 0; } if (autz_ctx->group_profile_dn_list) { - group_count = (int)talloc_str_list_num(autz_ctx->group_profile_dn_list); - RDEBUG2("Processing %i profile(s) found in group objects", group_count); + group_count = talloc_str_list_num(autz_ctx->group_profile_dn_list); + RDEBUG2("Processing %zu profile(s) found in group objects", group_count); } if (!have_default && (group_count == 0) && (count == 0)) break; @@ -2021,13 +2023,14 @@ static unlang_action_t CC_HINT(nonnull) mod_authorize_resume(unlang_result_t *p_ * profile first, then the profiles from the group * objects, then the profiles from the user object. */ - autz_ctx->profile_dn_list = fr_ldap_berval_to_string_list(autz_ctx, values, count, - (have_default ? 1 : 0) + group_count); - dn_p = autz_ctx->profile_dn_list; + MEM(list = fr_ldap_str_list_afrom_result(autz_ctx, handle, autz_ctx->query->result, + count ? profile_attr : NULL, + (have_default ? 1 : 0) + group_count)); + dn_p = list->strings; if (have_default) *dn_p++ = call_env->default_profile.vb_strvalue; for (i = 0; i < group_count; i++) *dn_p++ = autz_ctx->group_profile_dn_list->strings[i]; - if (values) ldap_value_free_len(values); + autz_ctx->profile_dn_list = list->strings; profile_dn_list_dedupe(autz_ctx->profile_dn_list); if (!autz_ctx->profile_dn_list[0]) break;