All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
ldap.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: 8e3cd3f371984d0626890e7420f574f95688596c $
19  * @file ldap.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 SARL <info@networkradius.com>
25  * @copyright 2013-2015 The FreeRADIUS Server Project.
26  */
27 #include <freeradius-devel/radiusd.h>
28 #include <freeradius-devel/modules.h>
29 #include <freeradius-devel/rad_assert.h>
30 
31 #include <stdarg.h>
32 #include <ctype.h>
33 
34 #include "ldap.h"
35 
36 static const char specials[] = ",+\"\\<>;*=()";
37 static const char hextab[] = "0123456789abcdef";
38 
40  { "bindname", LDAP_DEREF_NEVER },
41  { "x-bindpw", LDAP_DEREF_SEARCHING },
42 
43  { NULL , -1 }
44 };
45 
46 /** Converts "bad" strings into ones which are safe for LDAP
47  *
48  * @note RFC 4515 says filter strings can only use the @verbatim <hex><hex> @endverbatim
49  * format, whereas RFC 4514 indicates that some chars in DNs, may be escaped simply
50  * with a backslash. For simplicity, we always use the hex escape sequences.
51  * In other areas where we're doing DN comparison, the DNs need to be normalised first
52  * so that they both use only hex escape sequences.
53  *
54  * @note This is a callback for xlat operations.
55  *
56  * Will escape any characters in input strings that would cause the string to be interpreted
57  * as part of a DN and or filter. Escape sequence is @verbatim <hex><hex> @endverbatim.
58  *
59  * @param request The current request.
60  * @param out Pointer to output buffer.
61  * @param outlen Size of the output buffer.
62  * @param in Raw unescaped string.
63  * @param arg Any additional arguments (unused).
64  */
65 size_t rlm_ldap_escape_func(UNUSED REQUEST *request, char *out, size_t outlen, char const *in, UNUSED void *arg)
66 {
67 
68  size_t left = outlen;
69 
70  if (*in && ((*in == ' ') || (*in == '#'))) goto encode;
71 
72  while (*in) {
73  /*
74  * Encode unsafe characters.
75  */
76  if (memchr(specials, *in, sizeof(specials) - 1)) {
77  encode:
78  /*
79  * Only 3 or less bytes available.
80  */
81  if (left <= 3) break;
82 
83  *out++ = '\\';
84  *out++ = hextab[(*in >> 4) & 0x0f];
85  *out++ = hextab[*in & 0x0f];
86  in++;
87  left -= 3;
88 
89  continue;
90  }
91 
92  if (left <= 1) break;
93 
94  /*
95  * Doesn't need encoding
96  */
97  *out++ = *in++;
98  left--;
99  }
100 
101  *out = '\0';
102 
103  return outlen - left;
104 }
105 
106 /** Converts escaped DNs and filter strings into normal
107  *
108  * @note RFC 4515 says filter strings can only use the @verbatim <hex><hex> @endverbatim
109  * format, whereas RFC 4514 indicates that some chars in DNs, may be escaped simply
110  * with a backslash..
111  *
112  * Will unescape any special characters in strings, or @verbatim <hex><hex> @endverbatim
113  * sequences.
114  *
115  * @param request The current request.
116  * @param out Pointer to output buffer.
117  * @param outlen Size of the output buffer.
118  * @param in Escaped string string.
119  * @param arg Any additional arguments (unused).
120  */
121 size_t rlm_ldap_unescape_func(UNUSED REQUEST *request, char *out, size_t outlen, char const *in, UNUSED void *arg)
122 {
123  char const *p;
124  char *c1, *c2, c3;
125  size_t freespace = outlen;
126 
127  if (outlen <= 1) return 0;
128 
129  p = in;
130  while (*p && (--freespace > 0)) {
131  if (*p != '\\') {
132  next:
133  *out++ = *p++;
134  continue;
135  }
136 
137  p++;
138 
139  /* It's an escaped special, just remove the slash */
140  if (memchr(specials, *in, sizeof(specials) - 1)) {
141  *out++ = *p++;
142  continue;
143  }
144 
145  /* Is a hex sequence */
146  if (!(c1 = memchr(hextab, tolower(p[0]), 16)) ||
147  !(c2 = memchr(hextab, tolower(p[1]), 16))) goto next;
148  c3 = ((c1 - hextab) << 4) + (c2 - hextab);
149 
150  *out++ = c3;
151  p += 2;
152  }
153 
154  *out = '\0';
155 
156  return outlen - freespace;
157 }
158 
159 
160 /** Check whether a string looks like a DN
161  *
162  * @param[in] in Str to check.
163  * @param[in] inlen Length of string to check.
164  * @return
165  * - true if string looks like a DN.
166  * - false if string does not look like DN.
167  */
168 bool rlm_ldap_is_dn(char const *in, size_t inlen)
169 {
170  char const *p;
171 
172  char want = '=';
173  bool too_soon = true;
174  int comp = 1;
175 
176  for (p = in; inlen > 0; p++, inlen--) {
177  if (p[0] == '\\') {
178  char c;
179 
180  too_soon = false;
181 
182  /*
183  * Invalid escape sequence, not a DN
184  */
185  if (inlen < 2) return false;
186 
187  /*
188  * Double backslash, consume two chars
189  */
190  if (p[1] == '\\') {
191  inlen--;
192  p++;
193  continue;
194  }
195 
196  /*
197  * Special, consume two chars
198  */
199  switch (p[1]) {
200  case ' ':
201  case '#':
202  case '=':
203  case '"':
204  case '+':
205  case ',':
206  case ';':
207  case '<':
208  case '>':
209  case '\'':
210  inlen -= 1;
211  p += 1;
212  continue;
213 
214  default:
215  break;
216  }
217 
218  /*
219  * Invalid escape sequence, not a DN
220  */
221  if (inlen < 3) return false;
222 
223  /*
224  * Hex encoding, consume three chars
225  */
226  if (fr_hex2bin((uint8_t *) &c, 1, p + 1, 2) == 1) {
227  inlen -= 2;
228  p += 2;
229  continue;
230  }
231 
232  /*
233  * Invalid escape sequence, not a DN
234  */
235  return false;
236  }
237 
238  switch (*p) {
239  case '=':
240  if (too_soon || (*p != want)) return false; /* Too soon after last , or = */
241  want = ',';
242  too_soon = true;
243  break;
244 
245  case ',':
246  if (too_soon || (*p != want)) return false; /* Too soon after last , or = */
247  want = '=';
248  too_soon = true;
249  comp++;
250  break;
251 
252  default:
253  too_soon = false;
254  break;
255  }
256  }
257 
258  /*
259  * If the string ended with , or =, or the number
260  * of components was less than 2
261  *
262  * i.e. we don't have <attr>=<val>,<attr>=<val>
263  */
264  if (too_soon || (comp < 2)) return false;
265 
266  return true;
267 }
268 
269 /** Convert a berval to a talloced string
270  *
271  * The ldap_get_values function is deprecated, and ldap_get_values_len
272  * does not guarantee the berval buffers it returns are \0 terminated.
273  *
274  * For some cases this is fine, for others we require a \0 terminated
275  * buffer (feeding DNs back into libldap for example).
276  *
277  * @param ctx to allocate in.
278  * @param in Berval to copy.
279  * @return \0 terminated buffer containing in->bv_val.
280  */
281 char *rlm_ldap_berval_to_string(TALLOC_CTX *ctx, struct berval const *in)
282 {
283  char *out;
284 
285  out = talloc_array(ctx, char, in->bv_len + 1);
286  if (!out) return NULL;
287 
288  memcpy(out, in->bv_val, in->bv_len);
289  out[in->bv_len] = '\0';
290 
291  return out;
292 }
293 
294 /** Normalise escape sequences in a DN
295  *
296  * Characters in a DN can either be escaped as
297  * @verbatim <hex><hex> @endverbatim or @verbatim <special> @endverbatim
298  *
299  * The LDAP directory chooses how characters are escaped, which can make
300  * local comparisons of DNs difficult.
301  *
302  * Here we search for hex sequences that match special chars, and convert
303  * them to the @verbatim <special> @endverbatim form.
304  *
305  * @note the resulting output string will only ever be shorter than the
306  * input, so it's fine to use the same buffer for both out and in.
307  *
308  * @param out Where to write the normalised DN.
309  * @param in The input DN.
310  * @return The number of bytes written to out.
311  */
312 size_t rlm_ldap_normalise_dn(char *out, char const *in)
313 {
314  char const *p;
315  char *o = out;
316 
317  for (p = in; *p != '\0'; p++) {
318  if (p[0] == '\\') {
319  char c;
320 
321  /*
322  * Double backslashes get processed specially
323  */
324  if (p[1] == '\\') {
325  p += 1;
326  *o++ = p[0];
327  *o++ = p[1];
328  continue;
329  }
330 
331  /*
332  * Hex encodings that have an alternative
333  * special encoding, get rewritten to the
334  * special encoding.
335  */
336  if (fr_hex2bin((uint8_t *) &c, 1, p + 1, 2) == 1) {
337  switch (c) {
338  case ' ':
339  case '#':
340  case '=':
341  case '"':
342  case '+':
343  case ',':
344  case ';':
345  case '<':
346  case '>':
347  case '\'':
348  *o++ = '\\';
349  *o++ = c;
350  p += 2;
351  continue;
352 
353  default:
354  break;
355  }
356  }
357  }
358  *o++ = *p;
359  }
360  *o = '\0';
361 
362  return o - out;
363 }
364 
365 /** Find the place at which the two DN strings diverge
366  *
367  * Returns the length of the non matching string in full.
368  *
369  * @param full DN.
370  * @param part Partial DN as returned by ldap_parse_result.
371  * @return
372  * - Length of the portion of full which wasn't matched
373  * - -1 on failure.
374  */
375 static size_t rlm_ldap_common_dn(char const *full, char const *part)
376 {
377  size_t f_len, p_len, i;
378 
379  if (!full) {
380  return -1;
381  }
382 
383  f_len = strlen(full);
384 
385  if (!part) {
386  return -1;
387  }
388 
389  p_len = strlen(part);
390  if (!p_len) {
391  return f_len;
392  }
393 
394  if ((f_len < p_len) || !f_len) {
395  return -1;
396  }
397 
398  for (i = 0; i < p_len; i++) {
399  if (part[p_len - i] != full[f_len - i]) {
400  return -1;
401  }
402  }
403 
404  return f_len - p_len;
405 }
406 
407 /** Combine and expand filters
408  *
409  * @param request Current request.
410  * @param out Where to write the expanded string.
411  * @param outlen Length of output buffer.
412  * @param sub Array of subfilters (may contain NULLs).
413  * @param sublen Number of potential subfilters in array.
414  * @return length of expanded data.
415  */
416 ssize_t rlm_ldap_xlat_filter(REQUEST *request, char const **sub, size_t sublen, char *out, size_t outlen)
417 {
418  char buffer[LDAP_MAX_FILTER_STR_LEN + 1];
419  char const *in = NULL;
420  char *p = buffer;
421 
422  ssize_t len = 0;
423 
424  unsigned int i;
425  int cnt = 0;
426 
427  /*
428  * Figure out how many filter elements we need to integrate
429  */
430  for (i = 0; i < sublen; i++) {
431  if (sub[i] && *sub[i]) {
432  in = sub[i];
433  cnt++;
434  }
435  }
436 
437  if (!cnt) {
438  out[0] = '\0';
439  return 0;
440  }
441 
442  if (cnt > 1) {
443  if (outlen < 3) {
444  goto oob;
445  }
446 
447  p[len++] = '(';
448  p[len++] = '&';
449 
450  for (i = 0; i < sublen; i++) {
451  if (sub[i] && (*sub[i] != '\0')) {
452  len += strlcpy(p + len, sub[i], outlen - len);
453 
454  if ((size_t) len >= outlen) {
455  oob:
456  REDEBUG("Out of buffer space creating filter");
457 
458  return -1;
459  }
460  }
461  }
462 
463  if ((outlen - len) < 2) {
464  goto oob;
465  }
466 
467  p[len++] = ')';
468  p[len] = '\0';
469 
470  in = buffer;
471  }
472 
473  len = radius_xlat(out, outlen, request, in, rlm_ldap_escape_func, NULL);
474  if (len < 0) {
475  REDEBUG("Failed creating filter");
476 
477  return -1;
478  }
479 
480  return len;
481 }
482 
483 /** Return the error string associated with a handle
484  *
485  * @param conn to retrieve error from.
486  * @return error string.
487  */
488 char const *rlm_ldap_error_str(ldap_handle_t const *conn)
489 {
490  int lib_errno;
491  ldap_get_option(conn->handle, LDAP_OPT_ERROR_NUMBER, &lib_errno);
492  if (lib_errno == LDAP_SUCCESS) {
493  return "unknown";
494  }
495 
496  return ldap_err2string(lib_errno);
497 }
498 
499 /** Parse response from LDAP server dealing with any errors
500  *
501  * Should be called after an LDAP operation. Will check result of operation and if it was successful, then attempt
502  * to retrieve and parse the result.
503  *
504  * Will also produce extended error output including any messages the server sent, and information about partial
505  * DN matches.
506  *
507  * @param[in] inst of LDAP module.
508  * @param[in] conn Current connection.
509  * @param[in] msgid returned from last operation. May be -1 if no result processing is required.
510  * @param[in] dn Last search or bind DN.
511  * @param[out] result Where to write result, if NULL result will be freed.
512  * @param[out] error Where to write the error string, may be NULL, must not be freed.
513  * @param[out] extra Where to write additional error string to, may be NULL (faster) or must be freed
514  * (with talloc_free).
515  * @return One of the LDAP_PROC_* (#ldap_rcode_t) values.
516  */
517 ldap_rcode_t rlm_ldap_result(rlm_ldap_t const *inst, ldap_handle_t const *conn, int msgid, char const *dn,
518  LDAPMessage **result, char const **error, char **extra)
519 {
521 
522  int lib_errno = LDAP_SUCCESS; // errno returned by the library.
523  int srv_errno = LDAP_SUCCESS; // errno in the result message.
524 
525  char *part_dn = NULL; // Partial DN match.
526  char *our_err = NULL; // Our extended error message.
527  char *srv_err = NULL; // Server's extended error message.
528  char *p, *a;
529 
530  bool freeit = false; // Whether the message should be freed after being processed.
531  int len;
532 
533  struct timeval tv; // Holds timeout values.
534 
535  LDAPMessage *tmp_msg = NULL; // Temporary message pointer storage if we weren't provided with one.
536 
537  char const *tmp_err; // Temporary error pointer storage if we weren't provided with one.
538 
539  if (!error) error = &tmp_err;
540  *error = NULL;
541 
542  if (extra) *extra = NULL;
543  if (result) *result = NULL;
544 
545  /*
546  * We always need the result, but our caller may not
547  */
548  if (!result) {
549  result = &tmp_msg;
550  freeit = true;
551  }
552 
553  /*
554  * Check if there was an error sending the request
555  */
556  ldap_get_option(conn->handle, LDAP_OPT_ERROR_NUMBER, &lib_errno);
557  if (lib_errno != LDAP_SUCCESS) goto process_error;
558  if (msgid < 0) return LDAP_SUCCESS; /* No msgid and no error, return now */
559 
560  memset(&tv, 0, sizeof(tv));
561  tv.tv_sec = inst->res_timeout;
562 
563  /*
564  * Now retrieve the result and check for errors
565  * ldap_result returns -1 on failure, and 0 on timeout
566  */
567  lib_errno = ldap_result(conn->handle, msgid, 1, &tv, result);
568  if (lib_errno == 0) {
569  lib_errno = LDAP_TIMEOUT;
570 
571  goto process_error;
572  }
573 
574  if (lib_errno == -1) {
575  ldap_get_option(conn->handle, LDAP_OPT_ERROR_NUMBER, &lib_errno);
576 
577  goto process_error;
578  }
579 
580  /*
581  * Parse the result and check for errors sent by the server
582  */
583  lib_errno = ldap_parse_result(conn->handle, *result,
584  &srv_errno,
585  extra ? &part_dn : NULL,
586  extra ? &srv_err : NULL,
587  NULL, NULL, freeit);
588  if (freeit) *result = NULL;
589 
590  if (lib_errno != LDAP_SUCCESS) {
591  ldap_get_option(conn->handle, LDAP_OPT_ERROR_NUMBER, &lib_errno);
592  goto process_error;
593  }
594 
595 process_error:
596  if ((lib_errno == LDAP_SUCCESS) && (srv_errno != LDAP_SUCCESS)) {
597  lib_errno = srv_errno;
598  } else if ((lib_errno != LDAP_SUCCESS) && (srv_errno == LDAP_SUCCESS)) {
599  srv_errno = lib_errno;
600  }
601 
602  switch (lib_errno) {
603  case LDAP_SUCCESS:
604  *error = "Success";
605  break;
606 
607  case LDAP_SASL_BIND_IN_PROGRESS:
608  *error = "Continuing";
609  status = LDAP_PROC_CONTINUE;
610  break;
611 
612  case LDAP_NO_SUCH_OBJECT:
613  *error = "The specified DN wasn't found";
614  status = LDAP_PROC_BAD_DN;
615 
616  if (!extra) break;
617 
618  /*
619  * Build our own internal diagnostic string
620  */
621  len = rlm_ldap_common_dn(dn, part_dn);
622  if (len < 0) break;
623 
624  our_err = talloc_typed_asprintf(conn, "Match stopped here: [%.*s]%s", len, dn, part_dn ? part_dn : "");
625  goto error_string;
626 
627  case LDAP_INSUFFICIENT_ACCESS:
628  *error = "Insufficient access. Check the identity and password configuration directives";
629  status = LDAP_PROC_NOT_PERMITTED;
630  break;
631 
632  case LDAP_UNWILLING_TO_PERFORM:
633  *error = "Server was unwilling to perform";
634  status = LDAP_PROC_NOT_PERMITTED;
635  break;
636 
637  case LDAP_FILTER_ERROR:
638  *error = "Bad search filter";
639  status = LDAP_PROC_ERROR;
640  break;
641 
642  case LDAP_TIMEOUT:
643  *error = "Timed out while waiting for server to respond";
644  goto timeout;
645 
646  case LDAP_TIMELIMIT_EXCEEDED:
647  *error = "Time limit exceeded";
648  timeout:
649  exec_trigger(NULL, inst->cs, "modules.ldap.timeout", true);
650  /* FALL-THROUGH */
651 
652  case LDAP_BUSY:
653  case LDAP_UNAVAILABLE:
654  case LDAP_SERVER_DOWN:
655  status = LDAP_PROC_RETRY;
656  goto error_string;
657 
658  case LDAP_INVALID_CREDENTIALS:
659  case LDAP_CONSTRAINT_VIOLATION:
660  status = LDAP_PROC_REJECT;
661  goto error_string;
662 
663  case LDAP_OPERATIONS_ERROR:
664  *error = "Please set 'chase_referrals=yes' and 'rebind=yes'. See the ldap module configuration "
665  "for details.";
666 
667  /* FALL-THROUGH */
668  default:
669  status = LDAP_PROC_ERROR;
670 
671  error_string:
672  if (!*error) *error = ldap_err2string(lib_errno);
673 
674  if (!extra || ((lib_errno == srv_errno) && !our_err && !srv_err)) break;
675 
676  /*
677  * Output the error codes from the library and server
678  */
679  p = talloc_zero_array(conn, char, 1);
680  if (!p) break;
681 
682  if (lib_errno != srv_errno) {
683  a = talloc_asprintf_append(p, "LDAP lib error: %s (%u), srv error: %s (%u). ",
684  ldap_err2string(lib_errno), lib_errno,
685  ldap_err2string(srv_errno), srv_errno);
686  if (!a) {
687  talloc_free(p);
688  break;
689  }
690 
691  p = a;
692  }
693 
694  if (our_err) {
695  a = talloc_asprintf_append_buffer(p, "%s. ", our_err);
696  if (!a) {
697  talloc_free(p);
698  break;
699  }
700 
701  p = a;
702  }
703 
704  if (srv_err) {
705  a = talloc_asprintf_append_buffer(p, "Server said: %s. ", srv_err);
706  if (!a) {
707  talloc_free(p);
708  break;
709  }
710 
711  p = a;
712  }
713 
714  *extra = p;
715 
716  break;
717  }
718 
719  /*
720  * Cleanup memory
721  */
722  if (srv_err) ldap_memfree(srv_err);
723  if (part_dn) ldap_memfree(part_dn);
724 
725  talloc_free(our_err);
726 
727  if ((status < 0) && *result) {
728  ldap_msgfree(*result);
729  *result = NULL;
730  }
731 
732  return status;
733 }
734 
735 
736 /** Bind to the LDAP directory as a user
737  *
738  * Performs a simple bind to the LDAP directory, and handles any errors that occur.
739  *
740  * @param[in] inst rlm_ldap configuration.
741  * @param[in] request Current request, this may be NULL, in which case all debug logging is done with radlog.
742  * @param[in,out] pconn to use. May change as this function calls functions which auto re-connect.
743  * @param[in] dn of the user, may be NULL to bind anonymously.
744  * @param[in] password of the user, may be NULL if no password is specified.
745  * @param[in] sasl mechanism to use for bind, and additional parameters.
746  * @param[in] retry if the server is down.
747  * @param[in] serverctrls Search controls to pass to the server. Only used for SASL binds. May be NULL.
748  * @param[in] clientctrls Search controls for sasl_bind. Only used for SASL binds. May be NULL.
749  * @return One of the LDAP_PROC_* (#ldap_rcode_t) values.
750  */
751 ldap_rcode_t rlm_ldap_bind(rlm_ldap_t const *inst, REQUEST *request, ldap_handle_t **pconn, char const *dn,
752  char const *password, ldap_sasl *sasl, bool retry,
753  LDAPControl **serverctrls, LDAPControl **clientctrls
754  )
755 {
756  ldap_rcode_t status = LDAP_PROC_ERROR;
757 
758  int msgid = -1;
759 
760  char const *error = NULL;
761  char *extra = NULL;
762 
763  int i, num;
764 
765  rad_assert(*pconn && (*pconn)->handle);
766  rad_assert(!retry || inst->pool);
767 
768 #ifndef WITH_SASL
769  rad_assert(!sasl->mech);
770 #endif
771 
772  /*
773  * Bind as anonymous user
774  */
775  if (!dn) dn = "";
776 
777  /*
778  * For sanity, for when no connections are viable,
779  * and we can't make a new one.
780  */
781  num = retry ? fr_connection_pool_state(inst->pool)->num : 0;
782  for (i = num; i >= 0; i--) {
783 #ifdef WITH_SASL
784  if (sasl && sasl->mech) {
785  status = rlm_ldap_sasl_interactive(inst, request, *pconn, dn, password, sasl,
786  serverctrls, clientctrls, &error, &extra);
787  } else
788 #endif
789  {
790  int ret;
791  struct berval cred;
792 
793  memcpy(&cred.bv_val, &password, sizeof(cred.bv_val));
794  cred.bv_len = talloc_array_length(password) - 1;
795 
796  ret = ldap_sasl_bind((*pconn)->handle, dn, LDAP_SASL_SIMPLE, &cred,
797  serverctrls, clientctrls, &msgid);
798  /* We got a valid message ID */
799  if ((ret == 0) && (msgid >= 0)) {
800  MOD_ROPTIONAL(RDEBUG2, DEBUG2, "Waiting for bind result...");
801  }
802 
803  status = rlm_ldap_result(inst, *pconn, msgid, dn, NULL, &error, &extra);
804  }
805 
806  switch (status) {
807  case LDAP_PROC_SUCCESS:
808  LDAP_DBG_REQ("Bind successful");
809  break;
810 
812  LDAP_ERR_REQ("Bind was not permitted: %s", error);
813  LDAP_EXT_REQ();
814 
815  break;
816 
817  case LDAP_PROC_REJECT:
818  LDAP_ERR_REQ("Bind credentials incorrect: %s", error);
819  LDAP_EXT_REQ();
820 
821  break;
822 
823  case LDAP_PROC_RETRY:
824  if (retry) {
825  *pconn = fr_connection_reconnect(inst->pool, *pconn);
826  if (*pconn) {
827  LDAP_DBGW_REQ("Bind with %s to %s failed: %s. Got new socket, retrying...",
828  *dn ? dn : "(anonymous)", inst->server, error);
829 
830  talloc_free(extra); /* don't leak debug info */
831 
832  continue;
833  }
834  };
835  status = LDAP_PROC_ERROR;
836 
837  /*
838  * Were not allowed to retry, or there are no more
839  * sockets, treat this as a hard failure.
840  */
841  /* FALL-THROUGH */
842  default:
843  LDAP_ERR_REQ("Bind with %s to %s failed: %s", *dn ? dn : "(anonymous)",
844  inst->server, error);
845  LDAP_EXT_REQ();
846 
847  break;
848  }
849 
850  break;
851  }
852 
853  if (retry && (i < 0)) {
854  LDAP_ERR_REQ("Hit reconnection limit");
855  status = LDAP_PROC_ERROR;
856  }
857 
858  talloc_free(extra);
859 
860  return status; /* caller closes the connection */
861 }
862 
863 /** Search for something in the LDAP directory
864  *
865  * Binds as the administrative user and performs a search, dealing with any errors.
866  *
867  * @param[out] result Where to store the result. Must be freed with ldap_msgfree if LDAP_PROC_SUCCESS is returned.
868  * May be NULL in which case result will be automatically freed after use.
869  * @param[in] inst rlm_ldap configuration.
870  * @param[in] request Current request.
871  * @param[in,out] pconn to use. May change as this function calls functions which auto re-connect.
872  * @param[in] dn to use as base for the search.
873  * @param[in] scope to use (LDAP_SCOPE_BASE, LDAP_SCOPE_ONE, LDAP_SCOPE_SUB).
874  * @param[in] filter to use, should be pre-escaped.
875  * @param[in] attrs to retrieve.
876  * @param[in] serverctrls Search controls to pass to the server. May be NULL.
877  * @param[in] clientctrls Search controls for ldap_search. May be NULL.
878  * @return One of the LDAP_PROC_* (#ldap_rcode_t) values.
879  */
880 ldap_rcode_t rlm_ldap_search(LDAPMessage **result, rlm_ldap_t const *inst, REQUEST *request,
881  ldap_handle_t **pconn,
882  char const *dn, int scope, char const *filter, char const * const *attrs,
883  LDAPControl **serverctrls, LDAPControl **clientctrls)
884 {
885  ldap_rcode_t status = LDAP_PROC_ERROR;
886  LDAPMessage *our_result = NULL;
887 
888  int msgid; // Message id returned by
889  // ldap_search_ext.
890 
891  int count = 0; // Number of results we got.
892 
893  struct timeval tv; // Holds timeout values.
894 
895  char const *error = NULL;
896  char *extra = NULL;
897 
898  int i;
899 
900  LDAPControl *our_serverctrls[LDAP_MAX_CONTROLS];
901  LDAPControl *our_clientctrls[LDAP_MAX_CONTROLS];
902 
903  rlm_ldap_control_merge(our_serverctrls, our_clientctrls,
904  sizeof(our_serverctrls) / sizeof(*our_serverctrls),
905  sizeof(our_clientctrls) / sizeof(*our_clientctrls),
906  *pconn, serverctrls, clientctrls);
907 
908  rad_assert(*pconn && (*pconn)->handle);
909 
910  /*
911  * OpenLDAP library doesn't declare attrs array as const, but
912  * it really should be *sigh*.
913  */
914  char **search_attrs;
915  memcpy(&search_attrs, &attrs, sizeof(attrs));
916 
917  /*
918  * Do all searches as the admin user.
919  */
920  if ((*pconn)->rebound) {
921  status = rlm_ldap_bind(inst, request, pconn, (*pconn)->inst->admin_identity,
922  (*pconn)->inst->admin_password, &(*pconn)->inst->admin_sasl, true,
923  NULL, NULL);
924  if (status != LDAP_PROC_SUCCESS) {
925  return LDAP_PROC_ERROR;
926  }
927 
928  rad_assert(*pconn);
929 
930  (*pconn)->rebound = false;
931  }
932 
933  if (filter) {
934  LDAP_DBG_REQ("Performing search in \"%s\" with filter \"%s\", scope \"%s\"", dn, filter,
935  fr_int2str(ldap_scope, scope, "<INVALID>"));
936  } else {
937  LDAP_DBG_REQ("Performing unfiltered search in \"%s\", scope \"%s\"", dn,
938  fr_int2str(ldap_scope, scope, "<INVALID>"));
939  }
940  /*
941  * If LDAP search produced an error it should also be logged
942  * to the ld. result should pick it up without us
943  * having to pass it explicitly.
944  */
945  memset(&tv, 0, sizeof(tv));
946  tv.tv_sec = inst->res_timeout;
947 
948  /*
949  * For sanity, for when no connections are viable,
950  * and we can't make a new one.
951  */
952  for (i = fr_connection_pool_state(inst->pool)->num; i >= 0; i--) {
953  (void) ldap_search_ext((*pconn)->handle, dn, scope, filter, search_attrs,
954  0, our_serverctrls, our_clientctrls, &tv, 0, &msgid);
955 
956  LDAP_DBG_REQ("Waiting for search result...");
957  status = rlm_ldap_result(inst, *pconn, msgid, dn, &our_result, &error, &extra);
958  switch (status) {
959  case LDAP_PROC_SUCCESS:
960  break;
961 
962  /*
963  * Invalid DN isn't a failure when searching.
964  * The DN may be xlat expanded so may point directly
965  * to an LDAP object. If that can't be located, it's
966  * the same as notfound.
967  */
968  case LDAP_PROC_BAD_DN:
969  LDAP_DBG_REQ("%s", error);
970  if (extra) LDAP_DBG_REQ("%s", extra);
971  break;
972 
973  case LDAP_PROC_RETRY:
974  *pconn = fr_connection_reconnect(inst->pool, *pconn);
975  if (*pconn) {
976  LDAP_DBGW_REQ("Search failed: %s. Got new socket, retrying...", error);
977 
978  talloc_free(extra); /* don't leak debug info */
979 
980  continue;
981  }
982 
983  status = LDAP_PROC_ERROR;
984 
985  /* FALL-THROUGH */
986  default:
987  LDAP_ERR_REQ("Failed performing search: %s", error);
988  if (extra) LDAP_ERR_REQ("%s", extra);
989 
990  goto finish;
991  }
992 
993  break;
994  }
995 
996  if (i < 0) {
997  LDAP_ERR_REQ("Hit reconnection limit");
998  status = LDAP_PROC_ERROR;
999 
1000  goto finish;
1001  }
1002 
1003  count = ldap_count_entries((*pconn)->handle, our_result);
1004  if (count < 0) {
1005  LDAP_ERR_REQ("Error counting results: %s", rlm_ldap_error_str(*pconn));
1006  status = LDAP_PROC_ERROR;
1007 
1008  ldap_msgfree(our_result);
1009  our_result = NULL;
1010  } else if (count == 0) {
1011  LDAP_DBG_REQ("Search returned no results");
1012  status = LDAP_PROC_NO_RESULT;
1013 
1014  ldap_msgfree(our_result);
1015  our_result = NULL;
1016  }
1017 
1018 finish:
1019  talloc_free(extra);
1020 
1021  /*
1022  * We always need to get the result to count entries, but the caller
1023  * may not of requested one. If that's the case, free it, else write
1024  * it to where our caller said.
1025  */
1026  if (!result) {
1027  if (our_result) ldap_msgfree(our_result);
1028  } else {
1029  *result = our_result;
1030  }
1031 
1032  return status;
1033 }
1034 
1035 /** Modify something in the LDAP directory
1036  *
1037  * Binds as the administrative user and attempts to modify an LDAP object.
1038  *
1039  * @param[in] inst rlm_ldap configuration.
1040  * @param[in] request Current request.
1041  * @param[in,out] pconn to use. May change as this function calls functions which auto re-connect.
1042  * @param[in] dn of the object to modify.
1043  * @param[in] mods to make, see 'man ldap_modify' for more information.
1044  * @param[in] serverctrls Search controls to pass to the server. May be NULL.
1045  * @param[in] clientctrls Search controls for ldap_modify. May be NULL.
1046  * @return One of the LDAP_PROC_* (#ldap_rcode_t) values.
1047  */
1049  char const *dn, LDAPMod *mods[],
1050  LDAPControl **serverctrls, LDAPControl **clientctrls)
1051 {
1052  ldap_rcode_t status = LDAP_PROC_ERROR;
1053 
1054  int msgid; // Message id returned by ldap_search_ext.
1055 
1056  char const *error = NULL;
1057  char *extra = NULL;
1058 
1059  int i;
1060 
1061  LDAPControl *our_serverctrls[LDAP_MAX_CONTROLS];
1062  LDAPControl *our_clientctrls[LDAP_MAX_CONTROLS];
1063 
1064  rlm_ldap_control_merge(our_serverctrls, our_clientctrls,
1065  sizeof(our_serverctrls) / sizeof(*our_serverctrls),
1066  sizeof(our_clientctrls) / sizeof(*our_clientctrls),
1067  *pconn, serverctrls, clientctrls);
1068 
1069  rad_assert(*pconn && (*pconn)->handle);
1070 
1071  /*
1072  * Perform all modifications as the admin user.
1073  */
1074  if ((*pconn)->rebound) {
1075  status = rlm_ldap_bind(inst, request, pconn, (*pconn)->inst->admin_identity,
1076  (*pconn)->inst->admin_password, &(*pconn)->inst->admin_sasl, true,
1077  NULL, NULL);
1078  if (status != LDAP_PROC_SUCCESS) {
1079  return LDAP_PROC_ERROR;
1080  }
1081 
1082  rad_assert(*pconn);
1083 
1084  (*pconn)->rebound = false;
1085  }
1086 
1087  /*
1088  * For sanity, for when no connections are viable,
1089  * and we can't make a new one.
1090  */
1091  for (i = fr_connection_pool_state(inst->pool)->num; i >= 0; i--) {
1092  RDEBUG2("Modifying object with DN \"%s\"", dn);
1093  (void) ldap_modify_ext((*pconn)->handle, dn, mods, our_serverctrls, our_clientctrls, &msgid);
1094 
1095  RDEBUG2("Waiting for modify result...");
1096  status = rlm_ldap_result(inst, *pconn, msgid, dn, NULL, &error, &extra);
1097  switch (status) {
1098  case LDAP_PROC_SUCCESS:
1099  break;
1100 
1101  case LDAP_PROC_RETRY:
1102  *pconn = fr_connection_reconnect(inst->pool, *pconn);
1103  if (*pconn) {
1104  RWDEBUG("Modify failed: %s. Got new socket, retrying...", error);
1105 
1106  talloc_free(extra); /* don't leak debug info */
1107  continue;
1108  }
1109 
1110  status = LDAP_PROC_ERROR;
1111 
1112  /* FALL-THROUGH */
1113  default:
1114  REDEBUG("Failed modifying object: %s", error);
1115  REDEBUG("%s", extra);
1116 
1117  goto finish;
1118  }
1119 
1120  break;
1121  }
1122 
1123  if (i < 0) {
1124  LDAP_ERR_REQ("Hit reconnection limit");
1125  status = LDAP_PROC_ERROR;
1126  }
1127 
1128 finish:
1129  talloc_free(extra);
1130 
1131  return status;
1132 }
1133 
1134 /** Retrieve the DN of a user object
1135  *
1136  * Retrieves the DN of a user and adds it to the control list as LDAP-UserDN. Will also retrieve any
1137  * attributes passed and return the result in *result.
1138  *
1139  * This potentially allows for all authorization and authentication checks to be performed in one
1140  * ldap search operation, which is a big bonus given the number of crappy, slow *cough*AD*cough*
1141  * LDAP directory servers out there.
1142  *
1143  * @param[in] inst rlm_ldap configuration.
1144  * @param[in] request Current request.
1145  * @param[in,out] pconn to use. May change as this function calls functions which auto re-connect.
1146  * @param[in] attrs Additional attributes to retrieve, may be NULL.
1147  * @param[in] force Query even if the User-DN already exists.
1148  * @param[out] result Where to write the result, may be NULL in which case result is discarded.
1149  * @param[out] rcode The status of the operation, one of the RLM_MODULE_* codes.
1150  * @return The user's DN or NULL on error.
1151  */
1152 char const *rlm_ldap_find_user(rlm_ldap_t const *inst, REQUEST *request, ldap_handle_t **pconn,
1153  char const *attrs[], bool force, LDAPMessage **result, rlm_rcode_t *rcode)
1154 {
1155  static char const *tmp_attrs[] = { NULL };
1156 
1157  ldap_rcode_t status;
1158  VALUE_PAIR *vp = NULL;
1159  LDAPMessage *tmp_msg = NULL, *entry = NULL;
1160  int ldap_errno;
1161  int cnt;
1162  char *dn = NULL;
1163  char const *filter = NULL;
1164  char filter_buff[LDAP_MAX_FILTER_STR_LEN];
1165  char const *base_dn;
1166  char base_dn_buff[LDAP_MAX_DN_STR_LEN];
1167  LDAPControl *serverctrls[] = { inst->userobj_sort_ctrl, NULL };
1168 
1169  bool freeit = false; //!< Whether the message should
1170  //!< be freed after being processed.
1171 
1172  *rcode = RLM_MODULE_FAIL;
1173 
1174  if (!result) {
1175  result = &tmp_msg;
1176  freeit = true;
1177  }
1178  *result = NULL;
1179 
1180  if (!attrs) {
1181  memset(&attrs, 0, sizeof(tmp_attrs));
1182  }
1183 
1184  /*
1185  * If the caller isn't looking for the result we can just return the current userdn value.
1186  */
1187  if (!force) {
1188  vp = fr_pair_find_by_num(request->config, 0, PW_LDAP_USERDN, TAG_ANY);
1189  if (vp) {
1190  RDEBUG("Using user DN from request \"%s\"", vp->vp_strvalue);
1191  *rcode = RLM_MODULE_OK;
1192  return vp->vp_strvalue;
1193  }
1194  }
1195 
1196  /*
1197  * Perform all searches as the admin user.
1198  */
1199  if ((*pconn)->rebound) {
1200  status = rlm_ldap_bind(inst, request, pconn, (*pconn)->inst->admin_identity,
1201  (*pconn)->inst->admin_password, &(*pconn)->inst->admin_sasl, true,
1202  NULL, NULL);
1203  if (status != LDAP_PROC_SUCCESS) {
1204  *rcode = RLM_MODULE_FAIL;
1205  return NULL;
1206  }
1207 
1208  rad_assert(*pconn);
1209 
1210  (*pconn)->rebound = false;
1211  }
1212 
1213  if (inst->userobj_filter) {
1214  if (tmpl_expand(&filter, filter_buff, sizeof(filter_buff), request, inst->userobj_filter,
1215  rlm_ldap_escape_func, NULL) < 0) {
1216  REDEBUG("Unable to create filter");
1217  *rcode = RLM_MODULE_INVALID;
1218 
1219  return NULL;
1220  }
1221  }
1222 
1223  if (tmpl_expand(&base_dn, base_dn_buff, sizeof(base_dn_buff), request,
1224  inst->userobj_base_dn, rlm_ldap_escape_func, NULL) < 0) {
1225  REDEBUG("Unable to create base_dn");
1226  *rcode = RLM_MODULE_INVALID;
1227 
1228  return NULL;
1229  }
1230 
1231  status = rlm_ldap_search(result, inst, request, pconn, base_dn,
1232  inst->userobj_scope, filter, attrs, serverctrls, NULL);
1233  switch (status) {
1234  case LDAP_PROC_SUCCESS:
1235  break;
1236 
1237  case LDAP_PROC_BAD_DN:
1238  case LDAP_PROC_NO_RESULT:
1239  *rcode = RLM_MODULE_NOTFOUND;
1240  return NULL;
1241 
1242  default:
1243  *rcode = RLM_MODULE_FAIL;
1244  return NULL;
1245  }
1246 
1247  rad_assert(*pconn);
1248 
1249  /*
1250  * Forbid the use of unsorted search results that
1251  * contain multiple entries, as it's a potential
1252  * security issue, and likely non deterministic.
1253  */
1254  if (!inst->userobj_sort_ctrl) {
1255  cnt = ldap_count_entries((*pconn)->handle, *result);
1256  if (cnt > 1) {
1257  REDEBUG("Ambiguous search result, returned %i unsorted entries (should return 1 or 0). "
1258  "Enable sorting, or specify a more restrictive base_dn, filter or scope", cnt);
1259  REDEBUG("The following entries were returned:");
1260  RINDENT();
1261  for (entry = ldap_first_entry((*pconn)->handle, *result);
1262  entry;
1263  entry = ldap_next_entry((*pconn)->handle, entry)) {
1264  dn = ldap_get_dn((*pconn)->handle, entry);
1265  REDEBUG("%s", dn);
1266  ldap_memfree(dn);
1267  }
1268  REXDENT();
1269  *rcode = RLM_MODULE_FAIL;
1270  goto finish;
1271  }
1272  }
1273 
1274  entry = ldap_first_entry((*pconn)->handle, *result);
1275  if (!entry) {
1276  ldap_get_option((*pconn)->handle, LDAP_OPT_RESULT_CODE, &ldap_errno);
1277  REDEBUG("Failed retrieving entry: %s",
1278  ldap_err2string(ldap_errno));
1279 
1280  goto finish;
1281  }
1282 
1283  dn = ldap_get_dn((*pconn)->handle, entry);
1284  if (!dn) {
1285  ldap_get_option((*pconn)->handle, LDAP_OPT_RESULT_CODE, &ldap_errno);
1286  REDEBUG("Retrieving object DN from entry failed: %s", ldap_err2string(ldap_errno));
1287 
1288  goto finish;
1289  }
1290  rlm_ldap_normalise_dn(dn, dn);
1291 
1292  /*
1293  * We can't use fr_pair_make here to copy the value into the
1294  * attribute, as the dn must be copied into the attribute
1295  * verbatim (without de-escaping).
1296  *
1297  * Special chars are pre-escaped by libldap, and because
1298  * we pass the string back to libldap we must not alter it.
1299  */
1300  RDEBUG("User object found at DN \"%s\"", dn);
1301  vp = fr_pair_make(request, &request->config, "LDAP-UserDN", NULL, T_OP_EQ);
1302  if (vp) {
1303  fr_pair_value_strcpy(vp, dn);
1304  *rcode = RLM_MODULE_OK;
1305  }
1306  ldap_memfree(dn);
1307 
1308 finish:
1309  if ((freeit || (*rcode != RLM_MODULE_OK)) && *result) {
1310  ldap_msgfree(*result);
1311  *result = NULL;
1312  }
1313 
1314  return vp ? vp->vp_strvalue : NULL;
1315 }
1316 
1317 /** Check for presence of access attribute in result
1318  *
1319  * @param[in] inst rlm_ldap configuration.
1320  * @param[in] request Current request.
1321  * @param[in] conn used to retrieve access attributes.
1322  * @param[in] entry retrieved by rlm_ldap_find_user or rlm_ldap_search.
1323  * @return
1324  * - #RLM_MODULE_USERLOCK if the user was denied access.
1325  * - #RLM_MODULE_OK otherwise.
1326  */
1328  ldap_handle_t const *conn, LDAPMessage *entry)
1329 {
1330  rlm_rcode_t rcode = RLM_MODULE_OK;
1331  struct berval **values = NULL;
1332 
1333  values = ldap_get_values_len(conn->handle, entry, inst->userobj_access_attr);
1334  if (values) {
1335  if (inst->access_positive) {
1336  if ((values[0]->bv_len >= 5) && (strncasecmp(values[0]->bv_val, "false", 5) == 0)) {
1337  RDEBUG("\"%s\" attribute exists but is set to 'false' - user locked out",
1338  inst->userobj_access_attr);
1339  rcode = RLM_MODULE_USERLOCK;
1340  }
1341  /* RLM_MODULE_OK set above... */
1342  } else if ((values[0]->bv_len < 5) || (strncasecmp(values[0]->bv_val, "false", 5) != 0)) {
1343  RDEBUG("\"%s\" attribute exists - user locked out", inst->userobj_access_attr);
1344  rcode = RLM_MODULE_USERLOCK;
1345  }
1346  ldap_value_free_len(values);
1347  } else if (inst->access_positive) {
1348  RDEBUG("No \"%s\" attribute - user locked out", inst->userobj_access_attr);
1349  rcode = RLM_MODULE_USERLOCK;
1350  }
1351 
1352  return rcode;
1353 }
1354 
1355 /** Verify we got a password from the search
1356  *
1357  * Checks to see if after the LDAP to RADIUS mapping has been completed that a reference password.
1358  *
1359  * @param inst rlm_ldap configuration.
1360  * @param request Current request.
1361  */
1363 {
1364  /*
1365  * More warning messages for people who can't be bothered to read the documentation.
1366  *
1367  * Expect_password is set when we process the mapping, and is only true if there was a mapping between
1368  * an LDAP attribute and a password reference attribute in the control list.
1369  */
1370  if (inst->expect_password && (rad_debug_lvl > 1)) {
1371  if (!fr_pair_find_by_num(request->config, 0, PW_CLEARTEXT_PASSWORD, TAG_ANY) &&
1372  !fr_pair_find_by_num(request->config, 0, PW_NT_PASSWORD, TAG_ANY) &&
1373  !fr_pair_find_by_num(request->config, 0, PW_USER_PASSWORD, TAG_ANY) &&
1374  !fr_pair_find_by_num(request->config, 0, PW_PASSWORD_WITH_HEADER, TAG_ANY) &&
1375  !fr_pair_find_by_num(request->config, 0, PW_CRYPT_PASSWORD, TAG_ANY)) {
1376  RWDEBUG("No \"known good\" password added. Ensure the admin user has permission to "
1377  "read the password attribute");
1378  RWDEBUG("PAP authentication will *NOT* work with Active Directory (if that is what you "
1379  "were trying to configure)");
1380  }
1381  }
1382 }
1383 
1384 #if LDAP_SET_REBIND_PROC_ARGS == 3
1385 /** Callback for OpenLDAP to rebind and chase referrals
1386  *
1387  * Called by OpenLDAP when it receives a referral and has to rebind.
1388  *
1389  * @param handle to rebind.
1390  * @param url to bind to.
1391  * @param request that triggered the rebind.
1392  * @param msgid that triggered the rebind.
1393  * @param ctx rlm_ldap configuration.
1394  */
1395 static int rlm_ldap_rebind(LDAP *handle, LDAP_CONST char *url, UNUSED ber_tag_t request, UNUSED ber_int_t msgid,
1396  void *ctx)
1397 {
1398  ldap_rcode_t status;
1399  ldap_handle_t *conn = talloc_get_type_abort(ctx, ldap_handle_t);
1400  rlm_ldap_t *inst = conn->inst;
1401 
1402  char const *admin_identity = NULL;
1403  char const *admin_password = NULL;
1404 
1405  int ldap_errno;
1406 
1407  conn->referred = true;
1408  conn->rebound = true; /* not really, but oh well... */
1409  rad_assert(handle == conn->handle);
1410 
1411  DEBUG("rlm_ldap (%s): Rebinding to URL %s", inst->name, url);
1412 
1413 # ifdef HAVE_LDAP_URL_PARSE
1414  /*
1415  * Use bindname and x-bindpw extensions to get the bind credentials
1416  * SASL mech is inherited from the module that defined the connection
1417  * pool.
1418  */
1419  if (inst->use_referral_credentials) {
1420  LDAPURLDesc *ldap_url;
1421  int ret;
1422  char **ext;
1423 
1424  ret = ldap_url_parse(url, &ldap_url);
1425  if (ret != LDAP_SUCCESS) {
1426  ERROR("rlm_ldap (%s): Failed parsing LDAP URL \"%s\": %s",
1427  inst->name, url, ldap_err2string(ret));
1428  return -1;
1429  }
1430 
1431  /*
1432  * If there are no extensions, OpenLDAP doesn't
1433  * bother allocating an array.
1434  */
1435  for (ext = ldap_url->lud_exts; ext && *ext; ext++) {
1436  char const *p;
1437  bool critical = false;
1438 
1439  p = *ext;
1440 
1441  if (*p == '!') {
1442  critical = true;
1443  p++;
1444  }
1445 
1446  /*
1447  * LDAP Parse URL unescapes the extensions for us
1448  */
1449  switch (fr_substr2int(ldap_supported_extensions, p, LDAP_EXT_UNSUPPORTED, -1)) {
1450  case LDAP_EXT_BINDNAME:
1451  p = strchr(p, '=');
1452  if (!p) {
1453  bad_ext:
1454  ERROR("rlm_ldap (%s): Failed parsing extension \"%s\": "
1455  "No attribute/value delimiter '='", inst->name, *ext);
1456  ldap_free_urldesc(ldap_url);
1457  return LDAP_OTHER;
1458  }
1459  admin_identity = p + 1;
1460  break;
1461 
1462  case LDAP_EXT_BINDPW:
1463  p = strchr(p, '=');
1464  if (!p) goto bad_ext;
1465  admin_password = p + 1;
1466  break;
1467 
1468  default:
1469  if (critical) {
1470  ERROR("rlm_ldap (%s): Failed parsing critical extension \"%s\": "
1471  "Not supported by rlm_ldap", inst->name, *ext);
1472  ldap_free_urldesc(ldap_url);
1473  return LDAP_OTHER;
1474  }
1475  DEBUG2("rlm_ldap (%s): Skipping unsupported extension \"%s\"", inst->name, *ext);
1476  continue;
1477  }
1478  }
1479  ldap_free_urldesc(ldap_url);
1480  } else
1481 # endif
1482  {
1483  admin_identity = inst->admin_identity;
1484  admin_password = inst->admin_password;
1485  }
1486 
1487  status = rlm_ldap_bind(inst, NULL, &conn, admin_identity, admin_password,
1488  &inst->admin_sasl, false, NULL, NULL);
1489  if (status != LDAP_PROC_SUCCESS) {
1490  ldap_get_option(handle, LDAP_OPT_ERROR_NUMBER, &ldap_errno);
1491 
1492  return ldap_errno;
1493  }
1494 
1495  return LDAP_SUCCESS;
1496 }
1497 #endif
1498 
1499 /** Close and delete a connection
1500  *
1501  * Unbinds the LDAP connection, informing the server and freeing any memory, then releases the memory used by the
1502  * connection handle.
1503  *
1504  * @param conn to destroy.
1505  * @return always indicates success.
1506  */
1508 {
1509  if (conn->handle) {
1510 #ifdef HAVE_LDAP_UNBIND_EXT_S
1511  LDAPControl *our_serverctrls[LDAP_MAX_CONTROLS];
1512  LDAPControl *our_clientctrls[LDAP_MAX_CONTROLS];
1513 
1514  rlm_ldap_control_merge(our_serverctrls, our_clientctrls,
1515  sizeof(our_serverctrls) / sizeof(*our_serverctrls),
1516  sizeof(our_clientctrls) / sizeof(*our_clientctrls),
1517  conn, NULL, NULL);
1518 
1519  DEBUG3("rlm_ldap: Closing libldap handle %p", conn->handle);
1520  ldap_unbind_ext_s(conn->handle, our_serverctrls, our_clientctrls);
1521 #else
1522  DEBUG3("rlm_ldap: Closing libldap handle %p", conn->handle);
1523  ldap_unbind_s(conn->handle);
1524 #endif
1525  }
1526  rlm_ldap_control_clear(conn);
1527 
1528  return 0;
1529 }
1530 
1531 /** Create and return a new connection
1532  *
1533  * Create a new ldap connection and allocate memory for a new rlm_handle_t
1534  */
1535 void *mod_conn_create(TALLOC_CTX *ctx, void *instance, struct timeval const *timeout)
1536 {
1537  ldap_rcode_t status;
1538 
1539  int ldap_errno, ldap_version;
1540 
1541  rlm_ldap_t *inst = instance;
1542  ldap_handle_t *conn;
1543 
1544  /*
1545  * Allocate memory for the handle.
1546  */
1547  conn = talloc_zero(ctx, ldap_handle_t);
1548  if (!conn) return NULL;
1549  talloc_set_destructor(conn, _mod_conn_free);
1550 
1551  conn->inst = inst;
1552  conn->rebound = false;
1553  conn->referred = false;
1554 
1555  DEBUG("rlm_ldap (%s): Connecting to %s", inst->name, inst->server);
1556 #ifdef HAVE_LDAP_INITIALIZE
1557  ldap_errno = ldap_initialize(&conn->handle, inst->server);
1558  if (ldap_errno != LDAP_SUCCESS) {
1559  LDAP_ERR("ldap_initialize failed: %s", ldap_err2string(ldap_errno));
1560  goto error;
1561  }
1562 #else
1563  conn->handle = ldap_init(inst->server, inst->port);
1564  if (!conn->handle) {
1565  LDAP_ERR("ldap_init failed");
1566  goto error;
1567  }
1568 #endif
1569  DEBUG3("rlm_ldap (%s): New libldap handle %p", inst->name, conn->handle);
1570 
1571  /*
1572  * We now have a connection structure, but no actual connection.
1573  *
1574  * Set a bunch of LDAP options, using common code.
1575  */
1576 #define do_ldap_option(_option, _name, _value) \
1577  if (ldap_set_option(conn->handle, _option, _value) != LDAP_OPT_SUCCESS) { \
1578  ldap_get_option(conn->handle, LDAP_OPT_ERROR_NUMBER, &ldap_errno); \
1579  LDAP_ERR("Failed setting connection option %s: %s", _name, \
1580  (ldap_errno != LDAP_SUCCESS) ? ldap_err2string(ldap_errno) : "Unknown error"); \
1581  goto error;\
1582  }
1583 
1584 #define do_ldap_global_option(_option, _name, _value) \
1585  if (ldap_set_option(NULL, _option, _value) != LDAP_OPT_SUCCESS) { \
1586  ldap_get_option(conn->handle, LDAP_OPT_ERROR_NUMBER, &ldap_errno); \
1587  LDAP_ERR("Failed setting global option %s: %s", _name, \
1588  (ldap_errno != LDAP_SUCCESS) ? ldap_err2string(ldap_errno) : "Unknown error"); \
1589  goto error;\
1590  }
1591 
1592  if (inst->ldap_debug) {
1593  do_ldap_global_option(LDAP_OPT_DEBUG_LEVEL, "ldap_debug", &(inst->ldap_debug));
1594  }
1595 
1596  /*
1597  * Leave "dereference" unset to use the OpenLDAP default.
1598  */
1599  if (inst->dereference_str) {
1600  do_ldap_option(LDAP_OPT_DEREF, "dereference", &(inst->dereference));
1601  }
1602 
1603  /*
1604  * Leave "chase_referrals" unset to use the OpenLDAP default.
1605  */
1606  if (!inst->chase_referrals_unset) {
1607  if (inst->chase_referrals) {
1608  do_ldap_option(LDAP_OPT_REFERRALS, "chase_referrals", LDAP_OPT_ON);
1609 
1610  if (inst->rebind == true) {
1611 #if LDAP_SET_REBIND_PROC_ARGS == 3
1612  ldap_set_rebind_proc(conn->handle, rlm_ldap_rebind, conn);
1613 #endif
1614  }
1615  } else {
1616  do_ldap_option(LDAP_OPT_REFERRALS, "chase_referrals", LDAP_OPT_OFF);
1617  }
1618  }
1619 
1620 #ifdef LDAP_OPT_NETWORK_TIMEOUT
1621  do_ldap_option(LDAP_OPT_NETWORK_TIMEOUT, "pool.connect_timeout", &timeout);
1622 #endif
1623 
1624  do_ldap_option(LDAP_OPT_TIMELIMIT, "srv_timelimit", &(inst->srv_timelimit));
1625 
1626  ldap_version = LDAP_VERSION3;
1627  do_ldap_option(LDAP_OPT_PROTOCOL_VERSION, "ldap_version", &ldap_version);
1628 
1629 #ifdef LDAP_OPT_X_KEEPALIVE_IDLE
1630  do_ldap_option(LDAP_OPT_X_KEEPALIVE_IDLE, "keepalive_idle", &(inst->keepalive_idle));
1631 #endif
1632 
1633 #ifdef LDAP_OPT_X_KEEPALIVE_PROBES
1634  do_ldap_option(LDAP_OPT_X_KEEPALIVE_PROBES, "keepalive_probes", &(inst->keepalive_probes));
1635 #endif
1636 
1637 #ifdef LDAP_OPT_X_KEEPALIVE_INTERVAL
1638  do_ldap_option(LDAP_OPT_X_KEEPALIVE_INTERVAL, "keepalive_interval", &(inst->keepalive_interval));
1639 #endif
1640 
1641 #ifdef HAVE_LDAP_START_TLS_S
1642  /*
1643  * Set all of the TLS options
1644  */
1645  if (inst->tls_mode) {
1646  do_ldap_option(LDAP_OPT_X_TLS, "tls_mode", &(inst->tls_mode));
1647  }
1648 
1649 # define maybe_ldap_option(_option, _name, _value) \
1650  if (_value) do_ldap_option(_option, _name, _value)
1651 
1652  maybe_ldap_option(LDAP_OPT_X_TLS_CACERTFILE, "ca_file", inst->tls_ca_file);
1653  maybe_ldap_option(LDAP_OPT_X_TLS_CACERTDIR, "ca_path", inst->tls_ca_path);
1654 
1655 
1656  /*
1657  * Set certificate options
1658  */
1659  maybe_ldap_option(LDAP_OPT_X_TLS_CERTFILE, "certificate_file", inst->tls_certificate_file);
1660  maybe_ldap_option(LDAP_OPT_X_TLS_KEYFILE, "private_key_file", inst->tls_private_key_file);
1661  maybe_ldap_option(LDAP_OPT_X_TLS_RANDOM_FILE, "random_file", inst->tls_random_file);
1662 
1663 # ifdef LDAP_OPT_X_TLS_NEVER
1664  if (inst->tls_require_cert_str) {
1665  do_ldap_option(LDAP_OPT_X_TLS_REQUIRE_CERT, "require_cert", &inst->tls_require_cert);
1666  }
1667 # endif
1668 
1669  /*
1670  * Counter intuitively the TLS context appears to need to be initialised
1671  * after all the TLS options are set on the handle.
1672  */
1673 # ifdef LDAP_OPT_X_TLS_NEWCTX
1674  {
1675  /* Always use the new TLS configuration context */
1676  int is_server = 0;
1677  do_ldap_option(LDAP_OPT_X_TLS_NEWCTX, "new TLS context", &is_server);
1678 
1679  }
1680 # endif
1681 
1682  /*
1683  * And finally start the TLS code.
1684  */
1685  if (inst->start_tls) {
1686  if (inst->port == 636) {
1687  WARN("Told to Start TLS on LDAPS port this will probably fail, please correct the "
1688  "configuration");
1689  }
1690 
1691  if (ldap_start_tls_s(conn->handle, NULL, NULL) != LDAP_SUCCESS) {
1692  ldap_get_option(conn->handle, LDAP_OPT_ERROR_NUMBER, &ldap_errno);
1693 
1694  LDAP_ERR("Could not start TLS: %s", ldap_err2string(ldap_errno));
1695  goto error;
1696  }
1697  }
1698 #endif /* HAVE_LDAP_START_TLS_S */
1699 
1700  status = rlm_ldap_bind(inst, NULL, &conn, conn->inst->admin_identity, conn->inst->admin_password,
1701  &(conn->inst->admin_sasl), false, NULL, NULL);
1702  if (status != LDAP_PROC_SUCCESS) {
1703  goto error;
1704  }
1705 
1706  return conn;
1707 
1708 error:
1709  talloc_free(conn);
1710 
1711  return NULL;
1712 }
1713 
1714 /** Gets an LDAP socket from the connection pool
1715  *
1716  * Retrieve a socket from the connection pool, or NULL on error (of if no sockets are available).
1717  *
1718  * @param inst rlm_ldap configuration.
1719  * @param request Current request (may be NULL).
1720  */
1721 
1723 #ifdef LDAP_CONTROL_X_SESSION_TRACKING
1724  REQUEST *request
1725 #else
1726  UNUSED REQUEST *request
1727 #endif
1728  )
1729 {
1730  ldap_handle_t *conn;
1731 
1732  conn = fr_connection_get(inst->pool);
1733 
1734 #ifdef LDAP_CONTROL_X_SESSION_TRACKING
1735  /*
1736  * Add optional session tracking controls,
1737  * that contain values of some attributes
1738  * in the request.
1739  */
1740  if ((conn != NULL) & (request != NULL) & inst->session_tracking) {
1741  if (rlm_ldap_control_add_session_tracking(conn, request) < 0) {
1742  fr_connection_release(inst->pool, conn);
1743  return NULL;
1744  }
1745  }
1746 #endif
1747  return conn;
1748 }
1749 
1750 /** Frees an LDAP socket back to the connection pool
1751  *
1752  * If the socket was rebound chasing a referral onto another server then we destroy it.
1753  * If the socket was rebound to another user on the same server, we let the next caller rebind it.
1754  *
1755  * @param inst rlm_ldap configuration.
1756  * @param conn to release.
1757  */
1759 {
1760  /*
1761  * Could have already been free'd due to a previous error.
1762  */
1763  if (!conn) return;
1764 
1765  /*
1766  * Clear any client/server controls associated with the connection.
1767  */
1768  rlm_ldap_control_clear(conn);
1769 
1770  /*
1771  * We chased a referral to another server.
1772  *
1773  * This connection is no longer part of the pool which is
1774  * connected to and bound to the configured server.
1775  * Close it.
1776  *
1777  * Note that we do NOT close it if it was bound to another user.
1778  * Instead, we let the next caller do the rebind.
1779  */
1780  if (conn->referred) {
1781  fr_connection_close(inst->pool, conn);
1782  return;
1783  }
1784 
1785  fr_connection_release(inst->pool, conn);
1786  return;
1787 }
static size_t rlm_ldap_common_dn(char const *full, char const *part)
Find the place at which the two DN strings diverge.
Definition: ldap.c:375
ssize_t tmpl_expand(char const **out, char *buff, size_t outlen, REQUEST *request, vp_tmpl_t const *vpt, xlat_escape_t escape, void *escape_ctx)
Expand a vp_tmpl_t to a string writing the result to a buffer.
Definition: tmpl.c:1479
Tracks the state of a libldap connection handle.
Definition: ldap.h:163
ldap_rcode_t rlm_ldap_modify(rlm_ldap_t const *inst, REQUEST *request, ldap_handle_t **pconn, char const *dn, LDAPMod *mods[], LDAPControl **serverctrls, LDAPControl **clientctrls)
Modify something in the LDAP directory.
Definition: ldap.c:1048
void * mod_conn_create(TALLOC_CTX *ctx, void *instance, struct timeval const *timeout)
Create and return a new connection.
Definition: ldap.c:1535
ldap_rcode_t rlm_ldap_sasl_interactive(rlm_ldap_t const *inst, REQUEST *request, ldap_handle_t *pconn, char const *dn, char const *password, ldap_sasl *sasl, LDAPControl **serverctrls, LDAPControl **clientctrls, char const **error, char **error_extra)
Initiate an LDAP interactive bind.
Definition: sasl.c:105
VALUE_PAIR * config
VALUE_PAIR (s) used to set per request parameters for modules and the server core at runtime...
Definition: radiusd.h:227
Operation was successfull.
Definition: ldap.h:397
#define RINDENT()
Indent R* messages by one level.
Definition: log.h:265
#define DEBUG3(fmt,...)
Definition: log.h:177
The module is OK, continue.
Definition: radiusd.h:91
char const * userobj_access_attr
Attribute to check to see if the user should be locked out.
Definition: ldap.h:234
void exec_trigger(REQUEST *request, CONF_SECTION *cs, char const *name, bool quench) CC_HINT(nonnull(3))
Execute a trigger - call an executable to process an event.
Definition: exec.c:686
int rlm_ldap_control_add_session_tracking(ldap_handle_t *conn, REQUEST *request)
fr_connection_pool_t * pool
Connection pool instance.
Definition: ldap.h:182
uint32_t res_timeout
How long we wait for a result from the server.
Definition: ldap.h:340
ldap_handle_t * mod_conn_get(rlm_ldap_t const *inst, UNUSED REQUEST *request)
Gets an LDAP socket from the connection pool.
Definition: ldap.c:1722
uint32_t srv_timelimit
How long the server should spent on a single request (also bounded by value on the server)...
Definition: ldap.h:341
void rlm_ldap_control_merge(LDAPControl *serverctrls_out[], LDAPControl *clientctrls_out[], size_t serverctrls_len, size_t clientctrls_len, ldap_handle_t *conn, LDAPControl *serverctrls_in[], LDAPControl *clientctrls_in[])
Merge connection and call specific client and server controls.
Definition: control.c:41
int tls_mode
Definition: ldap.h:308
char const * admin_identity
Identity we bind as when we need to query the LDAP directory.
Definition: ldap.h:188
Specifies the password for an LDAP bind.
Definition: ldap.h:129
char const * admin_password
Password used in administrative bind.
Definition: ldap.h:190
char const * rlm_ldap_find_user(rlm_ldap_t const *inst, REQUEST *request, ldap_handle_t **pconn, char const *attrs[], bool force, LDAPMessage **result, rlm_rcode_t *rcode)
Retrieve the DN of a user object.
Definition: ldap.c:1152
bool start_tls
Send the Start TLS message to the LDAP directory to start encrypted communications using the standard...
Definition: ldap.h:309
static const char specials[]
Definition: ldap.c:36
bool use_referral_credentials
If true use credentials from the referral URL.
Definition: ldap.h:202
char const * tls_certificate_file
Sets the path to the public certificate file we present to the servers.
Definition: ldap.h:318
#define UNUSED
Definition: libradius.h:134
bool chase_referrals_unset
If true, use the OpenLDAP defaults for chase_referrals.
Definition: ldap.h:200
char * server
Initial server to bind to.
Definition: ldap.h:185
static float timeout
Definition: radclient.c:43
#define inst
Definition: token.h:46
The module considers the request invalid.
Definition: radiusd.h:93
int userobj_scope
Search scope.
Definition: ldap.h:231
ldap_rcode_t
Codes returned by rlm_ldap internal functions.
Definition: ldap.h:395
#define LDAP_MAX_FILTER_STR_LEN
Maximum length of an xlat expanded filter.
Definition: ldap.h:120
Specifies the user DN or name for an LDAP bind.
Definition: ldap.h:128
#define LDAP_DBG_REQ(fmt,...)
Definition: ldap.h:427
size_t rlm_ldap_normalise_dn(char *out, char const *in)
Normalise escape sequences in a DN.
Definition: ldap.c:312
#define LDAP_ERR_REQ(fmt,...)
Definition: ldap.h:436
Operation was not permitted, either current user was locked out in the case of binds, or has insufficient access.
Definition: ldap.h:404
int dereference
libldap value specifying dereferencing behaviour.
Definition: ldap.h:195
void mod_conn_release(rlm_ldap_t const *inst, ldap_handle_t *conn)
Frees an LDAP socket back to the connection pool.
Definition: ldap.c:1758
#define rad_assert(expr)
Definition: rad_assert.h:38
Reject the request (user is locked out).
Definition: radiusd.h:94
bool chase_referrals
If the LDAP server returns a referral to another server or point in the tree, follow it...
Definition: ldap.h:197
char const * tls_ca_file
Sets the full path to a CA certificate (used to validate the certificate the server presents)...
Definition: ldap.h:313
#define LDAP_MAX_DN_STR_LEN
Maximum length of an xlat expanded DN.
Definition: ldap.h:121
#define DEBUG(fmt,...)
Definition: log.h:175
vp_tmpl_t * userobj_base_dn
DN to search for users under.
Definition: ldap.h:226
static int comp(void const *a, void const *b)
Definition: rbmonkey.c:44
void fr_pair_value_strcpy(VALUE_PAIR *vp, char const *src)
Copy data into an "string" data type.
Definition: pair.c:2013
#define LDAP_ERR(fmt,...)
Definition: ldap.h:435
bool rebound
Whether the connection has been rebound to something other than the admin user.
Definition: ldap.h:165
#define MOD_ROPTIONAL(_l_request, _l_global, fmt,...)
Use different logging functions depending on whether request is NULL or not.
Definition: log.h:338
size_t fr_hex2bin(uint8_t *bin, size_t outlen, char const *hex, size_t inlen)
Convert hex strings to binary data.
Definition: misc.c:220
void rlm_ldap_check_reply(rlm_ldap_t const *inst, REQUEST *request)
Verify we got a password from the search.
Definition: ldap.c:1362
#define DEBUG2(fmt,...)
Definition: log.h:176
static int _mod_conn_free(ldap_handle_t *conn)
Close and delete a connection.
Definition: ldap.c:1507
bool rebind
Controls whether we set an ldad_rebind_proc function and so determines if we can bind to other server...
Definition: ldap.h:204
ldap_rcode_t rlm_ldap_bind(rlm_ldap_t const *inst, REQUEST *request, ldap_handle_t **pconn, char const *dn, char const *password, ldap_sasl *sasl, bool retry, LDAPControl **serverctrls, LDAPControl **clientctrls)
Bind to the LDAP directory as a user.
Definition: ldap.c:751
Stores an attribute, a value and various bits of other data.
Definition: pair.h:112
uint16_t port
Port to use when binding to the server.
Definition: ldap.h:186
char const * rlm_ldap_error_str(ldap_handle_t const *conn)
Return the error string associated with a handle.
Definition: ldap.c:488
ssize_t rlm_ldap_xlat_filter(REQUEST *request, char const **sub, size_t sublen, char *out, size_t outlen)
Combine and expand filters.
Definition: ldap.c:416
char * talloc_typed_asprintf(void const *t, char const *fmt,...)
Call talloc vasprintf, setting the type on the new chunk correctly.
Definition: missing.c:611
CONF_SECTION * cs
Main configuration section for this instance.
Definition: ldap.h:181
Operation is in progress.
Definition: ldap.h:396
static const char hextab[]
Definition: ldap.c:37
ldap_rcode_t rlm_ldap_search(LDAPMessage **result, rlm_ldap_t const *inst, REQUEST *request, ldap_handle_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: ldap.c:880
#define REXDENT()
Exdent (unindent) R* messages by one level.
Definition: log.h:272
char const * name
Instance name.
Definition: ldap.h:212
char const * tls_ca_path
Sets the path to a directory containing CA certificates.
Definition: ldap.h:316
enum rlm_rcodes rlm_rcode_t
Return codes indicating the result of the module call.
int tls_require_cert
OpenLDAP constant representing the require cert string.
Definition: ldap.h:330
ssize_t radius_xlat(char *out, size_t outlen, REQUEST *request, char const *fmt, xlat_escape_t escape, void *escape_ctx) CC_HINT(nonnull(1
rlm_ldap_t * inst
rlm_ldap configuration.
Definition: ldap.h:177
#define do_ldap_option(_option, _name, _value)
ldap_rcode_t rlm_ldap_result(rlm_ldap_t const *inst, ldap_handle_t const *conn, int msgid, char const *dn, LDAPMessage **result, char const **error, char **extra)
Parse response from LDAP server dealing with any errors.
Definition: ldap.c:517
#define RDEBUG2(fmt,...)
Definition: log.h:244
Module failed, don't reply.
Definition: radiusd.h:90
uint32_t ldap_debug
Debug flag for the SDK.
Definition: ldap.h:210
#define TAG_ANY
Definition: pair.h:191
log_lvl_t rad_debug_lvl
Global debugging level.
Definition: log.c:49
Specified an invalid object in a bind or search DN.
Definition: ldap.h:410
Unsupported extension.
Definition: ldap.h:127
uint32_t num
Number of connections in the pool.
Definition: connection.h:55
int strncasecmp(char *s1, char *s2, int n)
Definition: missing.c:43
void * fr_connection_get(fr_connection_pool_t *pool)
Reserve a connection in the connection pool.
Definition: connection.c:1291
int fr_connection_close(fr_connection_pool_t *pool, void *conn)
Delete a connection from the connection pool.
Definition: connection.c:1403
vp_tmpl_t * userobj_filter
Filter to retrieve only user objects.
Definition: ldap.h:225
Transitory error, caller should retry the operation with a new connection.
Definition: ldap.h:401
rlm_rcode_t rlm_ldap_check_access(rlm_ldap_t const *inst, REQUEST *request, ldap_handle_t const *conn, LDAPMessage *entry)
Check for presence of access attribute in result.
Definition: ldap.c:1327
size_t rlm_ldap_escape_func(UNUSED REQUEST *request, char *out, size_t outlen, char const *in, UNUSED void *arg)
Converts "bad" strings into ones which are safe for LDAP.
Definition: ldap.c:65
char const * tls_require_cert_str
Sets requirements for validating the certificate the server presents.
Definition: ldap.h:327
#define WARN(fmt,...)
Definition: log.h:144
#define LDAP_DBGW_REQ(fmt,...)
Definition: ldap.h:424
#define REDEBUG(fmt,...)
Definition: log.h:254
char const * tls_random_file
Path to the random file if /dev/random and /dev/urandom are unavailable.
Definition: ldap.h:324
VALUE_PAIR * fr_pair_find_by_num(VALUE_PAIR *head, unsigned int vendor, unsigned int attr, int8_t tag)
Find the pair with the matching attribute.
Definition: pair.c:639
size_t rlm_ldap_unescape_func(UNUSED REQUEST *request, char *out, size_t outlen, char const *in, UNUSED void *arg)
Converts escaped DNs and filter strings into normal.
Definition: ldap.c:121
char const * mech
SASL mech(s) to try.
Definition: ldap.h:143
size_t strlcpy(char *dst, char const *src, size_t siz)
Definition: strlcpy.c:38
FR_NAME_NUMBER const ldap_supported_extensions[]
Definition: ldap.c:39
LDAPControl * userobj_sort_ctrl
Server side sort control.
Definition: ldap.h:229
char const * fr_int2str(FR_NAME_NUMBER const *table, int number, char const *def)
Definition: token.c:506
char * rlm_ldap_berval_to_string(TALLOC_CTX *ctx, struct berval const *in)
Convert a berval to a talloced string.
Definition: ldap.c:281
void fr_connection_release(fr_connection_pool_t *pool, void *conn)
Release a connection.
Definition: connection.c:1305
bool access_positive
If true the presence of the attribute will allow access, else it will deny access.
Definition: ldap.h:235
ldap_sasl admin_sasl
SASL parameters used when binding as the admin.
Definition: ldap.h:192
#define RWDEBUG(fmt,...)
Definition: log.h:251
User not found.
Definition: radiusd.h:95
Unrecoverable library/server error.
Definition: ldap.h:399
#define LDAP_MAX_CONTROLS
Maximum number of client/server controls.
Definition: ldap.h:105
int fr_substr2int(FR_NAME_NUMBER const *table, char const *name, int def, int len)
Definition: token.c:471
LDAP authorization and authentication module headers.
fr_connection_pool_state_t const * fr_connection_pool_state(fr_connection_pool_t *pool)
Get the number of connections currently in the pool.
Definition: connection.c:1081
void rlm_ldap_control_clear(ldap_handle_t *conn)
Clear and free any controls associated with a connection.
Definition: control.c:127
bool expect_password
True if the user_map included a mapping between an LDAP attribute and one of our password reference a...
Definition: ldap.h:214
VALUE_PAIR * fr_pair_make(TALLOC_CTX *ctx, VALUE_PAIR **vps, char const *attribute, char const *value, FR_TOKEN op)
Create a VALUE_PAIR from ASCII strings.
Definition: pair.c:338
void * fr_connection_reconnect(fr_connection_pool_t *pool, void *conn)
Reconnect a suspected inviable connection.
Definition: connection.c:1367
char const * dereference_str
When to dereference (never, searching, finding, always)
Definition: ldap.h:194
#define RDEBUG(fmt,...)
Definition: log.h:243
#define do_ldap_global_option(_option, _name, _value)
bool referred
Whether the connection is now established a server other than the configured one. ...
Definition: ldap.h:167
#define ERROR(fmt,...)
Definition: log.h:145
bool rlm_ldap_is_dn(char const *in, size_t inlen)
Check whether a string looks like a DN.
Definition: ldap.c:168
#define LDAP_EXT_REQ()
Definition: ldap.h:439
LDAP * handle
libldap handle.
Definition: ldap.h:164
Bind failed, user was rejected.
Definition: ldap.h:408
char const * tls_private_key_file
Sets the path to the private key for our public certificate.
Definition: ldap.h:321
FR_NAME_NUMBER const ldap_scope[]
Definition: rlm_ldap.c:44
Got no results.
Definition: ldap.h:412