xref: /netbsd-src/external/bsd/openldap/dist/libraries/librewrite/map.c (revision 404fbe5fb94ca1e054339640cabb2801ce52dd30)
1 /* $OpenLDAP: pkg/ldap/libraries/librewrite/map.c,v 1.21.2.4 2008/02/11 23:26:42 kurt Exp $ */
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 }
548