refint.c 17.3 KB
Newer Older
1
2
3
4
/* refint.c - referential integrity module */
/* $OpenLDAP$ */
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
 *
Kurt Zeilenga's avatar
Kurt Zeilenga committed
5
 * Copyright 2004-2006 The OpenLDAP Foundation.
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
 * Portions Copyright 2004 Symas Corporation.
 * 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>.
 */
/* ACKNOWLEDGEMENTS:
 * This work was initially developed by Symas Corp. for inclusion in
 * OpenLDAP Software.  This work was sponsored by Hewlett-Packard.
 */

#include "portable.h"

/* This module maintains referential integrity for a set of
 * DN-valued attributes by searching for all references to a given
 * DN whenever the DN is changed or its entry is deleted, and making
 * the appropriate update.
 *
 * Updates are performed using the database rootdn, but the ModifiersName
 * is always set to refint_dn.
 */

#ifdef SLAPD_OVER_REFINT

#include <stdio.h>

#include <ac/string.h>
#include <ac/socket.h>

#include "slap.h"

static slap_overinst refint;

/* The DN to use in the ModifiersName for all refint updates */
static BerValue refint_dn = BER_BVC("cn=Referential Integrity Overlay");

typedef struct refint_attrs_s {
	struct refint_attrs_s *next;
	AttributeDescription *attr;
} refint_attrs;

typedef struct dependents_s {
	struct dependents_s *next;
	BerValue dn;				/* target dn */
	Modifications *mm;
} dependent_data;

typedef struct refint_data_s {
	const char *message;			/* breadcrumbs */
	struct refint_attrs_s *attrs;	/* list of known attrs */
	struct dependents_s *mods;		/* modifications returned from callback */
	BerValue dn;				/* basedn in parent, searchdn in call */
	BerValue newdn;				/* replacement value for modrdn callback */
	BerValue nnewdn;			/* normalized replacement value */
	BerValue nothing;			/* the nothing value, if needed */
	BerValue nnothing;			/* normalized nothingness */
} refint_data;

/*
** allocate new refint_data;
** initialize, copy basedn;
** store in on_bi.bi_private;
**
*/

static int
refint_db_init(
	BackendDB	*be
)
{
	slap_overinst *on = (slap_overinst *)be->bd_info;
	refint_data *id = ch_malloc(sizeof(refint_data));
83

84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
	id->message = "_init";
	id->attrs = NULL;
	id->newdn.bv_val = NULL;
	id->nothing.bv_val = NULL;
	id->nnothing.bv_val = NULL;
	ber_dupbv( &id->dn, &be->be_nsuffix[0] );
	on->on_bi.bi_private = id;
	return(0);
}


/*
** if command = attributes:
**	foreach argument:
**		convert to attribute;
**		add to configured attribute list;
** elseif command = basedn:
**	set our basedn to argument;
**
*/

