/* $OpenLDAP$ */ /* This work is part of OpenLDAP Software . * * Copyright 2000-2015 The OpenLDAP Foundation. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted only as authorized by the OpenLDAP * Public License. * * A copy of this license is available in the file LICENSE in the * top-level directory of the distribution or, alternatively, at * . */ /* ACKNOWLEDGEMENT: * This work was initially developed by Pierangelo Masarati for * inclusion in OpenLDAP Software. */ #include #include "rewrite-int.h" #include "rewrite-map.h" /* * Parses a plugin map */ static int rewrite_parse_builtin_map( struct rewrite_info *info, const char *fname, int lineno, int argc, char **argv ); /* * Parses a config line and takes actions to fit content in rewrite structure; * lines handled are of the form: * * rewriteEngine {on|off} * rewriteMaxPasses numPasses [numPassesPerRule] * rewriteContext contextName [alias aliasedContextName] * rewriteRule pattern substPattern [ruleFlags] * rewriteMap mapType mapName [mapArgs] * rewriteParam paramName paramValue */ int rewrite_parse( struct rewrite_info *info, const char *fname, int lineno, int argc, char **argv ) { int rc = -1; assert( info != NULL ); assert( fname != NULL ); assert( argv != NULL ); assert( argc > 0 ); /* * Switch on the rewrite engine */ if ( strcasecmp( argv[ 0 ], "rewriteEngine" ) == 0 ) { if ( argc < 2 ) { Debug( LDAP_DEBUG_ANY, "[%s:%d] rewriteEngine needs 'state'\n%s", fname, lineno, "" ); return -1; } else if ( argc > 2 ) { Debug( LDAP_DEBUG_ANY, "[%s:%d] extra fields in rewriteEngine" " will be discarded\n%s", fname, lineno, "" ); } if ( strcasecmp( argv[ 1 ], "on" ) == 0 ) { info->li_state = REWRITE_ON; } else if ( strcasecmp( argv[ 1 ], "off" ) == 0 ) { info->li_state = REWRITE_OFF; } else { Debug( LDAP_DEBUG_ANY, "[%s:%d] unknown 'state' in rewriteEngine;" " assuming 'on'\n%s", fname, lineno, "" ); info->li_state = REWRITE_ON; } rc = REWRITE_SUCCESS; /* * Alter max passes */ } else if ( strcasecmp( argv[ 0 ], "rewriteMaxPasses" ) == 0 ) { if ( argc < 2 ) { Debug( LDAP_DEBUG_ANY, "[%s:%d] rewriteMaxPasses needs 'value'\n%s", fname, lineno, "" ); return -1; } if ( lutil_atoi( &info->li_max_passes, argv[ 1 ] ) != 0 ) { Debug( LDAP_DEBUG_ANY, "[%s:%d] unable to parse rewriteMaxPasses=\"%s\"\n", fname, lineno, argv[ 1 ] ); return -1; } if ( info->li_max_passes <= 0 ) { Debug( LDAP_DEBUG_ANY, "[%s:%d] negative or null rewriteMaxPasses\n", fname, lineno, 0 ); return -1; } if ( argc > 2 ) { if ( lutil_atoi( &info->li_max_passes_per_rule, argv[ 2 ] ) != 0 ) { Debug( LDAP_DEBUG_ANY, "[%s:%d] unable to parse rewriteMaxPassesPerRule=\"%s\"\n", fname, lineno, argv[ 2 ] ); return -1; } if ( info->li_max_passes_per_rule <= 0 ) { Debug( LDAP_DEBUG_ANY, "[%s:%d] negative or null rewriteMaxPassesPerRule\n", fname, lineno, 0 ); return -1; } } else { info->li_max_passes_per_rule = info->li_max_passes; } rc = REWRITE_SUCCESS; /* * Start a new rewrite context and set current context */ } else if ( strcasecmp( argv[ 0 ], "rewriteContext" ) == 0 ) { if ( argc < 2 ) { Debug( LDAP_DEBUG_ANY, "[%s:%d] rewriteContext needs 'name'\n%s", fname, lineno, "" ); return -1; } /* * Checks for existence (lots of contexts should be * available by default ...) */ rewrite_int_curr_context = rewrite_context_find( info, argv[ 1 ] ); if ( rewrite_int_curr_context == NULL ) { rewrite_int_curr_context = rewrite_context_create( info, argv[ 1 ] ); } if ( rewrite_int_curr_context == NULL ) { return -1; } if ( argc > 2 ) { /* * A context can alias another (e.g., the `builtin' * contexts for backend operations, if not defined, * alias the `default' rewrite context (with the * notable exception of the searchResult context, * which can be undefined) */ if ( strcasecmp( argv[ 2 ], "alias" ) == 0 ) { struct rewrite_context *aliased; if ( argc == 3 ) { Debug( LDAP_DEBUG_ANY, "[%s:%d] rewriteContext" " needs 'name' after" " 'alias'\n%s", fname, lineno, "" ); return -1; } else if ( argc > 4 ) { Debug( LDAP_DEBUG_ANY, "[%s:%d] extra fields in" " rewriteContext" " after aliased name" " will be" " discarded\n%s", fname, lineno, "" ); } aliased = rewrite_context_find( info, argv[ 3 ] ); if ( aliased == NULL ) { Debug( LDAP_DEBUG_ANY, "[%s:%d] aliased" " rewriteContext '%s'" " does not exists\n", fname, lineno, argv[ 3 ] ); return -1; } rewrite_int_curr_context->lc_alias = aliased; rewrite_int_curr_context = aliased; } else { Debug( LDAP_DEBUG_ANY, "[%s:%d] extra fields" " in rewriteContext" " will be discarded\n%s", fname, lineno, "" ); } } rc = REWRITE_SUCCESS; /* * Compile a rule in current context */ } else if ( strcasecmp( argv[ 0 ], "rewriteRule" ) == 0 ) { if ( argc < 3 ) { Debug( LDAP_DEBUG_ANY, "[%s:%d] rewriteRule needs 'pattern'" " 'subst' ['flags']\n%s", fname, lineno, "" ); return -1; } else if ( argc > 4 ) { Debug( LDAP_DEBUG_ANY, "[%s:%d] extra fields in rewriteRule" " will be discarded\n%s", fname, lineno, "" ); } if ( rewrite_int_curr_context == NULL ) { Debug( LDAP_DEBUG_ANY, "[%s:%d] rewriteRule outside a" " context; will add to default\n%s", fname, lineno, "" ); rewrite_int_curr_context = rewrite_context_find( info, REWRITE_DEFAULT_CONTEXT ); /* * Default context MUST exist in a properly initialized * struct rewrite_info */ assert( rewrite_int_curr_context != NULL ); } rc = rewrite_rule_compile( info, rewrite_int_curr_context, argv[ 1 ], argv[ 2 ], ( argc == 4 ? argv[ 3 ] : "" ) ); /* * Add a plugin map to the map tree */ } else if ( strcasecmp( argv[ 0 ], "rewriteMap" ) == 0 ) { if ( argc < 3 ) { Debug( LDAP_DEBUG_ANY, "[%s:%d] rewriteMap needs at least 'type'" " and 'name' ['args']\n%s", fname, lineno, "" ); return -1; } rc = rewrite_parse_builtin_map( info, fname, lineno, argc, argv ); /* * Set the value of a global scope parameter */ } else if ( strcasecmp( argv[ 0 ], "rewriteParam" ) == 0 ) { if ( argc < 3 ) { Debug( LDAP_DEBUG_ANY, "[%s:%d] rewriteParam needs 'name'" " and 'value'\n%s", fname, lineno, "" ); return -1; } rc = rewrite_param_set( info, argv[ 1 ], argv[ 2 ] ); /* * Error */ } else { Debug( LDAP_DEBUG_ANY, "[%s:%d] unknown command '%s'\n", fname, lineno, "" ); return -1; } return rc; } /* * Compares two maps */ static int rewrite_builtin_map_cmp( const void *c1, const void *c2 ) { const struct rewrite_builtin_map *m1, *m2; m1 = ( const struct rewrite_builtin_map * )c1; m2 = ( const struct rewrite_builtin_map * )c2; assert( m1 != NULL ); assert( m2 != NULL ); assert( m1->lb_name != NULL ); assert( m2->lb_name != NULL ); return strcasecmp( m1->lb_name, m2->lb_name ); } /* * Duplicate map ? */ static int rewrite_builtin_map_dup( void *c1, void *c2 ) { struct rewrite_builtin_map *m1, *m2; m1 = ( struct rewrite_builtin_map * )c1; m2 = ( struct rewrite_builtin_map * )c2; assert( m1 != NULL ); assert( m2 != NULL ); assert( m1->lb_name != NULL ); assert( m2->lb_name != NULL ); return ( strcasecmp( m1->lb_name, m2->lb_name ) == 0 ? -1 : 0 ); } /* * Adds a map to the info map tree */ static int rewrite_builtin_map_insert( struct rewrite_info *info, struct rewrite_builtin_map *map ) { /* * May need a mutex? */ return avl_insert( &info->li_maps, ( caddr_t )map, rewrite_builtin_map_cmp, rewrite_builtin_map_dup ); } /* * Retrieves a map */ struct rewrite_builtin_map * rewrite_builtin_map_find( struct rewrite_info *info, const char *name ) { struct rewrite_builtin_map tmp; assert( info != NULL ); assert( name != NULL ); tmp.lb_name = ( char * )name; return ( struct rewrite_builtin_map * )avl_find( info->li_maps, ( caddr_t )&tmp, rewrite_builtin_map_cmp ); } /* * Parses a plugin map */ static int rewrite_parse_builtin_map( struct rewrite_info *info, const char *fname, int lineno, int argc, char **argv ) { struct rewrite_builtin_map *map; #define MAP_TYPE 1 #define MAP_NAME 2 assert( info != NULL ); assert( fname != NULL ); assert( argc > 2 ); assert( argv != NULL ); assert( strcasecmp( argv[ 0 ], "rewriteMap" ) == 0 ); map = calloc( sizeof( struct rewrite_builtin_map ), 1 ); if ( map == NULL ) { return REWRITE_ERR; } map->lb_name = strdup( argv[ MAP_NAME ] ); if ( map->lb_name == NULL ) { free( map ); return REWRITE_ERR; } /* * Built-in ldap map */ if (( map->lb_mapper = rewrite_mapper_find( argv[ MAP_TYPE ] ))) { map->lb_type = REWRITE_BUILTIN_MAP; #ifdef USE_REWRITE_LDAP_PVT_THREADS if ( ldap_pvt_thread_mutex_init( & map->lb_mutex ) ) { free( map->lb_name ); free( map ); return REWRITE_ERR; } #endif /* USE_REWRITE_LDAP_PVT_THREADS */ map->lb_private = map->lb_mapper->rm_config( fname, lineno, argc - 3, argv + 3 ); /* * Error */ } else { free( map ); Debug( LDAP_DEBUG_ANY, "[%s:%d] unknown map type\n%s", fname, lineno, "" ); return -1; } return rewrite_builtin_map_insert( info, map ); }