1/*	$NetBSD: config.c,v 1.1.1.3 2010/12/12 15:22:12 adam Exp $	*/
2
3/* OpenLDAP: pkg/ldap/libraries/librewrite/config.c,v 1.14.2.5 2010/04/13 20:23:08 kurt Exp */
4/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
5 *
6 * Copyright 2000-2010 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 "rewrite-int.h"
25#include "rewrite-map.h"
26
27/*
28 * Parses a plugin map
29 */
30static int
31rewrite_parse_builtin_map(
32		struct rewrite_info *info,
33		const char *fname,
34		int lineno,
35		int argc,
36		char **argv
37);
38
39/*
40 * Parses a config line and takes actions to fit content in rewrite structure;
41 * lines handled are of the form:
42 *
43 *      rewriteEngine 		{on|off}
44 *      rewriteMaxPasses        numPasses [numPassesPerRule]
45 *      rewriteContext 		contextName [alias aliasedContextName]
46 *      rewriteRule 		pattern substPattern [ruleFlags]
47 *      rewriteMap 		mapType mapName [mapArgs]
48 *      rewriteParam		paramName paramValue
49 */
50int
51rewrite_parse(
52		struct rewrite_info *info,
53		const char *fname,
54		int lineno,
55		int argc,
56		char **argv
57)
58{
59	int rc = -1;
60
61	assert( info != NULL );
62	assert( fname != NULL );
63	assert( argv != NULL );
64	assert( argc > 0 );
65
66	/*
67	 * Switch on the rewrite engine
68	 */
69	if ( strcasecmp( argv[ 0 ], "rewriteEngine" ) == 0 ) {
70		if ( argc < 2 ) {
71			Debug( LDAP_DEBUG_ANY,
72					"[%s:%d] rewriteEngine needs 'state'\n%s",
73					fname, lineno, "" );
74			return -1;
75
76		} else if ( argc > 2 ) {
77			Debug( LDAP_DEBUG_ANY,
78					"[%s:%d] extra fields in rewriteEngine"
79					" will be discarded\n%s",
80					fname, lineno, "" );
81		}
82
83		if ( strcasecmp( argv[ 1 ], "on" ) == 0 ) {
84			info->li_state = REWRITE_ON;
85
86		} else if ( strcasecmp( argv[ 1 ], "off" ) == 0 ) {
87			info->li_state = REWRITE_OFF;
88
89		} else {
90			Debug( LDAP_DEBUG_ANY,
91					"[%s:%d] unknown 'state' in rewriteEngine;"
92					" assuming 'on'\n%s",
93					fname, lineno, "" );
94			info->li_state = REWRITE_ON;
95		}
96		rc = REWRITE_SUCCESS;
97
98	/*
99	 * Alter max passes
100	 */
101	} else if ( strcasecmp( argv[ 0 ], "rewriteMaxPasses" ) == 0 ) {
102		if ( argc < 2 ) {
103			Debug( LDAP_DEBUG_ANY,
104					"[%s:%d] rewriteMaxPasses needs 'value'\n%s",
105					fname, lineno, "" );
106			return -1;
107		}
108
109		if ( lutil_atoi( &info->li_max_passes, argv[ 1 ] ) != 0 ) {
110			Debug( LDAP_DEBUG_ANY,
111					"[%s:%d] unable to parse rewriteMaxPasses=\"%s\"\n",
112					fname, lineno, argv[ 1 ] );
113			return -1;
114		}
115
116		if ( info->li_max_passes <= 0 ) {
117			Debug( LDAP_DEBUG_ANY,
118					"[%s:%d] negative or null rewriteMaxPasses\n",
119					fname, lineno, 0 );
120			return -1;
121		}
122
123		if ( argc > 2 ) {
124			if ( lutil_atoi( &info->li_max_passes_per_rule, argv[ 2 ] ) != 0 ) {
125				Debug( LDAP_DEBUG_ANY,
126						"[%s:%d] unable to parse rewriteMaxPassesPerRule=\"%s\"\n",
127						fname, lineno, argv[ 2 ] );
128				return -1;
129			}
130
131			if ( info->li_max_passes_per_rule <= 0 ) {
132				Debug( LDAP_DEBUG_ANY,
133						"[%s:%d] negative or null rewriteMaxPassesPerRule\n",
134						fname, lineno, 0 );
135				return -1;
136			}
137
138		} else {
139			info->li_max_passes_per_rule = info->li_max_passes;
140		}
141		rc = REWRITE_SUCCESS;
142
143	/*
144	 * Start a new rewrite context and set current context
145	 */
146	} else if ( strcasecmp( argv[ 0 ], "rewriteContext" ) == 0 ) {
147		if ( argc < 2 ) {
148			Debug( LDAP_DEBUG_ANY,
149					"[%s:%d] rewriteContext needs 'name'\n%s",
150					fname, lineno, "" );
151			return -1;
152		}
153
154		/*
155		 * Checks for existence (lots of contexts should be
156		 * available by default ...)
157		 */
158		 rewrite_int_curr_context = rewrite_context_find( info, argv[ 1 ] );
159		 if ( rewrite_int_curr_context == NULL ) {
160			 rewrite_int_curr_context = rewrite_context_create( info,
161					 argv[ 1 ] );
162		 }
163		 if ( rewrite_int_curr_context == NULL ) {
164			 return -1;
165		 }
166
167		 if ( argc > 2 ) {
168
169			 /*
170			  * A context can alias another (e.g., the `builtin'
171			  * contexts for backend operations, if not defined,
172			  * alias the `default' rewrite context (with the
173			  * notable exception of the searchResult context,
174			  * which can be undefined)
175			  */
176			 if ( strcasecmp( argv[ 2 ], "alias" ) == 0 ) {
177				 struct rewrite_context *aliased;
178
179				 if ( argc == 3 ) {
180					 Debug( LDAP_DEBUG_ANY,
181							 "[%s:%d] rewriteContext"
182							 " needs 'name' after"
183							 " 'alias'\n%s",
184							 fname, lineno, "" );
185					 return -1;
186
187				 } else if ( argc > 4 ) {
188					 Debug( LDAP_DEBUG_ANY,
189							 "[%s:%d] extra fields in"
190							 " rewriteContext"
191							 " after aliased name"
192							 " will be"
193							 " discarded\n%s",
194							 fname, lineno, "" );
195				 }
196
197				 aliased = rewrite_context_find( info,
198						 argv[ 3 ] );
199				 if ( aliased == NULL ) {
200					 Debug( LDAP_DEBUG_ANY,
201							 "[%s:%d] aliased"
202							 " rewriteContext '%s'"
203							 " does not exists\n",
204							 fname, lineno,
205							 argv[ 3 ] );
206					 return -1;
207				 }
208
209				 rewrite_int_curr_context->lc_alias = aliased;
210				 rewrite_int_curr_context = aliased;
211
212			 } else {
213				 Debug( LDAP_DEBUG_ANY,
214						 "[%s:%d] extra fields"
215						 " in rewriteContext"
216						 " will be discarded\n%s",
217						 fname, lineno, "" );
218			 }
219		 }
220		 rc = REWRITE_SUCCESS;
221
222	/*
223	 * Compile a rule in current context
224	 */
225	} else if ( strcasecmp( argv[ 0 ], "rewriteRule" ) == 0 ) {
226		if ( argc < 3 ) {
227			Debug( LDAP_DEBUG_ANY,
228					"[%s:%d] rewriteRule needs 'pattern'"
229					" 'subst' ['flags']\n%s",
230					fname, lineno, "" );
231			return -1;
232
233		} else if ( argc > 4 ) {
234			Debug( LDAP_DEBUG_ANY,
235					"[%s:%d] extra fields in rewriteRule"
236					" will be discarded\n%s",
237					fname, lineno, "" );
238		}
239
240		if ( rewrite_int_curr_context == NULL ) {
241			Debug( LDAP_DEBUG_ANY,
242					"[%s:%d] rewriteRule outside a"
243					" context; will add to default\n%s",
244					fname, lineno, "" );
245			rewrite_int_curr_context = rewrite_context_find( info,
246					REWRITE_DEFAULT_CONTEXT );
247
248			/*
249			 * Default context MUST exist in a properly initialized
250			 * struct rewrite_info
251			 */
252			assert( rewrite_int_curr_context != NULL );
253		}
254
255		rc = rewrite_rule_compile( info, rewrite_int_curr_context, argv[ 1 ],
256				argv[ 2 ], ( argc == 4 ? argv[ 3 ] : "" ) );
257
258	/*
259	 * Add a plugin map to the map tree
260	 */
261	} else if ( strcasecmp( argv[ 0 ], "rewriteMap" ) == 0 ) {
262		if ( argc < 3 ) {
263			Debug( LDAP_DEBUG_ANY,
264					"[%s:%d] rewriteMap needs at least 'type'"
265					" and 'name' ['args']\n%s",
266					fname, lineno, "" );
267			return -1;
268		}
269
270		rc = rewrite_parse_builtin_map( info, fname, lineno,
271				argc, argv );
272
273	/*
274	 * Set the value of a global scope parameter
275	 */
276	} else if ( strcasecmp( argv[ 0 ], "rewriteParam" ) == 0 ) {
277		if ( argc < 3 ) {
278			Debug( LDAP_DEBUG_ANY,
279					"[%s:%d] rewriteParam needs 'name'"
280					" and 'value'\n%s",
281					fname, lineno, "" );
282			return -1;
283		}
284
285		rc = rewrite_param_set( info, argv[ 1 ], argv[ 2 ] );
286
287	/*
288	 * Error
289	 */
290	} else {
291		Debug( LDAP_DEBUG_ANY,
292				"[%s:%d] unknown command '%s'\n",
293				fname, lineno, "" );
294		return -1;
295	}
296
297	return rc;
298}
299
300/*
301 * Compares two maps
302 */
303static int
304rewrite_builtin_map_cmp(
305		const void *c1,
306                const void *c2
307)
308{
309	const struct rewrite_builtin_map *m1, *m2;
310
311        m1 = ( const struct rewrite_builtin_map * )c1;
312        m2 = ( const struct rewrite_builtin_map * )c2;
313
314        assert( m1 != NULL );
315        assert( m2 != NULL );
316        assert( m1->lb_name != NULL );
317        assert( m2->lb_name != NULL );
318
319        return strcasecmp( m1->lb_name, m2->lb_name );
320}
321
322/*
323 * Duplicate map ?
324 */
325static int
326rewrite_builtin_map_dup(
327	                void *c1,
328	                void *c2
329)
330{
331        struct rewrite_builtin_map *m1, *m2;
332
333        m1 = ( struct rewrite_builtin_map * )c1;
334        m2 = ( struct rewrite_builtin_map * )c2;
335
336        assert( m1 != NULL );
337        assert( m2 != NULL );
338        assert( m1->lb_name != NULL );
339        assert( m2->lb_name != NULL );
340
341        return ( strcasecmp( m1->lb_name, m2->lb_name ) == 0 ? -1 : 0 );
342}
343
344/*
345 * Adds a map to the info map tree
346 */
347static int
348rewrite_builtin_map_insert(
349		struct rewrite_info *info,
350		struct rewrite_builtin_map *map
351)
352{
353	/*
354	 * May need a mutex?
355	 */
356	return avl_insert( &info->li_maps, ( caddr_t )map,
357			rewrite_builtin_map_cmp,
358		       	rewrite_builtin_map_dup );
359}
360
361/*
362 * Retrieves a map
363 */
364struct rewrite_builtin_map *
365rewrite_builtin_map_find(
366		struct rewrite_info *info,
367		const char *name
368)
369{
370	struct rewrite_builtin_map tmp;
371
372	assert( info != NULL );
373	assert( name != NULL );
374
375	tmp.lb_name = ( char * )name;
376
377	return ( struct rewrite_builtin_map * )avl_find( info->li_maps,
378			( caddr_t )&tmp, rewrite_builtin_map_cmp );
379}
380
381/*
382 * Parses a plugin map
383 */
384static int
385rewrite_parse_builtin_map(
386		struct rewrite_info *info,
387		const char *fname,
388		int lineno,
389		int argc,
390		char **argv
391)
392{
393	struct rewrite_builtin_map *map;
394
395#define MAP_TYPE	1
396#define MAP_NAME	2
397
398	assert( info != NULL );
399	assert( fname != NULL );
400	assert( argc > 2 );
401	assert( argv != NULL );
402	assert( strcasecmp( argv[ 0 ], "rewriteMap" ) == 0 );
403
404	map = calloc( sizeof( struct rewrite_builtin_map ), 1 );
405	if ( map == NULL ) {
406		return REWRITE_ERR;
407	}
408
409	map->lb_name = strdup( argv[ MAP_NAME ] );
410	if ( map->lb_name == NULL ) {
411		free( map );
412		return REWRITE_ERR;
413	}
414
415	/*
416	 * Built-in ldap map
417	 */
418	if (( map->lb_mapper = rewrite_mapper_find( argv[ MAP_TYPE ] ))) {
419		map->lb_type = REWRITE_BUILTIN_MAP;
420
421#ifdef USE_REWRITE_LDAP_PVT_THREADS
422		if ( ldap_pvt_thread_mutex_init( & map->lb_mutex ) ) {
423			free( map->lb_name );
424			free( map );
425			return REWRITE_ERR;
426		}
427#endif /* USE_REWRITE_LDAP_PVT_THREADS */
428
429		map->lb_private = map->lb_mapper->rm_config( fname, lineno,
430				argc - 3, argv + 3 );
431
432	/*
433	 * Error
434	 */
435	} else {
436		free( map );
437		Debug( LDAP_DEBUG_ANY, "[%s:%d] unknown map type\n%s",
438				fname, lineno, "" );
439		return -1;
440	}
441
442	return rewrite_builtin_map_insert( info, map );
443}
444