1 /* $NetBSD: backglue.c,v 1.1.1.5 2014/05/28 09:58:46 tron 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-2014 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 "portable.h" 32 33 #include <stdio.h> 34 35 #include <ac/string.h> 36 #include <ac/socket.h> 37 38 #define SLAPD_TOOLS 39 #include "slap.h" 40 #include "lutil.h" 41 #include "config.h" 42 43 typedef struct gluenode { 44 BackendDB *gn_be; 45 struct berval gn_pdn; 46 } gluenode; 47 48 typedef struct glueinfo { 49 int gi_nodes; 50 struct berval gi_pdn; 51 gluenode gi_n[1]; 52 } glueinfo; 53 54 static slap_overinst glue; 55 56 static int glueMode; 57 static BackendDB *glueBack; 58 static BackendDB glueBackDone; 59 #define GLUEBACK_DONE (&glueBackDone) 60 61 static slap_overinst * glue_tool_inst( BackendInfo *bi); 62 63 static slap_response glue_op_response; 64 65 /* Just like select_backend, but only for our backends */ 66 static BackendDB * 67 glue_back_select ( 68 BackendDB *be, 69 struct berval *dn 70 ) 71 { 72 slap_overinst *on = (slap_overinst *)be->bd_info; 73 glueinfo *gi = (glueinfo *)on->on_bi.bi_private; 74 int i; 75 76 for (i = gi->gi_nodes-1; i >= 0; i--) { 77 assert( gi->gi_n[i].gn_be->be_nsuffix != NULL ); 78 79 if (dnIsSuffix(dn, &gi->gi_n[i].gn_be->be_nsuffix[0])) { 80 return gi->gi_n[i].gn_be; 81 } 82 } 83 be->bd_info = on->on_info->oi_orig; 84 return be; 85 } 86 87 88 typedef struct glue_state { 89 char *matched; 90 BerVarray refs; 91 LDAPControl **ctrls; 92 int err; 93 int matchlen; 94 int nrefs; 95 int nctrls; 96 } glue_state; 97 98 static int 99 glue_op_cleanup( Operation *op, SlapReply *rs ) 100 { 101 /* This is not a final result */ 102 if (rs->sr_type == REP_RESULT ) 103 rs->sr_type = REP_GLUE_RESULT; 104 return SLAP_CB_CONTINUE; 105 } 106 107 static int 108 glue_op_response ( Operation *op, SlapReply *rs ) 109 { 110 glue_state *gs = op->o_callback->sc_private; 111 112 switch(rs->sr_type) { 113 case REP_SEARCH: 114 case REP_SEARCHREF: 115 case REP_INTERMEDIATE: 116 return SLAP_CB_CONTINUE; 117 118 default: 119 if (rs->sr_err == LDAP_SUCCESS || 120 rs->sr_err == LDAP_SIZELIMIT_EXCEEDED || 121 rs->sr_err == LDAP_TIMELIMIT_EXCEEDED || 122 rs->sr_err == LDAP_ADMINLIMIT_EXCEEDED || 123 rs->sr_err == LDAP_NO_SUCH_OBJECT || 124 gs->err != LDAP_SUCCESS) 125 gs->err = rs->sr_err; 126 if (gs->err == LDAP_SUCCESS && gs->matched) { 127 ch_free (gs->matched); 128 gs->matched = NULL; 129 gs->matchlen = 0; 130 } 131 if (gs->err != LDAP_SUCCESS && rs->sr_matched) { 132 int len; 133 len = strlen (rs->sr_matched); 134 if (len > gs->matchlen) { 135 if (gs->matched) 136 ch_free (gs->matched); 137 gs->matched = ch_strdup (rs->sr_matched); 138 gs->matchlen = len; 139 } 140 } 141 if (rs->sr_ref) { 142 int i, j, k; 143 BerVarray new; 144 145 for (i=0; rs->sr_ref[i].bv_val; i++); 146 147 j = gs->nrefs; 148 if (!j) { 149 new = ch_malloc ((i+1)*sizeof(struct berval)); 150 } else { 151 new = ch_realloc(gs->refs, 152 (j+i+1)*sizeof(struct berval)); 153 } 154 for (k=0; k<i; j++,k++) { 155 ber_dupbv( &new[j], &rs->sr_ref[k] ); 156 } 157 new[j].bv_val = NULL; 158 gs->nrefs = j; 159 gs->refs = new; 160 } 161 if (rs->sr_ctrls) { 162 int i, j, k; 163 LDAPControl **newctrls; 164 165 for (i=0; rs->sr_ctrls[i]; i++); 166 167 j = gs->nctrls; 168 if (!j) { 169 newctrls = op->o_tmpalloc((i+1)*sizeof(LDAPControl *), 170 op->o_tmpmemctx); 171 } else { 172 /* Forget old pagedResults response if we're sending 173 * a new one now 174 */ 175 if ( get_pagedresults( op ) > SLAP_CONTROL_IGNORED ) { 176 int newpage = 0; 177 for ( k=0; k<i; k++ ) { 178 if ( !strcmp(rs->sr_ctrls[k]->ldctl_oid, 179 LDAP_CONTROL_PAGEDRESULTS )) { 180 newpage = 1; 181 break; 182 } 183 } 184 if ( newpage ) { 185 for ( k=0; k<j; k++ ) { 186 if ( !strcmp(gs->ctrls[k]->ldctl_oid, 187 LDAP_CONTROL_PAGEDRESULTS )) 188 { 189 op->o_tmpfree(gs->ctrls[k], op->o_tmpmemctx); 190 gs->ctrls[k] = gs->ctrls[--j]; 191 gs->ctrls[j] = NULL; 192 break; 193 } 194 } 195 } 196 } 197 newctrls = op->o_tmprealloc(gs->ctrls, 198 (j+i+1)*sizeof(LDAPControl *), op->o_tmpmemctx); 199 } 200 for (k=0; k<i; j++,k++) { 201 ber_len_t oidlen = strlen( rs->sr_ctrls[k]->ldctl_oid ); 202 newctrls[j] = op->o_tmpalloc(sizeof(LDAPControl) + oidlen + 1 + rs->sr_ctrls[k]->ldctl_value.bv_len + 1, 203 op->o_tmpmemctx); 204 newctrls[j]->ldctl_iscritical = rs->sr_ctrls[k]->ldctl_iscritical; 205 newctrls[j]->ldctl_oid = (char *)&newctrls[j][1]; 206 lutil_strcopy( newctrls[j]->ldctl_oid, rs->sr_ctrls[k]->ldctl_oid ); 207 if ( !BER_BVISNULL( &rs->sr_ctrls[k]->ldctl_value ) ) { 208 newctrls[j]->ldctl_value.bv_val = &newctrls[j]->ldctl_oid[oidlen + 1]; 209 newctrls[j]->ldctl_value.bv_len = rs->sr_ctrls[k]->ldctl_value.bv_len; 210 lutil_memcopy( newctrls[j]->ldctl_value.bv_val, 211 rs->sr_ctrls[k]->ldctl_value.bv_val, 212 rs->sr_ctrls[k]->ldctl_value.bv_len + 1 ); 213 } else { 214 BER_BVZERO( &newctrls[j]->ldctl_value ); 215 } 216 } 217 newctrls[j] = NULL; 218 gs->nctrls = j; 219 gs->ctrls = newctrls; 220 } 221 } 222 return 0; 223 } 224 225 static int 226 glue_op_func ( Operation *op, SlapReply *rs ) 227 { 228 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info; 229 BackendDB *b0 = op->o_bd; 230 BackendInfo *bi0 = op->o_bd->bd_info; 231 BI_op_modify **func; 232 slap_operation_t which = op_bind; 233 int rc; 234 235 op->o_bd = glue_back_select (b0, &op->o_req_ndn); 236 237 /* If we're on the master backend, let overlay framework handle it */ 238 if ( op->o_bd == b0 ) 239 return SLAP_CB_CONTINUE; 240 241 b0->bd_info = on->on_info->oi_orig; 242 243 switch(op->o_tag) { 244 case LDAP_REQ_ADD: which = op_add; break; 245 case LDAP_REQ_DELETE: which = op_delete; break; 246 case LDAP_REQ_MODIFY: which = op_modify; break; 247 case LDAP_REQ_MODRDN: which = op_modrdn; break; 248 case LDAP_REQ_EXTENDED: which = op_extended; break; 249 default: assert( 0 ); break; 250 } 251 252 func = &op->o_bd->bd_info->bi_op_bind; 253 if ( func[which] ) 254 rc = func[which]( op, rs ); 255 else 256 rc = SLAP_CB_BYPASS; 257 258 op->o_bd = b0; 259 op->o_bd->bd_info = bi0; 260 return rc; 261 } 262 263 static int 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 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 master 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 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 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 master 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 363 glue_sub_search( Operation *op, SlapReply *rs, BackendDB *b0, 364 slap_overinst *on ) 365 { 366 /* Process any overlays on the master 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 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 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, 0 ); 791 return LDAP_OTHER; 792 } 793 } 794 } 795 } 796 797 return 0; 798 } 799 800 static int 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 * 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 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 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 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 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 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 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 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 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 * 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 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 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 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 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 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, 0, 0 ); 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 ) { 1318 be->bd_info = (BackendInfo *)oi; 1319 glue_sub_attach( 1 ); 1320 } 1321 1322 return 0; 1323 } 1324 1325 static int 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 SLAP_CB_CONTINUE; 1336 } 1337 1338 static int 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 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 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, 0, 0 ); 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 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, 0, 0 ); 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 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 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