rwm.c 49.6 KB
Newer Older
1
/* rwm.c - rewrite/remap operations */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
2
3
4
/* $OpenLDAP$ */
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
 *
Kurt Zeilenga's avatar
Kurt Zeilenga committed
5
 * Copyright 2003-2008 The OpenLDAP Foundation.
Kurt Zeilenga's avatar
Kurt Zeilenga committed
6
7
8
9
10
11
12
13
14
15
 * Portions Copyright 2003 Pierangelo Masarati.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted only as authorized by the OpenLDAP
 * Public License.
 *
 * A copy of this license is available in the file LICENSE in the
 * top-level directory of the distribution or, alternatively, at
 * <http://www.OpenLDAP.org/license.html>.
16
17
18
19
 */

#include "portable.h"

20
21
#ifdef SLAPD_OVER_RWM

22
23
#include <stdio.h>

24
25
#include <ac/string.h>

26
#include "slap.h"
27
28
#include "config.h"
#include "lutil.h"
29
30
#include "rwm.h"

31
typedef struct rwm_op_state {
Howard Chu's avatar
Howard Chu committed
32
	ber_tag_t r_tag;
33
34
35
36
	struct berval ro_dn;
	struct berval ro_ndn;
	struct berval r_dn;
	struct berval r_ndn;
37
	AttributeName *mapped_attrs;
38
39
40
	OpRequest o_request;
} rwm_op_state;

Pierangelo Masarati's avatar
Pierangelo Masarati committed
41
static int
42
rwm_db_destroy( BackendDB *be, ConfigReply *cr );
Pierangelo Masarati's avatar
Pierangelo Masarati committed
43

44
45
46
47
48
typedef struct rwm_op_cb {
	slap_callback cb;
	rwm_op_state ros;
} rwm_op_cb;

49
static int
50
51
52
53
54
rwm_op_cleanup( Operation *op, SlapReply *rs )
{
	slap_callback	*cb = op->o_callback;
	rwm_op_state *ros = cb->sc_private;

Howard Chu's avatar
Howard Chu committed
55
56
	if ( rs->sr_type == REP_RESULT || rs->sr_type == REP_EXTENDED ||
		op->o_abandon || rs->sr_err == SLAPD_ABANDON ) {
57
58
59
60

		op->o_req_dn = ros->ro_dn;
		op->o_req_ndn = ros->ro_ndn;

61
62
63
64
65
66
67
68
69
70
71
		if ( !BER_BVISNULL( &ros->r_dn )
			&& ros->r_dn.bv_val != ros->r_ndn.bv_val )
		{
			ch_free( ros->r_dn.bv_val );
			BER_BVZERO( &ros->r_dn );
		}

		if ( !BER_BVISNULL( &ros->r_ndn ) ) {
			ch_free( ros->r_ndn.bv_val );
			BER_BVZERO( &ros->r_ndn );
		}
72

Howard Chu's avatar
Howard Chu committed
73
		switch( ros->r_tag ) {
74
		case LDAP_REQ_COMPARE:
75
76
77
			if ( op->orc_ava->aa_value.bv_val != ros->orc_ava->aa_value.bv_val )
				op->o_tmpfree( op->orc_ava->aa_value.bv_val, op->o_tmpmemctx );
			op->orc_ava = ros->orc_ava;
78
79
			break;
		case LDAP_REQ_MODIFY:
80
81
			slap_mods_free( op->orm_modlist, 1 );
			op->orm_modlist = ros->orm_modlist;
82
83
84
85
86
87
88
89
90
91
92
93
			break;
		case LDAP_REQ_MODRDN:
			if ( op->orr_newSup != ros->orr_newSup ) {
				ch_free( op->orr_newSup->bv_val );
				ch_free( op->orr_nnewSup->bv_val );
				op->o_tmpfree( op->orr_newSup, op->o_tmpmemctx );
				op->o_tmpfree( op->orr_nnewSup, op->o_tmpmemctx );
				op->orr_newSup = ros->orr_newSup;
				op->orr_nnewSup = ros->orr_nnewSup;
			}
			break;
		case LDAP_REQ_SEARCH:
94
			ch_free( ros->mapped_attrs );
95
96
97
98
99
100
			filter_free_x( op, op->ors_filter );
			ch_free( op->ors_filterstr.bv_val );
			op->ors_attrs = ros->ors_attrs;
			op->ors_filter = ros->ors_filter;
			op->ors_filterstr = ros->ors_filterstr;
			break;
Howard Chu's avatar
Howard Chu committed
101
102
103
104
105
106
		case LDAP_REQ_EXTENDED:
			if ( op->ore_reqdata != ros->ore_reqdata ) {
				ber_bvfree( op->ore_reqdata );
				op->ore_reqdata = ros->ore_reqdata;
			}
			break;
107
108
		default:	break;
		}
Howard Chu's avatar
Howard Chu committed
109
110
		op->o_callback = op->o_callback->sc_next;
		op->o_tmpfree( cb, op->o_tmpmemctx );
111
112
113
114
115
116
117
118
119
120
	}

	return SLAP_CB_CONTINUE;
}

