1/* slapi_overlay.c - SLAPI overlay */ 2/* $OpenLDAP$ */ 3/* This work is part of OpenLDAP Software <http://www.openldap.org/>. 4 * 5 * Copyright 2001-2011 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/* ACKNOWLEDGEMENTS: 17 * This work was initially developed by Luke Howard for inclusion 18 * in OpenLDAP Software. 19 */ 20 21#include "portable.h" 22 23#include <stdio.h> 24 25#include <ac/string.h> 26#include <ac/socket.h> 27 28#include "slap.h" 29#include "slapi.h" 30#include "config.h" 31 32#ifdef LDAP_SLAPI 33 34static slap_overinst slapi; 35static int slapi_over_initialized = 0; 36 37static int slapi_over_response( Operation *op, SlapReply *rs ); 38static int slapi_over_cleanup( Operation *op, SlapReply *rs ); 39 40static Slapi_PBlock * 41slapi_over_pblock_new( Operation *op, SlapReply *rs ) 42{ 43 Slapi_PBlock *pb; 44 45 pb = slapi_pblock_new(); 46 pb->pb_op = op; 47 pb->pb_conn = op->o_conn; 48 pb->pb_rs = rs; 49 pb->pb_intop = 0; 50 51 PBLOCK_ASSERT_OP( pb, op->o_tag ); 52 53 return pb; 54} 55 56static int 57slapi_op_internal_p( Operation *op, SlapReply *rs, slap_callback *cb ) 58{ 59 int internal_op = 0; 60 Slapi_PBlock *pb = NULL; 61 slap_callback *pcb; 62 63 /* 64 * Abstraction violating check for SLAPI internal operations 65 * allows pblock to remain consistent when invoking internal 66 * op plugins 67 */ 68 for ( pcb = op->o_callback; pcb != NULL; pcb = pcb->sc_next ) { 69 if ( pcb->sc_response == slapi_int_response ) { 70 pb = (Slapi_PBlock *)pcb->sc_private; 71 PBLOCK_ASSERT_INTOP( pb, 0 ); 72 internal_op = 1; 73 break; 74 } 75 } 76 77 if ( cb != NULL ) { 78 if ( pb == NULL ) { 79 pb = slapi_over_pblock_new( op, rs ); 80 } 81 82 cb->sc_response = slapi_over_response; 83 cb->sc_cleanup = slapi_over_cleanup; 84 cb->sc_private = pb; 85 cb->sc_next = op->o_callback; 86 op->o_callback = cb; 87 } 88 89 return internal_op; 90} 91 92static int 93slapi_over_compute_output( 94 computed_attr_context *c, 95 Slapi_Attr *attribute, 96 Slapi_Entry *entry 97) 98{ 99 Attribute **a; 100 AttributeDescription *desc; 101 SlapReply *rs; 102 103 if ( c == NULL || attribute == NULL || entry == NULL ) { 104 return 0; 105 } 106 107 rs = (SlapReply *)c->cac_private; 108 109 assert( rs->sr_entry == entry ); 110 111 desc = attribute->a_desc; 112 113 if ( rs->sr_attrs == NULL ) { 114 /* All attrs request, skip operational attributes */ 115 if ( is_at_operational( desc->ad_type ) ) { 116 return 0; 117 } 118 } else { 119 /* Specific attributes requested */ 120 if ( is_at_operational( desc->ad_type ) ) { 121 if ( !SLAP_OPATTRS( rs->sr_attr_flags ) && 122 !ad_inlist( desc, rs->sr_attrs ) ) { 123 return 0; 124 } 125 } else { 126 if ( !SLAP_USERATTRS( rs->sr_attr_flags ) && 127 !ad_inlist( desc, rs->sr_attrs ) ) { 128 return 0; 129 } 130 } 131 } 132 133 /* XXX perhaps we should check for existing attributes and merge */ 134 for ( a = &rs->sr_operational_attrs; *a != NULL; a = &(*a)->a_next ) 135 ; 136 137 *a = slapi_attr_dup( attribute ); 138 139 return 0; 140} 141 142static int 143slapi_over_aux_operational( Operation *op, SlapReply *rs ) 144{ 145 /* Support for computed attribute plugins */ 146 computed_attr_context ctx; 147 AttributeName *anp; 148 149 if ( slapi_op_internal_p( op, rs, NULL ) ) { 150 return SLAP_CB_CONTINUE; 151 } 152 153 ctx.cac_pb = slapi_over_pblock_new( op, rs ); 154 ctx.cac_op = op; 155 ctx.cac_private = rs; 156 157 if ( rs->sr_entry != NULL ) { 158 /* 159 * For each client requested attribute, call the plugins. 160 */ 161 if ( rs->sr_attrs != NULL ) { 162 for ( anp = rs->sr_attrs; anp->an_name.bv_val != NULL; anp++ ) { 163 if ( compute_evaluator( &ctx, anp->an_name.bv_val, 164 rs->sr_entry, slapi_over_compute_output ) == 1 ) { 165 break; 166 } 167 } 168 } else { 169 /* 170 * Technically we shouldn't be returning operational attributes 171 * when the user requested only user attributes. We'll let the 172 * plugin decide whether to be naughty or not. 173 */ 174 compute_evaluator( &ctx, "*", rs->sr_entry, slapi_over_compute_output ); 175 } 176 } 177 178 slapi_pblock_destroy( ctx.cac_pb ); 179 180 return SLAP_CB_CONTINUE; 181} 182 183/* 184 * We need this function to call frontendDB (global) plugins before 185 * database plugins, if we are invoked by a slap_callback. 186 */ 187static int 188slapi_over_call_plugins( Slapi_PBlock *pb, int type ) 189{ 190 int rc = 1; /* means no plugins called */ 191 Operation *op; 192 193 PBLOCK_ASSERT_OP( pb, 0 ); 194 op = pb->pb_op; 195 196 if ( !be_match( op->o_bd, frontendDB ) ) { 197 rc = slapi_int_call_plugins( frontendDB, type, pb ); 198 } 199 if ( rc >= 0 ) { 200 rc = slapi_int_call_plugins( op->o_bd, type, pb ); 201 } 202 203 return rc; 204} 205 206static int 207slapi_over_search( Operation *op, SlapReply *rs, int type ) 208{ 209 int rc; 210 Slapi_PBlock *pb; 211 212 assert( rs->sr_type == REP_SEARCH || rs->sr_type == REP_SEARCHREF ); 213 214 /* create a new pblock to not trample on result controls */ 215 pb = slapi_over_pblock_new( op, rs ); 216 217 rc = slapi_over_call_plugins( pb, type ); 218 if ( rc >= 0 ) /* 1 means no plugins called */ 219 rc = SLAP_CB_CONTINUE; 220 else 221 rc = LDAP_SUCCESS; /* confusing: don't abort, but don't send */ 222 223 slapi_pblock_destroy(pb); 224 225 return rc; 226} 227 228/* 229 * Call pre- and post-result plugins 230 */ 231static int 232slapi_over_result( Operation *op, SlapReply *rs, int type ) 233{ 234 Slapi_PBlock *pb = SLAPI_OPERATION_PBLOCK( op ); 235 236 assert( rs->sr_type == REP_RESULT || rs->sr_type == REP_SASL || rs->sr_type == REP_EXTENDED ); 237 238 slapi_over_call_plugins( pb, type ); 239 240 return SLAP_CB_CONTINUE; 241} 242 243 244static int 245slapi_op_bind_callback( Operation *op, SlapReply *rs, int prc ) 246{ 247 switch ( prc ) { 248 case SLAPI_BIND_SUCCESS: 249 /* Continue with backend processing */ 250 break; 251 case SLAPI_BIND_FAIL: 252 /* Failure, frontend (that's us) sends result */ 253 rs->sr_err = LDAP_INVALID_CREDENTIALS; 254 send_ldap_result( op, rs ); 255 return rs->sr_err; 256 break; 257 case SLAPI_BIND_ANONYMOUS: /* undocumented */ 258 default: /* plugin sent result or no plugins called */ 259 BER_BVZERO( &op->orb_edn ); 260 261 if ( rs->sr_err == LDAP_SUCCESS ) { 262 /* 263 * Plugin will have called slapi_pblock_set(LDAP_CONN_DN) which 264 * will have set conn->c_dn and conn->c_ndn 265 */ 266 if ( BER_BVISNULL( &op->o_conn->c_ndn ) && prc == 1 ) { 267 /* No plugins were called; continue processing */ 268 return LDAP_SUCCESS; 269 } 270 ldap_pvt_thread_mutex_lock( &op->o_conn->c_mutex ); 271 if ( !BER_BVISEMPTY( &op->o_conn->c_ndn ) ) { 272 ber_len_t max = sockbuf_max_incoming_auth; 273 ber_sockbuf_ctrl( op->o_conn->c_sb, 274 LBER_SB_OPT_SET_MAX_INCOMING, &max ); 275 } 276 ldap_pvt_thread_mutex_unlock( &op->o_conn->c_mutex ); 277 278 /* log authorization identity */ 279 Statslog( LDAP_DEBUG_STATS, 280 "%s BIND dn=\"%s\" mech=%s (SLAPI) ssf=0\n", 281 op->o_log_prefix, 282 BER_BVISNULL( &op->o_conn->c_dn ) 283 ? "<empty>" : op->o_conn->c_dn.bv_val, 284 BER_BVISNULL( &op->orb_mech ) 285 ? "<empty>" : op->orb_mech.bv_val, 0, 0 ); 286 287 return -1; 288 } 289 break; 290 } 291 292 return rs->sr_err; 293} 294 295static int 296slapi_op_search_callback( Operation *op, SlapReply *rs, int prc ) 297{ 298 Slapi_PBlock *pb = SLAPI_OPERATION_PBLOCK( op ); 299 300 /* check preoperation result code */ 301 if ( prc < 0 ) { 302 return rs->sr_err; 303 } 304 305 rs->sr_err = LDAP_SUCCESS; 306 307 if ( pb->pb_intop == 0 && 308 slapi_int_call_plugins( op->o_bd, SLAPI_PLUGIN_COMPUTE_SEARCH_REWRITER_FN, pb ) == 0 ) { 309 /* 310 * The plugin can set the SLAPI_SEARCH_FILTER. 311 * SLAPI_SEARCH_STRFILER is not normative. 312 */ 313 op->o_tmpfree( op->ors_filterstr.bv_val, op->o_tmpmemctx ); 314 filter2bv_x( op, op->ors_filter, &op->ors_filterstr ); 315 } 316 317 return LDAP_SUCCESS; 318} 319 320struct slapi_op_info { 321 int soi_preop; /* preoperation plugin parameter */ 322 int soi_postop; /* postoperation plugin parameter */ 323 int soi_internal_preop; /* internal preoperation plugin parameter */ 324 int soi_internal_postop; /* internal postoperation plugin parameter */ 325 int (*soi_callback)(Operation *, SlapReply *, int); /* preoperation result handler */ 326} slapi_op_dispatch_table[] = { 327 { 328 SLAPI_PLUGIN_PRE_BIND_FN, 329 SLAPI_PLUGIN_POST_BIND_FN, 330 SLAPI_PLUGIN_INTERNAL_PRE_BIND_FN, 331 SLAPI_PLUGIN_INTERNAL_POST_BIND_FN, 332 slapi_op_bind_callback 333 }, 334 { 335 SLAPI_PLUGIN_PRE_UNBIND_FN, 336 SLAPI_PLUGIN_POST_UNBIND_FN, 337 SLAPI_PLUGIN_INTERNAL_PRE_UNBIND_FN, 338 SLAPI_PLUGIN_INTERNAL_POST_UNBIND_FN, 339 NULL 340 }, 341 { 342 SLAPI_PLUGIN_PRE_SEARCH_FN, 343 SLAPI_PLUGIN_POST_SEARCH_FN, 344 SLAPI_PLUGIN_INTERNAL_PRE_SEARCH_FN, 345 SLAPI_PLUGIN_INTERNAL_POST_SEARCH_FN, 346 slapi_op_search_callback 347 }, 348 { 349 SLAPI_PLUGIN_PRE_COMPARE_FN, 350 SLAPI_PLUGIN_POST_COMPARE_FN, 351 SLAPI_PLUGIN_INTERNAL_PRE_COMPARE_FN, 352 SLAPI_PLUGIN_INTERNAL_POST_COMPARE_FN, 353 NULL 354 }, 355 { 356 SLAPI_PLUGIN_PRE_MODIFY_FN, 357 SLAPI_PLUGIN_POST_MODIFY_FN, 358 SLAPI_PLUGIN_INTERNAL_PRE_MODIFY_FN, 359 SLAPI_PLUGIN_INTERNAL_POST_MODIFY_FN, 360 NULL 361 }, 362 { 363 SLAPI_PLUGIN_PRE_MODRDN_FN, 364 SLAPI_PLUGIN_POST_MODRDN_FN, 365 SLAPI_PLUGIN_INTERNAL_PRE_MODRDN_FN, 366 SLAPI_PLUGIN_INTERNAL_POST_MODRDN_FN, 367 NULL 368 }, 369 { 370 SLAPI_PLUGIN_PRE_ADD_FN, 371 SLAPI_PLUGIN_POST_ADD_FN, 372 SLAPI_PLUGIN_INTERNAL_PRE_ADD_FN, 373 SLAPI_PLUGIN_INTERNAL_POST_ADD_FN, 374 NULL 375 }, 376 { 377 SLAPI_PLUGIN_PRE_DELETE_FN, 378 SLAPI_PLUGIN_POST_DELETE_FN, 379 SLAPI_PLUGIN_INTERNAL_PRE_DELETE_FN, 380 SLAPI_PLUGIN_INTERNAL_POST_DELETE_FN, 381 NULL 382 }, 383 { 384 SLAPI_PLUGIN_PRE_ABANDON_FN, 385 SLAPI_PLUGIN_POST_ABANDON_FN, 386 SLAPI_PLUGIN_INTERNAL_PRE_ABANDON_FN, 387 SLAPI_PLUGIN_INTERNAL_POST_ABANDON_FN, 388 NULL 389 }, 390 { 391 0, 392 0, 393 0, 394 0, 395 NULL 396 } 397}; 398 399slap_operation_t 400slapi_tag2op( ber_tag_t tag ) 401{ 402 slap_operation_t op; 403 404 switch ( tag ) { 405 case LDAP_REQ_BIND: 406 op = op_bind; 407 break; 408 case LDAP_REQ_ADD: 409 op = op_add; 410 break; 411 case LDAP_REQ_DELETE: 412 op = op_delete; 413 break; 414 case LDAP_REQ_MODRDN: 415 op = op_modrdn; 416 break; 417 case LDAP_REQ_MODIFY: 418 op = op_modify; 419 break; 420 case LDAP_REQ_COMPARE: 421 op = op_compare; 422 break; 423 case LDAP_REQ_SEARCH: 424 op = op_search; 425 break; 426 case LDAP_REQ_UNBIND: 427 op = op_unbind; 428 break; 429 default: 430 op = op_last; 431 break; 432 } 433 434 return op; 435} 436 437/* Add SLAPI_RESCONTROLS to rs->sr_ctrls, with care, because 438 * rs->sr_ctrls could be allocated on the stack */ 439static int 440slapi_over_merge_controls( Operation *op, SlapReply *rs ) 441{ 442 Slapi_PBlock *pb = SLAPI_OPERATION_PBLOCK( op ); 443 LDAPControl **ctrls = NULL; 444 LDAPControl **slapi_ctrls = NULL; 445 size_t n_slapi_ctrls = 0; 446 size_t n_rs_ctrls = 0; 447 size_t i; 448 449 slapi_pblock_get( pb, SLAPI_RESCONTROLS, (void **)&slapi_ctrls ); 450 451 n_slapi_ctrls = slapi_int_count_controls( slapi_ctrls ); 452 n_rs_ctrls = slapi_int_count_controls( rs->sr_ctrls ); 453 454 slapi_pblock_set( pb, SLAPI_X_OLD_RESCONTROLS, (void *)rs->sr_ctrls ); 455 456 if ( n_slapi_ctrls == 0 ) 457 return LDAP_SUCCESS; /* no SLAPI controls */ 458 459 ctrls = (LDAPControl **) op->o_tmpalloc( 460 ( n_slapi_ctrls + n_rs_ctrls + 1 ) * sizeof(LDAPControl *), 461 op->o_tmpmemctx ); 462 463 for ( i = 0; i < n_slapi_ctrls; i++ ) { 464 ctrls[i] = slapi_ctrls[i]; 465 } 466 if ( rs->sr_ctrls != NULL ) { 467 for ( i = 0; i < n_rs_ctrls; i++ ) { 468 ctrls[n_slapi_ctrls + i] = rs->sr_ctrls[i]; 469 } 470 } 471 ctrls[n_slapi_ctrls + n_rs_ctrls] = NULL; 472 473 rs->sr_ctrls = ctrls; 474 475 return LDAP_SUCCESS; 476} 477 478static int 479slapi_over_unmerge_controls( Operation *op, SlapReply *rs ) 480{ 481 Slapi_PBlock *pb = SLAPI_OPERATION_PBLOCK( op ); 482 LDAPControl **rs_ctrls = NULL; 483 484 slapi_pblock_get( pb, SLAPI_X_OLD_RESCONTROLS, (void **)&rs_ctrls ); 485 486 if ( rs_ctrls == NULL || rs->sr_ctrls == rs_ctrls ) { 487 /* no copying done */ 488 return LDAP_SUCCESS; 489 } 490 491 op->o_tmpfree( rs->sr_ctrls, op->o_tmpmemctx ); 492 rs->sr_ctrls = rs_ctrls; 493 494 return LDAP_SUCCESS; 495} 496 497static int 498slapi_over_response( Operation *op, SlapReply *rs ) 499{ 500 Slapi_PBlock *pb = SLAPI_OPERATION_PBLOCK( op ); 501 int rc = SLAP_CB_CONTINUE; 502 503 if ( pb->pb_intop == 0 ) { 504 switch ( rs->sr_type ) { 505 case REP_RESULT: 506 case REP_SASL: 507 case REP_EXTENDED: 508 rc = slapi_over_result( op, rs, SLAPI_PLUGIN_PRE_RESULT_FN ); 509 break; 510 case REP_SEARCH: 511 rc = slapi_over_search( op, rs, SLAPI_PLUGIN_PRE_ENTRY_FN ); 512 break; 513 case REP_SEARCHREF: 514 rc = slapi_over_search( op, rs, SLAPI_PLUGIN_PRE_REFERRAL_FN ); 515 break; 516 default: 517 break; 518 } 519 } 520 521 slapi_over_merge_controls( op, rs ); 522 523 return rc; 524} 525 526static int 527slapi_over_cleanup( Operation *op, SlapReply *rs ) 528{ 529 Slapi_PBlock *pb = SLAPI_OPERATION_PBLOCK( op ); 530 int rc = SLAP_CB_CONTINUE; 531 532 slapi_over_unmerge_controls( op, rs ); 533 534 if ( pb->pb_intop == 0 ) { 535 switch ( rs->sr_type ) { 536 case REP_RESULT: 537 case REP_SASL: 538 case REP_EXTENDED: 539 rc = slapi_over_result( op, rs, SLAPI_PLUGIN_POST_RESULT_FN ); 540 break; 541 case REP_SEARCH: 542 rc = slapi_over_search( op, rs, SLAPI_PLUGIN_POST_ENTRY_FN ); 543 break; 544 case REP_SEARCHREF: 545 rc = slapi_over_search( op, rs, SLAPI_PLUGIN_POST_REFERRAL_FN ); 546 break; 547 default: 548 break; 549 } 550 } 551 552 return rc; 553} 554 555static int 556slapi_op_func( Operation *op, SlapReply *rs ) 557{ 558 Slapi_PBlock *pb; 559 slap_operation_t which; 560 struct slapi_op_info *opinfo; 561 int rc; 562 slap_overinfo *oi; 563 slap_overinst *on; 564 slap_callback cb; 565 int internal_op; 566 int preop_type, postop_type; 567 BackendDB *be; 568 569 if ( !slapi_plugins_used ) 570 return SLAP_CB_CONTINUE; 571 572 /* 573 * Find the SLAPI operation information for this LDAP 574 * operation; this will contain the preop and postop 575 * plugin types, as well as optional callbacks for 576 * setting up the SLAPI environment. 577 */ 578 which = slapi_tag2op( op->o_tag ); 579 if ( which >= op_last ) { 580 /* invalid operation, but let someone else deal with it */ 581 return SLAP_CB_CONTINUE; 582 } 583 584 opinfo = &slapi_op_dispatch_table[which]; 585 if ( opinfo == NULL ) { 586 /* no SLAPI plugin types for this operation */ 587 return SLAP_CB_CONTINUE; 588 } 589 590 internal_op = slapi_op_internal_p( op, rs, &cb ); 591 592 if ( internal_op ) { 593 preop_type = opinfo->soi_internal_preop; 594 postop_type = opinfo->soi_internal_postop; 595 } else { 596 preop_type = opinfo->soi_preop; 597 postop_type = opinfo->soi_postop; 598 } 599 600 if ( preop_type == 0 ) { 601 /* no SLAPI plugin types for this operation */ 602 pb = NULL; 603 rc = SLAP_CB_CONTINUE; 604 goto cleanup; 605 } 606 607 pb = SLAPI_OPERATION_PBLOCK( op ); 608 609 /* cache backend so we call correct postop plugins */ 610 be = pb->pb_op->o_bd; 611 612 rc = slapi_int_call_plugins( be, preop_type, pb ); 613 614 /* 615 * soi_callback is responsible for examining the result code 616 * of the preoperation plugin and determining whether to 617 * abort. This is needed because of special SLAPI behaviour 618 e with bind preoperation plugins. 619 * 620 * The soi_callback function is also used to reset any values 621 * returned from the preoperation plugin before calling the 622 * backend (for the success case). 623 */ 624 if ( opinfo->soi_callback == NULL ) { 625 /* default behaviour is preop plugin can abort operation */ 626 if ( rc < 0 ) { 627 rc = rs->sr_err; 628 goto cleanup; 629 } 630 } else { 631 rc = (opinfo->soi_callback)( op, rs, rc ); 632 if ( rc ) 633 goto cleanup; 634 } 635 636 /* 637 * Call actual backend (or next overlay in stack). We need to 638 * do this rather than returning SLAP_CB_CONTINUE and calling 639 * postoperation plugins in a response handler to match the 640 * behaviour of SLAPI in OpenLDAP 2.2, where postoperation 641 * plugins are called after the backend has completely 642 * finished processing the operation. 643 */ 644 on = (slap_overinst *)op->o_bd->bd_info; 645 oi = on->on_info; 646 647 rc = overlay_op_walk( op, rs, which, oi, on->on_next ); 648 649 /* 650 * Call postoperation plugins 651 */ 652 slapi_int_call_plugins( be, postop_type, pb ); 653 654cleanup: 655 if ( !internal_op ) { 656 slapi_pblock_destroy(pb); 657 cb.sc_private = NULL; 658 } 659 660 op->o_callback = cb.sc_next; 661 662 return rc; 663} 664 665static int 666slapi_over_extended( Operation *op, SlapReply *rs ) 667{ 668 Slapi_PBlock *pb; 669 SLAPI_FUNC callback; 670 int rc; 671 int internal_op; 672 slap_callback cb; 673 674 slapi_int_get_extop_plugin( &op->ore_reqoid, &callback ); 675 if ( callback == NULL ) { 676 return SLAP_CB_CONTINUE; 677 } 678 679 internal_op = slapi_op_internal_p( op, rs, &cb ); 680 if ( internal_op ) { 681 return SLAP_CB_CONTINUE; 682 } 683 684 pb = SLAPI_OPERATION_PBLOCK( op ); 685 686 rc = (*callback)( pb ); 687 if ( rc == SLAPI_PLUGIN_EXTENDED_SENT_RESULT ) { 688 goto cleanup; 689 } else if ( rc == SLAPI_PLUGIN_EXTENDED_NOT_HANDLED ) { 690 rc = SLAP_CB_CONTINUE; 691 goto cleanup; 692 } 693 694 assert( rs->sr_rspoid != NULL ); 695 696 send_ldap_extended( op, rs ); 697 698#if 0 699 slapi_ch_free_string( (char **)&rs->sr_rspoid ); 700#endif 701 702 if ( rs->sr_rspdata != NULL ) 703 ber_bvfree( rs->sr_rspdata ); 704 705 rc = rs->sr_err; 706 707cleanup: 708 slapi_pblock_destroy( pb ); 709 op->o_callback = cb.sc_next; 710 711 return rc; 712} 713 714static int 715slapi_over_access_allowed( 716 Operation *op, 717 Entry *e, 718 AttributeDescription *desc, 719 struct berval *val, 720 slap_access_t access, 721 AccessControlState *state, 722 slap_mask_t *maskp ) 723{ 724 int rc; 725 Slapi_PBlock *pb; 726 slap_callback cb; 727 int internal_op; 728 SlapReply rs = { REP_RESULT }; 729 730 internal_op = slapi_op_internal_p( op, &rs, &cb ); 731 732 cb.sc_response = NULL; 733 cb.sc_cleanup = NULL; 734 735 pb = SLAPI_OPERATION_PBLOCK( op ); 736 737 rc = slapi_int_access_allowed( op, e, desc, val, access, state ); 738 if ( rc ) { 739 rc = SLAP_CB_CONTINUE; 740 } 741 742 if ( !internal_op ) { 743 slapi_pblock_destroy( pb ); 744 } 745 746 op->o_callback = cb.sc_next; 747 748 return rc; 749} 750 751static int 752slapi_over_acl_group( 753 Operation *op, 754 Entry *target, 755 struct berval *gr_ndn, 756 struct berval *op_ndn, 757 ObjectClass *group_oc, 758 AttributeDescription *group_at ) 759{ 760 Slapi_Entry *e; 761 int rc; 762 Slapi_PBlock *pb; 763 BackendDB *be = op->o_bd; 764 GroupAssertion *g; 765 SlapReply rs = { REP_RESULT }; 766 767 op->o_bd = select_backend( gr_ndn, 0 ); 768 769 for ( g = op->o_groups; g; g = g->ga_next ) { 770 if ( g->ga_be != op->o_bd || g->ga_oc != group_oc || 771 g->ga_at != group_at || g->ga_len != gr_ndn->bv_len ) 772 { 773 continue; 774 } 775 if ( strcmp( g->ga_ndn, gr_ndn->bv_val ) == 0 ) { 776 break; 777 } 778 } 779 if ( g != NULL ) { 780 rc = g->ga_res; 781 goto done; 782 } 783 784 if ( target != NULL && dn_match( &target->e_nname, gr_ndn ) ) { 785 e = target; 786 rc = 0; 787 } else { 788 rc = be_entry_get_rw( op, gr_ndn, group_oc, group_at, 0, &e ); 789 } 790 if ( e != NULL ) { 791 int internal_op; 792 slap_callback cb; 793 794 internal_op = slapi_op_internal_p( op, &rs, &cb ); 795 796 cb.sc_response = NULL; 797 cb.sc_cleanup = NULL; 798 799 pb = SLAPI_OPERATION_PBLOCK( op ); 800 801 slapi_pblock_set( pb, SLAPI_X_GROUP_ENTRY, (void *)e ); 802 slapi_pblock_set( pb, SLAPI_X_GROUP_OPERATION_DN, (void *)op_ndn->bv_val ); 803 slapi_pblock_set( pb, SLAPI_X_GROUP_ATTRIBUTE, (void *)group_at->ad_cname.bv_val ); 804 slapi_pblock_set( pb, SLAPI_X_GROUP_TARGET_ENTRY, (void *)target ); 805 806 rc = slapi_over_call_plugins( pb, SLAPI_X_PLUGIN_PRE_GROUP_FN ); 807 if ( rc >= 0 ) /* 1 means no plugins called */ 808 rc = SLAP_CB_CONTINUE; 809 else 810 rc = pb->pb_rs->sr_err; 811 812 slapi_pblock_delete_param( pb, SLAPI_X_GROUP_ENTRY ); 813 slapi_pblock_delete_param( pb, SLAPI_X_GROUP_OPERATION_DN ); 814 slapi_pblock_delete_param( pb, SLAPI_X_GROUP_ATTRIBUTE ); 815 slapi_pblock_delete_param( pb, SLAPI_X_GROUP_TARGET_ENTRY ); 816 817 if ( !internal_op ) 818 slapi_pblock_destroy( pb ); 819 820 if ( e != target ) { 821 be_entry_release_r( op, e ); 822 } 823 824 op->o_callback = cb.sc_next; 825 } else { 826 rc = LDAP_NO_SUCH_OBJECT; /* return SLAP_CB_CONTINUE for correctness? */ 827 } 828 829 if ( op->o_tag != LDAP_REQ_BIND && !op->o_do_not_cache && 830 rc != SLAP_CB_CONTINUE ) { 831 g = op->o_tmpalloc( sizeof( GroupAssertion ) + gr_ndn->bv_len, 832 op->o_tmpmemctx ); 833 g->ga_be = op->o_bd; 834 g->ga_oc = group_oc; 835 g->ga_at = group_at; 836 g->ga_res = rc; 837 g->ga_len = gr_ndn->bv_len; 838 strcpy( g->ga_ndn, gr_ndn->bv_val ); 839 g->ga_next = op->o_groups; 840 op->o_groups = g; 841 } 842 /* 843 * XXX don't call POST_GROUP_FN, I have no idea what the point of 844 * that plugin function was anyway 845 */ 846done: 847 op->o_bd = be; 848 return rc; 849} 850 851static int 852slapi_over_db_open( 853 BackendDB *be, 854 ConfigReply *cr ) 855{ 856 Slapi_PBlock *pb; 857 int rc; 858 859 pb = slapi_pblock_new(); 860 861 rc = slapi_int_call_plugins( be, SLAPI_PLUGIN_START_FN, pb ); 862 863 slapi_pblock_destroy( pb ); 864 865 return rc; 866} 867 868static int 869slapi_over_db_close( 870 BackendDB *be, 871 ConfigReply *cr ) 872{ 873 Slapi_PBlock *pb; 874 int rc; 875 876 pb = slapi_pblock_new(); 877 878 rc = slapi_int_call_plugins( be, SLAPI_PLUGIN_CLOSE_FN, pb ); 879 880 slapi_pblock_destroy( pb ); 881 882 return rc; 883} 884 885static int 886slapi_over_init() 887{ 888 memset( &slapi, 0, sizeof(slapi) ); 889 890 slapi.on_bi.bi_type = SLAPI_OVERLAY_NAME; 891 892 slapi.on_bi.bi_op_bind = slapi_op_func; 893 slapi.on_bi.bi_op_unbind = slapi_op_func; 894 slapi.on_bi.bi_op_search = slapi_op_func; 895 slapi.on_bi.bi_op_compare = slapi_op_func; 896 slapi.on_bi.bi_op_modify = slapi_op_func; 897 slapi.on_bi.bi_op_modrdn = slapi_op_func; 898 slapi.on_bi.bi_op_add = slapi_op_func; 899 slapi.on_bi.bi_op_delete = slapi_op_func; 900 slapi.on_bi.bi_op_abandon = slapi_op_func; 901 slapi.on_bi.bi_op_cancel = slapi_op_func; 902 903 slapi.on_bi.bi_db_open = slapi_over_db_open; 904 slapi.on_bi.bi_db_close = slapi_over_db_close; 905 906 slapi.on_bi.bi_extended = slapi_over_extended; 907 slapi.on_bi.bi_access_allowed = slapi_over_access_allowed; 908 slapi.on_bi.bi_operational = slapi_over_aux_operational; 909 slapi.on_bi.bi_acl_group = slapi_over_acl_group; 910 911 return overlay_register( &slapi ); 912} 913 914int slapi_over_is_inst( BackendDB *be ) 915{ 916 return overlay_is_inst( be, SLAPI_OVERLAY_NAME ); 917} 918 919int slapi_over_config( BackendDB *be, ConfigReply *cr ) 920{ 921 if ( slapi_over_initialized == 0 ) { 922 int rc; 923 924 /* do global initializaiton */ 925 ldap_pvt_thread_mutex_init( &slapi_hn_mutex ); 926 ldap_pvt_thread_mutex_init( &slapi_time_mutex ); 927 ldap_pvt_thread_mutex_init( &slapi_printmessage_mutex ); 928 929 if ( slapi_log_file == NULL ) 930 slapi_log_file = slapi_ch_strdup( LDAP_RUNDIR LDAP_DIRSEP "errors" ); 931 932 rc = slapi_int_init_object_extensions(); 933 if ( rc != 0 ) 934 return rc; 935 936 rc = slapi_over_init(); 937 if ( rc != 0 ) 938 return rc; 939 940 slapi_over_initialized = 1; 941 } 942 943 return overlay_config( be, SLAPI_OVERLAY_NAME, -1, NULL, cr ); 944} 945 946#endif /* LDAP_SLAPI */ 947