From: Kurt Zeilenga Date: Tue, 16 Dec 2003 22:08:27 +0000 (+0000) Subject: Backport -lrewrite fixes (from Ando) X-Git-Tag: OPENLDAP_REL_ENG_2_1_26~27 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=d2facfe14548ac10753958a3b7f49f78e0168a4f;p=thirdparty%2Fopenldap.git Backport -lrewrite fixes (from Ando) Need to flush CHANGES out (with specific ITS #s) --- diff --git a/CHANGES b/CHANGES index f11eb65e13..e89a9d2437 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,7 @@ OpenLDAP 2.1 Change Log OpenLDAP 2.1.25 Release + Update librewrite (misc bug fixes) Build Environment Fix LDBM link bug (ITS#2863) diff --git a/INSTALL b/INSTALL index 51bd3c5612..53df83b625 100644 --- a/INSTALL +++ b/INSTALL @@ -94,8 +94,21 @@ configuration directory (normally /usr/local/etc/openldap). slapd.conf Standalone LDAP daemon schema/*.schema Schema Definitions -End of OpenLDAP INSTALL file. - +--- $OpenLDAP: pkg/openldap-guide/release/install.sdf,v 1.16 2002/02/18 17:09:26 kurt Exp $ +This work is part of OpenLDAP Software . + +Copyright 1998-2003 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 +. + +OpenLDAP is a registered trademark of the OpenLDAP Foundation. diff --git a/build/top.mk b/build/top.mk index 5495b79b00..bad1ba9097 100644 --- a/build/top.mk +++ b/build/top.mk @@ -185,7 +185,6 @@ SECURITY_LIBS = $(SASL_LIBS) $(KRB_LIBS) $(TLS_LIBS) $(AUTH_LIBS) MODULES_CPPFLAGS = @SLAPD_MODULES_CPPFLAGS@ MODULES_LDFLAGS = @SLAPD_MODULES_LDFLAGS@ MODULES_LIBS = @MODULES_LIBS@ -TERMCAP_LIBS = @TERMCAP_LIBS@ SLAPD_PERL_LDFLAGS = @SLAPD_PERL_LDFLAGS@ SLAPD_SQL_LDFLAGS = @SLAPD_SQL_LDFLAGS@ diff --git a/include/rewrite.h b/include/rewrite.h new file mode 100644 index 0000000000..fdf7c1f4df --- /dev/null +++ b/include/rewrite.h @@ -0,0 +1,231 @@ +/****************************************************************************** + * + * Copyright (C) 2000 Pierangelo Masarati, + * 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. + * + ******************************************************************************/ + +#ifndef REWRITE_H +#define REWRITE_H + +/* + * Default rewrite context + */ +#define REWRITE_DEFAULT_CONTEXT "default" + +/* + * Rewrite engine states + */ +#define REWRITE_OFF 0x0000 +#define REWRITE_ON 0x0001 +#define REWRITE_DEFAULT REWRITE_OFF + +/* + * Rewrite internal status returns + */ +#define REWRITE_SUCCESS LDAP_SUCCESS +#define REWRITE_ERR LDAP_OPERATIONS_ERROR +#define REWRITE_NO_SUCH_OBJECT LDAP_NO_SUCH_OBJECT + +/* + * Rewrite modes (input values for rewrite_info_init); determine the + * behavior in case a null or non existent context is required: + * + * REWRITE_MODE_ERR error + * REWRITE_MODE_OK no error but no rewrite + * REWRITE_MODE_COPY_INPUT a copy of the input is returned + * REWRITE_MODE_USE_DEFAULT the default context is used. + */ +#define REWRITE_MODE_ERR 0x0010 +#define REWRITE_MODE_OK 0x0011 +#define REWRITE_MODE_COPY_INPUT 0x0012 +#define REWRITE_MODE_USE_DEFAULT 0x0013 + +/* + * Rewrite status returns + * + * REWRITE_REGEXEC_OK success (result may be empty in case + * of no match) + * REWRITE_REGEXEC_ERR error (internal error, + * misconfiguration, map not working ...) + * REWRITE_REGEXEC_STOP internal use; never returned + * REWRITE_REGEXEC_UNWILLING the server should issue an 'unwilling + * to perform' error + */ +#define REWRITE_REGEXEC_OK 0x0000 +#define REWRITE_REGEXEC_ERR 0x0001 +#define REWRITE_REGEXEC_STOP 0x0002 +#define REWRITE_REGEXEC_UNWILLING 0x0004 + +/* + * Rewrite info + */ +struct rewrite_info; + +struct berval; /* avoid include */ + +LDAP_BEGIN_DECL + +/* + * Inits the info + */ +LDAP_REWRITE_F (struct rewrite_info *) +rewrite_info_init( + int mode +); + +/* + * Cleans up the info structure + */ +LDAP_REWRITE_F (int) +rewrite_info_delete( + struct rewrite_info **info +); + + +/* + * Parses a config line and takes actions to fit content in rewrite structure; + * lines handled are of the form: + * + * rewriteEngine {on|off} + * rewriteMaxPasses numPasses + * rewriteContext contextName [alias aliasedRewriteContex] + * rewriteRule pattern substPattern [ruleFlags] + * rewriteMap mapType mapName [mapArgs] + * rewriteParam paramName paramValue + */ +LDAP_REWRITE_F (int) +rewrite_parse( + struct rewrite_info *info, + const char *fname, + int lineno, + int argc, + char **argv +); + +/* + * process a config file that was already opened. Uses rewrite_parse. + */ +LDAP_REWRITE_F (int) +rewrite_read( + FILE *fin, + struct rewrite_info *info +); + +/* + * Rewrites a string according to context. + * If the engine is off, OK is returned, but the return string will be NULL. + * In case of 'unwilling to perform', UNWILLING is returned, and the + * return string will also be null. The same in case of error. + * Otherwise, OK is returned, and result will hold a newly allocated string + * with the rewriting. + * + * What to do in case of non-existing rewrite context is still an issue. + * Four possibilities: + * - error, + * - ok with NULL result, + * - ok with copy of string as result, + * - use the default rewrite context. + */ +LDAP_REWRITE_F (int) +rewrite( + struct rewrite_info *info, + const char *rewriteContext, + const char *string, + char **result +); + +/* + * Same as above; the cookie relates the rewrite to a session + */ +LDAP_REWRITE_F (int) +rewrite_session( + struct rewrite_info *info, + const char *rewriteContext, + const char *string, + const void *cookie, + char **result +); + +/* + * Inits a session + */ +LDAP_REWRITE_F (struct rewrite_session *) +rewrite_session_init( + struct rewrite_info *info, + const void *cookie +); + +/* + * Defines and inits a variable with session scope + */ +LDAP_REWRITE_F (int) +rewrite_session_var_set( + struct rewrite_info *info, + const void *cookie, + const char *name, + const char *value +); + +/* + * Deletes a session + */ +LDAP_REWRITE_F (int) +rewrite_session_delete( + struct rewrite_info *info, + const void *cookie +); + + +/* + * Params + */ + +/* + * Defines and inits a variable with global scope + */ +LDAP_REWRITE_F (int) +rewrite_param_set( + struct rewrite_info *info, + const char *name, + const char *value +); + +/* + * Gets a var with global scope + */ +LDAP_REWRITE_F (int) +rewrite_param_get( + struct rewrite_info *info, + const char *name, + struct berval *value +); + +/* + * Destroys the parameter tree + */ +LDAP_REWRITE_F (int) +rewrite_param_destroy( + struct rewrite_info *info +); + +LDAP_END_DECL + +#endif /* REWRITE_H */ diff --git a/libraries/librewrite/Makefile.in b/libraries/librewrite/Makefile.in index f2e4cdfa6a..f8e55bfd86 100644 --- a/libraries/librewrite/Makefile.in +++ b/libraries/librewrite/Makefile.in @@ -8,11 +8,11 @@ ## SRCS = config.c context.c info.c ldapmap.c map.c params.c rule.c \ - session.c subst.c var.c \ + session.c subst.c var.c xmap.c \ parse.c rewrite.c XSRCS = version.c OBJS = config.o context.o info.o ldapmap.o map.o params.o rule.o \ - session.o subst.o var.o + session.o subst.o var.o xmap.o LDAP_INCDIR= ../../include LDAP_LIBDIR= ../../libraries @@ -21,7 +21,7 @@ LIBRARY = librewrite.a PROGRAMS = rewrite XLIBS = $(LIBRARY) $(LDAP_LIBAVL_A) $(LDAP_LIBLUTIL_A) \ $(LDAP_LIBLDAP_R_LA) $(LDAP_LIBLBER_LA) -XXLIBS = $(SECURITY_LIBS) $(LDIF_LIBS) $(LUTIL_LIBS) +XXLIBS = $(SECURITY_LIBS) $(LUTIL_LIBS) XXXLIBS = $(LTHREAD_LIBS) rewrite: $(XLIBS) rewrite.o parse.o diff --git a/libraries/librewrite/config.c b/libraries/librewrite/config.c index 556fd30947..514b16c415 100644 --- a/libraries/librewrite/config.c +++ b/libraries/librewrite/config.c @@ -75,6 +75,7 @@ rewrite_parse( "[%s:%d] rewriteEngine needs 'state'\n%s", fname, lineno, "" ); return -1; + } else if ( argc > 2 ) { Debug( LDAP_DEBUG_ANY, "[%s:%d] extra fields in rewriteEngine" @@ -84,8 +85,10 @@ rewrite_parse( 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;" @@ -123,12 +126,12 @@ rewrite_parse( * Checks for existence (lots of contexts should be * available by default ...) */ - __curr_context = rewrite_context_find( info, argv[ 1 ] ); - if ( __curr_context == NULL ) { - __curr_context = rewrite_context_create( info, + 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 ( __curr_context == NULL ) { + if ( rewrite_int_curr_context == NULL ) { return -1; } @@ -151,6 +154,7 @@ rewrite_parse( " 'alias'\n%s", fname, lineno, "" ); return -1; + } else if ( argc > 4 ) { Debug( LDAP_DEBUG_ANY, "[%s:%d] extra fields in" @@ -173,8 +177,9 @@ rewrite_parse( return -1; } - __curr_context->lc_alias = aliased; - __curr_context = aliased; + rewrite_int_curr_context->lc_alias = aliased; + rewrite_int_curr_context = aliased; + } else { Debug( LDAP_DEBUG_ANY, "[%s:%d] extra fields" @@ -195,6 +200,7 @@ rewrite_parse( " 'subst' ['flags']\n%s", fname, lineno, "" ); return -1; + } else if ( argc > 4 ) { Debug( LDAP_DEBUG_ANY, "[%s:%d] extra fields in rewriteRule" @@ -202,22 +208,22 @@ rewrite_parse( fname, lineno, "" ); } - if ( __curr_context == NULL ) { + if ( rewrite_int_curr_context == NULL ) { Debug( LDAP_DEBUG_ANY, "[%s:%d] rewriteRule outside a" " context; will add to default\n%s", fname, lineno, "" ); - __curr_context = rewrite_context_find( info, + rewrite_int_curr_context = rewrite_context_find( info, REWRITE_DEFAULT_CONTEXT ); /* * Default context MUST exist in a properly initialized * struct rewrite_info */ - assert( __curr_context != NULL ); + assert( rewrite_int_curr_context != NULL ); } - rc = rewrite_rule_compile( info, __curr_context, argv[ 1 ], + rc = rewrite_rule_compile( info, rewrite_int_curr_context, argv[ 1 ], argv[ 2 ], ( argc == 4 ? argv[ 3 ] : "" ) ); /* diff --git a/libraries/librewrite/context.c b/libraries/librewrite/context.c index 115cca6f1e..e77b485165 100644 --- a/libraries/librewrite/context.c +++ b/libraries/librewrite/context.c @@ -144,6 +144,7 @@ rewrite_context_create( free( context ); return NULL; } + memset( context->lc_rule, 0, sizeof( struct rewrite_rule ) ); /* * Add context to tree @@ -250,7 +251,7 @@ rewrite_context_apply( case REWRITE_REGEXEC_ERR: Debug( LDAP_DEBUG_ANY, "==> rewrite_context_apply" - " error ...\n%s%s%s", "", "", ""); + " error ...\n", 0, 0, 0); /* * Checks for special actions to be taken @@ -272,8 +273,7 @@ rewrite_context_apply( case REWRITE_ACTION_IGNORE_ERR: Debug( LDAP_DEBUG_ANY, "==> rewrite_context_apply" - " ignoring error ...\n%s%s%s", - "", "", "" ); + " ignoring error ...\n", 0, 0, 0 ); do_continue = 1; break; @@ -413,3 +413,49 @@ rc_end_of_context:; return return_code; } +void +rewrite_context_free( + void *tmp +) +{ + struct rewrite_context *context = (struct rewrite_context *)tmp; + + assert( tmp ); + + rewrite_context_destroy( &context ); +} + +int +rewrite_context_destroy( + struct rewrite_context **pcontext +) +{ + struct rewrite_context *context; + struct rewrite_rule *r; + + assert( pcontext ); + assert( *pcontext ); + + context = *pcontext; + + assert( context->lc_rule ); + + for ( r = context->lc_rule->lr_next; r; ) { + struct rewrite_rule *cr = r; + + r = r->lr_next; + rewrite_rule_destroy( &cr ); + } + + free( context->lc_rule ); + context->lc_rule = NULL; + + assert( context->lc_name ); + free( context->lc_name ); + context->lc_name = NULL; + + free( context ); + *pcontext = NULL; + + return 0; +} diff --git a/libraries/librewrite/info.c b/libraries/librewrite/info.c new file mode 100644 index 0000000000..fbc2fc67ba --- /dev/null +++ b/libraries/librewrite/info.c @@ -0,0 +1,281 @@ +/****************************************************************************** + * + * Copyright (C) 2000 Pierangelo Masarati, + * 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 + +#include "rewrite-int.h" + +/* + * Global data + */ + +/* + * This becomes the running context for subsequent calls to + * rewrite_parse; it can be altered only by a + * rewriteContext config line or by a change in info. + */ +struct rewrite_context *rewrite_int_curr_context = NULL; + +/* + * Inits the info + */ +struct rewrite_info * +rewrite_info_init( + int mode +) +{ + struct rewrite_info *info; + struct rewrite_context *context; + + switch ( mode ) { + case REWRITE_MODE_ERR: + case REWRITE_MODE_OK: + case REWRITE_MODE_COPY_INPUT: + case REWRITE_MODE_USE_DEFAULT: + break; + default: + mode = REWRITE_MODE_USE_DEFAULT; + break; + /* return NULL */ + } + + /* + * Resets the running context for parsing ... + */ + rewrite_int_curr_context = NULL; + + info = calloc( sizeof( struct rewrite_info ), 1 ); + if ( info == NULL ) { + return NULL; + } + + info->li_state = REWRITE_DEFAULT; + info->li_max_passes = REWRITE_MAX_PASSES; + info->li_rewrite_mode = mode; + + /* + * Add the default (empty) rule + */ + context = rewrite_context_create( info, REWRITE_DEFAULT_CONTEXT ); + if ( context == NULL ) { + free( info ); + return NULL; + } + +#ifdef USE_REWRITE_LDAP_PVT_THREADS + if ( ldap_pvt_thread_rdwr_init( &info->li_cookies_mutex ) ) { + free( info ); + return NULL; + } + if ( ldap_pvt_thread_rdwr_init( &info->li_params_mutex ) ) { + free( info ); + return NULL; + } +#endif /* USE_REWRITE_LDAP_PVT_THREADS */ + + return info; +} + +/* + * Cleans up the info structure + */ +int +rewrite_info_delete( + struct rewrite_info **pinfo +) +{ + struct rewrite_info *info; + + assert( pinfo != NULL ); + assert( *pinfo != NULL ); + + info = *pinfo; + + if ( info->li_context ) { + avl_free( info->li_context, rewrite_context_free ); + } + info->li_context = NULL; + + if ( info->li_maps ) { + avl_free( info->li_maps, rewrite_builtin_map_free ); + } + info->li_context = NULL; + + rewrite_session_destroy( info ); + +#ifdef USE_REWRITE_LDAP_PVT_THREADS + ldap_pvt_thread_rdwr_destroy( &info->li_cookies_mutex ); +#endif /* USE_REWRITE_LDAP_PVT_THREADS */ + + rewrite_param_destroy( info ); + +#ifdef USE_REWRITE_LDAP_PVT_THREADS + ldap_pvt_thread_rdwr_destroy( &info->li_params_mutex ); +#endif /* USE_REWRITE_LDAP_PVT_THREADS */ + + free( info ); + *pinfo = NULL; + + return REWRITE_SUCCESS; +} + +/* + * Rewrites a string according to context. + * If the engine is off, OK is returned, but the return string will be NULL. + * In case of 'unwilling to perform', UNWILLING is returned, and the + * return string will also be null. The same in case of error. + * Otherwise, OK is returned, and result will hold a newly allocated string + * with the rewriting. + * + * What to do in case of non-existing rewrite context is still an issue. + * Four possibilities: + * - error, + * - ok with NULL result, + * - ok with copy of string as result, + * - use the default rewrite context. + */ +int +rewrite( + struct rewrite_info *info, + const char *rewriteContext, + const char *string, + char **result +) +{ + return rewrite_session( info, rewriteContext, + string, NULL, result ); +} + +int +rewrite_session( + struct rewrite_info *info, + const char *rewriteContext, + const char *string, + const void *cookie, + char **result +) +{ + struct rewrite_context *context; + struct rewrite_op op = { 0, 0, NULL, NULL, NULL }; + int rc; + + assert( info != NULL ); + assert( rewriteContext != NULL ); + assert( string != NULL ); + assert( result != NULL ); + + /* + * cookie can be null; means: don't care about session stuff + */ + + *result = NULL; + op.lo_cookie = cookie; + + /* + * Engine not on means no failure, but explicit no rewriting + */ + if ( info->li_state != REWRITE_ON ) { + rc = REWRITE_REGEXEC_OK; + goto rc_return; + } + + /* + * Undefined context means no rewriting also + * (conservative, are we sure it's what we want?) + */ + context = rewrite_context_find( info, rewriteContext ); + if ( context == NULL ) { + switch ( info->li_rewrite_mode ) { + case REWRITE_MODE_ERR: + rc = REWRITE_REGEXEC_ERR; + goto rc_return; + + case REWRITE_MODE_OK: + rc = REWRITE_REGEXEC_OK; + goto rc_return; + + case REWRITE_MODE_COPY_INPUT: + *result = strdup( string ); + rc = REWRITE_REGEXEC_OK; + goto rc_return; + + case REWRITE_MODE_USE_DEFAULT: + context = rewrite_context_find( info, + REWRITE_DEFAULT_CONTEXT ); + break; + } + } + +#if 0 /* FIXME: not used anywhere! (debug? then, why strdup?) */ + op.lo_string = strdup( string ); + if ( op.lo_string == NULL ) { + rc = REWRITE_REGEXEC_ERR; + goto rc_return; + } +#endif + + /* + * Applies rewrite context + */ + rc = rewrite_context_apply( info, &op, context, string, result ); + assert( op.lo_depth == 0 ); + +#if 0 /* FIXME: not used anywhere! (debug? then, why strdup?) */ + free( op.lo_string ); +#endif + + switch ( rc ) { + /* + * Success + */ + case REWRITE_REGEXEC_OK: + case REWRITE_REGEXEC_STOP: + /* + * If rewrite succeeded return OK regardless of how + * the successful rewriting was obtained! + */ + rc = REWRITE_REGEXEC_OK; + break; + + + /* + * Internal or forced error, return = NULL; rc already OK. + */ + case REWRITE_REGEXEC_UNWILLING: + case REWRITE_REGEXEC_ERR: + default: + if ( *result != NULL ) { + free( *result ); + *result = NULL; + } + } + +rc_return:; + if ( op.lo_vars ) { + rewrite_var_delete( op.lo_vars ); + } + + return rc; +} + diff --git a/libraries/librewrite/ldapmap.c b/libraries/librewrite/ldapmap.c new file mode 100644 index 0000000000..68b70d35eb --- /dev/null +++ b/libraries/librewrite/ldapmap.c @@ -0,0 +1,382 @@ +/****************************************************************************** + * + * Copyright (C) 2000 Pierangelo Masarati, + * 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 + +#include "rewrite-int.h" +#include "rewrite-map.h" + +/* + * LDAP map data structure + */ +struct ldap_map_data { + char *lm_url; + LDAPURLDesc *lm_lud; + int lm_attrsonly; + char *lm_binddn; + char *lm_bindpw; + +#define MAP_LDAP_EVERYTIME 0x00 +#define MAP_LDAP_NOW 0x01 +#define MAP_LDAP_LATER 0x02 + int lm_when; + + LDAP *lm_ld; + +#ifdef USE_REWRITE_LDAP_PVT_THREADS + ldap_pvt_thread_mutex_t lm_mutex; +#endif /* USE_REWRITE_LDAP_PVT_THREADS */ +}; + +static void +map_ldap_free( + struct ldap_map_data *data +) +{ + assert( data != NULL ); + + if ( data->lm_url != NULL ) { + free( data->lm_url ); + } + + if ( data->lm_lud != NULL ) { + ldap_free_urldesc( data->lm_lud ); + } + + if ( data->lm_binddn != NULL ) { + free( data->lm_binddn ); + } + + if ( data->lm_bindpw != NULL ) { + free( data->lm_bindpw ); + } + + if ( data->lm_when != MAP_LDAP_EVERYTIME && data->lm_ld != NULL ) { + ldap_unbind_s( data->lm_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->lm_url = strdup( argv[ 0 ] ); + if ( data->lm_url == NULL ) { + map_ldap_free( data ); + return NULL; + } + + if ( ldap_url_parse( argv[ 0 ], &data->lm_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->lm_url, '/' ); + assert( p[ 1 ] == '/' ); + if ( ( p = strchr( p + 2, '/' ) ) != NULL ) { + p[ 0 ] = '\0'; + } + + if ( strcasecmp( data->lm_lud->lud_attrs[ 0 ], "dn" ) == 0 ) { + data->lm_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->lm_binddn = strdup( p ); + if ( data->lm_binddn == NULL ) { + map_ldap_free( data ); + return NULL; + } + + if ( data->lm_binddn[ l ] == '\"' + || data->lm_binddn[ l ] == '\'' ) { + data->lm_binddn[ l ] = '\0'; + } + } else if ( strncasecmp( argv[ 0 ], "bindpw=", 7 ) == 0 ) { + data->lm_bindpw = strdup( argv[ 2 ] + 7 ); + if ( data->lm_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->lm_when = MAP_LDAP_NOW; + + /* + * Init LDAP handler ... + */ + rc = ldap_initialize( &data->lm_ld, data->lm_url ); + if ( rc != LDAP_SUCCESS ) { + map_ldap_free( data ); + return NULL; + } + +#ifdef USE_REWRITE_LDAP_PVT_THREADS + ldap_pvt_thread_mutex_init( &data->lm_mutex ); +#endif /* USE_REWRITE_LDAP_PVT_THREADS */ + + } else if ( strcasecmp( p, "later" ) == 0 ) { + data->lm_when = MAP_LDAP_LATER; + +#ifdef USE_REWRITE_LDAP_PVT_THREADS + ldap_pvt_thread_mutex_init( &data->lm_mutex ); +#endif /* USE_REWRITE_LDAP_PVT_THREADS */ + + } else if ( strcasecmp( p, "everytime" ) == 0 ) { + data->lm_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->lm_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->lm_when == MAP_LDAP_EVERYTIME ) { + rc = ldap_initialize( &ld, data->lm_url ); + + } else { +#ifdef USE_REWRITE_LDAP_PVT_THREADS + ldap_pvt_thread_mutex_lock( &data->lm_mutex ); +#endif /* USE_REWRITE_LDAP_PVT_THREADS */ + + rc = LDAP_SUCCESS; + + if ( data->lm_when == MAP_LDAP_LATER && data->lm_ld == NULL ) { + rc = ldap_initialize( &data->lm_ld, data->lm_url ); + } + + ld = data->lm_ld; + } + + if ( rc != LDAP_SUCCESS ) { + rc = REWRITE_ERR; + goto rc_return; + } + +do_bind:; + if ( data->lm_binddn != NULL ) { + rc = ldap_simple_bind_s( ld, data->lm_binddn, data->lm_bindpw ); + if ( rc == LDAP_SERVER_DOWN && first_try ) { + first_try = 0; + if ( ldap_initialize( &ld, data->lm_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->lm_attrsonly, &res ); + if ( rc == LDAP_SERVER_DOWN && first_try ) { + first_try = 0; + if ( ldap_initialize( &ld, data->lm_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->lm_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->lm_when == MAP_LDAP_EVERYTIME ) { + if ( ld != NULL ) { + ldap_unbind_s( ld ); + } + + } else { + data->lm_ld = ld; +#ifdef USE_REWRITE_LDAP_PVT_THREADS + ldap_pvt_thread_mutex_unlock( &data->lm_mutex ); +#endif /* USE_REWRITE_LDAP_PVT_THREADS */ + } + + return rc; +} + +int +map_ldap_destroy( + struct rewrite_builtin_map **pmap +) +{ + struct ldap_map_data *data; + + assert( pmap ); + assert( *pmap ); + + data = ( struct ldap_map_data * )(*pmap)->lb_private; + + if ( data->lm_when != MAP_LDAP_EVERYTIME && data->lm_ld != NULL ) { + ldap_unbind_s( data->lm_ld ); + data->lm_ld = NULL; + } + + if ( data->lm_lud ) { + ldap_free_urldesc( data->lm_lud ); + data->lm_lud = NULL; + } + + if ( data->lm_url ) { + free( data->lm_url ); + data->lm_url = NULL; + } + + if ( data->lm_binddn ) { + free( data->lm_binddn ); + data->lm_binddn = NULL; + } + + if (data->lm_bindpw ) { + memset( data->lm_bindpw, 0, strlen( data->lm_bindpw ) ); + free( data->lm_bindpw ); + data->lm_bindpw = NULL; + } + + free( data ); + (*pmap)->lb_private = NULL; + + return 0; +} + diff --git a/libraries/librewrite/map.c b/libraries/librewrite/map.c index 7ddd0d99dd..d17d814629 100644 --- a/libraries/librewrite/map.c +++ b/libraries/librewrite/map.c @@ -33,195 +33,6 @@ #include "rewrite-int.h" #include "rewrite-map.h" -/* - * Global data - */ -#ifdef USE_REWRITE_LDAP_PVT_THREADS -ldap_pvt_thread_mutex_t xpasswd_mutex; -static int xpasswd_mutex_init = 0; -#endif /* USE_REWRITE_LDAP_PVT_THREADS */ - -/* - * Map parsing - * NOTE: these are old-fashion maps; new maps will be parsed on separate - * config lines, and referred by name. - */ -struct rewrite_map * -rewrite_xmap_parse( - struct rewrite_info *info, - const char *s, - const char **currpos -) -{ - struct rewrite_map *map; - - assert( info != NULL ); - assert( s != NULL ); - assert( currpos != NULL ); - - Debug( LDAP_DEBUG_ARGS, "rewrite_xmap_parse: %s\n%s%s", - s, "", "" ); - - *currpos = NULL; - - map = calloc( sizeof( struct rewrite_map ), 1 ); - if ( map == NULL ) { - Debug( LDAP_DEBUG_ANY, "rewrite_xmap_parse:" - " calloc failed\n%s%s%s", "", "", "" ); - return NULL; - } - - /* - * Experimental passwd map: - * replaces the uid with the matching gecos from /etc/passwd file - */ - if ( strncasecmp(s, "xpasswd", 7 ) == 0 ) { - map->lm_type = REWRITE_MAP_XPWDMAP; - map->lm_name = strdup( "xpasswd" ); - - assert( s[7] == '}' ); - *currpos = s + 8; - -#ifdef USE_REWRITE_LDAP_PVT_THREADS - if ( !xpasswd_mutex_init ) { - xpasswd_mutex_init = 1; - if ( ldap_pvt_thread_mutex_init( &xpasswd_mutex ) ) { - free( map ); - return NULL; - } - } -#endif /* USE_REWRITE_LDAP_PVT_THREADS */ - - /* Don't really care if fails */ - return map; - - /* - * Experimental file map: - * looks up key in a `key value' ascii file - */ - } else if ( strncasecmp(s, "xfile", 5 ) == 0 ) { - char *filename; - const char *p; - int l; - int c = 5; - - map->lm_type = REWRITE_MAP_XFILEMAP; - - if ( s[ c ] != '(' ) { - free( map ); - return NULL; - } - - /* Must start with '/' for security concerns */ - c++; - if ( s[ c ] != '/' ) { - free( map ); - return NULL; - } - - for ( p = s + c; p[ 0 ] != '\0' && p[ 0 ] != ')'; p++ ); - if ( p[ 0 ] != ')' ) { - free( map ); - return NULL; - } - - l = p - s - c; - filename = calloc( sizeof( char ), l + 1 ); - AC_MEMCPY( filename, s + c, l ); - filename[ l ] = '\0'; - - map->lm_args = ( void * )fopen( filename, "r" ); - free( filename ); - - if ( map->lm_args == NULL ) { - free( map ); - return NULL; - } - - *currpos = p + 1; - -#ifdef USE_REWRITE_LDAP_PVT_THREADS - if ( ldap_pvt_thread_mutex_init( &map->lm_mutex ) ) { - fclose( ( FILE * )map->lm_args ); - free( map ); - return NULL; - } -#endif /* USE_REWRITE_LDAP_PVT_THREADS */ - - return map; - - /* - * Experimental ldap map: - * looks up key on the fly (not implemented!) - */ - } else if ( strncasecmp(s, "xldap", 5 ) == 0 ) { - char *p; - char *url; - int l, rc; - int c = 5; - LDAPURLDesc *lud; - - if ( s[ c ] != '(' ) { - free( map ); - return NULL; - } - c++; - - p = strchr( s, '}' ); - if ( p == NULL ) { - free( map ); - return NULL; - } - p--; - - *currpos = p + 2; - - /* - * Add two bytes for urlencoding of '%s' - */ - l = p - s - c; - url = calloc( sizeof( char ), l + 3 ); - AC_MEMCPY( url, s + c, l ); - url[ l ] = '\0'; - - /* - * Urlencodes the '%s' for ldap_url_parse - */ - p = strchr( url, '%' ); - if ( p != NULL ) { - AC_MEMCPY( p + 3, p + 1, strlen( p + 1 ) + 1 ); - p[ 1 ] = '2'; - p[ 2 ] = '5'; - } - - rc = ldap_url_parse( url, &lud ); - free( url ); - - if ( rc != LDAP_SUCCESS ) { - free( map ); - return NULL; - } - assert( lud != NULL ); - - map->lm_args = ( void * )lud; - map->lm_type = REWRITE_MAP_XLDAPMAP; - -#ifdef USE_REWRITE_LDAP_PVT_THREADS - if ( ldap_pvt_thread_mutex_init( &map->lm_mutex ) ) { - ldap_free_urldesc( lud ); - free( map ); - return NULL; - } -#endif /* USE_REWRITE_LDAP_PVT_THREADS */ - - return map; - - /* Unhandled map */ - } - - return NULL; -} - struct rewrite_map * rewrite_map_parse( struct rewrite_info *info, @@ -233,7 +44,7 @@ rewrite_map_parse( struct rewrite_subst *subst = NULL; char *s, *begin = NULL, *end; const char *p; - int l, cnt; + int l, cnt, mtx = 0, rc = 0; assert( info != NULL ); assert( string != NULL ); @@ -259,8 +70,11 @@ rewrite_map_parse( cnt++; p++; } - if ( p[ 1 ] != '\0' ) + + if ( p[ 1 ] != '\0' ) { p++; + } + } else if ( p[ 0 ] == '}' ) { cnt--; } @@ -285,11 +99,12 @@ rewrite_map_parse( case REWRITE_OPERATOR_VARIABLE_GET: case REWRITE_OPERATOR_PARAM_GET: break; + default: begin = strchr( s, '(' ); if ( begin == NULL ) { - free( s ); - return NULL; + rc = -1; + goto cleanup; } begin[ 0 ] = '\0'; begin++; @@ -333,13 +148,13 @@ rewrite_map_parse( * Check the syntax of the variable name */ if ( !isalpha( (unsigned char) p[ 0 ] ) ) { - free( s ); - return NULL; + rc = -1; + goto cleanup; } for ( p++; p[ 0 ] != '\0'; p++ ) { if ( !isalnum( (unsigned char) p[ 0 ] ) ) { - free( s ); - return NULL; + rc = -1; + goto cleanup; } } @@ -350,11 +165,12 @@ rewrite_map_parse( case REWRITE_OPERATOR_VARIABLE_GET: case REWRITE_OPERATOR_PARAM_GET: break; + default: end = strrchr( begin, ')' ); if ( end == NULL ) { - free( s ); - return NULL; + rc = -1; + goto cleanup; } end[ 0 ] = '\0'; @@ -363,8 +179,8 @@ rewrite_map_parse( */ subst = rewrite_subst_compile( info, begin ); if ( subst == NULL ) { - free( s ); - return NULL; + rc = -1; + goto cleanup; } break; } @@ -374,22 +190,17 @@ rewrite_map_parse( */ map = calloc( sizeof( struct rewrite_map ), 1 ); if ( map == NULL ) { - if ( subst != NULL ) { - free( subst ); - } - free( s ); - return NULL; + rc = -1; + goto cleanup; } + memset( map, 0, sizeof( struct rewrite_map ) ); #ifdef USE_REWRITE_LDAP_PVT_THREADS if ( ldap_pvt_thread_mutex_init( &map->lm_mutex ) ) { - if ( subst != NULL ) { - free( subst ); - } - free( s ); - free( map ); - return NULL; + rc = -1; + goto cleanup; } + ++mtx; #endif /* USE_REWRITE_LDAP_PVT_THREADS */ /* @@ -399,6 +210,7 @@ rewrite_map_parse( case REWRITE_OPERATOR_VARIABLE_GET: case REWRITE_OPERATOR_PARAM_GET: break; + default: map->lm_subst = subst; break; @@ -422,19 +234,17 @@ rewrite_map_parse( map->lm_name = strdup( s + 1 ); map->lm_data = rewrite_context_find( info, s + 1 ); if ( map->lm_data == NULL ) { - free( s ); - free( map ); - return NULL; + rc = -1; + goto cleanup; } break; /* - * External command + * External command (not implemented yet) */ case REWRITE_OPERATOR_COMMAND: /* '|' */ - free( map ); - map = NULL; - break; + rc = -1; + goto cleanup; /* * Variable set @@ -488,226 +298,36 @@ rewrite_map_parse( map->lm_name = strdup( s ); map->lm_data = rewrite_builtin_map_find( info, s ); if ( map->lm_data == NULL ) { - return NULL; + rc = -1; + goto cleanup; } break; } - - free( s ); - return map; -} -/* - * Map key -> value resolution - * NOTE: these are old-fashion maps; new maps will be parsed on separate - * config lines, and referred by name. - */ -int -rewrite_xmap_apply( - struct rewrite_info *info, - struct rewrite_op *op, - struct rewrite_map *map, - struct berval *key, - struct berval *val -) -{ - int rc = REWRITE_SUCCESS; - - assert( info != NULL ); - assert( op != NULL ); - assert( map != NULL ); - assert( key != NULL ); - assert( val != NULL ); - - val->bv_val = NULL; - val->bv_len = 0; - - switch ( map->lm_type ) { -#ifdef HAVE_GETPWNAM - case REWRITE_MAP_XPWDMAP: { - struct passwd *pwd; - -#ifdef USE_REWRITE_LDAP_PVT_THREADS - ldap_pvt_thread_mutex_lock( &xpasswd_mutex ); -#endif /* USE_REWRITE_LDAP_PVT_THREADS */ - - pwd = getpwnam( key->bv_val ); - if ( pwd == NULL ) { - -#ifdef USE_REWRITE_LDAP_PVT_THREADS - ldap_pvt_thread_mutex_unlock( &xpasswd_mutex ); -#endif /* USE_REWRITE_LDAP_PVT_THREADS */ - - rc = REWRITE_NO_SUCH_OBJECT; - break; +cleanup: + free( s ); + if ( rc ) { + if ( subst != NULL ) { + free( subst ); } - -#ifdef HAVE_PW_GECOS - if ( pwd->pw_gecos != NULL && pwd->pw_gecos[0] != '\0' ) { - int l = strlen( pwd->pw_gecos ); - - val->bv_val = strdup( pwd->pw_gecos ); - if ( val->bv_val == NULL ) { - + if ( map ) { #ifdef USE_REWRITE_LDAP_PVT_THREADS - ldap_pvt_thread_mutex_unlock( &xpasswd_mutex ); -#endif /* USE_REWRITE_LDAP_PVT_THREADS */ - - rc = REWRITE_ERR; - break; + if ( mtx ) { + ldap_pvt_thread_mutex_destroy( &map->lm_mutex ); } - val->bv_len = l; - } else -#endif /* HAVE_PW_GECOS */ - { - val->bv_val = strdup( key->bv_val ); - val->bv_len = key->bv_len; - } - -#ifdef USE_REWRITE_LDAP_PVT_THREADS - ldap_pvt_thread_mutex_unlock( &xpasswd_mutex ); -#endif /* USE_REWRITE_LDAP_PVT_THREADS */ - - break; - } -#endif /* HAVE_GETPWNAM*/ - - case REWRITE_MAP_XFILEMAP: { - char buf[1024]; - - if ( map->lm_args == NULL ) { - rc = REWRITE_ERR; - break; - } - -#ifdef USE_REWRITE_LDAP_PVT_THREADS - ldap_pvt_thread_mutex_lock( &map->lm_mutex ); #endif /* USE_REWRITE_LDAP_PVT_THREADS */ - rewind( ( FILE * )map->lm_args ); - - while ( fgets( buf, sizeof( buf ), ( FILE * )map->lm_args ) ) { - char *p; - int blen; - - blen = strlen( buf ); - if ( buf[ blen - 1 ] == '\n' ) { - buf[ blen - 1 ] = '\0'; + if ( map->lm_name ) { + free( map->lm_name ); + map->lm_name = NULL; } - - p = strtok( buf, " " ); - if ( p == NULL ) { -#ifdef USE_REWRITE_LDAP_PVT_THREADS - ldap_pvt_thread_mutex_unlock( &map->lm_mutex ); -#endif /* USE_REWRITE_LDAP_PVT_THREADS */ - rc = REWRITE_ERR; - goto rc_return; - } - if ( strcasecmp( p, key->bv_val ) == 0 - && ( p = strtok( NULL, "" ) ) ) { - val->bv_val = strdup( p ); - if ( val->bv_val == NULL ) { - return REWRITE_ERR; - } - - val->bv_len = strlen( p ); - -#ifdef USE_REWRITE_LDAP_PVT_THREADS - ldap_pvt_thread_mutex_unlock( &map->lm_mutex ); -#endif /* USE_REWRITE_LDAP_PVT_THREADS */ - - goto rc_return; - } - } - -#ifdef USE_REWRITE_LDAP_PVT_THREADS - ldap_pvt_thread_mutex_unlock( &map->lm_mutex ); -#endif /* USE_REWRITE_LDAP_PVT_THREADS */ - - rc = REWRITE_ERR; - - break; - } - - case REWRITE_MAP_XLDAPMAP: { - LDAP *ld; - char filter[1024]; - LDAPMessage *res = NULL, *entry; - LDAPURLDesc *lud = ( LDAPURLDesc * )map->lm_args; - int attrsonly = 0; - char **values; - - assert( lud != NULL ); - - /* - * No mutex because there is no write on the map data - */ - - ld = ldap_init( lud->lud_host, lud->lud_port ); - if ( ld == NULL ) { - rc = REWRITE_ERR; - goto rc_return; - } - - snprintf( filter, sizeof( filter ), lud->lud_filter, - key->bv_val ); - - if ( strcasecmp( lud->lud_attrs[ 0 ], "dn" ) == 0 ) { - attrsonly = 1; - } - rc = ldap_search_s( ld, lud->lud_dn, lud->lud_scope, - filter, lud->lud_attrs, attrsonly, &res ); - if ( rc != LDAP_SUCCESS ) { - ldap_unbind( ld ); - rc = REWRITE_ERR; - goto rc_return; - } - - if ( ldap_count_entries( ld, res ) != 1 ) { - ldap_unbind( ld ); - rc = REWRITE_ERR; - goto rc_return; - } - - entry = ldap_first_entry( ld, res ); - if ( entry == NULL ) { - ldap_msgfree( res ); - ldap_unbind( ld ); - rc = REWRITE_ERR; - goto rc_return; - } - if ( attrsonly == 1 ) { - val->bv_val = ldap_get_dn( ld, entry ); - if ( val->bv_val == NULL ) { - ldap_msgfree( res ); - ldap_unbind( ld ); - rc = REWRITE_ERR; - goto rc_return; - } - } else { - values = ldap_get_values( ld, entry, - lud->lud_attrs[0] ); - if ( values == NULL ) { - ldap_msgfree( res ); - ldap_unbind( ld ); - rc = REWRITE_ERR; - goto rc_return; - } - val->bv_val = strdup( values[ 0 ] ); - ldap_value_free( values ); + free( map ); + map = NULL; } - val->bv_len = strlen( val->bv_val ); - - ldap_msgfree( res ); - ldap_unbind( ld ); - - rc = REWRITE_SUCCESS; - } } -rc_return:; - return rc; + return map; } /* @@ -796,6 +416,7 @@ rewrite_map_apply( case REWRITE_MAP_BUILTIN: { struct rewrite_builtin_map *bmap = map->lm_data; + switch ( bmap->lb_type ) { case REWRITE_BUILTIN_MAP_LDAP: rc = map_ldap_apply( bmap, key->bv_val, val ); @@ -815,3 +436,62 @@ rewrite_map_apply( return rc; } +void +rewrite_builtin_map_free( + void *tmp +) +{ + struct rewrite_builtin_map *map = ( struct rewrite_builtin_map * )tmp; + + assert( map ); + + switch ( map->lb_type ) { + case REWRITE_BUILTIN_MAP_LDAP: + map_ldap_destroy( &map ); + break; + + default: + assert(0); + break; + } + + free( map->lb_name ); + free( map ); +} + +int +rewrite_map_destroy( + struct rewrite_map **pmap +) +{ + struct rewrite_map *map; + + assert( pmap ); + assert( *pmap ); + + map = *pmap; + +#ifdef USE_REWRITE_LDAP_PVT_THREADS + ldap_pvt_thread_mutex_lock( &map->lm_mutex ); +#endif /* USE_REWRITE_LDAP_PVT_THREADS */ + + if ( map->lm_name ) { + free( map->lm_name ); + map->lm_name = NULL; + } + + if ( map->lm_subst ) { + rewrite_subst_destroy( &map->lm_subst ); + } + +#ifdef USE_REWRITE_LDAP_PVT_THREADS + ldap_pvt_thread_mutex_unlock( &map->lm_mutex ); + ldap_pvt_thread_mutex_destroy( &map->lm_mutex ); +#endif /* USE_REWRITE_LDAP_PVT_THREADS */ + + free( map ); + *pmap = NULL; + + return 0; +} + diff --git a/libraries/librewrite/params.c b/libraries/librewrite/params.c new file mode 100644 index 0000000000..3f5488d69e --- /dev/null +++ b/libraries/librewrite/params.c @@ -0,0 +1,156 @@ +/****************************************************************************** + * + * Copyright (C) 2000 Pierangelo Masarati, + * 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 + +#include "rewrite-int.h" + +/* + * Defines and inits a variable with global scope + */ +int +rewrite_param_set( + struct rewrite_info *info, + const char *name, + const char *value +) +{ + struct rewrite_var *var; + + assert( info != NULL ); + assert( name != NULL ); + assert( value != NULL ); + +#ifdef USE_REWRITE_LDAP_PVT_THREADS + ldap_pvt_thread_rdwr_wlock( &info->li_params_mutex ); +#endif /* USE_REWRITE_LDAP_PVT_THREADS */ + + var = rewrite_var_find( info->li_params, name ); + if ( var != NULL ) { + assert( var->lv_value.bv_val != NULL ); + free( var->lv_value.bv_val ); + var->lv_value.bv_val = strdup( value ); + var->lv_value.bv_len = strlen( value ); + } else { + var = rewrite_var_insert( &info->li_params, name, value ); + if ( var == NULL ) { +#ifdef USE_REWRITE_LDAP_PVT_THREADS + ldap_pvt_thread_rdwr_wunlock( &info->li_params_mutex ); +#endif /* USE_REWRITE_LDAP_PVT_THREADS */ + return REWRITE_ERR; + } + } + +#ifdef USE_REWRITE_LDAP_PVT_THREADS + ldap_pvt_thread_rdwr_wunlock( &info->li_params_mutex ); +#endif /* USE_REWRITE_LDAP_PVT_THREADS */ + + return REWRITE_SUCCESS; +} + +/* + * Gets a var with global scope + */ +int +rewrite_param_get( + struct rewrite_info *info, + const char *name, + struct berval *value +) +{ + struct rewrite_var *var; + + assert( info != NULL ); + assert( name != NULL ); + assert( value != NULL ); + + value->bv_val = NULL; + value->bv_len = 0; + +#ifdef USE_REWRITE_LDAP_PVT_THREADS + ldap_pvt_thread_rdwr_rlock( &info->li_params_mutex ); +#endif /* USE_REWRITE_LDAP_PVT_THREADS */ + + var = rewrite_var_find( info->li_params, name ); + if ( var == NULL ) { + +#ifdef USE_REWRITE_LDAP_PVT_THREADS + ldap_pvt_thread_rdwr_runlock( &info->li_params_mutex ); +#endif /* USE_REWRITE_LDAP_PVT_THREADS */ + + return REWRITE_ERR; + } else { + value->bv_val = strdup( var->lv_value.bv_val ); + value->bv_len = var->lv_value.bv_len; + } + +#ifdef USE_REWRITE_LDAP_PVT_THREADS + ldap_pvt_thread_rdwr_runlock( &info->li_params_mutex ); +#endif /* USE_REWRITE_LDAP_PVT_THREADS */ + + return REWRITE_SUCCESS; +} + +static void +rewrite_param_free( + void *tmp +) +{ + struct rewrite_var *var = ( struct rewrite_var * )tmp; + assert( var != NULL ); + + assert( var->lv_name != NULL ); + assert( var->lv_value.bv_val != NULL ); + + free( var->lv_name ); + free( var->lv_value.bv_val ); + free( var ); +} + +/* + * Destroys the parameter tree + */ +int +rewrite_param_destroy( + struct rewrite_info *info +) +{ + int count; + + assert( info != NULL ); + +#ifdef USE_REWRITE_LDAP_PVT_THREADS + ldap_pvt_thread_rdwr_wlock( &info->li_params_mutex ); +#endif /* USE_REWRITE_LDAP_PVT_THREADS */ + + count = avl_free( info->li_params, rewrite_param_free ); + info->li_params = NULL; + +#ifdef USE_REWRITE_LDAP_PVT_THREADS + ldap_pvt_thread_rdwr_wunlock( &info->li_params_mutex ); +#endif /* USE_REWRITE_LDAP_PVT_THREADS */ + + return REWRITE_SUCCESS; +} + diff --git a/libraries/librewrite/rewrite-int.h b/libraries/librewrite/rewrite-int.h index b8bc161a54..85358b72fc 100644 --- a/libraries/librewrite/rewrite-int.h +++ b/libraries/librewrite/rewrite-int.h @@ -189,10 +189,10 @@ struct rewrite_submatch { */ struct rewrite_subst { size_t lt_subs_len; - struct berval **lt_subs; + struct berval *lt_subs; int lt_num_submatch; - struct rewrite_submatch **lt_submatch; + struct rewrite_submatch *lt_submatch; }; /* @@ -262,7 +262,9 @@ struct rewrite_var { struct rewrite_op { int lo_num_passes; int lo_depth; +#if 0 /* FIXME: not used anywhere! (debug? then, why strdup?) */ char *lo_string; +#endif char *lo_result; Avlnode *lo_vars; const void *lo_cookie; @@ -315,7 +317,7 @@ struct rewrite_info { * PRIVATE * ***********/ -LDAP_REWRITE_V (struct rewrite_context*) __curr_context; +LDAP_REWRITE_V (struct rewrite_context*) rewrite_int_curr_context; /* * Maps @@ -359,7 +361,20 @@ rewrite_xmap_apply( struct berval *val ); +LDAP_REWRITE_F (int) +rewrite_map_destroy( + struct rewrite_map **map +); + +LDAP_REWRITE_F (int) +rewrite_xmap_destroy( + struct rewrite_map **map +); +LDAP_REWRITE_F (void) +rewrite_builtin_map_free( + void *map +); /* * Submatch substitution */ @@ -387,6 +402,11 @@ rewrite_subst_apply( struct berval *val ); +LDAP_REWRITE_F (int) +rewrite_subst_destroy( + struct rewrite_subst **subst +); + /* * Rules @@ -422,6 +442,11 @@ rewrite_rule_apply( char **result ); +LDAP_REWRITE_F (int) +rewrite_rule_destroy( + struct rewrite_rule **rule +); + /* * Sessions */ @@ -555,5 +580,15 @@ rewrite_context_apply( char **result ); +LDAP_REWRITE_F (int) +rewrite_context_destroy( + struct rewrite_context **context +); + +LDAP_REWRITE_F (void) +rewrite_context_free( + void *tmp +); + #endif /* REWRITE_INT_H */ diff --git a/libraries/librewrite/rewrite-map.h b/libraries/librewrite/rewrite-map.h new file mode 100644 index 0000000000..13283e4bed --- /dev/null +++ b/libraries/librewrite/rewrite-map.h @@ -0,0 +1,59 @@ +/****************************************************************************** + * + * Copyright (C) 2000 Pierangelo Masarati, + * 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. + * + ******************************************************************************/ + +#ifndef MAP_H +#define MAP_H + +/* + * Retrieves a builtin map + */ +LDAP_REWRITE_F (struct rewrite_builtin_map *) +rewrite_builtin_map_find( + struct rewrite_info *info, + const char *name +); + + +/* + * LDAP map + */ +LDAP_REWRITE_F (void *) +map_ldap_parse( + struct rewrite_info *info, + const char *fname, + int lineno, + int argc, + char **argv +); + +LDAP_REWRITE_F (int) +map_ldap_apply( struct rewrite_builtin_map *map, + const char *filter, + struct berval *val +); + +LDAP_REWRITE_F (int) +map_ldap_destroy( struct rewrite_builtin_map **map ); + +#endif /* MAP_H */ diff --git a/libraries/librewrite/rewrite.c b/libraries/librewrite/rewrite.c index ac301b7a51..f02f6983cf 100644 --- a/libraries/librewrite/rewrite.c +++ b/libraries/librewrite/rewrite.c @@ -52,7 +52,7 @@ apply( int rc; void *cookie = &info; - info = rewrite_info_init(REWRITE_MODE_ERR); + info = rewrite_info_init( REWRITE_MODE_ERR ); if ( rewrite_read( fin, info ) != 0 ) { exit( EXIT_FAILURE ); @@ -84,8 +84,12 @@ apply( string = result; } + free( string ); + rewrite_session_delete( info, cookie ); + rewrite_info_delete( &info ); + return result; } @@ -128,7 +132,7 @@ main( int argc, char *argv[] ) exit( EXIT_SUCCESS ); case 'r': - rewriteContext = strdup( optarg ); + rewriteContext = optarg; break; } } @@ -139,6 +143,10 @@ main( int argc, char *argv[] ) apply( ( fin ? fin : stdin ), rewriteContext, argv[ optind ] ); + if ( fin ) { + fclose( fin ); + } + return 0; } diff --git a/libraries/librewrite/rule.c b/libraries/librewrite/rule.c new file mode 100644 index 0000000000..c025000183 --- /dev/null +++ b/libraries/librewrite/rule.c @@ -0,0 +1,478 @@ +/****************************************************************************** + * + * Copyright (C) 2000 Pierangelo Masarati, + * 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 + +#include "rewrite-int.h" + +/* + * Appends a rule to the double linked list of rules + * Helper for rewrite_rule_compile + */ +static int +append_rule( + struct rewrite_context *context, + struct rewrite_rule *rule +) +{ + struct rewrite_rule *r; + + assert( context != NULL ); + assert( context->lc_rule != NULL ); + assert( rule != NULL ); + + for ( r = context->lc_rule; r->lr_next != NULL; r = r->lr_next ); + r->lr_next = rule; + rule->lr_prev = r; + + return REWRITE_SUCCESS; +} + +/* + * Appends an action to the linked list of actions + * Helper for rewrite_rule_compile + */ +static int +append_action( + struct rewrite_action *base, + struct rewrite_action *action +) +{ + struct rewrite_action *a; + + assert( base != NULL ); + assert( action != NULL ); + + for ( a = base; a->la_next != NULL; a = a->la_next ); + a->la_next = action; + + return REWRITE_SUCCESS; +} + +static int +destroy_action( + struct rewrite_action **paction +) +{ + struct rewrite_action *action; + + assert( paction ); + assert( *paction ); + + action = *paction; + + /* do something */ + switch ( action->la_type ) { + case REWRITE_FLAG_GOTO: { + int *pi = (int *)action->la_args; + + if ( pi ) { + free( pi ); + } + break; + } + + default: + break; + } + + free( action ); + *paction = NULL; + + return 0; +} + +/* + * In case of error it returns NULL and does not free all the memory + * it allocated; as this is a once only phase, and an error at this stage + * would require the server to stop, there is no need to be paranoid + * about memory allocation + */ +int +rewrite_rule_compile( + struct rewrite_info *info, + struct rewrite_context *context, + const char *pattern, + const char *result, + const char *flagstring +) +{ + int flags = REWRITE_REGEX_EXTENDED | REWRITE_REGEX_ICASE; + int mode = REWRITE_RECURSE; + + struct rewrite_rule *rule = NULL; + struct rewrite_subst *subst = NULL; + struct rewrite_action *action = NULL, *first_action = NULL; + + const char *p; + + assert( info != NULL ); + assert( context != NULL ); + assert( pattern != NULL ); + assert( result != NULL ); + + /* + * A null flagstring should be allowed + */ + + /* + * Take care of substitution string + */ + subst = rewrite_subst_compile( info, result ); + if ( subst == NULL ) { + return REWRITE_ERR; + } + + /* + * Take care of flags + */ + for ( p = flagstring; p[ 0 ] != '\0'; p++ ) { + switch( p[ 0 ] ) { + + /* + * REGEX flags + */ + case REWRITE_FLAG_HONORCASE: /* 'C' */ + /* + * Honor case (default is case insensitive) + */ + flags &= ~REWRITE_REGEX_ICASE; + break; + + case REWRITE_FLAG_BASICREGEX: /* 'R' */ + /* + * Use POSIX Basic Regular Expression syntax + * instead of POSIX Extended Regular Expression + * syntax (default) + */ + flags &= ~REWRITE_REGEX_EXTENDED; + break; + + /* + * Execution mode flags + */ + case REWRITE_FLAG_EXECONCE: /* ':' */ + /* + * Apply rule once only + */ + mode &= ~REWRITE_RECURSE; + mode |= REWRITE_EXEC_ONCE; + break; + + /* + * Special action flags + */ + case REWRITE_FLAG_STOP: /* '@' */ + /* + * Bail out after applying rule + */ + action = calloc( sizeof( struct rewrite_action ), 1 ); + if ( action == NULL ) { + /* cleanup ... */ + return REWRITE_ERR; + } + + mode &= ~REWRITE_RECURSE; + mode |= REWRITE_EXEC_ONCE; + action->la_type = REWRITE_ACTION_STOP; + break; + + case REWRITE_FLAG_UNWILLING: /* '#' */ + /* + * Matching objs will be marked as gone! + */ + action = calloc( sizeof( struct rewrite_action ), 1 ); + if ( action == NULL ) { + /* cleanup ... */ + return REWRITE_ERR; + } + + mode &= ~REWRITE_RECURSE; + mode |= REWRITE_EXEC_ONCE; + action->la_type = REWRITE_ACTION_UNWILLING; + break; + + case REWRITE_FLAG_GOTO: { /* 'G' */ + /* + * After applying rule, jump N rules + */ + + char buf[16], *q; + size_t l; + int *d; + + if ( p[ 1 ] != '{' ) { + /* XXX Need to free stuff */ + return REWRITE_ERR; + } + + q = strchr( p + 2, '}' ); + if ( q == NULL ) { + /* XXX Need to free stuff */ + return REWRITE_ERR; + } + + l = q - p + 2; + if ( l >= sizeof( buf ) ) { + /* XXX Need to free stuff */ + return REWRITE_ERR; + } + AC_MEMCPY( buf, p + 2, l ); + buf[ l ] = '\0'; + + d = malloc( sizeof( int ) ); + if ( d == NULL ) { + /* XXX Need to free stuff */ + return REWRITE_ERR; + } + d[ 0 ] = atoi( buf ); + + action = calloc( sizeof( struct rewrite_action ), 1 ); + if ( action == NULL ) { + /* cleanup ... */ + return REWRITE_ERR; + } + action->la_type = REWRITE_ACTION_GOTO; + action->la_args = (void *)d; + + p = q; /* p is incremented by the for ... */ + + break; + } + + case REWRITE_FLAG_IGNORE_ERR: /* 'I' */ + /* + * Ignore errors! + */ + action = calloc( sizeof( struct rewrite_action ), 1 ); + if ( action == NULL ) { + /* cleanup ... */ + return REWRITE_ERR; + } + + action->la_type = REWRITE_ACTION_IGNORE_ERR; + break; + + /* + * Other flags ... + */ + default: + /* + * Unimplemented feature (complain only) + */ + break; + } + + /* + * Stupid way to append to a list ... + */ + if ( action != NULL ) { + if ( first_action == NULL ) { + first_action = action; + } else { + append_action( first_action, action ); + } + action = NULL; + } + } + + /* + * Finally, rule allocation + */ + rule = calloc( sizeof( struct rewrite_rule ), 1 ); + if ( rule == NULL ) { + /* charray_free( res ); */ + /* + * XXX need to free the value subst stuff! + */ + return REWRITE_ERR; + } + + /* + * REGEX compilation (luckily I don't need to take care of this ...) + */ + if ( regcomp( &rule->lr_regex, ( char * )pattern, flags ) != 0 ) { + /* charray_free( res ); */ + /* + *XXX need to free the value subst stuff! + */ + free( rule ); + return REWRITE_ERR; + } + + /* + * Just to remember them ... + */ + rule->lr_pattern = strdup( pattern ); + rule->lr_subststring = strdup( result ); + rule->lr_flagstring = strdup( flagstring ); + + /* + * Load compiled data into rule + */ + rule->lr_subst = subst; + + /* + * Set various parameters + */ + rule->lr_flags = flags; /* don't really need any longer ... */ + rule->lr_mode = mode; + rule->lr_action = first_action; + + /* + * Append rule at the end of the rewrite context + */ + append_rule( context, rule ); + + return REWRITE_SUCCESS; +} + +/* + * Rewrites string according to rule; may return: + * OK: fine; if *result != NULL rule matched and rewrite succeeded. + * STOP: fine, rule matched; stop processing following rules + * UNWILL: rule matched; force 'unwilling to perform' + */ +int +rewrite_rule_apply( + struct rewrite_info *info, + struct rewrite_op *op, + struct rewrite_rule *rule, + const char *arg, + char **result + ) +{ + size_t nmatch = REWRITE_MAX_MATCH; + regmatch_t match[ REWRITE_MAX_MATCH ]; + + int rc = REWRITE_SUCCESS; + + char *string; + int strcnt = 0; + struct berval val = { 0, NULL }; + + assert( info != NULL ); + assert( op != NULL ); + assert( rule != NULL ); + assert( arg != NULL ); + assert( result != NULL ); + + *result = NULL; + + string = (char *)arg; + + /* + * In case recursive match is required (default) + */ +recurse:; + + Debug( LDAP_DEBUG_TRACE, "==> rewrite_rule_apply" + " rule='%s' string='%s'\n", + rule->lr_pattern, string, 0 ); + + op->lo_num_passes++; + if ( regexec( &rule->lr_regex, string, nmatch, match, 0 ) != 0 ) { + if ( *result == NULL && strcnt > 0 ) { + free( string ); + string = NULL; + } + + /* + * No match is OK; *result = NULL means no match + */ + return REWRITE_REGEXEC_OK; + } + + rc = rewrite_subst_apply( info, op, rule->lr_subst, string, + match, &val ); + + *result = val.bv_val; + val.bv_val = NULL; + if ( strcnt > 0 ) { + free( string ); + string = NULL; + } + + if ( rc != REWRITE_REGEXEC_OK ) { + return rc; + } + + if ( ( rule->lr_mode & REWRITE_RECURSE ) == REWRITE_RECURSE + && op->lo_num_passes <= info->li_max_passes ) { + string = *result; + strcnt++; + + goto recurse; + } + + return REWRITE_REGEXEC_OK; +} + +int +rewrite_rule_destroy( + struct rewrite_rule **prule + ) +{ + struct rewrite_rule *rule; + struct rewrite_action *action; + + assert( prule ); + assert( *prule ); + + rule = *prule; + + if ( rule->lr_pattern ) { + free( rule->lr_pattern ); + rule->lr_pattern = NULL; + } + + if ( rule->lr_subststring ) { + free( rule->lr_subststring ); + rule->lr_subststring = NULL; + } + + if ( rule->lr_flagstring ) { + free( rule->lr_flagstring ); + rule->lr_flagstring = NULL; + } + + if ( rule->lr_subst ) { + rewrite_subst_destroy( &rule->lr_subst ); + } + + regfree( &rule->lr_regex ); + + for ( action = rule->lr_action; action; ) { + struct rewrite_action *curraction = action; + + action = action->la_next; + destroy_action( &curraction ); + } + + free( rule ); + *prule = NULL; + + return 0; +} + diff --git a/libraries/librewrite/session.c b/libraries/librewrite/session.c index 3366559a3d..20ab8fdde8 100644 --- a/libraries/librewrite/session.c +++ b/libraries/librewrite/session.c @@ -317,23 +317,27 @@ rewrite_session_delete( session = rewrite_session_find( info, cookie ); - if ( session != NULL ) { - if ( --session->ls_count > 0 ) { - rewrite_session_return( info, session ); - return REWRITE_SUCCESS; - } + if ( session == NULL ) { + return REWRITE_SUCCESS; + } + + if ( --session->ls_count > 0 ) { + rewrite_session_return( info, session ); + return REWRITE_SUCCESS; + } #ifdef USE_REWRITE_LDAP_PVT_THREADS - ldap_pvt_thread_rdwr_wlock( &session->ls_vars_mutex ); + ldap_pvt_thread_rdwr_wlock( &session->ls_vars_mutex ); #endif /* USE_REWRITE_LDAP_PVT_THREADS */ - rewrite_var_delete( session->ls_vars ); + rewrite_var_delete( session->ls_vars ); #ifdef USE_REWRITE_LDAP_PVT_THREADS - ldap_pvt_thread_rdwr_destroy( &session->ls_vars_mutex ); - ldap_pvt_thread_mutex_destroy( &session->ls_mutex ); + ldap_pvt_thread_rdwr_wunlock( &session->ls_vars_mutex ); + ldap_pvt_thread_rdwr_destroy( &session->ls_vars_mutex ); + ldap_pvt_thread_mutex_unlock( &session->ls_mutex ); + ldap_pvt_thread_mutex_destroy( &session->ls_mutex ); #endif /* USE_REWRITE_LDAP_PVT_THREADS */ - } #ifdef USE_REWRITE_LDAP_PVT_THREADS ldap_pvt_thread_rdwr_wlock( &info->li_cookies_mutex ); diff --git a/libraries/librewrite/subst.c b/libraries/librewrite/subst.c index 4c0bc411e0..5b9437f1aa 100644 --- a/libraries/librewrite/subst.c +++ b/libraries/librewrite/subst.c @@ -36,8 +36,8 @@ rewrite_subst_compile( ) { size_t subs_len; - struct berval **subs = NULL, **tmps; - struct rewrite_submatch **submatch = NULL; + struct berval *subs = NULL, *tmps; + struct rewrite_submatch *submatch = NULL; struct rewrite_subst *s = NULL; @@ -51,28 +51,27 @@ rewrite_subst_compile( * 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; } + if ( p[ 1 ] == REWRITE_SUBMATCH_ESCAPE ) { - AC_MEMCPY((char *)p, p + 1, strlen( p ) ); + /* Pull &p[1] over p, including the trailing '\0' */ + AC_MEMCPY((char *)p, &p[ 1 ], strlen( p ) ); continue; } - nsub++; - - tmps = (struct berval **)realloc( subs, - sizeof( struct berval * )*( nsub + 1 ) ); + tmps = ( struct berval * )realloc( subs, + sizeof( struct berval )*( nsub + 1 ) ); if ( tmps == NULL ) { - /* cleanup */ + /* FIXME: cleanup */ return NULL; } subs = tmps; - subs[ nsub ] = NULL; /* * I think an `if l > 0' at runtime is better outside than @@ -81,62 +80,52 @@ rewrite_subst_compile( 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 ) { + subs[ nsub ].bv_len = l; + subs[ nsub ].bv_val = malloc( l + 1 ); + if ( subs[ nsub ].bv_val == NULL ) { return NULL; } - AC_MEMCPY( subs[ nsub - 1 ]->bv_val, begin, l ); - subs[ nsub - 1 ]->bv_val[ l ] = '\0'; + AC_MEMCPY( subs[ nsub ].bv_val, begin, l ); + subs[ nsub ].bv_val[ l ] = '\0'; } else { - subs[ nsub - 1 ] = NULL; + subs[ nsub ].bv_val = NULL; + subs[ nsub ].bv_len = 0; } /* * Substitution pattern */ if ( isdigit( (unsigned char) p[ 1 ] ) ) { + struct rewrite_submatch *tmpsm; int d = p[ 1 ] - '0'; - struct rewrite_submatch **tmpsm; /* * Add a new value substitution scheme */ - tmpsm = realloc( submatch, - sizeof( struct rewrite_submatch * )*( nsub + 1 ) ); + + tmpsm = ( struct rewrite_submatch * )realloc( submatch, + sizeof( struct rewrite_submatch )*( nsub + 1 ) ); if ( tmpsm == NULL ) { /* cleanup */ return NULL; } submatch = tmpsm; - 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; + submatch[ nsub ].ls_submatch = d; /* * If there is no argument, use default * (substitute substring as is) */ if ( p[ 2 ] != '{' ) { - submatch[ nsub - 1 ]->ls_type = + submatch[ nsub ].ls_type = REWRITE_SUBMATCH_ASIS; + submatch[ nsub ].ls_map = NULL; begin = ++p + 1; + } else { struct rewrite_map *map; - submatch[ nsub - 1 ]->ls_type = + submatch[ nsub ].ls_type = REWRITE_SUBMATCH_XMAP; map = rewrite_xmap_parse( info, @@ -145,9 +134,8 @@ rewrite_subst_compile( /* cleanup */ return NULL; } + submatch[ nsub ].ls_map = map; p = begin - 1; - - submatch[ nsub - 1 ]->ls_map = map; } /* @@ -155,7 +143,7 @@ rewrite_subst_compile( */ } else if ( p[ 1 ] == '{' ) { struct rewrite_map *map; - struct rewrite_submatch **tmpsm; + struct rewrite_submatch *tmpsm; map = rewrite_map_parse( info, p + 2, &begin ); if ( map == NULL ) { @@ -167,52 +155,43 @@ rewrite_subst_compile( /* * Add a new value substitution scheme */ - tmpsm = realloc( submatch, - sizeof( struct rewrite_submatch * )*( nsub + 1 ) ); + tmpsm = ( struct rewrite_submatch * )realloc( submatch, + sizeof( struct rewrite_submatch )*( nsub + 1 ) ); if ( tmpsm == NULL ) { /* cleanup */ return NULL; } submatch = tmpsm; - 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 = + submatch[ nsub ].ls_type = REWRITE_SUBMATCH_MAP_W_ARG; - - submatch[ nsub - 1 ]->ls_map = map; + submatch[ nsub ].ls_map = map; } + + nsub++; } /* * Last part of string */ - tmps = realloc( subs, sizeof( struct berval *)*( nsub + 2 ) ); + tmps = (struct berval * )realloc( subs, sizeof( struct berval )*( nsub + 1 ) ); if ( tmps == NULL ) { /* * XXX need to free the value subst stuff! */ - free( submatch ); + free( subs ); return NULL; } - subs = tmps; - 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 ); - AC_MEMCPY( subs[ nsub ]->bv_val, begin, l ); - subs[ nsub ]->bv_val[ l ] = '\0'; + subs[ nsub ].bv_len = l; + subs[ nsub ].bv_val = malloc( l + 1 ); + AC_MEMCPY( subs[ nsub ].bv_val, begin, l ); + subs[ nsub ].bv_val[ l ] = '\0'; } else { - subs[ nsub ] = NULL; + subs[ nsub ].bv_val = NULL; + subs[ nsub ].bv_len = 0; } s = calloc( sizeof( struct rewrite_subst ), 1 ); @@ -241,8 +220,8 @@ submatch_copy( struct berval *val ) { - int c, l; - const char *s; + int c, l; + const char *s; assert( submatch != NULL ); assert( submatch->ls_type == REWRITE_SUBMATCH_ASIS @@ -250,14 +229,14 @@ submatch_copy( assert( string != NULL ); assert( match != NULL ); assert( val != NULL ); + assert( val->bv_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 ); + val->bv_val = malloc( l + 1 ); if ( val->bv_val == NULL ) { return REWRITE_ERR; } @@ -284,7 +263,7 @@ rewrite_subst_apply( { struct berval *submatch = NULL; char *res = NULL; - int n, l, cl; + int n = 0, l, cl; int rc = REWRITE_REGEXEC_OK; assert( info != NULL ); @@ -294,74 +273,79 @@ rewrite_subst_apply( assert( match != NULL ); assert( val != NULL ); + assert( val->bv_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; + if ( subst->lt_num_submatch > 0 ) { + 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; + struct berval key = { 0, NULL }; + + submatch[ n ].bv_val = NULL; /* * Get key */ - switch( subst->lt_submatch[ n ]->ls_type ) { + switch ( subst->lt_submatch[ n ].ls_type ) { case REWRITE_SUBMATCH_ASIS: case REWRITE_SUBMATCH_XMAP: - rc = submatch_copy( subst->lt_submatch[ n ], + rc = submatch_copy( &subst->lt_submatch[ n ], string, match, &key ); if ( rc != REWRITE_SUCCESS ) { - free( submatch ); - return REWRITE_REGEXEC_ERR; + rc = REWRITE_REGEXEC_ERR; + goto cleanup; } break; case REWRITE_SUBMATCH_MAP_W_ARG: - switch ( subst->lt_submatch[ n ]->ls_map->lm_type ) { + 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, + subst->lt_submatch[ n ].ls_map->lm_subst, string, match, &key); } if ( rc != REWRITE_SUCCESS ) { - free( submatch ); - return REWRITE_REGEXEC_ERR; + rc = REWRITE_REGEXEC_ERR; + goto cleanup; } break; default: - Debug( LDAP_DEBUG_ANY, "Not Implemented\n%s%s%s", - "", "", "" ); + Debug( LDAP_DEBUG_ANY, "Not Implemented\n", 0, 0, 0 ); rc = REWRITE_ERR; break; } if ( rc != REWRITE_SUCCESS ) { - free( submatch ); - return REWRITE_REGEXEC_ERR; + rc = REWRITE_REGEXEC_ERR; + goto cleanup; } /* * Resolve key */ - switch ( subst->lt_submatch[ n ]->ls_type ) { + switch ( subst->lt_submatch[ n ].ls_type ) { case REWRITE_SUBMATCH_ASIS: submatch[ n ] = key; rc = REWRITE_SUCCESS; @@ -369,16 +353,20 @@ rewrite_subst_apply( case REWRITE_SUBMATCH_XMAP: rc = rewrite_xmap_apply( info, op, - subst->lt_submatch[ n ]->ls_map, + subst->lt_submatch[ n ].ls_map, &key, &submatch[ n ] ); + free( key.bv_val ); + key.bv_val = NULL; break; case REWRITE_SUBMATCH_MAP_W_ARG: rc = rewrite_map_apply( info, op, - subst->lt_submatch[ n ]->ls_map, + subst->lt_submatch[ n ].ls_map, &key, &submatch[ n ] ); + free( key.bv_val ); + key.bv_val = NULL; break; - + default: /* * When implemented, this might return the @@ -391,8 +379,7 @@ rewrite_subst_apply( } if ( rc != REWRITE_SUCCESS ) { - free( submatch ); - return REWRITE_REGEXEC_ERR; + rc = REWRITE_REGEXEC_ERR; } /* @@ -402,38 +389,105 @@ rewrite_subst_apply( } /* - * Alloc result buffer as big as the constant part - * of the subst pattern and initialize it + * Alloc result buffer */ l += subst->lt_subs_len; - res = calloc( sizeof( char ), l + 1 ); + res = malloc( l + 1 ); if ( res == NULL ) { - free( submatch ); - return REWRITE_REGEXEC_ERR; + rc = REWRITE_REGEXEC_ERR; + goto cleanup; } /* - * Apply submatches (possibly resolved thru maps + * Apply submatches (possibly resolved thru maps) */ for ( n = 0, cl = 0; n < subst->lt_num_submatch; n++ ) { - if ( subst->lt_subs[ n ] != NULL ) { - AC_MEMCPY( res + cl, subst->lt_subs[ n ]->bv_val, - subst->lt_subs[ n ]->bv_len ); - cl += subst->lt_subs[ n ]->bv_len; + if ( subst->lt_subs[ n ].bv_val != NULL ) { + AC_MEMCPY( res + cl, subst->lt_subs[ n ].bv_val, + subst->lt_subs[ n ].bv_len ); + cl += subst->lt_subs[ n ].bv_len; } AC_MEMCPY( res + cl, submatch[ n ].bv_val, submatch[ n ].bv_len ); cl += submatch[ n ].bv_len; - free( submatch[ n ].bv_val ); } - if ( subst->lt_subs[ n ] != NULL ) { - AC_MEMCPY( res + cl, subst->lt_subs[ n ]->bv_val, - subst->lt_subs[ n ]->bv_len ); + if ( subst->lt_subs[ n ].bv_val != NULL ) { + AC_MEMCPY( res + cl, subst->lt_subs[ n ].bv_val, + subst->lt_subs[ n ].bv_len ); + cl += subst->lt_subs[ n ].bv_len; } + res[ cl ] = '\0'; val->bv_val = res; val->bv_len = l; - + +cleanup:; + if ( submatch ) { + for ( ; --n >= 0; ) { + if ( submatch[ n ].bv_val ) { + free( submatch[ n ].bv_val ); + } + } + free( submatch ); + } + return rc; } +/* + * frees data + */ +int +rewrite_subst_destroy( + struct rewrite_subst **psubst +) +{ + int n; + struct rewrite_subst *subst; + + assert( psubst ); + assert( *psubst ); + + subst = *psubst; + + for ( n = 0; n < subst->lt_num_submatch; n++ ) { + if ( subst->lt_subs[ n ].bv_val ) { + free( subst->lt_subs[ n ].bv_val ); + subst->lt_subs[ n ].bv_val = NULL; + } + + switch ( subst->lt_submatch[ n ].ls_type ) { + case REWRITE_SUBMATCH_ASIS: + break; + + case REWRITE_SUBMATCH_XMAP: + rewrite_xmap_destroy( &subst->lt_submatch[ n ].ls_map ); + break; + + case REWRITE_SUBMATCH_MAP_W_ARG: + rewrite_map_destroy( &subst->lt_submatch[ n ].ls_map ); + break; + + default: + break; + } + } + + free( subst->lt_submatch ); + subst->lt_submatch = NULL; + + /* last one */ + if ( subst->lt_subs[ n ].bv_val ) { + free( subst->lt_subs[ n ].bv_val ); + subst->lt_subs[ n ].bv_val = NULL; + } + + free( subst->lt_subs ); + subst->lt_subs = NULL; + + free( subst ); + *psubst = NULL; + + return 0; +} + diff --git a/libraries/librewrite/var.c b/libraries/librewrite/var.c index 941e54b426..aa39261ce5 100644 --- a/libraries/librewrite/var.c +++ b/libraries/librewrite/var.c @@ -109,25 +109,31 @@ rewrite_var_insert( if ( var == NULL ) { return NULL; } - var->lv_name = ( char * )strdup( name ); + memset( var, 0, sizeof( struct rewrite_var ) ); + var->lv_name = strdup( name ); if ( var->lv_name == NULL ) { - free( var ); - return NULL; + rc = -1; + goto cleanup; } var->lv_value.bv_val = strdup( value ); if ( var->lv_value.bv_val == NULL ) { - free( var ); - free( var->lv_name ); - return NULL; + rc = -1; + goto cleanup; } var->lv_value.bv_len = strlen( value ); rc = avl_insert( tree, ( caddr_t )var, rewrite_var_cmp, rewrite_var_dup ); if ( rc != 0 ) { - free( var ); + rc = -1; + goto cleanup; + } + +cleanup:; + if ( rc != 0 ) { free( var->lv_name ); free( var->lv_value.bv_val ); - return NULL; + free( var ); + var = NULL; } return var; @@ -184,6 +190,7 @@ rewrite_var_free( free( var->lv_name ); free( var->lv_value.bv_val ); + free( var ); } /* diff --git a/servers/slapd/back-ldap/init.c b/servers/slapd/back-ldap/init.c index 5a4b1e2798..26a9f7810d 100644 --- a/servers/slapd/back-ldap/init.c +++ b/servers/slapd/back-ldap/init.c @@ -183,7 +183,7 @@ ldap_back_db_destroy( } #ifdef ENABLE_REWRITE if (li->rwinfo) { - rewrite_info_delete( li->rwinfo ); + rewrite_info_delete( &li->rwinfo ); } #else /* !ENABLE_REWRITE */ if (li->suffix_massage) { diff --git a/servers/slapd/back-meta/init.c b/servers/slapd/back-meta/init.c index 5d3f2b8f20..4807f0c0d6 100644 --- a/servers/slapd/back-meta/init.c +++ b/servers/slapd/back-meta/init.c @@ -203,7 +203,7 @@ target_free( free( lt->pseudorootpw.bv_val ); } if ( lt->rwinfo ) { - rewrite_info_delete( lt->rwinfo ); + rewrite_info_delete( <->rwinfo ); } avl_free( lt->oc_map.remap, NULL ); avl_free( lt->oc_map.map, mapping_free );