static rwm_op_cb *
rwm_callback_get( Operation *op, SlapReply *rs )
{
	rwm_op_cb	*roc = NULL;

Howard Chu's avatar
Howard Chu committed
121
	roc = op->o_tmpalloc( sizeof( struct rwm_op_cb ), op->o_tmpmemctx );
122
123
124
125
	roc->cb.sc_cleanup = rwm_op_cleanup;
	roc->cb.sc_response = NULL;
	roc->cb.sc_next = op->o_callback;
	roc->cb.sc_private = &roc->ros;
Howard Chu's avatar
Howard Chu committed
126
	roc->ros.r_tag = op->o_tag;
127
128
129
130
131
132
133
134
135
136
137
138
139
	roc->ros.ro_dn = op->o_req_dn;
	roc->ros.ro_ndn = op->o_req_ndn;
	roc->ros.o_request = op->o_request;
	BER_BVZERO( &roc->ros.r_dn );
	BER_BVZERO( &roc->ros.r_ndn );

	return roc;
}


static int
rwm_op_dn_massage( Operation *op, SlapReply *rs, void *cookie,
	rwm_op_state *ros )
140
141
142
143
144
{
	slap_overinst		*on = (slap_overinst *) op->o_bd->bd_info;
	struct ldaprwmap	*rwmap = 
			(struct ldaprwmap *)on->on_bi.bi_private;

Pierangelo Masarati's avatar
Pierangelo Masarati committed
145
146
	struct berval		dn = BER_BVNULL,
				ndn = BER_BVNULL;
147
148
149
150
	int			rc = 0;
	dncookie		dc;

	/*
151
	 * Rewrite the dn if needed
152
153
154
155
156
157
	 */
	dc.rwmap = rwmap;
	dc.conn = op->o_conn;
	dc.rs = rs;
	dc.ctx = (char *)cookie;

158
159
160
161
	/* NOTE: in those cases where only the ndn is available,
	 * and the caller sets op->o_req_dn = op->o_req_ndn,
	 * only rewrite the op->o_req_ndn and use it as 
	 * op->o_req_dn as well */
162
	ndn = op->o_req_ndn;
163
	if ( op->o_req_dn.bv_val != op->o_req_ndn.bv_val ) {
164
165
166
167
		dn = op->o_req_dn;
		rc = rwm_dn_massage_pretty_normalize( &dc, &op->o_req_dn, &dn, &ndn );
	} else {
		rc = rwm_dn_massage_normalize( &dc, &op->o_req_ndn, &ndn );
168
169
	}

170
171
172
173
	if ( rc != LDAP_SUCCESS ) {
		return rc;
	}

174
175
176
	if ( ( op->o_req_dn.bv_val != op->o_req_ndn.bv_val && dn.bv_val == op->o_req_dn.bv_val )
			|| ndn.bv_val == op->o_req_ndn.bv_val )
	{
Pierangelo Masarati's avatar
Pierangelo Masarati committed
177
178
179
		return LDAP_SUCCESS;
	}

180
	if ( op->o_req_dn.bv_val != op->o_req_ndn.bv_val ) {
181
		op->o_req_dn = dn;
182
		ros->r_dn = dn;
183
184
185
	} else {
		op->o_req_dn = ndn;
	}
186
	op->o_req_ndn = ndn;
187
	ros->r_ndn = ndn;
188
189
190
191
192

	return LDAP_SUCCESS;
}

