1*549b59edSchristos /* $NetBSD: config.c,v 1.3 2021/08/14 16:14:58 christos Exp $ */
24e6df137Slukem
3d11b170bStron /* $OpenLDAP$ */
42de962bdSlukem /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
52de962bdSlukem *
6*549b59edSchristos * Copyright 2000-2021 The OpenLDAP Foundation.
72de962bdSlukem * All rights reserved.
82de962bdSlukem *
92de962bdSlukem * Redistribution and use in source and binary forms, with or without
102de962bdSlukem * modification, are permitted only as authorized by the OpenLDAP
112de962bdSlukem * Public License.
122de962bdSlukem *
132de962bdSlukem * A copy of this license is available in the file LICENSE in the
142de962bdSlukem * top-level directory of the distribution or, alternatively, at
152de962bdSlukem * <http://www.OpenLDAP.org/license.html>.
162de962bdSlukem */
172de962bdSlukem /* ACKNOWLEDGEMENT:
182de962bdSlukem * This work was initially developed by Pierangelo Masarati for
192de962bdSlukem * inclusion in OpenLDAP Software.
202de962bdSlukem */
212de962bdSlukem
222de962bdSlukem #include <portable.h>
232de962bdSlukem
242de962bdSlukem #include "rewrite-int.h"
252de962bdSlukem #include "rewrite-map.h"
262de962bdSlukem
272de962bdSlukem /*
282de962bdSlukem * Parses a plugin map
292de962bdSlukem */
302de962bdSlukem static int
312de962bdSlukem rewrite_parse_builtin_map(
322de962bdSlukem struct rewrite_info *info,
332de962bdSlukem const char *fname,
342de962bdSlukem int lineno,
352de962bdSlukem int argc,
362de962bdSlukem char **argv
372de962bdSlukem );
382de962bdSlukem
392de962bdSlukem /*
402de962bdSlukem * Parses a config line and takes actions to fit content in rewrite structure;
412de962bdSlukem * lines handled are of the form:
422de962bdSlukem *
432de962bdSlukem * rewriteEngine {on|off}
442de962bdSlukem * rewriteMaxPasses numPasses [numPassesPerRule]
452de962bdSlukem * rewriteContext contextName [alias aliasedContextName]
462de962bdSlukem * rewriteRule pattern substPattern [ruleFlags]
472de962bdSlukem * rewriteMap mapType mapName [mapArgs]
482de962bdSlukem * rewriteParam paramName paramValue
492de962bdSlukem */
502de962bdSlukem int
rewrite_parse(struct rewrite_info * info,const char * fname,int lineno,int argc,char ** argv)512de962bdSlukem rewrite_parse(
522de962bdSlukem struct rewrite_info *info,
532de962bdSlukem const char *fname,
542de962bdSlukem int lineno,
552de962bdSlukem int argc,
562de962bdSlukem char **argv
572de962bdSlukem )
582de962bdSlukem {
592de962bdSlukem int rc = -1;
602de962bdSlukem
612de962bdSlukem assert( info != NULL );
622de962bdSlukem assert( fname != NULL );
632de962bdSlukem assert( argv != NULL );
642de962bdSlukem assert( argc > 0 );
652de962bdSlukem
662de962bdSlukem /*
672de962bdSlukem * Switch on the rewrite engine
682de962bdSlukem */
692de962bdSlukem if ( strcasecmp( argv[ 0 ], "rewriteEngine" ) == 0 ) {
702de962bdSlukem if ( argc < 2 ) {
712de962bdSlukem Debug( LDAP_DEBUG_ANY,
72*549b59edSchristos "[%s:%d] rewriteEngine needs 'state'\n",
73*549b59edSchristos fname, lineno );
742de962bdSlukem return -1;
752de962bdSlukem
762de962bdSlukem } else if ( argc > 2 ) {
772de962bdSlukem Debug( LDAP_DEBUG_ANY,
782de962bdSlukem "[%s:%d] extra fields in rewriteEngine"
79*549b59edSchristos " will be discarded\n",
80*549b59edSchristos fname, lineno );
812de962bdSlukem }
822de962bdSlukem
832de962bdSlukem if ( strcasecmp( argv[ 1 ], "on" ) == 0 ) {
842de962bdSlukem info->li_state = REWRITE_ON;
852de962bdSlukem
862de962bdSlukem } else if ( strcasecmp( argv[ 1 ], "off" ) == 0 ) {
872de962bdSlukem info->li_state = REWRITE_OFF;
882de962bdSlukem
892de962bdSlukem } else {
902de962bdSlukem Debug( LDAP_DEBUG_ANY,
912de962bdSlukem "[%s:%d] unknown 'state' in rewriteEngine;"
92*549b59edSchristos " assuming 'on'\n",
93*549b59edSchristos fname, lineno );
942de962bdSlukem info->li_state = REWRITE_ON;
952de962bdSlukem }
962de962bdSlukem rc = REWRITE_SUCCESS;
972de962bdSlukem
982de962bdSlukem /*
992de962bdSlukem * Alter max passes
1002de962bdSlukem */
1012de962bdSlukem } else if ( strcasecmp( argv[ 0 ], "rewriteMaxPasses" ) == 0 ) {
1022de962bdSlukem if ( argc < 2 ) {
1032de962bdSlukem Debug( LDAP_DEBUG_ANY,
104*549b59edSchristos "[%s:%d] rewriteMaxPasses needs 'value'\n",
105*549b59edSchristos fname, lineno );
1062de962bdSlukem return -1;
1072de962bdSlukem }
1082de962bdSlukem
1092de962bdSlukem if ( lutil_atoi( &info->li_max_passes, argv[ 1 ] ) != 0 ) {
1102de962bdSlukem Debug( LDAP_DEBUG_ANY,
1112de962bdSlukem "[%s:%d] unable to parse rewriteMaxPasses=\"%s\"\n",
1122de962bdSlukem fname, lineno, argv[ 1 ] );
1132de962bdSlukem return -1;
1142de962bdSlukem }
1152de962bdSlukem
1162de962bdSlukem if ( info->li_max_passes <= 0 ) {
1172de962bdSlukem Debug( LDAP_DEBUG_ANY,
1182de962bdSlukem "[%s:%d] negative or null rewriteMaxPasses\n",
119*549b59edSchristos fname, lineno );
1202de962bdSlukem return -1;
1212de962bdSlukem }
1222de962bdSlukem
1232de962bdSlukem if ( argc > 2 ) {
1242de962bdSlukem if ( lutil_atoi( &info->li_max_passes_per_rule, argv[ 2 ] ) != 0 ) {
1252de962bdSlukem Debug( LDAP_DEBUG_ANY,
1262de962bdSlukem "[%s:%d] unable to parse rewriteMaxPassesPerRule=\"%s\"\n",
1272de962bdSlukem fname, lineno, argv[ 2 ] );
1282de962bdSlukem return -1;
1292de962bdSlukem }
1302de962bdSlukem
1312de962bdSlukem if ( info->li_max_passes_per_rule <= 0 ) {
1322de962bdSlukem Debug( LDAP_DEBUG_ANY,
1332de962bdSlukem "[%s:%d] negative or null rewriteMaxPassesPerRule\n",
134*549b59edSchristos fname, lineno );
1352de962bdSlukem return -1;
1362de962bdSlukem }
1372de962bdSlukem
1382de962bdSlukem } else {
1392de962bdSlukem info->li_max_passes_per_rule = info->li_max_passes;
1402de962bdSlukem }
1412de962bdSlukem rc = REWRITE_SUCCESS;
1422de962bdSlukem
1432de962bdSlukem /*
1442de962bdSlukem * Start a new rewrite context and set current context
1452de962bdSlukem */
1462de962bdSlukem } else if ( strcasecmp( argv[ 0 ], "rewriteContext" ) == 0 ) {
1472de962bdSlukem if ( argc < 2 ) {
1482de962bdSlukem Debug( LDAP_DEBUG_ANY,
149*549b59edSchristos "[%s:%d] rewriteContext needs 'name'\n",
150*549b59edSchristos fname, lineno );
1512de962bdSlukem return -1;
1522de962bdSlukem }
1532de962bdSlukem
1542de962bdSlukem /*
1552de962bdSlukem * Checks for existence (lots of contexts should be
1562de962bdSlukem * available by default ...)
1572de962bdSlukem */
1582de962bdSlukem rewrite_int_curr_context = rewrite_context_find( info, argv[ 1 ] );
1592de962bdSlukem if ( rewrite_int_curr_context == NULL ) {
1602de962bdSlukem rewrite_int_curr_context = rewrite_context_create( info,
1612de962bdSlukem argv[ 1 ] );
1622de962bdSlukem }
1632de962bdSlukem if ( rewrite_int_curr_context == NULL ) {
1642de962bdSlukem return -1;
1652de962bdSlukem }
1662de962bdSlukem
1672de962bdSlukem if ( argc > 2 ) {
1682de962bdSlukem
1692de962bdSlukem /*
1702de962bdSlukem * A context can alias another (e.g., the `builtin'
1712de962bdSlukem * contexts for backend operations, if not defined,
1722de962bdSlukem * alias the `default' rewrite context (with the
1732de962bdSlukem * notable exception of the searchResult context,
1742de962bdSlukem * which can be undefined)
1752de962bdSlukem */
1762de962bdSlukem if ( strcasecmp( argv[ 2 ], "alias" ) == 0 ) {
1772de962bdSlukem struct rewrite_context *aliased;
1782de962bdSlukem
1792de962bdSlukem if ( argc == 3 ) {
1802de962bdSlukem Debug( LDAP_DEBUG_ANY,
1812de962bdSlukem "[%s:%d] rewriteContext"
1822de962bdSlukem " needs 'name' after"
183*549b59edSchristos " 'alias'\n",
184*549b59edSchristos fname, lineno );
1852de962bdSlukem return -1;
1862de962bdSlukem
1872de962bdSlukem } else if ( argc > 4 ) {
1882de962bdSlukem Debug( LDAP_DEBUG_ANY,
1892de962bdSlukem "[%s:%d] extra fields in"
1902de962bdSlukem " rewriteContext"
1912de962bdSlukem " after aliased name"
1922de962bdSlukem " will be"
193*549b59edSchristos " discarded\n",
194*549b59edSchristos fname, lineno );
1952de962bdSlukem }
1962de962bdSlukem
1972de962bdSlukem aliased = rewrite_context_find( info,
1982de962bdSlukem argv[ 3 ] );
1992de962bdSlukem if ( aliased == NULL ) {
2002de962bdSlukem Debug( LDAP_DEBUG_ANY,
2012de962bdSlukem "[%s:%d] aliased"
2022de962bdSlukem " rewriteContext '%s'"
2032de962bdSlukem " does not exists\n",
2042de962bdSlukem fname, lineno,
2052de962bdSlukem argv[ 3 ] );
2062de962bdSlukem return -1;
2072de962bdSlukem }
2082de962bdSlukem
2092de962bdSlukem rewrite_int_curr_context->lc_alias = aliased;
2102de962bdSlukem rewrite_int_curr_context = aliased;
2112de962bdSlukem
2122de962bdSlukem } else {
2132de962bdSlukem Debug( LDAP_DEBUG_ANY,
2142de962bdSlukem "[%s:%d] extra fields"
2152de962bdSlukem " in rewriteContext"
216*549b59edSchristos " will be discarded\n",
217*549b59edSchristos fname, lineno );
2182de962bdSlukem }
2192de962bdSlukem }
2202de962bdSlukem rc = REWRITE_SUCCESS;
2212de962bdSlukem
2222de962bdSlukem /*
2232de962bdSlukem * Compile a rule in current context
2242de962bdSlukem */
2252de962bdSlukem } else if ( strcasecmp( argv[ 0 ], "rewriteRule" ) == 0 ) {
2262de962bdSlukem if ( argc < 3 ) {
2272de962bdSlukem Debug( LDAP_DEBUG_ANY,
2282de962bdSlukem "[%s:%d] rewriteRule needs 'pattern'"
229*549b59edSchristos " 'subst' ['flags']\n",
230*549b59edSchristos fname, lineno );
2312de962bdSlukem return -1;
2322de962bdSlukem
2332de962bdSlukem } else if ( argc > 4 ) {
2342de962bdSlukem Debug( LDAP_DEBUG_ANY,
2352de962bdSlukem "[%s:%d] extra fields in rewriteRule"
236*549b59edSchristos " will be discarded\n",
237*549b59edSchristos fname, lineno );
2382de962bdSlukem }
2392de962bdSlukem
2402de962bdSlukem if ( rewrite_int_curr_context == NULL ) {
2412de962bdSlukem Debug( LDAP_DEBUG_ANY,
2422de962bdSlukem "[%s:%d] rewriteRule outside a"
243*549b59edSchristos " context; will add to default\n",
244*549b59edSchristos fname, lineno );
2452de962bdSlukem rewrite_int_curr_context = rewrite_context_find( info,
2462de962bdSlukem REWRITE_DEFAULT_CONTEXT );
2472de962bdSlukem
2482de962bdSlukem /*
2492de962bdSlukem * Default context MUST exist in a properly initialized
2502de962bdSlukem * struct rewrite_info
2512de962bdSlukem */
2522de962bdSlukem assert( rewrite_int_curr_context != NULL );
2532de962bdSlukem }
2542de962bdSlukem
2552de962bdSlukem rc = rewrite_rule_compile( info, rewrite_int_curr_context, argv[ 1 ],
2562de962bdSlukem argv[ 2 ], ( argc == 4 ? argv[ 3 ] : "" ) );
2572de962bdSlukem
2582de962bdSlukem /*
2592de962bdSlukem * Add a plugin map to the map tree
2602de962bdSlukem */
2612de962bdSlukem } else if ( strcasecmp( argv[ 0 ], "rewriteMap" ) == 0 ) {
2622de962bdSlukem if ( argc < 3 ) {
2632de962bdSlukem Debug( LDAP_DEBUG_ANY,
2642de962bdSlukem "[%s:%d] rewriteMap needs at least 'type'"
265*549b59edSchristos " and 'name' ['args']\n",
266*549b59edSchristos fname, lineno );
2672de962bdSlukem return -1;
2682de962bdSlukem }
2692de962bdSlukem
2702de962bdSlukem rc = rewrite_parse_builtin_map( info, fname, lineno,
2712de962bdSlukem argc, argv );
2722de962bdSlukem
2732de962bdSlukem /*
2742de962bdSlukem * Set the value of a global scope parameter
2752de962bdSlukem */
2762de962bdSlukem } else if ( strcasecmp( argv[ 0 ], "rewriteParam" ) == 0 ) {
2772de962bdSlukem if ( argc < 3 ) {
2782de962bdSlukem Debug( LDAP_DEBUG_ANY,
2792de962bdSlukem "[%s:%d] rewriteParam needs 'name'"
280*549b59edSchristos " and 'value'\n",
281*549b59edSchristos fname, lineno );
2822de962bdSlukem return -1;
2832de962bdSlukem }
2842de962bdSlukem
2852de962bdSlukem rc = rewrite_param_set( info, argv[ 1 ], argv[ 2 ] );
2862de962bdSlukem
2872de962bdSlukem /*
2882de962bdSlukem * Error
2892de962bdSlukem */
2902de962bdSlukem } else {
2912de962bdSlukem Debug( LDAP_DEBUG_ANY,
2922de962bdSlukem "[%s:%d] unknown command '%s'\n",
293*549b59edSchristos fname, lineno, argv[ 0 ] );
2942de962bdSlukem return -1;
2952de962bdSlukem }
2962de962bdSlukem
2972de962bdSlukem return rc;
2982de962bdSlukem }
2992de962bdSlukem
3002de962bdSlukem /*
3012de962bdSlukem * Compares two maps
3022de962bdSlukem */
3032de962bdSlukem static int
rewrite_builtin_map_cmp(const void * c1,const void * c2)3042de962bdSlukem rewrite_builtin_map_cmp(
3052de962bdSlukem const void *c1,
3062de962bdSlukem const void *c2
3072de962bdSlukem )
3082de962bdSlukem {
3092de962bdSlukem const struct rewrite_builtin_map *m1, *m2;
3102de962bdSlukem
3112de962bdSlukem m1 = ( const struct rewrite_builtin_map * )c1;
3122de962bdSlukem m2 = ( const struct rewrite_builtin_map * )c2;
3132de962bdSlukem
3142de962bdSlukem assert( m1 != NULL );
3152de962bdSlukem assert( m2 != NULL );
3162de962bdSlukem assert( m1->lb_name != NULL );
3172de962bdSlukem assert( m2->lb_name != NULL );
3182de962bdSlukem
3192de962bdSlukem return strcasecmp( m1->lb_name, m2->lb_name );
3202de962bdSlukem }
3212de962bdSlukem
3222de962bdSlukem /*
3232de962bdSlukem * Duplicate map ?
3242de962bdSlukem */
3252de962bdSlukem static int
rewrite_builtin_map_dup(void * c1,void * c2)3262de962bdSlukem rewrite_builtin_map_dup(
3272de962bdSlukem void *c1,
3282de962bdSlukem void *c2
3292de962bdSlukem )
3302de962bdSlukem {
3312de962bdSlukem struct rewrite_builtin_map *m1, *m2;
3322de962bdSlukem
3332de962bdSlukem m1 = ( struct rewrite_builtin_map * )c1;
3342de962bdSlukem m2 = ( struct rewrite_builtin_map * )c2;
3352de962bdSlukem
3362de962bdSlukem assert( m1 != NULL );
3372de962bdSlukem assert( m2 != NULL );
3382de962bdSlukem assert( m1->lb_name != NULL );
3392de962bdSlukem assert( m2->lb_name != NULL );
3402de962bdSlukem
3412de962bdSlukem return ( strcasecmp( m1->lb_name, m2->lb_name ) == 0 ? -1 : 0 );
3422de962bdSlukem }
3432de962bdSlukem
3442de962bdSlukem /*
3452de962bdSlukem * Adds a map to the info map tree
3462de962bdSlukem */
3472de962bdSlukem static int
rewrite_builtin_map_insert(struct rewrite_info * info,struct rewrite_builtin_map * map)3482de962bdSlukem rewrite_builtin_map_insert(
3492de962bdSlukem struct rewrite_info *info,
3502de962bdSlukem struct rewrite_builtin_map *map
3512de962bdSlukem )
3522de962bdSlukem {
3532de962bdSlukem /*
3542de962bdSlukem * May need a mutex?
3552de962bdSlukem */
356*549b59edSchristos return ldap_avl_insert( &info->li_maps, ( caddr_t )map,
3572de962bdSlukem rewrite_builtin_map_cmp,
3582de962bdSlukem rewrite_builtin_map_dup );
3592de962bdSlukem }
3602de962bdSlukem
3612de962bdSlukem /*
3622de962bdSlukem * Retrieves a map
3632de962bdSlukem */
3642de962bdSlukem struct rewrite_builtin_map *
rewrite_builtin_map_find(struct rewrite_info * info,const char * name)3652de962bdSlukem rewrite_builtin_map_find(
3662de962bdSlukem struct rewrite_info *info,
3672de962bdSlukem const char *name
3682de962bdSlukem )
3692de962bdSlukem {
3702de962bdSlukem struct rewrite_builtin_map tmp;
3712de962bdSlukem
3722de962bdSlukem assert( info != NULL );
3732de962bdSlukem assert( name != NULL );
3742de962bdSlukem
3752de962bdSlukem tmp.lb_name = ( char * )name;
3762de962bdSlukem
377*549b59edSchristos return ( struct rewrite_builtin_map * )ldap_avl_find( info->li_maps,
3782de962bdSlukem ( caddr_t )&tmp, rewrite_builtin_map_cmp );
3792de962bdSlukem }
3802de962bdSlukem
3812de962bdSlukem /*
3822de962bdSlukem * Parses a plugin map
3832de962bdSlukem */
3842de962bdSlukem static int
rewrite_parse_builtin_map(struct rewrite_info * info,const char * fname,int lineno,int argc,char ** argv)3852de962bdSlukem rewrite_parse_builtin_map(
3862de962bdSlukem struct rewrite_info *info,
3872de962bdSlukem const char *fname,
3882de962bdSlukem int lineno,
3892de962bdSlukem int argc,
3902de962bdSlukem char **argv
3912de962bdSlukem )
3922de962bdSlukem {
3932de962bdSlukem struct rewrite_builtin_map *map;
3942de962bdSlukem
3952de962bdSlukem #define MAP_TYPE 1
3962de962bdSlukem #define MAP_NAME 2
3972de962bdSlukem
3982de962bdSlukem assert( info != NULL );
3992de962bdSlukem assert( fname != NULL );
4002de962bdSlukem assert( argc > 2 );
4012de962bdSlukem assert( argv != NULL );
4022de962bdSlukem assert( strcasecmp( argv[ 0 ], "rewriteMap" ) == 0 );
4032de962bdSlukem
4042de962bdSlukem map = calloc( sizeof( struct rewrite_builtin_map ), 1 );
4052de962bdSlukem if ( map == NULL ) {
4062de962bdSlukem return REWRITE_ERR;
4072de962bdSlukem }
4082de962bdSlukem
4092de962bdSlukem map->lb_name = strdup( argv[ MAP_NAME ] );
4102de962bdSlukem if ( map->lb_name == NULL ) {
4112de962bdSlukem free( map );
4122de962bdSlukem return REWRITE_ERR;
4132de962bdSlukem }
4142de962bdSlukem
4152de962bdSlukem /*
4162de962bdSlukem * Built-in ldap map
4172de962bdSlukem */
4182de962bdSlukem if (( map->lb_mapper = rewrite_mapper_find( argv[ MAP_TYPE ] ))) {
4192de962bdSlukem map->lb_type = REWRITE_BUILTIN_MAP;
4202de962bdSlukem
4212de962bdSlukem #ifdef USE_REWRITE_LDAP_PVT_THREADS
4222de962bdSlukem if ( ldap_pvt_thread_mutex_init( & map->lb_mutex ) ) {
4232de962bdSlukem free( map->lb_name );
4242de962bdSlukem free( map );
4252de962bdSlukem return REWRITE_ERR;
4262de962bdSlukem }
4272de962bdSlukem #endif /* USE_REWRITE_LDAP_PVT_THREADS */
4282de962bdSlukem
4292de962bdSlukem map->lb_private = map->lb_mapper->rm_config( fname, lineno,
4302de962bdSlukem argc - 3, argv + 3 );
4312de962bdSlukem
4322de962bdSlukem /*
4332de962bdSlukem * Error
4342de962bdSlukem */
4352de962bdSlukem } else {
4362de962bdSlukem free( map );
437*549b59edSchristos Debug( LDAP_DEBUG_ANY, "[%s:%d] unknown map type\n",
438*549b59edSchristos fname, lineno );
4392de962bdSlukem return -1;
4402de962bdSlukem }
4412de962bdSlukem
4422de962bdSlukem return rewrite_builtin_map_insert( info, map );
4432de962bdSlukem }
444