From: Arran Cudbard-Bell Date: Fri, 9 Jan 2026 20:44:44 +0000 (+0000) Subject: ldap: Allow the DN caching attribute to be set X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=2c2a45b61ac2a386fef927ace13e9dd83b9ae412;p=thirdparty%2Ffreeradius-server.git ldap: Allow the DN caching attribute to be set --- diff --git a/raddb/mods-available/ldap b/raddb/mods-available/ldap index fdb8a48249c..8ab8bbfe60b 100644 --- a/raddb/mods-available/ldap +++ b/raddb/mods-available/ldap @@ -388,6 +388,11 @@ ldap { # do not (e.g. mixed IPoE and PPPoE). # # expect_password = no + + # + # dn_attribute:: Where to cache the user's DN for use in authentication. + # +# dn_attribute = 'LDAP-UserDN' } # @@ -1103,4 +1108,3 @@ ldap { # my_profile = 'cn=profile1,ou=profiles,dc=example,dc=com' # %ldap.profile(my_profile) # ---- - diff --git a/src/modules/rlm_ldap/rlm_ldap.c b/src/modules/rlm_ldap/rlm_ldap.c index 78556eb3362..bcfc6f35195 100644 --- a/src/modules/rlm_ldap/rlm_ldap.c +++ b/src/modules/rlm_ldap/rlm_ldap.c @@ -53,6 +53,7 @@ USES_APPLE_DEPRECATED_API typedef struct { fr_dict_attr_t const *group_da; fr_dict_attr_t const *cache_da; + fr_dict_attr_t const *user_da; } rlm_ldap_boot_t; typedef struct { @@ -119,6 +120,7 @@ static conf_parser_t user_config[] = { { FR_CONF_OFFSET("access_positive", rlm_ldap_t, user.access_positive), .dflt = "yes" }, { FR_CONF_OFFSET("access_value_negate", rlm_ldap_t, user.access_value_negate), .dflt = "false" }, { FR_CONF_OFFSET("access_value_suspend", rlm_ldap_t, user.access_value_suspend), .dflt = "suspended" }, + { FR_CONF_OFFSET("dn_attribute", rlm_ldap_t, user.dn_attr_str), .dflt = "LDAP-UserDN" }, { FR_CONF_OFFSET_IS_SET("expect_password", FR_TYPE_BOOL, 0, rlm_ldap_t, user.expect_password) }, CONF_PARSER_TERMINATOR }; @@ -136,7 +138,7 @@ static conf_parser_t group_config[] = { { FR_CONF_OFFSET_FLAGS("membership_filter", CONF_FLAG_XLAT, rlm_ldap_t, group.obj_membership_filter) }, { FR_CONF_OFFSET("cacheable_name", rlm_ldap_t, group.cacheable_name), .dflt = "no" }, { FR_CONF_OFFSET("cacheable_dn", rlm_ldap_t, group.cacheable_dn), .dflt = "no" }, - { FR_CONF_OFFSET("cache_attribute", rlm_ldap_t, group.cache_attribute) }, + { FR_CONF_OFFSET("cache_attribute", rlm_ldap_t, group.cache_attr_str) }, { FR_CONF_OFFSET("group_attribute", rlm_ldap_t, group.attribute) }, { FR_CONF_OFFSET("allow_dangling_group_ref", rlm_ldap_t, group.allow_dangling_refs), .dflt = "no" }, { FR_CONF_OFFSET("skip_on_suspend", rlm_ldap_t, group.skip_on_suspend), .dflt = "yes"}, @@ -325,7 +327,6 @@ fr_dict_autoload_t rlm_ldap_dict[] = { fr_dict_attr_t const *attr_password; fr_dict_attr_t const *attr_cleartext_password; fr_dict_attr_t const *attr_crypt_password; -fr_dict_attr_t const *attr_ldap_userdn; fr_dict_attr_t const *attr_nt_password; fr_dict_attr_t const *attr_password_with_header; static fr_dict_attr_t const *attr_expr_bool_enum; @@ -335,7 +336,6 @@ fr_dict_attr_autoload_t rlm_ldap_dict_attr[] = { { .out = &attr_password, .name = "Password", .type = FR_TYPE_TLV, .dict = &dict_freeradius }, { .out = &attr_cleartext_password, .name = "Password.Cleartext", .type = FR_TYPE_STRING, .dict = &dict_freeradius }, { .out = &attr_crypt_password, .name = "Password.Crypt", .type = FR_TYPE_STRING, .dict = &dict_freeradius }, - { .out = &attr_ldap_userdn, .name = "LDAP-UserDN", .type = FR_TYPE_STRING, .dict = &dict_freeradius }, { .out = &attr_nt_password, .name = "Password.NT", .type = FR_TYPE_OCTETS, .dict = &dict_freeradius }, { .out = &attr_password_with_header, .name = "Password.With-Header", .type = FR_TYPE_STRING, .dict = &dict_freeradius }, { .out = &attr_expr_bool_enum, .name = "Expr-Bool-Enum", .type = FR_TYPE_BOOL, .dict = &dict_freeradius }, @@ -991,7 +991,7 @@ static unlang_action_t ldap_group_xlat_results(unlang_result_t *p_result, reques switch (xlat_ctx->status) { case GROUP_XLAT_FIND_USER: - if (!xlat_ctx->dn) xlat_ctx->dn = rlm_find_user_dn_cached(request); + if (!xlat_ctx->dn) xlat_ctx->dn = rlm_find_user_dn_cached(inst, request); if (!xlat_ctx->dn) RETURN_UNLANG_FAIL; RDEBUG3("Entered GROUP_XLAT_FIND_USER with user DN \"%s\"", xlat_ctx->dn); @@ -1116,7 +1116,7 @@ static xlat_action_t ldap_group_xlat(TALLOC_CTX *ctx, fr_dcursor_t *out, xlat_ct *xlat_ctx = (ldap_group_xlat_ctx_t){ .inst = inst, .group = group_vb, - .dn = rlm_find_user_dn_cached(request), + .dn = rlm_find_user_dn_cached(inst, request), .attrs = { inst->group.userobj_membership_attr, NULL }, .group_is_dn = group_is_dn, .env_data = env_data @@ -1576,14 +1576,14 @@ static unlang_action_t CC_HINT(nonnull) mod_authenticate(unlang_result_t *p_resu /* * Find the user's DN */ - auth_ctx->dn = rlm_find_user_dn_cached(request); + auth_ctx->dn = rlm_find_user_dn_cached(inst, request); /* * The DN is required for non-SASL auth */ if (!auth_ctx->dn && (call_env->user_sasl_mech.type != FR_TYPE_STRING)) { REDEBUG("No DN found for authentication. Populate control.%s with the DN to use in authentication.", - attr_ldap_userdn->name); + inst->user.da->name); REDEBUG("You should call %s in the recv section and check its return.", inst->mi->name); talloc_free(auth_ctx); RETURN_UNLANG_FAIL; @@ -1734,7 +1734,7 @@ static unlang_action_t CC_HINT(nonnull) mod_authorize_resume(unlang_result_t *p_ * Retrieve Universal Password if we use eDirectory */ if (inst->edir) { - autz_ctx->dn = rlm_find_user_dn_cached(request); + autz_ctx->dn = rlm_find_user_dn_cached(inst, request); /* * Retrieve universal password @@ -2199,7 +2199,7 @@ static unlang_action_t CC_HINT(nonnull) user_modify_resume(unlang_result_t *p_re * If an LDAP search was used to find the user DN * usermod_ctx->dn will be NULL. */ - if (!usermod_ctx->dn) usermod_ctx->dn = rlm_find_user_dn_cached(request); + if (!usermod_ctx->dn) usermod_ctx->dn = rlm_find_user_dn_cached(mctx->mi->data, request); if (!usermod_ctx->dn) { fail: @@ -2262,7 +2262,7 @@ static unlang_action_t CC_HINT(nonnull) mod_modify(unlang_result_t *p_result, mo RETURN_UNLANG_FAIL; } - usermod_ctx->dn = rlm_find_user_dn_cached(request); + usermod_ctx->dn = rlm_find_user_dn_cached(inst, request); /* * Find the user first */ @@ -2575,6 +2575,7 @@ static int mod_instantiate(module_inst_ctx_t const *mctx) inst->mi = mctx->mi; /* Cached for IO callbacks */ inst->group.da = boot->group_da; inst->group.cache_da = boot->cache_da; + inst->user.da = boot->user_da; inst->handle_config.name = talloc_typed_asprintf(inst, "rlm_ldap (%s)", mctx->mi->name); @@ -2835,21 +2836,33 @@ static int mod_bootstrap(module_inst_ctx_t const *mctx) /* * Setup the cache attribute */ - - if (inst->group.cache_attribute) { - boot->cache_da = fr_dict_attr_by_name(NULL, fr_dict_root(dict_freeradius), inst->group.cache_attribute); + if (inst->group.cache_attr_str) { + boot->cache_da = fr_dict_attr_by_name(NULL, fr_dict_root(dict_freeradius), inst->group.cache_attr_str); if (!boot->cache_da) { if (fr_dict_attr_add_name_only(fr_dict_unconst(dict_freeradius), fr_dict_root(dict_freeradius), - inst->group.cache_attribute, FR_TYPE_STRING, NULL) < 0) { + inst->group.cache_attr_str, FR_TYPE_STRING, NULL) < 0) { PERROR("Error creating cache attribute"); return -1; } - boot->cache_da = fr_dict_attr_by_name(NULL, fr_dict_root(dict_freeradius), inst->group.cache_attribute); + boot->cache_da = fr_dict_attr_by_name(NULL, fr_dict_root(dict_freeradius), inst->group.cache_attr_str); } } else { boot->cache_da = boot->group_da; /* Default to the group_da */ } + + if (inst->user.dn_attr_str) { + boot->user_da = fr_dict_attr_by_name(NULL, fr_dict_root(dict_freeradius), inst->user.dn_attr_str); + if (!boot->user_da) { + if (fr_dict_attr_add_name_only(fr_dict_unconst(dict_freeradius), fr_dict_root(dict_freeradius), + inst->user.dn_attr_str, FR_TYPE_STRING, NULL) < 0) { + PERROR("Error creating user DN cache attribute"); + return -1; + } + boot->user_da = fr_dict_attr_by_name(NULL, fr_dict_root(dict_freeradius), inst->user.dn_attr_str); + } + } + xlat = module_rlm_xlat_register(mctx->mi->boot, mctx, NULL, ldap_xlat, FR_TYPE_STRING); xlat_func_args_set(xlat, ldap_xlat_arg); diff --git a/src/modules/rlm_ldap/rlm_ldap.h b/src/modules/rlm_ldap/rlm_ldap.h index 7daf64dd662..d86c176a43a 100644 --- a/src/modules/rlm_ldap/rlm_ldap.h +++ b/src/modules/rlm_ldap/rlm_ldap.h @@ -47,6 +47,13 @@ typedef struct { bool expect_password; //!< Allow the user to forcefully decide if a password should be ///< expected. Controls whether warnings are issued. bool expect_password_is_set; //!< Whether an expect password value was provided. + + char const *dn_attr_str; //!< Sets the attribute we use when creating and retrieving + //!< cached group memberships. + + fr_dict_attr_t const *da; //!< The DA associated with this specific instance of the + //!< rlm_ldap module for caching user DNs between autz and + ///< auth phases. } user; /* @@ -72,7 +79,7 @@ typedef struct { //!< resolution necessary to determine the DNs of those groups, //!< then right them to the control list (LDAP-GroupDN). - char const *cache_attribute; //!< Sets the attribute we use when creating and retrieving + char const *cache_attr_str; //!< Sets the attribute we use when creating and retrieving //!< cached group memberships. fr_dict_attr_t const *cache_da; //!< The DA associated with this specific instance of the @@ -238,7 +245,6 @@ typedef struct { extern HIDDEN fr_dict_attr_t const *attr_password; extern HIDDEN fr_dict_attr_t const *attr_cleartext_password; extern HIDDEN fr_dict_attr_t const *attr_crypt_password; -extern HIDDEN fr_dict_attr_t const *attr_ldap_userdn; extern HIDDEN fr_dict_attr_t const *attr_nt_password; extern HIDDEN fr_dict_attr_t const *attr_password_with_header; @@ -248,11 +254,11 @@ extern HIDDEN fr_dict_attr_t const *attr_user_name; /* * user.c - User lookup functions */ -static inline char const *rlm_find_user_dn_cached(request_t *request) +static inline char const *rlm_find_user_dn_cached(rlm_ldap_t const *inst, request_t *request) { fr_pair_t *vp; - vp = fr_pair_find_by_da(&request->control_pairs, NULL, attr_ldap_userdn); + vp = fr_pair_find_by_da(&request->control_pairs, NULL, inst->user.da); if (!vp) return NULL; RDEBUG2("Using user DN from request \"%pV\"", &vp->data); diff --git a/src/modules/rlm_ldap/user.c b/src/modules/rlm_ldap/user.c index db8e5627e89..e648d4e8b95 100644 --- a/src/modules/rlm_ldap/user.c +++ b/src/modules/rlm_ldap/user.c @@ -119,7 +119,7 @@ static unlang_action_t ldap_find_user_async_result(unlang_result_t *p_result, re RDEBUG2("User object found at DN \"%s\"", dn); - MEM(pair_update_control(&vp, attr_ldap_userdn) >= 0); + MEM(pair_update_control(&vp, user_ctx->inst->user.da) >= 0); fr_pair_value_strdup(vp, dn, false); ldap_memfree(dn);