static int
193
rwm_op_add( Operation *op, SlapReply *rs )
194
{
195
196
197
198
199
	slap_overinst		*on = (slap_overinst *) op->o_bd->bd_info;
	struct ldaprwmap	*rwmap = 
			(struct ldaprwmap *)on->on_bi.bi_private;

	int			rc,
200
				i;
201
	Attribute		**ap = NULL;
202
	char			*olddn = op->o_req_dn.bv_val;
203
	int			isupdate;
204

205
	rwm_op_cb		*roc = rwm_callback_get( op, rs );
206
207

	rc = rwm_op_dn_massage( op, rs, "addDN", &roc->ros );
208
	if ( rc != LDAP_SUCCESS ) {
209
		op->o_bd->bd_info = (BackendInfo *)on->on_info;
210
		send_ldap_error( op, rs, rc, "addDN massage error" );
211
212
213
		return -1;
	}

214
	if ( olddn != op->o_req_dn.bv_val ) {
Pierangelo Masarati's avatar
Pierangelo Masarati committed
215
216
		ber_bvreplace( &op->ora_e->e_name, &op->o_req_dn );
		ber_bvreplace( &op->ora_e->e_nname, &op->o_req_ndn );
217
218
	}

219
	/* Count number of attributes in entry */ 
220
	isupdate = be_shadow_update( op );
221
222
223
	for ( i = 0, ap = &op->oq_add.rs_e->e_attrs; *ap; ) {
		Attribute	*a;

224
225
226
227
228
		if ( (*ap)->a_desc == slap_schema.si_ad_objectClass ||
				(*ap)->a_desc == slap_schema.si_ad_structuralObjectClass )
		{
			int		j, last;

229
			last = (*ap)->a_numvals - 1;
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
			for ( j = 0; !BER_BVISNULL( &(*ap)->a_vals[ j ] ); j++ ) {
				struct ldapmapping	*mapping = NULL;

				( void )rwm_mapping( &rwmap->rwm_oc, &(*ap)->a_vals[ j ],
						&mapping, RWM_MAP );
				if ( mapping == NULL ) {
					if ( rwmap->rwm_at.drop_missing ) {
						/* FIXME: we allow to remove objectClasses as well;
						 * if the resulting entry is inconsistent, that's
						 * the relayed database's business...
						 */
						ch_free( (*ap)->a_vals[ j ].bv_val );
						if ( last > j ) {
							(*ap)->a_vals[ j ] = (*ap)->a_vals[ last ];
						}
						BER_BVZERO( &(*ap)->a_vals[ last ] );
246
						(*ap)->a_numvals--;
247
248
249
250
251
252
253
254
255
256
						last--;
						j--;
					}

				} else {
					ch_free( (*ap)->a_vals[ j ].bv_val );
					ber_dupbv( &(*ap)->a_vals[ j ], &mapping->m_dst );
				}
			}

Kurt Zeilenga's avatar
Kurt Zeilenga committed
257
		} else if ( !isupdate && !get_relax( op ) && (*ap)->a_desc->ad_type->sat_no_user_mod )
258
		{
259
			goto next_attr;
260

261
262
		} else {
			struct ldapmapping	*mapping = NULL;
263

264
265
266
267
268
269
270
271
			( void )rwm_mapping( &rwmap->rwm_at, &(*ap)->a_desc->ad_cname,
					&mapping, RWM_MAP );
			if ( mapping == NULL ) {
				if ( rwmap->rwm_at.drop_missing ) {
					goto cleanup_attr;
				}
			}

272
273
			if ( (*ap)->a_desc->ad_type->sat_syntax == slap_schema.si_syn_distinguishedName
					|| ( mapping != NULL && mapping->m_dst_ad->ad_type->sat_syntax == slap_schema.si_syn_distinguishedName ) )
274
275
276
277
278
279
280
281
282
283
284
			{
				/*
				 * FIXME: rewrite could fail; in this case
				 * the operation should give up, right?
				 */
				rc = rwm_dnattr_rewrite( op, rs, "addAttrDN",
						(*ap)->a_vals,
						(*ap)->a_nvals ? &(*ap)->a_nvals : NULL );
				if ( rc ) {
					goto cleanup_attr;
				}
285

286
287
288
289
290
291
292
			} else if ( (*ap)->a_desc == slap_schema.si_ad_ref ) {
				rc = rwm_referral_rewrite( op, rs, "referralAttrDN",
						(*ap)->a_vals,
						(*ap)->a_nvals ? &(*ap)->a_nvals : NULL );
				if ( rc != LDAP_SUCCESS ) {
					goto cleanup_attr;
				}
293
			}
294
295
		
			if ( mapping != NULL ) {
296
				assert( mapping->m_dst_ad != NULL );
297
298
				(*ap)->a_desc = mapping->m_dst_ad;
			}
299
300
		}

301
next_attr:;
302
303
304
305
306
307
308
309
		ap = &(*ap)->a_next;
		continue;

cleanup_attr:;
		/* FIXME: leaking attribute/values? */
		a = *ap;

		*ap = (*ap)->a_next;
Pierangelo Masarati's avatar
Pierangelo Masarati committed
310
		attr_free( a );
311
312
	}

313
314
	op->o_callback = &roc->cb;

315
316
317
	return SLAP_CB_CONTINUE;
}

318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
static int
rwm_conn_init( BackendDB *be, Connection *conn )
{
	slap_overinst		*on = (slap_overinst *) be->bd_info;
	struct ldaprwmap	*rwmap = 
			(struct ldaprwmap *)on->on_bi.bi_private;

	( void )rewrite_session_init( rwmap->rwm_rw, conn );

	return SLAP_CB_CONTINUE;
}

static int
rwm_conn_destroy( BackendDB *be, Connection *conn )
{
	slap_overinst		*on = (slap_overinst *) be->bd_info;
	struct ldaprwmap	*rwmap = 
			(struct ldaprwmap *)on->on_bi.bi_private;

	( void )rewrite_session_delete( rwmap->rwm_rw, conn );

	return SLAP_CB_CONTINUE;
}

342
static int
343
rwm_op_bind( Operation *op, SlapReply *rs )
344
{
345
346
	slap_overinst		*on = (slap_overinst *) op->o_bd->bd_info;
	int			rc;
347

348
	rwm_op_cb		*roc = rwm_callback_get( op, rs );
349
350

	rc = rwm_op_dn_massage( op, rs, "bindDN", &roc->ros );
351
	if ( rc != LDAP_SUCCESS ) {
352
		op->o_bd->bd_info = (BackendInfo *)on->on_info;
353
		send_ldap_error( op, rs, rc, "bindDN massage error" );
354
		return -1;
355
356
	}

357
358
	op->o_callback = &roc->cb;

359
360
361
	return SLAP_CB_CONTINUE;
}

362
static int
363
rwm_op_unbind( Operation *op, SlapReply *rs )
364
365
366
367
368
369
370
371
372
373
{
	slap_overinst		*on = (slap_overinst *) op->o_bd->bd_info;
	struct ldaprwmap	*rwmap = 
			(struct ldaprwmap *)on->on_bi.bi_private;

	rewrite_session_delete( rwmap->rwm_rw, op->o_conn );

	return SLAP_CB_CONTINUE;
}

