]> git.sur5r.net Git - openldap/blob - servers/slapd/overlays/refint.c
Fix prev commit
[openldap] / servers / slapd / overlays / refint.c
1 /* refint.c - referential integrity module */
2 /* $OpenLDAP$ */
3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
4  *
5  * Copyright 2004-2006 The OpenLDAP Foundation.
6  * Portions Copyright 2004 Symas Corporation.
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 /* ACKNOWLEDGEMENTS:
18  * This work was initially developed by Symas Corp. for inclusion in
19  * OpenLDAP Software.  This work was sponsored by Hewlett-Packard.
20  */
21
22 #include "portable.h"
23
24 /* This module maintains referential integrity for a set of
25  * DN-valued attributes by searching for all references to a given
26  * DN whenever the DN is changed or its entry is deleted, and making
27  * the appropriate update.
28  *
29  * Updates are performed using the database rootdn, but the ModifiersName
30  * is always set to refint_dn.
31  */
32
33 #ifdef SLAPD_OVER_REFINT
34
35 #include <stdio.h>
36
37 #include <ac/string.h>
38 #include <ac/socket.h>
39
40 #include "slap.h"
41 #include "config.h"
42
43 static slap_overinst refint;
44
45 /* The DN to use in the ModifiersName for all refint updates */
46 static BerValue refint_dn = BER_BVC("cn=Referential Integrity Overlay");
47
48 typedef struct refint_attrs_s {
49         struct refint_attrs_s *next;
50         AttributeDescription *attr;
51 } refint_attrs;
52
53 typedef struct dependents_s {
54         struct dependents_s *next;
55         BerValue dn;                            /* target dn */
56         Modifications *mm;
57 } dependent_data;
58
59 typedef struct refint_data_s {
60         const char *message;                    /* breadcrumbs */
61         struct refint_attrs_s *attrs;   /* list of known attrs */
62         struct dependents_s *mods;              /* modifications returned from callback */
63         BerValue dn;                            /* basedn in parent, searchdn in call */
64         BerValue newdn;                         /* replacement value for modrdn callback */
65         BerValue nnewdn;                        /* normalized replacement value */
66         BerValue nothing;                       /* the nothing value, if needed */
67         BerValue nnothing;                      /* normalized nothingness */
68 } refint_data;
69
70 enum {
71         REFINT_ATTRS = 1,
72         REFINT_NOTHING
73 };
74
75 static ConfigDriver refint_cf_gen;
76
77 static ConfigTable refintcfg[] = {
78         { "refint_attributes", "attribute...", 2, 0, 0,
79           ARG_MAGIC|REFINT_ATTRS, refint_cf_gen,
80           "( OLcfgOvAt:11.1 NAME 'olcRefintAttribute' "
81           "DESC 'Attributes for referential integrity' "
82           "SYNTAX OMsDirectoryString )", NULL, NULL },
83         { "refint_nothing", "string", 2, 2, 0,
84           ARG_DN|ARG_MAGIC|REFINT_NOTHING, refint_cf_gen,
85           "( OLcfgOvAt:11.2 NAME 'olcRefintNothing' "
86           "DESC 'Replacement DN to supply when needed' "
87           "SYNTAX OMsDN SINGLE-VALUE )", NULL, NULL },
88         { NULL, NULL, 0, 0, 0, ARG_IGNORED }
89 };
90
91 static ConfigOCs refintocs[] = {
92         { "( OLcfgOvOc:11.1 "
93           "NAME 'olcRefintConfig' "
94           "DESC 'Referential integrity configuration' "
95           "SUP olcOverlayConfig "
96           "MAY ( olcRefintAttribute $ olcRefintNothing ) )",
97           Cft_Overlay, refintcfg },
98         { NULL, 0, NULL }
99 };
100
101 static int
102 refint_cf_gen(ConfigArgs *c)
103 {
104         slap_overinst *on = (slap_overinst *)c->bi;
105         refint_data *dd = (refint_data *)on->on_bi.bi_private;
106         refint_attrs *ip, *pip, **pipp = NULL;
107         AttributeDescription *ad;
108         const char *text;
109         int rc = ARG_BAD_CONF;
110         int i;
111
112         switch ( c->op ) {
113         case SLAP_CONFIG_EMIT:
114                 switch ( c->type ) {
115                 case REFINT_ATTRS:
116                         ip = dd->attrs;
117                         while ( ip ) {
118                                 value_add_one( &c->rvalue_vals,
119                                                &ip->attr->ad_cname );
120                                 ip = ip->next;
121                         }
122                         rc = 0;
123                         break;
124                 case REFINT_NOTHING:
125                         if ( !BER_BVISEMPTY( &dd->nothing )) {
126                                 rc = value_add_one( &c->rvalue_vals,
127                                                     &dd->nothing );
128                                 if ( rc ) return rc;
129                                 rc = value_add_one( &c->rvalue_nvals,
130                                                     &dd->nnothing );
131                                 return rc;
132                         }
133                         rc = 0;
134                         break;
135                 default:
136                         abort ();
137                 }
138                 break;
139         case LDAP_MOD_DELETE:
140                 switch ( c->type ) {
141                 case REFINT_ATTRS:
142                         pipp = &dd->attrs;
143                         if ( c->valx < 0 ) {
144                                 ip = *pipp;
145                                 *pipp = NULL;
146                                 while ( ip ) {
147                                         pip = ip;
148                                         ip = ip->next;
149                                         ch_free ( pip );
150                                 }
151                         } else {
152                                 /* delete from linked list */
153                                 for ( i=0; i < c->valx; ++i ) {
154                                         pipp = &(*pipp)->next;
155                                 }
156                                 ip = *pipp;
157                                 *pipp = (*pipp)->next;
158
159                                 /* AttributeDescriptions are global so
160                                  * shouldn't be freed here... */
161                                 ch_free ( ip );
162                         }
163                         rc = 0;
164                         break;
165                 case REFINT_NOTHING:
166                         if ( dd->nothing.bv_val )
167                                 ber_memfree ( dd->nothing.bv_val );
168                         if ( dd->nnothing.bv_val )
169                                 ber_memfree ( dd->nnothing.bv_val );
170                         dd->nothing.bv_len = 0;
171                         dd->nnothing.bv_len = 0;
172                         rc = 0;
173                         break;
174                 default:
175                         abort ();
176                 }
177                 break;
178         case SLAP_CONFIG_ADD:
179                 /* fallthrough to LDAP_MOD_ADD */
180         case LDAP_MOD_ADD:
181                 switch ( c->type ) {
182                 case REFINT_ATTRS:
183                         rc = 0;
184                         for ( i=1; i < c->argc; ++i ) {
185                                 ad = NULL;
186                                 if ( slap_str2ad ( c->argv[i], &ad, &text )
187                                      == LDAP_SUCCESS) {
188                                         ip = ch_malloc (
189                                                 sizeof ( refint_attrs ) );
190                                         ip->attr = ad;
191                                         ip->next = dd->attrs;
192                                         dd->attrs = ip;
193                                 } else {
194                                         Debug ( LDAP_DEBUG_CONFIG,
195                                                 "refint add: <%s>: %s\n",
196                                                 c->argv[i], text, NULL );
197                                         strncpy ( c->msg,
198                                                   text,
199                                                   SLAP_TEXT_BUFLEN-1 );
200                                         c->msg[SLAP_TEXT_BUFLEN-1] = '\0';
201                                         rc = ARG_BAD_CONF;
202                                 }
203                         }
204                         break;
205                 case REFINT_NOTHING:
206                         if ( dd->nothing.bv_val )
207                                 ber_memfree ( dd->nothing.bv_val );
208                         if ( dd->nnothing.bv_val )
209                                 ber_memfree ( dd->nnothing.bv_val );
210                         dd->nothing = c->value_dn;
211                         dd->nnothing = c->value_ndn;
212                         rc = 0;
213                         break;
214                 default:
215                         abort ();
216                 }
217                 break;
218         default:
219                 abort ();
220         }
221
222         return rc;
223 }
224
225 /*
226 ** allocate new refint_data;
227 ** store in on_bi.bi_private;
228 **
229 */
230
231 static int
232 refint_db_init(
233         BackendDB       *be
234 )
235 {
236         slap_overinst *on = (slap_overinst *)be->bd_info;
237         refint_data *id = ch_calloc(1,sizeof(refint_data));
238
239         id->message = "_init";
240         on->on_bi.bi_private = id;
241         return(0);
242 }
243
244 static int
245 refint_db_destroy(
246         BackendDB       *be
247 )
248 {
249         slap_overinst *on = (slap_overinst *)be->bd_info;
250
251         if ( on->on_bi.bi_private ) {
252                 ch_free( on->on_bi.bi_private );
253                 on->on_bi.bi_private = NULL;
254         }
255         return(0);
256 }
257
258 /*
259 ** initialize, copy basedn if not already set
260 **
261 */
262
263 static int
264 refint_open(
265         BackendDB *be
266 )
267 {
268         slap_overinst *on       = (slap_overinst *)be->bd_info;
269         refint_data *id = on->on_bi.bi_private;
270         id->message             = "_open";
271
272         if ( BER_BVISNULL( &id->dn )) {
273                 if ( BER_BVISNULL( &be->be_nsuffix[0] ))
274                         return -1;
275                 ber_dupbv( &id->dn, &be->be_nsuffix[0] );
276         }
277         return(0);
278 }
279
280
281 /*
282 ** foreach configured attribute:
283 **      free it;
284 ** free our basedn;
285 ** (do not) free id->message;
286 ** reset on_bi.bi_private;
287 ** free our config data;
288 **
289 */
290
291 static int
292 refint_close(
293         BackendDB *be
294 )
295 {
296         slap_overinst *on       = (slap_overinst *) be->bd_info;
297         refint_data *id = on->on_bi.bi_private;
298         refint_attrs *ii, *ij;
299         id->message             = "_close";
300
301         for(ii = id->attrs; ii; ii = ij) {
302                 ij = ii->next;
303                 ch_free(ii);
304         }
305
306         ch_free(id->dn.bv_val);
307         ch_free(id->nothing.bv_val);
308         ch_free(id->nnothing.bv_val);
309
310         memset( id, 0, sizeof(*id));
311
312         return(0);
313 }
314
315 /*
316 ** delete callback
317 ** generates a list of Modification* from search results
318 */
319
320 static int
321 refint_delete_cb(
322         Operation *op,
323         SlapReply *rs
324 )
325 {
326         Attribute *a;
327         BerVarray b = NULL;
328         refint_data *dd = op->o_callback->sc_private;
329         refint_attrs *ia, *da = dd->attrs;
330         dependent_data *ip;
331         Modifications *mp, *ma;
332         int i;
333
334         Debug(LDAP_DEBUG_TRACE, "refint_delete_cb <%s>\n",
335                 rs->sr_entry ? rs->sr_entry->e_name.bv_val : "NOTHING", 0, 0);
336
337         if (rs->sr_type != REP_SEARCH || !rs->sr_entry) return(0);
338         dd->message = "_delete_cb";
339
340         /*
341         ** foreach configured attribute type:
342         **      if this attr exists in the search result,
343         **      and it has a value matching the target:
344         **              allocate a Modification;
345         **              allocate its array of 2 BerValues;
346         **              if only one value, and we have a configured Nothing:
347         **                      allocate additional Modification
348         **                      type = MOD_ADD
349         **                      BerValues[] = { Nothing, NULL };
350         **                      add to list
351         **              type = MOD_DELETE
352         **              BerValues[] = { our target dn, NULL };
353         **      add this mod to the list of mods;
354         **
355         */
356
357         ip = ch_malloc(sizeof(dependent_data));
358         ip->dn.bv_val = NULL;
359         ip->next = NULL;
360         ip->mm = NULL;
361         ma = NULL;
362         for(ia = da; ia; ia = ia->next) {
363             if ( (a = attr_find(rs->sr_entry->e_attrs, ia->attr) ) )
364                 for(i = 0, b = a->a_nvals; b[i].bv_val; i++)
365                     if(bvmatch(&dd->dn, &b[i])) {
366                         if(!ip->dn.bv_val) ber_dupbv(&ip->dn, &rs->sr_entry->e_nname);
367                         if(!b[1].bv_val && dd->nothing.bv_val) {
368                                 mp = ch_malloc(sizeof(Modifications));
369                                 mp->sml_desc = ia->attr;                /* XXX */
370                                 mp->sml_type = a->a_desc->ad_cname;
371                                 mp->sml_values  = ch_malloc(2 * sizeof(BerValue));
372                                 mp->sml_nvalues = ch_malloc(2 * sizeof(BerValue));
373                                 mp->sml_values[1].bv_len = mp->sml_nvalues[1].bv_len = 0;
374                                 mp->sml_values[1].bv_val = mp->sml_nvalues[1].bv_val = NULL;
375
376                                 mp->sml_op = LDAP_MOD_ADD;
377                                 mp->sml_flags = 0;
378                                 ber_dupbv(&mp->sml_values[0],  &dd->nothing);
379                                 ber_dupbv(&mp->sml_nvalues[0], &dd->nnothing);
380                                 mp->sml_next = ma;
381                                 ma = mp;
382                         }
383                         /* this might violate the object class */
384                         mp = ch_malloc(sizeof(Modifications));
385                         mp->sml_desc = ia->attr;                /* XXX */
386                         mp->sml_type = a->a_desc->ad_cname;
387                         mp->sml_values  = ch_malloc(2 * sizeof(BerValue));
388                         mp->sml_nvalues = ch_malloc(2 * sizeof(BerValue));
389                         mp->sml_values[1].bv_len = mp->sml_nvalues[1].bv_len = 0;
390                         mp->sml_values[1].bv_val = mp->sml_nvalues[1].bv_val = NULL;
391                         mp->sml_op = LDAP_MOD_DELETE;
392                         mp->sml_flags = 0;
393                         ber_dupbv(&mp->sml_values[0], &dd->dn);
394                         ber_dupbv(&mp->sml_nvalues[0], &mp->sml_values[0]);
395                         mp->sml_next = ma;
396                         ma = mp;
397                         Debug(LDAP_DEBUG_TRACE, "refint_delete_cb: %s: %s\n",
398                                 a->a_desc->ad_cname.bv_val, dd->dn.bv_val, 0);
399                         break;
400             }
401         }
402         ip->mm = ma;
403         ip->next = dd->mods;
404         dd->mods = ip;
405
406         return(0);
407 }
408
409 /*
410 ** null callback
411 ** does nothing
412 */
413
414 static int
415 refint_null_cb(
416         Operation *op,
417         SlapReply *rs
418 )
419 {
420         ((refint_data *)op->o_callback->sc_private)->message = "_null_cb";
421         return(LDAP_SUCCESS);
422 }
423
424 /*
425 ** modrdn callback
426 ** generates a list of Modification* from search results
427 */
428
429 static int
430 refint_modrdn_cb(
431         Operation *op,
432         SlapReply *rs
433 )
434 {
435         Attribute *a;
436         BerVarray b = NULL;
437         refint_data *dd = op->o_callback->sc_private;
438         refint_attrs *ia, *da = dd->attrs;
439         dependent_data *ip = NULL;
440         Modifications *mp;
441         int i, fix;
442
443         Debug(LDAP_DEBUG_TRACE, "refint_modrdn_cb <%s>\n",
444                 rs->sr_entry ? rs->sr_entry->e_name.bv_val : "NOTHING", 0, 0);
445
446         if (rs->sr_type != REP_SEARCH || !rs->sr_entry) return(0);
447         dd->message = "_modrdn_cb";
448
449         /*
450         ** foreach configured attribute type:
451         **   if this attr exists in the search result,
452         **   and it has a value matching the target:
453         **      allocate a pair of Modifications;
454         **      make it MOD_ADD the new value and MOD_DELETE the old;
455         **      allocate its array of BerValues;
456         **      foreach value in the search result:
457         **         if it matches our target value, replace it;
458         **         otherwise, copy from the search result;
459         **      terminate the array of BerValues;
460         **   add these mods to the list of mods;
461         **
462         */
463
464         for(ia = da; ia; ia = ia->next) {
465             if((a = attr_find(rs->sr_entry->e_attrs, ia->attr))) {
466                     for(fix = 0, i = 0, b = a->a_nvals; b[i].bv_val; i++)
467                         if(bvmatch(&dd->dn, &b[i])) { fix++; break; }
468                     if(fix) {
469                         if (!ip) {
470                             ip = ch_malloc(sizeof(dependent_data));
471                             ip->next = NULL;
472                             ip->mm = NULL;
473                             ber_dupbv(&ip->dn, &rs->sr_entry->e_nname);
474                         }
475                         mp = ch_malloc(sizeof(Modifications));
476                         mp->sml_op = LDAP_MOD_ADD;
477                         mp->sml_flags = 0;
478                         mp->sml_desc = ia->attr;                /* XXX */
479                         mp->sml_type = ia->attr->ad_cname;
480                         mp->sml_values  = ch_malloc(2 * sizeof(BerValue));
481                         mp->sml_nvalues = ch_malloc(2 * sizeof(BerValue));
482                         ber_dupbv(&mp->sml_values[0], &dd->newdn);
483                         ber_dupbv(&mp->sml_nvalues[0], &dd->nnewdn);
484                         mp->sml_values[1].bv_len = mp->sml_nvalues[1].bv_len = 0;
485                         mp->sml_values[1].bv_val = mp->sml_nvalues[1].bv_val = NULL;
486                         mp->sml_next = ip->mm;
487                         ip->mm = mp;
488                         mp = ch_malloc(sizeof(Modifications));
489                         mp->sml_op = LDAP_MOD_DELETE;
490                         mp->sml_flags = 0;
491                         mp->sml_desc = ia->attr;                /* XXX */
492                         mp->sml_type = ia->attr->ad_cname;
493                         mp->sml_values  = ch_malloc(2 * sizeof(BerValue));
494                         mp->sml_nvalues = ch_malloc(2 * sizeof(BerValue));
495                         ber_dupbv(&mp->sml_values[0], &dd->dn);
496                         ber_dupbv(&mp->sml_nvalues[0], &dd->dn);
497                         mp->sml_values[1].bv_len = mp->sml_nvalues[1].bv_len = 0;
498                         mp->sml_values[1].bv_val = mp->sml_nvalues[1].bv_val = NULL;
499                         mp->sml_next = ip->mm;
500                         ip->mm = mp;
501                         Debug(LDAP_DEBUG_TRACE, "refint_modrdn_cb: %s: %s\n",
502                                 a->a_desc->ad_cname.bv_val, dd->dn.bv_val, 0);
503                 }
504             }
505         }
506         if (ip) {
507                 ip->next = dd->mods;
508                 dd->mods = ip;
509         }
510
511         return(0);
512 }
513
514
515 /*
516 ** refint_response
517 ** search for matching records and modify them
518 */
519
520 static int
521 refint_response(
522         Operation *op,
523         SlapReply *rs
524 )
525 {
526         Operation nop = *op;
527         SlapReply nrs = { REP_RESULT };
528         slap_callback cb = { NULL, NULL, NULL, NULL };
529         slap_callback cb2 = { NULL, slap_replog_cb, NULL, NULL };
530         slap_callback *cbo, *cbp;
531         slap_overinst *on = (slap_overinst *) op->o_bd->bd_info;
532         refint_data *id = on->on_bi.bi_private;
533         refint_data dd = *id;
534         refint_attrs *ip;
535         dependent_data *dp;
536         BerValue pdn;
537         int rc, ac;
538         Filter ftop, *fptr;
539
540         id->message = "_refint_response";
541
542         /* If the main op failed or is not a Delete or ModRdn, ignore it */
543         if (( op->o_tag != LDAP_REQ_DELETE && op->o_tag != LDAP_REQ_MODRDN ) ||
544                 rs->sr_err != LDAP_SUCCESS )
545                 return SLAP_CB_CONTINUE;
546
547         /*
548         ** validate (and count) the list of attrs;
549         **
550         */
551
552         for(ip = id->attrs, ac = 0; ip; ip = ip->next, ac++);
553         if(!ac) {
554                 Debug( LDAP_DEBUG_TRACE,
555                         "refint_response called without any attributes\n", 0, 0, 0 );
556                 return SLAP_CB_CONTINUE;
557         }
558
559         /*
560         ** find the backend that matches our configured basedn;
561         ** make sure it exists and has search and modify methods;
562         **
563         */
564
565         nop.o_bd = select_backend(&id->dn, 0, 1);
566
567         if(nop.o_bd) {
568                 if (!nop.o_bd->be_search || !nop.o_bd->be_modify) {
569                         Debug( LDAP_DEBUG_TRACE,
570                                 "refint_response: backend missing search and/or modify\n",
571                                 0, 0, 0 );
572                         return SLAP_CB_CONTINUE;
573                 }
574         } else {
575                 Debug( LDAP_DEBUG_TRACE,
576                         "refint_response: no backend for our baseDN %s??\n",
577                         id->dn.bv_val, 0, 0 );
578                 return SLAP_CB_CONTINUE;
579         }
580
581         cb2.sc_next = &cb;
582
583         /*
584         ** if delete: set delete callback;
585         ** else modrdn: create a newdn, set modify callback;
586         **
587         */
588
589         if(op->o_tag == LDAP_REQ_DELETE) {
590                 cb.sc_response = &refint_delete_cb;
591                 dd.newdn.bv_val = NULL;
592                 dd.nnewdn.bv_val = NULL;
593         } else {
594                 cb.sc_response = &refint_modrdn_cb;
595                 if ( op->oq_modrdn.rs_newSup ) {
596                         pdn = *op->oq_modrdn.rs_newSup;
597                 } else {
598                         dnParent( &op->o_req_dn, &pdn );
599                 }
600                 build_new_dn( &dd.newdn, &pdn, &op->orr_newrdn, NULL );
601                 if ( op->oq_modrdn.rs_nnewSup ) {
602                         pdn = *op->oq_modrdn.rs_nnewSup;
603                 } else {
604                         dnParent( &op->o_req_ndn, &pdn );
605                 }
606                 build_new_dn( &dd.nnewdn, &pdn, &op->orr_nnewrdn, NULL );
607         }
608
609         /*
610         ** build a search filter for all configured attributes;
611         ** populate our Operation;
612         ** pass our data (attr list, dn) to backend via sc_private;
613         ** call the backend search function;
614         ** nb: (|(one=thing)) is valid, but do smart formatting anyway;
615         ** nb: 16 is arbitrarily a dozen or so extra bytes;
616         **
617         */
618
619         ftop.f_choice = LDAP_FILTER_OR;
620         ftop.f_next = NULL;
621         ftop.f_or = NULL;
622         nop.ors_filter = &ftop;
623         for(ip = id->attrs; ip; ip = ip->next) {
624                 fptr = ch_malloc( sizeof(Filter) + sizeof(AttributeAssertion) );
625                 fptr->f_choice = LDAP_FILTER_EQUALITY;
626                 fptr->f_ava = (AttributeAssertion *)(fptr+1);
627                 fptr->f_ava->aa_desc = ip->attr;
628                 fptr->f_ava->aa_value = op->o_req_ndn;
629                 fptr->f_next = ftop.f_or;
630                 ftop.f_or = fptr;
631         }
632         filter2bv( nop.ors_filter, &nop.ors_filterstr );
633
634         /* callback gets the searched dn instead */
635         dd.dn = op->o_req_ndn;
636         dd.message      = "_dependent_search";
637         dd.mods         = NULL;
638         cb.sc_private   = &dd;
639         nop.o_callback  = &cb;
640         nop.o_tag       = LDAP_REQ_SEARCH;
641         nop.ors_scope   = LDAP_SCOPE_SUBTREE;
642         nop.ors_deref   = LDAP_DEREF_NEVER;
643         nop.ors_limit   = NULL;
644         nop.ors_slimit  = SLAP_NO_LIMIT;
645         nop.ors_tlimit  = SLAP_NO_LIMIT;
646
647         /* no attrs! */
648         nop.ors_attrs = slap_anlist_no_attrs;
649         nop.ors_attrsonly = 1;
650
651         nop.o_req_ndn = id->dn;
652         nop.o_req_dn = id->dn;
653
654         /* search */
655         rc = nop.o_bd->be_search(&nop, &nrs);
656
657         ch_free( nop.ors_filterstr.bv_val );
658         while ( (fptr = ftop.f_or) != NULL ) {
659                 ftop.f_or = fptr->f_next;
660                 ch_free( fptr );
661         }
662         ch_free(dd.nnewdn.bv_val);
663         ch_free(dd.newdn.bv_val);
664         dd.newdn.bv_val = NULL;
665         dd.nnewdn.bv_val = NULL;
666
667         if(rc != LDAP_SUCCESS) {
668                 Debug( LDAP_DEBUG_TRACE,
669                         "refint_response: search failed: %d\n",
670                         rc, 0, 0 );
671                 goto done;
672         }
673
674         /* safety? paranoid just in case */
675         if(!cb.sc_private) {
676                 Debug( LDAP_DEBUG_TRACE,
677                         "refint_response: callback wiped out sc_private?!\n",
678                         0, 0, 0 );
679                 goto done;
680         }
681
682         /* presto! now it's a modify request with null callback */
683         cb.sc_response  = &refint_null_cb;
684         nop.o_tag       = LDAP_REQ_MODIFY;
685         dd.message      = "_dependent_modify";
686
687         /* See if the parent operation is going into the replog */
688         for (cbo=op->o_callback, cbp = cbo->sc_next; cbp; cbo=cbp,cbp=cbp->sc_next) {
689                 if (cbp->sc_response == slap_replog_cb) {
690                         /* Invoke replog now, arrange for our
691                          * dependent mods to also be logged
692                          */
693                         cbo->sc_next = cbp->sc_next;
694                         replog( op );
695                         nop.o_callback = &cb2;
696                         break;
697                 }
698         }
699
700         /*
701         ** [our search callback builds a list of mods]
702         ** foreach mod:
703         **      make sure its dn has a backend;
704         **      connect Modification* chain to our op;
705         **      call the backend modify function;
706         **      pass any errors upstream;
707         **
708         */
709
710         for(dp = dd.mods; dp; dp = dp->next) {
711                 nop.o_req_dn    = dp->dn;
712                 nop.o_req_ndn   = dp->dn;
713                 nop.o_bd = select_backend(&dp->dn, 0, 1);
714                 if(!nop.o_bd) {
715                         Debug( LDAP_DEBUG_TRACE,
716                                 "refint_response: no backend for DN %s!\n",
717                                 dp->dn.bv_val, 0, 0 );
718                         goto done;
719                 }
720                 nrs.sr_type     = REP_RESULT;
721                 nop.orm_modlist = dp->mm;       /* callback did all the work */
722                 nop.o_dn = refint_dn;
723                 nop.o_ndn = refint_dn;
724                 nop.o_dn = nop.o_bd->be_rootdn;
725                 nop.o_ndn = nop.o_bd->be_rootndn;
726                 if(rs->sr_err != LDAP_SUCCESS) goto done;
727                 if((rc = nop.o_bd->be_modify(&nop, &nrs)) != LDAP_SUCCESS) {
728                         Debug( LDAP_DEBUG_TRACE,
729                                 "refint_response: dependent modify failed: %d\n",
730                                 nrs.sr_err, 0, 0 );
731                         goto done;
732                 }
733         }
734
735 done:
736         for(dp = dd.mods; dp; dp = dd.mods) {
737                 dd.mods = dp->next;
738                 ch_free(dp->dn.bv_val);
739                 slap_mods_free(dp->mm, 1);
740         }
741         dd.mods = NULL;
742
743         return(SLAP_CB_CONTINUE);
744 }
745
746 /*
747 ** init_module is last so the symbols resolve "for free" --
748 ** it expects to be called automagically during dynamic module initialization
749 */
750
751 int refint_initialize() {
752         int rc;
753
754         /* statically declared just after the #includes at top */
755         refint.on_bi.bi_type = "refint";
756         refint.on_bi.bi_db_init = refint_db_init;
757         refint.on_bi.bi_db_destroy = refint_db_destroy;
758         refint.on_bi.bi_db_open = refint_open;
759         refint.on_bi.bi_db_close = refint_close;
760         refint.on_response = refint_response;
761
762         refint.on_bi.bi_cf_ocs = refintocs;
763         rc = config_register_schema ( refintcfg, refintocs );
764         if ( rc ) return rc;
765
766         return(overlay_register(&refint));
767 }
768
769 #if SLAPD_OVER_REFINT == SLAPD_MOD_DYNAMIC && defined(PIC)
770 int init_module(int argc, char *argv[]) {
771         return refint_initialize();
772 }
773 #endif
774
775 #endif /* SLAPD_OVER_REFINT */