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