All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
rlm_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: 3d29cb1cb5d8830472e60b87b8c4980dc2032281 $
19  * @file rlm_ldap.c
20  * @brief LDAP authorization and authentication module.
21  *
22  * @author Arran Cudbard-Bell <a.cudbardb@freeradius.org>
23  * @author Alan DeKok <aland@freeradius.org>
24  *
25  * @copyright 2012,2015 Arran Cudbard-Bell <a.cudbardb@freeradius.org>
26  * @copyright 2013,2015 Network RADIUS SARL <info@networkradius.com>
27  * @copyright 2012 Alan DeKok <aland@freeradius.org>
28  * @copyright 1999-2013 The FreeRADIUS Server Project.
29  */
30 RCSID("$Id: 3d29cb1cb5d8830472e60b87b8c4980dc2032281 $")
31 
32 #include <freeradius-devel/rad_assert.h>
33 
34 #include <stdarg.h>
35 #include <ctype.h>
36 
37 #include "ldap.h"
38 
39 #include <freeradius-devel/map_proc.h>
40 
41 /*
42  * Scopes
43  */
45  { "sub", LDAP_SCOPE_SUB },
46  { "one", LDAP_SCOPE_ONE },
47  { "base", LDAP_SCOPE_BASE },
48 #ifdef LDAP_SCOPE_CHILDREN
49  { "children", LDAP_SCOPE_CHILDREN },
50 #endif
51  { NULL , -1 }
52 };
53 
54 #ifdef LDAP_OPT_X_TLS_NEVER
56  { "never", LDAP_OPT_X_TLS_NEVER },
57  { "demand", LDAP_OPT_X_TLS_DEMAND },
58  { "allow", LDAP_OPT_X_TLS_ALLOW },
59  { "try", LDAP_OPT_X_TLS_TRY },
60  { "hard", LDAP_OPT_X_TLS_HARD }, /* oh yes, just like that */
61 
62  { NULL , -1 }
63 };
64 #endif
65 
66 static FR_NAME_NUMBER const ldap_dereference[] = {
67  { "never", LDAP_DEREF_NEVER },
68  { "searching", LDAP_DEREF_SEARCHING },
69  { "finding", LDAP_DEREF_FINDING },
70  { "always", LDAP_DEREF_ALWAYS },
71 
72  { NULL , -1 }
73 };
74 
77  { FR_CONF_OFFSET("proxy", PW_TYPE_TMPL, ldap_sasl_dynamic, proxy) },
78  { FR_CONF_OFFSET("realm", PW_TYPE_TMPL, ldap_sasl_dynamic, realm) },
80 };
81 
84  { FR_CONF_OFFSET("proxy", PW_TYPE_STRING, ldap_sasl, proxy) },
85  { FR_CONF_OFFSET("realm", PW_TYPE_STRING, ldap_sasl, realm) },
87 };
88 
89 /*
90  * TLS Configuration
91  */
92 static CONF_PARSER tls_config[] = {
93  /*
94  * Deprecated attributes
95  */
96  { FR_CONF_OFFSET("ca_file", PW_TYPE_FILE_INPUT, rlm_ldap_t, tls_ca_file) },
97 
98  { FR_CONF_OFFSET("ca_path", PW_TYPE_FILE_INPUT, rlm_ldap_t, tls_ca_path) },
99 
100  { FR_CONF_OFFSET("certificate_file", PW_TYPE_FILE_INPUT, rlm_ldap_t, tls_certificate_file) },
101 
102  { FR_CONF_OFFSET("private_key_file", PW_TYPE_FILE_INPUT, rlm_ldap_t, tls_private_key_file) }, // OK if it changes on HUP
103 
104  { FR_CONF_OFFSET("random_file", PW_TYPE_FILE_INPUT, rlm_ldap_t, tls_random_file) },
105 
106  /*
107  * LDAP Specific TLS attributes
108  */
109  { FR_CONF_OFFSET("start_tls", PW_TYPE_BOOLEAN, rlm_ldap_t, start_tls), .dflt = "no" },
110  { FR_CONF_OFFSET("require_cert", PW_TYPE_STRING, rlm_ldap_t, tls_require_cert_str) },
112 };
113 
114 
116  { FR_CONF_OFFSET("filter", PW_TYPE_TMPL, rlm_ldap_t, profile_filter), .dflt = "(&)", .quote = T_SINGLE_QUOTED_STRING }, //!< Correct filter for when the DN is known.
117  { FR_CONF_OFFSET("attribute", PW_TYPE_STRING, rlm_ldap_t, profile_attr) },
118  { FR_CONF_OFFSET("default", PW_TYPE_TMPL, rlm_ldap_t, default_profile) },
120 };
121 
122 /*
123  * User configuration
124  */
126  { FR_CONF_OFFSET("filter", PW_TYPE_TMPL, rlm_ldap_t, userobj_filter) },
127  { FR_CONF_OFFSET("scope", PW_TYPE_STRING, rlm_ldap_t, userobj_scope_str), .dflt = "sub" },
128  { FR_CONF_OFFSET("base_dn", PW_TYPE_TMPL, rlm_ldap_t, userobj_base_dn), .dflt = "", .quote = T_SINGLE_QUOTED_STRING },
129  { FR_CONF_OFFSET("sort_by", PW_TYPE_STRING, rlm_ldap_t, userobj_sort_by) },
130 
131  { FR_CONF_OFFSET("access_attribute", PW_TYPE_STRING, rlm_ldap_t, userobj_access_attr) },
132  { FR_CONF_OFFSET("access_positive", PW_TYPE_BOOLEAN, rlm_ldap_t, access_positive), .dflt = "yes" },
133 
134  /* Should be deprecated */
135  { FR_CONF_OFFSET("sasl", PW_TYPE_SUBSECTION, rlm_ldap_t, user_sasl), .dflt = (void const *) sasl_mech_dynamic },
137 };
138 
139 /*
140  * Group configuration
141  */
143  { FR_CONF_OFFSET("filter", PW_TYPE_STRING, rlm_ldap_t, groupobj_filter) },
144  { FR_CONF_OFFSET("scope", PW_TYPE_STRING, rlm_ldap_t, groupobj_scope_str), .dflt = "sub" },
145  { FR_CONF_OFFSET("base_dn", PW_TYPE_TMPL, rlm_ldap_t, groupobj_base_dn), .dflt = "", .quote = T_SINGLE_QUOTED_STRING },
146 
147  { FR_CONF_OFFSET("name_attribute", PW_TYPE_STRING, rlm_ldap_t, groupobj_name_attr), .dflt = "cn" },
148  { FR_CONF_OFFSET("membership_attribute", PW_TYPE_STRING, rlm_ldap_t, userobj_membership_attr) },
149  { FR_CONF_OFFSET("membership_filter", PW_TYPE_STRING | PW_TYPE_XLAT, rlm_ldap_t, groupobj_membership_filter) },
150  { FR_CONF_OFFSET("cacheable_name", PW_TYPE_BOOLEAN, rlm_ldap_t, cacheable_group_name), .dflt = "no" },
151  { FR_CONF_OFFSET("cacheable_dn", PW_TYPE_BOOLEAN, rlm_ldap_t, cacheable_group_dn), .dflt = "no" },
152  { FR_CONF_OFFSET("cache_attribute", PW_TYPE_STRING, rlm_ldap_t, cache_attribute) },
153  { FR_CONF_OFFSET("group_attribute", PW_TYPE_STRING, rlm_ldap_t, group_attribute) },
155 };
156 
158  { FR_CONF_OFFSET("filter", PW_TYPE_STRING, rlm_ldap_t, clientobj_filter) },
159  { FR_CONF_OFFSET("scope", PW_TYPE_STRING, rlm_ldap_t, clientobj_scope_str), .dflt = "sub" },
160  { FR_CONF_OFFSET("base_dn", PW_TYPE_STRING, rlm_ldap_t, clientobj_base_dn), .dflt = "" },
162 };
163 
164 /*
165  * Reference for accounting updates
166  */
168  { FR_CONF_OFFSET("reference", PW_TYPE_STRING | PW_TYPE_XLAT, ldap_acct_section_t, reference), .dflt = "." },
170 };
171 
172 /*
173  * Various options that don't belong in the main configuration.
174  *
175  * Note that these overlap a bit with the connection pool code!
176  */
178  /*
179  * Debugging flags to the server
180  */
181  { FR_CONF_OFFSET("ldap_debug", PW_TYPE_INTEGER, rlm_ldap_t, ldap_debug), .dflt = "0x0000" },
182 
183  { FR_CONF_OFFSET("dereference", PW_TYPE_STRING, rlm_ldap_t, dereference_str) },
184 
185  { FR_CONF_OFFSET("chase_referrals", PW_TYPE_BOOLEAN, rlm_ldap_t, chase_referrals) },
186 
187  { FR_CONF_OFFSET("use_referral_credentials", PW_TYPE_BOOLEAN, rlm_ldap_t, use_referral_credentials), .dflt = "no" },
188 
189  { FR_CONF_OFFSET("rebind", PW_TYPE_BOOLEAN, rlm_ldap_t, rebind) },
190 
191 #ifdef LDAP_CONTROL_X_SESSION_TRACKING
192  { FR_CONF_OFFSET("session_tracking", PW_TYPE_BOOLEAN, rlm_ldap_t, session_tracking), .dflt = "no" },
193 #endif
194 
195 #ifdef LDAP_OPT_NETWORK_TIMEOUT
196  /* timeout on network activity */
197  { FR_CONF_DEPRECATED("net_timeout", PW_TYPE_INTEGER, rlm_ldap_t, net_timeout), .dflt = "10" },
198 #endif
199 
200  /* timeout for search results */
201  { FR_CONF_OFFSET("res_timeout", PW_TYPE_INTEGER, rlm_ldap_t, res_timeout), .dflt = "20" },
202 
203  /* allow server unlimited time for search (server-side limit) */
204  { FR_CONF_OFFSET("srv_timelimit", PW_TYPE_INTEGER, rlm_ldap_t, srv_timelimit), .dflt = "20" },
205 
206 #ifdef LDAP_OPT_X_KEEPALIVE_IDLE
207  { FR_CONF_OFFSET("idle", PW_TYPE_INTEGER, rlm_ldap_t, keepalive_idle), .dflt = "60" },
208 #endif
209 #ifdef LDAP_OPT_X_KEEPALIVE_PROBES
210  { FR_CONF_OFFSET("probes", PW_TYPE_INTEGER, rlm_ldap_t, keepalive_probes), .dflt = "3" },
211 #endif
212 #ifdef LDAP_OPT_X_KEEPALIVE_INTERVAL
213  { FR_CONF_OFFSET("interval", PW_TYPE_INTEGER, rlm_ldap_t, keepalive_interval), .dflt = "30" },
214 #endif
216 };
217 
218 
219 static const CONF_PARSER module_config[] = {
220  { FR_CONF_OFFSET("server", PW_TYPE_STRING, rlm_ldap_t, config_server) }, /* Do not set to required */
221  { FR_CONF_OFFSET("port", PW_TYPE_SHORT, rlm_ldap_t, port) },
222 
223  { FR_CONF_OFFSET("identity", PW_TYPE_STRING, rlm_ldap_t, admin_identity) },
224  { FR_CONF_OFFSET("password", PW_TYPE_STRING | PW_TYPE_SECRET, rlm_ldap_t, admin_password) },
225 
226  { FR_CONF_OFFSET("sasl", PW_TYPE_SUBSECTION, rlm_ldap_t, admin_sasl), .dflt = (void const *) sasl_mech_static },
227 
228  { FR_CONF_OFFSET("valuepair_attribute", PW_TYPE_STRING, rlm_ldap_t, valuepair_attr) },
229 
230 #ifdef WITH_EDIR
231  /* support for eDirectory Universal Password */
232  { FR_CONF_OFFSET("edir", PW_TYPE_BOOLEAN, rlm_ldap_t, edir) }, /* NULL defaults to "no" */
233 
234  /*
235  * Attempt to bind with the cleartext password we got from eDirectory
236  * Universal password for additional authorization checks.
237  */
238  { FR_CONF_OFFSET("edir_autz", PW_TYPE_BOOLEAN, rlm_ldap_t, edir_autz) }, /* NULL defaults to "no" */
239 #endif
240 
241  { FR_CONF_OFFSET("read_clients", PW_TYPE_BOOLEAN, rlm_ldap_t, do_clients) }, /* NULL defaults to "no" */
242 
243  { FR_CONF_POINTER("user", PW_TYPE_SUBSECTION, NULL), .dflt = (void const *) user_config },
244 
245  { FR_CONF_POINTER("group", PW_TYPE_SUBSECTION, NULL), .dflt = (void const *) group_config },
246 
247  { FR_CONF_POINTER("client", PW_TYPE_SUBSECTION, NULL), .dflt = (void const *) client_config },
248 
249  { FR_CONF_POINTER("profile", PW_TYPE_SUBSECTION, NULL), .dflt = (void const *) profile_config },
250 
251  { FR_CONF_POINTER("options", PW_TYPE_SUBSECTION, NULL), .dflt = (void const *) option_config },
252 
253  { FR_CONF_POINTER("tls", PW_TYPE_SUBSECTION, NULL), .dflt = (void const *) tls_config },
255 };
256 
257 static ssize_t ldap_escape_xlat(char **out, size_t outlen,
258  UNUSED void const *mod_inst, UNUSED void const *xlat_inst,
259  REQUEST *request, char const *fmt)
260 {
261  return rlm_ldap_escape_func(request, *out, outlen, fmt, NULL);
262 }
263 
264 static ssize_t ldap_unescape_xlat(char **out, size_t outlen,
265  UNUSED void const *mod_inst, UNUSED void const *xlat_inst,
266  REQUEST *request, char const *fmt)
267 {
268  return rlm_ldap_unescape_func(request, *out, outlen, fmt, NULL);
269 }
270 
271 /** Expand an LDAP URL into a query, and return a string result from that query.
272  *
273  */
274 static ssize_t ldap_xlat(char **out, size_t outlen,
275  void const *mod_inst, UNUSED void const *xlat_inst,
276  REQUEST *request, char const *fmt)
277 {
278  ldap_rcode_t status;
279  size_t len = 0;
280  rlm_ldap_t const *inst = mod_inst;
281 
282  LDAPURLDesc *ldap_url;
283  LDAPMessage *result = NULL;
284  LDAPMessage *entry = NULL;
285 
286  struct berval **values;
287 
288  ldap_handle_t *conn;
289  int ldap_errno;
290 
291  char const *url;
292  char const **attrs;
293 
294  url = fmt;
295 
296  if (!ldap_is_ldap_url(url)) {
297  REDEBUG("String passed does not look like an LDAP URL");
298  return -1;
299  }
300 
301  if (ldap_url_parse(url, &ldap_url)){
302  REDEBUG("Parsing LDAP URL failed");
303  return -1;
304  }
305 
306  /*
307  * Nothing, empty string, "*" string, or got 2 things, die.
308  */
309  if (!ldap_url->lud_attrs || !ldap_url->lud_attrs[0] ||
310  !*ldap_url->lud_attrs[0] ||
311  (strcmp(ldap_url->lud_attrs[0], "*") == 0) ||
312  ldap_url->lud_attrs[1]) {
313  REDEBUG("Bad attributes list in LDAP URL. URL must specify exactly one attribute to retrieve");
314 
315  goto free_urldesc;
316  }
317 
318  conn = mod_conn_get(inst, request);
319  if (!conn) goto free_urldesc;
320 
321  memcpy(&attrs, &ldap_url->lud_attrs, sizeof(attrs));
322 
323  status = rlm_ldap_search(&result, inst, request, &conn, ldap_url->lud_dn, ldap_url->lud_scope,
324  ldap_url->lud_filter, attrs, NULL, NULL);
325  switch (status) {
326  case LDAP_PROC_SUCCESS:
327  break;
328 
329  default:
330  goto free_socket;
331  }
332 
333  rad_assert(conn);
334  rad_assert(result);
335 
336  entry = ldap_first_entry(conn->handle, result);
337  if (!entry) {
338  ldap_get_option(conn->handle, LDAP_OPT_RESULT_CODE, &ldap_errno);
339  REDEBUG("Failed retrieving entry: %s", ldap_err2string(ldap_errno));
340  len = -1;
341  goto free_result;
342  }
343 
344  values = ldap_get_values_len(conn->handle, entry, ldap_url->lud_attrs[0]);
345  if (!values) {
346  RDEBUG("No \"%s\" attributes found in specified object", ldap_url->lud_attrs[0]);
347  goto free_result;
348  }
349 
350  if (values[0]->bv_len >= outlen) goto free_values;
351 
352  memcpy(*out, values[0]->bv_val, values[0]->bv_len + 1); /* +1 as strlcpy expects buffer size */
353  len = values[0]->bv_len;
354 
355 free_values:
356  ldap_value_free_len(values);
357 free_result:
358  ldap_msgfree(result);
359 free_socket:
360  mod_conn_release(inst, conn);
361 free_urldesc:
362  ldap_free_urldesc(ldap_url);
363 
364  return len;
365 }
366 
367 /** Perform a search and map the result of the search to server attributes
368  *
369  * Unlike LDAP xlat, this can be used to process attributes from multiple entries.
370  *
371  * @param[in] mod_inst #rlm_ldap_t
372  * @param[in] proc_inst unused.
373  * @param[in,out] request The current request.
374  * @param[in] url LDAP url specifying base DN and filter.
375  * @param[in] maps Head of the map list.
376  * @return
377  * - #RLM_MODULE_NOOP no rows were returned.
378  * - #RLM_MODULE_UPDATED if one or more #VALUE_PAIR were added to the #REQUEST.
379  * - #RLM_MODULE_FAIL if an error occurred.
380  */
381 static rlm_rcode_t mod_map_proc(void *mod_inst, UNUSED void *proc_inst, REQUEST *request,
382  char const *url, vp_map_t const *maps)
383 {
385  rlm_ldap_t *inst = talloc_get_type_abort(mod_inst, rlm_ldap_t);
386  ldap_rcode_t status;
387 
388  LDAPURLDesc *ldap_url;
389 
390  LDAPMessage *result = NULL;
391  LDAPMessage *entry = NULL;
392  vp_map_t const *map;
393 
394  ldap_handle_t *conn;
395 
396  rlm_ldap_map_exp_t expanded; /* faster than mallocing every time */
397 
398  if (!ldap_is_ldap_url(url)) {
399  REDEBUG("Map query string does not look like a valid LDAP URI");
400  return RLM_MODULE_FAIL;
401  }
402 
403  if (ldap_url_parse(url, &ldap_url)){
404  REDEBUG("Parsing LDAP URL failed");
405  return RLM_MODULE_FAIL;
406  }
407 
408  /*
409  * Expand the RHS of the maps to get the name of the attributes.
410  */
411  if (rlm_ldap_map_expand(&expanded, request, maps) < 0) {
412  rcode = RLM_MODULE_FAIL;
413  goto free_urldesc;
414  }
415 
416  conn = mod_conn_get(inst, request);
417  if (!conn) goto free_expanded;
418 
419  status = rlm_ldap_search(&result, inst, request, &conn, ldap_url->lud_dn, ldap_url->lud_scope,
420  ldap_url->lud_filter, expanded.attrs, NULL, NULL);
421  switch (status) {
422  case LDAP_PROC_SUCCESS:
423  break;
424 
425  case LDAP_PROC_NO_RESULT:
426  rcode = RLM_MODULE_NOOP;
427  goto free_socket;
428 
429  default:
430  rcode = RLM_MODULE_FAIL;
431  goto free_socket;
432  }
433 
434  rad_assert(conn);
435  rad_assert(result);
436 
437  for (entry = ldap_first_entry(conn->handle, result);
438  entry;
439  entry = ldap_next_entry(conn->handle, entry)) {
440  int i;
441  char *dn = NULL;
442 
443  if (RDEBUG_ENABLED2) {
444  dn = ldap_get_dn(conn->handle, entry);
445  RDEBUG2("Processing \"%s\"", dn);
446  }
447 
448  RINDENT();
449  for (map = maps, i = 0;
450  map != NULL;
451  map = map->next, i++) {
452  int ret;
453  rlm_ldap_result_t attr;
454 
455  attr.values = ldap_get_values_len(conn->handle, entry, expanded.attrs[i]);
456  if (!attr.values) {
457  /*
458  * Many LDAP directories don't expose the DN of
459  * the object as an attribute, so we need this
460  * hack, to allow the user to retrieve it.
461  */
462  if (strcmp(LDAP_VIRTUAL_DN_ATTR, expanded.attrs[i]) == 0) {
463  struct berval value;
464  struct berval *values[2] = { &value, NULL };
465 
466  if (!dn) dn = ldap_get_dn(conn->handle, entry);
467  value.bv_val = dn;
468  value.bv_len = strlen(dn);
469 
470  attr.values = values;
471  attr.count = 1;
472 
473  ret = map_to_request(request, map, rlm_ldap_map_getvalue, &attr);
474  if (ret == -1) {
475  rcode = RLM_MODULE_FAIL;
476  ldap_memfree(dn);
477  goto free_result;
478  }
479  continue;
480  }
481 
482  RDEBUG3("Attribute \"%s\" not found in LDAP object", expanded.attrs[i]);
483 
484  continue;
485  }
486  attr.count = ldap_count_values_len(attr.values);
487 
488  ret = map_to_request(request, map, rlm_ldap_map_getvalue, &attr);
489  ldap_value_free_len(attr.values);
490  if (ret == -1) {
491  rcode = RLM_MODULE_FAIL;
492  ldap_memfree(dn);
493  goto free_result;
494  }
495  }
496  ldap_memfree(dn);
497  REXDENT();
498  }
499 
500 free_result:
501  ldap_msgfree(result);
502 free_socket:
503  mod_conn_release(inst, conn);
504 free_expanded:
505  talloc_free(expanded.ctx);
506 free_urldesc:
507  ldap_free_urldesc(ldap_url);
508 
509  return rcode;
510 }
511 
512 /** Perform LDAP-Group comparison checking
513  *
514  * Attempts to match users to groups using a variety of methods.
515  *
516  * @param instance of the rlm_ldap module.
517  * @param request Current request.
518  * @param thing Unknown.
519  * @param check Which group to check for user membership.
520  * @param check_pairs Unknown.
521  * @param reply_pairs Unknown.
522  * @return
523  * - 1 on failure (or if the user is not a member).
524  * - 0 on success.
525  */
526 static int rlm_ldap_groupcmp(void *instance, REQUEST *request, UNUSED VALUE_PAIR *thing, VALUE_PAIR *check,
527  UNUSED VALUE_PAIR *check_pairs, UNUSED VALUE_PAIR **reply_pairs)
528 {
529  rlm_ldap_t *inst = instance;
530  rlm_rcode_t rcode;
531 
532  bool found = false;
533  bool check_is_dn;
534 
535  ldap_handle_t *conn = NULL;
536  char const *user_dn;
537 
539 
540  RDEBUG("Searching for user in group \"%s\"", check->vp_strvalue);
541 
542  if (check->vp_length == 0) {
543  REDEBUG("Cannot do comparison (group name is empty)");
544  return 1;
545  }
546 
547  /*
548  * Check if we can do cached membership verification
549  */
550  check_is_dn = rlm_ldap_is_dn(check->vp_strvalue, check->vp_length);
551  if (check_is_dn) {
552  char *norm;
553 
554  MEM(norm = talloc_memdup(check, check->vp_strvalue, talloc_array_length(check->vp_strvalue)));
555  rlm_ldap_normalise_dn(norm, check->vp_strvalue);
556  fr_pair_value_strsteal(check, norm);
557  }
558  if ((check_is_dn && inst->cacheable_group_dn) || (!check_is_dn && inst->cacheable_group_name)) {
559  switch (rlm_ldap_check_cached(inst, request, check)) {
560  case RLM_MODULE_NOTFOUND:
561  found = false;
562  goto finish;
563 
564  case RLM_MODULE_OK:
565  found = true;
566  goto finish;
567  /*
568  * Fallback to dynamic search on failure
569  */
570  case RLM_MODULE_FAIL:
571  case RLM_MODULE_INVALID:
572  default:
573  break;
574  }
575  }
576 
577  conn = mod_conn_get(inst, request);
578  if (!conn) return 1;
579 
580  /*
581  * This is used in the default membership filter.
582  */
583  user_dn = rlm_ldap_find_user(inst, request, &conn, NULL, false, NULL, &rcode);
584  if (!user_dn) {
585  mod_conn_release(inst, conn);
586  return 1;
587  }
588 
589  rad_assert(conn);
590 
591  /*
592  * Check groupobj user membership
593  */
594  if (inst->groupobj_membership_filter) {
595  switch (rlm_ldap_check_groupobj_dynamic(inst, request, &conn, check)) {
596  case RLM_MODULE_NOTFOUND:
597  break;
598 
599  case RLM_MODULE_OK:
600  found = true;
601 
602  default:
603  goto finish;
604  }
605  }
606 
607  rad_assert(conn);
608 
609  /*
610  * Check userobj group membership
611  */
612  if (inst->userobj_membership_attr) {
613  switch (rlm_ldap_check_userobj_dynamic(inst, request, &conn, user_dn, check)) {
614  case RLM_MODULE_NOTFOUND:
615  break;
616 
617  case RLM_MODULE_OK:
618  found = true;
619 
620  default:
621  goto finish;
622  }
623  }
624 
625  rad_assert(conn);
626 
627 finish:
628  if (conn) mod_conn_release(inst, conn);
629 
630  if (!found) {
631  RDEBUG("User is not a member of \"%s\"", check->vp_strvalue);
632 
633  return 1;
634  }
635 
636  return 0;
637 }
638 
639 /** Detach from the LDAP server and cleanup internal state.
640  *
641  */
642 static int mod_detach(void *instance)
643 {
644  rlm_ldap_t *inst = instance;
645 
647 
648  if (inst->user_map) {
649  talloc_free(inst->user_map);
650  }
651 
652  /*
653  * Keeping the dummy ld around for the lifetime
654  * of the module should always work,
655  * irrespective of what changes happen in libldap.
656  */
657  if (inst->handle) {
658 #ifdef HAVE_LDAP_UNBIND_EXT_S
659  ldap_unbind_ext_s(inst->handle, NULL, NULL);
660 #else
661  ldap_unbind_s(inst->handle);
662 #endif
663  }
664 
665 #ifdef HAVE_LDAP_CREATE_SORT_CONTROL
666  if (inst->userobj_sort_ctrl) ldap_control_free(inst->userobj_sort_ctrl);
667 #endif
668 
669  return 0;
670 }
671 
672 /** Parse an accounting sub section.
673  *
674  * Allocate a new ldap_acct_section_t and write the config data into it.
675  *
676  * @param[in] inst rlm_ldap configuration.
677  * @param[in] parent of the config section.
678  * @param[out] config to write the sub section parameters to.
679  * @param[in] comp The section name were parsing the config for.
680  * @return
681  * - 0 on success.
682  * - < 0 on failure.
683  */
686 {
687  CONF_SECTION *cs;
688 
689  char const *name = section_type_value[comp].section;
690 
691  cs = cf_section_sub_find(parent, name);
692  if (!cs) {
693  DEBUG2("rlm_ldap (%s): Couldn't find configuration for %s, will return NOOP for calls "
694  "from this section", inst->name, name);
695 
696  return 0;
697  }
698 
699  *config = talloc_zero(inst, ldap_acct_section_t);
700  if (cf_section_parse(cs, *config, acct_section_config) < 0) {
701  LDAP_ERR("Failed parsing configuration for section %s", name);
702 
703  return -1;
704  }
705 
706  (*config)->cs = cs;
707 
708  return 0;
709 }
710 
711 /** Bootstrap the module
712  *
713  * Define attributes.
714  *
715  * @param conf to parse.
716  * @param instance configuration data.
717  * @return
718  * - 0 on success.
719  * - < 0 on failure.
720  */
721 static int mod_bootstrap(CONF_SECTION *conf, void *instance)
722 {
723  rlm_ldap_t *inst = instance;
724  char buffer[256];
725  char const *group_attribute;
726 
727  inst->name = cf_section_name2(conf);
728  if (!inst->name) inst->name = cf_section_name1(conf);
729 
730  if (inst->group_attribute) {
731  group_attribute = inst->group_attribute;
732  } else if (cf_section_name2(conf)) {
733  snprintf(buffer, sizeof(buffer), "%s-LDAP-Group", inst->name);
734  group_attribute = buffer;
735  } else {
736  group_attribute = "LDAP-Group";
737  }
738 
739  if (paircompare_register_byname(group_attribute, fr_dict_attr_by_num(NULL, 0, PW_USER_NAME),
740  false, rlm_ldap_groupcmp, inst) < 0) {
741  LDAP_ERR("Error registering group comparison: %s", fr_strerror());
742  goto error;
743  }
744 
745  inst->group_da = fr_dict_attr_by_name(NULL, group_attribute);
746 
747  /*
748  * Setup the cache attribute
749  */
750  if (inst->cache_attribute) {
751  fr_dict_attr_flags_t flags;
752 
753  memset(&flags, 0, sizeof(flags));
755  flags) < 0) {
756  LDAP_ERR("Error creating cache attribute: %s", fr_strerror());
757  error:
758  return -1;
759 
760  }
761  inst->cache_da = fr_dict_attr_by_name(NULL, inst->cache_attribute);
762  } else {
763  inst->cache_da = inst->group_da; /* Default to the group_da */
764  }
765 
767  xlat_register(inst, "ldapquote", ldap_escape_xlat, NULL, NULL, 0, XLAT_DEFAULT_BUF_LEN); /* Deprecated */
768 
769  xlat_register(inst, "ldap_escape", ldap_escape_xlat, NULL, NULL, 0, XLAT_DEFAULT_BUF_LEN);
770  xlat_register(inst, "ldap_unescape", ldap_unescape_xlat, NULL, NULL, 0, XLAT_DEFAULT_BUF_LEN);
771  map_proc_register(inst, inst->name, mod_map_proc, NULL, NULL, 0);
772 
773  return 0;
774 }
775 
776 
777 /** Instantiate the module
778  *
779  * Creates a new instance of the module reading parameters from a configuration section.
780  *
781  * @param conf to parse.
782  * @param instance configuration data.
783  * @return
784  * - 0 on success.
785  * - < 0 on failure.
786  */
787 static int mod_instantiate(CONF_SECTION *conf, void *instance)
788 {
789  static bool version_done;
790 
791  CONF_PAIR *cp;
792  CONF_ITEM *ci;
793 
794  CONF_SECTION *options, *update;
795  rlm_ldap_t *inst = instance;
796 
797  inst->cs = conf;
798 
799  options = cf_section_sub_find(conf, "options");
800  if (!options || !cf_pair_find(options, "chase_referrals")) {
801  inst->chase_referrals_unset = true; /* use OpenLDAP defaults */
802  }
803 
804  /*
805  * Only needs to be done once, prevents races in environment
806  * initialisation within libldap.
807  *
808  * See: https://github.com/arr2036/ldapperf/issues/2
809  */
810 #ifdef HAVE_LDAP_INITIALIZE
811  ldap_initialize(&inst->handle, "");
812 #else
813  inst->handle = ldap_init("", 0);
814 #endif
815 
816  /*
817  * Get version info from the LDAP API.
818  */
819  if (!version_done) {
820  static LDAPAPIInfo info = { .ldapai_info_version = LDAP_API_INFO_VERSION }; /* static to quiet valgrind about this being uninitialised */
821  int ldap_errno;
822 
823  version_done = true;
824 
825  ldap_errno = ldap_get_option(NULL, LDAP_OPT_API_INFO, &info);
826  if (ldap_errno == LDAP_OPT_SUCCESS) {
827  /*
828  * Don't generate warnings if the compile type vendor name
829  * is found within the link time vendor name.
830  *
831  * This allows the server to be built against OpenLDAP but
832  * run with Symas OpenLDAP.
833  */
834  if (strcasestr(info.ldapai_vendor_name, LDAP_VENDOR_NAME) == NULL) {
835  WARN("rlm_ldap: libldap vendor changed since the server was built");
836  WARN("rlm_ldap: linked: %s, built: %s", info.ldapai_vendor_name, LDAP_VENDOR_NAME);
837  }
838 
839  if (info.ldapai_vendor_version < LDAP_VENDOR_VERSION) {
840  WARN("rlm_ldap: libldap older than the version the server was built against");
841  WARN("rlm_ldap: linked: %i, built: %i",
842  info.ldapai_vendor_version, LDAP_VENDOR_VERSION);
843  }
844 
845  INFO("rlm_ldap: libldap vendor: %s, version: %i", info.ldapai_vendor_name,
846  info.ldapai_vendor_version);
847 
848  ldap_memfree(info.ldapai_vendor_name);
849  ldap_memfree(info.ldapai_extensions);
850  } else {
851  DEBUG("rlm_ldap: Falling back to build time libldap version info. Query for LDAP_OPT_API_INFO "
852  "returned: %i", ldap_errno);
853  INFO("rlm_ldap: libldap vendor: %s, version: %i.%i.%i", LDAP_VENDOR_NAME,
854  LDAP_VENDOR_VERSION_MAJOR, LDAP_VENDOR_VERSION_MINOR, LDAP_VENDOR_VERSION_PATCH);
855  }
856  }
857 
858  /*
859  * If the configuration parameters can't be parsed, then fail.
860  */
861  if ((parse_sub_section(inst, conf, &inst->accounting, MOD_ACCOUNTING) < 0) ||
862  (parse_sub_section(inst, conf, &inst->postauth, MOD_POST_AUTH) < 0)) {
863  cf_log_err_cs(conf, "Failed parsing configuration");
864 
865  goto error;
866  }
867 
868  /*
869  * Sanity checks for cacheable groups code.
870  */
872  if (!inst->groupobj_name_attr) {
873  cf_log_err_cs(conf, "Configuration item 'group.name_attribute' must be set if cacheable "
874  "group names are enabled");
875 
876  goto error;
877  }
878  }
879 
880  /*
881  * If we have a *pair* as opposed to a *section*
882  * then the module is referencing another ldap module's
883  * connection pool.
884  */
885  if (!cf_pair_find(conf, "pool")) {
886  if (!inst->config_server) {
887  cf_log_err_cs(conf, "Configuration item 'server' must have a value");
888  goto error;
889  }
890  }
891 
892 #ifndef WITH_SASL
893  if (inst->user_sasl.mech) {
894  cf_log_err_cs(conf, "Configuration item 'user.sasl.mech' not supported. "
895  "Linked libldap does not provide ldap_sasl_bind function");
896  goto error;
897  }
898 
899  if (inst->admin_sasl.mech) {
900  cf_log_err_cs(conf, "Configuration item 'sasl.mech' not supported. "
901  "Linked libldap does not provide ldap_sasl_interactive_bind function");
902  goto error;
903  }
904 #endif
905 
906 #ifndef HAVE_LDAP_CREATE_SORT_CONTROL
907  if (inst->userobj_sort_by) {
908  cf_log_err_cs(conf, "Configuration item 'sort_by' not supported. "
909  "Linked libldap does not provide ldap_create_sort_control function");
910  goto error;
911  }
912 #endif
913 
914 #ifndef HAVE_LDAP_URL_PARSE
915  if (inst->use_referral_credentials) {
916  cf_log_err_cs(conf, "Configuration item 'use_referral_credentials' not supported. "
917  "Linked libldap does not support URL parsing");
918  goto error;
919  }
920 #endif
921 
922  /*
923  * For backwards compatibility hack up the first 'server'
924  * CONF_ITEM into chunks, and add them back into the config.
925  *
926  * @fixme this should be removed at some point.
927  */
928  if (inst->config_server) {
929  char const *value;
930  char const *p;
931  char const *q;
932  char *buff;
933 
934  bool done = false;
935  bool first = true;
936 
937  cp = cf_pair_find(conf, "server");
938  if (!cp) {
939  cf_log_err_cs(conf, "Configuration item 'server' must have a value");
940  return -1;
941  }
942 
943  value = cf_pair_value(cp);
944 
945  p = value;
946  q = p;
947  while (!done) {
948  switch (*q) {
949  case '\0':
950  done = true;
951  if (p == value) break; /* string contained no separators */
952 
953  /* FALL-THROUGH */
954 
955  case ',':
956  case ';':
957  case ' ':
958  while (isspace((int) *p)) p++;
959  if (p == q) continue;
960 
961  buff = talloc_array(inst, char, (q - p) + 1);
962  strlcpy(buff, p, talloc_array_length(buff));
963  p = ++q;
964 
965  if (first) {
966  WARN("Listing multiple LDAP servers in the 'server' configuration item "
967  "is deprecated and will be removed in a future release. "
968  "Use multiple 'server' configuration items instead");
969  WARN("- server = '%s'", value);
970  }
971  WARN("+ server = '%s'", buff);
972 
973  /*
974  * For the first instance of server we find, just replace
975  * the existing "server" config item.
976  */
977  if (first) {
978  cf_pair_replace(conf, cp, buff);
979  first = false;
980  continue;
981  }
982 
983  /*
984  * For subsequent instances we need to add new conf pairs.
985  */
986  cp = cf_pair_alloc(conf, "server", buff, T_OP_EQ, T_BARE_WORD, T_SINGLE_QUOTED_STRING);
987  if (!cp) return -1;
988 
989  ci = cf_pair_to_item(cp);
990  cf_item_add(conf, ci);
991 
992  break;
993 
994  default:
995  q++;
996  continue;
997  }
998  }
999  }
1000 
1001  /*
1002  * Now iterate over all the 'server' config items
1003  */
1004  for (cp = cf_pair_find(conf, "server");
1005  cp;
1006  cp = cf_pair_find_next(conf, cp, "server")) {
1007  char const *value;
1008 
1009  value = cf_pair_value(cp);
1010 
1011 #ifdef LDAP_CAN_PARSE_URLS
1012  /*
1013  * Split original server value out into URI, server and port
1014  * so whatever initialization function we use later will have
1015  * the server information in the format it needs.
1016  */
1017  if (ldap_is_ldap_url(value)) {
1018  LDAPURLDesc *ldap_url;
1019  bool set_port_maybe = true;
1020  int default_port = LDAP_PORT;
1021  char *p;
1022 
1023  if (ldap_url_parse(value, &ldap_url)){
1024  cf_log_err_cs(conf, "Parsing LDAP URL \"%s\" failed", value);
1025  ldap_url_error:
1026  ldap_free_urldesc(ldap_url);
1027  return -1;
1028  }
1029 
1030  if (ldap_url->lud_dn && (ldap_url->lud_dn[0] != '\0')) {
1031  cf_log_err_cs(conf, "Base DN cannot be specified via server URL");
1032  goto ldap_url_error;
1033  }
1034 
1035  if (ldap_url->lud_attrs && ldap_url->lud_attrs[0]) {
1036  cf_log_err_cs(conf, "Attribute list cannot be specified via server URL");
1037  goto ldap_url_error;
1038  }
1039 
1040  /*
1041  * ldap_url_parse sets this to base by default.
1042  */
1043  if (ldap_url->lud_scope != LDAP_SCOPE_BASE) {
1044  cf_log_err_cs(conf, "Scope cannot be specified via server URL");
1045  goto ldap_url_error;
1046  }
1047  ldap_url->lud_scope = -1; /* Otherwise LDAP adds ?base */
1048 
1049  /*
1050  * The public ldap_url_parse function sets the default
1051  * port, so we have to discover whether a port was
1052  * included ourselves.
1053  */
1054  if ((p = strchr(value, ']')) && (p[1] == ':')) { /* IPv6 */
1055  set_port_maybe = false;
1056  } else if ((p = strchr(value, ':')) && (p = strchr(p + 1, ':'))) { /* IPv4 */
1057  set_port_maybe = false;
1058  }
1059 
1060  /* We allow extensions */
1061 
1062 # ifdef HAVE_LDAP_INITIALIZE
1063  {
1064  char *url;
1065 
1066  /*
1067  * Figure out the default port from the URL
1068  */
1069  if (ldap_url->lud_scheme) {
1070  if (strcmp(ldap_url->lud_scheme, "ldaps") == 0) {
1071  if (inst->start_tls == true) {
1072  cf_log_err_cs(conf, "ldaps:// scheme is not compatible "
1073  "with 'start_tls'");
1074  goto ldap_url_error;
1075  }
1076  default_port = LDAPS_PORT;
1077 
1078  } else if (strcmp(ldap_url->lud_scheme, "ldapi") == 0) {
1079  set_port_maybe = false; /* Unix socket, no port */
1080  }
1081  }
1082 
1083  if (set_port_maybe) {
1084  /*
1085  * URL port overrides configured port.
1086  */
1087  ldap_url->lud_port = inst->port;
1088 
1089  /*
1090  * If there's no URL port, then set it to the default
1091  * this is so debugging messages show explicitly
1092  * the port we're connecting to.
1093  */
1094  if (!ldap_url->lud_port) ldap_url->lud_port = default_port;
1095  }
1096 
1097  url = ldap_url_desc2str(ldap_url);
1098  if (!url) {
1099  cf_log_err_cs(conf, "Failed recombining URL components");
1100  goto ldap_url_error;
1101  }
1102  inst->server = talloc_asprintf_append(inst->server, "%s ", url);
1103  free(url);
1104  }
1105 # else
1106  /*
1107  * No LDAP initialize function. Can't specify a scheme.
1108  */
1109  if (ldap_url->lud_scheme &&
1110  ((strcmp(ldap_url->lud_scheme, "ldaps") == 0) ||
1111  (strcmp(ldap_url->lud_scheme, "ldapi") == 0) ||
1112  (strcmp(ldap_url->lud_scheme, "cldap") == 0))) {
1113  cf_log_err_cs(conf, "%s is not supported by linked libldap",
1114  ldap_url->lud_scheme);
1115  return -1;
1116  }
1117 
1118  /*
1119  * URL port over-rides the configured
1120  * port. But if there's no configured
1121  * port, we use the hard-coded default.
1122  */
1123  if (set_port_maybe) {
1124  ldap_url->lud_port = inst->port;
1125  if (!ldap_url->lud_port) ldap_url->lud_port = default_port;
1126  }
1127 
1128  inst->server = talloc_asprintf_append(inst->server, "%s:%i ",
1129  ldap_url->lud_host ? ldap_url->lud_host : "localhost",
1130  ldap_url->lud_port);
1131 # endif
1132  /*
1133  * @todo We could set a few other top level
1134  * directives using the URL, like base_dn
1135  * and scope.
1136  */
1137  ldap_free_urldesc(ldap_url);
1138  /*
1139  * We need to construct an LDAP URI
1140  */
1141  } else
1142 #endif /* HAVE_LDAP_URL_PARSE && HAVE_LDAP_IS_LDAP_URL && LDAP_URL_DESC2STR */
1143  /*
1144  * If it's not an URL, or we don't have the functions necessary
1145  * to break apart the URL and recombine it, then just treat
1146  * server as a hostname.
1147  */
1148  {
1149 #ifdef HAVE_LDAP_INITIALIZE
1150  char const *p;
1151  char *q;
1152  int port = 0;
1153  size_t len;
1154 
1155  port = inst->port;
1156 
1157  /*
1158  * We don't support URLs if the library didn't provide
1159  * URL parsing functions.
1160  */
1161  if (strchr(value, '/')) {
1162  bad_server_fmt:
1163 #ifdef LDAP_CAN_PARSE_URLS
1164  cf_log_err_cp(cp, "Invalid server value, must be in format <server>[:<port>] or "
1165  "an ldap URI (ldap|cldap|ldaps|ldapi)://<server>:<port>");
1166 #else
1167  cf_log_err_cp(cp, "Invalid server value, must be in format <server>[:<port>]");
1168 #endif
1169  return -1;
1170  }
1171 
1172  p = strrchr(value, ':');
1173  if (p) {
1174  port = (int)strtol((p + 1), &q, 10);
1175  if ((p == value) || ((p + 1) == q) || (*q != '\0')) goto bad_server_fmt;
1176  len = p - value;
1177  } else {
1178  len = strlen(value);
1179  }
1180  if (port == 0) port = LDAP_PORT;
1181 
1182  inst->server = talloc_asprintf_append(inst->server, "ldap://%.*s:%i ", (int) len, value, port);
1183 #else
1184  /*
1185  * ldap_init takes port, which can be overridden by :port so
1186  * we don't need to do any parsing here.
1187  */
1188  inst->server = talloc_asprintf_append(inst->server, "%s ", value);
1189 #endif
1190  }
1191  }
1192  if (inst->server) inst->server[talloc_array_length(inst->server) - 2] = '\0';
1193 
1194  DEBUG4("LDAP server string: %s", inst->server);
1195 
1196 #ifdef LDAP_OPT_X_TLS_NEVER
1197  /*
1198  * Workaround for servers which support LDAPS but not START TLS
1199  */
1200  if (inst->port == LDAPS_PORT || inst->tls_mode) {
1201  inst->tls_mode = LDAP_OPT_X_TLS_HARD;
1202  } else {
1203  inst->tls_mode = 0;
1204  }
1205 #endif
1206 
1207  /*
1208  * Convert dereference strings to enumerated constants
1209  */
1210  if (inst->dereference_str) {
1211  inst->dereference = fr_str2int(ldap_dereference, inst->dereference_str, -1);
1212  if (inst->dereference < 0) {
1213  cf_log_err_cs(conf, "Invalid 'dereference' value \"%s\", expected 'never', 'searching', "
1214  "'finding' or 'always'", inst->dereference_str);
1215  goto error;
1216  }
1217  }
1218 
1219 #if LDAP_SET_REBIND_PROC_ARGS != 3
1220  /*
1221  * The 2-argument rebind doesn't take an instance variable. Our rebind function needs the instance
1222  * variable for the username, password, etc.
1223  */
1224  if (inst->rebind == true) {
1225  cf_log_err_cs(conf, "Cannot use 'rebind' configuration item as this version of libldap "
1226  "does not support the API that we need");
1227 
1228  goto error;
1229  }
1230 #endif
1231 
1232  /*
1233  * Convert scope strings to enumerated constants
1234  */
1235  inst->userobj_scope = fr_str2int(ldap_scope, inst->userobj_scope_str, -1);
1236  if (inst->userobj_scope < 0) {
1237  cf_log_err_cs(conf, "Invalid 'user.scope' value \"%s\", expected 'sub', 'one'"
1238 #ifdef LDAP_SCOPE_CHILDREN
1239  ", 'base' or 'children'"
1240 #else
1241  " or 'base'"
1242 #endif
1243  , inst->userobj_scope_str);
1244  goto error;
1245  }
1246 
1247  inst->groupobj_scope = fr_str2int(ldap_scope, inst->groupobj_scope_str, -1);
1248  if (inst->groupobj_scope < 0) {
1249  cf_log_err_cs(conf, "Invalid 'group.scope' value \"%s\", expected 'sub', 'one'"
1250 #ifdef LDAP_SCOPE_CHILDREN
1251  ", 'base' or 'children'"
1252 #else
1253  " or 'base'"
1254 #endif
1255  , inst->groupobj_scope_str);
1256  goto error;
1257  }
1258 
1259  inst->clientobj_scope = fr_str2int(ldap_scope, inst->clientobj_scope_str, -1);
1260  if (inst->clientobj_scope < 0) {
1261  cf_log_err_cs(conf, "Invalid 'client.scope' value \"%s\", expected 'sub', 'one'"
1262 #ifdef LDAP_SCOPE_CHILDREN
1263  ", 'base' or 'children'"
1264 #else
1265  " or 'base'"
1266 #endif
1267  , inst->clientobj_scope_str);
1268  goto error;
1269  }
1270 
1271 #ifdef HAVE_LDAP_CREATE_SORT_CONTROL
1272  /*
1273  * Build the server side sort control for user objects
1274  */
1275  if (inst->userobj_sort_by) {
1276  LDAPSortKey **keys;
1277  int ret;
1278  char *p;
1279 
1280  memcpy(&p, &inst->userobj_sort_by, sizeof(p));
1281 
1282  ret = ldap_create_sort_keylist(&keys, p);
1283  if (ret != LDAP_SUCCESS) {
1284  cf_log_err_cs(conf, "Invalid user.sort_by value \"%s\": %s",
1285  inst->userobj_sort_by, ldap_err2string(ret));
1286  goto error;
1287  }
1288 
1289  /*
1290  * Always set the control as critical, if it's not needed
1291  * the user can comment it out...
1292  */
1293  ret = ldap_create_sort_control(inst->handle, keys, 1, &inst->userobj_sort_ctrl);
1294  ldap_free_sort_keylist(keys);
1295  if (ret != LDAP_SUCCESS) {
1296  LDAP_ERR("Failed creating server sort control: %s", ldap_err2string(ret));
1297  goto error;
1298  }
1299  }
1300 #endif
1301 
1302  if (inst->tls_require_cert_str) {
1303 #ifdef LDAP_OPT_X_TLS_NEVER
1304  /*
1305  * Convert cert strictness to enumerated constants
1306  */
1307  inst->tls_require_cert = fr_str2int(ldap_tls_require_cert, inst->tls_require_cert_str, -1);
1308  if (inst->tls_require_cert < 0) {
1309  cf_log_err_cs(conf, "Invalid 'tls.require_cert' value \"%s\", expected 'never', "
1310  "'demand', 'allow', 'try' or 'hard'", inst->tls_require_cert_str);
1311  goto error;
1312  }
1313 #else
1314  cf_log_err_cs(conf, "Modifying 'tls.require_cert' is not supported by current "
1315  "version of libldap. Please upgrade or substitute current libldap and "
1316  "rebuild this module");
1317 
1318  goto error;
1319 #endif
1320  }
1321 
1322  /*
1323  * Build the attribute map
1324  */
1325  update = cf_section_sub_find(inst->cs, "update");
1326  if (update && (map_afrom_cs(&inst->user_map, update,
1328  LDAP_MAX_ATTRMAP) < 0)) {
1329  return -1;
1330  }
1331 
1332  /*
1333  * Initialize the socket pool.
1334  */
1335  inst->pool = module_connection_pool_init(inst->cs, inst, mod_conn_create, NULL, NULL);
1336  if (!inst->pool) goto error;
1337 
1338  /*
1339  * Bulk load dynamic clients.
1340  */
1341  if (inst->do_clients) {
1342  CONF_SECTION *cs, *map, *tmpl;
1343 
1344  cs = cf_section_sub_find(inst->cs, "client");
1345  if (!cs) {
1346  cf_log_err_cs(conf, "Told to load clients but no client section found");
1347  goto error;
1348  }
1349 
1350  map = cf_section_sub_find(cs, "attribute");
1351  if (!map) {
1352  cf_log_err_cs(cs, "Told to load clients but no attribute section found");
1353  goto error;
1354  }
1355 
1356  tmpl = cf_section_sub_find(cs, "template");
1357 
1358  if (rlm_ldap_client_load(inst, tmpl, map) < 0) {
1359  cf_log_err_cs(cs, "Error loading clients");
1360 
1361  return -1;
1362  }
1363  }
1364 
1365  return 0;
1366 
1367 error:
1368  return -1;
1369 }
1370 
1371 static rlm_rcode_t mod_authenticate(void *instance, REQUEST *request) CC_HINT(nonnull);
1372 static rlm_rcode_t CC_HINT(nonnull) mod_authenticate(void *instance, REQUEST *request)
1373 {
1374  rlm_rcode_t rcode;
1375  ldap_rcode_t status;
1376  char const *dn;
1377  rlm_ldap_t *inst = instance;
1378  ldap_handle_t *conn;
1379 
1380  char sasl_mech_buff[LDAP_MAX_DN_STR_LEN];
1381  char sasl_proxy_buff[LDAP_MAX_DN_STR_LEN];
1382  char sasl_realm_buff[LDAP_MAX_DN_STR_LEN];
1383  ldap_sasl sasl;
1384 
1385  /*
1386  * Ensure that we're being passed a plain-text password, and not
1387  * anything else.
1388  */
1389 
1390  if (!request->username) {
1391  REDEBUG("Attribute \"User-Name\" is required for authentication");
1392 
1393  return RLM_MODULE_INVALID;
1394  }
1395 
1396  if (!request->password ||
1397  (request->password->da->attr != PW_USER_PASSWORD)) {
1398  RWDEBUG("You have set \"Auth-Type := LDAP\" somewhere");
1399  RWDEBUG("*********************************************");
1400  RWDEBUG("* THAT CONFIGURATION IS WRONG. DELETE IT. ");
1401  RWDEBUG("* YOU ARE PREVENTING THE SERVER FROM WORKING");
1402  RWDEBUG("*********************************************");
1403 
1404  REDEBUG("Attribute \"User-Password\" is required for authentication");
1405 
1406  return RLM_MODULE_INVALID;
1407  }
1408 
1409  if (request->password->vp_length == 0) {
1410  REDEBUG("Empty password supplied");
1411 
1412  return RLM_MODULE_INVALID;
1413  }
1414 
1415  conn = mod_conn_get(inst, request);
1416  if (!conn) return RLM_MODULE_FAIL;
1417 
1418  /*
1419  * Expand dynamic SASL fields
1420  */
1421  if (conn->inst->user_sasl.mech) {
1422  memset(&sasl, 0, sizeof(sasl));
1423 
1424  if (tmpl_expand(&sasl.mech, sasl_mech_buff, sizeof(sasl_mech_buff), request,
1425  conn->inst->user_sasl.mech, rlm_ldap_escape_func, inst) < 0) {
1426  REDEBUG("Failed expanding user.sasl.mech: %s", fr_strerror());
1427  rcode = RLM_MODULE_FAIL;
1428  goto finish;
1429  }
1430 
1431  if (conn->inst->user_sasl.proxy) {
1432  if (tmpl_expand(&sasl.proxy, sasl_proxy_buff, sizeof(sasl_proxy_buff), request,
1433  conn->inst->user_sasl.proxy, rlm_ldap_escape_func, inst) < 0) {
1434  REDEBUG("Failed expanding user.sasl.proxy: %s", fr_strerror());
1435  rcode = RLM_MODULE_FAIL;
1436  goto finish;
1437  }
1438  }
1439 
1440  if (conn->inst->user_sasl.realm) {
1441  if (tmpl_expand(&sasl.realm, sasl_realm_buff, sizeof(sasl_realm_buff), request,
1442  conn->inst->user_sasl.realm, rlm_ldap_escape_func, inst) < 0) {
1443  REDEBUG("Failed expanding user.sasl.realm: %s", fr_strerror());
1444  rcode = RLM_MODULE_FAIL;
1445  goto finish;
1446  }
1447  }
1448  }
1449 
1450  RDEBUG("Login attempt by \"%s\"", request->username->vp_strvalue);
1451 
1452  /*
1453  * Get the DN by doing a search.
1454  */
1455  dn = rlm_ldap_find_user(inst, request, &conn, NULL, false, NULL, &rcode);
1456  if (!dn) {
1457  mod_conn_release(inst, conn);
1458 
1459  return rcode;
1460  }
1461  conn->rebound = true;
1462  status = rlm_ldap_bind(inst, request, &conn, dn, request->password->vp_strvalue,
1463  conn->inst->user_sasl.mech ? &sasl : NULL, true, NULL, NULL);
1464  switch (status) {
1465  case LDAP_PROC_SUCCESS:
1466  rcode = RLM_MODULE_OK;
1467  RDEBUG("Bind as user \"%s\" was successful", dn);
1468  break;
1469 
1471  rcode = RLM_MODULE_USERLOCK;
1472  break;
1473 
1474  case LDAP_PROC_REJECT:
1475  rcode = RLM_MODULE_REJECT;
1476  break;
1477 
1478  case LDAP_PROC_BAD_DN:
1479  rcode = RLM_MODULE_INVALID;
1480  break;
1481 
1482  case LDAP_PROC_NO_RESULT:
1483  rcode = RLM_MODULE_NOTFOUND;
1484  break;
1485 
1486  default:
1487  rcode = RLM_MODULE_FAIL;
1488  break;
1489  };
1490 
1491 finish:
1492  mod_conn_release(inst, conn);
1493 
1494  return rcode;
1495 }
1496 
1497 /** Search for and apply an LDAP profile
1498  *
1499  * LDAP profiles are mapped using the same attribute map as user objects, they're used to add common
1500  * sets of attributes to the request.
1501  *
1502  * @param[in] inst rlm_ldap configuration.
1503  * @param[in] request Current request.
1504  * @param[in,out] pconn to use. May change as this function calls functions which auto re-connect.
1505  * @param[in] dn of profile object to apply.
1506  * @param[in] expanded Structure containing a list of xlat expanded attribute names and mapping
1507 information.
1508  * @return One of the RLM_MODULE_* values.
1509  */
1511  char const *dn, rlm_ldap_map_exp_t const *expanded)
1512 {
1513  rlm_rcode_t rcode = RLM_MODULE_OK;
1514  ldap_rcode_t status;
1515  LDAPMessage *result = NULL, *entry = NULL;
1516  int ldap_errno;
1517  LDAP *handle = (*pconn)->handle;
1518  char const *filter;
1519  char filter_buff[LDAP_MAX_FILTER_STR_LEN];
1520 
1521  rad_assert(inst->profile_filter); /* We always have a default filter set */
1522 
1523  if (!dn || !*dn) return RLM_MODULE_OK;
1524 
1525  if (tmpl_expand(&filter, filter_buff, sizeof(filter_buff), request,
1526  inst->profile_filter, rlm_ldap_escape_func, NULL) < 0) {
1527  REDEBUG("Failed creating profile filter");
1528 
1529  return RLM_MODULE_INVALID;
1530  }
1531 
1532  status = rlm_ldap_search(&result, inst, request, pconn, dn,
1533  LDAP_SCOPE_BASE, filter, expanded->attrs, NULL, NULL);
1534  switch (status) {
1535  case LDAP_PROC_SUCCESS:
1536  break;
1537 
1538  case LDAP_PROC_BAD_DN:
1539  case LDAP_PROC_NO_RESULT:
1540  RDEBUG("Profile object \"%s\" not found", dn);
1541  return RLM_MODULE_NOTFOUND;
1542 
1543  default:
1544  return RLM_MODULE_FAIL;
1545  }
1546 
1547  rad_assert(*pconn);
1548  rad_assert(result);
1549 
1550  entry = ldap_first_entry(handle, result);
1551  if (!entry) {
1552  ldap_get_option(handle, LDAP_OPT_RESULT_CODE, &ldap_errno);
1553  REDEBUG("Failed retrieving entry: %s", ldap_err2string(ldap_errno));
1554 
1555  rcode = RLM_MODULE_NOTFOUND;
1556 
1557  goto free_result;
1558  }
1559 
1560  RDEBUG("Processing profile attributes");
1561  if (rlm_ldap_map_do(inst, request, handle, expanded, entry) > 0) rcode = RLM_MODULE_UPDATED;
1562 
1563 free_result:
1564  ldap_msgfree(result);
1565 
1566  return rcode;
1567 }
1568 
1569 static rlm_rcode_t mod_authorize(void *instance, REQUEST *request) CC_HINT(nonnull);
1570 static rlm_rcode_t mod_authorize(void *instance, REQUEST *request)
1571 {
1572  rlm_rcode_t rcode = RLM_MODULE_OK;
1573  ldap_rcode_t status;
1574  int ldap_errno;
1575  int i;
1576  rlm_ldap_t *inst = instance;
1577  struct berval **values;
1578  VALUE_PAIR *vp;
1579  ldap_handle_t *conn;
1580  LDAPMessage *result, *entry;
1581  char const *dn = NULL;
1582  rlm_ldap_map_exp_t expanded; /* faster than mallocing every time */
1583 
1584  /*
1585  * Don't be tempted to add a check for request->username
1586  * or request->password here. rlm_ldap.authorize can be used for
1587  * many things besides searching for users.
1588  */
1589 
1590  if (rlm_ldap_map_expand(&expanded, request, inst->user_map) < 0) return RLM_MODULE_FAIL;
1591 
1592  conn = mod_conn_get(inst, request);
1593  if (!conn) return RLM_MODULE_FAIL;
1594 
1595  /*
1596  * Add any additional attributes we need for checking access, memberships, and profiles
1597  */
1598  if (inst->userobj_access_attr) {
1599  expanded.attrs[expanded.count++] = inst->userobj_access_attr;
1600  }
1601 
1602  if (inst->userobj_membership_attr && (inst->cacheable_group_dn || inst->cacheable_group_name)) {
1603  expanded.attrs[expanded.count++] = inst->userobj_membership_attr;
1604  }
1605 
1606  if (inst->profile_attr) {
1607  expanded.attrs[expanded.count++] = inst->profile_attr;
1608  }
1609 
1610  if (inst->valuepair_attr) {
1611  expanded.attrs[expanded.count++] = inst->valuepair_attr;
1612  }
1613 
1614  expanded.attrs[expanded.count] = NULL;
1615 
1616  dn = rlm_ldap_find_user(inst, request, &conn, expanded.attrs, true, &result, &rcode);
1617  if (!dn) {
1618  goto finish;
1619  }
1620 
1621  entry = ldap_first_entry(conn->handle, result);
1622  if (!entry) {
1623  ldap_get_option(conn->handle, LDAP_OPT_RESULT_CODE, &ldap_errno);
1624  REDEBUG("Failed retrieving entry: %s", ldap_err2string(ldap_errno));
1625 
1626  goto finish;
1627  }
1628 
1629  /*
1630  * Check for access.
1631  */
1632  if (inst->userobj_access_attr) {
1633  rcode = rlm_ldap_check_access(inst, request, conn, entry);
1634  if (rcode != RLM_MODULE_OK) {
1635  goto finish;
1636  }
1637  }
1638 
1639  /*
1640  * Check if we need to cache group memberships
1641  */
1642  if (inst->cacheable_group_dn || inst->cacheable_group_name) {
1643  if (inst->userobj_membership_attr) {
1644  rcode = rlm_ldap_cacheable_userobj(inst, request, &conn, entry, inst->userobj_membership_attr);
1645  if (rcode != RLM_MODULE_OK) {
1646  goto finish;
1647  }
1648  }
1649 
1650  rcode = rlm_ldap_cacheable_groupobj(inst, request, &conn);
1651  if (rcode != RLM_MODULE_OK) {
1652  goto finish;
1653  }
1654  }
1655 
1656 #ifdef WITH_EDIR
1657  /*
1658  * We already have a Cleartext-Password. Skip edir.
1659  */
1660  if (fr_pair_find_by_num(request->config, 0, PW_CLEARTEXT_PASSWORD, TAG_ANY)) {
1661  goto skip_edir;
1662  }
1663 
1664  /*
1665  * Retrieve Universal Password if we use eDirectory
1666  */
1667  if (inst->edir) {
1668  int res = 0;
1669  char password[256];
1670  size_t pass_size = sizeof(password);
1671 
1672  /*
1673  * Retrive universal password
1674  */
1675  res = nmasldap_get_password(conn->handle, dn, password, &pass_size);
1676  if (res != 0) {
1677  REDEBUG("Failed to retrieve eDirectory password: (%i) %s", res, edir_errstr(res));
1678  rcode = RLM_MODULE_FAIL;
1679 
1680  goto finish;
1681  }
1682 
1683  /*
1684  * Add Cleartext-Password attribute to the request
1685  */
1686  vp = radius_pair_create(request, &request->config, PW_CLEARTEXT_PASSWORD, 0);
1687  fr_pair_value_strcpy(vp, password);
1688  vp->vp_length = pass_size;
1689 
1690  if (RDEBUG_ENABLED3) {
1691  RDEBUG3("Added eDirectory password. control:%s += '%s'", vp->da->name, vp->vp_strvalue);
1692  } else {
1693  RDEBUG2("Added eDirectory password");
1694  }
1695 
1696  if (inst->edir_autz) {
1697  RDEBUG2("Binding as user for eDirectory authorization checks");
1698  /*
1699  * Bind as the user
1700  */
1701  conn->rebound = true;
1702  status = rlm_ldap_bind(inst, request, &conn, dn, vp->vp_strvalue, NULL, true, NULL, NULL);
1703  switch (status) {
1704  case LDAP_PROC_SUCCESS:
1705  rcode = RLM_MODULE_OK;
1706  RDEBUG("Bind as user '%s' was successful", dn);
1707  break;
1708 
1710  rcode = RLM_MODULE_USERLOCK;
1711  goto finish;
1712 
1713  case LDAP_PROC_REJECT:
1714  rcode = RLM_MODULE_REJECT;
1715  goto finish;
1716 
1717  case LDAP_PROC_BAD_DN:
1718  rcode = RLM_MODULE_INVALID;
1719  goto finish;
1720 
1721  case LDAP_PROC_NO_RESULT:
1722  rcode = RLM_MODULE_NOTFOUND;
1723  goto finish;
1724 
1725  default:
1726  rcode = RLM_MODULE_FAIL;
1727  goto finish;
1728  };
1729  }
1730  }
1731 
1732 skip_edir:
1733 #endif
1734 
1735  /*
1736  * Apply ONE user profile, or a default user profile.
1737  */
1738  if (inst->default_profile) {
1739  char const *profile;
1740  char profile_buff[1024];
1741 
1742  if (tmpl_expand(&profile, profile_buff, sizeof(profile_buff),
1743  request, inst->default_profile, NULL, NULL) < 0) {
1744  REDEBUG("Failed creating default profile string");
1745 
1746  rcode = RLM_MODULE_INVALID;
1747  goto finish;
1748  }
1749 
1750  switch (rlm_ldap_map_profile(inst, request, &conn, profile, &expanded)) {
1751  case RLM_MODULE_INVALID:
1752  rcode = RLM_MODULE_INVALID;
1753  goto finish;
1754 
1755  case RLM_MODULE_FAIL:
1756  rcode = RLM_MODULE_FAIL;
1757  goto finish;
1758 
1759  case RLM_MODULE_UPDATED:
1760  rcode = RLM_MODULE_UPDATED;
1761  /* FALL-THROUGH */
1762  default:
1763  break;
1764  }
1765  }
1766 
1767  /*
1768  * Apply a SET of user profiles.
1769  */
1770  if (inst->profile_attr) {
1771  values = ldap_get_values_len(conn->handle, entry, inst->profile_attr);
1772  if (values != NULL) {
1773  for (i = 0; values[i] != NULL; i++) {
1774  rlm_rcode_t ret;
1775  char *value;
1776 
1777  value = rlm_ldap_berval_to_string(request, values[i]);
1778  ret = rlm_ldap_map_profile(inst, request, &conn, value, &expanded);
1779  talloc_free(value);
1780  if (ret == RLM_MODULE_FAIL) {
1781  ldap_value_free_len(values);
1782  rcode = ret;
1783  goto finish;
1784  }
1785 
1786  }
1787  ldap_value_free_len(values);
1788  }
1789  }
1790 
1791  if (inst->user_map || inst->valuepair_attr) {
1792  RDEBUG("Processing user attributes");
1793  if (rlm_ldap_map_do(inst, request, conn->handle, &expanded, entry) > 0) rcode = RLM_MODULE_UPDATED;
1794  rlm_ldap_check_reply(inst, request);
1795  }
1796 
1797 finish:
1798  talloc_free(expanded.ctx);
1799  if (result) ldap_msgfree(result);
1800  mod_conn_release(inst, conn);
1801 
1802  return rcode;
1803 }
1804 
1805 /** Modify user's object in LDAP
1806  *
1807  * Process a modifcation map to update a user object in the LDAP directory.
1808  *
1809  * @param inst rlm_ldap instance.
1810  * @param request Current request.
1811  * @param section that holds the map to process.
1812  * @return one of the RLM_MODULE_* values.
1813  */
1815 {
1816  rlm_rcode_t rcode = RLM_MODULE_OK;
1817  ldap_rcode_t status;
1818 
1819  ldap_handle_t *conn = NULL;
1820 
1821  LDAPMod *mod_p[LDAP_MAX_ATTRMAP + 1], mod_s[LDAP_MAX_ATTRMAP];
1822  LDAPMod **modify = mod_p;
1823 
1824  char *passed[LDAP_MAX_ATTRMAP * 2];
1825  int i, total = 0, last_pass = 0;
1826 
1827  char *expanded[LDAP_MAX_ATTRMAP];
1828  int last_exp = 0;
1829 
1830  char const *attr;
1831  char const *value;
1832 
1833  char const *dn;
1834  /*
1835  * Build our set of modifications using the update sections in
1836  * the config.
1837  */
1838  CONF_ITEM *ci;
1839  CONF_PAIR *cp;
1840  CONF_SECTION *cs;
1841  FR_TOKEN op;
1842  char path[MAX_STRING_LEN];
1843 
1844  char *p = path;
1845 
1846  rad_assert(section);
1847 
1848  /*
1849  * Locate the update section were going to be using
1850  */
1851  if (section->reference[0] != '.') {
1852  *p++ = '.';
1853  }
1854 
1855  if (radius_xlat(p, (sizeof(path) - (p - path)) - 1, request, section->reference, NULL, NULL) < 0) {
1856  goto error;
1857  }
1858 
1859  ci = cf_reference_item(NULL, section->cs, path);
1860  if (!ci) {
1861  goto error;
1862  }
1863 
1864  if (!cf_item_is_section(ci)){
1865  REDEBUG("Reference must resolve to a section");
1866 
1867  goto error;
1868  }
1869 
1870  cs = cf_section_sub_find(cf_item_to_section(ci), "update");
1871  if (!cs) {
1872  REDEBUG("Section must contain 'update' subsection");
1873 
1874  goto error;
1875  }
1876 
1877  /*
1878  * Iterate over all the pairs, building our mods array
1879  */
1880  for (ci = cf_item_find_next(cs, NULL); ci != NULL; ci = cf_item_find_next(cs, ci)) {
1881  bool do_xlat = false;
1882 
1883  if (total == LDAP_MAX_ATTRMAP) {
1884  REDEBUG("Modify map size exceeded");
1885 
1886  goto error;
1887  }
1888 
1889  if (!cf_item_is_pair(ci)) {
1890  REDEBUG("Entry is not in \"ldap-attribute = value\" format");
1891 
1892  goto error;
1893  }
1894 
1895  /*
1896  * Retrieve all the information we need about the pair
1897  */
1898  cp = cf_item_to_pair(ci);
1899  value = cf_pair_value(cp);
1900  attr = cf_pair_attr(cp);
1901  op = cf_pair_operator(cp);
1902 
1903  if (!value || (*value == '\0')) {
1904  RDEBUG("Empty value string, skipping attribute \"%s\"", attr);
1905 
1906  continue;
1907  }
1908 
1909  switch (cf_pair_value_type(cp)) {
1910  case T_BARE_WORD:
1912  break;
1913 
1914  case T_BACK_QUOTED_STRING:
1916  do_xlat = true;
1917  break;
1918 
1919  default:
1920  rad_assert(0);
1921  goto error;
1922  }
1923 
1924  if (op == T_OP_CMP_FALSE) {
1925  passed[last_pass] = NULL;
1926  } else if (do_xlat) {
1927  char *exp = NULL;
1928 
1929  if (radius_axlat(&exp, request, value, NULL, NULL) <= 0) {
1930  RDEBUG("Skipping attribute \"%s\"", attr);
1931 
1932  talloc_free(exp);
1933 
1934  continue;
1935  }
1936 
1937  expanded[last_exp++] = exp;
1938  passed[last_pass] = exp;
1939  /*
1940  * Static strings
1941  */
1942  } else {
1943  memcpy(&(passed[last_pass]), &value, sizeof(passed[last_pass]));
1944  }
1945 
1946  passed[last_pass + 1] = NULL;
1947 
1948  mod_s[total].mod_values = &(passed[last_pass]);
1949 
1950  last_pass += 2;
1951 
1952  switch (op) {
1953  /*
1954  * T_OP_EQ is *NOT* supported, it is impossible to
1955  * support because of the lack of transactions in LDAP
1956  */
1957  case T_OP_ADD:
1958  mod_s[total].mod_op = LDAP_MOD_ADD;
1959  break;
1960 
1961  case T_OP_SET:
1962  mod_s[total].mod_op = LDAP_MOD_REPLACE;
1963  break;
1964 
1965  case T_OP_SUB:
1966  case T_OP_CMP_FALSE:
1967  mod_s[total].mod_op = LDAP_MOD_DELETE;
1968  break;
1969 
1970 #ifdef LDAP_MOD_INCREMENT
1971  case T_OP_INCRM:
1972  mod_s[total].mod_op = LDAP_MOD_INCREMENT;
1973  break;
1974 #endif
1975  default:
1976  REDEBUG("Operator '%s' is not supported for LDAP modify operations",
1977  fr_int2str(fr_tokens_table, op, "<INVALID>"));
1978 
1979  goto error;
1980  }
1981 
1982  /*
1983  * Now we know the value is ok, copy the pointers into
1984  * the ldapmod struct.
1985  */
1986  memcpy(&(mod_s[total].mod_type), &attr, sizeof(mod_s[total].mod_type));
1987 
1988  mod_p[total] = &(mod_s[total]);
1989  total++;
1990  }
1991 
1992  if (total == 0) {
1993  rcode = RLM_MODULE_NOOP;
1994  goto release;
1995  }
1996 
1997  mod_p[total] = NULL;
1998 
1999  conn = mod_conn_get(inst, request);
2000  if (!conn) return RLM_MODULE_FAIL;
2001 
2002 
2003  dn = rlm_ldap_find_user(inst, request, &conn, NULL, false, NULL, &rcode);
2004  if (!dn || (rcode != RLM_MODULE_OK)) {
2005  goto error;
2006  }
2007 
2008  status = rlm_ldap_modify(inst, request, &conn, dn, modify, NULL, NULL);
2009  switch (status) {
2010  case LDAP_PROC_SUCCESS:
2011  break;
2012 
2013  case LDAP_PROC_REJECT:
2014  case LDAP_PROC_BAD_DN:
2015  rcode = RLM_MODULE_INVALID;
2016  break;
2017 
2018  default:
2019  rcode = RLM_MODULE_FAIL;
2020  break;
2021  };
2022 
2023  release:
2024  error:
2025  /*
2026  * Free up any buffers we allocated for xlat expansion
2027  */
2028  for (i = 0; i < last_exp; i++) {
2029  talloc_free(expanded[i]);
2030  }
2031 
2032  mod_conn_release(inst, conn);
2033 
2034  return rcode;
2035 }
2036 
2037 static rlm_rcode_t mod_accounting(void *instance, REQUEST *request) CC_HINT(nonnull);
2038 static rlm_rcode_t mod_accounting(void *instance, REQUEST *request)
2039 {
2040  rlm_ldap_t *inst = instance;
2041 
2042  if (inst->accounting) return user_modify(inst, request, inst->accounting);
2043 
2044  return RLM_MODULE_NOOP;
2045 }
2046 
2047 static rlm_rcode_t mod_post_auth(void *instance, REQUEST *request) CC_HINT(nonnull);
2048 static rlm_rcode_t CC_HINT(nonnull) mod_post_auth(void *instance, REQUEST *request)
2049 {
2050  rlm_ldap_t *inst = instance;
2051 
2052  if (inst->postauth) {
2053  return user_modify(inst, request, inst->postauth);
2054  }
2055 
2056  return RLM_MODULE_NOOP;
2057 }
2058 
2059 
2060 /* globally exported name */
2061 extern module_t rlm_ldap;
2062 module_t rlm_ldap = {
2064  .name = "ldap",
2065  .type = 0,
2066  .inst_size = sizeof(rlm_ldap_t),
2067  .config = module_config,
2068  .bootstrap = mod_bootstrap,
2069  .instantiate = mod_instantiate,
2070  .detach = mod_detach,
2071  .methods = {
2076  },
2077 };
static int parse_sub_section(rlm_ldap_t *inst, CONF_SECTION *parent, ldap_acct_section_t **config, rlm_components_t comp)
Parse an accounting sub section.
Definition: rlm_ldap.c:684
ssize_t ssize_t ssize_t radius_axlat(char **out, REQUEST *request, char const *fmt, xlat_escape_t escape, void *escape_ctx) CC_HINT(nonnull(1
static CONF_PARSER option_config[]
Definition: rlm_ldap.c:177
char const * cache_attribute
Sets the attribute we use when creating and retrieving cached group memberships.
Definition: ldap.h:265
#define PW_TYPE_FILE_INPUT
File matching value must exist, and must be readable.
Definition: conffile.h:204
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
VALUE_PAIR * config
VALUE_PAIR (s) used to set per request parameters for modules and the server core at runtime...
Definition: radiusd.h:227
FR_TOKEN cf_pair_value_type(CONF_PAIR const *pair)
Return the value (rhs) type.
Definition: conffile.c:3541
Operation was successfull.
Definition: ldap.h:397
#define RINDENT()
Indent R* messages by one level.
Definition: log.h:265
int int map_to_request(REQUEST *request, vp_map_t const *map, radius_map_getvalue_t func, void *ctx)
Convert vp_map_t to VALUE_PAIR (s) and add them to a REQUEST.
Definition: map.c:1019
int xlat_register(void *mod_inst, char const *name, xlat_func_t func, xlat_escape_t escape, xlat_instantiate_t instantiate, size_t inst_size, size_t buf_len)
Register an xlat function.
Definition: xlat.c:717
#define RDEBUG_ENABLED3
True if request debug level 1-3 messages are enabled.
Definition: log.h:239
FR_NAME_NUMBER const ldap_scope[]
Definition: rlm_ldap.c:44
#define LDAP_VIRTUAL_DN_ATTR
'Virtual' attribute which maps to the DN of the object.
Definition: ldap.h:123
The module is OK, continue.
Definition: radiusd.h:91
static int mod_instantiate(CONF_SECTION *conf, void *instance)
Instantiate the module.
Definition: rlm_ldap.c:787
char const * userobj_access_attr
Attribute to check to see if the user should be locked out.
Definition: ldap.h:234
static rlm_rcode_t mod_post_auth(void *instance, REQUEST *request) CC_HINT(nonnull)
Metadata exported by the module.
Definition: modules.h:134
static CONF_PARSER sasl_mech_static[]
Definition: rlm_ldap.c:82
#define RDEBUG_ENABLED2
True if request debug level 1-2 messages are enabled.
Definition: log.h:238
fr_connection_pool_t * pool
Connection pool instance.
Definition: ldap.h:182
#define MEM(x)
Definition: radiusd.h:396
vp_tmpl_t * groupobj_base_dn
DN to search for users under.
Definition: ldap.h:247
fr_dict_attr_t const * group_da
The DA associated with this specific instance of the.
Definition: ldap.h:274
7 methods index for postauth section.
Definition: modules.h:48
CONF_ITEM * cf_pair_to_item(CONF_PAIR const *cp)
Cast a CONF_PAIR to a CONF_ITEM.
Definition: conffile.c:211
static int mod_bootstrap(CONF_SECTION *conf, void *instance)
Bootstrap the module.
Definition: rlm_ldap.c:721
#define INFO(fmt,...)
Definition: log.h:143
static char const * name
VALUE_PAIR * radius_pair_create(TALLOC_CTX *ctx, VALUE_PAIR **vps, unsigned int attribute, unsigned int vendor)
Create a VALUE_PAIR and add it to a list of VALUE_PAIR s.
Definition: pair.c:704
static ssize_t ldap_unescape_xlat(char **out, size_t outlen, UNUSED void const *mod_inst, UNUSED void const *xlat_inst, REQUEST *request, char const *fmt)
Definition: rlm_ldap.c:264
int tls_mode
Definition: ldap.h:308
int groupobj_scope
Search scope.
Definition: ldap.h:249
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
bool use_referral_credentials
If true use credentials from the referral URL.
Definition: ldap.h:202
#define LDAP_VENDOR_VERSION_PATCH
Definition: ldap.h:73
char const * group_attribute
Sets the attribute we use when comparing group group memberships.
Definition: ldap.h:271
#define UNUSED
Definition: libradius.h:134
#define RLM_MODULE_INIT
Definition: modules.h:86
vp_tmpl_t * proxy
Identity to proxy.
Definition: ldap.h:150
#define CONF_PARSER_TERMINATOR
Definition: conffile.h:289
bool chase_referrals_unset
If true, use the OpenLDAP defaults for chase_referrals.
Definition: ldap.h:200
const FR_NAME_NUMBER fr_tokens_table[]
Definition: token.c:30
char * server
Initial server to bind to.
Definition: ldap.h:185
ldap_acct_section_t * accounting
Modify mappings for accounting.
Definition: ldap.h:302
void void void cf_log_err_cp(CONF_PAIR const *cp, char const *fmt,...) CC_HINT(format(printf
int fr_dict_attr_add(fr_dict_t *dict, fr_dict_attr_t const *parent, char const *name, int attr, PW_TYPE type, fr_dict_attr_flags_t flags)
Add an attribute to the dictionary.
Definition: dict.c:582
PUBLIC int snprintf(char *string, size_t length, char *format, va_alist)
Definition: snprintf.c:686
Values of the encryption flags.
Definition: dict.h:40
static ssize_t ldap_xlat(char **out, size_t outlen, void const *mod_inst, UNUSED void const *xlat_inst, REQUEST *request, char const *fmt)
Expand an LDAP URL into a query, and return a string result from that query.
Definition: rlm_ldap.c:274
static rlm_rcode_t mod_map_proc(void *mod_inst, UNUSED void *proc_inst, REQUEST *request, char const *url, vp_map_t const *maps)
Perform a search and map the result of the search to server attributes.
Definition: rlm_ldap.c:381
int map_proc_register(void *mod_inst, char const *name, map_proc_func_t evaluate, xlat_escape_t escape, map_proc_instantiate_t instantiate, size_t inst_size)
Register a map processor.
Definition: map_proc.c:132
#define PW_TYPE_SECRET
Only print value if debug level >= 3.
Definition: conffile.h:202
vp_tmpl_t * realm
Kerberos realm.
Definition: ldap.h:151
#define inst
Definition: token.h:46
bool cacheable_group_name
If true the server will determine complete set of group memberships for the current user object...
Definition: ldap.h:255
The module considers the request invalid.
Definition: radiusd.h:93
int userobj_scope
Search scope.
Definition: ldap.h:231
static expr_map_t map[]
Definition: rlm_expr.c:169
bool cacheable_group_dn
If true the server will determine complete set of group memberships for the current user object...
Definition: ldap.h:260
#define XLAT_DEFAULT_BUF_LEN
Definition: xlat.h:89
ldap_rcode_t
Codes returned by rlm_ldap internal functions.
Definition: ldap.h:395
CONF_SECTION * cf_item_to_section(CONF_ITEM const *item)
Cast a CONF_ITEM to a CONF_SECTION.
Definition: conffile.c:196
char const * profile_attr
Attribute that identifies profiles to apply.
Definition: ldap.h:294
static rlm_rcode_t mod_authenticate(void *instance, REQUEST *request) CC_HINT(nonnull)
#define LDAP_MAX_FILTER_STR_LEN
Maximum length of an xlat expanded filter.
Definition: ldap.h:120
#define PW_TYPE_SUBSECTION
Definition: conffile.h:188
size_t rlm_ldap_normalise_dn(char *out, char const *in)
Normalise escape sequences in a DN.
Definition: ldap.c:312
Defines a CONF_PAIR to C data type mapping.
Definition: conffile.h:267
void void void void void void cf_item_add(CONF_SECTION *cs, CONF_ITEM *ci)
Definition: conffile.c:803
char const * clientobj_scope_str
Scope (sub, one, base).
Definition: ldap.h:282
CONF_PAIR * cf_pair_find(CONF_SECTION const *, char const *name)
Definition: conffile.c:3478
char const * cf_pair_value(CONF_PAIR const *pair)
Definition: conffile.c:3506
struct vp_map * next
The next valuepair map.
Definition: map.h:55
rlm_rcode_t rlm_ldap_check_userobj_dynamic(rlm_ldap_t const *inst, REQUEST *request, ldap_handle_t **pconn, char const *dn, VALUE_PAIR *check)
Query the LDAP directory to check if a user object is a member of a group.
Definition: groups.c:632
static const CONF_PARSER acct_section_config[]
Definition: rlm_ldap.c:167
char const * reference
Configuration reference string.
Definition: ldap.h:139
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
static CONF_PARSER group_config[]
Definition: rlm_ldap.c:142
char const * groupobj_scope_str
Scope (sub, one, base).
Definition: ldap.h:248
void fr_pair_value_strsteal(VALUE_PAIR *vp, char const *src)
Reparent an allocated char buffer to a VALUE_PAIR.
Definition: pair.c:1955
int map_afrom_cs(vp_map_t **out, CONF_SECTION *cs, pair_lists_t dst_list_def, pair_lists_t src_list_def, map_validate_t validate, void *ctx, unsigned int max) CC_HINT(nonnull(1
#define rad_assert(expr)
Definition: rad_assert.h:38
Reject the request (user is locked out).
Definition: radiusd.h:94
char const * userobj_membership_attr
Attribute that describes groups the user is a member of.
Definition: ldap.h:233
char const * valuepair_attr
Generic dynamic mapping attribute, contains a RADIUS attribute and value.
Definition: ldap.h:238
int fr_str2int(FR_NAME_NUMBER const *table, char const *name, int def)
Definition: token.c:451
rlm_rcode_t rlm_ldap_cacheable_userobj(rlm_ldap_t const *inst, REQUEST *request, ldap_handle_t **pconn, LDAPMessage *entry, char const *attr)
Convert group membership information into attributes.
Definition: groups.c:267
fr_connection_pool_t * module_connection_pool_init(CONF_SECTION *module, void *opaque, fr_connection_create_t c, fr_connection_alive_t a, char const *prefix)
Initialise a module specific connection pool.
Definition: modules.c:1759
int cf_pair_replace(CONF_SECTION *cs, CONF_PAIR *cp, char const *value)
Replace pair in a given section with a new pair, of the given value.
Definition: conffile.c:768
#define LDAP_MAX_DN_STR_LEN
Maximum length of an xlat expanded DN.
Definition: ldap.h:121
char const * groupobj_name_attr
The name of the group.
Definition: ldap.h:251
Result of expanding the RHS of a set of maps.
Definition: ldap.h:375
char const * cf_pair_attr(CONF_PAIR const *pair)
Definition: conffile.c:3497
#define DEBUG(fmt,...)
Definition: log.h:175
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
bool cf_item_is_section(CONF_ITEM const *item)
Definition: conffile.c:3923
static void * mod_conn_create(TALLOC_CTX *ctx, void *instance, struct timeval const *timeout)
Create a new memcached handle.
#define LDAP_ERR(fmt,...)
Definition: ldap.h:435
static ssize_t ldap_escape_xlat(char **out, size_t outlen, UNUSED void const *mod_inst, UNUSED void const *xlat_inst, REQUEST *request, char const *fmt)
Definition: rlm_ldap.c:257
static CONF_PARSER profile_config[]
Definition: rlm_ldap.c:115
fr_dict_attr_t const * cache_da
The DA associated with this specific instance of the.
Definition: ldap.h:268
bool rebound
Whether the connection has been rebound to something other than the admin user.
Definition: ldap.h:165
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
#define PW_TYPE_XLAT
string will be dynamically expanded.
Definition: conffile.h:207
CONF_PAIR * cf_item_to_pair(CONF_ITEM const *item)
Cast a CONF_ITEM to a CONF_PAIR.
Definition: conffile.c:181
int cf_section_parse(CONF_SECTION *, void *base, CONF_PARSER const *variables)
Parse a configuration section into user-supplied variables.
Definition: conffile.c:2234
static bool done
Definition: radclient.c:53
Immediately reject the request.
Definition: radiusd.h:89
Definition: token.h:43
Attributes in incoming or internally proxied request.
Definition: tmpl.h:82
int count
Number of values.
Definition: ldap.h:389
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
3 methods index for accounting section.
Definition: modules.h:44
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
Definition: token.h:44
const section_type_value_t section_type_value[]
Mappings between section names, typenames and control attributes.
Definition: modules.c:64
char const * groupobj_membership_filter
Filter to only retrieve groups which contain the user as a member.
Definition: ldap.h:252
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
ldap_sasl_dynamic user_sasl
SASL parameters used when binding as the user.
Definition: ldap.h:241
Contains a collection of values.
Definition: ldap.h:386
void void cf_log_err_cs(CONF_SECTION const *cs, char const *fmt,...) CC_HINT(format(printf
0 methods index for authenticate section.
Definition: modules.h:41
CONF_SECTION * cs
Main configuration section for this instance.
Definition: ldap.h:181
CONF_PAIR * cf_pair_find_next(CONF_SECTION const *, CONF_PAIR const *, char const *name)
Find a pair with a name matching attr, after specified pair.
Definition: conffile.c:3673
bool cf_item_is_pair(CONF_ITEM const *item)
Definition: conffile.c:3928
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
static const CONF_PARSER module_config[]
Definition: rlm_ldap.c:219
A truth value.
Definition: radius.h:56
Configuration AVP similar to a VALUE_PAIR.
Definition: conffile.c:82
char const * proxy
Identity to proxy.
Definition: ldap.h:144
char const * name
Instance name.
Definition: ldap.h:212
#define FR_CONF_DEPRECATED(_n, _t, _p, _f)
Definition: conffile.h:179
Definition: token.h:45
32 Bit unsigned integer.
Definition: radius.h:34
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
static rs_t * conf
Definition: radsniff.c:46
char const * fr_strerror(void)
Get the last library error.
Definition: log.c:212
static CONF_PARSER sasl_mech_dynamic[]
Definition: rlm_ldap.c:75
CONF_SECTION * cf_section_sub_find(CONF_SECTION const *, char const *name)
Find a sub-section in a section.
Definition: conffile.c:3708
int count
Index on next free element.
Definition: ldap.h:380
vp_map_t * user_map
Attribute map applied to users and profiles.
Definition: ldap.h:220
static int mod_conn_get(void **handle, UNUSED rlm_cache_config_t const *config, void *driver_inst, UNUSED REQUEST *request)
Get a memcached handle.
static CONF_PARSER tls_config[]
Definition: rlm_ldap.c:92
rlm_ldap_t * inst
rlm_ldap configuration.
Definition: ldap.h:177
#define DEBUG4(fmt,...)
Definition: log.h:178
LDAP * handle
Hack for OpenLDAP libldap global initialisation.
Definition: ldap.h:368
char const * cf_section_name1(CONF_SECTION const *cs)
Definition: conffile.c:3592
CONF_PAIR * cf_pair_alloc(CONF_SECTION *parent, char const *attr, char const *value, FR_TOKEN op, FR_TOKEN lhs_type, FR_TOKEN rhs_type)
Allocate a CONF_PAIR.
Definition: conffile.c:546
#define PW_TYPE_NOT_EMPTY
CONF_PAIR is required to have a non zero length value.
Definition: conffile.h:211
rlm_rcode_t rlm_ldap_cacheable_groupobj(rlm_ldap_t const *inst, REQUEST *request, ldap_handle_t **pconn)
Convert group membership information into attributes.
Definition: groups.c:415
Module succeeded without doing anything.
Definition: radiusd.h:96
#define RDEBUG2(fmt,...)
Definition: log.h:244
CONF_SECTION * cs
Section configuration.
Definition: ldap.h:137
char name[1]
Attribute name.
Definition: dict.h:89
struct ldap_instance rlm_ldap_t
Definition: ldap.h:134
#define LDAP_MAX_ATTRMAP
Maximum number of mappings between LDAP and.
Definition: ldap.h:107
uint64_t magic
Used to validate module struct.
Definition: modules.h:135
Module failed, don't reply.
Definition: radiusd.h:90
int rlm_ldap_map_expand(rlm_ldap_map_exp_t *expanded, REQUEST *request, vp_map_t const *maps)
Expand values in an attribute map where needed.
Definition: attrmap.c:251
#define TAG_ANY
Definition: pair.h:191
int clientobj_scope
Search scope.
Definition: ldap.h:283
#define FR_CONF_OFFSET(_n, _t, _s, _f)
Definition: conffile.h:168
FR_NAME_NUMBER const ldap_tls_require_cert[]
int rlm_ldap_client_load(rlm_ldap_t const *inst, CONF_SECTION *tmpl, CONF_SECTION *map)
Load clients from LDAP on server start.
Definition: clients.c:102
rlm_rcode_t rlm_ldap_check_cached(rlm_ldap_t const *inst, REQUEST *request, VALUE_PAIR *check)
Check group membership attributes to see if a user is a member.
Definition: groups.c:812
struct berval ** values
libldap struct containing bv_val (char *) and length bv_len.
Definition: ldap.h:387
char const * edir_errstr(int code)
Definition: edir.c:245
int paircompare_register_byname(char const *name, fr_dict_attr_t const *from, bool first_only, RAD_COMPARE_FUNC func, void *instance)
Register a function as compare function.
Definition: pair.c:351
Specified an invalid object in a bind or search DN.
Definition: ldap.h:410
static void mod_conn_release(UNUSED rlm_cache_config_t const *config, void *driver_inst, UNUSED REQUEST *request, rlm_cache_handle_t *handle)
Release a memcached handle.
int rlm_ldap_map_getvalue(TALLOC_CTX *ctx, VALUE_PAIR **out, REQUEST *request, vp_map_t const *map, void *uctx)
Callback for map_to_request.
Definition: attrmap.c:36
enum rlm_components rlm_components_t
The different section components of the server.
static rlm_rcode_t mod_accounting(void *instance, REQUEST *request) CC_HINT(nonnull)
Definition: rlm_ldap.c:2038
static rlm_rcode_t rlm_ldap_map_profile(rlm_ldap_t const *inst, REQUEST *request, ldap_handle_t **pconn, char const *dn, rlm_ldap_map_exp_t const *expanded)
Search for and apply an LDAP profile.
Definition: rlm_ldap.c:1510
static int rlm_ldap_groupcmp(void *instance, REQUEST *request, UNUSED VALUE_PAIR *thing, VALUE_PAIR *check, UNUSED VALUE_PAIR *check_pairs, UNUSED VALUE_PAIR **reply_pairs)
Perform LDAP-Group comparison checking.
Definition: rlm_ldap.c:526
Attributes to send in the response.
Definition: tmpl.h:84
int nmasldap_get_password(LDAP *ld, char const *dn, char *password, size_t *passlen)
Attempt to retrieve the universal password from Novell eDirectory.
Definition: edir.c:165
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
int rlm_ldap_map_do(const rlm_ldap_t *inst, REQUEST *request, LDAP *handle, rlm_ldap_map_exp_t const *expanded, LDAPMessage *entry)
Convert attribute map into valuepairs.
Definition: attrmap.c:302
#define WARN(fmt,...)
Definition: log.h:144
char const * attrs[LDAP_MAX_ATTRMAP+LDAP_MAP_RESERVED+1]
Reserve some space for access attributes.
Definition: ldap.h:377
#define REDEBUG(fmt,...)
Definition: log.h:254
CONF_ITEM * cf_item_find_next(CONF_SECTION const *section, CONF_ITEM const *item)
Return the next item after a CONF_ITEM.
Definition: conffile.c:3850
bool do_clients
If true, attempt to load clients on instantiation.
Definition: ldap.h:285
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
static CONF_PARSER client_config[]
Definition: rlm_ldap.c:157
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
TALLOC_CTX * ctx
Context to allocate new attributes in.
Definition: ldap.h:379
enum fr_token FR_TOKEN
char const * mech
SASL mech(s) to try.
Definition: ldap.h:143
vp_tmpl_t * profile_filter
Filter to retrieve only retrieve group objects.
Definition: ldap.h:296
size_t strlcpy(char *dst, char const *src, size_t siz)
Definition: strlcpy.c:38
static CONF_PARSER user_config[]
Definition: rlm_ldap.c:125
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
vp_tmpl_t * default_profile
If this is set, we will search for a profile object with this name, and map any attributes it contain...
Definition: ldap.h:290
static rlm_rcode_t user_modify(rlm_ldap_t *inst, REQUEST *request, ldap_acct_section_t *section)
Modify user's object in LDAP.
Definition: rlm_ldap.c:1814
fr_dict_attr_t const * da
Dictionary attribute defines the attribute.
Definition: pair.h:113
char const * userobj_scope_str
Scope (sub, one, base).
Definition: ldap.h:227
char const * realm
Kerberos realm.
Definition: ldap.h:145
#define MAX_STRING_LEN
Definition: libradius.h:120
fr_dict_attr_t const * fr_dict_attr_by_num(fr_dict_t *dict, unsigned int vendor, unsigned int attr)
Lookup a fr_dict_attr_t by its vendor and attribute numbers.
Definition: dict.c:3519
String of printable characters.
Definition: radius.h:33
#define FR_CONF_POINTER(_n, _t, _p)
Definition: conffile.h:172
ldap_sasl admin_sasl
SASL parameters used when binding as the admin.
Definition: ldap.h:192
#define RWDEBUG(fmt,...)
Definition: log.h:251
#define PW_TYPE_TMPL
CONF_PAIR should be parsed as a template.
Definition: conffile.h:208
1 methods index for authorize section.
Definition: modules.h:42
User not found.
Definition: radiusd.h:95
rlm_rcode_t rlm_ldap_check_groupobj_dynamic(rlm_ldap_t const *inst, REQUEST *request, ldap_handle_t **pconn, VALUE_PAIR *check)
Query the LDAP directory to check if a group object includes a user object as a member.
Definition: groups.c:530
static rlm_rcode_t CC_HINT(nonnull)
Definition: rlm_ldap.c:1372
char const * section
Section name e.g. "Authorize".
Definition: modules.h:64
#define RCSID(id)
Definition: build.h:135
ldap_acct_section_t * postauth
Modify mappings for post-auth.
Definition: ldap.h:301
int rlm_ldap_map_verify(vp_map_t *map, void *instance)
Definition: attrmap.c:146
FR_TOKEN cf_pair_operator(CONF_PAIR const *pair)
Definition: conffile.c:3511
OK (pairs modified).
Definition: radiusd.h:97
LDAP authorization and authentication module headers.
Value pair map.
Definition: map.h:46
fr_dict_t * fr_dict_internal
Internal server dictionary.
Definition: dict.c:81
fr_dict_attr_t const * fr_dict_root(fr_dict_t const *dict)
Return the root attribute of a dictionary.
Definition: dict.c:2339
char const * userobj_sort_by
List of attributes to sort by.
Definition: ldap.h:228
static int mod_detach(void *instance)
Detach from the LDAP server and cleanup internal state.
Definition: rlm_ldap.c:642
char const * dereference_str
When to dereference (never, searching, finding, always)
Definition: ldap.h:194
#define RDEBUG(fmt,...)
Definition: log.h:243
16 Bit unsigned integer.
Definition: radius.h:43
bool rlm_ldap_is_dn(char const *in, size_t inlen)
Check whether a string looks like a DN.
Definition: ldap.c:168
char const * config_server
Server set in the config.
Definition: ldap.h:184
static rlm_rcode_t mod_authorize(void *instance, REQUEST *request) CC_HINT(nonnull)
Definition: rlm_ldap.c:1570
char const * cf_section_name2(CONF_SECTION const *cs)
Definition: conffile.c:3601
module_t rlm_ldap
Definition: rlm_ldap.c:2062
void fr_connection_pool_free(fr_connection_pool_t *pool)
Delete a connection pool.
Definition: connection.c:1226
LDAP * handle
libldap handle.
Definition: ldap.h:164
static FR_NAME_NUMBER const ldap_dereference[]
Definition: rlm_ldap.c:66
Bind failed, user was rejected.
Definition: ldap.h:408
vp_tmpl_t * mech
SASL mech(s) to try.
Definition: ldap.h:149
fr_dict_attr_t const * fr_dict_attr_by_name(fr_dict_t *dict, char const *attr)
Locate a fr_dict_attr_t by its name.
Definition: dict.c:3493
#define RDEBUG3(fmt,...)
Definition: log.h:245
Got no results.
Definition: ldap.h:412
CONF_ITEM * cf_reference_item(CONF_SECTION const *parentcs, CONF_SECTION *outercs, char const *ptr)
Definition: conffile.c:906