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