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