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