xref: /netbsd-src/external/bsd/openldap/dist/libraries/librewrite/config.c (revision 549b59ed3ccf0d36d3097190a0db27b770f3a839)
1 /*	$NetBSD: config.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 "rewrite-int.h"
25 #include "rewrite-map.h"
26 
27 /*
28  * Parses a plugin map
29  */
30 static int
31 rewrite_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  */
50 int
rewrite_parse(struct rewrite_info * info,const char * fname,int lineno,int argc,char ** argv)51 rewrite_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",
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",
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",
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",
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 );
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 );
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",
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",
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",
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",
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",
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",
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",
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",
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",
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, argv[ 0 ] );
294 		return -1;
295 	}
296 
297 	return rc;
298 }
299 
300 /*
301  * Compares two maps
302  */
303 static int
rewrite_builtin_map_cmp(const void * c1,const void * c2)304 rewrite_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  */
325 static int
rewrite_builtin_map_dup(void * c1,void * c2)326 rewrite_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  */
347 static int
rewrite_builtin_map_insert(struct rewrite_info * info,struct rewrite_builtin_map * map)348 rewrite_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 ldap_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  */
364 struct rewrite_builtin_map *
rewrite_builtin_map_find(struct rewrite_info * info,const char * name)365 rewrite_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 * )ldap_avl_find( info->li_maps,
378 			( caddr_t )&tmp, rewrite_builtin_map_cmp );
379 }
380 
381 /*
382  * Parses a plugin map
383  */
384 static int
rewrite_parse_builtin_map(struct rewrite_info * info,const char * fname,int lineno,int argc,char ** argv)385 rewrite_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",
438 				fname, lineno );
439 		return -1;
440 	}
441 
442 	return rewrite_builtin_map_insert( info, map );
443 }
444