374
static int
375
rwm_op_compare( Operation *op, SlapReply *rs )
376
{
377
378
379
380
381
	slap_overinst		*on = (slap_overinst *) op->o_bd->bd_info;
	struct ldaprwmap	*rwmap = 
			(struct ldaprwmap *)on->on_bi.bi_private;

	int			rc;
382
	struct berval		mapped_vals[2] = { BER_BVNULL, BER_BVNULL };
383

384
	rwm_op_cb		*roc = rwm_callback_get( op, rs );
385
386

	rc = rwm_op_dn_massage( op, rs, "compareDN", &roc->ros );
387
	if ( rc != LDAP_SUCCESS ) {
388
		op->o_bd->bd_info = (BackendInfo *)on->on_info;
389
		send_ldap_error( op, rs, rc, "compareDN massage error" );
390
391
392
393
394
395
396
397
398
		return -1;
	}

	/* if the attribute is an objectClass, try to remap its value */
	if ( op->orc_ava->aa_desc == slap_schema.si_ad_objectClass
			|| op->orc_ava->aa_desc == slap_schema.si_ad_structuralObjectClass )
	{
		rwm_map( &rwmap->rwm_oc, &op->orc_ava->aa_value,
				&mapped_vals[0], RWM_MAP );
Pierangelo Masarati's avatar
Pierangelo Masarati committed
399
		if ( BER_BVISNULL( &mapped_vals[0] ) || BER_BVISEMPTY( &mapped_vals[0] ) )
400
401
402
403
404
405
		{
			op->o_bd->bd_info = (BackendInfo *)on->on_info;
			send_ldap_error( op, rs, LDAP_OTHER, "compare objectClass map error" );
			return -1;

		} else if ( mapped_vals[0].bv_val != op->orc_ava->aa_value.bv_val ) {
406
407
			ber_dupbv_x( &op->orc_ava->aa_value, &mapped_vals[0],
				op->o_tmpmemctx );
408
409
410
		}

	} else {
411
412
413
414
415
416
417
418
419
420
421
422
423
		struct ldapmapping	*mapping = NULL;
		AttributeDescription	*ad = op->orc_ava->aa_desc;

		( void )rwm_mapping( &rwmap->rwm_at, &op->orc_ava->aa_desc->ad_cname,
				&mapping, RWM_MAP );
		if ( mapping == NULL ) {
			if ( rwmap->rwm_at.drop_missing ) {
				op->o_bd->bd_info = (BackendInfo *)on->on_info;
				send_ldap_error( op, rs, LDAP_OTHER, "compare attributeType map error" );
				return -1;
			}

		} else {
424
			assert( mapping->m_dst_ad != NULL );
425
			ad = mapping->m_dst_ad;
426
		}
427

428
429
		if ( op->orc_ava->aa_desc->ad_type->sat_syntax == slap_schema.si_syn_distinguishedName
				|| ( mapping != NULL && mapping->m_dst_ad->ad_type->sat_syntax == slap_schema.si_syn_distinguishedName ) )
430
		{
431
432
433
434
435
			struct berval	*mapped_valsp[2];
			
			mapped_valsp[0] = &mapped_vals[0];
			mapped_valsp[1] = &mapped_vals[1];

436
			mapped_vals[0] = op->orc_ava->aa_value;
Pierangelo Masarati's avatar
Pierangelo Masarati committed
437

438
			rc = rwm_dnattr_rewrite( op, rs, "compareAttrDN", NULL, mapped_valsp );
Pierangelo Masarati's avatar
Pierangelo Masarati committed
439

440
441
442
443
444
445
			if ( rc != LDAP_SUCCESS ) {
				op->o_bd->bd_info = (BackendInfo *)on->on_info;
				send_ldap_error( op, rs, rc, "compareAttrDN massage error" );
				return -1;
			}

Pierangelo Masarati's avatar
Pierangelo Masarati committed
446
			if ( mapped_vals[ 0 ].bv_val != op->orc_ava->aa_value.bv_val ) {
447
448
449
450
				/* NOTE: if we get here, rwm_dnattr_rewrite()
				 * already freed the old value, so now 
				 * it's invalid */
				ber_dupbv_x( &op->orc_ava->aa_value, &mapped_vals[0],
451
					op->o_tmpmemctx );
452
				ber_memfree_x( mapped_vals[ 0 ].bv_val, NULL );
Pierangelo Masarati's avatar
Pierangelo Masarati committed
453
			}
454
		}
455
		op->orc_ava->aa_desc = ad;
456
457
	}

458
459
	op->o_callback = &roc->cb;

460
461
462
463
	return SLAP_CB_CONTINUE;
}

static int
464
rwm_op_delete( Operation *op, SlapReply *rs )
465
{
466
467
	slap_overinst		*on = (slap_overinst *) op->o_bd->bd_info;
	int			rc;
468

469
	rwm_op_cb		*roc = rwm_callback_get( op, rs );
470
471

	rc = rwm_op_dn_massage( op, rs, "deleteDN", &roc->ros );
472
	if ( rc != LDAP_SUCCESS ) {
473
		op->o_bd->bd_info = (BackendInfo *)on->on_info;
474
		send_ldap_error( op, rs, rc, "deleteDN massage error" );
475
		return -1;
476
477
	}

478
479
	op->o_callback = &roc->cb;

480
481
482
483
	return SLAP_CB_CONTINUE;
}