static int
refint_config(
	BackendDB	*be,
	const char	*fname,
	int		lineno,
	int		argc,
	char		**argv
)
{
	slap_overinst *on	= (slap_overinst *) be->bd_info;
	refint_data *id	= on->on_bi.bi_private;
	refint_attrs *ip;
	const char *text;
	AttributeDescription *ad;
	BerValue dn;
	int i;

	if(!strcasecmp(*argv, "refint_attributes")) {
		for(i = 1; i < argc; i++) {
			for(ip = id->attrs; ip; ip = ip->next)
			    if(!strcmp(argv[i], ip->attr->ad_cname.bv_val)) {
				Debug(LDAP_DEBUG_ANY,
					"%s: line %d: duplicate attribute <s>, ignored\n",
					fname, lineno, argv[i]);
				continue;
			}
			ad = NULL;
			if(slap_str2ad(argv[i], &ad, &text) != LDAP_SUCCESS) {
				Debug(LDAP_DEBUG_ANY,
					"%s: line %d: bad attribute <%s>, ignored\n",
					fname, lineno, text);
				continue;		/* XXX */
			} else if(ad->ad_next) {
				Debug(LDAP_DEBUG_ANY,
					"%s: line %d: multiple attributes match <%s>, ignored\n",
					fname, lineno, argv[i]);
				continue;
			}
			ip = ch_malloc(sizeof(refint_attrs));
			ip->attr = ad;
			ip->next = id->attrs;
			id->attrs = ip;
			Debug(LDAP_DEBUG_ANY, "%s: line %d: new attribute <%s>\n",
				fname, lineno, argv[i]);
		}
	} else if(!strcasecmp(*argv, "refint_base")) {
		/* XXX only one basedn (yet) - need validate argument! */
		if(id->dn.bv_val) ch_free(id->dn.bv_val);
		ber_str2bv( argv[1], 0, 0, &dn );
		Debug(LDAP_DEBUG_ANY, "%s: line %d: new baseDN <%s>\n",
			fname, lineno, argv[1]);
		if(dnNormalize(0, NULL, NULL, &dn, &id->dn, NULL)) {
			Debug(LDAP_DEBUG_ANY, "%s: line %d: bad baseDN!\n", fname, lineno, 0);
			return(1);
		}
	} else if(!strcasecmp(*argv, "refint_nothing")) {
		if(id->nothing.bv_val) ch_free(id->nothing.bv_val);
		if(id->nnothing.bv_val) ch_free(id->nnothing.bv_val);
		ber_str2bv( argv[1], 0, 1, &id->nothing );
		if(dnNormalize(0, NULL, NULL, &id->nothing, &id->nnothing, NULL)) {
			Debug(LDAP_DEBUG_ANY, "%s: line %d: bad nothingDN!\n", fname, lineno, 0);
			return(1);
		}
		Debug(LDAP_DEBUG_ANY, "%s: line %d: new nothingDN<%s>\n",
			fname, lineno, argv[1]);
	} else {
		return(SLAP_CONF_UNKNOWN);
	}

	id->message = "_config";
	return(0);
}


/*
** nothing really happens here;
**
*/

static int
refint_open(
	BackendDB *be
)
{
	slap_overinst *on	= (slap_overinst *)be->bd_info;
	refint_data *id	= on->on_bi.bi_private;
	id->message		= "_open";
	return(0);
}


/*
** foreach configured attribute:
**	free it;
** free our basedn;
** (do not) free id->message;
** reset on_bi.bi_private;
** free our config data;
**
*/

static int
refint_close(
	BackendDB *be
)
{
	slap_overinst *on	= (slap_overinst *) be->bd_info;
	refint_data *id	= on->on_bi.bi_private;
	refint_attrs *ii, *ij;
	id->message		= "_close";

	for(ii = id->attrs; ii; ii = ij) {
		ij = ii->next;
		ch_free(ii);
	}

	ch_free(id->dn.bv_val);
	ch_free(id->nothing.bv_val);
	ch_free(id->nnothing.bv_val);

	on->on_bi.bi_private = NULL;	/* XXX */

	ch_free(id);

	return(0);
}

/*
** delete callback
** generates a list of Modification* from search results
*/

