/* $OpenLDAP$ */
/* This work is part of OpenLDAP Software .
*
* Copyright 2000-2022 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",
fname, lineno );
return -1;
} else if ( argc > 2 ) {
Debug( LDAP_DEBUG_ANY,
"[%s:%d] extra fields in rewriteEngine"
" will be discarded\n",
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",
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",
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 );
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 );
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",
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",
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",
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",
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",
fname, lineno );
return -1;
} else if ( argc > 4 ) {
Debug( LDAP_DEBUG_ANY,
"[%s:%d] extra fields in rewriteRule"
" will be discarded\n",
fname, lineno );
}
if ( rewrite_int_curr_context == NULL ) {
Debug( LDAP_DEBUG_ANY,
"[%s:%d] rewriteRule outside a"
" context; will add to default\n",
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",
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",
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, argv[ 0 ] );
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 ldap_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 * )ldap_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",
fname, lineno );
return -1;
}
return rewrite_builtin_map_insert( info, map );
}