The FreeRADIUS server $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
Loading...
Searching...
No Matches
base.c
Go to the documentation of this file.
1/*
2 * This program is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License as published by
4 * the Free Software Foundation; either version 2 of the License, or (at
5 * your option) any later version.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
15 */
16
17/**
18 * $Id: be69499968def75bba2b03a7def646153d2fec00 $
19 * @file lib/ldap/base.c
20 * @brief LDAP module library functions.
21 *
22 * @author Arran Cudbard-Bell (a.cudbardb@freeradius.org)
23 * @copyright 2015 Arran Cudbard-Bell (a.cudbardb@freeradius.org)
24 * @copyright 2013-2015 Network RADIUS SAS (legal@networkradius.com)
25 * @copyright 2013-2015 The FreeRADIUS Server Project.
26 */
27RCSID("$Id: be69499968def75bba2b03a7def646153d2fec00 $")
28
30
31#include <freeradius-devel/util/debug.h>
32
33#define LOG_PREFIX handle_config->name
34
35#include <freeradius-devel/server/base.h>
36#include <freeradius-devel/ldap/base.h>
37
38LDAP *ldap_global_handle; //!< Hack for OpenLDAP libldap global initialisation.
39
40static _Thread_local LDAP *ldap_thread_local_handle; //!< Hack for functions which require an ldap handle
41 ///< but don't actually use it for anything.
42
43/** Used to set the global log prefix for functions which don't operate on connections
44 *
45 */
47 .name = "global"
48};
49
51 { L("bind"), FR_LDAP_STATE_BIND },
52 { L("error"), FR_LDAP_STATE_ERROR },
53 { L("init"), FR_LDAP_STATE_INIT },
54 { L("run"), FR_LDAP_STATE_RUN },
55 { L("start-tls"), FR_LDAP_STATE_START_TLS }
56};
58
60 { L("bindname"), LDAP_EXT_BINDNAME },
61 { L("x-bindpw"), LDAP_EXT_BINDPW }
62};
64
65/*
66 * Scopes
67 */
69 { L("base"), LDAP_SCOPE_BASE },
70 { L("children"), LDAP_SCOPE_CHILDREN },
71 { L("one"), LDAP_SCOPE_ONE },
72 { L("sub"), LDAP_SCOPE_SUB }
73};
75
77 { L("allow"), LDAP_OPT_X_TLS_ALLOW },
78 { L("demand"), LDAP_OPT_X_TLS_DEMAND },
79 { L("hard"), LDAP_OPT_X_TLS_HARD },
80 { L("never"), LDAP_OPT_X_TLS_NEVER },
81 { L("try"), LDAP_OPT_X_TLS_TRY }
82};
84
86 { L("always"), LDAP_DEREF_ALWAYS },
87 { L("finding"), LDAP_DEREF_FINDING },
88 { L("never"), LDAP_DEREF_NEVER },
89 { L("searching"), LDAP_DEREF_SEARCHING }
90};
92
94 .ldap_debug = 0x00,
95 .tls_random_file = ""
96};
97
99 { FR_CONF_OFFSET_FLAGS("random_file", CONF_FLAG_FILE_EXISTS, fr_libldap_global_config_t, tls_random_file) },
100 { FR_CONF_OFFSET("ldap_debug", fr_libldap_global_config_t, ldap_debug), .dflt = "0x0000" },
102};
103
104/** Initialise libldap library and set global options
105 *
106 * Used as a callback from global library initialisation.
107 */
108static int libldap_init(void)
109{
110 if (fr_ldap_init() < 0) return -1;
111
113
114 return 0;
115}
116
117/** Free any global libldap resources
118 *
119 */
120static void libldap_free(void)
121{
122 /*
123 * Keeping the dummy ld around for the lifetime
124 * of the module should always work,
125 * irrespective of what changes happen in libldap.
126 */
127 ldap_unbind_ext_s(ldap_global_handle, NULL, NULL);
128}
129
130/*
131 * Public symbol modules can reference to auto instantiate libldap
132 */
140
141typedef struct {
143 LDAPMessage **result;
145
146/** Prints information to the debug log on the current timeout settings
147 *
148 * There are so many different timers in LDAP it's often hard to debug
149 * issues with them, hence the need for this function.
150 */
152 fr_time_delta_t timeout, char const *prefix)
153{
154 struct timeval *net = NULL, *client = NULL;
155 int server = 0;
156 fr_ldap_config_t const *handle_config = conn->config;
157
158 if (request) RINDENT();
159
160 if (ldap_get_option(conn->handle, LDAP_OPT_NETWORK_TIMEOUT, &net) != LDAP_OPT_SUCCESS) {
161 ROPTIONAL(REDEBUG, ERROR, "Failed getting LDAP_OPT_NETWORK_TIMEOUT");
162 }
163
164 if (ldap_get_option(conn->handle, LDAP_OPT_TIMEOUT, &client) != LDAP_OPT_SUCCESS) {
165 ROPTIONAL(REDEBUG, ERROR, "Failed getting LDAP_OPT_TIMEOUT");
166 }
167
168 if (ldap_get_option(conn->handle, LDAP_OPT_TIMELIMIT, &server) != LDAP_OPT_SUCCESS) {
169 ROPTIONAL(REDEBUG, ERROR, "Failed getting LDAP_OPT_TIMELIMIT");
170 }
171
172 ROPTIONAL(RDEBUG4, DEBUG4, "%s: Timeout settings", prefix);
173
174 if (fr_time_delta_ispos(timeout)) {
175 ROPTIONAL(RDEBUG4, DEBUG4, "Client side result timeout (ovr): %pVs",
176 fr_box_time_delta(timeout));
177 } else {
178 ROPTIONAL(RDEBUG4, DEBUG4, "Client side result timeout (ovr): unset");
179 }
180
181 if (client && (client->tv_sec != -1)) {
182 ROPTIONAL(RDEBUG4, DEBUG4, "Client side result timeout (dfl): %pVs",
184
185 } else {
186 ROPTIONAL(RDEBUG4, DEBUG4, "Client side result timeout (dfl): unset");
187 }
188
189 if (net && (net->tv_sec != -1)) {
190 ROPTIONAL(RDEBUG4, DEBUG4, "Client side network I/O timeout : %pVs",
192 } else {
193 ROPTIONAL(RDEBUG4, DEBUG4, "Client side network I/O timeout : unset");
194
195 }
196
197 ROPTIONAL(RDEBUG4, DEBUG4, "Server side result timeout : %i", server);
198 if (request) REXDENT();
199
200 free(net);
201 free(client);
202}
203
204/** Return the error string associated with a handle
205 *
206 * @param conn to retrieve error from.
207 * @return error string.
208 */
210{
211 int lib_errno;
212 ldap_get_option(conn->handle, LDAP_OPT_RESULT_CODE, &lib_errno);
213 if (lib_errno == LDAP_SUCCESS) {
214 return "unknown";
215 }
216
217 return ldap_err2string(lib_errno);
218}
219
220/** Perform basic parsing of multiple types of messages, checking for error conditions
221 *
222 * @note Error messages should be retrieved with fr_strerror() and fr_strerror_pop()
223 *
224 * @param[out] ctrls Server ctrls returned to the client. May be NULL if not required.
225 * Must be freed with ldap_free_ctrls.
226 * @param[in] conn the message was received on.
227 * @param[in] msg we're parsing.
228 * @param[in] dn if processing the result from a search request.
229 * @return One of the LDAP_PROC_* (#fr_ldap_rcode_t) values.
230 */
231fr_ldap_rcode_t fr_ldap_error_check(LDAPControl ***ctrls, fr_ldap_connection_t const *conn, LDAPMessage *msg, char const *dn)
232{
234
235 int msg_type;
236 int lib_errno = LDAP_SUCCESS; /* errno returned by the library */
237 int srv_errno = LDAP_SUCCESS; /* errno in the result message */
238
239 char *part_dn = NULL; /* Partial DN match */
240 char *srv_err = NULL; /* Server's extended error message */
241
242 ssize_t len;
243
244 if (ctrls) *ctrls = NULL;
245
246 if (!msg) {
247 ldap_get_option(conn->handle, LDAP_OPT_RESULT_CODE, &lib_errno);
248 if (lib_errno != LDAP_SUCCESS) goto process_error;
249
250 fr_strerror_const("No result available");
251 return LDAP_PROC_NO_RESULT;
252 }
253
254 msg_type = ldap_msgtype(msg);
255 switch (msg_type) {
256 /*
257 * Parse the result and check for errors sent by the server
258 */
259 case LDAP_RES_SEARCH_RESULT: /* The result of a search */
260 case LDAP_RES_BIND: /* The result of a bind operation */
261 case LDAP_RES_EXTENDED:
262 case LDAP_RES_MODIFY:
263 lib_errno = ldap_parse_result(conn->handle, msg,
264 &srv_errno, &part_dn, &srv_err,
265 NULL, ctrls, 0);
266 break;
267
268 /*
269 * These are messages containing objects so unless they're
270 * malformed they can't contain errors.
271 */
272 case LDAP_RES_SEARCH_ENTRY:
273 if (ctrls) lib_errno = ldap_get_entry_controls(conn->handle, msg, ctrls);
274 break;
275
276 /*
277 * Retrieve the controls if the message is a reference message
278 */
279 case LDAP_RES_SEARCH_REFERENCE:
280 if (ctrls) lib_errno = ldap_parse_reference(conn->handle, msg, NULL, ctrls, 0);
281 break;
282
283 /*
284 * An intermediate message updating us on the result of an operation
285 */
286 case LDAP_RES_INTERMEDIATE:
287 lib_errno = ldap_parse_intermediate(conn->handle, msg, NULL, NULL, ctrls, 0);
288 break;
289
290 /*
291 * Can't extract any more useful information.
292 */
293 default:
294 return LDAP_PROC_SUCCESS;
295 }
296
297 /*
298 * Stupid messy API
299 */
300 if (lib_errno != LDAP_SUCCESS) {
301 fr_assert(!ctrls || !*ctrls);
302 ldap_get_option(conn->handle, LDAP_OPT_RESULT_CODE, &lib_errno);
303 }
304
305process_error:
306 if ((lib_errno == LDAP_SUCCESS) && (srv_errno != LDAP_SUCCESS)) {
307 lib_errno = srv_errno;
308 } else if ((lib_errno != LDAP_SUCCESS) && (srv_errno == LDAP_SUCCESS)) {
309 srv_errno = lib_errno;
310 }
311
312 switch (lib_errno) {
313 case LDAP_SUCCESS:
314 fr_strerror_const("Success");
315 break;
316
317 case LDAP_REFERRAL:
318 fr_strerror_const("Referral");
319 status = LDAP_PROC_REFERRAL;
320 break;
321
322 case LDAP_SASL_BIND_IN_PROGRESS:
323 fr_strerror_const("Continuing");
324 status = LDAP_PROC_CONTINUE;
325 break;
326
327 case LDAP_NO_SUCH_OBJECT:
328 fr_strerror_const("The specified DN wasn't found");
329 status = LDAP_PROC_BAD_DN;
330
331 /*
332 * Build our own internal diagnostic string
333 */
334 if (dn && part_dn) {
335 char *spaces;
336 char *text;
337
338 len = fr_ldap_common_dn(dn, part_dn);
339 if (len < 0) break;
340
341 fr_canonicalize_error(NULL, &spaces, &text, -len, dn);
342 fr_strerror_printf_push("%s", text);
343 fr_strerror_printf_push("%s^ %s", spaces, "match stopped here");
344
346 talloc_free(text);
347 }
348 goto error_string;
349
350 case LDAP_INSUFFICIENT_ACCESS:
351 fr_strerror_const("Insufficient access. Check the identity and password configuration directives");
353 break;
354
355 case LDAP_UNWILLING_TO_PERFORM:
356 fr_strerror_const("Server was unwilling to perform");
358 break;
359
360 case LDAP_FILTER_ERROR:
361 fr_strerror_const("Bad search filter");
362 status = LDAP_PROC_ERROR;
363 break;
364
365 case LDAP_TIMEOUT:
366 fr_strerror_const("Timed out while waiting for server to respond");
367 status = LDAP_PROC_TIMEOUT;
368 break;
369
370 case LDAP_TIMELIMIT_EXCEEDED:
371 fr_strerror_const("Time limit exceeded");
372 status = LDAP_PROC_TIMEOUT;
373 break;
374
375 case LDAP_SYNC_REFRESH_REQUIRED:
376 fr_strerror_const("Refresh required");
378 break;
379
380 case LDAP_BUSY:
381 case LDAP_UNAVAILABLE:
382 case LDAP_SERVER_DOWN:
383 status = LDAP_PROC_BAD_CONN;
384 goto error_string;
385
386 case LDAP_INVALID_CREDENTIALS:
387 case LDAP_CONSTRAINT_VIOLATION:
388 status = LDAP_PROC_REJECT;
389 goto error_string;
390
391 case LDAP_OPERATIONS_ERROR:
392 fr_strerror_printf("Please set 'chase_referrals=yes' and 'rebind=yes'. "
393 "See the ldap module configuration for details");
395
396 default:
397 status = LDAP_PROC_ERROR;
398
399 error_string:
400 if (lib_errno == srv_errno) {
401 fr_strerror_printf("lib error: %s (%u)", ldap_err2string(lib_errno), lib_errno);
402 } else {
403 fr_strerror_printf("lib error: %s (%u), srv error: %s (%u)",
404 ldap_err2string(lib_errno), lib_errno,
405 ldap_err2string(srv_errno), srv_errno);
406 }
407
408 if (srv_err) fr_strerror_printf_push("Server said: %s", srv_err);
409
410 break;
411 }
412
413 /*
414 * Cleanup memory
415 */
416 if (srv_err) ldap_memfree(srv_err);
417 if (part_dn) ldap_memfree(part_dn);
418
419 return status;
420}
421
422/** Parse response from LDAP server dealing with any errors
423 *
424 * Should be called after an LDAP operation. Will check result of operation and if
425 * it was successful, then attempt to retrieve and parse the result. Will also produce
426 * extended error output including any messages the server sent, and information about
427 * partial DN matches.
428 *
429 * @note Error messages should be retrieved with fr_strerror() and fr_strerror_pop()
430 *
431 * @param[out] result Where to write result, if NULL result will be freed. If not NULL caller
432 * must free with ldap_msgfree().
433 * @param[out] ctrls Server ctrls returned to the client. May be NULL if not required.
434 * Must be freed with ldap_free_ctrls.
435 * @param[in] conn Current connection.
436 * @param[in] msgid returned from last operation.
437 * Special values are:
438 * - LDAP_RES_ANY - Retrieve any received messages useful for multiplexing.
439 * - LDAP_RES_UNSOLICITED - Any unsolicited message.
440 * @param[in] all How many messages to retrieve:
441 * - LDAP_MSG_ONE - Retrieve the first message matching msgid (waiting if one is not available).
442 * - LDAP_MSG_ALL - Retrieve all received messages matching msgid (waiting if none are available).
443 * - LDAP_MSG_RECEIVED - Retrieve all received messages.
444 * @param[in] dn Last search or bind DN. May be NULL.
445 * @param[in] timeout Override the default result timeout.
446 *
447 * @return One of the LDAP_PROC_* (#fr_ldap_rcode_t) values.
448 */
449fr_ldap_rcode_t fr_ldap_result(LDAPMessage **result, LDAPControl ***ctrls,
450 fr_ldap_connection_t const *conn, int msgid, int all,
451 char const *dn,
452 fr_time_delta_t timeout)
453{
455 int lib_errno;
456 fr_time_delta_t our_timeout = timeout;
457
458 LDAPMessage *tmp_msg = NULL, *msg; /* Temporary message pointer storage if we weren't provided with one */
459 LDAPMessage **result_p = result;
460
461 if (result) *result = NULL;
462 if (ctrls) *ctrls = NULL;
463
464 /*
465 * We always need the result, but our caller may not
466 */
467 if (!result) result_p = &tmp_msg;
468
469 /*
470 * Check if there was an error sending the request
471 */
472 ldap_get_option(conn->handle, LDAP_OPT_RESULT_CODE, &lib_errno);
473 if (lib_errno != LDAP_SUCCESS) return fr_ldap_error_check(NULL, conn, NULL, dn);
474
475 if (!fr_time_delta_ispos(timeout)) our_timeout = conn->config->res_timeout;
476
477 /*
478 * Now retrieve the result and check for errors
479 * ldap_result returns -1 on failure, and 0 on timeout
480 */
481 lib_errno = ldap_result(conn->handle, msgid, all, &fr_time_delta_to_timeval(our_timeout), result_p);
482 switch (lib_errno) {
483 case 0:
484 lib_errno = LDAP_TIMEOUT;
485 fr_strerror_const("timeout waiting for result");
486 return LDAP_PROC_TIMEOUT;
487
488 case -1:
489 return fr_ldap_error_check(NULL, conn, NULL, dn);
490
491 default:
492 break;
493 }
494
495 for (msg = ldap_first_message(conn->handle, *result_p);
496 msg;
497 msg = ldap_next_message(conn->handle, msg)) {
498 status = fr_ldap_error_check(ctrls, conn, msg, dn);
499 if (status != LDAP_PROC_SUCCESS) break;
500 }
501
502 if (*result_p && (!result)) {
503 ldap_msgfree(*result_p);
504 *result_p = NULL;
505 }
506
507 return status;
508}
509
510/** Search for something in the LDAP directory
511 *
512 * Performs an LDAP search, typically on a connection bound as the
513 * administrative user, dealing with any errors.
514 * Called from the trunk mux function and elsewhere where appropriate
515 * event handlers have been set on the connection fd.
516 *
517 * @param[out] msgid to match response to request.
518 * @param[in] request Current request.
519 * @param[in] pconn to use.
520 * @param[in] dn to use as base for the search.
521 * @param[in] scope to use (LDAP_SCOPE_BASE, LDAP_SCOPE_ONE, LDAP_SCOPE_SUB).
522 * @param[in] filter to use, should be pre-escaped.
523 * @param[in] attrs to retrieve.
524 * @param[in] serverctrls Search controls to pass to the server. May be NULL.
525 * @param[in] clientctrls Search controls for ldap_search. May be NULL.
526 * @return One of the LDAP_PROC_* (#fr_ldap_rcode_t) values.
527 */
530 char const *dn, int scope, char const *filter, char const * const *attrs,
531 LDAPControl **serverctrls, LDAPControl **clientctrls)
532{
533 fr_ldap_config_t const *handle_config = pconn->config;
534
535 LDAPControl *our_serverctrls[LDAP_MAX_CONTROLS];
536 LDAPControl *our_clientctrls[LDAP_MAX_CONTROLS];
537
538 char **search_attrs;
539
540 fr_ldap_control_merge(our_serverctrls, our_clientctrls,
541 NUM_ELEMENTS(our_serverctrls),
542 NUM_ELEMENTS(our_clientctrls),
543 pconn, serverctrls, clientctrls);
544
545 fr_assert(pconn && pconn->handle);
546
547 if (DEBUG_ENABLED4 || (request && RDEBUG_ENABLED4)) {
548 fr_ldap_timeout_debug(request, pconn, fr_time_delta_wrap(0), __FUNCTION__);
549 }
550
551 /*
552 * OpenLDAP library doesn't declare attrs array as const, but
553 * it really should be *sigh*.
554 */
555 memcpy(&search_attrs, &attrs, sizeof(attrs));
556
557 if ((request && RDEBUG_ENABLED2) || DEBUG_ENABLED2) {
558 fr_sbuff_t *log_msg;
559
560 FR_SBUFF_TALLOC_THREAD_LOCAL(&log_msg, 128, SIZE_MAX);
561
562 (void) fr_sbuff_in_sprintf(log_msg, "Performing search in \"%s\"", dn);
563 if (filter) {
564 (void) fr_sbuff_in_sprintf(log_msg, " with filter \"%s\"", filter);
565 } else {
566 (void) fr_sbuff_in_strcpy_literal(log_msg, " with no filter");
567 }
568 (void) fr_sbuff_in_sprintf(log_msg, ", scope \"%s\"",
569 fr_table_str_by_value(fr_ldap_scope, scope, "<INVALID>"));
570 if (attrs) {
571 (void) fr_sbuff_in_strcpy(log_msg, ", attrs ");
572 (void) fr_sbuff_in_array(log_msg, attrs, ", ");
573 }
574 ROPTIONAL(RDEBUG2, DEBUG2, "%s", fr_sbuff_start(log_msg));
575 }
576
577 if (ldap_search_ext(pconn->handle, dn, scope, filter, search_attrs,
578 0, our_serverctrls, our_clientctrls, NULL, 0, msgid) != LDAP_SUCCESS) {
579 fr_ldap_rcode_t ret = fr_ldap_error_check(NULL, pconn, NULL, NULL);
580 ROPTIONAL(RPERROR, PERROR, "Failed performing search");
581 return ret;
582 }
583
584 return LDAP_PROC_SUCCESS;
585}
586
588{
589 LDAP *ld = query->ldap_conn->handle;
590 LDAPMessage *message;
591 char const * const *attr;
592 char *dn;
593 struct berval **values;
594 int count;
595
596 count = ldap_count_entries(ld, query->result);
597 RDEBUG3("LDAP query returned %d entr%s", count, count > 1 ? "y" : "ies");
598 message = ldap_first_entry(ld, query->result);
599 RINDENT();
600 while (message) {
601 dn = ldap_get_dn(ld, message);
602 RDEBUG3("Entry DN %s", dn);
603 ldap_memfree(dn);
604 attr = query->search.attrs;
605 if (!attr) goto next;
606 RINDENT();
607 while(*attr) {
608 values = ldap_get_values_len(ld, message, *attr);
609 if (!values) {
610 RDEBUG3("Attribute \"%s\" not found", *attr);
611 } else {
612 count = ldap_count_values_len(values);
613 RDEBUG3("Attribute \"%s\" found %d time%s", *attr, count, count > 1 ? "s" : "");
614 }
615 ldap_value_free_len(values);
616 attr++;
617 }
618 REXDENT();
619 next:
620 message = ldap_next_entry(query->ldap_conn->handle, message);
621 }
622 REXDENT();
623}
624
625/** Handle the return code from parsed LDAP results to set the module rcode
626 *
627 * @note This function sets no rcode, the result of query is available in query->ret.
628 */
630{
631 fr_ldap_query_t *query = talloc_get_type_abort(uctx, fr_ldap_query_t);
632
633 switch (query->ret) {
635 /* The query we want hasn't returned yet */
636 return UNLANG_ACTION_YIELD;
637
641
642 default:
643 return UNLANG_ACTION_CALCULATE_RESULT; /* result is actually discarded, all callers should use query->ret */
644 }
645}
646
647/** Signal an LDAP query running on a trunk connection to cancel
648 *
649 */
650static void ldap_trunk_query_cancel(UNUSED request_t *request, UNUSED fr_signal_t action, void *uctx)
651{
652 fr_ldap_query_t *query = talloc_get_type_abort(uctx, fr_ldap_query_t);
653
654 /*
655 * Query may have completed, but the request
656 * not yet have been resumed.
657 */
658 if (!query->treq) return;
659
660 /*
661 * Depending on the state of the trunk request, the query needs to
662 * be parented by the treq so that it still exists when the
663 * cancel_mux callback is run.
664 * Other states free the trunk request (and its children) immediately.
665 * So no re-parenting is needed.
666 */
667 switch (query->treq->state) {
674 talloc_steal(query->treq, query);
675 break;
676 default:
677 break;
678 }
679
681
682 /*
683 * Once we've called cancel, the treq is no
684 * longer ours to manipulate, it belongs to
685 * the trunk code.
686 */
687 query->treq = NULL;
688}
689
690#define SET_LDAP_CTRLS(_dest, _src) \
691do { \
692 int i; \
693 if (!_src) break; \
694 for (i = 0; i < LDAP_MAX_CONTROLS; i++) { \
695 if (!(_src[i])) break; \
696 _dest[i].control = _src[i]; \
697 } \
698} while (0)
699
700/** Run an async search LDAP query on a trunk connection
701 *
702 * @param[in] ctx to allocate the query in.
703 * @param[out] out Query that has been allocated.
704 * Result is available in (*out)->ret.
705 * @param[in] request this query relates to.
706 * @param[in] ttrunk to submit the query to.
707 * @param[in] base_dn for the search.
708 * @param[in] scope of the search.
709 * @param[in] filter for the search.
710 * @param[in] attrs to be returned.
711 * @param[in] serverctrls specific to this query.
712 * @param[in] clientctrls specific to this query.
713 * @return
714 * - UNLANG_ACTION_FAIL on error.
715 * - UNLANG_ACTION_PUSHED_CHILD on success.
716 */
719 request_t *request, fr_ldap_thread_trunk_t *ttrunk,
720 char const *base_dn, int scope, char const *filter, char const * const *attrs,
721 LDAPControl **serverctrls, LDAPControl **clientctrls)
722{
723 unlang_action_t action;
724 fr_ldap_query_t *query;
725
726 query = fr_ldap_search_alloc(ctx, base_dn, scope, filter, attrs, serverctrls, clientctrls);
727
728 switch (trunk_request_enqueue(&query->treq, ttrunk->trunk, request, query, NULL)) {
729 case TRUNK_ENQUEUE_OK:
731 break;
732
733 default:
734 error:
735 *out = NULL;
736 talloc_free(query);
737 return UNLANG_ACTION_FAIL;
738 }
739
740 action = unlang_function_push(request,
741 NULL,
745 query);
746
747 if (action == UNLANG_ACTION_FAIL) goto error;
748
749 *out = query;
750
752}
753
754/** Run an async modification LDAP query on a trunk connection
755 *
756 * @param[in] ctx to allocate the query in.
757 * @param[out] out Query that has been allocated.
758 * Result is available in (*out)->ret.
759 * @param[in] request this query relates to.
760 * @param[in] ttrunk to submit the query to.
761 * @param[in] dn of the object being modified.
762 * @param[in] mods to be performed.
763 * @param[in] serverctrls specific to this query.
764 * @param[in] clientctrls specific to this query.
765 * @return
766 * - UNLANG_ACTION_FAIL on error.
767 * - UNLANG_ACTION_PUSHED_CHILD on success.
768 */
771 char const *dn, LDAPMod *mods[],
772 LDAPControl **serverctrls, LDAPControl **clientctrls)
773{
774 unlang_action_t action;
775 fr_ldap_query_t *query;
776
777 query = fr_ldap_modify_alloc(ctx, dn, mods, serverctrls, clientctrls);
778
779 switch (trunk_request_enqueue(&query->treq, ttrunk->trunk, request, query, NULL)) {
780 case TRUNK_ENQUEUE_OK:
782 break;
783
784 default:
785 error:
786 *out = NULL;
787 talloc_free(query);
788 return UNLANG_ACTION_FAIL;
789 }
790
791 action = unlang_function_push(request,
792 NULL,
796 query);
797
798 if (action == UNLANG_ACTION_FAIL) goto error;
799
800 *out = query;
801
803}
804
805/** Modify something in the LDAP directory
806 *
807 * Used on connections bound as the administrative user to attempt to modify an LDAP object.
808 * Called by the trunk mux function
809 *
810 * @param[out] msgid LDAP message ID.
811 * @param[in] request Current request.
812 * @param[in] pconn to use.
813 * @param[in] dn of the object to modify.
814 * @param[in] mods to make, see 'man ldap_modify' for more information.
815 * @param[in] serverctrls Search controls to pass to the server. May be NULL.
816 * @param[in] clientctrls Search controls for ldap_modify. May be NULL.
817 * @return One of the LDAP_PROC_* (#fr_ldap_rcode_t) values.
818 */
820 char const *dn, LDAPMod *mods[],
821 LDAPControl **serverctrls, LDAPControl **clientctrls)
822{
823 LDAPControl *our_serverctrls[LDAP_MAX_CONTROLS];
824 LDAPControl *our_clientctrls[LDAP_MAX_CONTROLS];
825
826 fr_ldap_control_merge(our_serverctrls, our_clientctrls,
827 NUM_ELEMENTS(our_serverctrls),
828 NUM_ELEMENTS(our_clientctrls),
829 pconn, serverctrls, clientctrls);
830
831 fr_assert(pconn && pconn->handle);
832
833 if (RDEBUG_ENABLED4) fr_ldap_timeout_debug(request, pconn, fr_time_delta_wrap(0), __FUNCTION__);
834
835 RDEBUG2("Modifying object with DN \"%s\"", dn);
836 if(ldap_modify_ext(pconn->handle, dn, mods, our_serverctrls, our_clientctrls, msgid) != LDAP_SUCCESS) {
837 fr_ldap_rcode_t ret = fr_ldap_error_check(NULL, pconn, NULL, NULL);
838 ROPTIONAL(RPEDEBUG, RPERROR, "Failed sending request to modify object");
839
840 return ret;
841 }
842
843 return LDAP_PROC_SUCCESS;
844}
845
846/** Modify something in the LDAP directory
847 *
848 * Used on connections bound as the administrative user to attempt to modify an LDAP object.
849 * Called by the trunk mux function
850 *
851 * @param[out] msgid LDAP message ID.
852 * @param[in] request Current request.
853 * @param[in] pconn to use.
854 * @param[in] dn of the object to delete.
855 * @param[in] serverctrls Search controls to pass to the server. May be NULL.
856 * @param[in] clientctrls Search controls for ldap_delete. May be NULL.
857 * @return One of the LDAP_PROC_* (#fr_ldap_rcode_t) values.
858 */
860 char const *dn,
861 LDAPControl **serverctrls, LDAPControl **clientctrls)
862{
863 LDAPControl *our_serverctrls[LDAP_MAX_CONTROLS];
864 LDAPControl *our_clientctrls[LDAP_MAX_CONTROLS];
865
866 fr_ldap_control_merge(our_serverctrls, our_clientctrls,
867 NUM_ELEMENTS(our_serverctrls),
868 NUM_ELEMENTS(our_clientctrls),
869 pconn, serverctrls, clientctrls);
870
871 fr_assert(pconn && pconn->handle);
872
873 if (RDEBUG_ENABLED4) fr_ldap_timeout_debug(request, pconn, fr_time_delta_wrap(0), __FUNCTION__);
874
875 RDEBUG2("Deleting object with DN \"%s\"", dn);
876 if(ldap_delete_ext(pconn->handle, dn, our_serverctrls, our_clientctrls, msgid) != LDAP_SUCCESS) {
877 fr_ldap_rcode_t ret = fr_ldap_error_check(NULL, pconn, NULL, NULL);
878 ROPTIONAL(RPEDEBUG, RPERROR, "Failed sending request to delete object");
879
880 return ret;
881 }
882
883 return LDAP_PROC_SUCCESS;
884}
885
886/** Run an async LDAP "extended operation" query on a trunk connection
887 *
888 * @param[in] ctx to allocate the query in.
889 * @param[out] out that has been allocated.
890 * Result is available in (*out)->ret.
891 * @param[in] request this query relates to.
892 * @param[in] ttrunk to submit the query to.
893 * @param[in] reqoid OID of extended operation.
894 * @param[in] reqdata Request data to send.
895 * @param[in] serverctrls specific to this query.
896 * @param[in] clientctrls specific to this query.
897 * @return
898 * - UNLANG_ACTION_FAIL on error.
899 * - UNLANG_ACTION_PUSHED_CHILD on success.
900 */
903 char const *reqoid, struct berval *reqdata,
904 LDAPControl **serverctrls, LDAPControl **clientctrls)
905{
906 unlang_action_t action;
907 fr_ldap_query_t *query;
908
909 query = fr_ldap_extended_alloc(ctx, reqoid, reqdata, serverctrls, clientctrls);
910
911 switch (trunk_request_enqueue(&query->treq, ttrunk->trunk, request, query, NULL)) {
912 case TRUNK_ENQUEUE_OK:
914 break;
915
916 default:
917 error:
918 *out = NULL;
919 talloc_free(query);
920 return UNLANG_ACTION_FAIL;
921 }
922
923 action = unlang_function_push(request,
924 NULL,
928 query);
929
930 if (action == UNLANG_ACTION_FAIL) goto error;
931
932 *out = query;
933
935}
936
937/** Initiate an LDAP extended operation
938 *
939 * Called by the trunk mux function
940 *
941 * @param[out] msgid LDAP message ID.
942 * @param[in] request Current request.
943 * @param[in] pconn to use.
944 * @param[in] reqoid OID of extended operation to perform.
945 * @param[in] reqdata Data required for the request.
946 * @return One of the LDAP_PROC_* (#fr_ldap_rcode_t) values.
947 */
949 char const *reqoid, struct berval *reqdata)
950{
951 fr_assert(pconn && pconn->handle);
952
953 RDEBUG2("Requesting extended operation with OID %s", reqoid);
954 if (ldap_extended_operation(pconn->handle, reqoid, reqdata, NULL, NULL, msgid)) {
955 fr_ldap_rcode_t ret = fr_ldap_error_check(NULL, pconn, NULL, NULL);
956 RPERROR("Failed requesting extended operation");
957 return ret;
958 }
959 return LDAP_PROC_SUCCESS;
960}
961
962/** Free any libldap structures when an fr_ldap_query_t is freed
963 *
964 * It is also possible that the connection used for this query is now closed,
965 * in that instance we free it here.
966 */
968{
969 int i;
970
971 /*
972 * Free any results which were retrieved
973 */
974 if (query->result) ldap_msgfree(query->result);
975
976 /*
977 * Free any server and client controls that need freeing
978 */
979 for (i = 0; i < LDAP_MAX_CONTROLS; i++) {
980 if (!query->serverctrls[i].control) break;
981 if (query->serverctrls[i].freeit) ldap_control_free(query->serverctrls[i].control);
982 }
983
984 for (i = 0; i < LDAP_MAX_CONTROLS; i++) {
985 if (!query->clientctrls[i].control) break;
986 if (query->clientctrls[i].freeit) ldap_control_free(query->clientctrls[i].control);
987 }
988
989 /*
990 * If a URL was parsed, free it.
991 */
992 if (query->ldap_url) ldap_free_urldesc(query->ldap_url);
993
994 /*
995 * If any referrals were followed, the parsed referral URLS should be freed
996 */
997 if (query->referral_urls) ldap_memvfree((void **)query->referral_urls);
998
1000
1001 if (query->ldap_conn) {
1002 /*
1003 * Remove the query from the list of references to its connection
1004 */
1005 fr_dlist_remove(&query->ldap_conn->refs, query);
1006
1007 /*
1008 * If the connection this query was using has no pending queries and
1009 * is no-longer associated with a connection_t then free it
1010 */
1011 if (!query->ldap_conn->conn && (fr_dlist_num_elements(&query->ldap_conn->refs) == 0) &&
1012 (fr_rb_num_elements(query->ldap_conn->queries) == 0)) talloc_free(query->ldap_conn);
1013 }
1014
1015 /*
1016 * Ensure the request data for extended operations are freed.
1017 */
1018 if (query->type == LDAP_REQUEST_EXTENDED && query->extended.reqdata) ber_bvfree(query->extended.reqdata);
1019
1020 return 0;
1021}
1022
1023/** Allocate an fr_ldap_query_t, setting the talloc destructor
1024 *
1025 */
1026static inline CC_HINT(always_inline)
1028{
1029 fr_ldap_query_t *query;
1030
1031 MEM(query = talloc_zero(ctx, fr_ldap_query_t));
1032 talloc_set_destructor(query, _ldap_query_free);
1033
1034 query->ret = LDAP_RESULT_PENDING;
1035 query->type = type;
1036
1037 return query;
1038}
1039
1040/** Allocate a new search object
1041 *
1042 * @param[in] ctx to allocate query in.
1043 * @param[in] base_dn for the search.
1044 * @param[in] scope of the search.
1045 * @param[in] filter for the search
1046 * @param[in] attrs to request.
1047 * @param[in] serverctrls Search controls to pass to the server. May be NULL.
1048 * @param[in] clientctrls Client controls. May be NULL.
1049 */
1051 char const *base_dn, int scope, char const *filter, char const * const * attrs,
1052 LDAPControl **serverctrls, LDAPControl **clientctrls)
1053{
1054 fr_ldap_query_t *query;
1055
1057 query->dn = base_dn;
1058 query->search.scope = scope;
1059 query->search.filter = filter;
1060 query->search.attrs = UNCONST(char const **, attrs);
1061 SET_LDAP_CTRLS(query->serverctrls, serverctrls);
1062 SET_LDAP_CTRLS(query->clientctrls, clientctrls);
1063
1064 return query;
1065}
1066
1067/** Allocate a new LDAP modify object
1068 *
1069 * @param[in] ctx to allocate the query in.
1070 * @param[in] dn of the object to modify.
1071 * @param[in] mods to apply to the object.
1072 * @param[in] serverctrls Controls to pass to the server. May be NULL.
1073 * @param[in] clientctrls Client controls. May be NULL.
1074 * @return LDAP query object
1075 */
1076fr_ldap_query_t *fr_ldap_modify_alloc(TALLOC_CTX *ctx, char const *dn,
1077 LDAPMod *mods[], LDAPControl **serverctrls, LDAPControl **clientctrls)
1078{
1079 fr_ldap_query_t *query;
1080
1082 query->dn = dn;
1083 query->mods = mods;
1084 SET_LDAP_CTRLS(query->serverctrls, serverctrls);
1085 SET_LDAP_CTRLS(query->clientctrls, clientctrls);
1086
1087 return query;
1088}
1089
1090/** Allocate a new LDAP extended operations object
1091 *
1092 * @param[in] ctx to allocate the query in.
1093 * @param[in] reqoid OID of extended operation to perform.
1094 * @param[in] reqdata Request data to send.
1095 * @param[in] serverctrls Controls to pass to the server. May be NULL.
1096 * @param[in] clientctrls Client controls. May be NULL.
1097 * @return LDAP query object
1098 */
1099fr_ldap_query_t *fr_ldap_extended_alloc(TALLOC_CTX *ctx, char const *reqoid, struct berval *reqdata,
1100 LDAPControl **serverctrls, LDAPControl **clientctrls)
1101{
1102 fr_ldap_query_t *query;
1103
1105 query->extended.reqoid = reqoid;
1106 query->extended.reqdata = reqdata;
1107 SET_LDAP_CTRLS(query->serverctrls, serverctrls);
1108 SET_LDAP_CTRLS(query->clientctrls, clientctrls);
1109
1110 return (query);
1111}
1112
1113static int _ldap_handle_thread_local_free(void *handle)
1114{
1115 if (ldap_unbind_ext_s(handle, NULL, NULL) < 0) return -1;
1116 return 0;
1117}
1118
1119/** Get a thread local dummy LDAP handle
1120 *
1121 * Many functions in the OpenLDAP API don't actually use the handle
1122 * for anything other than writing out error codes.
1123 *
1124 * This is true for most of the LDAP extensions API functions.
1125 *
1126 * This gives us a reusable handle that was can pass to those
1127 * functions when we don't already have one available.
1128 */
1130{
1132 LDAP *handle;
1133
1134 MEM(ldap_initialize(&ldap_thread_local_handle, "") == LDAP_SUCCESS);
1135 handle = ldap_thread_local_handle;
1136
1138 }
1139
1141}
1142
1143/** Change settings global to libldap
1144 *
1145 * May only be called once. Subsequent calls will be ignored.
1146 *
1147 * @param[in] debug_level to enable in libldap.
1148 * @param[in] tls_random_file Where OpenSSL gets its randomness.
1149 */
1150int fr_ldap_global_config(int debug_level, char const *tls_random_file)
1151{
1152 static bool done_config;
1154
1155 if (done_config) return 0;
1156
1157#define do_ldap_global_option(_option, _name, _value) \
1158 if (ldap_set_option(NULL, _option, _value) != LDAP_OPT_SUCCESS) do { \
1159 int _ldap_errno; \
1160 ldap_get_option(NULL, LDAP_OPT_RESULT_CODE, &_ldap_errno); \
1161 ERROR("Failed setting global option %s: %s", _name, \
1162 (_ldap_errno != LDAP_SUCCESS) ? ldap_err2string(_ldap_errno) : "Unknown error"); \
1163 return -1;\
1164 } while (0)
1165
1166#define maybe_ldap_global_option(_option, _name, _value) \
1167 if (_value) do_ldap_global_option(_option, _name, _value)
1168
1169 if (debug_level) do_ldap_global_option(LDAP_OPT_DEBUG_LEVEL, "ldap_debug", &debug_level);
1170
1171 /*
1172 * OpenLDAP will error out if we attempt to set
1173 * this on a handle. Presumably it's global in
1174 * OpenSSL too.
1175 */
1176 maybe_ldap_global_option(LDAP_OPT_X_TLS_RANDOM_FILE, "random_file", tls_random_file);
1177
1178 done_config = true;
1179
1180 return 0;
1181}
1182
1183/** Initialise libldap and check library versions
1184 *
1185 * @return
1186 * - 0 on success.
1187 * - -1 on failure.
1188 */
1190{
1191 int ldap_errno;
1192 static LDAPAPIInfo info = { .ldapai_info_version = LDAP_API_INFO_VERSION }; /* static to quiet valgrind about this being uninitialised */
1194
1195 /*
1196 * Only needs to be done once, prevents races in environment
1197 * initialisation within libldap.
1198 *
1199 * See: https://github.com/arr2036/ldapperf/issues/2
1200 */
1201 if (ldap_initialize(&ldap_global_handle, "") != LDAP_SUCCESS) {
1202 ERROR("Failed initialising global LDAP handle");
1203 return -1;
1204 }
1205
1206 ldap_errno = ldap_get_option(NULL, LDAP_OPT_API_INFO, &info);
1207 if (ldap_errno == LDAP_OPT_SUCCESS) {
1208 /*
1209 * Don't generate warnings if the compile type vendor name
1210 * is found within the link time vendor name.
1211 *
1212 * This allows the server to be built against OpenLDAP but
1213 * run with Symas OpenLDAP.
1214 */
1215 if (strcasestr(info.ldapai_vendor_name, LDAP_VENDOR_NAME) == NULL) {
1216 WARN("ldap - libldap vendor changed since the server was built");
1217 WARN("ldap - linked: %s, built: %s", info.ldapai_vendor_name, LDAP_VENDOR_NAME);
1218 }
1219
1220 if (info.ldapai_vendor_version < LDAP_VENDOR_VERSION) {
1221 WARN("ldap - libldap older than the version the server was built against");
1222 WARN("ldap - linked: %i, built: %i",
1223 info.ldapai_vendor_version, LDAP_VENDOR_VERSION);
1224 }
1225
1226 INFO("ldap - libldap vendor: %s, version: %i", info.ldapai_vendor_name,
1227 info.ldapai_vendor_version);
1228
1229 if (info.ldapai_extensions) {
1230 char **p;
1231
1232 for (p = info.ldapai_extensions; *p != NULL; p++) {
1233 INFO("ldap - extension: %s", *p);
1234 ldap_memfree(*p);
1235 }
1236
1237 ldap_memfree(info.ldapai_extensions);
1238 }
1239
1240 ldap_memfree(info.ldapai_vendor_name);
1241
1242 } else {
1243 DEBUG("ldap - Falling back to build time libldap version info. Query for LDAP_OPT_API_INFO "
1244 "returned: %i", ldap_errno);
1245 INFO("ldap - libldap vendor: %s, version: %i.%i.%i", LDAP_VENDOR_NAME,
1246 LDAP_VENDOR_VERSION_MAJOR, LDAP_VENDOR_VERSION_MINOR, LDAP_VENDOR_VERSION_PATCH);
1247 }
1248
1249 return 0;
1250}
unlang_action_t
Returned by unlang_op_t calls, determine the next action of the interpreter.
Definition action.h:35
@ UNLANG_ACTION_PUSHED_CHILD
unlang_t pushed a new child onto the stack, execute it instead of continuing.
Definition action.h:39
@ UNLANG_ACTION_FAIL
Encountered an unexpected error.
Definition action.h:36
@ UNLANG_ACTION_CALCULATE_RESULT
Calculate a new section rlm_rcode_t value.
Definition action.h:37
@ UNLANG_ACTION_YIELD
Temporarily pause execution until an event occurs.
Definition action.h:41
log_entry msg
Definition acutest.h:794
#define fr_atexit_thread_local(_name, _free, _uctx)
Definition atexit.h:220
static bool init
Definition fuzzer.c:40
#define UNCONST(_type, _ptr)
Remove const qualification from a pointer.
Definition build.h:186
#define USES_APPLE_DEPRECATED_API
Definition build.h:493
#define RCSID(id)
Definition build.h:506
#define L(_str)
Helper for initialising arrays of string literals.
Definition build.h:228
#define FALL_THROUGH
clang 10 doesn't recognised the FALL-THROUGH comment anymore
Definition build.h:343
#define UNUSED
Definition build.h:336
#define NUM_ELEMENTS(_t)
Definition build.h:358
#define CONF_PARSER_TERMINATOR
Definition cf_parse.h:657
#define FR_CONF_OFFSET(_name, _struct, _field)
conf_parser_t which parses a single CONF_PAIR, writing the result to a field in a struct
Definition cf_parse.h:280
#define FR_CONF_OFFSET_FLAGS(_name, _flags, _struct, _field)
conf_parser_t which parses a single CONF_PAIR, writing the result to a field in a struct
Definition cf_parse.h:268
@ CONF_FLAG_FILE_EXISTS
File matching value must exist.
Definition cf_parse.h:441
Defines a CONF_PAIR to C data type mapping.
Definition cf_parse.h:594
#define MEM(x)
Definition debug.h:46
#define ERROR(fmt,...)
Definition dhcpclient.c:40
#define DEBUG(fmt,...)
Definition dhcpclient.c:38
static void * fr_dlist_remove(fr_dlist_head_t *list_head, void *ptr)
Remove an item from the list.
Definition dlist.h:620
static void fr_dlist_talloc_free(fr_dlist_head_t *head)
Free all items in a doubly linked list (with talloc)
Definition dlist.h:892
static unsigned int fr_dlist_num_elements(fr_dlist_head_t const *head)
Return the number of elements in the dlist.
Definition dlist.h:921
#define unlang_function_push(_request, _func, _repeat, _signal, _sigmask, _top_frame, _uctx)
Push a generic function onto the unlang stack.
Definition function.h:179
char const * name
Name of library and section within global config.
Definition global_lib.h:39
Structure to define how to initialise libraries with global configuration.
Definition global_lib.h:38
free(array)
talloc_free(hp)
#define UNLANG_SUB_FRAME
Definition interpret.h:37
fr_ldap_control_t serverctrls[LDAP_MAX_CONTROLS]
Server controls specific to this query.
Definition base.h:452
fr_time_delta_t res_timeout
How long we wait for results.
Definition base.h:298
char ** referral_urls
Referral results to follow.
Definition base.h:463
size_t fr_ldap_common_dn(char const *full, char const *part)
Find the place at which the two DN strings diverge.
Definition util.c:540
LDAP * handle
libldap handle.
Definition base.h:333
char const * dn
Base DN for searches, DN for modifications.
Definition base.h:431
void fr_ldap_control_merge(LDAPControl *serverctrls_out[], LDAPControl *clientctrls_out[], size_t serverctrls_len, size_t clientctrls_len, fr_ldap_connection_t *conn, LDAPControl *serverctrls_in[], LDAPControl *clientctrls_in[])
Merge connection and call specific client and server controls.
Definition control.c:48
fr_dlist_head_t referrals
List of parsed referrals.
Definition base.h:464
fr_ldap_result_code_t ret
Result code.
Definition base.h:472
bool freeit
Whether the control should be freed after we've finished using it.
Definition base.h:136
fr_rb_tree_t * queries
Outstanding queries on this connection.
Definition base.h:351
@ FR_LDAP_STATE_ERROR
Connection is in an error state.
Definition base.h:172
@ FR_LDAP_STATE_BIND
Connection is being bound.
Definition base.h:170
@ FR_LDAP_STATE_START_TLS
TLS is being negotiated.
Definition base.h:169
@ FR_LDAP_STATE_RUN
Connection is muxing/demuxing requests.
Definition base.h:171
@ FR_LDAP_STATE_INIT
Connection uninitialised.
Definition base.h:168
trunk_request_t * treq
Trunk request this query is associated with.
Definition base.h:458
fr_dlist_head_t refs
Replied to queries still referencing this connection.
Definition base.h:352
fr_ldap_config_t const * config
rlm_ldap connection configuration.
Definition base.h:344
fr_ldap_control_t clientctrls[LDAP_MAX_CONTROLS]
Client controls specific to this query.
Definition base.h:453
char const * tls_random_file
Path to the ramdon file if /dev/random and /dev/urandom are unavailable.
Definition base.h:321
fr_ldap_request_type_t
Types of LDAP requests.
Definition base.h:178
@ LDAP_REQUEST_MODIFY
A modification to an LDAP entity.
Definition base.h:180
@ LDAP_REQUEST_SEARCH
A lookup in an LDAP directory.
Definition base.h:179
@ LDAP_REQUEST_EXTENDED
An extended LDAP operation.
Definition base.h:182
fr_ldap_connection_t * ldap_conn
LDAP connection this query is running on.
Definition base.h:459
@ LDAP_RESULT_SUCCESS
Successfully got LDAP results.
Definition base.h:190
@ LDAP_RESULT_PENDING
Result not yet returned.
Definition base.h:189
#define LDAP_MAX_CONTROLS
Maximum number of client/server controls.
Definition base.h:94
char const * name
Name of the module that created this connection.
Definition base.h:222
LDAPMessage * result
Head of LDAP results list.
Definition base.h:470
LDAPControl * control
LDAP control.
Definition base.h:135
#define LDAP_VENDOR_VERSION_PATCH
Definition base.h:67
trunk_t * trunk
Connection trunk.
Definition base.h:407
connection_t * conn
Connection state handle.
Definition base.h:345
uint32_t ldap_debug
LDAP debug level.
Definition base.h:320
@ LDAP_EXT_BINDPW
Specifies the password for an LDAP bind.
Definition base.h:125
@ LDAP_EXT_BINDNAME
Specifies the user DN or name for an LDAP bind.
Definition base.h:124
fr_ldap_request_type_t type
What type of query this is.
Definition base.h:450
fr_ldap_rcode_t
Codes returned by fr_ldap internal functions.
Definition base.h:584
@ LDAP_PROC_CONTINUE
Operation is in progress.
Definition base.h:586
@ LDAP_PROC_SUCCESS
Operation was successful.
Definition base.h:587
@ LDAP_PROC_REFERRAL
LDAP server returned referral URLs.
Definition base.h:585
@ LDAP_PROC_TIMEOUT
Operation timed out.
Definition base.h:604
@ LDAP_PROC_ERROR
Unrecoverable library/server error.
Definition base.h:589
@ LDAP_PROC_BAD_CONN
Transitory error, caller should retry the operation with a new connection.
Definition base.h:591
@ LDAP_PROC_NOT_PERMITTED
Operation was not permitted, either current user was locked out in the case of binds,...
Definition base.h:594
@ LDAP_PROC_REJECT
Bind failed, user was rejected.
Definition base.h:598
@ LDAP_PROC_REFRESH_REQUIRED
Don't continue with the current refresh phase, exit, and retry the operation with a NULL cookie.
Definition base.h:606
@ LDAP_PROC_BAD_DN
Specified an invalid object in a bind or search DN.
Definition base.h:600
@ LDAP_PROC_NO_RESULT
Got no results.
Definition base.h:602
LDAPURLDesc * ldap_url
parsed URL for current query if the source of the query was a URL.
Definition base.h:428
Connection configuration.
Definition base.h:221
Tracks the state of a libldap connection handle.
Definition base.h:332
LDAP query structure.
Definition base.h:424
Thread LDAP trunk structure.
Definition base.h:401
libldap global configuration data
Definition base.h:319
static fr_libldap_global_config_t libldap_global_config
Definition base.c:93
#define do_ldap_global_option(_option, _name, _value)
fr_ldap_rcode_t fr_ldap_error_check(LDAPControl ***ctrls, fr_ldap_connection_t const *conn, LDAPMessage *msg, char const *dn)
Perform basic parsing of multiple types of messages, checking for error conditions.
Definition base.c:231
LDAP * ldap_global_handle
Hack for OpenLDAP libldap global initialisation.
Definition base.c:38
#define maybe_ldap_global_option(_option, _name, _value)
size_t fr_ldap_dereference_len
Definition base.c:91
static int _ldap_query_free(fr_ldap_query_t *query)
Free any libldap structures when an fr_ldap_query_t is freed.
Definition base.c:967
fr_ldap_rcode_t fr_ldap_search_async(int *msgid, request_t *request, fr_ldap_connection_t *pconn, char const *dn, int scope, char const *filter, char const *const *attrs, LDAPControl **serverctrls, LDAPControl **clientctrls)
Search for something in the LDAP directory.
Definition base.c:528
char const * fr_ldap_error_str(fr_ldap_connection_t const *conn)
Return the error string associated with a handle.
Definition base.c:209
static fr_ldap_config_t ldap_global_handle_config
Used to set the global log prefix for functions which don't operate on connections.
Definition base.c:46
size_t fr_ldap_scope_len
Definition base.c:74
LDAP * fr_ldap_handle_thread_local(void)
Get a thread local dummy LDAP handle.
Definition base.c:1129
static void ldap_trunk_search_results_debug(request_t *request, fr_ldap_query_t *query)
Definition base.c:587
fr_table_num_sorted_t const fr_ldap_supported_extensions[]
Definition base.c:59
int fr_ldap_global_config(int debug_level, char const *tls_random_file)
Change settings global to libldap.
Definition base.c:1150
global_lib_autoinst_t fr_libldap_global_config
Definition base.c:133
static conf_parser_t const ldap_global_config[]
Definition base.c:98
fr_ldap_rcode_t fr_ldap_result(LDAPMessage **result, LDAPControl ***ctrls, fr_ldap_connection_t const *conn, int msgid, int all, char const *dn, fr_time_delta_t timeout)
Parse response from LDAP server dealing with any errors.
Definition base.c:449
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)
Run an async modification LDAP query on a trunk connection.
Definition base.c:769
size_t fr_ldap_supported_extensions_len
Definition base.c:63
size_t fr_ldap_connection_states_len
Definition base.c:57
fr_table_num_sorted_t const fr_ldap_connection_states[]
Definition base.c:50
static void libldap_free(void)
Free any global libldap resources.
Definition base.c:120
static unlang_action_t ldap_trunk_query_results(request_t *request, void *uctx)
Handle the return code from parsed LDAP results to set the module rcode.
Definition base.c:629
fr_ldap_rcode_t fr_ldap_modify_async(int *msgid, request_t *request, fr_ldap_connection_t *pconn, char const *dn, LDAPMod *mods[], LDAPControl **serverctrls, LDAPControl **clientctrls)
Modify something in the LDAP directory.
Definition base.c:819
fr_table_num_sorted_t const fr_ldap_tls_require_cert[]
Definition base.c:76
fr_table_num_sorted_t const fr_ldap_dereference[]
Definition base.c:85
fr_ldap_rcode_t fr_ldap_extended_async(int *msgid, request_t *request, fr_ldap_connection_t *pconn, char const *reqoid, struct berval *reqdata)
Initiate an LDAP extended operation.
Definition base.c:948
static void ldap_trunk_query_cancel(UNUSED request_t *request, UNUSED fr_signal_t action, void *uctx)
Signal an LDAP query running on a trunk connection to cancel.
Definition base.c:650
fr_ldap_rcode_t fr_ldap_delete_async(int *msgid, request_t *request, fr_ldap_connection_t *pconn, char const *dn, LDAPControl **serverctrls, LDAPControl **clientctrls)
Modify something in the LDAP directory.
Definition base.c:859
static int _ldap_handle_thread_local_free(void *handle)
Definition base.c:1113
#define SET_LDAP_CTRLS(_dest, _src)
Definition base.c:690
fr_ldap_query_t * fr_ldap_modify_alloc(TALLOC_CTX *ctx, char const *dn, LDAPMod *mods[], LDAPControl **serverctrls, LDAPControl **clientctrls)
Allocate a new LDAP modify object.
Definition base.c:1076
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)
Allocate a new search object.
Definition base.c:1050
static fr_ldap_query_t * ldap_query_alloc(TALLOC_CTX *ctx, fr_ldap_request_type_t type)
Allocate an fr_ldap_query_t, setting the talloc destructor.
Definition base.c:1027
unlang_action_t fr_ldap_trunk_extended(TALLOC_CTX *ctx, fr_ldap_query_t **out, request_t *request, fr_ldap_thread_trunk_t *ttrunk, char const *reqoid, struct berval *reqdata, LDAPControl **serverctrls, LDAPControl **clientctrls)
Run an async LDAP "extended operation" query on a trunk connection.
Definition base.c:901
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)
Run an async search LDAP query on a trunk connection.
Definition base.c:717
fr_ldap_query_t * query
Definition base.c:142
void fr_ldap_timeout_debug(request_t *request, fr_ldap_connection_t const *conn, fr_time_delta_t timeout, char const *prefix)
Prints information to the debug log on the current timeout settings.
Definition base.c:151
fr_ldap_query_t * fr_ldap_extended_alloc(TALLOC_CTX *ctx, char const *reqoid, struct berval *reqdata, LDAPControl **serverctrls, LDAPControl **clientctrls)
Allocate a new LDAP extended operations object.
Definition base.c:1099
size_t fr_ldap_tls_require_cert_len
Definition base.c:83
fr_table_num_sorted_t const fr_ldap_scope[]
Definition base.c:68
LDAPMessage ** result
Definition base.c:143
static int libldap_init(void)
Initialise libldap library and set global options.
Definition base.c:108
static _Thread_local LDAP * ldap_thread_local_handle
Hack for functions which require an ldap handle.
Definition base.c:40
int fr_ldap_init(void)
Initialise libldap and check library versions.
Definition base.c:1189
#define PERROR(_fmt,...)
Definition log.h:228
#define REXDENT()
Exdent (unindent) R* messages by one level.
Definition log.h:455
#define DEBUG_ENABLED2
True if global debug level 1-2 messages are enabled.
Definition log.h:258
#define ROPTIONAL(_l_request, _l_global, _fmt,...)
Use different logging functions depending on whether request is NULL or not.
Definition log.h:540
#define RDEBUG3(fmt,...)
Definition log.h:355
#define DEBUG_ENABLED4
True if global debug level 1-4 messages are enabled.
Definition log.h:260
#define DEBUG4(_fmt,...)
Definition log.h:267
#define RPERROR(fmt,...)
Definition log.h:314
#define RPEDEBUG(fmt,...)
Definition log.h:388
#define RDEBUG4(fmt,...)
Definition log.h:356
#define DEBUG_ENABLED3
True if global debug level 1-3 messages are enabled.
Definition log.h:259
#define RDEBUG_ENABLED4
True if request debug level 1-4 messages are enabled.
Definition log.h:348
#define RINDENT()
Indent R* messages by one level.
Definition log.h:442
void fr_canonicalize_error(TALLOC_CTX *ctx, char **sp, char **text, ssize_t slen, char const *fmt)
Canonicalize error strings, removing tabs, and generate spaces for error marker.
Definition log.c:87
long int ssize_t
#define fr_assert(_expr)
Definition rad_assert.h:37
#define REDEBUG(fmt,...)
#define RDEBUG_ENABLED2()
#define RDEBUG2(fmt,...)
#define DEBUG2(fmt,...)
#define WARN(fmt,...)
#define INFO(fmt,...)
Definition radict.c:63
static const char * spaces
Definition radict.c:177
uint32_t fr_rb_num_elements(fr_rb_tree_t *tree)
Return how many nodes there are in a tree.
Definition rb.c:781
ssize_t fr_sbuff_in_strcpy(fr_sbuff_t *sbuff, char const *str)
Copy bytes into the sbuff up to the first \0.
Definition sbuff.c:1472
ssize_t fr_sbuff_in_sprintf(fr_sbuff_t *sbuff, char const *fmt,...)
Print using a fmt string to an sbuff.
Definition sbuff.c:1605
fr_slen_t fr_sbuff_in_array(fr_sbuff_t *out, char const *const *array, char const *sep)
Concat an array of strings (NULL terminated), with a string separator.
Definition sbuff.c:1721
#define fr_sbuff_start(_sbuff_or_marker)
#define fr_sbuff_in_strcpy_literal(_sbuff, _str)
#define FR_SBUFF_TALLOC_THREAD_LOCAL(_out, _init, _max)
fr_signal_t
Signals that can be generated/processed by request signal handlers.
Definition signal.h:38
@ FR_SIGNAL_CANCEL
Request has been cancelled.
Definition signal.h:40
return count
Definition module.c:155
eap_aka_sim_process_conf_t * inst
fr_aka_sim_id_type_t type
#define fr_table_str_by_value(_table, _number, _def)
Convert an integer to a string.
Definition table.h:772
An element in a lexicographically sorted array of name to num mappings.
Definition table.h:49
#define fr_time_delta_wrap(_time)
Definition time.h:152
#define fr_time_delta_ispos(_a)
Definition time.h:290
#define fr_time_delta_to_timeval(_delta)
Convert a delta to a timeval.
Definition time.h:656
static fr_time_delta_t fr_time_delta_from_timeval(struct timeval const *tv)
Definition time.h:597
A time delta, a difference in time measured in nanoseconds.
Definition time.h:80
trunk_enqueue_t trunk_request_enqueue(trunk_request_t **treq_out, trunk_t *trunk, request_t *request, void *preq, void *rctx)
Enqueue a request that needs data written to the trunk.
Definition trunk.c:2639
void trunk_request_signal_cancel(trunk_request_t *treq)
Cancel a trunk request.
Definition trunk.c:2198
@ TRUNK_ENQUEUE_OK
Operation was successful.
Definition trunk.h:151
@ TRUNK_ENQUEUE_IN_BACKLOG
Request should be enqueued in backlog.
Definition trunk.h:150
@ TRUNK_REQUEST_STATE_PARTIAL
Some of the request was written to the socket, more of it should be written later.
Definition trunk.h:171
@ TRUNK_REQUEST_STATE_CANCEL_SENT
We've informed the remote server that the request has been cancelled.
Definition trunk.h:186
@ TRUNK_REQUEST_STATE_CANCEL
A request on a particular socket was cancel.
Definition trunk.h:185
@ TRUNK_REQUEST_STATE_CANCEL_PARTIAL
We partially wrote a cancellation request.
Definition trunk.h:188
@ TRUNK_REQUEST_STATE_CANCEL_COMPLETE
Remote server has acknowledged our cancellation.
Definition trunk.h:189
@ TRUNK_REQUEST_STATE_SENT
Was written to a socket. Waiting for a response.
Definition trunk.h:173
#define fr_strerror_printf(_fmt,...)
Log to thread local error buffer.
Definition strerror.h:64
#define fr_strerror_printf_push(_fmt,...)
Add a message to an existing stack of messages at the tail.
Definition strerror.h:84
#define fr_strerror_const(_msg)
Definition strerror.h:223
#define fr_box_time_delta(_val)
Definition value.h:366
static size_t char ** out
Definition value.h:1030