static int
refint_delete_cb(
	Operation *op,
	SlapReply *rs
)
{
	Attribute *a;
	BerVarray b = NULL;
245
	refint_data *dd = op->o_callback->sc_private;
246
	refint_attrs *ia, *da = dd->attrs;
247
	dependent_data *ip;
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
	Modifications *mp, *ma;
	int i;

	Debug(LDAP_DEBUG_TRACE, "refint_delete_cb <%s>\n",
		rs->sr_entry ? rs->sr_entry->e_name.bv_val : "NOTHING", 0, 0);

	if (rs->sr_type != REP_SEARCH || !rs->sr_entry) return(0);
	dd->message = "_delete_cb";

	/*
	** foreach configured attribute type:
	**	if this attr exists in the search result,
	**	and it has a value matching the target:
	**		allocate a Modification;
	**		allocate its array of 2 BerValues;
	**		if only one value, and we have a configured Nothing:
	**			allocate additional Modification
	**			type = MOD_ADD
	**			BerValues[] = { Nothing, NULL };
	**			add to list
	**		type = MOD_DELETE
	**		BerValues[] = { our target dn, NULL };
	**	add this mod to the list of mods;
	**
	*/

	ip = ch_malloc(sizeof(dependent_data));
	ip->dn.bv_val = NULL;
	ip->next = NULL;
	ip->mm = NULL;
	ma = NULL;
	for(ia = da; ia; ia = ia->next) {
Pierangelo Masarati's avatar
Pierangelo Masarati committed
280
	    if ( (a = attr_find(rs->sr_entry->e_attrs, ia->attr) ) )
281
282
283
284
285
286
287
288
289
290
291
292
293
		for(i = 0, b = a->a_nvals; b[i].bv_val; i++)
		    if(bvmatch(&dd->dn, &b[i])) {
			if(!ip->dn.bv_val) ber_dupbv(&ip->dn, &rs->sr_entry->e_nname);
			if(!b[1].bv_val && dd->nothing.bv_val) {
				mp = ch_malloc(sizeof(Modifications));
				mp->sml_desc = ia->attr;		/* XXX */
				mp->sml_type = a->a_desc->ad_cname;
				mp->sml_values  = ch_malloc(2 * sizeof(BerValue));
				mp->sml_nvalues = ch_malloc(2 * sizeof(BerValue));
				mp->sml_values[1].bv_len = mp->sml_nvalues[1].bv_len = 0;
				mp->sml_values[1].bv_val = mp->sml_nvalues[1].bv_val = NULL;

				mp->sml_op = LDAP_MOD_ADD;
294
				mp->sml_flags = 0;
295
296
297
298
299
300
301
302
303
304
305
306
307
308
				ber_dupbv(&mp->sml_values[0],  &dd->nothing);
				ber_dupbv(&mp->sml_nvalues[0], &dd->nnothing);
				mp->sml_next = ma;
				ma = mp;
			}
		 	/* this might violate the object class */
			mp = ch_malloc(sizeof(Modifications));
			mp->sml_desc = ia->attr;		/* XXX */
			mp->sml_type = a->a_desc->ad_cname;
			mp->sml_values  = ch_malloc(2 * sizeof(BerValue));
			mp->sml_nvalues = ch_malloc(2 * sizeof(BerValue));
			mp->sml_values[1].bv_len = mp->sml_nvalues[1].bv_len = 0;
			mp->sml_values[1].bv_val = mp->sml_nvalues[1].bv_val = NULL;
			mp->sml_op = LDAP_MOD_DELETE;
309
			mp->sml_flags = 0;
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
			ber_dupbv(&mp->sml_values[0], &dd->dn);
			ber_dupbv(&mp->sml_nvalues[0], &mp->sml_values[0]);
			mp->sml_next = ma;
			ma = mp;
			Debug(LDAP_DEBUG_TRACE, "refint_delete_cb: %s: %s\n",
				a->a_desc->ad_cname.bv_val, dd->dn.bv_val, 0);
			break;
	    }
	}
	ip->mm = ma;
	ip->next = dd->mods;
	dd->mods = ip;

	return(0);
}

/*
** null callback
** does nothing
*/

static int
refint_null_cb(
	Operation *op,
	SlapReply *rs
)
{
	((refint_data *)op->o_callback->sc_private)->message = "_null_cb";
	return(LDAP_SUCCESS);
}

/*
** modrdn callback
** generates a list of Modification* from search results
*/

