00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00021 #include <stdlib.h>
00022
00023 #ifndef _V2L_JABBER2
00024 #include <jabberd.h>
00025 #else
00026 #include <pthread.h>
00027 #include "../util/util.h"
00028
00029 #define log_warn log_debug
00030 #define log_error log_debug
00031 typedef pool_t pool;
00032 #endif
00033
00034 #include <v2l_conn.h>
00035
00039 #define V2L_CONN_LIFETIME 30
00040
00042 #define V2L_POLL_INTERVAL 1
00043
00044 #define LOG_ERROR_MEM log_error (ZONE, "Unable to allocate memory")
00045
00047 static xht V2L_CONN_LIST = NULL;
00048
00058 static v2l_LdapConn *_v2l_create_conn (char *host, int port, const char *binddn,
00059 const char *user, const char *passwd, int expire);
00060
00072 static int _v2l_ldap_get_credentials (v2l_Config *self, const char *user,
00073 char **passwd, char **cn);
00074
00083 static void _v2l_free_conn (xht h, const char *user, void *val);
00084
00089 static int _v2l_count_attrs (v2l_LdapRequest *req);
00090
00098 static int _v2l_ldap_modify (char *dn, LDAPMod **attrs, v2l_LdapEvt *evt_res);
00099
00109 static int _v2l_ldap_search (char *dn, char *suffix, char **attrs, int subtree,
00110 v2l_LdapEvt *evt_res);
00111
00119 static char *_v2l_ldap_filter (v2l_Config *self, const char *user);
00120
00125 static void _v2l_ldap_sync (v2l_LdapEvt *evt_res);
00126
00134 static v2l_LdapRequest *_v2l_add_attr (v2l_LdapRequest *req, LDAPMod *attr);
00135
00141 static void _v2l_add_conn (v2l_LdapConn *ldap_conn);
00142
00147 static void _v2l_free_walker (xht h, const char *key, void *val,
00148 void *arg);
00149
00170 static void *_v2l_purge_conn_callback (void *arg);
00171
00176 static void _v2l_free_expired_walker (xht h, const char *key, void *val,
00177 void *arg);
00178
00180 static int _v2l_ldap_wait_callback (void *arg);
00181
00182 #ifdef _V2L_JABBER2
00183 static void *_v2l_ldap_wait_callback_g (void *arg);
00184 #endif
00185
00186
00187
00188 v2l_LdapConn *
00189 v2l_get_conn (v2l_Config *self, const char *user)
00190 {
00191 v2l_LdapConn *user_conn;
00192
00193 user_conn = (v2l_LdapConn *) xhash_get (V2L_CONN_LIST, user);
00194
00195 if (user_conn == NULL)
00196 {
00197 char *passwd, *cn, *binddn;
00198
00199
00200 if (_v2l_ldap_get_credentials (self, user, &passwd, &cn) == 0)
00201 {
00202 log_error (ZONE, "User \"%s\" not found in the directory", user);
00203 return NULL;
00204 }
00205
00206 binddn = (char *) malloc (strlen (self->suffix) + strlen (cn) + 4);
00207
00208 if (binddn == NULL)
00209 {
00210 LOG_ERROR_MEM;
00211 free (passwd);
00212 free (cn);
00213 return NULL;
00214 }
00215
00216 sprintf (binddn, "cn=%s,%s", cn, self->suffix);
00217
00218 log_debug (ZONE, "Attempting to connect with DN: %s", binddn);
00219
00220 user_conn = _v2l_create_conn (self->host, self->port, binddn, user,
00221 passwd, 1);
00222
00223 free (passwd);
00224 free (cn);
00225 free (binddn);
00226
00227 }
00228
00229 return user_conn;
00230 }
00231
00232 v2l_LdapConn *
00233 v2l_get_master_conn (v2l_Config *self)
00234 {
00235 return _v2l_create_conn (self->host, self->port, self->binddn, V2L_ADMIN,
00236 self->bindpw, 0);
00237 }
00238
00239 void
00240 v2l_free_allconn (void)
00241 {
00242 xhash_walk (V2L_CONN_LIST, _v2l_free_walker, NULL);
00243 xhash_free (V2L_CONN_LIST);
00244 }
00245
00246 v2l_LdapEvt *
00247 v2l_ldap_get_entry (v2l_Config *self, v2l_LdapConn *curr_conn)
00248 {
00249 v2l_LdapEvt *evt_res;
00250 int rc;
00251
00252 evt_res = (v2l_LdapEvt *) malloc (sizeof (v2l_LdapEvt));
00253
00254 if (evt_res == NULL)
00255 {
00256 LOG_ERROR_MEM;
00257 return NULL;
00258 }
00259
00260 evt_res->ld = curr_conn->ld;
00261
00262 rc = _v2l_ldap_search (curr_conn->entry, self->suffix, NULL, 1, evt_res);
00263
00264 if (rc != LDAP_SUCCESS)
00265 {
00266 log_error (ZONE, "LDAP error attempting to retrieve user info: %s",
00267 ldap_err2string (rc));
00268 free (evt_res);
00269 return NULL;
00270 }
00271
00272 _v2l_ldap_sync (evt_res);
00273
00274 if (ldap_count_entries (evt_res->ld, evt_res->result) != 1)
00275 {
00276 log_warn (ZONE, "Multiple users with the same dn?");
00277 free (evt_res);
00278 return NULL;
00279 }
00280
00281 return evt_res;
00282 }
00283
00284 int
00285 v2l_request_record (v2l_Config *self, v2l_LdapConn *curr_conn,
00286 v2l_LdapRequest *req)
00287 {
00288 LDAPMod **attrs;
00289 int i, nbmod, ret;
00290 v2l_LdapRequest *cur_req;
00291 v2l_LdapEvt *evt_res;
00292
00293 if (req == NULL)
00294 {
00295 log_warn (ZONE, "LDAP request is NULL? I cannot record anything");
00296 return 1;
00297 }
00298
00299 nbmod = _v2l_count_attrs (req);
00300
00301 attrs = (LDAPMod **) malloc ((nbmod + 1) * sizeof (LDAPMod *));
00302
00303 if (attrs == NULL)
00304 {
00305 LOG_ERROR_MEM;
00306 return 0;
00307 }
00308
00309
00310 evt_res = (v2l_LdapEvt *) malloc (sizeof (v2l_LdapEvt));
00311
00312 if (evt_res == NULL)
00313 {
00314 LOG_ERROR_MEM;
00315 free (attrs);
00316 return 0;
00317 }
00318
00319 for (i = 0; i < nbmod; i++)
00320 {
00321 attrs[i] = (LDAPMod *) malloc (sizeof (LDAPMod));
00322
00323 if (attrs[i] == NULL)
00324 {
00325 while (--i >= 0)
00326 {
00327 free (attrs[i]);
00328 }
00329
00330 LOG_ERROR_MEM;
00331 free (attrs);
00332 free (evt_res);
00333 return 0;
00334 }
00335 }
00336
00337 for (cur_req = req, i = 0; i < nbmod; cur_req = cur_req->next, i++)
00338 {
00339 memcpy (attrs[i], cur_req->attr, sizeof (LDAPMod));
00340 log_debug (ZONE, "Element \"%s\" (%d) in the LDAP request: %s",
00341 attrs[i]->mod_type, i, attrs[i]->mod_values[0]);
00342 }
00343
00344 attrs[nbmod] = NULL;
00345
00346 log_debug (ZONE, "LDAP attempting to modify \"%s\" with dn \"%s\"",
00347 curr_conn->user, curr_conn->binddn);
00348
00349 evt_res->ld = curr_conn->ld;
00350 evt_res->rc = _v2l_ldap_modify (curr_conn->binddn, attrs, evt_res);
00351 ret = evt_res->rc == LDAP_SUCCESS;
00352
00353 if (!ret)
00354 {
00355 log_error (ZONE, "LDAP error attempting to modify user info: %s",
00356 ldap_err2string (evt_res->rc));
00357 }
00358 else
00359 {
00360 _v2l_ldap_sync (evt_res);
00361 }
00362
00363 ldap_msgfree (evt_res->result);
00364 free (evt_res);
00365
00366 for (cur_req = req, i = 0; i < nbmod; cur_req = cur_req->next, i++)
00367 {
00368 free (attrs[i]);
00369 free (cur_req->attr->mod_values[0]);
00370 free (cur_req->attr->mod_values);
00371 free (cur_req->attr);
00372 free (cur_req);
00373 }
00374
00375 free (attrs);
00376
00377 return ret;
00378 }
00379
00380 v2l_LdapRequest *
00381 v2l_add_attr_str (v2l_LdapRequest *req, const char *attr, const char *str)
00382 {
00383 LDAPMod *mod;
00384
00385 mod = (LDAPMod *) malloc (sizeof (LDAPMod));
00386
00387 if (mod == NULL)
00388 {
00389 return NULL;
00390 }
00391
00392 mod->mod_op = LDAP_MOD_REPLACE;
00393 mod->mod_type = (char *) attr;
00394
00395 mod->mod_values = (char **) malloc (2 * sizeof (char *));
00396
00397 if (mod->mod_values == NULL)
00398 {
00399 free (mod);
00400 return NULL;
00401 }
00402
00403 mod->mod_values[0] = (char *) malloc (strlen (str) + 1);
00404
00405 if (mod->mod_values[0] == NULL)
00406 {
00407 free (mod->mod_values);
00408 free (mod);
00409 return NULL;
00410 }
00411
00412 memcpy (mod->mod_values[0], str, strlen (str) + 1);
00413 mod->mod_values[1] = NULL;
00414
00415 return _v2l_add_attr (req, mod);
00416 }
00417
00418 void
00419 v2l_ldap_for_all_attrs (v2l_AttrValueFunction value_func,
00420 v2l_AttrMatchFunction match_func, void *pointer, v2l_LdapEvt *evt_res)
00421 {
00422 LDAPMessage *current_result;
00423 BerElement *ber;
00424 char *current_attr, **vals;
00425 void *shrdata;
00426
00427 current_result = ldap_first_entry (evt_res->ld, evt_res->result);
00428 current_attr = ldap_first_attribute (evt_res->ld, current_result, &ber);
00429
00430
00431 for (;
00432 current_attr != NULL;
00433 current_attr = ldap_next_attribute (evt_res->ld, current_result, ber))
00434 {
00435
00436 if (match_func (current_attr, &shrdata))
00437 {
00438 vals = ldap_get_values (evt_res->ld, current_result, current_attr);
00439 value_func (current_attr, (const char **) vals, pointer, shrdata);
00440
00441 if (vals != NULL)
00442 {
00443 ldap_value_free (vals);
00444 }
00445 }
00446
00447 ldap_memfree (current_attr);
00448 }
00449
00450 if (ber != NULL)
00451 {
00452 ber_free (ber, 0);
00453 }
00454
00455
00456 ldap_memfree (current_attr);
00457 ldap_msgfree (evt_res->result);
00458 }
00459
00460
00461
00462 static v2l_LdapConn *
00463 _v2l_create_conn (char *host, int port, const char *binddn, const char *user,
00464 const char *passwd, int expire)
00465 {
00466 LDAP *ld;
00467 v2l_LdapConn *ldap_conn;
00468 int version;
00469 int rc;
00470 pool poolref;
00471
00472 ld = ldap_init (host, port);
00473
00474 if (ld == NULL)
00475 {
00476 log_error (ZONE, "Unable to init LDAP");
00477 return NULL;
00478 }
00479
00480
00481 version = LDAP_VERSION3;
00482
00483
00484 ldap_set_option (ld, LDAP_OPT_PROTOCOL_VERSION, &version);
00485 rc = ldap_simple_bind_s (ld, binddn, passwd);
00486
00487 if (rc != LDAP_SUCCESS)
00488 {
00489 log_error (ZONE,
00490 "LDAP simple bind error : %s", ldap_err2string (rc));
00491 return NULL;
00492 }
00493
00494 poolref = pool_new ();
00495
00496 if (poolref == NULL)
00497 {
00498 LOG_ERROR_MEM;
00499 ldap_unbind_s (ld);
00500 return NULL;
00501 }
00502
00503 ldap_conn = (v2l_LdapConn *) pmalloc (poolref, sizeof (v2l_LdapConn));
00504
00505 if (ldap_conn == NULL)
00506 {
00507 LOG_ERROR_MEM;
00508 ldap_unbind_s (ld);
00509 pool_free (poolref);
00510 return NULL;
00511 }
00512
00513 ldap_conn->poolref = poolref;
00514 ldap_conn->ld = ld;
00515
00516 ldap_conn->binddn = (char *) pmalloc (ldap_conn->poolref,
00517 strlen (binddn) + 1);
00518
00519 if (ldap_conn->binddn == NULL)
00520 {
00521 LOG_ERROR_MEM;
00522 ldap_unbind_s (ld);
00523 pool_free (poolref);
00524 return NULL;
00525 }
00526
00527 strcpy (ldap_conn->binddn, binddn);
00528
00529 ldap_conn->entry = (char *) pmalloc (ldap_conn->poolref, strlen (binddn) + 1);
00530
00531 if (ldap_conn->entry == NULL)
00532 {
00533 LOG_ERROR_MEM;
00534 ldap_unbind_s (ld);
00535 pool_free (poolref);
00536 return NULL;
00537 }
00538
00539 strcpy (ldap_conn->entry, binddn);
00540 strtok (ldap_conn->entry, ", ");
00541
00542 ldap_conn->user = (char *) pmalloc (ldap_conn->poolref, strlen (user) + 1);
00543
00544 if (ldap_conn->user == NULL)
00545 {
00546 LOG_ERROR_MEM;
00547 ldap_unbind_s (ld);
00548 pool_free (poolref);
00549 return NULL;
00550 }
00551
00552 strcpy (ldap_conn->user, user);
00553
00554 ldap_conn->creation_time = time (NULL);
00555
00556 if (expire == 1)
00557 {
00558 _v2l_add_conn (ldap_conn);
00559 }
00560
00561 return ldap_conn;
00562 }
00563
00564 static char *
00565 _v2l_ldap_filter (v2l_Config *self, const char *user)
00566 {
00567 char *filter;
00568
00569 if (self->filter == NULL || user == NULL)
00570 {
00571 log_error (ZONE, "Attempt to make a NULL filter");
00572 return NULL;
00573 }
00574
00575 filter = (char *) malloc (strlen (self->filter) + strlen (user));
00576
00577 if (filter == NULL)
00578 {
00579 LOG_ERROR_MEM;
00580 return NULL;
00581 }
00582
00583 sprintf (filter, self->filter, user);
00584
00585 return filter;
00586 }
00587
00588 static int
00589 _v2l_ldap_get_credentials (v2l_Config *self, const char *user, char **passwd,
00590 char **cn)
00591 {
00592 LDAPMessage *e;
00593 v2l_LdapEvt *evt_res;
00594 char *filter, **vpw, **vcn;
00595 char *attrs[3] = {"userPassword", "cn", NULL};
00596
00597 evt_res = (v2l_LdapEvt *) malloc (sizeof (v2l_LdapEvt));
00598
00599 if (evt_res == NULL)
00600 {
00601 LOG_ERROR_MEM;
00602 return 0;
00603 }
00604
00605 filter = _v2l_ldap_filter (self, user);
00606
00607 evt_res->ld = self->master_conn->ld;
00608 evt_res->rc = _v2l_ldap_search (filter, self->suffix, attrs, 0, evt_res);
00609
00610 free (filter);
00611
00612 if (evt_res->rc != LDAP_SUCCESS)
00613 {
00614 log_error (ZONE,
00615 "LDAP error attempting to retrieve \"%s\"'s password: %s",
00616 user, ldap_err2string (evt_res->rc));
00617 free (evt_res);
00618 return 0;
00619 }
00620
00621 _v2l_ldap_sync (evt_res);
00622
00623 *passwd = NULL;
00624 *cn = NULL;
00625
00626 if (ldap_count_entries (evt_res->ld, evt_res->result) == 1)
00627 {
00628 e = ldap_first_entry (evt_res->ld, evt_res->result);
00629
00630 vpw = ldap_get_values (evt_res->ld, e, "userPassword");
00631
00632 if (vpw == NULL)
00633 {
00634 log_debug (ZONE, "User has no password!");
00635 ldap_msgfree (evt_res->result);
00636 free (evt_res);
00637 return 0;
00638 }
00639
00640 vcn = ldap_get_values (evt_res->ld, e, "cn");
00641
00642 if (vcn == NULL)
00643 {
00644 log_debug (ZONE, "LDAP general failure!!");
00645 ldap_value_free (vpw);
00646 ldap_msgfree (evt_res->result);
00647 free (evt_res);
00648 return 0;
00649 }
00650
00651 *passwd = (char *) malloc (strlen (vpw[0]) + 1);
00652
00653 if (*passwd == NULL)
00654 {
00655 LOG_ERROR_MEM;
00656 ldap_value_free (vpw);
00657 ldap_value_free (vcn);
00658 ldap_msgfree (evt_res->result);
00659 free (evt_res);
00660 return 0;
00661 }
00662
00663 strcpy (*passwd, vpw[0]);
00664 ldap_value_free (vpw);
00665
00666 *cn = (char *) malloc (strlen (vcn[0]) + 1);
00667
00668 if (*cn == NULL)
00669 {
00670 LOG_ERROR_MEM;
00671 free (*passwd);
00672 ldap_value_free (vpw);
00673 ldap_value_free (vcn);
00674 ldap_msgfree (evt_res->result);
00675 free (evt_res);
00676 return 0;
00677 }
00678
00679 strcpy (*cn, vcn[0]);
00680 ldap_value_free (vcn);
00681 }
00682
00683 ldap_msgfree (evt_res->result);
00684 free (evt_res);
00685
00686 return *passwd != NULL && *cn != NULL;
00687 }
00688
00689 static int
00690 _v2l_ldap_modify (char *dn, LDAPMod **attrs, v2l_LdapEvt *evt_res)
00691 {
00692 return ldap_modify_ext (evt_res->ld, dn, attrs, NULL, NULL,
00693 &(evt_res->msgid));
00694 }
00695
00696 static int
00697 _v2l_ldap_search (char *dn, char *suffix, char **attrs, int subtree,
00698 v2l_LdapEvt *evt_res)
00699 {
00700 int scope;
00701
00702 scope = subtree ? LDAP_SCOPE_SUBTREE : LDAP_SCOPE_ONELEVEL;
00703
00704 return ldap_search_ext (evt_res->ld, suffix, scope,
00705 dn, attrs, 0, NULL, NULL, NULL, LDAP_NO_LIMIT,
00706 &(evt_res->msgid));
00707 }
00708
00709 static void
00710 _v2l_ldap_sync (v2l_LdapEvt *evt_res)
00711 {
00712 #ifndef _V2L_JABBER2
00713 pth_event_t evt;
00714
00715 evt = pth_event (PTH_EVENT_FUNC, &_v2l_ldap_wait_callback,
00716 (void *) evt_res, pth_time (V2L_POLL_INTERVAL, 0));
00717 pth_wait (evt);
00718 #else
00719 pthread_t thr;
00720 int rc;
00721
00722 rc = pthread_create (&thr, NULL, _v2l_ldap_wait_callback_g, (void *) evt_res);
00723
00724 if (rc != 0)
00725 {
00726 log_error (ZONE, "Thread create failed: %d", rc);
00727 return;
00728 }
00729
00730 pthread_join (thr, NULL);
00731 #endif
00732 }
00733
00735 static int
00736 _v2l_count_attrs (v2l_LdapRequest *req)
00737 {
00738 int nbmod;
00739
00740 for (nbmod = 0; req != NULL; req = req->next, nbmod++);
00741
00742 return nbmod;
00743 }
00744
00745 static v2l_LdapRequest *
00746 _v2l_add_attr (v2l_LdapRequest *req, LDAPMod *attr)
00747 {
00748 v2l_LdapRequest *new_req, *ptr;
00749
00750 if (attr == NULL)
00751 {
00752 log_warn (ZONE, "LDAP attribute is NULL? I cannot add anything");
00753 return NULL;
00754 }
00755
00756 new_req = (v2l_LdapRequest *) malloc (sizeof (v2l_LdapRequest));
00757
00758 if (new_req == NULL)
00759 {
00760 LOG_ERROR_MEM;
00761 return NULL;
00762 }
00763
00764 new_req->attr = attr;
00765 new_req->next = NULL;
00766
00767 if (req == NULL)
00768 {
00769 req = new_req;
00770 }
00771 else
00772 {
00773 for (ptr = req; ptr->next != NULL; ptr = ptr->next);
00774 ptr->next = new_req;
00775 }
00776
00777 return req;
00778 }
00779
00780 static int
00781 _v2l_ldap_wait_callback (void *arg)
00782 {
00783 v2l_LdapEvt *evt_res = (v2l_LdapEvt *) arg;
00784 LDAPMessage *result;
00785 int rc;
00786
00787 rc = ldap_result (evt_res->ld, evt_res->msgid, 1, NULL, &result);
00788
00789 if (rc == -1)
00790 {
00791 log_error (ZONE, "LDAP result error %s",
00792 ldap_err2string (rc));
00793 evt_res->result = NULL;
00794 evt_res->rc = -1;
00795 return 1;
00796 }
00797
00798 if ((rc == LDAP_RES_ADD)
00799 || (rc == LDAP_RES_MODIFY)
00800 || (rc == LDAP_RES_SEARCH_RESULT)
00801 || (rc == LDAP_RES_SEARCH_ENTRY)
00802 || (rc == LDAP_RES_DELETE))
00803 {
00804 evt_res->result = result;
00805 evt_res->rc = rc;
00806 return 1;
00807 }
00808
00809 return 0;
00810 }
00811
00812 #ifdef _V2L_JABBER2
00813 static void *
00814 _v2l_ldap_wait_callback_g (void *arg)
00815 {
00816 while (!_v2l_ldap_wait_callback (arg))
00817 {
00818 sleep (V2L_POLL_INTERVAL);
00819 }
00820
00821 return NULL;
00822 }
00823 #endif
00824
00825 static void
00826 _v2l_free_walker (xht h, const char *key, void *val, void *arg)
00827 {
00828 _v2l_free_conn (h, key, val);
00829 }
00830
00831 static void
00832 _v2l_free_conn (xht h, const char *user, void *val)
00833 {
00834 v2l_LdapConn *temp_conn = (v2l_LdapConn *) val;
00835
00836 log_debug (ZONE, "Freeing LDAP connection for user \"%s\"", user);
00837
00838 xhash_zap (h, user);
00839 ldap_unbind_s (temp_conn->ld);
00840 pool_free (temp_conn->poolref);
00841 }
00842
00843 static void
00844 _v2l_free_expired_walker (xht h, const char *key, void *val, void *arg)
00845 {
00846 v2l_LdapConn *temp_conn = (v2l_LdapConn *) val;
00847
00848
00849 if ((time (NULL) - temp_conn->creation_time) > (time_t) V2L_CONN_LIFETIME)
00850 {
00851 _v2l_free_conn (h, key, val);
00852 }
00853 }
00854
00855 static void *
00856 _v2l_purge_conn_callback (void *arg)
00857 {
00858 log_debug (ZONE, "Checking connections lifetime");
00859
00860 while (1)
00861 {
00862
00863 if (V2L_CONN_LIST != NULL)
00864 {
00865 xhash_walk (V2L_CONN_LIST, _v2l_free_expired_walker, NULL);
00866 }
00867 #ifndef _V2L_JABBER2
00868 pth_sleep (V2L_CONN_LIFETIME);
00869 #else
00870 sleep (V2L_CONN_LIFETIME);
00871 #endif
00872 }
00873
00874 return NULL;
00875 }
00876
00877 static void
00878 _v2l_add_conn (v2l_LdapConn *ldap_conn)
00879 {
00880 #ifndef _V2L_JABBER2
00881 pth_attr_t attr;
00882 #else
00883 pthread_t thr;
00884 pthread_attr_t attr;
00885 int rc;
00886 #endif
00887
00888 if (V2L_CONN_LIST == NULL)
00889 {
00890
00891 log_debug (ZONE, "V2L_CONN_LIST hashtable is not initialized yet");
00892
00893 V2L_CONN_LIST = xhash_new (509);
00894
00895
00896 #ifndef _V2L_JABBER2
00897 attr = pth_attr_new ();
00898 pth_attr_set (attr, PTH_ATTR_JOINABLE, FALSE);
00899 pth_spawn (attr, _v2l_purge_conn_callback, NULL);
00900 pth_attr_destroy (attr);
00901 #else
00902 pthread_attr_init (&attr);
00903 pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED);
00904
00905 rc = pthread_create (&thr, &attr, _v2l_purge_conn_callback, NULL);
00906 pthread_attr_destroy (&attr);
00907
00908 if (rc != 0)
00909 {
00910 log_error (ZONE, "Thread create failed: %d", rc);
00911 }
00912 #endif
00913 }
00914
00915 xhash_put (V2L_CONN_LIST, ldap_conn->user, (void *) ldap_conn);
00916 }