1 /* $NetBSD: backglue.c,v 1.3 2021/08/14 16:14:58 christos Exp $ */
2
3 /* backglue.c - backend glue */
4 /* $OpenLDAP$ */
5 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
6 *
7 * Copyright 2001-2021 The OpenLDAP Foundation.
8 * All rights reserved.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted only as authorized by the OpenLDAP
12 * Public License.
13 *
14 * A copy of this license is available in the file LICENSE in the
15 * top-level directory of the distribution or, alternatively, at
16 * <http://www.OpenLDAP.org/license.html>.
17 */
18
19 /*
20 * Functions to glue a bunch of other backends into a single tree.
21 * All of the glued backends must share a common suffix. E.g., you
22 * can glue o=foo and ou=bar,o=foo but you can't glue o=foo and o=bar.
23 *
24 * The purpose of these functions is to allow you to split a single database
25 * into pieces (for load balancing purposes, whatever) but still be able
26 * to treat it as a single database after it's been split. As such, each
27 * of the glued backends should have identical rootdn.
28 * -- Howard Chu
29 */
30
31 #include <sys/cdefs.h>
32 __RCSID("$NetBSD: backglue.c,v 1.3 2021/08/14 16:14:58 christos Exp $");
33
34 #include "portable.h"
35
36 #include <stdio.h>
37
38 #include <ac/string.h>
39 #include <ac/socket.h>
40
41 #define SLAPD_TOOLS
42 #include "slap.h"
43 #include "lutil.h"
44 #include "slap-config.h"
45
46 typedef struct gluenode {
47 BackendDB *gn_be;
48 struct berval gn_pdn;
49 } gluenode;
50
51 typedef struct glueinfo {
52 int gi_nodes;
53 struct berval gi_pdn;
54 gluenode gi_n[1];
55 } glueinfo;
56
57 static slap_overinst glue;
58
59 static int glueMode;
60 static BackendDB *glueBack;
61 static BackendDB glueBackDone;
62 #define GLUEBACK_DONE (&glueBackDone)
63
64 static slap_overinst * glue_tool_inst( BackendInfo *bi);
65
66 static slap_response glue_op_response;
67
68 /* Just like select_backend, but only for our backends */
69 static BackendDB *
glue_back_select(BackendDB * be,struct berval * dn)70 glue_back_select (
71 BackendDB *be,
72 struct berval *dn
73 )
74 {
75 slap_overinst *on = (slap_overinst *)be->bd_info;
76 glueinfo *gi = (glueinfo *)on->on_bi.bi_private;
77 int i;
78
79 for (i = gi->gi_nodes-1; i >= 0; i--) {
80 assert( gi->gi_n[i].gn_be->be_nsuffix != NULL );
81
82 if (dnIsSuffix(dn, &gi->gi_n[i].gn_be->be_nsuffix[0])) {
83 return gi->gi_n[i].gn_be;
84 }
85 }
86 be->bd_info = on->on_info->oi_orig;
87 return be;
88 }
89
90
91 typedef struct glue_state {
92 char *matched;
93 BerVarray refs;
94 LDAPControl **ctrls;
95 int err;
96 int matchlen;
97 int nrefs;
98 int nctrls;
99 } glue_state;
100
101 static int
glue_op_cleanup(Operation * op,SlapReply * rs)102 glue_op_cleanup( Operation *op, SlapReply *rs )
103 {
104 /* This is not a final result */
105 if (rs->sr_type == REP_RESULT )
106 rs->sr_type = REP_GLUE_RESULT;
107 return SLAP_CB_CONTINUE;
108 }
109
110 static int
glue_op_response(Operation * op,SlapReply * rs)111 glue_op_response ( Operation *op, SlapReply *rs )
112 {
113 glue_state *gs = op->o_callback->sc_private;
114
115 switch(rs->sr_type) {
116 case REP_SEARCH:
117 case REP_SEARCHREF:
118 case REP_INTERMEDIATE:
119 return SLAP_CB_CONTINUE;
120
121 default:
122 if (rs->sr_err == LDAP_SUCCESS ||
123 rs->sr_err == LDAP_SIZELIMIT_EXCEEDED ||
124 rs->sr_err == LDAP_TIMELIMIT_EXCEEDED ||
125 rs->sr_err == LDAP_ADMINLIMIT_EXCEEDED ||
126 rs->sr_err == LDAP_NO_SUCH_OBJECT ||
127 gs->err != LDAP_SUCCESS)
128 gs->err = rs->sr_err;
129 if (gs->err == LDAP_SUCCESS && gs->matched) {
130 ch_free (gs->matched);
131 gs->matched = NULL;
132 gs->matchlen = 0;
133 }
134 if (gs->err != LDAP_SUCCESS && rs->sr_matched) {
135 int len;
136 len = strlen (rs->sr_matched);
137 if (len > gs->matchlen) {
138 if (gs->matched)
139 ch_free (gs->matched);
140 gs->matched = ch_strdup (rs->sr_matched);
141 gs->matchlen = len;
142 }
143 }
144 if (rs->sr_ref) {
145 int i, j, k;
146 BerVarray new;
147
148 for (i=0; rs->sr_ref[i].bv_val; i++);
149
150 j = gs->nrefs;
151 if (!j) {
152 new = ch_malloc ((i+1)*sizeof(struct berval));
153 } else {
154 new = ch_realloc(gs->refs,
155 (j+i+1)*sizeof(struct berval));
156 }
157 for (k=0; k<i; j++,k++) {
158 ber_dupbv( &new[j], &rs->sr_ref[k] );
159 }
160 new[j].bv_val = NULL;
161 gs->nrefs = j;
162 gs->refs = new;
163 }
164 if (rs->sr_ctrls) {
165 int i, j, k;
166 LDAPControl **newctrls;
167
168 for (i=0; rs->sr_ctrls[i]; i++);
169
170 j = gs->nctrls;
171 if (!j) {
172 newctrls = op->o_tmpalloc((i+1)*sizeof(LDAPControl *),
173 op->o_tmpmemctx);
174 } else {
175 /* Forget old pagedResults response if we're sending
176 * a new one now
177 */
178 if ( get_pagedresults( op ) > SLAP_CONTROL_IGNORED ) {
179 int newpage = 0;
180 for ( k=0; k<i; k++ ) {
181 if ( !strcmp(rs->sr_ctrls[k]->ldctl_oid,
182 LDAP_CONTROL_PAGEDRESULTS )) {
183 newpage = 1;
184 break;
185 }
186 }
187 if ( newpage ) {
188 for ( k=0; k<j; k++ ) {
189 if ( !strcmp(gs->ctrls[k]->ldctl_oid,
190 LDAP_CONTROL_PAGEDRESULTS ))
191 {
192 op->o_tmpfree(gs->ctrls[k], op->o_tmpmemctx);
193 gs->ctrls[k] = gs->ctrls[--j];
194 gs->ctrls[j] = NULL;
195 break;
196 }
197 }
198 }
199 }
200 newctrls = op->o_tmprealloc(gs->ctrls,
201 (j+i+1)*sizeof(LDAPControl *), op->o_tmpmemctx);
202 }
203 for (k=0; k<i; j++,k++) {
204 ber_len_t oidlen = strlen( rs->sr_ctrls[k]->ldctl_oid );
205 newctrls[j] = op->o_tmpalloc(sizeof(LDAPControl) + oidlen + 1 + rs->sr_ctrls[k]->ldctl_value.bv_len + 1,
206 op->o_tmpmemctx);
207 newctrls[j]->ldctl_iscritical = rs->sr_ctrls[k]->ldctl_iscritical;
208 newctrls[j]->ldctl_oid = (char *)&newctrls[j][1];
209 lutil_strcopy( newctrls[j]->ldctl_oid, rs->sr_ctrls[k]->ldctl_oid );
210 if ( !BER_BVISNULL( &rs->sr_ctrls[k]->ldctl_value ) ) {
211 newctrls[j]->ldctl_value.bv_val = &newctrls[j]->ldctl_oid[oidlen + 1];
212 newctrls[j]->ldctl_value.bv_len = rs->sr_ctrls[k]->ldctl_value.bv_len;
213 lutil_memcopy( newctrls[j]->ldctl_value.bv_val,
214 rs->sr_ctrls[k]->ldctl_value.bv_val,
215 rs->sr_ctrls[k]->ldctl_value.bv_len + 1 );
216 } else {
217 BER_BVZERO( &newctrls[j]->ldctl_value );
218 }
219 }
220 newctrls[j] = NULL;
221 gs->nctrls = j;
222 gs->ctrls = newctrls;
223 }
224 }
225 return 0;
226 }
227
228 static int
glue_op_func(Operation * op,SlapReply * rs)229 glue_op_func ( Operation *op, SlapReply *rs )
230 {
231 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
232 BackendDB *b0 = op->o_bd;
233 BackendInfo *bi0 = op->o_bd->bd_info, *bi1;
234 slap_operation_t which = op_bind;
235 int rc;
236
237 op->o_bd = glue_back_select (b0, &op->o_req_ndn);
238
239 /* If we're on the primary backend, let overlay framework handle it */
240 if ( op->o_bd == b0 )
241 return SLAP_CB_CONTINUE;
242
243 b0->bd_info = on->on_info->oi_orig;
244
245 switch(op->o_tag) {
246 case LDAP_REQ_ADD: which = op_add; break;
247 case LDAP_REQ_DELETE: which = op_delete; break;
248 case LDAP_REQ_MODIFY: which = op_modify; break;
249 case LDAP_REQ_MODRDN: which = op_modrdn; break;
250 case LDAP_REQ_EXTENDED: which = op_extended; break;
251 default: assert( 0 ); break;
252 }
253
254 bi1 = op->o_bd->bd_info;
255 rc = (&bi1->bi_op_bind)[ which ] ?
256 (&bi1->bi_op_bind)[ which ]( op, rs ) : SLAP_CB_BYPASS;
257
258 op->o_bd = b0;
259 op->o_bd->bd_info = bi0;
260 return rc;
261 }
262
263 static int
glue_op_abandon(Operation * op,SlapReply * rs)264 glue_op_abandon( Operation *op, SlapReply *rs )
265 {
266 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
267 glueinfo *gi = (glueinfo *)on->on_bi.bi_private;
268 BackendDB *b0 = op->o_bd;
269 BackendInfo *bi0 = op->o_bd->bd_info;
270 int i;
271
272 b0->bd_info = on->on_info->oi_orig;
273
274 for (i = gi->gi_nodes-1; i >= 0; i--) {
275 assert( gi->gi_n[i].gn_be->be_nsuffix != NULL );
276 op->o_bd = gi->gi_n[i].gn_be;
277 if ( op->o_bd == b0 )
278 continue;
279 if ( op->o_bd->bd_info->bi_op_abandon )
280 op->o_bd->bd_info->bi_op_abandon( op, rs );
281 }
282 op->o_bd = b0;
283 op->o_bd->bd_info = bi0;
284 return SLAP_CB_CONTINUE;
285 }
286
287 static int
glue_response(Operation * op,SlapReply * rs)288 glue_response ( Operation *op, SlapReply *rs )
289 {
290 BackendDB *be = op->o_bd;
291 be = glue_back_select (op->o_bd, &op->o_req_ndn);
292
293 /* If we're on the primary backend, let overlay framework handle it.
294 * Otherwise, bail out.
295 */
296 return ( op->o_bd == be ) ? SLAP_CB_CONTINUE : SLAP_CB_BYPASS;
297 }
298
299 static int
glue_chk_referrals(Operation * op,SlapReply * rs)300 glue_chk_referrals ( Operation *op, SlapReply *rs )
301 {
302 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
303 BackendDB *b0 = op->o_bd;
304 BackendInfo *bi0 = op->o_bd->bd_info;
305 int rc;
306
307 op->o_bd = glue_back_select (b0, &op->o_req_ndn);
308 if ( op->o_bd == b0 )
309 return SLAP_CB_CONTINUE;
310
311 b0->bd_info = on->on_info->oi_orig;
312
313 if ( op->o_bd->bd_info->bi_chk_referrals )
314 rc = ( *op->o_bd->bd_info->bi_chk_referrals )( op, rs );
315 else
316 rc = SLAP_CB_CONTINUE;
317
318 op->o_bd = b0;
319 op->o_bd->bd_info = bi0;
320 return rc;
321 }
322
323 static int
glue_chk_controls(Operation * op,SlapReply * rs)324 glue_chk_controls ( Operation *op, SlapReply *rs )
325 {
326 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
327 BackendDB *b0 = op->o_bd;
328 BackendInfo *bi0 = op->o_bd->bd_info;
329 int rc = SLAP_CB_CONTINUE;
330
331 op->o_bd = glue_back_select (b0, &op->o_req_ndn);
332 if ( op->o_bd == b0 )
333 return SLAP_CB_CONTINUE;
334
335 b0->bd_info = on->on_info->oi_orig;
336
337 /* if the subordinate database has overlays, the bi_chk_controls()
338 * hook is actually over_aux_chk_controls(); in case it actually
339 * wraps a missing hok, we need to mimic the behavior
340 * of the frontend applied to that database */
341 if ( op->o_bd->bd_info->bi_chk_controls ) {
342 rc = ( *op->o_bd->bd_info->bi_chk_controls )( op, rs );
343 }
344
345
346 if ( rc == SLAP_CB_CONTINUE ) {
347 rc = backend_check_controls( op, rs );
348 }
349
350 op->o_bd = b0;
351 op->o_bd->bd_info = bi0;
352 return rc;
353 }
354
355 /* ITS#4615 - overlays configured above the glue overlay should be
356 * invoked for the entire glued tree. Overlays configured below the
357 * glue overlay should only be invoked on the primary backend.
358 * So, if we're searching on any subordinates, we need to force the
359 * current overlay chain to stop processing, without stopping the
360 * overall callback flow.
361 */
362 static int
glue_sub_search(Operation * op,SlapReply * rs,BackendDB * b0,slap_overinst * on)363 glue_sub_search( Operation *op, SlapReply *rs, BackendDB *b0,
364 slap_overinst *on )
365 {
366 /* Process any overlays on the primary backend */
367 if ( op->o_bd == b0 && on->on_next ) {
368 BackendInfo *bi = op->o_bd->bd_info;
369 int rc = SLAP_CB_CONTINUE;
370 for ( on=on->on_next; on; on=on->on_next ) {
371 op->o_bd->bd_info = (BackendInfo *)on;
372 if ( on->on_bi.bi_op_search ) {
373 rc = on->on_bi.bi_op_search( op, rs );
374 if ( rc != SLAP_CB_CONTINUE )
375 break;
376 }
377 }
378 op->o_bd->bd_info = bi;
379 if ( rc != SLAP_CB_CONTINUE )
380 return rc;
381 }
382 return op->o_bd->be_search( op, rs );
383 }
384
385 static const ID glueID = NOID;
386 static const struct berval gluecookie = { sizeof( glueID ), (char *)&glueID };
387
388 static int
glue_op_search(Operation * op,SlapReply * rs)389 glue_op_search ( Operation *op, SlapReply *rs )
390 {
391 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
392 glueinfo *gi = (glueinfo *)on->on_bi.bi_private;
393 BackendDB *b0 = op->o_bd;
394 BackendDB *b1 = NULL, *btmp;
395 BackendInfo *bi0 = op->o_bd->bd_info;
396 int i;
397 long stoptime = 0, starttime;
398 glue_state gs = {NULL, NULL, NULL, 0, 0, 0, 0};
399 slap_callback cb = { NULL, glue_op_response, glue_op_cleanup, NULL };
400 int scope0, tlimit0;
401 struct berval dn, ndn, *pdn;
402
403 cb.sc_private = &gs;
404
405 cb.sc_next = op->o_callback;
406
407 starttime = op->o_time;
408 stoptime = slap_get_time () + op->ors_tlimit;
409
410 /* reset dummy cookie used to keep paged results going across databases */
411 if ( get_pagedresults( op ) > SLAP_CONTROL_IGNORED
412 && bvmatch( &((PagedResultsState *)op->o_pagedresults_state)->ps_cookieval, &gluecookie ) )
413 {
414 PagedResultsState *ps = op->o_pagedresults_state;
415 BerElementBuffer berbuf;
416 BerElement *ber = (BerElement *)&berbuf;
417 struct berval cookie = BER_BVC(""), value;
418 int c;
419
420 for (c = 0; op->o_ctrls[c] != NULL; c++) {
421 if (strcmp(op->o_ctrls[c]->ldctl_oid, LDAP_CONTROL_PAGEDRESULTS) == 0)
422 break;
423 }
424
425 assert( op->o_ctrls[c] != NULL );
426
427 ber_init2( ber, NULL, LBER_USE_DER );
428 ber_printf( ber, "{iO}", ps->ps_size, &cookie );
429 ber_flatten2( ber, &value, 0 );
430 assert( op->o_ctrls[c]->ldctl_value.bv_len >= value.bv_len );
431 op->o_ctrls[c]->ldctl_value.bv_len = value.bv_len;
432 lutil_memcopy( op->o_ctrls[c]->ldctl_value.bv_val,
433 value.bv_val, value.bv_len );
434 ber_free_buf( ber );
435
436 ps->ps_cookie = (PagedResultsCookie)0;
437 BER_BVZERO( &ps->ps_cookieval );
438 }
439
440 op->o_bd = glue_back_select (b0, &op->o_req_ndn);
441 b0->bd_info = on->on_info->oi_orig;
442
443 switch (op->ors_scope) {
444 case LDAP_SCOPE_BASE:
445 if ( op->o_bd == b0 )
446 return SLAP_CB_CONTINUE;
447
448 if (op->o_bd && op->o_bd->be_search) {
449 rs->sr_err = op->o_bd->be_search( op, rs );
450 } else {
451 rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
452 }
453 return rs->sr_err;
454
455 case LDAP_SCOPE_ONELEVEL:
456 case LDAP_SCOPE_SUBTREE:
457 case LDAP_SCOPE_SUBORDINATE: /* FIXME */
458 op->o_callback = &cb;
459 rs->sr_err = gs.err = LDAP_UNWILLING_TO_PERFORM;
460 scope0 = op->ors_scope;
461 tlimit0 = op->ors_tlimit;
462 dn = op->o_req_dn;
463 ndn = op->o_req_ndn;
464 b1 = op->o_bd;
465
466 /*
467 * Execute in reverse order, most specific first
468 */
469 for (i = gi->gi_nodes; i >= 0; i--) {
470 if ( i == gi->gi_nodes ) {
471 btmp = b0;
472 pdn = &gi->gi_pdn;
473 } else {
474 btmp = gi->gi_n[i].gn_be;
475 pdn = &gi->gi_n[i].gn_pdn;
476 }
477 if (!btmp || !btmp->be_search)
478 continue;
479 if (!dnIsSuffix(&btmp->be_nsuffix[0], &b1->be_nsuffix[0]))
480 continue;
481 if (get_no_subordinate_glue(op) && btmp != b1)
482 continue;
483 /* If we remembered which backend we were on before,
484 * skip down to it now
485 */
486 if ( get_pagedresults( op ) > SLAP_CONTROL_IGNORED &&
487 op->o_conn->c_pagedresults_state.ps_be &&
488 op->o_conn->c_pagedresults_state.ps_be != btmp )
489 continue;
490
491 if (tlimit0 != SLAP_NO_LIMIT) {
492 op->o_time = slap_get_time();
493 op->ors_tlimit = stoptime - op->o_time;
494 if (op->ors_tlimit <= 0) {
495 rs->sr_err = gs.err = LDAP_TIMELIMIT_EXCEEDED;
496 break;
497 }
498 }
499 rs->sr_err = 0;
500 /*
501 * check for abandon
502 */
503 if (op->o_abandon) {
504 goto end_of_loop;
505 }
506 op->o_bd = btmp;
507
508 assert( op->o_bd->be_suffix != NULL );
509 assert( op->o_bd->be_nsuffix != NULL );
510
511 if (scope0 == LDAP_SCOPE_ONELEVEL &&
512 dn_match(pdn, &ndn))
513 {
514 struct berval mdn, mndn;
515 op->ors_scope = LDAP_SCOPE_BASE;
516 mdn = op->o_req_dn = op->o_bd->be_suffix[0];
517 mndn = op->o_req_ndn = op->o_bd->be_nsuffix[0];
518 rs->sr_err = op->o_bd->be_search(op, rs);
519 if ( rs->sr_err == LDAP_NO_SUCH_OBJECT ) {
520 gs.err = LDAP_SUCCESS;
521 }
522 op->ors_scope = LDAP_SCOPE_ONELEVEL;
523 if ( op->o_req_dn.bv_val == mdn.bv_val )
524 op->o_req_dn = dn;
525 if ( op->o_req_ndn.bv_val == mndn.bv_val )
526 op->o_req_ndn = ndn;
527
528 } else if (scope0 == LDAP_SCOPE_SUBTREE &&
529 dn_match(&op->o_bd->be_nsuffix[0], &ndn))
530 {
531 rs->sr_err = glue_sub_search( op, rs, b0, on );
532
533 } else if (scope0 == LDAP_SCOPE_SUBTREE &&
534 dnIsSuffix(&op->o_bd->be_nsuffix[0], &ndn))
535 {
536 struct berval mdn, mndn;
537 mdn = op->o_req_dn = op->o_bd->be_suffix[0];
538 mndn = op->o_req_ndn = op->o_bd->be_nsuffix[0];
539 rs->sr_err = glue_sub_search( op, rs, b0, on );
540 if ( rs->sr_err == LDAP_NO_SUCH_OBJECT ) {
541 gs.err = LDAP_SUCCESS;
542 }
543 if ( op->o_req_dn.bv_val == mdn.bv_val )
544 op->o_req_dn = dn;
545 if ( op->o_req_ndn.bv_val == mndn.bv_val )
546 op->o_req_ndn = ndn;
547
548 } else if (dnIsSuffix(&ndn, &op->o_bd->be_nsuffix[0])) {
549 rs->sr_err = glue_sub_search( op, rs, b0, on );
550 }
551
552 switch ( gs.err ) {
553
554 /*
555 * Add errors that should result in dropping
556 * the search
557 */
558 case LDAP_SIZELIMIT_EXCEEDED:
559 case LDAP_TIMELIMIT_EXCEEDED:
560 case LDAP_ADMINLIMIT_EXCEEDED:
561 case LDAP_NO_SUCH_OBJECT:
562 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
563 case LDAP_X_CANNOT_CHAIN:
564 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
565 goto end_of_loop;
566
567 case LDAP_SUCCESS:
568 if ( get_pagedresults( op ) > SLAP_CONTROL_IGNORED ) {
569 PagedResultsState *ps = op->o_pagedresults_state;
570
571 /* Assume this backend can be forgotten now */
572 op->o_conn->c_pagedresults_state.ps_be = NULL;
573
574 /* If we have a full page, exit the loop. We may
575 * need to remember this backend so we can continue
576 * from here on a subsequent request.
577 */
578 if ( rs->sr_nentries >= ps->ps_size ) {
579 PagedResultsState *cps = &op->o_conn->c_pagedresults_state;
580
581 /* Don't bother to remember the first backend.
582 * Only remember the last one if there's more state left.
583 */
584 if ( op->o_bd != b0 &&
585 ( cps->ps_cookie != NOID
586 || !BER_BVISNULL( &cps->ps_cookieval )
587 || op->o_bd != gi->gi_n[0].gn_be ) )
588 {
589 op->o_conn->c_pagedresults_state.ps_be = op->o_bd;
590 }
591
592 /* Check whether the cookie is empty,
593 * and give remaining databases a chance
594 */
595 if ( op->o_bd != gi->gi_n[0].gn_be || cps->ps_cookie == NOID ) {
596 int c;
597
598 for ( c = 0; gs.ctrls[c] != NULL; c++ ) {
599 if ( strcmp( gs.ctrls[c]->ldctl_oid, LDAP_CONTROL_PAGEDRESULTS ) == 0 ) {
600 break;
601 }
602 }
603
604 if ( gs.ctrls[c] != NULL ) {
605 BerElementBuffer berbuf;
606 BerElement *ber = (BerElement *)&berbuf;
607 ber_tag_t tag;
608 ber_int_t size;
609 struct berval cookie, value;
610
611 ber_init2( ber, &gs.ctrls[c]->ldctl_value, LBER_USE_DER );
612
613 tag = ber_scanf( ber, "{im}", &size, &cookie );
614 assert( tag != LBER_ERROR );
615
616 if ( BER_BVISEMPTY( &cookie ) && op->o_bd != gi->gi_n[0].gn_be ) {
617 /* delete old, create new cookie with NOID */
618 PagedResultsCookie respcookie = (PagedResultsCookie)NOID;
619 ber_len_t oidlen = strlen( gs.ctrls[c]->ldctl_oid );
620 LDAPControl *newctrl;
621
622 /* it's next database's turn */
623 if ( btmp == b0 ) {
624 op->o_conn->c_pagedresults_state.ps_be = gi->gi_n[gi->gi_nodes - 1].gn_be;
625
626 } else {
627 op->o_conn->c_pagedresults_state.ps_be = gi->gi_n[(i > 0 ? i - 1: 0)].gn_be;
628 }
629
630 cookie.bv_val = (char *)&respcookie;
631 cookie.bv_len = sizeof( PagedResultsCookie );
632
633 ber_init2( ber, NULL, LBER_USE_DER );
634 ber_printf( ber, "{iO}", 0, &cookie );
635 ber_flatten2( ber, &value, 0 );
636
637 newctrl = op->o_tmprealloc( gs.ctrls[c],
638 sizeof(LDAPControl) + oidlen + 1 + value.bv_len + 1,
639 op->o_tmpmemctx);
640 newctrl->ldctl_iscritical = gs.ctrls[c]->ldctl_iscritical;
641 newctrl->ldctl_oid = (char *)&newctrl[1];
642 lutil_strcopy( newctrl->ldctl_oid, gs.ctrls[c]->ldctl_oid );
643 newctrl->ldctl_value.bv_len = value.bv_len;
644 lutil_memcopy( newctrl->ldctl_value.bv_val,
645 value.bv_val, value.bv_len );
646
647 gs.ctrls[c] = newctrl;
648
649 ber_free_buf( ber );
650
651 } else if ( !BER_BVISEMPTY( &cookie ) && op->o_bd != b0 ) {
652 /* if cookie not empty, it's again this database's turn */
653 op->o_conn->c_pagedresults_state.ps_be = op->o_bd;
654 }
655 }
656 }
657
658 goto end_of_loop;
659 }
660
661 /* This backend has run out of entries, but more responses
662 * can fit in the page. Fake a reset of the state so the
663 * next backend will start up properly. Only back-[bh]db
664 * and back-sql look at this state info.
665 */
666 ps->ps_cookie = (PagedResultsCookie)0;
667 BER_BVZERO( &ps->ps_cookieval );
668
669 {
670 /* change the size of the page in the request
671 * that will be propagated, and reset the cookie */
672 BerElementBuffer berbuf;
673 BerElement *ber = (BerElement *)&berbuf;
674 int size = ps->ps_size - rs->sr_nentries;
675 struct berval cookie = BER_BVC(""), value;
676 int c;
677
678 for (c = 0; op->o_ctrls[c] != NULL; c++) {
679 if (strcmp(op->o_ctrls[c]->ldctl_oid, LDAP_CONTROL_PAGEDRESULTS) == 0)
680 break;
681 }
682
683 assert( op->o_ctrls[c] != NULL );
684
685 ber_init2( ber, NULL, LBER_USE_DER );
686 ber_printf( ber, "{iO}", size, &cookie );
687 ber_flatten2( ber, &value, 0 );
688 assert( op->o_ctrls[c]->ldctl_value.bv_len >= value.bv_len );
689 op->o_ctrls[c]->ldctl_value.bv_len = value.bv_len;
690 lutil_memcopy( op->o_ctrls[c]->ldctl_value.bv_val,
691 value.bv_val, value.bv_len );
692 ber_free_buf( ber );
693 }
694 }
695
696 default:
697 break;
698 }
699 }
700 end_of_loop:;
701 op->ors_scope = scope0;
702 op->ors_tlimit = tlimit0;
703 op->o_time = starttime;
704
705 break;
706 }
707
708 op->o_callback = cb.sc_next;
709 if ( op->o_abandon ) {
710 rs->sr_err = SLAPD_ABANDON;
711 } else {
712 rs->sr_err = gs.err;
713 rs->sr_matched = gs.matched;
714 rs->sr_ref = gs.refs;
715 }
716 rs->sr_ctrls = gs.ctrls;
717
718 send_ldap_result( op, rs );
719
720 op->o_bd = b0;
721 op->o_bd->bd_info = bi0;
722 if (gs.matched)
723 free (gs.matched);
724 if (gs.refs)
725 ber_bvarray_free(gs.refs);
726 if (gs.ctrls) {
727 for (i = gs.nctrls; --i >= 0; ) {
728 op->o_tmpfree(gs.ctrls[i], op->o_tmpmemctx);
729 }
730 op->o_tmpfree(gs.ctrls, op->o_tmpmemctx);
731 }
732 return rs->sr_err;
733 }
734
735 static BackendDB toolDB;
736
737 static int
glue_tool_entry_open(BackendDB * b0,int mode)738 glue_tool_entry_open (
739 BackendDB *b0,
740 int mode
741 )
742 {
743 slap_overinfo *oi = (slap_overinfo *)b0->bd_info;
744
745 /* We don't know which backend to talk to yet, so just
746 * remember the mode and move on...
747 */
748
749 glueMode = mode;
750 glueBack = NULL;
751 toolDB = *b0;
752 toolDB.bd_info = oi->oi_orig;
753
754 /* Sanity checks */
755 {
756 slap_overinst *on = glue_tool_inst( b0->bd_info );
757 glueinfo *gi = on->on_bi.bi_private;
758
759 int i;
760 for (i = 0; i < gi->gi_nodes; i++) {
761 BackendDB *bd;
762 struct berval pdn;
763
764 dnParent( &gi->gi_n[i].gn_be->be_nsuffix[0], &pdn );
765 bd = select_backend( &pdn, 0 );
766 if ( bd ) {
767 ID id;
768 BackendDB db;
769
770 if ( overlay_is_over( bd ) ) {
771 slap_overinfo *oi = (slap_overinfo *)bd->bd_info;
772 db = *bd;
773 db.bd_info = oi->oi_orig;
774 bd = &db;
775 }
776
777 if ( !bd->bd_info->bi_tool_dn2id_get
778 || !bd->bd_info->bi_tool_entry_open
779 || !bd->bd_info->bi_tool_entry_close )
780 {
781 continue;
782 }
783
784 bd->bd_info->bi_tool_entry_open( bd, 0 );
785 id = bd->bd_info->bi_tool_dn2id_get( bd, &gi->gi_n[i].gn_be->be_nsuffix[0] );
786 bd->bd_info->bi_tool_entry_close( bd );
787 if ( id != NOID ) {
788 Debug( LDAP_DEBUG_ANY,
789 "glue_tool_entry_open: subordinate database suffix entry DN=\"%s\" also present in superior database rooted at DN=\"%s\"\n",
790 gi->gi_n[i].gn_be->be_suffix[0].bv_val, bd->be_suffix[0].bv_val );
791 return LDAP_OTHER;
792 }
793 }
794 }
795 }
796
797 return 0;
798 }
799
800 static int
glue_tool_entry_close(BackendDB * b0)801 glue_tool_entry_close (
802 BackendDB *b0
803 )
804 {
805 int rc = 0;
806
807 if (glueBack && glueBack != GLUEBACK_DONE) {
808 if (!glueBack->be_entry_close)
809 return 0;
810 rc = glueBack->be_entry_close (glueBack);
811 }
812 return rc;
813 }
814
815 static slap_overinst *
glue_tool_inst(BackendInfo * bi)816 glue_tool_inst(
817 BackendInfo *bi
818 )
819 {
820 slap_overinfo *oi = (slap_overinfo *)bi;
821 slap_overinst *on;
822
823 for ( on = oi->oi_list; on; on=on->on_next ) {
824 if ( !strcmp( on->on_bi.bi_type, glue.on_bi.bi_type ))
825 return on;
826 }
827 return NULL;
828 }
829
830 /* This function will only be called in tool mode */
831 static int
glue_open(BackendInfo * bi)832 glue_open (
833 BackendInfo *bi
834 )
835 {
836 slap_overinst *on = glue_tool_inst( bi );
837 glueinfo *gi = on->on_bi.bi_private;
838 static int glueOpened = 0;
839 int i, j, same, bsame = 0, rc = 0;
840 ConfigReply cr = {0};
841
842 if (glueOpened) return 0;
843
844 glueOpened = 1;
845
846 /* If we were invoked in tool mode, open all the underlying backends */
847 if (slapMode & SLAP_TOOL_MODE) {
848 for (i = 0; i<gi->gi_nodes; i++) {
849 same = 0;
850 /* Same bi_open as our main backend? */
851 if ( gi->gi_n[i].gn_be->bd_info->bi_open ==
852 on->on_info->oi_orig->bi_open )
853 bsame = 1;
854
855 /* Loop thru the bd_info's and make sure we only
856 * invoke their bi_open functions once each.
857 */
858 for ( j = 0; j<i; j++ ) {
859 if ( gi->gi_n[i].gn_be->bd_info->bi_open ==
860 gi->gi_n[j].gn_be->bd_info->bi_open ) {
861 same = 1;
862 break;
863 }
864 }
865 /* OK, it's unique and non-NULL, call it. */
866 if ( !same && gi->gi_n[i].gn_be->bd_info->bi_open )
867 rc = gi->gi_n[i].gn_be->bd_info->bi_open(
868 gi->gi_n[i].gn_be->bd_info );
869 /* Let backend.c take care of the rest of startup */
870 if ( !rc )
871 rc = backend_startup_one( gi->gi_n[i].gn_be, &cr );
872 if ( rc ) break;
873 }
874 if ( !rc && !bsame && on->on_info->oi_orig->bi_open )
875 rc = on->on_info->oi_orig->bi_open( on->on_info->oi_orig );
876
877 } /* other case is impossible */
878 return rc;
879 }
880
881 /* This function will only be called in tool mode */
882 static int
glue_close(BackendInfo * bi)883 glue_close (
884 BackendInfo *bi
885 )
886 {
887 static int glueClosed = 0;
888 int rc = 0;
889
890 if (glueClosed) return 0;
891
892 glueClosed = 1;
893
894 if (slapMode & SLAP_TOOL_MODE) {
895 rc = backend_shutdown( NULL );
896 }
897 return rc;
898 }
899
900 static int
glue_entry_get_rw(Operation * op,struct berval * dn,ObjectClass * oc,AttributeDescription * ad,int rw,Entry ** e)901 glue_entry_get_rw (
902 Operation *op,
903 struct berval *dn,
904 ObjectClass *oc,
905 AttributeDescription *ad,
906 int rw,
907 Entry **e )
908 {
909 int rc;
910 BackendDB *b0 = op->o_bd;
911 op->o_bd = glue_back_select( b0, dn );
912
913 if ( op->o_bd->be_fetch ) {
914 rc = op->o_bd->be_fetch( op, dn, oc, ad, rw, e );
915 } else {
916 rc = LDAP_UNWILLING_TO_PERFORM;
917 }
918 op->o_bd =b0;
919 return rc;
920 }
921
922 static int
glue_entry_release_rw(Operation * op,Entry * e,int rw)923 glue_entry_release_rw (
924 Operation *op,
925 Entry *e,
926 int rw
927 )
928 {
929 BackendDB *b0 = op->o_bd;
930 int rc = -1;
931
932 op->o_bd = glue_back_select (b0, &e->e_nname);
933
934 if ( op->o_bd->be_release ) {
935 rc = op->o_bd->be_release( op, e, rw );
936
937 } else {
938 /* FIXME: mimic be_entry_release_rw
939 * when no be_release() available */
940 /* free entry */
941 entry_free( e );
942 rc = 0;
943 }
944 op->o_bd = b0;
945 return rc;
946 }
947
948 static struct berval *glue_base;
949 static int glue_scope;
950 static Filter *glue_filter;
951
952 static ID
glue_tool_entry_first(BackendDB * b0)953 glue_tool_entry_first (
954 BackendDB *b0
955 )
956 {
957 slap_overinst *on = glue_tool_inst( b0->bd_info );
958 glueinfo *gi = on->on_bi.bi_private;
959 int i;
960 ID rc;
961
962 /* If we're starting from scratch, start at the most general */
963 if (!glueBack) {
964 if ( toolDB.be_entry_open && toolDB.be_entry_first ) {
965 glueBack = &toolDB;
966 } else {
967 for (i = gi->gi_nodes-1; i >= 0; i--) {
968 if (gi->gi_n[i].gn_be->be_entry_open &&
969 gi->gi_n[i].gn_be->be_entry_first) {
970 glueBack = gi->gi_n[i].gn_be;
971 break;
972 }
973 }
974 }
975 }
976 if (!glueBack || !glueBack->be_entry_open || !glueBack->be_entry_first ||
977 glueBack->be_entry_open (glueBack, glueMode) != 0)
978 return NOID;
979
980 rc = glueBack->be_entry_first (glueBack);
981 while ( rc == NOID ) {
982 if ( glueBack && glueBack->be_entry_close )
983 glueBack->be_entry_close (glueBack);
984 for (i=0; i<gi->gi_nodes; i++) {
985 if (gi->gi_n[i].gn_be == glueBack)
986 break;
987 }
988 if (i == 0) {
989 glueBack = GLUEBACK_DONE;
990 break;
991 } else {
992 glueBack = gi->gi_n[i-1].gn_be;
993 rc = glue_tool_entry_first (b0);
994 if ( glueBack == GLUEBACK_DONE ) {
995 break;
996 }
997 }
998 }
999 return rc;
1000 }
1001
1002 static ID
glue_tool_entry_first_x(BackendDB * b0,struct berval * base,int scope,Filter * f)1003 glue_tool_entry_first_x (
1004 BackendDB *b0,
1005 struct berval *base,
1006 int scope,
1007 Filter *f
1008 )
1009 {
1010 slap_overinst *on = glue_tool_inst( b0->bd_info );
1011 glueinfo *gi = on->on_bi.bi_private;
1012 int i;
1013 ID rc;
1014
1015 glue_base = base;
1016 glue_scope = scope;
1017 glue_filter = f;
1018
1019 /* If we're starting from scratch, start at the most general */
1020 if (!glueBack) {
1021 if ( toolDB.be_entry_open && toolDB.be_entry_first_x ) {
1022 glueBack = &toolDB;
1023 } else {
1024 for (i = gi->gi_nodes-1; i >= 0; i--) {
1025 if (gi->gi_n[i].gn_be->be_entry_open &&
1026 gi->gi_n[i].gn_be->be_entry_first_x)
1027 {
1028 glueBack = gi->gi_n[i].gn_be;
1029 break;
1030 }
1031 }
1032 }
1033 }
1034 if (!glueBack || !glueBack->be_entry_open || !glueBack->be_entry_first_x ||
1035 glueBack->be_entry_open (glueBack, glueMode) != 0)
1036 return NOID;
1037
1038 rc = glueBack->be_entry_first_x (glueBack,
1039 glue_base, glue_scope, glue_filter);
1040 while ( rc == NOID ) {
1041 if ( glueBack && glueBack->be_entry_close )
1042 glueBack->be_entry_close (glueBack);
1043 for (i=0; i<gi->gi_nodes; i++) {
1044 if (gi->gi_n[i].gn_be == glueBack)
1045 break;
1046 }
1047 if (i == 0) {
1048 glueBack = GLUEBACK_DONE;
1049 break;
1050 } else {
1051 glueBack = gi->gi_n[i-1].gn_be;
1052 rc = glue_tool_entry_first_x (b0,
1053 glue_base, glue_scope, glue_filter);
1054 if ( glueBack == GLUEBACK_DONE ) {
1055 break;
1056 }
1057 }
1058 }
1059 return rc;
1060 }
1061
1062 static ID
glue_tool_entry_next(BackendDB * b0)1063 glue_tool_entry_next (
1064 BackendDB *b0
1065 )
1066 {
1067 slap_overinst *on = glue_tool_inst( b0->bd_info );
1068 glueinfo *gi = on->on_bi.bi_private;
1069 int i;
1070 ID rc;
1071
1072 if (!glueBack || !glueBack->be_entry_next)
1073 return NOID;
1074
1075 rc = glueBack->be_entry_next (glueBack);
1076
1077 /* If we ran out of entries in one database, move on to the next */
1078 while (rc == NOID) {
1079 if ( glueBack && glueBack->be_entry_close )
1080 glueBack->be_entry_close (glueBack);
1081 for (i=0; i<gi->gi_nodes; i++) {
1082 if (gi->gi_n[i].gn_be == glueBack)
1083 break;
1084 }
1085 if (i == 0) {
1086 glueBack = GLUEBACK_DONE;
1087 break;
1088 } else {
1089 glueBack = gi->gi_n[i-1].gn_be;
1090 if ( glue_base || glue_filter ) {
1091 /* using entry_first_x() */
1092 rc = glue_tool_entry_first_x (b0,
1093 glue_base, glue_scope, glue_filter);
1094
1095 } else {
1096 /* using entry_first() */
1097 rc = glue_tool_entry_first (b0);
1098 }
1099 if ( glueBack == GLUEBACK_DONE ) {
1100 break;
1101 }
1102 }
1103 }
1104 return rc;
1105 }
1106
1107 static ID
glue_tool_dn2id_get(BackendDB * b0,struct berval * dn)1108 glue_tool_dn2id_get (
1109 BackendDB *b0,
1110 struct berval *dn
1111 )
1112 {
1113 BackendDB *be, b2;
1114 int rc = -1;
1115
1116 b2 = *b0;
1117 b2.bd_info = (BackendInfo *)glue_tool_inst( b0->bd_info );
1118 be = glue_back_select (&b2, dn);
1119 if ( be == &b2 ) be = &toolDB;
1120
1121 if (!be->be_dn2id_get)
1122 return NOID;
1123
1124 if (!glueBack) {
1125 if ( be->be_entry_open ) {
1126 rc = be->be_entry_open (be, glueMode);
1127 }
1128 if (rc != 0) {
1129 return NOID;
1130 }
1131 } else if (be != glueBack) {
1132 /* If this entry belongs in a different branch than the
1133 * previous one, close the current database and open the
1134 * new one.
1135 */
1136 if ( glueBack->be_entry_close ) {
1137 glueBack->be_entry_close (glueBack);
1138 }
1139 if ( be->be_entry_open ) {
1140 rc = be->be_entry_open (be, glueMode);
1141 }
1142 if (rc != 0) {
1143 return NOID;
1144 }
1145 }
1146 glueBack = be;
1147 return be->be_dn2id_get (be, dn);
1148 }
1149
1150 static Entry *
glue_tool_entry_get(BackendDB * b0,ID id)1151 glue_tool_entry_get (
1152 BackendDB *b0,
1153 ID id
1154 )
1155 {
1156 if (!glueBack || !glueBack->be_entry_get)
1157 return NULL;
1158
1159 return glueBack->be_entry_get (glueBack, id);
1160 }
1161
1162 static ID
glue_tool_entry_put(BackendDB * b0,Entry * e,struct berval * text)1163 glue_tool_entry_put (
1164 BackendDB *b0,
1165 Entry *e,
1166 struct berval *text
1167 )
1168 {
1169 BackendDB *be, b2;
1170 int rc = -1;
1171
1172 b2 = *b0;
1173 b2.bd_info = (BackendInfo *)glue_tool_inst( b0->bd_info );
1174 be = glue_back_select (&b2, &e->e_nname);
1175 if ( be == &b2 ) be = &toolDB;
1176
1177 if (!be->be_entry_put)
1178 return NOID;
1179
1180 if (!glueBack) {
1181 if ( be->be_entry_open ) {
1182 rc = be->be_entry_open (be, glueMode);
1183 }
1184 if (rc != 0) {
1185 return NOID;
1186 }
1187 } else if (be != glueBack) {
1188 /* If this entry belongs in a different branch than the
1189 * previous one, close the current database and open the
1190 * new one.
1191 */
1192 if ( glueBack->be_entry_close ) {
1193 glueBack->be_entry_close (glueBack);
1194 }
1195 if ( be->be_entry_open ) {
1196 rc = be->be_entry_open (be, glueMode);
1197 }
1198 if (rc != 0) {
1199 return NOID;
1200 }
1201 }
1202 glueBack = be;
1203 return be->be_entry_put (be, e, text);
1204 }
1205
1206 static ID
glue_tool_entry_modify(BackendDB * b0,Entry * e,struct berval * text)1207 glue_tool_entry_modify (
1208 BackendDB *b0,
1209 Entry *e,
1210 struct berval *text
1211 )
1212 {
1213 if (!glueBack || !glueBack->be_entry_modify)
1214 return NOID;
1215
1216 return glueBack->be_entry_modify (glueBack, e, text);
1217 }
1218
1219 static int
glue_tool_entry_reindex(BackendDB * b0,ID id,AttributeDescription ** adv)1220 glue_tool_entry_reindex (
1221 BackendDB *b0,
1222 ID id,
1223 AttributeDescription **adv
1224 )
1225 {
1226 if (!glueBack || !glueBack->be_entry_reindex)
1227 return -1;
1228
1229 return glueBack->be_entry_reindex (glueBack, id, adv);
1230 }
1231
1232 static int
glue_tool_sync(BackendDB * b0)1233 glue_tool_sync (
1234 BackendDB *b0
1235 )
1236 {
1237 slap_overinst *on = glue_tool_inst( b0->bd_info );
1238 glueinfo *gi = on->on_bi.bi_private;
1239 BackendInfo *bi = b0->bd_info;
1240 int i;
1241
1242 /* just sync everyone */
1243 for (i = 0; i<gi->gi_nodes; i++)
1244 if (gi->gi_n[i].gn_be->be_sync)
1245 gi->gi_n[i].gn_be->be_sync (gi->gi_n[i].gn_be);
1246 b0->bd_info = on->on_info->oi_orig;
1247 if ( b0->be_sync )
1248 b0->be_sync( b0 );
1249 b0->bd_info = bi;
1250 return 0;
1251 }
1252
1253 typedef struct glue_Addrec {
1254 struct glue_Addrec *ga_next;
1255 BackendDB *ga_be;
1256 } glue_Addrec;
1257
1258 /* List of added subordinates */
1259 static glue_Addrec *ga_list;
1260 static int ga_adding;
1261
1262 static int
glue_db_init(BackendDB * be,ConfigReply * cr)1263 glue_db_init(
1264 BackendDB *be,
1265 ConfigReply *cr
1266 )
1267 {
1268 slap_overinst *on = (slap_overinst *)be->bd_info;
1269 slap_overinfo *oi = on->on_info;
1270 BackendInfo *bi = oi->oi_orig;
1271 glueinfo *gi;
1272
1273 if ( SLAP_GLUE_SUBORDINATE( be )) {
1274 Debug( LDAP_DEBUG_ANY, "glue: backend %s is already subordinate, "
1275 "cannot have glue overlay!\n",
1276 be->be_suffix[0].bv_val );
1277 return LDAP_OTHER;
1278 }
1279
1280 gi = ch_calloc( 1, sizeof(glueinfo));
1281 on->on_bi.bi_private = gi;
1282 dnParent( be->be_nsuffix, &gi->gi_pdn );
1283
1284 /* Currently the overlay framework doesn't handle these entry points
1285 * but we need them....
1286 */
1287 oi->oi_bi.bi_open = glue_open;
1288 oi->oi_bi.bi_close = glue_close;
1289
1290 /* Only advertise these if the root DB supports them */
1291 if ( bi->bi_tool_entry_open )
1292 oi->oi_bi.bi_tool_entry_open = glue_tool_entry_open;
1293 if ( bi->bi_tool_entry_close )
1294 oi->oi_bi.bi_tool_entry_close = glue_tool_entry_close;
1295 if ( bi->bi_tool_entry_first )
1296 oi->oi_bi.bi_tool_entry_first = glue_tool_entry_first;
1297 /* FIXME: check whether all support bi_tool_entry_first_x() ? */
1298 if ( bi->bi_tool_entry_first_x )
1299 oi->oi_bi.bi_tool_entry_first_x = glue_tool_entry_first_x;
1300 if ( bi->bi_tool_entry_next )
1301 oi->oi_bi.bi_tool_entry_next = glue_tool_entry_next;
1302 if ( bi->bi_tool_entry_get )
1303 oi->oi_bi.bi_tool_entry_get = glue_tool_entry_get;
1304 if ( bi->bi_tool_dn2id_get )
1305 oi->oi_bi.bi_tool_dn2id_get = glue_tool_dn2id_get;
1306 if ( bi->bi_tool_entry_put )
1307 oi->oi_bi.bi_tool_entry_put = glue_tool_entry_put;
1308 if ( bi->bi_tool_entry_reindex )
1309 oi->oi_bi.bi_tool_entry_reindex = glue_tool_entry_reindex;
1310 if ( bi->bi_tool_entry_modify )
1311 oi->oi_bi.bi_tool_entry_modify = glue_tool_entry_modify;
1312 if ( bi->bi_tool_sync )
1313 oi->oi_bi.bi_tool_sync = glue_tool_sync;
1314
1315 SLAP_DBFLAGS( be ) |= SLAP_DBFLAG_GLUE_INSTANCE;
1316
1317 if ( ga_list && ( slapMode & SLAP_SERVER_MODE ) ) {
1318 be->bd_info = (BackendInfo *)oi;
1319 glue_sub_attach( 1 );
1320 }
1321
1322 return 0;
1323 }
1324
1325 static int
glue_db_destroy(BackendDB * be,ConfigReply * cr)1326 glue_db_destroy (
1327 BackendDB *be,
1328 ConfigReply *cr
1329 )
1330 {
1331 slap_overinst *on = (slap_overinst *)be->bd_info;
1332 glueinfo *gi = (glueinfo *)on->on_bi.bi_private;
1333
1334 free (gi);
1335 return 0;
1336 }
1337
1338 static int
glue_db_close(BackendDB * be,ConfigReply * cr)1339 glue_db_close(
1340 BackendDB *be,
1341 ConfigReply *cr
1342 )
1343 {
1344 slap_overinst *on = (slap_overinst *)be->bd_info;
1345
1346 on->on_info->oi_bi.bi_db_close = 0;
1347 return 0;
1348 }
1349
1350 int
glue_sub_del(BackendDB * b0)1351 glue_sub_del( BackendDB *b0 )
1352 {
1353 BackendDB *be;
1354 int rc = 0;
1355
1356 /* Find the top backend for this subordinate */
1357 be = b0;
1358 while ( (be=LDAP_STAILQ_NEXT( be, be_next )) != NULL ) {
1359 slap_overinfo *oi;
1360 slap_overinst *on;
1361 glueinfo *gi;
1362 int i;
1363
1364 if ( SLAP_GLUE_SUBORDINATE( be ))
1365 continue;
1366 if ( !SLAP_GLUE_INSTANCE( be ))
1367 continue;
1368 if ( !dnIsSuffix( &b0->be_nsuffix[0], &be->be_nsuffix[0] ))
1369 continue;
1370
1371 /* OK, got the right backend, find the overlay */
1372 oi = (slap_overinfo *)be->bd_info;
1373 for ( on=oi->oi_list; on; on=on->on_next ) {
1374 if ( on->on_bi.bi_type == glue.on_bi.bi_type )
1375 break;
1376 }
1377 assert( on != NULL );
1378 gi = on->on_bi.bi_private;
1379 for ( i=0; i < gi->gi_nodes; i++ ) {
1380 if ( gi->gi_n[i].gn_be == b0 ) {
1381 int j;
1382
1383 for (j=i+1; j < gi->gi_nodes; j++)
1384 gi->gi_n[j-1] = gi->gi_n[j];
1385
1386 gi->gi_nodes--;
1387 }
1388 }
1389 }
1390 if ( be == NULL )
1391 rc = LDAP_NO_SUCH_OBJECT;
1392
1393 return rc;
1394 }
1395
1396
1397 /* Attach all the subordinate backends to their superior */
1398 int
glue_sub_attach(int online)1399 glue_sub_attach( int online )
1400 {
1401 glue_Addrec *ga, *gnext = NULL;
1402 int rc = 0;
1403
1404 if ( ga_adding )
1405 return 0;
1406
1407 ga_adding = 1;
1408
1409 /* For all the subordinate backends */
1410 for ( ga=ga_list; ga != NULL; ga = gnext ) {
1411 BackendDB *be;
1412
1413 gnext = ga->ga_next;
1414
1415 /* Find the top backend for this subordinate */
1416 be = ga->ga_be;
1417 while ( (be=LDAP_STAILQ_NEXT( be, be_next )) != NULL ) {
1418 slap_overinfo *oi;
1419 slap_overinst *on;
1420 glueinfo *gi;
1421
1422 if ( SLAP_GLUE_SUBORDINATE( be ))
1423 continue;
1424 if ( !dnIsSuffix( &ga->ga_be->be_nsuffix[0], &be->be_nsuffix[0] ))
1425 continue;
1426
1427 /* If it's not already configured, set up the overlay */
1428 if ( !SLAP_GLUE_INSTANCE( be )) {
1429 rc = overlay_config( be, glue.on_bi.bi_type, -1, NULL, NULL);
1430 if ( rc )
1431 break;
1432 }
1433 /* Find the overlay instance */
1434 oi = (slap_overinfo *)be->bd_info;
1435 for ( on=oi->oi_list; on; on=on->on_next ) {
1436 if ( on->on_bi.bi_type == glue.on_bi.bi_type )
1437 break;
1438 }
1439 assert( on != NULL );
1440 gi = on->on_bi.bi_private;
1441 gi = (glueinfo *)ch_realloc( gi, sizeof(glueinfo) +
1442 gi->gi_nodes * sizeof(gluenode));
1443 gi->gi_n[gi->gi_nodes].gn_be = ga->ga_be;
1444 dnParent( &ga->ga_be->be_nsuffix[0],
1445 &gi->gi_n[gi->gi_nodes].gn_pdn );
1446 gi->gi_nodes++;
1447 on->on_bi.bi_private = gi;
1448 ga->ga_be->be_flags |= SLAP_DBFLAG_GLUE_LINKED;
1449 break;
1450 }
1451 if ( !be ) {
1452 Debug( LDAP_DEBUG_ANY, "glue: no superior found for sub %s!\n",
1453 ga->ga_be->be_suffix[0].bv_val );
1454 /* allow this for now, assume a superior will
1455 * be added later
1456 */
1457 if ( online ) {
1458 rc = 0;
1459 gnext = ga_list;
1460 break;
1461 }
1462 rc = LDAP_NO_SUCH_OBJECT;
1463 }
1464 ch_free( ga );
1465 if ( rc ) break;
1466 }
1467
1468 ga_list = gnext;
1469
1470 ga_adding = 0;
1471
1472 return rc;
1473 }
1474
1475 int
glue_sub_add(BackendDB * be,int advert,int online)1476 glue_sub_add( BackendDB *be, int advert, int online )
1477 {
1478 glue_Addrec *ga;
1479 int rc = 0;
1480
1481 if ( overlay_is_inst( be, "glue" )) {
1482 Debug( LDAP_DEBUG_ANY, "glue: backend %s already has glue overlay, "
1483 "cannot be a subordinate!\n",
1484 be->be_suffix[0].bv_val );
1485 return LDAP_OTHER;
1486 }
1487 SLAP_DBFLAGS( be ) |= SLAP_DBFLAG_GLUE_SUBORDINATE;
1488 if ( advert )
1489 SLAP_DBFLAGS( be ) |= SLAP_DBFLAG_GLUE_ADVERTISE;
1490
1491 ga = ch_malloc( sizeof( glue_Addrec ));
1492 ga->ga_next = ga_list;
1493 ga->ga_be = be;
1494 ga_list = ga;
1495
1496 if ( online )
1497 rc = glue_sub_attach( online );
1498
1499 return rc;
1500 }
1501
1502 static int
glue_access_allowed(Operation * op,Entry * e,AttributeDescription * desc,struct berval * val,slap_access_t access,AccessControlState * state,slap_mask_t * maskp)1503 glue_access_allowed(
1504 Operation *op,
1505 Entry *e,
1506 AttributeDescription *desc,
1507 struct berval *val,
1508 slap_access_t access,
1509 AccessControlState *state,
1510 slap_mask_t *maskp )
1511 {
1512 BackendDB *b0, *be = glue_back_select( op->o_bd, &e->e_nname );
1513 int rc;
1514
1515 if ( be == NULL || be == op->o_bd || be->bd_info->bi_access_allowed == NULL )
1516 return SLAP_CB_CONTINUE;
1517
1518 b0 = op->o_bd;
1519 op->o_bd = be;
1520 rc = be->bd_info->bi_access_allowed ( op, e, desc, val, access, state, maskp );
1521 op->o_bd = b0;
1522 return rc;
1523 }
1524
1525 int
glue_sub_init()1526 glue_sub_init()
1527 {
1528 glue.on_bi.bi_type = "glue";
1529
1530 glue.on_bi.bi_db_init = glue_db_init;
1531 glue.on_bi.bi_db_close = glue_db_close;
1532 glue.on_bi.bi_db_destroy = glue_db_destroy;
1533
1534 glue.on_bi.bi_op_search = glue_op_search;
1535 glue.on_bi.bi_op_modify = glue_op_func;
1536 glue.on_bi.bi_op_modrdn = glue_op_func;
1537 glue.on_bi.bi_op_add = glue_op_func;
1538 glue.on_bi.bi_op_delete = glue_op_func;
1539 glue.on_bi.bi_op_abandon = glue_op_abandon;
1540 glue.on_bi.bi_extended = glue_op_func;
1541
1542 glue.on_bi.bi_chk_referrals = glue_chk_referrals;
1543 glue.on_bi.bi_chk_controls = glue_chk_controls;
1544 glue.on_bi.bi_entry_get_rw = glue_entry_get_rw;
1545 glue.on_bi.bi_entry_release_rw = glue_entry_release_rw;
1546 glue.on_bi.bi_access_allowed = glue_access_allowed;
1547
1548 glue.on_response = glue_response;
1549
1550 return overlay_register( &glue );
1551 }
1552