openldap/libraries/librewrite/ldapmap.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

334 lines
7.3 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"
#include "rewrite-map.h"
/*
* LDAP map data structure
*/
struct ldap_map_data {
char *url;
LDAPURLDesc *lud;
int attrsonly;
char *binddn;
char *bindpw;
#define MAP_LDAP_EVERYTIME 0x00
#define MAP_LDAP_NOW 0x01
#define MAP_LDAP_LATER 0x02
int when;
LDAP *ld;
#ifdef USE_REWRITE_LDAP_PVT_THREADS
ldap_pvt_thread_mutex_t mutex;
#endif /* USE_REWRITE_LDAP_PVT_THREADS */
};
static void
map_ldap_free(
struct ldap_map_data *data
)
{
assert( data != NULL );
if ( data->url != NULL ) {
free( data->url );
}
if ( data->lud != NULL ) {
ldap_free_urldesc( data->lud );
}
if ( data->binddn != NULL ) {
free( data->binddn );
}
if ( data->bindpw != NULL ) {
free( data->bindpw );
}
if ( data->when != MAP_LDAP_EVERYTIME && data->ld != NULL ) {
ldap_unbind_s( data->ld );
}
free( data );
}
void *
map_ldap_parse(
struct rewrite_info *info,
const char *fname,
int lineno,
int argc,
char **argv
)
{
struct ldap_map_data *data;
char *p;
assert( info != NULL );
assert( fname != NULL );
assert( argv != NULL );
data = calloc( sizeof( struct ldap_map_data ), 1 );
if ( data == NULL ) {
return NULL;
}
if ( argc < 1 ) {
Debug( LDAP_DEBUG_ANY,
"[%s:%d] ldap map needs URI\n%s",
fname, lineno, "" );
free( data );
return NULL;
}
data->url = strdup( argv[ 0 ] );
if ( data->url == NULL ) {
map_ldap_free( data );
return NULL;
}
if ( ldap_url_parse( argv[ 0 ], &data->lud ) != REWRITE_SUCCESS ) {
Debug( LDAP_DEBUG_ANY,
"[%s:%d] illegal URI '%s'\n",
fname, lineno, argv[ 0 ] );
map_ldap_free( data );
return NULL;
}
p = strchr( data->url, '/' );
assert( p[ 1 ] == '/' );
if ( ( p = strchr( p + 2, '/' ) ) != NULL ) {
p[ 0 ] = '\0';
}
if ( strcasecmp( data->lud->lud_attrs[ 0 ], "dn" ) == 0 ) {
data->attrsonly = 1;
}
for ( argc--, argv++; argc > 0; argc--, argv++ ) {
if ( strncasecmp( argv[ 0 ], "binddn=", 7 ) == 0 ) {
char *p = argv[ 0 ] + 7;
int l;
if ( p[ 0 ] == '\"' || p [ 0 ] == '\'' ) {
l = strlen( p ) - 2;
p++;
if ( p[ l ] != p[ 0 ] ) {
map_ldap_free( data );
return NULL;
}
} else {
l = strlen( p );
}
data->binddn = strdup( p );
if ( data->binddn == NULL ) {
map_ldap_free( data );
return NULL;
}
if ( data->binddn[ l ] == '\"'
|| data->binddn[ l ] == '\'' ) {
data->binddn[ l ] = '\0';
}
} else if ( strncasecmp( argv[ 0 ], "bindpw=", 7 ) == 0 ) {
data->bindpw = strdup( argv[ 2 ] + 7 );
if ( data->bindpw == NULL ) {
map_ldap_free( data );
return NULL;
}
} else if ( strncasecmp( argv[ 0 ], "bindwhen=", 9 ) == 0 ) {
char *p = argv[ 0 ] + 9;
if ( strcasecmp( p, "now" ) == 0 ) {
int rc;
data->when = MAP_LDAP_NOW;
/*
* Init LDAP handler ...
*/
rc = ldap_initialize( &data->ld, data->url );
if ( rc != LDAP_SUCCESS ) {
map_ldap_free( data );
return NULL;
}
#ifdef USE_REWRITE_LDAP_PVT_THREADS
ldap_pvt_thread_mutex_init( &data->mutex );
#endif /* USE_REWRITE_LDAP_PVT_THREADS */
} else if ( strcasecmp( p, "later" ) == 0 ) {
data->when = MAP_LDAP_LATER;
#ifdef USE_REWRITE_LDAP_PVT_THREADS
ldap_pvt_thread_mutex_init( &data->mutex );
#endif /* USE_REWRITE_LDAP_PVT_THREADS */
} else if ( strcasecmp( p, "everytime" ) == 0 ) {
data->when = MAP_LDAP_EVERYTIME;
} else {
/* ignore ... */
}
}
}
return ( void * )data;
}
int
map_ldap_apply(
struct rewrite_builtin_map *map,
const char *filter,
struct berval *val
)
{
LDAP *ld;
LDAPMessage *res = NULL, *entry;
char **values;
int rc;
struct ldap_map_data *data = ( struct ldap_map_data * )map->lb_private;
LDAPURLDesc *lud = data->lud;
int first_try = 1;
assert( map != NULL );
assert( map->lb_type == REWRITE_BUILTIN_MAP_LDAP );
assert( map->lb_private != NULL );
assert( filter != NULL );
assert( val != NULL );
val->bv_val = NULL;
val->bv_len = 0;
if ( data->when == MAP_LDAP_EVERYTIME ) {
rc = ldap_initialize( &ld, data->url );
} else {
#ifdef USE_REWRITE_LDAP_PVT_THREADS
ldap_pvt_thread_mutex_lock( &data->mutex );
#endif /* USE_REWRITE_LDAP_PVT_THREADS */
rc = LDAP_SUCCESS;
if ( data->when == MAP_LDAP_LATER && data->ld == NULL ) {
rc = ldap_initialize( &data->ld, data->url );
}
ld = data->ld;
}
if ( rc != LDAP_SUCCESS ) {
rc = REWRITE_ERR;
goto rc_return;
}
do_bind:
if ( data->binddn != NULL ) {
rc = ldap_simple_bind_s( ld, data->binddn, data->bindpw );
if ( rc == LDAP_SERVER_DOWN && first_try ) {
first_try = 0;
if ( ldap_initialize( &ld, data->url ) != LDAP_SUCCESS ) {
rc = REWRITE_ERR;
goto rc_return;
}
goto do_bind;
} else if ( rc != REWRITE_SUCCESS ) {
rc = REWRITE_ERR;
goto rc_return;
}
}
rc = ldap_search_s( ld, lud->lud_dn, lud->lud_scope, ( char * )filter,
lud->lud_attrs, data->attrsonly, &res );
if ( rc == LDAP_SERVER_DOWN && first_try ) {
first_try = 0;
if ( ldap_initialize( &ld, data->url ) != LDAP_SUCCESS ) {
rc = REWRITE_ERR;
goto rc_return;
}
goto do_bind;
} else if ( rc != REWRITE_SUCCESS ) {
rc = REWRITE_ERR;
goto rc_return;
}
if ( ldap_count_entries( ld, res ) != 1 ) {
ldap_msgfree( res );
rc = REWRITE_ERR;
goto rc_return;
}
entry = ldap_first_entry( ld, res );
assert( entry != NULL );
if ( data->attrsonly == 1 ) {
/*
* dn is newly allocated, so there's no need to strdup it
*/
val->bv_val = ldap_get_dn( ld, entry );
} else {
values = ldap_get_values( ld, entry, lud->lud_attrs[ 0 ] );
if ( values == NULL || values[ 0 ] == NULL ) {
if ( values != NULL ) {
ldap_value_free( values );
}
ldap_msgfree( res );
rc = REWRITE_ERR;
goto rc_return;
}
val->bv_val = strdup( values[ 0 ] );
ldap_value_free( values );
}
ldap_msgfree( res );
if ( val->bv_val == NULL ) {
rc = REWRITE_ERR;
goto rc_return;
}
val->bv_len = strlen( val->bv_val );
rc_return:
if ( data->when == MAP_LDAP_EVERYTIME ) {
if ( ld != NULL ) {
ldap_unbind_s( ld );
}
} else {
data->ld = ld;
#ifdef USE_REWRITE_LDAP_PVT_THREADS
ldap_pvt_thread_mutex_unlock( &data->mutex );
#endif /* USE_REWRITE_LDAP_PVT_THREADS */
}
return rc;
}