1/* $OpenLDAP$ */
2/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
3 *
4 * Copyright 2000-2011 The OpenLDAP Foundation.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted only as authorized by the OpenLDAP
9 * Public License.
10 *
11 * A copy of this license is available in the file LICENSE in the
12 * top-level directory of the distribution or, alternatively, at
13 * <http://www.OpenLDAP.org/license.html>.
14 */
15/* ACKNOWLEDGEMENT:
16 * This work was initially developed by Pierangelo Masarati for
17 * inclusion in OpenLDAP Software.
18 */
19
20#include <portable.h>
21
22#include "rewrite-int.h"
23
24/*
25 * Compares two cookies
26 */
27static int
28rewrite_cookie_cmp(
29                const void *c1,
30                const void *c2
31)
32{
33	const struct rewrite_session *s1, *s2;
34
35	s1 = ( const struct rewrite_session * )c1;
36	s2 = ( const struct rewrite_session * )c2;
37
38	assert( s1 != NULL );
39	assert( s2 != NULL );
40	assert( s1->ls_cookie != NULL );
41	assert( s2->ls_cookie != NULL );
42
43        return ( ( s1->ls_cookie < s2->ls_cookie ) ? -1 :
44			( ( s1->ls_cookie > s2->ls_cookie ) ? 1 : 0 ) );
45}
46
47/*
48 * Duplicate cookies?
49 */
50static int
51rewrite_cookie_dup(
52                void *c1,
53                void *c2
54)
55{
56	struct rewrite_session *s1, *s2;
57
58	s1 = ( struct rewrite_session * )c1;
59	s2 = ( struct rewrite_session * )c2;
60
61	assert( s1 != NULL );
62	assert( s2 != NULL );
63	assert( s1->ls_cookie != NULL );
64	assert( s2->ls_cookie != NULL );
65
66	assert( s1->ls_cookie != s2->ls_cookie );
67
68        return ( ( s1->ls_cookie == s2->ls_cookie ) ? -1 : 0 );
69}
70
71/*
72 * Inits a session
73 */
74struct rewrite_session *
75rewrite_session_init(
76		struct rewrite_info *info,
77		const void *cookie
78)
79{
80	struct rewrite_session 	*session, tmp;
81	int			rc;
82
83	assert( info != NULL );
84	assert( cookie != NULL );
85
86#ifdef USE_REWRITE_LDAP_PVT_THREADS
87	ldap_pvt_thread_rdwr_wlock( &info->li_cookies_mutex );
88#endif /* USE_REWRITE_LDAP_PVT_THREADS */
89
90	tmp.ls_cookie = ( void * )cookie;
91	session = ( struct rewrite_session * )avl_find( info->li_cookies,
92			( caddr_t )&tmp, rewrite_cookie_cmp );
93	if ( session ) {
94		session->ls_count++;
95#ifdef USE_REWRITE_LDAP_PVT_THREADS
96		ldap_pvt_thread_rdwr_wunlock( &info->li_cookies_mutex );
97#endif /* USE_REWRITE_LDAP_PVT_THREADS */
98		return session;
99	}
100
101	session = calloc( sizeof( struct rewrite_session ), 1 );
102	if ( session == NULL ) {
103		return NULL;
104	}
105	session->ls_cookie = ( void * )cookie;
106	session->ls_count = 1;
107
108#ifdef USE_REWRITE_LDAP_PVT_THREADS
109	if ( ldap_pvt_thread_mutex_init( &session->ls_mutex ) ) {
110		free( session );
111		return NULL;
112	}
113	if ( ldap_pvt_thread_rdwr_init( &session->ls_vars_mutex ) ) {
114		ldap_pvt_thread_mutex_destroy( &session->ls_mutex );
115		free( session );
116		return NULL;
117	}
118#endif /* USE_REWRITE_LDAP_PVT_THREADS */
119
120	rc = avl_insert( &info->li_cookies, ( caddr_t )session,
121			rewrite_cookie_cmp, rewrite_cookie_dup );
122	info->li_num_cookies++;
123
124#ifdef USE_REWRITE_LDAP_PVT_THREADS
125        ldap_pvt_thread_rdwr_wunlock( &info->li_cookies_mutex );
126#endif /* USE_REWRITE_LDAP_PVT_THREADS */
127
128	if ( rc != 0 ) {
129#ifdef USE_REWRITE_LDAP_PVT_THREADS
130		ldap_pvt_thread_rdwr_destroy( &session->ls_vars_mutex );
131		ldap_pvt_thread_mutex_destroy( &session->ls_mutex );
132#endif /* USE_REWRITE_LDAP_PVT_THREADS */
133
134		free( session );
135		return NULL;
136	}
137
138	return session;
139}
140
141/*
142 * Fetches a session
143 */
144struct rewrite_session *
145rewrite_session_find(
146		struct rewrite_info *info,
147		const void *cookie
148)
149{
150	struct rewrite_session *session, tmp;
151
152	assert( info != NULL );
153	assert( cookie != NULL );
154
155	tmp.ls_cookie = ( void * )cookie;
156#ifdef USE_REWRITE_LDAP_PVT_THREADS
157	ldap_pvt_thread_rdwr_rlock( &info->li_cookies_mutex );
158#endif /* USE_REWRITE_LDAP_PVT_THREADS */
159	session = ( struct rewrite_session * )avl_find( info->li_cookies,
160			( caddr_t )&tmp, rewrite_cookie_cmp );
161#ifdef USE_REWRITE_LDAP_PVT_THREADS
162	if ( session ) {
163		ldap_pvt_thread_mutex_lock( &session->ls_mutex );
164	}
165	ldap_pvt_thread_rdwr_runlock( &info->li_cookies_mutex );
166#endif /* USE_REWRITE_LDAP_PVT_THREADS */
167
168	return session;
169}
170
171/*
172 * Returns a session
173 */
174void
175rewrite_session_return(
176		struct rewrite_info *info,
177		struct rewrite_session *session
178)
179{
180	assert( session != NULL );
181	ldap_pvt_thread_mutex_unlock( &session->ls_mutex );
182}
183
184/*
185 * Defines and inits a var with session scope
186 */
187int
188rewrite_session_var_set_f(
189		struct rewrite_info *info,
190		const void *cookie,
191		const char *name,
192		const char *value,
193		int flags
194)
195{
196	struct rewrite_session *session;
197	struct rewrite_var *var;
198
199	assert( info != NULL );
200	assert( cookie != NULL );
201	assert( name != NULL );
202	assert( value != NULL );
203
204	session = rewrite_session_find( info, cookie );
205	if ( session == NULL ) {
206		session = rewrite_session_init( info, cookie );
207		if ( session == NULL ) {
208			return REWRITE_ERR;
209		}
210
211#ifdef USE_REWRITE_LDAP_PVT_THREADS
212		ldap_pvt_thread_mutex_lock( &session->ls_mutex );
213#endif /* USE_REWRITE_LDAP_PVT_THREADS */
214	}
215
216#ifdef USE_REWRITE_LDAP_PVT_THREADS
217	ldap_pvt_thread_rdwr_wlock( &session->ls_vars_mutex );
218#endif /* USE_REWRITE_LDAP_PVT_THREADS */
219
220	var = rewrite_var_find( session->ls_vars, name );
221	if ( var != NULL ) {
222		assert( var->lv_value.bv_val != NULL );
223
224		(void)rewrite_var_replace( var, value, flags );
225
226	} else {
227		var = rewrite_var_insert_f( &session->ls_vars, name, value, flags );
228		if ( var == NULL ) {
229#ifdef USE_REWRITE_LDAP_PVT_THREADS
230			ldap_pvt_thread_rdwr_wunlock( &session->ls_vars_mutex );
231#endif /* USE_REWRITE_LDAP_PVT_THREADS */
232			rewrite_session_return( info, session );
233			return REWRITE_ERR;
234		}
235	}
236
237#ifdef USE_REWRITE_LDAP_PVT_THREADS
238	ldap_pvt_thread_rdwr_wunlock( &session->ls_vars_mutex );
239#endif /* USE_REWRITE_LDAP_PVT_THREADS */
240
241	rewrite_session_return( info, session );
242
243	return REWRITE_SUCCESS;
244}
245
246/*
247 * Gets a var with session scope
248 */
249int
250rewrite_session_var_get(
251		struct rewrite_info *info,
252		const void *cookie,
253		const char *name,
254		struct berval *value
255)
256{
257	struct rewrite_session *session;
258	struct rewrite_var *var;
259	int rc = REWRITE_SUCCESS;
260
261	assert( info != NULL );
262	assert( cookie != NULL );
263	assert( name != NULL );
264	assert( value != NULL );
265
266	value->bv_val = NULL;
267	value->bv_len = 0;
268
269	if ( cookie == NULL ) {
270		return REWRITE_ERR;
271	}
272
273	session = rewrite_session_find( info, cookie );
274	if ( session == NULL ) {
275		return REWRITE_ERR;
276	}
277
278#ifdef USE_REWRITE_LDAP_PVT_THREADS
279	ldap_pvt_thread_rdwr_rlock( &session->ls_vars_mutex );
280#endif /* USE_REWRITE_LDAP_PVT_THREADS */
281
282	var = rewrite_var_find( session->ls_vars, name );
283	if ( var != NULL ) {
284		value->bv_val = strdup( var->lv_value.bv_val );
285		value->bv_len = var->lv_value.bv_len;
286	}
287
288	if ( var == NULL || value->bv_val == NULL ) {
289		rc = REWRITE_ERR;
290	}
291
292#ifdef USE_REWRITE_LDAP_PVT_THREADS
293        ldap_pvt_thread_rdwr_runlock( &session->ls_vars_mutex );
294#endif /* USE_REWRITE_LDAP_PVT_THREADS */
295
296	rewrite_session_return( info, session );
297
298	return rc;
299}
300
301static void
302rewrite_session_clean( void *v_session )
303{
304	struct rewrite_session	*session = (struct rewrite_session *)v_session;
305
306#ifdef USE_REWRITE_LDAP_PVT_THREADS
307	ldap_pvt_thread_rdwr_wlock( &session->ls_vars_mutex );
308#endif /* USE_REWRITE_LDAP_PVT_THREADS */
309
310	rewrite_var_delete( session->ls_vars );
311
312#ifdef USE_REWRITE_LDAP_PVT_THREADS
313	ldap_pvt_thread_rdwr_wunlock( &session->ls_vars_mutex );
314	ldap_pvt_thread_rdwr_destroy( &session->ls_vars_mutex );
315	ldap_pvt_thread_mutex_unlock( &session->ls_mutex );
316	ldap_pvt_thread_mutex_destroy( &session->ls_mutex );
317#endif /* USE_REWRITE_LDAP_PVT_THREADS */
318}
319
320static void
321rewrite_session_free( void *v_session )
322{
323	struct rewrite_session	*session = (struct rewrite_session *)v_session;
324
325	ldap_pvt_thread_mutex_lock( &session->ls_mutex );
326	rewrite_session_clean( v_session );
327	free( v_session );
328}
329
330/*
331 * Deletes a session
332 */
333int
334rewrite_session_delete(
335		struct rewrite_info *info,
336		const void *cookie
337)
338{
339	struct rewrite_session *session, tmp = { 0 };
340
341	assert( info != NULL );
342	assert( cookie != NULL );
343
344	session = rewrite_session_find( info, cookie );
345
346	if ( session == NULL ) {
347		return REWRITE_SUCCESS;
348	}
349
350	if ( --session->ls_count > 0 ) {
351		rewrite_session_return( info, session );
352		return REWRITE_SUCCESS;
353	}
354
355	rewrite_session_clean( session );
356
357#ifdef USE_REWRITE_LDAP_PVT_THREADS
358	ldap_pvt_thread_rdwr_wlock( &info->li_cookies_mutex );
359#endif /* USE_REWRITE_LDAP_PVT_THREADS */
360
361	assert( info->li_num_cookies > 0 );
362	info->li_num_cookies--;
363
364	/*
365	 * There is nothing to delete in the return value
366	 */
367	tmp.ls_cookie = ( void * )cookie;
368	avl_delete( &info->li_cookies, ( caddr_t )&tmp, rewrite_cookie_cmp );
369
370	free( session );
371
372#ifdef USE_REWRITE_LDAP_PVT_THREADS
373	ldap_pvt_thread_rdwr_wunlock( &info->li_cookies_mutex );
374#endif /* USE_REWRITE_LDAP_PVT_THREADS */
375
376	return REWRITE_SUCCESS;
377}
378
379/*
380 * Destroys the cookie tree
381 */
382int
383rewrite_session_destroy(
384		struct rewrite_info *info
385)
386{
387	int count;
388
389	assert( info != NULL );
390
391#ifdef USE_REWRITE_LDAP_PVT_THREADS
392	ldap_pvt_thread_rdwr_wlock( &info->li_cookies_mutex );
393#endif /* USE_REWRITE_LDAP_PVT_THREADS */
394
395	/*
396	 * Should call per-session destruction routine ...
397	 */
398
399	count = avl_free( info->li_cookies, rewrite_session_free );
400	info->li_cookies = NULL;
401
402#if 0
403	fprintf( stderr, "count = %d; num_cookies = %d\n",
404			count, info->li_num_cookies );
405#endif
406
407	assert( count == info->li_num_cookies );
408	info->li_num_cookies = 0;
409
410#ifdef USE_REWRITE_LDAP_PVT_THREADS
411	ldap_pvt_thread_rdwr_wunlock( &info->li_cookies_mutex );
412#endif /* USE_REWRITE_LDAP_PVT_THREADS */
413
414	return REWRITE_SUCCESS;
415}
416
417