From f02b6cfba7b7d43560765a147c89d6c799c1d1ee Mon Sep 17 00:00:00 2001 From: Pierangelo Masarati Date: Sat, 6 Dec 2003 09:53:41 +0000 Subject: [PATCH] first cut at dn rewrite/attr mapping overlay --- servers/slapd/overlays/rwm.c | 601 +++++++++++++++++++++++++++++++ servers/slapd/overlays/rwm.h | 162 +++++++++ servers/slapd/overlays/rwmconf.c | 330 +++++++++++++++++ servers/slapd/overlays/rwmdn.c | 196 ++++++++++ servers/slapd/overlays/rwmmap.c | 590 ++++++++++++++++++++++++++++++ 5 files changed, 1879 insertions(+) create mode 100644 servers/slapd/overlays/rwm.c create mode 100644 servers/slapd/overlays/rwm.h create mode 100644 servers/slapd/overlays/rwmconf.c create mode 100644 servers/slapd/overlays/rwmdn.c create mode 100644 servers/slapd/overlays/rwmmap.c diff --git a/servers/slapd/overlays/rwm.c b/servers/slapd/overlays/rwm.c new file mode 100644 index 0000000000..d0929c5dc8 --- /dev/null +++ b/servers/slapd/overlays/rwm.c @@ -0,0 +1,601 @@ +/* rwm.c - rewrite/remap operations */ +/* + * Copyright 2003 The OpenLDAP Foundation, All Rights Reserved. + * COPYING RESTRICTIONS APPLY, see COPYRIGHT file + */ +/* + * Copyright 2003, 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 "portable.h" + +#include + +#include "slap.h" +#include "rwm.h" + +static int +rwm_op_dn_massage( Operation *op, SlapReply *rs, void *cookie ) +{ + slap_overinst *on = (slap_overinst *) op->o_bd->bd_info; + struct ldaprwmap *rwmap = + (struct ldaprwmap *)on->on_bi.bi_private; + + struct berval dn, ndn, mdn = { 0, NULL }; + int rc = 0; + dncookie dc; + + /* + * Rewrite the bind dn if needed + */ + dc.rwmap = rwmap; +#ifdef ENABLE_REWRITE + dc.conn = op->o_conn; + dc.rs = rs; + dc.ctx = (char *)cookie; +#else + dc.tofrom = ((int *)cookie)[0]; + dc.normalized = 0; +#endif + + rc = rwm_dn_massage( &dc, &op->o_req_dn, &mdn ); + if ( rc != LDAP_SUCCESS ) { + return rc; + } + + rc = dnPrettyNormal( NULL, &mdn, &dn, &ndn, op->o_tmpmemctx ); + if ( rc != LDAP_SUCCESS ) { + return rc; + } + + if ( mdn.bv_val != dn.bv_val ) { + ch_free( mdn.bv_val ); + } + + op->o_tmpfree( op->o_req_dn.bv_val, op->o_tmpmemctx ); + op->o_tmpfree( op->o_req_ndn.bv_val, op->o_tmpmemctx ); + + op->o_req_dn = dn; + op->o_req_ndn = ndn; + + return LDAP_SUCCESS; +} + +static int +rwm_bind( Operation *op, SlapReply *rs ) +{ + int rc; + +#ifdef ENABLE_REWRITE + rc = rwm_op_dn_massage( op, rs, "bindDn" ); +#else + rc = 1; + rc = rwm_op_dn_massage( op, rs, &rc ); +#endif + if ( rc != LDAP_SUCCESS ) { + return rc; + } + + return SLAP_CB_CONTINUE; +} + +static int +rwm_add( Operation *op, SlapReply *rs ) +{ + int rc; + +#ifdef ENABLE_REWRITE + rc = rwm_op_dn_massage( op, rs, "addDn" ); +#else + rc = 1; + rc = rwm_op_dn_massage( op, rs, &rc ); +#endif + if ( rc != LDAP_SUCCESS ) { + return rc; + } + + /* TODO: rewrite attribute types, values of DN-valued attributes ... */ + return SLAP_CB_CONTINUE; +} + +static int +rwm_delete( Operation *op, SlapReply *rs ) +{ + int rc; + +#ifdef ENABLE_REWRITE + rc = rwm_op_dn_massage( op, rs, "addDn" ); +#else + rc = 1; + rc = rwm_op_dn_massage( op, rs, &rc ); +#endif + if ( rc != LDAP_SUCCESS ) { + return rc; + } + + return SLAP_CB_CONTINUE; +} + +static int +rwm_modrdn( Operation *op, SlapReply *rs ) +{ + int rc; + +#ifdef ENABLE_REWRITE + rc = rwm_op_dn_massage( op, rs, "addDn" ); +#else + rc = 1; + rc = rwm_op_dn_massage( op, rs, &rc ); +#endif + if ( rc != LDAP_SUCCESS ) { + return rc; + } + + /* TODO: rewrite attribute types, values of DN-valued attributes ... */ + return SLAP_CB_CONTINUE; +} + +static int +rwm_modify( Operation *op, SlapReply *rs ) +{ + int rc; + +#ifdef ENABLE_REWRITE + rc = rwm_op_dn_massage( op, rs, "addDn" ); +#else + rc = 1; + rc = rwm_op_dn_massage( op, rs, &rc ); +#endif + if ( rc != LDAP_SUCCESS ) { + return rc; + } + + /* TODO: rewrite attribute types, values of DN-valued attributes ... */ + return SLAP_CB_CONTINUE; +} + +static int +rwm_compare( Operation *op, SlapReply *rs ) +{ + int rc; + +#ifdef ENABLE_REWRITE + rc = rwm_op_dn_massage( op, rs, "addDn" ); +#else + rc = 1; + rc = rwm_op_dn_massage( op, rs, &rc ); +#endif + if ( rc != LDAP_SUCCESS ) { + return rc; + } + + /* TODO: rewrite attribute types, values of DN-valued attributes ... */ + return SLAP_CB_CONTINUE; +} + +static int +rwm_search( Operation *op, SlapReply *rs ) +{ + int rc; + +#ifdef ENABLE_REWRITE + rc = rwm_op_dn_massage( op, rs, "addDn" ); +#else + rc = 1; + rc = rwm_op_dn_massage( op, rs, &rc ); +#endif + if ( rc != LDAP_SUCCESS ) { + return rc; + } + + return SLAP_CB_CONTINUE; +} + +static int +rwm_extended( Operation *op, SlapReply *rs ) +{ + int rc; + +#ifdef ENABLE_REWRITE + rc = rwm_op_dn_massage( op, rs, "addDn" ); +#else + rc = 1; + rc = rwm_op_dn_massage( op, rs, &rc ); +#endif + if ( rc != LDAP_SUCCESS ) { + return rc; + } + + return 0; +} + +static int +rwm_matched( Operation *op, SlapReply *rs ) +{ + slap_overinst *on = (slap_overinst *) op->o_bd->bd_info; + struct ldaprwmap *rwmap = + (struct ldaprwmap *)on->on_bi.bi_private; + + struct berval dn, mdn; + dncookie dc; + + if ( rs->sr_matched == NULL ) { + return SLAP_CB_CONTINUE; + } + + dc.rwmap = rwmap; +#ifdef ENABLE_REWRITE + dc.conn = op->o_conn; + dc.rs = rs; + dc.ctx = "matchedDn"; +#else + dc.tofrom = 0; + dc.normalized = 0; +#endif + ber_str2bv( rs->sr_matched, 0, 0, &dn ); + rwm_dn_massage( &dc, &dn, &mdn ); + + if ( mdn.bv_val != dn.bv_val ) { + if ( rs->sr_flags & REP_MATCHED_MUSTBEFREED ) { + free( rs->sr_matched ); + } else { + rs->sr_flags |= REP_MATCHED_MUSTBEFREED; + } + rs->sr_matched = mdn.bv_val; + } + + return SLAP_CB_CONTINUE; +} + +static int +rwm_send_entry( Operation *op, SlapReply *rs ) +{ + slap_overinst *on = (slap_overinst *) op->o_bd->bd_info; + struct ldaprwmap *rwmap = + (struct ldaprwmap *)on->on_bi.bi_private; + + Entry *e = NULL; + struct berval dn = { 0, NULL }, ndn = { 0, NULL }; + dncookie dc; + int rc = SLAP_CB_CONTINUE; + + assert( rs->sr_entry ); + + e = rs->sr_entry; + + /* + * Rewrite the dn of the result, if needed + */ + dc.rwmap = rwmap; +#ifdef ENABLE_REWRITE + dc.conn = op->o_conn; + dc.rs = NULL; + dc.ctx = "searchResult"; +#else + dc.tofrom = 0; + dc.normalized = 0; +#endif + if ( rwm_dn_massage( &dc, &e->e_name, &dn ) ) { + return LDAP_OTHER; + } + + /* + * Note: this may fail if the target host(s) schema differs + * from the one known to the meta, and a DN with unknown + * attributes is returned. + */ + if ( dnNormalize( 0, NULL, NULL, &dn, &ndn, NULL ) != LDAP_SUCCESS ) { + if ( dn.bv_val != e->e_name.bv_val ) { + ch_free( dn.bv_val ); + } + rc = LDAP_INVALID_DN_SYNTAX; + goto fail; + } + + if ( !rs->sr_flags & REP_ENTRY_MODIFIABLE ) { + e = entry_dup( e ); + if ( e == NULL ) { + goto fail; + } + rs->sr_flags |= ( REP_ENTRY_MODIFIABLE | REP_ENTRY_MUSTBEFREED ); + } + + free( e->e_name.bv_val ); + free( e->e_nname.bv_val ); + + e->e_name = dn; + e->e_nname = ndn; + + rs->sr_entry = e; + + return SLAP_CB_CONTINUE; + +fail:; + if ( dn.bv_val && ( dn.bv_val != e->e_name.bv_val ) ) { + ch_free( dn.bv_val ); + } + + if ( ndn.bv_val ) { + ch_free( ndn.bv_val ); + } + + return rc; +} + +static int +rwm_rw_config( + BackendDB *be, + const char *fname, + int lineno, + int argc, + char **argv +) +{ +#ifdef ENABLE_REWRITE + slap_overinst *on = (slap_overinst *) be->bd_info; + struct ldaprwmap *rwmap = + (struct ldaprwmap *)on->on_bi.bi_private; + + return rewrite_parse( rwmap->rwm_rw, + fname, lineno, argc, argv ); + +#else /* !ENABLE_REWRITE */ + fprintf( stderr, "%s: line %d: rewrite capabilities " + "are not enabled\n", fname, lineno ); +#endif /* !ENABLE_REWRITE */ + + return 0; +} + +static int +rwm_suffixmassage_config( + BackendDB *be, + const char *fname, + int lineno, + int argc, + char **argv +) +{ + slap_overinst *on = (slap_overinst *) be->bd_info; + struct ldaprwmap *rwmap = + (struct ldaprwmap *)on->on_bi.bi_private; + + struct berval bvnc, nvnc, pvnc, brnc, nrnc, prnc; +#ifdef ENABLE_REWRITE + int rc; +#endif /* ENABLE_REWRITE */ + + /* + * syntax: + * + * suffixmassage + * + * the field must be defined as a valid suffix + * (or suffixAlias?) for the current database; + * the shouldn't have already been + * defined as a valid suffix or suffixAlias for the + * current server + */ + if ( argc != 3 ) { + fprintf( stderr, "%s: line %d: syntax is" + " \"suffixMassage " + " \"\n", + fname, lineno ); + return 1; + } + + ber_str2bv( argv[1], 0, 0, &bvnc ); + if ( dnPrettyNormal( NULL, &bvnc, &pvnc, &nvnc, NULL ) != LDAP_SUCCESS ) { + fprintf( stderr, "%s: line %d: suffix DN %s is invalid\n", + fname, lineno, bvnc.bv_val ); + return 1; + } + + ber_str2bv( argv[2], 0, 0, &brnc ); + if ( dnPrettyNormal( NULL, &brnc, &prnc, &nrnc, NULL ) != LDAP_SUCCESS ) { + fprintf( stderr, "%s: line %d: suffix DN %s is invalid\n", + fname, lineno, brnc.bv_val ); + free( nvnc.bv_val ); + free( pvnc.bv_val ); + return 1; + } + +#ifdef ENABLE_REWRITE + /* + * The suffix massaging is emulated + * by means of the rewrite capabilities + */ + rc = suffix_massage_config( rwmap->rwm_rw, + &pvnc, &nvnc, &prnc, &nrnc ); + free( nvnc.bv_val ); + free( pvnc.bv_val ); + free( nrnc.bv_val ); + free( prnc.bv_val ); + + return( rc ); + +#else /* !ENABLE_REWRITE */ + ber_bvarray_add( &rwmap->rwm_suffix_massage, &pvnc ); + ber_bvarray_add( &rwmap->rwm_suffix_massage, &nvnc ); + + ber_bvarray_add( &rwmap->rwm_suffix_massage, &prnc ); + ber_bvarray_add( &rwmap->rwm_suffix_massage, &nrnc ); +#endif /* !ENABLE_REWRITE */ + + return 0; +} + +static int +rwm_m_config( + BackendDB *be, + const char *fname, + int lineno, + int argc, + char **argv +) +{ + slap_overinst *on = (slap_overinst *) be->bd_info; + struct ldaprwmap *rwmap = + (struct ldaprwmap *)on->on_bi.bi_private; + + /* objectclass/attribute mapping */ + return rwm_map_config( &rwmap->rwm_oc, + &rwmap->rwm_at, + fname, lineno, argc, argv ); +} + +static int +rwm_response( Operation *op, SlapReply *rs ) +{ + int rc; + + if ( op->o_tag == LDAP_REQ_SEARCH && rs->sr_type == REP_SEARCH ) { + return rwm_send_entry( op, rs ); + } + + switch( op->o_tag ) { + case LDAP_REQ_BIND: + case LDAP_REQ_ADD: + case LDAP_REQ_DELETE: + case LDAP_REQ_MODRDN: + case LDAP_REQ_MODIFY: + case LDAP_REQ_COMPARE: + case LDAP_REQ_SEARCH: + case LDAP_REQ_EXTENDED: + rc = rwm_matched( op, rs ); + break; + default: + rc = SLAP_CB_CONTINUE; + break; + } + + return rc; +} + +static int +rwm_config( + BackendDB *be, + const char *fname, + int lineno, + int argc, + char **argv +) +{ + int rc = 0; + + if ( strncasecmp( argv[0], "rewrite", sizeof("rewrite") - 1) == 0 ) { + rc = rwm_rw_config( be, fname, lineno, argc, argv ); + + } else if (strcasecmp( argv[0], "map" ) == 0 ) { + rc = rwm_m_config( be, fname, lineno, argc, argv ); + + } else if (strcasecmp( argv[0], "suffixmassage" ) == 0 ) { + rc = rwm_suffixmassage_config( be, fname, lineno, argc, argv ); + + } + + return rc; +} + +static int +rwm_init( + BackendDB *be +) +{ + slap_overinst *on = (slap_overinst *) be->bd_info; + struct ldapmapping *mapping = NULL; + struct ldaprwmap *rwmap; + + rwmap = (struct ldaprwmap *)ch_malloc(sizeof(struct ldaprwmap)); + memset(rwmap, 0, sizeof(struct ldaprwmap)); + +#ifdef ENABLE_REWRITE + rwmap->rwm_rw = rewrite_info_init( REWRITE_MODE_USE_DEFAULT ); + if ( rwmap->rwm_rw == NULL ) { + ch_free( rwmap ); + return -1; + } +#endif /* ENABLE_REWRITE */ + + rwm_map_init( &rwmap->rwm_oc, &mapping ); + rwm_map_init( &rwmap->rwm_at, &mapping ); + + on->on_bi.bi_private = (void *)rwmap; + + return 0; +} + +static int +rwm_destroy( + BackendDB *be +) +{ + slap_overinst *on = (slap_overinst *) be->bd_info; + int rc = 0; + + if ( on->on_bi.bi_private ) { + struct ldaprwmap *rwmap = + (struct ldaprwmap *)on->on_bi.bi_private; + +#ifdef ENABLE_REWRITE + if (rwmap->rwm_rw) { + rewrite_info_delete( &rwmap->rwm_rw ); + } +#else /* !ENABLE_REWRITE */ + if ( rwmap->lrwm_suffix_massage ) { + ber_bvarray_free( rwmap->rwm_suffix_massage ); + } +#endif /* !ENABLE_REWRITE */ + + avl_free( rwmap->rwm_oc.remap, NULL ); + avl_free( rwmap->rwm_oc.map, mapping_free ); + avl_free( rwmap->rwm_at.remap, NULL ); + avl_free( rwmap->rwm_at.map, mapping_free ); + } + + return rc; +} + +static slap_overinst rwm = { { NULL } }; + +int +init_module(void) +{ + memset( &rwm, 0, sizeof(slap_overinst) ); + + rwm.on_bi.bi_type = "rewrite-remap"; + rwm.on_bi.bi_db_init = rwm_init; + rwm.on_bi.bi_db_config = rwm_config; + rwm.on_bi.bi_db_destroy = rwm_destroy; + + rwm.on_bi.bi_op_bind = rwm_bind; + rwm.on_bi.bi_op_search = rwm_search; + rwm.on_bi.bi_op_compare = rwm_compare; + rwm.on_bi.bi_op_modify = rwm_modify; + rwm.on_bi.bi_op_modrdn = rwm_modrdn; + rwm.on_bi.bi_op_add = rwm_add; + rwm.on_bi.bi_op_delete = rwm_delete; + rwm.on_bi.bi_extended = rwm_extended; + + rwm.on_response = rwm_response; + + return overlay_register( &rwm ); +} + diff --git a/servers/slapd/overlays/rwm.h b/servers/slapd/overlays/rwm.h new file mode 100644 index 0000000000..c1a5b8cdeb --- /dev/null +++ b/servers/slapd/overlays/rwm.h @@ -0,0 +1,162 @@ +/* rwm.h - dn rewrite/attribute mapping header file */ +/* $OpenLDAP$ */ +/* This work is part of OpenLDAP Software . + * + * Copyright 1999-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 + * . + */ +/* ACKNOWLEDGEMENTS: + * This work was initially developed by the Howard Chu for inclusion + * in OpenLDAP Software and subsequently enhanced by Pierangelo + * Masarati. + */ +/* This is an altered version */ +/* + * Copyright 1999, Howard Chu, 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. + * + * + * + * Copyright 2000, Pierangelo Masarati, All rights reserved. + * + * This software is being modified by Pierangelo Masarati. + * The previously reported conditions apply to the modified code as well. + * Changes in the original code are highlighted where required. + * Credits for the original code go to the author, Howard Chu. + */ + +#ifndef RWM_H +#define RWM_H + +/* String rewrite library */ +#ifdef ENABLE_REWRITE +#include "rewrite.h" +#endif /* ENABLE_REWRITE */ + +LDAP_BEGIN_DECL + +struct ldapmap { + int drop_missing; + + Avlnode *map; + Avlnode *remap; +}; + +struct ldapmapping { + struct berval src; + struct berval dst; +}; + +struct ldaprwmap { + /* + * DN rewriting + */ +#ifdef ENABLE_REWRITE + struct rewrite_info *rwm_rw; +#else /* !ENABLE_REWRITE */ + /* some time the suffix massaging without librewrite + * will be disabled */ + BerVarray rwm_suffix_massage; +#endif /* !ENABLE_REWRITE */ + + /* + * Attribute/objectClass mapping + */ + struct ldapmap rwm_oc; + struct ldapmap rwm_at; +}; + +/* Whatever context ldap_back_dn_massage needs... */ +typedef struct dncookie { + struct ldaprwmap *rwmap; + +#ifdef ENABLE_REWRITE + Connection *conn; + char *ctx; + SlapReply *rs; +#else + int normalized; + int tofrom; +#endif +} dncookie; + +int rwm_dn_massage(dncookie *dc, struct berval *dn, struct berval *res); + +/* attributeType/objectClass mapping */ +int mapping_cmp (const void *, const void *); +int mapping_dup (void *, void *); + +void rwm_map_init ( struct ldapmap *lm, struct ldapmapping ** ); +void rwm_map ( struct ldapmap *map, struct berval *s, struct berval *m, + int remap ); +#define BACKLDAP_MAP 0 +#define BACKLDAP_REMAP 1 +char * +rwm_map_filter( + struct ldapmap *at_map, + struct ldapmap *oc_map, + struct berval *f, + int remap +); + +int +rwm_map_attrs( + struct ldapmap *at_map, + AttributeName *a, + int remap, + char ***mapped_attrs +); + +extern void mapping_free ( void *mapping ); + +extern int rwm_map_config( + struct ldapmap *oc_map, + struct ldapmap *at_map, + const char *fname, + int lineno, + int argc, + char **argv ); + +extern int +rwm_filter_map_rewrite( + dncookie *dc, + Filter *f, + struct berval *fstr, + int remap ); + +/* suffix massaging by means of librewrite */ +#ifdef ENABLE_REWRITE +extern int suffix_massage_config( struct rewrite_info *info, + struct berval *pvnc, struct berval *nvnc, + struct berval *prnc, struct berval *nrnc); +#endif /* ENABLE_REWRITE */ +extern int ldap_dnattr_rewrite( dncookie *dc, BerVarray a_vals ); +extern int ldap_dnattr_result_rewrite( dncookie *dc, BerVarray a_vals ); + +LDAP_END_DECL + +#endif /* RWM_H */ diff --git a/servers/slapd/overlays/rwmconf.c b/servers/slapd/overlays/rwmconf.c new file mode 100644 index 0000000000..4e20ed2506 --- /dev/null +++ b/servers/slapd/overlays/rwmconf.c @@ -0,0 +1,330 @@ +/* rwmconf.c - rewrite/map configuration file routines */ +/* $OpenLDAP$ */ +/* This work is part of OpenLDAP Software . + * + * Copyright 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 + * . + */ +/* ACKNOWLEDGEMENTS: + * This work was initially developed by the Howard Chu for inclusion + * in OpenLDAP Software and subsequently enhanced by Pierangelo + * Masarati. + */ +/* This is an altered version */ +/* + * Copyright 1999, Howard Chu, 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. + * + * + * + * Copyright 2000, Pierangelo Masarati, All rights reserved. + * + * This software is being modified by Pierangelo Masarati. + * The previously reported conditions apply to the modified code as well. + * Changes in the original code are highlighted where required. + * Credits for the original code go to the author, Howard Chu. + */ + +#include "portable.h" + +#include + +#include +#include + +#include "slap.h" +#include "rwm.h" +#include "lutil.h" + +int +rwm_map_config( + struct ldapmap *oc_map, + struct ldapmap *at_map, + const char *fname, + int lineno, + int argc, + char **argv ) +{ + struct ldapmap *map; + struct ldapmapping *mapping; + char *src, *dst; + int is_oc = 0; + + if ( argc < 3 || argc > 4 ) { + fprintf( stderr, + "%s: line %d: syntax is \"map {objectclass | attribute} [ | *] { | *}\"\n", + fname, lineno ); + return 1; + } + + if ( strcasecmp( argv[1], "objectclass" ) == 0 ) { + map = oc_map; + is_oc = 1; + + } else if ( strcasecmp( argv[1], "attribute" ) == 0 ) { + map = at_map; + + } else { + fprintf( stderr, "%s: line %d: syntax is " + "\"map {objectclass | attribute} [ | *] " + "{ | *}\"\n", + fname, lineno ); + return 1; + } + + if ( strcmp( argv[2], "*" ) == 0 ) { + if ( argc < 4 || strcmp( argv[3], "*" ) == 0 ) { + map->drop_missing = ( argc < 4 ); + return 0; + } + src = dst = argv[3]; + + } else if ( argc < 4 ) { + src = ""; + dst = argv[2]; + + } else { + src = argv[2]; + dst = ( strcmp( argv[3], "*" ) == 0 ? src : argv[3] ); + } + + if ( ( map == at_map ) + && ( strcasecmp( src, "objectclass" ) == 0 + || strcasecmp( dst, "objectclass" ) == 0 ) ) + { + fprintf( stderr, + "%s: line %d: objectclass attribute cannot be mapped\n", + fname, lineno ); + } + + mapping = (struct ldapmapping *)ch_calloc( 2, + sizeof(struct ldapmapping) ); + if ( mapping == NULL ) { + fprintf( stderr, + "%s: line %d: out of memory\n", + fname, lineno ); + return 1; + } + ber_str2bv( src, 0, 1, &mapping->src ); + ber_str2bv( dst, 0, 1, &mapping->dst ); + mapping[1].src = mapping->dst; + mapping[1].dst = mapping->src; + + /* + * schema check + */ + if ( is_oc ) { + if ( src[0] != '\0' ) { + if ( oc_bvfind( &mapping->src ) == NULL ) { + fprintf( stderr, + "%s: line %d: warning, source objectClass '%s' " + "should be defined in schema\n", + fname, lineno, src ); + + /* + * FIXME: this should become an err + */ + } + } + + if ( oc_bvfind( &mapping->dst ) == NULL ) { + fprintf( stderr, + "%s: line %d: warning, destination objectClass '%s' " + "is not defined in schema\n", + fname, lineno, dst ); + } + } else { + int rc; + const char *text = NULL; + AttributeDescription *ad = NULL; + + if ( src[0] != '\0' ) { + rc = slap_bv2ad( &mapping->src, &ad, &text ); + if ( rc != LDAP_SUCCESS ) { + fprintf( stderr, + "%s: line %d: warning, source attributeType '%s' " + "should be defined in schema\n", + fname, lineno, src ); + + /* + * FIXME: this should become an err + */ + } + + ad = NULL; + } + + rc = slap_bv2ad( &mapping->dst, &ad, &text ); + if ( rc != LDAP_SUCCESS ) { + fprintf( stderr, + "%s: line %d: warning, destination attributeType '%s' " + "is not defined in schema\n", + fname, lineno, dst ); + } + } + + if ( (src[0] != '\0' && avl_find( map->map, (caddr_t)mapping, mapping_cmp ) != NULL) + || avl_find( map->remap, (caddr_t)&mapping[1], mapping_cmp ) != NULL) + { + fprintf( stderr, + "%s: line %d: duplicate mapping found (ignored)\n", + fname, lineno ); + /* FIXME: free stuff */ + goto error_return; + } + + if ( src[0] != '\0' ) { + avl_insert( &map->map, (caddr_t)mapping, + mapping_cmp, mapping_dup ); + } + avl_insert( &map->remap, (caddr_t)&mapping[1], + mapping_cmp, mapping_dup ); + + return 0; + +error_return:; + if ( mapping ) { + ch_free( mapping->src.bv_val ); + ch_free( mapping->dst.bv_val ); + ch_free( mapping ); + } + + return 1; +} + +#ifdef ENABLE_REWRITE +static char * +suffix_massage_regexize( const char *s ) +{ + char *res, *ptr; + const char *p, *r; + int i; + + for ( i = 0, p = s; + ( r = strchr( p, ',' ) ) != NULL; + p = r + 1, i++ ) + ; + + res = ch_calloc( sizeof( char ), strlen( s ) + 4 + 4*i + 1 ); + + ptr = lutil_strcopy( res, "(.*)" ); + for ( i = 0, p = s; + ( r = strchr( p, ',' ) ) != NULL; + p = r + 1 , i++ ) { + ptr = lutil_strncopy( ptr, p, r - p + 1 ); + ptr = lutil_strcopy( ptr, "[ ]?" ); + + if ( r[ 1 ] == ' ' ) { + r++; + } + } + lutil_strcopy( ptr, p ); + + return res; +} + +static char * +suffix_massage_patternize( const char *s ) +{ + ber_len_t len; + char *res; + + len = strlen( s ); + + res = ch_calloc( sizeof( char ), len + sizeof( "%1" ) ); + if ( res == NULL ) { + return NULL; + } + + strcpy( res, "%1" ); + strcpy( res + sizeof( "%1" ) - 1, s ); + + return res; +} + +int +suffix_massage_config( + struct rewrite_info *info, + struct berval *pvnc, + struct berval *nvnc, + struct berval *prnc, + struct berval *nrnc +) +{ + char *rargv[ 5 ]; + int line = 0; + + rargv[ 0 ] = "rewriteEngine"; + rargv[ 1 ] = "on"; + rargv[ 2 ] = NULL; + rewrite_parse( info, "", ++line, 2, rargv ); + + rargv[ 0 ] = "rewriteContext"; + rargv[ 1 ] = "default"; + rargv[ 2 ] = NULL; + rewrite_parse( info, "", ++line, 2, rargv ); + + rargv[ 0 ] = "rewriteRule"; + rargv[ 1 ] = suffix_massage_regexize( pvnc->bv_val ); + rargv[ 2 ] = suffix_massage_patternize( prnc->bv_val ); + rargv[ 3 ] = ":"; + rargv[ 4 ] = NULL; + rewrite_parse( info, "", ++line, 4, rargv ); + ch_free( rargv[ 1 ] ); + ch_free( rargv[ 2 ] ); + + rargv[ 0 ] = "rewriteContext"; + rargv[ 1 ] = "searchResult"; + rargv[ 2 ] = NULL; + rewrite_parse( info, "", ++line, 2, rargv ); + + rargv[ 0 ] = "rewriteRule"; + rargv[ 1 ] = suffix_massage_regexize( prnc->bv_val ); + rargv[ 2 ] = suffix_massage_patternize( pvnc->bv_val ); + rargv[ 3 ] = ":"; + rargv[ 4 ] = NULL; + rewrite_parse( info, "", ++line, 4, rargv ); + ch_free( rargv[ 1 ] ); + ch_free( rargv[ 2 ] ); + + rargv[ 0 ] = "rewriteContext"; + rargv[ 1 ] = "matchedDN"; + rargv[ 2 ] = "alias"; + rargv[ 3 ] = "searchResult"; + rargv[ 4 ] = NULL; + rewrite_parse( info, "", ++line, 4, rargv ); + + rargv[ 0 ] = "rewriteContext"; + rargv[ 1 ] = "searchAttrDN"; + rargv[ 2 ] = "alias"; + rargv[ 3 ] = "searchResult"; + rargv[ 4 ] = NULL; + rewrite_parse( info, "", ++line, 4, rargv ); + + return 0; +} +#endif /* ENABLE_REWRITE */ diff --git a/servers/slapd/overlays/rwmdn.c b/servers/slapd/overlays/rwmdn.c new file mode 100644 index 0000000000..703a50641f --- /dev/null +++ b/servers/slapd/overlays/rwmdn.c @@ -0,0 +1,196 @@ +/* rwmdn.c - massages dns */ +/* $OpenLDAP$ */ +/* This work is part of OpenLDAP Software . + * + * Copyright 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 + * . + */ +/* ACKNOWLEDGEMENTS: + * This work was initially developed by the Howard Chu for inclusion + * in OpenLDAP Software and subsequently enhanced by Pierangelo + * Masarati. + */ +/* This is an altered version */ + +/* + * Copyright 1999, Howard Chu, All rights reserved. + * Copyright 2000, Pierangelo Masarati, All rights reserved. + * + * Module back-ldap, originally developed by Howard Chu + * + * has been modified by Pierangelo Masarati. The original copyright + * notice has been maintained. + * + * 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 + +#include +#include + +#include "slap.h" +#include "rwm.h" + +/* FIXME: after rewriting, we should also remap attributes ... */ + +#ifdef ENABLE_REWRITE +int +rwm_dn_massage( + dncookie *dc, + struct berval *dn, + struct berval *res +) +{ + int rc = 0; + + switch ( rewrite_session( dc->rwmap->rwm_rw, dc->ctx, + (dn->bv_len ? dn->bv_val : ""), + dc->conn, &res->bv_val ) ) + { + case REWRITE_REGEXEC_OK: + if ( res->bv_val != NULL ) { + res->bv_len = strlen( res->bv_val ); + } else { + *res = *dn; + } +#ifdef NEW_LOGGING + LDAP_LOG( BACK_LDAP, DETAIL1, + "[rw] %s: \"%s\" -> \"%s\"\n", dc->ctx, dn->bv_val, res->bv_val ); +#else /* !NEW_LOGGING */ + Debug( LDAP_DEBUG_ARGS, + "[rw] %s: \"%s\" -> \"%s\"\n", dc->ctx, dn->bv_val, res->bv_val ); +#endif /* !NEW_LOGGING */ + rc = LDAP_SUCCESS; + break; + + case REWRITE_REGEXEC_UNWILLING: + if ( dc->rs ) { + dc->rs->sr_err = LDAP_UNWILLING_TO_PERFORM; + dc->rs->sr_text = "Operation not allowed"; + } + rc = LDAP_UNWILLING_TO_PERFORM; + break; + + case REWRITE_REGEXEC_ERR: + if ( dc->rs ) { + dc->rs->sr_err = LDAP_OTHER; + dc->rs->sr_text = "Rewrite error"; + } + rc = LDAP_OTHER; + break; + } + return rc; +} + +#else +/* + * rwm_dn_massage + * + * Aliases the suffix; based on suffix_alias (servers/slapd/suffixalias.c). + */ +int +rwm_dn_massage( + dncookie *dc, + struct berval *odn, + struct berval *res +) +{ + int i, src, dst; + struct berval pretty = {0,NULL}, *dn = odn; + + assert( res ); + + if ( dn == NULL ) { + res->bv_val = NULL; + res->bv_len = 0; + return 0; + } + if ( dc->rwmap == NULL || dc->rwmap->rwm_suffix_massage == NULL ) { + *res = *dn; + return 0; + } + + if ( dc->tofrom ) { + src = 0 + dc->normalized; + dst = 2 + dc->normalized; + } else { + src = 2 + dc->normalized; + dst = 0 + dc->normalized; + /* DN from remote server may be in arbitrary form. + * Pretty it so we can parse reliably. + */ + dnPretty( NULL, dn, &pretty, NULL ); + if (pretty.bv_val) dn = &pretty; + } + + for ( i = 0; + dc->rwmap->rwm_suffix_massage[i].bv_val != NULL; + i += 4 ) { + int aliasLength = dc->rwmap->rwm_suffix_massage[i+src].bv_len; + int diff = dn->bv_len - aliasLength; + + if ( diff < 0 ) { + /* alias is longer than dn */ + continue; + } else if ( diff > 0 && ( !DN_SEPARATOR(dn->bv_val[diff-1]))) { + /* boundary is not at a DN separator */ + continue; + /* At a DN Separator */ + } + + if ( !strcmp( dc->rwmap->rwm_suffix_massage[i+src].bv_val, &dn->bv_val[diff] ) ) { + res->bv_len = diff + dc->rwmap->rwm_suffix_massage[i+dst].bv_len; + res->bv_val = ch_malloc( res->bv_len + 1 ); + strncpy( res->bv_val, dn->bv_val, diff ); + strcpy( &res->bv_val[diff], dc->rwmap->rwm_suffix_massage[i+dst].bv_val ); +#ifdef NEW_LOGGING + LDAP_LOG ( BACK_LDAP, ARGS, + "rwm_dn_massage: converted \"%s\" to \"%s\"\n", + dn->bv_val, res->bv_val, 0 ); +#else + Debug( LDAP_DEBUG_ARGS, + "rwm_dn_massage:" + " converted \"%s\" to \"%s\"\n", + dn->bv_val, res->bv_val, 0 ); +#endif + break; + } + } + if (pretty.bv_val) { + ch_free(pretty.bv_val); + dn = odn; + } + /* Nothing matched, just return the original DN */ + if (res->bv_val == NULL) { + *res = *dn; + } + + return 0; +} +#endif /* !ENABLE_REWRITE */ diff --git a/servers/slapd/overlays/rwmmap.c b/servers/slapd/overlays/rwmmap.c new file mode 100644 index 0000000000..85246e1655 --- /dev/null +++ b/servers/slapd/overlays/rwmmap.c @@ -0,0 +1,590 @@ +/* rwmmap.c - rewrite/mapping routines */ +/* $OpenLDAP$ */ +/* 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 + * . + */ +/* ACKNOWLEDGEMENTS: + * This work was initially developed by the Howard Chu for inclusion + * in OpenLDAP Software and subsequently enhanced by Pierangelo + * Masarati. + */ +/* This is an altered version */ +/* + * Copyright 1999, Howard Chu, 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. + * + * + * + * Copyright 2000, Pierangelo Masarati, All rights reserved. + * + * This software is being modified by Pierangelo Masarati. + * The previously reported conditions apply to the modified code as well. + * Changes in the original code are highlighted where required. + * Credits for the original code go to the author, Howard Chu. + */ + +#include "portable.h" + +#include + +#include +#include + +#include "slap.h" +#include "rwm.h" + +#undef ldap_debug /* silence a warning in ldap-int.h */ +#include "../../../libraries/libldap/ldap-int.h" + +int +mapping_cmp ( const void *c1, const void *c2 ) +{ + struct ldapmapping *map1 = (struct ldapmapping *)c1; + struct ldapmapping *map2 = (struct ldapmapping *)c2; + int rc = map1->src.bv_len - map2->src.bv_len; + if (rc) return rc; + return ( strcasecmp(map1->src.bv_val, map2->src.bv_val) ); +} + +int +mapping_dup ( void *c1, void *c2 ) +{ + struct ldapmapping *map1 = (struct ldapmapping *)c1; + struct ldapmapping *map2 = (struct ldapmapping *)c2; + + return( ( strcasecmp(map1->src.bv_val, map2->src.bv_val) == 0 ) ? -1 : 0 ); +} + +void +rwm_map_init ( struct ldapmap *lm, struct ldapmapping **m ) +{ + struct ldapmapping *mapping; + + assert( m ); + + *m = NULL; + + mapping = (struct ldapmapping *)ch_calloc( 2, + sizeof( struct ldapmapping ) ); + if ( mapping == NULL ) { + return; + } + + ber_str2bv( "objectclass", sizeof("objectclass")-1, 1, &mapping->src); + ber_dupbv( &mapping->dst, &mapping->src ); + mapping[1].src = mapping->src; + mapping[1].dst = mapping->dst; + + avl_insert( &lm->map, (caddr_t)mapping, + mapping_cmp, mapping_dup ); + avl_insert( &lm->remap, (caddr_t)&mapping[1], + mapping_cmp, mapping_dup ); + *m = mapping; +} + +void +rwm_map ( struct ldapmap *map, struct berval *s, struct berval *bv, + int remap ) +{ + Avlnode *tree; + struct ldapmapping *mapping, fmapping; + + if (remap == BACKLDAP_REMAP) + tree = map->remap; + else + tree = map->map; + + bv->bv_len = 0; + bv->bv_val = NULL; + fmapping.src = *s; + mapping = (struct ldapmapping *)avl_find( tree, (caddr_t)&fmapping, mapping_cmp ); + if (mapping != NULL) { + if ( mapping->dst.bv_val ) + *bv = mapping->dst; + return; + } + + if (!map->drop_missing) + *bv = *s; + + return; +} + +int +rwm_map_attrs( + struct ldapmap *at_map, + AttributeName *an, + int remap, + char ***mapped_attrs +) +{ + int i, j; + char **na; + struct berval mapped; + + if (an == NULL) { + *mapped_attrs = NULL; + return LDAP_SUCCESS; + } + + for (i = 0; an[i].an_name.bv_val; i++) { + /* */ + } + + na = (char **)ch_calloc( i + 1, sizeof(char *) ); + if (na == NULL) { + *mapped_attrs = NULL; + return LDAP_NO_MEMORY; + } + + for (i = j = 0; an[i].an_name.bv_val; i++) { + rwm_map(at_map, &an[i].an_name, &mapped, remap); + if (mapped.bv_val != NULL && mapped.bv_val != '\0') + na[j++] = mapped.bv_val; + } + if (j == 0 && i != 0) + na[j++] = LDAP_NO_ATTRS; + na[j] = NULL; + + *mapped_attrs = na; + return LDAP_SUCCESS; +} + +int +map_attr_value( + dncookie *dc, + AttributeDescription *ad, + struct berval *mapped_attr, + struct berval *value, + struct berval *mapped_value, + int remap ) +{ + struct berval vtmp; + int freeval = 0; + + rwm_map( &dc->rwmap->rwm_at, &ad->ad_cname, mapped_attr, remap ); + if ( mapped_attr->bv_val == NULL || mapped_attr->bv_val[0] == '\0') { + /* + * FIXME: are we sure we need to search oc_map if at_map fails? + */ + rwm_map( &dc->rwmap->rwm_oc, &ad->ad_cname, mapped_attr, remap ); + if ( mapped_attr->bv_val == NULL || mapped_attr->bv_val[0] == '\0' ) { + *mapped_attr = ad->ad_cname; + } + } + + if ( value == NULL ) { + return 0; + } + + if ( ad->ad_type->sat_syntax == slap_schema.si_syn_distinguishedName ) + { + dncookie fdc = *dc; + +#ifdef ENABLE_REWRITE + fdc.ctx = "searchFilter"; +#endif + + switch ( rwm_dn_massage( &fdc, value, &vtmp ) ) { + case LDAP_SUCCESS: + if ( vtmp.bv_val != value->bv_val ) { + freeval = 1; + } + break; + + case LDAP_UNWILLING_TO_PERFORM: + return -1; + + case LDAP_OTHER: + return -1; + } + + } else if ( ad == slap_schema.si_ad_objectClass || ad == slap_schema.si_ad_structuralObjectClass ) { + rwm_map( &dc->rwmap->rwm_oc, value, &vtmp, remap ); + if ( vtmp.bv_val == NULL || vtmp.bv_val[0] == '\0' ) { + vtmp = *value; + } + + } else { + vtmp = *value; + } + + filter_escape_value( &vtmp, mapped_value ); + + if ( freeval ) { + ber_memfree( vtmp.bv_val ); + } + + return 0; +} + +int +rwm_filter_map_rewrite( + dncookie *dc, + Filter *f, + struct berval *fstr, + int remap ) +{ + int i; + Filter *p; + struct berval atmp; + struct berval vtmp; + ber_len_t len; + + if ( f == NULL ) { + ber_str2bv( "No filter!", sizeof("No filter!")-1, 1, fstr ); + return -1; + } + + switch ( f->f_choice ) { + case LDAP_FILTER_EQUALITY: + if ( map_attr_value( dc, f->f_av_desc, &atmp, + &f->f_av_value, &vtmp, remap ) ) + { + return -1; + } + + fstr->bv_len = atmp.bv_len + vtmp.bv_len + + ( sizeof("(=)") - 1 ); + fstr->bv_val = malloc( fstr->bv_len + 1 ); + + snprintf( fstr->bv_val, fstr->bv_len + 1, "(%s=%s)", + atmp.bv_val, vtmp.bv_val ); + + ber_memfree( vtmp.bv_val ); + break; + + case LDAP_FILTER_GE: + if ( map_attr_value( dc, f->f_av_desc, &atmp, + &f->f_av_value, &vtmp, remap ) ) + { + return -1; + } + + fstr->bv_len = atmp.bv_len + vtmp.bv_len + + ( sizeof("(>=)") - 1 ); + fstr->bv_val = malloc( fstr->bv_len + 1 ); + + snprintf( fstr->bv_val, fstr->bv_len + 1, "(%s>=%s)", + atmp.bv_val, vtmp.bv_val ); + + ber_memfree( vtmp.bv_val ); + break; + + case LDAP_FILTER_LE: + if ( map_attr_value( dc, f->f_av_desc, &atmp, + &f->f_av_value, &vtmp, remap ) ) + { + return -1; + } + + fstr->bv_len = atmp.bv_len + vtmp.bv_len + + ( sizeof("(<=)") - 1 ); + fstr->bv_val = malloc( fstr->bv_len + 1 ); + + snprintf( fstr->bv_val, fstr->bv_len + 1, "(%s<=%s)", + atmp.bv_val, vtmp.bv_val ); + + ber_memfree( vtmp.bv_val ); + break; + + case LDAP_FILTER_APPROX: + if ( map_attr_value( dc, f->f_av_desc, &atmp, + &f->f_av_value, &vtmp, remap ) ) + { + return -1; + } + + fstr->bv_len = atmp.bv_len + vtmp.bv_len + + ( sizeof("(~=)") - 1 ); + fstr->bv_val = malloc( fstr->bv_len + 1 ); + + snprintf( fstr->bv_val, fstr->bv_len + 1, "(%s~=%s)", + atmp.bv_val, vtmp.bv_val ); + + ber_memfree( vtmp.bv_val ); + break; + + case LDAP_FILTER_SUBSTRINGS: + if ( map_attr_value( dc, f->f_sub_desc, &atmp, + NULL, NULL, remap ) ) + { + return -1; + } + + /* cannot be a DN ... */ + + fstr->bv_len = atmp.bv_len + ( sizeof("(=*)") - 1 ); + fstr->bv_val = malloc( fstr->bv_len + 128 ); + + snprintf( fstr->bv_val, fstr->bv_len + 1, "(%s=*)", + atmp.bv_val ); + + if ( f->f_sub_initial.bv_val != NULL ) { + len = fstr->bv_len; + + filter_escape_value( &f->f_sub_initial, &vtmp ); + + fstr->bv_len += vtmp.bv_len; + fstr->bv_val = ch_realloc( fstr->bv_val, fstr->bv_len + 1 ); + + snprintf( &fstr->bv_val[len - 2], vtmp.bv_len + 3, + /* "(attr=" */ "%s*)", + vtmp.bv_val ); + + ber_memfree( vtmp.bv_val ); + } + + if ( f->f_sub_any != NULL ) { + for ( i = 0; f->f_sub_any[i].bv_val != NULL; i++ ) { + len = fstr->bv_len; + filter_escape_value( &f->f_sub_any[i], &vtmp ); + + fstr->bv_len += vtmp.bv_len + 1; + fstr->bv_val = ch_realloc( fstr->bv_val, fstr->bv_len + 1 ); + + snprintf( &fstr->bv_val[len - 1], vtmp.bv_len + 3, + /* "(attr=[init]*[any*]" */ "%s*)", + vtmp.bv_val ); + ber_memfree( vtmp.bv_val ); + } + } + + if ( f->f_sub_final.bv_val != NULL ) { + len = fstr->bv_len; + + filter_escape_value( &f->f_sub_final, &vtmp ); + + fstr->bv_len += vtmp.bv_len; + fstr->bv_val = ch_realloc( fstr->bv_val, fstr->bv_len + 1 ); + + snprintf( &fstr->bv_val[len - 1], vtmp.bv_len + 3, + /* "(attr=[init*][any*]" */ "%s)", + vtmp.bv_val ); + + ber_memfree( vtmp.bv_val ); + } + + break; + + case LDAP_FILTER_PRESENT: + if ( map_attr_value( dc, f->f_desc, &atmp, + NULL, NULL, remap ) ) + { + return -1; + } + + fstr->bv_len = atmp.bv_len + ( sizeof("(=*)") - 1 ); + fstr->bv_val = malloc( fstr->bv_len + 1 ); + + snprintf( fstr->bv_val, fstr->bv_len + 1, "(%s=*)", + atmp.bv_val ); + break; + + case LDAP_FILTER_AND: + case LDAP_FILTER_OR: + case LDAP_FILTER_NOT: + fstr->bv_len = sizeof("(%)") - 1; + fstr->bv_val = malloc( fstr->bv_len + 128 ); + + snprintf( fstr->bv_val, fstr->bv_len + 1, "(%c)", + f->f_choice == LDAP_FILTER_AND ? '&' : + f->f_choice == LDAP_FILTER_OR ? '|' : '!' ); + + for ( p = f->f_list; p != NULL; p = p->f_next ) { + len = fstr->bv_len; + + if ( rwm_filter_map_rewrite( dc, p, &vtmp, remap ) ) + { + return -1; + } + + fstr->bv_len += vtmp.bv_len; + fstr->bv_val = ch_realloc( fstr->bv_val, fstr->bv_len + 1 ); + + snprintf( &fstr->bv_val[len-1], vtmp.bv_len + 2, + /*"("*/ "%s)", vtmp.bv_val ); + + ch_free( vtmp.bv_val ); + } + + break; + + case LDAP_FILTER_EXT: { + if ( f->f_mr_desc ) { + if ( map_attr_value( dc, f->f_mr_desc, &atmp, + &f->f_mr_value, &vtmp, remap ) ) + { + return -1; + } + + } else { + atmp.bv_len = 0; + atmp.bv_val = ""; + + filter_escape_value( &f->f_mr_value, &vtmp ); + } + + + fstr->bv_len = atmp.bv_len + + ( f->f_mr_dnattrs ? sizeof(":dn")-1 : 0 ) + + ( f->f_mr_rule_text.bv_len ? f->f_mr_rule_text.bv_len+1 : 0 ) + + vtmp.bv_len + ( sizeof("(:=)") - 1 ); + fstr->bv_val = malloc( fstr->bv_len + 1 ); + + snprintf( fstr->bv_val, fstr->bv_len + 1, "(%s%s%s%s:=%s)", + atmp.bv_val, + f->f_mr_dnattrs ? ":dn" : "", + f->f_mr_rule_text.bv_len ? ":" : "", + f->f_mr_rule_text.bv_len ? f->f_mr_rule_text.bv_val : "", + vtmp.bv_val ); + ber_memfree( vtmp.bv_val ); + } break; + + case SLAPD_FILTER_COMPUTED: + ber_str2bv( + f->f_result == LDAP_COMPARE_FALSE ? "(?=false)" : + f->f_result == LDAP_COMPARE_TRUE ? "(?=true)" : + f->f_result == SLAPD_COMPARE_UNDEFINED ? "(?=undefined)" : + "(?=error)", + f->f_result == LDAP_COMPARE_FALSE ? sizeof("(?=false)")-1 : + f->f_result == LDAP_COMPARE_TRUE ? sizeof("(?=true)")-1 : + f->f_result == SLAPD_COMPARE_UNDEFINED ? sizeof("(?=undefined)")-1 : + sizeof("(?=error)")-1, + 1, fstr ); + break; + + default: + ber_str2bv( "(?=unknown)", sizeof("(?=unknown)")-1, 1, fstr ); + break; + } + + return 0; +} + +/* + * I don't like this much, but we need two different + * functions because different heap managers may be + * in use in back-ldap/meta to reduce the amount of + * calls to malloc routines, and some of the free() + * routines may be macros with args + */ +int +ldap_dnattr_rewrite( + dncookie *dc, + BerVarray a_vals +) +{ + struct berval bv; + int i, last; + + for ( last = 0; a_vals[last].bv_val != NULL; last++ ); + last--; + + for ( i = 0; a_vals[i].bv_val != NULL; i++ ) { + switch ( rwm_dn_massage( dc, &a_vals[i], &bv ) ) { + case LDAP_UNWILLING_TO_PERFORM: + /* + * FIXME: need to check if it may be considered + * legal to trim values when adding/modifying; + * it should be when searching (e.g. ACLs). + */ + ch_free( a_vals[i].bv_val ); + if (last > i ) { + a_vals[i] = a_vals[last]; + } + a_vals[last].bv_len = 0; + a_vals[last].bv_val = NULL; + last--; + break; + + default: + /* leave attr untouched if massage failed */ + if ( bv.bv_val && bv.bv_val != a_vals[i].bv_val ) { + ch_free( a_vals[i].bv_val ); + a_vals[i] = bv; + } + break; + } + } + + return 0; +} + +int +ldap_dnattr_result_rewrite( + dncookie *dc, + BerVarray a_vals +) +{ + struct berval bv; + int i, last; + + for ( last = 0; a_vals[last].bv_val; last++ ); + last--; + + for ( i = 0; a_vals[i].bv_val; i++ ) { + switch ( rwm_dn_massage( dc, &a_vals[i], &bv ) ) { + case LDAP_UNWILLING_TO_PERFORM: + /* + * FIXME: need to check if it may be considered + * legal to trim values when adding/modifying; + * it should be when searching (e.g. ACLs). + */ + LBER_FREE( &a_vals[i].bv_val ); + if ( last > i ) { + a_vals[i] = a_vals[last]; + } + a_vals[last].bv_val = NULL; + a_vals[last].bv_len = 0; + last--; + break; + + default: + /* leave attr untouched if massage failed */ + if ( bv.bv_val && a_vals[i].bv_val != bv.bv_val ) { + LBER_FREE( a_vals[i].bv_val ); + a_vals[i] = bv; + } + break; + } + } + + return 0; +} + +void +mapping_free( void *v_mapping ) +{ + struct ldapmapping *mapping = v_mapping; + ch_free( mapping->src.bv_val ); + ch_free( mapping->dst.bv_val ); + ch_free( mapping ); +} + -- 2.39.5