From: Arran Cudbard-Bell Date: Wed, 13 Oct 2021 20:50:22 +0000 (-0500) Subject: ldap: Add specialised query alloc functions X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=8e7b955510b7039455c9fbff1271a45504e3c2c1;p=thirdparty%2Ffreeradius-server.git ldap: Add specialised query alloc functions --- diff --git a/src/lib/ldap/base.c b/src/lib/ldap/base.c index aec9c1cfa4e..293c03407c3 100644 --- a/src/lib/ldap/base.c +++ b/src/lib/ldap/base.c @@ -763,18 +763,6 @@ fr_ldap_rcode_t fr_ldap_search_async(int *msgid, request_t *request, return LDAP_PROC_SUCCESS; } -/** Submit an LDAP query to be handled by a trunk conneciton - * - */ -static unlang_action_t ldap_trunk_query_start(UNUSED rlm_rcode_t *p_result, UNUSED int *priority, request_t *request, void *uctx) -{ - fr_ldap_query_t *query = talloc_get_type_abort(uctx, fr_ldap_query_t); - - fr_trunk_request_enqueue(&query->treq, query->ttrunk->trunk, request, query, NULL); - - return UNLANG_ACTION_YIELD; -} - /** Handle the return code from parsed LDAP results to set the module rcode * */ @@ -822,6 +810,16 @@ do { \ } \ } while (0) + +/** Hack to make code work with synchronous interpreter + * + */ +static unlang_action_t ldap_trunk_query_start(UNUSED rlm_rcode_t *p_result, UNUSED int *priority, + UNUSED request_t *request, UNUSED void *uctx) +{ + return UNLANG_ACTION_YIELD; +} + /** Run an async search LDAP query on a trunk connection * * @param[in] ctx to allocate the query in. @@ -834,23 +832,35 @@ do { \ * @param[in] attrs to be returned. * @param[in] serverctrls specific to this query. * @param[in] clientctrls specific to this query. + * @return + * - UNLANG_ACTION_FAIL on error. + * - UNLANG_ACTION_YIELD on success. */ -int fr_ldap_trunk_search(TALLOC_CTX *ctx, fr_ldap_query_t **query, request_t *request, fr_ldap_thread_trunk_t *ttrunk, char const *base_dn, - int scope, char const *filter, char const * const *attrs, LDAPControl **serverctrls, LDAPControl **clientctrls ) +unlang_action_t fr_ldap_trunk_search(TALLOC_CTX *ctx, + fr_ldap_query_t **out, request_t *request, fr_ldap_thread_trunk_t *ttrunk, + char const *base_dn, int scope, char const *filter, char const * const *attrs, + LDAPControl **serverctrls, LDAPControl **clientctrls, + bool is_async) { - *query = fr_ldap_query_alloc(ctx); - - (*query)->type = LDAP_REQUEST_SEARCH; - (*query)->request = request; - (*query)->ttrunk = ttrunk; - (*query)->dn = base_dn; - (*query)->search.scope = scope; - (*query)->search.filter = filter; - memcpy(&(*query)->search.attrs, &attrs, sizeof((*query)->search.attrs)); - SET_LDAP_CTRLS((*query)->serverctrls, serverctrls); - SET_LDAP_CTRLS((*query)->clientctrls, clientctrls); - - return unlang_function_push(request, ldap_trunk_query_start, ldap_trunk_query_results, ldap_trunk_query_cancel, UNLANG_TOP_FRAME, *query); + unlang_action_t action; + fr_ldap_query_t *query; + + query = fr_ldap_search_alloc(ctx, base_dn, scope, filter, attrs, serverctrls, clientctrls); + + if (fr_trunk_request_enqueue(&query->treq, ttrunk->trunk, request, query, NULL) != FR_TRUNK_ENQUEUE_OK) { + error: + talloc_free(query); + return UNLANG_ACTION_FAIL; + } + + action = unlang_function_push(request, is_async ? NULL : ldap_trunk_query_start, ldap_trunk_query_results, + ldap_trunk_query_cancel, is_async ? UNLANG_SUB_FRAME : UNLANG_TOP_FRAME, query); + + if (action == UNLANG_ACTION_FAIL) goto error; + + *out = query; + + return is_async ? action : UNLANG_ACTION_YIELD; } /** Run an async modification LDAP query on a trunk connection @@ -863,21 +873,35 @@ int fr_ldap_trunk_search(TALLOC_CTX *ctx, fr_ldap_query_t **query, request_t *re * @param[in] mods to be performed. * @param[in] serverctrls specific to this query. * @param[in] clientctrls specific to this query. + * @return + * - UNLANG_ACTION_FAIL on error. + * - UNLANG_ACTION_YIELD on success. */ -int fr_ldap_trunk_modify(TALLOC_CTX *ctx, fr_ldap_query_t **query, request_t *request, fr_ldap_thread_trunk_t *ttrunk, - char const *dn, LDAPMod *mods[], LDAPControl **serverctrls, LDAPControl **clientctrls) +unlang_action_t fr_ldap_trunk_modify(TALLOC_CTX *ctx, + fr_ldap_query_t **out, request_t *request, fr_ldap_thread_trunk_t *ttrunk, + char const *dn, LDAPMod *mods[], + LDAPControl **serverctrls, LDAPControl **clientctrls, + bool is_async) { - *query = fr_ldap_query_alloc(ctx); + unlang_action_t action; + fr_ldap_query_t *query; - (*query)->type = LDAP_REQUEST_MODIFY; - (*query)->request = request; - (*query)->ttrunk = ttrunk; - (*query)->dn = dn; - (*query)->mods = mods; - SET_LDAP_CTRLS((*query)->serverctrls, serverctrls); - SET_LDAP_CTRLS((*query)->clientctrls, clientctrls); + query = fr_ldap_modify_alloc(ctx, dn, mods, serverctrls, clientctrls); - return unlang_function_push(request, ldap_trunk_query_start, ldap_trunk_query_results, ldap_trunk_query_cancel, UNLANG_TOP_FRAME, *query); + if (fr_trunk_request_enqueue(&query->treq, ttrunk->trunk, request, query, NULL) != FR_TRUNK_ENQUEUE_OK) { + error: + talloc_free(query); + return UNLANG_ACTION_FAIL; + } + + action = unlang_function_push(request, is_async ? NULL : ldap_trunk_query_start, ldap_trunk_query_results, + ldap_trunk_query_cancel, is_async ? UNLANG_SUB_FRAME : UNLANG_TOP_FRAME, query); + + if (action == UNLANG_ACTION_FAIL) goto error; + + *out = query; + + return is_async ? action : UNLANG_ACTION_YIELD; } /** Modify something in the LDAP directory @@ -988,52 +1012,6 @@ fr_ldap_rcode_t fr_ldap_modify_async(int *msgid, request_t *request, fr_ldap_con return LDAP_PROC_SUCCESS; } -/** Change settings global to libldap - * - * May only be called once. Subsequent calls will be ignored. - * - * @param[in] debug_level to enable in libldap. - * @param[in] tls_random_file Where OpenSSL gets its randomness. - */ -int fr_ldap_global_config(int debug_level, char const *tls_random_file) -{ - static bool done_config; - fr_ldap_config_t *handle_config = &ldap_global_handle_config; - - if (done_config) return 0; - -#define do_ldap_global_option(_option, _name, _value) \ - if (ldap_set_option(NULL, _option, _value) != LDAP_OPT_SUCCESS) { \ - int _ldap_errno; \ - ldap_get_option(NULL, LDAP_OPT_RESULT_CODE, &_ldap_errno); \ - ERROR("Failed setting global option %s: %s", _name, \ - (_ldap_errno != LDAP_SUCCESS) ? ldap_err2string(_ldap_errno) : "Unknown error"); \ - return -1;\ - } - -#define maybe_ldap_global_option(_option, _name, _value) \ - if (_value) do_ldap_global_option(_option, _name, _value) - -#ifdef LDAP_OPT_DEBUG_LEVEL - if (debug_level) do_ldap_global_option(LDAP_OPT_DEBUG_LEVEL, "ldap_debug", &debug_level); -#else - if (debug_level) WARN("ldap_debug not honoured as LDAP_OPT_DEBUG_LEVEL is not available"); -#endif - -#ifdef LDAP_OPT_X_TLS_RANDOM_FILE - /* - * OpenLDAP will error out if we attempt to set - * this on a handle. Presumably it's global in - * OpenSSL too. - */ - maybe_ldap_global_option(LDAP_OPT_X_TLS_RANDOM_FILE, "random_file", tls_random_file); -#endif - - done_config = true; - - return 0; -} - /** Free any libldap structures when an fr_ldap_query_t is freed * * It is also possible that the connection used for this query is now closed, @@ -1093,7 +1071,8 @@ static int _ldap_query_free(fr_ldap_query_t *query) /** Allocate an fr_ldap_query_t, setting the talloc destructor * */ -fr_ldap_query_t *fr_ldap_query_alloc(TALLOC_CTX *ctx) +static inline CC_HINT(always_inline) +fr_ldap_query_t *ldap_query_alloc(TALLOC_CTX *ctx, fr_ldap_request_type_t type) { fr_ldap_query_t *query; @@ -1101,10 +1080,92 @@ fr_ldap_query_t *fr_ldap_query_alloc(TALLOC_CTX *ctx) talloc_set_destructor(query, _ldap_query_free); query->ret = LDAP_RESULT_PENDING; + query->type = type; + + return query; +} + +/** Allocate a new search object + * + * @param[in] ctx to allocate query in. + */ +fr_ldap_query_t *fr_ldap_search_alloc(TALLOC_CTX *ctx, + char const *base_dn, int scope, char const *filter, char const * const * attrs, + LDAPControl **serverctrls, LDAPControl **clientctrls) +{ + fr_ldap_query_t *query; + + query = ldap_query_alloc(ctx, LDAP_REQUEST_SEARCH); + query->dn = base_dn; + query->search.scope = scope; + query->search.filter = filter; + query->search.attrs = UNCONST(char const **, attrs); + SET_LDAP_CTRLS(query->serverctrls, serverctrls); + SET_LDAP_CTRLS(query->clientctrls, clientctrls); + + return query; +} + +fr_ldap_query_t *fr_ldap_modify_alloc(TALLOC_CTX *ctx, char const *dn, + LDAPMod *mods[], LDAPControl **serverctrls, LDAPControl **clientctrls) +{ + fr_ldap_query_t *query; + + query = ldap_query_alloc(ctx, LDAP_REQUEST_MODIFY); + query->dn = dn; + query->mods = mods; + SET_LDAP_CTRLS(query->serverctrls, serverctrls); + SET_LDAP_CTRLS(query->clientctrls, clientctrls); return query; } +/** Change settings global to libldap + * + * May only be called once. Subsequent calls will be ignored. + * + * @param[in] debug_level to enable in libldap. + * @param[in] tls_random_file Where OpenSSL gets its randomness. + */ +int fr_ldap_global_config(int debug_level, char const *tls_random_file) +{ + static bool done_config; + fr_ldap_config_t *handle_config = &ldap_global_handle_config; + + if (done_config) return 0; + +#define do_ldap_global_option(_option, _name, _value) \ + if (ldap_set_option(NULL, _option, _value) != LDAP_OPT_SUCCESS) { \ + int _ldap_errno; \ + ldap_get_option(NULL, LDAP_OPT_RESULT_CODE, &_ldap_errno); \ + ERROR("Failed setting global option %s: %s", _name, \ + (_ldap_errno != LDAP_SUCCESS) ? ldap_err2string(_ldap_errno) : "Unknown error"); \ + return -1;\ + } + +#define maybe_ldap_global_option(_option, _name, _value) \ + if (_value) do_ldap_global_option(_option, _name, _value) + +#ifdef LDAP_OPT_DEBUG_LEVEL + if (debug_level) do_ldap_global_option(LDAP_OPT_DEBUG_LEVEL, "ldap_debug", &debug_level); +#else + if (debug_level) WARN("ldap_debug not honoured as LDAP_OPT_DEBUG_LEVEL is not available"); +#endif + +#ifdef LDAP_OPT_X_TLS_RANDOM_FILE + /* + * OpenLDAP will error out if we attempt to set + * this on a handle. Presumably it's global in + * OpenSSL too. + */ + maybe_ldap_global_option(LDAP_OPT_X_TLS_RANDOM_FILE, "random_file", tls_random_file); +#endif + + done_config = true; + + return 0; +} + /** Initialise libldap and check library versions * * @return diff --git a/src/lib/ldap/base.h b/src/lib/ldap/base.h index bef33084cf9..07609b88e49 100644 --- a/src/lib/ldap/base.h +++ b/src/lib/ldap/base.h @@ -582,8 +582,6 @@ static inline int8_t fr_ldap_query_cmp(void const *one, void const *two) return CMP(a->msgid, b->msgid); } -fr_ldap_query_t *fr_ldap_query_alloc(TALLOC_CTX *ctx); - /** Compare two ldap bind auth structures on msgid * * @param[in] one first bind request to compare. @@ -597,9 +595,12 @@ static inline int8_t fr_ldap_bind_auth_cmp(void const *one, void const *two) return CMP(a->msgid, b->msgid); } -int fr_ldap_trunk_search(TALLOC_CTX *ctx, fr_ldap_query_t **query, request_t *request, fr_ldap_thread_trunk_t *ttrunk, - char const *base_dn, int scope, char const *filter, char const * const *attrs, - LDAPControl **serverctrls, LDAPControl **clientctrls); +fr_ldap_query_t *fr_ldap_search_alloc(TALLOC_CTX *ctx, + char const *base_dn, int scope, char const *filter, char const * const * attrs, + LDAPControl **serverctrls, LDAPControl **clientctrls); + +fr_ldap_query_t *fr_ldap_modify_alloc(TALLOC_CTX *ctx, char const *dn, + LDAPMod *mods[], LDAPControl **serverctrls, LDAPControl **clientctrls); int fr_ldap_trunk_modify(TALLOC_CTX *ctx, fr_ldap_query_t **query, request_t *request, fr_ldap_thread_trunk_t *ttrunk, char const *dn, LDAPMod *mods[], LDAPControl **serverctrls, LDAPControl **clientctrls); diff --git a/src/modules/rlm_ldap/rlm_ldap.c b/src/modules/rlm_ldap/rlm_ldap.c index 8c5a50b9889..6691869145f 100644 --- a/src/modules/rlm_ldap/rlm_ldap.c +++ b/src/modules/rlm_ldap/rlm_ldap.c @@ -511,7 +511,7 @@ static xlat_action_t ldap_xlat(UNUSED TALLOC_CTX *ctx, UNUSED fr_dcursor_t *out, if (fr_uri_escape(in, ldap_uri_parts, NULL) < 0) return XLAT_ACTION_FAIL; in_vb = fr_dlist_head(in); - if(fr_value_box_list_concat_in_place(in_vb, in_vb, in, FR_TYPE_STRING, FR_VALUE_BOX_LIST_FREE, + if (fr_value_box_list_concat_in_place(in_vb, in_vb, in, FR_TYPE_STRING, FR_VALUE_BOX_LIST_FREE, true, SIZE_MAX) < 0) { REDEBUG("Failed concattenating input"); return XLAT_ACTION_FAIL; @@ -522,17 +522,14 @@ static xlat_action_t ldap_xlat(UNUSED TALLOC_CTX *ctx, UNUSED fr_dcursor_t *out, return XLAT_ACTION_FAIL; } - query = fr_ldap_query_alloc(unlang_interpret_frame_talloc_ctx(request)); - - if (ldap_url_parse(in_vb->vb_strvalue, &query->ldap_url)){ + if (ldap_url_parse(in_vb->vb_strvalue, &ldap_url)){ REDEBUG("Parsing LDAP URL failed"); - free_query: + error: + ldap_free_urldesc(ldap_url); talloc_free(query); return XLAT_ACTION_FAIL; } - ldap_url = query->ldap_url; - /* * Nothing, empty string, "*" string, or got 2 things, die. */ @@ -540,7 +537,27 @@ static xlat_action_t ldap_xlat(UNUSED TALLOC_CTX *ctx, UNUSED fr_dcursor_t *out, (strcmp(ldap_url->lud_attrs[0], "*") == 0) || ldap_url->lud_attrs[1]) { REDEBUG("Bad attributes list in LDAP URL. URL must specify exactly one attribute to retrieve"); - goto free_query; + goto error; + } + + query = fr_ldap_search_alloc(unlang_interpret_frame_talloc_ctx(request), + ldap_url->lud_dn, ldap_url->lud_scope, ldap_url->lud_filter, + (char const * const*)ldap_url->lud_attrs, NULL, NULL); + if (ldap_url->lud_exts) { + LDAPControl *serverctrls[LDAP_MAX_CONTROLS]; + int i; + + if (fr_ldap_parse_url_extensions(serverctrls, NUM_ELEMENTS(serverctrls), + query->ldap_url->lud_exts) < 0) { + RPERROR("Parsing URL extensions failed"); + goto error; + } + + for (i = 0; i < LDAP_MAX_CONTROLS; i++) { + if (!serverctrls[i]) break; + query->serverctrls[i].control = serverctrls[i]; + query->serverctrls[i].freeit = true; + } } /* @@ -557,11 +574,10 @@ static xlat_action_t ldap_xlat(UNUSED TALLOC_CTX *ctx, UNUSED fr_dcursor_t *out, handle_config->admin_password, request, handle_config); if (!query->ttrunk) { REDEBUG("Unable to get LDAP query for xlat"); - goto free_query; + goto error; } - query->type = LDAP_REQUEST_SEARCH; - query->request = request; + query->ldap_url = ldap_url; /* query destructor will free URL */ fr_trunk_request_enqueue(&query->treq, query->ttrunk->trunk, request, query, NULL);