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