1 /* backglue.c - backend glue */
2 /* $OpenLDAP: pkg/ldap/servers/slapd/backglue.c,v 1.112.2.12 2008/06/02 18:00:53 quanah Exp $ */
3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
5 * Copyright 2001-2008 The OpenLDAP Foundation.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted only as authorized by the OpenLDAP
12 * A copy of this license is available in the file LICENSE in the
13 * top-level directory of the distribution or, alternatively, at
14 * <http://www.OpenLDAP.org/license.html>.
18 * Functions to glue a bunch of other backends into a single tree.
19 * All of the glued backends must share a common suffix. E.g., you
20 * can glue o=foo and ou=bar,o=foo but you can't glue o=foo and o=bar.
22 * The purpose of these functions is to allow you to split a single database
23 * into pieces (for load balancing purposes, whatever) but still be able
24 * to treat it as a single database after it's been split. As such, each
25 * of the glued backends should have identical rootdn.
33 #include <ac/string.h>
34 #include <ac/socket.h>
40 typedef struct gluenode
{
45 typedef struct glueinfo
{
51 static slap_overinst glue
;
54 static BackendDB
*glueBack
;
56 static slap_response glue_op_response
;
58 /* Just like select_backend, but only for our backends */
65 slap_overinst
*on
= (slap_overinst
*)be
->bd_info
;
66 glueinfo
*gi
= (glueinfo
*)on
->on_bi
.bi_private
;
69 for (i
= gi
->gi_nodes
-1; i
>= 0; i
--) {
70 assert( gi
->gi_n
[i
].gn_be
->be_nsuffix
!= NULL
);
72 if (dnIsSuffix(dn
, &gi
->gi_n
[i
].gn_be
->be_nsuffix
[0])) {
73 return gi
->gi_n
[i
].gn_be
;
76 be
->bd_info
= on
->on_info
->oi_orig
;
81 typedef struct glue_state
{
92 glue_op_cleanup( Operation
*op
, SlapReply
*rs
)
94 /* This is not a final result */
95 if (rs
->sr_type
== REP_RESULT
)
96 rs
->sr_type
= REP_GLUE_RESULT
;
97 return SLAP_CB_CONTINUE
;
101 glue_op_response ( Operation
*op
, SlapReply
*rs
)
103 glue_state
*gs
= op
->o_callback
->sc_private
;
105 switch(rs
->sr_type
) {
108 case REP_INTERMEDIATE
:
109 return SLAP_CB_CONTINUE
;
112 if (rs
->sr_err
== LDAP_SUCCESS
||
113 rs
->sr_err
== LDAP_SIZELIMIT_EXCEEDED
||
114 rs
->sr_err
== LDAP_TIMELIMIT_EXCEEDED
||
115 rs
->sr_err
== LDAP_ADMINLIMIT_EXCEEDED
||
116 rs
->sr_err
== LDAP_NO_SUCH_OBJECT
||
117 gs
->err
!= LDAP_SUCCESS
)
118 gs
->err
= rs
->sr_err
;
119 if (gs
->err
== LDAP_SUCCESS
&& gs
->matched
) {
120 ch_free (gs
->matched
);
124 if (gs
->err
!= LDAP_SUCCESS
&& rs
->sr_matched
) {
126 len
= strlen (rs
->sr_matched
);
127 if (len
> gs
->matchlen
) {
129 ch_free (gs
->matched
);
130 gs
->matched
= ch_strdup (rs
->sr_matched
);
138 for (i
=0; rs
->sr_ref
[i
].bv_val
; i
++);
142 new = ch_malloc ((i
+1)*sizeof(struct berval
));
144 new = ch_realloc(gs
->refs
,
145 (j
+i
+1)*sizeof(struct berval
));
147 for (k
=0; k
<i
; j
++,k
++) {
148 ber_dupbv( &new[j
], &rs
->sr_ref
[k
] );
150 new[j
].bv_val
= NULL
;
156 LDAPControl
**newctrls
;
158 for (i
=0; rs
->sr_ctrls
[i
]; i
++);
162 newctrls
= ch_malloc((i
+1)*sizeof(LDAPControl
*));
164 /* Forget old pagedResults response if we're sending
167 if ( get_pagedresults( op
) > SLAP_CONTROL_IGNORED
) {
169 for ( k
=0; k
<i
; k
++ ) {
170 if ( !strcmp(rs
->sr_ctrls
[k
]->ldctl_oid
,
171 LDAP_CONTROL_PAGEDRESULTS
)) {
177 for ( k
=0; k
<j
; k
++ ) {
178 if ( !strcmp(gs
->ctrls
[k
]->ldctl_oid
,
179 LDAP_CONTROL_PAGEDRESULTS
)) {
180 gs
->ctrls
[k
]->ldctl_oid
= NULL
;
181 ldap_control_free( gs
->ctrls
[k
] );
182 gs
->ctrls
[k
] = gs
->ctrls
[--j
];
189 newctrls
= ch_realloc(gs
->ctrls
,
190 (j
+i
+1)*sizeof(LDAPControl
*));
192 for (k
=0; k
<i
; j
++,k
++) {
193 newctrls
[j
] = ch_malloc(sizeof(LDAPControl
));
194 *newctrls
[j
] = *rs
->sr_ctrls
[k
];
195 if ( !BER_BVISNULL( &rs
->sr_ctrls
[k
]->ldctl_value
))
196 ber_dupbv( &newctrls
[j
]->ldctl_value
,
197 &rs
->sr_ctrls
[k
]->ldctl_value
);
201 gs
->ctrls
= newctrls
;
208 glue_op_func ( Operation
*op
, SlapReply
*rs
)
210 slap_overinst
*on
= (slap_overinst
*)op
->o_bd
->bd_info
;
211 BackendDB
*b0
= op
->o_bd
;
212 BackendInfo
*bi0
= op
->o_bd
->bd_info
;
214 slap_operation_t which
= op_bind
;
217 op
->o_bd
= glue_back_select (b0
, &op
->o_req_ndn
);
219 /* If we're on the master backend, let overlay framework handle it */
220 if ( op
->o_bd
== b0
)
221 return SLAP_CB_CONTINUE
;
223 b0
->bd_info
= on
->on_info
->oi_orig
;
226 case LDAP_REQ_ADD
: which
= op_add
; break;
227 case LDAP_REQ_DELETE
: which
= op_delete
; break;
228 case LDAP_REQ_MODIFY
: which
= op_modify
; break;
229 case LDAP_REQ_MODRDN
: which
= op_modrdn
; break;
230 case LDAP_REQ_EXTENDED
: which
= op_extended
; break;
231 default: assert( 0 ); break;
234 func
= &op
->o_bd
->bd_info
->bi_op_bind
;
236 rc
= func
[which
]( op
, rs
);
241 op
->o_bd
->bd_info
= bi0
;
246 glue_response ( Operation
*op
, SlapReply
*rs
)
248 BackendDB
*be
= op
->o_bd
;
249 be
= glue_back_select (op
->o_bd
, &op
->o_req_ndn
);
251 /* If we're on the master backend, let overlay framework handle it.
252 * Otherwise, bail out.
254 return ( op
->o_bd
== be
) ? SLAP_CB_CONTINUE
: SLAP_CB_BYPASS
;
258 glue_chk_referrals ( Operation
*op
, SlapReply
*rs
)
260 slap_overinst
*on
= (slap_overinst
*)op
->o_bd
->bd_info
;
261 BackendDB
*b0
= op
->o_bd
;
262 BackendInfo
*bi0
= op
->o_bd
->bd_info
;
265 op
->o_bd
= glue_back_select (b0
, &op
->o_req_ndn
);
266 if ( op
->o_bd
== b0
)
267 return SLAP_CB_CONTINUE
;
269 b0
->bd_info
= on
->on_info
->oi_orig
;
271 if ( op
->o_bd
->bd_info
->bi_chk_referrals
)
272 rc
= ( *op
->o_bd
->bd_info
->bi_chk_referrals
)( op
, rs
);
274 rc
= SLAP_CB_CONTINUE
;
277 op
->o_bd
->bd_info
= bi0
;
282 glue_chk_controls ( Operation
*op
, SlapReply
*rs
)
284 slap_overinst
*on
= (slap_overinst
*)op
->o_bd
->bd_info
;
285 BackendDB
*b0
= op
->o_bd
;
286 BackendInfo
*bi0
= op
->o_bd
->bd_info
;
287 int rc
= SLAP_CB_CONTINUE
;
289 op
->o_bd
= glue_back_select (b0
, &op
->o_req_ndn
);
290 if ( op
->o_bd
== b0
)
291 return SLAP_CB_CONTINUE
;
293 b0
->bd_info
= on
->on_info
->oi_orig
;
295 /* if the subordinate database has overlays, the bi_chk_controls()
296 * hook is actually over_aux_chk_controls(); in case it actually
297 * wraps a missing hok, we need to mimic the behavior
298 * of the frontend applied to that database */
299 if ( op
->o_bd
->bd_info
->bi_chk_controls
) {
300 rc
= ( *op
->o_bd
->bd_info
->bi_chk_controls
)( op
, rs
);
304 if ( rc
== SLAP_CB_CONTINUE
) {
305 rc
= backend_check_controls( op
, rs
);
309 op
->o_bd
->bd_info
= bi0
;
313 /* ITS#4615 - overlays configured above the glue overlay should be
314 * invoked for the entire glued tree. Overlays configured below the
315 * glue overlay should only be invoked on the master backend.
316 * So, if we're searching on any subordinates, we need to force the
317 * current overlay chain to stop processing, without stopping the
318 * overall callback flow.
321 glue_sub_search( Operation
*op
, SlapReply
*rs
, BackendDB
*b0
,
324 /* Process any overlays on the master backend */
325 if ( op
->o_bd
== b0
&& on
->on_next
) {
326 BackendInfo
*bi
= op
->o_bd
->bd_info
;
327 int rc
= SLAP_CB_CONTINUE
;
328 for ( on
=on
->on_next
; on
; on
=on
->on_next
) {
329 op
->o_bd
->bd_info
= (BackendInfo
*)on
;
330 if ( on
->on_bi
.bi_op_search
) {
331 rc
= on
->on_bi
.bi_op_search( op
, rs
);
332 if ( rc
!= SLAP_CB_CONTINUE
)
336 op
->o_bd
->bd_info
= bi
;
337 if ( rc
!= SLAP_CB_CONTINUE
)
340 return op
->o_bd
->be_search( op
, rs
);
344 glue_op_search ( Operation
*op
, SlapReply
*rs
)
346 slap_overinst
*on
= (slap_overinst
*)op
->o_bd
->bd_info
;
347 glueinfo
*gi
= (glueinfo
*)on
->on_bi
.bi_private
;
348 BackendDB
*b0
= op
->o_bd
;
349 BackendDB
*b1
= NULL
, *btmp
;
350 BackendInfo
*bi0
= op
->o_bd
->bd_info
;
352 long stoptime
= 0, starttime
;
353 glue_state gs
= {NULL
, NULL
, NULL
, 0, 0, 0, 0};
354 slap_callback cb
= { NULL
, glue_op_response
, glue_op_cleanup
, NULL
};
356 struct berval dn
, ndn
, *pdn
;
360 cb
.sc_next
= op
->o_callback
;
362 starttime
= op
->o_time
;
363 stoptime
= slap_get_time () + op
->ors_tlimit
;
365 op
->o_bd
= glue_back_select (b0
, &op
->o_req_ndn
);
366 b0
->bd_info
= on
->on_info
->oi_orig
;
368 switch (op
->ors_scope
) {
369 case LDAP_SCOPE_BASE
:
370 if ( op
->o_bd
== b0
)
371 return SLAP_CB_CONTINUE
;
373 rs
->sr_err
= LDAP_UNWILLING_TO_PERFORM
;
374 if (op
->o_bd
&& op
->o_bd
->be_search
) {
375 rs
->sr_err
= op
->o_bd
->be_search( op
, rs
);
379 case LDAP_SCOPE_ONELEVEL
:
380 case LDAP_SCOPE_SUBTREE
:
381 case LDAP_SCOPE_SUBORDINATE
: /* FIXME */
382 op
->o_callback
= &cb
;
383 rs
->sr_err
= gs
.err
= LDAP_UNWILLING_TO_PERFORM
;
384 scope0
= op
->ors_scope
;
385 tlimit0
= op
->ors_tlimit
;
391 * Execute in reverse order, most specific first
393 for (i
= gi
->gi_nodes
; i
>= 0; i
--) {
394 if ( i
== gi
->gi_nodes
) {
398 btmp
= gi
->gi_n
[i
].gn_be
;
399 pdn
= &gi
->gi_n
[i
].gn_pdn
;
401 if (!btmp
|| !btmp
->be_search
)
403 if (!dnIsSuffix(&btmp
->be_nsuffix
[0], &b1
->be_nsuffix
[0]))
405 if (get_no_subordinate_glue(op
) && btmp
!= b1
)
407 /* If we remembered which backend we were on before,
408 * skip down to it now
410 if ( get_pagedresults( op
) > SLAP_CONTROL_IGNORED
&&
411 op
->o_conn
->c_pagedresults_state
.ps_be
&&
412 op
->o_conn
->c_pagedresults_state
.ps_be
!= btmp
)
415 if (tlimit0
!= SLAP_NO_LIMIT
) {
416 op
->o_time
= slap_get_time();
417 op
->ors_tlimit
= stoptime
- op
->o_time
;
418 if (op
->ors_tlimit
<= 0) {
419 rs
->sr_err
= gs
.err
= LDAP_TIMELIMIT_EXCEEDED
;
432 assert( op
->o_bd
->be_suffix
!= NULL
);
433 assert( op
->o_bd
->be_nsuffix
!= NULL
);
435 if (scope0
== LDAP_SCOPE_ONELEVEL
&&
438 op
->ors_scope
= LDAP_SCOPE_BASE
;
439 op
->o_req_dn
= op
->o_bd
->be_suffix
[0];
440 op
->o_req_ndn
= op
->o_bd
->be_nsuffix
[0];
441 rs
->sr_err
= op
->o_bd
->be_search(op
, rs
);
442 if ( rs
->sr_err
== LDAP_NO_SUCH_OBJECT
) {
443 gs
.err
= LDAP_SUCCESS
;
445 op
->ors_scope
= LDAP_SCOPE_ONELEVEL
;
449 } else if (scope0
== LDAP_SCOPE_SUBTREE
&&
450 dn_match(&op
->o_bd
->be_nsuffix
[0], &ndn
))
452 rs
->sr_err
= glue_sub_search( op
, rs
, b0
, on
);
454 } else if (scope0
== LDAP_SCOPE_SUBTREE
&&
455 dnIsSuffix(&op
->o_bd
->be_nsuffix
[0], &ndn
))
457 op
->o_req_dn
= op
->o_bd
->be_suffix
[0];
458 op
->o_req_ndn
= op
->o_bd
->be_nsuffix
[0];
459 rs
->sr_err
= glue_sub_search( op
, rs
, b0
, on
);
460 if ( rs
->sr_err
== LDAP_NO_SUCH_OBJECT
) {
461 gs
.err
= LDAP_SUCCESS
;
466 } else if (dnIsSuffix(&ndn
, &op
->o_bd
->be_nsuffix
[0])) {
467 rs
->sr_err
= glue_sub_search( op
, rs
, b0
, on
);
473 * Add errors that should result in dropping
476 case LDAP_SIZELIMIT_EXCEEDED
:
477 case LDAP_TIMELIMIT_EXCEEDED
:
478 case LDAP_ADMINLIMIT_EXCEEDED
:
479 case LDAP_NO_SUCH_OBJECT
:
480 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
481 case LDAP_X_CANNOT_CHAIN
:
482 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
486 if ( get_pagedresults( op
) > SLAP_CONTROL_IGNORED
) {
487 PagedResultsState
*ps
= op
->o_pagedresults_state
;
489 /* Assume this backend can be forgotten now */
490 op
->o_conn
->c_pagedresults_state
.ps_be
= NULL
;
492 /* If we have a full page, exit the loop. We may
493 * need to remember this backend so we can continue
494 * from here on a subsequent request.
496 if ( rs
->sr_nentries
>= ps
->ps_size
) {
497 /* Don't bother to remember the first backend.
498 * Only remember the last one if there's more state left.
500 if ( op
->o_bd
!= b0
&&
501 ( op
->o_conn
->c_pagedresults_state
.ps_cookie
||
502 op
->o_bd
!= gi
->gi_n
[0].gn_be
))
503 op
->o_conn
->c_pagedresults_state
.ps_be
= op
->o_bd
;
507 /* This backend has run out of entries, but more responses
508 * can fit in the page. Fake a reset of the state so the
509 * next backend will start up properly. Only back-[bh]db
510 * and back-sql look at this state info.
512 if ( ps
->ps_cookieval
.bv_len
== sizeof( PagedResultsCookie
)) {
514 memset( ps
->ps_cookieval
.bv_val
, 0,
515 sizeof( PagedResultsCookie
));
524 op
->ors_scope
= scope0
;
525 op
->ors_tlimit
= tlimit0
;
526 op
->o_time
= starttime
;
532 if ( op
->o_abandon
) {
533 rs
->sr_err
= SLAPD_ABANDON
;
535 op
->o_callback
= cb
.sc_next
;
537 rs
->sr_matched
= gs
.matched
;
538 rs
->sr_ref
= gs
.refs
;
539 rs
->sr_ctrls
= gs
.ctrls
;
541 send_ldap_result( op
, rs
);
545 op
->o_bd
->bd_info
= bi0
;
549 ber_bvarray_free(gs
.refs
);
551 for (i
= gs
.nctrls
; --i
>= 0; ) {
552 if (!BER_BVISNULL( &gs
.ctrls
[i
]->ldctl_value
))
553 free(gs
.ctrls
[i
]->ldctl_value
.bv_val
);
561 static BackendDB toolDB
;
564 glue_tool_entry_open (
569 slap_overinfo
*oi
= (slap_overinfo
*)b0
->bd_info
;
571 /* We don't know which backend to talk to yet, so just
572 * remember the mode and move on...
578 toolDB
.bd_info
= oi
->oi_orig
;
584 glue_tool_entry_close (
591 if (!glueBack
->be_entry_close
)
593 rc
= glueBack
->be_entry_close (glueBack
);
598 static slap_overinst
*
603 slap_overinfo
*oi
= (slap_overinfo
*)bi
;
606 for ( on
= oi
->oi_list
; on
; on
=on
->on_next
) {
607 if ( !strcmp( on
->on_bi
.bi_type
, glue
.on_bi
.bi_type
))
613 /* This function will only be called in tool mode */
619 slap_overinst
*on
= glue_tool_inst( bi
);
620 glueinfo
*gi
= on
->on_bi
.bi_private
;
621 static int glueOpened
= 0;
622 int i
, j
, same
, bsame
= 0, rc
= 0;
623 ConfigReply cr
= {0};
625 if (glueOpened
) return 0;
629 /* If we were invoked in tool mode, open all the underlying backends */
630 if (slapMode
& SLAP_TOOL_MODE
) {
631 for (i
= 0; i
<gi
->gi_nodes
; i
++) {
633 /* Same bi_open as our main backend? */
634 if ( gi
->gi_n
[i
].gn_be
->bd_info
->bi_open
==
635 on
->on_info
->oi_orig
->bi_open
)
638 /* Loop thru the bd_info's and make sure we only
639 * invoke their bi_open functions once each.
641 for ( j
= 0; j
<i
; j
++ ) {
642 if ( gi
->gi_n
[i
].gn_be
->bd_info
->bi_open
==
643 gi
->gi_n
[j
].gn_be
->bd_info
->bi_open
) {
648 /* OK, it's unique and non-NULL, call it. */
649 if ( !same
&& gi
->gi_n
[i
].gn_be
->bd_info
->bi_open
)
650 rc
= gi
->gi_n
[i
].gn_be
->bd_info
->bi_open(
651 gi
->gi_n
[i
].gn_be
->bd_info
);
652 /* Let backend.c take care of the rest of startup */
654 rc
= backend_startup_one( gi
->gi_n
[i
].gn_be
, &cr
);
657 if ( !rc
&& !bsame
&& on
->on_info
->oi_orig
->bi_open
)
658 rc
= on
->on_info
->oi_orig
->bi_open( on
->on_info
->oi_orig
);
660 } /* other case is impossible */
664 /* This function will only be called in tool mode */
670 static int glueClosed
= 0;
673 if (glueClosed
) return 0;
677 if (slapMode
& SLAP_TOOL_MODE
) {
678 rc
= backend_shutdown( NULL
);
688 AttributeDescription
*ad
,
693 BackendDB
*b0
= op
->o_bd
;
694 op
->o_bd
= glue_back_select( b0
, dn
);
696 if ( op
->o_bd
->be_fetch
) {
697 rc
= op
->o_bd
->be_fetch( op
, dn
, oc
, ad
, rw
, e
);
699 rc
= LDAP_UNWILLING_TO_PERFORM
;
706 glue_entry_release_rw (
712 BackendDB
*b0
= op
->o_bd
;
715 op
->o_bd
= glue_back_select (b0
, &e
->e_nname
);
717 if ( op
->o_bd
->be_release
) {
718 rc
= op
->o_bd
->be_release( op
, e
, rw
);
721 /* FIXME: mimic be_entry_release_rw
722 * when no be_release() available */
732 glue_tool_entry_first (
736 slap_overinst
*on
= glue_tool_inst( b0
->bd_info
);
737 glueinfo
*gi
= on
->on_bi
.bi_private
;
740 /* If we're starting from scratch, start at the most general */
742 if ( toolDB
.be_entry_open
&& toolDB
.be_entry_first
) {
745 for (i
= gi
->gi_nodes
-1; i
>= 0; i
--) {
746 if (gi
->gi_n
[i
].gn_be
->be_entry_open
&&
747 gi
->gi_n
[i
].gn_be
->be_entry_first
) {
748 glueBack
= gi
->gi_n
[i
].gn_be
;
754 if (!glueBack
|| !glueBack
->be_entry_open
|| !glueBack
->be_entry_first
||
755 glueBack
->be_entry_open (glueBack
, glueMode
) != 0)
758 return glueBack
->be_entry_first (glueBack
);
762 glue_tool_entry_next (
766 slap_overinst
*on
= glue_tool_inst( b0
->bd_info
);
767 glueinfo
*gi
= on
->on_bi
.bi_private
;
771 if (!glueBack
|| !glueBack
->be_entry_next
)
774 rc
= glueBack
->be_entry_next (glueBack
);
776 /* If we ran out of entries in one database, move on to the next */
778 if ( glueBack
&& glueBack
->be_entry_close
)
779 glueBack
->be_entry_close (glueBack
);
780 for (i
=0; i
<gi
->gi_nodes
; i
++) {
781 if (gi
->gi_n
[i
].gn_be
== glueBack
)
788 glueBack
= gi
->gi_n
[i
-1].gn_be
;
789 rc
= glue_tool_entry_first (b0
);
796 glue_tool_dn2id_get (
805 b2
.bd_info
= (BackendInfo
*)glue_tool_inst( b0
->bd_info
);
806 be
= glue_back_select (&b2
, dn
);
807 if ( be
== &b2
) be
= &toolDB
;
809 if (!be
->be_dn2id_get
)
813 if ( be
->be_entry_open
) {
814 rc
= be
->be_entry_open (be
, glueMode
);
819 } else if (be
!= glueBack
) {
820 /* If this entry belongs in a different branch than the
821 * previous one, close the current database and open the
824 if ( glueBack
->be_entry_close
) {
825 glueBack
->be_entry_close (glueBack
);
827 if ( be
->be_entry_open
) {
828 rc
= be
->be_entry_open (be
, glueMode
);
835 return be
->be_dn2id_get (be
, dn
);
839 glue_tool_entry_get (
844 if (!glueBack
|| !glueBack
->be_entry_get
)
847 return glueBack
->be_entry_get (glueBack
, id
);
851 glue_tool_entry_put (
861 b2
.bd_info
= (BackendInfo
*)glue_tool_inst( b0
->bd_info
);
862 be
= glue_back_select (&b2
, &e
->e_nname
);
863 if ( be
== &b2
) be
= &toolDB
;
865 if (!be
->be_entry_put
)
869 if ( be
->be_entry_open
) {
870 rc
= be
->be_entry_open (be
, glueMode
);
875 } else if (be
!= glueBack
) {
876 /* If this entry belongs in a different branch than the
877 * previous one, close the current database and open the
880 if ( glueBack
->be_entry_close
) {
881 glueBack
->be_entry_close (glueBack
);
883 if ( be
->be_entry_open
) {
884 rc
= be
->be_entry_open (be
, glueMode
);
891 return be
->be_entry_put (be
, e
, text
);
895 glue_tool_entry_modify (
901 if (!glueBack
|| !glueBack
->be_entry_modify
)
904 return glueBack
->be_entry_modify (glueBack
, e
, text
);
908 glue_tool_entry_reindex (
911 AttributeDescription
**adv
914 if (!glueBack
|| !glueBack
->be_entry_reindex
)
917 return glueBack
->be_entry_reindex (glueBack
, id
, adv
);
925 slap_overinst
*on
= glue_tool_inst( b0
->bd_info
);
926 glueinfo
*gi
= on
->on_bi
.bi_private
;
927 BackendInfo
*bi
= b0
->bd_info
;
930 /* just sync everyone */
931 for (i
= 0; i
<gi
->gi_nodes
; i
++)
932 if (gi
->gi_n
[i
].gn_be
->be_sync
)
933 gi
->gi_n
[i
].gn_be
->be_sync (gi
->gi_n
[i
].gn_be
);
934 b0
->bd_info
= on
->on_info
->oi_orig
;
947 slap_overinst
*on
= (slap_overinst
*)be
->bd_info
;
948 slap_overinfo
*oi
= on
->on_info
;
949 BackendInfo
*bi
= oi
->oi_orig
;
952 if ( SLAP_GLUE_SUBORDINATE( be
)) {
953 Debug( LDAP_DEBUG_ANY
, "glue: backend %s is already subordinate, "
954 "cannot have glue overlay!\n",
955 be
->be_suffix
[0].bv_val
, 0, 0 );
959 gi
= ch_calloc( 1, sizeof(glueinfo
));
960 on
->on_bi
.bi_private
= gi
;
961 dnParent( be
->be_nsuffix
, &gi
->gi_pdn
);
963 /* Currently the overlay framework doesn't handle these entry points
964 * but we need them....
966 oi
->oi_bi
.bi_open
= glue_open
;
967 oi
->oi_bi
.bi_close
= glue_close
;
969 /* Only advertise these if the root DB supports them */
970 if ( bi
->bi_tool_entry_open
)
971 oi
->oi_bi
.bi_tool_entry_open
= glue_tool_entry_open
;
972 if ( bi
->bi_tool_entry_close
)
973 oi
->oi_bi
.bi_tool_entry_close
= glue_tool_entry_close
;
974 if ( bi
->bi_tool_entry_first
)
975 oi
->oi_bi
.bi_tool_entry_first
= glue_tool_entry_first
;
976 if ( bi
->bi_tool_entry_next
)
977 oi
->oi_bi
.bi_tool_entry_next
= glue_tool_entry_next
;
978 if ( bi
->bi_tool_entry_get
)
979 oi
->oi_bi
.bi_tool_entry_get
= glue_tool_entry_get
;
980 if ( bi
->bi_tool_dn2id_get
)
981 oi
->oi_bi
.bi_tool_dn2id_get
= glue_tool_dn2id_get
;
982 if ( bi
->bi_tool_entry_put
)
983 oi
->oi_bi
.bi_tool_entry_put
= glue_tool_entry_put
;
984 if ( bi
->bi_tool_entry_reindex
)
985 oi
->oi_bi
.bi_tool_entry_reindex
= glue_tool_entry_reindex
;
986 if ( bi
->bi_tool_entry_modify
)
987 oi
->oi_bi
.bi_tool_entry_modify
= glue_tool_entry_modify
;
988 if ( bi
->bi_tool_sync
)
989 oi
->oi_bi
.bi_tool_sync
= glue_tool_sync
;
991 SLAP_DBFLAGS( be
) |= SLAP_DBFLAG_GLUE_INSTANCE
;
1002 slap_overinst
*on
= (slap_overinst
*)be
->bd_info
;
1003 glueinfo
*gi
= (glueinfo
*)on
->on_bi
.bi_private
;
1006 return SLAP_CB_CONTINUE
;
1015 slap_overinst
*on
= (slap_overinst
*)be
->bd_info
;
1017 on
->on_info
->oi_bi
.bi_db_close
= 0;
1022 glue_sub_del( BackendDB
*b0
)
1027 /* Find the top backend for this subordinate */
1029 while ( (be
=LDAP_STAILQ_NEXT( be
, be_next
)) != NULL
) {
1035 if ( SLAP_GLUE_SUBORDINATE( be
))
1037 if ( !SLAP_GLUE_INSTANCE( be
))
1039 if ( !dnIsSuffix( &b0
->be_nsuffix
[0], &be
->be_nsuffix
[0] ))
1042 /* OK, got the right backend, find the overlay */
1043 oi
= (slap_overinfo
*)be
->bd_info
;
1044 for ( on
=oi
->oi_list
; on
; on
=on
->on_next
) {
1045 if ( on
->on_bi
.bi_type
== glue
.on_bi
.bi_type
)
1048 assert( on
!= NULL
);
1049 gi
= on
->on_bi
.bi_private
;
1050 for ( i
=0; i
< gi
->gi_nodes
; i
++ ) {
1051 if ( gi
->gi_n
[i
].gn_be
== b0
) {
1054 for (j
=i
+1; j
< gi
->gi_nodes
; j
++)
1055 gi
->gi_n
[j
-1] = gi
->gi_n
[j
];
1062 rc
= LDAP_NO_SUCH_OBJECT
;
1067 typedef struct glue_Addrec
{
1068 struct glue_Addrec
*ga_next
;
1072 /* List of added subordinates */
1073 static glue_Addrec
*ga_list
;
1075 /* Attach all the subordinate backends to their superior */
1079 glue_Addrec
*ga
, *gnext
= NULL
;
1082 /* For all the subordinate backends */
1083 for ( ga
=ga_list
; ga
!= NULL
; ga
= gnext
) {
1086 gnext
= ga
->ga_next
;
1088 /* Find the top backend for this subordinate */
1090 while ( (be
=LDAP_STAILQ_NEXT( be
, be_next
)) != NULL
) {
1095 if ( SLAP_GLUE_SUBORDINATE( be
))
1097 if ( !dnIsSuffix( &ga
->ga_be
->be_nsuffix
[0], &be
->be_nsuffix
[0] ))
1100 /* If it's not already configured, set up the overlay */
1101 if ( !SLAP_GLUE_INSTANCE( be
)) {
1102 rc
= overlay_config( be
, glue
.on_bi
.bi_type
, -1, NULL
, NULL
);
1106 /* Find the overlay instance */
1107 oi
= (slap_overinfo
*)be
->bd_info
;
1108 for ( on
=oi
->oi_list
; on
; on
=on
->on_next
) {
1109 if ( on
->on_bi
.bi_type
== glue
.on_bi
.bi_type
)
1112 assert( on
!= NULL
);
1113 gi
= on
->on_bi
.bi_private
;
1114 gi
= (glueinfo
*)ch_realloc( gi
, sizeof(glueinfo
) +
1115 gi
->gi_nodes
* sizeof(gluenode
));
1116 gi
->gi_n
[gi
->gi_nodes
].gn_be
= ga
->ga_be
;
1117 dnParent( &ga
->ga_be
->be_nsuffix
[0],
1118 &gi
->gi_n
[gi
->gi_nodes
].gn_pdn
);
1120 on
->on_bi
.bi_private
= gi
;
1124 Debug( LDAP_DEBUG_ANY
, "glue: no superior found for sub %s!\n",
1125 ga
->ga_be
->be_suffix
[0].bv_val
, 0, 0 );
1126 rc
= LDAP_NO_SUCH_OBJECT
;
1138 glue_sub_add( BackendDB
*be
, int advert
, int online
)
1143 if ( overlay_is_inst( be
, "glue" )) {
1144 Debug( LDAP_DEBUG_ANY
, "glue: backend %s already has glue overlay, "
1145 "cannot be a subordinate!\n",
1146 be
->be_suffix
[0].bv_val
, 0, 0 );
1149 SLAP_DBFLAGS( be
) |= SLAP_DBFLAG_GLUE_SUBORDINATE
;
1151 SLAP_DBFLAGS( be
) |= SLAP_DBFLAG_GLUE_ADVERTISE
;
1153 ga
= ch_malloc( sizeof( glue_Addrec
));
1154 ga
->ga_next
= ga_list
;
1159 rc
= glue_sub_attach();
1167 glue
.on_bi
.bi_type
= "glue";
1169 glue
.on_bi
.bi_db_init
= glue_db_init
;
1170 glue
.on_bi
.bi_db_close
= glue_db_close
;
1171 glue
.on_bi
.bi_db_destroy
= glue_db_destroy
;
1173 glue
.on_bi
.bi_op_search
= glue_op_search
;
1174 glue
.on_bi
.bi_op_modify
= glue_op_func
;
1175 glue
.on_bi
.bi_op_modrdn
= glue_op_func
;
1176 glue
.on_bi
.bi_op_add
= glue_op_func
;
1177 glue
.on_bi
.bi_op_delete
= glue_op_func
;
1178 glue
.on_bi
.bi_extended
= glue_op_func
;
1180 glue
.on_bi
.bi_chk_referrals
= glue_chk_referrals
;
1181 glue
.on_bi
.bi_chk_controls
= glue_chk_controls
;
1182 glue
.on_bi
.bi_entry_get_rw
= glue_entry_get_rw
;
1183 glue
.on_bi
.bi_entry_release_rw
= glue_entry_release_rw
;
1185 glue
.on_response
= glue_response
;
1187 return overlay_register( &glue
);