GIT (commit) target in Makefile
[vcard2ldap.git] / src / v2l_conn.c
blob22d281f3256d6d1a23835580dfff0d9840e10052
1 /*
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.
18 * connection management : if an user has no connection, a new one is created
19 * and the binding is done with its dn and userPassword.
20 * then the connection is added in the local hashtable
21 * a monitor thread checks the connections which are older than 10s and
22 * deletes them. that mainly permits to make the authentication
23 * process (4 requests) with the same LDAP connection.
26 #include <stdlib.h>
27 #include <stdio.h>
28 #include <time.h>
29 #include <ldap.h>
30 #include <jabberd.h>
31 #include <v2l_conn.h>
32 #include <v2l_config.h>
34 /* linked list of all currently active LDAP connections */
35 static xht global_conn_list = NULL;
37 /* unbind and free the connection owned by user */
38 static void v2l_free_conn (xht h, const char *user, void *val);
39 /* add a connection to the hashtable */
40 static void v2l_add_conn (v2l_LdapConn * ldap_conn);
41 /* walker function used to unbind and free all the LDAP connections */
42 static void v2l_free_callback (xht h, const char *key, void *val,
43 void *arg);
44 /* walker function used to unbind and free an expired connection */
45 static void v2l_free_expired (xht h, const char *key, void *val,
46 void *arg);
47 /* periodic function which expunge expired functions */
48 static void v2l_check_func (void *arg);
50 v2l_LdapConn *
51 v2l_create_conn (char *host, int port, const char *binddn,
52 const char *user, const char *passwd, int add_in_list)
54 LDAP *ld;
55 v2l_LdapConn *ldap_conn;
56 int version; /* LDAP protocol version */
57 int rc;
58 char *tmp_str, *ptr;
59 pool p;
61 if ((ld = ldap_init (host, port)) == NULL)
63 log_error (ZONE, "[v2l_create_conn] unable to init LDAP");
64 return NULL;
67 /* Set the LDAP protocol version supported by the client
68 * to 3. (By default, this is set to 2. SASL authentication
69 * is part of version 3 of the LDAP protocol.) */
70 version = LDAP_VERSION3;
71 ldap_set_option (ld, LDAP_OPT_PROTOCOL_VERSION, &version);
73 /* Bind to the LDAP server. */
75 if ((rc = ldap_simple_bind_s (ld, binddn, passwd)) != LDAP_SUCCESS)
77 log_error (ZONE,
78 "[v2l_create_conn] error : %s", ldap_err2string (rc));
79 return NULL;
82 /* Add it in the main list */
83 p = pool_new ();
84 ldap_conn = pmalloc (p, sizeof (v2l_LdapConn));
85 ldap_conn->p = p;
86 ldap_conn->ld = ld;
88 ldap_conn->binddn =
89 pmalloc (ldap_conn->p, sizeof (char) * (strlen (binddn) + 1));
90 strcpy (ldap_conn->binddn, binddn);
92 tmp_str = (char *) malloc (sizeof (char) * (strlen (binddn) + 1));
93 strcpy (tmp_str, binddn);
94 ptr = strtok (tmp_str, ", ");
96 ldap_conn->entry =
97 pmalloc (ldap_conn->p, sizeof (char) * (strlen (tmp_str) + 1));
98 strcpy (ldap_conn->entry, tmp_str);
100 ldap_conn->user =
101 pmalloc (ldap_conn->p, sizeof (char) * (strlen (user) + 1));
102 strcpy (ldap_conn->user, user);
104 ldap_conn->creation_time = time (NULL);
105 ldap_conn->exists = 1;
107 if (add_in_list == 1)
108 v2l_add_conn (ldap_conn);
110 free (tmp_str);
111 return ldap_conn;
114 int v2l_ldap_wait_result(void *arg)
116 v2l_LdapEvt *evt_res = (v2l_LdapEvt *) arg;
117 LDAPMessage *result;
118 int rc;
120 rc = ldap_result (evt_res->ld, evt_res->msgid, 1, NULL, &result);
122 if (rc == -1)
124 log_error(ZONE, "[v2l_wait_result] result error %d",
125 ldap_err2string(rc));
126 evt_res->result = NULL;
127 evt_res->rc = -1;
128 return 1;
131 if ((rc == LDAP_RES_ADD)
132 || (rc == LDAP_RES_MODIFY)
133 || (rc == LDAP_RES_SEARCH_RESULT)
134 || (rc == LDAP_RES_SEARCH_ENTRY)
135 || (rc == LDAP_RES_DELETE))
137 evt_res->result = result;
138 evt_res->rc = rc;
139 return 1;
142 return 0; /* still waiting */
145 v2l_LdapConn *
146 v2l_get_conn (const char *user)
148 return (v2l_LdapConn *) xhash_get (global_conn_list, user);
151 /* get user password from LDAP */
152 /* caller must free the returned string */
153 char *v2l_ldap_get_passwd(v2l_Config *self, char *user)
155 LDAPMessage *e; /* pointer to LDAP result */
156 v2l_LdapEvt *evt_res;
157 pth_event_t evt;
158 int rc;
159 char *data, *filter, **vals, *attrs[2] = {"userPassword", NULL};
161 /* to wait for the results */
162 evt_res = (v2l_LdapEvt *) malloc(sizeof(v2l_LdapEvt));
164 if (evt_res == NULL)
166 log_error(ZONE, "[v2l_ldap_get_passwd] unable to allocate memory");
167 return NULL;
170 filter = (char *) malloc (sizeof(char)*
171 (strlen(self->uniqattr) + strlen(user) + 2));
173 if (filter == NULL)
175 log_error(ZONE, "[v2l_ldap_get_passwd] unable to allocate memory");
176 free (evt_res);
177 return NULL;
180 sprintf(filter, "%s=%s", self->uniqattr, user);
181 evt_res->ld = self->master_conn->ld;
183 /* Search for the entry. */
184 evt_res->rc = ldap_search_ext(evt_res->ld, self->suffix,
185 LDAP_SCOPE_ONELEVEL, filter, attrs, 0, NULL, NULL, NULL,
186 LDAP_NO_LIMIT, &(evt_res->msgid));
188 free (filter);
190 if (evt_res->rc != LDAP_SUCCESS)
192 log_error(ZONE,
193 "[v2l_ldap_get_passwd] search error : %s", ldap_err2string(rc));
194 free (evt_res);
195 return NULL;
198 /* wait for the operation to be terminated, poll every second */
199 evt = pth_event(PTH_EVENT_FUNC, &v2l_ldap_wait_result, (void *) evt_res,
200 pth_time(1, 0));
201 pth_wait(evt);
203 data = NULL;
205 if (ldap_count_entries(evt_res->ld, evt_res->result) == 1)
207 e = ldap_first_entry(evt_res->ld, evt_res->result);
208 vals = ldap_get_values(evt_res->ld, e, "userPassword");
210 if (vals == NULL)
212 log_debug(ZONE, "[v2l_ldap_get_passwd] user has no password !");
213 data = (char *) malloc(sizeof(char));
215 if (data == NULL)
217 ldap_msgfree(evt_res->result);
218 return NULL;
221 data[0] = 0;
223 else
225 /* build the result set */
226 data = (char *) malloc(sizeof(char) * (strlen(vals[0]) + 1));
228 if (data != NULL)
230 strcpy(data, vals[0]);
233 ldap_value_free(vals);
236 ldap_msgfree(evt_res->result);
239 /* log_debug(ZONE, "[v2l_ldap_get_passwd] user does not exist");
240 * log_warn(ZONE, "[v2l_ldap_get_passwd] more than one user found");
242 free(evt_res);
243 return data;
246 void
247 v2l_free_allconn ()
249 xhash_walk (global_conn_list, v2l_free_callback, NULL);
250 xhash_free (global_conn_list);
253 /***********************/
254 /* public api ends here */
256 static void
257 v2l_free_callback (xht h, const char *key, void *val, void *arg)
259 v2l_free_conn (h, key, val);
262 static void
263 v2l_free_conn (xht h, const char *user, void *val)
265 v2l_LdapConn *temp_conn = (v2l_LdapConn *) val;
267 log_debug (ZONE, "[v2l_free_conn] freeing %s LDAP connection", user);
269 xhash_zap (h, user);
270 ldap_unbind (temp_conn->ld);
271 pool_free (temp_conn->p);
274 static void
275 v2l_free_expired (xht h, const char *key, void *val, void *arg)
277 v2l_LdapConn *temp_conn = (v2l_LdapConn *) val;
279 /* kill connections older than 10s */
280 if ((time (NULL) - temp_conn->creation_time) > (time_t) 50)
282 v2l_free_conn (h, key, val);
286 static void
287 v2l_check_func (void *arg)
289 log_debug (ZONE,
290 "[v2l_check_func] monitor thread enters its main loop");
292 while (1)
294 /* special case : when it is called and xdb_ldap is shutting down
295 * and that global_conn_list has already been deallocated
296 * added by BO, 2001/08/31
298 if (global_conn_list != NULL)
300 xhash_walk (global_conn_list, v2l_free_expired, NULL);
302 pth_sleep (10);
306 static void
307 v2l_add_conn (v2l_LdapConn * ldap_conn)
309 pth_attr_t attr;
311 if (global_conn_list == NULL)
314 log_debug (ZONE, "[v2l_add_conn] no existing hashtable for conns");
316 global_conn_list = xhash_new (509);
318 /* spawn the thread which deletes expired connections */
319 attr = pth_attr_new ();
320 pth_attr_set (attr, PTH_ATTR_JOINABLE, FALSE);
321 pth_spawn (attr, (void *) v2l_check_func, NULL);
322 pth_attr_destroy (attr);
325 xhash_put (global_conn_list, ldap_conn->user, (void *) ldap_conn);