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: 39cd3e5bfe3aaf72e7b41bb62a33a46e531a9a80 $
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: 39cd3e5bfe3aaf72e7b41bb62a33a46e531a9a80 $")
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  * Depending on the state of the trunk request, the query needs to
654  * be parented by the treq so that it still exists when the
655  * cancel_mux callback is run.
656  * Other states free the trunk request (and its children) immediately.
657  * So no re-parenting is needed.
658  */
659  switch (query->treq->state) {
666  talloc_steal(query->treq, query);
667  break;
668  default:
669  break;
670  }
671 
673 
674  /*
675  * Once we've called cancel, the treq is no
676  * longer ours to manipulate, it belongs to
677  * the trunk code.
678  */
679  query->treq = NULL;
680 }
681 
682 #define SET_LDAP_CTRLS(_dest, _src) \
683 do { \
684  int i; \
685  if (!_src) break; \
686  for (i = 0; i < LDAP_MAX_CONTROLS; i++) { \
687  if (!(_src[i])) break; \
688  _dest[i].control = _src[i]; \
689  } \
690 } while (0)
691 
692 /** Run an async search LDAP query on a trunk connection
693  *
694  * @param[in] ctx to allocate the query in.
695  * @param[out] out that has been allocated.
696  * @param[in] request this query relates to.
697  * @param[in] ttrunk to submit the query to.
698  * @param[in] base_dn for the search.
699  * @param[in] scope of the search.
700  * @param[in] filter for the search.
701  * @param[in] attrs to be returned.
702  * @param[in] serverctrls specific to this query.
703  * @param[in] clientctrls specific to this query.
704  * @return
705  * - UNLANG_ACTION_FAIL on error.
706  * - UNLANG_ACTION_PUSHED_CHILD on success.
707  */
710  char const *base_dn, int scope, char const *filter, char const * const *attrs,
711  LDAPControl **serverctrls, LDAPControl **clientctrls)
712 {
713  unlang_action_t action;
714  fr_ldap_query_t *query;
715 
716  query = fr_ldap_search_alloc(ctx, base_dn, scope, filter, attrs, serverctrls, clientctrls);
717 
718  switch (trunk_request_enqueue(&query->treq, ttrunk->trunk, request, query, NULL)) {
719  case TRUNK_ENQUEUE_OK:
721  break;
722 
723  default:
724  error:
725  *out = NULL;
726  talloc_free(query);
727  return UNLANG_ACTION_FAIL;
728  }
729 
730  action = unlang_function_push(request, NULL, ldap_trunk_query_results,
731  ldap_trunk_query_cancel, ~FR_SIGNAL_CANCEL, UNLANG_SUB_FRAME, query);
732 
733  if (action == UNLANG_ACTION_FAIL) goto error;
734 
735  *out = query;
736 
738 }
739 
740 /** Run an async modification LDAP query on a trunk connection
741  *
742  * @param[in] ctx to allocate the query in.
743  * @param[out] out that has been allocated.
744  * @param[in] request this query relates to.
745  * @param[in] ttrunk to submit the query to.
746  * @param[in] dn of the object being modified.
747  * @param[in] mods to be performed.
748  * @param[in] serverctrls specific to this query.
749  * @param[in] clientctrls specific to this query.
750  * @return
751  * - UNLANG_ACTION_FAIL on error.
752  * - UNLANG_ACTION_PUSHED_CHILD on success.
753  */
756  char const *dn, LDAPMod *mods[],
757  LDAPControl **serverctrls, LDAPControl **clientctrls)
758 {
759  unlang_action_t action;
760  fr_ldap_query_t *query;
761 
762  query = fr_ldap_modify_alloc(ctx, dn, mods, serverctrls, clientctrls);
763 
764  switch (trunk_request_enqueue(&query->treq, ttrunk->trunk, request, query, NULL)) {
765  case TRUNK_ENQUEUE_OK:
767  break;
768 
769  default:
770  error:
771  *out = NULL;
772  talloc_free(query);
773  return UNLANG_ACTION_FAIL;
774  }
775 
777  ~FR_SIGNAL_CANCEL, UNLANG_SUB_FRAME, query);
778 
779  if (action == UNLANG_ACTION_FAIL) goto error;
780 
781  *out = query;
782 
784 }
785 
786 /** Modify something in the LDAP directory
787  *
788  * Used on connections bound as the administrative user to attempt to modify an LDAP object.
789  * Called by the trunk mux function
790  *
791  * @param[out] msgid LDAP message ID.
792  * @param[in] request Current request.
793  * @param[in] pconn to use.
794  * @param[in] dn of the object to modify.
795  * @param[in] mods to make, see 'man ldap_modify' for more information.
796  * @param[in] serverctrls Search controls to pass to the server. May be NULL.
797  * @param[in] clientctrls Search controls for ldap_modify. May be NULL.
798  * @return One of the LDAP_PROC_* (#fr_ldap_rcode_t) values.
799  */
801  char const *dn, LDAPMod *mods[],
802  LDAPControl **serverctrls, LDAPControl **clientctrls)
803 {
804  LDAPControl *our_serverctrls[LDAP_MAX_CONTROLS];
805  LDAPControl *our_clientctrls[LDAP_MAX_CONTROLS];
806 
807  fr_ldap_control_merge(our_serverctrls, our_clientctrls,
808  NUM_ELEMENTS(our_serverctrls),
809  NUM_ELEMENTS(our_clientctrls),
810  pconn, serverctrls, clientctrls);
811 
812  fr_assert(pconn && pconn->handle);
813 
814  if (RDEBUG_ENABLED4) fr_ldap_timeout_debug(request, pconn, fr_time_delta_wrap(0), __FUNCTION__);
815 
816  RDEBUG2("Modifying object with DN \"%s\"", dn);
817  if(ldap_modify_ext(pconn->handle, dn, mods, our_serverctrls, our_clientctrls, msgid) != LDAP_SUCCESS) {
818  fr_ldap_rcode_t ret = fr_ldap_error_check(NULL, pconn, NULL, NULL);
819  ROPTIONAL(RPEDEBUG, RPERROR, "Failed sending request to modify object");
820 
821  return ret;
822  }
823 
824  return LDAP_PROC_SUCCESS;
825 }
826 
827 /** Modify something in the LDAP directory
828  *
829  * Used on connections bound as the administrative user to attempt to modify an LDAP object.
830  * Called by the trunk mux function
831  *
832  * @param[out] msgid LDAP message ID.
833  * @param[in] request Current request.
834  * @param[in] pconn to use.
835  * @param[in] dn of the object to delete.
836  * @param[in] serverctrls Search controls to pass to the server. May be NULL.
837  * @param[in] clientctrls Search controls for ldap_delete. May be NULL.
838  * @return One of the LDAP_PROC_* (#fr_ldap_rcode_t) values.
839  */
841  char const *dn,
842  LDAPControl **serverctrls, LDAPControl **clientctrls)
843 {
844  LDAPControl *our_serverctrls[LDAP_MAX_CONTROLS];
845  LDAPControl *our_clientctrls[LDAP_MAX_CONTROLS];
846 
847  fr_ldap_control_merge(our_serverctrls, our_clientctrls,
848  NUM_ELEMENTS(our_serverctrls),
849  NUM_ELEMENTS(our_clientctrls),
850  pconn, serverctrls, clientctrls);
851 
852  fr_assert(pconn && pconn->handle);
853 
854  if (RDEBUG_ENABLED4) fr_ldap_timeout_debug(request, pconn, fr_time_delta_wrap(0), __FUNCTION__);
855 
856  RDEBUG2("Deleting object with DN \"%s\"", dn);
857  if(ldap_delete_ext(pconn->handle, dn, our_serverctrls, our_clientctrls, msgid) != LDAP_SUCCESS) {
858  fr_ldap_rcode_t ret = fr_ldap_error_check(NULL, pconn, NULL, NULL);
859  ROPTIONAL(RPEDEBUG, RPERROR, "Failed sending request to delete object");
860 
861  return ret;
862  }
863 
864  return LDAP_PROC_SUCCESS;
865 }
866 
867 /** Run an async LDAP "extended operation" query on a trunk connection
868  *
869  * @param[in] ctx to allocate the query in.
870  * @param[out] out that has been allocated.
871  * @param[in] request this query relates to.
872  * @param[in] ttrunk to submit the query to.
873  * @param[in] reqoid OID of extended operation.
874  * @param[in] reqdata Request data to send.
875  * @param[in] serverctrls specific to this query.
876  * @param[in] clientctrls specific to this query.
877  * @return
878  * - UNLANG_ACTION_FAIL on error.
879  * - UNLANG_ACTION_PUSHED_CHILD on success.
880  */
883  char const *reqoid, struct berval *reqdata,
884  LDAPControl **serverctrls, LDAPControl **clientctrls)
885 {
886  unlang_action_t action;
887  fr_ldap_query_t *query;
888 
889  query = fr_ldap_extended_alloc(ctx, reqoid, reqdata, serverctrls, clientctrls);
890 
891  switch (trunk_request_enqueue(&query->treq, ttrunk->trunk, request, query, NULL)) {
892  case TRUNK_ENQUEUE_OK:
894  break;
895 
896  default:
897  error:
898  *out = NULL;
899  talloc_free(query);
900  return UNLANG_ACTION_FAIL;
901  }
902 
904  ~FR_SIGNAL_CANCEL, UNLANG_SUB_FRAME, query);
905 
906  if (action == UNLANG_ACTION_FAIL) goto error;
907 
908  *out = query;
909 
911 }
912 
913 /** Initiate an LDAP extended operation
914  *
915  * Called by the trunk mux function
916  *
917  * @param[out] msgid LDAP message ID.
918  * @param[in] request Current request.
919  * @param[in] pconn to use.
920  * @param[in] reqoid OID of extended operation to perform.
921  * @param[in] reqdata Data required for the request.
922  * @return One of the LDAP_PROC_* (#fr_ldap_rcode_t) values.
923  */
925  char const *reqoid, struct berval *reqdata)
926 {
927  fr_assert(pconn && pconn->handle);
928 
929  RDEBUG2("Requesting extended operation with OID %s", reqoid);
930  if (ldap_extended_operation(pconn->handle, reqoid, reqdata, NULL, NULL, msgid)) {
931  fr_ldap_rcode_t ret = fr_ldap_error_check(NULL, pconn, NULL, NULL);
932  RPERROR("Failed requesting extended operation");
933  return ret;
934  }
935  return LDAP_PROC_SUCCESS;
936 }
937 
938 /** Free any libldap structures when an fr_ldap_query_t is freed
939  *
940  * It is also possible that the connection used for this query is now closed,
941  * in that instance we free it here.
942  */
944 {
945  int i;
946 
947  /*
948  * Free any results which were retrieved
949  */
950  if (query->result) ldap_msgfree(query->result);
951 
952  /*
953  * Free any server and client controls that need freeing
954  */
955  for (i = 0; i < LDAP_MAX_CONTROLS; i++) {
956  if (!query->serverctrls[i].control) break;
957  if (query->serverctrls[i].freeit) ldap_control_free(query->serverctrls[i].control);
958  }
959 
960  for (i = 0; i < LDAP_MAX_CONTROLS; i++) {
961  if (!query->clientctrls[i].control) break;
962  if (query->clientctrls[i].freeit) ldap_control_free(query->clientctrls[i].control);
963  }
964 
965  /*
966  * If a URL was parsed, free it.
967  */
968  if (query->ldap_url) ldap_free_urldesc(query->ldap_url);
969 
970  /*
971  * If any referrals were followed, the parsed referral URLS should be freed
972  */
973  if (query->referral_urls) ldap_memvfree((void **)query->referral_urls);
974 
976 
977  if (query->ldap_conn) {
978  /*
979  * Remove the query from the list of references to its connection
980  */
981  fr_dlist_remove(&query->ldap_conn->refs, query);
982 
983  /*
984  * If the connection this query was using has no pending queries and
985  * is no-longer associated with a connection_t then free it
986  */
987  if (!query->ldap_conn->conn && (fr_dlist_num_elements(&query->ldap_conn->refs) == 0) &&
988  (fr_rb_num_elements(query->ldap_conn->queries) == 0)) talloc_free(query->ldap_conn);
989  }
990 
991  /*
992  * Ensure the request data for extended operations are freed.
993  */
994  if (query->type == LDAP_REQUEST_EXTENDED && query->extended.reqdata) ber_bvfree(query->extended.reqdata);
995 
996  return 0;
997 }
998 
999 /** Allocate an fr_ldap_query_t, setting the talloc destructor
1000  *
1001  */
1002 static inline CC_HINT(always_inline)
1004 {
1005  fr_ldap_query_t *query;
1006 
1007  MEM(query = talloc_zero(ctx, fr_ldap_query_t));
1008  talloc_set_destructor(query, _ldap_query_free);
1009 
1010  query->ret = LDAP_RESULT_PENDING;
1011  query->type = type;
1012 
1013  return query;
1014 }
1015 
1016 /** Allocate a new search object
1017  *
1018  * @param[in] ctx to allocate query in.
1019  * @param[in] base_dn for the search.
1020  * @param[in] scope of the search.
1021  * @param[in] filter for the search
1022  * @param[in] attrs to request.
1023  * @param[in] serverctrls Search controls to pass to the server. May be NULL.
1024  * @param[in] clientctrls Client controls. May be NULL.
1025  */
1027  char const *base_dn, int scope, char const *filter, char const * const * attrs,
1028  LDAPControl **serverctrls, LDAPControl **clientctrls)
1029 {
1030  fr_ldap_query_t *query;
1031 
1032  query = ldap_query_alloc(ctx, LDAP_REQUEST_SEARCH);
1033  query->dn = base_dn;
1034  query->search.scope = scope;
1035  query->search.filter = filter;
1036  query->search.attrs = UNCONST(char const **, attrs);
1037  SET_LDAP_CTRLS(query->serverctrls, serverctrls);
1038  SET_LDAP_CTRLS(query->clientctrls, clientctrls);
1039 
1040  return query;
1041 }
1042 
1043 /** Allocate a new LDAP modify object
1044  *
1045  * @param[in] ctx to allocate the query in.
1046  * @param[in] dn of the object to modify.
1047  * @param[in] mods to apply to the object.
1048  * @param[in] serverctrls Controls to pass to the server. May be NULL.
1049  * @param[in] clientctrls Client controls. May be NULL.
1050  * @return LDAP query object
1051  */
1052 fr_ldap_query_t *fr_ldap_modify_alloc(TALLOC_CTX *ctx, char const *dn,
1053  LDAPMod *mods[], LDAPControl **serverctrls, LDAPControl **clientctrls)
1054 {
1055  fr_ldap_query_t *query;
1056 
1057  query = ldap_query_alloc(ctx, LDAP_REQUEST_MODIFY);
1058  query->dn = dn;
1059  query->mods = mods;
1060  SET_LDAP_CTRLS(query->serverctrls, serverctrls);
1061  SET_LDAP_CTRLS(query->clientctrls, clientctrls);
1062 
1063  return query;
1064 }
1065 
1066 /** Allocate a new LDAP extended operations object
1067  *
1068  * @param[in] ctx to allocate the query in.
1069  * @param[in] reqoid OID of extended operation to perform.
1070  * @param[in] reqdata Request data to send.
1071  * @param[in] serverctrls Controls to pass to the server. May be NULL.
1072  * @param[in] clientctrls Client controls. May be NULL.
1073  * @return LDAP query object
1074  */
1075 fr_ldap_query_t *fr_ldap_extended_alloc(TALLOC_CTX *ctx, char const *reqoid, struct berval *reqdata,
1076  LDAPControl **serverctrls, LDAPControl **clientctrls)
1077 {
1078  fr_ldap_query_t *query;
1079 
1081  query->extended.reqoid = reqoid;
1082  query->extended.reqdata = reqdata;
1083  SET_LDAP_CTRLS(query->serverctrls, serverctrls);
1084  SET_LDAP_CTRLS(query->clientctrls, clientctrls);
1085 
1086  return (query);
1087 }
1088 
1089 static int _ldap_handle_thread_local_free(void *handle)
1090 {
1091  if (ldap_unbind_ext_s(handle, NULL, NULL) < 0) return -1;
1092  return 0;
1093 }
1094 
1095 /** Get a thread local dummy LDAP handle
1096  *
1097  * Many functions in the OpenLDAP API don't actually use the handle
1098  * for anything other than writing out error codes.
1099  *
1100  * This is true for most of the LDAP extensions API functions.
1101  *
1102  * This gives us a reusable handle that was can pass to those
1103  * functions when we don't already have one available.
1104  */
1106 {
1107  if (!ldap_thread_local_handle) {
1108  LDAP *handle;
1109 
1110  ldap_initialize(&handle, "");
1111 
1113  }
1114 
1115  return ldap_thread_local_handle;
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  */
1125 int fr_ldap_global_config(int debug_level, char const *tls_random_file)
1126 {
1127  static bool done_config;
1128  fr_ldap_config_t *handle_config = &ldap_global_handle_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  */
1164 int fr_ldap_init(void)
1165 {
1166  int ldap_errno;
1167  static LDAPAPIInfo info = { .ldapai_info_version = LDAP_API_INFO_VERSION }; /* static to quiet valgrind about this being uninitialised */
1168  fr_ldap_config_t *handle_config = &ldap_global_handle_config;
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  ldap_initialize(&ldap_global_handle, "");
1177 
1178  if (!ldap_global_handle) {
1179  ERROR("Failed initialising global LDAP handle");
1180  return -1;
1181  }
1182 
1183  ldap_errno = ldap_get_option(NULL, LDAP_OPT_API_INFO, &info);
1184  if (ldap_errno == LDAP_OPT_SUCCESS) {
1185  /*
1186  * Don't generate warnings if the compile type vendor name
1187  * is found within the link time vendor name.
1188  *
1189  * This allows the server to be built against OpenLDAP but
1190  * run with Symas OpenLDAP.
1191  */
1192  if (strcasestr(info.ldapai_vendor_name, LDAP_VENDOR_NAME) == NULL) {
1193  WARN("ldap - libldap vendor changed since the server was built");
1194  WARN("ldap - linked: %s, built: %s", info.ldapai_vendor_name, LDAP_VENDOR_NAME);
1195  }
1196 
1197  if (info.ldapai_vendor_version < LDAP_VENDOR_VERSION) {
1198  WARN("ldap - libldap older than the version the server was built against");
1199  WARN("ldap - linked: %i, built: %i",
1200  info.ldapai_vendor_version, LDAP_VENDOR_VERSION);
1201  }
1202 
1203  INFO("ldap - libldap vendor: %s, version: %i", info.ldapai_vendor_name,
1204  info.ldapai_vendor_version);
1205 
1206  if (info.ldapai_extensions) {
1207  char **p;
1208 
1209  for (p = info.ldapai_extensions; *p != NULL; p++) {
1210  INFO("ldap - extension: %s", *p);
1211  ldap_memfree(*p);
1212  }
1213 
1214  ldap_memfree(info.ldapai_extensions);
1215  }
1216 
1217  ldap_memfree(info.ldapai_vendor_name);
1218 
1219  } else {
1220  DEBUG("ldap - Falling back to build time libldap version info. Query for LDAP_OPT_API_INFO "
1221  "returned: %i", ldap_errno);
1222  INFO("ldap - libldap vendor: %s, version: %i.%i.%i", LDAP_VENDOR_NAME,
1223  LDAP_VENDOR_VERSION_MAJOR, LDAP_VENDOR_VERSION_MINOR, LDAP_VENDOR_VERSION_PATCH);
1224  }
1225 
1226  return 0;
1227 }
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:468
#define RCSID(id)
Definition: build.h:481
#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:627
#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:422
Defines a CONF_PAIR to C data type mapping.
Definition: cf_parse.h:564
next
Definition: dcursor.h:178
fr_dcursor_eval_t void const * uctx
Definition: dcursor.h:546
static char const * spaces
Definition: dependency.c:371
#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:450
fr_time_delta_t res_timeout
How long we wait for results.
Definition: base.h:298
char ** referral_urls
Referral results to follow.
Definition: base.h:461
size_t fr_ldap_common_dn(char const *full, char const *part)
Find the place at which the two DN strings diverge.
Definition: util.c:488
LDAP * handle
libldap handle.
Definition: base.h:333
char const * dn
Base DN for searches, DN for modifications.
Definition: base.h:429
void fr_ldap_control_merge(LDAPControl *serverctrls_out[], LDAPControl *clientctrls_out[], size_t serverctrls_len, size_t clientctrls_len, fr_ldap_connection_t *conn, LDAPControl *serverctrls_in[], LDAPControl *clientctrls_in[])
Merge connection and call specific client and server controls.
Definition: control.c:48
fr_dlist_head_t referrals
List of parsed referrals.
Definition: base.h:462
fr_ldap_result_code_t ret
Result code.
Definition: base.h:470
bool freeit
Whether the control should be freed after we've finished using it.
Definition: base.h:136
fr_rb_tree_t * queries
Outstanding queries on this connection.
Definition: base.h:351
@ FR_LDAP_STATE_ERROR
Connection is in an error state.
Definition: base.h:172
@ FR_LDAP_STATE_BIND
Connection is being bound.
Definition: base.h:170
@ FR_LDAP_STATE_START_TLS
TLS is being negotiated.
Definition: base.h:169
@ FR_LDAP_STATE_RUN
Connection is muxing/demuxing requests.
Definition: base.h:171
@ FR_LDAP_STATE_INIT
Connection uninitialised.
Definition: base.h:168
trunk_request_t * treq
Trunk request this query is associated with.
Definition: base.h:456
fr_dlist_head_t refs
Replied to queries still referencing this connection.
Definition: base.h:352
fr_ldap_config_t const * config
rlm_ldap connection configuration.
Definition: base.h:344
fr_ldap_control_t clientctrls[LDAP_MAX_CONTROLS]
Client controls specific to this query.
Definition: base.h:451
char const * tls_random_file
Path to the ramdon file if /dev/random and /dev/urandom are unavailable.
Definition: base.h:321
fr_ldap_request_type_t
Types of LDAP requests.
Definition: base.h:178
@ LDAP_REQUEST_MODIFY
A modification to an LDAP entity.
Definition: base.h:180
@ LDAP_REQUEST_SEARCH
A lookup in an LDAP directory.
Definition: base.h:179
@ LDAP_REQUEST_EXTENDED
An extended LDAP operation.
Definition: base.h:182
fr_ldap_connection_t * ldap_conn
LDAP connection this query is running on.
Definition: base.h:457
@ LDAP_RESULT_SUCCESS
Successfully got LDAP results.
Definition: base.h:190
@ LDAP_RESULT_PENDING
Result not yet returned.
Definition: base.h:189
@ LDAP_RESULT_NO_RESULT
No results returned.
Definition: base.h:194
@ LDAP_RESULT_BAD_DN
The requested DN does not exist.
Definition: base.h:193
#define LDAP_MAX_CONTROLS
Maximum number of client/server controls.
Definition: base.h:94
char const * name
Name of the module that created this connection.
Definition: base.h:222
LDAPMessage * result
Head of LDAP results list.
Definition: base.h:468
LDAPControl * control
LDAP control.
Definition: base.h:135
#define LDAP_VENDOR_VERSION_PATCH
Definition: base.h:67
trunk_t * trunk
Connection trunk.
Definition: base.h:405
connection_t * conn
Connection state handle.
Definition: base.h:345
uint32_t ldap_debug
LDAP debug level.
Definition: base.h:320
@ LDAP_EXT_BINDPW
Specifies the password for an LDAP bind.
Definition: base.h:125
@ LDAP_EXT_BINDNAME
Specifies the user DN or name for an LDAP bind.
Definition: base.h:124
fr_ldap_request_type_t type
What type of query this is.
Definition: base.h:448
fr_ldap_rcode_t
Codes returned by fr_ldap internal functions.
Definition: base.h:582
@ LDAP_PROC_CONTINUE
Operation is in progress.
Definition: base.h:584
@ LDAP_PROC_SUCCESS
Operation was successful.
Definition: base.h:585
@ LDAP_PROC_REFERRAL
LDAP server returned referral URLs.
Definition: base.h:583
@ LDAP_PROC_TIMEOUT
Operation timed out.
Definition: base.h:602
@ LDAP_PROC_ERROR
Unrecoverable library/server error.
Definition: base.h:587
@ LDAP_PROC_BAD_CONN
Transitory error, caller should retry the operation with a new connection.
Definition: base.h:589
@ LDAP_PROC_NOT_PERMITTED
Operation was not permitted, either current user was locked out in the case of binds,...
Definition: base.h:592
@ LDAP_PROC_REJECT
Bind failed, user was rejected.
Definition: base.h:596
@ LDAP_PROC_REFRESH_REQUIRED
Don't continue with the current refresh phase, exit, and retry the operation with a NULL cookie.
Definition: base.h:604
@ LDAP_PROC_BAD_DN
Specified an invalid object in a bind or search DN.
Definition: base.h:598
@ LDAP_PROC_NO_RESULT
Got no results.
Definition: base.h:600
LDAPURLDesc * ldap_url
parsed URL for current query if the source of the query was a URL.
Definition: base.h:426
Connection configuration.
Definition: base.h:221
Tracks the state of a libldap connection handle.
Definition: base.h:332
LDAP query structure.
Definition: base.h:422
Thread LDAP trunk structure.
Definition: base.h:399
libldap global configuration data
Definition: base.h:319
static fr_libldap_global_config_t libldap_global_config
Definition: base.c:94
static unlang_action_t ldap_trunk_query_results(rlm_rcode_t *p_result, UNUSED int *priority, request_t *request, void *uctx)
Handle the return code from parsed LDAP results to set the module rcode.
Definition: base.c: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:1105
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:943
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:1125
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:1003
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:1052
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:754
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:800
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:924
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
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:840
static int _ldap_handle_thread_local_free(void *handle)
Definition: base.c:1089
#define SET_LDAP_CTRLS(_dest, _src)
Definition: base.c:682
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:1026
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:881
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:1075
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:708
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:1164
#define PERROR(_fmt,...)
Definition: log.h:228
#define REXDENT()
Exdent (unindent) R* messages by one level.
Definition: log.h:443
#define ROPTIONAL(_l_request, _l_global, _fmt,...)
Use different logging functions depending on whether request is NULL or not.
Definition: log.h:528
#define RDEBUG3(fmt,...)
Definition: log.h:343
#define DEBUG_ENABLED4
True if global debug level 1-3 messages are enabled.
Definition: log.h:260
#define DEBUG4(_fmt,...)
Definition: log.h:267
#define RPERROR(fmt,...)
Definition: log.h:302
#define RPEDEBUG(fmt,...)
Definition: log.h:376
#define RDEBUG4(fmt,...)
Definition: log.h:344
#define DEBUG_ENABLED3
True if global debug level 1-3 messages are enabled.
Definition: log.h:259
#define RDEBUG_ENABLED4
True if request debug level 1-4 messages are enabled.
Definition: log.h:336
#define RINDENT()
Indent R* messages by one level.
Definition: log.h:430
talloc_free(reap)
void fr_canonicalize_error(TALLOC_CTX *ctx, char **sp, char **text, ssize_t slen, char const *fmt)
Canonicalize error strings, removing tabs, and generate spaces for error marker.
Definition: log.c:90
long int ssize_t
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)
#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:163
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:772
An element in a lexicographically sorted array of name to num mappings.
Definition: table.h:49
#define fr_time_delta_wrap(_time)
Definition: time.h:152
#define fr_time_delta_ispos(_a)
Definition: time.h:290
#define fr_time_delta_to_timeval(_delta)
Convert a delta to a timeval.
Definition: time.h:656
static fr_time_delta_t fr_time_delta_from_timeval(struct timeval const *tv)
Definition: time.h:597
A time delta, a difference in time measured in nanoseconds.
Definition: time.h:80
trunk_enqueue_t trunk_request_enqueue(trunk_request_t **treq_out, trunk_t *trunk, request_t *request, void *preq, void *rctx)
Enqueue a request that needs data written to the trunk.
Definition: trunk.c:2575
void trunk_request_signal_cancel(trunk_request_t *treq)
Cancel a trunk request.
Definition: trunk.c:2140
@ TRUNK_ENQUEUE_OK
Operation was successful.
Definition: trunk.h:150
@ TRUNK_ENQUEUE_IN_BACKLOG
Request should be enqueued in backlog.
Definition: trunk.h:149
@ TRUNK_REQUEST_STATE_PARTIAL
Some of the request was written to the socket, more of it should be written later.
Definition: trunk.h:170
@ TRUNK_REQUEST_STATE_CANCEL_SENT
We've informed the remote server that the request has been cancelled.
Definition: trunk.h:185
@ TRUNK_REQUEST_STATE_CANCEL
A request on a particular socket was cancel.
Definition: trunk.h:184
@ TRUNK_REQUEST_STATE_CANCEL_PARTIAL
We partially wrote a cancellation request.
Definition: trunk.h:187
@ TRUNK_REQUEST_STATE_CANCEL_COMPLETE
Remote server has acknowledged our cancellation.
Definition: trunk.h:188
@ TRUNK_REQUEST_STATE_SENT
Was written to a socket. Waiting for a response.
Definition: trunk.h:172
#define fr_strerror_printf(_fmt,...)
Log to thread local error buffer.
Definition: strerror.h:64
#define fr_strerror_printf_push(_fmt,...)
Add a message to an existing stack of messages at the tail.
Definition: strerror.h:84
#define fr_strerror_const(_msg)
Definition: strerror.h:223
#define fr_box_time_delta(_val)
Definition: value.h:343
static size_t char ** out
Definition: value.h:997