2 * This program is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License as published by
4 * the Free Software Foundation; either version 2 of the License, or
5 * (at your option) any later version.
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
26 #include "../util/util.h"
28 #define log_warn log_debug
29 #define log_error log_debug
34 #include <v2l_config.h>
36 #define V2L_CONN_LIFETIME 30 /* seconds */
37 #define V2L_POLL_INTERVAL 1 /* seconds */
39 #define LOG_ERROR_MEM log_error(ZONE, "Unable to allocate memory")
41 /* Global hashtable of all currently active LDAP connections */
42 static xht global_conn_list
= NULL
;
44 static v2l_LdapConn
*_v2l_create_conn (char *host
, int port
, const char *binddn
,
45 const char *user
, const char *passwd
, int add_in_list
);
46 /* NOTE: Allocated memory must be freed by the caller */
47 static char *_v2l_ldap_get_passwd (v2l_Config
* self
, const char * user
);
48 static void _v2l_free_conn (xht h
, const char *user
, void *val
);
49 static int _v2l_count_attrs (v2l_LdapRequest
* req
);
50 static v2l_LdapRequest
*_v2l_add_attr (v2l_LdapRequest
*req
, LDAPMod
* attr
);
51 static void _v2l_add_conn (v2l_LdapConn
* ldap_conn
);
52 static void _v2l_free_callback (xht h
, const char *key
, void *val
,
55 /* Free connections when its time has expired (periodic thread) */
56 static void _v2l_purge_conn_callback (void *arg
);
57 /* Free connections in a hashtable, walker function */
58 static void _v2l_free_expired (xht h
, const char *key
, void *val
,
61 /* A thread for wait for LDAP results */
62 static int _v2l_ldap_wait_callback(void *arg
);
65 static void *_v2l_ldap_wait_callback_g (void *arg
);
66 static void *_v2l_purge_conn_callback_g (void *arg
);
72 v2l_get_conn (v2l_Config
*self
, const char *user
)
74 v2l_LdapConn
*user_conn
;
76 user_conn
= (v2l_LdapConn
*) xhash_get (global_conn_list
, user
);
80 char *passwd
, *binddn
;
82 /* Get the user password for connecting him to LDAP server */
83 passwd
= _v2l_ldap_get_passwd (self
, user
);
88 log_error (ZONE
, "User \"%s\" not found in the directory", user
);
92 binddn
= (char *) malloc (sizeof(char) * (strlen (self
->suffix
) +
93 strlen (self
->uniqattr
) + strlen (user
) + 3));
97 log_error (ZONE
, "Unable to allocate memory");
102 sprintf (binddn
, "%s=%s,%s", self
->uniqattr
, user
, self
->suffix
);
104 log_debug (ZONE
, "Attempting to connect with DN: %s", binddn
);
106 user_conn
= _v2l_create_conn (self
->host
, self
->port
, binddn
, user
,
112 } /* user_conn == NULL */
118 v2l_get_master_conn (v2l_Config
*self
)
120 return _v2l_create_conn (self
->host
, self
->port
, self
->binddn
, V2L_ADMIN
,
127 xhash_walk (global_conn_list
, _v2l_free_callback
, NULL
);
128 xhash_free (global_conn_list
);
132 v2l_ldap_sync (v2l_LdapEvt
*evt_res
)
137 evt
= pth_event (PTH_EVENT_FUNC
, &_v2l_ldap_wait_callback
,
138 (void *) evt_res
, pth_time (V2L_POLL_INTERVAL
, 0));
144 rc
= pthread_create(&thr
, NULL
, _v2l_ldap_wait_callback_g
, (void *) evt_res
);
148 log_error (ZONE
, "Thread create failed: %d", rc
);
152 pthread_join(thr
, NULL
);
157 v2l_ldap_search (char *dn
, char *suffix
, char **attrs
, int subtree
,
158 v2l_LdapEvt
*evt_res
)
162 scope
= subtree
? LDAP_SCOPE_SUBTREE
: LDAP_SCOPE_ONELEVEL
;
164 return ldap_search_ext (evt_res
->ld
, suffix
, scope
,
165 dn
, attrs
, 0, NULL
, NULL
, NULL
, LDAP_NO_LIMIT
,
170 v2l_ldap_modify (char *dn
, LDAPMod
**attrs
, v2l_LdapEvt
*evt_res
)
172 return ldap_modify_ext (evt_res
->ld
, dn
, attrs
, NULL
, NULL
,
177 v2l_request_record (v2l_Config
*self
, v2l_LdapConn
*curr_conn
,
178 v2l_LdapRequest
*req
)
182 v2l_LdapRequest
*cur_req
, *cur_temp
;
183 v2l_LdapEvt
*evt_res
;
187 log_warn (ZONE
, "LDAP request is NULL? I cannot record anything");
191 nbmod
= _v2l_count_attrs (req
);
193 attrs
= (LDAPMod
**) malloc ((nbmod
+ 1) * sizeof (LDAPMod
*));
201 /* to wait for the results */
202 evt_res
= (v2l_LdapEvt
*) malloc (sizeof (v2l_LdapEvt
));
211 for (i
= 0; i
< nbmod
; i
++)
213 attrs
[i
] = (LDAPMod
*) malloc (sizeof (LDAPMod
));
215 if (attrs
[i
] == NULL
)
229 for (cur_req
= req
, i
= 0; i
< nbmod
; cur_req
= cur_req
->next
, i
++)
231 memcpy (attrs
[i
], cur_req
->attr
, sizeof (LDAPMod
));
232 log_debug (ZONE
, "Element \"%s\" (%d) in the LDAP request: %s",
233 attrs
[i
]->mod_type
, i
, attrs
[i
]->mod_values
[0]);
238 log_debug (ZONE
, "LDAP attempting to modify \"%s\" with dn \"%s\"",
239 curr_conn
->user
, curr_conn
->binddn
);
241 evt_res
->ld
= curr_conn
->ld
;
242 evt_res
->rc
= v2l_ldap_modify (curr_conn
->binddn
, attrs
, evt_res
);
244 if (evt_res
->rc
!= LDAP_SUCCESS
)
246 log_error (ZONE
, "LDAP error attempting to modify user info: %s",
247 ldap_err2string (evt_res
->rc
));
252 v2l_ldap_sync (evt_res
);
256 ldap_msgfree (evt_res
->result
);
259 for (cur_req
= req
, i
= 0; i
< nbmod
; i
++)
262 cur_req
= cur_req
->next
;
265 free (cur_temp
->attr
->mod_values
[0]);
266 free (cur_temp
->attr
->mod_values
);
267 free (cur_temp
->attr
);
277 v2l_add_attr_str (v2l_LdapRequest
*req
, const char *attr
, const char *str
)
281 mod
= (LDAPMod
*) malloc (sizeof (LDAPMod
));
288 mod
->mod_op
= LDAP_MOD_REPLACE
;
289 mod
->mod_type
= (char *) attr
;
291 mod
->mod_values
= (char **) malloc (2 * sizeof (char *));
293 if (mod
->mod_values
== NULL
)
299 mod
->mod_values
[0] = (char *) malloc ((strlen (str
) + 1) * sizeof (char));
301 if (mod
->mod_values
[0] == NULL
)
303 free (mod
->mod_values
);
308 memcpy (mod
->mod_values
[0], str
, strlen (str
) + 1);
309 mod
->mod_values
[1] = NULL
;
311 return _v2l_add_attr (req
, mod
);
314 /************************/
315 /* public api ends here */
317 static v2l_LdapConn
*
318 _v2l_create_conn (char *host
, int port
, const char *binddn
,
319 const char *user
, const char *passwd
, int add_in_list
)
322 v2l_LdapConn
*ldap_conn
;
323 int version
; /* LDAP protocol version */
328 if ((ld
= ldap_init (host
, port
)) == NULL
)
330 log_error (ZONE
, "Unable to init LDAP");
335 version
= LDAP_VERSION3
;
338 ldap_set_option (ld
, LDAP_OPT_PROTOCOL_VERSION
, &version
);
340 if ((rc
= ldap_simple_bind_s (ld
, binddn
, passwd
)) != LDAP_SUCCESS
)
343 "LDAP simple bind error : %s", ldap_err2string (rc
));
347 tmp_str
= (char *) malloc (sizeof (char) * (strlen (binddn
) + 1));
355 strcpy (tmp_str
, binddn
);
356 ptr
= strtok (tmp_str
, ", ");
359 ldap_conn
= pmalloc (p
, sizeof (v2l_LdapConn
));
364 pmalloc (ldap_conn
->p
, sizeof (char) * (strlen (binddn
) + 1));
365 strcpy (ldap_conn
->binddn
, binddn
);
368 pmalloc (ldap_conn
->p
, sizeof (char) * (strlen (tmp_str
) + 1));
369 strcpy (ldap_conn
->entry
, tmp_str
);
372 pmalloc (ldap_conn
->p
, sizeof (char) * (strlen (user
) + 1));
373 strcpy (ldap_conn
->user
, user
);
375 ldap_conn
->creation_time
= time (NULL
); /* timestamp */
376 ldap_conn
->exists
= 1;
378 if (add_in_list
== 1) /* Add it to global_conn_list */
380 _v2l_add_conn (ldap_conn
);
388 _v2l_ldap_get_passwd(v2l_Config
*self
, const char *user
)
391 v2l_LdapEvt
*evt_res
;
392 char *data
, *filter
, **vals
, *attrs
[2] = {"userPassword", NULL
};
394 evt_res
= (v2l_LdapEvt
*) malloc(sizeof(v2l_LdapEvt
));
402 filter
= (char *) malloc (sizeof(char)*
403 (strlen(self
->uniqattr
) + strlen(user
) + 2));
412 sprintf(filter
, "%s=%s", self
->uniqattr
, user
);
413 evt_res
->ld
= self
->master_conn
->ld
;
415 evt_res
->rc
= v2l_ldap_search (filter
, self
->suffix
, attrs
, 0, evt_res
);
418 if (evt_res
->rc
!= LDAP_SUCCESS
)
421 "LDAP error attempting to retrieve \"%s\"'s password: %s",
422 user
, ldap_err2string (evt_res
->rc
));
427 v2l_ldap_sync (evt_res
);
430 if (ldap_count_entries(evt_res
->ld
, evt_res
->result
) == 1)
432 e
= ldap_first_entry(evt_res
->ld
, evt_res
->result
);
433 vals
= ldap_get_values(evt_res
->ld
, e
, "userPassword");
437 log_debug(ZONE
, "User has no password!");
438 data
= (char *) malloc(sizeof(char));
443 ldap_msgfree(evt_res
->result
);
452 data
= (char *) malloc(sizeof(char) * (strlen(vals
[0]) + 1));
456 strcpy(data
, vals
[0]);
459 ldap_value_free(vals
);
462 ldap_msgfree(evt_res
->result
);
469 /* count the number of LDAPMod in the structure */
471 _v2l_count_attrs (v2l_LdapRequest
* req
)
473 v2l_LdapRequest
*ptr
;
476 for (nbmod
= 0, ptr
= req
; ptr
!= NULL
; ptr
= ptr
->next
, nbmod
++);
481 static v2l_LdapRequest
*
482 _v2l_add_attr (v2l_LdapRequest
*req
, LDAPMod
* attr
)
486 log_warn (ZONE
, "LDAP attribute is NULL? I cannot add anything");
492 req
= (v2l_LdapRequest
*) malloc (sizeof (v2l_LdapRequest
));
505 v2l_LdapRequest
*ptr
;
506 v2l_LdapRequest
*new_req
;
508 new_req
= (v2l_LdapRequest
*) malloc (sizeof (v2l_LdapRequest
));
516 new_req
->attr
= attr
;
517 new_req
->next
= NULL
;
519 for (ptr
= req
; ptr
->next
!= NULL
; ptr
= ptr
->next
);
528 _v2l_ldap_wait_callback(void *arg
)
530 v2l_LdapEvt
*evt_res
= (v2l_LdapEvt
*) arg
;
534 rc
= ldap_result (evt_res
->ld
, evt_res
->msgid
, 1, NULL
, &result
);
538 log_error(ZONE
, "LDAP result error %s",
539 ldap_err2string(rc
));
540 evt_res
->result
= NULL
;
545 if ((rc
== LDAP_RES_ADD
)
546 || (rc
== LDAP_RES_MODIFY
)
547 || (rc
== LDAP_RES_SEARCH_RESULT
)
548 || (rc
== LDAP_RES_SEARCH_ENTRY
)
549 || (rc
== LDAP_RES_DELETE
))
551 evt_res
->result
= result
;
556 return 0; /* still waiting */
561 _v2l_ldap_wait_callback_g (void *arg
)
563 while (!_v2l_ldap_wait_callback (arg
))
565 sleep (V2L_POLL_INTERVAL
);
573 _v2l_free_callback (xht h
, const char *key
, void *val
, void *arg
)
575 _v2l_free_conn (h
, key
, val
);
579 _v2l_free_conn (xht h
, const char *user
, void *val
)
581 v2l_LdapConn
*temp_conn
= (v2l_LdapConn
*) val
;
583 log_debug (ZONE
, "Freeing LDAP connection for user \"%s\"", user
);
586 ldap_unbind (temp_conn
->ld
);
587 pool_free (temp_conn
->p
);
591 _v2l_free_expired (xht h
, const char *key
, void *val
, void *arg
)
593 v2l_LdapConn
*temp_conn
= (v2l_LdapConn
*) val
;
595 /* kill connections older than V2L_CONN_LIFETIME */
596 if ((time (NULL
) - temp_conn
->creation_time
) > (time_t) V2L_CONN_LIFETIME
)
598 _v2l_free_conn (h
, key
, val
);
603 _v2l_purge_conn_callback (void *arg
)
605 log_debug (ZONE
, "Checking connections lifetime");
609 /* global_conn_list has been freed? */
610 if (global_conn_list
!= NULL
)
612 xhash_walk (global_conn_list
, _v2l_free_expired
, NULL
);
615 pth_sleep (V2L_CONN_LIFETIME
);
617 sleep (V2L_CONN_LIFETIME
);
625 _v2l_purge_conn_callback_g (void *arg
)
627 _v2l_purge_conn_callback(arg
);
633 _v2l_add_conn (v2l_LdapConn
* ldap_conn
)
643 if (global_conn_list
== NULL
)
646 log_debug (ZONE
, "global_conn_list hashtable is not initialized yet");
648 global_conn_list
= xhash_new (509);
650 /* spawn the thread which deletes expired connections */
652 attr
= pth_attr_new ();
653 pth_attr_set (attr
, PTH_ATTR_JOINABLE
, FALSE
);
654 pth_spawn (attr
, (void *) _v2l_purge_conn_callback
, NULL
);
655 pth_attr_destroy (attr
);
657 pthread_attr_init(&attr
);
658 pthread_attr_setdetachstate(&attr
, PTHREAD_CREATE_DETACHED
);
660 rc
= pthread_create (&thr
, &attr
, _v2l_purge_conn_callback_g
, NULL
);
661 pthread_attr_destroy(&attr
);
665 log_error (ZONE
, "Thread create failed: %d", rc
);
670 xhash_put (global_conn_list
, ldap_conn
->user
, (void *) ldap_conn
);