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