The FreeRADIUS server  $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
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: 31749e1f1fa18a4ad9a47c15068a87938e219be8 $
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  */
27 RCSID("$Id: 31749e1f1fa18a4ad9a47c15068a87938e219be8 $")
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 
39 LDAP *ldap_global_handle; //!< Hack for OpenLDAP libldap global initialisation.
40 
41 static _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  */
109 static 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  */
121 static 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  */
135  .name = "ldap",
136  .config = (const conf_parser_t *)ldap_global_config,
138  .init = libldap_init,
139  .free = libldap_free
140 };
141 
142 typedef 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 
176  ROPTIONAL(RDEBUG4, DEBUG4, "Client side result timeout (ovr): %pVs",
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  */
210 char const *fr_ldap_error_str(fr_ldap_connection_t const *conn)
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  */
232 fr_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  lib_errno = ldap_parse_result(conn->handle, msg,
264  &srv_errno, &part_dn, &srv_err,
265  NULL, ctrls, 0);
266  break;
267 
268  /*
269  * These are messages containing objects so unless they're
270  * malformed they can't contain errors.
271  */
272  case LDAP_RES_SEARCH_ENTRY:
273  if (ctrls) lib_errno = ldap_get_entry_controls(conn->handle, msg, ctrls);
274  break;
275 
276  /*
277  * Retrieve the controls if the message is a reference message
278  */
279  case LDAP_RES_SEARCH_REFERENCE:
280  if (ctrls) lib_errno = ldap_parse_reference(conn->handle, msg, NULL, ctrls, 0);
281  break;
282 
283  /*
284  * An intermediate message updating us on the result of an operation
285  */
286  case LDAP_RES_INTERMEDIATE:
287  lib_errno = ldap_parse_intermediate(conn->handle, msg, NULL, NULL, ctrls, 0);
288  break;
289 
290  /*
291  * Can't extract any more useful information.
292  */
293  default:
294  return LDAP_PROC_SUCCESS;
295  }
296 
297  /*
298  * Stupid messy API
299  */
300  if (lib_errno != LDAP_SUCCESS) {
301  fr_assert(!ctrls || !*ctrls);
302  ldap_get_option(conn->handle, LDAP_OPT_RESULT_CODE, &lib_errno);
303  }
304 
305 process_error:
306  if ((lib_errno == LDAP_SUCCESS) && (srv_errno != LDAP_SUCCESS)) {
307  lib_errno = srv_errno;
308  } else if ((lib_errno != LDAP_SUCCESS) && (srv_errno == LDAP_SUCCESS)) {
309  srv_errno = lib_errno;
310  }
311 
312  switch (lib_errno) {
313  case LDAP_SUCCESS:
314  fr_strerror_const("Success");
315  break;
316 
317  case LDAP_REFERRAL:
318  fr_strerror_const("Referral");
319  status = LDAP_PROC_REFERRAL;
320  break;
321 
322  case LDAP_SASL_BIND_IN_PROGRESS:
323  fr_strerror_const("Continuing");
324  status = LDAP_PROC_CONTINUE;
325  break;
326 
327  case LDAP_NO_SUCH_OBJECT:
328  fr_strerror_const("The specified DN wasn't found");
329  status = LDAP_PROC_BAD_DN;
330 
331  /*
332  * Build our own internal diagnostic string
333  */
334  if (dn && part_dn) {
335  char *spaces;
336  char *text;
337 
338  len = fr_ldap_common_dn(dn, part_dn);
339  if (len < 0) break;
340 
341  fr_canonicalize_error(NULL, &spaces, &text, -len, dn);
342  fr_strerror_printf_push("%s", text);
343  fr_strerror_printf_push("%s^ %s", spaces, "match stopped here");
344 
346  talloc_free(text);
347  }
348  goto error_string;
349 
350  case LDAP_INSUFFICIENT_ACCESS:
351  fr_strerror_const("Insufficient access. Check the identity and password configuration directives");
352  status = LDAP_PROC_NOT_PERMITTED;
353  break;
354 
355  case LDAP_UNWILLING_TO_PERFORM:
356  fr_strerror_const("Server was unwilling to perform");
357  status = LDAP_PROC_NOT_PERMITTED;
358  break;
359 
360  case LDAP_FILTER_ERROR:
361  fr_strerror_const("Bad search filter");
362  status = LDAP_PROC_ERROR;
363  break;
364 
365  case LDAP_TIMEOUT:
366  fr_strerror_const("Timed out while waiting for server to respond");
367  status = LDAP_PROC_TIMEOUT;
368  break;
369 
370  case LDAP_TIMELIMIT_EXCEEDED:
371  fr_strerror_const("Time limit exceeded");
372  status = LDAP_PROC_TIMEOUT;
373  break;
374 
375  case LDAP_SYNC_REFRESH_REQUIRED:
376  fr_strerror_const("Refresh required");
378  break;
379 
380  case LDAP_BUSY:
381  case LDAP_UNAVAILABLE:
382  case LDAP_SERVER_DOWN:
383  status = LDAP_PROC_BAD_CONN;
384  goto error_string;
385 
386  case LDAP_INVALID_CREDENTIALS:
387  case LDAP_CONSTRAINT_VIOLATION:
388  status = LDAP_PROC_REJECT;
389  goto error_string;
390 
391  case LDAP_OPERATIONS_ERROR:
392  fr_strerror_printf("Please set 'chase_referrals=yes' and 'rebind=yes'. "
393  "See the ldap module configuration for details");
394  FALL_THROUGH;
395 
396  default:
397  status = LDAP_PROC_ERROR;
398 
399  error_string:
400  if (lib_errno == srv_errno) {
401  fr_strerror_printf("lib error: %s (%u)", ldap_err2string(lib_errno), lib_errno);
402  } else {
403  fr_strerror_printf("lib error: %s (%u), srv error: %s (%u)",
404  ldap_err2string(lib_errno), lib_errno,
405  ldap_err2string(srv_errno), srv_errno);
406  }
407 
408  if (srv_err) fr_strerror_printf_push("Server said: %s", srv_err);
409 
410  break;
411  }
412 
413  /*
414  * Cleanup memory
415  */
416  if (srv_err) ldap_memfree(srv_err);
417  if (part_dn) ldap_memfree(part_dn);
418 
419  return status;
420 }
421 
422 /** Parse response from LDAP server dealing with any errors
423  *
424  * Should be called after an LDAP operation. Will check result of operation and if
425  * it was successful, then attempt to retrieve and parse the result. Will also produce
426  * extended error output including any messages the server sent, and information about
427  * partial DN matches.
428  *
429  * @note Error messages should be retrieved with fr_strerror() and fr_strerror_pop()
430  *
431  * @param[out] result Where to write result, if NULL result will be freed. If not NULL caller
432  * must free with ldap_msgfree().
433  * @param[out] ctrls Server ctrls returned to the client. May be NULL if not required.
434  * Must be freed with ldap_free_ctrls.
435  * @param[in] conn Current connection.
436  * @param[in] msgid returned from last operation.
437  * Special values are:
438  * - LDAP_RES_ANY - Retrieve any received messages useful for multiplexing.
439  * - LDAP_RES_UNSOLICITED - Any unsolicited message.
440  * @param[in] all How many messages to retrieve:
441  * - LDAP_MSG_ONE - Retrieve the first message matching msgid (waiting if one is not available).
442  * - LDAP_MSG_ALL - Retrieve all received messages matching msgid (waiting if none are available).
443  * - LDAP_MSG_RECEIVED - Retrieve all received messages.
444  * @param[in] dn Last search or bind DN. May be NULL.
445  * @param[in] timeout Override the default result timeout.
446  *
447  * @return One of the LDAP_PROC_* (#fr_ldap_rcode_t) values.
448  */
449 fr_ldap_rcode_t fr_ldap_result(LDAPMessage **result, LDAPControl ***ctrls,
450  fr_ldap_connection_t const *conn, int msgid, int all,
451  char const *dn,
453 {
455  int lib_errno;
456  fr_time_delta_t our_timeout = timeout;
457 
458  LDAPMessage *tmp_msg = NULL, *msg; /* Temporary message pointer storage if we weren't provided with one */
459  LDAPMessage **result_p = result;
460 
461  if (result) *result = NULL;
462  if (ctrls) *ctrls = NULL;
463 
464  /*
465  * We always need the result, but our caller may not
466  */
467  if (!result) result_p = &tmp_msg;
468 
469  /*
470  * Check if there was an error sending the request
471  */
472  ldap_get_option(conn->handle, LDAP_OPT_RESULT_CODE, &lib_errno);
473  if (lib_errno != LDAP_SUCCESS) return fr_ldap_error_check(NULL, conn, NULL, dn);
474 
475  if (!fr_time_delta_ispos(timeout)) our_timeout = conn->config->res_timeout;
476 
477  /*
478  * Now retrieve the result and check for errors
479  * ldap_result returns -1 on failure, and 0 on timeout
480  */
481  lib_errno = ldap_result(conn->handle, msgid, all, &fr_time_delta_to_timeval(our_timeout), result_p);
482  switch (lib_errno) {
483  case 0:
484  lib_errno = LDAP_TIMEOUT;
485  fr_strerror_const("timeout waiting for result");
486  return LDAP_PROC_TIMEOUT;
487 
488  case -1:
489  return fr_ldap_error_check(NULL, conn, NULL, dn);
490 
491  default:
492  break;
493  }
494 
495  for (msg = ldap_first_message(conn->handle, *result_p);
496  msg;
497  msg = ldap_next_message(conn->handle, msg)) {
498  status = fr_ldap_error_check(ctrls, conn, msg, dn);
499  if (status != LDAP_PROC_SUCCESS) break;
500  }
501 
502  if (*result_p && (!result)) {
503  ldap_msgfree(*result_p);
504  *result_p = NULL;
505  }
506 
507  return status;
508 }
509 
510 /** Search for something in the LDAP directory
511  *
512  * Performs an LDAP search, typically on a connection bound as the
513  * administrative user, dealing with any errors.
514  * Called from the trunk mux function and elsewhere where appropriate
515  * event handlers have been set on the connection fd.
516  *
517  * @param[out] msgid to match response to request.
518  * @param[in] request Current request.
519  * @param[in] pconn to use.
520  * @param[in] dn to use as base for the search.
521  * @param[in] scope to use (LDAP_SCOPE_BASE, LDAP_SCOPE_ONE, LDAP_SCOPE_SUB).
522  * @param[in] filter to use, should be pre-escaped.
523  * @param[in] attrs to retrieve.
524  * @param[in] serverctrls Search controls to pass to the server. May be NULL.
525  * @param[in] clientctrls Search controls for ldap_search. May be NULL.
526  * @return One of the LDAP_PROC_* (#fr_ldap_rcode_t) values.
527  */
529  fr_ldap_connection_t *pconn,
530  char const *dn, int scope, char const *filter, char const * const *attrs,
531  LDAPControl **serverctrls, LDAPControl **clientctrls)
532 {
533  fr_ldap_config_t const *handle_config = pconn->config;
534 
535  LDAPControl *our_serverctrls[LDAP_MAX_CONTROLS];
536  LDAPControl *our_clientctrls[LDAP_MAX_CONTROLS];
537 
538  char **search_attrs;
539 
540  fr_ldap_control_merge(our_serverctrls, our_clientctrls,
541  NUM_ELEMENTS(our_serverctrls),
542  NUM_ELEMENTS(our_clientctrls),
543  pconn, serverctrls, clientctrls);
544 
545  fr_assert(pconn && pconn->handle);
546 
547  if (DEBUG_ENABLED4 || (request && RDEBUG_ENABLED4)) {
548  fr_ldap_timeout_debug(request, pconn, fr_time_delta_wrap(0), __FUNCTION__);
549  }
550 
551  /*
552  * OpenLDAP library doesn't declare attrs array as const, but
553  * it really should be *sigh*.
554  */
555  memcpy(&search_attrs, &attrs, sizeof(attrs));
556 
557  if (filter) {
558  ROPTIONAL(RDEBUG2, DEBUG2, "Performing search in \"%s\" with filter \"%s\", scope \"%s\"", dn, filter,
559  fr_table_str_by_value(fr_ldap_scope, scope, "<INVALID>"));
560  } else {
561  ROPTIONAL(RDEBUG2, DEBUG2, "Performing unfiltered search in \"%s\", scope \"%s\"", dn,
562  fr_table_str_by_value(fr_ldap_scope, scope, "<INVALID>"));
563  }
564 
565  if (ldap_search_ext(pconn->handle, dn, scope, filter, search_attrs,
566  0, our_serverctrls, our_clientctrls, NULL, 0, msgid) != LDAP_SUCCESS) {
567  fr_ldap_rcode_t ret = fr_ldap_error_check(NULL, pconn, NULL, NULL);
568  ROPTIONAL(RPERROR, PERROR, "Failed performing search");
569  return ret;
570  }
571 
572  return LDAP_PROC_SUCCESS;
573 }
574 
576 {
577  LDAP *ld = query->ldap_conn->handle;
578  LDAPMessage *message;
579  char const * const *attr;
580  char *dn;
581  struct berval **values;
582  int count;
583 
584  count = ldap_count_entries(ld, query->result);
585  RDEBUG3("LDAP query returned %d entr%s", count, count > 1 ? "y" : "ies");
586  message = ldap_first_entry(ld, query->result);
587  RINDENT();
588  while (message) {
589  dn = ldap_get_dn(ld, message);
590  RDEBUG3("Entry DN %s", dn);
591  ldap_memfree(dn);
592  attr = query->search.attrs;
593  if (!attr) goto next;
594  RINDENT();
595  while(*attr) {
596  values = ldap_get_values_len(ld, message, *attr);
597  if (!values) {
598  RDEBUG3("Attribute \"%s\" not found", *attr);
599  } else {
600  count = ldap_count_values_len(values);
601  RDEBUG3("Attribute \"%s\" found %d time%s", *attr, count, count > 1 ? "s" : "");
602  }
603  ldap_value_free_len(values);
604  attr++;
605  }
606  REXDENT();
607  next:
608  message = ldap_next_entry(query->ldap_conn->handle, message);
609  }
610  REXDENT();
611 }
612 
613 /** Handle the return code from parsed LDAP results to set the module rcode
614  *
615  */
617  request_t *request, void *uctx)
618 {
619  fr_ldap_query_t *query = talloc_get_type_abort(uctx, fr_ldap_query_t);
620 
621  switch (query->ret) {
622  case LDAP_RESULT_PENDING:
623  /* The query we want hasn't returned yet */
624  return UNLANG_ACTION_YIELD;
625 
626  case LDAP_RESULT_SUCCESS:
629 
630  case LDAP_RESULT_BAD_DN:
633 
634  default:
636  }
637 }
638 
639 /** Signal an LDAP query running on a trunk connection to cancel
640  *
641  */
642 static void ldap_trunk_query_cancel(UNUSED request_t *request, UNUSED fr_signal_t action, void *uctx)
643 {
644  fr_ldap_query_t *query = talloc_get_type_abort(uctx, fr_ldap_query_t);
645 
646  /*
647  * Query may have completed, but the request
648  * not yet have been resumed.
649  */
650  if (!query->treq) return;
651 
652  /*
653  * The query needs to be parented by the treq so that it still
654  * exists when the cancel_mux callback is run.
655  */
656  talloc_steal(query->treq, query);
657 
659 
660  /*
661  * Once we've called cancel, the treq is no
662  * longer ours to manipulate, it belongs to
663  * the trunk code.
664  */
665  query->treq = NULL;
666 }
667 
668 #define SET_LDAP_CTRLS(_dest, _src) \
669 do { \
670  int i; \
671  if (!_src) break; \
672  for (i = 0; i < LDAP_MAX_CONTROLS; i++) { \
673  if (!(_src[i])) break; \
674  _dest[i].control = _src[i]; \
675  } \
676 } while (0)
677 
678 /** Run an async search LDAP query on a trunk connection
679  *
680  * @param[in] ctx to allocate the query in.
681  * @param[out] out that has been allocated.
682  * @param[in] request this query relates to.
683  * @param[in] ttrunk to submit the query to.
684  * @param[in] base_dn for the search.
685  * @param[in] scope of the search.
686  * @param[in] filter for the search.
687  * @param[in] attrs to be returned.
688  * @param[in] serverctrls specific to this query.
689  * @param[in] clientctrls specific to this query.
690  * @return
691  * - UNLANG_ACTION_FAIL on error.
692  * - UNLANG_ACTION_PUSHED_CHILD on success.
693  */
696  char const *base_dn, int scope, char const *filter, char const * const *attrs,
697  LDAPControl **serverctrls, LDAPControl **clientctrls)
698 {
699  unlang_action_t action;
700  fr_ldap_query_t *query;
701 
702  query = fr_ldap_search_alloc(ctx, base_dn, scope, filter, attrs, serverctrls, clientctrls);
703 
704  switch (fr_trunk_request_enqueue(&query->treq, ttrunk->trunk, request, query, NULL)) {
705  case FR_TRUNK_ENQUEUE_OK:
707  break;
708 
709  default:
710  error:
711  *out = NULL;
712  talloc_free(query);
713  return UNLANG_ACTION_FAIL;
714  }
715 
716  action = unlang_function_push(request, NULL, ldap_trunk_query_results,
717  ldap_trunk_query_cancel, ~FR_SIGNAL_CANCEL, UNLANG_SUB_FRAME, query);
718 
719  if (action == UNLANG_ACTION_FAIL) goto error;
720 
721  *out = query;
722 
724 }
725 
726 /** Run an async modification LDAP query on a trunk connection
727  *
728  * @param[in] ctx to allocate the query in.
729  * @param[out] out that has been allocated.
730  * @param[in] request this query relates to.
731  * @param[in] ttrunk to submit the query to.
732  * @param[in] dn of the object being modified.
733  * @param[in] mods to be performed.
734  * @param[in] serverctrls specific to this query.
735  * @param[in] clientctrls specific to this query.
736  * @return
737  * - UNLANG_ACTION_FAIL on error.
738  * - UNLANG_ACTION_PUSHED_CHILD on success.
739  */
742  char const *dn, LDAPMod *mods[],
743  LDAPControl **serverctrls, LDAPControl **clientctrls)
744 {
745  unlang_action_t action;
746  fr_ldap_query_t *query;
747 
748  query = fr_ldap_modify_alloc(ctx, dn, mods, serverctrls, clientctrls);
749 
750  switch (fr_trunk_request_enqueue(&query->treq, ttrunk->trunk, request, query, NULL)) {
751  case FR_TRUNK_ENQUEUE_OK:
753  break;
754 
755  default:
756  error:
757  *out = NULL;
758  talloc_free(query);
759  return UNLANG_ACTION_FAIL;
760  }
761 
763  ~FR_SIGNAL_CANCEL, UNLANG_SUB_FRAME, query);
764 
765  if (action == UNLANG_ACTION_FAIL) goto error;
766 
767  *out = query;
768 
770 }
771 
772 /** Modify something in the LDAP directory
773  *
774  * Used on connections bound as the administrative user to attempt to modify an LDAP object.
775  * Called by the trunk mux function
776  *
777  * @param[out] msgid LDAP message ID.
778  * @param[in] request Current request.
779  * @param[in] pconn to use.
780  * @param[in] dn of the object to modify.
781  * @param[in] mods to make, see 'man ldap_modify' for more information.
782  * @param[in] serverctrls Search controls to pass to the server. May be NULL.
783  * @param[in] clientctrls Search controls for ldap_modify. May be NULL.
784  * @return One of the LDAP_PROC_* (#fr_ldap_rcode_t) values.
785  */
787  char const *dn, LDAPMod *mods[],
788  LDAPControl **serverctrls, LDAPControl **clientctrls)
789 {
790  LDAPControl *our_serverctrls[LDAP_MAX_CONTROLS];
791  LDAPControl *our_clientctrls[LDAP_MAX_CONTROLS];
792 
793  fr_ldap_control_merge(our_serverctrls, our_clientctrls,
794  NUM_ELEMENTS(our_serverctrls),
795  NUM_ELEMENTS(our_clientctrls),
796  pconn, serverctrls, clientctrls);
797 
798  fr_assert(pconn && pconn->handle);
799 
800  if (RDEBUG_ENABLED4) fr_ldap_timeout_debug(request, pconn, fr_time_delta_wrap(0), __FUNCTION__);
801 
802  RDEBUG2("Modifying object with DN \"%s\"", dn);
803  if(ldap_modify_ext(pconn->handle, dn, mods, our_serverctrls, our_clientctrls, msgid) != LDAP_SUCCESS) {
804  fr_ldap_rcode_t ret = fr_ldap_error_check(NULL, pconn, NULL, NULL);
805  ROPTIONAL(RPEDEBUG, RPERROR, "Failed modifying object");
806 
807  return ret;
808  }
809 
810  return LDAP_PROC_SUCCESS;
811 }
812 
813 /** Run an async LDAP "extended operation" query on a trunk connection
814  *
815  * @param[in] ctx to allocate the query in.
816  * @param[out] out that has been allocated.
817  * @param[in] request this query relates to.
818  * @param[in] ttrunk to submit the query to.
819  * @param[in] reqoid OID of extended operation.
820  * @param[in] reqdata Request data to send.
821  * @param[in] serverctrls specific to this query.
822  * @param[in] clientctrls specific to this query.
823  * @return
824  * - UNLANG_ACTION_FAIL on error.
825  * - UNLANG_ACTION_PUSHED_CHILD on success.
826  */
829  char const *reqoid, struct berval *reqdata,
830  LDAPControl **serverctrls, LDAPControl **clientctrls)
831 {
832  unlang_action_t action;
833  fr_ldap_query_t *query;
834 
835  query = fr_ldap_extended_alloc(ctx, reqoid, reqdata, serverctrls, clientctrls);
836 
837  switch (fr_trunk_request_enqueue(&query->treq, ttrunk->trunk, request, query, NULL)) {
838  case FR_TRUNK_ENQUEUE_OK:
840  break;
841 
842  default:
843  error:
844  *out = NULL;
845  talloc_free(query);
846  return UNLANG_ACTION_FAIL;
847  }
848 
850  ~FR_SIGNAL_CANCEL, UNLANG_SUB_FRAME, query);
851 
852  if (action == UNLANG_ACTION_FAIL) goto error;
853 
854  *out = query;
855 
857 }
858 
859 /** Initiate an LDAP extended operation
860  *
861  * Called by the trunk mux function
862  *
863  * @param[out] msgid LDAP message ID.
864  * @param[in] request Current request.
865  * @param[in] pconn to use.
866  * @param[in] reqoid OID of extended operation to perform.
867  * @param[in] reqdata Data required for the request.
868  * @return One of the LDAP_PROC_* (#fr_ldap_rcode_t) values.
869  */
871  char const *reqoid, struct berval *reqdata)
872 {
873  fr_assert(pconn && pconn->handle);
874 
875  RDEBUG2("Requesting extended operation with OID %s", reqoid);
876  if (ldap_extended_operation(pconn->handle, reqoid, reqdata, NULL, NULL, msgid)) {
877  fr_ldap_rcode_t ret = fr_ldap_error_check(NULL, pconn, NULL, NULL);
878  RPERROR("Failed requesting extended operation");
879  return ret;
880  }
881  return LDAP_PROC_SUCCESS;
882 }
883 
884 /** Free any libldap structures when an fr_ldap_query_t is freed
885  *
886  * It is also possible that the connection used for this query is now closed,
887  * in that instance we free it here.
888  */
890 {
891  int i;
892 
893  /*
894  * Free any results which were retrieved
895  */
896  if (query->result) ldap_msgfree(query->result);
897 
898  /*
899  * Free any server and client controls that need freeing
900  */
901  for (i = 0; i < LDAP_MAX_CONTROLS; i++) {
902  if (!query->serverctrls[i].control) break;
903  if (query->serverctrls[i].freeit) ldap_control_free(query->serverctrls[i].control);
904  }
905 
906  for (i = 0; i < LDAP_MAX_CONTROLS; i++) {
907  if (!query->clientctrls[i].control) break;
908  if (query->clientctrls[i].freeit) ldap_control_free(query->clientctrls[i].control);
909  }
910 
911  /*
912  * If a URL was parsed, free it.
913  */
914  if (query->ldap_url) ldap_free_urldesc(query->ldap_url);
915 
916  /*
917  * If any referrals were followed, the parsed referral URLS should be freed
918  */
919  if (query->referral_urls) ldap_memvfree((void **)query->referral_urls);
920 
922 
923  if (query->ldap_conn) {
924  /*
925  * Remove the query from the list of references to its connection
926  */
927  fr_dlist_remove(&query->ldap_conn->refs, query);
928 
929  /*
930  * If the connection this query was using has no pending queries and
931  * is no-longer associated with a fr_connection_t then free it
932  */
933  if (!query->ldap_conn->conn && (fr_dlist_num_elements(&query->ldap_conn->refs) == 0) &&
934  (fr_rb_num_elements(query->ldap_conn->queries) == 0)) talloc_free(query->ldap_conn);
935  }
936 
937  /*
938  * Ensure the request data for extended operations are freed.
939  */
940  if (query->type == LDAP_REQUEST_EXTENDED && query->extended.reqdata) ber_bvfree(query->extended.reqdata);
941 
942  return 0;
943 }
944 
945 /** Allocate an fr_ldap_query_t, setting the talloc destructor
946  *
947  */
948 static inline CC_HINT(always_inline)
950 {
951  fr_ldap_query_t *query;
952 
953  MEM(query = talloc_zero(ctx, fr_ldap_query_t));
954  talloc_set_destructor(query, _ldap_query_free);
955 
956  query->ret = LDAP_RESULT_PENDING;
957  query->type = type;
958 
959  return query;
960 }
961 
962 /** Allocate a new search object
963  *
964  * @param[in] ctx to allocate query in.
965  * @param[in] base_dn for the search.
966  * @param[in] scope of the search.
967  * @param[in] filter for the search
968  * @param[in] attrs to request.
969  * @param[in] serverctrls Search controls to pass to the server. May be NULL.
970  * @param[in] clientctrls Client controls. May be NULL.
971  */
973  char const *base_dn, int scope, char const *filter, char const * const * attrs,
974  LDAPControl **serverctrls, LDAPControl **clientctrls)
975 {
976  fr_ldap_query_t *query;
977 
979  query->dn = base_dn;
980  query->search.scope = scope;
981  query->search.filter = filter;
982  query->search.attrs = UNCONST(char const **, attrs);
983  SET_LDAP_CTRLS(query->serverctrls, serverctrls);
984  SET_LDAP_CTRLS(query->clientctrls, clientctrls);
985 
986  return query;
987 }
988 
989 /** Allocate a new LDAP modify object
990  *
991  * @param[in] ctx to allocate the query in.
992  * @param[in] dn of the object to modify.
993  * @param[in] mods to apply to the object.
994  * @param[in] serverctrls Controls to pass to the server. May be NULL.
995  * @param[in] clientctrls Client controls. May be NULL.
996  * @return LDAP query object
997  */
998 fr_ldap_query_t *fr_ldap_modify_alloc(TALLOC_CTX *ctx, char const *dn,
999  LDAPMod *mods[], LDAPControl **serverctrls, LDAPControl **clientctrls)
1000 {
1001  fr_ldap_query_t *query;
1002 
1003  query = ldap_query_alloc(ctx, LDAP_REQUEST_MODIFY);
1004  query->dn = dn;
1005  query->mods = mods;
1006  SET_LDAP_CTRLS(query->serverctrls, serverctrls);
1007  SET_LDAP_CTRLS(query->clientctrls, clientctrls);
1008 
1009  return query;
1010 }
1011 
1012 /** Allocate a new LDAP extended operations object
1013  *
1014  * @param[in] ctx to allocate the query in.
1015  * @param[in] reqoid OID of extended operation to perform.
1016  * @param[in] reqdata Request data to send.
1017  * @param[in] serverctrls Controls to pass to the server. May be NULL.
1018  * @param[in] clientctrls Client controls. May be NULL.
1019  * @return LDAP query object
1020  */
1021 fr_ldap_query_t *fr_ldap_extended_alloc(TALLOC_CTX *ctx, char const *reqoid, struct berval *reqdata,
1022  LDAPControl **serverctrls, LDAPControl **clientctrls)
1023 {
1024  fr_ldap_query_t *query;
1025 
1027  query->extended.reqoid = reqoid;
1028  query->extended.reqdata = reqdata;
1029  SET_LDAP_CTRLS(query->serverctrls, serverctrls);
1030  SET_LDAP_CTRLS(query->clientctrls, clientctrls);
1031 
1032  return (query);
1033 }
1034 
1035 static int _ldap_handle_thread_local_free(void *handle)
1036 {
1037  if (ldap_unbind_ext_s(handle, NULL, NULL) < 0) return -1;
1038  return 0;
1039 }
1040 
1041 /** Get a thread local dummy LDAP handle
1042  *
1043  * Many functions in the OpenLDAP API don't actually use the handle
1044  * for anything other than writing out error codes.
1045  *
1046  * This is true for most of the LDAP extensions API functions.
1047  *
1048  * This gives us a reusable handle that was can pass to those
1049  * functions when we don't already have one available.
1050  */
1052 {
1053  if (!ldap_thread_local_handle) {
1054  LDAP *handle;
1055 
1056  ldap_initialize(&handle, "");
1057 
1059  }
1060 
1061  return ldap_thread_local_handle;
1062 }
1063 
1064 /** Change settings global to libldap
1065  *
1066  * May only be called once. Subsequent calls will be ignored.
1067  *
1068  * @param[in] debug_level to enable in libldap.
1069  * @param[in] tls_random_file Where OpenSSL gets its randomness.
1070  */
1071 int fr_ldap_global_config(int debug_level, char const *tls_random_file)
1072 {
1073  static bool done_config;
1074  fr_ldap_config_t *handle_config = &ldap_global_handle_config;
1075 
1076  if (done_config) return 0;
1077 
1078 #define do_ldap_global_option(_option, _name, _value) \
1079  if (ldap_set_option(NULL, _option, _value) != LDAP_OPT_SUCCESS) do { \
1080  int _ldap_errno; \
1081  ldap_get_option(NULL, LDAP_OPT_RESULT_CODE, &_ldap_errno); \
1082  ERROR("Failed setting global option %s: %s", _name, \
1083  (_ldap_errno != LDAP_SUCCESS) ? ldap_err2string(_ldap_errno) : "Unknown error"); \
1084  return -1;\
1085  } while (0)
1086 
1087 #define maybe_ldap_global_option(_option, _name, _value) \
1088  if (_value) do_ldap_global_option(_option, _name, _value)
1089 
1090  if (debug_level) do_ldap_global_option(LDAP_OPT_DEBUG_LEVEL, "ldap_debug", &debug_level);
1091 
1092  /*
1093  * OpenLDAP will error out if we attempt to set
1094  * this on a handle. Presumably it's global in
1095  * OpenSSL too.
1096  */
1097  maybe_ldap_global_option(LDAP_OPT_X_TLS_RANDOM_FILE, "random_file", tls_random_file);
1098 
1099  done_config = true;
1100 
1101  return 0;
1102 }
1103 
1104 /** Initialise libldap and check library versions
1105  *
1106  * @return
1107  * - 0 on success.
1108  * - -1 on failure.
1109  */
1110 int fr_ldap_init(void)
1111 {
1112  int ldap_errno;
1113  static LDAPAPIInfo info = { .ldapai_info_version = LDAP_API_INFO_VERSION }; /* static to quiet valgrind about this being uninitialised */
1114  fr_ldap_config_t *handle_config = &ldap_global_handle_config;
1115 
1116  /*
1117  * Only needs to be done once, prevents races in environment
1118  * initialisation within libldap.
1119  *
1120  * See: https://github.com/arr2036/ldapperf/issues/2
1121  */
1122  ldap_initialize(&ldap_global_handle, "");
1123 
1124  if (!ldap_global_handle) {
1125  ERROR("Failed initialising global LDAP handle");
1126  return -1;
1127  }
1128 
1129  ldap_errno = ldap_get_option(NULL, LDAP_OPT_API_INFO, &info);
1130  if (ldap_errno == LDAP_OPT_SUCCESS) {
1131  /*
1132  * Don't generate warnings if the compile type vendor name
1133  * is found within the link time vendor name.
1134  *
1135  * This allows the server to be built against OpenLDAP but
1136  * run with Symas OpenLDAP.
1137  */
1138  if (strcasestr(info.ldapai_vendor_name, LDAP_VENDOR_NAME) == NULL) {
1139  WARN("ldap - libldap vendor changed since the server was built");
1140  WARN("ldap - linked: %s, built: %s", info.ldapai_vendor_name, LDAP_VENDOR_NAME);
1141  }
1142 
1143  if (info.ldapai_vendor_version < LDAP_VENDOR_VERSION) {
1144  WARN("ldap - libldap older than the version the server was built against");
1145  WARN("ldap - linked: %i, built: %i",
1146  info.ldapai_vendor_version, LDAP_VENDOR_VERSION);
1147  }
1148 
1149  INFO("ldap - libldap vendor: %s, version: %i", info.ldapai_vendor_name,
1150  info.ldapai_vendor_version);
1151 
1152  if (info.ldapai_extensions) {
1153  char **p;
1154 
1155  for (p = info.ldapai_extensions; *p != NULL; p++) {
1156  INFO("ldap - extension: %s", *p);
1157  ldap_memfree(*p);
1158  }
1159 
1160  ldap_memfree(info.ldapai_extensions);
1161  }
1162 
1163  ldap_memfree(info.ldapai_vendor_name);
1164 
1165  } else {
1166  DEBUG("ldap - Falling back to build time libldap version info. Query for LDAP_OPT_API_INFO "
1167  "returned: %i", ldap_errno);
1168  INFO("ldap - libldap vendor: %s, version: %i.%i.%i", LDAP_VENDOR_NAME,
1169  LDAP_VENDOR_VERSION_MAJOR, LDAP_VENDOR_VERSION_MINOR, LDAP_VENDOR_VERSION_PATCH);
1170  }
1171 
1172  return 0;
1173 }
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
#define UNCONST(_type, _ptr)
Remove const qualification from a pointer.
Definition: build.h:165
#define USES_APPLE_DEPRECATED_API
Definition: build.h:431
#define RCSID(id)
Definition: build.h:444
#define L(_str)
Helper for initialising arrays of string literals.
Definition: build.h:207
#define FALL_THROUGH
clang 10 doesn't recognised the FALL-THROUGH comment anymore
Definition: build.h:320
#define UNUSED
Definition: build.h:313
#define NUM_ELEMENTS(_t)
Definition: build.h:335
#define CONF_PARSER_TERMINATOR
Definition: cf_parse.h:626
#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:423
Defines a CONF_PAIR to C data type mapping.
Definition: cf_parse.h:563
static char const * spaces
Definition: dependency.c:364
#define ERROR(fmt,...)
Definition: dhcpclient.c:41
#define DEBUG(fmt,...)
Definition: dhcpclient.c:39
static fr_time_delta_t timeout
Definition: dhcpclient.c:54
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
static void * fr_dlist_remove(fr_dlist_head_t *list_head, void *ptr)
Remove an item from the list.
Definition: dlist.h:638
#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:444
fr_trunk_request_t * treq
Trunk request this query is associated with.
Definition: base.h:451
fr_time_delta_t res_timeout
How long we wait for results.
Definition: base.h:296
char ** referral_urls
Referral results to follow.
Definition: base.h:456
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:331
char const * dn
Base DN for searches, DN for modifications.
Definition: base.h:427
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:457
fr_ldap_result_code_t ret
Result code.
Definition: base.h:465
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:349
fr_connection_t * conn
Connection state handle.
Definition: base.h:343
@ FR_LDAP_STATE_ERROR
Connection is in an error state.
Definition: base.h:171
@ 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:170
@ FR_LDAP_STATE_INIT
Connection uninitialised.
Definition: base.h:167
fr_dlist_head_t refs
Replied to queries still referencing this connection.
Definition: base.h:350
fr_ldap_config_t const * config
rlm_ldap connection configuration.
Definition: base.h:342
fr_ldap_control_t clientctrls[LDAP_MAX_CONTROLS]
Client controls specific to this query.
Definition: base.h:445
char const * tls_random_file
Path to the ramdon file if /dev/random and /dev/urandom are unavailable.
Definition: base.h:319
fr_ldap_request_type_t
Types of LDAP requests.
Definition: base.h:177
@ LDAP_REQUEST_MODIFY
A modification to an LDAP entity.
Definition: base.h:179
@ LDAP_REQUEST_SEARCH
A lookup in an LDAP directory.
Definition: base.h:178
@ LDAP_REQUEST_EXTENDED
An extended LDAP operation.
Definition: base.h:180
fr_ldap_connection_t * ldap_conn
LDAP connection this query is running on.
Definition: base.h:452
@ LDAP_RESULT_SUCCESS
Successfully got LDAP results.
Definition: base.h:188
@ LDAP_RESULT_PENDING
Result not yet returned.
Definition: base.h:187
@ LDAP_RESULT_NO_RESULT
No results returned.
Definition: base.h:192
@ LDAP_RESULT_BAD_DN
The requested DN does not exist.
Definition: base.h:191
#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:220
LDAPMessage * result
Head of LDAP results list.
Definition: base.h:463
LDAPControl * control
LDAP control.
Definition: base.h:135
#define LDAP_VENDOR_VERSION_PATCH
Definition: base.h:67
fr_trunk_t * trunk
Connection trunk.
Definition: base.h:403
uint32_t ldap_debug
LDAP debug level.
Definition: base.h:318
@ 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:442
fr_ldap_rcode_t
Codes returned by fr_ldap internal functions.
Definition: base.h:577
@ LDAP_PROC_CONTINUE
Operation is in progress.
Definition: base.h:579
@ LDAP_PROC_SUCCESS
Operation was successful.
Definition: base.h:580
@ LDAP_PROC_REFERRAL
LDAP server returned referral URLs.
Definition: base.h:578
@ LDAP_PROC_TIMEOUT
Operation timed out.
Definition: base.h:597
@ LDAP_PROC_ERROR
Unrecoverable library/server error.
Definition: base.h:582
@ LDAP_PROC_BAD_CONN
Transitory error, caller should retry the operation with a new connection.
Definition: base.h:584
@ LDAP_PROC_NOT_PERMITTED
Operation was not permitted, either current user was locked out in the case of binds,...
Definition: base.h:587
@ LDAP_PROC_REJECT
Bind failed, user was rejected.
Definition: base.h:591
@ LDAP_PROC_REFRESH_REQUIRED
Don't continue with the current refresh phase, exit, and retry the operation with a NULL cookie.
Definition: base.h:599
@ LDAP_PROC_BAD_DN
Specified an invalid object in a bind or search DN.
Definition: base.h:593
@ LDAP_PROC_NO_RESULT
Got no results.
Definition: base.h:595
LDAPURLDesc * ldap_url
parsed URL for current query if the source of the query was a URL.
Definition: base.h:424
Connection configuration.
Definition: base.h:219
Tracks the state of a libldap connection handle.
Definition: base.h:330
LDAP query structure.
Definition: base.h:420
Thread LDAP trunk structure.
Definition: base.h:397
libldap global configuration data
Definition: base.h:317
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:616
#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)
LDAP * fr_ldap_handle_thread_local(void)
Get a thread local dummy LDAP handle.
Definition: base.c:1051
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:889
fr_ldap_rcode_t fr_ldap_search_async(int *msgid, request_t *request, fr_ldap_connection_t *pconn, char const *dn, int scope, char const *filter, char const *const *attrs, LDAPControl **serverctrls, LDAPControl **clientctrls)
Search for something in the LDAP directory.
Definition: base.c:528
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
static void ldap_trunk_search_results_debug(request_t *request, fr_ldap_query_t *query)
Definition: base.c:575
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:1071
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_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:949
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:449
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:998
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:740
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:786
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:870
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:642
static int _ldap_handle_thread_local_free(void *handle)
Definition: base.c:1035
#define SET_LDAP_CTRLS(_dest, _src)
Definition: base.c:668
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:972
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:827
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:1021
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:694
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
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:1110
#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:89
long int ssize_t
Definition: merged_model.c:24
#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:775
#define RETURN_MODULE_OK
Definition: rcode.h:57
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
Definition: signal.h:48
return count
Definition: module.c:175
RETURN_MODULE_FAIL
fr_assert(0)
MEM(pair_append_request(&vp, attr_eap_aka_sim_identity) >=0)
init
Enter the EAP-IDENTITY state.
Definition: state_machine.c:90
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:253
An element in a lexicographically sorted array of name to num mappings.
Definition: table.h:45
#define fr_time_delta_wrap(_time)
Definition: time.h:152
#define fr_time_delta_ispos(_a)
Definition: time.h:288
#define fr_time_delta_to_timeval(_delta)
Convert a delta to a timeval.
Definition: time.h:654
static fr_time_delta_t fr_time_delta_from_timeval(struct timeval const *tv)
Definition: time.h:595
A time delta, a difference in time measured in nanoseconds.
Definition: time.h:80
void fr_trunk_request_signal_cancel(fr_trunk_request_t *treq)
Cancel a trunk request.
Definition: trunk.c:2047
fr_trunk_enqueue_t fr_trunk_request_enqueue(fr_trunk_request_t **treq_out, fr_trunk_t *trunk, request_t *request, void *preq, void *rctx)
Enqueue a request that needs data written to the trunk.
Definition: trunk.c:2481
@ FR_TRUNK_ENQUEUE_IN_BACKLOG
Request should be enqueued in backlog.
Definition: trunk.h:149
@ FR_TRUNK_ENQUEUE_OK
Operation was successful.
Definition: trunk.h:150
#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:336
static size_t char ** out
Definition: value.h:984