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