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