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