/* $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 Ondřej Kuzník for inclusion in OpenLDAP
* Software.
*/
#include
#define LDAP_DEPRECATED 1
#include "rewrite-int.h"
#include "rewrite-map.h"
#include
typedef int (escape_fn)( struct berval *input, struct berval *output );
/*
* Map configuration, a NULL-terminated list of escape_fn pointers
*/
struct escape_map_data {
escape_fn **fn;
};
/*
* (un)escape functions
*/
static int
map_escape_to_filter( struct berval *input, struct berval *output )
{
return ldap_bv2escaped_filter_value( input, output );
}
static int
map_unescape_filter( struct berval *input, struct berval *output )
{
ber_slen_t len;
if ( ber_dupbv( output, input ) == NULL ) {
return REWRITE_ERR;
}
len = ldap_pvt_filter_value_unescape( output->bv_val );
if ( len < 0 ) {
ber_memfree( output->bv_val );
return REWRITE_ERR;
}
output->bv_len = len;
return LDAP_SUCCESS;
}
static int
map_escape_to_dn( struct berval *input, struct berval *output )
{
LDAPAVA ava = { .la_attr = BER_BVC("uid"),
.la_value = *input,
.la_flags = LDAP_AVA_STRING },
*ava_[] = { &ava, NULL };
LDAPRDN rdn[] = { ava_, NULL };
LDAPDN dn = rdn;
struct berval dnstr;
char *p;
int rc;
rc = ldap_dn2bv( dn, &dnstr, LDAP_DN_FORMAT_LDAPV3 );
if ( rc != LDAP_SUCCESS ) {
return REWRITE_ERR;
}
p = strchr( dnstr.bv_val, '=' );
p++;
output->bv_len = dnstr.bv_len - ( p - dnstr.bv_val );
output->bv_val = malloc( output->bv_len + 1 );
if ( output->bv_val == NULL ) {
free( dnstr.bv_val );
return REWRITE_ERR;
}
memcpy( output->bv_val, p, output->bv_len );
output->bv_val[output->bv_len] = '\0';
free( dnstr.bv_val );
return REWRITE_SUCCESS;
}
static int
map_unescape_dn( struct berval *input, struct berval *output )
{
LDAPDN dn;
struct berval fake_dn;
char *p;
int rc = REWRITE_SUCCESS;
fake_dn.bv_len = STRLENOF("uid=") + input->bv_len;
fake_dn.bv_val = p = malloc( fake_dn.bv_len + 1 );
if ( p == NULL ) {
return REWRITE_ERR;
}
memcpy( p, "uid=", STRLENOF("uid=") );
p += STRLENOF("uid=");
memcpy( p, input->bv_val, input->bv_len );
fake_dn.bv_val[fake_dn.bv_len] = '\0';
if ( ldap_bv2dn( &fake_dn, &dn, LDAP_DN_FORMAT_LDAPV3 ) != LDAP_SUCCESS ) {
free( fake_dn.bv_val );
return REWRITE_ERR;
}
if ( ber_dupbv( output, &dn[0][0]->la_value ) == NULL ) {
rc = REWRITE_ERR;
}
ldap_dnfree( dn );
free( fake_dn.bv_val );
return rc;
}
/* Registered callbacks */
static void *
map_escape_parse(
const char *fname,
int lineno,
int argc,
char **argv
)
{
escape_fn **fns;
int i;
assert( fname != NULL );
assert( argv != NULL );
if ( argc < 1 ) {
Debug( LDAP_DEBUG_ANY,
"[%s:%d] escape map needs at least one operation\n",
fname, lineno );
return NULL;
}
fns = calloc( sizeof(escape_fn *), argc + 1 );
if ( fns == NULL ) {
return NULL;
}
for ( i = 0; i < argc; i++ ) {
if ( strcasecmp( argv[i], "escape2dn" ) == 0 ) {
fns[i] = map_escape_to_dn;
} else if ( strcasecmp( argv[i], "escape2filter" ) == 0 ) {
fns[i] = map_escape_to_filter;
} else if ( strcasecmp( argv[i], "unescapedn" ) == 0 ) {
fns[i] = map_unescape_dn;
} else if ( strcasecmp( argv[i], "unescapefilter" ) == 0 ) {
fns[i] = map_unescape_filter;
} else {
Debug( LDAP_DEBUG_ANY,
"[%s:%d] unknown option %s (ignored)\n",
fname, lineno, argv[i] );
free( fns );
return NULL;
}
}
return (void *)fns;
}
static int
map_escape_apply(
void *private,
const char *input,
struct berval *output )
{
escape_fn **fns = private;
struct berval tmpin, tmpout = BER_BVNULL;
int i;
assert( private != NULL );
assert( input != NULL );
assert( output != NULL );
ber_str2bv( input, 0, 1, &tmpin );
for ( i=0; fns[i]; i++ ) {
int rc = fns[i]( &tmpin, &tmpout );
free( tmpin.bv_val );
if ( rc != REWRITE_SUCCESS ) {
return rc;
}
tmpin = tmpout;
BER_BVZERO( &tmpout );
}
*output = tmpin;
return REWRITE_SUCCESS;
}
static int
map_escape_destroy(
void *private
)
{
struct ldap_map_data *data = private;
assert( private != NULL );
free( data );
return 0;
}
const rewrite_mapper rewrite_escape_mapper = {
"escape",
map_escape_parse,
map_escape_apply,
map_escape_destroy
};