]> git.sur5r.net Git - openldap/blob - libraries/librewrite/map.c
68bc44d60e101c4c827428ac1418ac5c57cad876
[openldap] / libraries / librewrite / map.c
1 /* $OpenLDAP$ */
2 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
3  *
4  * Copyright 2000-2007 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                         if ( val->bv_val == key->bv_val ) {
358                                 val->bv_len = key->bv_len;
359                                 key->bv_val = NULL;
360                         } else {
361                                 val->bv_len = strlen( val->bv_val );
362                         }
363                 }
364                 break;
365
366         case REWRITE_MAP_SET_OP_VAR:
367         case REWRITE_MAP_SETW_OP_VAR:
368                 rc = rewrite_var_set( &op->lo_vars, map->lm_name,
369                                 key->bv_val, 1 )
370                         ? REWRITE_SUCCESS : REWRITE_ERR;
371                 if ( map->lm_type == REWRITE_MAP_SET_OP_VAR ) {
372                         val->bv_val = strdup( "" );
373                 } else {
374                         val->bv_val = strdup( key->bv_val );
375                         val->bv_len = key->bv_len;
376                 }
377                 break;
378         
379         case REWRITE_MAP_GET_OP_VAR: {
380                 struct rewrite_var *var;
381
382                 var = rewrite_var_find( op->lo_vars, map->lm_name );
383                 if ( var == NULL ) {
384                         rc = REWRITE_ERR;
385                 } else {
386                         val->bv_val = strdup( var->lv_value.bv_val );
387                         val->bv_len = var->lv_value.bv_len;
388                 }
389                 break;  
390         }
391
392         case REWRITE_MAP_SET_SESN_VAR:
393         case REWRITE_MAP_SETW_SESN_VAR:
394                 if ( op->lo_cookie == NULL ) {
395                         rc = REWRITE_ERR;
396                         break;
397                 }
398                 rc = rewrite_session_var_set( info, op->lo_cookie, 
399                                 map->lm_name, key->bv_val );
400                 if ( map->lm_type == REWRITE_MAP_SET_SESN_VAR ) {
401                         val->bv_val = strdup( "" );
402                 } else {
403                         val->bv_val = strdup( key->bv_val );
404                         val->bv_len = key->bv_len;
405                 }
406                 break;
407
408         case REWRITE_MAP_GET_SESN_VAR:
409                 rc = rewrite_session_var_get( info, op->lo_cookie,
410                                 map->lm_name, val );
411                 break;          
412
413         case REWRITE_MAP_GET_PARAM:
414                 rc = rewrite_param_get( info, map->lm_name, val );
415                 break;
416
417         case REWRITE_MAP_BUILTIN: {
418                 struct rewrite_builtin_map *bmap = map->lm_data;
419
420                 switch ( bmap->lb_type ) {
421                 case REWRITE_BUILTIN_MAP_LDAP:
422                         rc = map_ldap_apply( bmap, key->bv_val, val );
423                         break;
424                 default:
425                         rc = REWRITE_ERR;
426                         break;
427                 }
428                 break;
429         }
430
431         default:
432                 rc = REWRITE_ERR;
433                 break;
434         }
435
436         return rc;
437 }
438
439 void
440 rewrite_builtin_map_free(
441                 void *tmp
442 )
443 {
444         struct rewrite_builtin_map *map = ( struct rewrite_builtin_map * )tmp;
445
446         assert( map != NULL );
447
448         switch ( map->lb_type ) {
449         case REWRITE_BUILTIN_MAP_LDAP:
450                 map_ldap_destroy( &map );
451                 break;
452
453         default:
454                 assert(0);
455                 break;
456         }
457
458         free( map->lb_name );
459         free( map );
460 }
461
462 int
463 rewrite_map_destroy(
464                 struct rewrite_map **pmap
465 )
466 {
467         struct rewrite_map *map;
468         
469         assert( pmap != NULL );
470         assert( *pmap != NULL );
471
472         map = *pmap;
473
474 #ifdef USE_REWRITE_LDAP_PVT_THREADS
475         ldap_pvt_thread_mutex_lock( &map->lm_mutex );
476 #endif /* USE_REWRITE_LDAP_PVT_THREADS */
477
478         if ( map->lm_name ) {
479                 free( map->lm_name );
480                 map->lm_name = NULL;
481         }
482
483         if ( map->lm_subst ) {
484                 rewrite_subst_destroy( &map->lm_subst );
485         }
486
487 #ifdef USE_REWRITE_LDAP_PVT_THREADS
488         ldap_pvt_thread_mutex_unlock( &map->lm_mutex );
489         ldap_pvt_thread_mutex_destroy( &map->lm_mutex );
490 #endif /* USE_REWRITE_LDAP_PVT_THREADS */
491
492         free( map );
493         *pmap = NULL;
494         
495         return 0;
496 }
497