]> git.sur5r.net Git - openldap/blob - libraries/librewrite/map.c
Sync with HEAD
[openldap] / libraries / librewrite / map.c
1 /* $OpenLDAP$ */
2 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
3  *
4  * Copyright 2000-2004 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 <stdio.h>
23
24 #ifdef HAVE_PWD_H
25 #include <pwd.h>
26 #endif
27
28 #include "rewrite-int.h"
29 #include "rewrite-map.h"
30
31 struct rewrite_map *
32 rewrite_map_parse(
33                 struct rewrite_info *info,
34                 const char *string,
35                 const char **currpos
36 )
37 {
38         struct rewrite_map *map = NULL;
39         struct rewrite_subst *subst = NULL;
40         char *s, *begin = NULL, *end;
41         const char *p;
42         int l, cnt, mtx = 0, rc = 0;
43
44         assert( info != NULL );
45         assert( string != NULL );
46         assert( currpos != NULL );
47
48         *currpos = NULL;
49
50         /*
51          * Go to the end of the map invocation (the right closing brace)
52          */
53         for ( p = string, cnt = 1; p[ 0 ] != '\0' && cnt > 0; p++ ) {
54                 if ( IS_REWRITE_SUBMATCH_ESCAPE( p[ 0 ] ) ) {
55                         /*
56                          * '%' marks the beginning of a new map
57                          */
58                         if ( p[ 1 ] == '{' ) {
59                                 cnt++;
60                         /*
61                          * '%' followed by a digit may mark the beginning
62                          * of an old map
63                          */
64                         } else if ( isdigit( (unsigned char) p[ 1 ] ) && p[ 2 ] == '{' ) {
65                                 cnt++;
66                                 p++;
67                         }
68
69                         if ( p[ 1 ] != '\0' ) {
70                                 p++;
71                         }
72
73                 } else if ( p[ 0 ] == '}' ) {
74                         cnt--;
75                 }
76         }
77         if ( cnt != 0 ) {
78                 return NULL;
79         }
80         *currpos = p;
81         
82         /*
83          * Copy the map invocation
84          */
85         l = p - string - 1;
86         s = calloc( sizeof( char ), l + 1 );
87         AC_MEMCPY( s, string, l );
88         s[ l ] = 0;
89
90         /*
91          * Isolate the map name (except for variable deref)
92          */
93         switch ( s[ 0 ] ) {
94         case REWRITE_OPERATOR_VARIABLE_GET:
95         case REWRITE_OPERATOR_PARAM_GET:
96                 break;
97
98         default:
99                 begin = strchr( s, '(' );
100                 if ( begin == NULL ) {
101                         rc = -1;
102                         goto cleanup;
103                 }
104                 begin[ 0 ] = '\0';
105                 begin++;
106                 break;
107         }
108
109         /*
110          * Check for special map types
111          */
112         p = s;
113         switch ( p[ 0 ] ) {
114         case REWRITE_OPERATOR_SUBCONTEXT:
115         case REWRITE_OPERATOR_COMMAND:
116         case REWRITE_OPERATOR_VARIABLE_SET:
117         case REWRITE_OPERATOR_VARIABLE_GET:
118         case REWRITE_OPERATOR_PARAM_GET:
119                 p++;
120                 break;
121         }
122
123         /*
124          * Variable set and get may be repeated to indicate session-wide
125          * instead of operation-wide variables
126          */
127         switch ( p[ 0 ] ) {
128         case REWRITE_OPERATOR_VARIABLE_SET:
129         case REWRITE_OPERATOR_VARIABLE_GET:
130                 p++;
131                 break;
132         }
133
134         /*
135          * Variable get token can be appended to variable set to mean store
136          * AND rewrite
137          */
138         if ( p[ 0 ] == REWRITE_OPERATOR_VARIABLE_GET ) {
139                 p++;
140         }
141         
142         /*
143          * Check the syntax of the variable name
144          */
145         if ( !isalpha( (unsigned char) p[ 0 ] ) ) {
146                 rc = -1;
147                 goto cleanup;
148         }
149         for ( p++; p[ 0 ] != '\0'; p++ ) {
150                 if ( !isalnum( (unsigned char) p[ 0 ] ) ) {
151                         rc = -1;
152                         goto cleanup;
153                 }
154         }
155
156         /*
157          * Isolate the argument of the map (except for variable deref)
158          */
159         switch ( s[ 0 ] ) {
160         case REWRITE_OPERATOR_VARIABLE_GET:
161         case REWRITE_OPERATOR_PARAM_GET:
162                 break;
163
164         default:
165                 end = strrchr( begin, ')' );
166                 if ( end == NULL ) {
167                         rc = -1;
168                         goto cleanup;
169                 }
170                 end[ 0 ] = '\0';
171
172                 /*
173                  * Compile the substitution pattern of the map argument
174                  */
175                 subst = rewrite_subst_compile( info, begin );
176                 if ( subst == NULL ) {
177                         rc = -1;
178                         goto cleanup;
179                 }
180                 break;
181         }
182
183         /*
184          * Create the map
185          */
186         map = calloc( sizeof( struct rewrite_map ), 1 );
187         if ( map == NULL ) {
188                 rc = -1;
189                 goto cleanup;
190         }
191         memset( map, 0, sizeof( struct rewrite_map ) );
192         
193 #ifdef USE_REWRITE_LDAP_PVT_THREADS
194         if ( ldap_pvt_thread_mutex_init( &map->lm_mutex ) ) {
195                 rc = -1;
196                 goto cleanup;
197         }
198         ++mtx;
199 #endif /* USE_REWRITE_LDAP_PVT_THREADS */
200                         
201         /*
202          * No subst for variable deref
203          */
204         switch ( s[ 0 ] ) {
205         case REWRITE_OPERATOR_VARIABLE_GET:
206         case REWRITE_OPERATOR_PARAM_GET:
207                 break;
208
209         default:
210                 map->lm_subst = subst;
211                 break;
212         }
213
214         /*
215          * Parses special map types
216          */
217         switch ( s[ 0 ] ) {
218         
219         /*
220          * Subcontext
221          */
222         case REWRITE_OPERATOR_SUBCONTEXT:               /* '>' */
223
224                 /*
225                  * Fetch the rewrite context
226                  * it MUST have been defined previously
227                  */
228                 map->lm_type = REWRITE_MAP_SUBCONTEXT;
229                 map->lm_name = strdup( s + 1 );
230                 map->lm_data = rewrite_context_find( info, s + 1 );
231                 if ( map->lm_data == NULL ) {
232                         rc = -1;
233                         goto cleanup;
234                 }
235                 break;
236
237         /*
238          * External command (not implemented yet)
239          */
240         case REWRITE_OPERATOR_COMMAND:          /* '|' */
241                 rc = -1;
242                 goto cleanup;
243         
244         /*
245          * Variable set
246          */
247         case REWRITE_OPERATOR_VARIABLE_SET:     /* '&' */
248                 if ( s[ 1 ] == REWRITE_OPERATOR_VARIABLE_SET ) {
249                         if ( s[ 2 ] == REWRITE_OPERATOR_VARIABLE_GET ) {
250                                 map->lm_type = REWRITE_MAP_SETW_SESN_VAR;
251                                 map->lm_name = strdup( s + 3 );
252                         } else {
253                                 map->lm_type = REWRITE_MAP_SET_SESN_VAR;
254                                 map->lm_name = strdup( s + 2 );
255                         }
256                 } else {
257                         if ( s[ 1 ] == REWRITE_OPERATOR_VARIABLE_GET ) {
258                                 map->lm_type = REWRITE_MAP_SETW_OP_VAR;
259                                 map->lm_name = strdup( s + 2 );
260                         } else {
261                                 map->lm_type = REWRITE_MAP_SET_OP_VAR;
262                                 map->lm_name = strdup( s + 1 );
263                         }
264                 }
265                 break;
266         
267         /*
268          * Variable dereference
269          */
270         case REWRITE_OPERATOR_VARIABLE_GET:     /* '*' */
271                 if ( s[ 1 ] == REWRITE_OPERATOR_VARIABLE_GET ) {
272                         map->lm_type = REWRITE_MAP_GET_SESN_VAR;
273                         map->lm_name = strdup( s + 2 );
274                 } else {
275                         map->lm_type = REWRITE_MAP_GET_OP_VAR;
276                         map->lm_name = strdup( s + 1 );
277                 }
278                 break;
279         
280         /*
281          * Parameter
282          */
283         case REWRITE_OPERATOR_PARAM_GET:                /* '$' */
284                 map->lm_type = REWRITE_MAP_GET_PARAM;
285                 map->lm_name = strdup( s + 1 );
286                 break;
287         
288         /*
289          * Built-in map
290          */
291         default:
292                 map->lm_type = REWRITE_MAP_BUILTIN;
293                 map->lm_name = strdup( s );
294                 map->lm_data = rewrite_builtin_map_find( info, s );
295                 if ( map->lm_data == NULL ) {
296                         rc = -1;
297                         goto cleanup;
298                 }
299                 break;
300
301         }
302
303 cleanup:
304         free( s );
305         if ( rc ) {
306                 if ( subst != NULL ) {
307                         free( subst );
308                 }
309                 if ( map ) {
310 #ifdef USE_REWRITE_LDAP_PVT_THREADS
311                         if ( mtx ) {
312                                 ldap_pvt_thread_mutex_destroy( &map->lm_mutex );
313                         }
314 #endif /* USE_REWRITE_LDAP_PVT_THREADS */
315
316                         if ( map->lm_name ) {
317                                 free( map->lm_name );
318                                 map->lm_name = NULL;
319                         }
320                         free( map );
321                         map = NULL;
322                 }
323         }
324
325         return map;
326 }
327
328 /*
329  * Applies the new map type
330  */
331 int
332 rewrite_map_apply(
333                 struct rewrite_info *info,
334                 struct rewrite_op *op,
335                 struct rewrite_map *map,
336                 struct berval *key,
337                 struct berval *val
338 )
339 {
340         int rc = REWRITE_SUCCESS;
341
342         assert( info != NULL );
343         assert( op != NULL );
344         assert( map != NULL );
345         assert( key != NULL );
346         assert( val != NULL );
347
348         val->bv_val = NULL;
349         val->bv_len = 0;
350         
351         switch ( map->lm_type ) {
352         case REWRITE_MAP_SUBCONTEXT:
353                 rc = rewrite_context_apply( info, op, 
354                                 ( struct rewrite_context * )map->lm_data,
355                                 key->bv_val, &val->bv_val );
356                 if ( val->bv_val != NULL ) {
357                         val->bv_len = strlen( val->bv_val );
358                 }
359                 break;
360
361         case REWRITE_MAP_SET_OP_VAR:
362         case REWRITE_MAP_SETW_OP_VAR:
363                 rc = rewrite_var_set( &op->lo_vars, map->lm_name,
364                                 key->bv_val, 1 )
365                         ? REWRITE_SUCCESS : REWRITE_ERR;
366                 if ( map->lm_type == REWRITE_MAP_SET_OP_VAR ) {
367                         val->bv_val = strdup( "" );
368                 } else {
369                         val->bv_val = strdup( key->bv_val );
370                         val->bv_len = key->bv_len;
371                 }
372                 break;
373         
374         case REWRITE_MAP_GET_OP_VAR: {
375                 struct rewrite_var *var;
376
377                 var = rewrite_var_find( op->lo_vars, map->lm_name );
378                 if ( var == NULL ) {
379                         rc = REWRITE_ERR;
380                 } else {
381                         val->bv_val = strdup( var->lv_value.bv_val );
382                         val->bv_len = var->lv_value.bv_len;
383                 }
384                 break;  
385         }
386
387         case REWRITE_MAP_SET_SESN_VAR:
388         case REWRITE_MAP_SETW_SESN_VAR:
389                 if ( op->lo_cookie == NULL ) {
390                         rc = REWRITE_ERR;
391                         break;
392                 }
393                 rc = rewrite_session_var_set( info, op->lo_cookie, 
394                                 map->lm_name, key->bv_val );
395                 if ( map->lm_type == REWRITE_MAP_SET_SESN_VAR ) {
396                         val->bv_val = strdup( "" );
397                 } else {
398                         val->bv_val = strdup( key->bv_val );
399                         val->bv_len = key->bv_len;
400                 }
401                 break;
402
403         case REWRITE_MAP_GET_SESN_VAR:
404                 rc = rewrite_session_var_get( info, op->lo_cookie,
405                                 map->lm_name, val );
406                 break;          
407
408         case REWRITE_MAP_GET_PARAM:
409                 rc = rewrite_param_get( info, map->lm_name, val );
410                 break;
411
412         case REWRITE_MAP_BUILTIN: {
413                 struct rewrite_builtin_map *bmap = map->lm_data;
414
415                 switch ( bmap->lb_type ) {
416                 case REWRITE_BUILTIN_MAP_LDAP:
417                         rc = map_ldap_apply( bmap, key->bv_val, val );
418                         break;
419                 default:
420                         rc = REWRITE_ERR;
421                         break;
422                 }
423                 break;
424         }
425
426         default:
427                 rc = REWRITE_ERR;
428                 break;
429         }
430
431         return rc;
432 }
433
434 void
435 rewrite_builtin_map_free(
436                 void *tmp
437 )
438 {
439         struct rewrite_builtin_map *map = ( struct rewrite_builtin_map * )tmp;
440
441         assert( map );
442
443         switch ( map->lb_type ) {
444         case REWRITE_BUILTIN_MAP_LDAP:
445                 map_ldap_destroy( &map );
446                 break;
447
448         default:
449                 assert(0);
450                 break;
451         }
452
453         free( map->lb_name );
454         free( map );
455 }
456
457 int
458 rewrite_map_destroy(
459                 struct rewrite_map **pmap
460 )
461 {
462         struct rewrite_map *map;
463         
464         assert( pmap );
465         assert( *pmap );
466
467         map = *pmap;
468
469 #ifdef USE_REWRITE_LDAP_PVT_THREADS
470         ldap_pvt_thread_mutex_lock( &map->lm_mutex );
471 #endif /* USE_REWRITE_LDAP_PVT_THREADS */
472
473         if ( map->lm_name ) {
474                 free( map->lm_name );
475                 map->lm_name = NULL;
476         }
477
478         if ( map->lm_subst ) {
479                 rewrite_subst_destroy( &map->lm_subst );
480         }
481
482 #ifdef USE_REWRITE_LDAP_PVT_THREADS
483         ldap_pvt_thread_mutex_unlock( &map->lm_mutex );
484         ldap_pvt_thread_mutex_destroy( &map->lm_mutex );
485 #endif /* USE_REWRITE_LDAP_PVT_THREADS */
486
487         free( map );
488         *pmap = NULL;
489         
490         return 0;
491 }
492