mirror of
https://git.openldap.org/openldap/openldap.git
synced 2024-12-15 03:01:09 +08:00
442 lines
9.8 KiB
C
442 lines
9.8 KiB
C
/* $OpenLDAP$ */
|
|
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
|
|
*
|
|
* Copyright 2000-2019 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
|
|
* <http://www.OpenLDAP.org/license.html>.
|
|
*/
|
|
/* ACKNOWLEDGEMENT:
|
|
* This work was initially developed by Pierangelo Masarati for
|
|
* inclusion in OpenLDAP Software.
|
|
*/
|
|
|
|
#include <portable.h>
|
|
|
|
#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 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",
|
|
fname, lineno );
|
|
return -1;
|
|
}
|
|
|
|
return rewrite_builtin_map_insert( info, map );
|
|
}
|