static int
484
rwm_op_modify( Operation *op, SlapReply *rs )
485
{
486
	slap_overinst		*on = (slap_overinst *) op->o_bd->bd_info;
Pierangelo Masarati's avatar
Pierangelo Masarati committed
487
488
489
	struct ldaprwmap	*rwmap = 
			(struct ldaprwmap *)on->on_bi.bi_private;

490
	int			isupdate;
Pierangelo Masarati's avatar
Pierangelo Masarati committed
491
	Modifications		**mlp;
492
	int			rc;
493

494
	rwm_op_cb		*roc = rwm_callback_get( op, rs );
495
496

	rc = rwm_op_dn_massage( op, rs, "modifyDN", &roc->ros );
497
	if ( rc != LDAP_SUCCESS ) {
498
		op->o_bd->bd_info = (BackendInfo *)on->on_info;
499
		send_ldap_error( op, rs, rc, "modifyDN massage error" );
500
		return -1;
501
502
	}

503
	isupdate = be_shadow_update( op );
504
	for ( mlp = &op->orm_modlist; *mlp; ) {
505
		int			is_oc = 0;
Pierangelo Masarati's avatar
Pierangelo Masarati committed
506
		Modifications		*ml = *mlp;
507
		struct ldapmapping	*mapping = NULL;
Pierangelo Masarati's avatar
Pierangelo Masarati committed
508

Pierangelo Masarati's avatar
Pierangelo Masarati committed
509
		/* ml points to a temporary mod until needs duplication */
510
511
		if ( ml->sml_desc == slap_schema.si_ad_objectClass 
				|| ml->sml_desc == slap_schema.si_ad_structuralObjectClass )
512
		{
Pierangelo Masarati's avatar
Pierangelo Masarati committed
513
514
			is_oc = 1;

515
		} else if ( !isupdate && !get_relax( op ) && ml->sml_desc->ad_type->sat_no_user_mod  )
516
		{
Pierangelo Masarati's avatar
Pierangelo Masarati committed
517
518
519
520
521
522
523
524
525
			ml = ch_malloc( sizeof( Modifications ) );
			*ml = **mlp;
			if ( (*mlp)->sml_values ) {
				ber_bvarray_dup_x( &ml->sml_values, (*mlp)->sml_values, NULL );
				if ( (*mlp)->sml_nvalues ) {
					ber_bvarray_dup_x( &ml->sml_nvalues, (*mlp)->sml_nvalues, NULL );
				}
			}
			*mlp = ml;
526
527
			goto next_mod;

Pierangelo Masarati's avatar
Pierangelo Masarati committed
528
529
530
		} else {
			int			drop_missing;

531
			drop_missing = rwm_mapping( &rwmap->rwm_at,
532
					&ml->sml_desc->ad_cname,
533
534
					&mapping, RWM_MAP );
			if ( drop_missing || ( mapping != NULL && BER_BVISNULL( &mapping->m_dst ) ) )
Pierangelo Masarati's avatar
Pierangelo Masarati committed
535
			{
536
				goto cleanup_mod;
Pierangelo Masarati's avatar
Pierangelo Masarati committed
537
538
539
			}
		}

Pierangelo Masarati's avatar
Pierangelo Masarati committed
540
541
542
543
544
		/* duplicate the modlist */
		ml = ch_malloc( sizeof( Modifications ));
		*ml = **mlp;
		*mlp = ml;

545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
		if ( ml->sml_values != NULL ) {
			int i, num;
			struct berval *bva;

			for ( num = 0; !BER_BVISNULL( &ml->sml_values[ num ] ); num++ )
				/* count values */ ;

			bva = ch_malloc( (num+1) * sizeof( struct berval ));
			for (i=0; i<num; i++)
				ber_dupbv( &bva[i], &ml->sml_values[i] );
			BER_BVZERO( &bva[i] );
			ml->sml_values = bva;

			if ( ml->sml_nvalues ) {
				bva = ch_malloc( (num+1) * sizeof( struct berval ));
				for (i=0; i<num; i++)
					ber_dupbv( &bva[i], &ml->sml_nvalues[i] );
				BER_BVZERO( &bva[i] );
				ml->sml_nvalues = bva;
			}

Pierangelo Masarati's avatar
Pierangelo Masarati committed
566
567
568
			if ( is_oc ) {
				int	last, j;

569
				last = num-1;
Pierangelo Masarati's avatar
Pierangelo Masarati committed
570

571
				for ( j = 0; !BER_BVISNULL( &ml->sml_values[ j ] ); j++ ) {
572
573
					struct ldapmapping	*oc_mapping = NULL;
		
574
					( void )rwm_mapping( &rwmap->rwm_oc, &ml->sml_values[ j ],
575
576
							&oc_mapping, RWM_MAP );
					if ( oc_mapping == NULL ) {
577
578
579
580
581
582
						if ( rwmap->rwm_at.drop_missing ) {
							/* FIXME: we allow to remove objectClasses as well;
							 * if the resulting entry is inconsistent, that's
							 * the relayed database's business...
							 */
							if ( last > j ) {
583
584
								ch_free( ml->sml_values[ j ].bv_val );
								ml->sml_values[ j ] = ml->sml_values[ last ];
585
							}
586
							BER_BVZERO( &ml->sml_values[ last ] );
587
588
							last--;
							j--;
Pierangelo Masarati's avatar
Pierangelo Masarati committed
589
						}
590
	
Pierangelo Masarati's avatar
Pierangelo Masarati committed
591
					} else {
592
593
						ch_free( ml->sml_values[ j ].bv_val );
						ber_dupbv( &ml->sml_values[ j ], &oc_mapping->m_dst );
Pierangelo Masarati's avatar
Pierangelo Masarati committed
594
595
596
597
					}
				}

			} else {
598
				if ( ml->sml_desc->ad_type->sat_syntax == slap_schema.si_syn_distinguishedName
599
						|| ( mapping != NULL && mapping->m_dst_ad->ad_type->sat_syntax == slap_schema.si_syn_distinguishedName ) )
Pierangelo Masarati's avatar
Pierangelo Masarati committed
600
				{
601
					rc = rwm_dnattr_rewrite( op, rs, "modifyAttrDN",
602
603
							ml->sml_values,
							ml->sml_nvalues ? &ml->sml_nvalues : NULL );
604

605
				} else if ( ml->sml_desc == slap_schema.si_ad_ref ) {
606
607
					rc = rwm_referral_rewrite( op, rs,
							"referralAttrDN",
608
609
							ml->sml_values,
							ml->sml_nvalues ? &ml->sml_nvalues : NULL );
610
611
612
					if ( rc != LDAP_SUCCESS ) {
						goto cleanup_mod;
					}
Pierangelo Masarati's avatar
Pierangelo Masarati committed
613
614
615
				}

				if ( rc != LDAP_SUCCESS ) {
616
					goto cleanup_mod;
Pierangelo Masarati's avatar
Pierangelo Masarati committed
617
618
619
620
				}
			}
		}

621
next_mod:;
622
623
		if ( mapping != NULL ) {
			/* use new attribute description */
624
			assert( mapping->m_dst_ad != NULL );
625
			ml->sml_desc = mapping->m_dst_ad;
626
627
		}

628
		mlp = &ml->sml_next;
629
630
631
632
633
634
635
		continue;

cleanup_mod:;
		ml = *mlp;
		*mlp = (*mlp)->sml_next;
		slap_mod_free( &ml->sml_mod, 0 );
		free( ml );
Pierangelo Masarati's avatar
Pierangelo Masarati committed
636
637
	}

638
639
	op->o_callback = &roc->cb;

640
641
642
643
	return SLAP_CB_CONTINUE;
}

