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