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