]> git.ipfire.org Git - thirdparty/freeradius-server.git/commitdiff
rlm_ldap: merge profile DN sources into one pooled allocation
authorArran Cudbard-Bell <a.cudbardb@freeradius.org>
Fri, 17 Jul 2026 18:49:49 +0000 (14:49 -0400)
committerArran Cudbard-Bell <a.cudbardb@freeradius.org>
Fri, 17 Jul 2026 18:49:49 +0000 (14:49 -0400)
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.

src/lib/ldap/base.h
src/lib/ldap/util.c
src/modules/rlm_ldap/groups.c
src/modules/rlm_ldap/rlm_ldap.c

index b75477212e767722ccfb10bd479675fa71dfb0da..40217f3809565f7b1885d2188d8acc34a9e0cc14 100644 (file)
@@ -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);
 
index 41c71e2293de699d832f80b315406bfc19c82491..a54d6c12340a0df87f84b31d1b7f0a33b7adcd16 100644 (file)
@@ -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;
index 245c2b81eb220259f393fb3ddfa1f1e8da0e3249..9f1ac11954a44623ba805751698e9b12ec7b170a 100644 (file)
@@ -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;
index f12bc3fbcaca1a7fe736ea347e469a8f6371ba69..85a2659d467a5a075e58fad83929a1258b844213 100644 (file)
@@ -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;