1 /* backglue.c - backend glue */ 2 /* $OpenLDAP: pkg/ldap/servers/slapd/backglue.c,v 1.112.2.12 2008/06/02 18:00:53 quanah Exp $ */ 3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>. 4 * 5 * Copyright 2001-2008 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 "config.h" 39 40 typedef struct gluenode { 41 BackendDB *gn_be; 42 struct berval gn_pdn; 43 } gluenode; 44 45 typedef struct glueinfo { 46 int gi_nodes; 47 struct berval gi_pdn; 48 gluenode gi_n[1]; 49 } glueinfo; 50 51 static slap_overinst glue; 52 53 static int glueMode; 54 static BackendDB *glueBack; 55 56 static slap_response glue_op_response; 57 58 /* Just like select_backend, but only for our backends */ 59 static BackendDB * 60 glue_back_select ( 61 BackendDB *be, 62 struct berval *dn 63 ) 64 { 65 slap_overinst *on = (slap_overinst *)be->bd_info; 66 glueinfo *gi = (glueinfo *)on->on_bi.bi_private; 67 int i; 68 69 for (i = gi->gi_nodes-1; i >= 0; i--) { 70 assert( gi->gi_n[i].gn_be->be_nsuffix != NULL ); 71 72 if (dnIsSuffix(dn, &gi->gi_n[i].gn_be->be_nsuffix[0])) { 73 return gi->gi_n[i].gn_be; 74 } 75 } 76 be->bd_info = on->on_info->oi_orig; 77 return be; 78 } 79 80 81 typedef struct glue_state { 82 char *matched; 83 BerVarray refs; 84 LDAPControl **ctrls; 85 int err; 86 int matchlen; 87 int nrefs; 88 int nctrls; 89 } glue_state; 90 91 static int 92 glue_op_cleanup( Operation *op, SlapReply *rs ) 93 { 94 /* This is not a final result */ 95 if (rs->sr_type == REP_RESULT ) 96 rs->sr_type = REP_GLUE_RESULT; 97 return SLAP_CB_CONTINUE; 98 } 99 100 static int 101 glue_op_response ( Operation *op, SlapReply *rs ) 102 { 103 glue_state *gs = op->o_callback->sc_private; 104 105 switch(rs->sr_type) { 106 case REP_SEARCH: 107 case REP_SEARCHREF: 108 case REP_INTERMEDIATE: 109 return SLAP_CB_CONTINUE; 110 111 default: 112 if (rs->sr_err == LDAP_SUCCESS || 113 rs->sr_err == LDAP_SIZELIMIT_EXCEEDED || 114 rs->sr_err == LDAP_TIMELIMIT_EXCEEDED || 115 rs->sr_err == LDAP_ADMINLIMIT_EXCEEDED || 116 rs->sr_err == LDAP_NO_SUCH_OBJECT || 117 gs->err != LDAP_SUCCESS) 118 gs->err = rs->sr_err; 119 if (gs->err == LDAP_SUCCESS && gs->matched) { 120 ch_free (gs->matched); 121 gs->matched = NULL; 122 gs->matchlen = 0; 123 } 124 if (gs->err != LDAP_SUCCESS && rs->sr_matched) { 125 int len; 126 len = strlen (rs->sr_matched); 127 if (len > gs->matchlen) { 128 if (gs->matched) 129 ch_free (gs->matched); 130 gs->matched = ch_strdup (rs->sr_matched); 131 gs->matchlen = len; 132 } 133 } 134 if (rs->sr_ref) { 135 int i, j, k; 136 BerVarray new; 137 138 for (i=0; rs->sr_ref[i].bv_val; i++); 139 140 j = gs->nrefs; 141 if (!j) { 142 new = ch_malloc ((i+1)*sizeof(struct berval)); 143 } else { 144 new = ch_realloc(gs->refs, 145 (j+i+1)*sizeof(struct berval)); 146 } 147 for (k=0; k<i; j++,k++) { 148 ber_dupbv( &new[j], &rs->sr_ref[k] ); 149 } 150 new[j].bv_val = NULL; 151 gs->nrefs = j; 152 gs->refs = new; 153 } 154 if (rs->sr_ctrls) { 155 int i, j, k; 156 LDAPControl **newctrls; 157 158 for (i=0; rs->sr_ctrls[i]; i++); 159 160 j = gs->nctrls; 161 if (!j) { 162 newctrls = ch_malloc((i+1)*sizeof(LDAPControl *)); 163 } else { 164 /* Forget old pagedResults response if we're sending 165 * a new one now 166 */ 167 if ( get_pagedresults( op ) > SLAP_CONTROL_IGNORED ) { 168 int newpage = 0; 169 for ( k=0; k<i; k++ ) { 170 if ( !strcmp(rs->sr_ctrls[k]->ldctl_oid, 171 LDAP_CONTROL_PAGEDRESULTS )) { 172 newpage = 1; 173 break; 174 } 175 } 176 if ( newpage ) { 177 for ( k=0; k<j; k++ ) { 178 if ( !strcmp(gs->ctrls[k]->ldctl_oid, 179 LDAP_CONTROL_PAGEDRESULTS )) { 180 gs->ctrls[k]->ldctl_oid = NULL; 181 ldap_control_free( gs->ctrls[k] ); 182 gs->ctrls[k] = gs->ctrls[--j]; 183 gs->ctrls[j] = NULL; 184 break; 185 } 186 } 187 } 188 } 189 newctrls = ch_realloc(gs->ctrls, 190 (j+i+1)*sizeof(LDAPControl *)); 191 } 192 for (k=0; k<i; j++,k++) { 193 newctrls[j] = ch_malloc(sizeof(LDAPControl)); 194 *newctrls[j] = *rs->sr_ctrls[k]; 195 if ( !BER_BVISNULL( &rs->sr_ctrls[k]->ldctl_value )) 196 ber_dupbv( &newctrls[j]->ldctl_value, 197 &rs->sr_ctrls[k]->ldctl_value ); 198 } 199 newctrls[j] = NULL; 200 gs->nctrls = j; 201 gs->ctrls = newctrls; 202 } 203 } 204 return 0; 205 } 206 207 static int 208 glue_op_func ( Operation *op, SlapReply *rs ) 209 { 210 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info; 211 BackendDB *b0 = op->o_bd; 212 BackendInfo *bi0 = op->o_bd->bd_info; 213 BI_op_modify **func; 214 slap_operation_t which = op_bind; 215 int rc; 216 217 op->o_bd = glue_back_select (b0, &op->o_req_ndn); 218 219 /* If we're on the master backend, let overlay framework handle it */ 220 if ( op->o_bd == b0 ) 221 return SLAP_CB_CONTINUE; 222 223 b0->bd_info = on->on_info->oi_orig; 224 225 switch(op->o_tag) { 226 case LDAP_REQ_ADD: which = op_add; break; 227 case LDAP_REQ_DELETE: which = op_delete; break; 228 case LDAP_REQ_MODIFY: which = op_modify; break; 229 case LDAP_REQ_MODRDN: which = op_modrdn; break; 230 case LDAP_REQ_EXTENDED: which = op_extended; break; 231 default: assert( 0 ); break; 232 } 233 234 func = &op->o_bd->bd_info->bi_op_bind; 235 if ( func[which] ) 236 rc = func[which]( op, rs ); 237 else 238 rc = SLAP_CB_BYPASS; 239 240 op->o_bd = b0; 241 op->o_bd->bd_info = bi0; 242 return rc; 243 } 244 245 static int 246 glue_response ( Operation *op, SlapReply *rs ) 247 { 248 BackendDB *be = op->o_bd; 249 be = glue_back_select (op->o_bd, &op->o_req_ndn); 250 251 /* If we're on the master backend, let overlay framework handle it. 252 * Otherwise, bail out. 253 */ 254 return ( op->o_bd == be ) ? SLAP_CB_CONTINUE : SLAP_CB_BYPASS; 255 } 256 257 static int 258 glue_chk_referrals ( Operation *op, SlapReply *rs ) 259 { 260 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info; 261 BackendDB *b0 = op->o_bd; 262 BackendInfo *bi0 = op->o_bd->bd_info; 263 int rc; 264 265 op->o_bd = glue_back_select (b0, &op->o_req_ndn); 266 if ( op->o_bd == b0 ) 267 return SLAP_CB_CONTINUE; 268 269 b0->bd_info = on->on_info->oi_orig; 270 271 if ( op->o_bd->bd_info->bi_chk_referrals ) 272 rc = ( *op->o_bd->bd_info->bi_chk_referrals )( op, rs ); 273 else 274 rc = SLAP_CB_CONTINUE; 275 276 op->o_bd = b0; 277 op->o_bd->bd_info = bi0; 278 return rc; 279 } 280 281 static int 282 glue_chk_controls ( Operation *op, SlapReply *rs ) 283 { 284 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info; 285 BackendDB *b0 = op->o_bd; 286 BackendInfo *bi0 = op->o_bd->bd_info; 287 int rc = SLAP_CB_CONTINUE; 288 289 op->o_bd = glue_back_select (b0, &op->o_req_ndn); 290 if ( op->o_bd == b0 ) 291 return SLAP_CB_CONTINUE; 292 293 b0->bd_info = on->on_info->oi_orig; 294 295 /* if the subordinate database has overlays, the bi_chk_controls() 296 * hook is actually over_aux_chk_controls(); in case it actually 297 * wraps a missing hok, we need to mimic the behavior 298 * of the frontend applied to that database */ 299 if ( op->o_bd->bd_info->bi_chk_controls ) { 300 rc = ( *op->o_bd->bd_info->bi_chk_controls )( op, rs ); 301 } 302 303 304 if ( rc == SLAP_CB_CONTINUE ) { 305 rc = backend_check_controls( op, rs ); 306 } 307 308 op->o_bd = b0; 309 op->o_bd->bd_info = bi0; 310 return rc; 311 } 312 313 /* ITS#4615 - overlays configured above the glue overlay should be 314 * invoked for the entire glued tree. Overlays configured below the 315 * glue overlay should only be invoked on the master backend. 316 * So, if we're searching on any subordinates, we need to force the 317 * current overlay chain to stop processing, without stopping the 318 * overall callback flow. 319 */ 320 static int 321 glue_sub_search( Operation *op, SlapReply *rs, BackendDB *b0, 322 slap_overinst *on ) 323 { 324 /* Process any overlays on the master backend */ 325 if ( op->o_bd == b0 && on->on_next ) { 326 BackendInfo *bi = op->o_bd->bd_info; 327 int rc = SLAP_CB_CONTINUE; 328 for ( on=on->on_next; on; on=on->on_next ) { 329 op->o_bd->bd_info = (BackendInfo *)on; 330 if ( on->on_bi.bi_op_search ) { 331 rc = on->on_bi.bi_op_search( op, rs ); 332 if ( rc != SLAP_CB_CONTINUE ) 333 break; 334 } 335 } 336 op->o_bd->bd_info = bi; 337 if ( rc != SLAP_CB_CONTINUE ) 338 return rc; 339 } 340 return op->o_bd->be_search( op, rs ); 341 } 342 343 static int 344 glue_op_search ( Operation *op, SlapReply *rs ) 345 { 346 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info; 347 glueinfo *gi = (glueinfo *)on->on_bi.bi_private; 348 BackendDB *b0 = op->o_bd; 349 BackendDB *b1 = NULL, *btmp; 350 BackendInfo *bi0 = op->o_bd->bd_info; 351 int i; 352 long stoptime = 0, starttime; 353 glue_state gs = {NULL, NULL, NULL, 0, 0, 0, 0}; 354 slap_callback cb = { NULL, glue_op_response, glue_op_cleanup, NULL }; 355 int scope0, tlimit0; 356 struct berval dn, ndn, *pdn; 357 358 cb.sc_private = &gs; 359 360 cb.sc_next = op->o_callback; 361 362 starttime = op->o_time; 363 stoptime = slap_get_time () + op->ors_tlimit; 364 365 op->o_bd = glue_back_select (b0, &op->o_req_ndn); 366 b0->bd_info = on->on_info->oi_orig; 367 368 switch (op->ors_scope) { 369 case LDAP_SCOPE_BASE: 370 if ( op->o_bd == b0 ) 371 return SLAP_CB_CONTINUE; 372 373 rs->sr_err = LDAP_UNWILLING_TO_PERFORM; 374 if (op->o_bd && op->o_bd->be_search) { 375 rs->sr_err = op->o_bd->be_search( op, rs ); 376 } 377 return rs->sr_err; 378 379 case LDAP_SCOPE_ONELEVEL: 380 case LDAP_SCOPE_SUBTREE: 381 case LDAP_SCOPE_SUBORDINATE: /* FIXME */ 382 op->o_callback = &cb; 383 rs->sr_err = gs.err = LDAP_UNWILLING_TO_PERFORM; 384 scope0 = op->ors_scope; 385 tlimit0 = op->ors_tlimit; 386 dn = op->o_req_dn; 387 ndn = op->o_req_ndn; 388 b1 = op->o_bd; 389 390 /* 391 * Execute in reverse order, most specific first 392 */ 393 for (i = gi->gi_nodes; i >= 0; i--) { 394 if ( i == gi->gi_nodes ) { 395 btmp = b0; 396 pdn = &gi->gi_pdn; 397 } else { 398 btmp = gi->gi_n[i].gn_be; 399 pdn = &gi->gi_n[i].gn_pdn; 400 } 401 if (!btmp || !btmp->be_search) 402 continue; 403 if (!dnIsSuffix(&btmp->be_nsuffix[0], &b1->be_nsuffix[0])) 404 continue; 405 if (get_no_subordinate_glue(op) && btmp != b1) 406 continue; 407 /* If we remembered which backend we were on before, 408 * skip down to it now 409 */ 410 if ( get_pagedresults( op ) > SLAP_CONTROL_IGNORED && 411 op->o_conn->c_pagedresults_state.ps_be && 412 op->o_conn->c_pagedresults_state.ps_be != btmp ) 413 continue; 414 415 if (tlimit0 != SLAP_NO_LIMIT) { 416 op->o_time = slap_get_time(); 417 op->ors_tlimit = stoptime - op->o_time; 418 if (op->ors_tlimit <= 0) { 419 rs->sr_err = gs.err = LDAP_TIMELIMIT_EXCEEDED; 420 break; 421 } 422 } 423 rs->sr_err = 0; 424 /* 425 * check for abandon 426 */ 427 if (op->o_abandon) { 428 goto end_of_loop; 429 } 430 op->o_bd = btmp; 431 432 assert( op->o_bd->be_suffix != NULL ); 433 assert( op->o_bd->be_nsuffix != NULL ); 434 435 if (scope0 == LDAP_SCOPE_ONELEVEL && 436 dn_match(pdn, &ndn)) 437 { 438 op->ors_scope = LDAP_SCOPE_BASE; 439 op->o_req_dn = op->o_bd->be_suffix[0]; 440 op->o_req_ndn = op->o_bd->be_nsuffix[0]; 441 rs->sr_err = op->o_bd->be_search(op, rs); 442 if ( rs->sr_err == LDAP_NO_SUCH_OBJECT ) { 443 gs.err = LDAP_SUCCESS; 444 } 445 op->ors_scope = LDAP_SCOPE_ONELEVEL; 446 op->o_req_dn = dn; 447 op->o_req_ndn = ndn; 448 449 } else if (scope0 == LDAP_SCOPE_SUBTREE && 450 dn_match(&op->o_bd->be_nsuffix[0], &ndn)) 451 { 452 rs->sr_err = glue_sub_search( op, rs, b0, on ); 453 454 } else if (scope0 == LDAP_SCOPE_SUBTREE && 455 dnIsSuffix(&op->o_bd->be_nsuffix[0], &ndn)) 456 { 457 op->o_req_dn = op->o_bd->be_suffix[0]; 458 op->o_req_ndn = op->o_bd->be_nsuffix[0]; 459 rs->sr_err = glue_sub_search( op, rs, b0, on ); 460 if ( rs->sr_err == LDAP_NO_SUCH_OBJECT ) { 461 gs.err = LDAP_SUCCESS; 462 } 463 op->o_req_dn = dn; 464 op->o_req_ndn = ndn; 465 466 } else if (dnIsSuffix(&ndn, &op->o_bd->be_nsuffix[0])) { 467 rs->sr_err = glue_sub_search( op, rs, b0, on ); 468 } 469 470 switch ( gs.err ) { 471 472 /* 473 * Add errors that should result in dropping 474 * the search 475 */ 476 case LDAP_SIZELIMIT_EXCEEDED: 477 case LDAP_TIMELIMIT_EXCEEDED: 478 case LDAP_ADMINLIMIT_EXCEEDED: 479 case LDAP_NO_SUCH_OBJECT: 480 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR 481 case LDAP_X_CANNOT_CHAIN: 482 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */ 483 goto end_of_loop; 484 485 case LDAP_SUCCESS: 486 if ( get_pagedresults( op ) > SLAP_CONTROL_IGNORED ) { 487 PagedResultsState *ps = op->o_pagedresults_state; 488 489 /* Assume this backend can be forgotten now */ 490 op->o_conn->c_pagedresults_state.ps_be = NULL; 491 492 /* If we have a full page, exit the loop. We may 493 * need to remember this backend so we can continue 494 * from here on a subsequent request. 495 */ 496 if ( rs->sr_nentries >= ps->ps_size ) { 497 /* Don't bother to remember the first backend. 498 * Only remember the last one if there's more state left. 499 */ 500 if ( op->o_bd != b0 && 501 ( op->o_conn->c_pagedresults_state.ps_cookie || 502 op->o_bd != gi->gi_n[0].gn_be )) 503 op->o_conn->c_pagedresults_state.ps_be = op->o_bd; 504 goto end_of_loop; 505 } 506 507 /* This backend has run out of entries, but more responses 508 * can fit in the page. Fake a reset of the state so the 509 * next backend will start up properly. Only back-[bh]db 510 * and back-sql look at this state info. 511 */ 512 if ( ps->ps_cookieval.bv_len == sizeof( PagedResultsCookie )) { 513 ps->ps_cookie = 0; 514 memset( ps->ps_cookieval.bv_val, 0, 515 sizeof( PagedResultsCookie )); 516 } 517 } 518 519 default: 520 break; 521 } 522 } 523 end_of_loop:; 524 op->ors_scope = scope0; 525 op->ors_tlimit = tlimit0; 526 op->o_time = starttime; 527 op->o_req_dn = dn; 528 op->o_req_ndn = ndn; 529 530 break; 531 } 532 if ( op->o_abandon ) { 533 rs->sr_err = SLAPD_ABANDON; 534 } else { 535 op->o_callback = cb.sc_next; 536 rs->sr_err = gs.err; 537 rs->sr_matched = gs.matched; 538 rs->sr_ref = gs.refs; 539 rs->sr_ctrls = gs.ctrls; 540 541 send_ldap_result( op, rs ); 542 } 543 544 op->o_bd = b0; 545 op->o_bd->bd_info = bi0; 546 if (gs.matched) 547 free (gs.matched); 548 if (gs.refs) 549 ber_bvarray_free(gs.refs); 550 if (gs.ctrls) { 551 for (i = gs.nctrls; --i >= 0; ) { 552 if (!BER_BVISNULL( &gs.ctrls[i]->ldctl_value )) 553 free(gs.ctrls[i]->ldctl_value.bv_val); 554 free(gs.ctrls[i]); 555 } 556 free(gs.ctrls); 557 } 558 return rs->sr_err; 559 } 560 561 static BackendDB toolDB; 562 563 static int 564 glue_tool_entry_open ( 565 BackendDB *b0, 566 int mode 567 ) 568 { 569 slap_overinfo *oi = (slap_overinfo *)b0->bd_info; 570 571 /* We don't know which backend to talk to yet, so just 572 * remember the mode and move on... 573 */ 574 575 glueMode = mode; 576 glueBack = NULL; 577 toolDB = *b0; 578 toolDB.bd_info = oi->oi_orig; 579 580 return 0; 581 } 582 583 static int 584 glue_tool_entry_close ( 585 BackendDB *b0 586 ) 587 { 588 int rc = 0; 589 590 if (glueBack) { 591 if (!glueBack->be_entry_close) 592 return 0; 593 rc = glueBack->be_entry_close (glueBack); 594 } 595 return rc; 596 } 597 598 static slap_overinst * 599 glue_tool_inst( 600 BackendInfo *bi 601 ) 602 { 603 slap_overinfo *oi = (slap_overinfo *)bi; 604 slap_overinst *on; 605 606 for ( on = oi->oi_list; on; on=on->on_next ) { 607 if ( !strcmp( on->on_bi.bi_type, glue.on_bi.bi_type )) 608 return on; 609 } 610 return NULL; 611 } 612 613 /* This function will only be called in tool mode */ 614 static int 615 glue_open ( 616 BackendInfo *bi 617 ) 618 { 619 slap_overinst *on = glue_tool_inst( bi ); 620 glueinfo *gi = on->on_bi.bi_private; 621 static int glueOpened = 0; 622 int i, j, same, bsame = 0, rc = 0; 623 ConfigReply cr = {0}; 624 625 if (glueOpened) return 0; 626 627 glueOpened = 1; 628 629 /* If we were invoked in tool mode, open all the underlying backends */ 630 if (slapMode & SLAP_TOOL_MODE) { 631 for (i = 0; i<gi->gi_nodes; i++) { 632 same = 0; 633 /* Same bi_open as our main backend? */ 634 if ( gi->gi_n[i].gn_be->bd_info->bi_open == 635 on->on_info->oi_orig->bi_open ) 636 bsame = 1; 637 638 /* Loop thru the bd_info's and make sure we only 639 * invoke their bi_open functions once each. 640 */ 641 for ( j = 0; j<i; j++ ) { 642 if ( gi->gi_n[i].gn_be->bd_info->bi_open == 643 gi->gi_n[j].gn_be->bd_info->bi_open ) { 644 same = 1; 645 break; 646 } 647 } 648 /* OK, it's unique and non-NULL, call it. */ 649 if ( !same && gi->gi_n[i].gn_be->bd_info->bi_open ) 650 rc = gi->gi_n[i].gn_be->bd_info->bi_open( 651 gi->gi_n[i].gn_be->bd_info ); 652 /* Let backend.c take care of the rest of startup */ 653 if ( !rc ) 654 rc = backend_startup_one( gi->gi_n[i].gn_be, &cr ); 655 if ( rc ) break; 656 } 657 if ( !rc && !bsame && on->on_info->oi_orig->bi_open ) 658 rc = on->on_info->oi_orig->bi_open( on->on_info->oi_orig ); 659 660 } /* other case is impossible */ 661 return rc; 662 } 663 664 /* This function will only be called in tool mode */ 665 static int 666 glue_close ( 667 BackendInfo *bi 668 ) 669 { 670 static int glueClosed = 0; 671 int rc = 0; 672 673 if (glueClosed) return 0; 674 675 glueClosed = 1; 676 677 if (slapMode & SLAP_TOOL_MODE) { 678 rc = backend_shutdown( NULL ); 679 } 680 return rc; 681 } 682 683 static int 684 glue_entry_get_rw ( 685 Operation *op, 686 struct berval *dn, 687 ObjectClass *oc, 688 AttributeDescription *ad, 689 int rw, 690 Entry **e ) 691 { 692 int rc; 693 BackendDB *b0 = op->o_bd; 694 op->o_bd = glue_back_select( b0, dn ); 695 696 if ( op->o_bd->be_fetch ) { 697 rc = op->o_bd->be_fetch( op, dn, oc, ad, rw, e ); 698 } else { 699 rc = LDAP_UNWILLING_TO_PERFORM; 700 } 701 op->o_bd =b0; 702 return rc; 703 } 704 705 static int 706 glue_entry_release_rw ( 707 Operation *op, 708 Entry *e, 709 int rw 710 ) 711 { 712 BackendDB *b0 = op->o_bd; 713 int rc = -1; 714 715 op->o_bd = glue_back_select (b0, &e->e_nname); 716 717 if ( op->o_bd->be_release ) { 718 rc = op->o_bd->be_release( op, e, rw ); 719 720 } else { 721 /* FIXME: mimic be_entry_release_rw 722 * when no be_release() available */ 723 /* free entry */ 724 entry_free( e ); 725 rc = 0; 726 } 727 op->o_bd = b0; 728 return rc; 729 } 730 731 static ID 732 glue_tool_entry_first ( 733 BackendDB *b0 734 ) 735 { 736 slap_overinst *on = glue_tool_inst( b0->bd_info ); 737 glueinfo *gi = on->on_bi.bi_private; 738 int i; 739 740 /* If we're starting from scratch, start at the most general */ 741 if (!glueBack) { 742 if ( toolDB.be_entry_open && toolDB.be_entry_first ) { 743 glueBack = &toolDB; 744 } else { 745 for (i = gi->gi_nodes-1; i >= 0; i--) { 746 if (gi->gi_n[i].gn_be->be_entry_open && 747 gi->gi_n[i].gn_be->be_entry_first) { 748 glueBack = gi->gi_n[i].gn_be; 749 break; 750 } 751 } 752 } 753 } 754 if (!glueBack || !glueBack->be_entry_open || !glueBack->be_entry_first || 755 glueBack->be_entry_open (glueBack, glueMode) != 0) 756 return NOID; 757 758 return glueBack->be_entry_first (glueBack); 759 } 760 761 static ID 762 glue_tool_entry_next ( 763 BackendDB *b0 764 ) 765 { 766 slap_overinst *on = glue_tool_inst( b0->bd_info ); 767 glueinfo *gi = on->on_bi.bi_private; 768 int i; 769 ID rc; 770 771 if (!glueBack || !glueBack->be_entry_next) 772 return NOID; 773 774 rc = glueBack->be_entry_next (glueBack); 775 776 /* If we ran out of entries in one database, move on to the next */ 777 while (rc == NOID) { 778 if ( glueBack && glueBack->be_entry_close ) 779 glueBack->be_entry_close (glueBack); 780 for (i=0; i<gi->gi_nodes; i++) { 781 if (gi->gi_n[i].gn_be == glueBack) 782 break; 783 } 784 if (i == 0) { 785 glueBack = NULL; 786 break; 787 } else { 788 glueBack = gi->gi_n[i-1].gn_be; 789 rc = glue_tool_entry_first (b0); 790 } 791 } 792 return rc; 793 } 794 795 static ID 796 glue_tool_dn2id_get ( 797 BackendDB *b0, 798 struct berval *dn 799 ) 800 { 801 BackendDB *be, b2; 802 int rc = -1; 803 804 b2 = *b0; 805 b2.bd_info = (BackendInfo *)glue_tool_inst( b0->bd_info ); 806 be = glue_back_select (&b2, dn); 807 if ( be == &b2 ) be = &toolDB; 808 809 if (!be->be_dn2id_get) 810 return NOID; 811 812 if (!glueBack) { 813 if ( be->be_entry_open ) { 814 rc = be->be_entry_open (be, glueMode); 815 } 816 if (rc != 0) { 817 return NOID; 818 } 819 } else if (be != glueBack) { 820 /* If this entry belongs in a different branch than the 821 * previous one, close the current database and open the 822 * new one. 823 */ 824 if ( glueBack->be_entry_close ) { 825 glueBack->be_entry_close (glueBack); 826 } 827 if ( be->be_entry_open ) { 828 rc = be->be_entry_open (be, glueMode); 829 } 830 if (rc != 0) { 831 return NOID; 832 } 833 } 834 glueBack = be; 835 return be->be_dn2id_get (be, dn); 836 } 837 838 static Entry * 839 glue_tool_entry_get ( 840 BackendDB *b0, 841 ID id 842 ) 843 { 844 if (!glueBack || !glueBack->be_entry_get) 845 return NULL; 846 847 return glueBack->be_entry_get (glueBack, id); 848 } 849 850 static ID 851 glue_tool_entry_put ( 852 BackendDB *b0, 853 Entry *e, 854 struct berval *text 855 ) 856 { 857 BackendDB *be, b2; 858 int rc = -1; 859 860 b2 = *b0; 861 b2.bd_info = (BackendInfo *)glue_tool_inst( b0->bd_info ); 862 be = glue_back_select (&b2, &e->e_nname); 863 if ( be == &b2 ) be = &toolDB; 864 865 if (!be->be_entry_put) 866 return NOID; 867 868 if (!glueBack) { 869 if ( be->be_entry_open ) { 870 rc = be->be_entry_open (be, glueMode); 871 } 872 if (rc != 0) { 873 return NOID; 874 } 875 } else if (be != glueBack) { 876 /* If this entry belongs in a different branch than the 877 * previous one, close the current database and open the 878 * new one. 879 */ 880 if ( glueBack->be_entry_close ) { 881 glueBack->be_entry_close (glueBack); 882 } 883 if ( be->be_entry_open ) { 884 rc = be->be_entry_open (be, glueMode); 885 } 886 if (rc != 0) { 887 return NOID; 888 } 889 } 890 glueBack = be; 891 return be->be_entry_put (be, e, text); 892 } 893 894 static ID 895 glue_tool_entry_modify ( 896 BackendDB *b0, 897 Entry *e, 898 struct berval *text 899 ) 900 { 901 if (!glueBack || !glueBack->be_entry_modify) 902 return NOID; 903 904 return glueBack->be_entry_modify (glueBack, e, text); 905 } 906 907 static int 908 glue_tool_entry_reindex ( 909 BackendDB *b0, 910 ID id, 911 AttributeDescription **adv 912 ) 913 { 914 if (!glueBack || !glueBack->be_entry_reindex) 915 return -1; 916 917 return glueBack->be_entry_reindex (glueBack, id, adv); 918 } 919 920 static int 921 glue_tool_sync ( 922 BackendDB *b0 923 ) 924 { 925 slap_overinst *on = glue_tool_inst( b0->bd_info ); 926 glueinfo *gi = on->on_bi.bi_private; 927 BackendInfo *bi = b0->bd_info; 928 int i; 929 930 /* just sync everyone */ 931 for (i = 0; i<gi->gi_nodes; i++) 932 if (gi->gi_n[i].gn_be->be_sync) 933 gi->gi_n[i].gn_be->be_sync (gi->gi_n[i].gn_be); 934 b0->bd_info = on->on_info->oi_orig; 935 if ( b0->be_sync ) 936 b0->be_sync( b0 ); 937 b0->bd_info = bi; 938 return 0; 939 } 940 941 static int 942 glue_db_init( 943 BackendDB *be, 944 ConfigReply *cr 945 ) 946 { 947 slap_overinst *on = (slap_overinst *)be->bd_info; 948 slap_overinfo *oi = on->on_info; 949 BackendInfo *bi = oi->oi_orig; 950 glueinfo *gi; 951 952 if ( SLAP_GLUE_SUBORDINATE( be )) { 953 Debug( LDAP_DEBUG_ANY, "glue: backend %s is already subordinate, " 954 "cannot have glue overlay!\n", 955 be->be_suffix[0].bv_val, 0, 0 ); 956 return LDAP_OTHER; 957 } 958 959 gi = ch_calloc( 1, sizeof(glueinfo)); 960 on->on_bi.bi_private = gi; 961 dnParent( be->be_nsuffix, &gi->gi_pdn ); 962 963 /* Currently the overlay framework doesn't handle these entry points 964 * but we need them.... 965 */ 966 oi->oi_bi.bi_open = glue_open; 967 oi->oi_bi.bi_close = glue_close; 968 969 /* Only advertise these if the root DB supports them */ 970 if ( bi->bi_tool_entry_open ) 971 oi->oi_bi.bi_tool_entry_open = glue_tool_entry_open; 972 if ( bi->bi_tool_entry_close ) 973 oi->oi_bi.bi_tool_entry_close = glue_tool_entry_close; 974 if ( bi->bi_tool_entry_first ) 975 oi->oi_bi.bi_tool_entry_first = glue_tool_entry_first; 976 if ( bi->bi_tool_entry_next ) 977 oi->oi_bi.bi_tool_entry_next = glue_tool_entry_next; 978 if ( bi->bi_tool_entry_get ) 979 oi->oi_bi.bi_tool_entry_get = glue_tool_entry_get; 980 if ( bi->bi_tool_dn2id_get ) 981 oi->oi_bi.bi_tool_dn2id_get = glue_tool_dn2id_get; 982 if ( bi->bi_tool_entry_put ) 983 oi->oi_bi.bi_tool_entry_put = glue_tool_entry_put; 984 if ( bi->bi_tool_entry_reindex ) 985 oi->oi_bi.bi_tool_entry_reindex = glue_tool_entry_reindex; 986 if ( bi->bi_tool_entry_modify ) 987 oi->oi_bi.bi_tool_entry_modify = glue_tool_entry_modify; 988 if ( bi->bi_tool_sync ) 989 oi->oi_bi.bi_tool_sync = glue_tool_sync; 990 991 SLAP_DBFLAGS( be ) |= SLAP_DBFLAG_GLUE_INSTANCE; 992 993 return 0; 994 } 995 996 static int 997 glue_db_destroy ( 998 BackendDB *be, 999 ConfigReply *cr 1000 ) 1001 { 1002 slap_overinst *on = (slap_overinst *)be->bd_info; 1003 glueinfo *gi = (glueinfo *)on->on_bi.bi_private; 1004 1005 free (gi); 1006 return SLAP_CB_CONTINUE; 1007 } 1008 1009 static int 1010 glue_db_close( 1011 BackendDB *be, 1012 ConfigReply *cr 1013 ) 1014 { 1015 slap_overinst *on = (slap_overinst *)be->bd_info; 1016 1017 on->on_info->oi_bi.bi_db_close = 0; 1018 return 0; 1019 } 1020 1021 int 1022 glue_sub_del( BackendDB *b0 ) 1023 { 1024 BackendDB *be; 1025 int rc = 0; 1026 1027 /* Find the top backend for this subordinate */ 1028 be = b0; 1029 while ( (be=LDAP_STAILQ_NEXT( be, be_next )) != NULL ) { 1030 slap_overinfo *oi; 1031 slap_overinst *on; 1032 glueinfo *gi; 1033 int i; 1034 1035 if ( SLAP_GLUE_SUBORDINATE( be )) 1036 continue; 1037 if ( !SLAP_GLUE_INSTANCE( be )) 1038 continue; 1039 if ( !dnIsSuffix( &b0->be_nsuffix[0], &be->be_nsuffix[0] )) 1040 continue; 1041 1042 /* OK, got the right backend, find the overlay */ 1043 oi = (slap_overinfo *)be->bd_info; 1044 for ( on=oi->oi_list; on; on=on->on_next ) { 1045 if ( on->on_bi.bi_type == glue.on_bi.bi_type ) 1046 break; 1047 } 1048 assert( on != NULL ); 1049 gi = on->on_bi.bi_private; 1050 for ( i=0; i < gi->gi_nodes; i++ ) { 1051 if ( gi->gi_n[i].gn_be == b0 ) { 1052 int j; 1053 1054 for (j=i+1; j < gi->gi_nodes; j++) 1055 gi->gi_n[j-1] = gi->gi_n[j]; 1056 1057 gi->gi_nodes--; 1058 } 1059 } 1060 } 1061 if ( be == NULL ) 1062 rc = LDAP_NO_SUCH_OBJECT; 1063 1064 return rc; 1065 } 1066 1067 typedef struct glue_Addrec { 1068 struct glue_Addrec *ga_next; 1069 BackendDB *ga_be; 1070 } glue_Addrec; 1071 1072 /* List of added subordinates */ 1073 static glue_Addrec *ga_list; 1074 1075 /* Attach all the subordinate backends to their superior */ 1076 int 1077 glue_sub_attach() 1078 { 1079 glue_Addrec *ga, *gnext = NULL; 1080 int rc = 0; 1081 1082 /* For all the subordinate backends */ 1083 for ( ga=ga_list; ga != NULL; ga = gnext ) { 1084 BackendDB *be; 1085 1086 gnext = ga->ga_next; 1087 1088 /* Find the top backend for this subordinate */ 1089 be = ga->ga_be; 1090 while ( (be=LDAP_STAILQ_NEXT( be, be_next )) != NULL ) { 1091 slap_overinfo *oi; 1092 slap_overinst *on; 1093 glueinfo *gi; 1094 1095 if ( SLAP_GLUE_SUBORDINATE( be )) 1096 continue; 1097 if ( !dnIsSuffix( &ga->ga_be->be_nsuffix[0], &be->be_nsuffix[0] )) 1098 continue; 1099 1100 /* If it's not already configured, set up the overlay */ 1101 if ( !SLAP_GLUE_INSTANCE( be )) { 1102 rc = overlay_config( be, glue.on_bi.bi_type, -1, NULL, NULL); 1103 if ( rc ) 1104 break; 1105 } 1106 /* Find the overlay instance */ 1107 oi = (slap_overinfo *)be->bd_info; 1108 for ( on=oi->oi_list; on; on=on->on_next ) { 1109 if ( on->on_bi.bi_type == glue.on_bi.bi_type ) 1110 break; 1111 } 1112 assert( on != NULL ); 1113 gi = on->on_bi.bi_private; 1114 gi = (glueinfo *)ch_realloc( gi, sizeof(glueinfo) + 1115 gi->gi_nodes * sizeof(gluenode)); 1116 gi->gi_n[gi->gi_nodes].gn_be = ga->ga_be; 1117 dnParent( &ga->ga_be->be_nsuffix[0], 1118 &gi->gi_n[gi->gi_nodes].gn_pdn ); 1119 gi->gi_nodes++; 1120 on->on_bi.bi_private = gi; 1121 break; 1122 } 1123 if ( !be ) { 1124 Debug( LDAP_DEBUG_ANY, "glue: no superior found for sub %s!\n", 1125 ga->ga_be->be_suffix[0].bv_val, 0, 0 ); 1126 rc = LDAP_NO_SUCH_OBJECT; 1127 } 1128 ch_free( ga ); 1129 if ( rc ) break; 1130 } 1131 1132 ga_list = gnext; 1133 1134 return rc; 1135 } 1136 1137 int 1138 glue_sub_add( BackendDB *be, int advert, int online ) 1139 { 1140 glue_Addrec *ga; 1141 int rc = 0; 1142 1143 if ( overlay_is_inst( be, "glue" )) { 1144 Debug( LDAP_DEBUG_ANY, "glue: backend %s already has glue overlay, " 1145 "cannot be a subordinate!\n", 1146 be->be_suffix[0].bv_val, 0, 0 ); 1147 return LDAP_OTHER; 1148 } 1149 SLAP_DBFLAGS( be ) |= SLAP_DBFLAG_GLUE_SUBORDINATE; 1150 if ( advert ) 1151 SLAP_DBFLAGS( be ) |= SLAP_DBFLAG_GLUE_ADVERTISE; 1152 1153 ga = ch_malloc( sizeof( glue_Addrec )); 1154 ga->ga_next = ga_list; 1155 ga->ga_be = be; 1156 ga_list = ga; 1157 1158 if ( online ) 1159 rc = glue_sub_attach(); 1160 1161 return rc; 1162 } 1163 1164 int 1165 glue_sub_init() 1166 { 1167 glue.on_bi.bi_type = "glue"; 1168 1169 glue.on_bi.bi_db_init = glue_db_init; 1170 glue.on_bi.bi_db_close = glue_db_close; 1171 glue.on_bi.bi_db_destroy = glue_db_destroy; 1172 1173 glue.on_bi.bi_op_search = glue_op_search; 1174 glue.on_bi.bi_op_modify = glue_op_func; 1175 glue.on_bi.bi_op_modrdn = glue_op_func; 1176 glue.on_bi.bi_op_add = glue_op_func; 1177 glue.on_bi.bi_op_delete = glue_op_func; 1178 glue.on_bi.bi_extended = glue_op_func; 1179 1180 glue.on_bi.bi_chk_referrals = glue_chk_referrals; 1181 glue.on_bi.bi_chk_controls = glue_chk_controls; 1182 glue.on_bi.bi_entry_get_rw = glue_entry_get_rw; 1183 glue.on_bi.bi_entry_release_rw = glue_entry_release_rw; 1184 1185 glue.on_response = glue_response; 1186 1187 return overlay_register( &glue ); 1188 } 1189