openldap/libraries/librewrite/subst.c
Pierangelo Masarati 74fa239a20 This is the commit of:
- librewrite, for string rewriting; it may be used in back-ldap
    by configuring with '--enable-rewrite'. It must be used in
    back-meta. There's a text file, 'libraries/librewrite/RATIONALE',
    that explains the usage and the features. More comprehensive
    documentation will follow.
  - enhancements of back-ldap (ITS#989,ITS#998,ITS#1002,ITS#1054 and ITS#1137)
    including dn rewriting, a fix to group acl matching and so
  - back-meta: a new backend that proxies a set of remote servers
    by spawning queries. It uses portions of back-ldap and the rewrite
    capabilities of librewrite. It can be compiled by configuring
    with `--enable-ldap --enable-rewrite --enable-meta'.
    There's a text file, 'servers/slapd/back-meta/Documentation', that
    describes the main features and config statements.

Note: someone (Kurt?) should run 'autoconf' and commit 'configure' as
my autoconf version must be different: my configures contain a number
of differences and I didn't feel comfortable in adding them :)
2001-05-12 00:51:28 +00:00

428 lines
9.4 KiB
C

/******************************************************************************
*
* Copyright (C) 2000 Pierangelo Masarati, <ando@sys-net.it>
* All rights reserved.
*
* Permission is granted to anyone to use this software for any purpose
* on any computer system, and to alter it and redistribute it, subject
* to the following restrictions:
*
* 1. The author is not responsible for the consequences of use of this
* software, no matter how awful, even if they arise from flaws in it.
*
* 2. The origin of this software must not be misrepresented, either by
* explicit claim or by omission. Since few users ever read sources,
* credits should appear in the documentation.
*
* 3. Altered versions must be plainly marked as such, and must not be
* misrepresented as being the original software. Since few users
* ever read sources, credits should appear in the documentation.
*
* 4. This notice may not be removed or altered.
*
******************************************************************************/
#include <portable.h>
#include "rewrite-int.h"
/*
* Compiles a substitution pattern
*/
struct rewrite_subst *
rewrite_subst_compile(
struct rewrite_info *info,
const char *result
)
{
size_t subs_len;
struct berval **subs = NULL;
struct rewrite_submatch **submatch = NULL;
struct rewrite_subst *s = NULL;
const char *begin, *p;
int nsub = 0, l;
assert( info != NULL );
assert( result != NULL );
/*
* Take care of substitution string
*/
for ( p = begin = result, subs_len = 0; p[ 0 ] != '\0'; p++ ) {
/*
* Keep only single escapes '\'
*/
if ( p[ 0 ] != REWRITE_SUBMATCH_ESCAPE ) {
continue;
} else if ( p[ 1 ] == REWRITE_SUBMATCH_ESCAPE ) {
continue;
}
nsub++;
subs = (struct berval **)realloc( subs,
sizeof( struct berval * )*( nsub + 1 ) );
if ( subs == NULL ) {
/* cleanup */
return NULL;
}
subs[ nsub ] = NULL;
/*
* I think an `if l > 0' at runtime is better outside than
* inside a function call ...
*/
l = p - begin;
if ( l > 0 ) {
subs_len += l;
subs[ nsub - 1 ] =
calloc( sizeof( struct berval ), 1 );
if ( subs[ nsub - 1 ] == NULL ) {
/* cleanup */
return NULL;
}
subs[ nsub - 1 ]->bv_len = l;
subs[ nsub - 1 ]->bv_val = malloc( l + 1 );
if ( subs[ nsub - 1 ]->bv_val == NULL ) {
return NULL;
}
strncpy( subs[ nsub - 1 ]->bv_val, begin, l );
subs[ nsub - 1 ]->bv_val[ l ] = '\0';
} else {
subs[ nsub - 1 ] = NULL;
}
/*
* Substitution pattern
*/
if ( isdigit( p[ 1 ] ) ) {
int d = p[ 1 ] - '0';
/*
* Add a new value substitution scheme
*/
submatch = realloc( submatch,
sizeof( struct rewrite_submatch * )*( nsub + 1 ) );
if ( submatch == NULL ) {
/* cleanup */
return NULL;
}
submatch[ nsub ] = NULL;
submatch[ nsub - 1 ] =
calloc( sizeof( struct rewrite_submatch ), 1 );
if ( submatch[ nsub - 1 ] == NULL ) {
/* cleanup */
return NULL;
}
submatch[ nsub - 1 ]->ls_submatch = d;
/*
* If there is no argument, use default
* (substitute substring as is)
*/
if ( p[ 2 ] != '{' ) {
submatch[ nsub - 1 ]->ls_type =
REWRITE_SUBMATCH_ASIS;
begin = ++p + 1;
} else {
struct rewrite_map *map;
submatch[ nsub - 1 ]->ls_type =
REWRITE_SUBMATCH_XMAP;
map = rewrite_xmap_parse( info,
p + 3, &begin );
if ( map == NULL ) {
/* cleanup */
return NULL;
}
p = begin - 1;
submatch[ nsub - 1 ]->ls_map = map;
}
/*
* Map with args ...
*/
} else if ( p[ 1 ] == '{' ) {
struct rewrite_map *map;
map = rewrite_map_parse( info, p + 2, &begin );
if ( map == NULL ) {
/* cleanup */
return NULL;
}
p = begin - 1;
/*
* Add a new value substitution scheme
*/
submatch = realloc( submatch,
sizeof( struct rewrite_submatch * )*( nsub + 1 ) );
if ( submatch == NULL ) {
/* cleanup */
return NULL;
}
submatch[ nsub ] = NULL;
submatch[ nsub - 1 ] =
calloc( sizeof( struct rewrite_submatch ), 1 );
if ( submatch[ nsub - 1 ] == NULL ) {
/* cleanup */
return NULL;
}
submatch[ nsub - 1 ]->ls_type =
REWRITE_SUBMATCH_MAP_W_ARG;
submatch[ nsub - 1 ]->ls_map = map;
}
}
/*
* Last part of string
*/
subs = realloc( subs, sizeof( struct berval *)*( nsub + 2 ) );
if ( subs == NULL ) {
/*
* XXX need to free the value subst stuff!
*/
free( submatch );
return NULL;
}
subs[ nsub + 1 ] = NULL;
l = p - begin;
if ( l > 0 ) {
subs[ nsub ] = calloc( sizeof( struct berval ), 1 );
subs_len += l;
subs[ nsub ]->bv_len = l;
subs[ nsub ]->bv_val = malloc( l + 1 );
strncpy( subs[ nsub ]->bv_val, begin, l );
subs[ nsub ]->bv_val[ l ] = '\0';
} else {
subs[ nsub ] = NULL;
}
s = calloc( sizeof( struct rewrite_subst ), 1 );
if ( s == NULL ) {
/* cleanup */
return NULL;
}
s->lt_subs_len = subs_len;
s->lt_subs = subs;
s->lt_num_submatch = nsub;
s->lt_submatch = submatch;
return s;
}
/*
* Copies the match referred to by submatch and fetched in string by match.
* Helper for rewrite_rule_apply.
*/
static int
submatch_copy(
struct rewrite_submatch *submatch,
const char *string,
const regmatch_t *match,
struct berval *val
)
{
int c, l;
const char *s;
assert( submatch != NULL );
assert( submatch->ls_type == REWRITE_SUBMATCH_ASIS
|| submatch->ls_type == REWRITE_SUBMATCH_XMAP );
assert( string != NULL );
assert( match != NULL );
assert( val != NULL );
c = submatch->ls_submatch;
s = string + match[ c ].rm_so;
l = match[ c ].rm_eo - match[ c ].rm_so;
val->bv_val = NULL;
val->bv_len = l;
val->bv_val = calloc( sizeof( char ), l + 1 );
if ( val->bv_val == NULL ) {
return REWRITE_ERR;
}
strncpy( val->bv_val, s, l );
val->bv_val[ l ] = '\0';
return REWRITE_SUCCESS;
}
/*
* Substitutes a portion of rewritten string according to substitution
* pattern using submatches
*/
int
rewrite_subst_apply(
struct rewrite_info *info,
struct rewrite_op *op,
struct rewrite_subst *subst,
const char *string,
const regmatch_t *match,
struct berval *val
)
{
struct berval *submatch = NULL;
char *res = NULL;
int n, l, cl;
int rc = REWRITE_REGEXEC_OK;
assert( info != NULL );
assert( op != NULL );
assert( subst != NULL );
assert( string != NULL );
assert( match != NULL );
assert( val != NULL );
val->bv_val = NULL;
val->bv_len = 0;
/*
* Prepare room for submatch expansion
*/
submatch = calloc( sizeof( struct berval ),
subst->lt_num_submatch );
if ( submatch == NULL ) {
return REWRITE_REGEXEC_ERR;
}
/*
* Resolve submatches (simple subst, map expansion and so).
*/
for ( n = 0, l = 0; n < subst->lt_num_submatch; n++ ) {
struct berval key;
int rc;
/*
* Get key
*/
switch( subst->lt_submatch[ n ]->ls_type ) {
case REWRITE_SUBMATCH_ASIS:
case REWRITE_SUBMATCH_XMAP:
rc = submatch_copy( subst->lt_submatch[ n ],
string, match, &key );
if ( rc != REWRITE_SUCCESS ) {
free( submatch );
return REWRITE_REGEXEC_ERR;
}
break;
case REWRITE_SUBMATCH_MAP_W_ARG:
switch ( subst->lt_submatch[ n ]->ls_map->lm_type ) {
case REWRITE_MAP_GET_OP_VAR:
case REWRITE_MAP_GET_SESN_VAR:
case REWRITE_MAP_GET_PARAM:
rc = REWRITE_SUCCESS;
break;
default:
rc = rewrite_subst_apply( info, op,
subst->lt_submatch[ n ]->ls_map->lm_subst,
string, match, &key);
}
if ( rc != REWRITE_SUCCESS ) {
free( submatch );
return REWRITE_REGEXEC_ERR;
}
break;
default:
Debug( LDAP_DEBUG_ANY, "Not Implemented\n%s%s%s",
"", "", "" );
rc = REWRITE_ERR;
break;
}
if ( rc != REWRITE_SUCCESS ) {
free( submatch );
return REWRITE_REGEXEC_ERR;
}
/*
* Resolve key
*/
switch ( subst->lt_submatch[ n ]->ls_type ) {
case REWRITE_SUBMATCH_ASIS:
submatch[ n ] = key;
rc = REWRITE_SUCCESS;
break;
case REWRITE_SUBMATCH_XMAP:
rc = rewrite_xmap_apply( info, op,
subst->lt_submatch[ n ]->ls_map,
&key, &submatch[ n ] );
break;
case REWRITE_SUBMATCH_MAP_W_ARG:
rc = rewrite_map_apply( info, op,
subst->lt_submatch[ n ]->ls_map,
&key, &submatch[ n ] );
break;
default:
/*
* When implemented, this might return the
* exit status of a rewrite context,
* which may include a stop, or an
* unwilling to perform
*/
rc = REWRITE_ERR;
break;
}
if ( rc != REWRITE_SUCCESS ) {
free( submatch );
return REWRITE_REGEXEC_ERR;
}
/*
* Increment the length of the resulting string
*/
l += submatch[ n ].bv_len;
}
/*
* Alloc result buffer as big as the constant part
* of the subst pattern and initialize it
*/
l += subst->lt_subs_len;
res = calloc( sizeof( char ), l + 1 );
if ( res == NULL ) {
free( submatch );
return REWRITE_REGEXEC_ERR;
}
/*
* Apply submatches (possibly resolved thru maps
*/
for ( n = 0, cl = 0; n < subst->lt_num_submatch; n++ ) {
if ( subst->lt_subs[ n ] != NULL ) {
strcpy( res + cl, subst->lt_subs[ n ]->bv_val);
cl += subst->lt_subs[ n ]->bv_len;
}
strcpy( res + cl, submatch[ n ].bv_val );
cl += submatch[ n ].bv_len;
free( submatch[ n ].bv_val );
}
if ( subst->lt_subs[ n ] != NULL ) {
strcpy( res + cl, subst->lt_subs[ n ]->bv_val );
}
val->bv_val = res;
val->bv_len = l;
return rc;
}