static int
644
rwm_op_modrdn( Operation *op, SlapReply *rs )
645
{
646
	slap_overinst		*on = (slap_overinst *) op->o_bd->bd_info;
647
648
649
	struct ldaprwmap	*rwmap = 
			(struct ldaprwmap *)on->on_bi.bi_private;
	
650
	int			rc;
651

652
	rwm_op_cb		*roc = rwm_callback_get( op, rs );
653

654
655
656
657
658
659
660
661
662
663
664
665
	if ( op->orr_newSup ) {
		dncookie	dc;
		struct berval	nnewSup = BER_BVNULL;
		struct berval	newSup = BER_BVNULL;

		/*
		 * Rewrite the new superior, if defined and required
	 	 */
		dc.rwmap = rwmap;
		dc.conn = op->o_conn;
		dc.rs = rs;
		dc.ctx = "newSuperiorDN";
666
667
668
		newSup = *op->orr_newSup;
		nnewSup = *op->orr_nnewSup;
		rc = rwm_dn_massage_pretty_normalize( &dc, op->orr_newSup, &newSup, &nnewSup );
669
670
671
672
673
674
675
		if ( rc != LDAP_SUCCESS ) {
			op->o_bd->bd_info = (BackendInfo *)on->on_info;
			send_ldap_error( op, rs, rc, "newSuperiorDN massage error" );
			return -1;
		}

		if ( op->orr_newSup->bv_val != newSup.bv_val ) {
676
677
678
679
			op->orr_newSup = op->o_tmpalloc( sizeof( struct berval ),
				op->o_tmpmemctx );
			op->orr_nnewSup = op->o_tmpalloc( sizeof( struct berval ),
				op->o_tmpmemctx );
680
681
682
683
684
			*op->orr_newSup = newSup;
			*op->orr_nnewSup = nnewSup;
		}
	}

685
686
687
	/*
	 * Rewrite the dn, if needed
 	 */
688
	rc = rwm_op_dn_massage( op, rs, "renameDN", &roc->ros );
689
	if ( rc != LDAP_SUCCESS ) {
690
		op->o_bd->bd_info = (BackendInfo *)on->on_info;
691
		send_ldap_error( op, rs, rc, "renameDN massage error" );
692
693
694
695
696
697
698
699
		if ( op->orr_newSup != roc->ros.orr_newSup ) {
			ch_free( op->orr_newSup->bv_val );
			ch_free( op->orr_nnewSup->bv_val );
			op->o_tmpfree( op->orr_newSup, op->o_tmpmemctx );
			op->o_tmpfree( op->orr_nnewSup, op->o_tmpmemctx );
			op->orr_newSup = roc->ros.orr_newSup;
			op->orr_nnewSup = roc->ros.orr_nnewSup;
		}
700
		return -1;
701
702
	}

703
704
	/* TODO: rewrite newRDN, attribute types, 
	 * values of DN-valued attributes ... */
705

706
	op->o_callback = &roc->cb;
707

708
	return SLAP_CB_CONTINUE;
709
710
711
}


Pierangelo Masarati's avatar
Pierangelo Masarati committed
712
713
714
715
static int
rwm_swap_attrs( Operation *op, SlapReply *rs )
{
	slap_callback	*cb = op->o_callback;
716
	rwm_op_state *ros = cb->sc_private;
Pierangelo Masarati's avatar
Pierangelo Masarati committed
717

718
	rs->sr_attrs = ros->ors_attrs;
719
720
721
722
723

	/* other overlays might have touched op->ors_attrs, 
	 * so we restore the original version here, otherwise
	 * attribute-mapping might fail */
	op->ors_attrs = ros->mapped_attrs; 
Pierangelo Masarati's avatar
Pierangelo Masarati committed
724
	
725
 	return SLAP_CB_CONTINUE;
Pierangelo Masarati's avatar
Pierangelo Masarati committed
726
727
}

