1 /* refint.c - referential integrity module */
2 /* $OpenLDAP: pkg/ldap/servers/slapd/overlays/refint.c,v 1.19.2.9 2008/05/27 20:18:19 quanah Exp $ */
3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
5 * Copyright 2004-2008 The OpenLDAP Foundation.
6 * Portions Copyright 2004 Symas Corporation.
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted only as authorized by the OpenLDAP
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>.
18 * This work was initially developed by Symas Corp. for inclusion in
19 * OpenLDAP Software. This work was sponsored by Hewlett-Packard.
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.
29 * Updates are performed using the database rootdn in a separate task
30 * to allow the original operation to complete immediately.
33 #ifdef SLAPD_OVER_REFINT
37 #include <ac/string.h>
38 #include <ac/socket.h>
44 static slap_overinst refint
;
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");
50 typedef struct refint_attrs_s
{
51 struct refint_attrs_s
*next
;
52 AttributeDescription
*attr
;
60 typedef struct dependents_s
{
61 struct dependents_s
*next
;
62 BerValue dn
; /* target dn */
67 typedef struct refint_q
{
68 struct refint_q
*next
;
69 struct refint_data_s
*rdata
;
70 dependent_data
*attrs
; /* entries and attrs returned from callback */
78 typedef struct refint_data_s
{
79 const char *message
; /* breadcrumbs */
80 struct refint_attrs_s
*attrs
; /* list of known attrs */
81 BerValue dn
; /* basedn in parent, */
82 BerValue nothing
; /* the nothing value, if needed */
83 BerValue nnothing
; /* normalized nothingness */
84 BerValue refint_dn
; /* modifier's name */
85 BerValue refint_ndn
; /* normalized modifier's name */
89 ldap_pvt_thread_mutex_t qmutex
;
92 #define RUNQ_INTERVAL 36000 /* a long time */
94 static MatchingRule
*mr_dnSubtreeMatch
;
102 static ConfigDriver refint_cf_gen
;
104 static ConfigTable refintcfg
[] = {
105 { "refint_attributes", "attribute...", 2, 0, 0,
106 ARG_MAGIC
|REFINT_ATTRS
, refint_cf_gen
,
107 "( OLcfgOvAt:11.1 NAME 'olcRefintAttribute' "
108 "DESC 'Attributes for referential integrity' "
109 "EQUALITY caseIgnoreMatch "
110 "SYNTAX OMsDirectoryString )", NULL
, NULL
},
111 { "refint_nothing", "string", 2, 2, 0,
112 ARG_DN
|ARG_MAGIC
|REFINT_NOTHING
, refint_cf_gen
,
113 "( OLcfgOvAt:11.2 NAME 'olcRefintNothing' "
114 "DESC 'Replacement DN to supply when needed' "
115 "SYNTAX OMsDN SINGLE-VALUE )", NULL
, NULL
},
116 { "refint_modifiersName", "DN", 2, 2, 0,
117 ARG_DN
|ARG_MAGIC
|REFINT_MODIFIERSNAME
, refint_cf_gen
,
118 "( OLcfgOvAt:11.3 NAME 'olcRefintModifiersName' "
119 "DESC 'The DN to use as modifiersName' "
120 "SYNTAX OMsDN SINGLE-VALUE )", NULL
, NULL
},
121 { NULL
, NULL
, 0, 0, 0, ARG_IGNORED
}
124 static ConfigOCs refintocs
[] = {
125 { "( OLcfgOvOc:11.1 "
126 "NAME 'olcRefintConfig' "
127 "DESC 'Referential integrity configuration' "
128 "SUP olcOverlayConfig "
129 "MAY ( olcRefintAttribute "
130 "$ olcRefintNothing "
131 "$ olcRefintModifiersName "
133 Cft_Overlay
, refintcfg
},
138 refint_cf_gen(ConfigArgs
*c
)
140 slap_overinst
*on
= (slap_overinst
*)c
->bi
;
141 refint_data
*dd
= (refint_data
*)on
->on_bi
.bi_private
;
142 refint_attrs
*ip
, *pip
, **pipp
= NULL
;
143 AttributeDescription
*ad
;
145 int rc
= ARG_BAD_CONF
;
149 case SLAP_CONFIG_EMIT
:
154 value_add_one( &c
->rvalue_vals
,
155 &ip
->attr
->ad_cname
);
161 if ( !BER_BVISEMPTY( &dd
->nothing
)) {
162 rc
= value_add_one( &c
->rvalue_vals
,
165 rc
= value_add_one( &c
->rvalue_nvals
,
171 case REFINT_MODIFIERSNAME
:
172 if ( !BER_BVISEMPTY( &dd
->refint_dn
)) {
173 rc
= value_add_one( &c
->rvalue_vals
,
176 rc
= value_add_one( &c
->rvalue_nvals
,
186 case LDAP_MOD_DELETE
:
199 /* delete from linked list */
200 for ( i
=0; i
< c
->valx
; ++i
) {
201 pipp
= &(*pipp
)->next
;
204 *pipp
= (*pipp
)->next
;
206 /* AttributeDescriptions are global so
207 * shouldn't be freed here... */
213 if ( dd
->nothing
.bv_val
)
214 ber_memfree ( dd
->nothing
.bv_val
);
215 if ( dd
->nnothing
.bv_val
)
216 ber_memfree ( dd
->nnothing
.bv_val
);
217 dd
->nothing
.bv_len
= 0;
218 dd
->nnothing
.bv_len
= 0;
221 case REFINT_MODIFIERSNAME
:
222 if ( dd
->refint_dn
.bv_val
)
223 ber_memfree ( dd
->refint_dn
.bv_val
);
224 if ( dd
->refint_ndn
.bv_val
)
225 ber_memfree ( dd
->refint_ndn
.bv_val
);
226 dd
->refint_dn
.bv_len
= 0;
227 dd
->refint_ndn
.bv_len
= 0;
234 case SLAP_CONFIG_ADD
:
235 /* fallthrough to LDAP_MOD_ADD */
240 for ( i
=1; i
< c
->argc
; ++i
) {
242 if ( slap_str2ad ( c
->argv
[i
], &ad
, &text
)
245 sizeof ( refint_attrs
) );
247 ip
->next
= dd
->attrs
;
250 snprintf( c
->cr_msg
, sizeof( c
->cr_msg
),
251 "%s <%s>: %s", c
->argv
[0], c
->argv
[i
], text
);
252 Debug ( LDAP_DEBUG_CONFIG
|LDAP_DEBUG_NONE
,
253 "%s: %s\n", c
->log
, c
->cr_msg
, 0 );
259 if ( dd
->nothing
.bv_val
)
260 ber_memfree ( dd
->nothing
.bv_val
);
261 if ( dd
->nnothing
.bv_val
)
262 ber_memfree ( dd
->nnothing
.bv_val
);
263 dd
->nothing
= c
->value_dn
;
264 dd
->nnothing
= c
->value_ndn
;
267 case REFINT_MODIFIERSNAME
:
268 if ( dd
->refint_dn
.bv_val
)
269 ber_memfree ( dd
->refint_dn
.bv_val
);
270 if ( dd
->refint_ndn
.bv_val
)
271 ber_memfree ( dd
->refint_ndn
.bv_val
);
272 dd
->refint_dn
= c
->value_dn
;
273 dd
->refint_ndn
= c
->value_ndn
;
288 ** allocate new refint_data;
289 ** store in on_bi.bi_private;
299 slap_overinst
*on
= (slap_overinst
*)be
->bd_info
;
300 refint_data
*id
= ch_calloc(1,sizeof(refint_data
));
302 id
->message
= "_init";
303 on
->on_bi
.bi_private
= id
;
304 ldap_pvt_thread_mutex_init( &id
->qmutex
);
314 slap_overinst
*on
= (slap_overinst
*)be
->bd_info
;
316 if ( on
->on_bi
.bi_private
) {
317 refint_data
*id
= on
->on_bi
.bi_private
;
318 on
->on_bi
.bi_private
= NULL
;
319 ldap_pvt_thread_mutex_destroy( &id
->qmutex
);
326 ** initialize, copy basedn if not already set
336 slap_overinst
*on
= (slap_overinst
*)be
->bd_info
;
337 refint_data
*id
= on
->on_bi
.bi_private
;
338 id
->message
= "_open";
340 if ( BER_BVISNULL( &id
->dn
)) {
341 if ( BER_BVISNULL( &be
->be_nsuffix
[0] ))
343 ber_dupbv( &id
->dn
, &be
->be_nsuffix
[0] );
345 if ( BER_BVISNULL( &id
->refint_dn
) ) {
346 ber_dupbv( &id
->refint_dn
, &refint_dn
);
347 ber_dupbv( &id
->refint_ndn
, &refint_ndn
);
354 ** foreach configured attribute:
357 ** (do not) free id->message;
358 ** reset on_bi.bi_private;
359 ** free our config data;
369 slap_overinst
*on
= (slap_overinst
*) be
->bd_info
;
370 refint_data
*id
= on
->on_bi
.bi_private
;
371 refint_attrs
*ii
, *ij
;
372 id
->message
= "_close";
374 for(ii
= id
->attrs
; ii
; ii
= ij
) {
380 ch_free( id
->dn
.bv_val
);
381 BER_BVZERO( &id
->dn
);
382 ch_free( id
->nothing
.bv_val
);
383 BER_BVZERO( &id
->nothing
);
384 ch_free( id
->nnothing
.bv_val
);
385 BER_BVZERO( &id
->nnothing
);
386 ch_free( id
->refint_dn
.bv_val
);
387 BER_BVZERO( &id
->refint_dn
);
388 ch_free( id
->refint_ndn
.bv_val
);
389 BER_BVZERO( &id
->refint_ndn
);
396 ** generates a list of Attributes from search results
407 refint_q
*rq
= op
->o_callback
->sc_private
;
408 refint_data
*dd
= rq
->rdata
;
409 refint_attrs
*ia
, *da
= dd
->attrs
, *na
;
413 Debug(LDAP_DEBUG_TRACE
, "refint_search_cb <%s>\n",
414 rs
->sr_entry
? rs
->sr_entry
->e_name
.bv_val
: "NOTHING", 0, 0);
416 if (rs
->sr_type
!= REP_SEARCH
|| !rs
->sr_entry
) return(0);
419 ** foreach configured attribute type:
420 ** if this attr exists in the search result,
421 ** and it has a value matching the target:
423 ** if this is a delete and there's only one value:
424 ** allocate the same attr again;
428 ip
= op
->o_tmpalloc(sizeof(dependent_data
), op
->o_tmpmemctx
);
429 ber_dupbv_x( &ip
->dn
, &rs
->sr_entry
->e_name
, op
->o_tmpmemctx
);
430 ber_dupbv_x( &ip
->ndn
, &rs
->sr_entry
->e_nname
, op
->o_tmpmemctx
);
431 ip
->next
= rq
->attrs
;
434 for(ia
= da
; ia
; ia
= ia
->next
) {
435 if ( (a
= attr_find(rs
->sr_entry
->e_attrs
, ia
->attr
) ) ) {
436 int first
= -1, count
= 0, deleted
= 0;
440 for(i
= 0, b
= a
->a_nvals
; b
[i
].bv_val
; i
++) {
443 if(dnIsSuffix(&b
[i
], &rq
->oldndn
)) {
444 /* first match? create structure */
446 na
= op
->o_tmpcalloc( 1,
447 sizeof( refint_attrs
),
449 na
->next
= ip
->attrs
;
453 /* delete, or exact match? note it's first match */
454 if ( BER_BVISEMPTY( &rq
->newdn
) &&
455 b
[i
].bv_len
== rq
->oldndn
.bv_len
)
461 /* if it's a rename, or a subordinate match,
462 * save old and build new dn */
463 if ( !BER_BVISEMPTY( &rq
->newdn
) &&
464 b
[i
].bv_len
!= rq
->oldndn
.bv_len
)
466 struct berval newsub
, newdn
, olddn
, oldndn
;
468 /* if not first, save first as well */
471 ber_dupbv_x( &olddn
, &a
->a_vals
[first
], op
->o_tmpmemctx
);
472 ber_bvarray_add_x( &na
->old_vals
, &olddn
, op
->o_tmpmemctx
);
473 ber_dupbv_x( &oldndn
, &a
->a_nvals
[first
], op
->o_tmpmemctx
);
474 ber_bvarray_add_x( &na
->old_nvals
, &oldndn
, op
->o_tmpmemctx
);
477 newsub
= a
->a_vals
[first
];
478 newsub
.bv_len
-= rq
->olddn
.bv_len
+ 1;
480 build_new_dn( &newdn
, &rq
->newdn
, &newsub
, op
->o_tmpmemctx
);
482 ber_bvarray_add_x( &na
->new_vals
, &newdn
, op
->o_tmpmemctx
);
484 newsub
= a
->a_nvals
[first
];
485 newsub
.bv_len
-= rq
->oldndn
.bv_len
+ 1;
487 build_new_dn( &newdn
, &rq
->newndn
, &newsub
, op
->o_tmpmemctx
);
489 ber_bvarray_add_x( &na
->new_nvals
, &newdn
, op
->o_tmpmemctx
);
494 ber_dupbv_x( &olddn
, &a
->a_vals
[i
], op
->o_tmpmemctx
);
495 ber_bvarray_add_x( &na
->old_vals
, &olddn
, op
->o_tmpmemctx
);
496 ber_dupbv_x( &oldndn
, &a
->a_nvals
[i
], op
->o_tmpmemctx
);
497 ber_bvarray_add_x( &na
->old_nvals
, &oldndn
, op
->o_tmpmemctx
);
500 newsub
= a
->a_vals
[i
];
501 newsub
.bv_len
-= rq
->olddn
.bv_len
+ 1;
503 build_new_dn( &newdn
, &rq
->newdn
, &newsub
, op
->o_tmpmemctx
);
505 ber_bvarray_add_x( &na
->new_vals
, &newdn
, op
->o_tmpmemctx
);
507 newsub
= a
->a_nvals
[i
];
508 newsub
.bv_len
-= rq
->oldndn
.bv_len
+ 1;
510 build_new_dn( &newdn
, &rq
->newndn
, &newsub
, op
->o_tmpmemctx
);
512 ber_bvarray_add_x( &na
->new_nvals
, &newdn
, op
->o_tmpmemctx
);
516 if ( BER_BVISEMPTY( &rq
->newdn
) ) {
521 /* If this is a delete and no value would be left, and
522 * we have a nothing DN configured, allocate the attr again.
524 if ( count
== deleted
&& !BER_BVISNULL(&dd
->nothing
) )
526 na
= op
->o_tmpcalloc( 1,
527 sizeof( refint_attrs
),
529 na
->next
= ip
->attrs
;
534 Debug( LDAP_DEBUG_TRACE
, "refint_search_cb: %s: %s (#%d)\n",
535 a
->a_desc
->ad_cname
.bv_val
, rq
->olddn
.bv_val
, count
);
550 dependent_data
*dp
, *dp_next
;
553 op
->o_callback
->sc_response
= refint_search_cb
;
554 op
->o_req_dn
= op
->o_bd
->be_suffix
[ 0 ];
555 op
->o_req_ndn
= op
->o_bd
->be_nsuffix
[ 0 ];
556 op
->o_dn
= op
->o_bd
->be_rootdn
;
557 op
->o_ndn
= op
->o_bd
->be_rootndn
;
560 rc
= op
->o_bd
->be_search( op
, rs
);
562 if ( rc
!= LDAP_SUCCESS
) {
563 Debug( LDAP_DEBUG_TRACE
,
564 "refint_repair: search failed: %d\n",
569 /* safety? paranoid just in case */
570 if ( op
->o_callback
->sc_private
== NULL
) {
571 Debug( LDAP_DEBUG_TRACE
,
572 "refint_repair: callback wiped out sc_private?!\n",
577 /* Set up the Modify requests */
578 op
->o_callback
->sc_response
= &slap_null_cb
;
581 * [our search callback builds a list of attrs]
583 * make sure its dn has a backend;
584 * build Modification* chain;
585 * call the backend modify function;
589 for ( dp
= rq
->attrs
; dp
; dp
= dp_next
) {
591 SlapReply rs2
= { 0 };
593 Modifications
*m
, *first
= NULL
;
597 op2
.o_tag
= LDAP_REQ_MODIFY
;
598 op2
.orm_modlist
= NULL
;
599 op2
.o_req_dn
= dp
->dn
;
600 op2
.o_req_ndn
= dp
->ndn
;
601 op2
.o_bd
= select_backend( &dp
->ndn
, 1 );
603 Debug( LDAP_DEBUG_TRACE
,
604 "refint_repair: no backend for DN %s!\n",
605 dp
->dn
.bv_val
, 0, 0 );
609 rs2
.sr_type
= REP_RESULT
;
610 for ( ra
= dp
->attrs
; ra
; ra
= dp
->attrs
) {
613 dp
->attrs
= ra
->next
;
614 /* Set our ModifiersName */
615 if ( SLAP_LASTMOD( op
->o_bd
) ) {
616 m
= op2
.o_tmpalloc( sizeof(Modifications
) +
617 4*sizeof(BerValue
), op2
.o_tmpmemctx
);
618 m
->sml_next
= op2
.orm_modlist
;
622 m
->sml_op
= LDAP_MOD_REPLACE
;
623 m
->sml_flags
= SLAP_MOD_INTERNAL
;
624 m
->sml_desc
= slap_schema
.si_ad_modifiersName
;
625 m
->sml_type
= m
->sml_desc
->ad_cname
;
627 m
->sml_values
= (BerVarray
)(m
+1);
628 m
->sml_nvalues
= m
->sml_values
+2;
629 BER_BVZERO( &m
->sml_values
[1] );
630 BER_BVZERO( &m
->sml_nvalues
[1] );
631 m
->sml_values
[0] = id
->refint_dn
;
632 m
->sml_nvalues
[0] = id
->refint_ndn
;
634 if ( !BER_BVISEMPTY( &rq
->newdn
) || ( ra
->next
&&
635 ra
->attr
== ra
->next
->attr
) )
637 len
= sizeof(Modifications
);
639 if ( ra
->new_vals
== NULL
) {
640 len
+= 4*sizeof(BerValue
);
643 m
= op2
.o_tmpalloc( len
, op2
.o_tmpmemctx
);
644 m
->sml_next
= op2
.orm_modlist
;
648 m
->sml_op
= LDAP_MOD_ADD
;
650 m
->sml_desc
= ra
->attr
;
651 m
->sml_type
= ra
->attr
->ad_cname
;
652 if ( ra
->new_vals
== NULL
) {
653 m
->sml_values
= (BerVarray
)(m
+1);
654 m
->sml_nvalues
= m
->sml_values
+2;
655 BER_BVZERO( &m
->sml_values
[1] );
656 BER_BVZERO( &m
->sml_nvalues
[1] );
658 if ( BER_BVISEMPTY( &rq
->newdn
) ) {
659 op2
.o_tmpfree( ra
, op2
.o_tmpmemctx
);
661 dp
->attrs
= ra
->next
;
662 m
->sml_values
[0] = id
->nothing
;
663 m
->sml_nvalues
[0] = id
->nnothing
;
665 m
->sml_values
[0] = rq
->newdn
;
666 m
->sml_nvalues
[0] = rq
->newndn
;
669 m
->sml_values
= ra
->new_vals
;
670 m
->sml_nvalues
= ra
->new_nvals
;
671 m
->sml_numvals
= ra
->ra_numvals
;
675 len
= sizeof(Modifications
);
676 if ( ra
->old_vals
== NULL
) {
677 len
+= 4*sizeof(BerValue
);
680 m
= op2
.o_tmpalloc( len
, op2
.o_tmpmemctx
);
681 m
->sml_next
= op2
.orm_modlist
;
685 m
->sml_op
= LDAP_MOD_DELETE
;
687 m
->sml_desc
= ra
->attr
;
688 m
->sml_type
= ra
->attr
->ad_cname
;
689 if ( ra
->old_vals
== NULL
) {
691 m
->sml_values
= (BerVarray
)(m
+1);
692 m
->sml_nvalues
= m
->sml_values
+2;
693 m
->sml_values
[0] = rq
->olddn
;
694 m
->sml_nvalues
[0] = rq
->oldndn
;
695 BER_BVZERO( &m
->sml_values
[1] );
696 BER_BVZERO( &m
->sml_nvalues
[1] );
698 m
->sml_values
= ra
->old_vals
;
699 m
->sml_nvalues
= ra
->old_nvals
;
700 m
->sml_numvals
= ra
->ra_numvals
;
702 op2
.o_tmpfree( ra
, op2
.o_tmpmemctx
);
705 op2
.o_dn
= op2
.o_bd
->be_rootdn
;
706 op2
.o_ndn
= op2
.o_bd
->be_rootndn
;
707 slap_op_time( &op2
.o_time
, &op2
.o_tincr
);
708 if ( ( rc
= op2
.o_bd
->be_modify( &op2
, &rs2
) ) != LDAP_SUCCESS
) {
709 Debug( LDAP_DEBUG_TRACE
,
710 "refint_repair: dependent modify failed: %d\n",
714 while ( ( m
= op2
.orm_modlist
) ) {
715 op2
.orm_modlist
= m
->sml_next
;
716 if ( m
->sml_values
&& m
->sml_values
!= (BerVarray
)(m
+1) ) {
717 ber_bvarray_free_x( m
->sml_values
, op2
.o_tmpmemctx
);
718 ber_bvarray_free_x( m
->sml_nvalues
, op2
.o_tmpmemctx
);
720 op2
.o_tmpfree( m
, op2
.o_tmpmemctx
);
721 if ( m
== first
) break;
723 slap_mods_free( op2
.orm_modlist
, 1 );
724 op2
.o_tmpfree( dp
->ndn
.bv_val
, op2
.o_tmpmemctx
);
725 op2
.o_tmpfree( dp
->dn
.bv_val
, op2
.o_tmpmemctx
);
726 op2
.o_tmpfree( dp
, op2
.o_tmpmemctx
);
733 refint_qtask( void *ctx
, void *arg
)
735 struct re_s
*rtask
= arg
;
736 refint_data
*id
= rtask
->arg
;
737 Connection conn
= {0};
738 OperationBuffer opbuf
;
740 SlapReply rs
= {REP_RESULT
};
741 slap_callback cb
= { NULL
, NULL
, NULL
, NULL
};
746 connection_fake_init( &conn
, &opbuf
, ctx
);
750 ** build a search filter for all configured attributes;
751 ** populate our Operation;
752 ** pass our data (attr list, dn) to backend via sc_private;
753 ** call the backend search function;
754 ** nb: (|(one=thing)) is valid, but do smart formatting anyway;
755 ** nb: 16 is arbitrarily a dozen or so extra bytes;
759 ftop
.f_choice
= LDAP_FILTER_OR
;
762 op
->ors_filter
= &ftop
;
763 for(ip
= id
->attrs
; ip
; ip
= ip
->next
) {
764 fptr
= op
->o_tmpcalloc( sizeof(Filter
) + sizeof(MatchingRuleAssertion
),
765 1, op
->o_tmpmemctx
);
766 /* Use (attr:dnSubtreeMatch:=value) to catch subtree rename
767 * and subtree delete where supported */
768 fptr
->f_choice
= LDAP_FILTER_EXT
;
769 fptr
->f_mra
= (MatchingRuleAssertion
*)(fptr
+1);
770 fptr
->f_mr_rule
= mr_dnSubtreeMatch
;
771 fptr
->f_mr_rule_text
= mr_dnSubtreeMatch
->smr_bvoid
;
772 fptr
->f_mr_desc
= ip
->attr
;
773 fptr
->f_mr_dnattrs
= 0;
774 fptr
->f_next
= ftop
.f_or
;
780 ldap_pvt_thread_mutex_lock( &id
->qmutex
);
783 id
->qhead
= rq
->next
;
787 ldap_pvt_thread_mutex_unlock( &id
->qmutex
);
791 for (fptr
= ftop
.f_or
; fptr
; fptr
= fptr
->f_next
)
792 fptr
->f_mr_value
= rq
->oldndn
;
794 filter2bv_x( op
, op
->ors_filter
, &op
->ors_filterstr
);
796 /* callback gets the searched dn instead */
798 cb
.sc_response
= refint_search_cb
;
799 op
->o_callback
= &cb
;
800 op
->o_tag
= LDAP_REQ_SEARCH
;
801 op
->ors_scope
= LDAP_SCOPE_SUBTREE
;
802 op
->ors_deref
= LDAP_DEREF_NEVER
;
803 op
->ors_limit
= NULL
;
804 op
->ors_slimit
= SLAP_NO_LIMIT
;
805 op
->ors_tlimit
= SLAP_NO_LIMIT
;
808 op
->ors_attrs
= slap_anlist_no_attrs
;
810 slap_op_time( &op
->o_time
, &op
->o_tincr
);
812 if ( rq
->db
!= NULL
) {
814 refint_repair( op
, &rs
, id
, rq
);
819 LDAP_STAILQ_FOREACH( be
, &backendDB
, be_next
) {
820 /* we may want to skip cn=config */
821 if ( be
== LDAP_STAILQ_FIRST(&backendDB
) ) {
825 if ( be
->be_search
&& be
->be_modify
) {
827 refint_repair( op
, &rs
, id
, rq
);
832 if ( !BER_BVISNULL( &rq
->newndn
)) {
833 ch_free( rq
->newndn
.bv_val
);
834 ch_free( rq
->newdn
.bv_val
);
836 ch_free( rq
->oldndn
.bv_val
);
837 ch_free( rq
->olddn
.bv_val
);
842 for ( fptr
= ftop
.f_or
; fptr
; ) {
843 Filter
*f_next
= fptr
->f_next
;
844 op
->o_tmpfree( fptr
, op
->o_tmpmemctx
);
848 /* wait until we get explicitly scheduled again */
849 ldap_pvt_thread_mutex_lock( &slapd_rq
.rq_mutex
);
850 ldap_pvt_runqueue_stoptask( &slapd_rq
, id
->qtask
);
851 ldap_pvt_runqueue_resched( &slapd_rq
,id
->qtask
, 1 );
852 ldap_pvt_thread_mutex_unlock( &slapd_rq
.rq_mutex
);
859 ** search for matching records and modify them
868 slap_overinst
*on
= (slap_overinst
*) op
->o_bd
->bd_info
;
869 refint_data
*id
= on
->on_bi
.bi_private
;
873 BackendDB
*db
= NULL
;
876 id
->message
= "_refint_response";
878 /* If the main op failed or is not a Delete or ModRdn, ignore it */
879 if (( op
->o_tag
!= LDAP_REQ_DELETE
&& op
->o_tag
!= LDAP_REQ_MODRDN
) ||
880 rs
->sr_err
!= LDAP_SUCCESS
)
881 return SLAP_CB_CONTINUE
;
884 ** validate (and count) the list of attrs;
888 for(ip
= id
->attrs
, ac
= 0; ip
; ip
= ip
->next
, ac
++);
890 Debug( LDAP_DEBUG_TRACE
,
891 "refint_response called without any attributes\n", 0, 0, 0 );
892 return SLAP_CB_CONTINUE
;
896 ** find the backend that matches our configured basedn;
897 ** make sure it exists and has search and modify methods;
901 if ( on
->on_info
->oi_origdb
!= frontendDB
) {
902 db
= select_backend(&id
->dn
, 1);
905 if ( !db
->be_search
|| !db
->be_modify
) {
906 Debug( LDAP_DEBUG_TRACE
,
907 "refint_response: backend missing search and/or modify\n",
909 return SLAP_CB_CONTINUE
;
912 Debug( LDAP_DEBUG_TRACE
,
913 "refint_response: no backend for our baseDN %s??\n",
914 id
->dn
.bv_val
, 0, 0 );
915 return SLAP_CB_CONTINUE
;
919 rq
= ch_calloc( 1, sizeof( refint_q
));
920 ber_dupbv( &rq
->olddn
, &op
->o_req_dn
);
921 ber_dupbv( &rq
->oldndn
, &op
->o_req_ndn
);
925 if ( op
->o_tag
== LDAP_REQ_MODRDN
) {
926 if ( op
->oq_modrdn
.rs_newSup
) {
927 pdn
= *op
->oq_modrdn
.rs_newSup
;
929 dnParent( &op
->o_req_dn
, &pdn
);
931 build_new_dn( &rq
->newdn
, &pdn
, &op
->orr_newrdn
, NULL
);
932 if ( op
->oq_modrdn
.rs_nnewSup
) {
933 pdn
= *op
->oq_modrdn
.rs_nnewSup
;
935 dnParent( &op
->o_req_ndn
, &pdn
);
937 build_new_dn( &rq
->newndn
, &pdn
, &op
->orr_nnewrdn
, NULL
);
940 ldap_pvt_thread_mutex_lock( &id
->qmutex
);
942 id
->qtail
->next
= rq
;
947 ldap_pvt_thread_mutex_unlock( &id
->qmutex
);
950 ldap_pvt_thread_mutex_lock( &slapd_rq
.rq_mutex
);
952 id
->qtask
= ldap_pvt_runqueue_insert( &slapd_rq
, RUNQ_INTERVAL
,
953 refint_qtask
, id
, "refint_qtask",
954 op
->o_bd
->be_suffix
[0].bv_val
);
957 if ( !ldap_pvt_runqueue_isrunning( &slapd_rq
, id
->qtask
) &&
958 !id
->qtask
->next_sched
.tv_sec
) {
959 id
->qtask
->interval
.tv_sec
= 0;
960 ldap_pvt_runqueue_resched( &slapd_rq
, id
->qtask
, 0 );
961 id
->qtask
->interval
.tv_sec
= RUNQ_INTERVAL
;
965 ldap_pvt_thread_mutex_unlock( &slapd_rq
.rq_mutex
);
967 slap_wake_listener();
969 return SLAP_CB_CONTINUE
;
973 ** init_module is last so the symbols resolve "for free" --
974 ** it expects to be called automagically during dynamic module initialization
977 int refint_initialize() {
980 mr_dnSubtreeMatch
= mr_find( "dnSubtreeMatch" );
981 if ( mr_dnSubtreeMatch
== NULL
) {
982 Debug( LDAP_DEBUG_ANY
, "refint_initialize: "
983 "unable to find MatchingRule 'dnSubtreeMatch'.\n",
988 /* statically declared just after the #includes at top */
989 refint
.on_bi
.bi_type
= "refint";
990 refint
.on_bi
.bi_db_init
= refint_db_init
;
991 refint
.on_bi
.bi_db_destroy
= refint_db_destroy
;
992 refint
.on_bi
.bi_db_open
= refint_open
;
993 refint
.on_bi
.bi_db_close
= refint_close
;
994 refint
.on_response
= refint_response
;
996 refint
.on_bi
.bi_cf_ocs
= refintocs
;
997 rc
= config_register_schema ( refintcfg
, refintocs
);
1000 return(overlay_register(&refint
));
1003 #if SLAPD_OVER_REFINT == SLAPD_MOD_DYNAMIC && defined(PIC)
1004 int init_module(int argc
, char *argv
[]) {
1005 return refint_initialize();
1009 #endif /* SLAPD_OVER_REFINT */