It's cleartext password not Clear-Text password or Cleartext Password
[freeradius.git] / src / modules / rlm_ldap / rlm_ldap.c
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, version 2 if the
4  *   License as published by the Free Software Foundation.
5  *
6  *   This program is distributed in the hope that it will be useful,
7  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
8  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
9  *   GNU General Public License for more details.
10  *
11  *   You should have received a copy of the GNU General Public License
12  *   along with this program; if not, write to the Free Software
13  *   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
14  */
15
16 /**
17  * $Id$
18  * @file rlm_ldap.c
19  * @brief LDAP authorization and authentication module.
20  *
21  * @author Arran Cudbard-Bell <a.cudbardb@freeradius.org>
22  * @author Alan DeKok <aland@freeradius.org>
23  *
24  * @copyright 2013 Network RADIUS SARL <info@networkradius.com>
25  * @copyright 2012-2013 Arran Cudbard-Bell <a.cudbardb@freeradius.org>
26  * @copyright 2012 Alan DeKok <aland@freeradius.org>
27  * @copyright 1999-2013 The FreeRADIUS Server Project.
28  */
29 RCSID("$Id$")
30
31 #include        <freeradius-devel/rad_assert.h>
32
33 #include        <stdarg.h>
34 #include        <ctype.h>
35
36 #include        "ldap.h"
37
38 /*
39  *      Scopes
40  */
41 FR_NAME_NUMBER const ldap_scope[] = {
42         { "sub",        LDAP_SCOPE_SUB  },
43         { "one",        LDAP_SCOPE_ONE  },
44         { "base",       LDAP_SCOPE_BASE },
45         { "children",   LDAP_SCOPE_CHILDREN },
46
47         {  NULL , -1 }
48 };
49
50 #ifdef LDAP_OPT_X_TLS_NEVER
51 FR_NAME_NUMBER const ldap_tls_require_cert[] = {
52         { "never",      LDAP_OPT_X_TLS_NEVER    },
53         { "demand",     LDAP_OPT_X_TLS_DEMAND   },
54         { "allow",      LDAP_OPT_X_TLS_ALLOW    },
55         { "try",        LDAP_OPT_X_TLS_TRY      },
56         { "hard",       LDAP_OPT_X_TLS_HARD     },      /* oh yes, just like that */
57
58         {  NULL , -1 }
59 };
60 #endif
61
62 /*
63  *      TLS Configuration
64  */
65 static CONF_PARSER tls_config[] = {
66         /*
67          *      Deprecated attributes
68          */
69         {"cacertfile", PW_TYPE_FILE_INPUT | PW_TYPE_DEPRECATED, offsetof(ldap_instance_t, tls_ca_file), NULL, NULL},
70         {"ca_file", PW_TYPE_FILE_INPUT, offsetof(ldap_instance_t, tls_ca_file), NULL, NULL},
71
72         {"cacertdir", PW_TYPE_FILE_INPUT | PW_TYPE_DEPRECATED, offsetof(ldap_instance_t, tls_ca_path), NULL, NULL},
73         {"ca_path", PW_TYPE_FILE_INPUT, offsetof(ldap_instance_t, tls_ca_path), NULL, NULL},
74
75         {"certfile", PW_TYPE_FILE_INPUT | PW_TYPE_DEPRECATED, offsetof(ldap_instance_t, tls_certificate_file), NULL, NULL},
76         {"certificate_file", PW_TYPE_FILE_INPUT, offsetof(ldap_instance_t, tls_certificate_file), NULL, NULL},
77
78         {"keyfile", PW_TYPE_FILE_INPUT | PW_TYPE_DEPRECATED, offsetof(ldap_instance_t, tls_private_key_file), NULL, NULL}, // OK if it changes on HUP
79         {"private_key_file", PW_TYPE_FILE_INPUT, offsetof(ldap_instance_t, tls_private_key_file), NULL, NULL}, // OK if it changes on HUP
80
81         {"randfile", PW_TYPE_FILE_INPUT | PW_TYPE_DEPRECATED, offsetof(ldap_instance_t, tls_random_file), NULL, NULL},
82         {"random_file", PW_TYPE_FILE_INPUT, offsetof(ldap_instance_t, tls_random_file), NULL, NULL},
83
84         /*
85          *      LDAP Specific TLS attributes
86          */
87         {"start_tls", PW_TYPE_BOOLEAN, offsetof(ldap_instance_t, start_tls), NULL, "no"},
88         {"require_cert", PW_TYPE_STRING_PTR, offsetof(ldap_instance_t, tls_require_cert_str), NULL, NULL},
89
90         { NULL, -1, 0, NULL, NULL }
91 };
92
93
94 static CONF_PARSER profile_config[] = {
95         {"filter", PW_TYPE_STRING_PTR, offsetof(ldap_instance_t, profile_filter), NULL, "(&)"}, //!< Correct filter for
96                                                                                                 //!< when the DN is
97                                                                                                 //!< known.
98         {"attribute", PW_TYPE_STRING_PTR, offsetof(ldap_instance_t, profile_attr), NULL, NULL},
99         {"default", PW_TYPE_STRING_PTR, offsetof(ldap_instance_t, default_profile), NULL, NULL},
100
101         { NULL, -1, 0, NULL, NULL }
102 };
103
104 /*
105  *      User configuration
106  */
107 static CONF_PARSER user_config[] = {
108         {"filter", PW_TYPE_STRING_PTR, offsetof(ldap_instance_t, userobj_filter), NULL, "(uid=%u)"},
109         {"scope", PW_TYPE_STRING_PTR, offsetof(ldap_instance_t, userobj_scope_str), NULL, "sub"},
110         {"base_dn", PW_TYPE_STRING_PTR, offsetof(ldap_instance_t,userobj_base_dn), NULL, ""},
111
112         {"access_attribute", PW_TYPE_STRING_PTR, offsetof(ldap_instance_t, userobj_access_attr), NULL, NULL},
113         {"access_positive", PW_TYPE_BOOLEAN, offsetof(ldap_instance_t, access_positive), NULL, "yes"},
114
115         { NULL, -1, 0, NULL, NULL }
116 };
117
118 /*
119  *      Group configuration
120  */
121 static CONF_PARSER group_config[] = {
122         {"filter", PW_TYPE_STRING_PTR, offsetof(ldap_instance_t, groupobj_filter), NULL, NULL},
123         {"scope", PW_TYPE_STRING_PTR, offsetof(ldap_instance_t, groupobj_scope_str), NULL, "sub"},
124         {"base_dn", PW_TYPE_STRING_PTR, offsetof(ldap_instance_t, groupobj_base_dn), NULL, ""},
125
126         {"name_attribute", PW_TYPE_STRING_PTR, offsetof(ldap_instance_t, groupobj_name_attr), NULL, "cn"},
127         {"membership_attribute", PW_TYPE_STRING_PTR, offsetof(ldap_instance_t, userobj_membership_attr), NULL, NULL},
128         {"membership_filter", PW_TYPE_STRING_PTR, offsetof(ldap_instance_t, groupobj_membership_filter), NULL, NULL},
129         {"cacheable_name", PW_TYPE_BOOLEAN, offsetof(ldap_instance_t, cacheable_group_name), NULL, "no"},
130         {"cacheable_dn", PW_TYPE_BOOLEAN, offsetof(ldap_instance_t, cacheable_group_dn), NULL, "no"},
131
132         { NULL, -1, 0, NULL, NULL }
133 };
134
135 /*
136  *      Client configuration
137  */
138 static CONF_PARSER client_attribute[] = {
139         {"identifier", PW_TYPE_STRING_PTR, offsetof(ldap_instance_t, clientobj_identifier), NULL, "host"},
140         {"shortname", PW_TYPE_STRING_PTR, offsetof(ldap_instance_t, clientobj_shortname), NULL, "cn"},
141         {"nas_type", PW_TYPE_STRING_PTR, offsetof(ldap_instance_t, clientobj_type), NULL, NULL},
142         {"secret", PW_TYPE_STRING_PTR, offsetof(ldap_instance_t, clientobj_secret), NULL, NULL},
143         {"virtual_server", PW_TYPE_STRING_PTR, offsetof(ldap_instance_t, clientobj_server), NULL, NULL},
144         {"require_message_authenticator", PW_TYPE_STRING_PTR, offsetof(ldap_instance_t, clientobj_require_ma),
145          NULL, NULL},
146
147         { NULL, -1, 0, NULL, NULL }
148 };
149
150 static CONF_PARSER client_config[] = {
151         {"filter", PW_TYPE_STRING_PTR, offsetof(ldap_instance_t, clientobj_filter), NULL, NULL},
152         {"scope", PW_TYPE_STRING_PTR, offsetof(ldap_instance_t, clientobj_scope_str), NULL, "sub"},
153         {"base_dn", PW_TYPE_STRING_PTR, offsetof(ldap_instance_t, clientobj_base_dn), NULL, ""},
154         {"attribute", PW_TYPE_SUBSECTION, 0, NULL, (void const *) client_attribute},
155
156         { NULL, -1, 0, NULL, NULL }
157 };
158
159 /*
160  *      Reference for accounting updates
161  */
162 static const CONF_PARSER acct_section_config[] = {
163         {"reference", PW_TYPE_STRING_PTR, offsetof(ldap_acct_section_t, reference), NULL, "."},
164
165         {NULL, -1, 0, NULL, NULL}
166 };
167
168 /*
169  *      Various options that don't belong in the main configuration.
170  *
171  *      Note that these overlap a bit with the connection pool code!
172  */
173 static CONF_PARSER option_config[] = {
174         /*
175          *      Debugging flags to the server
176          */
177         {"ldap_debug", PW_TYPE_INTEGER, offsetof(ldap_instance_t,ldap_debug), NULL, "0x0000"},
178
179         {"chase_referrals", PW_TYPE_BOOLEAN, offsetof(ldap_instance_t,chase_referrals), NULL, NULL},
180
181         {"rebind", PW_TYPE_BOOLEAN, offsetof(ldap_instance_t,rebind), NULL, NULL},
182
183         /* timeout on network activity */
184         {"net_timeout", PW_TYPE_INTEGER, offsetof(ldap_instance_t,net_timeout), NULL, "10"},
185
186         /* timeout for search results */
187         {"res_timeout", PW_TYPE_INTEGER, offsetof(ldap_instance_t,res_timeout), NULL, "20"},
188
189         /* allow server unlimited time for search (server-side limit) */
190         {"srv_timelimit", PW_TYPE_INTEGER, offsetof(ldap_instance_t,srv_timelimit), NULL, "20"},
191
192 #ifdef LDAP_OPT_X_KEEPALIVE_IDLE
193         {"idle", PW_TYPE_INTEGER, offsetof(ldap_instance_t,keepalive_idle), NULL, "60"},
194 #endif
195 #ifdef LDAP_OPT_X_KEEPALIVE_PROBES
196         {"probes", PW_TYPE_INTEGER, offsetof(ldap_instance_t,keepalive_probes), NULL, "3"},
197 #endif
198 #ifdef LDAP_OPT_X_KEEPALIVE_INTERVAL
199         {"interval", PW_TYPE_INTEGER,  offsetof(ldap_instance_t,keepalive_interval), NULL, "30"},
200 #endif
201
202         { NULL, -1, 0, NULL, NULL }
203 };
204
205
206 static const CONF_PARSER module_config[] = {
207         {"server", PW_TYPE_STRING_PTR | PW_TYPE_REQUIRED, offsetof(ldap_instance_t,server), NULL, "localhost"},
208         {"port", PW_TYPE_INTEGER, offsetof(ldap_instance_t,port), NULL, "389"},
209
210         {"password", PW_TYPE_STRING_PTR | PW_TYPE_SECRET, offsetof(ldap_instance_t,password), NULL, ""},
211         {"identity", PW_TYPE_STRING_PTR, offsetof(ldap_instance_t,admin_dn), NULL, ""},
212
213         {"valuepair_attribute", PW_TYPE_STRING_PTR, offsetof(ldap_instance_t, valuepair_attr), NULL, NULL},
214
215 #ifdef WITH_EDIR
216         /* support for eDirectory Universal Password */
217         {"edir", PW_TYPE_BOOLEAN, offsetof(ldap_instance_t,edir), NULL, NULL}, /* NULL defaults to "no" */
218
219         /*
220          *      Attempt to bind with the cleartext password we got from eDirectory
221          *      Universal password for additional authorization checks.
222          */
223         {"edir_autz", PW_TYPE_BOOLEAN, offsetof(ldap_instance_t,edir_autz), NULL, NULL}, /* NULL defaults to "no" */
224 #endif
225
226         {"read_clients", PW_TYPE_BOOLEAN, offsetof(ldap_instance_t,do_clients), NULL, NULL}, /* NULL defaults to "no" */
227
228         { "user", PW_TYPE_SUBSECTION, 0, NULL, (void const *) user_config },
229
230         { "group", PW_TYPE_SUBSECTION, 0, NULL, (void const *) group_config },
231
232         { "client", PW_TYPE_SUBSECTION, 0, NULL, (void const *) client_config },
233
234         { "profile", PW_TYPE_SUBSECTION, 0, NULL, (void const *) profile_config },
235
236         { "options", PW_TYPE_SUBSECTION, 0, NULL, (void const *) option_config },
237
238         { "tls", PW_TYPE_SUBSECTION, 0, NULL, (void const *) tls_config },
239
240         {NULL, -1, 0, NULL, NULL}
241 };
242
243 /** Expand an LDAP URL into a query, and return a string result from that query.
244  *
245  */
246 static ssize_t ldap_xlat(void *instance, REQUEST *request, char const *fmt, char *out, size_t freespace)
247 {
248         ldap_rcode_t status;
249         size_t len = 0;
250         ldap_instance_t *inst = instance;
251         LDAPURLDesc *ldap_url;
252         LDAPMessage *result = NULL;
253         LDAPMessage *entry = NULL;
254         char **vals;
255         ldap_handle_t *conn;
256         int ldap_errno;
257         char const *url;
258         char const **attrs;
259
260         url = fmt;
261
262         if (!ldap_is_ldap_url(url)) {
263                 REDEBUG("String passed does not look like an LDAP URL");
264                 return -1;
265         }
266
267         if (ldap_url_parse(url, &ldap_url)){
268                 REDEBUG("Parsing LDAP URL failed");
269                 return -1;
270         }
271
272         /*
273          *      Nothing, empty string, "*" string, or got 2 things, die.
274          */
275         if (!ldap_url->lud_attrs || !ldap_url->lud_attrs[0] ||
276             !*ldap_url->lud_attrs[0] ||
277             (strcmp(ldap_url->lud_attrs[0], "*") == 0) ||
278             ldap_url->lud_attrs[1]) {
279                 REDEBUG("Bad attributes list in LDAP URL. URL must specify exactly one attribute to retrieve");
280
281                 goto free_urldesc;
282         }
283
284         if (ldap_url->lud_host &&
285             ((strncmp(inst->server, ldap_url->lud_host, strlen(inst->server)) != 0) ||
286              (ldap_url->lud_port != inst->port))) {
287                 RDEBUG("Requested server/port is \"%s:%i\"", ldap_url->lud_host, inst->port);
288
289                 goto free_urldesc;
290         }
291
292         conn = rlm_ldap_get_socket(inst, request);
293         if (!conn) goto free_urldesc;
294
295         memcpy(&attrs, &ldap_url->lud_attrs, sizeof(attrs));
296
297         status = rlm_ldap_search(inst, request, &conn, ldap_url->lud_dn, ldap_url->lud_scope, ldap_url->lud_filter,
298                                  attrs, &result);
299         switch (status) {
300                 case LDAP_PROC_SUCCESS:
301                         break;
302                 case LDAP_PROC_NO_RESULT:
303                         RDEBUG("Search returned not found");
304                 default:
305                         goto free_socket;
306         }
307
308         rad_assert(conn);
309         rad_assert(result);
310
311         entry = ldap_first_entry(conn->handle, result);
312         if (!entry) {
313                 ldap_get_option(conn->handle, LDAP_OPT_RESULT_CODE, &ldap_errno);
314                 REDEBUG("Failed retrieving entry: %s", ldap_err2string(ldap_errno));
315                 len = -1;
316                 goto free_result;
317         }
318
319         vals = ldap_get_values(conn->handle, entry, ldap_url->lud_attrs[0]);
320         if (!vals) {
321                 RDEBUG("No \"%s\" attributes found in specified object", ldap_url->lud_attrs[0]);
322                 goto free_result;
323         }
324
325         len = strlen(vals[0]);
326         if (len >= freespace){
327                 goto free_vals;
328         }
329
330         strlcpy(out, vals[0], freespace);
331
332 free_vals:
333         ldap_value_free(vals);
334 free_result:
335         ldap_msgfree(result);
336 free_socket:
337         rlm_ldap_release_socket(inst, conn);
338 free_urldesc:
339         ldap_free_urldesc(ldap_url);
340
341         return len;
342 }
343
344 /** Perform LDAP-Group comparison checking
345  *
346  * Attempts to match users to groups using a variety of methods.
347  *
348  * @param instance of the rlm_ldap module.
349  * @param request Current request.
350  * @param thing Unknown.
351  * @param check Which group to check for user membership.
352  * @param check_pairs Unknown.
353  * @param reply_pairs Unknown.
354  * @return 1 on failure (or if the user is not a member), else 0.
355  */
356 static int rlm_ldap_groupcmp(void *instance, REQUEST *request, UNUSED VALUE_PAIR *thing, VALUE_PAIR *check,
357                              UNUSED VALUE_PAIR *check_pairs, UNUSED VALUE_PAIR **reply_pairs)
358 {
359         ldap_instance_t *inst = instance;
360         rlm_rcode_t     rcode;
361
362         int             found = false;
363         int             check_is_dn;
364
365         ldap_handle_t   *conn = NULL;
366         char const      *user_dn;
367
368         rad_assert(inst->groupobj_base_dn);
369
370         RDEBUG("Searching for user in group \"%s\"", check->vp_strvalue);
371
372         if (check->length == 0) {
373                 RDEBUG("Cannot do comparison (group name is empty)");
374                 return 1;
375         }
376
377         /*
378          *      Check if we can do cached membership verification
379          */
380         check_is_dn = rlm_ldap_is_dn(check->vp_strvalue);
381         if ((check_is_dn && inst->cacheable_group_dn) || (!check_is_dn && inst->cacheable_group_name)) {
382                 switch(rlm_ldap_check_cached(inst, request, check)) {
383                         case RLM_MODULE_NOTFOUND:
384                                 found = false;
385                                 goto finish;
386                         case RLM_MODULE_OK:
387                                 found = true;
388                                 goto finish;
389                         /*
390                          *      Fallback to dynamic search on failure
391                          */
392                         case RLM_MODULE_FAIL:
393                         case RLM_MODULE_INVALID:
394                         default:
395                                 break;
396                 }
397         }
398
399         conn = rlm_ldap_get_socket(inst, request);
400         if (!conn) return 1;
401
402         /*
403          *      This is used in the default membership filter.
404          */
405         user_dn = rlm_ldap_find_user(inst, request, &conn, NULL, false, NULL, &rcode);
406         if (!user_dn) {
407                 rlm_ldap_release_socket(inst, conn);
408                 return 1;
409         }
410
411         rad_assert(conn);
412
413         /*
414          *      Check groupobj user membership
415          */
416         if (inst->groupobj_membership_filter) {
417                 switch(rlm_ldap_check_groupobj_dynamic(inst, request, &conn, check)) {
418                         case RLM_MODULE_NOTFOUND:
419                                 break;
420                         case RLM_MODULE_OK:
421                                 found = true;
422                         default:
423                                 goto finish;
424                 }
425         }
426
427         rad_assert(conn);
428
429         /*
430          *      Check userobj group membership
431          */
432         if (inst->userobj_membership_attr) {
433                 switch(rlm_ldap_check_userobj_dynamic(inst, request, &conn, user_dn, check)) {
434                         case RLM_MODULE_NOTFOUND:
435                                 break;
436                         case RLM_MODULE_OK:
437                                 found = true;
438                         default:
439                                 goto finish;
440                 }
441         }
442
443         rad_assert(conn);
444
445         finish:
446         if (conn) {
447                 rlm_ldap_release_socket(inst, conn);
448         }
449
450         if (!found) {
451                 RDEBUG("User is not a member of specified group");
452
453                 return 1;
454         }
455
456         return 0;
457 }
458
459 /** Detach from the LDAP server and cleanup internal state.
460  *
461  */
462 static int mod_detach(void *instance)
463 {
464         ldap_instance_t *inst = instance;
465
466         fr_connection_pool_delete(inst->pool);
467
468         if (inst->user_map) {
469                 talloc_free(inst->user_map);
470         }
471
472         return 0;
473 }
474
475 /** Parse an accounting sub section.
476  *
477  * Allocate a new ldap_acct_section_t and write the config data into it.
478  *
479  * @param[in] inst rlm_ldap configuration.
480  * @param[in] parent of the config section.
481  * @param[out] config to write the sub section parameters to.
482  * @param[in] comp The section name were parsing the config for.
483  * @return 0 on success, else < 0 on failure.
484  */
485 static int parse_sub_section(ldap_instance_t *inst, CONF_SECTION *parent, ldap_acct_section_t **config,
486                              rlm_components_t comp)
487 {
488         CONF_SECTION *cs;
489
490         char const *name = section_type_value[comp].section;
491
492         cs = cf_section_sub_find(parent, name);
493         if (!cs) {
494                 INFO("rlm_ldap (%s): Couldn't find configuration for %s, will return NOOP for calls "
495                        "from this section", inst->xlat_name, name);
496
497                 return 0;
498         }
499
500         *config = talloc_zero(inst, ldap_acct_section_t);
501         if (cf_section_parse(cs, *config, acct_section_config) < 0) {
502                 LDAP_ERR("Failed parsing configuration for section %s", name);
503
504                 return -1;
505         }
506
507         (*config)->cs = cs;
508
509         return 0;
510 }
511
512 /** Instantiate the module
513  *
514  * Creates a new instance of the module reading parameters from a configuration section.
515  *
516  * @param conf to parse.
517  * @param instance Where to write pointer to configuration data.
518  * @return 0 on success < 0 on failure.
519  */
520 static int mod_instantiate(CONF_SECTION *conf, void *instance)
521 {
522         CONF_SECTION *options;
523         ldap_instance_t *inst = instance;
524
525         inst->cs = conf;
526
527         options = cf_section_sub_find(conf, "options");
528         if (!options || !cf_pair_find(options, "chase_referrals")) {
529                 inst->chase_referrals_unset = true;      /* use OpenLDAP defaults */
530         }
531
532         inst->xlat_name = cf_section_name2(conf);
533         if (!inst->xlat_name) {
534                 inst->xlat_name = cf_section_name1(conf);
535         }
536
537         /*
538          *      If the configuration parameters can't be parsed, then fail.
539          */
540         if ((parse_sub_section(inst, conf, &inst->accounting, RLM_COMPONENT_ACCT) < 0) ||
541             (parse_sub_section(inst, conf, &inst->postauth, RLM_COMPONENT_POST_AUTH) < 0)) {
542                 LDAP_ERR("Failed parsing configuration");
543
544                 goto error;
545         }
546
547         /*
548          *      Sanity checks for cacheable groups code.
549          */
550         if (inst->cacheable_group_name && inst->groupobj_membership_filter) {
551                 if (!inst->groupobj_name_attr) {
552                         LDAP_ERR("Directive 'group.name_attribute' must be set if cacheable group names are enabled");
553
554                         goto error;
555                 }
556         }
557
558         /*
559          *      Check for URLs.  If they're used and the library doesn't support them, then complain.
560          */
561         inst->is_url = 0;
562         if (ldap_is_ldap_url(inst->server)) {
563 #ifdef HAVE_LDAP_INITIALIZE
564                 inst->is_url = 1;
565                 inst->port = 0;
566 #else
567                 LDAP_ERR("Directive 'server' is in URL form but ldap_initialize() is not available");
568                 goto error;
569 #endif
570         }
571
572         /*
573          *      Workaround for servers which support LDAPS but not START TLS
574          */
575         if (inst->port == LDAPS_PORT || inst->tls_mode) {
576                 inst->tls_mode = LDAP_OPT_X_TLS_HARD;
577         } else {
578                 inst->tls_mode = 0;
579         }
580
581 #if LDAP_SET_REBIND_PROC_ARGS != 3
582         /*
583          *      The 2-argument rebind doesn't take an instance variable.  Our rebind function needs the instance
584          *      variable for the username, password, etc.
585          */
586         if (inst->rebind == true) {
587                 LDAP_ERR("Cannot use 'rebind' directive as this version of libldap does not support the API "
588                          "that we need");
589
590                 goto error;
591         }
592 #endif
593
594         /*
595          *      Convert scope strings to enumerated constants
596          */
597         inst->userobj_scope = fr_str2int(ldap_scope, inst->userobj_scope_str, -1);
598         if (inst->userobj_scope < 0) {
599                 LDAP_ERR("Invalid 'user.scope' value \"%s\", expected 'sub', 'one', 'base' or 'children'",
600                          inst->userobj_scope_str);
601                 goto error;
602         }
603
604         inst->groupobj_scope = fr_str2int(ldap_scope, inst->groupobj_scope_str, -1);
605         if (inst->groupobj_scope < 0) {
606                 LDAP_ERR("Invalid 'group.scope' value \"%s\", expected 'sub', 'one', 'base' or 'children'",
607                          inst->groupobj_scope_str);
608                 goto error;
609         }
610
611         inst->clientobj_scope = fr_str2int(ldap_scope, inst->clientobj_scope_str, -1);
612         if (inst->clientobj_scope < 0) {
613                 LDAP_ERR("Invalid 'client.scope' value \"%s\", expected 'sub', 'one', 'base' or 'children'",
614                          inst->clientobj_scope_str);
615                 goto error;
616         }
617
618         if (inst->tls_require_cert_str) {
619 #ifdef LDAP_OPT_X_TLS_NEVER
620                 /*
621                  *      Convert cert strictness to enumerated constants
622                  */
623                 inst->tls_require_cert = fr_str2int(ldap_tls_require_cert, inst->tls_require_cert_str, -1);
624                 if (inst->tls_require_cert < 0) {
625                         LDAP_ERR("Invalid 'tls.require_cert' value \"%s\", expected 'never', 'demand', 'allow', "
626                                  "'try' or 'hard'", inst->tls_require_cert_str);
627                         goto error;
628                 }
629 #else
630                 LDAP_ERR("Modifying 'tls.require_cert' is not supported by current version of libldap. "
631                          "Please upgrade libldap and rebuild this module");
632
633                 goto error;
634 #endif
635         }
636         /*
637          *      Build the attribute map
638          */
639         if (rlm_ldap_map_verify(inst, &(inst->user_map)) < 0) {
640                 goto error;
641         }
642
643         /*
644          *      Group comparison checks.
645          */
646         if (cf_section_name2(conf)) {
647                 ATTR_FLAGS flags;
648                 char buffer[256];
649
650                 snprintf(buffer, sizeof(buffer), "%s-Ldap-Group",
651                          inst->xlat_name);
652                 memset(&flags, 0, sizeof(flags));
653
654                 dict_addattr(buffer, -1, 0, PW_TYPE_STRING, flags);
655                 inst->group_da = dict_attrbyname(buffer);
656                 if (!inst->group_da) {
657                         LDAP_ERR("Failed creating attribute %s", buffer);
658
659                         goto error;
660                 }
661
662                 paircompare_register(inst->group_da, dict_attrbyvalue(PW_USER_NAME, 0), false, rlm_ldap_groupcmp, inst);
663         /*
664          *      Were the default instance
665          */
666         } else {
667                 inst->group_da = dict_attrbyvalue(PW_LDAP_GROUP, 0);
668                 paircompare_register(dict_attrbyvalue(PW_LDAP_GROUP, 0), dict_attrbyvalue(PW_USER_NAME, 0),
669                                 false, rlm_ldap_groupcmp, inst);
670         }
671
672         xlat_register(inst->xlat_name, ldap_xlat, rlm_ldap_escape_func, inst);
673
674         /*
675          *      Initialize the socket pool.
676          */
677         inst->pool = fr_connection_pool_init(inst->cs, inst, mod_conn_create, NULL, mod_conn_delete, NULL);
678         if (!inst->pool) {
679                 return -1;
680         }
681
682         /*
683          *      Bulk load dynamic clients.
684          */
685         if (inst->do_clients) {
686                 if (rlm_ldap_load_clients(inst) < 0) {
687                         LDAP_ERR("Error loading clients");
688
689                         return -1;
690                 }
691         }
692
693         return 0;
694
695 error:
696         return -1;
697 }
698
699 /** Check the user's password against ldap directory
700  *
701  * @param instance rlm_ldap configuration.
702  * @param request Current request.
703  * @return one of the RLM_MODULE_* values.
704  */
705 static rlm_rcode_t mod_authenticate(void *instance, REQUEST *request)
706 {
707         rlm_rcode_t     rcode;
708         ldap_rcode_t    status;
709         char const      *dn;
710         ldap_instance_t *inst = instance;
711         ldap_handle_t   *conn;
712
713         /*
714          * Ensure that we're being passed a plain-text password, and not
715          * anything else.
716          */
717
718         if (!request->username) {
719                 REDEBUG("Attribute \"User-Name\" is required for authentication");
720
721                 return RLM_MODULE_INVALID;
722         }
723
724         if (!request->password ||
725             (request->password->da->attr != PW_USER_PASSWORD)) {
726                 RWDEBUG("You have set \"Auth-Type := LDAP\" somewhere.");
727                 RWDEBUG("*********************************************");
728                 RWDEBUG("* THAT CONFIGURATION IS WRONG.  DELETE IT.   ");
729                 RWDEBUG("* YOU ARE PREVENTING THE SERVER FROM WORKING.");
730                 RWDEBUG("*********************************************");
731
732                 REDEBUG("Attribute \"User-Password\" is required for authentication.");
733
734                 return RLM_MODULE_INVALID;
735         }
736
737         if (request->password->length == 0) {
738                 REDEBUG("Empty password supplied");
739
740                 return RLM_MODULE_INVALID;
741         }
742
743         RDEBUG("Login attempt by \"%s\"", request->username->vp_strvalue);
744
745         conn = rlm_ldap_get_socket(inst, request);
746         if (!conn) return RLM_MODULE_FAIL;
747
748         /*
749          *      Get the DN by doing a search.
750          */
751         dn = rlm_ldap_find_user(inst, request, &conn, NULL, false, NULL, &rcode);
752         if (!dn) {
753                 rlm_ldap_release_socket(inst, conn);
754
755                 return rcode;
756         }
757
758         /*
759          *      Bind as the user
760          */
761         conn->rebound = true;
762         status = rlm_ldap_bind(inst, request, &conn, dn, request->password->vp_strvalue, true);
763         switch (status) {
764         case LDAP_PROC_SUCCESS:
765                 rcode = RLM_MODULE_OK;
766                 RDEBUG("Bind as user \"%s\" was successful", dn);
767                 break;
768
769         case LDAP_PROC_NOT_PERMITTED:
770                 rcode = RLM_MODULE_USERLOCK;
771                 break;
772
773         case LDAP_PROC_REJECT:
774                 rcode = RLM_MODULE_REJECT;
775                 break;
776
777         case LDAP_PROC_BAD_DN:
778                 rcode = RLM_MODULE_INVALID;
779                 break;
780
781         case LDAP_PROC_NO_RESULT:
782                 rcode = RLM_MODULE_NOTFOUND;
783                 break;
784
785         default:
786                 rcode = RLM_MODULE_FAIL;
787                 break;
788         };
789
790         rlm_ldap_release_socket(inst, conn);
791
792         return rcode;
793 }
794
795 /** Check if user is authorized for remote access
796  *
797  */
798 static rlm_rcode_t mod_authorize(void *instance, REQUEST *request)
799 {
800         rlm_rcode_t     rcode = RLM_MODULE_OK;
801         ldap_rcode_t    status;
802         int             ldap_errno;
803         int             i;
804         ldap_instance_t *inst = instance;
805         char            **vals;
806         VALUE_PAIR      *vp;
807         ldap_handle_t   *conn;
808         LDAPMessage     *result, *entry;
809         char const      *dn = NULL;
810         rlm_ldap_map_xlat_t     expanded; /* faster than mallocing every time */
811
812         if (!request->username) {
813                 RDEBUG2("Attribute \"User-Name\" is required for authorization.");
814
815                 return RLM_MODULE_NOOP;
816         }
817
818         /*
819          *      Check for valid input, zero length names not permitted
820          */
821         if (request->username->length == 0) {
822                 RDEBUG2("Zero length username not permitted");
823
824                 return RLM_MODULE_INVALID;
825         }
826
827         if (rlm_ldap_map_xlat(request, inst->user_map, &expanded) < 0) {
828                 return RLM_MODULE_FAIL;
829         }
830
831         conn = rlm_ldap_get_socket(inst, request);
832         if (!conn) return RLM_MODULE_FAIL;
833
834         /*
835          *      Add any additional attributes we need for checking access, memberships, and profiles
836          */
837         if (inst->userobj_access_attr) {
838                 expanded.attrs[expanded.count++] = inst->userobj_access_attr;
839         }
840
841         if (inst->userobj_membership_attr && (inst->cacheable_group_dn || inst->cacheable_group_name)) {
842                 expanded.attrs[expanded.count++] = inst->userobj_membership_attr;
843         }
844
845         if (inst->profile_attr) {
846                 expanded.attrs[expanded.count++] = inst->profile_attr;
847         }
848
849         if (inst->valuepair_attr) {
850                 expanded.attrs[expanded.count++] = inst->valuepair_attr;
851         }
852
853         expanded.attrs[expanded.count] = NULL;
854
855         dn = rlm_ldap_find_user(inst, request, &conn, expanded.attrs, true, &result, &rcode);
856         if (!dn) {
857                 goto finish;
858         }
859
860         entry = ldap_first_entry(conn->handle, result);
861         if (!entry) {
862                 ldap_get_option(conn->handle, LDAP_OPT_RESULT_CODE, &ldap_errno);
863                 REDEBUG("Failed retrieving entry: %s", ldap_err2string(ldap_errno));
864
865                 goto finish;
866         }
867
868         /*
869          *      Check for access.
870          */
871         if (inst->userobj_access_attr) {
872                 rcode = rlm_ldap_check_access(inst, request, conn, entry);
873                 if (rcode != RLM_MODULE_OK) {
874                         goto finish;
875                 }
876         }
877
878         /*
879          *      Check if we need to cache group memberships
880          */
881         if (inst->cacheable_group_dn || inst->cacheable_group_name) {
882                 if (inst->userobj_membership_attr) {
883                         rcode = rlm_ldap_cacheable_userobj(inst, request, &conn, entry, inst->userobj_membership_attr);
884                         if (rcode != RLM_MODULE_OK) {
885                                 goto finish;
886                         }
887                 }
888
889                 rcode = rlm_ldap_cacheable_groupobj(inst, request, &conn);
890                 if (rcode != RLM_MODULE_OK) {
891                         goto finish;
892                 }
893         }
894
895 #ifdef WITH_EDIR
896         /*
897          *      We already have a Cleartext-Password.  Skip edir.
898          */
899         if (pairfind(request->config_items, PW_CLEARTEXT_PASSWORD, 0, TAG_ANY)) {
900                 goto skip_edir;
901         }
902
903         /*
904          *      Retrieve Universal Password if we use eDirectory
905          */
906         if (inst->edir) {
907                 int res = 0;
908                 char password[256];
909                 size_t pass_size = sizeof(password);
910
911                 /*
912                  *      Retrive universal password
913                  */
914                 res = nmasldap_get_password(conn->handle, dn, password, &pass_size);
915                 if (res != 0) {
916                         REDEBUG("Failed to retrieve eDirectory password: (%i) %s", res, edir_errstr(res));
917                         rcode = RLM_MODULE_FAIL;
918
919                         goto finish;
920                 }
921
922                 /*
923                  *      Add Cleartext-Password attribute to the request
924                  */
925                 vp = radius_paircreate(request, &request->config_items, PW_CLEARTEXT_PASSWORD, 0);
926                 pairstrcpy(vp, password);
927                 vp->length = pass_size;
928
929                 if (RDEBUG_ENABLED3) {
930                         RDEBUG3("Added eDirectory password.  control:%s += '%s'", vp->da->name, vp->vp_strvalue);
931                 } else {
932                         RDEBUG2("Added eDirectory password");
933                 }
934
935                 if (inst->edir_autz) {
936                         RDEBUG2("Binding as user for eDirectory authorization checks");
937                         /*
938                          *      Bind as the user
939                          */
940                         conn->rebound = true;
941                         status = rlm_ldap_bind(inst, request, &conn, dn, vp->vp_strvalue, true);
942                         switch (status) {
943                         case LDAP_PROC_SUCCESS:
944                                 rcode = RLM_MODULE_OK;
945                                 RDEBUG("Bind as user '%s' was successful", dn);
946                                 break;
947
948                         case LDAP_PROC_NOT_PERMITTED:
949                                 rcode = RLM_MODULE_USERLOCK;
950                                 goto finish;
951
952                         case LDAP_PROC_REJECT:
953                                 rcode = RLM_MODULE_REJECT;
954                                 goto finish;
955
956                         case LDAP_PROC_BAD_DN:
957                                 rcode = RLM_MODULE_INVALID;
958                                 goto finish;
959
960                         case LDAP_PROC_NO_RESULT:
961                                 rcode = RLM_MODULE_NOTFOUND;
962                                 goto finish;
963
964                         default:
965                                 rcode = RLM_MODULE_FAIL;
966                                 goto finish;
967                         };
968                 }
969         }
970
971 skip_edir:
972 #endif
973
974         /*
975          *      Apply ONE user profile, or a default user profile.
976          */
977         if (inst->default_profile) {
978                 char profile[1024];
979
980                 if (radius_xlat(profile, sizeof(profile), request, inst->default_profile, NULL, NULL) < 0) {
981                         REDEBUG("Failed creating default profile string");
982
983                         rcode = RLM_MODULE_INVALID;
984                         goto finish;
985                 }
986
987                 rlm_ldap_map_profile(inst, request, &conn, profile, &expanded);
988         }
989
990         /*
991          *      Apply a SET of user profiles.
992          */
993         if (inst->profile_attr) {
994                 vals = ldap_get_values(conn->handle, entry, inst->profile_attr);
995                 if (vals != NULL) {
996                         for (i = 0; vals[i] != NULL; i++) {
997                                 rlm_ldap_map_profile(inst, request, &conn, vals[i], &expanded);
998                         }
999
1000                         ldap_value_free(vals);
1001                 }
1002         }
1003
1004         if (inst->user_map || inst->valuepair_attr) {
1005                 RDEBUG("Processing user attributes");
1006                 rlm_ldap_map_do(inst, request, conn->handle, &expanded, entry);
1007                 rlm_ldap_check_reply(inst, request);
1008         }
1009
1010 finish:
1011         rlm_ldap_map_xlat_free(&expanded);
1012         if (result) {
1013                 ldap_msgfree(result);
1014         }
1015         rlm_ldap_release_socket(inst, conn);
1016
1017         return rcode;
1018 }
1019
1020 /** Modify user's object in LDAP
1021  *
1022  * Process a modifcation map to update a user object in the LDAP directory.
1023  *
1024  * @param inst rlm_ldap instance.
1025  * @param request Current request.
1026  * @param section that holds the map to process.
1027  * @return one of the RLM_MODULE_* values.
1028  */
1029 static rlm_rcode_t user_modify(ldap_instance_t *inst, REQUEST *request, ldap_acct_section_t *section)
1030 {
1031         rlm_rcode_t     rcode = RLM_MODULE_OK;
1032         ldap_rcode_t    status;
1033
1034         ldap_handle_t   *conn = NULL;
1035
1036         LDAPMod         *mod_p[LDAP_MAX_ATTRMAP + 1], mod_s[LDAP_MAX_ATTRMAP];
1037         LDAPMod         **modify = mod_p;
1038
1039         char            *passed[LDAP_MAX_ATTRMAP * 2];
1040         int             i, total = 0, last_pass = 0;
1041
1042         char            *expanded[LDAP_MAX_ATTRMAP];
1043         int             last_exp = 0;
1044
1045         char const      *attr;
1046         char const      *value;
1047
1048         char const      *dn;
1049         /*
1050          *      Build our set of modifications using the update sections in
1051          *      the config.
1052          */
1053         CONF_ITEM       *ci;
1054         CONF_PAIR       *cp;
1055         CONF_SECTION    *cs;
1056         FR_TOKEN        op;
1057         char            path[MAX_STRING_LEN];
1058
1059         char            *p = path;
1060
1061         rad_assert(section);
1062
1063         /*
1064          *      Locate the update section were going to be using
1065          */
1066         if (section->reference[0] != '.') {
1067                 *p++ = '.';
1068         }
1069
1070         if (radius_xlat(p, (sizeof(path) - (p - path)) - 1, request, section->reference, NULL, NULL) < 0) {
1071                 goto error;
1072         }
1073
1074         ci = cf_reference_item(NULL, section->cs, path);
1075         if (!ci) {
1076                 goto error;
1077         }
1078
1079         if (!cf_item_is_section(ci)){
1080                 REDEBUG("Reference must resolve to a section");
1081
1082                 goto error;
1083         }
1084
1085         cs = cf_section_sub_find(cf_itemtosection(ci), "update");
1086         if (!cs) {
1087                 REDEBUG("Section must contain 'update' subsection");
1088
1089                 goto error;
1090         }
1091
1092         /*
1093          *      Iterate over all the pairs, building our mods array
1094          */
1095         for (ci = cf_item_find_next(cs, NULL); ci != NULL; ci = cf_item_find_next(cs, ci)) {
1096                 int do_xlat = false;
1097
1098                 if (total == LDAP_MAX_ATTRMAP) {
1099                         REDEBUG("Modify map size exceeded");
1100
1101                         goto error;
1102                 }
1103
1104                 if (!cf_item_is_pair(ci)) {
1105                         REDEBUG("Entry is not in \"ldap-attribute = value\" format");
1106
1107                         goto error;
1108                 }
1109
1110                 /*
1111                  *      Retrieve all the information we need about the pair
1112                  */
1113                 cp = cf_itemtopair(ci);
1114                 value = cf_pair_value(cp);
1115                 attr = cf_pair_attr(cp);
1116                 op = cf_pair_operator(cp);
1117
1118                 if (!value || (*value == '\0')) {
1119                         RDEBUG("Empty value string, skipping attribute \"%s\"", attr);
1120
1121                         continue;
1122                 }
1123
1124                 switch (cf_pair_value_type(cp))
1125                 {
1126                         case T_BARE_WORD:
1127                         case T_SINGLE_QUOTED_STRING:
1128                         break;
1129                         case T_BACK_QUOTED_STRING:
1130                         case T_DOUBLE_QUOTED_STRING:
1131                                 do_xlat = true;
1132                         break;
1133                         default:
1134                                 rad_assert(0);
1135                                 goto error;
1136                 }
1137
1138                 if (op == T_OP_CMP_FALSE) {
1139                         passed[last_pass] = NULL;
1140                 } else if (do_xlat) {
1141                         char *exp = NULL;
1142
1143                         if (radius_xlat(exp, 0, request, value, NULL, NULL) <= 0) {
1144                                 RDEBUG("Skipping attribute \"%s\"", attr);
1145
1146                                 talloc_free(exp);
1147
1148                                 continue;
1149                         }
1150
1151                         expanded[last_exp++] = exp;
1152                         passed[last_pass] = exp;
1153                 /*
1154                  *      Static strings
1155                  */
1156                 } else {
1157                         memcpy(&(passed[last_pass]), &value, sizeof(passed[last_pass]));
1158                 }
1159
1160                 passed[last_pass + 1] = NULL;
1161
1162                 mod_s[total].mod_values = &(passed[last_pass]);
1163
1164                 last_pass += 2;
1165
1166                 switch (op)
1167                 {
1168                 /*
1169                  *  T_OP_EQ is *NOT* supported, it is impossible to
1170                  *  support because of the lack of transactions in LDAP
1171                  */
1172                 case T_OP_ADD:
1173                         mod_s[total].mod_op = LDAP_MOD_ADD;
1174                         break;
1175
1176                 case T_OP_SET:
1177                         mod_s[total].mod_op = LDAP_MOD_REPLACE;
1178                         break;
1179
1180                 case T_OP_SUB:
1181                 case T_OP_CMP_FALSE:
1182                         mod_s[total].mod_op = LDAP_MOD_DELETE;
1183                         break;
1184
1185 #ifdef LDAP_MOD_INCREMENT
1186                 case T_OP_INCRM:
1187                         mod_s[total].mod_op = LDAP_MOD_INCREMENT;
1188                         break;
1189 #endif
1190                 default:
1191                         REDEBUG("Operator '%s' is not supported for LDAP modify operations",
1192                                 fr_int2str(fr_tokens, op, "<INVALID>"));
1193
1194                         goto error;
1195                 }
1196
1197                 /*
1198                  *      Now we know the value is ok, copy the pointers into
1199                  *      the ldapmod struct.
1200                  */
1201                 memcpy(&(mod_s[total].mod_type), &(attr), sizeof(mod_s[total].mod_type));
1202
1203                 mod_p[total] = &(mod_s[total]);
1204                 total++;
1205         }
1206
1207         if (total == 0) {
1208                 rcode = RLM_MODULE_NOOP;
1209                 goto release;
1210         }
1211
1212         mod_p[total] = NULL;
1213
1214         conn = rlm_ldap_get_socket(inst, request);
1215         if (!conn) return RLM_MODULE_FAIL;
1216
1217
1218         dn = rlm_ldap_find_user(inst, request, &conn, NULL, false, NULL, &rcode);
1219         if (!dn || (rcode != RLM_MODULE_OK)) {
1220                 goto error;
1221         }
1222
1223         status = rlm_ldap_modify(inst, request, &conn, dn, modify);
1224         switch (status) {
1225         case LDAP_PROC_SUCCESS:
1226                 break;
1227
1228         case LDAP_PROC_REJECT:
1229         case LDAP_PROC_BAD_DN:
1230                 rcode = RLM_MODULE_INVALID;
1231                 break;
1232
1233         default:
1234                 rcode = RLM_MODULE_FAIL;
1235                 break;
1236         };
1237
1238         release:
1239         error:
1240         /*
1241          *      Free up any buffers we allocated for xlat expansion
1242          */
1243         for (i = 0; i < last_exp; i++) {
1244                 talloc_free(expanded[i]);
1245         }
1246
1247         rlm_ldap_release_socket(inst, conn);
1248
1249         return rcode;
1250 }
1251
1252 static rlm_rcode_t mod_accounting(void *instance, REQUEST * request) {
1253         ldap_instance_t *inst = instance;
1254
1255         if (inst->accounting) {
1256                 return user_modify(inst, request, inst->accounting);
1257         }
1258
1259         return RLM_MODULE_NOOP;
1260 }
1261
1262 static rlm_rcode_t mod_post_auth(void *instance, REQUEST * request)
1263 {
1264         ldap_instance_t *inst = instance;
1265
1266         if (inst->postauth) {
1267                 return user_modify(inst, request, inst->postauth);
1268         }
1269
1270         return RLM_MODULE_NOOP;
1271 }
1272
1273
1274 /* globally exported name */
1275 module_t rlm_ldap = {
1276         RLM_MODULE_INIT,
1277         "ldap",
1278         RLM_TYPE_THREAD_SAFE,   /* type: reserved        */
1279         sizeof(ldap_instance_t),
1280         module_config,
1281         mod_instantiate,        /* instantiation         */
1282         mod_detach,             /* detach                */
1283         {
1284                 mod_authenticate,       /* authentication        */
1285                 mod_authorize,          /* authorization         */
1286                 NULL,                   /* preaccounting         */
1287                 mod_accounting,         /* accounting            */
1288                 NULL,                   /* checksimul            */
1289                 NULL,                   /* pre-proxy             */
1290                 NULL,                   /* post-proxy            */
1291                 mod_post_auth           /* post-auth */
1292         },
1293 };