]> git.sur5r.net Git - openldap/blob - libraries/librewrite/map.c
Happy New Year
[openldap] / libraries / librewrite / map.c
1 /* $OpenLDAP$ */
2 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
3  *
4  * Copyright 2000-2018 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         if ( s == NULL ) {
92                 return NULL;
93         }
94         AC_MEMCPY( s, string, l );
95         s[ l ] = 0;
96
97         /*
98          * Isolate the map name (except for variable deref)
99          */
100         switch ( s[ 0 ] ) {
101         case REWRITE_OPERATOR_VARIABLE_GET:
102         case REWRITE_OPERATOR_PARAM_GET:
103                 break;
104
105         default:
106                 begin = strchr( s, '(' );
107                 if ( begin == NULL ) {
108                         rc = -1;
109                         goto cleanup;
110                 }
111                 begin[ 0 ] = '\0';
112                 begin++;
113                 break;
114         }
115
116         /*
117          * Check for special map types
118          */
119         p = s;
120         switch ( p[ 0 ] ) {
121         case REWRITE_OPERATOR_SUBCONTEXT:
122         case REWRITE_OPERATOR_COMMAND:
123         case REWRITE_OPERATOR_VARIABLE_SET:
124         case REWRITE_OPERATOR_VARIABLE_GET:
125         case REWRITE_OPERATOR_PARAM_GET:
126                 p++;
127                 break;
128         }
129
130         /*
131          * Variable set and get may be repeated to indicate session-wide
132          * instead of operation-wide variables
133          */
134         switch ( p[ 0 ] ) {
135         case REWRITE_OPERATOR_VARIABLE_SET:
136         case REWRITE_OPERATOR_VARIABLE_GET:
137                 p++;
138                 break;
139         }
140
141         /*
142          * Variable get token can be appended to variable set to mean store
143          * AND rewrite
144          */
145         if ( p[ 0 ] == REWRITE_OPERATOR_VARIABLE_GET ) {
146                 p++;
147         }
148         
149         /*
150          * Check the syntax of the variable name
151          */
152         if ( !isalpha( (unsigned char) p[ 0 ] ) ) {
153                 rc = -1;
154                 goto cleanup;
155         }
156         for ( p++; p[ 0 ] != '\0'; p++ ) {
157                 if ( !isalnum( (unsigned char) p[ 0 ] ) ) {
158                         rc = -1;
159                         goto cleanup;
160                 }
161         }
162
163         /*
164          * Isolate the argument of the map (except for variable deref)
165          */
166         switch ( s[ 0 ] ) {
167         case REWRITE_OPERATOR_VARIABLE_GET:
168         case REWRITE_OPERATOR_PARAM_GET:
169                 break;
170
171         default:
172                 end = strrchr( begin, ')' );
173                 if ( end == NULL ) {
174                         rc = -1;
175                         goto cleanup;
176                 }
177                 end[ 0 ] = '\0';
178
179                 /*
180                  * Compile the substitution pattern of the map argument
181                  */
182                 subst = rewrite_subst_compile( info, begin );
183                 if ( subst == NULL ) {
184                         rc = -1;
185                         goto cleanup;
186                 }
187                 break;
188         }
189
190         /*
191          * Create the map
192          */
193         map = calloc( sizeof( struct rewrite_map ), 1 );
194         if ( map == NULL ) {
195                 rc = -1;
196                 goto cleanup;
197         }
198         memset( map, 0, sizeof( struct rewrite_map ) );
199         
200 #ifdef USE_REWRITE_LDAP_PVT_THREADS
201         if ( ldap_pvt_thread_mutex_init( &map->lm_mutex ) ) {
202                 rc = -1;
203                 goto cleanup;
204         }
205         ++mtx;
206 #endif /* USE_REWRITE_LDAP_PVT_THREADS */
207                         
208         /*
209          * No subst for variable deref
210          */
211         switch ( s[ 0 ] ) {
212         case REWRITE_OPERATOR_VARIABLE_GET:
213         case REWRITE_OPERATOR_PARAM_GET:
214                 break;
215
216         default:
217                 map->lm_subst = subst;
218                 break;
219         }
220
221         /*
222          * Parses special map types
223          */
224         switch ( s[ 0 ] ) {
225         
226         /*
227          * Subcontext
228          */
229         case REWRITE_OPERATOR_SUBCONTEXT:               /* '>' */
230
231                 /*
232                  * Fetch the rewrite context
233                  * it MUST have been defined previously
234                  */
235                 map->lm_type = REWRITE_MAP_SUBCONTEXT;
236                 map->lm_name = strdup( s + 1 );
237                 if ( map->lm_name == NULL ) {
238                         rc = -1;
239                         goto cleanup;
240                 }
241                 map->lm_data = rewrite_context_find( info, s + 1 );
242                 if ( map->lm_data == NULL ) {
243                         rc = -1;
244                         goto cleanup;
245                 }
246                 break;
247
248         /*
249          * External command (not implemented yet)
250          */
251         case REWRITE_OPERATOR_COMMAND:          /* '|' */
252                 rc = -1;
253                 goto cleanup;
254         
255         /*
256          * Variable set
257          */
258         case REWRITE_OPERATOR_VARIABLE_SET:     /* '&' */
259                 if ( s[ 1 ] == REWRITE_OPERATOR_VARIABLE_SET ) {
260                         if ( s[ 2 ] == REWRITE_OPERATOR_VARIABLE_GET ) {
261                                 map->lm_type = REWRITE_MAP_SETW_SESN_VAR;
262                                 map->lm_name = strdup( s + 3 );
263                         } else {
264                                 map->lm_type = REWRITE_MAP_SET_SESN_VAR;
265                                 map->lm_name = strdup( s + 2 );
266                         }
267                 } else {
268                         if ( s[ 1 ] == REWRITE_OPERATOR_VARIABLE_GET ) {
269                                 map->lm_type = REWRITE_MAP_SETW_OP_VAR;
270                                 map->lm_name = strdup( s + 2 );
271                         } else {
272                                 map->lm_type = REWRITE_MAP_SET_OP_VAR;
273                                 map->lm_name = strdup( s + 1 );
274                         }
275                 }
276                 if ( map->lm_name == NULL ) {
277                         rc = -1;
278                         goto cleanup;
279                 }
280                 break;
281         
282         /*
283          * Variable dereference
284          */
285         case REWRITE_OPERATOR_VARIABLE_GET:     /* '*' */
286                 if ( s[ 1 ] == REWRITE_OPERATOR_VARIABLE_GET ) {
287                         map->lm_type = REWRITE_MAP_GET_SESN_VAR;
288                         map->lm_name = strdup( s + 2 );
289                 } else {
290                         map->lm_type = REWRITE_MAP_GET_OP_VAR;
291                         map->lm_name = strdup( s + 1 );
292                 }
293                 if ( map->lm_name == NULL ) {
294                         rc = -1;
295                         goto cleanup;
296                 }
297                 break;
298         
299         /*
300          * Parameter
301          */
302         case REWRITE_OPERATOR_PARAM_GET:                /* '$' */
303                 map->lm_type = REWRITE_MAP_GET_PARAM;
304                 map->lm_name = strdup( s + 1 );
305                 if ( map->lm_name == NULL ) {
306                         rc = -1;
307                         goto cleanup;
308                 }
309                 break;
310         
311         /*
312          * Built-in map
313          */
314         default:
315                 map->lm_type = REWRITE_MAP_BUILTIN;
316                 map->lm_name = strdup( s );
317                 if ( map->lm_name == NULL ) {
318                         rc = -1;
319                         goto cleanup;
320                 }
321                 map->lm_data = rewrite_builtin_map_find( info, s );
322                 if ( map->lm_data == NULL ) {
323                         rc = -1;
324                         goto cleanup;
325                 }
326                 break;
327
328         }
329
330 cleanup:
331         free( s );
332         if ( rc ) {
333                 if ( subst != NULL ) {
334                         free( subst );
335                 }
336                 if ( map ) {
337 #ifdef USE_REWRITE_LDAP_PVT_THREADS
338                         if ( mtx ) {
339                                 ldap_pvt_thread_mutex_destroy( &map->lm_mutex );
340                         }
341 #endif /* USE_REWRITE_LDAP_PVT_THREADS */
342
343                         if ( map->lm_name ) {
344                                 free( map->lm_name );
345                                 map->lm_name = NULL;
346                         }
347                         free( map );
348                         map = NULL;
349                 }
350         }
351
352         return map;
353 }
354
355 /*
356  * Applies the new map type
357  */
358 int
359 rewrite_map_apply(
360                 struct rewrite_info *info,
361                 struct rewrite_op *op,
362                 struct rewrite_map *map,
363                 struct berval *key,
364                 struct berval *val
365 )
366 {
367         int rc = REWRITE_SUCCESS;
368
369         assert( info != NULL );
370         assert( op != NULL );
371         assert( map != NULL );
372         assert( key != NULL );
373         assert( val != NULL );
374
375         val->bv_val = NULL;
376         val->bv_len = 0;
377         
378         switch ( map->lm_type ) {
379         case REWRITE_MAP_SUBCONTEXT:
380                 rc = rewrite_context_apply( info, op, 
381                                 ( struct rewrite_context * )map->lm_data,
382                                 key->bv_val, &val->bv_val );
383                 if ( val->bv_val != NULL ) {
384                         if ( val->bv_val == key->bv_val ) {
385                                 val->bv_len = key->bv_len;
386                                 key->bv_val = NULL;
387                         } else {
388                                 val->bv_len = strlen( val->bv_val );
389                         }
390                 }
391                 break;
392
393         case REWRITE_MAP_SET_OP_VAR:
394         case REWRITE_MAP_SETW_OP_VAR:
395                 rc = rewrite_var_set( &op->lo_vars, map->lm_name,
396                                 key->bv_val, 1 )
397                         ? REWRITE_SUCCESS : REWRITE_ERR;
398                 if ( rc == REWRITE_SUCCESS ) {
399                         if ( map->lm_type == REWRITE_MAP_SET_OP_VAR ) {
400                                 val->bv_val = strdup( "" );
401                         } else {
402                                 val->bv_val = strdup( key->bv_val );
403                                 val->bv_len = key->bv_len;
404                         }
405                         if ( val->bv_val == NULL ) {
406                                 rc = REWRITE_ERR;
407                         }
408                 }
409                 break;
410         
411         case REWRITE_MAP_GET_OP_VAR: {
412                 struct rewrite_var *var;
413
414                 var = rewrite_var_find( op->lo_vars, map->lm_name );
415                 if ( var == NULL ) {
416                         rc = REWRITE_ERR;
417                 } else {
418                         val->bv_val = strdup( var->lv_value.bv_val );
419                         val->bv_len = var->lv_value.bv_len;
420                         if ( val->bv_val == NULL ) {
421                                 rc = REWRITE_ERR;
422                         }
423                 }
424                 break;  
425         }
426
427         case REWRITE_MAP_SET_SESN_VAR:
428         case REWRITE_MAP_SETW_SESN_VAR:
429                 if ( op->lo_cookie == NULL ) {
430                         rc = REWRITE_ERR;
431                         break;
432                 }
433                 rc = rewrite_session_var_set( info, op->lo_cookie, 
434                                 map->lm_name, key->bv_val );
435                 if ( rc == REWRITE_SUCCESS ) {
436                         if ( map->lm_type == REWRITE_MAP_SET_SESN_VAR ) {
437                                 val->bv_val = strdup( "" );
438                         } else {
439                                 val->bv_val = strdup( key->bv_val );
440                                 val->bv_len = key->bv_len;
441                         }
442                         if ( val->bv_val == NULL ) {
443                                 rc = REWRITE_ERR;
444                         }
445                 }
446                 break;
447
448         case REWRITE_MAP_GET_SESN_VAR:
449                 rc = rewrite_session_var_get( info, op->lo_cookie,
450                                 map->lm_name, val );
451                 break;          
452
453         case REWRITE_MAP_GET_PARAM:
454                 rc = rewrite_param_get( info, map->lm_name, val );
455                 break;
456
457         case REWRITE_MAP_BUILTIN: {
458                 struct rewrite_builtin_map *bmap = map->lm_data;
459
460                 if ( bmap->lb_mapper && bmap->lb_mapper->rm_apply )
461                         rc = bmap->lb_mapper->rm_apply( bmap->lb_private, key->bv_val,
462                                 val );
463                 else
464                         rc = REWRITE_ERR;
465                         break;
466                 break;
467         }
468
469         default:
470                 rc = REWRITE_ERR;
471                 break;
472         }
473
474         return rc;
475 }
476
477 void
478 rewrite_builtin_map_free(
479                 void *tmp
480 )
481 {
482         struct rewrite_builtin_map *map = ( struct rewrite_builtin_map * )tmp;
483
484         assert( map != NULL );
485
486         if ( map->lb_mapper && map->lb_mapper->rm_destroy )
487                 map->lb_mapper->rm_destroy( map->lb_private );
488
489         free( map->lb_name );
490         free( map );
491 }
492
493 int
494 rewrite_map_destroy(
495                 struct rewrite_map **pmap
496 )
497 {
498         struct rewrite_map *map;
499         
500         assert( pmap != NULL );
501         assert( *pmap != NULL );
502
503         map = *pmap;
504
505 #ifdef USE_REWRITE_LDAP_PVT_THREADS
506         ldap_pvt_thread_mutex_lock( &map->lm_mutex );
507 #endif /* USE_REWRITE_LDAP_PVT_THREADS */
508
509         if ( map->lm_name ) {
510                 free( map->lm_name );
511                 map->lm_name = NULL;
512         }
513
514         if ( map->lm_subst ) {
515                 rewrite_subst_destroy( &map->lm_subst );
516         }
517
518 #ifdef USE_REWRITE_LDAP_PVT_THREADS
519         ldap_pvt_thread_mutex_unlock( &map->lm_mutex );
520         ldap_pvt_thread_mutex_destroy( &map->lm_mutex );
521 #endif /* USE_REWRITE_LDAP_PVT_THREADS */
522
523         free( map );
524         *pmap = NULL;
525         
526         return 0;
527 }
528
529 /* ldapmap.c */
530 extern const rewrite_mapper rewrite_ldap_mapper;
531
532 const rewrite_mapper *
533 rewrite_mapper_find(
534         const char *name
535 )
536 {
537         int i;
538
539         if ( !strcasecmp( name, "ldap" ))
540                 return &rewrite_ldap_mapper;
541
542         for (i=0; i<num_mappers; i++)
543                 if ( !strcasecmp( name, mappers[i]->rm_name ))
544                         return mappers[i];
545         return NULL;
546 }
547
548 int
549 rewrite_mapper_register(
550         const rewrite_mapper *map
551 )
552 {
553         if ( num_mappers % MAPPER_ALLOC == 0 ) {
554                 const rewrite_mapper **mnew;
555                 mnew = realloc( mappers, (num_mappers + MAPPER_ALLOC) *
556                         sizeof( rewrite_mapper * ));
557                 if ( mnew )
558                         mappers = mnew;
559                 else
560                         return -1;
561         }
562         mappers[num_mappers++] = map;
563         return 0;
564 }
565
566 int
567 rewrite_mapper_unregister(
568         const rewrite_mapper *map
569 )
570 {
571         int i;
572
573         for (i = 0; i<num_mappers; i++) {
574                 if ( mappers[i] == map ) {
575                         num_mappers--;
576                         mappers[i] = mappers[num_mappers];
577                         mappers[num_mappers] = NULL;
578                         return 0;
579                 }
580         }
581         /* not found */
582         return -1;
583 }