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