1 /* $NetBSD: backover.c,v 1.1.1.7 2018/02/06 01:53:14 christos Exp $ */ 2 3 /* backover.c - backend overlay routines */ 4 /* $OpenLDAP$ */ 5 /* This work is part of OpenLDAP Software <http://www.openldap.org/>. 6 * 7 * Copyright 2003-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 /* Functions to overlay other modules over a backend. */ 20 21 #include <sys/cdefs.h> 22 __RCSID("$NetBSD: backover.c,v 1.1.1.7 2018/02/06 01:53:14 christos Exp $"); 23 24 #include "portable.h" 25 26 #include <stdio.h> 27 28 #include <ac/string.h> 29 #include <ac/socket.h> 30 31 #define SLAPD_TOOLS 32 #include "slap.h" 33 #include "config.h" 34 35 static slap_overinst *overlays; 36 37 static int 38 over_db_config( 39 BackendDB *be, 40 const char *fname, 41 int lineno, 42 int argc, 43 char **argv 44 ) 45 { 46 slap_overinfo *oi = be->bd_info->bi_private; 47 slap_overinst *on = oi->oi_list; 48 BackendInfo *bi_orig = be->bd_info; 49 struct ConfigOCs *be_cf_ocs = be->be_cf_ocs; 50 ConfigArgs ca = {0}; 51 int rc = 0; 52 53 if ( oi->oi_orig->bi_db_config ) { 54 be->bd_info = oi->oi_orig; 55 be->be_cf_ocs = oi->oi_orig->bi_cf_ocs; 56 rc = oi->oi_orig->bi_db_config( be, fname, lineno, 57 argc, argv ); 58 59 if ( be->bd_info != oi->oi_orig ) { 60 slap_overinfo *oi2; 61 slap_overinst *on2, **onp; 62 BackendDB be2 = *be; 63 int i; 64 65 /* a database added an overlay; 66 * work it around... */ 67 assert( overlay_is_over( be ) ); 68 69 oi2 = ( slap_overinfo * )be->bd_info->bi_private; 70 on2 = oi2->oi_list; 71 72 /* need to put a uniqueness check here as well; 73 * note that in principle there could be more than 74 * one overlay as a result of multiple calls to 75 * overlay_config() */ 76 be2.bd_info = (BackendInfo *)oi; 77 78 for ( i = 0, onp = &on2; *onp; i++, onp = &(*onp)->on_next ) { 79 if ( overlay_is_inst( &be2, (*onp)->on_bi.bi_type ) ) { 80 Debug( LDAP_DEBUG_ANY, "over_db_config(): " 81 "warning, freshly added " 82 "overlay #%d \"%s\" is already in list\n", 83 i, (*onp)->on_bi.bi_type, 0 ); 84 85 /* NOTE: if the overlay already exists, 86 * there is no way to merge the results 87 * of the configuration that may have 88 * occurred during bi_db_config(); we 89 * just issue a warning, and the 90 * administrator should deal with this */ 91 } 92 } 93 *onp = oi->oi_list; 94 95 oi->oi_list = on2; 96 97 ch_free( be->bd_info ); 98 } 99 100 be->bd_info = (BackendInfo *)oi; 101 if ( rc != SLAP_CONF_UNKNOWN ) return rc; 102 } 103 104 ca.argv = argv; 105 ca.argc = argc; 106 ca.fname = fname; 107 ca.lineno = lineno; 108 ca.be = be; 109 snprintf( ca.log, sizeof( ca.log ), "%s: line %d", 110 ca.fname, ca.lineno ); 111 ca.op = SLAP_CONFIG_ADD; 112 ca.valx = -1; 113 114 for (; on; on=on->on_next) { 115 rc = SLAP_CONF_UNKNOWN; 116 if (on->on_bi.bi_cf_ocs) { 117 ConfigTable *ct; 118 ca.bi = &on->on_bi; 119 ct = config_find_keyword( on->on_bi.bi_cf_ocs->co_table, &ca ); 120 if ( ct ) { 121 ca.table = on->on_bi.bi_cf_ocs->co_type; 122 rc = config_add_vals( ct, &ca ); 123 if ( rc != SLAP_CONF_UNKNOWN ) 124 break; 125 } 126 } 127 if (on->on_bi.bi_db_config && rc == SLAP_CONF_UNKNOWN) { 128 be->bd_info = &on->on_bi; 129 rc = on->on_bi.bi_db_config( be, fname, lineno, 130 argc, argv ); 131 if ( rc != SLAP_CONF_UNKNOWN ) break; 132 } 133 } 134 be->bd_info = bi_orig; 135 be->be_cf_ocs = be_cf_ocs; 136 137 return rc; 138 } 139 140 static int 141 over_db_open( 142 BackendDB *be, 143 ConfigReply *cr 144 ) 145 { 146 slap_overinfo *oi = be->bd_info->bi_private; 147 slap_overinst *on = oi->oi_list; 148 BackendDB db = *be; 149 int rc = 0; 150 151 db.be_flags |= SLAP_DBFLAG_OVERLAY; 152 db.bd_info = oi->oi_orig; 153 if ( db.bd_info->bi_db_open ) { 154 rc = db.bd_info->bi_db_open( &db, cr ); 155 } 156 157 for (; on && rc == 0; on=on->on_next) { 158 db.bd_info = &on->on_bi; 159 if ( db.bd_info->bi_db_open ) { 160 rc = db.bd_info->bi_db_open( &db, cr ); 161 } 162 } 163 164 return rc; 165 } 166 167 static int 168 over_db_close( 169 BackendDB *be, 170 ConfigReply *cr 171 ) 172 { 173 slap_overinfo *oi = be->bd_info->bi_private; 174 slap_overinst *on = oi->oi_list; 175 BackendInfo *bi_orig = be->bd_info; 176 int rc = 0; 177 178 for (; on && rc == 0; on=on->on_next) { 179 be->bd_info = &on->on_bi; 180 if ( be->bd_info->bi_db_close ) { 181 rc = be->bd_info->bi_db_close( be, cr ); 182 } 183 } 184 185 if ( oi->oi_orig->bi_db_close ) { 186 be->bd_info = oi->oi_orig; 187 rc = be->bd_info->bi_db_close( be, cr ); 188 } 189 190 be->bd_info = bi_orig; 191 return rc; 192 } 193 194 static int 195 over_db_destroy( 196 BackendDB *be, 197 ConfigReply *cr 198 ) 199 { 200 slap_overinfo *oi = be->bd_info->bi_private; 201 slap_overinst *on = oi->oi_list, *next; 202 BackendInfo *bi_orig = be->bd_info; 203 int rc = 0; 204 205 be->bd_info = oi->oi_orig; 206 if ( be->bd_info->bi_db_destroy ) { 207 rc = be->bd_info->bi_db_destroy( be, cr ); 208 } 209 210 for (; on && rc == 0; on=on->on_next) { 211 be->bd_info = &on->on_bi; 212 if ( be->bd_info->bi_db_destroy ) { 213 rc = be->bd_info->bi_db_destroy( be, cr ); 214 } 215 } 216 217 on = oi->oi_list; 218 if ( on ) { 219 for (next = on->on_next; on; on=next) { 220 next = on->on_next; 221 free( on ); 222 } 223 } 224 be->bd_info = bi_orig; 225 free( oi ); 226 return rc; 227 } 228 229 static int 230 over_back_response ( Operation *op, SlapReply *rs ) 231 { 232 slap_overinfo *oi = op->o_callback->sc_private; 233 slap_overinst *on = oi->oi_list; 234 int rc = SLAP_CB_CONTINUE; 235 BackendDB *be = op->o_bd, db = *op->o_bd; 236 237 db.be_flags |= SLAP_DBFLAG_OVERLAY; 238 op->o_bd = &db; 239 for (; on; on=on->on_next ) { 240 if ( on->on_response ) { 241 db.bd_info = (BackendInfo *)on; 242 rc = on->on_response( op, rs ); 243 if ( rc != SLAP_CB_CONTINUE ) break; 244 } 245 } 246 /* Bypass the remaining on_response layers, but allow 247 * normal execution to continue. 248 */ 249 if ( rc == SLAP_CB_BYPASS ) 250 rc = SLAP_CB_CONTINUE; 251 op->o_bd = be; 252 return rc; 253 } 254 255 static int 256 over_access_allowed( 257 Operation *op, 258 Entry *e, 259 AttributeDescription *desc, 260 struct berval *val, 261 slap_access_t access, 262 AccessControlState *state, 263 slap_mask_t *maskp ) 264 { 265 slap_overinfo *oi; 266 slap_overinst *on; 267 BackendInfo *bi; 268 BackendDB *be = op->o_bd, db; 269 int rc = SLAP_CB_CONTINUE; 270 271 /* FIXME: used to happen for instance during abandon 272 * when global overlays are used... */ 273 assert( op->o_bd != NULL ); 274 275 bi = op->o_bd->bd_info; 276 /* Were we invoked on the frontend? */ 277 if ( !bi->bi_access_allowed ) { 278 oi = frontendDB->bd_info->bi_private; 279 } else { 280 oi = op->o_bd->bd_info->bi_private; 281 } 282 on = oi->oi_list; 283 284 for ( ; on; on = on->on_next ) { 285 if ( on->on_bi.bi_access_allowed ) { 286 /* NOTE: do not copy the structure until required */ 287 if ( !SLAP_ISOVERLAY( op->o_bd ) ) { 288 db = *op->o_bd; 289 db.be_flags |= SLAP_DBFLAG_OVERLAY; 290 op->o_bd = &db; 291 } 292 293 op->o_bd->bd_info = (BackendInfo *)on; 294 rc = on->on_bi.bi_access_allowed( op, e, 295 desc, val, access, state, maskp ); 296 if ( rc != SLAP_CB_CONTINUE ) break; 297 } 298 } 299 300 if ( rc == SLAP_CB_CONTINUE ) { 301 BI_access_allowed *bi_access_allowed; 302 303 /* if the database structure was changed, o_bd points to a 304 * copy of the structure; put the original bd_info in place */ 305 if ( SLAP_ISOVERLAY( op->o_bd ) ) { 306 op->o_bd->bd_info = oi->oi_orig; 307 } 308 309 if ( oi->oi_orig->bi_access_allowed ) { 310 bi_access_allowed = oi->oi_orig->bi_access_allowed; 311 } else { 312 bi_access_allowed = slap_access_allowed; 313 } 314 315 rc = bi_access_allowed( op, e, 316 desc, val, access, state, maskp ); 317 } 318 /* should not fall thru this far without anything happening... */ 319 if ( rc == SLAP_CB_CONTINUE ) { 320 /* access not allowed */ 321 rc = 0; 322 } 323 324 op->o_bd = be; 325 op->o_bd->bd_info = bi; 326 327 return rc; 328 } 329 330 int 331 overlay_entry_get_ov( 332 Operation *op, 333 struct berval *dn, 334 ObjectClass *oc, 335 AttributeDescription *ad, 336 int rw, 337 Entry **e, 338 slap_overinst *on ) 339 { 340 slap_overinfo *oi = on->on_info; 341 BackendDB *be = op->o_bd, db; 342 BackendInfo *bi = op->o_bd->bd_info; 343 int rc = SLAP_CB_CONTINUE; 344 345 for ( ; on; on = on->on_next ) { 346 if ( on->on_bi.bi_entry_get_rw ) { 347 /* NOTE: do not copy the structure until required */ 348 if ( !SLAP_ISOVERLAY( op->o_bd ) ) { 349 db = *op->o_bd; 350 db.be_flags |= SLAP_DBFLAG_OVERLAY; 351 op->o_bd = &db; 352 } 353 354 op->o_bd->bd_info = (BackendInfo *)on; 355 rc = on->on_bi.bi_entry_get_rw( op, dn, 356 oc, ad, rw, e ); 357 if ( rc != SLAP_CB_CONTINUE ) break; 358 } 359 } 360 361 if ( rc == SLAP_CB_CONTINUE ) { 362 /* if the database structure was changed, o_bd points to a 363 * copy of the structure; put the original bd_info in place */ 364 if ( SLAP_ISOVERLAY( op->o_bd ) ) { 365 op->o_bd->bd_info = oi->oi_orig; 366 } 367 368 if ( oi->oi_orig->bi_entry_get_rw ) { 369 rc = oi->oi_orig->bi_entry_get_rw( op, dn, 370 oc, ad, rw, e ); 371 } 372 } 373 /* should not fall thru this far without anything happening... */ 374 if ( rc == SLAP_CB_CONTINUE ) { 375 rc = LDAP_UNWILLING_TO_PERFORM; 376 } 377 378 op->o_bd = be; 379 op->o_bd->bd_info = bi; 380 381 return rc; 382 } 383 384 static int 385 over_entry_get_rw( 386 Operation *op, 387 struct berval *dn, 388 ObjectClass *oc, 389 AttributeDescription *ad, 390 int rw, 391 Entry **e ) 392 { 393 slap_overinfo *oi; 394 slap_overinst *on; 395 396 assert( op->o_bd != NULL ); 397 398 oi = op->o_bd->bd_info->bi_private; 399 on = oi->oi_list; 400 401 return overlay_entry_get_ov( op, dn, oc, ad, rw, e, on ); 402 } 403 404 int 405 overlay_entry_release_ov( 406 Operation *op, 407 Entry *e, 408 int rw, 409 slap_overinst *on ) 410 { 411 slap_overinfo *oi = on->on_info; 412 BackendDB *be = op->o_bd, db; 413 BackendInfo *bi = op->o_bd->bd_info; 414 int rc = SLAP_CB_CONTINUE; 415 416 for ( ; on; on = on->on_next ) { 417 if ( on->on_bi.bi_entry_release_rw ) { 418 /* NOTE: do not copy the structure until required */ 419 if ( !SLAP_ISOVERLAY( op->o_bd ) ) { 420 db = *op->o_bd; 421 db.be_flags |= SLAP_DBFLAG_OVERLAY; 422 op->o_bd = &db; 423 } 424 425 op->o_bd->bd_info = (BackendInfo *)on; 426 rc = on->on_bi.bi_entry_release_rw( op, e, rw ); 427 if ( rc != SLAP_CB_CONTINUE ) break; 428 } 429 } 430 431 if ( rc == SLAP_CB_CONTINUE ) { 432 /* if the database structure was changed, o_bd points to a 433 * copy of the structure; put the original bd_info in place */ 434 if ( SLAP_ISOVERLAY( op->o_bd ) ) { 435 op->o_bd->bd_info = oi->oi_orig; 436 } 437 438 if ( oi->oi_orig->bi_entry_release_rw ) { 439 rc = oi->oi_orig->bi_entry_release_rw( op, e, rw ); 440 } 441 } 442 /* should not fall thru this far without anything happening... */ 443 if ( rc == SLAP_CB_CONTINUE ) { 444 entry_free( e ); 445 rc = 0; 446 } 447 448 op->o_bd = be; 449 op->o_bd->bd_info = bi; 450 451 return rc; 452 } 453 454 static int 455 over_entry_release_rw( 456 Operation *op, 457 Entry *e, 458 int rw ) 459 { 460 slap_overinfo *oi; 461 slap_overinst *on; 462 463 assert( op->o_bd != NULL ); 464 465 oi = op->o_bd->bd_info->bi_private; 466 on = oi->oi_list; 467 468 return overlay_entry_release_ov( op, e, rw, on ); 469 } 470 471 static int 472 over_acl_group( 473 Operation *op, 474 Entry *e, 475 struct berval *gr_ndn, 476 struct berval *op_ndn, 477 ObjectClass *group_oc, 478 AttributeDescription *group_at ) 479 { 480 slap_overinfo *oi; 481 slap_overinst *on; 482 BackendInfo *bi; 483 BackendDB *be = op->o_bd, db; 484 int rc = SLAP_CB_CONTINUE; 485 486 /* FIXME: used to happen for instance during abandon 487 * when global overlays are used... */ 488 assert( be != NULL ); 489 490 bi = be->bd_info; 491 oi = bi->bi_private; 492 on = oi->oi_list; 493 494 for ( ; on; on = on->on_next ) { 495 if ( on->on_bi.bi_acl_group ) { 496 /* NOTE: do not copy the structure until required */ 497 if ( !SLAP_ISOVERLAY( op->o_bd ) ) { 498 db = *op->o_bd; 499 db.be_flags |= SLAP_DBFLAG_OVERLAY; 500 op->o_bd = &db; 501 } 502 503 op->o_bd->bd_info = (BackendInfo *)on; 504 rc = on->on_bi.bi_acl_group( op, e, 505 gr_ndn, op_ndn, group_oc, group_at ); 506 if ( rc != SLAP_CB_CONTINUE ) break; 507 } 508 } 509 510 if ( rc == SLAP_CB_CONTINUE ) { 511 BI_acl_group *bi_acl_group; 512 513 /* if the database structure was changed, o_bd points to a 514 * copy of the structure; put the original bd_info in place */ 515 if ( SLAP_ISOVERLAY( op->o_bd ) ) { 516 op->o_bd->bd_info = oi->oi_orig; 517 } 518 519 if ( oi->oi_orig->bi_acl_group ) { 520 bi_acl_group = oi->oi_orig->bi_acl_group; 521 } else { 522 bi_acl_group = backend_group; 523 } 524 525 rc = bi_acl_group( op, e, 526 gr_ndn, op_ndn, group_oc, group_at ); 527 } 528 /* should not fall thru this far without anything happening... */ 529 if ( rc == SLAP_CB_CONTINUE ) { 530 /* access not allowed */ 531 rc = 0; 532 } 533 534 op->o_bd = be; 535 op->o_bd->bd_info = bi; 536 537 return rc; 538 } 539 540 static int 541 over_acl_attribute( 542 Operation *op, 543 Entry *target, 544 struct berval *entry_ndn, 545 AttributeDescription *entry_at, 546 BerVarray *vals, 547 slap_access_t access ) 548 { 549 slap_overinfo *oi; 550 slap_overinst *on; 551 BackendInfo *bi; 552 BackendDB *be = op->o_bd, db; 553 int rc = SLAP_CB_CONTINUE; 554 555 /* FIXME: used to happen for instance during abandon 556 * when global overlays are used... */ 557 assert( be != NULL ); 558 559 bi = be->bd_info; 560 oi = bi->bi_private; 561 on = oi->oi_list; 562 563 for ( ; on; on = on->on_next ) { 564 if ( on->on_bi.bi_acl_attribute ) { 565 /* NOTE: do not copy the structure until required */ 566 if ( !SLAP_ISOVERLAY( op->o_bd ) ) { 567 db = *op->o_bd; 568 db.be_flags |= SLAP_DBFLAG_OVERLAY; 569 op->o_bd = &db; 570 } 571 572 op->o_bd->bd_info = (BackendInfo *)on; 573 rc = on->on_bi.bi_acl_attribute( op, target, 574 entry_ndn, entry_at, vals, access ); 575 if ( rc != SLAP_CB_CONTINUE ) break; 576 } 577 } 578 579 if ( rc == SLAP_CB_CONTINUE ) { 580 BI_acl_attribute *bi_acl_attribute; 581 582 /* if the database structure was changed, o_bd points to a 583 * copy of the structure; put the original bd_info in place */ 584 if ( SLAP_ISOVERLAY( op->o_bd ) ) { 585 op->o_bd->bd_info = oi->oi_orig; 586 } 587 588 if ( oi->oi_orig->bi_acl_attribute ) { 589 bi_acl_attribute = oi->oi_orig->bi_acl_attribute; 590 } else { 591 bi_acl_attribute = backend_attribute; 592 } 593 594 rc = bi_acl_attribute( op, target, 595 entry_ndn, entry_at, vals, access ); 596 } 597 /* should not fall thru this far without anything happening... */ 598 if ( rc == SLAP_CB_CONTINUE ) { 599 /* access not allowed */ 600 rc = 0; 601 } 602 603 op->o_bd = be; 604 op->o_bd->bd_info = bi; 605 606 return rc; 607 } 608 609 int 610 overlay_callback_after_backover( Operation *op, slap_callback *sc, int append ) 611 { 612 slap_callback **scp; 613 614 for ( scp = &op->o_callback; *scp != NULL; scp = &(*scp)->sc_next ) { 615 if ( (*scp)->sc_response == over_back_response ) { 616 sc->sc_next = (*scp)->sc_next; 617 (*scp)->sc_next = sc; 618 return 0; 619 } 620 } 621 622 if ( append ) { 623 *scp = sc; 624 return 0; 625 } 626 627 return 1; 628 } 629 630 /* 631 * default return code in case of missing backend function 632 * and overlay stack returning SLAP_CB_CONTINUE 633 */ 634 static int op_rc[ op_last ] = { 635 LDAP_UNWILLING_TO_PERFORM, /* bind */ 636 LDAP_UNWILLING_TO_PERFORM, /* unbind */ 637 LDAP_UNWILLING_TO_PERFORM, /* search */ 638 SLAP_CB_CONTINUE, /* compare; pass to frontend */ 639 LDAP_UNWILLING_TO_PERFORM, /* modify */ 640 LDAP_UNWILLING_TO_PERFORM, /* modrdn */ 641 LDAP_UNWILLING_TO_PERFORM, /* add */ 642 LDAP_UNWILLING_TO_PERFORM, /* delete */ 643 LDAP_UNWILLING_TO_PERFORM, /* abandon */ 644 LDAP_UNWILLING_TO_PERFORM, /* cancel */ 645 LDAP_UNWILLING_TO_PERFORM, /* extended */ 646 LDAP_SUCCESS, /* aux_operational */ 647 LDAP_SUCCESS, /* aux_chk_referrals */ 648 SLAP_CB_CONTINUE /* aux_chk_controls; pass to frontend */ 649 }; 650 651 int overlay_op_walk( 652 Operation *op, 653 SlapReply *rs, 654 slap_operation_t which, 655 slap_overinfo *oi, 656 slap_overinst *on 657 ) 658 { 659 BI_op_bind **func; 660 int rc = SLAP_CB_CONTINUE; 661 662 for (; on; on=on->on_next ) { 663 func = &on->on_bi.bi_op_bind; 664 if ( func[which] ) { 665 op->o_bd->bd_info = (BackendInfo *)on; 666 rc = func[which]( op, rs ); 667 if ( rc != SLAP_CB_CONTINUE ) break; 668 } 669 } 670 if ( rc == SLAP_CB_BYPASS ) 671 rc = SLAP_CB_CONTINUE; 672 673 /* if an overlay halted processing, make sure 674 * any previously set cleanup handlers are run 675 */ 676 if ( rc != SLAP_CB_CONTINUE ) 677 goto cleanup; 678 679 func = &oi->oi_orig->bi_op_bind; 680 if ( func[which] ) { 681 op->o_bd->bd_info = oi->oi_orig; 682 rc = func[which]( op, rs ); 683 } 684 /* should not fall thru this far without anything happening... */ 685 if ( rc == SLAP_CB_CONTINUE ) { 686 rc = op_rc[ which ]; 687 } 688 689 /* The underlying backend didn't handle the request, make sure 690 * overlay cleanup is processed. 691 */ 692 if ( rc == LDAP_UNWILLING_TO_PERFORM ) { 693 slap_callback *sc_next; 694 cleanup: 695 for ( ; op->o_callback && op->o_callback->sc_response != 696 over_back_response; op->o_callback = sc_next ) { 697 sc_next = op->o_callback->sc_next; 698 if ( op->o_callback->sc_cleanup ) { 699 op->o_callback->sc_cleanup( op, rs ); 700 } 701 } 702 } 703 return rc; 704 } 705 706 static int 707 over_op_func( 708 Operation *op, 709 SlapReply *rs, 710 slap_operation_t which 711 ) 712 { 713 slap_overinfo *oi; 714 slap_overinst *on; 715 BackendDB *be = op->o_bd, db; 716 slap_callback cb = {NULL, over_back_response, NULL, NULL}, **sc; 717 int rc = SLAP_CB_CONTINUE; 718 719 /* FIXME: used to happen for instance during abandon 720 * when global overlays are used... */ 721 assert( op->o_bd != NULL ); 722 723 oi = op->o_bd->bd_info->bi_private; 724 on = oi->oi_list; 725 726 if ( !SLAP_ISOVERLAY( op->o_bd )) { 727 db = *op->o_bd; 728 db.be_flags |= SLAP_DBFLAG_OVERLAY; 729 op->o_bd = &db; 730 } 731 cb.sc_next = op->o_callback; 732 cb.sc_private = oi; 733 op->o_callback = &cb; 734 735 rc = overlay_op_walk( op, rs, which, oi, on ); 736 for ( sc = &op->o_callback; *sc; sc = &(*sc)->sc_next ) { 737 if ( *sc == &cb ) { 738 *sc = cb.sc_next; 739 break; 740 } 741 } 742 743 op->o_bd = be; 744 return rc; 745 } 746 747 static int 748 over_op_bind( Operation *op, SlapReply *rs ) 749 { 750 return over_op_func( op, rs, op_bind ); 751 } 752 753 static int 754 over_op_unbind( Operation *op, SlapReply *rs ) 755 { 756 return over_op_func( op, rs, op_unbind ); 757 } 758 759 static int 760 over_op_search( Operation *op, SlapReply *rs ) 761 { 762 return over_op_func( op, rs, op_search ); 763 } 764 765 static int 766 over_op_compare( Operation *op, SlapReply *rs ) 767 { 768 return over_op_func( op, rs, op_compare ); 769 } 770 771 static int 772 over_op_modify( Operation *op, SlapReply *rs ) 773 { 774 return over_op_func( op, rs, op_modify ); 775 } 776 777 static int 778 over_op_modrdn( Operation *op, SlapReply *rs ) 779 { 780 return over_op_func( op, rs, op_modrdn ); 781 } 782 783 static int 784 over_op_add( Operation *op, SlapReply *rs ) 785 { 786 return over_op_func( op, rs, op_add ); 787 } 788 789 static int 790 over_op_delete( Operation *op, SlapReply *rs ) 791 { 792 return over_op_func( op, rs, op_delete ); 793 } 794 795 static int 796 over_op_abandon( Operation *op, SlapReply *rs ) 797 { 798 return over_op_func( op, rs, op_abandon ); 799 } 800 801 static int 802 over_op_cancel( Operation *op, SlapReply *rs ) 803 { 804 return over_op_func( op, rs, op_cancel ); 805 } 806 807 static int 808 over_op_extended( Operation *op, SlapReply *rs ) 809 { 810 return over_op_func( op, rs, op_extended ); 811 } 812 813 static int 814 over_aux_operational( Operation *op, SlapReply *rs ) 815 { 816 return over_op_func( op, rs, op_aux_operational ); 817 } 818 819 static int 820 over_aux_chk_referrals( Operation *op, SlapReply *rs ) 821 { 822 return over_op_func( op, rs, op_aux_chk_referrals ); 823 } 824 825 static int 826 over_aux_chk_controls( Operation *op, SlapReply *rs ) 827 { 828 return over_op_func( op, rs, op_aux_chk_controls ); 829 } 830 831 enum conn_which { 832 conn_init = 0, 833 conn_destroy, 834 conn_last 835 }; 836 837 static int 838 over_connection_func( 839 BackendDB *bd, 840 Connection *conn, 841 enum conn_which which 842 ) 843 { 844 slap_overinfo *oi; 845 slap_overinst *on; 846 BackendDB db; 847 int rc = SLAP_CB_CONTINUE; 848 BI_connection_init **func; 849 850 /* FIXME: used to happen for instance during abandon 851 * when global overlays are used... */ 852 assert( bd != NULL ); 853 854 oi = bd->bd_info->bi_private; 855 on = oi->oi_list; 856 857 if ( !SLAP_ISOVERLAY( bd ) ) { 858 db = *bd; 859 db.be_flags |= SLAP_DBFLAG_OVERLAY; 860 bd = &db; 861 } 862 863 for ( ; on; on = on->on_next ) { 864 func = &on->on_bi.bi_connection_init; 865 if ( func[ which ] ) { 866 bd->bd_info = (BackendInfo *)on; 867 rc = func[ which ]( bd, conn ); 868 if ( rc != SLAP_CB_CONTINUE ) break; 869 } 870 } 871 872 func = &oi->oi_orig->bi_connection_init; 873 if ( func[ which ] && rc == SLAP_CB_CONTINUE ) { 874 bd->bd_info = oi->oi_orig; 875 rc = func[ which ]( bd, conn ); 876 } 877 /* should not fall thru this far without anything happening... */ 878 if ( rc == SLAP_CB_CONTINUE ) { 879 rc = LDAP_UNWILLING_TO_PERFORM; 880 } 881 882 return rc; 883 } 884 885 static int 886 over_connection_init( 887 BackendDB *bd, 888 Connection *conn 889 ) 890 { 891 return over_connection_func( bd, conn, conn_init ); 892 } 893 894 static int 895 over_connection_destroy( 896 BackendDB *bd, 897 Connection *conn 898 ) 899 { 900 return over_connection_func( bd, conn, conn_destroy ); 901 } 902 903 int 904 overlay_register( 905 slap_overinst *on 906 ) 907 { 908 slap_overinst *tmp; 909 910 /* FIXME: check for duplicates? */ 911 for ( tmp = overlays; tmp != NULL; tmp = tmp->on_next ) { 912 if ( strcmp( on->on_bi.bi_type, tmp->on_bi.bi_type ) == 0 ) { 913 Debug( LDAP_DEBUG_ANY, 914 "overlay_register(\"%s\"): " 915 "name already in use.\n", 916 on->on_bi.bi_type, 0, 0 ); 917 return -1; 918 } 919 920 if ( on->on_bi.bi_obsolete_names != NULL ) { 921 int i; 922 923 for ( i = 0; on->on_bi.bi_obsolete_names[ i ] != NULL; i++ ) { 924 if ( strcmp( on->on_bi.bi_obsolete_names[ i ], tmp->on_bi.bi_type ) == 0 ) { 925 Debug( LDAP_DEBUG_ANY, 926 "overlay_register(\"%s\"): " 927 "obsolete name \"%s\" already in use " 928 "by overlay \"%s\".\n", 929 on->on_bi.bi_type, 930 on->on_bi.bi_obsolete_names[ i ], 931 tmp->on_bi.bi_type ); 932 return -1; 933 } 934 } 935 } 936 937 if ( tmp->on_bi.bi_obsolete_names != NULL ) { 938 int i; 939 940 for ( i = 0; tmp->on_bi.bi_obsolete_names[ i ] != NULL; i++ ) { 941 int j; 942 943 if ( strcmp( on->on_bi.bi_type, tmp->on_bi.bi_obsolete_names[ i ] ) == 0 ) { 944 Debug( LDAP_DEBUG_ANY, 945 "overlay_register(\"%s\"): " 946 "name already in use " 947 "as obsolete by overlay \"%s\".\n", 948 on->on_bi.bi_type, 949 tmp->on_bi.bi_obsolete_names[ i ], 0 ); 950 return -1; 951 } 952 953 if ( on->on_bi.bi_obsolete_names != NULL ) { 954 for ( j = 0; on->on_bi.bi_obsolete_names[ j ] != NULL; j++ ) { 955 if ( strcmp( on->on_bi.bi_obsolete_names[ j ], tmp->on_bi.bi_obsolete_names[ i ] ) == 0 ) { 956 Debug( LDAP_DEBUG_ANY, 957 "overlay_register(\"%s\"): " 958 "obsolete name \"%s\" already in use " 959 "as obsolete by overlay \"%s\".\n", 960 on->on_bi.bi_type, 961 on->on_bi.bi_obsolete_names[ j ], 962 tmp->on_bi.bi_type ); 963 return -1; 964 } 965 } 966 } 967 } 968 } 969 } 970 971 on->on_next = overlays; 972 overlays = on; 973 return 0; 974 } 975 976 /* 977 * iterator on registered overlays; overlay_next( NULL ) returns the first 978 * overlay; subsequent calls with the previously returned value allow to 979 * iterate over the entire list; returns NULL when no more overlays are 980 * registered. 981 */ 982 983 slap_overinst * 984 overlay_next( 985 slap_overinst *on 986 ) 987 { 988 if ( on == NULL ) { 989 return overlays; 990 } 991 992 return on->on_next; 993 } 994 995 /* 996 * returns a specific registered overlay based on the type; NULL if not 997 * registered. 998 */ 999 1000 slap_overinst * 1001 overlay_find( const char *over_type ) 1002 { 1003 slap_overinst *on = overlays; 1004 1005 assert( over_type != NULL ); 1006 1007 for ( ; on; on = on->on_next ) { 1008 if ( strcmp( on->on_bi.bi_type, over_type ) == 0 ) { 1009 goto foundit; 1010 } 1011 1012 if ( on->on_bi.bi_obsolete_names != NULL ) { 1013 int i; 1014 1015 for ( i = 0; on->on_bi.bi_obsolete_names[ i ] != NULL; i++ ) { 1016 if ( strcmp( on->on_bi.bi_obsolete_names[ i ], over_type ) == 0 ) { 1017 Debug( LDAP_DEBUG_ANY, 1018 "overlay_find(\"%s\"): " 1019 "obsolete name for \"%s\".\n", 1020 on->on_bi.bi_obsolete_names[ i ], 1021 on->on_bi.bi_type, 0 ); 1022 goto foundit; 1023 } 1024 } 1025 } 1026 } 1027 1028 foundit:; 1029 return on; 1030 } 1031 1032 static const char overtype[] = "over"; 1033 1034 /* 1035 * returns TRUE (1) if the database is actually an overlay instance; 1036 * FALSE (0) otherwise. 1037 */ 1038 1039 int 1040 overlay_is_over( BackendDB *be ) 1041 { 1042 return be->bd_info->bi_type == overtype; 1043 } 1044 1045 /* 1046 * returns TRUE (1) if the given database is actually an overlay 1047 * instance and, somewhere in the list, contains the requested overlay; 1048 * FALSE (0) otherwise. 1049 */ 1050 1051 int 1052 overlay_is_inst( BackendDB *be, const char *over_type ) 1053 { 1054 slap_overinst *on; 1055 1056 assert( be != NULL ); 1057 1058 if ( !overlay_is_over( be ) ) { 1059 return 0; 1060 } 1061 1062 on = ((slap_overinfo *)be->bd_info->bi_private)->oi_list; 1063 for ( ; on; on = on->on_next ) { 1064 if ( strcmp( on->on_bi.bi_type, over_type ) == 0 ) { 1065 return 1; 1066 } 1067 } 1068 1069 return 0; 1070 } 1071 1072 int 1073 overlay_register_control( BackendDB *be, const char *oid ) 1074 { 1075 int gotit = 0; 1076 int cid; 1077 1078 if ( slap_find_control_id( oid, &cid ) == LDAP_CONTROL_NOT_FOUND ) { 1079 return -1; 1080 } 1081 1082 if ( SLAP_ISGLOBALOVERLAY( be ) ) { 1083 BackendDB *bd; 1084 1085 /* add to all backends... */ 1086 LDAP_STAILQ_FOREACH( bd, &backendDB, be_next ) { 1087 if ( bd == be->bd_self ) { 1088 gotit = 1; 1089 } 1090 1091 /* overlays can be instanciated multiple times, use 1092 * be_ctrls[ cid ] as an instance counter, so that the 1093 * overlay's controls are only really disabled after the 1094 * last instance called overlay_register_control() */ 1095 bd->be_ctrls[ cid ]++; 1096 bd->be_ctrls[ SLAP_MAX_CIDS ] = 1; 1097 } 1098 1099 } 1100 1101 if ( !gotit ) { 1102 /* overlays can be instanciated multiple times, use 1103 * be_ctrls[ cid ] as an instance counter, so that the 1104 * overlay's controls are only really unregistered after the 1105 * last instance called overlay_register_control() */ 1106 be->bd_self->be_ctrls[ cid ]++; 1107 be->bd_self->be_ctrls[ SLAP_MAX_CIDS ] = 1; 1108 } 1109 1110 return 0; 1111 } 1112 1113 #ifdef SLAP_CONFIG_DELETE 1114 void 1115 overlay_unregister_control( BackendDB *be, const char *oid ) 1116 { 1117 int gotit = 0; 1118 int cid; 1119 1120 if ( slap_find_control_id( oid, &cid ) == LDAP_CONTROL_NOT_FOUND ) { 1121 return; 1122 } 1123 1124 if ( SLAP_ISGLOBALOVERLAY( be ) ) { 1125 BackendDB *bd; 1126 1127 /* remove from all backends... */ 1128 LDAP_STAILQ_FOREACH( bd, &backendDB, be_next ) { 1129 if ( bd == be->bd_self ) { 1130 gotit = 1; 1131 } 1132 1133 bd->be_ctrls[ cid ]--; 1134 } 1135 } 1136 1137 if ( !gotit ) { 1138 be->bd_self->be_ctrls[ cid ]--; 1139 } 1140 } 1141 #endif /* SLAP_CONFIG_DELETE */ 1142 1143 void 1144 overlay_destroy_one( BackendDB *be, slap_overinst *on ) 1145 { 1146 slap_overinfo *oi = on->on_info; 1147 slap_overinst **oidx; 1148 1149 for ( oidx = &oi->oi_list; *oidx; oidx = &(*oidx)->on_next ) { 1150 if ( *oidx == on ) { 1151 *oidx = on->on_next; 1152 if ( on->on_bi.bi_db_destroy ) { 1153 BackendInfo *bi_orig = be->bd_info; 1154 be->bd_info = (BackendInfo *)on; 1155 on->on_bi.bi_db_destroy( be, NULL ); 1156 be->bd_info = bi_orig; 1157 } 1158 free( on ); 1159 break; 1160 } 1161 } 1162 } 1163 1164 #ifdef SLAP_CONFIG_DELETE 1165 typedef struct ov_remove_ctx { 1166 BackendDB *be; 1167 slap_overinst *on; 1168 } ov_remove_ctx; 1169 1170 int 1171 overlay_remove_cb( Operation *op, SlapReply *rs ) 1172 { 1173 ov_remove_ctx *rm_ctx = (ov_remove_ctx*) op->o_callback->sc_private; 1174 BackendInfo *bi_orig = rm_ctx->be->bd_info; 1175 1176 rm_ctx->be->bd_info = (BackendInfo*) rm_ctx->on; 1177 1178 if ( rm_ctx->on->on_bi.bi_db_close ) { 1179 rm_ctx->on->on_bi.bi_db_close( rm_ctx->be, NULL ); 1180 } 1181 if ( rm_ctx->on->on_bi.bi_db_destroy ) { 1182 rm_ctx->on->on_bi.bi_db_destroy( rm_ctx->be, NULL ); 1183 } 1184 1185 /* clean up after removing last overlay */ 1186 if ( ! rm_ctx->on->on_info->oi_list ) { 1187 /* reset db flags and bd_info to orig */ 1188 SLAP_DBFLAGS( rm_ctx->be ) &= ~SLAP_DBFLAG_GLOBAL_OVERLAY; 1189 rm_ctx->be->bd_info = rm_ctx->on->on_info->oi_orig; 1190 ch_free(rm_ctx->on->on_info); 1191 } else { 1192 rm_ctx->be->bd_info = bi_orig; 1193 } 1194 free( rm_ctx->on ); 1195 op->o_tmpfree(rm_ctx, op->o_tmpmemctx); 1196 return SLAP_CB_CONTINUE; 1197 } 1198 1199 void 1200 overlay_remove( BackendDB *be, slap_overinst *on, Operation *op ) 1201 { 1202 slap_overinfo *oi = on->on_info; 1203 slap_overinst **oidx; 1204 ov_remove_ctx *rm_ctx; 1205 slap_callback *rm_cb, *cb; 1206 1207 /* remove overlay from oi_list */ 1208 for ( oidx = &oi->oi_list; *oidx; oidx = &(*oidx)->on_next ) { 1209 if ( *oidx == on ) { 1210 *oidx = on->on_next; 1211 break; 1212 } 1213 } 1214 1215 /* The db_close and db_destroy handlers to cleanup a release 1216 * the overlay's resources are called from the cleanup callback 1217 */ 1218 rm_ctx = op->o_tmpalloc( sizeof( ov_remove_ctx ), op->o_tmpmemctx ); 1219 rm_ctx->be = be; 1220 rm_ctx->on = on; 1221 1222 rm_cb = op->o_tmpalloc( sizeof( slap_callback ), op->o_tmpmemctx ); 1223 rm_cb->sc_next = NULL; 1224 rm_cb->sc_cleanup = overlay_remove_cb; 1225 rm_cb->sc_response = NULL; 1226 rm_cb->sc_private = (void*) rm_ctx; 1227 rm_cb->sc_writewait = NULL; 1228 1229 /* Append callback to the end of the list */ 1230 if ( !op->o_callback ) { 1231 op->o_callback = rm_cb; 1232 } else { 1233 for ( cb = op->o_callback; cb->sc_next; cb = cb->sc_next ); 1234 cb->sc_next = rm_cb; 1235 } 1236 } 1237 #endif /* SLAP_CONFIG_DELETE */ 1238 1239 void 1240 overlay_insert( BackendDB *be, slap_overinst *on2, slap_overinst ***prev, 1241 int idx ) 1242 { 1243 slap_overinfo *oi = (slap_overinfo *)be->bd_info; 1244 1245 if ( idx == -1 ) { 1246 on2->on_next = oi->oi_list; 1247 oi->oi_list = on2; 1248 } else { 1249 int i, novs; 1250 slap_overinst *on, **prev; 1251 1252 /* Since the list is in reverse order and is singly linked, 1253 * we have to count the overlays and then insert backwards. 1254 * Adding on overlay at a specific point should be a pretty 1255 * infrequent occurrence. 1256 */ 1257 novs = 0; 1258 for ( on = oi->oi_list; on; on=on->on_next ) 1259 novs++; 1260 1261 if (idx > novs) 1262 idx = 0; 1263 else 1264 idx = novs - idx; 1265 1266 /* advance to insertion point */ 1267 prev = &oi->oi_list; 1268 for ( i=0; i<idx; i++ ) { 1269 on = *prev; 1270 prev = &on->on_next; 1271 } 1272 /* insert */ 1273 on2->on_next = *prev; 1274 *prev = on2; 1275 } 1276 } 1277 1278 void 1279 overlay_move( BackendDB *be, slap_overinst *on, int idx ) 1280 { 1281 slap_overinfo *oi = (slap_overinfo *)be->bd_info; 1282 slap_overinst **onp; 1283 1284 for (onp = &oi->oi_list; *onp; onp= &(*onp)->on_next) { 1285 if ( *onp == on ) { 1286 *onp = on->on_next; 1287 break; 1288 } 1289 } 1290 overlay_insert( be, on, &onp, idx ); 1291 } 1292 1293 /* add an overlay to a particular backend. */ 1294 int 1295 overlay_config( BackendDB *be, const char *ov, int idx, BackendInfo **res, ConfigReply *cr ) 1296 { 1297 slap_overinst *on = NULL, *on2 = NULL, **prev; 1298 slap_overinfo *oi = NULL; 1299 BackendInfo *bi = NULL; 1300 1301 if ( res ) 1302 *res = NULL; 1303 1304 on = overlay_find( ov ); 1305 if ( !on ) { 1306 Debug( LDAP_DEBUG_ANY, "overlay \"%s\" not found\n", ov, 0, 0 ); 1307 return 1; 1308 } 1309 1310 /* If this is the first overlay on this backend, set up the 1311 * overlay info structure 1312 */ 1313 if ( !overlay_is_over( be ) ) { 1314 int isglobal = 0; 1315 1316 /* NOTE: the first time a global overlay is configured, 1317 * frontendDB gets this flag; it is used later by overlays 1318 * to determine if they're stacked on top of the frontendDB */ 1319 if ( be->bd_info == frontendDB->bd_info || SLAP_ISGLOBALOVERLAY( be ) ) { 1320 isglobal = 1; 1321 if ( on->on_bi.bi_flags & SLAPO_BFLAG_DBONLY ) { 1322 Debug( LDAP_DEBUG_ANY, "overlay_config(): " 1323 "overlay \"%s\" cannot be global.\n", 1324 ov, 0, 0 ); 1325 return 1; 1326 } 1327 1328 } else if ( on->on_bi.bi_flags & SLAPO_BFLAG_GLOBONLY ) { 1329 Debug( LDAP_DEBUG_ANY, "overlay_config(): " 1330 "overlay \"%s\" can only be global.\n", 1331 ov, 0, 0 ); 1332 return 1; 1333 } 1334 1335 oi = ch_malloc( sizeof( slap_overinfo ) ); 1336 oi->oi_orig = be->bd_info; 1337 oi->oi_bi = *be->bd_info; 1338 oi->oi_origdb = be; 1339 1340 if ( isglobal ) { 1341 SLAP_DBFLAGS( be ) |= SLAP_DBFLAG_GLOBAL_OVERLAY; 1342 } 1343 1344 /* Save a pointer to ourself in bi_private. 1345 */ 1346 oi->oi_bi.bi_private = oi; 1347 oi->oi_list = NULL; 1348 bi = (BackendInfo *)oi; 1349 1350 bi->bi_type = (char *)overtype; 1351 1352 bi->bi_db_config = over_db_config; 1353 bi->bi_db_open = over_db_open; 1354 bi->bi_db_close = over_db_close; 1355 bi->bi_db_destroy = over_db_destroy; 1356 1357 bi->bi_op_bind = over_op_bind; 1358 bi->bi_op_unbind = over_op_unbind; 1359 bi->bi_op_search = over_op_search; 1360 bi->bi_op_compare = over_op_compare; 1361 bi->bi_op_modify = over_op_modify; 1362 bi->bi_op_modrdn = over_op_modrdn; 1363 bi->bi_op_add = over_op_add; 1364 bi->bi_op_delete = over_op_delete; 1365 bi->bi_op_abandon = over_op_abandon; 1366 bi->bi_op_cancel = over_op_cancel; 1367 1368 bi->bi_extended = over_op_extended; 1369 1370 /* 1371 * this is fine because it has the same 1372 * args of the operations; we need to rework 1373 * all the hooks to share the same args 1374 * of the operations... 1375 */ 1376 bi->bi_operational = over_aux_operational; 1377 bi->bi_chk_referrals = over_aux_chk_referrals; 1378 bi->bi_chk_controls = over_aux_chk_controls; 1379 1380 /* these have specific arglists */ 1381 bi->bi_entry_get_rw = over_entry_get_rw; 1382 bi->bi_entry_release_rw = over_entry_release_rw; 1383 bi->bi_access_allowed = over_access_allowed; 1384 bi->bi_acl_group = over_acl_group; 1385 bi->bi_acl_attribute = over_acl_attribute; 1386 1387 bi->bi_connection_init = over_connection_init; 1388 bi->bi_connection_destroy = over_connection_destroy; 1389 1390 be->bd_info = bi; 1391 1392 } else { 1393 if ( overlay_is_inst( be, ov ) ) { 1394 if ( SLAPO_SINGLE( be ) ) { 1395 Debug( LDAP_DEBUG_ANY, "overlay_config(): " 1396 "overlay \"%s\" already in list\n", 1397 ov, 0, 0 ); 1398 return 1; 1399 } 1400 } 1401 1402 oi = be->bd_info->bi_private; 1403 } 1404 1405 /* Insert new overlay into list. By default overlays are 1406 * added to head of list and executed in LIFO order. 1407 */ 1408 on2 = ch_calloc( 1, sizeof(slap_overinst) ); 1409 *on2 = *on; 1410 on2->on_info = oi; 1411 1412 prev = &oi->oi_list; 1413 /* Do we need to find the insertion point? */ 1414 if ( idx >= 0 ) { 1415 int i; 1416 1417 /* count current overlays */ 1418 for ( i=0, on=oi->oi_list; on; on=on->on_next, i++ ); 1419 1420 /* are we just appending a new one? */ 1421 if ( idx >= i ) 1422 idx = -1; 1423 } 1424 overlay_insert( be, on2, &prev, idx ); 1425 1426 /* Any initialization needed? */ 1427 if ( on2->on_bi.bi_db_init ) { 1428 int rc; 1429 be->bd_info = (BackendInfo *)on2; 1430 rc = on2->on_bi.bi_db_init( be, cr); 1431 be->bd_info = (BackendInfo *)oi; 1432 if ( rc ) { 1433 *prev = on2->on_next; 1434 ch_free( on2 ); 1435 on2 = NULL; 1436 return rc; 1437 } 1438 } 1439 1440 if ( res ) 1441 *res = &on2->on_bi; 1442 1443 return 0; 1444 } 1445 1446