Ignore right operand for !*
[freeradius.git] / src / modules / rlm_ldap / rlm_ldap.c
1 /*
2  * rlm_ldap.c   LDAP authorization and authentication module.
3  *
4  *   This program is free software; you can redistribute it and/or modify
5  *   it under the terms of the GNU General Public License as published by
6  *   the Free Software Foundation; either version 2 of the License, or
7  *   (at your option) any later version.
8  *
9  *   This program is distributed in the hope that it will be useful,
10  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
11  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  *   GNU General Public License for more details.
13  *
14  *   You should have received a copy of the GNU General Public License
15  *   along with this program; if not, write to the Free Software
16  *   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
17  *
18  *   Copyright 1999-2012 The FreeRADIUS Server Project.
19  *
20  *   Copyright 2012 Alan DeKok <aland@freeradius.org>
21  *   Copyright 2012 Arran Cudbard-Bell <a.cudbardb@freeradius.org>
22  */
23
24 #include <freeradius-devel/ident.h>
25 RCSID("$Id$")
26
27 #include        <freeradius-devel/radiusd.h>
28 #include        <freeradius-devel/modules.h>
29 #include        <freeradius-devel/rad_assert.h>
30
31 #include        <stdarg.h>
32 #include        <ctype.h>
33
34 #include        <lber.h>
35 #include        <ldap.h>
36
37 #define MAX_ATTRMAP             128
38 #define MAX_ATTR_STR_LEN        256
39 #define MAX_FILTER_STR_LEN      1024
40
41 #ifdef WITH_EDIR
42 extern int nmasldap_get_password(LDAP *ld,char *objectDN, char *pwd, size_t *pwdSize);
43
44 #endif
45
46 typedef struct ldap_acct_section {
47         CONF_SECTION    *cs;
48         
49         const char *reference;
50 } ldap_acct_section_t;
51
52
53 typedef struct {
54         CONF_SECTION    *cs;
55         fr_connection_pool_t *pool;
56
57         char            *server;
58         int             port;
59
60         char            *login;
61         char            *password;
62
63         char            *filter;
64         char            *basedn;
65
66         int             chase_referrals;
67         int             rebind;
68
69         int             ldap_debug; /* Debug flag for LDAP SDK */
70
71         const char      *xlat_name; /* name used to xlat */
72
73         int             expect_password;
74         
75         /*
76          *      RADIUS attribute to LDAP attribute maps
77          */
78         VALUE_PAIR_MAP  *user_map;      /* Applied to users and profiles */
79         
80         /*
81          *      Access related configuration
82          */
83         char            *access_attr;
84         int             positive_access_attr;
85
86         /*
87          *      Profiles
88          */
89         char            *base_filter;
90         char            *default_profile;
91         char            *profile_attr;
92
93         /*
94          *      Group checking.
95          */
96         char            *groupname_attr;
97         char            *groupmemb_filter;
98         char            *groupmemb_attr;
99         
100         /*
101          *      Accounting
102          */
103         ldap_acct_section_t *postauth;
104         ldap_acct_section_t *accounting;
105
106         /*
107          *      TLS items.  We should really normalize these with the
108          *      TLS code in 3.0.
109          */
110         int             tls_mode;
111         int             start_tls;
112         char            *tls_cacertfile;
113         char            *tls_cacertdir;
114         char            *tls_certfile;
115         char            *tls_keyfile;
116         char            *tls_randfile;
117         char            *tls_require_cert;
118
119         /*
120          *      Options
121          */
122         int             timelimit;
123         int             net_timeout;
124         int             timeout;
125         int             is_url;
126
127 #ifdef WITH_EDIR
128         /*
129          *      eDir support
130          */
131         int             edir;
132         int             edir_autz;
133 #endif
134         /*
135          *      For keep-alives.
136          */
137 #ifdef LDAP_OPT_X_KEEPALIVE_IDLE
138         int             keepalive_idle;
139 #endif
140 #ifdef LDAP_OPT_X_KEEPALIVE_PROBES
141         int             keepalive_probes;
142 #endif
143 #ifdef LDAP_OPT_ERROR_NUMBER
144         int             keepalive_interval;
145 #endif
146
147 }  ldap_instance;
148
149 /* The default setting for TLS Certificate Verification */
150 #define TLS_DEFAULT_VERIFY "allow"
151
152 /*
153  *      TLS Configuration
154  */
155 static CONF_PARSER tls_config[] = {
156         {"start_tls", PW_TYPE_BOOLEAN,
157          offsetof(ldap_instance,start_tls), NULL, "no"},
158         {"cacertfile", PW_TYPE_FILENAME,
159          offsetof(ldap_instance,tls_cacertfile), NULL, NULL},
160         {"cacertdir", PW_TYPE_FILENAME,
161          offsetof(ldap_instance,tls_cacertdir), NULL, NULL},
162         {"certfile", PW_TYPE_FILENAME,
163          offsetof(ldap_instance,tls_certfile), NULL, NULL},
164         {"keyfile", PW_TYPE_FILENAME,
165          offsetof(ldap_instance,tls_keyfile), NULL, NULL},
166         {"randfile", PW_TYPE_STRING_PTR, /* OK if it changes on HUP */
167          offsetof(ldap_instance,tls_randfile), NULL, NULL},
168         {"require_cert", PW_TYPE_STRING_PTR,
169          offsetof(ldap_instance,tls_require_cert), NULL, TLS_DEFAULT_VERIFY},
170         { NULL, -1, 0, NULL, NULL }
171 };
172
173
174 static CONF_PARSER attr_config[] = {
175         /*
176          *      Access limitations
177          */
178         /* LDAP attribute name that controls remote access */
179         {"access_attr", PW_TYPE_STRING_PTR,
180          offsetof(ldap_instance,access_attr), NULL, NULL},
181         {"positive_access_attr", PW_TYPE_BOOLEAN,
182          offsetof(ldap_instance,positive_access_attr), NULL, "yes"},
183
184         {"base_filter", PW_TYPE_STRING_PTR,
185          offsetof(ldap_instance,base_filter), NULL,
186          "(objectclass=radiusprofile)"},
187         {"default_profile", PW_TYPE_STRING_PTR,
188          offsetof(ldap_instance,default_profile), NULL, NULL},
189         {"profile_attribute", PW_TYPE_STRING_PTR,
190          offsetof(ldap_instance,profile_attr), NULL, NULL},
191
192         { NULL, -1, 0, NULL, NULL }
193 };
194
195
196 /*
197  *      Group configuration
198  */
199 static CONF_PARSER group_config[] = {
200         /*
201          *      Group checks.  These could probably be done
202          *      via dynamic xlat's.
203          */
204         {"name_attribute", PW_TYPE_STRING_PTR,
205          offsetof(ldap_instance,groupname_attr), NULL, "cn"},
206         {"membership_filter", PW_TYPE_STRING_PTR,
207          offsetof(ldap_instance,groupmemb_filter), NULL,
208          "(|(&(objectClass=GroupOfNames)(member=%{Ldap-UserDn}))"
209          "(&(objectClass=GroupOfUniqueNames)(uniquemember=%{Ldap-UserDn})))"},
210         {"membership_attribute", PW_TYPE_STRING_PTR,
211          offsetof(ldap_instance,groupmemb_attr), NULL, NULL},
212
213
214         { NULL, -1, 0, NULL, NULL }
215 };
216
217 /*
218  *      Reference for accounting updates
219  */
220 static const CONF_PARSER acct_section_config[] = {
221         {"reference", PW_TYPE_STRING_PTR,
222           offsetof(ldap_acct_section_t, reference), NULL, "."},
223         {NULL, -1, 0, NULL, NULL}
224 };
225
226 /*
227  *      Various options that don't belong in the main configuration.
228  *
229  *      Note that these overlap a bit with the connection pool code!
230  */
231 static CONF_PARSER option_config[] = {
232         /*
233          *      Debugging flags to the server
234          */
235         {"ldap_debug", PW_TYPE_INTEGER,
236          offsetof(ldap_instance,ldap_debug), NULL, "0x0000"},
237
238         {"chase_referrals", PW_TYPE_BOOLEAN,
239          offsetof(ldap_instance,chase_referrals), NULL, NULL},
240
241         {"rebind", PW_TYPE_BOOLEAN,
242          offsetof(ldap_instance,rebind), NULL, NULL},
243
244         /* timeout on network activity */
245         {"net_timeout", PW_TYPE_INTEGER,
246          offsetof(ldap_instance,net_timeout), NULL, "10"},
247
248         /* timeout for search results */
249         {"timeout", PW_TYPE_INTEGER,
250          offsetof(ldap_instance,timeout), NULL, "20"},
251
252         /* allow server unlimited time for search (server-side limit) */
253         {"timelimit", PW_TYPE_INTEGER,
254          offsetof(ldap_instance,timelimit), NULL, "20"},
255
256 #ifdef LDAP_OPT_X_KEEPALIVE_IDLE
257         {"idle", PW_TYPE_INTEGER,
258          offsetof(ldap_instance,keepalive_idle), NULL, "60"},
259 #endif
260 #ifdef LDAP_OPT_X_KEEPALIVE_PROBES
261         {"probes", PW_TYPE_INTEGER,
262          offsetof(ldap_instance,keepalive_probes), NULL, "3"},
263 #endif
264 #ifdef LDAP_OPT_ERROR_NUMBER
265         {"interval", PW_TYPE_INTEGER, 
266          offsetof(ldap_instance,keepalive_interval), NULL, "30"},
267 #endif
268         { NULL, -1, 0, NULL, NULL }
269 };
270
271
272 static const CONF_PARSER module_config[] = {
273         {"server", PW_TYPE_STRING_PTR,
274          offsetof(ldap_instance,server), NULL, "localhost"},
275         {"port", PW_TYPE_INTEGER,
276          offsetof(ldap_instance,port), NULL, "389"},
277
278         {"password", PW_TYPE_STRING_PTR,
279          offsetof(ldap_instance,password), NULL, ""},
280         {"identity", PW_TYPE_STRING_PTR,
281          offsetof(ldap_instance,login), NULL, ""},
282
283         /*
284          *      DN's and filters.
285          */
286         {"basedn", PW_TYPE_STRING_PTR,
287          offsetof(ldap_instance,basedn), NULL, "o=notexist"},
288
289         {"filter", PW_TYPE_STRING_PTR,
290          offsetof(ldap_instance,filter), NULL, "(uid=%u)"},
291
292         /* turn off the annoying warning if we don't expect a password */
293         {"expect_password", PW_TYPE_BOOLEAN,
294          offsetof(ldap_instance,expect_password), NULL, "yes"},
295          
296 #ifdef WITH_EDIR
297         /* support for eDirectory Universal Password */
298         {"edir", PW_TYPE_BOOLEAN,
299          offsetof(ldap_instance,edir), NULL, NULL}, /* NULL defaults to "no" */
300
301         /*
302          * Attempt to bind with the Cleartext password we got from eDirectory
303          * Universal password for additional authorization checks.
304          */
305         {"edir_autz", PW_TYPE_BOOLEAN,
306          offsetof(ldap_instance,edir_autz), NULL, NULL}, /* NULL defaults to "no" */
307 #endif
308
309         /*
310          *      Terrible things which should be deleted.
311          */
312         { "profiles", PW_TYPE_SUBSECTION, 0, NULL, (const void *) attr_config },
313
314         { "group", PW_TYPE_SUBSECTION, 0, NULL, (const void *) group_config },
315
316         { "options", PW_TYPE_SUBSECTION, 0, NULL,
317          (const void *) option_config },
318
319         { "tls", PW_TYPE_SUBSECTION, 0, NULL, (const void *) tls_config },
320
321         {NULL, -1, 0, NULL, NULL}
322 };
323
324 typedef struct ldap_conn {
325         LDAP    *handle;
326         int     rebound;
327         int     referred;
328         ldap_instance *inst;
329 } LDAP_CONN;
330
331 typedef struct xlat_attrs {
332         const VALUE_PAIR_MAP *maps;
333         const char *attrs[MAX_ATTRMAP];
334 } xlat_attrs_t;
335
336 typedef struct rlm_ldap_result {
337         char    **values;
338         int     count;
339 } rlm_ldap_result_t;
340
341
342 #if LDAP_SET_REBIND_PROC_ARGS == 3
343 /*
344  *      Rebind && chase referral stuff
345  */
346 static int ldap_rebind(LDAP *handle, LDAP_CONST char *url,
347                        UNUSED ber_tag_t request, UNUSED ber_int_t msgid,
348                        void *ctx )
349 {
350         LDAP_CONN *conn = ctx;
351
352         conn->referred = TRUE;
353         conn->rebound = TRUE;   /* not really, but oh well... */
354         rad_assert(handle == conn->handle);
355
356         DEBUG("rlm_ldap (%s): Rebinding to URL %s", conn->inst->xlat_name, url);
357         
358         return ldap_bind_s(handle, conn->inst->login, conn->inst->password,
359                            LDAP_AUTH_SIMPLE);
360 }
361 #endif
362
363 static int ldap_bind_wrapper(LDAP_CONN **pconn, const char *user,
364                              const char *password,
365                              const char **perror_str, int do_rebind)
366 {
367         int             rcode, ldap_errno, msg_id;
368         int             module_rcode = RLM_MODULE_FAIL;
369         int             reconnect = FALSE;
370         const char      *error_string;
371         LDAP_CONN       *conn = *pconn;
372         ldap_instance   *inst = conn->inst;
373         LDAPMessage     *result = NULL;
374         struct timeval tv;
375
376 redo:
377         msg_id = ldap_bind(conn->handle, user, password,
378                            LDAP_AUTH_SIMPLE);
379         if (msg_id < 0) {
380         get_error:
381                 ldap_get_option(conn->handle, LDAP_OPT_ERROR_NUMBER,
382                                 &ldap_errno);
383                                 
384                 error_string = ldap_err2string(ldap_errno);
385
386                 if (do_rebind && !reconnect) {
387                         conn = fr_connection_reconnect(inst->pool, conn);
388                         *pconn = conn;
389                         if (!conn) return RLM_MODULE_FAIL;
390                         goto redo;
391                 }
392
393         print_error:
394                 if (perror_str) *perror_str = error_string;
395
396 #ifdef HAVE_LDAP_INITIALIZE
397                 if (inst->is_url) {
398                         radlog(L_ERR, "rlm_ldap (%s): %s bind to %s failed: %s",
399                                inst->xlat_name, user,
400                                inst->server, error_string);
401                 } else
402 #endif
403                 {
404                         radlog(L_ERR, "rlm_ldap (%s): %s bind to %s:%d "
405                                       "failed: %s",
406                                inst->xlat_name, user,
407                                inst->server, inst->port,
408                                error_string);
409                 }
410
411                 return module_rcode; /* caller closes the connection */
412         }
413
414         DEBUG3("rlm_ldap (%s): Waiting for bind result...", inst->xlat_name);
415
416         tv.tv_sec = inst->timeout;
417         tv.tv_usec = 0;
418         rcode = ldap_result(conn->handle, msg_id, 1, &tv, &result);
419         if (rcode < 0) goto get_error;
420
421         if (rcode == 0) {
422                 error_string = "timeout";
423                 goto print_error;
424         }
425
426         ldap_errno = ldap_result2error(conn->handle, result, 1);
427         switch (ldap_errno) {
428         case LDAP_SUCCESS:
429                 break;
430
431         case LDAP_INVALID_CREDENTIALS:
432         case LDAP_CONSTRAINT_VIOLATION:
433                 rcode = RLM_MODULE_REJECT;
434                 /* FALL-THROUGH */
435
436         default:
437                 goto get_error;
438         }
439
440         return RLM_MODULE_OK;
441 }
442
443 /** Create and return a new connection
444  * This function is probably too big.
445  */
446 static void *ldap_conn_create(void *ctx)
447 {
448         int module_rcode;
449         int ldap_errno, ldap_version;
450         struct timeval tv;
451         ldap_instance *inst = ctx;
452         LDAP *handle = NULL;
453         LDAP_CONN *conn = NULL;
454         const char *error;
455
456 #ifdef HAVE_LDAP_INITIALIZE
457         if (inst->is_url) {
458                 DEBUG("rlm_ldap (%s): Connect to %s", inst->xlat_name,
459                       inst->server);
460
461                 ldap_errno = ldap_initialize(&handle, inst->server);
462                 if (ldap_errno != LDAP_SUCCESS) {
463                         radlog(L_ERR, "rlm_ldap (%s): ldap_initialize() "
464                                "failed: %s",
465                                inst->xlat_name, ldap_err2string(ldap_errno));
466                         goto conn_fail;
467                 }
468         } else
469 #endif
470         {
471                 DEBUG("rlm_ldap (%s): Connect to %s:%d", inst->xlat_name,
472                       inst->server, inst->port);
473
474                 handle = ldap_init(inst->server, inst->port);
475                 if (!handle) {
476                         radlog(L_ERR, "rlm_ldap (%s): ldap_init() failed",
477                                inst->xlat_name);
478                 conn_fail:
479                         if (handle) ldap_unbind_s(handle);
480                         return NULL;
481                 }
482         }
483
484         /*
485          *      We now have a connection structure, but no actual TCP connection.
486          *
487          *      Set a bunch of LDAP options, using common code.
488          */
489 #define do_ldap_option(_option, _name, _value) \
490         if (ldap_set_option(handle, _option, _value) != LDAP_OPT_SUCCESS) { \
491                 ldap_get_option(handle, LDAP_OPT_ERROR_NUMBER, &ldap_errno); \
492                 radlog(L_ERR, "rlm_ldap (%s): Could not set %s: %s", \
493                        inst->xlat_name, _name, ldap_err2string(ldap_errno)); \
494         }
495                 
496         if (inst->ldap_debug) {
497                 do_ldap_option(LDAP_OPT_DEBUG_LEVEL, "ldap_debug",
498                                &(inst->ldap_debug));
499         }
500
501         /*
502          *      Leave "chase_referrals" unset to use the OpenLDAP
503          *      default.
504          */
505         if (inst->chase_referrals != 2) {
506                 if (inst->chase_referrals) {
507                         do_ldap_option(LDAP_OPT_REFERRALS, "chase_referrals",
508                                        LDAP_OPT_ON);
509                         
510 #if LDAP_SET_REBIND_PROC_ARGS == 3
511                         if (inst->rebind == 1) {
512                                 ldap_set_rebind_proc(handle, ldap_rebind, inst);
513                         }
514 #endif
515                 } else {
516                         do_ldap_option(LDAP_OPT_REFERRALS, "chase_referrals",
517                                        LDAP_OPT_OFF);
518                 }
519         }
520
521         tv.tv_sec = inst->net_timeout;
522         tv.tv_usec = 0;
523         do_ldap_option(LDAP_OPT_NETWORK_TIMEOUT, "net_timeout", &tv);
524
525         do_ldap_option(LDAP_OPT_TIMELIMIT, "timelimit",
526                        &(inst->timelimit));
527
528         ldap_version = LDAP_VERSION3;
529         do_ldap_option(LDAP_OPT_PROTOCOL_VERSION, "ldap_version",
530                        &ldap_version);
531
532 #ifdef LDAP_OPT_X_KEEPALIVE_IDLE
533         do_ldap_option(LDAP_OPT_X_KEEPALIVE_IDLE, "keepalive idle",
534                        &(inst->keepalive_idle));
535 #endif
536
537 #ifdef LDAP_OPT_X_KEEPALIVE_PROBES
538         do_ldap_option(LDAP_OPT_X_KEEPALIVE_PROBES, "keepalive probes",
539                        &(inst->keepalive_probes));
540 #endif
541
542 #ifdef LDAP_OPT_X_KEEPALIVE_INTERVAL
543         do_ldap_option(LDAP_OPT_X_KEEPALIVE_INTERVAL, "keepalive interval",
544                        &(inst->keepalive_interval));
545 #endif
546
547 #ifdef HAVE_LDAP_START_TLS
548         /*
549          *      Set all of the TLS options
550          */
551         if (inst->tls_mode) {
552                 do_ldap_option(LDAP_OPT_X_TLS, "tls_mode", &(inst->tls_mode));
553         }
554
555 #define maybe_ldap_option(_option, _name, _value) \
556         if (_value) do_ldap_option(_option, _name, _value)
557
558         maybe_ldap_option(LDAP_OPT_X_TLS_CACERTFILE,
559                           "cacertfile", inst->tls_cacertfile);
560         maybe_ldap_option(LDAP_OPT_X_TLS_CACERTDIR,
561                           "cacertdir", inst->tls_cacertdir);
562
563 #ifdef HAVE_LDAP_INT_TLS_CONFIG
564         if (ldap_int_tls_config(NULL, LDAP_OPT_X_TLS_REQUIRE_CERT,
565                                 (inst->tls_require_cert)) != LDAP_OPT_SUCCESS) {
566                 ldap_get_option(handle, LDAP_OPT_ERROR_NUMBER, &ldap_errno);
567                 radlog(L_ERR, "rlm_ldap (%s): could not set "
568                        "LDAP_OPT_X_TLS_REQUIRE_CERT option to %s: %s",
569                        inst->xlat_name, 
570                        inst->tls_require_cert,
571                        ldap_err2string(ldap_errno));
572         }
573 #endif
574
575         maybe_ldap_option(LDAP_OPT_X_TLS_CERTFILE,
576                           "certfile", inst->tls_certfile);
577         maybe_ldap_option(LDAP_OPT_X_TLS_KEYFILE,
578                           "keyfile", inst->tls_keyfile);
579         maybe_ldap_option(LDAP_OPT_X_TLS_RANDOM_FILE,
580                           "randfile", inst->tls_randfile);
581
582         /*
583          *      And finally start the TLS code.
584          */
585         if (inst->start_tls && (inst->port != 636)) {
586                 ldap_errno = ldap_start_tls_s(handle, NULL, NULL);
587                 if (ldap_errno != LDAP_SUCCESS) {
588                         ldap_get_option(handle, LDAP_OPT_ERROR_NUMBER,
589                                         &ldap_errno);
590                         radlog(L_ERR, "rlm_ldap (%s): could not start TLS: %s",
591                                inst->xlat_name,
592                                ldap_err2string(ldap_errno));
593                         goto conn_fail;
594                 }
595         }
596 #endif /* HAVE_LDAP_START_TLS */
597
598         conn = rad_malloc(sizeof(*conn));
599         conn->inst = inst;
600         conn->handle = handle;
601         conn->rebound = FALSE;
602         conn->referred = FALSE;
603
604         module_rcode = ldap_bind_wrapper(&conn, inst->login, inst->password,
605                                          &error, FALSE);
606         if (module_rcode != RLM_MODULE_OK) {
607                 radlog(L_ERR, "rlm_ldap (%s): failed binding to LDAP "
608                        "server: %s",
609                        inst->xlat_name, error);
610
611                 /*
612                  *      FIXME: print "check config, morians!
613                  */
614                 goto conn_fail;
615         }
616
617         return conn;
618 }
619
620
621 /** Close and delete a connection
622  *
623  */
624 static int ldap_conn_delete(UNUSED void *ctx, void *connection)
625 {
626         LDAP_CONN *conn = connection;
627
628         ldap_unbind_s(conn->handle);
629         free(conn);
630
631         return 0;
632 }
633
634
635 /** Gets an LDAP socket from the connection pool
636  *
637  */
638 static LDAP_CONN *ldap_get_socket(ldap_instance *inst)
639 {
640         LDAP_CONN *conn;
641
642         conn = fr_connection_get(inst->pool);
643         if (!conn) {
644                 radlog(L_ERR, "rlm_ldap (%s): all ldap connections are in use",
645                        inst->xlat_name);
646                 return NULL;
647         }
648
649         return conn;
650 }
651
652 /** Frees an LDAP socket back to the connection pool
653  *
654  */
655 static void ldap_release_socket(ldap_instance *inst, LDAP_CONN *conn)
656 {
657         /*
658          *      Could have already been free'd due to a previous error.
659          */
660         if (!conn) return;
661
662         /*
663          *      We chased a referral to another server.
664          *
665          *      This connection is no longer part of the pool which is
666          *      connected to and bound to the configured server.
667          *      Close it.
668          *
669          *      Note that we do NOT close it if it was bound to
670          *      another user.  Instead, we let the next caller do the
671          *      rebind.
672          */
673         if (conn->referred) {
674                 fr_connection_del(inst->pool, conn);
675                 return;
676         }
677
678         fr_connection_release(inst->pool, conn);
679         return;
680 }
681
682
683 /* Converts "bad" strings into ones which are safe for LDAP
684  *
685  */
686 static size_t ldap_escape_func(UNUSED REQUEST *request, char *out,
687                                size_t outlen, const char *in, UNUSED void *arg)
688 {
689         size_t len = 0;
690
691         while (in[0]) {
692                 /*
693                  *      Encode unsafe characters.
694                  */
695                 if (((len == 0) &&
696                     ((in[0] == ' ') || (in[0] == '#'))) ||
697                     (strchr(",+\"\\<>;*=()", *in))) {
698                         static const char hex[] = "0123456789abcdef";
699
700                         /*
701                          *      Only 3 or less bytes available.
702                          */
703                         if (outlen <= 3) {
704                                 break;
705                         }
706
707                         *(out++) = '\\';
708                         *(out++) = hex[((*in) >> 4) & 0x0f];
709                         *(out++) = hex[(*in) & 0x0f];
710                         outlen -= 3;
711                         len += 3;
712                         in++;
713                         continue;
714                 }
715
716                 /*
717                  *      Only one byte left.
718                  */
719                 if (outlen <= 1) {
720                         break;
721                 }
722
723                 /*
724                  *      Allowed character.
725                  */
726                 *(out++) = *(in++);
727                 outlen--;
728                 len++;
729         }
730         *out = '\0';
731         return len;
732 }
733
734 /** Do a search and get a response
735  *
736  */
737 static int perform_search(ldap_instance *inst, REQUEST *request,
738                           LDAP_CONN **pconn, const char *search_basedn,
739                           int scope, const char *filter, 
740                           const char * const *attrs, LDAPMessage **presult)
741 {
742         int             ldap_errno;
743         int             count = 0;
744         int             reconnect = FALSE;
745         LDAP_CONN       *conn = *pconn;
746         struct timeval  tv;
747
748         /*
749          *      OpenLDAP library doesn't declare attrs array as const, but
750          *      it really should be *sigh*.
751          */
752         char **search_attrs;
753         memcpy(&search_attrs, &attrs, sizeof(attrs));
754
755         *presult = NULL;
756
757         /*
758          *      Do all searches as the default admin user.
759          */
760         if (conn->rebound) {
761                 ldap_errno = ldap_bind_wrapper(pconn,
762                                                inst->login, inst->password,
763                                                NULL, TRUE);
764                 if (ldap_errno != RLM_MODULE_OK) {
765                         return -1;
766                 }
767
768                 rad_assert(*pconn != NULL);
769                 conn = *pconn;
770                 conn->rebound = FALSE;
771         }
772
773         tv.tv_sec = inst->timeout;
774         tv.tv_usec = 0;
775         RDEBUG2("Performing search in '%s' with filter '%s'",
776                 search_basedn ? search_basedn : "(null)" ,
777                 filter);
778
779 retry:
780         ldap_errno = ldap_search_ext_s(conn->handle, search_basedn, scope,
781                                        filter, search_attrs, 0, NULL, NULL,
782                                        &tv, 0, presult);
783         switch (ldap_errno) {
784         case LDAP_SUCCESS:
785         case LDAP_NO_SUCH_OBJECT:
786                 break;
787
788         case LDAP_SERVER_DOWN:
789         do_reconnect:
790                 ldap_msgfree(*presult);
791
792                 if (reconnect) return -1;
793                 reconnect = TRUE;
794
795                 conn = fr_connection_reconnect(inst->pool, conn);
796                 *pconn = conn;  /* tell the caller we have a new connection */
797                 if (!conn) return -1;
798                 goto retry;
799
800         case LDAP_INSUFFICIENT_ACCESS:
801                 radlog(L_ERR, "rlm_ldap (%s): Search failed: "
802                        "Insufficient access. Check the identity and password "
803                        "configuration directives", inst->xlat_name);
804                 ldap_msgfree(*presult);
805                 return -1;
806
807         case LDAP_TIMEOUT:
808                 exec_trigger(NULL, inst->cs, "modules.ldap.timeout", TRUE);
809                 radlog(L_ERR, "rlm_ldap (%s): Search failed: Timed out "
810                        "while waiting for server to respond"
811                        "Please increase the timeout", inst->xlat_name);
812                 ldap_msgfree(*presult);
813                 return -1;
814
815         case LDAP_FILTER_ERROR:
816                 radlog(L_ERR, "rlm_ldap (%s): Search failed: Bad search "
817                        "filter: %s", inst->xlat_name,filter);
818                 ldap_msgfree(*presult);
819                 return -1;
820
821         case LDAP_TIMELIMIT_EXCEEDED:
822                 exec_trigger(NULL, inst->cs, "modules.ldap.timeout", TRUE);
823
824         case LDAP_BUSY:
825         case LDAP_UNAVAILABLE:
826                 /*
827                  *      Reconnect.  There's an issue with the socket
828                  *      or LDAP server.
829                  */
830                 ldap_get_option(conn->handle, LDAP_OPT_ERROR_NUMBER,
831                                 &ldap_errno);
832                 radlog(L_ERR, "rlm_ldap (%s): Search failed: %s",
833                        inst->xlat_name, ldap_err2string(ldap_errno));
834                 goto do_reconnect;
835
836         default:
837                 ldap_get_option(conn->handle, LDAP_OPT_ERROR_NUMBER,
838                                 &ldap_errno);
839                 radlog(L_ERR, "rlm_ldap (%s): Search failed: %s",
840                        inst->xlat_name, ldap_err2string(ldap_errno));
841                 ldap_msgfree(*presult);
842                 return -1;
843         }
844
845         count = ldap_count_entries(conn->handle, *presult);
846         if (count == 0) {
847                 ldap_msgfree(*presult);
848                 RDEBUG("Search returned no results");
849                 
850                 return -2;
851         }
852
853         if (count != 1) {
854                 ldap_msgfree(*presult);
855                 RDEBUG("Got ambiguous search result (%d results)", count);
856                       
857                 return -2;
858         }
859
860         return 0;
861 }
862
863 /** Expand an LDAP URL into a query, and return a string result from that query.
864  *
865  */
866 static size_t ldap_xlat(void *instance, REQUEST *request, const char *fmt,
867                         char *out, size_t freespace)
868 {
869         int rcode;
870         size_t length = 0;
871         ldap_instance *inst = instance;
872         LDAPURLDesc *ldap_url;
873         LDAPMessage *result = NULL;
874         LDAPMessage *entry = NULL;
875         char **vals;
876         LDAP_CONN *conn;
877         int ldap_errno;
878         const char *url;
879         const char **attrs;
880         char buffer[MAX_FILTER_STR_LEN];
881
882         if (strchr(fmt, '%') != NULL) {
883                 if (!radius_xlat(buffer, sizeof(buffer), fmt, request,
884                                  ldap_escape_func, NULL)) {
885                         radlog(L_ERR,
886                                "rlm_ldap (%s): Unable to create LDAP URL", 
887                                inst->xlat_name);
888                         return 0;
889                 }
890                 url = buffer;
891         } else {
892                 url = fmt;
893         }
894
895         if (!ldap_is_ldap_url(url)) {
896                 radlog(L_ERR, "rlm_ldap (%s): String passed does not look "
897                        "like an LDAP URL", inst->xlat_name);
898                 return 0;
899         }
900
901         if (ldap_url_parse(url, &ldap_url)){
902                 radlog(L_ERR, "rlm_ldap (%s): Parsing LDAP URL failed",
903                        inst->xlat_name);
904                 return 0;
905         }
906
907         /*
908          *      Nothing, empty string, "*" string, or got 2 things, die.
909          */
910         if (!ldap_url->lud_attrs || !ldap_url->lud_attrs[0] ||
911             !*ldap_url->lud_attrs[0] ||
912             (strcmp(ldap_url->lud_attrs[0], "*") == 0) ||
913             ldap_url->lud_attrs[1]) {
914                 radlog(L_ERR, "rlm_ldap (%s): Bad attributes list in LDAP "
915                        "URL. URL must specify exactly one attribute to "
916                        "retrieve",
917                        inst->xlat_name);
918                        
919                 goto free_urldesc;
920         }
921
922         if (ldap_url->lud_host &&
923             ((strncmp(inst->server, ldap_url->lud_host,
924                       strlen(inst->server)) != 0) ||
925              (ldap_url->lud_port != inst->port))) {
926                 RDEBUG("Requested server/port is \"%s:%i\"", ldap_url->lud_host,
927                        inst->port);
928                 
929                 goto free_urldesc;
930         }
931
932         conn = ldap_get_socket(inst);
933         if (!conn) goto free_urldesc;
934
935         memcpy(&attrs, &ldap_url->lud_attrs, sizeof(attrs));
936         
937         rcode = perform_search(inst, request, &conn, ldap_url->lud_dn, 
938                                ldap_url->lud_scope, ldap_url->lud_filter, attrs,
939                                &result);
940         if (rcode < 0) {
941                 if (rcode == -2) {
942                         RDEBUG("Search returned not found", inst->xlat_name);
943                         goto free_socket;
944                 }
945
946                 goto free_socket;
947         }
948
949         entry = ldap_first_entry(conn->handle, result);
950         if (!entry) {
951                 ldap_get_option(conn->handle, LDAP_OPT_RESULT_CODE,
952                                 &ldap_errno);
953                 radlog(L_ERR, "rlm_ldap (%s): Failed retrieving entry: %s", 
954                        inst->xlat_name,
955                        ldap_err2string(ldap_errno));
956                 goto free_result;
957         }
958
959         vals = ldap_get_values(conn->handle, entry, ldap_url->lud_attrs[0]);
960         if (!vals) {
961                 RDEBUG("No \"%s\" attributes found in specified object",
962                        inst->xlat_name, ldap_url->lud_attrs[0]);
963                 goto free_result;
964         }
965
966         length = strlen(vals[0]);
967         if (length >= freespace){
968
969                 goto free_vals;
970         }
971
972         strlcpy(out, vals[0], freespace);
973
974 free_vals:
975         ldap_value_free(vals);
976 free_result:
977         ldap_msgfree(result);
978 free_socket:
979         ldap_release_socket(inst, conn);
980 free_urldesc:
981         ldap_free_urldesc(ldap_url);
982
983         return length;
984 }
985
986
987 static char *get_userdn(LDAP_CONN **pconn, REQUEST *request, int *module_rcode)
988 {
989         int             rcode;
990         VALUE_PAIR      *vp;
991         ldap_instance   *inst = (*pconn)->inst;
992         LDAP            *handle = (*pconn)->handle;
993         LDAPMessage     *result, *entry;
994         int             ldap_errno;
995         static char     firstattr[] = "uid";
996         char            *user_dn;
997         const char      *attrs[] = {firstattr, NULL};
998         char            filter[MAX_FILTER_STR_LEN];     
999         char            basedn[MAX_FILTER_STR_LEN];     
1000
1001         *module_rcode = RLM_MODULE_FAIL;
1002
1003         vp = pairfind(request->config_items, PW_LDAP_USERDN, 0);
1004         if (vp) {
1005                 *module_rcode = RLM_MODULE_OK;
1006                 return vp->vp_strvalue;
1007         }
1008         
1009         if (!radius_xlat(filter, sizeof(filter), inst->filter,
1010                          request, ldap_escape_func, NULL)) {
1011                 radlog(L_ERR, "rlm_ldap (%s): Unable to create filter",
1012                        inst->xlat_name);
1013                 *module_rcode = RLM_MODULE_INVALID;
1014                 return NULL;
1015         }
1016
1017         if (!radius_xlat(basedn, sizeof(basedn), inst->basedn,
1018                          request, ldap_escape_func, NULL)) {
1019                 radlog(L_ERR, "rlm_ldap (%s): Unable to create basedn",
1020                        inst->xlat_name);
1021                 *module_rcode = RLM_MODULE_INVALID;
1022                 return NULL;
1023         }
1024
1025         rcode = perform_search(inst, request, pconn, basedn, LDAP_SCOPE_SUBTREE,
1026                                filter, attrs, &result);
1027         if (rcode < 0) {
1028                 if (rcode == -2) {
1029                         *module_rcode = RLM_MODULE_NOTFOUND;
1030                 }
1031
1032                 return NULL;
1033         }
1034
1035         if ((entry = ldap_first_entry(handle, result)) == NULL) {
1036                 ldap_get_option(handle, LDAP_OPT_RESULT_CODE,
1037                                 &ldap_errno);
1038                 radlog(L_ERR, "rlm_ldap (%s): Failed retrieving entry: %s", 
1039                        inst->xlat_name,
1040                        ldap_err2string(ldap_errno));
1041                 ldap_msgfree(result);
1042                 return NULL;
1043         }
1044
1045         if ((user_dn = ldap_get_dn(handle, entry)) == NULL) {
1046                 ldap_get_option(handle, LDAP_OPT_RESULT_CODE,
1047                                 &ldap_errno);
1048                 radlog(L_ERR, "rlm_ldap (%s): ldap_get_dn() failed: %s",
1049                        inst->xlat_name,
1050                        ldap_err2string(ldap_errno));
1051                        
1052                 ldap_msgfree(result);
1053                 return NULL;
1054         }
1055
1056         vp = pairmake("LDAP-UserDn", user_dn, T_OP_EQ);
1057         if (!vp) {
1058                 ldap_memfree(user_dn);
1059                 ldap_msgfree(result);
1060                 return NULL;
1061         }
1062         
1063         *module_rcode = RLM_MODULE_OK;
1064         
1065         pairadd(&request->config_items, vp);
1066         ldap_memfree(user_dn);
1067         ldap_msgfree(result);
1068
1069         return vp->vp_strvalue;
1070 }
1071
1072
1073 /** Perform LDAP-Group comparison checking
1074  *
1075  */
1076 static int ldap_groupcmp(void *instance, REQUEST *request,
1077                          UNUSED VALUE_PAIR *thing, VALUE_PAIR *check,
1078                          UNUSED VALUE_PAIR *check_pairs,
1079                          UNUSED VALUE_PAIR **reply_pairs)
1080 {
1081         ldap_instance   *inst = instance;
1082         int             i, rcode, found, module_rcode;
1083         LDAPMessage     *result = NULL;
1084         LDAPMessage     *entry = NULL;
1085         int             ldap_errno;
1086         int             check_is_dn = FALSE, value_is_dn = FALSE;
1087         static char     firstattr[] = "dn";
1088         const char      *attrs[] = {firstattr, NULL};
1089         char            **vals;
1090         const char      *group_attrs[] = {inst->groupmemb_attr, NULL};
1091         LDAP_CONN       *conn;
1092         char            *user_dn;
1093
1094         char            gr_filter[MAX_FILTER_STR_LEN];
1095         char            filter[MAX_FILTER_STR_LEN];
1096         char            basedn[MAX_FILTER_STR_LEN];
1097
1098         RDEBUG("Searching for user in group \"%s\"", check->vp_strvalue);
1099
1100         if (check->length == 0) {
1101                 RDEBUG("Cannot do comparison (group name is empty)");
1102                 return 1;
1103         }
1104
1105         conn = ldap_get_socket(inst);
1106         if (!conn) return 1;
1107
1108         /*
1109          *      This is used in the default membership filter.
1110          */
1111         user_dn = get_userdn(&conn, request, &module_rcode);
1112         if (!user_dn) {
1113                 ldap_release_socket(inst, conn);
1114                 return 1;
1115         }
1116
1117         if (!inst->groupmemb_filter) goto check_attr;
1118
1119         if (!radius_xlat(gr_filter, sizeof(gr_filter),
1120                          inst->groupmemb_filter, request, ldap_escape_func,
1121                          NULL)) {
1122                 radlog(L_ERR, "rlm_ldap (%s): Failed creating group filter",
1123                        inst->xlat_name);
1124                 return 1;
1125         }
1126
1127         /*
1128          *      If it's a DN, use that.
1129          */
1130         check_is_dn = strchr(check->vp_strvalue,',') == NULL ? FALSE : TRUE;
1131         
1132         if (check_is_dn) {
1133                 strlcpy(filter, gr_filter, sizeof(filter));
1134                 strlcpy(basedn, check->vp_strvalue, sizeof(basedn));    
1135         } else {
1136                 snprintf(filter, sizeof(filter), "(&(%s=%s)%s)",
1137                          inst->groupname_attr,
1138                          check->vp_strvalue, gr_filter);
1139
1140                 /*
1141                  *      get_userdn does this, too.  Oh well.
1142                  */
1143                 if (!radius_xlat(basedn, sizeof(basedn), inst->basedn,
1144                                  request, ldap_escape_func, NULL)) {
1145                         radlog(L_ERR, "rlm_ldap (%s): Failed creating basedn",
1146                                inst->xlat_name);
1147                         return 1;
1148                 }
1149         }
1150
1151         rcode = perform_search(inst, request, &conn, basedn, LDAP_SCOPE_SUBTREE,
1152                                filter, attrs, &result);
1153         if (rcode == 0) {
1154                 ldap_release_socket(inst, conn);
1155                 ldap_msgfree(result);
1156                         
1157                 RDEBUG("User found in group object");
1158                 
1159                 return 0;
1160         }
1161
1162         if (rcode == -1) {
1163                 ldap_release_socket(inst, conn);
1164                 return 1;
1165         }
1166
1167         /* else the search returned -2, for "not found" */
1168
1169         /*
1170          *      Else the search returned NOTFOUND.  See if we're
1171          *      configured to search for group membership using user
1172          *      object attribute.
1173          */
1174         if (!inst->groupmemb_attr) {
1175                 ldap_release_socket(inst, conn);
1176                 RDEBUG("Group object \"%s\" not found, or user is not a member",
1177                        check->vp_strvalue);
1178                 return 1;
1179         }
1180
1181 check_attr:
1182         RDEBUG2("Checking user object membership (%s) attributes",
1183                 inst->groupmemb_attr);
1184
1185         snprintf(filter ,sizeof(filter), "(objectclass=*)");
1186
1187         rcode = perform_search(inst, request, &conn, user_dn, LDAP_SCOPE_BASE,
1188                                filter, group_attrs, &result);
1189         if (rcode < 0) {
1190                 if (rcode == -2) {
1191                         RDEBUG("Can't check membership attributes, user object "
1192                                "not found");
1193                 }
1194                 ldap_release_socket(inst, conn);
1195                 return 1;
1196         }
1197
1198         entry = ldap_first_entry(conn->handle, result);
1199         if (!entry) {
1200                 ldap_get_option(conn->handle, LDAP_OPT_RESULT_CODE,
1201                                 &ldap_errno);
1202                 radlog(L_ERR, "rlm_ldap (%s): Failed retrieving entry: %s", 
1203                        inst->xlat_name,
1204                        ldap_err2string(ldap_errno));
1205                                
1206                 ldap_release_socket(inst, conn);
1207                 ldap_msgfree(result);
1208                 return 1;
1209         }
1210
1211         vals = ldap_get_values(conn->handle, entry, inst->groupmemb_attr);
1212         if (!vals) {
1213                 RDEBUG("No group membership attribute(s) found in user object");
1214                 ldap_release_socket(inst, conn);
1215                 ldap_msgfree(result);
1216                 return 1;
1217         }
1218
1219         /*
1220          *      Loop over the list of groups the user is a member of,
1221          *      looking for a match.
1222          */
1223         found = FALSE;
1224         for (i = 0; i < ldap_count_values(vals); i++) {
1225                 LDAPMessage *gr_result = NULL;
1226                 
1227                 value_is_dn = strchr(vals[i], ',') == NULL ? FALSE : TRUE;
1228                 
1229                 RDEBUG2("Processing group membership value \"%s\"", vals[i]);
1230
1231                 /*
1232                  *      Both literal group names, do case sensitive comparison
1233                  */
1234                 if (!check_is_dn && !value_is_dn) {
1235                         if (strcmp(vals[i], check->vp_strvalue) == 0){
1236                                 RDEBUG("User found (membership value matches "
1237                                        "check value)");
1238                                
1239                                 found = TRUE;
1240                                 break;
1241                         }
1242                         
1243                         continue;
1244                 }
1245
1246                 /*
1247                  *      Both DNs, do case insensitive comparison
1248                  */
1249                 if (check_is_dn && value_is_dn) {
1250                         if (strcasecmp(vals[i], check->vp_strvalue) == 0){
1251                                 RDEBUG("User found (membership DN matches "
1252                                        "check DN)");
1253                                
1254                                 found = TRUE;
1255                                 break;
1256                         }
1257                         
1258                         continue;
1259                 }
1260                 
1261                 /*
1262                  *      If the value is not a DN, or the check item is a DN
1263                  *      there's nothing more we can do.
1264                  */
1265                 if (!value_is_dn && check_is_dn) continue;
1266
1267                 /*
1268                  *      We have a value which is a DN, and a check item which
1269                  *      specifies the name of a group, search using the value
1270                  *      DN for the group, and see if it has a groupname_attr
1271                  *      which matches our check val.
1272                  */
1273                 RDEBUG2("Searching with membership DN and group name");
1274
1275                 snprintf(filter,sizeof(filter), "(%s=%s)",
1276                          inst->groupname_attr, check->vp_strvalue);
1277
1278                 rcode = perform_search(inst, request, &conn, vals[i],
1279                                        LDAP_SCOPE_BASE, filter, attrs,
1280                                        &gr_result);
1281                                        
1282                 ldap_msgfree(gr_result);
1283
1284                 /* Error occurred */
1285                 if (rcode == -1) {
1286                         ldap_value_free(vals);
1287                         ldap_msgfree(result);
1288                         ldap_release_socket(inst, conn);
1289                         return 1;
1290                 }
1291                 
1292                 /*
1293                  *      Either the group DN wasn't found, or it didn't have the
1294                  *      correct name. Continue looping over the attributes.
1295                  */
1296                 if (rcode == -2) {
1297                         ldap_msgfree(gr_result);
1298                         continue;
1299                 }
1300
1301                 found = TRUE;
1302
1303                 RDEBUG("User found (group name in membership DN matches check "
1304                        "value)");
1305
1306                 break;
1307         }
1308
1309         ldap_value_free(vals);
1310         ldap_msgfree(result);
1311         ldap_release_socket(inst, conn);
1312
1313         if (!found){
1314                 RDEBUG("User is not a member of specified group");
1315                 return 1;
1316         }
1317
1318         return 0;
1319 }
1320
1321 /** Parse update section
1322  *
1323  * Verify that the ldap update section makes sense, and add attribute names
1324  * to array of attributes for efficient querying later.
1325  */
1326 static int build_attrmap(CONF_SECTION *cs, VALUE_PAIR_MAP **head)
1327 {
1328         const char *cs_list, *p;
1329
1330         request_refs_t request_def = REQUEST_CURRENT;
1331         pair_lists_t list_def = PAIR_LIST_REQUEST;
1332
1333         CONF_ITEM *ci = cf_sectiontoitem(cs);
1334         CONF_PAIR *cp;
1335
1336         unsigned int total = 0;
1337         VALUE_PAIR_MAP **tail, *map;
1338         *head = NULL;
1339         tail = head;
1340         
1341         if (!cs) return 0;
1342         
1343         cs_list = p = cf_section_name2(cs);
1344         if (cs_list) {
1345                 request_def = radius_request_name(&p, REQUEST_UNKNOWN);
1346                 if (request_def == REQUEST_UNKNOWN) {
1347                         cf_log_err(ci, "rlm_ldap: Default request specified "
1348                                    "in mapping section is invalid");
1349                         return -1;
1350                 }
1351                 
1352                 list_def = fr_str2int(pair_lists, p, PAIR_LIST_UNKNOWN);
1353                 if (list_def == PAIR_LIST_UNKNOWN) {
1354                         cf_log_err(ci, "rlm_ldap: Default list specified "
1355                                    "in mapping section is invalid");
1356                         return -1;
1357                 }
1358         }
1359
1360         for (ci = cf_item_find_next(cs, NULL);
1361              ci != NULL;
1362              ci = cf_item_find_next(cs, ci)) {
1363                 if (total++ == MAX_ATTRMAP) {
1364                         cf_log_err(ci, "rlm_ldap: Attribute map size exceeded");
1365                         goto error;
1366                 }
1367                 
1368                 if (!cf_item_is_pair(ci)) {
1369                         cf_log_err(ci, "rlm_ldap: Entry is not in \"attribute ="
1370                                        " ldap-attribute\" format");
1371                         goto error;
1372                 }
1373         
1374                 cp = cf_itemtopair(ci);
1375                 map = radius_cp2map(cp, REQUEST_CURRENT, list_def);
1376                 if (!map) {
1377                         goto error;
1378                 }
1379                 
1380                 *tail = map;
1381                 tail = &(map->next);
1382         }
1383
1384         return 0;
1385         
1386         error:
1387                 radius_mapfree(head);
1388                 return -1;
1389 }
1390
1391 /** Detach from the LDAP server and cleanup internal state.
1392  *
1393  */
1394 static int ldap_detach(void *instance)
1395 {
1396         ldap_instance *inst = instance;
1397
1398         if (inst->postauth) free(inst->postauth);
1399         if (inst->accounting) free(inst->accounting);
1400         
1401         fr_connection_pool_delete(inst->pool);
1402         
1403         if (inst->user_map) {
1404                 radius_mapfree(&inst->user_map);
1405         }
1406
1407         free(inst);
1408
1409         return 0;
1410 }
1411
1412 static int parse_sub_section(CONF_SECTION *parent, 
1413                              ldap_instance *inst,
1414                              ldap_acct_section_t **config,
1415                              rlm_components_t comp)
1416 {
1417         CONF_SECTION *cs;
1418
1419         const char *name = section_type_value[comp].section;
1420         
1421         cs = cf_section_sub_find(parent, name);
1422         if (!cs) {
1423                 radlog(L_INFO, "rlm_ldap (%s): Couldn't find configuration for "
1424                        "%s, will return NOOP for calls from this section",
1425                        inst->xlat_name, name);
1426                 
1427                 return 0;
1428         }
1429         
1430         *config = rad_calloc(sizeof(**config));
1431         if (cf_section_parse(cs, *config, acct_section_config) < 0) {
1432                 radlog(L_ERR, "rlm_ldap (%s): Failed parsing configuration for "
1433                        "section %s", inst->xlat_name, name);
1434                 
1435                 free(*config);
1436                 *config = NULL;
1437                 
1438                 return -1;
1439         }
1440                 
1441         (*config)->cs = cs;
1442
1443         return 0;
1444 }
1445
1446 /** Parses config
1447  * Uses section of radiusd config file passed as parameter to create an
1448  * instance of the module.
1449  */
1450 static int ldap_instantiate(CONF_SECTION * conf, void **instance)
1451 {
1452         ldap_instance *inst;
1453         CONF_SECTION *cs;
1454
1455         inst = rad_calloc(sizeof *inst);
1456         inst->cs = conf;
1457
1458         inst->chase_referrals = 2; /* use OpenLDAP defaults */
1459         inst->rebind = 2;
1460         
1461         inst->xlat_name = cf_section_name2(conf);
1462         if (!inst->xlat_name) {
1463                 inst->xlat_name = cf_section_name1(conf);
1464         }
1465                 
1466         rad_assert(inst->xlat_name);
1467
1468         /*
1469          *      If the configuration parameters can't be parsed, then fail.
1470          */
1471         if ((cf_section_parse(conf, inst, module_config) < 0) ||
1472             (parse_sub_section(conf, inst,
1473                                &inst->accounting,
1474                                RLM_COMPONENT_ACCT) < 0) ||
1475             (parse_sub_section(conf, inst,
1476                                &inst->postauth,
1477                                RLM_COMPONENT_POST_AUTH) < 0)) {
1478                 radlog(L_ERR, "rlm_ldap (%s): Failed parsing configuration",
1479                        inst->xlat_name);
1480                 goto error;
1481         }
1482
1483         if (inst->server == NULL) {
1484                 radlog(L_ERR, "rlm_ldap (%s): Missing 'server' directive",
1485                        inst->xlat_name);
1486                 goto error;
1487         }
1488
1489         /*
1490          *      Check for URLs.  If they're used and the library doesn't
1491          *      support them, then complain.
1492          */
1493         inst->is_url = 0;
1494         if (ldap_is_ldap_url(inst->server)) {
1495 #ifdef HAVE_LDAP_INITIALIZE
1496                 inst->is_url = 1;
1497                 inst->port = 0;
1498 #else
1499                 radlog(L_ERR, "rlm_ldap (%s): 'server' directive is in URL "
1500                        "form but ldap_initialize() is not available",
1501                        inst->xlat_name);
1502                 goto error;
1503 #endif
1504         }
1505
1506         /* workaround for servers which support LDAPS but not START TLS */
1507         if (inst->port == LDAPS_PORT || inst->tls_mode) {
1508                 inst->tls_mode = LDAP_OPT_X_TLS_HARD;
1509         } else {
1510                 inst->tls_mode = 0;
1511         }
1512
1513 #if LDAP_SET_REBIND_PROC_ARGS != 3
1514         /*
1515          *      The 2-argument rebind doesn't take an instance
1516          *      variable.  Our rebind function needs the instance
1517          *      variable for the username, password, etc.
1518          */
1519         if (inst->rebind == 1) {
1520                 radlog(L_ERR, "rlm_ldap (%s): Cannot use 'rebind' directive "
1521                        "as this version of libldap does not support the API "
1522                        "that we need", inst->xlat-name);
1523                 goto error;
1524         }
1525 #endif
1526
1527         /*
1528          *      Build the attribute map
1529          */
1530         cs = cf_section_sub_find(conf, "update");
1531         if (cs) {       
1532                 if (build_attrmap(cs, &(inst->user_map)) < 0) {
1533                         goto error;
1534                 }
1535         }
1536
1537         /*
1538          *      Group comparison checks.
1539          */
1540         paircompare_register(PW_LDAP_GROUP, PW_USER_NAME, ldap_groupcmp, inst); 
1541         if (cf_section_name2(conf)) {
1542                 DICT_ATTR *da;
1543                 ATTR_FLAGS flags;
1544                 char buffer[256];
1545
1546                 snprintf(buffer, sizeof(buffer), "%s-Ldap-Group",
1547                          inst->xlat_name);
1548                 memset(&flags, 0, sizeof(flags));
1549
1550                 dict_addattr(buffer, -1, 0, PW_TYPE_STRING, flags);
1551                 da = dict_attrbyname(buffer);
1552                 if (!da) {
1553                         radlog(L_ERR, "rlm_ldap (%s): Failed creating "
1554                                "attribute %s", inst->xlat_name, buffer);
1555                         goto error;
1556                 }
1557
1558                 paircompare_register(da->attr, PW_USER_NAME, ldap_groupcmp,
1559                                      inst);
1560         }
1561
1562         xlat_register(inst->xlat_name, ldap_xlat, inst);
1563
1564         /*
1565          *      Initialize the socket pool.
1566          */
1567         inst->pool = fr_connection_pool_init(inst->cs, inst,
1568                                              ldap_conn_create,
1569                                              NULL,
1570                                              ldap_conn_delete);
1571         if (!inst->pool) {
1572                 ldap_detach(inst);
1573                 return -1;
1574         }
1575         
1576         *instance = inst;
1577         return 0;
1578         
1579         error:
1580         ldap_detach(inst);
1581         return -1;
1582 }
1583
1584 static int check_access(ldap_instance *inst, REQUEST* request, LDAP_CONN *conn,
1585                         LDAPMessage *entry)
1586 {
1587         int rcode = -1;
1588         char **vals = NULL;
1589
1590         vals = ldap_get_values(conn->handle, entry, inst->access_attr);
1591         if (vals) {
1592                 if (inst->positive_access_attr) {
1593                         if (strncmp(vals[0], "FALSE", 5) == 0) {
1594                                 RDEBUG("Dialup access disabled");
1595
1596                         } else {
1597                                 rcode = 0;
1598                         }
1599
1600                 } else {
1601                         RDEBUG("\"%s\" attribute exists - access denied by"
1602                                " default", inst->access_attr);
1603                 }
1604
1605                 ldap_value_free(vals);
1606
1607         } else if (inst->positive_access_attr) {
1608                 RDEBUG("No %s attribute - access denied by default",
1609                        inst->access_attr);
1610
1611         } else {
1612                 rcode = 0;
1613         }
1614
1615         return rcode;
1616 }
1617
1618
1619 static VALUE_PAIR *ldap_getvalue(REQUEST *request, const VALUE_PAIR_TMPL *dst,
1620                                  void *ctx)
1621 {
1622         rlm_ldap_result_t *self = ctx;
1623         VALUE_PAIR *head, **tail, *vp;
1624         int i;
1625         
1626         request = request;
1627         
1628         head = NULL;
1629         tail = &head;
1630         
1631         /*
1632          *      Iterate over all the retrieved values,
1633          *      don't try and be clever about changing operators
1634          *      just use whatever was set in the attribute map. 
1635          */
1636         for (i = 0; i < self->count; i++) {
1637                 vp = pairalloc(dst->da);
1638                 rad_assert(vp);
1639
1640                 pairparsevalue(vp, self->values[i]);
1641                 
1642                 *tail = vp;
1643                 tail = &(vp->next);
1644         }
1645         
1646         return head;            
1647 }
1648
1649
1650 static void xlat_attrsfree(const xlat_attrs_t *expanded)
1651 {
1652         const VALUE_PAIR_MAP *map;
1653         unsigned int total = 0;
1654         
1655         const char *name;
1656         
1657         for (map = expanded->maps; map != NULL; map = map->next)
1658         {
1659                 name = expanded->attrs[total++];
1660                 if (!name) return;
1661                 
1662                 if (map->src->do_xlat) {
1663                         rad_cfree(name);
1664                 }
1665         }
1666 }
1667
1668
1669 static int xlat_attrs(REQUEST *request, const VALUE_PAIR_MAP *maps,
1670                       xlat_attrs_t *expanded)
1671 {
1672         const VALUE_PAIR_MAP *map;
1673         unsigned int total = 0;
1674         
1675         size_t len;
1676         char *buffer;
1677
1678         for (map = maps; map != NULL; map = map->next)
1679         {
1680                 if (map->src->do_xlat) {
1681                         buffer = rad_malloc(MAX_ATTR_STR_LEN);
1682                         len = radius_xlat(buffer, MAX_ATTR_STR_LEN,
1683                                           map->src->name, request, NULL, NULL);
1684                                           
1685                         if (!len) {
1686                                 RDEBUG("Expansion of LDAP attribute "
1687                                        "\"%s\" failed", map->src->name);
1688                                        
1689                                 expanded->attrs[total] = NULL;
1690                                 
1691                                 xlat_attrsfree(expanded);
1692                                 
1693                                 return -1;
1694                         }
1695                         
1696                         expanded->attrs[total++] = buffer;
1697                 } else {
1698                         expanded->attrs[total++] = map->src->name;
1699                 }
1700         }
1701         
1702         expanded->attrs[total] = NULL;
1703         expanded->maps = maps;
1704         
1705         return 0;
1706 }
1707
1708
1709 /** Convert attribute map into valuepairs
1710  *
1711  * Use the attribute map built earlier to convert LDAP values into valuepairs
1712  * and insert them into whichever list they need to go into.
1713  *
1714  * This is *NOT* atomic, but there's no condition in which we should error
1715  * out...
1716  */
1717 static void do_attrmap(UNUSED ldap_instance *inst, REQUEST *request,
1718                        LDAP *handle, const xlat_attrs_t *expanded,
1719                        LDAPMessage *entry)
1720 {
1721         const VALUE_PAIR_MAP    *map;
1722         unsigned int            total = 0;
1723         
1724         rlm_ldap_result_t       result;
1725         const char              *name;
1726
1727         for (map = expanded->maps; map != NULL; map = map->next)
1728         {
1729                 name = expanded->attrs[total++];
1730                 
1731                 result.values = ldap_get_values(handle, entry, name);
1732                 if (!result.values) {
1733                         RDEBUG2("Attribute \"%s\" not found in LDAP object",
1734                                 name);
1735                                 
1736                         goto next;
1737                 }
1738                 
1739                 /*
1740                  *      Find out how many values there are for the
1741                  *      attribute and extract all of them.
1742                  */
1743                 result.count = ldap_count_values(result.values);
1744                 
1745                 /*
1746                  *      If something bad happened, just skip, this is probably
1747                  *      a case of the dst being incorrect for the current
1748                  *      request context
1749                  */
1750                 if (radius_map2request(request, map, name, ldap_getvalue,
1751                                        &result) < 0) {
1752                         goto next;
1753                 }
1754                 
1755                 next:
1756                 
1757                 ldap_value_free(result.values);
1758         }
1759 }
1760
1761
1762 static void do_check_reply(ldap_instance *inst, REQUEST *request)
1763 {
1764        /*
1765         *       More warning messages for people who can't be bothered
1766         *       to read the documentation.
1767         */
1768         if (inst->expect_password && (debug_flag > 1)) {
1769                 if (!pairfind(request->config_items,PW_CLEARTEXT_PASSWORD, 0) &&
1770                         !pairfind(request->config_items,
1771                                   PW_NT_PASSWORD, 0) &&
1772                         !pairfind(request->config_items,
1773                                   PW_USER_PASSWORD, 0) &&
1774                         !pairfind(request->config_items,
1775                                   PW_PASSWORD_WITH_HEADER, 0) &&
1776                         !pairfind(request->config_items,
1777                                   PW_CRYPT_PASSWORD, 0)) {
1778                                 RDEBUG("WARNING: No \"known good\" password "
1779                                        "was found in LDAP.  Are you sure that "
1780                                        "the user is configured correctly?");
1781                }
1782        }
1783 }
1784
1785
1786 static void apply_profile(ldap_instance *inst, REQUEST *request,
1787                           LDAP_CONN **pconn, const char *profile,
1788                           const xlat_attrs_t *expanded)
1789 {
1790         int rcode;
1791         LDAPMessage     *result, *entry;
1792         int             ldap_errno;
1793         LDAP            *handle = (*pconn)->handle;
1794         char            filter[MAX_FILTER_STR_LEN];
1795
1796         if (!profile || !*profile) return;
1797
1798         strlcpy(filter, inst->base_filter, sizeof(filter));
1799
1800         rcode = perform_search(inst, request, pconn, profile, LDAP_SCOPE_BASE,
1801                                filter, expanded->attrs, &result);
1802                 
1803         if (rcode < 0) {
1804                 if (rcode == -2) {
1805                         RDEBUG("Profile \"%s\" not found", profile);
1806                 }
1807                 goto free_result;
1808         }
1809
1810         entry = ldap_first_entry(handle, result);
1811         if (!entry) {
1812                 ldap_get_option(handle, LDAP_OPT_RESULT_CODE,
1813                                 &ldap_errno);
1814                 radlog(L_ERR, "rlm_ldap (%s): Failed retrieving entry: %s", 
1815                        inst->xlat_name,
1816                        ldap_err2string(ldap_errno));
1817                        
1818                 goto free_result;
1819         }
1820         
1821         do_attrmap(inst, request, handle, expanded, entry);
1822
1823 free_result:
1824         ldap_msgfree(result);
1825 }
1826
1827
1828 /** Check if user is authorized for remote access
1829  *
1830  */
1831 static int ldap_authorize(void *instance, REQUEST * request)
1832 {
1833         int rcode;
1834         int module_rcode = RLM_MODULE_OK;
1835         ldap_instance   *inst = instance;
1836         char            *user_dn = NULL;
1837         char            **vals;
1838         VALUE_PAIR      *vp;
1839         LDAP_CONN       *conn;
1840         LDAPMessage     *result, *entry;
1841         int             ldap_errno;
1842         char            filter[MAX_FILTER_STR_LEN];
1843         char            basedn[MAX_FILTER_STR_LEN];
1844         xlat_attrs_t    expanded; /* faster that mallocing every time */
1845         
1846         if (!request->username) {
1847                 RDEBUG2("Attribute \"User-Name\" is required for "
1848                         "authorization.");
1849                 return RLM_MODULE_NOOP;
1850         }
1851
1852         /*
1853          *      Check for valid input, zero length names not permitted
1854          */
1855         if (request->username->length == 0) {
1856                 RDEBUG2("Zero length username not permitted");
1857                 return RLM_MODULE_INVALID;
1858         }
1859
1860         if (!radius_xlat(filter, sizeof(filter), inst->filter,
1861                          request, ldap_escape_func, NULL)) {
1862                 radlog(L_ERR, "rlm_ldap (%s): Failed creating filter",
1863                        inst->xlat_name);
1864                 return RLM_MODULE_INVALID;
1865         }
1866
1867         if (!radius_xlat(basedn, sizeof(basedn), inst->basedn,
1868                          request, ldap_escape_func, NULL)) {
1869                 radlog(L_ERR, "rlm_ldap (%s): Failed creating basedn",
1870                        inst->xlat_name);
1871                 return RLM_MODULE_INVALID;
1872         }
1873
1874         conn = ldap_get_socket(inst);
1875         if (!conn) return RLM_MODULE_FAIL;
1876         
1877         if (xlat_attrs(request, inst->user_map, &expanded) < 0) {
1878                 return RLM_MODULE_FAIL;
1879         }
1880         
1881         rcode = perform_search(inst, request, &conn, basedn,
1882                                LDAP_SCOPE_SUBTREE, filter, expanded.attrs,
1883                                &result);
1884         
1885         if (rcode < 0) {
1886                 if (rcode == -2) {
1887                         module_failure_msg(request,
1888                                            "rlm_ldap (%s): User object not "
1889                                            " found",
1890                                            inst->xlat_name);
1891                                            
1892                         RDEBUG("User object not found", inst->xlat_name);
1893                                
1894                         module_rcode = RLM_MODULE_NOTFOUND;
1895                         goto free_socket;
1896                 }
1897
1898                 goto free_socket;
1899         }
1900
1901         entry = ldap_first_entry(conn->handle, result);
1902         if (!entry) {
1903                 ldap_get_option(conn->handle, LDAP_OPT_RESULT_CODE,
1904                                 &ldap_errno);
1905                 radlog(L_ERR, "rlm_ldap (%s): Failed retrieving entry: %s", 
1906                        inst->xlat_name,
1907                        ldap_err2string(ldap_errno));
1908                        
1909                 goto free_result;
1910         }
1911
1912         user_dn = ldap_get_dn(conn->handle, entry);
1913         if (!user_dn) {
1914                 ldap_get_option(conn->handle, LDAP_OPT_RESULT_CODE,
1915                                 &ldap_errno);
1916                 radlog(L_ERR, "rlm_ldap (%s): ldap_get_dn() failed: %s",
1917                        inst->xlat_name,
1918                        ldap_err2string(ldap_errno));
1919                 goto free_result;
1920         }
1921         
1922         RDEBUG2("User found at DN \"%s\"", user_dn);
1923         /*
1924          *      Adding attribute containing the Users' DN.
1925          */
1926         pairadd(&request->config_items,
1927                 pairmake("Ldap-UserDn", user_dn, T_OP_EQ));
1928
1929 #ifdef WITH_EDIR
1930         /*
1931          *      We already have a Cleartext-Password.  Skip edir.
1932          */
1933         if (inst->edir && pairfind(request->config_items,
1934                                    PW_CLEARTEXT_PASSWORD, 0)) {
1935                 goto skip_edir;
1936         }
1937
1938         /*
1939          *      Retrieve Universal Password if we use eDirectory
1940          */
1941         if (inst->edir) {
1942                 int res = 0;
1943                 size_t bufsize;
1944                 char buffer[256];
1945
1946                 bufsize = sizeof(buffer);
1947
1948                 /* retrive universal password */
1949                 res = nmasldap_get_password(conn->handle, user_dn,
1950                                             buffer, &bufsize);
1951                 if (res != 0) {
1952                         RDEBUG2("Failed to retrieve eDirectory password. Check "
1953                                 "your configuration !");
1954                         module_rcode = RLM_MODULE_NOOP;
1955                         goto free_result;
1956                 }
1957
1958                 /* Add Cleartext-Password attribute to the request */
1959                 vp = radius_paircreate(request, &request->config_items,
1960                                        PW_CLEARTEXT_PASSWORD, 0,
1961                                        PW_TYPE_STRING);
1962                 strlcpy(vp->vp_strvalue, buffer, sizeof(vp->vp_strvalue));
1963                 vp->length = strlen(vp->vp_strvalue);
1964                 
1965                 RDEBUG2("Added eDirectory password in check items as %s = %s",
1966                         vp->name, vp->vp_strvalue);
1967                         
1968                 if (inst->edir_autz) {
1969                         RDEBUG2("Binding as user for eDirectory authorization "
1970                                 "checks");
1971                         /*
1972                          *      Bind as the user
1973                          */
1974                         conn->rebound = TRUE;
1975                         module_rcode = ldap_bind_wrapper(&conn, user_dn,
1976                                                          vp->vp_strvalue,
1977                                                          NULL, TRUE);
1978                         if (module_rcode != RLM_MODULE_OK) {
1979                                 goto free_result;
1980                         }
1981                         
1982                         RDEBUG("Bind as user \"%s\" was successful", user_dn);
1983                 }
1984         }
1985
1986 skip_edir:
1987 #endif
1988
1989         /*
1990          *      Check for access.
1991          */
1992         if (inst->access_attr) {
1993                 if (check_access(inst, request, conn, entry) < 0) {
1994                         module_rcode = RLM_MODULE_USERLOCK;
1995                         goto free_result;
1996                 }
1997         }
1998
1999         /*
2000          *      Apply ONE user profile, or a default user profile.
2001          */
2002         vp = pairfind(request->config_items, PW_USER_PROFILE, 0);
2003         if (vp || inst->default_profile) {
2004                 char *profile = inst->default_profile;
2005
2006                 if (vp) profile = vp->vp_strvalue;
2007
2008                 apply_profile(inst, request, &conn, profile, &expanded);
2009         }
2010
2011         /*
2012          *      Apply a SET of user profiles.
2013          */
2014         if (inst->profile_attr) {
2015                 vals = ldap_get_values(conn->handle, entry, inst->profile_attr);
2016                 if (vals != NULL) {
2017                         int i;
2018         
2019                         for (i = 0; (vals[i] != NULL) && (*vals[i] != '\0');
2020                              i++) {
2021                                 apply_profile(inst, request, &conn, vals[i],
2022                                               &expanded);
2023                         }
2024         
2025                         ldap_value_free(vals);
2026                 }
2027         }
2028
2029         if (inst->user_map) {
2030                 do_attrmap(inst, request, conn->handle, &expanded, entry);
2031                 do_check_reply(inst, request);
2032         }
2033         
2034 free_result:
2035         if (user_dn) ldap_memfree(user_dn);
2036         xlat_attrsfree(&expanded);
2037         ldap_msgfree(result);
2038 free_socket:
2039         ldap_release_socket(inst, conn);
2040
2041         return module_rcode;
2042 }
2043
2044
2045 /** Check the user's password against ldap database
2046  *
2047  */
2048 static int ldap_authenticate(void *instance, REQUEST * request)
2049 {
2050         int             module_rcode;
2051         const char      *user_dn;
2052         ldap_instance   *inst = instance;
2053         LDAP_CONN       *conn;
2054
2055         /*
2056          * Ensure that we're being passed a plain-text password, and not
2057          * anything else.
2058          */
2059
2060         if (!request->username) {
2061                 radlog(L_AUTH, "rlm_ldap (%s): Attribute \"User-Name\" is "
2062                        "required for authentication", inst->xlat_name);
2063                 return RLM_MODULE_INVALID;
2064         }
2065
2066         if (!request->password) {
2067                 radlog(L_AUTH, "rlm_ldap (%s): Attribute \"User-Password\" "
2068                        "is required for authentication.", inst->xlat_name);
2069                 RDEBUG2("  You have set \"Auth-Type := LDAP\" somewhere.");
2070                 RDEBUG2("  *********************************************");
2071                 RDEBUG2("  * THAT CONFIGURATION IS WRONG.  DELETE IT.   ");
2072                 RDEBUG2("  * YOU ARE PREVENTING THE SERVER FROM WORKING.");
2073                 RDEBUG2("  *********************************************");
2074                 return RLM_MODULE_INVALID;
2075         }
2076
2077         if (request->password->attribute != PW_USER_PASSWORD) {
2078                 radlog(L_AUTH, "rlm_ldap (%s): Attribute \"User-Password\" "
2079                        "is required for authentication. Cannot use \"%s\".",
2080                        inst->xlat_name, request->password->name);
2081                 return RLM_MODULE_INVALID;
2082         }
2083
2084         if (request->password->length == 0) {
2085                 module_failure_msg(request,
2086                                    "rlm_ldap (%s): Empty password supplied",
2087                                    inst->xlat_name);
2088                 return RLM_MODULE_INVALID;
2089         }
2090
2091         conn = ldap_get_socket(inst);
2092         if (!conn) return RLM_MODULE_FAIL;
2093
2094         RDEBUG("Login attempt by \"%s\" with password \"%s\"",
2095                request->username->vp_strvalue, request->password->vp_strvalue);
2096
2097         /*
2098          *      Get the DN by doing a search.
2099          */
2100         user_dn = get_userdn(&conn, request, &module_rcode);
2101         if (!user_dn) {
2102                 ldap_release_socket(inst, conn);
2103                 return module_rcode;
2104         }
2105
2106         /*
2107          *      Bind as the user
2108          */
2109         conn->rebound = TRUE;
2110         module_rcode = ldap_bind_wrapper(&conn, user_dn,
2111                                          request->password->vp_strvalue,
2112                                          NULL, TRUE);
2113         if (module_rcode == RLM_MODULE_OK) {
2114                 RDEBUG("Bind as user \"%s\" was successful", user_dn);
2115         }
2116
2117         ldap_release_socket(inst, conn);
2118         return module_rcode;
2119 }
2120
2121 /** Modify user's object in LDAP
2122  *
2123  */
2124 static int user_modify(ldap_instance *inst, REQUEST *request,
2125                        ldap_acct_section_t *section)
2126 {
2127         int             module_rcode = RLM_MODULE_OK;
2128         int             ldap_errno;
2129         const char      *error_string;
2130         
2131         LDAP_CONN       *conn;
2132         
2133         LDAPMod         *mod_p[MAX_ATTRMAP + 1], mod_s[MAX_ATTRMAP];
2134         LDAPMod         **modify = mod_p;
2135         
2136         char            *passed[MAX_ATTRMAP * 2];
2137         int             i, total = 0, last_pass = 0;
2138         
2139         char            *expanded[MAX_ATTRMAP];
2140         int             last_exp = 0;
2141         
2142         const char      *attr;
2143         const char      *value;
2144         
2145         const char      *user_dn;
2146
2147         conn = ldap_get_socket(inst);
2148         if (!conn) return RLM_MODULE_FAIL;
2149
2150         /*
2151          *      Build our set of modifications using the update sections in
2152          *      the config.
2153          */
2154         CONF_ITEM       *ci;
2155         CONF_PAIR       *cp;
2156         CONF_SECTION    *cs;
2157         FR_TOKEN        op;
2158         char            path[MAX_STRING_LEN];
2159         
2160         char            *p = path;
2161
2162         rad_assert(section);
2163         
2164         /*
2165          *      Locate the update section were going to be using
2166          */
2167         if (section->reference[0] != '.') {
2168                 *p++ = '.';
2169         }
2170         
2171         if (!radius_xlat(p, (sizeof(path) - (p - path)) - 1,
2172                          section->reference, request, NULL, NULL)) {
2173                 goto error;     
2174         }
2175
2176         ci = cf_reference_item(NULL, section->cs, path);
2177         if (!ci) {
2178                 goto error;     
2179         }
2180         
2181         if (!cf_item_is_section(ci)){
2182                 radlog(L_ERR, "rlm_ldap (%s): Reference must resolve to a "
2183                        "section", inst->xlat_name);
2184                 
2185                 goto error;     
2186         }
2187         
2188         cs = cf_section_sub_find(cf_itemtosection(ci), "update");
2189         if (!cs) {
2190                 radlog(L_ERR, "rlm_ldap (%s): Section must contain 'update' "
2191                        "subsection",
2192                        inst->xlat_name);
2193                 
2194                 goto error;
2195         }
2196         
2197         /*
2198          *      Iterate over all the pairs, building our mods array
2199          */
2200         for (ci = cf_item_find_next(cs, NULL);
2201              ci != NULL;
2202              ci = cf_item_find_next(cs, ci)) {
2203                 int do_xlat = FALSE;
2204                 
2205                 if (total == MAX_ATTRMAP) {
2206                         radlog(L_ERR, "rlm_ldap (%s): Modify map size exceeded",
2207                                inst->xlat_name);
2208         
2209                         goto error;
2210                 }
2211                 
2212                 if (!cf_item_is_pair(ci)) {
2213                         radlog(L_ERR, "rlm_ldap (%s): Entry is not in "
2214                                "\"ldap-attribute = value\" format",
2215                                inst->xlat_name);
2216                                
2217                         goto error;
2218                 }
2219         
2220                 /*
2221                  *      Retrieve all the information we need about the pair
2222                  */
2223                 cp = cf_itemtopair(ci);
2224                 value = cf_pair_value(cp);
2225                 attr = cf_pair_attr(cp);
2226                 op = cf_pair_operator(cp);
2227                 
2228                 if ((value == NULL) || (*value == '\0')) {
2229                         RDEBUG("empty value string, "
2230                                "skipping attribute \"%s\"", attr);
2231                         
2232                         continue;
2233                 }
2234
2235                 switch (cf_pair_value_type(cp))
2236                 {
2237                         case T_BARE_WORD:
2238                         case T_SINGLE_QUOTED_STRING:
2239                         break;
2240                         case T_BACK_QUOTED_STRING:
2241                         case T_DOUBLE_QUOTED_STRING:
2242                                 do_xlat = TRUE;         
2243                         break;
2244                         default:
2245                                 rad_assert(0);
2246                                 goto error;
2247                 }
2248                 
2249                 if (op == T_OP_CMP_FALSE) {
2250                         passed[last_pass] = NULL;
2251                 } else if (do_xlat) {
2252                         p = rad_malloc(1024);
2253                         radius_xlat(p, 1024, value, request, NULL, NULL);
2254                         
2255                         if (*p == '\0') {
2256                         
2257                                 RDEBUG("xlat failed or empty value string, "
2258                                        "skipping attribute \"%s\"", attr);
2259                                        
2260                                 free(p);
2261                                 
2262                                 continue;
2263                         }
2264                         
2265                         expanded[last_exp++] = p;
2266                         passed[last_pass] = p;
2267                 /* 
2268                  *      Static strings
2269                  */
2270                 } else {
2271                         memcpy(&(passed[last_pass]), &value,
2272                                sizeof(passed[last_pass]));
2273                 }
2274                 
2275                 passed[last_pass + 1] = NULL;
2276                 
2277                 mod_s[total].mod_values = &(passed[last_pass]);
2278                                         
2279                 last_pass += 2;
2280                 
2281                 switch (op)
2282                 {
2283                         /*
2284                          *  T_OP_EQ is *NOT* supported, it is impossible to
2285                          *  support because of the lack of transactions in LDAP
2286                          */
2287                         case T_OP_ADD:
2288                                 mod_s[total].mod_op = LDAP_MOD_ADD;
2289                         break;
2290                         case T_OP_SET:
2291                                 mod_s[total].mod_op = LDAP_MOD_REPLACE;
2292                         break;
2293                         case T_OP_SUB:
2294                         case T_OP_CMP_FALSE:
2295                                 mod_s[total].mod_op = LDAP_MOD_DELETE;
2296                         break;
2297 #ifdef LDAP_MOD_INCREMENT
2298                         case T_OP_INCRM:
2299                                 mod_s[total].mod_op = LDAP_MOD_INCREMENT;
2300                         break;
2301 #endif
2302                         default:
2303                                 radlog(L_ERR, "rlm_ldap (%s): Operator '%s' "
2304                                        "is not supported for LDAP modify "
2305                                        "operations", inst->xlat_name,
2306                                        fr_int2str(fr_tokens, op, "¿unknown?"));
2307                                        
2308                                 goto error;
2309                 }
2310                 
2311                 /*
2312                  *      Now we know the value is ok, copy the pointers into
2313                  *      the ldapmod struct.
2314                  */
2315                 memcpy(&(mod_s[total].mod_type), &(attr), 
2316                        sizeof(mod_s[total].mod_type));
2317                 
2318                 mod_p[total] = &(mod_s[total]);
2319                 total++;
2320         }
2321         
2322         if (total == 0) {
2323                 module_rcode = RLM_MODULE_NOOP;
2324                 goto release;
2325         }
2326         
2327         mod_p[total] = NULL;
2328         
2329         /*
2330          *      Perform all modifications as the default admin user.
2331          */
2332         if (conn->rebound) {
2333                 ldap_errno = ldap_bind_wrapper(&conn,
2334                                                inst->login, inst->password,
2335                                                NULL, TRUE);
2336                 if (ldap_errno != RLM_MODULE_OK) {
2337                         goto error;
2338                 }
2339
2340                 rad_assert(conn != NULL);
2341                 conn->rebound = FALSE;
2342         }
2343
2344         user_dn = get_userdn(&conn, request, &module_rcode);
2345         if (!user_dn) {
2346                 module_rcode = RLM_MODULE_NOTFOUND;
2347                 goto release;
2348         }
2349         
2350         RDEBUG2("Modifying user object with DN \"%s\"", user_dn);
2351         
2352         ldap_errno = ldap_modify_ext_s(conn->handle, user_dn, modify, NULL,
2353                                        NULL);
2354                              
2355         if (ldap_errno != LDAP_SUCCESS) {
2356                 error_string = ldap_err2string(ldap_errno);
2357
2358                 radlog(L_ERR, "rlm_ldap (%s): Modifying DN \"%s\" failed: %s",
2359                        inst->xlat_name, user_dn, error_string);
2360                 
2361         error:
2362                 module_rcode = RLM_MODULE_FAIL;
2363                 
2364                 goto release;
2365         }
2366         
2367         RDEBUG2("Modification successful!");
2368         
2369         release:
2370         
2371         /*
2372          *      Free up any buffers we allocated for xlat expansion
2373          */     
2374         for (i = 0; i < last_exp; i++) {
2375                 free(expanded[i]);
2376         }
2377         
2378         ldap_release_socket(inst, conn);
2379         
2380         return module_rcode;
2381 }
2382
2383
2384 static int ldap_accounting(void *instance, REQUEST * request) {
2385         ldap_instance *inst = instance;         
2386
2387         if (inst->accounting) {
2388                 return user_modify(inst, request, inst->accounting); 
2389         }
2390         
2391         return RLM_MODULE_NOOP;
2392 }
2393
2394
2395 /** Check the user's password against ldap database
2396  *
2397  */
2398 static int ldap_postauth(void *instance, REQUEST * request)
2399 {
2400         ldap_instance   *inst = instance;
2401
2402         if (inst->postauth) {
2403                 return user_modify(inst, request, inst->postauth); 
2404         }
2405
2406         return RLM_MODULE_NOOP;
2407 }
2408
2409
2410 /* globally exported name */
2411 module_t rlm_ldap = {
2412         RLM_MODULE_INIT,
2413         "ldap",
2414         RLM_TYPE_THREAD_SAFE,   /* type: reserved        */
2415         ldap_instantiate,       /* instantiation         */
2416         ldap_detach,            /* detach                */
2417         {
2418                 ldap_authenticate,      /* authentication        */
2419                 ldap_authorize,         /* authorization         */
2420                 NULL,                   /* preaccounting         */
2421                 ldap_accounting,        /* accounting            */
2422                 NULL,                   /* checksimul            */
2423                 NULL,                   /* pre-proxy             */
2424                 NULL,                   /* post-proxy            */
2425                 ldap_postauth           /* post-auth */
2426         },
2427 };