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