1 /* rwm.c - rewrite/remap operations */
2 /* $OpenLDAP$ */
3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
4  *
5  * Copyright 2003-2021 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 "slap-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 	struct berval rx_dn;
38 	struct berval rx_ndn;
39 	AttributeName *mapped_attrs;
40 	OpRequest o_request;
41 } rwm_op_state;
42 
43 typedef struct rwm_op_cb {
44 	slap_callback cb;
45 	rwm_op_state ros;
46 } rwm_op_cb;
47 
48 static int
49 rwm_db_destroy( BackendDB *be, ConfigReply *cr );
50 
51 static int
52 rwm_send_entry( Operation *op, SlapReply *rs );
53 
54 static void
rwm_op_rollback(Operation * op,SlapReply * rs,rwm_op_state * ros)55 rwm_op_rollback( Operation *op, SlapReply *rs, rwm_op_state *ros )
56 {
57 	/* in case of successful extended operation cleanup
58 	 * gets called *after* (ITS#6632); this hack counts
59 	 * on others to cleanup our o_req_dn/o_req_ndn,
60 	 * while we cleanup theirs. */
61 	if ( ros->r_tag == LDAP_REQ_EXTENDED && rs->sr_err == LDAP_SUCCESS ) {
62 		if ( !BER_BVISNULL( &ros->rx_dn ) ) {
63 			ch_free( ros->rx_dn.bv_val );
64 		}
65 		if ( !BER_BVISNULL( &ros->rx_ndn ) ) {
66 			ch_free( ros->rx_ndn.bv_val );
67 		}
68 
69 	} else {
70 		if ( !BER_BVISNULL( &ros->ro_dn ) ) {
71 			op->o_req_dn = ros->ro_dn;
72 		}
73 		if ( !BER_BVISNULL( &ros->ro_ndn ) ) {
74 			op->o_req_ndn = ros->ro_ndn;
75 		}
76 
77 		if ( !BER_BVISNULL( &ros->r_dn )
78 			&& ros->r_dn.bv_val != ros->ro_dn.bv_val )
79 		{
80 			assert( ros->r_dn.bv_val != ros->r_ndn.bv_val );
81 			ch_free( ros->r_dn.bv_val );
82 		}
83 
84 		if ( !BER_BVISNULL( &ros->r_ndn )
85 			&& ros->r_ndn.bv_val != ros->ro_ndn.bv_val )
86 		{
87 			ch_free( ros->r_ndn.bv_val );
88 		}
89 	}
90 
91 	BER_BVZERO( &ros->r_dn );
92 	BER_BVZERO( &ros->r_ndn );
93 	BER_BVZERO( &ros->ro_dn );
94 	BER_BVZERO( &ros->ro_ndn );
95 	BER_BVZERO( &ros->rx_dn );
96 	BER_BVZERO( &ros->rx_ndn );
97 
98 	switch( ros->r_tag ) {
99 	case LDAP_REQ_COMPARE:
100 		if ( op->orc_ava->aa_value.bv_val != ros->orc_ava->aa_value.bv_val )
101 			op->o_tmpfree( op->orc_ava->aa_value.bv_val, op->o_tmpmemctx );
102 		op->orc_ava = ros->orc_ava;
103 		break;
104 	case LDAP_REQ_MODIFY:
105 		slap_mods_free( op->orm_modlist, 1 );
106 		op->orm_modlist = ros->orm_modlist;
107 		break;
108 	case LDAP_REQ_MODRDN:
109 		if ( op->orr_newSup != ros->orr_newSup ) {
110 			if ( op->orr_newSup ) {
111 				ch_free( op->orr_newSup->bv_val );
112 				ch_free( op->orr_nnewSup->bv_val );
113 				op->o_tmpfree( op->orr_newSup, op->o_tmpmemctx );
114 				op->o_tmpfree( op->orr_nnewSup, op->o_tmpmemctx );
115 			}
116 			op->orr_newSup = ros->orr_newSup;
117 			op->orr_nnewSup = ros->orr_nnewSup;
118 		}
119 		if ( op->orr_newrdn.bv_val != ros->orr_newrdn.bv_val ) {
120 			ch_free( op->orr_newrdn.bv_val );
121 			ch_free( op->orr_nnewrdn.bv_val );
122 			op->orr_newrdn = ros->orr_newrdn;
123 			op->orr_nnewrdn = ros->orr_nnewrdn;
124 		}
125 		if ( op->orr_newDN.bv_val != ros->orr_newDN.bv_val ) {
126 			ch_free( op->orr_newDN.bv_val );
127 			ch_free( op->orr_nnewDN.bv_val );
128 			op->orr_newDN = ros->orr_newDN;
129 			op->orr_nnewDN = ros->orr_nnewDN;
130 		}
131 		break;
132 	case LDAP_REQ_SEARCH:
133 		op->o_tmpfree( ros->mapped_attrs, op->o_tmpmemctx );
134 		op->ors_attrs = ros->ors_attrs;
135 		if ( op->ors_filter != ros->ors_filter ) {
136 			filter_free_x( op, op->ors_filter, 1 );
137 			op->ors_filter = ros->ors_filter;
138 		}
139 		if ( op->ors_filterstr.bv_val != ros->ors_filterstr.bv_val ) {
140 			op->o_tmpfree( op->ors_filterstr.bv_val, op->o_tmpmemctx );
141 			op->ors_filterstr = ros->ors_filterstr;
142 		}
143 		break;
144 	case LDAP_REQ_EXTENDED:
145 		if ( op->ore_reqdata != ros->ore_reqdata ) {
146 			ber_bvfree( op->ore_reqdata );
147 			op->ore_reqdata = ros->ore_reqdata;
148 		}
149 		break;
150 	case LDAP_REQ_BIND:
151 		if ( rs->sr_err == LDAP_SUCCESS ) {
152 #if 0
153 			ldap_pvt_thread_mutex_lock( &op->o_conn->c_mutex );
154 			/* too late, c_mutex released */
155 			Debug( LDAP_DEBUG_ANY, "*** DN: \"%s\" => \"%s\"\n",
156 				op->o_conn->c_ndn.bv_val,
157 				op->o_req_ndn.bv_val );
158 			ber_bvreplace( &op->o_conn->c_ndn,
159 				&op->o_req_ndn );
160 			ldap_pvt_thread_mutex_unlock( &op->o_conn->c_mutex );
161 #endif
162 		}
163 		break;
164 	default:	break;
165 	}
166 }
167 
168 static int
rwm_op_cleanup(Operation * op,SlapReply * rs)169 rwm_op_cleanup( Operation *op, SlapReply *rs )
170 {
171 	slap_callback	*cb = op->o_callback;
172 	rwm_op_state *ros = cb->sc_private;
173 
174 	if ( rs->sr_type == REP_RESULT || rs->sr_type == REP_EXTENDED ||
175 		op->o_abandon || rs->sr_err == SLAPD_ABANDON )
176 	{
177 		rwm_op_rollback( op, rs, ros );
178 
179 		op->o_callback = op->o_callback->sc_next;
180 		op->o_tmpfree( cb, op->o_tmpmemctx );
181 	}
182 
183 	return SLAP_CB_CONTINUE;
184 }
185 
186 static rwm_op_cb *
rwm_callback_get(Operation * op)187 rwm_callback_get( Operation *op )
188 {
189 	rwm_op_cb	*roc;
190 
191 	roc = op->o_tmpcalloc( 1, sizeof( struct rwm_op_cb ), op->o_tmpmemctx );
192 	roc->cb.sc_cleanup = rwm_op_cleanup;
193 	roc->cb.sc_response = NULL;
194 	roc->cb.sc_next = op->o_callback;
195 	roc->cb.sc_private = &roc->ros;
196 	roc->ros.r_tag = op->o_tag;
197 	roc->ros.ro_dn = op->o_req_dn;
198 	roc->ros.ro_ndn = op->o_req_ndn;
199 	BER_BVZERO( &roc->ros.r_dn );
200 	BER_BVZERO( &roc->ros.r_ndn );
201 	BER_BVZERO( &roc->ros.rx_dn );
202 	BER_BVZERO( &roc->ros.rx_ndn );
203 	roc->ros.mapped_attrs = NULL;
204 	roc->ros.o_request = op->o_request;
205 
206 	return roc;
207 }
208 
209 
210 static int
rwm_op_dn_massage(Operation * op,SlapReply * rs,void * cookie,rwm_op_state * ros)211 rwm_op_dn_massage( Operation *op, SlapReply *rs, void *cookie,
212 	rwm_op_state *ros )
213 {
214 	slap_overinst		*on = (slap_overinst *) op->o_bd->bd_info;
215 	struct ldaprwmap	*rwmap =
216 			(struct ldaprwmap *)on->on_bi.bi_private;
217 
218 	struct berval		dn = BER_BVNULL,
219 				ndn = BER_BVNULL;
220 	int			rc = 0;
221 	dncookie		dc;
222 
223 	/*
224 	 * Rewrite the dn if needed
225 	 */
226 	dc.rwmap = rwmap;
227 	dc.conn = op->o_conn;
228 	dc.rs = rs;
229 	dc.ctx = (char *)cookie;
230 
231 	/* NOTE: in those cases where only the ndn is available,
232 	 * and the caller sets op->o_req_dn = op->o_req_ndn,
233 	 * only rewrite the op->o_req_ndn and use it as
234 	 * op->o_req_dn as well */
235 	ndn = op->o_req_ndn;
236 	if ( op->o_req_dn.bv_val != op->o_req_ndn.bv_val ) {
237 		dn = op->o_req_dn;
238 		rc = rwm_dn_massage_pretty_normalize( &dc, &op->o_req_dn, &dn, &ndn );
239 	} else {
240 		rc = rwm_dn_massage_normalize( &dc, &op->o_req_ndn, &ndn );
241 	}
242 
243 	if ( rc != LDAP_SUCCESS ) {
244 		return rc;
245 	}
246 
247 	if ( ( op->o_req_dn.bv_val != op->o_req_ndn.bv_val && dn.bv_val == op->o_req_dn.bv_val )
248 			|| ndn.bv_val == op->o_req_ndn.bv_val )
249 	{
250 		return LDAP_SUCCESS;
251 	}
252 
253 	if ( op->o_req_dn.bv_val != op->o_req_ndn.bv_val ) {
254 		op->o_req_dn = dn;
255 		assert( BER_BVISNULL( &ros->r_dn ) );
256 		ros->r_dn = dn;
257 	} else {
258 		op->o_req_dn = ndn;
259 	}
260 	op->o_req_ndn = ndn;
261 	assert( BER_BVISNULL( &ros->r_ndn ) );
262 	ros->r_ndn = ndn;
263 
264 	if ( ros->r_tag == LDAP_REQ_EXTENDED ) {
265 		ros->rx_dn = ros->r_dn;
266 		ros->rx_ndn = ros->r_ndn;
267 	}
268 
269 	return LDAP_SUCCESS;
270 }
271 
272 static int
rwm_op_add(Operation * op,SlapReply * rs)273 rwm_op_add( Operation *op, SlapReply *rs )
274 {
275 	slap_overinst		*on = (slap_overinst *) op->o_bd->bd_info;
276 	struct ldaprwmap	*rwmap =
277 			(struct ldaprwmap *)on->on_bi.bi_private;
278 
279 	int			rc,
280 				i;
281 	Attribute		**ap = NULL;
282 	char			*olddn = op->o_req_dn.bv_val;
283 	int			isupdate;
284 
285 	rwm_op_cb		*roc = rwm_callback_get( op );
286 
287 	rc = rwm_op_dn_massage( op, rs, "addDN", &roc->ros );
288 	if ( rc != LDAP_SUCCESS ) {
289 		op->o_bd->bd_info = (BackendInfo *)on->on_info;
290 		send_ldap_error( op, rs, rc, "addDN massage error" );
291 		return -1;
292 	}
293 
294 	if ( olddn != op->o_req_dn.bv_val ) {
295 		ber_bvreplace( &op->ora_e->e_name, &op->o_req_dn );
296 		ber_bvreplace( &op->ora_e->e_nname, &op->o_req_ndn );
297 	}
298 
299 	/* Count number of attributes in entry */
300 	isupdate = be_shadow_update( op );
301 	for ( i = 0, ap = &op->oq_add.rs_e->e_attrs; *ap; ) {
302 		Attribute	*a;
303 
304 		if ( (*ap)->a_desc == slap_schema.si_ad_objectClass ||
305 				(*ap)->a_desc == slap_schema.si_ad_structuralObjectClass )
306 		{
307 			int		j, last;
308 
309 			last = (*ap)->a_numvals - 1;
310 			for ( j = 0; !BER_BVISNULL( &(*ap)->a_vals[ j ] ); j++ ) {
311 				struct ldapmapping	*mapping = NULL;
312 
313 				( void )rwm_mapping( &rwmap->rwm_oc, &(*ap)->a_vals[ j ],
314 						&mapping, RWM_MAP );
315 				if ( mapping == NULL ) {
316 					if ( rwmap->rwm_at.drop_missing ) {
317 						/* FIXME: we allow to remove objectClasses as well;
318 						 * if the resulting entry is inconsistent, that's
319 						 * the relayed database's business...
320 						 */
321 						ch_free( (*ap)->a_vals[ j ].bv_val );
322 						if ( last > j ) {
323 							(*ap)->a_vals[ j ] = (*ap)->a_vals[ last ];
324 						}
325 						BER_BVZERO( &(*ap)->a_vals[ last ] );
326 						(*ap)->a_numvals--;
327 						last--;
328 						j--;
329 					}
330 
331 				} else {
332 					ch_free( (*ap)->a_vals[ j ].bv_val );
333 					ber_dupbv( &(*ap)->a_vals[ j ], &mapping->m_dst );
334 				}
335 			}
336 
337 		} else if ( !isupdate && !get_relax( op ) && (*ap)->a_desc->ad_type->sat_no_user_mod )
338 		{
339 			goto next_attr;
340 
341 		} else {
342 			struct ldapmapping	*mapping = NULL;
343 
344 			( void )rwm_mapping( &rwmap->rwm_at, &(*ap)->a_desc->ad_cname,
345 					&mapping, RWM_MAP );
346 			if ( mapping == NULL ) {
347 				if ( rwmap->rwm_at.drop_missing ) {
348 					goto cleanup_attr;
349 				}
350 			}
351 
352 			if ( (*ap)->a_desc->ad_type->sat_syntax == slap_schema.si_syn_distinguishedName
353 					|| ( mapping != NULL && mapping->m_dst_ad->ad_type->sat_syntax == slap_schema.si_syn_distinguishedName ) )
354 			{
355 				/*
356 				 * FIXME: rewrite could fail; in this case
357 				 * the operation should give up, right?
358 				 */
359 				rc = rwm_dnattr_rewrite( op, rs, "addAttrDN",
360 						(*ap)->a_vals,
361 						(*ap)->a_nvals ? &(*ap)->a_nvals : NULL );
362 				if ( rc ) {
363 					goto cleanup_attr;
364 				}
365 
366 			} else if ( (*ap)->a_desc == slap_schema.si_ad_ref ) {
367 				rc = rwm_referral_rewrite( op, rs, "referralAttrDN",
368 						(*ap)->a_vals,
369 						(*ap)->a_nvals ? &(*ap)->a_nvals : NULL );
370 				if ( rc != LDAP_SUCCESS ) {
371 					goto cleanup_attr;
372 				}
373 			}
374 
375 			if ( mapping != NULL ) {
376 				assert( mapping->m_dst_ad != NULL );
377 				(*ap)->a_desc = mapping->m_dst_ad;
378 			}
379 		}
380 
381 next_attr:;
382 		ap = &(*ap)->a_next;
383 		continue;
384 
385 cleanup_attr:;
386 		/* FIXME: leaking attribute/values? */
387 		a = *ap;
388 
389 		*ap = (*ap)->a_next;
390 		attr_free( a );
391 	}
392 
393 	op->o_callback = &roc->cb;
394 
395 	return SLAP_CB_CONTINUE;
396 }
397 
398 static int
rwm_conn_init(BackendDB * be,Connection * conn)399 rwm_conn_init( BackendDB *be, Connection *conn )
400 {
401 	slap_overinst		*on = (slap_overinst *) be->bd_info;
402 	struct ldaprwmap	*rwmap =
403 			(struct ldaprwmap *)on->on_bi.bi_private;
404 
405 	( void )rewrite_session_init( rwmap->rwm_rw, conn );
406 
407 	return SLAP_CB_CONTINUE;
408 }
409 
410 static int
rwm_conn_destroy(BackendDB * be,Connection * conn)411 rwm_conn_destroy( BackendDB *be, Connection *conn )
412 {
413 	slap_overinst		*on = (slap_overinst *) be->bd_info;
414 	struct ldaprwmap	*rwmap =
415 			(struct ldaprwmap *)on->on_bi.bi_private;
416 
417 	( void )rewrite_session_delete( rwmap->rwm_rw, conn );
418 
419 	return SLAP_CB_CONTINUE;
420 }
421 
422 static int
rwm_op_bind(Operation * op,SlapReply * rs)423 rwm_op_bind( Operation *op, SlapReply *rs )
424 {
425 	slap_overinst		*on = (slap_overinst *) op->o_bd->bd_info;
426 	int			rc;
427 
428 	rwm_op_cb		*roc = rwm_callback_get( op );
429 
430 	rc = rwm_op_dn_massage( op, rs, "bindDN", &roc->ros );
431 	if ( rc != LDAP_SUCCESS ) {
432 		op->o_bd->bd_info = (BackendInfo *)on->on_info;
433 		send_ldap_error( op, rs, rc, "bindDN massage error" );
434 		return -1;
435 	}
436 
437 	overlay_callback_after_backover( op, &roc->cb, 1 );
438 
439 	return SLAP_CB_CONTINUE;
440 }
441 
442 static int
rwm_op_unbind(Operation * op,SlapReply * rs)443 rwm_op_unbind( Operation *op, SlapReply *rs )
444 {
445 	slap_overinst		*on = (slap_overinst *) op->o_bd->bd_info;
446 	struct ldaprwmap	*rwmap =
447 			(struct ldaprwmap *)on->on_bi.bi_private;
448 
449 	rewrite_session_delete( rwmap->rwm_rw, op->o_conn );
450 
451 	return SLAP_CB_CONTINUE;
452 }
453 
454 static int
rwm_op_compare(Operation * op,SlapReply * rs)455 rwm_op_compare( Operation *op, SlapReply *rs )
456 {
457 	slap_overinst		*on = (slap_overinst *) op->o_bd->bd_info;
458 	struct ldaprwmap	*rwmap =
459 			(struct ldaprwmap *)on->on_bi.bi_private;
460 
461 	int			rc;
462 	struct berval		mapped_vals[2] = { BER_BVNULL, BER_BVNULL };
463 
464 	rwm_op_cb		*roc = rwm_callback_get( op );
465 
466 	rc = rwm_op_dn_massage( op, rs, "compareDN", &roc->ros );
467 	if ( rc != LDAP_SUCCESS ) {
468 		op->o_bd->bd_info = (BackendInfo *)on->on_info;
469 		send_ldap_error( op, rs, rc, "compareDN massage error" );
470 		return -1;
471 	}
472 
473 	/* if the attribute is an objectClass, try to remap its value */
474 	if ( op->orc_ava->aa_desc == slap_schema.si_ad_objectClass
475 			|| op->orc_ava->aa_desc == slap_schema.si_ad_structuralObjectClass )
476 	{
477 		rwm_map( &rwmap->rwm_oc, &op->orc_ava->aa_value,
478 				&mapped_vals[0], RWM_MAP );
479 		if ( BER_BVISNULL( &mapped_vals[0] ) || BER_BVISEMPTY( &mapped_vals[0] ) )
480 		{
481 			op->o_bd->bd_info = (BackendInfo *)on->on_info;
482 			send_ldap_error( op, rs, LDAP_OTHER, "compare objectClass map error" );
483 			return -1;
484 
485 		} else if ( mapped_vals[0].bv_val != op->orc_ava->aa_value.bv_val ) {
486 			ber_dupbv_x( &op->orc_ava->aa_value, &mapped_vals[0],
487 				op->o_tmpmemctx );
488 		}
489 
490 	} else {
491 		struct ldapmapping	*mapping = NULL;
492 		AttributeDescription	*ad = op->orc_ava->aa_desc;
493 
494 		( void )rwm_mapping( &rwmap->rwm_at, &op->orc_ava->aa_desc->ad_cname,
495 				&mapping, RWM_MAP );
496 		if ( mapping == NULL ) {
497 			if ( rwmap->rwm_at.drop_missing ) {
498 				op->o_bd->bd_info = (BackendInfo *)on->on_info;
499 				send_ldap_error( op, rs, LDAP_OTHER, "compare attributeType map error" );
500 				return -1;
501 			}
502 
503 		} else {
504 			assert( mapping->m_dst_ad != NULL );
505 			ad = mapping->m_dst_ad;
506 		}
507 
508 		if ( op->orc_ava->aa_desc->ad_type->sat_syntax == slap_schema.si_syn_distinguishedName
509 				|| ( mapping != NULL && mapping->m_dst_ad->ad_type->sat_syntax == slap_schema.si_syn_distinguishedName ) )
510 		{
511 			struct berval	*mapped_valsp[2];
512 
513 			mapped_valsp[0] = &mapped_vals[0];
514 			mapped_valsp[1] = &mapped_vals[1];
515 
516 			mapped_vals[0] = op->orc_ava->aa_value;
517 
518 			rc = rwm_dnattr_rewrite( op, rs, "compareAttrDN", NULL, mapped_valsp );
519 
520 			if ( rc != LDAP_SUCCESS ) {
521 				op->o_bd->bd_info = (BackendInfo *)on->on_info;
522 				send_ldap_error( op, rs, rc, "compareAttrDN massage error" );
523 				return -1;
524 			}
525 
526 			if ( mapped_vals[ 0 ].bv_val != op->orc_ava->aa_value.bv_val ) {
527 				/* NOTE: if we get here, rwm_dnattr_rewrite()
528 				 * already freed the old value, so now
529 				 * it's invalid */
530 				ber_dupbv_x( &op->orc_ava->aa_value, &mapped_vals[0],
531 					op->o_tmpmemctx );
532 				ber_memfree_x( mapped_vals[ 0 ].bv_val, NULL );
533 			}
534 		}
535 		op->orc_ava->aa_desc = ad;
536 	}
537 
538 	op->o_callback = &roc->cb;
539 
540 	return SLAP_CB_CONTINUE;
541 }
542 
543 static int
rwm_op_delete(Operation * op,SlapReply * rs)544 rwm_op_delete( Operation *op, SlapReply *rs )
545 {
546 	slap_overinst		*on = (slap_overinst *) op->o_bd->bd_info;
547 	int			rc;
548 
549 	rwm_op_cb		*roc = rwm_callback_get( op );
550 
551 	rc = rwm_op_dn_massage( op, rs, "deleteDN", &roc->ros );
552 	if ( rc != LDAP_SUCCESS ) {
553 		op->o_bd->bd_info = (BackendInfo *)on->on_info;
554 		send_ldap_error( op, rs, rc, "deleteDN massage error" );
555 		return -1;
556 	}
557 
558 	op->o_callback = &roc->cb;
559 
560 	return SLAP_CB_CONTINUE;
561 }
562 
563 static int
rwm_op_modify(Operation * op,SlapReply * rs)564 rwm_op_modify( Operation *op, SlapReply *rs )
565 {
566 	slap_overinst		*on = (slap_overinst *) op->o_bd->bd_info;
567 	struct ldaprwmap	*rwmap =
568 			(struct ldaprwmap *)on->on_bi.bi_private;
569 
570 	int			isupdate;
571 	Modifications		**mlp;
572 	int			rc;
573 
574 	rwm_op_cb		*roc = rwm_callback_get( op );
575 
576 	rc = rwm_op_dn_massage( op, rs, "modifyDN", &roc->ros );
577 	if ( rc != LDAP_SUCCESS ) {
578 		op->o_bd->bd_info = (BackendInfo *)on->on_info;
579 		send_ldap_error( op, rs, rc, "modifyDN massage error" );
580 		return -1;
581 	}
582 
583 	isupdate = be_shadow_update( op );
584 	for ( mlp = &op->orm_modlist; *mlp; ) {
585 		int			is_oc = 0;
586 		Modifications		*ml = *mlp;
587 		struct ldapmapping	*mapping = NULL;
588 
589 		/* ml points to a temporary mod until needs duplication */
590 		if ( ml->sml_desc == slap_schema.si_ad_objectClass
591 				|| ml->sml_desc == slap_schema.si_ad_structuralObjectClass )
592 		{
593 			is_oc = 1;
594 
595 		} else if ( !isupdate && !get_relax( op ) && ml->sml_desc->ad_type->sat_no_user_mod  )
596 		{
597 			ml = ch_malloc( sizeof( Modifications ) );
598 			*ml = **mlp;
599 			if ( (*mlp)->sml_values ) {
600 				ber_bvarray_dup_x( &ml->sml_values, (*mlp)->sml_values, NULL );
601 				if ( (*mlp)->sml_nvalues ) {
602 					ber_bvarray_dup_x( &ml->sml_nvalues, (*mlp)->sml_nvalues, NULL );
603 				}
604 			}
605 			*mlp = ml;
606 			goto next_mod;
607 
608 		} else {
609 			int			drop_missing;
610 
611 			drop_missing = rwm_mapping( &rwmap->rwm_at,
612 					&ml->sml_desc->ad_cname,
613 					&mapping, RWM_MAP );
614 			if ( drop_missing || ( mapping != NULL && BER_BVISNULL( &mapping->m_dst ) ) )
615 			{
616 				goto skip_mod;
617 			}
618 		}
619 
620 		/* duplicate the modlist */
621 		ml = ch_malloc( sizeof( Modifications ));
622 		*ml = **mlp;
623 		*mlp = ml;
624 
625 		if ( ml->sml_values != NULL ) {
626 			int i, num;
627 			struct berval *bva;
628 
629 			for ( num = 0; !BER_BVISNULL( &ml->sml_values[ num ] ); num++ )
630 				/* count values */ ;
631 
632 			bva = ch_malloc( (num+1) * sizeof( struct berval ));
633 			for (i=0; i<num; i++)
634 				ber_dupbv( &bva[i], &ml->sml_values[i] );
635 			BER_BVZERO( &bva[i] );
636 			ml->sml_values = bva;
637 
638 			if ( ml->sml_nvalues ) {
639 				bva = ch_malloc( (num+1) * sizeof( struct berval ));
640 				for (i=0; i<num; i++)
641 					ber_dupbv( &bva[i], &ml->sml_nvalues[i] );
642 				BER_BVZERO( &bva[i] );
643 				ml->sml_nvalues = bva;
644 			}
645 
646 			if ( is_oc ) {
647 				int	last, j;
648 
649 				last = num-1;
650 
651 				for ( j = 0; !BER_BVISNULL( &ml->sml_values[ j ] ); j++ ) {
652 					struct ldapmapping	*oc_mapping = NULL;
653 
654 					( void )rwm_mapping( &rwmap->rwm_oc, &ml->sml_values[ j ],
655 							&oc_mapping, RWM_MAP );
656 					if ( oc_mapping == NULL ) {
657 						if ( rwmap->rwm_at.drop_missing ) {
658 							/* FIXME: we allow to remove objectClasses as well;
659 							 * if the resulting entry is inconsistent, that's
660 							 * the relayed database's business...
661 							 */
662 							if ( last > j ) {
663 								ch_free( ml->sml_values[ j ].bv_val );
664 								ml->sml_values[ j ] = ml->sml_values[ last ];
665 							}
666 							BER_BVZERO( &ml->sml_values[ last ] );
667 							last--;
668 							j--;
669 						}
670 
671 					} else {
672 						ch_free( ml->sml_values[ j ].bv_val );
673 						ber_dupbv( &ml->sml_values[ j ], &oc_mapping->m_dst );
674 					}
675 				}
676 
677 			} else {
678 				if ( ml->sml_desc->ad_type->sat_syntax == slap_schema.si_syn_distinguishedName
679 						|| ( mapping != NULL && mapping->m_dst_ad->ad_type->sat_syntax == slap_schema.si_syn_distinguishedName ) )
680 				{
681 					rc = rwm_dnattr_rewrite( op, rs, "modifyAttrDN",
682 							ml->sml_values,
683 							ml->sml_nvalues ? &ml->sml_nvalues : NULL );
684 
685 				} else if ( ml->sml_desc == slap_schema.si_ad_ref ) {
686 					rc = rwm_referral_rewrite( op, rs,
687 							"referralAttrDN",
688 							ml->sml_values,
689 							ml->sml_nvalues ? &ml->sml_nvalues : NULL );
690 					if ( rc != LDAP_SUCCESS ) {
691 						goto cleanup_mod;
692 					}
693 				}
694 
695 				if ( rc != LDAP_SUCCESS ) {
696 					goto cleanup_mod;
697 				}
698 			}
699 		}
700 
701 next_mod:;
702 		if ( mapping != NULL ) {
703 			/* use new attribute description */
704 			assert( mapping->m_dst_ad != NULL );
705 			ml->sml_desc = mapping->m_dst_ad;
706 		}
707 
708 		mlp = &ml->sml_next;
709 		continue;
710 
711 skip_mod:;
712 		*mlp = (*mlp)->sml_next;
713 		continue;
714 
715 cleanup_mod:;
716 		ml = *mlp;
717 		*mlp = (*mlp)->sml_next;
718 		slap_mod_free( &ml->sml_mod, 0 );
719 		free( ml );
720 	}
721 
722 	op->o_callback = &roc->cb;
723 
724 	return SLAP_CB_CONTINUE;
725 }
726 
727 static int
rwm_op_modrdn(Operation * op,SlapReply * rs)728 rwm_op_modrdn( Operation *op, SlapReply *rs )
729 {
730 	slap_overinst		*on = (slap_overinst *) op->o_bd->bd_info;
731 	struct ldaprwmap	*rwmap =
732 			(struct ldaprwmap *)on->on_bi.bi_private;
733 	struct berval pdn, pndn;
734 
735 	int			rc;
736 	dncookie		dc;
737 
738 	rwm_op_cb		*roc = rwm_callback_get( op );
739 
740 	if ( op->orr_newSup ) {
741 		struct berval	nnewSup = BER_BVNULL;
742 		struct berval	newSup = BER_BVNULL;
743 
744 		/*
745 		 * Rewrite the new superior, if defined and required
746 	 	 */
747 		dc.rwmap = rwmap;
748 		dc.conn = op->o_conn;
749 		dc.rs = rs;
750 		dc.ctx = "newSuperiorDN";
751 		newSup = *op->orr_newSup;
752 		nnewSup = *op->orr_nnewSup;
753 		rc = rwm_dn_massage_pretty_normalize( &dc, op->orr_newSup, &newSup, &nnewSup );
754 		if ( rc != LDAP_SUCCESS ) {
755 			op->o_bd->bd_info = (BackendInfo *)on->on_info;
756 			send_ldap_error( op, rs, rc, "newSuperiorDN massage error" );
757 			return -1;
758 		}
759 
760 		if ( op->orr_newSup->bv_val != newSup.bv_val ) {
761 			op->orr_newSup = op->o_tmpalloc( sizeof( struct berval ),
762 				op->o_tmpmemctx );
763 			op->orr_nnewSup = op->o_tmpalloc( sizeof( struct berval ),
764 				op->o_tmpmemctx );
765 			*op->orr_newSup = newSup;
766 			*op->orr_nnewSup = nnewSup;
767 		}
768 		pdn = newSup;
769 		pndn = nnewSup;
770 	}
771 
772 	/*
773 	 * Rewrite the newRDN, if needed
774  	 */
775 	{
776 		struct berval	newrdn = BER_BVNULL;
777 		struct berval	nnewrdn = BER_BVNULL;
778 
779 		dc.rwmap = rwmap;
780 		dc.conn = op->o_conn;
781 		dc.rs = rs;
782 		dc.ctx = "newRDN";
783 		newrdn = op->orr_newrdn;
784 		nnewrdn = op->orr_nnewrdn;
785 		rc = rwm_dn_massage_pretty_normalize( &dc, &op->orr_newrdn, &newrdn, &nnewrdn );
786 		if ( rc != LDAP_SUCCESS ) {
787 			op->o_bd->bd_info = (BackendInfo *)on->on_info;
788 			send_ldap_error( op, rs, rc, "newRDN massage error" );
789 			goto err;
790 		}
791 
792 		if ( op->orr_newrdn.bv_val != newrdn.bv_val ) {
793 			op->orr_newrdn = newrdn;
794 			op->orr_nnewrdn = nnewrdn;
795 		}
796 	}
797 
798 	/*
799 	 * Rewrite the dn, if needed
800  	 */
801 	rc = rwm_op_dn_massage( op, rs, "renameDN", &roc->ros );
802 	if ( rc != LDAP_SUCCESS ) {
803 		op->o_bd->bd_info = (BackendInfo *)on->on_info;
804 		send_ldap_error( op, rs, rc, "renameDN massage error" );
805 		goto err;
806 	}
807 	if ( !op->orr_newSup ) {
808 		dnParent( &op->o_req_dn, &pdn );
809 		dnParent( &op->o_req_ndn, &pndn );
810 	}
811 
812 	/*
813 	 * Update the new DN
814 	 */
815 	build_new_dn( &op->orr_newDN, &pdn, &op->orr_newrdn, op->o_tmpmemctx );
816 	build_new_dn( &op->orr_nnewDN, &pndn, &op->orr_nnewrdn, op->o_tmpmemctx );
817 
818 	op->o_callback = &roc->cb;
819 
820 	rc = SLAP_CB_CONTINUE;
821 
822 	if ( 0 ) {
823 err:;
824 		if ( op->orr_newSup != roc->ros.orr_newSup ) {
825 			ch_free( op->orr_newSup->bv_val );
826 			ch_free( op->orr_nnewSup->bv_val );
827 			op->o_tmpfree( op->orr_newSup, op->o_tmpmemctx );
828 			op->o_tmpfree( op->orr_nnewSup, op->o_tmpmemctx );
829 			op->orr_newSup = roc->ros.orr_newSup;
830 			op->orr_nnewSup = roc->ros.orr_nnewSup;
831 		}
832 
833 		if ( op->orr_newrdn.bv_val != roc->ros.orr_newrdn.bv_val ) {
834 			ch_free( op->orr_newrdn.bv_val );
835 			ch_free( op->orr_nnewrdn.bv_val );
836 			op->orr_newrdn = roc->ros.orr_newrdn;
837 			op->orr_nnewrdn = roc->ros.orr_nnewrdn;
838 		}
839 
840 		if ( op->orr_newDN.bv_val != roc->ros.orr_newDN.bv_val ) {
841 			op->o_tmpfree( op->orr_newDN.bv_val, op->o_tmpmemctx );
842 			op->o_tmpfree( op->orr_nnewDN.bv_val, op->o_tmpmemctx );
843 			op->orr_newDN = roc->ros.orr_newDN;
844 			op->orr_nnewDN = roc->ros.orr_nnewDN;
845 		}
846 	}
847 
848 	return rc;
849 }
850 
851 
852 static int
rwm_swap_attrs(Operation * op,SlapReply * rs)853 rwm_swap_attrs( Operation *op, SlapReply *rs )
854 {
855 	slap_callback	*cb = op->o_callback;
856 	rwm_op_state *ros = cb->sc_private;
857 
858 	rs->sr_attrs = ros->ors_attrs;
859 
860 	/* other overlays might have touched op->ors_attrs,
861 	 * so we restore the original version here, otherwise
862 	 * attribute-mapping might fail */
863 	op->ors_attrs = ros->mapped_attrs;
864 
865  	return SLAP_CB_CONTINUE;
866 }
867 
868 /*
869  * NOTE: this implementation of get/release entry is probably far from
870  * optimal.  The rationale consists in intercepting the request directed
871  * to the underlying database, in order to rewrite/remap the request,
872  * perform it using the modified data, duplicate the resulting entry
873  * and finally free it when release is called.
874  * This implies that subsequent overlays are not called, as the request
875  * is directly shunted to the underlying database.
876  */
877 static int
rwm_entry_release_rw(Operation * op,Entry * e,int rw)878 rwm_entry_release_rw( Operation *op, Entry *e, int rw )
879 {
880 	slap_overinst		*on = (slap_overinst *) op->o_bd->bd_info;
881 
882 	/* can't be ours */
883 	if ( ((BackendInfo *)on->on_info->oi_orig)->bi_entry_get_rw == NULL ) {
884 		return SLAP_CB_CONTINUE;
885 	}
886 
887 	/* just free entry if (probably) ours */
888 	if ( e->e_private == NULL && BER_BVISNULL( &e->e_bv ) ) {
889 		entry_free( e );
890 		return LDAP_SUCCESS;
891 	}
892 
893 	return SLAP_CB_CONTINUE;
894 }
895 
896 static struct berval *passwd_oid;
897 
898 static int
rwm_entry_get_rw(Operation * op,struct berval * ndn,ObjectClass * oc,AttributeDescription * at,int rw,Entry ** ep)899 rwm_entry_get_rw( Operation *op, struct berval *ndn,
900 	ObjectClass *oc, AttributeDescription *at, int rw, Entry **ep )
901 {
902 	slap_overinst		*on = (slap_overinst *) op->o_bd->bd_info;
903 	int			rc;
904 	BackendDB		db;
905 	Operation		op2;
906 	SlapReply		rs = { REP_SEARCH };
907 
908 	rwm_op_state		ros = { 0 };
909 	struct berval		mndn = BER_BVNULL;
910 
911 	if ( ((BackendInfo *)on->on_info->oi_orig)->bi_entry_get_rw == NULL ) {
912 		return SLAP_CB_CONTINUE;
913 	}
914 
915 	/* If we're fetching the target of a password mod, must let real DNs thru */
916 	if ( op->o_tag == LDAP_REQ_EXTENDED && bvmatch( passwd_oid, &op->oq_extended.rs_reqoid ) ) {
917 		return SLAP_CB_CONTINUE;
918 	}
919 
920 	/* massage DN */
921 	op2.o_tag = LDAP_REQ_SEARCH;
922 	op2 = *op;
923 	op2.o_req_dn = *ndn;
924 	op2.o_req_ndn = *ndn;
925 	rc = rwm_op_dn_massage( &op2, &rs, "searchDN", &ros );
926 	if ( rc != LDAP_SUCCESS ) {
927 		return LDAP_OTHER;
928 	}
929 
930 	mndn = BER_BVISNULL( &ros.r_ndn ) ? *ndn : ros.r_ndn;
931 
932 	/* map attribute & objectClass */
933 	if ( at != NULL ) {
934 	}
935 
936 	if ( oc != NULL ) {
937 	}
938 
939 	/* fetch entry */
940 	db = *op->o_bd;
941 	op2.o_bd = &db;
942 	op2.o_bd->bd_info = (BackendInfo *)on->on_info->oi_orig;
943 	op2.ors_attrs = slap_anlist_all_attributes;
944 	rc = op2.o_bd->bd_info->bi_entry_get_rw( &op2, &mndn, oc, at, rw, ep );
945 	if ( rc == LDAP_SUCCESS && *ep != NULL ) {
946 		/* we assume be_entry_release() needs to be called */
947 		rs.sr_flags = REP_ENTRY_MUSTRELEASE;
948 		rs.sr_entry = *ep;
949 
950 		/* duplicate & release */
951 		op2.o_bd->bd_info = (BackendInfo *)on;
952 		rc = rwm_send_entry( &op2, &rs );
953 		RS_ASSERT( rs.sr_flags & REP_ENTRY_MUSTFLUSH );
954 		if ( rc == SLAP_CB_CONTINUE ) {
955 			*ep = rs.sr_entry;
956 			rc = LDAP_SUCCESS;
957 		} else {
958 			assert( rc != LDAP_SUCCESS && rs.sr_entry == *ep );
959 			*ep = NULL;
960 			op2.o_bd->bd_info = (BackendInfo *)on->on_info;
961 			be_entry_release_r( &op2, rs.sr_entry );
962 			op2.o_bd->bd_info = (BackendInfo *)on;
963 		}
964 	}
965 
966 	if ( !BER_BVISNULL( &ros.r_ndn) && ros.r_ndn.bv_val != ndn->bv_val ) {
967 		op->o_tmpfree( ros.r_ndn.bv_val, op->o_tmpmemctx );
968 	}
969 
970 	return rc;
971 }
972 
973 static int
rwm_op_search(Operation * op,SlapReply * rs)974 rwm_op_search( Operation *op, SlapReply *rs )
975 {
976 	slap_overinst		*on = (slap_overinst *) op->o_bd->bd_info;
977 	struct ldaprwmap	*rwmap =
978 			(struct ldaprwmap *)on->on_bi.bi_private;
979 
980 	int			rc;
981 	dncookie		dc;
982 
983 	struct berval		fstr = BER_BVNULL;
984 	Filter			*f = NULL;
985 
986 	AttributeName		*an = NULL;
987 
988 	char			*text = NULL;
989 
990 	rwm_op_cb		*roc = rwm_callback_get( op );
991 
992 	rc = rewrite_session_var_set( rwmap->rwm_rw, op->o_conn,
993 		"searchFilter", op->ors_filterstr.bv_val );
994 	if ( rc == LDAP_SUCCESS )
995 		rc = rwm_op_dn_massage( op, rs, "searchDN", &roc->ros );
996 	if ( rc != LDAP_SUCCESS ) {
997 		text = "searchDN massage error";
998 		goto error_return;
999 	}
1000 
1001 	/*
1002 	 * Rewrite the dn if needed
1003 	 */
1004 	dc.rwmap = rwmap;
1005 	dc.conn = op->o_conn;
1006 	dc.rs = rs;
1007 	dc.ctx = "searchFilterAttrDN";
1008 
1009 	rc = rwm_filter_map_rewrite( op, &dc, op->ors_filter, &fstr );
1010 	if ( rc != LDAP_SUCCESS ) {
1011 		text = "searchFilter/searchFilterAttrDN massage error";
1012 		goto error_return;
1013 	}
1014 
1015 	f = str2filter_x( op, fstr.bv_val );
1016 
1017 	if ( f == NULL ) {
1018 		text = "massaged filter parse error";
1019 		goto error_return;
1020 	}
1021 
1022 	op->ors_filter = f;
1023 	op->ors_filterstr = fstr;
1024 
1025 	rc = rwm_map_attrnames( op, &rwmap->rwm_at, &rwmap->rwm_oc,
1026 			op->ors_attrs, &an, RWM_MAP );
1027 	if ( rc != LDAP_SUCCESS ) {
1028 		text = "attribute list mapping error";
1029 		goto error_return;
1030 	}
1031 
1032 	op->ors_attrs = an;
1033 	/* store the mapped Attributes for later usage, in
1034 	 * the case that other overlays change op->ors_attrs */
1035 	roc->ros.mapped_attrs = an;
1036 	roc->cb.sc_response = rwm_swap_attrs;
1037 
1038 	op->o_callback = &roc->cb;
1039 
1040 	return SLAP_CB_CONTINUE;
1041 
1042 error_return:;
1043 	if ( an != NULL ) {
1044 		ch_free( an );
1045 	}
1046 
1047 	if ( f != NULL ) {
1048 		filter_free_x( op, f, 1 );
1049 	}
1050 
1051 	if ( !BER_BVISNULL( &fstr ) ) {
1052 		op->o_tmpfree( fstr.bv_val, op->o_tmpmemctx );
1053 	}
1054 
1055 	rwm_op_rollback( op, rs, &roc->ros );
1056 	op->oq_search = roc->ros.oq_search;
1057 	op->o_tmpfree( roc, op->o_tmpmemctx );
1058 
1059 	op->o_bd->bd_info = (BackendInfo *)on->on_info;
1060 	send_ldap_error( op, rs, rc, text );
1061 
1062 	return -1;
1063 
1064 }
1065 
1066 static int
rwm_exop_passwd(Operation * op,SlapReply * rs)1067 rwm_exop_passwd( Operation *op, SlapReply *rs )
1068 {
1069 	slap_overinst		*on = (slap_overinst *) op->o_bd->bd_info;
1070 	int			rc;
1071 	rwm_op_cb *roc;
1072 
1073 	struct berval	id = BER_BVNULL,
1074 			pwold = BER_BVNULL,
1075 			pwnew = BER_BVNULL;
1076 	BerElement *ber = NULL;
1077 
1078 	if ( !BER_BVISNULL( &op->o_req_ndn ) ) {
1079 		return LDAP_SUCCESS;
1080 	}
1081 
1082 	if ( !SLAP_ISGLOBALOVERLAY( op->o_bd ) ) {
1083 		rs->sr_err = LDAP_OTHER;
1084 		return rs->sr_err;
1085 	}
1086 
1087 	rs->sr_err = slap_passwd_parse( op->ore_reqdata, &id,
1088 		&pwold, &pwnew, &rs->sr_text );
1089 	if ( rs->sr_err != LDAP_SUCCESS ) {
1090 		return rs->sr_err;
1091 	}
1092 
1093 	if ( !BER_BVISNULL( &id ) ) {
1094 		char idNul = id.bv_val[id.bv_len];
1095 		id.bv_val[id.bv_len] = '\0';
1096 		rs->sr_err = dnPrettyNormal( NULL, &id, &op->o_req_dn,
1097 				&op->o_req_ndn, op->o_tmpmemctx );
1098 		id.bv_val[id.bv_len] = idNul;
1099 		if ( rs->sr_err != LDAP_SUCCESS ) {
1100 			rs->sr_text = "Invalid DN";
1101 			return rs->sr_err;
1102 		}
1103 
1104 	} else {
1105 		ber_dupbv_x( &op->o_req_dn, &op->o_dn, op->o_tmpmemctx );
1106 		ber_dupbv_x( &op->o_req_ndn, &op->o_ndn, op->o_tmpmemctx );
1107 	}
1108 
1109 	roc = rwm_callback_get( op );
1110 
1111 	rc = rwm_op_dn_massage( op, rs, "extendedDN", &roc->ros );
1112 	if ( rc != LDAP_SUCCESS ) {
1113 		op->o_bd->bd_info = (BackendInfo *)on->on_info;
1114 		send_ldap_error( op, rs, rc, "extendedDN massage error" );
1115 		return -1;
1116 	}
1117 
1118 	ber = ber_alloc_t( LBER_USE_DER );
1119 	if ( !ber ) {
1120 		rs->sr_err = LDAP_OTHER;
1121 		rs->sr_text = "No memory";
1122 		return rs->sr_err;
1123 	}
1124 	ber_printf( ber, "{" );
1125 	if ( !BER_BVISNULL( &id )) {
1126 		ber_printf( ber, "tO", LDAP_TAG_EXOP_MODIFY_PASSWD_ID,
1127 			&op->o_req_dn );
1128 	}
1129 	if ( !BER_BVISNULL( &pwold )) {
1130 		ber_printf( ber, "tO", LDAP_TAG_EXOP_MODIFY_PASSWD_OLD, &pwold );
1131 	}
1132 	if ( !BER_BVISNULL( &pwnew )) {
1133 		ber_printf( ber, "tO", LDAP_TAG_EXOP_MODIFY_PASSWD_NEW, &pwnew );
1134 	}
1135 	ber_printf( ber, "N}" );
1136 	ber_flatten( ber, &op->ore_reqdata );
1137 	ber_free( ber, 1 );
1138 
1139 	op->o_callback = &roc->cb;
1140 
1141 	return SLAP_CB_CONTINUE;
1142 }
1143 
1144 static struct exop {
1145 	struct berval	oid;
1146 	BI_op_extended	*extended;
1147 } exop_table[] = {
1148 	{ BER_BVC(LDAP_EXOP_MODIFY_PASSWD),	rwm_exop_passwd },
1149 	{ BER_BVNULL, NULL }
1150 };
1151 
1152 static struct berval *passwd_oid = &exop_table[0].oid;
1153 
1154 static int
rwm_extended(Operation * op,SlapReply * rs)1155 rwm_extended( Operation *op, SlapReply *rs )
1156 {
1157 	slap_overinst		*on = (slap_overinst *) op->o_bd->bd_info;
1158 	int			rc;
1159 	rwm_op_cb *roc;
1160 
1161 	int	i;
1162 
1163 	for ( i = 0; exop_table[i].extended != NULL; i++ ) {
1164 		if ( bvmatch( &exop_table[i].oid, &op->oq_extended.rs_reqoid ) )
1165 		{
1166 			rc = exop_table[i].extended( op, rs );
1167 			switch ( rc ) {
1168 			case LDAP_SUCCESS:
1169 				break;
1170 
1171 			case SLAP_CB_CONTINUE:
1172 			case SLAPD_ABANDON:
1173 				return rc;
1174 
1175 			default:
1176 				send_ldap_result( op, rs );
1177 				return rc;
1178 			}
1179 			break;
1180 		}
1181 	}
1182 
1183 	roc = rwm_callback_get( op );
1184 
1185 	rc = rwm_op_dn_massage( op, rs, "extendedDN", &roc->ros );
1186 	if ( rc != LDAP_SUCCESS ) {
1187 		op->o_bd->bd_info = (BackendInfo *)on->on_info;
1188 		send_ldap_error( op, rs, rc, "extendedDN massage error" );
1189 		return -1;
1190 	}
1191 
1192 	/* TODO: rewrite/map extended data ? ... */
1193 	op->o_callback = &roc->cb;
1194 
1195 	return SLAP_CB_CONTINUE;
1196 }
1197 
1198 static void
rwm_matched(Operation * op,SlapReply * rs)1199 rwm_matched( Operation *op, SlapReply *rs )
1200 {
1201 	slap_overinst		*on = (slap_overinst *) op->o_bd->bd_info;
1202 	struct ldaprwmap	*rwmap =
1203 			(struct ldaprwmap *)on->on_bi.bi_private;
1204 
1205 	struct berval		dn, mdn;
1206 	dncookie		dc;
1207 	int			rc;
1208 
1209 	if ( rs->sr_matched == NULL ) {
1210 		return;
1211 	}
1212 
1213 	dc.rwmap = rwmap;
1214 	dc.conn = op->o_conn;
1215 	dc.rs = rs;
1216 	dc.ctx = "matchedDN";
1217 	ber_str2bv( rs->sr_matched, 0, 0, &dn );
1218 	mdn = dn;
1219 	rc = rwm_dn_massage_pretty( &dc, &dn, &mdn );
1220 	if ( rc != LDAP_SUCCESS ) {
1221 		rs->sr_err = rc;
1222 		rs->sr_text = "Rewrite error";
1223 
1224 	} else if ( mdn.bv_val != dn.bv_val ) {
1225 		if ( rs->sr_flags & REP_MATCHED_MUSTBEFREED ) {
1226 			ch_free( (void *)rs->sr_matched );
1227 
1228 		} else {
1229 			rs->sr_flags |= REP_MATCHED_MUSTBEFREED;
1230 		}
1231 		rs->sr_matched = mdn.bv_val;
1232 	}
1233 }
1234 
1235 static int
rwm_attrs(Operation * op,SlapReply * rs,Attribute ** a_first,int stripEntryDN)1236 rwm_attrs( Operation *op, SlapReply *rs, Attribute** a_first, int stripEntryDN )
1237 {
1238 	slap_overinst		*on = (slap_overinst *) op->o_bd->bd_info;
1239 	struct ldaprwmap	*rwmap =
1240 			(struct ldaprwmap *)on->on_bi.bi_private;
1241 
1242 	dncookie		dc;
1243 	int			rc;
1244 	Attribute		**ap;
1245 	int			isupdate;
1246 	int			check_duplicate_attrs = 0;
1247 
1248 	/*
1249 	 * Rewrite the dn attrs, if needed
1250 	 */
1251 	dc.rwmap = rwmap;
1252 	dc.conn = op->o_conn;
1253 	dc.rs = NULL;
1254 
1255 	/* FIXME: the entries are in the remote mapping form;
1256 	 * so we need to select those attributes we are willing
1257 	 * to return, and remap them accordingly */
1258 
1259 	/* FIXME: in principle, one could map an attribute
1260 	 * on top of another, which already exists.
1261 	 * As such, in the end there might exist more than
1262 	 * one instance of an attribute.
1263 	 * We should at least check if this occurs, and issue
1264 	 * an error (because multiple instances of attrs in
1265 	 * response are not valid), or merge the values (what
1266 	 * about duplicate values?) */
1267 	isupdate = be_shadow_update( op );
1268 	for ( ap = a_first; *ap; ) {
1269 		struct ldapmapping	*mapping = NULL;
1270 		int			drop_missing;
1271 		int			last = -1;
1272 		Attribute		*a;
1273 
1274 		if ( ( rwmap->rwm_flags & RWM_F_DROP_UNREQUESTED_ATTRS ) &&
1275 				op->ors_attrs != NULL &&
1276 				!SLAP_USERATTRS( rs->sr_attr_flags ) &&
1277 				!ad_inlist( (*ap)->a_desc, op->ors_attrs ) )
1278 		{
1279 			goto cleanup_attr;
1280 		}
1281 
1282 		drop_missing = rwm_mapping( &rwmap->rwm_at,
1283 				&(*ap)->a_desc->ad_cname, &mapping, RWM_REMAP );
1284 		if ( drop_missing || ( mapping != NULL && BER_BVISEMPTY( &mapping->m_dst ) ) )
1285 		{
1286 			goto cleanup_attr;
1287 		}
1288 		if ( mapping != NULL ) {
1289 			assert( mapping->m_dst_ad != NULL );
1290 
1291 			/* try to normalize mapped Attributes if the original
1292 			 * AttributeType was not normalized */
1293 			if ( (!(*ap)->a_desc->ad_type->sat_equality ||
1294 				!(*ap)->a_desc->ad_type->sat_equality->smr_normalize) &&
1295 				mapping->m_dst_ad->ad_type->sat_equality &&
1296 				mapping->m_dst_ad->ad_type->sat_equality->smr_normalize )
1297 			{
1298 				if ((rwmap->rwm_flags & RWM_F_NORMALIZE_MAPPED_ATTRS))
1299 				{
1300 					int i = 0;
1301 
1302 					last = (*ap)->a_numvals;
1303 					if ( last )
1304 					{
1305 						(*ap)->a_nvals = ch_malloc( (last+1) * sizeof(struct berval) );
1306 
1307 						for ( i = 0; !BER_BVISNULL( &(*ap)->a_vals[i]); i++ ) {
1308 							int		rc;
1309 							/*
1310 							 * check that each value is valid per syntax
1311 							 * and pretty if appropriate
1312 							 */
1313 							rc = mapping->m_dst_ad->ad_type->sat_equality->smr_normalize(
1314 								SLAP_MR_VALUE_OF_ATTRIBUTE_SYNTAX,
1315 								mapping->m_dst_ad->ad_type->sat_syntax,
1316 								mapping->m_dst_ad->ad_type->sat_equality,
1317 								&(*ap)->a_vals[i], &(*ap)->a_nvals[i],
1318 								NULL );
1319 
1320 							if ( rc != LDAP_SUCCESS ) {
1321 								/* FIXME: this is wrong, putting a non-normalized value
1322 								 * into nvals. But when a proxy sends us bogus data,
1323 								 * we still need to give it to the client, even if it
1324 								 * violates the syntax. I.e., we don't want to silently
1325 								 * drop things and trigger an apparent data loss.
1326 								 */
1327 								ber_dupbv( &(*ap)->a_nvals[i], &(*ap)->a_vals[i] );
1328 							}
1329 						}
1330 						BER_BVZERO( &(*ap)->a_nvals[i] );
1331 					}
1332 
1333 				} else {
1334 					assert( (*ap)->a_nvals == (*ap)->a_vals );
1335 					(*ap)->a_nvals = NULL;
1336 					ber_bvarray_dup_x( &(*ap)->a_nvals, (*ap)->a_vals, NULL );
1337 				}
1338 			}
1339 
1340 			/* rewrite the attribute description */
1341 			(*ap)->a_desc = mapping->m_dst_ad;
1342 
1343 			/* will need to check for duplicate attrs */
1344 			check_duplicate_attrs++;
1345 		}
1346 
1347 		if ( (*ap)->a_desc == slap_schema.si_ad_entryDN ) {
1348 			if ( stripEntryDN ) {
1349 				/* will be generated by frontend */
1350 				goto cleanup_attr;
1351 			}
1352 
1353 		} else if ( !isupdate
1354 			&& !get_relax( op )
1355 			&& (*ap)->a_desc->ad_type->sat_no_user_mod
1356 			&& (*ap)->a_desc->ad_type != slap_schema.si_at_undefined )
1357 		{
1358 			goto next_attr;
1359 		}
1360 
1361 		if ( last == -1 ) { /* not yet counted */
1362 			last = (*ap)->a_numvals;
1363 		}
1364 
1365 		if ( last == 0 ) {
1366 			/* empty? leave it in place because of attrsonly and vlv */
1367 			goto next_attr;
1368 		}
1369 		last--;
1370 
1371 		if ( (*ap)->a_desc == slap_schema.si_ad_objectClass
1372 				|| (*ap)->a_desc == slap_schema.si_ad_structuralObjectClass )
1373 		{
1374 			struct berval	*bv;
1375 
1376 			for ( bv = (*ap)->a_vals; !BER_BVISNULL( bv ); bv++ ) {
1377 				struct berval	mapped;
1378 
1379 				rwm_map( &rwmap->rwm_oc, &bv[0], &mapped, RWM_REMAP );
1380 				if ( BER_BVISNULL( &mapped ) || BER_BVISEMPTY( &mapped ) ) {
1381 remove_oc:;
1382 					ch_free( bv[0].bv_val );
1383 					BER_BVZERO( &bv[0] );
1384 					if ( &(*ap)->a_vals[last] > &bv[0] ) {
1385 						bv[0] = (*ap)->a_vals[last];
1386 						BER_BVZERO( &(*ap)->a_vals[last] );
1387 					}
1388 					last--;
1389 					bv--;
1390 
1391 				} else if ( mapped.bv_val != bv[0].bv_val
1392 					&& ber_bvstrcasecmp( &mapped, &bv[0] ) != 0 )
1393 				{
1394 					int	i;
1395 
1396 					for ( i = 0; !BER_BVISNULL( &(*ap)->a_vals[ i ] ); i++ ) {
1397 						if ( &(*ap)->a_vals[ i ] == bv ) {
1398 							continue;
1399 						}
1400 
1401 						if ( ber_bvstrcasecmp( &mapped, &(*ap)->a_vals[ i ] ) == 0 ) {
1402 							break;
1403 						}
1404 					}
1405 
1406 					if ( !BER_BVISNULL( &(*ap)->a_vals[ i ] ) ) {
1407 						goto remove_oc;
1408 					}
1409 
1410 					/*
1411 					 * FIXME: after LBER_FREEing
1412 					 * the value is replaced by
1413 					 * ch_alloc'ed memory
1414 					 */
1415 					ber_bvreplace( &bv[0], &mapped );
1416 
1417 					/* FIXME: will need to check
1418 					 * if the structuralObjectClass
1419 					 * changed */
1420 				}
1421 			}
1422 
1423 		/*
1424 		 * It is necessary to try to rewrite attributes with
1425 		 * dn syntax because they might be used in ACLs as
1426 		 * members of groups; since ACLs are applied to the
1427 		 * rewritten stuff, no dn-based subject clause could
1428 		 * be used at the ldap backend side (see
1429 		 * http://www.OpenLDAP.org/faq/data/cache/452.html)
1430 		 * The problem can be overcome by moving the dn-based
1431 		 * ACLs to the target directory server, and letting
1432 		 * everything pass thru the ldap backend. */
1433 		/* FIXME: handle distinguishedName-like syntaxes, like
1434 		 * nameAndOptionalUID */
1435 		} else if ( (*ap)->a_desc->ad_type->sat_syntax == slap_schema.si_syn_distinguishedName
1436 				|| ( mapping != NULL && mapping->m_src_ad->ad_type->sat_syntax == slap_schema.si_syn_distinguishedName ) )
1437 		{
1438 			dc.ctx = "searchAttrDN";
1439 			rc = rwm_dnattr_result_rewrite( &dc, (*ap)->a_vals, (*ap)->a_nvals );
1440 			if ( rc != LDAP_SUCCESS ) {
1441 				goto cleanup_attr;
1442 			}
1443 
1444 		} else if ( (*ap)->a_desc == slap_schema.si_ad_ref ) {
1445 			dc.ctx = "searchAttrDN";
1446 			rc = rwm_referral_result_rewrite( &dc, (*ap)->a_vals );
1447 			if ( rc != LDAP_SUCCESS ) {
1448 				goto cleanup_attr;
1449 			}
1450 		}
1451 
1452 
1453 next_attr:;
1454 		ap = &(*ap)->a_next;
1455 		continue;
1456 
1457 cleanup_attr:;
1458 		a = *ap;
1459 		*ap = (*ap)->a_next;
1460 
1461 		attr_free( a );
1462 	}
1463 
1464 	/* only check if some mapping occurred */
1465 	if ( check_duplicate_attrs ) {
1466 		for ( ap = a_first; *ap != NULL; ap = &(*ap)->a_next ) {
1467 			Attribute	**tap;
1468 
1469 			for ( tap = &(*ap)->a_next; *tap != NULL; ) {
1470 				if ( (*tap)->a_desc == (*ap)->a_desc ) {
1471 					Entry		e = { 0 };
1472 					Modification	mod = { 0 };
1473 					const char	*text = NULL;
1474 					char		textbuf[ SLAP_TEXT_BUFLEN ];
1475 					Attribute	*next = (*tap)->a_next;
1476 
1477 					BER_BVSTR( &e.e_name, "" );
1478 					BER_BVSTR( &e.e_nname, "" );
1479 					e.e_attrs = *ap;
1480 					mod.sm_op = LDAP_MOD_ADD;
1481 					mod.sm_desc = (*ap)->a_desc;
1482 					mod.sm_type = mod.sm_desc->ad_cname;
1483 					mod.sm_numvals = (*tap)->a_numvals;
1484 					mod.sm_values = (*tap)->a_vals;
1485 					if ( (*tap)->a_nvals != (*tap)->a_vals ) {
1486 						mod.sm_nvalues = (*tap)->a_nvals;
1487 					}
1488 
1489 					(void)modify_add_values( &e, &mod,
1490 						/* permissive */ 1,
1491 						&text, textbuf, sizeof( textbuf ) );
1492 
1493 					/* should not insert new attrs! */
1494 					assert( e.e_attrs == *ap );
1495 
1496 					attr_free( *tap );
1497 					*tap = next;
1498 
1499 				} else {
1500 					tap = &(*tap)->a_next;
1501 				}
1502 			}
1503 		}
1504 	}
1505 
1506 	return 0;
1507 }
1508 
1509 /* Should return SLAP_CB_CONTINUE or failure, never LDAP_SUCCESS. */
1510 static int
rwm_send_entry(Operation * op,SlapReply * rs)1511 rwm_send_entry( 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 	Entry			*e = NULL;
1518 	struct berval		dn = BER_BVNULL,
1519 				ndn = BER_BVNULL;
1520 	dncookie		dc;
1521 	int			rc;
1522 
1523 	assert( rs->sr_entry != NULL );
1524 
1525 	/*
1526 	 * Rewrite the dn of the result, if needed
1527 	 */
1528 	dc.rwmap = rwmap;
1529 	dc.conn = op->o_conn;
1530 	dc.rs = NULL;
1531 	dc.ctx = "searchEntryDN";
1532 
1533 	e = rs->sr_entry;
1534 	if ( !( rs->sr_flags & REP_ENTRY_MODIFIABLE ) ) {
1535 		/* FIXME: all we need to duplicate are:
1536 		 * - dn
1537 		 * - ndn
1538 		 * - attributes that are requested
1539 		 * - no values if attrsonly is set
1540 		 */
1541 		e = entry_dup( e );
1542 		if ( e == NULL ) {
1543 			rc = LDAP_NO_MEMORY;
1544 			goto fail;
1545 		}
1546 	} else if ( rs->sr_flags & REP_ENTRY_MUSTRELEASE ) {
1547 		/* ITS#6423: REP_ENTRY_MUSTRELEASE incompatible
1548 		 * with REP_ENTRY_MODIFIABLE */
1549 		RS_ASSERT( 0 );
1550 		rc = 1;
1551 		goto fail;
1552 	}
1553 
1554 	/*
1555 	 * Note: this may fail if the target host(s) schema differs
1556 	 * from the one known to the meta, and a DN with unknown
1557 	 * attributes is returned.
1558 	 */
1559 	dn = e->e_name;
1560 	ndn = e->e_nname;
1561 	rc = rwm_dn_massage_pretty_normalize( &dc, &e->e_name, &dn, &ndn );
1562 	if ( rc != LDAP_SUCCESS ) {
1563 		rc = 1;
1564 		goto fail;
1565 	}
1566 
1567 	if ( e->e_name.bv_val != dn.bv_val ) {
1568 		ch_free( e->e_name.bv_val );
1569 		ch_free( e->e_nname.bv_val );
1570 
1571 		e->e_name = dn;
1572 		e->e_nname = ndn;
1573 	}
1574 
1575 	/* TODO: map entry attribute types, objectclasses
1576 	 * and dn-valued attribute values */
1577 
1578 	/* FIXME: the entries are in the remote mapping form;
1579 	 * so we need to select those attributes we are willing
1580 	 * to return, and remap them accordingly */
1581 	(void)rwm_attrs( op, rs, &e->e_attrs, 1 );
1582 
1583 	if ( e != rs->sr_entry ) {
1584 		/* Reimplementing rs_replace_entry(), I suppose to
1585 		 * bypass our own dubious rwm_entry_release_rw() */
1586 		if ( rs->sr_flags & REP_ENTRY_MUSTRELEASE ) {
1587 			rs->sr_flags ^= REP_ENTRY_MUSTRELEASE;
1588 			op->o_bd->bd_info = (BackendInfo *)on->on_info;
1589 			be_entry_release_r( op, rs->sr_entry );
1590 			op->o_bd->bd_info = (BackendInfo *)on;
1591 		} else if ( rs->sr_flags & REP_ENTRY_MUSTBEFREED ) {
1592 			entry_free( rs->sr_entry );
1593 		}
1594 		rs->sr_entry = e;
1595 		rs->sr_flags |= REP_ENTRY_MODIFIABLE | REP_ENTRY_MUSTBEFREED;
1596 	}
1597 
1598 	return SLAP_CB_CONTINUE;
1599 
1600 fail:;
1601 	if ( e != NULL && e != rs->sr_entry ) {
1602 		if ( e->e_name.bv_val == dn.bv_val ) {
1603 			BER_BVZERO( &e->e_name );
1604 		}
1605 
1606 		if ( e->e_nname.bv_val == ndn.bv_val ) {
1607 			BER_BVZERO( &e->e_nname );
1608 		}
1609 
1610 		entry_free( e );
1611 	}
1612 
1613 	if ( !BER_BVISNULL( &dn ) ) {
1614 		ch_free( dn.bv_val );
1615 	}
1616 
1617 	if ( !BER_BVISNULL( &ndn ) ) {
1618 		ch_free( ndn.bv_val );
1619 	}
1620 
1621 	return rc;
1622 }
1623 
1624 static int
rwm_operational(Operation * op,SlapReply * rs)1625 rwm_operational( Operation *op, SlapReply *rs )
1626 {
1627 	/* FIXME: the entries are in the remote mapping form;
1628 	 * so we need to select those attributes we are willing
1629 	 * to return, and remap them accordingly */
1630 	if ( rs->sr_operational_attrs ) {
1631 		rwm_attrs( op, rs, &rs->sr_operational_attrs, 1 );
1632 	}
1633 
1634 	return SLAP_CB_CONTINUE;
1635 }
1636 
1637 #if 0
1638 /* don't use this; it cannot be reverted, and leaves op->o_req_dn
1639  * rewritten for subsequent operations; fine for plain suffixmassage,
1640  * but destroys everything else */
1641 static int
1642 rwm_chk_referrals( Operation *op, SlapReply *rs )
1643 {
1644 	slap_overinst		*on = (slap_overinst *) op->o_bd->bd_info;
1645 	int			rc;
1646 
1647 	rc = rwm_op_dn_massage( op, rs, "referralCheckDN" );
1648 	if ( rc != LDAP_SUCCESS ) {
1649 		op->o_bd->bd_info = (BackendInfo *)on->on_info;
1650 		send_ldap_error( op, rs, rc, "referralCheckDN massage error" );
1651 		return -1;
1652 	}
1653 
1654 	return SLAP_CB_CONTINUE;
1655 }
1656 #endif
1657 
1658 static int
rwm_rw_config(BackendDB * be,const char * fname,int lineno,int argc,char ** argv)1659 rwm_rw_config(
1660 	BackendDB	*be,
1661 	const char	*fname,
1662 	int		lineno,
1663 	int		argc,
1664 	char		**argv )
1665 {
1666 	slap_overinst		*on = (slap_overinst *) be->bd_info;
1667 	struct ldaprwmap	*rwmap =
1668 			(struct ldaprwmap *)on->on_bi.bi_private;
1669 
1670 	return rewrite_parse( rwmap->rwm_rw,
1671 				fname, lineno, argc, argv );
1672 
1673 	return 0;
1674 }
1675 
1676 static int
rwm_suffixmassage_config(BackendDB * be,const char * fname,int lineno,int argc,char ** argv)1677 rwm_suffixmassage_config(
1678 	BackendDB	*be,
1679 	const char	*fname,
1680 	int		lineno,
1681 	int		argc,
1682 	char		**argv )
1683 {
1684 	slap_overinst		*on = (slap_overinst *) be->bd_info;
1685 	struct ldaprwmap	*rwmap =
1686 			(struct ldaprwmap *)on->on_bi.bi_private;
1687 
1688 	struct berval		bvnc, nvnc, pvnc, brnc, nrnc, prnc;
1689 	int			massaged;
1690 	int			rc;
1691 
1692 	/*
1693 	 * syntax:
1694 	 *
1695 	 * 	suffixmassage [<suffix>] <massaged suffix>
1696 	 *
1697 	 * the [<suffix>] field must be defined as a valid suffix
1698 	 * for the current database;
1699 	 * the <massaged suffix> shouldn't have already been
1700 	 * defined as a valid suffix for the current server
1701 	 */
1702 	if ( argc == 2 ) {
1703 		if ( be->be_suffix == NULL ) {
1704  			Debug( LDAP_DEBUG_ANY, "%s: line %d: "
1705 				       " \"suffixMassage [<suffix>]"
1706 				       " <massaged suffix>\" without "
1707 				       "<suffix> part requires database "
1708 				       "suffix be defined first.\n",
1709 				fname, lineno );
1710 			return 1;
1711 		}
1712 		bvnc = be->be_suffix[ 0 ];
1713 		massaged = 1;
1714 
1715 	} else if ( argc == 3 ) {
1716 		ber_str2bv( argv[ 1 ], 0, 0, &bvnc );
1717 		massaged = 2;
1718 
1719 	} else  {
1720  		Debug( LDAP_DEBUG_ANY, "%s: line %d: syntax is"
1721 			       " \"suffixMassage [<suffix>]"
1722 			       " <massaged suffix>\"\n",
1723 			fname, lineno );
1724 		return 1;
1725 	}
1726 
1727 	if ( dnPrettyNormal( NULL, &bvnc, &pvnc, &nvnc, NULL ) != LDAP_SUCCESS ) {
1728 		Debug( LDAP_DEBUG_ANY, "%s: line %d: suffix DN %s is invalid\n",
1729 			fname, lineno, bvnc.bv_val );
1730 		return 1;
1731 	}
1732 
1733 	ber_str2bv( argv[ massaged ], 0, 0, &brnc );
1734 	if ( dnPrettyNormal( NULL, &brnc, &prnc, &nrnc, NULL ) != LDAP_SUCCESS ) {
1735 		Debug( LDAP_DEBUG_ANY, "%s: line %d: suffix DN %s is invalid\n",
1736 				fname, lineno, brnc.bv_val );
1737 		free( nvnc.bv_val );
1738 		free( pvnc.bv_val );
1739 		return 1;
1740 	}
1741 
1742 	/*
1743 	 * The suffix massaging is emulated
1744 	 * by means of the rewrite capabilities
1745 	 */
1746  	rc = rwm_suffix_massage_config( rwmap->rwm_rw,
1747 			&pvnc, &nvnc, &prnc, &nrnc );
1748 	free( nvnc.bv_val );
1749 	free( pvnc.bv_val );
1750 	free( nrnc.bv_val );
1751 	free( prnc.bv_val );
1752 
1753 	return rc;
1754 }
1755 
1756 static int
rwm_m_config(BackendDB * be,const char * fname,int lineno,int argc,char ** argv)1757 rwm_m_config(
1758 	BackendDB	*be,
1759 	const char	*fname,
1760 	int		lineno,
1761 	int		argc,
1762 	char		**argv )
1763 {
1764 	slap_overinst		*on = (slap_overinst *) be->bd_info;
1765 	struct ldaprwmap	*rwmap =
1766 			(struct ldaprwmap *)on->on_bi.bi_private;
1767 
1768 	/* objectclass/attribute mapping */
1769 	return rwm_map_config( &rwmap->rwm_oc,
1770 			&rwmap->rwm_at,
1771 			fname, lineno, argc, argv );
1772 }
1773 
1774 static int
rwm_response(Operation * op,SlapReply * rs)1775 rwm_response( Operation *op, SlapReply *rs )
1776 {
1777 	slap_overinst		*on = (slap_overinst *)op->o_bd->bd_info;
1778 	struct ldaprwmap	*rwmap =
1779 			(struct ldaprwmap *)on->on_bi.bi_private;
1780 
1781 	int		rc;
1782 
1783 	if ( op->o_tag == LDAP_REQ_SEARCH && rs->sr_type == REP_SEARCH ) {
1784 		return rwm_send_entry( op, rs );
1785 	}
1786 
1787 	switch( op->o_tag ) {
1788 	case LDAP_REQ_SEARCH:
1789 	case LDAP_REQ_BIND:
1790 	case LDAP_REQ_ADD:
1791 	case LDAP_REQ_DELETE:
1792 	case LDAP_REQ_MODRDN:
1793 	case LDAP_REQ_MODIFY:
1794 	case LDAP_REQ_COMPARE:
1795 	case LDAP_REQ_EXTENDED:
1796 		if ( rs->sr_ref ) {
1797 			dncookie		dc;
1798 
1799 			/*
1800 			 * Rewrite the dn of the referrals, if needed
1801 			 */
1802 			dc.rwmap = rwmap;
1803 			dc.conn = op->o_conn;
1804 			dc.rs = NULL;
1805 			dc.ctx = "referralDN";
1806 			rc = rwm_referral_result_rewrite( &dc, rs->sr_ref );
1807 			/* FIXME: impossible, so far */
1808 			if ( rc != LDAP_SUCCESS ) {
1809 				rs->sr_err = rc;
1810 				break;
1811 			}
1812 		}
1813 
1814 		rwm_matched( op, rs );
1815 		break;
1816 	}
1817 
1818 	return SLAP_CB_CONTINUE;
1819 }
1820 
1821 static int
rwm_db_config(BackendDB * be,const char * fname,int lineno,int argc,char ** argv)1822 rwm_db_config(
1823 	BackendDB	*be,
1824 	const char	*fname,
1825 	int		lineno,
1826 	int		argc,
1827 	char		**argv )
1828 {
1829 	slap_overinst		*on = (slap_overinst *) be->bd_info;
1830 	struct ldaprwmap	*rwmap =
1831 			(struct ldaprwmap *)on->on_bi.bi_private;
1832 
1833 	int		rc = 0;
1834 	char		*argv0 = NULL;
1835 
1836 	if ( strncasecmp( argv[ 0 ], "rwm-", STRLENOF( "rwm-" ) ) == 0 ) {
1837 		argv0 = argv[ 0 ];
1838 		argv[ 0 ] = &argv0[ STRLENOF( "rwm-" ) ];
1839 	}
1840 
1841 	if ( strncasecmp( argv[0], "rewrite", STRLENOF("rewrite") ) == 0 ) {
1842 		rc = rwm_rw_config( be, fname, lineno, argc, argv );
1843 
1844 	} else if ( strcasecmp( argv[0], "map" ) == 0 ) {
1845 		rc = rwm_m_config( be, fname, lineno, argc, argv );
1846 
1847 	} else if ( strcasecmp( argv[0], "suffixmassage" ) == 0 ) {
1848 		rc = rwm_suffixmassage_config( be, fname, lineno, argc, argv );
1849 
1850 	} else if ( strcasecmp( argv[0], "t-f-support" ) == 0 ) {
1851 		if ( argc != 2 ) {
1852 			Debug( LDAP_DEBUG_ANY,
1853 		"%s: line %d: \"t-f-support {no|yes|discover}\" needs 1 argument.\n",
1854 					fname, lineno );
1855 			return( 1 );
1856 		}
1857 
1858 		if ( strcasecmp( argv[ 1 ], "no" ) == 0 ) {
1859 			rwmap->rwm_flags &= ~(RWM_F_SUPPORT_T_F_MASK2);
1860 
1861 		} else if ( strcasecmp( argv[ 1 ], "yes" ) == 0 ) {
1862 			rwmap->rwm_flags |= RWM_F_SUPPORT_T_F;
1863 
1864 		/* TODO: not implemented yet */
1865 		} else if ( strcasecmp( argv[ 1 ], "discover" ) == 0 ) {
1866 			Debug( LDAP_DEBUG_ANY,
1867 		"%s: line %d: \"discover\" not supported yet "
1868 		"in \"t-f-support {no|yes|discover}\".\n",
1869 					fname, lineno );
1870 			return( 1 );
1871 #if 0
1872 			rwmap->rwm_flags |= RWM_F_SUPPORT_T_F_DISCOVER;
1873 #endif
1874 
1875 		} else {
1876 			Debug( LDAP_DEBUG_ANY,
1877 	"%s: line %d: unknown value \"%s\" for \"t-f-support {no|yes|discover}\".\n",
1878 				fname, lineno, argv[ 1 ] );
1879 			return 1;
1880 		}
1881 
1882 	} else if ( strcasecmp( argv[0], "normalize-mapped-attrs" ) ==  0 ) {
1883 		if ( argc !=2 ) {
1884 			Debug( LDAP_DEBUG_ANY,
1885 		"%s: line %d: \"normalize-mapped-attrs {no|yes}\" needs 1 argument.\n",
1886 					fname, lineno );
1887 			return( 1 );
1888 		}
1889 
1890 		if ( strcasecmp( argv[ 1 ], "no" ) == 0 ) {
1891 			rwmap->rwm_flags &= ~(RWM_F_NORMALIZE_MAPPED_ATTRS);
1892 
1893 		} else if ( strcasecmp( argv[ 1 ], "yes" ) == 0 ) {
1894 			rwmap->rwm_flags |= RWM_F_NORMALIZE_MAPPED_ATTRS;
1895 		}
1896 
1897 	} else {
1898 		rc = SLAP_CONF_UNKNOWN;
1899 	}
1900 
1901 	if ( argv0 ) {
1902 		argv[ 0 ] = argv0;
1903 	}
1904 
1905 	return rc;
1906 }
1907 
1908 /*
1909  * dynamic configuration...
1910  */
1911 
1912 enum {
1913 	/* rewrite */
1914 	RWM_CF_REWRITE = 1,
1915 
1916 	/* map */
1917 	RWM_CF_MAP,
1918 	RWM_CF_T_F_SUPPORT,
1919 	RWM_CF_NORMALIZE_MAPPED,
1920 	RWM_CF_DROP_UNREQUESTED,
1921 
1922 	RWM_CF_LAST
1923 };
1924 
1925 static slap_verbmasks t_f_mode[] = {
1926 	{ BER_BVC( "true" ),		RWM_F_SUPPORT_T_F },
1927 	{ BER_BVC( "yes" ),		RWM_F_SUPPORT_T_F },
1928 	{ BER_BVC( "discover" ),	RWM_F_SUPPORT_T_F_DISCOVER },
1929 	{ BER_BVC( "false" ),		RWM_F_NONE },
1930 	{ BER_BVC( "no" ),		RWM_F_NONE },
1931 	{ BER_BVNULL,			0 }
1932 };
1933 
1934 static ConfigDriver rwm_cf_gen;
1935 
1936 static ConfigTable rwmcfg[] = {
1937 	{ "rwm-rewrite", "rewrite",
1938 		2, 0, STRLENOF("rwm-rewrite"),
1939 		ARG_MAGIC|RWM_CF_REWRITE, rwm_cf_gen,
1940 		"( OLcfgOvAt:16.1 NAME 'olcRwmRewrite' "
1941 			"DESC 'Rewrites strings' "
1942 			"EQUALITY caseIgnoreMatch "
1943 			"SYNTAX OMsDirectoryString "
1944 			"X-ORDERED 'VALUES' )",
1945 		NULL, NULL },
1946 
1947 	{ "rwm-suffixmassage", "[virtual]> <real",
1948 		2, 3, 0, ARG_MAGIC|RWM_CF_REWRITE, rwm_cf_gen,
1949 		NULL, NULL, NULL },
1950 
1951 	{ "rwm-t-f-support", "true|false|discover",
1952 		2, 2, 0, ARG_MAGIC|RWM_CF_T_F_SUPPORT, rwm_cf_gen,
1953 		"( OLcfgOvAt:16.2 NAME 'olcRwmTFSupport' "
1954 			"DESC 'Absolute filters support' "
1955 			"EQUALITY caseIgnoreMatch "
1956 			"SYNTAX OMsDirectoryString "
1957 			"SINGLE-VALUE )",
1958 		NULL, NULL },
1959 
1960 	{ "rwm-map", "{objectClass|attribute}",
1961 		2, 4, 0, ARG_MAGIC|RWM_CF_MAP, rwm_cf_gen,
1962 		"( OLcfgOvAt:16.3 NAME 'olcRwmMap' "
1963 			"DESC 'maps attributes/objectClasses' "
1964 			"EQUALITY caseIgnoreMatch "
1965 			"SYNTAX OMsDirectoryString "
1966 			"X-ORDERED 'VALUES' )",
1967 		NULL, NULL },
1968 
1969 	{ "rwm-normalize-mapped-attrs", "true|false",
1970 		2, 2, 0, ARG_MAGIC|ARG_ON_OFF|RWM_CF_NORMALIZE_MAPPED, rwm_cf_gen,
1971 		"( OLcfgOvAt:16.4 NAME 'olcRwmNormalizeMapped' "
1972 			"DESC 'Normalize mapped attributes/objectClasses' "
1973 			"EQUALITY booleanMatch "
1974 			"SYNTAX OMsBoolean "
1975 			"SINGLE-VALUE )",
1976 		NULL, NULL },
1977 
1978 	{ "rwm-drop-unrequested-attrs", "true|false",
1979 		2, 2, 0, ARG_MAGIC|ARG_ON_OFF|RWM_CF_DROP_UNREQUESTED, rwm_cf_gen,
1980 		"( OLcfgOvAt:16.5 NAME 'olcRwmDropUnrequested' "
1981 			"DESC 'Drop unrequested attributes' "
1982 			"EQUALITY booleanMatch "
1983 			"SYNTAX OMsBoolean "
1984 			"SINGLE-VALUE )",
1985 		NULL, NULL },
1986 
1987 	{ NULL, NULL, 0, 0, 0, ARG_IGNORED }
1988 };
1989 
1990 static ConfigOCs rwmocs[] = {
1991 	{ "( OLcfgOvOc:16.1 "
1992 		"NAME 'olcRwmConfig' "
1993 		"DESC 'Rewrite/remap configuration' "
1994 		"SUP olcOverlayConfig "
1995 		"MAY ( "
1996 			"olcRwmRewrite $ "
1997 			"olcRwmTFSupport $ "
1998 			"olcRwmMap $ "
1999 			"olcRwmNormalizeMapped $ "
2000 			"olcRwmDropUnrequested"
2001 			") )",
2002 		Cft_Overlay, rwmcfg, NULL, NULL },
2003 	{ NULL, 0, NULL }
2004 };
2005 
2006 static int
rwm_bva_add(BerVarray * bva,int idx,char ** argv)2007 rwm_bva_add(
2008 	BerVarray		*bva,
2009 	int			idx,
2010 	char			**argv )
2011 {
2012 	char		*line;
2013 	struct berval	bv;
2014 
2015 	line = ldap_charray2str( argv, "\" \"" );
2016 	if ( line != NULL ) {
2017 		int	len = strlen( argv[ 0 ] );
2018 
2019 		ber_str2bv( line, 0, 0, &bv );
2020 		AC_MEMCPY( &bv.bv_val[ len ], &bv.bv_val[ len + 1 ],
2021 			bv.bv_len - ( len + 1 ) );
2022 		bv.bv_val[ bv.bv_len - 1 ] = '"';
2023 
2024 		if ( idx == -1 ) {
2025 			ber_bvarray_add( bva, &bv );
2026 
2027 		} else {
2028 			(*bva)[ idx ] = bv;
2029 		}
2030 
2031 		return 0;
2032 	}
2033 
2034 	return -1;
2035 }
2036 
2037 static int
rwm_bva_rewrite_add(struct ldaprwmap * rwmap,int idx,char ** argv)2038 rwm_bva_rewrite_add(
2039 	struct ldaprwmap	*rwmap,
2040 	int			idx,
2041 	char			**argv )
2042 {
2043 	return rwm_bva_add( &rwmap->rwm_bva_rewrite, idx, argv );
2044 }
2045 
2046 #ifdef unused
2047 static int
rwm_bva_map_add(struct ldaprwmap * rwmap,int idx,char ** argv)2048 rwm_bva_map_add(
2049 	struct ldaprwmap	*rwmap,
2050 	int			idx,
2051 	char			**argv )
2052 {
2053 	return rwm_bva_add( &rwmap->rwm_bva_map, idx, argv );
2054 }
2055 #endif /* unused */
2056 
2057 static int
rwm_info_init(struct rewrite_info ** rwm_rw)2058 rwm_info_init( struct rewrite_info ** rwm_rw )
2059 {
2060 	char			*rargv[ 3 ];
2061 
2062  	*rwm_rw = rewrite_info_init( REWRITE_MODE_USE_DEFAULT );
2063 	if ( *rwm_rw == NULL ) {
2064  		return -1;
2065  	}
2066 
2067 	/* this rewriteContext by default must be null;
2068 	 * rules can be added if required */
2069 	rargv[ 0 ] = "rewriteContext";
2070 	rargv[ 1 ] = "searchFilter";
2071 	rargv[ 2 ] = NULL;
2072 	rewrite_parse( *rwm_rw, "<suffix massage>", 1, 2, rargv );
2073 
2074 	rargv[ 0 ] = "rewriteContext";
2075 	rargv[ 1 ] = "default";
2076 	rargv[ 2 ] = NULL;
2077 	rewrite_parse( *rwm_rw, "<suffix massage>", 2, 2, rargv );
2078 
2079 	return 0;
2080 }
2081 
2082 static int
rwm_cf_gen(ConfigArgs * c)2083 rwm_cf_gen( ConfigArgs *c )
2084 {
2085 	slap_overinst		*on = (slap_overinst *)c->bi;
2086 	struct ldaprwmap	*rwmap =
2087 			(struct ldaprwmap *)on->on_bi.bi_private;
2088 
2089 	BackendDB		db;
2090 	char			*argv0;
2091 	int			idx0 = 0;
2092 	int			rc = 0;
2093 
2094 	db = *c->be;
2095 	db.bd_info = c->bi;
2096 
2097 	if ( c->op == SLAP_CONFIG_EMIT ) {
2098 		struct berval	bv = BER_BVNULL;
2099 
2100 		switch ( c->type ) {
2101 		case RWM_CF_REWRITE:
2102 			if ( rwmap->rwm_bva_rewrite == NULL ) {
2103 				rc = 1;
2104 
2105 			} else {
2106 				rc = slap_bv_x_ordered_unparse( rwmap->rwm_bva_rewrite, &c->rvalue_vals );
2107 			}
2108 			break;
2109 
2110 		case RWM_CF_T_F_SUPPORT:
2111 			enum_to_verb( t_f_mode, (rwmap->rwm_flags & RWM_F_SUPPORT_T_F_MASK2), &bv );
2112 			if ( BER_BVISNULL( &bv ) ) {
2113 				/* there's something wrong... */
2114 				assert( 0 );
2115 				rc = 1;
2116 
2117 			} else {
2118 				value_add_one( &c->rvalue_vals, &bv );
2119 			}
2120 			break;
2121 
2122 		case RWM_CF_MAP:
2123 			if ( rwmap->rwm_bva_map == NULL ) {
2124 				rc = 1;
2125 
2126 			} else {
2127 				slap_bv_x_ordered_unparse( rwmap->rwm_bva_map, &c->rvalue_vals );
2128 				if ( !c->rvalue_vals ) {
2129 					rc = 1;
2130 				}
2131 			}
2132 			break;
2133 
2134 		case RWM_CF_NORMALIZE_MAPPED:
2135 			c->value_int = ( rwmap->rwm_flags & RWM_F_NORMALIZE_MAPPED_ATTRS );
2136 			break;
2137 
2138 		case RWM_CF_DROP_UNREQUESTED:
2139 			c->value_int = ( rwmap->rwm_flags & RWM_F_DROP_UNREQUESTED_ATTRS );
2140 			break;
2141 
2142 		default:
2143 			assert( 0 );
2144 			rc = 1;
2145 		}
2146 
2147 		return rc;
2148 
2149 	} else if ( c->op == LDAP_MOD_DELETE ) {
2150 		switch ( c->type ) {
2151 		case RWM_CF_REWRITE:
2152 			if ( c->valx >= 0 ) {
2153 				int i;
2154 
2155 				for ( i = 0; !BER_BVISNULL( &rwmap->rwm_bva_rewrite[ i ] ); i++ )
2156 					/* count'em */ ;
2157 
2158 				if ( c->valx >= i ) {
2159 					rc = 1;
2160 					break;
2161 				}
2162 
2163 				ber_memfree( rwmap->rwm_bva_rewrite[ c->valx ].bv_val );
2164 				for ( i = c->valx; !BER_BVISNULL( &rwmap->rwm_bva_rewrite[ i + 1 ] ); i++ )
2165 				{
2166 					rwmap->rwm_bva_rewrite[ i ] = rwmap->rwm_bva_rewrite[ i + 1 ];
2167 				}
2168 				BER_BVZERO( &rwmap->rwm_bva_rewrite[ i ] );
2169 
2170 				rewrite_info_delete( &rwmap->rwm_rw );
2171 				assert( rwmap->rwm_rw == NULL );
2172 
2173 				rc = rwm_info_init( &rwmap->rwm_rw );
2174 
2175 				for ( i = 0; !BER_BVISNULL( &rwmap->rwm_bva_rewrite[ i ] ); i++ )
2176 				{
2177 					ConfigArgs ca = { 0 };
2178 
2179 					ca.line = rwmap->rwm_bva_rewrite[ i ].bv_val;
2180 					ca.argc = 0;
2181 					init_config_argv( &ca );
2182 					config_parse_ldif( &ca );
2183 
2184 					argv0 = ca.argv[ 0 ];
2185 					ca.argv[ 0 ] += STRLENOF( "rwm-" );
2186 
2187 					if ( strcasecmp( ca.argv[ 0 ], "suffixmassage" ) == 0 ) {
2188 						rc = rwm_suffixmassage_config( &db, c->fname, c->lineno,
2189 							ca.argc, ca.argv );
2190 
2191 					} else {
2192 						rc = rwm_rw_config( &db, c->fname, c->lineno,
2193 							ca.argc, ca.argv );
2194 					}
2195 
2196 					ca.argv[ 0 ] = argv0;
2197 
2198 					ch_free( ca.tline );
2199 					ch_free( ca.argv );
2200 
2201 					assert( rc == 0 );
2202 				}
2203 
2204 			} else if ( rwmap->rwm_rw != NULL ) {
2205 				rewrite_info_delete( &rwmap->rwm_rw );
2206 				assert( rwmap->rwm_rw == NULL );
2207 
2208 				ber_bvarray_free( rwmap->rwm_bva_rewrite );
2209 				rwmap->rwm_bva_rewrite = NULL;
2210 
2211 				rc = rwm_info_init( &rwmap->rwm_rw );
2212 			}
2213 			break;
2214 
2215 		case RWM_CF_T_F_SUPPORT:
2216 			rwmap->rwm_flags &= ~RWM_F_SUPPORT_T_F_MASK2;
2217 			break;
2218 
2219 		case RWM_CF_MAP:
2220 			if ( c->valx >= 0 ) {
2221 				struct ldapmap rwm_oc = rwmap->rwm_oc;
2222 				struct ldapmap rwm_at = rwmap->rwm_at;
2223 				char *argv[5];
2224 				int cnt = 0;
2225 
2226 				if ( rwmap->rwm_bva_map ) {
2227 					for ( ; !BER_BVISNULL( &rwmap->rwm_bva_map[ cnt ] ); cnt++ )
2228 						/* count */ ;
2229 				}
2230 
2231 				if ( c->valx >= cnt ) {
2232 					rc = 1;
2233 					break;
2234 				}
2235 
2236 				memset( &rwmap->rwm_oc, 0, sizeof( rwmap->rwm_oc ) );
2237 				memset( &rwmap->rwm_at, 0, sizeof( rwmap->rwm_at ) );
2238 
2239 				/* re-parse all mappings except the one
2240 				 * that needs to be eliminated */
2241 				argv[0] = "map";
2242 				for ( cnt = 0; !BER_BVISNULL( &rwmap->rwm_bva_map[ cnt ] ); cnt++ ) {
2243 					ConfigArgs ca = { 0 };
2244 
2245 					if ( cnt == c->valx ) {
2246 						continue;
2247 					}
2248 
2249 					ca.line = rwmap->rwm_bva_map[ cnt ].bv_val;
2250 					ca.argc = 0;
2251 					init_config_argv( &ca );
2252 					config_parse_ldif( &ca );
2253 
2254 					argv[1] = ca.argv[0];
2255 					argv[2] = ca.argv[1];
2256 					argv[3] = ca.argv[2];
2257 					argv[4] = ca.argv[3];
2258 
2259 					rc = rwm_m_config( &db, c->fname, c->lineno, ca.argc + 1, argv );
2260 
2261 					ch_free( ca.tline );
2262 					ch_free( ca.argv );
2263 
2264 					/* in case of failure, restore
2265 					 * the existing mapping */
2266 					if ( rc ) {
2267 						ldap_avl_free( rwmap->rwm_oc.remap, rwm_mapping_dst_free );
2268 						ldap_avl_free( rwmap->rwm_oc.map, rwm_mapping_free );
2269 						ldap_avl_free( rwmap->rwm_at.remap, rwm_mapping_dst_free );
2270 						ldap_avl_free( rwmap->rwm_at.map, rwm_mapping_free );
2271 						rwmap->rwm_oc = rwm_oc;
2272 						rwmap->rwm_at = rwm_at;
2273 						break;
2274 					}
2275 				}
2276 
2277 				/* in case of success, destroy the old mapping
2278 				 * and eliminate the deleted one */
2279 				if ( rc == 0 ) {
2280 					ldap_avl_free( rwm_oc.remap, rwm_mapping_dst_free );
2281 					ldap_avl_free( rwm_oc.map, rwm_mapping_free );
2282 					ldap_avl_free( rwm_at.remap, rwm_mapping_dst_free );
2283 					ldap_avl_free( rwm_at.map, rwm_mapping_free );
2284 
2285 					ber_memfree( rwmap->rwm_bva_map[ c->valx ].bv_val );
2286 					for ( cnt = c->valx; !BER_BVISNULL( &rwmap->rwm_bva_map[ cnt ] ); cnt++ ) {
2287 						rwmap->rwm_bva_map[ cnt ] = rwmap->rwm_bva_map[ cnt + 1 ];
2288 					}
2289 				}
2290 
2291 			} else {
2292 				ldap_avl_free( rwmap->rwm_oc.remap, rwm_mapping_dst_free );
2293 				ldap_avl_free( rwmap->rwm_oc.map, rwm_mapping_free );
2294 				ldap_avl_free( rwmap->rwm_at.remap, rwm_mapping_dst_free );
2295 				ldap_avl_free( rwmap->rwm_at.map, rwm_mapping_free );
2296 
2297 				rwmap->rwm_oc.remap = NULL;
2298 				rwmap->rwm_oc.map = NULL;
2299 				rwmap->rwm_at.remap = NULL;
2300 				rwmap->rwm_at.map = NULL;
2301 
2302 				ber_bvarray_free( rwmap->rwm_bva_map );
2303 				rwmap->rwm_bva_map = NULL;
2304 			}
2305 			break;
2306 
2307 		case RWM_CF_NORMALIZE_MAPPED:
2308 			rwmap->rwm_flags &= ~RWM_F_NORMALIZE_MAPPED_ATTRS;
2309 			break;
2310 
2311 		case RWM_CF_DROP_UNREQUESTED:
2312 			rwmap->rwm_flags &= ~RWM_F_DROP_UNREQUESTED_ATTRS;
2313 			break;
2314 
2315 		default:
2316 			return 1;
2317 		}
2318 		return rc;
2319 	}
2320 
2321 	if ( strncasecmp( c->argv[ 0 ], "olcRwm", STRLENOF( "olcRwm" ) ) == 0 ) {
2322 		idx0 = 1;
2323 	}
2324 
2325 	switch ( c->type ) {
2326 	case RWM_CF_REWRITE:
2327 		if ( c->valx >= 0 ) {
2328 			struct rewrite_info *rwm_rw = rwmap->rwm_rw;
2329 			int i, last;
2330 
2331 			for ( last = 0; rwmap->rwm_bva_rewrite && !BER_BVISNULL( &rwmap->rwm_bva_rewrite[ last ] ); last++ )
2332 				/* count'em */ ;
2333 
2334 			if ( c->valx > last ) {
2335 				c->valx = last;
2336 			}
2337 
2338 			rwmap->rwm_rw = NULL;
2339 			rc = rwm_info_init( &rwmap->rwm_rw );
2340 
2341 			for ( i = 0; i < c->valx; i++ ) {
2342 				ConfigArgs ca = { 0 };
2343 
2344 				ca.line = rwmap->rwm_bva_rewrite[ i ].bv_val;
2345 				ca.argc = 0;
2346 				init_config_argv( &ca );
2347 				config_parse_ldif( &ca );
2348 
2349 				argv0 = ca.argv[ 0 ];
2350 				ca.argv[ 0 ] += STRLENOF( "rwm-" );
2351 
2352 				if ( strcasecmp( ca.argv[ 0 ], "suffixmassage" ) == 0 ) {
2353 					rc = rwm_suffixmassage_config( &db, c->fname, c->lineno,
2354 						ca.argc, ca.argv );
2355 
2356 				} else {
2357 					rc = rwm_rw_config( &db, c->fname, c->lineno,
2358 						ca.argc, ca.argv );
2359 				}
2360 
2361 				ca.argv[ 0 ] = argv0;
2362 
2363 				ch_free( ca.tline );
2364 				ch_free( ca.argv );
2365 
2366 				assert( rc == 0 );
2367 			}
2368 
2369 			argv0 = c->argv[ idx0 ];
2370 			if ( strncasecmp( argv0, "rwm-", STRLENOF( "rwm-" ) ) != 0 ) {
2371 				return 1;
2372 			}
2373 			c->argv[ idx0 ] += STRLENOF( "rwm-" );
2374 			if ( strcasecmp( c->argv[ idx0 ], "suffixmassage" ) == 0 ) {
2375 				rc = rwm_suffixmassage_config( &db, c->fname, c->lineno,
2376 					c->argc - idx0, &c->argv[ idx0 ] );
2377 
2378 			} else {
2379 				rc = rwm_rw_config( &db, c->fname, c->lineno,
2380 					c->argc - idx0, &c->argv[ idx0 ] );
2381 			}
2382 			c->argv[ idx0 ] = argv0;
2383 			if ( rc != 0 ) {
2384 				rewrite_info_delete( &rwmap->rwm_rw );
2385 				assert( rwmap->rwm_rw == NULL );
2386 
2387 				rwmap->rwm_rw = rwm_rw;
2388 				return 1;
2389 			}
2390 
2391 			for ( i = c->valx; rwmap->rwm_bva_rewrite && !BER_BVISNULL( &rwmap->rwm_bva_rewrite[ i ] ); i++ )
2392 			{
2393 				ConfigArgs ca = { 0 };
2394 
2395 				ca.line = rwmap->rwm_bva_rewrite[ i ].bv_val;
2396 				ca.argc = 0;
2397 				init_config_argv( &ca );
2398 				config_parse_ldif( &ca );
2399 
2400 				argv0 = ca.argv[ 0 ];
2401 				ca.argv[ 0 ] += STRLENOF( "rwm-" );
2402 
2403 				if ( strcasecmp( ca.argv[ 0 ], "suffixmassage" ) == 0 ) {
2404 					rc = rwm_suffixmassage_config( &db, c->fname, c->lineno,
2405 						ca.argc, ca.argv );
2406 
2407 				} else {
2408 					rc = rwm_rw_config( &db, c->fname, c->lineno,
2409 						ca.argc, ca.argv );
2410 				}
2411 
2412 				ca.argv[ 0 ] = argv0;
2413 
2414 				ch_free( ca.tline );
2415 				ch_free( ca.argv );
2416 
2417 				assert( rc == 0 );
2418 			}
2419 
2420 			rwmap->rwm_bva_rewrite = ch_realloc( rwmap->rwm_bva_rewrite,
2421 				( last + 2 )*sizeof( struct berval ) );
2422 			BER_BVZERO( &rwmap->rwm_bva_rewrite[last+1] );
2423 
2424 			for ( i = last - 1; i >= c->valx; i-- )
2425 			{
2426 				rwmap->rwm_bva_rewrite[ i + 1 ] = rwmap->rwm_bva_rewrite[ i ];
2427 			}
2428 
2429 			rwm_bva_rewrite_add( rwmap, c->valx, &c->argv[ idx0 ] );
2430 
2431 			rewrite_info_delete( &rwm_rw );
2432 			assert( rwm_rw == NULL );
2433 
2434 			break;
2435 		}
2436 
2437 		argv0 = c->argv[ idx0 ];
2438 		if ( strncasecmp( argv0, "rwm-", STRLENOF( "rwm-" ) ) != 0 ) {
2439 			return 1;
2440 		}
2441 		c->argv[ idx0 ] += STRLENOF( "rwm-" );
2442 		if ( strcasecmp( c->argv[ idx0 ], "suffixmassage" ) == 0 ) {
2443 			rc = rwm_suffixmassage_config( &db, c->fname, c->lineno,
2444 				c->argc - idx0, &c->argv[ idx0 ] );
2445 
2446 		} else {
2447 			rc = rwm_rw_config( &db, c->fname, c->lineno,
2448 				c->argc - idx0, &c->argv[ idx0 ] );
2449 		}
2450 		c->argv[ idx0 ] = argv0;
2451 		if ( rc ) {
2452 			return 1;
2453 
2454 		} else {
2455 			rwm_bva_rewrite_add( rwmap, -1, &c->argv[ idx0 ] );
2456 		}
2457 		break;
2458 
2459 	case RWM_CF_T_F_SUPPORT:
2460 		rc = verb_to_mask( c->argv[ 1 ], t_f_mode );
2461 		if ( BER_BVISNULL( &t_f_mode[ rc ].word ) ) {
2462 			return 1;
2463 		}
2464 
2465 		rwmap->rwm_flags &= ~RWM_F_SUPPORT_T_F_MASK2;
2466 		rwmap->rwm_flags |= t_f_mode[ rc ].mask;
2467 		rc = 0;
2468 		break;
2469 
2470 	case RWM_CF_MAP:
2471 		if ( c->valx >= 0 ) {
2472 			struct ldapmap rwm_oc = rwmap->rwm_oc;
2473 			struct ldapmap rwm_at = rwmap->rwm_at;
2474 			char *argv[5];
2475 			int cnt = 0;
2476 
2477 			if ( rwmap->rwm_bva_map ) {
2478 				for ( ; !BER_BVISNULL( &rwmap->rwm_bva_map[ cnt ] ); cnt++ )
2479 					/* count */ ;
2480 			}
2481 
2482 			if ( c->valx >= cnt ) {
2483 				c->valx = cnt;
2484 			}
2485 
2486 			memset( &rwmap->rwm_oc, 0, sizeof( rwmap->rwm_oc ) );
2487 			memset( &rwmap->rwm_at, 0, sizeof( rwmap->rwm_at ) );
2488 
2489 			/* re-parse all mappings, including the one
2490 			 * that needs to be added */
2491 			argv[0] = "map";
2492 			for ( cnt = 0; cnt < c->valx; cnt++ ) {
2493 				ConfigArgs ca = { 0 };
2494 
2495 				ca.line = rwmap->rwm_bva_map[ cnt ].bv_val;
2496 				ca.argc = 0;
2497 				init_config_argv( &ca );
2498 				config_parse_ldif( &ca );
2499 
2500 				argv[1] = ca.argv[0];
2501 				argv[2] = ca.argv[1];
2502 				argv[3] = ca.argv[2];
2503 				argv[4] = ca.argv[3];
2504 
2505 				rc = rwm_m_config( &db, c->fname, c->lineno, ca.argc + 1, argv );
2506 
2507 				ch_free( ca.tline );
2508 				ch_free( ca.argv );
2509 
2510 				/* in case of failure, restore
2511 				 * the existing mapping */
2512 				if ( rc ) {
2513 					goto rwmmap_fail;
2514 				}
2515 			}
2516 
2517 			argv0 = c->argv[0];
2518 			c->argv[0] = "map";
2519 			rc = rwm_m_config( &db, c->fname, c->lineno, c->argc, c->argv );
2520 			c->argv[0] = argv0;
2521 			if ( rc ) {
2522 				goto rwmmap_fail;
2523 			}
2524 
2525 			if ( rwmap->rwm_bva_map ) {
2526 				for ( ; !BER_BVISNULL( &rwmap->rwm_bva_map[ cnt ] ); cnt++ ) {
2527 					ConfigArgs ca = { 0 };
2528 
2529 					ca.line = rwmap->rwm_bva_map[ cnt ].bv_val;
2530 					ca.argc = 0;
2531 					init_config_argv( &ca );
2532 					config_parse_ldif( &ca );
2533 
2534 					argv[1] = ca.argv[0];
2535 					argv[2] = ca.argv[1];
2536 					argv[3] = ca.argv[2];
2537 					argv[4] = ca.argv[3];
2538 
2539 					rc = rwm_m_config( &db, c->fname, c->lineno, ca.argc + 1, argv );
2540 
2541 					ch_free( ca.tline );
2542 					ch_free( ca.argv );
2543 
2544 					/* in case of failure, restore
2545 					 * the existing mapping */
2546 					if ( rc ) {
2547 						goto rwmmap_fail;
2548 					}
2549 				}
2550 			}
2551 
2552 			/* in case of success, destroy the old mapping
2553 			 * and add the new one */
2554 			if ( rc == 0 ) {
2555 				BerVarray tmp;
2556 				struct berval bv, *bvp = &bv;
2557 
2558 				if ( rwm_bva_add( &bvp, 0, &c->argv[ idx0 ] ) ) {
2559 					rc = 1;
2560 					goto rwmmap_fail;
2561 				}
2562 
2563 				tmp = ber_memrealloc( rwmap->rwm_bva_map,
2564 					sizeof( struct berval )*( cnt + 2 ) );
2565 				if ( tmp == NULL ) {
2566 					ber_memfree( bv.bv_val );
2567 					rc = 1;
2568 					goto rwmmap_fail;
2569 				}
2570 				rwmap->rwm_bva_map = tmp;
2571 				BER_BVZERO( &rwmap->rwm_bva_map[ cnt + 1 ] );
2572 
2573 				ldap_avl_free( rwm_oc.remap, rwm_mapping_dst_free );
2574 				ldap_avl_free( rwm_oc.map, rwm_mapping_free );
2575 				ldap_avl_free( rwm_at.remap, rwm_mapping_dst_free );
2576 				ldap_avl_free( rwm_at.map, rwm_mapping_free );
2577 
2578 				for ( ; cnt-- > c->valx; ) {
2579 					rwmap->rwm_bva_map[ cnt + 1 ] = rwmap->rwm_bva_map[ cnt ];
2580 				}
2581 				rwmap->rwm_bva_map[ c->valx ] = bv;
2582 
2583 			} else {
2584 rwmmap_fail:;
2585 				ldap_avl_free( rwmap->rwm_oc.remap, rwm_mapping_dst_free );
2586 				ldap_avl_free( rwmap->rwm_oc.map, rwm_mapping_free );
2587 				ldap_avl_free( rwmap->rwm_at.remap, rwm_mapping_dst_free );
2588 				ldap_avl_free( rwmap->rwm_at.map, rwm_mapping_free );
2589 				rwmap->rwm_oc = rwm_oc;
2590 				rwmap->rwm_at = rwm_at;
2591 			}
2592 
2593 			break;
2594 		}
2595 
2596 		argv0 = c->argv[ 0 ];
2597 		c->argv[ 0 ] += STRLENOF( "rwm-" );
2598 		rc = rwm_m_config( &db, c->fname, c->lineno, c->argc, c->argv );
2599 		c->argv[ 0 ] = argv0;
2600 		if ( rc ) {
2601 			return 1;
2602 
2603 		} else {
2604 			char		*line;
2605 			struct berval	bv;
2606 
2607 			line = ldap_charray2str( &c->argv[ 1 ], " " );
2608 			if ( line != NULL ) {
2609 				ber_str2bv( line, 0, 0, &bv );
2610 				ber_bvarray_add( &rwmap->rwm_bva_map, &bv );
2611 			}
2612 		}
2613 		break;
2614 
2615 	case RWM_CF_NORMALIZE_MAPPED:
2616 		if ( c->value_int ) {
2617 			rwmap->rwm_flags |= RWM_F_NORMALIZE_MAPPED_ATTRS;
2618 		} else {
2619 			rwmap->rwm_flags &= ~RWM_F_NORMALIZE_MAPPED_ATTRS;
2620 		}
2621 		break;
2622 
2623 	case RWM_CF_DROP_UNREQUESTED:
2624 		if ( c->value_int ) {
2625 			rwmap->rwm_flags |= RWM_F_DROP_UNREQUESTED_ATTRS;
2626 		} else {
2627 			rwmap->rwm_flags &= ~RWM_F_DROP_UNREQUESTED_ATTRS;
2628 		}
2629 		break;
2630 
2631 	default:
2632 		assert( 0 );
2633 		return 1;
2634 	}
2635 
2636 	return rc;
2637 }
2638 
2639 static int
rwm_db_init(BackendDB * be,ConfigReply * cr)2640 rwm_db_init(
2641 	BackendDB	*be,
2642 	ConfigReply	*cr )
2643 {
2644 	slap_overinst		*on = (slap_overinst *) be->bd_info;
2645 	struct ldaprwmap	*rwmap;
2646 	int			rc = 0;
2647 
2648 	rwmap = (struct ldaprwmap *)ch_calloc( 1, sizeof( struct ldaprwmap ) );
2649 
2650 	/* default */
2651 	rwmap->rwm_flags = RWM_F_DROP_UNREQUESTED_ATTRS;
2652 
2653 	rc = rwm_info_init( &rwmap->rwm_rw );
2654 
2655 	on->on_bi.bi_private = (void *)rwmap;
2656 
2657 	if ( rc ) {
2658 		(void)rwm_db_destroy( be, NULL );
2659 	}
2660 
2661 	return rc;
2662 }
2663 
2664 static int
rwm_db_destroy(BackendDB * be,ConfigReply * cr)2665 rwm_db_destroy(
2666 	BackendDB	*be,
2667 	ConfigReply	*cr )
2668 {
2669 	slap_overinst	*on = (slap_overinst *) be->bd_info;
2670 	int		rc = 0;
2671 
2672 	if ( on->on_bi.bi_private ) {
2673 		struct ldaprwmap	*rwmap =
2674 			(struct ldaprwmap *)on->on_bi.bi_private;
2675 
2676 		if ( rwmap->rwm_rw ) {
2677 			rewrite_info_delete( &rwmap->rwm_rw );
2678 			if ( rwmap->rwm_bva_rewrite )
2679 				ber_bvarray_free( rwmap->rwm_bva_rewrite );
2680 		}
2681 
2682 		ldap_avl_free( rwmap->rwm_oc.remap, rwm_mapping_dst_free );
2683 		ldap_avl_free( rwmap->rwm_oc.map, rwm_mapping_free );
2684 		ldap_avl_free( rwmap->rwm_at.remap, rwm_mapping_dst_free );
2685 		ldap_avl_free( rwmap->rwm_at.map, rwm_mapping_free );
2686 		ber_bvarray_free( rwmap->rwm_bva_map );
2687 
2688 		ch_free( rwmap );
2689 	}
2690 
2691 	return rc;
2692 }
2693 
2694 static slap_overinst rwm = { { NULL } };
2695 
2696 #if SLAPD_OVER_RWM == SLAPD_MOD_DYNAMIC
2697 static
2698 #endif /* SLAPD_OVER_RWM == SLAPD_MOD_DYNAMIC */
2699 int
rwm_initialize(void)2700 rwm_initialize( void )
2701 {
2702 	int		rc;
2703 
2704 	/* Make sure we don't exceed the bits reserved for userland */
2705 	config_check_userland( RWM_CF_LAST );
2706 
2707 	memset( &rwm, 0, sizeof( slap_overinst ) );
2708 
2709 	rwm.on_bi.bi_type = "rwm";
2710 	rwm.on_bi.bi_flags =
2711 		SLAPO_BFLAG_SINGLE |
2712 		0;
2713 
2714 	rwm.on_bi.bi_db_init = rwm_db_init;
2715 	rwm.on_bi.bi_db_config = rwm_db_config;
2716 	rwm.on_bi.bi_db_destroy = rwm_db_destroy;
2717 
2718 	rwm.on_bi.bi_op_bind = rwm_op_bind;
2719 	rwm.on_bi.bi_op_search = rwm_op_search;
2720 	rwm.on_bi.bi_op_compare = rwm_op_compare;
2721 	rwm.on_bi.bi_op_modify = rwm_op_modify;
2722 	rwm.on_bi.bi_op_modrdn = rwm_op_modrdn;
2723 	rwm.on_bi.bi_op_add = rwm_op_add;
2724 	rwm.on_bi.bi_op_delete = rwm_op_delete;
2725 	rwm.on_bi.bi_op_unbind = rwm_op_unbind;
2726 	rwm.on_bi.bi_extended = rwm_extended;
2727 #if 1 /* TODO */
2728 	rwm.on_bi.bi_entry_release_rw = rwm_entry_release_rw;
2729 	rwm.on_bi.bi_entry_get_rw = rwm_entry_get_rw;
2730 #endif
2731 
2732 	rwm.on_bi.bi_operational = rwm_operational;
2733 	rwm.on_bi.bi_chk_referrals = 0 /* rwm_chk_referrals */ ;
2734 
2735 	rwm.on_bi.bi_connection_init = rwm_conn_init;
2736 	rwm.on_bi.bi_connection_destroy = rwm_conn_destroy;
2737 
2738 	rwm.on_response = rwm_response;
2739 
2740 	rwm.on_bi.bi_cf_ocs = rwmocs;
2741 
2742 	rc = config_register_schema( rwmcfg, rwmocs );
2743 	if ( rc ) {
2744 		return rc;
2745 	}
2746 
2747 	return overlay_register( &rwm );
2748 }
2749 
2750 #if SLAPD_OVER_RWM == SLAPD_MOD_DYNAMIC
2751 int
init_module(int argc,char * argv[])2752 init_module( int argc, char *argv[] )
2753 {
2754 	return rwm_initialize();
2755 }
2756 #endif /* SLAPD_OVER_RWM == SLAPD_MOD_DYNAMIC */
2757 
2758 #endif /* SLAPD_OVER_RWM */
2759