2 * rlm_ldap.c LDAP authorization and authentication module.
5 * This module is based on LDAP patch to Cistron radiusd, which in turn was
6 * based mostly on a Mysql+Cistron patch from oyarzun@wilmington.net
8 * 17 Jan 2000: OpenLDAP SDK porting, basic TLS support, LDAP authorization,
9 * fault tolerance with multiple LDAP server support done by Adrian
10 * Pavlykevych <pam@polynet.lviv.ua>
11 * 24 May 2000: converting to new configuration file format, futher improvements
12 * in fault tolerance, threaded operation
13 * Adrian Pavlykevych <pam@polynet.lviv.ua>
15 static const char rcsid[] = "$Id$";
19 #include <sys/types.h>
20 #include <sys/socket.h>
22 #include <netinet/in.h>
44 #define MAX_AUTH_QUERY_LEN 256
52 static char *make_filter(char *, char *);
54 static void fieldcpy(char *, char **);
56 static char *dn_base(char *);
57 static VALUE_PAIR *ldap_pairget(LDAP *, LDAPMessage *, TLDAP_RADIUS *);
58 static LDAP *rlm_ldap_connect(const char *, const char *, int, int *);
59 void *conn_maint(void *);
61 #define MAX_SERVER_LINE 1024
63 * These should really be in a module-specific data structure,
64 * which is passed to the module with every request.
66 static char *ldap_server = NULL;
67 static int ldap_port = 389;
68 static int ldap_timelimit = TIMELIMIT;
69 /* wait forever on network activity */
70 static struct timeval ldap_net_timeout = { -1, 0 };
71 /* wait forever for search results */
72 static struct timeval ldap_timeout = { -1, 0 };
73 static struct timeval *timeout = NULL;
74 static int ldap_cache_size = 0; /* cache size limited only by TTL */
75 static int ldap_cache_ttl = 30 ;/* cache objects TTL 30 secs */
76 static int ldap_debug = 0; /* 0x0005; */
77 static int ldap_tls_mode = LDAP_OPT_X_TLS_TRY;
78 static char *ldap_login = NULL;
79 static char *ldap_password = NULL;
80 static char *ldap_filter = NULL;
81 static char *ldap_basedn = NULL;
82 static char *group_basedn = NULL;
83 static char *ldap_radius_group = NULL;
85 static LDAP *ld = NULL;
86 static pthread_t conn_thread = 0; /*ID of thread, which performs LDAP connect*/
87 /* signal from module thread to conn_maint thread to perform LDAP
88 * connection operation (bind/unbind) */
89 static pthread_cond_t conn_cv = PTHREAD_COND_INITIALIZER;
90 /* signal from conn_maint to module threads to proceed afer (re)connect */
91 static pthread_cond_t go_ahead_cv = PTHREAD_COND_INITIALIZER;
92 /* signal from rlm_detach() to conn_maint thread to close connection */
93 static pthread_mutex_t sig_mutex = PTHREAD_MUTEX_INITIALIZER;
94 static pthread_mutex_t conn_mutex = PTHREAD_MUTEX_INITIALIZER;
95 static pthread_mutex_t mnt_mutex = PTHREAD_MUTEX_INITIALIZER;
99 static int readers; /* number of threads performing LDAP lookups */
101 static CONF_PARSER module_config[] = {
102 { "server", PW_TYPE_STRING_PTR, &ldap_server, NULL },
103 { "port", PW_TYPE_INTEGER, &ldap_port, "389" },
104 { "net_timeout", PW_TYPE_INTEGER, &ldap_net_timeout.tv_sec, "-1" },
105 { "timeout", PW_TYPE_INTEGER, &ldap_timeout.tv_sec, "-1" },
107 { "identity", PW_TYPE_STRING_PTR, &ldap_login, NULL },
108 { "password", PW_TYPE_STRING_PTR, &ldap_password, NULL },
109 { "basedn", PW_TYPE_STRING_PTR, &ldap_basedn, NULL },
110 { "filter", PW_TYPE_STRING_PTR, &ldap_filter, NULL },
111 { "access_group", PW_TYPE_STRING_PTR, &ldap_radius_group, NULL },
113 { "cache_size", PW_TYPE_INTEGER, &ldap_cache_size, "0" },
114 { "cache_ttl", PW_TYPE_INTEGER, &ldap_cache_ttl, "30" },
116 { NULL, -1, NULL, NULL }
119 /* LDAP attribute name that controls remote access */
120 #define LDAP_RADIUSACCESS "dialupAccess"
122 /* Fallback to default settings if no basic attributes defined in object
123 * (An ugly hack to be replaced by profiles and policies)
128 #define DEFAULT_SERVICE_TYPE "Framed-User"
129 #define DEFAULT_FRAMED_PROTOCOL "PPP"
130 #define DEFAULT_FRAMED_MTU "576"
131 #define DEFAULT_FRAMED_COMPRESSION "Van-Jacobson-TCP-IP"
132 #define DEFAULT_IDLE_TIMEOUT "240"
133 #define DEFAULT_SIMULTANEOUS_USE "1"
136 #define ld_valid ld_options.ldo_valid
137 #define LDAP_VALID_SESSION 0x2
138 #define LDAP_VALID(ld) ( (ld)->ld_valid == LDAP_VALID_SESSION )
141 * Mappings of LDAP radius* attributes to RADIUS attributes
143 * Hmm... these should really be read in from the configuration file
145 static TLDAP_RADIUS check_item_map[] = {
146 { "radiusAuthType", "Auth-Type" },
147 { "npSessionsAllowed", "Simultaneous-Use" },
150 static TLDAP_RADIUS reply_item_map[] = {
151 { "radiusServiceType", "Service-Type" },
152 { "radiusFramedProtocol", "Framed-Protocol" },
153 { "radiusFramedIPAddress", "Framed-IP-Address" },
154 { "radiusFramedIPNetmask", "Framed-IP-Netmask" },
155 { "radiusFramedRoute", "Framed-Route" },
156 { "radiusFramedRouting", "Framed-Routing" },
157 { "radiusFilterId", "Filter-Id" },
158 { "radiusFramedMTU", "Framed-MTU" },
159 { "radiusFramedCompression", "Framed-Compression" },
160 { "radiusLoginIPHost", "Login-IP-Host" },
161 { "radiusLoginService", "Login-Service" },
162 { "radiusLoginTCPPort", "Login-TCP-Port" },
163 { "radiusCallbackNumber", "Callback-Number" },
164 { "radiusCallbackId", "Callback-Id" },
165 { "radiusFramedRoute", "Framed-Route" },
166 { "radiusFramedIPXNetwork", "Framed-IPX-Network" },
167 { "radiusClass", "Class" },
168 { "radiusSessionTimeout", "Session-Timeout" },
169 { "radiusIdleTimeout", "Idle-Timeout" },
170 { "radiusTerminationAction", "Termination-Action" },
171 { "radiusCalledStationId", "Called-Station-Id" },
172 { "radiusCallingStationId", "Calling-Station-Id" },
173 { "radiusLoginLATService", "Login-LAT-Service" },
174 { "radiusLoginLATNode", "Login-LAT-Node" },
175 { "radiusLoginLATGroup", "Login-LAT-Group" },
176 { "radiusFramedAppleTalkLink", "Framed-AppleTalk-Link" },
177 { "radiusFramedAppleTalkNetwork", "Framed-AppleTalk-Network" },
178 { "radiusFramedAppleTalkZone", "Framed-AppleTalk-Zone" },
179 { "radiusPortLimit", "Port-Limit" },
180 { "radiusLoginLATPort", "Login-LAT-Port" },
184 /*************************************************************************
186 * Function: rlm_ldap_instantiate
188 * Purpose: Uses section of radiusd config file passed as parameter
189 * to create an instance ofthe module.
190 * Note: Currently multiple instances are not supported, lots of
191 * data structures restructuring should be done to support it
193 *************************************************************************/
194 static int rlm_ldap_instantiate(CONF_SECTION *conf, void **instance)
197 cf_section_parse(conf, module_config);
199 if(ldap_radius_group != NULL)
200 group_basedn = dn_base(ldap_radius_group);
201 if(ldap_net_timeout.tv_sec != -1)
202 timeout = &ldap_net_timeout;
203 if(ldap_timeout.tv_sec != -1 )
204 timeout = &ldap_timeout;
210 DEBUG("rlm_ldap_instantiate() using:");
211 for(i = 0; module_config[i].name != NULL; i++) {
212 switch(module_config[i].type){
213 case PW_TYPE_STRING_PTR:
214 DEBUG( "%s = %s",module_config[i].name, (char *)*(int *)(module_config[i].data));
216 case PW_TYPE_INTEGER:
217 DEBUG( "%s = %d",module_config[i].name, *((int *)module_config[i].data));
224 DEBUG("timeout: %ld.%ld", timeout->tv_sec,timeout->tv_usec);
226 DEBUG("Starting connection thread");
227 pthread_mutex_lock(&mnt_mutex);
228 pthread_create(&conn_thread,NULL,conn_maint,NULL);
229 /* Block until maintainer is created and initialized */
230 pthread_mutex_lock(&mnt_mutex);
231 pthread_mutex_unlock(&mnt_mutex);
232 DEBUG("Connection thread started");
237 void *conn_maint(void *arg)
242 pthread_mutex_unlock(&mnt_mutex);
244 DEBUG("rlm_ldap: connection maintainer obtaining lock ...");
245 pthread_mutex_lock(&sig_mutex);
246 DEBUG("rlm_ldap: maintainer got lock.");
247 while((bound && !cleanup) || readers) {
248 DEBUG("rlm_ldap: maintainer waits for wakeup signal, %d readers active", readers);
249 pthread_cond_wait(&conn_cv,&sig_mutex);
251 DEBUG("rlm_ldap: connection maintainer woke up");
253 DEBUG("rlm_ldap: maintainer #%p closing connection", pthread_self());
255 pthread_mutex_unlock(&sig_mutex);
258 if((ld = rlm_ldap_connect(ldap_login, ldap_password, 0, &res)) == NULL) {
264 // pthread_mutex_lock(&sig_mutex);
266 DEBUG("rlm_ldap: maintainer reconnecton attempt succeeded? (%d)", bound);
267 if(bound && readers) {
268 DEBUG("rlm_ldap: maintainer waking workers");
269 pthread_cond_broadcast(&go_ahead_cv);
270 DEBUG("rlm_ldap: worker wakeup done.");
272 pthread_mutex_unlock(&sig_mutex);
276 static int perform_search(char *ldap_basedn, char *filter, char **attrs, LDAPMessage **result)
279 int res = RLM_MODULE_OK;
282 DEBUG2("rlm_ldap: thread #%p trying to get lock", pthread_self());
283 pthread_mutex_lock(&sig_mutex);
286 * Wake up connection maintenance thread, if there is no established LDAP
289 DEBUG2("rlm_ldap: thread #%p got lock", pthread_self());
291 DEBUG("rlm_ldap: worker thread #%p signaling for LDAP reconnection", pthread_self());
292 pthread_cond_signal(&conn_cv);
293 DEBUG("rlm_ldap: worker thread #%p waiting for LDAP connection", pthread_self());
295 DEBUG2("rlm_ldap: thread #%p bind loop", pthread_self());
297 pthread_cond_wait(&go_ahead_cv, &sig_mutex);
298 DEBUG2("rlm_ldap: thread #%p unlocking", pthread_self());
299 pthread_mutex_unlock(&sig_mutex);
301 DEBUG("rlm_ldap: thread #%p performing search", pthread_self());
302 pthread_mutex_lock(&conn_mutex);
303 msgid = ldap_search(ld,ldap_basedn,LDAP_SCOPE_SUBTREE,filter,attrs,0);
304 pthread_mutex_unlock(&conn_mutex);
306 radlog(L_ERR,"rlm_ldap: thread #%p ldap_search() API failed\n", pthread_self());
310 pthread_mutex_lock(&conn_mutex);
311 rc = ldap_result(ld, msgid, 1, timeout, result);
312 pthread_mutex_unlock(&conn_mutex);
315 ldap_perror( ld, "rlm_ldap: ldap_result()" );
316 radlog(L_ERR,"rlm_ldap: thread #%p ldap_result() failed - %s\n", pthread_self(), strerror(errno));
320 switch(ldap_result2error(ld, *result, 0)) {
324 case LDAP_TIMELIMIT_EXCEEDED:
325 radlog(L_ERR, "rlm_ldap: thread #%p Warning timelimit exceeded, using partial results\n", pthread_self());
329 DEBUG("rlm_ldap: thread #%p ldap_search() failed", pthread_self());
330 ldap_msgfree(*result);
334 if ((ldap_count_entries(ld, *result)) != 1) {
335 DEBUG("rlm_ldap: thread #%p user object not found or got ambiguous search result", pthread_self());
336 ldap_msgfree(*result);
337 res = RLM_MODULE_NOTFOUND;
340 DEBUG2("rlm_ldap: thread #%p locking connection flag ...", pthread_self());
341 pthread_mutex_lock(&sig_mutex);
342 DEBUG2("rlm_ldap: done. thread #%p Clearing flag, active workers: %d", pthread_self(), readers-1);
344 pthread_mutex_unlock(&sig_mutex);
348 DEBUG2("rlm_ldap: thread #%p locking connection flag ...", pthread_self());
349 pthread_mutex_lock(&sig_mutex);
350 DEBUG2("rlm_ldap: thread #%p done. Clearing flag, active workers: %d", pthread_self(), readers-1);
351 bound = 0; readers--;
352 DEBUG("rlm_ldap: thread #%p sending signal to maintainer...", pthread_self());
353 pthread_cond_signal(&conn_cv);
354 DEBUG2("rlm_ldap: thread #%p done", pthread_self());
355 pthread_mutex_unlock(&sig_mutex);
356 return RLM_MODULE_FAIL;
359 /******************************************************************************
361 * Function: rlm_ldap_authorize
363 * Purpose: Check if user is authorized for remote access
365 *****************************************************************************/
366 static int rlm_ldap_authorize(void *instance, REQUEST *request)
368 LDAPMessage *result, *msg, *gr_result, *gr_msg;
369 char *filter, *name, *user_dn,
370 *attrs[] = { "*", NULL },
371 *group_attrs[] = { "member", NULL },
373 VALUE_PAIR *check_tmp;
374 VALUE_PAIR *reply_tmp;
377 VALUE_PAIR **check_pairs, **reply_pairs;
379 check_pairs = &request->config_items;
380 reply_pairs = &request->reply->vps;
382 DEBUG("rlm_ldap: thread #%p - authorize", pthread_self());
383 name = request->username->strvalue;
386 * Check for valid input, zero length names not permitted
389 radlog(L_ERR, "rlm_ldap: zero length username not permitted\n");
390 return RLM_MODULE_INVALID;
393 /* Unfortunately LDAP queries are case insensitive, so in order to provide
394 unique names for simultaneous logins verification, we need to lowercase
395 USERNAME attribute value
397 for(i=0; name[i] != 0; i++)
398 name[i] = tolower(name[i]);
400 DEBUG("rlm_ldap: performing user authorization for %s", name);
402 filter = make_filter(ldap_filter, name);
404 if((res = perform_search(ldap_basedn, filter, attrs, &result)) != 0)
407 if((msg = ldap_first_entry(ld,result)) == NULL) {
408 DEBUG("rlm_ldap: thread #%p ldap_first_entry() failed", pthread_self());
409 ldap_msgfree(result);
410 return RLM_MODULE_FAIL;
413 if ((user_dn = ldap_get_dn(ld,msg)) == NULL) {
414 DEBUG("rlm_ldap: thread #%p ldap_get_dn() failed", pthread_self());
415 ldap_msgfree(result);
416 return RLM_MODULE_FAIL;
420 /* Remote access is controled by LDAP_RADIUSACCESS attribute of user object */
421 if((vals = ldap_get_values(ld, msg, LDAP_RADIUSACCESS)) != NULL ) {
422 if(!strncmp(vals[0],"FALSE",5)) {
423 DEBUG("rlm_ldap: thread #%p dialup access disabled", pthread_self());
424 ldap_msgfree(result);
425 return RLM_MODULE_REJECT;
428 DEBUG("rlm_ldap: thread #%p no %s attribute - access denied by default", pthread_self(), LDAP_RADIUSACCESS);
429 ldap_msgfree(result);
430 return RLM_MODULE_REJECT;
434 /* Remote access controled by group membership attribute of user object */
435 if(ldap_radius_group != NULL) {
438 DEBUG("rlm_ldap: thread #%p checking user membership in dialup-enabling group %s", pthread_self(), ldap_radius_group);
439 if((res = perform_search(group_basedn, ldap_radius_group, group_attrs, &gr_result)))
442 if((gr_msg = ldap_first_entry(ld, gr_result)) == NULL) {
443 DEBUG("rlm_ldap: thread #%p ldap_first_entry() failed", pthread_self);
444 ldap_msgfree(result);
445 return RLM_MODULE_FAIL;
448 if((vals = ldap_get_values(ld, gr_msg, "member")) != NULL ) {
451 (vals[valno] != NULL)
452 && !(found = !strncmp(vals[valno],user_dn,strlen(user_dn)));
455 ldap_value_free(vals);
457 ldap_msgfree(gr_result);
459 DEBUG("rlm_ldap: thread #%p user does not belong to dialup-enabling group", pthread_self());
460 ldap_msgfree(result);
461 return RLM_MODULE_REJECT;
466 DEBUG("rlm_ldap: thread #%p looking for check items in directory...", pthread_self());
467 if((check_tmp = ldap_pairget(ld, msg, check_item_map)) != (VALUE_PAIR *)0) {
468 pairadd(check_pairs, check_tmp);
471 /* Module should default to LDAP authentication if no Auth-Type specified */
472 if(pairfind(*check_pairs, PW_AUTHTYPE) == NULL){
473 pairadd(check_pairs, pairmake("Auth-Type", "LDAP", T_OP_CMP_EQ));
476 * Adding new attribute containing DN for LDAP object associated with given
479 pairadd(&request->packet->vps, pairmake("Ldap-UserDn", user_dn, T_OP_EQ));
481 DEBUG("rlm_ldap: thread #%p looking for reply items in directory...", pthread_self());
482 if((reply_tmp = ldap_pairget(ld,msg, reply_item_map)) != (VALUE_PAIR *)0) {
483 pairadd(reply_pairs, reply_tmp);
487 if(pairfind(*reply_pairs, PW_SERVICE_TYPE) == NULL){
488 pairadd(reply_pairs, pairmake("Service-Type", DEFAULT_SERVICE_TYPE, T_OP_EQ));
490 if(pairfind(*reply_pairs, PW_FRAMED_PROTOCOL) == NULL){
491 pairadd(reply_pairs, pairmake("Framed-Protocol", DEFAULT_FRAMED_PROTOCOL, T_OP_EQ));
493 if(pairfind(*reply_pairs, PW_FRAMED_MTU) == NULL){
494 pairadd(reply_pairs, pairmake("Framed-MTU", DEFAULT_FRAMED_MTU, T_OP_EQ));
496 if(pairfind(*reply_pairs, PW_FRAMED_COMPRESSION) == NULL){
497 pairadd(reply_pairs, pairmake("Framed-Compression", DEFAULT_FRAMED_COMPRESSION, T_OP_EQ));
499 if(pairfind(*reply_pairs, PW_IDLE_TIMEOUT) == NULL){
500 pairadd(reply_pairs, pairmake("Idle-Timeout", DEFAULT_IDLE_TIMEOUT, T_OP_EQ));
502 if(pairfind(*check_pairs, PW_SIMULTANEOUS_USE) == NULL){
503 pairadd(check_pairs, pairmake("Simultaneous-Use", DEFAULT_SIMULTANEOUS_USE, T_OP_EQ));
508 DEBUG("rlm_ldap: thread #%p user %s authorized to use remote access", pthread_self(), name);
509 ldap_msgfree(result);
510 return RLM_MODULE_OK;
513 /******************************************************************************
515 * Function: rlm_ldap_authenticate
517 * Purpose: Check the user's password against ldap database
519 *****************************************************************************/
520 static int rlm_ldap_authenticate(void *instance, REQUEST *request);
523 LDAPMessage *result, *msg;
524 char *filter, *passwd, *user_dn, *name,
525 *attrs[] = { "uid", NULL };
527 VALUE_PAIR *vp_user_dn;
529 DEBUG("rlm_ldap: thread #%p - authenticate", pthread_self());
531 * Ensure that we're being passed a plain-text password,
532 * and not anything else.
534 if(request->password->attribute != PW_PASSWORD) {
535 radlog(L_AUTH, "rlm_ldap: Attribute \"Password\" is required for authentication. Cannot use \"%s\".", request->password->name);
536 return RLM_MODULE_INVALID;
539 name = request->username->strvalue;
540 passwd = request->password->strvalue;
542 if(strlen(passwd) == 0) {
543 radlog(L_ERR, "rlm_ldap: empty password supplied");
544 return RLM_MODULE_INVALID;
547 DEBUG("rlm_ldap: thread #%p login attempt by \"%s\" with password \"%s\"", pthread_self(), name, passwd);
548 filter = make_filter(ldap_filter, name);
550 if((vp_user_dn = pairfind(request->packet->vps, LDAP_USERDN)) == NULL){
551 if((res = perform_search(ldap_basedn, filter, attrs, &result)))
554 if ((msg = ldap_first_entry(ld,result)) == NULL) {
555 ldap_msgfree(result);
557 return RLM_MODULE_FAIL;
560 if ((user_dn = ldap_get_dn(ld,msg)) == NULL) {
561 DEBUG("rlm_ldap: thread #%p ldap_get_dn() failed", pthread_self());
562 ldap_msgfree(result);
564 return RLM_MODULE_FAIL;
566 pairadd(&request->packet->vps,pairmake("Ldap-UserDn",user_dn,T_OP_EQ));
567 ldap_msgfree(result);
571 user_dn = vp_user_dn->strvalue;
574 DEBUG("rlm_ldap: thread #%p user DN: %s", pthread_self(), user_dn);
576 if((ld_user = rlm_ldap_connect(user_dn, passwd, 1, &res)) == NULL)
579 DEBUG("rlm_ldap: thread #%p user %s authenticated succesfully", pthread_self(), name);
580 ldap_unbind_s(ld_user);
581 return RLM_MODULE_OK;
584 static LDAP *rlm_ldap_connect(const char *dn, const char *password, int auth, int *result)
590 DEBUG("rlm_ldap: thread #%p (re)connect, authentication %d", pthread_self(), auth);
591 if ((ld = ldap_init(ldap_server,ldap_port)) == NULL){
592 radlog(L_ERR, "rlm_ldap: ldap_init() failed");
593 *result = RLM_MODULE_FAIL;
597 if (timeout != NULL && ldap_set_option(ld, LDAP_OPT_NETWORK_TIMEOUT, (void *)timeout) != LDAP_OPT_SUCCESS) {
598 radlog(L_ERR, "rlm_ldap: Could not set LDAP_OPT_NETWORK_TIMEOUT %d.%d", timeout->tv_sec, timeout->tv_usec);
601 if (ldap_timelimit != -1 && ldap_set_option(ld, LDAP_OPT_TIMELIMIT, (void *) &ldap_timelimit) != LDAP_OPT_SUCCESS ){
602 radlog(L_ERR, "rlm_ldap: Could not set LDAP_OPT_TIMELIMIT %d", ldap_timelimit );
605 if(ldap_debug && ldap_set_option( NULL, LDAP_OPT_DEBUG_LEVEL, &ldap_debug ) != LDAP_OPT_SUCCESS ) {
606 radlog(L_ERR, "rlm_ldap: Could not set LDAP_OPT_DEBUG_LEVEL %d", ldap_debug);
609 if (ldap_tls_mode && ldap_set_option(ld, LDAP_OPT_X_TLS,(void *) &ldap_tls_mode) != LDAP_OPT_SUCCESS ){
610 radlog(L_ERR, "rlm_ldap: Could not set LDAP_OPT_X_TLS_TRY");
615 if (ldap_enable_cache(ld, ldap_cache_ttl, ldap_cache_size) != LDAP_SUCCESS)
616 radlog(L_ERR,"rlm_ldap: ldap_enable_cache failed");
618 msgid = ldap_bind(ld, dn, password, LDAP_AUTH_SIMPLE);
620 ldap_perror(ld, "rlm_ldap: rlm_ldap_connect()" );
621 *result = RLM_MODULE_FAIL;
626 DEBUG("rlm_ldap: thread #%p rlm_ldap_connect() waiting for bind result ...", pthread_self());
628 rc = ldap_result(ld, msgid, 1, timeout, &res);
630 ldap_perror( ld, "rlm_ldap: ldap_result()" );
631 *result = RLM_MODULE_FAIL;
635 DEBUG("rlm_ldap: thread #%p rlm_ldap_connect() bind finished", pthread_self());
636 switch(ldap_result2error(ld, res, 1)) {
638 *result = RLM_MODULE_OK;
641 case LDAP_INVALID_CREDENTIALS:
643 *result = RLM_MODULE_REJECT;
647 DEBUG("rlm_ldap: thread #%p LDAP FAILURE", pthread_self());
648 *result = RLM_MODULE_FAIL;
650 if(*result != RLM_MODULE_OK) {
657 /*****************************************************************************
659 * Detach from the LDAP server and cleanup internal state.
661 *****************************************************************************/
662 static int rlm_ldap_detach(void *instance)
664 pthread_mutex_lock(&sig_mutex);
666 pthread_cond_signal(&conn_cv);
667 pthread_mutex_unlock(&sig_mutex);
668 pthread_join(conn_thread, NULL);
672 /*****************************************************************************
674 * This function takes DN as parameter and returns RDN and BASEDN for search.
675 * Has anyone better idea about getting object attributes based on its DN?
677 *****************************************************************************/
678 char *dn_base(char *dn)
682 if((ptr = (char *)strchr(dn, ',')) == NULL) {
683 DEBUG("Invalid DN syntax: no ',' in the string %s, maibe it's a CN? Returning default base", dn);
688 DEBUG("Invalid DN syntax: ',' is the last symbol in the string");
694 /*****************************************************************************
695 * Replace %<whatever> in a string.
699 *****************************************************************************/
700 static char *make_filter(char *str, char *name)
702 static char buf[MAX_AUTH_QUERY_LEN];
706 for(p = str; *p; p++) {
708 if (c != '%' && c != '\\') {
712 if (*++p == 0) break;
713 if (c == '%') switch(*p) {
717 case 'u': /* User name */
719 strcpy(buf + i, name);
721 strcpy(buf + i, " ");
722 i += strlen(buf + i);
729 if (c == '\\') switch(*p) {
745 if (i >= MAX_AUTH_QUERY_LEN)
746 i = MAX_AUTH_QUERY_LEN - 1;
752 static void fieldcpy(char *string, char **uptr)
757 while (*ptr == ' ' || *ptr == '\t') {
762 while(*ptr != '"' && *ptr != '\0' && *ptr != '\n') {
773 while(*ptr != ' ' && *ptr != '\t' && *ptr != '\0' && *ptr != '\n' &&
774 *ptr != '=' && *ptr != ',') {
782 /*****************************************************************************
783 * Get RADIUS attributes from LDAP object
784 * ( according to draft-adoba-radius-05.txt
785 * <http://www.ietf.org/internet-drafts/draft-adoba-radius-05.txt> )
787 *****************************************************************************/
789 static VALUE_PAIR *ldap_pairget(LDAP *ld, LDAPMessage *entry,
790 TLDAP_RADIUS *item_map)
796 TLDAP_RADIUS *element;
799 VALUE_PAIR *pairlist;
800 VALUE_PAIR *newpair = NULL;
802 if((attr = ldap_first_attribute(ld, entry, &berptr)) == (char *)0) {
803 DEBUG("rlm_ldap: thread #%p Object has no attributes", pthread_self());
808 for(element=item_map; element->attr != NULL; element++) {
809 if(!strncasecmp(attr,element->attr,strlen(element->attr))) {
810 if(((vals = ldap_get_values(ld, entry, attr)) == NULL) ||
811 (ldap_count_values(vals) > 1)) {
812 DEBUG("rlm_ldap: thread #%p Attribute %s has multiple values", pthread_self(), attr);
816 token = gettoken(&ptr, value, sizeof(value));
817 if (token < T_EQSTART || token > T_EQEND) {
820 gettoken(&ptr, value, sizeof(value));
823 DEBUG("rlm_ldap: thread #%p Attribute %s has no value", pthread_self(), attr);
826 DEBUG("rlm_ldap: thread #%p Adding %s as %s, value %s & op=%d", pthread_self(), attr, element->radius_attr, value, token);
827 if((newpair = pairmake(element->radius_attr, value, token)) == NULL)
829 pairadd(&pairlist, newpair);
830 ldap_value_free(vals);
833 } while ((attr = ldap_next_attribute(ld, entry, berptr)) != NULL);
839 /* globally exported name */
840 module_t rlm_ldap = {
842 0, /* type: reserved */
843 NULL, /* initialization */
844 rlm_ldap_instantiate, /* instantiation */
845 rlm_ldap_authorize, /* authorization */
846 rlm_ldap_authenticate, /* authentication */
847 NULL, /* preaccounting */
848 NULL, /* accounting */
849 rlm_ldap_detach, /* detach */