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