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