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