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