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