1/* $NetBSD: backover.c,v 1.1.1.4 2010/12/12 15:22:19 adam Exp $ */ 2 3/* backover.c - backend overlay routines */ 4/* OpenLDAP: pkg/ldap/servers/slapd/backover.c,v 1.71.2.21 2010/04/13 20:23:11 kurt Exp */ 5/* This work is part of OpenLDAP Software <http://www.openldap.org/>. 6 * 7 * Copyright 2003-2010 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 32static slap_overinst *overlays; 33 34static int 35over_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 137static int 138over_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 164static int 165over_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 191static int 192over_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 226static int 227over_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 252static int 253over_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 327int 328overlay_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 381static int 382over_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 401int 402overlay_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 451static int 452over_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 468static int 469over_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 = op->o_bd->bd_info; 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( op->o_bd != NULL ); 486 487 oi = op->o_bd->bd_info->bi_private; 488 on = oi->oi_list; 489 490 for ( ; on; on = on->on_next ) { 491 if ( on->on_bi.bi_acl_group ) { 492 /* NOTE: do not copy the structure until required */ 493 if ( !SLAP_ISOVERLAY( op->o_bd ) ) { 494 db = *op->o_bd; 495 db.be_flags |= SLAP_DBFLAG_OVERLAY; 496 op->o_bd = &db; 497 } 498 499 op->o_bd->bd_info = (BackendInfo *)on; 500 rc = on->on_bi.bi_acl_group( op, e, 501 gr_ndn, op_ndn, group_oc, group_at ); 502 if ( rc != SLAP_CB_CONTINUE ) break; 503 } 504 } 505 506 if ( rc == SLAP_CB_CONTINUE ) { 507 BI_acl_group *bi_acl_group; 508 509 /* if the database structure was changed, o_bd points to a 510 * copy of the structure; put the original bd_info in place */ 511 if ( SLAP_ISOVERLAY( op->o_bd ) ) { 512 op->o_bd->bd_info = oi->oi_orig; 513 } 514 515 if ( oi->oi_orig->bi_acl_group ) { 516 bi_acl_group = oi->oi_orig->bi_acl_group; 517 } else { 518 bi_acl_group = backend_group; 519 } 520 521 rc = bi_acl_group( op, e, 522 gr_ndn, op_ndn, group_oc, group_at ); 523 } 524 /* should not fall thru this far without anything happening... */ 525 if ( rc == SLAP_CB_CONTINUE ) { 526 /* access not allowed */ 527 rc = 0; 528 } 529 530 op->o_bd = be; 531 op->o_bd->bd_info = bi; 532 533 return rc; 534} 535 536static int 537over_acl_attribute( 538 Operation *op, 539 Entry *target, 540 struct berval *entry_ndn, 541 AttributeDescription *entry_at, 542 BerVarray *vals, 543 slap_access_t access ) 544{ 545 slap_overinfo *oi; 546 slap_overinst *on; 547 BackendInfo *bi = op->o_bd->bd_info; 548 BackendDB *be = op->o_bd, db; 549 int rc = SLAP_CB_CONTINUE; 550 551 /* FIXME: used to happen for instance during abandon 552 * when global overlays are used... */ 553 assert( op->o_bd != NULL ); 554 555 oi = op->o_bd->bd_info->bi_private; 556 on = oi->oi_list; 557 558 for ( ; on; on = on->on_next ) { 559 if ( on->on_bi.bi_acl_attribute ) { 560 /* NOTE: do not copy the structure until required */ 561 if ( !SLAP_ISOVERLAY( op->o_bd ) ) { 562 db = *op->o_bd; 563 db.be_flags |= SLAP_DBFLAG_OVERLAY; 564 op->o_bd = &db; 565 } 566 567 op->o_bd->bd_info = (BackendInfo *)on; 568 rc = on->on_bi.bi_acl_attribute( op, target, 569 entry_ndn, entry_at, vals, access ); 570 if ( rc != SLAP_CB_CONTINUE ) break; 571 } 572 } 573 574 if ( rc == SLAP_CB_CONTINUE ) { 575 BI_acl_attribute *bi_acl_attribute; 576 577 /* if the database structure was changed, o_bd points to a 578 * copy of the structure; put the original bd_info in place */ 579 if ( SLAP_ISOVERLAY( op->o_bd ) ) { 580 op->o_bd->bd_info = oi->oi_orig; 581 } 582 583 if ( oi->oi_orig->bi_acl_attribute ) { 584 bi_acl_attribute = oi->oi_orig->bi_acl_attribute; 585 } else { 586 bi_acl_attribute = backend_attribute; 587 } 588 589 rc = bi_acl_attribute( op, target, 590 entry_ndn, entry_at, vals, access ); 591 } 592 /* should not fall thru this far without anything happening... */ 593 if ( rc == SLAP_CB_CONTINUE ) { 594 /* access not allowed */ 595 rc = 0; 596 } 597 598 op->o_bd = be; 599 op->o_bd->bd_info = bi; 600 601 return rc; 602} 603 604int 605overlay_callback_after_backover( Operation *op, slap_callback *sc, int append ) 606{ 607 slap_callback **scp; 608 609 for ( scp = &op->o_callback; *scp != NULL; scp = &(*scp)->sc_next ) { 610 if ( (*scp)->sc_response == over_back_response ) { 611 sc->sc_next = (*scp)->sc_next; 612 (*scp)->sc_next = sc; 613 return 0; 614 } 615 } 616 617 if ( append ) { 618 *scp = sc; 619 return 0; 620 } 621 622 return 1; 623} 624 625/* 626 * default return code in case of missing backend function 627 * and overlay stack returning SLAP_CB_CONTINUE 628 */ 629static int op_rc[ op_last ] = { 630 LDAP_UNWILLING_TO_PERFORM, /* bind */ 631 LDAP_UNWILLING_TO_PERFORM, /* unbind */ 632 LDAP_UNWILLING_TO_PERFORM, /* search */ 633 SLAP_CB_CONTINUE, /* compare; pass to frontend */ 634 LDAP_UNWILLING_TO_PERFORM, /* modify */ 635 LDAP_UNWILLING_TO_PERFORM, /* modrdn */ 636 LDAP_UNWILLING_TO_PERFORM, /* add */ 637 LDAP_UNWILLING_TO_PERFORM, /* delete */ 638 LDAP_UNWILLING_TO_PERFORM, /* abandon */ 639 LDAP_UNWILLING_TO_PERFORM, /* cancel */ 640 LDAP_UNWILLING_TO_PERFORM, /* extended */ 641 LDAP_SUCCESS, /* aux_operational */ 642 LDAP_SUCCESS, /* aux_chk_referrals */ 643 SLAP_CB_CONTINUE /* aux_chk_controls; pass to frontend */ 644}; 645 646int overlay_op_walk( 647 Operation *op, 648 SlapReply *rs, 649 slap_operation_t which, 650 slap_overinfo *oi, 651 slap_overinst *on 652) 653{ 654 BI_op_bind **func; 655 int rc = SLAP_CB_CONTINUE; 656 657 for (; on; on=on->on_next ) { 658 func = &on->on_bi.bi_op_bind; 659 if ( func[which] ) { 660 op->o_bd->bd_info = (BackendInfo *)on; 661 rc = func[which]( op, rs ); 662 if ( rc != SLAP_CB_CONTINUE ) break; 663 } 664 } 665 if ( rc == SLAP_CB_BYPASS ) 666 rc = SLAP_CB_CONTINUE; 667 668 func = &oi->oi_orig->bi_op_bind; 669 if ( func[which] && rc == SLAP_CB_CONTINUE ) { 670 op->o_bd->bd_info = oi->oi_orig; 671 rc = func[which]( op, rs ); 672 } 673 /* should not fall thru this far without anything happening... */ 674 if ( rc == SLAP_CB_CONTINUE ) { 675 rc = op_rc[ which ]; 676 } 677 678 /* The underlying backend didn't handle the request, make sure 679 * overlay cleanup is processed. 680 */ 681 if ( rc == LDAP_UNWILLING_TO_PERFORM ) { 682 slap_callback *sc_next; 683 for ( ; op->o_callback && op->o_callback->sc_response != 684 over_back_response; op->o_callback = sc_next ) { 685 sc_next = op->o_callback->sc_next; 686 if ( op->o_callback->sc_cleanup ) { 687 op->o_callback->sc_cleanup( op, rs ); 688 } 689 } 690 } 691 return rc; 692} 693 694static int 695over_op_func( 696 Operation *op, 697 SlapReply *rs, 698 slap_operation_t which 699) 700{ 701 slap_overinfo *oi; 702 slap_overinst *on; 703 BackendDB *be = op->o_bd, db; 704 slap_callback cb = {NULL, over_back_response, NULL, NULL}, **sc; 705 int rc = SLAP_CB_CONTINUE; 706 707 /* FIXME: used to happen for instance during abandon 708 * when global overlays are used... */ 709 assert( op->o_bd != NULL ); 710 711 oi = op->o_bd->bd_info->bi_private; 712 on = oi->oi_list; 713 714 if ( !SLAP_ISOVERLAY( op->o_bd )) { 715 db = *op->o_bd; 716 db.be_flags |= SLAP_DBFLAG_OVERLAY; 717 op->o_bd = &db; 718 } 719 cb.sc_next = op->o_callback; 720 cb.sc_private = oi; 721 op->o_callback = &cb; 722 723 rc = overlay_op_walk( op, rs, which, oi, on ); 724 for ( sc = &op->o_callback; *sc; sc = &(*sc)->sc_next ) { 725 if ( *sc == &cb ) { 726 *sc = cb.sc_next; 727 break; 728 } 729 } 730 731 op->o_bd = be; 732 return rc; 733} 734 735static int 736over_op_bind( Operation *op, SlapReply *rs ) 737{ 738 return over_op_func( op, rs, op_bind ); 739} 740 741static int 742over_op_unbind( Operation *op, SlapReply *rs ) 743{ 744 return over_op_func( op, rs, op_unbind ); 745} 746 747static int 748over_op_search( Operation *op, SlapReply *rs ) 749{ 750 return over_op_func( op, rs, op_search ); 751} 752 753static int 754over_op_compare( Operation *op, SlapReply *rs ) 755{ 756 return over_op_func( op, rs, op_compare ); 757} 758 759static int 760over_op_modify( Operation *op, SlapReply *rs ) 761{ 762 return over_op_func( op, rs, op_modify ); 763} 764 765static int 766over_op_modrdn( Operation *op, SlapReply *rs ) 767{ 768 return over_op_func( op, rs, op_modrdn ); 769} 770 771static int 772over_op_add( Operation *op, SlapReply *rs ) 773{ 774 return over_op_func( op, rs, op_add ); 775} 776 777static int 778over_op_delete( Operation *op, SlapReply *rs ) 779{ 780 return over_op_func( op, rs, op_delete ); 781} 782 783static int 784over_op_abandon( Operation *op, SlapReply *rs ) 785{ 786 return over_op_func( op, rs, op_abandon ); 787} 788 789static int 790over_op_cancel( Operation *op, SlapReply *rs ) 791{ 792 return over_op_func( op, rs, op_cancel ); 793} 794 795static int 796over_op_extended( Operation *op, SlapReply *rs ) 797{ 798 return over_op_func( op, rs, op_extended ); 799} 800 801static int 802over_aux_operational( Operation *op, SlapReply *rs ) 803{ 804 return over_op_func( op, rs, op_aux_operational ); 805} 806 807static int 808over_aux_chk_referrals( Operation *op, SlapReply *rs ) 809{ 810 return over_op_func( op, rs, op_aux_chk_referrals ); 811} 812 813static int 814over_aux_chk_controls( Operation *op, SlapReply *rs ) 815{ 816 return over_op_func( op, rs, op_aux_chk_controls ); 817} 818 819enum conn_which { 820 conn_init = 0, 821 conn_destroy, 822 conn_last 823}; 824 825static int 826over_connection_func( 827 BackendDB *bd, 828 Connection *conn, 829 enum conn_which which 830) 831{ 832 slap_overinfo *oi; 833 slap_overinst *on; 834 BackendDB db; 835 int rc = SLAP_CB_CONTINUE; 836 BI_connection_init **func; 837 838 /* FIXME: used to happen for instance during abandon 839 * when global overlays are used... */ 840 assert( bd != NULL ); 841 842 oi = bd->bd_info->bi_private; 843 on = oi->oi_list; 844 845 if ( !SLAP_ISOVERLAY( bd ) ) { 846 db = *bd; 847 db.be_flags |= SLAP_DBFLAG_OVERLAY; 848 bd = &db; 849 } 850 851 for ( ; on; on = on->on_next ) { 852 func = &on->on_bi.bi_connection_init; 853 if ( func[ which ] ) { 854 bd->bd_info = (BackendInfo *)on; 855 rc = func[ which ]( bd, conn ); 856 if ( rc != SLAP_CB_CONTINUE ) break; 857 } 858 } 859 860 func = &oi->oi_orig->bi_connection_init; 861 if ( func[ which ] && rc == SLAP_CB_CONTINUE ) { 862 bd->bd_info = oi->oi_orig; 863 rc = func[ which ]( bd, conn ); 864 } 865 /* should not fall thru this far without anything happening... */ 866 if ( rc == SLAP_CB_CONTINUE ) { 867 rc = LDAP_UNWILLING_TO_PERFORM; 868 } 869 870 return rc; 871} 872 873static int 874over_connection_init( 875 BackendDB *bd, 876 Connection *conn 877) 878{ 879 return over_connection_func( bd, conn, conn_init ); 880} 881 882static int 883over_connection_destroy( 884 BackendDB *bd, 885 Connection *conn 886) 887{ 888 return over_connection_func( bd, conn, conn_destroy ); 889} 890 891int 892overlay_register( 893 slap_overinst *on 894) 895{ 896 slap_overinst *tmp; 897 898 /* FIXME: check for duplicates? */ 899 for ( tmp = overlays; tmp != NULL; tmp = tmp->on_next ) { 900 if ( strcmp( on->on_bi.bi_type, tmp->on_bi.bi_type ) == 0 ) { 901 Debug( LDAP_DEBUG_ANY, 902 "overlay_register(\"%s\"): " 903 "name already in use.\n", 904 on->on_bi.bi_type, 0, 0 ); 905 return -1; 906 } 907 908 if ( on->on_bi.bi_obsolete_names != NULL ) { 909 int i; 910 911 for ( i = 0; on->on_bi.bi_obsolete_names[ i ] != NULL; i++ ) { 912 if ( strcmp( on->on_bi.bi_obsolete_names[ i ], tmp->on_bi.bi_type ) == 0 ) { 913 Debug( LDAP_DEBUG_ANY, 914 "overlay_register(\"%s\"): " 915 "obsolete name \"%s\" already in use " 916 "by overlay \"%s\".\n", 917 on->on_bi.bi_type, 918 on->on_bi.bi_obsolete_names[ i ], 919 tmp->on_bi.bi_type ); 920 return -1; 921 } 922 } 923 } 924 925 if ( tmp->on_bi.bi_obsolete_names != NULL ) { 926 int i; 927 928 for ( i = 0; tmp->on_bi.bi_obsolete_names[ i ] != NULL; i++ ) { 929 int j; 930 931 if ( strcmp( on->on_bi.bi_type, tmp->on_bi.bi_obsolete_names[ i ] ) == 0 ) { 932 Debug( LDAP_DEBUG_ANY, 933 "overlay_register(\"%s\"): " 934 "name already in use " 935 "as obsolete by overlay \"%s\".\n", 936 on->on_bi.bi_type, 937 tmp->on_bi.bi_obsolete_names[ i ], 0 ); 938 return -1; 939 } 940 941 if ( on->on_bi.bi_obsolete_names != NULL ) { 942 for ( j = 0; on->on_bi.bi_obsolete_names[ j ] != NULL; j++ ) { 943 if ( strcmp( on->on_bi.bi_obsolete_names[ j ], tmp->on_bi.bi_obsolete_names[ i ] ) == 0 ) { 944 Debug( LDAP_DEBUG_ANY, 945 "overlay_register(\"%s\"): " 946 "obsolete name \"%s\" already in use " 947 "as obsolete by overlay \"%s\".\n", 948 on->on_bi.bi_type, 949 on->on_bi.bi_obsolete_names[ j ], 950 tmp->on_bi.bi_type ); 951 return -1; 952 } 953 } 954 } 955 } 956 } 957 } 958 959 on->on_next = overlays; 960 overlays = on; 961 return 0; 962} 963 964/* 965 * iterator on registered overlays; overlay_next( NULL ) returns the first 966 * overlay; subsequent calls with the previously returned value allow to 967 * iterate over the entire list; returns NULL when no more overlays are 968 * registered. 969 */ 970 971slap_overinst * 972overlay_next( 973 slap_overinst *on 974) 975{ 976 if ( on == NULL ) { 977 return overlays; 978 } 979 980 return on->on_next; 981} 982 983/* 984 * returns a specific registered overlay based on the type; NULL if not 985 * registered. 986 */ 987 988slap_overinst * 989overlay_find( const char *over_type ) 990{ 991 slap_overinst *on = overlays; 992 993 assert( over_type != NULL ); 994 995 for ( ; on; on = on->on_next ) { 996 if ( strcmp( on->on_bi.bi_type, over_type ) == 0 ) { 997 goto foundit; 998 } 999 1000 if ( on->on_bi.bi_obsolete_names != NULL ) { 1001 int i; 1002 1003 for ( i = 0; on->on_bi.bi_obsolete_names[ i ] != NULL; i++ ) { 1004 if ( strcmp( on->on_bi.bi_obsolete_names[ i ], over_type ) == 0 ) { 1005 Debug( LDAP_DEBUG_ANY, 1006 "overlay_find(\"%s\"): " 1007 "obsolete name for \"%s\".\n", 1008 on->on_bi.bi_obsolete_names[ i ], 1009 on->on_bi.bi_type, 0 ); 1010 goto foundit; 1011 } 1012 } 1013 } 1014 } 1015 1016foundit:; 1017 return on; 1018} 1019 1020static const char overtype[] = "over"; 1021 1022/* 1023 * returns TRUE (1) if the database is actually an overlay instance; 1024 * FALSE (0) otherwise. 1025 */ 1026 1027int 1028overlay_is_over( BackendDB *be ) 1029{ 1030 return be->bd_info->bi_type == overtype; 1031} 1032 1033/* 1034 * returns TRUE (1) if the given database is actually an overlay 1035 * instance and, somewhere in the list, contains the requested overlay; 1036 * FALSE (0) otherwise. 1037 */ 1038 1039int 1040overlay_is_inst( BackendDB *be, const char *over_type ) 1041{ 1042 slap_overinst *on; 1043 1044 assert( be != NULL ); 1045 1046 if ( !overlay_is_over( be ) ) { 1047 return 0; 1048 } 1049 1050 on = ((slap_overinfo *)be->bd_info->bi_private)->oi_list; 1051 for ( ; on; on = on->on_next ) { 1052 if ( strcmp( on->on_bi.bi_type, over_type ) == 0 ) { 1053 return 1; 1054 } 1055 } 1056 1057 return 0; 1058} 1059 1060int 1061overlay_register_control( BackendDB *be, const char *oid ) 1062{ 1063 int gotit = 0; 1064 int cid; 1065 1066 if ( slap_find_control_id( oid, &cid ) == LDAP_CONTROL_NOT_FOUND ) { 1067 return -1; 1068 } 1069 1070 if ( SLAP_ISGLOBALOVERLAY( be ) ) { 1071 BackendDB *bd; 1072 1073 /* add to all backends... */ 1074 LDAP_STAILQ_FOREACH( bd, &backendDB, be_next ) { 1075 if ( bd == be->bd_self ) { 1076 gotit = 1; 1077 } 1078 1079 bd->be_ctrls[ cid ] = 1; 1080 bd->be_ctrls[ SLAP_MAX_CIDS ] = 1; 1081 } 1082 1083 } 1084 1085 if ( !gotit ) { 1086 be->bd_self->be_ctrls[ cid ] = 1; 1087 be->bd_self->be_ctrls[ SLAP_MAX_CIDS ] = 1; 1088 } 1089 1090 return 0; 1091} 1092 1093void 1094overlay_destroy_one( BackendDB *be, slap_overinst *on ) 1095{ 1096 slap_overinfo *oi = on->on_info; 1097 slap_overinst **oidx; 1098 1099 for ( oidx = &oi->oi_list; *oidx; oidx = &(*oidx)->on_next ) { 1100 if ( *oidx == on ) { 1101 *oidx = on->on_next; 1102 if ( on->on_bi.bi_db_destroy ) { 1103 BackendInfo *bi_orig = be->bd_info; 1104 be->bd_info = (BackendInfo *)on; 1105 on->on_bi.bi_db_destroy( be, NULL ); 1106 be->bd_info = bi_orig; 1107 } 1108 free( on ); 1109 break; 1110 } 1111 } 1112} 1113 1114#ifdef SLAP_CONFIG_DELETE 1115void 1116overlay_remove( BackendDB *be, slap_overinst *on ) 1117{ 1118 slap_overinfo *oi = on->on_info; 1119 slap_overinst **oidx; 1120 BackendInfo *bi_orig; 1121 1122 /* remove overlay from oi_list an call db_close and db_destroy 1123 * handlers */ 1124 for ( oidx = &oi->oi_list; *oidx; oidx = &(*oidx)->on_next ) { 1125 if ( *oidx == on ) { 1126 *oidx = on->on_next; 1127 bi_orig = be->bd_info; 1128 be->bd_info = (BackendInfo *)on; 1129 if ( on->on_bi.bi_db_close ) { 1130 on->on_bi.bi_db_close( be, NULL ); 1131 } 1132 if ( on->on_bi.bi_db_destroy ) { 1133 on->on_bi.bi_db_destroy( be, NULL ); 1134 } 1135 be->bd_info = bi_orig; 1136 free( on ); 1137 break; 1138 } 1139 } 1140 1141 /* clean up after removing last overlay */ 1142 if ( ! oi->oi_list ) 1143 { 1144 /* reset db flags and bd_info to orig */ 1145 SLAP_DBFLAGS( be ) &= ~SLAP_DBFLAG_GLOBAL_OVERLAY; 1146 be->bd_info = oi->oi_orig; 1147 ch_free(oi); 1148 } 1149} 1150#endif /* SLAP_CONFIG_DELETE */ 1151 1152void 1153overlay_insert( BackendDB *be, slap_overinst *on2, slap_overinst ***prev, 1154 int idx ) 1155{ 1156 slap_overinfo *oi = (slap_overinfo *)be->bd_info; 1157 1158 if ( idx == -1 ) { 1159 on2->on_next = oi->oi_list; 1160 oi->oi_list = on2; 1161 } else { 1162 int i; 1163 slap_overinst *on, *otmp1 = NULL, *otmp2; 1164 1165 /* Since the list is in reverse order and is singly linked, 1166 * we reverse it to find the idx insertion point. Adding 1167 * on overlay at a specific point should be a pretty 1168 * infrequent occurrence. 1169 */ 1170 for ( on = oi->oi_list; on; on=otmp2 ) { 1171 otmp2 = on->on_next; 1172 on->on_next = otmp1; 1173 otmp1 = on; 1174 } 1175 oi->oi_list = NULL; 1176 /* advance to insertion point */ 1177 for ( i=0, on = otmp1; i<idx; i++ ) { 1178 otmp1 = on->on_next; 1179 on->on_next = oi->oi_list; 1180 oi->oi_list = on; 1181 } 1182 /* insert */ 1183 on2->on_next = oi->oi_list; 1184 oi->oi_list = on2; 1185 if ( otmp1 ) { 1186 *prev = &otmp1->on_next; 1187 /* replace remainder of list */ 1188 for ( on=otmp1; on; on=otmp1 ) { 1189 otmp1 = on->on_next; 1190 on->on_next = oi->oi_list; 1191 oi->oi_list = on; 1192 } 1193 } 1194 } 1195} 1196 1197void 1198overlay_move( BackendDB *be, slap_overinst *on, int idx ) 1199{ 1200 slap_overinfo *oi = (slap_overinfo *)be->bd_info; 1201 slap_overinst **onp; 1202 1203 for (onp = &oi->oi_list; *onp; onp= &(*onp)->on_next) { 1204 if ( *onp == on ) { 1205 *onp = on->on_next; 1206 break; 1207 } 1208 } 1209 overlay_insert( be, on, &onp, idx ); 1210} 1211 1212/* add an overlay to a particular backend. */ 1213int 1214overlay_config( BackendDB *be, const char *ov, int idx, BackendInfo **res, ConfigReply *cr ) 1215{ 1216 slap_overinst *on = NULL, *on2 = NULL, **prev; 1217 slap_overinfo *oi = NULL; 1218 BackendInfo *bi = NULL; 1219 1220 if ( res ) 1221 *res = NULL; 1222 1223 on = overlay_find( ov ); 1224 if ( !on ) { 1225 Debug( LDAP_DEBUG_ANY, "overlay \"%s\" not found\n", ov, 0, 0 ); 1226 return 1; 1227 } 1228 1229 /* If this is the first overlay on this backend, set up the 1230 * overlay info structure 1231 */ 1232 if ( !overlay_is_over( be ) ) { 1233 int isglobal = 0; 1234 1235 /* NOTE: the first time a global overlay is configured, 1236 * frontendDB gets this flag; it is used later by overlays 1237 * to determine if they're stacked on top of the frontendDB */ 1238 if ( be->bd_info == frontendDB->bd_info || SLAP_ISGLOBALOVERLAY( be ) ) { 1239 isglobal = 1; 1240 if ( on->on_bi.bi_flags & SLAPO_BFLAG_DBONLY ) { 1241 Debug( LDAP_DEBUG_ANY, "overlay_config(): " 1242 "overlay \"%s\" cannot be global.\n", 1243 ov, 0, 0 ); 1244 return 1; 1245 } 1246 1247 } else if ( on->on_bi.bi_flags & SLAPO_BFLAG_GLOBONLY ) { 1248 Debug( LDAP_DEBUG_ANY, "overlay_config(): " 1249 "overlay \"%s\" can only be global.\n", 1250 ov, 0, 0 ); 1251 return 1; 1252 } 1253 1254 oi = ch_malloc( sizeof( slap_overinfo ) ); 1255 oi->oi_orig = be->bd_info; 1256 oi->oi_bi = *be->bd_info; 1257 oi->oi_origdb = be; 1258 1259 if ( isglobal ) { 1260 SLAP_DBFLAGS( be ) |= SLAP_DBFLAG_GLOBAL_OVERLAY; 1261 } 1262 1263 /* Save a pointer to ourself in bi_private. 1264 */ 1265 oi->oi_bi.bi_private = oi; 1266 oi->oi_list = NULL; 1267 bi = (BackendInfo *)oi; 1268 1269 bi->bi_type = (char *)overtype; 1270 1271 bi->bi_db_config = over_db_config; 1272 bi->bi_db_open = over_db_open; 1273 bi->bi_db_close = over_db_close; 1274 bi->bi_db_destroy = over_db_destroy; 1275 1276 bi->bi_op_bind = over_op_bind; 1277 bi->bi_op_unbind = over_op_unbind; 1278 bi->bi_op_search = over_op_search; 1279 bi->bi_op_compare = over_op_compare; 1280 bi->bi_op_modify = over_op_modify; 1281 bi->bi_op_modrdn = over_op_modrdn; 1282 bi->bi_op_add = over_op_add; 1283 bi->bi_op_delete = over_op_delete; 1284 bi->bi_op_abandon = over_op_abandon; 1285 bi->bi_op_cancel = over_op_cancel; 1286 1287 bi->bi_extended = over_op_extended; 1288 1289 /* 1290 * this is fine because it has the same 1291 * args of the operations; we need to rework 1292 * all the hooks to share the same args 1293 * of the operations... 1294 */ 1295 bi->bi_operational = over_aux_operational; 1296 bi->bi_chk_referrals = over_aux_chk_referrals; 1297 bi->bi_chk_controls = over_aux_chk_controls; 1298 1299 /* these have specific arglists */ 1300 bi->bi_entry_get_rw = over_entry_get_rw; 1301 bi->bi_entry_release_rw = over_entry_release_rw; 1302 bi->bi_access_allowed = over_access_allowed; 1303 bi->bi_acl_group = over_acl_group; 1304 bi->bi_acl_attribute = over_acl_attribute; 1305 1306 bi->bi_connection_init = over_connection_init; 1307 bi->bi_connection_destroy = over_connection_destroy; 1308 1309 be->bd_info = bi; 1310 1311 } else { 1312 if ( overlay_is_inst( be, ov ) ) { 1313 if ( SLAPO_SINGLE( be ) ) { 1314 Debug( LDAP_DEBUG_ANY, "overlay_config(): " 1315 "overlay \"%s\" already in list\n", 1316 ov, 0, 0 ); 1317 return 1; 1318 } 1319 } 1320 1321 oi = be->bd_info->bi_private; 1322 } 1323 1324 /* Insert new overlay into list. By default overlays are 1325 * added to head of list and executed in LIFO order. 1326 */ 1327 on2 = ch_calloc( 1, sizeof(slap_overinst) ); 1328 *on2 = *on; 1329 on2->on_info = oi; 1330 1331 prev = &oi->oi_list; 1332 /* Do we need to find the insertion point? */ 1333 if ( idx >= 0 ) { 1334 int i; 1335 1336 /* count current overlays */ 1337 for ( i=0, on=oi->oi_list; on; on=on->on_next, i++ ); 1338 1339 /* are we just appending a new one? */ 1340 if ( idx >= i ) 1341 idx = -1; 1342 } 1343 overlay_insert( be, on2, &prev, idx ); 1344 1345 /* Any initialization needed? */ 1346 if ( on2->on_bi.bi_db_init ) { 1347 int rc; 1348 be->bd_info = (BackendInfo *)on2; 1349 rc = on2->on_bi.bi_db_init( be, cr); 1350 be->bd_info = (BackendInfo *)oi; 1351 if ( rc ) { 1352 *prev = on2->on_next; 1353 ch_free( on2 ); 1354 on2 = NULL; 1355 return rc; 1356 } 1357 } 1358 1359 if ( res ) 1360 *res = &on2->on_bi; 1361 1362 return 0; 1363} 1364 1365