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