Home | History | Annotate | Line # | Download | only in overlays
rwm.c revision 1.1.1.1
      1 /* rwm.c - rewrite/remap operations */
      2 /* $OpenLDAP: pkg/ldap/servers/slapd/overlays/rwm.c,v 1.70.2.10 2008/02/15 18:11:46 quanah Exp $ */
      3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
      4  *
      5  * Copyright 2003-2008 The OpenLDAP Foundation.
      6  * Portions Copyright 2003 Pierangelo Masarati.
      7  * All rights reserved.
      8  *
      9  * Redistribution and use in source and binary forms, with or without
     10  * modification, are permitted only as authorized by the OpenLDAP
     11  * Public License.
     12  *
     13  * A copy of this license is available in the file LICENSE in the
     14  * top-level directory of the distribution or, alternatively, at
     15  * <http://www.OpenLDAP.org/license.html>.
     16  */
     17 
     18 #include "portable.h"
     19 
     20 #ifdef SLAPD_OVER_RWM
     21 
     22 #include <stdio.h>
     23 
     24 #include <ac/string.h>
     25 
     26 #include "slap.h"
     27 #include "config.h"
     28 #include "lutil.h"
     29 #include "rwm.h"
     30 
     31 typedef struct rwm_op_state {
     32 	ber_tag_t r_tag;
     33 	struct berval ro_dn;
     34 	struct berval ro_ndn;
     35 	struct berval r_dn;
     36 	struct berval r_ndn;
     37 	AttributeName *mapped_attrs;
     38 	OpRequest o_request;
     39 } rwm_op_state;
     40 
     41 static int
     42 rwm_db_destroy( BackendDB *be, ConfigReply *cr );
     43 
     44 typedef struct rwm_op_cb {
     45 	slap_callback cb;
     46 	rwm_op_state ros;
     47 } rwm_op_cb;
     48 
     49 static int
     50 rwm_op_cleanup( Operation *op, SlapReply *rs )
     51 {
     52 	slap_callback	*cb = op->o_callback;
     53 	rwm_op_state *ros = cb->sc_private;
     54 
     55 	if ( rs->sr_type == REP_RESULT || rs->sr_type == REP_EXTENDED ||
     56 		op->o_abandon || rs->sr_err == SLAPD_ABANDON ) {
     57 
     58 		op->o_req_dn = ros->ro_dn;
     59 		op->o_req_ndn = ros->ro_ndn;
     60 
     61 		if ( !BER_BVISNULL( &ros->r_dn )
     62 			&& ros->r_dn.bv_val != ros->r_ndn.bv_val )
     63 		{
     64 			ch_free( ros->r_dn.bv_val );
     65 			BER_BVZERO( &ros->r_dn );
     66 		}
     67 
     68 		if ( !BER_BVISNULL( &ros->r_ndn ) ) {
     69 			ch_free( ros->r_ndn.bv_val );
     70 			BER_BVZERO( &ros->r_ndn );
     71 		}
     72 
     73 		switch( ros->r_tag ) {
     74 		case LDAP_REQ_COMPARE:
     75 			if ( op->orc_ava->aa_value.bv_val != ros->orc_ava->aa_value.bv_val )
     76 				op->o_tmpfree( op->orc_ava->aa_value.bv_val, op->o_tmpmemctx );
     77 			op->orc_ava = ros->orc_ava;
     78 			break;
     79 		case LDAP_REQ_MODIFY:
     80 			slap_mods_free( op->orm_modlist, 1 );
     81 			op->orm_modlist = ros->orm_modlist;
     82 			break;
     83 		case LDAP_REQ_MODRDN:
     84 			if ( op->orr_newSup != ros->orr_newSup ) {
     85 				ch_free( op->orr_newSup->bv_val );
     86 				ch_free( op->orr_nnewSup->bv_val );
     87 				op->o_tmpfree( op->orr_newSup, op->o_tmpmemctx );
     88 				op->o_tmpfree( op->orr_nnewSup, op->o_tmpmemctx );
     89 				op->orr_newSup = ros->orr_newSup;
     90 				op->orr_nnewSup = ros->orr_nnewSup;
     91 			}
     92 			break;
     93 		case LDAP_REQ_SEARCH:
     94 			ch_free( ros->mapped_attrs );
     95 			filter_free_x( op, op->ors_filter );
     96 			ch_free( op->ors_filterstr.bv_val );
     97 			op->ors_attrs = ros->ors_attrs;
     98 			op->ors_filter = ros->ors_filter;
     99 			op->ors_filterstr = ros->ors_filterstr;
    100 			break;
    101 		case LDAP_REQ_EXTENDED:
    102 			if ( op->ore_reqdata != ros->ore_reqdata ) {
    103 				ber_bvfree( op->ore_reqdata );
    104 				op->ore_reqdata = ros->ore_reqdata;
    105 			}
    106 			break;
    107 		default:	break;
    108 		}
    109 		op->o_callback = op->o_callback->sc_next;
    110 		op->o_tmpfree( cb, op->o_tmpmemctx );
    111 	}
    112 
    113 	return SLAP_CB_CONTINUE;
    114 }
    115 
    116 static rwm_op_cb *
    117 rwm_callback_get( Operation *op, SlapReply *rs )
    118 {
    119 	rwm_op_cb	*roc = NULL;
    120 
    121 	roc = op->o_tmpalloc( sizeof( struct rwm_op_cb ), op->o_tmpmemctx );
    122 	roc->cb.sc_cleanup = rwm_op_cleanup;
    123 	roc->cb.sc_response = NULL;
    124 	roc->cb.sc_next = op->o_callback;
    125 	roc->cb.sc_private = &roc->ros;
    126 	roc->ros.r_tag = op->o_tag;
    127 	roc->ros.ro_dn = op->o_req_dn;
    128 	roc->ros.ro_ndn = op->o_req_ndn;
    129 	roc->ros.o_request = op->o_request;
    130 	BER_BVZERO( &roc->ros.r_dn );
    131 	BER_BVZERO( &roc->ros.r_ndn );
    132 
    133 	return roc;
    134 }
    135 
    136 
    137 static int
    138 rwm_op_dn_massage( Operation *op, SlapReply *rs, void *cookie,
    139 	rwm_op_state *ros )
    140 {
    141 	slap_overinst		*on = (slap_overinst *) op->o_bd->bd_info;
    142 	struct ldaprwmap	*rwmap =
    143 			(struct ldaprwmap *)on->on_bi.bi_private;
    144 
    145 	struct berval		dn = BER_BVNULL,
    146 				ndn = BER_BVNULL;
    147 	int			rc = 0;
    148 	dncookie		dc;
    149 
    150 	/*
    151 	 * Rewrite the dn if needed
    152 	 */
    153 	dc.rwmap = rwmap;
    154 	dc.conn = op->o_conn;
    155 	dc.rs = rs;
    156 	dc.ctx = (char *)cookie;
    157 
    158 	/* NOTE: in those cases where only the ndn is available,
    159 	 * and the caller sets op->o_req_dn = op->o_req_ndn,
    160 	 * only rewrite the op->o_req_ndn and use it as
    161 	 * op->o_req_dn as well */
    162 	ndn = op->o_req_ndn;
    163 	if ( op->o_req_dn.bv_val != op->o_req_ndn.bv_val ) {
    164 		dn = op->o_req_dn;
    165 		rc = rwm_dn_massage_pretty_normalize( &dc, &op->o_req_dn, &dn, &ndn );
    166 	} else {
    167 		rc = rwm_dn_massage_normalize( &dc, &op->o_req_ndn, &ndn );
    168 	}
    169 
    170 	if ( rc != LDAP_SUCCESS ) {
    171 		return rc;
    172 	}
    173 
    174 	if ( ( op->o_req_dn.bv_val != op->o_req_ndn.bv_val && dn.bv_val == op->o_req_dn.bv_val )
    175 			|| ndn.bv_val == op->o_req_ndn.bv_val )
    176 	{
    177 		return LDAP_SUCCESS;
    178 	}
    179 
    180 	if ( op->o_req_dn.bv_val != op->o_req_ndn.bv_val ) {
    181 		op->o_req_dn = dn;
    182 		ros->r_dn = dn;
    183 	} else {
    184 		op->o_req_dn = ndn;
    185 	}
    186 	op->o_req_ndn = ndn;
    187 	ros->r_ndn = ndn;
    188 
    189 	return LDAP_SUCCESS;
    190 }
    191 
    192 static int
    193 rwm_op_add( Operation *op, SlapReply *rs )
    194 {
    195 	slap_overinst		*on = (slap_overinst *) op->o_bd->bd_info;
    196 	struct ldaprwmap	*rwmap =
    197 			(struct ldaprwmap *)on->on_bi.bi_private;
    198 
    199 	int			rc,
    200 				i;
    201 	Attribute		**ap = NULL;
    202 	char			*olddn = op->o_req_dn.bv_val;
    203 	int			isupdate;
    204 
    205 	rwm_op_cb		*roc = rwm_callback_get( op, rs );
    206 
    207 	rc = rwm_op_dn_massage( op, rs, "addDN", &roc->ros );
    208 	if ( rc != LDAP_SUCCESS ) {
    209 		op->o_bd->bd_info = (BackendInfo *)on->on_info;
    210 		send_ldap_error( op, rs, rc, "addDN massage error" );
    211 		return -1;
    212 	}
    213 
    214 	if ( olddn != op->o_req_dn.bv_val ) {
    215 		ber_bvreplace( &op->ora_e->e_name, &op->o_req_dn );
    216 		ber_bvreplace( &op->ora_e->e_nname, &op->o_req_ndn );
    217 	}
    218 
    219 	/* Count number of attributes in entry */
    220 	isupdate = be_shadow_update( op );
    221 	for ( i = 0, ap = &op->oq_add.rs_e->e_attrs; *ap; ) {
    222 		Attribute	*a;
    223 
    224 		if ( (*ap)->a_desc == slap_schema.si_ad_objectClass ||
    225 				(*ap)->a_desc == slap_schema.si_ad_structuralObjectClass )
    226 		{
    227 			int		j, last;
    228 
    229 			last = (*ap)->a_numvals - 1;
    230 			for ( j = 0; !BER_BVISNULL( &(*ap)->a_vals[ j ] ); j++ ) {
    231 				struct ldapmapping	*mapping = NULL;
    232 
    233 				( void )rwm_mapping( &rwmap->rwm_oc, &(*ap)->a_vals[ j ],
    234 						&mapping, RWM_MAP );
    235 				if ( mapping == NULL ) {
    236 					if ( rwmap->rwm_at.drop_missing ) {
    237 						/* FIXME: we allow to remove objectClasses as well;
    238 						 * if the resulting entry is inconsistent, that's
    239 						 * the relayed database's business...
    240 						 */
    241 						ch_free( (*ap)->a_vals[ j ].bv_val );
    242 						if ( last > j ) {
    243 							(*ap)->a_vals[ j ] = (*ap)->a_vals[ last ];
    244 						}
    245 						BER_BVZERO( &(*ap)->a_vals[ last ] );
    246 						(*ap)->a_numvals--;
    247 						last--;
    248 						j--;
    249 					}
    250 
    251 				} else {
    252 					ch_free( (*ap)->a_vals[ j ].bv_val );
    253 					ber_dupbv( &(*ap)->a_vals[ j ], &mapping->m_dst );
    254 				}
    255 			}
    256 
    257 		} else if ( !isupdate && !get_relax( op ) && (*ap)->a_desc->ad_type->sat_no_user_mod )
    258 		{
    259 			goto next_attr;
    260 
    261 		} else {
    262 			struct ldapmapping	*mapping = NULL;
    263 
    264 			( void )rwm_mapping( &rwmap->rwm_at, &(*ap)->a_desc->ad_cname,
    265 					&mapping, RWM_MAP );
    266 			if ( mapping == NULL ) {
    267 				if ( rwmap->rwm_at.drop_missing ) {
    268 					goto cleanup_attr;
    269 				}
    270 			}
    271 
    272 			if ( (*ap)->a_desc->ad_type->sat_syntax == slap_schema.si_syn_distinguishedName
    273 					|| ( mapping != NULL && mapping->m_dst_ad->ad_type->sat_syntax == slap_schema.si_syn_distinguishedName ) )
    274 			{
    275 				/*
    276 				 * FIXME: rewrite could fail; in this case
    277 				 * the operation should give up, right?
    278 				 */
    279 				rc = rwm_dnattr_rewrite( op, rs, "addAttrDN",
    280 						(*ap)->a_vals,
    281 						(*ap)->a_nvals ? &(*ap)->a_nvals : NULL );
    282 				if ( rc ) {
    283 					goto cleanup_attr;
    284 				}
    285 
    286 			} else if ( (*ap)->a_desc == slap_schema.si_ad_ref ) {
    287 				rc = rwm_referral_rewrite( op, rs, "referralAttrDN",
    288 						(*ap)->a_vals,
    289 						(*ap)->a_nvals ? &(*ap)->a_nvals : NULL );
    290 				if ( rc != LDAP_SUCCESS ) {
    291 					goto cleanup_attr;
    292 				}
    293 			}
    294 
    295 			if ( mapping != NULL ) {
    296 				assert( mapping->m_dst_ad != NULL );
    297 				(*ap)->a_desc = mapping->m_dst_ad;
    298 			}
    299 		}
    300 
    301 next_attr:;
    302 		ap = &(*ap)->a_next;
    303 		continue;
    304 
    305 cleanup_attr:;
    306 		/* FIXME: leaking attribute/values? */
    307 		a = *ap;
    308 
    309 		*ap = (*ap)->a_next;
    310 		attr_free( a );
    311 	}
    312 
    313 	op->o_callback = &roc->cb;
    314 
    315 	return SLAP_CB_CONTINUE;
    316 }
    317 
    318 static int
    319 rwm_conn_init( BackendDB *be, Connection *conn )
    320 {
    321 	slap_overinst		*on = (slap_overinst *) be->bd_info;
    322 	struct ldaprwmap	*rwmap =
    323 			(struct ldaprwmap *)on->on_bi.bi_private;
    324 
    325 	( void )rewrite_session_init( rwmap->rwm_rw, conn );
    326 
    327 	return SLAP_CB_CONTINUE;
    328 }
    329 
    330 static int
    331 rwm_conn_destroy( BackendDB *be, Connection *conn )
    332 {
    333 	slap_overinst		*on = (slap_overinst *) be->bd_info;
    334 	struct ldaprwmap	*rwmap =
    335 			(struct ldaprwmap *)on->on_bi.bi_private;
    336 
    337 	( void )rewrite_session_delete( rwmap->rwm_rw, conn );
    338 
    339 	return SLAP_CB_CONTINUE;
    340 }
    341 
    342 static int
    343 rwm_op_bind( Operation *op, SlapReply *rs )
    344 {
    345 	slap_overinst		*on = (slap_overinst *) op->o_bd->bd_info;
    346 	int			rc;
    347 
    348 	rwm_op_cb		*roc = rwm_callback_get( op, rs );
    349 
    350 	rc = rwm_op_dn_massage( op, rs, "bindDN", &roc->ros );
    351 	if ( rc != LDAP_SUCCESS ) {
    352 		op->o_bd->bd_info = (BackendInfo *)on->on_info;
    353 		send_ldap_error( op, rs, rc, "bindDN massage error" );
    354 		return -1;
    355 	}
    356 
    357 	op->o_callback = &roc->cb;
    358 
    359 	return SLAP_CB_CONTINUE;
    360 }
    361 
    362 static int
    363 rwm_op_unbind( Operation *op, SlapReply *rs )
    364 {
    365 	slap_overinst		*on = (slap_overinst *) op->o_bd->bd_info;
    366 	struct ldaprwmap	*rwmap =
    367 			(struct ldaprwmap *)on->on_bi.bi_private;
    368 
    369 	rewrite_session_delete( rwmap->rwm_rw, op->o_conn );
    370 
    371 	return SLAP_CB_CONTINUE;
    372 }
    373 
    374 static int
    375 rwm_op_compare( Operation *op, SlapReply *rs )
    376 {
    377 	slap_overinst		*on = (slap_overinst *) op->o_bd->bd_info;
    378 	struct ldaprwmap	*rwmap =
    379 			(struct ldaprwmap *)on->on_bi.bi_private;
    380 
    381 	int			rc;
    382 	struct berval		mapped_vals[2] = { BER_BVNULL, BER_BVNULL };
    383 
    384 	rwm_op_cb		*roc = rwm_callback_get( op, rs );
    385 
    386 	rc = rwm_op_dn_massage( op, rs, "compareDN", &roc->ros );
    387 	if ( rc != LDAP_SUCCESS ) {
    388 		op->o_bd->bd_info = (BackendInfo *)on->on_info;
    389 		send_ldap_error( op, rs, rc, "compareDN massage error" );
    390 		return -1;
    391 	}
    392 
    393 	/* if the attribute is an objectClass, try to remap its value */
    394 	if ( op->orc_ava->aa_desc == slap_schema.si_ad_objectClass
    395 			|| op->orc_ava->aa_desc == slap_schema.si_ad_structuralObjectClass )
    396 	{
    397 		rwm_map( &rwmap->rwm_oc, &op->orc_ava->aa_value,
    398 				&mapped_vals[0], RWM_MAP );
    399 		if ( BER_BVISNULL( &mapped_vals[0] ) || BER_BVISEMPTY( &mapped_vals[0] ) )
    400 		{
    401 			op->o_bd->bd_info = (BackendInfo *)on->on_info;
    402 			send_ldap_error( op, rs, LDAP_OTHER, "compare objectClass map error" );
    403 			return -1;
    404 
    405 		} else if ( mapped_vals[0].bv_val != op->orc_ava->aa_value.bv_val ) {
    406 			ber_dupbv_x( &op->orc_ava->aa_value, &mapped_vals[0],
    407 				op->o_tmpmemctx );
    408 		}
    409 
    410 	} else {
    411 		struct ldapmapping	*mapping = NULL;
    412 		AttributeDescription	*ad = op->orc_ava->aa_desc;
    413 
    414 		( void )rwm_mapping( &rwmap->rwm_at, &op->orc_ava->aa_desc->ad_cname,
    415 				&mapping, RWM_MAP );
    416 		if ( mapping == NULL ) {
    417 			if ( rwmap->rwm_at.drop_missing ) {
    418 				op->o_bd->bd_info = (BackendInfo *)on->on_info;
    419 				send_ldap_error( op, rs, LDAP_OTHER, "compare attributeType map error" );
    420 				return -1;
    421 			}
    422 
    423 		} else {
    424 			assert( mapping->m_dst_ad != NULL );
    425 			ad = mapping->m_dst_ad;
    426 		}
    427 
    428 		if ( op->orc_ava->aa_desc->ad_type->sat_syntax == slap_schema.si_syn_distinguishedName
    429 				|| ( mapping != NULL && mapping->m_dst_ad->ad_type->sat_syntax == slap_schema.si_syn_distinguishedName ) )
    430 		{
    431 			struct berval	*mapped_valsp[2];
    432 
    433 			mapped_valsp[0] = &mapped_vals[0];
    434 			mapped_valsp[1] = &mapped_vals[1];
    435 
    436 			mapped_vals[0] = op->orc_ava->aa_value;
    437 
    438 			rc = rwm_dnattr_rewrite( op, rs, "compareAttrDN", NULL, mapped_valsp );
    439 
    440 			if ( rc != LDAP_SUCCESS ) {
    441 				op->o_bd->bd_info = (BackendInfo *)on->on_info;
    442 				send_ldap_error( op, rs, rc, "compareAttrDN massage error" );
    443 				return -1;
    444 			}
    445 
    446 			if ( mapped_vals[ 0 ].bv_val != op->orc_ava->aa_value.bv_val ) {
    447 				/* NOTE: if we get here, rwm_dnattr_rewrite()
    448 				 * already freed the old value, so now
    449 				 * it's invalid */
    450 				ber_dupbv_x( &op->orc_ava->aa_value, &mapped_vals[0],
    451 					op->o_tmpmemctx );
    452 				ber_memfree_x( mapped_vals[ 0 ].bv_val, NULL );
    453 			}
    454 		}
    455 		op->orc_ava->aa_desc = ad;
    456 	}
    457 
    458 	op->o_callback = &roc->cb;
    459 
    460 	return SLAP_CB_CONTINUE;
    461 }
    462 
    463 static int
    464 rwm_op_delete( Operation *op, SlapReply *rs )
    465 {
    466 	slap_overinst		*on = (slap_overinst *) op->o_bd->bd_info;
    467 	int			rc;
    468 
    469 	rwm_op_cb		*roc = rwm_callback_get( op, rs );
    470 
    471 	rc = rwm_op_dn_massage( op, rs, "deleteDN", &roc->ros );
    472 	if ( rc != LDAP_SUCCESS ) {
    473 		op->o_bd->bd_info = (BackendInfo *)on->on_info;
    474 		send_ldap_error( op, rs, rc, "deleteDN massage error" );
    475 		return -1;
    476 	}
    477 
    478 	op->o_callback = &roc->cb;
    479 
    480 	return SLAP_CB_CONTINUE;
    481 }
    482 
    483 static int
    484 rwm_op_modify( Operation *op, SlapReply *rs )
    485 {
    486 	slap_overinst		*on = (slap_overinst *) op->o_bd->bd_info;
    487 	struct ldaprwmap	*rwmap =
    488 			(struct ldaprwmap *)on->on_bi.bi_private;
    489 
    490 	int			isupdate;
    491 	Modifications		**mlp;
    492 	int			rc;
    493 
    494 	rwm_op_cb		*roc = rwm_callback_get( op, rs );
    495 
    496 	rc = rwm_op_dn_massage( op, rs, "modifyDN", &roc->ros );
    497 	if ( rc != LDAP_SUCCESS ) {
    498 		op->o_bd->bd_info = (BackendInfo *)on->on_info;
    499 		send_ldap_error( op, rs, rc, "modifyDN massage error" );
    500 		return -1;
    501 	}
    502 
    503 	isupdate = be_shadow_update( op );
    504 	for ( mlp = &op->orm_modlist; *mlp; ) {
    505 		int			is_oc = 0;
    506 		Modifications		*ml = *mlp;
    507 		struct ldapmapping	*mapping = NULL;
    508 
    509 		/* ml points to a temporary mod until needs duplication */
    510 		if ( ml->sml_desc == slap_schema.si_ad_objectClass
    511 				|| ml->sml_desc == slap_schema.si_ad_structuralObjectClass )
    512 		{
    513 			is_oc = 1;
    514 
    515 		} else if ( !isupdate && !get_relax( op ) && ml->sml_desc->ad_type->sat_no_user_mod  )
    516 		{
    517 			ml = ch_malloc( sizeof( Modifications ) );
    518 			*ml = **mlp;
    519 			if ( (*mlp)->sml_values ) {
    520 				ber_bvarray_dup_x( &ml->sml_values, (*mlp)->sml_values, NULL );
    521 				if ( (*mlp)->sml_nvalues ) {
    522 					ber_bvarray_dup_x( &ml->sml_nvalues, (*mlp)->sml_nvalues, NULL );
    523 				}
    524 			}
    525 			*mlp = ml;
    526 			goto next_mod;
    527 
    528 		} else {
    529 			int			drop_missing;
    530 
    531 			drop_missing = rwm_mapping( &rwmap->rwm_at,
    532 					&ml->sml_desc->ad_cname,
    533 					&mapping, RWM_MAP );
    534 			if ( drop_missing || ( mapping != NULL && BER_BVISNULL( &mapping->m_dst ) ) )
    535 			{
    536 				goto cleanup_mod;
    537 			}
    538 		}
    539 
    540 		/* duplicate the modlist */
    541 		ml = ch_malloc( sizeof( Modifications ));
    542 		*ml = **mlp;
    543 		*mlp = ml;
    544 
    545 		if ( ml->sml_values != NULL ) {
    546 			int i, num;
    547 			struct berval *bva;
    548 
    549 			for ( num = 0; !BER_BVISNULL( &ml->sml_values[ num ] ); num++ )
    550 				/* count values */ ;
    551 
    552 			bva = ch_malloc( (num+1) * sizeof( struct berval ));
    553 			for (i=0; i<num; i++)
    554 				ber_dupbv( &bva[i], &ml->sml_values[i] );
    555 			BER_BVZERO( &bva[i] );
    556 			ml->sml_values = bva;
    557 
    558 			if ( ml->sml_nvalues ) {
    559 				bva = ch_malloc( (num+1) * sizeof( struct berval ));
    560 				for (i=0; i<num; i++)
    561 					ber_dupbv( &bva[i], &ml->sml_nvalues[i] );
    562 				BER_BVZERO( &bva[i] );
    563 				ml->sml_nvalues = bva;
    564 			}
    565 
    566 			if ( is_oc ) {
    567 				int	last, j;
    568 
    569 				last = num-1;
    570 
    571 				for ( j = 0; !BER_BVISNULL( &ml->sml_values[ j ] ); j++ ) {
    572 					struct ldapmapping	*oc_mapping = NULL;
    573 
    574 					( void )rwm_mapping( &rwmap->rwm_oc, &ml->sml_values[ j ],
    575 							&oc_mapping, RWM_MAP );
    576 					if ( oc_mapping == NULL ) {
    577 						if ( rwmap->rwm_at.drop_missing ) {
    578 							/* FIXME: we allow to remove objectClasses as well;
    579 							 * if the resulting entry is inconsistent, that's
    580 							 * the relayed database's business...
    581 							 */
    582 							if ( last > j ) {
    583 								ch_free( ml->sml_values[ j ].bv_val );
    584 								ml->sml_values[ j ] = ml->sml_values[ last ];
    585 							}
    586 							BER_BVZERO( &ml->sml_values[ last ] );
    587 							last--;
    588 							j--;
    589 						}
    590 
    591 					} else {
    592 						ch_free( ml->sml_values[ j ].bv_val );
    593 						ber_dupbv( &ml->sml_values[ j ], &oc_mapping->m_dst );
    594 					}
    595 				}
    596 
    597 			} else {
    598 				if ( ml->sml_desc->ad_type->sat_syntax == slap_schema.si_syn_distinguishedName
    599 						|| ( mapping != NULL && mapping->m_dst_ad->ad_type->sat_syntax == slap_schema.si_syn_distinguishedName ) )
    600 				{
    601 					rc = rwm_dnattr_rewrite( op, rs, "modifyAttrDN",
    602 							ml->sml_values,
    603 							ml->sml_nvalues ? &ml->sml_nvalues : NULL );
    604 
    605 				} else if ( ml->sml_desc == slap_schema.si_ad_ref ) {
    606 					rc = rwm_referral_rewrite( op, rs,
    607 							"referralAttrDN",
    608 							ml->sml_values,
    609 							ml->sml_nvalues ? &ml->sml_nvalues : NULL );
    610 					if ( rc != LDAP_SUCCESS ) {
    611 						goto cleanup_mod;
    612 					}
    613 				}
    614 
    615 				if ( rc != LDAP_SUCCESS ) {
    616 					goto cleanup_mod;
    617 				}
    618 			}
    619 		}
    620 
    621 next_mod:;
    622 		if ( mapping != NULL ) {
    623 			/* use new attribute description */
    624 			assert( mapping->m_dst_ad != NULL );
    625 			ml->sml_desc = mapping->m_dst_ad;
    626 		}
    627 
    628 		mlp = &ml->sml_next;
    629 		continue;
    630 
    631 cleanup_mod:;
    632 		ml = *mlp;
    633 		*mlp = (*mlp)->sml_next;
    634 		slap_mod_free( &ml->sml_mod, 0 );
    635 		free( ml );
    636 	}
    637 
    638 	op->o_callback = &roc->cb;
    639 
    640 	return SLAP_CB_CONTINUE;
    641 }
    642 
    643 static int
    644 rwm_op_modrdn( Operation *op, SlapReply *rs )
    645 {
    646 	slap_overinst		*on = (slap_overinst *) op->o_bd->bd_info;
    647 	struct ldaprwmap	*rwmap =
    648 			(struct ldaprwmap *)on->on_bi.bi_private;
    649 
    650 	int			rc;
    651 
    652 	rwm_op_cb		*roc = rwm_callback_get( op, rs );
    653 
    654 	if ( op->orr_newSup ) {
    655 		dncookie	dc;
    656 		struct berval	nnewSup = BER_BVNULL;
    657 		struct berval	newSup = BER_BVNULL;
    658 
    659 		/*
    660 		 * Rewrite the new superior, if defined and required
    661 	 	 */
    662 		dc.rwmap = rwmap;
    663 		dc.conn = op->o_conn;
    664 		dc.rs = rs;
    665 		dc.ctx = "newSuperiorDN";
    666 		newSup = *op->orr_newSup;
    667 		nnewSup = *op->orr_nnewSup;
    668 		rc = rwm_dn_massage_pretty_normalize( &dc, op->orr_newSup, &newSup, &nnewSup );
    669 		if ( rc != LDAP_SUCCESS ) {
    670 			op->o_bd->bd_info = (BackendInfo *)on->on_info;
    671 			send_ldap_error( op, rs, rc, "newSuperiorDN massage error" );
    672 			return -1;
    673 		}
    674 
    675 		if ( op->orr_newSup->bv_val != newSup.bv_val ) {
    676 			op->orr_newSup = op->o_tmpalloc( sizeof( struct berval ),
    677 				op->o_tmpmemctx );
    678 			op->orr_nnewSup = op->o_tmpalloc( sizeof( struct berval ),
    679 				op->o_tmpmemctx );
    680 			*op->orr_newSup = newSup;
    681 			*op->orr_nnewSup = nnewSup;
    682 		}
    683 	}
    684 
    685 	/*
    686 	 * Rewrite the dn, if needed
    687  	 */
    688 	rc = rwm_op_dn_massage( op, rs, "renameDN", &roc->ros );
    689 	if ( rc != LDAP_SUCCESS ) {
    690 		op->o_bd->bd_info = (BackendInfo *)on->on_info;
    691 		send_ldap_error( op, rs, rc, "renameDN massage error" );
    692 		if ( op->orr_newSup != roc->ros.orr_newSup ) {
    693 			ch_free( op->orr_newSup->bv_val );
    694 			ch_free( op->orr_nnewSup->bv_val );
    695 			op->o_tmpfree( op->orr_newSup, op->o_tmpmemctx );
    696 			op->o_tmpfree( op->orr_nnewSup, op->o_tmpmemctx );
    697 			op->orr_newSup = roc->ros.orr_newSup;
    698 			op->orr_nnewSup = roc->ros.orr_nnewSup;
    699 		}
    700 		return -1;
    701 	}
    702 
    703 	/* TODO: rewrite newRDN, attribute types,
    704 	 * values of DN-valued attributes ... */
    705 
    706 	op->o_callback = &roc->cb;
    707 
    708 	return SLAP_CB_CONTINUE;
    709 }
    710 
    711 
    712 static int
    713 rwm_swap_attrs( Operation *op, SlapReply *rs )
    714 {
    715 	slap_callback	*cb = op->o_callback;
    716 	rwm_op_state *ros = cb->sc_private;
    717 
    718 	rs->sr_attrs = ros->ors_attrs;
    719 
    720 	/* other overlays might have touched op->ors_attrs,
    721 	 * so we restore the original version here, otherwise
    722 	 * attribute-mapping might fail */
    723 	op->ors_attrs = ros->mapped_attrs;
    724 
    725  	return SLAP_CB_CONTINUE;
    726 }
    727 
    728 static int
    729 rwm_op_search( Operation *op, SlapReply *rs )
    730 {
    731 	slap_overinst		*on = (slap_overinst *) op->o_bd->bd_info;
    732 	struct ldaprwmap	*rwmap =
    733 			(struct ldaprwmap *)on->on_bi.bi_private;
    734 
    735 	int			rc;
    736 	dncookie		dc;
    737 
    738 	struct berval		fstr = BER_BVNULL;
    739 	Filter			*f = NULL;
    740 
    741 	AttributeName		*an = NULL;
    742 
    743 	char			*text = NULL;
    744 
    745 	rwm_op_cb		*roc = rwm_callback_get( op, rs );
    746 
    747 	rc = rewrite_session_var_set( rwmap->rwm_rw, op->o_conn,
    748 		"searchFilter", op->ors_filterstr.bv_val );
    749 	if ( rc == LDAP_SUCCESS )
    750 		rc = rwm_op_dn_massage( op, rs, "searchDN", &roc->ros );
    751 	if ( rc != LDAP_SUCCESS ) {
    752 		text = "searchDN massage error";
    753 		goto error_return;
    754 	}
    755 
    756 	/*
    757 	 * Rewrite the dn if needed
    758 	 */
    759 	dc.rwmap = rwmap;
    760 	dc.conn = op->o_conn;
    761 	dc.rs = rs;
    762 	dc.ctx = "searchFilterAttrDN";
    763 
    764 	rc = rwm_filter_map_rewrite( op, &dc, op->ors_filter, &fstr );
    765 	if ( rc != LDAP_SUCCESS ) {
    766 		text = "searchFilter/searchFilterAttrDN massage error";
    767 		goto error_return;
    768 	}
    769 
    770 	f = str2filter_x( op, fstr.bv_val );
    771 
    772 	if ( f == NULL ) {
    773 		text = "massaged filter parse error";
    774 		goto error_return;
    775 	}
    776 
    777 	op->ors_filter = f;
    778 	op->ors_filterstr = fstr;
    779 
    780 	rc = rwm_map_attrnames( &rwmap->rwm_at, &rwmap->rwm_oc,
    781 			op->ors_attrs, &an, RWM_MAP );
    782 	if ( rc != LDAP_SUCCESS ) {
    783 		text = "attribute list mapping error";
    784 		goto error_return;
    785 	}
    786 
    787 	op->ors_attrs = an;
    788 	/* store the mapped Attributes for later usage, in
    789 	 * the case that other overlays change op->ors_attrs */
    790 	roc->ros.mapped_attrs = an;
    791 	roc->cb.sc_response = rwm_swap_attrs;
    792 
    793 	op->o_callback = &roc->cb;
    794 
    795 	return SLAP_CB_CONTINUE;
    796 
    797 error_return:;
    798 	if ( an != NULL ) {
    799 		ch_free( an );
    800 	}
    801 
    802 	if ( f != NULL ) {
    803 		filter_free_x( op, f );
    804 	}
    805 
    806 	if ( !BER_BVISNULL( &fstr ) ) {
    807 		ch_free( fstr.bv_val );
    808 	}
    809 
    810 	op->oq_search = roc->ros.oq_search;
    811 
    812 	op->o_bd->bd_info = (BackendInfo *)on->on_info;
    813 	send_ldap_error( op, rs, rc, text );
    814 
    815 	return -1;
    816 
    817 }
    818 
    819 static int
    820 rwm_exop_passwd( Operation *op, SlapReply *rs )
    821 {
    822 	slap_overinst		*on = (slap_overinst *) op->o_bd->bd_info;
    823 	int			rc;
    824 	rwm_op_cb *roc;
    825 
    826 	struct berval	id = BER_BVNULL,
    827 			pwold = BER_BVNULL,
    828 			pwnew = BER_BVNULL;
    829 	BerElement *ber = NULL;
    830 
    831 	if ( !BER_BVISNULL( &op->o_req_ndn ) ) {
    832 		return LDAP_SUCCESS;
    833 	}
    834 
    835 	if ( !SLAP_ISGLOBALOVERLAY( op->o_bd ) ) {
    836 		rs->sr_err = LDAP_OTHER;
    837 		return rs->sr_err;
    838 	}
    839 
    840 	rs->sr_err = slap_passwd_parse( op->ore_reqdata, &id,
    841 		&pwold, &pwnew, &rs->sr_text );
    842 	if ( rs->sr_err != LDAP_SUCCESS ) {
    843 		return rs->sr_err;
    844 	}
    845 
    846 	if ( !BER_BVISNULL( &id ) ) {
    847 		char idNul = id.bv_val[id.bv_len];
    848 		id.bv_val[id.bv_len] = '\0';
    849 		rs->sr_err = dnPrettyNormal( NULL, &id, &op->o_req_dn,
    850 				&op->o_req_ndn, op->o_tmpmemctx );
    851 		id.bv_val[id.bv_len] = idNul;
    852 		if ( rs->sr_err != LDAP_SUCCESS ) {
    853 			rs->sr_text = "Invalid DN";
    854 			return rs->sr_err;
    855 		}
    856 
    857 	} else {
    858 		ber_dupbv_x( &op->o_req_dn, &op->o_dn, op->o_tmpmemctx );
    859 		ber_dupbv_x( &op->o_req_ndn, &op->o_ndn, op->o_tmpmemctx );
    860 	}
    861 
    862 	roc = rwm_callback_get( op, rs );
    863 
    864 	rc = rwm_op_dn_massage( op, rs, "extendedDN", &roc->ros );
    865 	if ( rc != LDAP_SUCCESS ) {
    866 		op->o_bd->bd_info = (BackendInfo *)on->on_info;
    867 		send_ldap_error( op, rs, rc, "extendedDN massage error" );
    868 		return -1;
    869 	}
    870 
    871 	ber = ber_alloc_t( LBER_USE_DER );
    872 	if ( !ber ) {
    873 		rs->sr_err = LDAP_OTHER;
    874 		rs->sr_text = "No memory";
    875 		return rs->sr_err;
    876 	}
    877 	ber_printf( ber, "{" );
    878 	if ( !BER_BVISNULL( &id )) {
    879 		ber_printf( ber, "tO", LDAP_TAG_EXOP_MODIFY_PASSWD_ID,
    880 			&op->o_req_dn );
    881 	}
    882 	if ( !BER_BVISNULL( &pwold )) {
    883 		ber_printf( ber, "tO", LDAP_TAG_EXOP_MODIFY_PASSWD_OLD, &pwold );
    884 	}
    885 	if ( !BER_BVISNULL( &pwnew )) {
    886 		ber_printf( ber, "tO", LDAP_TAG_EXOP_MODIFY_PASSWD_NEW, &pwnew );
    887 	}
    888 	ber_printf( ber, "N}" );
    889 	ber_flatten( ber, &op->ore_reqdata );
    890 	ber_free( ber, 1 );
    891 
    892 	op->o_callback = &roc->cb;
    893 
    894 	return SLAP_CB_CONTINUE;
    895 }
    896 
    897 static struct exop {
    898 	struct berval	oid;
    899 	BI_op_extended	*extended;
    900 } exop_table[] = {
    901 	{ BER_BVC(LDAP_EXOP_MODIFY_PASSWD),	rwm_exop_passwd },
    902 	{ BER_BVNULL, NULL }
    903 };
    904 
    905 static int
    906 rwm_extended( Operation *op, SlapReply *rs )
    907 {
    908 	slap_overinst		*on = (slap_overinst *) op->o_bd->bd_info;
    909 	int			rc;
    910 	rwm_op_cb *roc;
    911 
    912 	int	i;
    913 
    914 	for ( i = 0; exop_table[i].extended != NULL; i++ ) {
    915 		if ( bvmatch( &exop_table[i].oid, &op->oq_extended.rs_reqoid ) )
    916 		{
    917 			rc = exop_table[i].extended( op, rs );
    918 			switch ( rc ) {
    919 			case LDAP_SUCCESS:
    920 				break;
    921 
    922 			case SLAP_CB_CONTINUE:
    923 			case SLAPD_ABANDON:
    924 				return rc;
    925 
    926 			default:
    927 				send_ldap_result( op, rs );
    928 				return rc;
    929 			}
    930 			break;
    931 		}
    932 	}
    933 
    934 	roc = rwm_callback_get( op, rs );
    935 
    936 	rc = rwm_op_dn_massage( op, rs, "extendedDN", &roc->ros );
    937 	if ( rc != LDAP_SUCCESS ) {
    938 		op->o_bd->bd_info = (BackendInfo *)on->on_info;
    939 		send_ldap_error( op, rs, rc, "extendedDN massage error" );
    940 		return -1;
    941 	}
    942 
    943 	/* TODO: rewrite/map extended data ? ... */
    944 	op->o_callback = &roc->cb;
    945 
    946 	return SLAP_CB_CONTINUE;
    947 }
    948 
    949 static int
    950 rwm_matched( Operation *op, SlapReply *rs )
    951 {
    952 	slap_overinst		*on = (slap_overinst *) op->o_bd->bd_info;
    953 	struct ldaprwmap	*rwmap =
    954 			(struct ldaprwmap *)on->on_bi.bi_private;
    955 
    956 	struct berval		dn, mdn;
    957 	dncookie		dc;
    958 	int			rc;
    959 
    960 	if ( rs->sr_matched == NULL ) {
    961 		return SLAP_CB_CONTINUE;
    962 	}
    963 
    964 	dc.rwmap = rwmap;
    965 	dc.conn = op->o_conn;
    966 	dc.rs = rs;
    967 	dc.ctx = "matchedDN";
    968 	ber_str2bv( rs->sr_matched, 0, 0, &dn );
    969 	mdn = dn;
    970 	rc = rwm_dn_massage_pretty( &dc, &dn, &mdn );
    971 	if ( rc != LDAP_SUCCESS ) {
    972 		rs->sr_err = rc;
    973 		rs->sr_text = "Rewrite error";
    974 		return 1;
    975 	}
    976 
    977 	if ( mdn.bv_val != dn.bv_val ) {
    978 		if ( rs->sr_flags & REP_MATCHED_MUSTBEFREED ) {
    979 			ch_free( (void *)rs->sr_matched );
    980 
    981 		} else {
    982 			rs->sr_flags |= REP_MATCHED_MUSTBEFREED;
    983 		}
    984 		rs->sr_matched = mdn.bv_val;
    985 	}
    986 
    987 	return SLAP_CB_CONTINUE;
    988 }
    989 
    990 static int
    991 rwm_attrs( Operation *op, SlapReply *rs, Attribute** a_first, int stripEntryDN )
    992 {
    993 	slap_overinst		*on = (slap_overinst *) op->o_bd->bd_info;
    994 	struct ldaprwmap	*rwmap =
    995 			(struct ldaprwmap *)on->on_bi.bi_private;
    996 
    997 	dncookie		dc;
    998 	int			rc;
    999 	Attribute		**ap;
   1000 	int			isupdate;
   1001 	int			check_duplicate_attrs = 0;
   1002 
   1003 	/*
   1004 	 * Rewrite the dn attrs, if needed
   1005 	 */
   1006 	dc.rwmap = rwmap;
   1007 	dc.conn = op->o_conn;
   1008 	dc.rs = NULL;
   1009 
   1010 	/* FIXME: the entries are in the remote mapping form;
   1011 	 * so we need to select those attributes we are willing
   1012 	 * to return, and remap them accordingly */
   1013 
   1014 	/* FIXME: in principle, one could map an attribute
   1015 	 * on top of another, which already exists.
   1016 	 * As such, in the end there might exist more than
   1017 	 * one instance of an attribute.
   1018 	 * We should at least check if this occurs, and issue
   1019 	 * an error (because multiple instances of attrs in
   1020 	 * response are not valid), or merge the values (what
   1021 	 * about duplicate values?) */
   1022 	isupdate = be_shadow_update( op );
   1023 	for ( ap = a_first; *ap; ) {
   1024 		struct ldapmapping	*mapping = NULL;
   1025 		int			drop_missing;
   1026 		int			last = -1;
   1027 		Attribute		*a;
   1028 
   1029 		if ( SLAP_OPATTRS( rs->sr_attr_flags ) && is_at_operational( (*ap)->a_desc->ad_type ) )
   1030 		{
   1031 			/* go on */ ;
   1032 
   1033 		} else {
   1034 			if ( op->ors_attrs != NULL &&
   1035 					!SLAP_USERATTRS( rs->sr_attr_flags ) &&
   1036 					!ad_inlist( (*ap)->a_desc, op->ors_attrs ) )
   1037 			{
   1038 				goto cleanup_attr;
   1039 			}
   1040 
   1041 			drop_missing = rwm_mapping( &rwmap->rwm_at,
   1042 					&(*ap)->a_desc->ad_cname, &mapping, RWM_REMAP );
   1043 			if ( drop_missing || ( mapping != NULL && BER_BVISEMPTY( &mapping->m_dst ) ) )
   1044 			{
   1045 				goto cleanup_attr;
   1046 			}
   1047 			if ( mapping != NULL ) {
   1048 				assert( mapping->m_dst_ad != NULL );
   1049 
   1050 				/* try to normalize mapped Attributes if the original
   1051 				 * AttributeType was not normalized */
   1052 				if ((rwmap->rwm_flags & RWM_F_NORMALIZE_MAPPED_ATTRS) &&
   1053 					(!(*ap)->a_desc->ad_type->sat_equality ||
   1054 					!(*ap)->a_desc->ad_type->sat_equality->smr_normalize) &&
   1055 					mapping->m_dst_ad->ad_type->sat_equality &&
   1056 					mapping->m_dst_ad->ad_type->sat_equality->smr_normalize )
   1057 				{
   1058 					int i = 0;
   1059 
   1060 					last = (*ap)->a_numvals;
   1061 					if ( last )
   1062 					{
   1063 						(*ap)->a_nvals = ch_malloc( (last+1) * sizeof(struct berval) );
   1064 
   1065 						for ( i = 0; !BER_BVISNULL( &(*ap)->a_vals[i]); i++ ) {
   1066 							int		rc;
   1067 							/*
   1068 							 * check that each value is valid per syntax
   1069 							 * and pretty if appropriate
   1070 							 */
   1071 							rc = mapping->m_dst_ad->ad_type->sat_equality->smr_normalize(
   1072 								SLAP_MR_VALUE_OF_ATTRIBUTE_SYNTAX,
   1073 								mapping->m_dst_ad->ad_type->sat_syntax,
   1074 								mapping->m_dst_ad->ad_type->sat_equality,
   1075 								&(*ap)->a_vals[i], &(*ap)->a_nvals[i],
   1076 								NULL );
   1077 
   1078 							if ( rc != LDAP_SUCCESS ) {
   1079 								BER_BVZERO( &(*ap)->a_nvals[i] );
   1080 							}
   1081 						}
   1082 						BER_BVZERO( &(*ap)->a_nvals[i] );
   1083 					}
   1084 				}
   1085 
   1086 				/* rewrite the attribute description */
   1087 				(*ap)->a_desc = mapping->m_dst_ad;
   1088 
   1089 				/* will need to check for duplicate attrs */
   1090 				check_duplicate_attrs++;
   1091 			}
   1092 		}
   1093 
   1094 		if ( (*ap)->a_desc == slap_schema.si_ad_entryDN ) {
   1095 			if ( stripEntryDN ) {
   1096 				/* will be generated by frontend */
   1097 				goto cleanup_attr;
   1098 			}
   1099 
   1100 		} else if ( !isupdate
   1101 			&& !get_relax( op )
   1102 			&& (*ap)->a_desc->ad_type->sat_no_user_mod
   1103 			&& (*ap)->a_desc->ad_type != slap_schema.si_at_undefined )
   1104 		{
   1105 			goto next_attr;
   1106 		}
   1107 
   1108 		if ( last == -1 ) { /* not yet counted */
   1109 			last = (*ap)->a_numvals;
   1110 		}
   1111 
   1112 		if ( last == 0 ) {
   1113 			/* empty? leave it in place because of attrsonly and vlv */
   1114 			goto next_attr;
   1115 		}
   1116 		last--;
   1117 
   1118 		if ( (*ap)->a_desc == slap_schema.si_ad_objectClass
   1119 				|| (*ap)->a_desc == slap_schema.si_ad_structuralObjectClass )
   1120 		{
   1121 			struct berval	*bv;
   1122 
   1123 			for ( bv = (*ap)->a_vals; !BER_BVISNULL( bv ); bv++ ) {
   1124 				struct berval	mapped;
   1125 
   1126 				rwm_map( &rwmap->rwm_oc, &bv[0], &mapped, RWM_REMAP );
   1127 				if ( BER_BVISNULL( &mapped ) || BER_BVISEMPTY( &mapped ) ) {
   1128 remove_oc:;
   1129 					ch_free( bv[0].bv_val );
   1130 					BER_BVZERO( &bv[0] );
   1131 					if ( &(*ap)->a_vals[last] > &bv[0] ) {
   1132 						bv[0] = (*ap)->a_vals[last];
   1133 						BER_BVZERO( &(*ap)->a_vals[last] );
   1134 					}
   1135 					last--;
   1136 					bv--;
   1137 
   1138 				} else if ( mapped.bv_val != bv[0].bv_val ) {
   1139 					int	i;
   1140 
   1141 					for ( i = 0; !BER_BVISNULL( &(*ap)->a_vals[ i ] ); i++ ) {
   1142 						if ( &(*ap)->a_vals[ i ] == bv ) {
   1143 							continue;
   1144 						}
   1145 
   1146 						if ( ber_bvstrcasecmp( &mapped, &(*ap)->a_vals[ i ] ) == 0 ) {
   1147 							break;
   1148 						}
   1149 					}
   1150 
   1151 					if ( !BER_BVISNULL( &(*ap)->a_vals[ i ] ) ) {
   1152 						goto remove_oc;
   1153 					}
   1154 
   1155 					/*
   1156 					 * FIXME: after LBER_FREEing
   1157 					 * the value is replaced by
   1158 					 * ch_alloc'ed memory
   1159 					 */
   1160 					ber_bvreplace( &bv[0], &mapped );
   1161 
   1162 					/* FIXME: will need to check
   1163 					 * if the structuralObjectClass
   1164 					 * changed */
   1165 				}
   1166 			}
   1167 
   1168 		/*
   1169 		 * It is necessary to try to rewrite attributes with
   1170 		 * dn syntax because they might be used in ACLs as
   1171 		 * members of groups; since ACLs are applied to the
   1172 		 * rewritten stuff, no dn-based subject clause could
   1173 		 * be used at the ldap backend side (see
   1174 		 * http://www.OpenLDAP.org/faq/data/cache/452.html)
   1175 		 * The problem can be overcome by moving the dn-based
   1176 		 * ACLs to the target directory server, and letting
   1177 		 * everything pass thru the ldap backend. */
   1178 		/* FIXME: handle distinguishedName-like syntaxes, like
   1179 		 * nameAndOptionalUID */
   1180 		} else if ( (*ap)->a_desc->ad_type->sat_syntax == slap_schema.si_syn_distinguishedName
   1181 				|| ( mapping != NULL && mapping->m_src_ad->ad_type->sat_syntax == slap_schema.si_syn_distinguishedName ) )
   1182 		{
   1183 			dc.ctx = "searchAttrDN";
   1184 			rc = rwm_dnattr_result_rewrite( &dc, (*ap)->a_vals );
   1185 			if ( rc != LDAP_SUCCESS ) {
   1186 				goto cleanup_attr;
   1187 			}
   1188 
   1189 		} else if ( (*ap)->a_desc == slap_schema.si_ad_ref ) {
   1190 			dc.ctx = "searchAttrDN";
   1191 			rc = rwm_referral_result_rewrite( &dc, (*ap)->a_vals );
   1192 			if ( rc != LDAP_SUCCESS ) {
   1193 				goto cleanup_attr;
   1194 			}
   1195 		}
   1196 
   1197 
   1198 next_attr:;
   1199 		ap = &(*ap)->a_next;
   1200 		continue;
   1201 
   1202 cleanup_attr:;
   1203 		a = *ap;
   1204 		*ap = (*ap)->a_next;
   1205 
   1206 		attr_free( a );
   1207 	}
   1208 
   1209 	/* only check if some mapping occurred */
   1210 	if ( check_duplicate_attrs ) {
   1211 		for ( ap = a_first; *ap != NULL; ap = &(*ap)->a_next ) {
   1212 			Attribute	**tap;
   1213 
   1214 			for ( tap = &(*ap)->a_next; *tap != NULL; ) {
   1215 				if ( (*tap)->a_desc == (*ap)->a_desc ) {
   1216 					Entry		e = { 0 };
   1217 					Modification	mod = { 0 };
   1218 					const char	*text = NULL;
   1219 					char		textbuf[ SLAP_TEXT_BUFLEN ];
   1220 					Attribute	*next = (*tap)->a_next;
   1221 
   1222 					BER_BVSTR( &e.e_name, "" );
   1223 					BER_BVSTR( &e.e_nname, "" );
   1224 					e.e_attrs = *ap;
   1225 					mod.sm_op = LDAP_MOD_ADD;
   1226 					mod.sm_desc = (*ap)->a_desc;
   1227 					mod.sm_type = mod.sm_desc->ad_cname;
   1228 					mod.sm_numvals = (*tap)->a_numvals;
   1229 					mod.sm_values = (*tap)->a_vals;
   1230 					if ( (*tap)->a_nvals != (*tap)->a_vals ) {
   1231 						mod.sm_nvalues = (*tap)->a_nvals;
   1232 					}
   1233 
   1234 					(void)modify_add_values( &e, &mod,
   1235 						/* permissive */ 1,
   1236 						&text, textbuf, sizeof( textbuf ) );
   1237 
   1238 					/* should not insert new attrs! */
   1239 					assert( e.e_attrs == *ap );
   1240 
   1241 					attr_free( *tap );
   1242 					*tap = next;
   1243 
   1244 				} else {
   1245 					tap = &(*tap)->a_next;
   1246 				}
   1247 			}
   1248 		}
   1249 	}
   1250 
   1251 	return 0;
   1252 }
   1253 
   1254 static int
   1255 rwm_send_entry( Operation *op, SlapReply *rs )
   1256 {
   1257 	slap_overinst		*on = (slap_overinst *) op->o_bd->bd_info;
   1258 	struct ldaprwmap	*rwmap =
   1259 			(struct ldaprwmap *)on->on_bi.bi_private;
   1260 
   1261 	Entry			*e = NULL;
   1262 	slap_mask_t		flags;
   1263 	struct berval		dn = BER_BVNULL,
   1264 				ndn = BER_BVNULL;
   1265 	dncookie		dc;
   1266 	int			rc;
   1267 
   1268 	assert( rs->sr_entry != NULL );
   1269 
   1270 	/*
   1271 	 * Rewrite the dn of the result, if needed
   1272 	 */
   1273 	dc.rwmap = rwmap;
   1274 	dc.conn = op->o_conn;
   1275 	dc.rs = NULL;
   1276 	dc.ctx = "searchEntryDN";
   1277 
   1278 	e = rs->sr_entry;
   1279 	flags = rs->sr_flags;
   1280 	if ( !( rs->sr_flags & REP_ENTRY_MODIFIABLE ) ) {
   1281 		/* FIXME: all we need to duplicate are:
   1282 		 * - dn
   1283 		 * - ndn
   1284 		 * - attributes that are requested
   1285 		 * - no values if attrsonly is set
   1286 		 */
   1287 
   1288 		e = entry_dup( e );
   1289 		if ( e == NULL ) {
   1290 			rc = LDAP_NO_MEMORY;
   1291 			goto fail;
   1292 		}
   1293 
   1294 		flags &= ~REP_ENTRY_MUSTRELEASE;
   1295 		flags |= ( REP_ENTRY_MODIFIABLE | REP_ENTRY_MUSTBEFREED );
   1296 	}
   1297 
   1298 	/*
   1299 	 * Note: this may fail if the target host(s) schema differs
   1300 	 * from the one known to the meta, and a DN with unknown
   1301 	 * attributes is returned.
   1302 	 */
   1303 	dn = e->e_name;
   1304 	ndn = e->e_nname;
   1305 	rc = rwm_dn_massage_pretty_normalize( &dc, &e->e_name, &dn, &ndn );
   1306 	if ( rc != LDAP_SUCCESS ) {
   1307 		rc = 1;
   1308 		goto fail;
   1309 	}
   1310 
   1311 	if ( e->e_name.bv_val != dn.bv_val ) {
   1312 		ch_free( e->e_name.bv_val );
   1313 		ch_free( e->e_nname.bv_val );
   1314 
   1315 		e->e_name = dn;
   1316 		e->e_nname = ndn;
   1317 	}
   1318 
   1319 	/* TODO: map entry attribute types, objectclasses
   1320 	 * and dn-valued attribute values */
   1321 
   1322 	/* FIXME: the entries are in the remote mapping form;
   1323 	 * so we need to select those attributes we are willing
   1324 	 * to return, and remap them accordingly */
   1325 	(void)rwm_attrs( op, rs, &e->e_attrs, 1 );
   1326 
   1327 	if ( rs->sr_flags & REP_ENTRY_MUSTRELEASE ) {
   1328 		be_entry_release_rw( op, rs->sr_entry, 0 );
   1329 	}
   1330 
   1331 	rs->sr_entry = e;
   1332 	rs->sr_flags = flags;
   1333 
   1334 	return SLAP_CB_CONTINUE;
   1335 
   1336 fail:;
   1337 	if ( e != NULL && e != rs->sr_entry ) {
   1338 		if ( e->e_name.bv_val == dn.bv_val ) {
   1339 			BER_BVZERO( &e->e_name );
   1340 		}
   1341 
   1342 		if ( e->e_nname.bv_val == ndn.bv_val ) {
   1343 			BER_BVZERO( &e->e_nname );
   1344 		}
   1345 
   1346 		entry_free( e );
   1347 	}
   1348 
   1349 	if ( !BER_BVISNULL( &dn ) ) {
   1350 		ch_free( dn.bv_val );
   1351 	}
   1352 
   1353 	if ( !BER_BVISNULL( &ndn ) ) {
   1354 		ch_free( ndn.bv_val );
   1355 	}
   1356 
   1357 	return rc;
   1358 }
   1359 
   1360 static int
   1361 rwm_operational( Operation *op, SlapReply *rs )
   1362 {
   1363 	/* FIXME: the entries are in the remote mapping form;
   1364 	 * so we need to select those attributes we are willing
   1365 	 * to return, and remap them accordingly */
   1366 	if ( rs->sr_operational_attrs ) {
   1367 		rwm_attrs( op, rs, &rs->sr_operational_attrs, 1 );
   1368 	}
   1369 
   1370 	return SLAP_CB_CONTINUE;
   1371 }
   1372 
   1373 #if 0
   1374 /* don't use this; it cannot be reverted, and leaves op->o_req_dn
   1375  * rewritten for subsequent operations; fine for plain suffixmassage,
   1376  * but destroys everything else */
   1377 static int
   1378 rwm_chk_referrals( Operation *op, SlapReply *rs )
   1379 {
   1380 	slap_overinst		*on = (slap_overinst *) op->o_bd->bd_info;
   1381 	int			rc;
   1382 
   1383 	rc = rwm_op_dn_massage( op, rs, "referralCheckDN" );
   1384 	if ( rc != LDAP_SUCCESS ) {
   1385 		op->o_bd->bd_info = (BackendInfo *)on->on_info;
   1386 		send_ldap_error( op, rs, rc, "referralCheckDN massage error" );
   1387 		return -1;
   1388 	}
   1389 
   1390 	return SLAP_CB_CONTINUE;
   1391 }
   1392 #endif
   1393 
   1394 static int
   1395 rwm_rw_config(
   1396 	BackendDB	*be,
   1397 	const char	*fname,
   1398 	int		lineno,
   1399 	int		argc,
   1400 	char		**argv )
   1401 {
   1402 	slap_overinst		*on = (slap_overinst *) be->bd_info;
   1403 	struct ldaprwmap	*rwmap =
   1404 			(struct ldaprwmap *)on->on_bi.bi_private;
   1405 
   1406 	return rewrite_parse( rwmap->rwm_rw,
   1407 				fname, lineno, argc, argv );
   1408 
   1409 	return 0;
   1410 }
   1411 
   1412 static int
   1413 rwm_suffixmassage_config(
   1414 	BackendDB	*be,
   1415 	const char	*fname,
   1416 	int		lineno,
   1417 	int		argc,
   1418 	char		**argv )
   1419 {
   1420 	slap_overinst		*on = (slap_overinst *) be->bd_info;
   1421 	struct ldaprwmap	*rwmap =
   1422 			(struct ldaprwmap *)on->on_bi.bi_private;
   1423 
   1424 	struct berval		bvnc, nvnc, pvnc, brnc, nrnc, prnc;
   1425 	int			massaged;
   1426 	int			rc;
   1427 
   1428 	/*
   1429 	 * syntax:
   1430 	 *
   1431 	 * 	suffixmassage [<suffix>] <massaged suffix>
   1432 	 *
   1433 	 * the [<suffix>] field must be defined as a valid suffix
   1434 	 * for the current database;
   1435 	 * the <massaged suffix> shouldn't have already been
   1436 	 * defined as a valid suffix for the current server
   1437 	 */
   1438 	if ( argc == 2 ) {
   1439 		if ( be->be_suffix == NULL ) {
   1440  			fprintf( stderr, "%s: line %d: "
   1441 				       " \"suffixMassage [<suffix>]"
   1442 				       " <massaged suffix>\" without "
   1443 				       "<suffix> part requires database "
   1444 				       "suffix be defined first.\n",
   1445 				fname, lineno );
   1446 			return 1;
   1447 		}
   1448 		bvnc = be->be_suffix[ 0 ];
   1449 		massaged = 1;
   1450 
   1451 	} else if ( argc == 3 ) {
   1452 		ber_str2bv( argv[ 1 ], 0, 0, &bvnc );
   1453 		massaged = 2;
   1454 
   1455 	} else  {
   1456  		fprintf( stderr, "%s: line %d: syntax is"
   1457 			       " \"suffixMassage [<suffix>]"
   1458 			       " <massaged suffix>\"\n",
   1459 			fname, lineno );
   1460 		return 1;
   1461 	}
   1462 
   1463 	if ( dnPrettyNormal( NULL, &bvnc, &pvnc, &nvnc, NULL ) != LDAP_SUCCESS ) {
   1464 		fprintf( stderr, "%s: line %d: suffix DN %s is invalid\n",
   1465 			fname, lineno, bvnc.bv_val );
   1466 		return 1;
   1467 	}
   1468 
   1469 	ber_str2bv( argv[ massaged ], 0, 0, &brnc );
   1470 	if ( dnPrettyNormal( NULL, &brnc, &prnc, &nrnc, NULL ) != LDAP_SUCCESS ) {
   1471 		fprintf( stderr, "%s: line %d: suffix DN %s is invalid\n",
   1472 				fname, lineno, brnc.bv_val );
   1473 		free( nvnc.bv_val );
   1474 		free( pvnc.bv_val );
   1475 		return 1;
   1476 	}
   1477 
   1478 	/*
   1479 	 * The suffix massaging is emulated
   1480 	 * by means of the rewrite capabilities
   1481 	 */
   1482  	rc = rwm_suffix_massage_config( rwmap->rwm_rw,
   1483 			&pvnc, &nvnc, &prnc, &nrnc );
   1484 	free( nvnc.bv_val );
   1485 	free( pvnc.bv_val );
   1486 	free( nrnc.bv_val );
   1487 	free( prnc.bv_val );
   1488 
   1489 	return rc;
   1490 }
   1491 
   1492 static int
   1493 rwm_m_config(
   1494 	BackendDB	*be,
   1495 	const char	*fname,
   1496 	int		lineno,
   1497 	int		argc,
   1498 	char		**argv )
   1499 {
   1500 	slap_overinst		*on = (slap_overinst *) be->bd_info;
   1501 	struct ldaprwmap	*rwmap =
   1502 			(struct ldaprwmap *)on->on_bi.bi_private;
   1503 
   1504 	/* objectclass/attribute mapping */
   1505 	return rwm_map_config( &rwmap->rwm_oc,
   1506 			&rwmap->rwm_at,
   1507 			fname, lineno, argc, argv );
   1508 }
   1509 
   1510 static int
   1511 rwm_response( Operation *op, SlapReply *rs )
   1512 {
   1513 	slap_overinst		*on = (slap_overinst *)op->o_bd->bd_info;
   1514 	struct ldaprwmap	*rwmap =
   1515 			(struct ldaprwmap *)on->on_bi.bi_private;
   1516 
   1517 	int		rc;
   1518 
   1519 	if ( op->o_tag == LDAP_REQ_SEARCH && rs->sr_type == REP_SEARCH ) {
   1520 		return rwm_send_entry( op, rs );
   1521 	}
   1522 
   1523 	switch( op->o_tag ) {
   1524 	case LDAP_REQ_SEARCH:
   1525 	case LDAP_REQ_BIND:
   1526 	case LDAP_REQ_ADD:
   1527 	case LDAP_REQ_DELETE:
   1528 	case LDAP_REQ_MODRDN:
   1529 	case LDAP_REQ_MODIFY:
   1530 	case LDAP_REQ_COMPARE:
   1531 	case LDAP_REQ_EXTENDED:
   1532 		if ( rs->sr_ref ) {
   1533 			dncookie		dc;
   1534 
   1535 			/*
   1536 			 * Rewrite the dn of the referrals, if needed
   1537 			 */
   1538 			dc.rwmap = rwmap;
   1539 			dc.conn = op->o_conn;
   1540 			dc.rs = NULL;
   1541 			dc.ctx = "referralDN";
   1542 			rc = rwm_referral_result_rewrite( &dc, rs->sr_ref );
   1543 			if ( rc != LDAP_SUCCESS ) {
   1544 				rc = 1;
   1545 				break;
   1546 			}
   1547 		}
   1548 		rc = rwm_matched( op, rs );
   1549 		break;
   1550 
   1551 	default:
   1552 		rc = SLAP_CB_CONTINUE;
   1553 		break;
   1554 	}
   1555 
   1556 	return rc;
   1557 }
   1558 
   1559 static int
   1560 rwm_db_config(
   1561 	BackendDB	*be,
   1562 	const char	*fname,
   1563 	int		lineno,
   1564 	int		argc,
   1565 	char		**argv )
   1566 {
   1567 	slap_overinst		*on = (slap_overinst *) be->bd_info;
   1568 	struct ldaprwmap	*rwmap =
   1569 			(struct ldaprwmap *)on->on_bi.bi_private;
   1570 
   1571 	int		rc = 0;
   1572 	char		*argv0 = NULL;
   1573 
   1574 	if ( strncasecmp( argv[ 0 ], "rwm-", STRLENOF( "rwm-" ) ) == 0 ) {
   1575 		argv0 = argv[ 0 ];
   1576 		argv[ 0 ] = &argv0[ STRLENOF( "rwm-" ) ];
   1577 	}
   1578 
   1579 	if ( strncasecmp( argv[0], "rewrite", STRLENOF("rewrite") ) == 0 ) {
   1580 		rc = rwm_rw_config( be, fname, lineno, argc, argv );
   1581 
   1582 	} else if ( strcasecmp( argv[0], "map" ) == 0 ) {
   1583 		rc = rwm_m_config( be, fname, lineno, argc, argv );
   1584 
   1585 	} else if ( strcasecmp( argv[0], "suffixmassage" ) == 0 ) {
   1586 		rc = rwm_suffixmassage_config( be, fname, lineno, argc, argv );
   1587 
   1588 	} else if ( strcasecmp( argv[0], "t-f-support" ) == 0 ) {
   1589 		if ( argc != 2 ) {
   1590 			fprintf( stderr,
   1591 		"%s: line %d: \"t-f-support {no|yes|discover}\" needs 1 argument.\n",
   1592 					fname, lineno );
   1593 			return( 1 );
   1594 		}
   1595 
   1596 		if ( strcasecmp( argv[ 1 ], "no" ) == 0 ) {
   1597 			rwmap->rwm_flags &= ~(RWM_F_SUPPORT_T_F_MASK2);
   1598 
   1599 		} else if ( strcasecmp( argv[ 1 ], "yes" ) == 0 ) {
   1600 			rwmap->rwm_flags |= RWM_F_SUPPORT_T_F;
   1601 
   1602 		/* TODO: not implemented yet */
   1603 		} else if ( strcasecmp( argv[ 1 ], "discover" ) == 0 ) {
   1604 			fprintf( stderr,
   1605 		"%s: line %d: \"discover\" not supported yet "
   1606 		"in \"t-f-support {no|yes|discover}\".\n",
   1607 					fname, lineno );
   1608 			return( 1 );
   1609 #if 0
   1610 			rwmap->rwm_flags |= RWM_F_SUPPORT_T_F_DISCOVER;
   1611 #endif
   1612 
   1613 		} else {
   1614 			fprintf( stderr,
   1615 	"%s: line %d: unknown value \"%s\" for \"t-f-support {no|yes|discover}\".\n",
   1616 				fname, lineno, argv[ 1 ] );
   1617 			return 1;
   1618 		}
   1619 
   1620 	} else if ( strcasecmp( argv[0], "normalize-mapped-attrs" ) ==  0 ) {
   1621 		if ( argc !=2 ) {
   1622 			fprintf( stderr,
   1623 		"%s: line %d: \"normalize-mapped-attrs {no|yes}\" needs 1 argument.\n",
   1624 					fname, lineno );
   1625 			return( 1 );
   1626 		}
   1627 
   1628 		if ( strcasecmp( argv[ 1 ], "no" ) == 0 ) {
   1629 			rwmap->rwm_flags &= ~(RWM_F_NORMALIZE_MAPPED_ATTRS);
   1630 
   1631 		} else if ( strcasecmp( argv[ 1 ], "yes" ) == 0 ) {
   1632 			rwmap->rwm_flags |= RWM_F_NORMALIZE_MAPPED_ATTRS;
   1633 		}
   1634 
   1635 	} else {
   1636 		rc = SLAP_CONF_UNKNOWN;
   1637 	}
   1638 
   1639 	if ( argv0 ) {
   1640 		argv[ 0 ] = argv0;
   1641 	}
   1642 
   1643 	return rc;
   1644 }
   1645 
   1646 /*
   1647  * dynamic configuration...
   1648  */
   1649 
   1650 enum {
   1651 	/* rewrite */
   1652 	RWM_CF_REWRITE = 1,
   1653 	RWM_CF_SUFFIXMASSAGE,
   1654 
   1655 	/* map */
   1656 	RWM_CF_MAP,
   1657 	RWM_CF_T_F_SUPPORT,
   1658 	RWM_CF_NORMALIZE_MAPPED,
   1659 
   1660 	RWM_CF_LAST
   1661 };
   1662 
   1663 static slap_verbmasks t_f_mode[] = {
   1664 	{ BER_BVC( "yes" ),		RWM_F_SUPPORT_T_F },
   1665 	{ BER_BVC( "discover" ),	RWM_F_SUPPORT_T_F_DISCOVER },
   1666 	{ BER_BVC( "no" ),		RWM_F_NONE },
   1667 	{ BER_BVNULL,			0 }
   1668 };
   1669 
   1670 static ConfigDriver rwm_cf_gen;
   1671 
   1672 static ConfigTable rwmcfg[] = {
   1673 	{ "rwm-rewrite", "rewrite",
   1674 		2, 0, STRLENOF("rwm-rewrite"),
   1675 		ARG_MAGIC|ARG_QUOTE|RWM_CF_REWRITE, rwm_cf_gen,
   1676 		"( OLcfgOvAt:16.1 NAME 'olcRwmRewrite' "
   1677 			"DESC 'Rewrites strings' "
   1678 			"EQUALITY caseIgnoreMatch "
   1679 			"SYNTAX OMsDirectoryString "
   1680 			"X-ORDERED 'VALUES' )",
   1681 		NULL, NULL },
   1682 
   1683 	{ "rwm-suffixmassage", "[virtual]> <real",
   1684 		2, 3, 0, ARG_MAGIC|RWM_CF_SUFFIXMASSAGE, rwm_cf_gen,
   1685 		NULL, NULL, NULL },
   1686 
   1687 	{ "rwm-t-f-support", "true|false|discover",
   1688 		2, 2, 0, ARG_MAGIC|RWM_CF_T_F_SUPPORT, rwm_cf_gen,
   1689 		"( OLcfgOvAt:16.2 NAME 'olcRwmTFSupport' "
   1690 			"DESC 'Absolute filters support' "
   1691 			"SYNTAX OMsDirectoryString "
   1692 			"SINGLE-VALUE )",
   1693 		NULL, NULL },
   1694 
   1695 	{ "rwm-map", "{objectClass|attribute}",
   1696 		2, 4, 0, ARG_MAGIC|RWM_CF_MAP, rwm_cf_gen,
   1697 		"( OLcfgOvAt:16.3 NAME 'olcRwmMap' "
   1698 			"DESC 'maps attributes/objectClasses' "
   1699 			"SYNTAX OMsDirectoryString "
   1700 			"X-ORDERED 'VALUES' )",
   1701 		NULL, NULL },
   1702 
   1703 	{ "rwm-normalize-mapped-attrs", "true|false",
   1704 		2, 2, 0, ARG_MAGIC|ARG_ON_OFF|RWM_CF_NORMALIZE_MAPPED, rwm_cf_gen,
   1705 		"( OLcfgOvAt:16.4 NAME 'olcRwmNormalizeMapped' "
   1706 			"DESC 'Normalize mapped attributes/objectClasses' "
   1707 			"SYNTAX OMsBoolean "
   1708 			"SINGLE-VALUE )",
   1709 		NULL, NULL },
   1710 
   1711 	{ NULL, NULL, 0, 0, 0, ARG_IGNORED }
   1712 };
   1713 
   1714 static ConfigOCs rwmocs[] = {
   1715 	{ "( OLcfgOvOc:16.1 "
   1716 		"NAME 'olcRwmConfig' "
   1717 		"DESC 'Rewrite/remap configuration' "
   1718 		"SUP olcOverlayConfig "
   1719 		"MAY ( "
   1720 			"olcRwmRewrite $ "
   1721 			"olcRwmTFSupport $ "
   1722 			"olcRwmMap $ "
   1723 			"olcRwmNormalizeMapped "
   1724 			") )",
   1725 		Cft_Overlay, rwmcfg, NULL, NULL },
   1726 	{ NULL, 0, NULL }
   1727 };
   1728 
   1729 static void
   1730 slap_rewrite_unparse( BerVarray in, BerVarray *out )
   1731 {
   1732 	int		i;
   1733 	BerVarray	bva = NULL;
   1734 	char		ibuf[32], *ptr;
   1735 	struct berval	idx;
   1736 
   1737 	assert( in != NULL );
   1738 
   1739 	for ( i = 0; !BER_BVISNULL( &in[i] ); i++ )
   1740 		/* count'em */ ;
   1741 
   1742 	if ( i == 0 ) {
   1743 		return;
   1744 	}
   1745 
   1746 	idx.bv_val = ibuf;
   1747 
   1748 	bva = ch_malloc( ( i + 1 ) * sizeof(struct berval) );
   1749 	BER_BVZERO( &bva[ 0 ] );
   1750 
   1751 	for ( i = 0; !BER_BVISNULL( &in[i] ); i++ ) {
   1752 		idx.bv_len = snprintf( idx.bv_val, sizeof( ibuf ), "{%d}", i );
   1753 		if ( idx.bv_len >= sizeof( ibuf ) ) {
   1754 			ber_bvarray_free( bva );
   1755 			return;
   1756 		}
   1757 
   1758 		bva[i].bv_len = idx.bv_len + in[i].bv_len;
   1759 		bva[i].bv_val = ch_malloc( bva[i].bv_len + 1 );
   1760 		ptr = lutil_strcopy( bva[i].bv_val, ibuf );
   1761 		ptr = lutil_strcopy( ptr, in[i].bv_val );
   1762 		*ptr = '\0';
   1763 		BER_BVZERO( &bva[ i + 1 ] );
   1764 	}
   1765 
   1766 	*out = bva;
   1767 }
   1768 
   1769 static int
   1770 rwm_cf_gen( ConfigArgs *c )
   1771 {
   1772 	slap_overinst		*on = (slap_overinst *)c->bi;
   1773 	struct ldaprwmap	*rwmap =
   1774 			(struct ldaprwmap *)on->on_bi.bi_private;
   1775 
   1776 	BackendDB		db;
   1777 	char			*argv0;
   1778 	int			rc = 0;
   1779 
   1780 	db = *c->be;
   1781 	db.bd_info = c->bi;
   1782 
   1783 	if ( c->op == SLAP_CONFIG_EMIT ) {
   1784 		struct berval	bv = BER_BVNULL;
   1785 
   1786 		switch ( c->type ) {
   1787 		case RWM_CF_REWRITE:
   1788 			if ( rwmap->rwm_bva_rewrite == NULL ) {
   1789 				rc = 1;
   1790 
   1791 			} else {
   1792 				slap_rewrite_unparse( rwmap->rwm_bva_rewrite, &c->rvalue_vals );
   1793 				if ( !c->rvalue_vals ) {
   1794 					rc = 1;
   1795 				}
   1796 			}
   1797 			break;
   1798 
   1799 		case RWM_CF_T_F_SUPPORT:
   1800 			enum_to_verb( t_f_mode, (rwmap->rwm_flags & RWM_F_SUPPORT_T_F_MASK2), &bv );
   1801 			if ( BER_BVISNULL( &bv ) ) {
   1802 				/* there's something wrong... */
   1803 				assert( 0 );
   1804 				rc = 1;
   1805 
   1806 			} else {
   1807 				value_add_one( &c->rvalue_vals, &bv );
   1808 			}
   1809 			break;
   1810 
   1811 		case RWM_CF_MAP:
   1812 			if ( rwmap->rwm_bva_map == NULL ) {
   1813 				rc = 1;
   1814 
   1815 			} else {
   1816 				value_add( &c->rvalue_vals, rwmap->rwm_bva_map );
   1817 			}
   1818 			break;
   1819 
   1820 		case RWM_CF_NORMALIZE_MAPPED:
   1821 			c->value_int = ( rwmap->rwm_flags & RWM_F_NORMALIZE_MAPPED_ATTRS );
   1822 			break;
   1823 
   1824 		default:
   1825 			assert( 0 );
   1826 			rc = 1;
   1827 		}
   1828 
   1829 		return rc;
   1830 
   1831 	} else if ( c->op == LDAP_MOD_DELETE ) {
   1832 		switch ( c->type ) {
   1833 		case RWM_CF_REWRITE:
   1834 			if ( c->valx >= 0 ) {
   1835 				/* single modification is not allowed */
   1836 				rc = 1;
   1837 
   1838 			} else if ( rwmap->rwm_rw != NULL ) {
   1839 				rewrite_info_delete( &rwmap->rwm_rw );
   1840 				assert( rwmap->rwm_rw == NULL );
   1841 
   1842 				ber_bvarray_free( rwmap->rwm_bva_rewrite );
   1843 				rwmap->rwm_bva_rewrite = NULL;
   1844 			}
   1845 			break;
   1846 
   1847 		case RWM_CF_T_F_SUPPORT:
   1848 			rwmap->rwm_flags &= ~RWM_F_SUPPORT_T_F_MASK2;
   1849 			break;
   1850 
   1851 		case RWM_CF_MAP:
   1852 			if ( c->valx >= 0 ) {
   1853 				/* single modification is not allowed */
   1854 				rc = 1;
   1855 
   1856 			} else {
   1857 				avl_free( rwmap->rwm_oc.remap, rwm_mapping_dst_free );
   1858 				avl_free( rwmap->rwm_oc.map, rwm_mapping_free );
   1859 				avl_free( rwmap->rwm_at.remap, rwm_mapping_dst_free );
   1860 				avl_free( rwmap->rwm_at.map, rwm_mapping_free );
   1861 
   1862 				rwmap->rwm_oc.remap = NULL;
   1863 				rwmap->rwm_oc.map = NULL;
   1864 				rwmap->rwm_at.remap = NULL;
   1865 				rwmap->rwm_at.map = NULL;
   1866 
   1867 				ber_bvarray_free( rwmap->rwm_bva_map );
   1868 				rwmap->rwm_bva_map = NULL;
   1869 			}
   1870 			break;
   1871 
   1872 		case RWM_CF_NORMALIZE_MAPPED:
   1873 			rwmap->rwm_flags &= ~RWM_F_NORMALIZE_MAPPED_ATTRS;
   1874 			break;
   1875 
   1876 		default:
   1877 			return 1;
   1878 		}
   1879 		return rc;
   1880 	}
   1881 
   1882 	switch ( c->type ) {
   1883 	case RWM_CF_REWRITE:
   1884 		argv0 = c->argv[ 0 ];
   1885 		c->argv[ 0 ] += STRLENOF( "rwm-" );
   1886 		rc = rwm_rw_config( &db, c->fname, c->lineno, c->argc, c->argv );
   1887 		c->argv[ 0 ] = argv0;
   1888 		if ( rc ) {
   1889 			return 1;
   1890 
   1891 		} else {
   1892 			char		*line;
   1893 			struct berval	bv;
   1894 
   1895 			line = ldap_charray2str( c->argv, "\" \"" );
   1896 			if ( line != NULL ) {
   1897 				int	len = strlen( c->argv[ 0 ] );
   1898 
   1899 				ber_str2bv( line, 0, 0, &bv );
   1900 				AC_MEMCPY( &bv.bv_val[ len ], &bv.bv_val[ len + 1 ],
   1901 					bv.bv_len - ( len + 1 ) );
   1902 				bv.bv_val[ bv.bv_len - 1 ] = '"';
   1903 				ber_bvarray_add( &rwmap->rwm_bva_rewrite, &bv );
   1904 			}
   1905 		}
   1906 		break;
   1907 
   1908 	case RWM_CF_SUFFIXMASSAGE:
   1909 		argv0 = c->argv[ 0 ];
   1910 		c->argv[ 0 ] += STRLENOF( "rwm-" );
   1911 		rc = rwm_suffixmassage_config( &db, c->fname, c->lineno, c->argc, c->argv );
   1912 		c->argv[ 0 ] = argv0;
   1913 		if ( rc ) {
   1914 			return 1;
   1915 
   1916 		} else {
   1917 			char		*line;
   1918 			struct berval	bv;
   1919 
   1920 			/* FIXME: not optimal; in fact, this keeps track
   1921 			 * of the fact that a set of rules was added
   1922 			 * using the rwm-suffixmassage shortcut, but the
   1923 			 * rules are not clarified */
   1924 
   1925 			line = ldap_charray2str( c->argv, "\" \"" );
   1926 			if ( line != NULL ) {
   1927 				int	len = strlen( c->argv[ 0 ] );
   1928 
   1929 				ber_str2bv( line, 0, 0, &bv );
   1930 				AC_MEMCPY( &bv.bv_val[ len ], &bv.bv_val[ len + 1 ],
   1931 					bv.bv_len - ( len + 1 ) );
   1932 				bv.bv_val[ bv.bv_len - 1 ] = '"';
   1933 				ber_bvarray_add( &rwmap->rwm_bva_rewrite, &bv );
   1934 			}
   1935 		}
   1936 		break;
   1937 
   1938 	case RWM_CF_T_F_SUPPORT:
   1939 		rc = verb_to_mask( c->argv[ 1 ], t_f_mode );
   1940 		if ( BER_BVISNULL( &t_f_mode[ rc ].word ) ) {
   1941 			return 1;
   1942 		}
   1943 
   1944 		rwmap->rwm_flags &= ~RWM_F_SUPPORT_T_F_MASK2;
   1945 		rwmap->rwm_flags |= t_f_mode[ rc ].mask;
   1946 		rc = 0;
   1947 		break;
   1948 
   1949 	case RWM_CF_MAP:
   1950 		argv0 = c->argv[ 0 ];
   1951 		c->argv[ 0 ] += STRLENOF( "rwm-" );
   1952 		rc = rwm_m_config( &db, c->fname, c->lineno, c->argc, c->argv );
   1953 		c->argv[ 0 ] = argv0;
   1954 		if ( rc ) {
   1955 			return 1;
   1956 
   1957 		} else {
   1958 			char		*line;
   1959 			struct berval	bv;
   1960 
   1961 			line = ldap_charray2str( &c->argv[ 1 ], " " );
   1962 			if ( line != NULL ) {
   1963 				ber_str2bv( line, 0, 0, &bv );
   1964 				ber_bvarray_add( &rwmap->rwm_bva_map, &bv );
   1965 			}
   1966 		}
   1967 		break;
   1968 
   1969 	case RWM_CF_NORMALIZE_MAPPED:
   1970 		if ( c->value_int ) {
   1971 			rwmap->rwm_flags |= RWM_F_NORMALIZE_MAPPED_ATTRS;
   1972 		} else {
   1973 			rwmap->rwm_flags &= ~RWM_F_NORMALIZE_MAPPED_ATTRS;
   1974 		}
   1975 		break;
   1976 
   1977 	default:
   1978 		assert( 0 );
   1979 		return 1;
   1980 	}
   1981 
   1982 	return rc;
   1983 }
   1984 
   1985 static int
   1986 rwm_db_init(
   1987 	BackendDB	*be,
   1988 	ConfigReply	*cr )
   1989 {
   1990 	slap_overinst		*on = (slap_overinst *) be->bd_info;
   1991 	struct ldaprwmap	*rwmap;
   1992 	char			*rargv[ 3 ];
   1993 	int			rc = 0;
   1994 
   1995 	rwmap = (struct ldaprwmap *)ch_calloc( 1, sizeof( struct ldaprwmap ) );
   1996 
   1997  	rwmap->rwm_rw = rewrite_info_init( REWRITE_MODE_USE_DEFAULT );
   1998 	if ( rwmap->rwm_rw == NULL ) {
   1999  		rc = -1;
   2000 		goto error_return;
   2001  	}
   2002 
   2003 	/* this rewriteContext by default must be null;
   2004 	 * rules can be added if required */
   2005 	rargv[ 0 ] = "rewriteContext";
   2006 	rargv[ 1 ] = "searchFilter";
   2007 	rargv[ 2 ] = NULL;
   2008 	rewrite_parse( rwmap->rwm_rw, "<suffix massage>", 1, 2, rargv );
   2009 
   2010 	rargv[ 0 ] = "rewriteContext";
   2011 	rargv[ 1 ] = "default";
   2012 	rargv[ 2 ] = NULL;
   2013 	rewrite_parse( rwmap->rwm_rw, "<suffix massage>", 2, 2, rargv );
   2014 
   2015 error_return:;
   2016 	on->on_bi.bi_private = (void *)rwmap;
   2017 
   2018 	if ( rc ) {
   2019 		(void)rwm_db_destroy( be, NULL );
   2020 	}
   2021 
   2022 	return rc;
   2023 }
   2024 
   2025 static int
   2026 rwm_db_destroy(
   2027 	BackendDB	*be,
   2028 	ConfigReply	*cr )
   2029 {
   2030 	slap_overinst	*on = (slap_overinst *) be->bd_info;
   2031 	int		rc = 0;
   2032 
   2033 	if ( on->on_bi.bi_private ) {
   2034 		struct ldaprwmap	*rwmap =
   2035 			(struct ldaprwmap *)on->on_bi.bi_private;
   2036 
   2037 		if ( rwmap->rwm_rw ) {
   2038 			rewrite_info_delete( &rwmap->rwm_rw );
   2039 			ber_bvarray_free( rwmap->rwm_bva_rewrite );
   2040 		}
   2041 
   2042 		avl_free( rwmap->rwm_oc.remap, rwm_mapping_dst_free );
   2043 		avl_free( rwmap->rwm_oc.map, rwm_mapping_free );
   2044 		avl_free( rwmap->rwm_at.remap, rwm_mapping_dst_free );
   2045 		avl_free( rwmap->rwm_at.map, rwm_mapping_free );
   2046 		ber_bvarray_free( rwmap->rwm_bva_map );
   2047 
   2048 		ch_free( rwmap );
   2049 	}
   2050 
   2051 	return rc;
   2052 }
   2053 
   2054 static slap_overinst rwm = { { NULL } };
   2055 
   2056 #if SLAPD_OVER_RWM == SLAPD_MOD_DYNAMIC
   2057 static
   2058 #endif /* SLAPD_OVER_RWM == SLAPD_MOD_DYNAMIC */
   2059 int
   2060 rwm_initialize( void )
   2061 {
   2062 	int		rc;
   2063 
   2064 	/* Make sure we don't exceed the bits reserved for userland */
   2065 	config_check_userland( RWM_CF_LAST );
   2066 
   2067 	memset( &rwm, 0, sizeof( slap_overinst ) );
   2068 
   2069 	rwm.on_bi.bi_type = "rwm";
   2070 	rwm.on_bi.bi_flags =
   2071 		SLAPO_BFLAG_SINGLE |
   2072 		0;
   2073 
   2074 	rwm.on_bi.bi_db_init = rwm_db_init;
   2075 	rwm.on_bi.bi_db_config = rwm_db_config;
   2076 	rwm.on_bi.bi_db_destroy = rwm_db_destroy;
   2077 
   2078 	rwm.on_bi.bi_op_bind = rwm_op_bind;
   2079 	rwm.on_bi.bi_op_search = rwm_op_search;
   2080 	rwm.on_bi.bi_op_compare = rwm_op_compare;
   2081 	rwm.on_bi.bi_op_modify = rwm_op_modify;
   2082 	rwm.on_bi.bi_op_modrdn = rwm_op_modrdn;
   2083 	rwm.on_bi.bi_op_add = rwm_op_add;
   2084 	rwm.on_bi.bi_op_delete = rwm_op_delete;
   2085 	rwm.on_bi.bi_op_unbind = rwm_op_unbind;
   2086 	rwm.on_bi.bi_extended = rwm_extended;
   2087 
   2088 	rwm.on_bi.bi_operational = rwm_operational;
   2089 	rwm.on_bi.bi_chk_referrals = 0 /* rwm_chk_referrals */ ;
   2090 
   2091 	rwm.on_bi.bi_connection_init = rwm_conn_init;
   2092 	rwm.on_bi.bi_connection_destroy = rwm_conn_destroy;
   2093 
   2094 	rwm.on_response = rwm_response;
   2095 
   2096 	rwm.on_bi.bi_cf_ocs = rwmocs;
   2097 
   2098 	rc = config_register_schema( rwmcfg, rwmocs );
   2099 	if ( rc ) {
   2100 		return rc;
   2101 	}
   2102 
   2103 	return overlay_register( &rwm );
   2104 }
   2105 
   2106 #if SLAPD_OVER_RWM == SLAPD_MOD_DYNAMIC
   2107 int
   2108 init_module( int argc, char *argv[] )
   2109 {
   2110 	return rwm_initialize();
   2111 }
   2112 #endif /* SLAPD_OVER_RWM == SLAPD_MOD_DYNAMIC */
   2113 
   2114 #endif /* SLAPD_OVER_RWM */
   2115