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