728
static int
729
rwm_op_search( Operation *op, SlapReply *rs )
730
{
731
	slap_overinst		*on = (slap_overinst *) op->o_bd->bd_info;
Pierangelo Masarati's avatar
Pierangelo Masarati committed
732
733
734
	struct ldaprwmap	*rwmap = 
			(struct ldaprwmap *)on->on_bi.bi_private;

735
	int			rc;
Pierangelo Masarati's avatar
Pierangelo Masarati committed
736
737
738
739
740
741
742
743
	dncookie		dc;

	struct berval		fstr = BER_BVNULL;
	Filter			*f = NULL;

	AttributeName		*an = NULL;

	char			*text = NULL;
744

745
	rwm_op_cb		*roc = rwm_callback_get( op, rs );
746

747
748
749
	rc = rewrite_session_var_set( rwmap->rwm_rw, op->o_conn,
		"searchFilter", op->ors_filterstr.bv_val );
	if ( rc == LDAP_SUCCESS )
750
		rc = rwm_op_dn_massage( op, rs, "searchDN", &roc->ros );
751
	if ( rc != LDAP_SUCCESS ) {
752
		text = "searchDN massage error";
Pierangelo Masarati's avatar
Pierangelo Masarati committed
753
754
755
756
		goto error_return;
	}

	/*
757
	 * Rewrite the dn if needed
Pierangelo Masarati's avatar
Pierangelo Masarati committed
758
759
760
761
762
763
	 */
	dc.rwmap = rwmap;
	dc.conn = op->o_conn;
	dc.rs = rs;
	dc.ctx = "searchFilterAttrDN";

764
	rc = rwm_filter_map_rewrite( op, &dc, op->ors_filter, &fstr );
Pierangelo Masarati's avatar
Pierangelo Masarati committed
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
	if ( rc != LDAP_SUCCESS ) {
		text = "searchFilter/searchFilterAttrDN massage error";
		goto error_return;
	}

	f = str2filter_x( op, fstr.bv_val );

	if ( f == NULL ) {
		text = "massaged filter parse error";
		goto error_return;
	}

	op->ors_filter = f;
	op->ors_filterstr = fstr;

	rc = rwm_map_attrnames( &rwmap->rwm_at, &rwmap->rwm_oc,
			op->ors_attrs, &an, RWM_MAP );
	if ( rc != LDAP_SUCCESS ) {
		text = "attribute list mapping error";
		goto error_return;
785
786
	}

Pierangelo Masarati's avatar
Pierangelo Masarati committed
787
	op->ors_attrs = an;
788
789
790
	/* store the mapped Attributes for later usage, in
	 * the case that other overlays change op->ors_attrs */
	roc->ros.mapped_attrs = an;
791
792
793
	roc->cb.sc_response = rwm_swap_attrs;

	op->o_callback = &roc->cb;
Pierangelo Masarati's avatar
Pierangelo Masarati committed
794

795
	return SLAP_CB_CONTINUE;
Pierangelo Masarati's avatar
Pierangelo Masarati committed
796
797
798
799
800
801
802
803
804
805
806
807
808
809

error_return:;
	if ( an != NULL ) {
		ch_free( an );
	}

	if ( f != NULL ) {
		filter_free_x( op, f );
	}

	if ( !BER_BVISNULL( &fstr ) ) {
		ch_free( fstr.bv_val );
	}

810
811
	op->oq_search = roc->ros.oq_search;

Pierangelo Masarati's avatar
Pierangelo Masarati committed
812
813
814
	op->o_bd->bd_info = (BackendInfo *)on->on_info;
	send_ldap_error( op, rs, rc, text );

815
	return -1;
Pierangelo Masarati's avatar
Pierangelo Masarati committed
816

817
818
}

819
820
821
822
823
static int
rwm_exop_passwd( Operation *op, SlapReply *rs )
{
	slap_overinst		*on = (slap_overinst *) op->o_bd->bd_info;
	int			rc;
824
	rwm_op_cb *roc;
825
826
827
828

	struct berval	id = BER_BVNULL,
			pwold = BER_BVNULL,
			pwnew = BER_BVNULL;
Howard Chu's avatar
Howard Chu committed
829
	BerElement *ber = NULL;
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846

	if ( !BER_BVISNULL( &op->o_req_ndn ) ) {
		return LDAP_SUCCESS;
	}

	if ( !SLAP_ISGLOBALOVERLAY( op->o_bd ) ) {
		rs->sr_err = LDAP_OTHER;
		return rs->sr_err;
	}

	rs->sr_err = slap_passwd_parse( op->ore_reqdata, &id,
		&pwold, &pwnew, &rs->sr_text );
	if ( rs->sr_err != LDAP_SUCCESS ) {
		return rs->sr_err;
	}

	if ( !BER_BVISNULL( &id ) ) {
847
848
		char idNul = id.bv_val[id.bv_len];
		id.bv_val[id.bv_len] = '\0';
849
850
		rs->sr_err = dnPrettyNormal( NULL, &id, &op->o_req_dn,
				&op->o_req_ndn, op->o_tmpmemctx );
851
		id.bv_val[id.bv_len] = idNul;
852
853
854
855
856
857
858
859
860
861
		if ( rs->sr_err != LDAP_SUCCESS ) {
			rs->sr_text = "Invalid DN";
			return rs->sr_err;
		}

	} else {
		ber_dupbv_x( &op->o_req_dn, &op->o_dn, op->o_tmpmemctx );
		ber_dupbv_x( &op->o_req_ndn, &op->o_ndn, op->o_tmpmemctx );
	}

862
863
864
	roc = rwm_callback_get( op, rs );

	rc = rwm_op_dn_massage( op, rs, "extendedDN", &roc->ros );
865
866
867
868
869
870
	if ( rc != LDAP_SUCCESS ) {
		op->o_bd->bd_info = (BackendInfo *)on->on_info;
		send_ldap_error( op, rs, rc, "extendedDN massage error" );
		return -1;
	}

Howard Chu's avatar
Howard Chu committed
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
	ber = ber_alloc_t( LBER_USE_DER );
	if ( !ber ) {
		rs->sr_err = LDAP_OTHER;
		rs->sr_text = "No memory";
		return rs->sr_err;
	}
	ber_printf( ber, "{" );
	if ( !BER_BVISNULL( &id )) {
		ber_printf( ber, "tO", LDAP_TAG_EXOP_MODIFY_PASSWD_ID, 
			&op->o_req_dn );
	}
	if ( !BER_BVISNULL( &pwold )) {
		ber_printf( ber, "tO", LDAP_TAG_EXOP_MODIFY_PASSWD_OLD, &pwold );
	}
	if ( !BER_BVISNULL( &pwnew )) {
		ber_printf( ber, "tO", LDAP_TAG_EXOP_MODIFY_PASSWD_NEW, &pwnew );
	}
	ber_printf( ber, "N}" );
	ber_flatten( ber, &op->ore_reqdata );
	ber_free( ber, 1 );
891

892
893
	op->o_callback = &roc->cb;

894
895
896
897
898
899
900
901
902
903
904
	return SLAP_CB_CONTINUE;
}