static int
refint_modrdn_cb(
	Operation *op,
	SlapReply *rs
)
{
	Attribute *a;
	BerVarray b = NULL;
354
	refint_data *dd = op->o_callback->sc_private;
355
	refint_attrs *ia, *da = dd->attrs;
356
	dependent_data *ip = NULL;
357
	Modifications *mp;
358
	int i, fix;
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381

	Debug(LDAP_DEBUG_TRACE, "refint_modrdn_cb <%s>\n",
		rs->sr_entry ? rs->sr_entry->e_name.bv_val : "NOTHING", 0, 0);

	if (rs->sr_type != REP_SEARCH || !rs->sr_entry) return(0);
	dd->message = "_modrdn_cb";

	/*
	** foreach configured attribute type:
	**   if this attr exists in the search result,
	**   and it has a value matching the target:
	**	allocate a pair of Modifications;
	**	make it MOD_ADD the new value and MOD_DELETE the old;
	**	allocate its array of BerValues;
	**	foreach value in the search result:
	**	   if it matches our target value, replace it;
	**	   otherwise, copy from the search result;
	**	terminate the array of BerValues;
	**   add these mods to the list of mods;
	**
	*/

	for(ia = da; ia; ia = ia->next) {
Pierangelo Masarati's avatar
Pierangelo Masarati committed
382
	    if((a = attr_find(rs->sr_entry->e_attrs, ia->attr))) {
383
384
385
386
387
388
389
390
391
392
393
		    for(fix = 0, i = 0, b = a->a_nvals; b[i].bv_val; i++)
			if(bvmatch(&dd->dn, &b[i])) { fix++; break; }
		    if(fix) {
			if (!ip) {
	    		    ip = ch_malloc(sizeof(dependent_data));
	    		    ip->next = NULL;
	    		    ip->mm = NULL;
	    		    ber_dupbv(&ip->dn, &rs->sr_entry->e_nname);
			}
			mp = ch_malloc(sizeof(Modifications));
			mp->sml_op = LDAP_MOD_ADD;
394
			mp->sml_flags = 0;
395
396
397
398
399
400
401
402
403
404
405
406
			mp->sml_desc = ia->attr;		/* XXX */
			mp->sml_type = ia->attr->ad_cname;
			mp->sml_values  = ch_malloc(2 * sizeof(BerValue));
			mp->sml_nvalues = ch_malloc(2 * sizeof(BerValue));
			ber_dupbv(&mp->sml_values[0], &dd->newdn);
			ber_dupbv(&mp->sml_nvalues[0], &dd->nnewdn);
			mp->sml_values[1].bv_len = mp->sml_nvalues[1].bv_len = 0;
			mp->sml_values[1].bv_val = mp->sml_nvalues[1].bv_val = NULL;
			mp->sml_next = ip->mm;
			ip->mm = mp;
			mp = ch_malloc(sizeof(Modifications));
			mp->sml_op = LDAP_MOD_DELETE;
407
			mp->sml_flags = 0;
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
			mp->sml_desc = ia->attr;		/* XXX */
			mp->sml_type = ia->attr->ad_cname;
			mp->sml_values  = ch_malloc(2 * sizeof(BerValue));
			mp->sml_nvalues = ch_malloc(2 * sizeof(BerValue));
			ber_dupbv(&mp->sml_values[0], &dd->dn);
			ber_dupbv(&mp->sml_nvalues[0], &dd->dn);
			mp->sml_values[1].bv_len = mp->sml_nvalues[1].bv_len = 0;
			mp->sml_values[1].bv_val = mp->sml_nvalues[1].bv_val = NULL;
			mp->sml_next = ip->mm;
			ip->mm = mp;
			Debug(LDAP_DEBUG_TRACE, "refint_modrdn_cb: %s: %s\n",
				a->a_desc->ad_cname.bv_val, dd->dn.bv_val, 0);
		}
	    }
	}
	if (ip) {
		ip->next = dd->mods;
		dd->mods = ip;
	}

	return(0);
}


/*
** refint_response
** search for matching records and modify them
*/

