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