static struct exop {
	struct berval	oid;
	BI_op_extended	*extended;
} exop_table[] = {
	{ BER_BVC(LDAP_EXOP_MODIFY_PASSWD),	rwm_exop_passwd },
	{ BER_BVNULL, NULL }
};

905
906
907
static int
rwm_extended( Operation *op, SlapReply *rs )
{
908
909
	slap_overinst		*on = (slap_overinst *) op->o_bd->bd_info;
	int			rc;
910
	rwm_op_cb *roc;
911

912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
	int	i;

	for ( i = 0; exop_table[i].extended != NULL; i++ ) {
		if ( bvmatch( &exop_table[i].oid, &op->oq_extended.rs_reqoid ) )
		{
			rc = exop_table[i].extended( op, rs );
			switch ( rc ) {
			case LDAP_SUCCESS:
				break;

			case SLAP_CB_CONTINUE:
			case SLAPD_ABANDON:
				return rc;

			default:
				send_ldap_result( op, rs );
				return rc;
			}
			break;
		}
	}

934
935
936
	roc = rwm_callback_get( op, rs );

	rc = rwm_op_dn_massage( op, rs, "extendedDN", &roc->ros );
937
	if ( rc != LDAP_SUCCESS ) {
938
		op->o_bd->bd_info = (BackendInfo *)on->on_info;
939
		send_ldap_error( op, rs, rc, "extendedDN massage error" );
940
		return -1;
941
942
	}

943
	/* TODO: rewrite/map extended data ? ... */
944
945
	op->o_callback = &roc->cb;

946
	return SLAP_CB_CONTINUE;
947
948
949
950
951
952
953
954
955
956
957
}

static int
rwm_matched( Operation *op, SlapReply *rs )
{
	slap_overinst		*on = (slap_overinst *) op->o_bd->bd_info;
	struct ldaprwmap	*rwmap = 
			(struct ldaprwmap *)on->on_bi.bi_private;

	struct berval		dn, mdn;
	dncookie		dc;
Pierangelo Masarati's avatar
Pierangelo Masarati committed
958
	int			rc;
959
960
961
962
963
964
965
966

	if ( rs->sr_matched == NULL ) {
		return SLAP_CB_CONTINUE;
	}

	dc.rwmap = rwmap;
	dc.conn = op->o_conn;
	dc.rs = rs;
967
	dc.ctx = "matchedDN";
968
	ber_str2bv( rs->sr_matched, 0, 0, &dn );
969
970
	mdn = dn;
	rc = rwm_dn_massage_pretty( &dc, &dn, &mdn );
Pierangelo Masarati's avatar
Pierangelo Masarati committed
971
972
973
974
975
	if ( rc != LDAP_SUCCESS ) {
		rs->sr_err = rc;
		rs->sr_text = "Rewrite error";
		return 1;
	}
976
977
978

	if ( mdn.bv_val != dn.bv_val ) {
		if ( rs->sr_flags & REP_MATCHED_MUSTBEFREED ) {
Pierangelo Masarati's avatar
Pierangelo Masarati committed
979
			ch_free( (void *)rs->sr_matched );
Pierangelo Masarati's avatar
Pierangelo Masarati committed
980

981
982
983
984
985
986
987
988
989
990
		} else {
			rs->sr_flags |= REP_MATCHED_MUSTBEFREED;
		}
		rs->sr_matched = mdn.bv_val;
	}
	
	return SLAP_CB_CONTINUE;
}

static int
991
rwm_attrs( Operation *op, SlapReply *rs, Attribute** a_first, int stripEntryDN )
992
993
994
995
996
{
	slap_overinst		*on = (slap_overinst *) op->o_bd->bd_info;
	struct ldaprwmap	*rwmap = 
			(struct ldaprwmap *)on->on_bi.bi_private;

997
998
999
	dncookie		dc;
	int			rc;
	Attribute		**ap;
1000
	int			isupdate;
For faster browsing, not all history is shown. View entire blame