static int
refint_response(
	Operation *op,
	SlapReply *rs
)
{
	Operation nop = *op;
	SlapReply nrs = { REP_RESULT };
	slap_callback cb = { NULL, NULL, NULL, NULL };
	slap_callback cb2 = { NULL, slap_replog_cb, NULL, NULL };
	slap_callback *cbo, *cbp;
	slap_overinst *on = (slap_overinst *) op->o_bd->bd_info;
	refint_data *id = on->on_bi.bi_private;
	refint_data dd = *id;
	refint_attrs *ip;
	dependent_data *dp;
453
454
455
	BerValue pdn;
	int rc, ac;
	Filter ftop, *fptr;
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470

	id->message = "_refint_response";

	/* If the main op failed or is not a Delete or ModRdn, ignore it */
	if (( op->o_tag != LDAP_REQ_DELETE && op->o_tag != LDAP_REQ_MODRDN ) ||
		rs->sr_err != LDAP_SUCCESS )
		return SLAP_CB_CONTINUE;

	/*
	** validate (and count) the list of attrs;
	**
	*/

	for(ip = id->attrs, ac = 0; ip; ip = ip->next, ac++);
	if(!ac) {
471
472
		Debug( LDAP_DEBUG_TRACE,
			"refint_response called without any attributes\n", 0, 0, 0 );
473
474
475
476
477
478
479
480
481
482
483
484
485
		return SLAP_CB_CONTINUE;
	}

	/*
	** find the backend that matches our configured basedn;
	** make sure it exists and has search and modify methods;
	**
	*/

	nop.o_bd = select_backend(&id->dn, 0, 1);

	if(nop.o_bd) {
		if (!nop.o_bd->be_search || !nop.o_bd->be_modify) {
486
487
488
			Debug( LDAP_DEBUG_TRACE,
				"refint_response: backend missing search and/or modify\n",
				0, 0, 0 );
489
490
491
			return SLAP_CB_CONTINUE;
		}
	} else {
492
493
494
		Debug( LDAP_DEBUG_TRACE,
			"refint_response: no backend for our baseDN %s??\n",
			id->dn.bv_val, 0, 0 );
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
		return SLAP_CB_CONTINUE;
	}

	cb2.sc_next = &cb;

	/*
	** if delete: set delete callback;
	** else modrdn: create a newdn, set modify callback;
	**
	*/

	if(op->o_tag == LDAP_REQ_DELETE) {
		cb.sc_response = &refint_delete_cb;
		dd.newdn.bv_val = NULL;
		dd.nnewdn.bv_val = NULL;
	} else {
		cb.sc_response = &refint_modrdn_cb;
		if ( op->oq_modrdn.rs_newSup ) {
			pdn = *op->oq_modrdn.rs_newSup;
		} else {
			dnParent( &op->o_req_dn, &pdn );
		}
		build_new_dn( &dd.newdn, &pdn, &op->orr_newrdn, NULL );
		if ( op->oq_modrdn.rs_nnewSup ) {
			pdn = *op->oq_modrdn.rs_nnewSup;
		} else {
			dnParent( &op->o_req_ndn, &pdn );
		}
		build_new_dn( &dd.nnewdn, &pdn, &op->orr_nnewrdn, NULL );
	}

	/*
	** build a search filter for all configured attributes;
	** populate our Operation;
	** pass our data (attr list, dn) to backend via sc_private;
	** call the backend search function;
	** nb: (|(one=thing)) is valid, but do smart formatting anyway;
	** nb: 16 is arbitrarily a dozen or so extra bytes;
	**
	*/

536
537
538
539
540
541
542
543
544
545
546
547
548
549
	ftop.f_choice = LDAP_FILTER_OR;
	ftop.f_next = NULL;
	ftop.f_or = NULL;
	nop.ors_filter = &ftop;
	for(ip = id->attrs; ip; ip = ip->next) {
		fptr = ch_malloc( sizeof(Filter) + sizeof(AttributeAssertion) );
		fptr->f_choice = LDAP_FILTER_EQUALITY;
		fptr->f_ava = (AttributeAssertion *)(fptr+1);
		fptr->f_ava->aa_desc = ip->attr;
		fptr->f_ava->aa_value = op->o_req_ndn;
		fptr->f_next = ftop.f_or;
		ftop.f_or = fptr;
	}
	filter2bv( nop.ors_filter, &nop.ors_filterstr );
550
551
552
553
554
555
556
557
558
559

	/* callback gets the searched dn instead */
	dd.dn = op->o_req_ndn;
	dd.message	= "_dependent_search";
	dd.mods		= NULL;
	cb.sc_private	= &dd;
	nop.o_callback	= &cb;
	nop.o_tag	= LDAP_REQ_SEARCH;
	nop.ors_scope	= LDAP_SCOPE_SUBTREE;
	nop.ors_deref	= LDAP_DEREF_NEVER;
Howard Chu's avatar
Howard Chu committed
560
	nop.ors_limit   = NULL;
561
562
	nop.ors_slimit	= SLAP_NO_LIMIT;
	nop.ors_tlimit	= SLAP_NO_LIMIT;
Pierangelo Masarati's avatar
Pierangelo Masarati committed
563
564

	/* no attrs! */
565
566
	nop.ors_attrs = slap_anlist_no_attrs;
	nop.ors_attrsonly = 1;
Pierangelo Masarati's avatar
Pierangelo Masarati committed
567

568
569
570
571
572
573
	nop.o_req_ndn = id->dn;
	nop.o_req_dn = id->dn;

	/* search */
	rc = nop.o_bd->be_search(&nop, &nrs);

574
	ch_free( nop.ors_filterstr.bv_val );
Hallvard Furuseth's avatar
Hallvard Furuseth committed
575
	while ( (fptr = ftop.f_or) != NULL ) {
576
577
578
		ftop.f_or = fptr->f_next;
		ch_free( fptr );
	}
579
580
581
582
583
584
	ch_free(dd.nnewdn.bv_val);
	ch_free(dd.newdn.bv_val);
	dd.newdn.bv_val	= NULL;
	dd.nnewdn.bv_val = NULL;

	if(rc != LDAP_SUCCESS) {
585
586
587
		Debug( LDAP_DEBUG_TRACE,
			"refint_response: search failed: %d\n",
			rc, 0, 0 );
588
589
590
591
592
		goto done;
	}

	/* safety? paranoid just in case */
	if(!cb.sc_private) {
593
594
595
		Debug( LDAP_DEBUG_TRACE,
			"refint_response: callback wiped out sc_private?!\n",
			0, 0, 0 );
596
597
598
599
600
601
602
603
604
		goto done;
	}

	/* presto! now it's a modify request with null callback */
	cb.sc_response	= &refint_null_cb;
	nop.o_tag	= LDAP_REQ_MODIFY;
	dd.message	= "_dependent_modify";

	/* See if the parent operation is going into the replog */
Howard Chu's avatar
Howard Chu committed
605
	for (cbo=op->o_callback, cbp = cbo->sc_next; cbp; cbo=cbp,cbp=cbp->sc_next) {
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
		if (cbp->sc_response == slap_replog_cb) {
			/* Invoke replog now, arrange for our
			 * dependent mods to also be logged
			 */
			cbo->sc_next = cbp->sc_next;
			replog( op );
			nop.o_callback = &cb2;
			break;
		}
	}

	/*
	** [our search callback builds a list of mods]
	** foreach mod:
	**	make sure its dn has a backend;
	**	connect Modification* chain to our op;
	**	call the backend modify function;
	**	pass any errors upstream;
	**
	*/

	for(dp = dd.mods; dp; dp = dp->next) {
		nop.o_req_dn	= dp->dn;
		nop.o_req_ndn	= dp->dn;
		nop.o_bd = select_backend(&dp->dn, 0, 1);
		if(!nop.o_bd) {
632
633
634
			Debug( LDAP_DEBUG_TRACE,
				"refint_response: no backend for DN %s!\n",
				dp->dn.bv_val, 0, 0 );
635
636
637
638
639
640
641
642
643
644
			goto done;
		}
		nrs.sr_type	= REP_RESULT;
		nop.orm_modlist = dp->mm;	/* callback did all the work */
		nop.o_dn = refint_dn;
		nop.o_ndn = refint_dn;
		nop.o_dn = nop.o_bd->be_rootdn;
		nop.o_ndn = nop.o_bd->be_rootndn;
		if(rs->sr_err != LDAP_SUCCESS) goto done;
		if((rc = nop.o_bd->be_modify(&nop, &nrs)) != LDAP_SUCCESS) {
645
646
647
			Debug( LDAP_DEBUG_TRACE,
				"refint_response: dependent modify failed: %d\n",
				nrs.sr_err, 0, 0 );
648
649
650
651
652
653
654
655
			goto done;
		}
	}

done:
	for(dp = dd.mods; dp; dp = dd.mods) {
		dd.mods = dp->next;
		ch_free(dp->dn.bv_val);
656
		slap_mods_free(dp->mm, 1);
657
658
659
660
661
662
663
664
665
666
667
	}
	dd.mods = NULL;

	return(SLAP_CB_CONTINUE);
}

/*
** init_module is last so the symbols resolve "for free" --
** it expects to be called automagically during dynamic module initialization
*/

668
int refint_initialize() {
669
670
671
672
673
674
675
676
677
678
679
680
681
682

	/* statically declared just after the #includes at top */
	refint.on_bi.bi_type = "refint";
	refint.on_bi.bi_db_init = refint_db_init;
	refint.on_bi.bi_db_config = refint_config;
	refint.on_bi.bi_db_open = refint_open;
	refint.on_bi.bi_db_close = refint_close;
	refint.on_response = refint_response;

	return(overlay_register(&refint));
}

#if SLAPD_OVER_REFINT == SLAPD_MOD_DYNAMIC && defined(PIC)
int init_module(int argc, char *argv[]) {
683
	return refint_initialize();
684
685
686
687
}
#endif

#endif /* SLAPD_OVER_REFINT */