user_ctx->attrs, serverctrls, NULL, true);
}
-/** Retrieve the DN of a user object
- *
- * Retrieves the DN of a user and adds it to the control list as LDAP-UserDN. Will also retrieve any
- * attributes passed and return the result in *result.
- *
- * This potentially allows for all authorization and authentication checks to be performed in one
- * ldap search operation, which is a big bonus given the number of crappy, slow *cough*AD*cough*
- * LDAP directory servers out there.
- *
- * @param[in] inst rlm_ldap configuration.
- * @param[in] request Current request.
- * @param[in] ttrunk LDAP thread trunk to use.
- * @param[in] attrs Additional attributes to retrieve, may be NULL.
- * @param[in] force Query even if the User-DN already exists.
- * @param[out] result Where to write the result, may be NULL in which case result is discarded.
- * @param[out] handle on which the LDAP query is run.
- * @param[out] rcode The status of the operation, one of the RLM_MODULE_* codes.
- * @return The user's DN or NULL on error.
- */
-char const *rlm_ldap_find_user(rlm_ldap_t const *inst, request_t *request, fr_ldap_thread_trunk_t *ttrunk,
- char const *attrs[], bool force, LDAPMessage **result, LDAP **handle, rlm_rcode_t *rcode)
-{
- static char const *tmp_attrs[] = { NULL };
-
- fr_pair_t *vp = NULL;
- LDAPMessage *tmp_msg = NULL, *entry = NULL;
- int ldap_errno;
- int cnt;
- char *dn = NULL;
- char const *filter = NULL;
- char filter_buff[LDAP_MAX_FILTER_STR_LEN];
- char const *base_dn;
- char base_dn_buff[LDAP_MAX_DN_STR_LEN];
- LDAPControl *serverctrls[] = { inst->userobj_sort_ctrl, NULL };
- fr_ldap_query_t *query = NULL;
-
- bool freeit = false; //!< Whether the message should
- //!< be freed after being processed.
-
- *rcode = RLM_MODULE_FAIL;
-
- if (!result) {
- result = &tmp_msg;
- freeit = true;
- }
- *result = NULL;
-
- if (!attrs) {
- memset(&attrs, 0, sizeof(tmp_attrs));
- }
-
- /*
- * If the caller isn't looking for the result we can just return the current userdn value.
- */
- if (!force) {
- vp = fr_pair_find_by_da(&request->control_pairs, NULL, attr_ldap_userdn);
- if (vp) {
- RDEBUG2("Using user DN from request \"%pV\"", &vp->data);
- *rcode = RLM_MODULE_OK;
- return vp->vp_strvalue;
- }
- }
-
- if (inst->userobj_filter) {
- if (tmpl_expand(&filter, filter_buff, sizeof(filter_buff), request, inst->userobj_filter,
- fr_ldap_escape_func, NULL) < 0) {
- REDEBUG("Unable to create filter");
- *rcode = RLM_MODULE_INVALID;
-
- return NULL;
- }
- }
-
- if (tmpl_expand(&base_dn, base_dn_buff, sizeof(base_dn_buff), request,
- inst->userobj_base_dn, fr_ldap_escape_func, NULL) < 0) {
- REDEBUG("Unable to create base_dn");
- *rcode = RLM_MODULE_INVALID;
-
- return NULL;
- }
-
- if (fr_ldap_trunk_search(rcode,
- unlang_interpret_frame_talloc_ctx(request), &query ,request, ttrunk, base_dn,
- inst->userobj_scope, filter, attrs, serverctrls, NULL, false) < 0) {
- *rcode = RLM_MODULE_FAIL;
- return NULL;
- }
-
- if (*rcode != RLM_MODULE_OK) return NULL;
-
- *result = query->result;
-
- /*
- * Forbid the use of unsorted search results that
- * contain multiple entries, as it's a potential
- * security issue, and likely non deterministic.
- */
- if (!inst->userobj_sort_ctrl) {
- cnt = ldap_count_entries(query->ldap_conn->handle, *result);
- if (cnt > 1) {
- REDEBUG("Ambiguous search result, returned %i unsorted entries (should return 1 or 0). "
- "Enable sorting, or specify a more restrictive base_dn, filter or scope", cnt);
- REDEBUG("The following entries were returned:");
- RINDENT();
- for (entry = ldap_first_entry(query->ldap_conn->handle, *result);
- entry;
- entry = ldap_next_entry(query->ldap_conn->handle, entry)) {
- dn = ldap_get_dn(query->ldap_conn->handle, entry);
- REDEBUG("%s", dn);
- ldap_memfree(dn);
- }
- REXDENT();
- *rcode = RLM_MODULE_INVALID;
- goto finish;
- }
- }
-
- entry = ldap_first_entry(query->ldap_conn->handle, *result);
- if (!entry) {
- ldap_get_option(query->ldap_conn->handle, LDAP_OPT_RESULT_CODE, &ldap_errno);
- REDEBUG("Failed retrieving entry: %s",
- ldap_err2string(ldap_errno));
-
- goto finish;
- }
-
- dn = ldap_get_dn(query->ldap_conn->handle, entry);
- if (!dn) {
- ldap_get_option(query->ldap_conn->handle, LDAP_OPT_RESULT_CODE, &ldap_errno);
- REDEBUG("Retrieving object DN from entry failed: %s", ldap_err2string(ldap_errno));
-
- goto finish;
- }
- fr_ldap_util_normalise_dn(dn, dn);
-
- RDEBUG2("User object found at DN \"%s\"", dn);
-
- MEM(pair_update_control(&vp, attr_ldap_userdn) >= 0);
- fr_pair_value_strdup(vp, dn, false);
- if (handle) *handle = query->ldap_conn->handle;
-
- ldap_memfree(dn);
-
-finish:
- /*
- * Actual freeing of the result is handled by the query destructor
- */
- if ((freeit || (*rcode != RLM_MODULE_OK)) && *result) *result = NULL;
-
- return vp ? vp->vp_strvalue : NULL;
-}
-
/** Check for presence of access attribute in result
*
* @param[in] inst rlm_ldap configuration.