1 /* $NetBSD: slapi_overlay.c,v 1.1.1.4 2010/12/12 15:23:52 adam Exp $ */ 2 3 /* slapi_overlay.c - SLAPI overlay */ 4 /* OpenLDAP: pkg/ldap/servers/slapd/slapi/slapi_overlay.c,v 1.40.2.9 2010/04/13 20:23:50 kurt Exp */ 5 /* This work is part of OpenLDAP Software <http://www.openldap.org/>. 6 * 7 * Copyright 2001-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 /* 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 302 /* check preoperation result code */ 303 if ( prc < 0 ) { 304 return rs->sr_err; 305 } 306 307 rs->sr_err = LDAP_SUCCESS; 308 309 if ( pb->pb_intop == 0 && 310 slapi_int_call_plugins( op->o_bd, SLAPI_PLUGIN_COMPUTE_SEARCH_REWRITER_FN, pb ) == 0 ) { 311 /* 312 * The plugin can set the SLAPI_SEARCH_FILTER. 313 * SLAPI_SEARCH_STRFILER is not normative. 314 */ 315 op->o_tmpfree( op->ors_filterstr.bv_val, op->o_tmpmemctx ); 316 filter2bv_x( op, op->ors_filter, &op->ors_filterstr ); 317 } 318 319 return LDAP_SUCCESS; 320 } 321 322 struct slapi_op_info { 323 int soi_preop; /* preoperation plugin parameter */ 324 int soi_postop; /* postoperation plugin parameter */ 325 int soi_internal_preop; /* internal preoperation plugin parameter */ 326 int soi_internal_postop; /* internal postoperation plugin parameter */ 327 int (*soi_callback)(Operation *, SlapReply *, int); /* preoperation result handler */ 328 } slapi_op_dispatch_table[] = { 329 { 330 SLAPI_PLUGIN_PRE_BIND_FN, 331 SLAPI_PLUGIN_POST_BIND_FN, 332 SLAPI_PLUGIN_INTERNAL_PRE_BIND_FN, 333 SLAPI_PLUGIN_INTERNAL_POST_BIND_FN, 334 slapi_op_bind_callback 335 }, 336 { 337 SLAPI_PLUGIN_PRE_UNBIND_FN, 338 SLAPI_PLUGIN_POST_UNBIND_FN, 339 SLAPI_PLUGIN_INTERNAL_PRE_UNBIND_FN, 340 SLAPI_PLUGIN_INTERNAL_POST_UNBIND_FN, 341 NULL 342 }, 343 { 344 SLAPI_PLUGIN_PRE_SEARCH_FN, 345 SLAPI_PLUGIN_POST_SEARCH_FN, 346 SLAPI_PLUGIN_INTERNAL_PRE_SEARCH_FN, 347 SLAPI_PLUGIN_INTERNAL_POST_SEARCH_FN, 348 slapi_op_search_callback 349 }, 350 { 351 SLAPI_PLUGIN_PRE_COMPARE_FN, 352 SLAPI_PLUGIN_POST_COMPARE_FN, 353 SLAPI_PLUGIN_INTERNAL_PRE_COMPARE_FN, 354 SLAPI_PLUGIN_INTERNAL_POST_COMPARE_FN, 355 NULL 356 }, 357 { 358 SLAPI_PLUGIN_PRE_MODIFY_FN, 359 SLAPI_PLUGIN_POST_MODIFY_FN, 360 SLAPI_PLUGIN_INTERNAL_PRE_MODIFY_FN, 361 SLAPI_PLUGIN_INTERNAL_POST_MODIFY_FN, 362 NULL 363 }, 364 { 365 SLAPI_PLUGIN_PRE_MODRDN_FN, 366 SLAPI_PLUGIN_POST_MODRDN_FN, 367 SLAPI_PLUGIN_INTERNAL_PRE_MODRDN_FN, 368 SLAPI_PLUGIN_INTERNAL_POST_MODRDN_FN, 369 NULL 370 }, 371 { 372 SLAPI_PLUGIN_PRE_ADD_FN, 373 SLAPI_PLUGIN_POST_ADD_FN, 374 SLAPI_PLUGIN_INTERNAL_PRE_ADD_FN, 375 SLAPI_PLUGIN_INTERNAL_POST_ADD_FN, 376 NULL 377 }, 378 { 379 SLAPI_PLUGIN_PRE_DELETE_FN, 380 SLAPI_PLUGIN_POST_DELETE_FN, 381 SLAPI_PLUGIN_INTERNAL_PRE_DELETE_FN, 382 SLAPI_PLUGIN_INTERNAL_POST_DELETE_FN, 383 NULL 384 }, 385 { 386 SLAPI_PLUGIN_PRE_ABANDON_FN, 387 SLAPI_PLUGIN_POST_ABANDON_FN, 388 SLAPI_PLUGIN_INTERNAL_PRE_ABANDON_FN, 389 SLAPI_PLUGIN_INTERNAL_POST_ABANDON_FN, 390 NULL 391 }, 392 { 393 0, 394 0, 395 0, 396 0, 397 NULL 398 } 399 }; 400 401 slap_operation_t 402 slapi_tag2op( ber_tag_t tag ) 403 { 404 slap_operation_t op; 405 406 switch ( tag ) { 407 case LDAP_REQ_BIND: 408 op = op_bind; 409 break; 410 case LDAP_REQ_ADD: 411 op = op_add; 412 break; 413 case LDAP_REQ_DELETE: 414 op = op_delete; 415 break; 416 case LDAP_REQ_MODRDN: 417 op = op_modrdn; 418 break; 419 case LDAP_REQ_MODIFY: 420 op = op_modify; 421 break; 422 case LDAP_REQ_COMPARE: 423 op = op_compare; 424 break; 425 case LDAP_REQ_SEARCH: 426 op = op_search; 427 break; 428 case LDAP_REQ_UNBIND: 429 op = op_unbind; 430 break; 431 default: 432 op = op_last; 433 break; 434 } 435 436 return op; 437 } 438 439 /* Add SLAPI_RESCONTROLS to rs->sr_ctrls, with care, because 440 * rs->sr_ctrls could be allocated on the stack */ 441 static int 442 slapi_over_merge_controls( Operation *op, SlapReply *rs ) 443 { 444 Slapi_PBlock *pb = SLAPI_OPERATION_PBLOCK( op ); 445 LDAPControl **ctrls = NULL; 446 LDAPControl **slapi_ctrls = NULL; 447 size_t n_slapi_ctrls = 0; 448 size_t n_rs_ctrls = 0; 449 size_t i; 450 451 slapi_pblock_get( pb, SLAPI_RESCONTROLS, (void **)&slapi_ctrls ); 452 453 n_slapi_ctrls = slapi_int_count_controls( slapi_ctrls ); 454 n_rs_ctrls = slapi_int_count_controls( rs->sr_ctrls ); 455 456 slapi_pblock_set( pb, SLAPI_X_OLD_RESCONTROLS, (void *)rs->sr_ctrls ); 457 458 if ( n_slapi_ctrls == 0 ) 459 return LDAP_SUCCESS; /* no SLAPI controls */ 460 461 ctrls = (LDAPControl **) op->o_tmpalloc( 462 ( n_slapi_ctrls + n_rs_ctrls + 1 ) * sizeof(LDAPControl *), 463 op->o_tmpmemctx ); 464 465 for ( i = 0; i < n_slapi_ctrls; i++ ) { 466 ctrls[i] = slapi_ctrls[i]; 467 } 468 if ( rs->sr_ctrls != NULL ) { 469 for ( i = 0; i < n_rs_ctrls; i++ ) { 470 ctrls[n_slapi_ctrls + i] = rs->sr_ctrls[i]; 471 } 472 } 473 ctrls[n_slapi_ctrls + n_rs_ctrls] = NULL; 474 475 rs->sr_ctrls = ctrls; 476 477 return LDAP_SUCCESS; 478 } 479 480 static int 481 slapi_over_unmerge_controls( Operation *op, SlapReply *rs ) 482 { 483 Slapi_PBlock *pb = SLAPI_OPERATION_PBLOCK( op ); 484 LDAPControl **rs_ctrls = NULL; 485 486 slapi_pblock_get( pb, SLAPI_X_OLD_RESCONTROLS, (void **)&rs_ctrls ); 487 488 if ( rs_ctrls == NULL || rs->sr_ctrls == rs_ctrls ) { 489 /* no copying done */ 490 return LDAP_SUCCESS; 491 } 492 493 op->o_tmpfree( rs->sr_ctrls, op->o_tmpmemctx ); 494 rs->sr_ctrls = rs_ctrls; 495 496 return LDAP_SUCCESS; 497 } 498 499 static int 500 slapi_over_response( Operation *op, SlapReply *rs ) 501 { 502 Slapi_PBlock *pb = SLAPI_OPERATION_PBLOCK( op ); 503 int rc = SLAP_CB_CONTINUE; 504 505 if ( pb->pb_intop == 0 ) { 506 switch ( rs->sr_type ) { 507 case REP_RESULT: 508 case REP_SASL: 509 case REP_EXTENDED: 510 rc = slapi_over_result( op, rs, SLAPI_PLUGIN_PRE_RESULT_FN ); 511 break; 512 case REP_SEARCH: 513 rc = slapi_over_search( op, rs, SLAPI_PLUGIN_PRE_ENTRY_FN ); 514 break; 515 case REP_SEARCHREF: 516 rc = slapi_over_search( op, rs, SLAPI_PLUGIN_PRE_REFERRAL_FN ); 517 break; 518 default: 519 break; 520 } 521 } 522 523 slapi_over_merge_controls( op, rs ); 524 525 return rc; 526 } 527 528 static int 529 slapi_over_cleanup( Operation *op, SlapReply *rs ) 530 { 531 Slapi_PBlock *pb = SLAPI_OPERATION_PBLOCK( op ); 532 int rc = SLAP_CB_CONTINUE; 533 534 slapi_over_unmerge_controls( op, rs ); 535 536 if ( pb->pb_intop == 0 ) { 537 switch ( rs->sr_type ) { 538 case REP_RESULT: 539 case REP_SASL: 540 case REP_EXTENDED: 541 rc = slapi_over_result( op, rs, SLAPI_PLUGIN_POST_RESULT_FN ); 542 break; 543 case REP_SEARCH: 544 rc = slapi_over_search( op, rs, SLAPI_PLUGIN_POST_ENTRY_FN ); 545 break; 546 case REP_SEARCHREF: 547 rc = slapi_over_search( op, rs, SLAPI_PLUGIN_POST_REFERRAL_FN ); 548 break; 549 default: 550 break; 551 } 552 } 553 554 return rc; 555 } 556 557 static int 558 slapi_op_func( Operation *op, SlapReply *rs ) 559 { 560 Slapi_PBlock *pb; 561 slap_operation_t which; 562 struct slapi_op_info *opinfo; 563 int rc; 564 slap_overinfo *oi; 565 slap_overinst *on; 566 slap_callback cb; 567 int internal_op; 568 int preop_type, postop_type; 569 BackendDB *be; 570 571 if ( !slapi_plugins_used ) 572 return SLAP_CB_CONTINUE; 573 574 /* 575 * Find the SLAPI operation information for this LDAP 576 * operation; this will contain the preop and postop 577 * plugin types, as well as optional callbacks for 578 * setting up the SLAPI environment. 579 */ 580 which = slapi_tag2op( op->o_tag ); 581 if ( which >= op_last ) { 582 /* invalid operation, but let someone else deal with it */ 583 return SLAP_CB_CONTINUE; 584 } 585 586 opinfo = &slapi_op_dispatch_table[which]; 587 if ( opinfo == NULL ) { 588 /* no SLAPI plugin types for this operation */ 589 return SLAP_CB_CONTINUE; 590 } 591 592 internal_op = slapi_op_internal_p( op, rs, &cb ); 593 594 if ( internal_op ) { 595 preop_type = opinfo->soi_internal_preop; 596 postop_type = opinfo->soi_internal_postop; 597 } else { 598 preop_type = opinfo->soi_preop; 599 postop_type = opinfo->soi_postop; 600 } 601 602 if ( preop_type == 0 ) { 603 /* no SLAPI plugin types for this operation */ 604 pb = NULL; 605 rc = SLAP_CB_CONTINUE; 606 goto cleanup; 607 } 608 609 pb = SLAPI_OPERATION_PBLOCK( op ); 610 611 /* cache backend so we call correct postop plugins */ 612 be = pb->pb_op->o_bd; 613 614 rc = slapi_int_call_plugins( be, preop_type, pb ); 615 616 /* 617 * soi_callback is responsible for examining the result code 618 * of the preoperation plugin and determining whether to 619 * abort. This is needed because of special SLAPI behaviour 620 e with bind preoperation plugins. 621 * 622 * The soi_callback function is also used to reset any values 623 * returned from the preoperation plugin before calling the 624 * backend (for the success case). 625 */ 626 if ( opinfo->soi_callback == NULL ) { 627 /* default behaviour is preop plugin can abort operation */ 628 if ( rc < 0 ) { 629 rc = rs->sr_err; 630 goto cleanup; 631 } 632 } else { 633 rc = (opinfo->soi_callback)( op, rs, rc ); 634 if ( rc ) 635 goto cleanup; 636 } 637 638 /* 639 * Call actual backend (or next overlay in stack). We need to 640 * do this rather than returning SLAP_CB_CONTINUE and calling 641 * postoperation plugins in a response handler to match the 642 * behaviour of SLAPI in OpenLDAP 2.2, where postoperation 643 * plugins are called after the backend has completely 644 * finished processing the operation. 645 */ 646 on = (slap_overinst *)op->o_bd->bd_info; 647 oi = on->on_info; 648 649 rc = overlay_op_walk( op, rs, which, oi, on->on_next ); 650 651 /* 652 * Call postoperation plugins 653 */ 654 slapi_int_call_plugins( be, postop_type, pb ); 655 656 cleanup: 657 if ( !internal_op ) { 658 slapi_pblock_destroy(pb); 659 cb.sc_private = NULL; 660 } 661 662 op->o_callback = cb.sc_next; 663 664 return rc; 665 } 666 667 static int 668 slapi_over_extended( Operation *op, SlapReply *rs ) 669 { 670 Slapi_PBlock *pb; 671 SLAPI_FUNC callback; 672 int rc; 673 int internal_op; 674 slap_callback cb; 675 676 slapi_int_get_extop_plugin( &op->ore_reqoid, &callback ); 677 if ( callback == NULL ) { 678 return SLAP_CB_CONTINUE; 679 } 680 681 internal_op = slapi_op_internal_p( op, rs, &cb ); 682 if ( internal_op ) { 683 return SLAP_CB_CONTINUE; 684 } 685 686 pb = SLAPI_OPERATION_PBLOCK( op ); 687 688 rc = (*callback)( pb ); 689 if ( rc == SLAPI_PLUGIN_EXTENDED_SENT_RESULT ) { 690 goto cleanup; 691 } else if ( rc == SLAPI_PLUGIN_EXTENDED_NOT_HANDLED ) { 692 rc = SLAP_CB_CONTINUE; 693 goto cleanup; 694 } 695 696 assert( rs->sr_rspoid != NULL ); 697 698 send_ldap_extended( op, rs ); 699 700 #if 0 701 slapi_ch_free_string( (char **)&rs->sr_rspoid ); 702 #endif 703 704 if ( rs->sr_rspdata != NULL ) 705 ber_bvfree( rs->sr_rspdata ); 706 707 rc = rs->sr_err; 708 709 cleanup: 710 slapi_pblock_destroy( pb ); 711 op->o_callback = cb.sc_next; 712 713 return rc; 714 } 715 716 static int 717 slapi_over_access_allowed( 718 Operation *op, 719 Entry *e, 720 AttributeDescription *desc, 721 struct berval *val, 722 slap_access_t access, 723 AccessControlState *state, 724 slap_mask_t *maskp ) 725 { 726 int rc; 727 Slapi_PBlock *pb; 728 slap_callback cb; 729 int internal_op; 730 SlapReply rs = { REP_RESULT }; 731 732 internal_op = slapi_op_internal_p( op, &rs, &cb ); 733 734 cb.sc_response = NULL; 735 cb.sc_cleanup = NULL; 736 737 pb = SLAPI_OPERATION_PBLOCK( op ); 738 739 rc = slapi_int_access_allowed( op, e, desc, val, access, state ); 740 if ( rc ) { 741 rc = SLAP_CB_CONTINUE; 742 } 743 744 if ( !internal_op ) { 745 slapi_pblock_destroy( pb ); 746 } 747 748 op->o_callback = cb.sc_next; 749 750 return rc; 751 } 752 753 static int 754 slapi_over_acl_group( 755 Operation *op, 756 Entry *target, 757 struct berval *gr_ndn, 758 struct berval *op_ndn, 759 ObjectClass *group_oc, 760 AttributeDescription *group_at ) 761 { 762 Slapi_Entry *e; 763 int rc; 764 Slapi_PBlock *pb; 765 BackendDB *be = op->o_bd; 766 GroupAssertion *g; 767 SlapReply rs = { REP_RESULT }; 768 769 op->o_bd = select_backend( gr_ndn, 0 ); 770 771 for ( g = op->o_groups; g; g = g->ga_next ) { 772 if ( g->ga_be != op->o_bd || g->ga_oc != group_oc || 773 g->ga_at != group_at || g->ga_len != gr_ndn->bv_len ) 774 { 775 continue; 776 } 777 if ( strcmp( g->ga_ndn, gr_ndn->bv_val ) == 0 ) { 778 break; 779 } 780 } 781 if ( g != NULL ) { 782 rc = g->ga_res; 783 goto done; 784 } 785 786 if ( target != NULL && dn_match( &target->e_nname, gr_ndn ) ) { 787 e = target; 788 rc = 0; 789 } else { 790 rc = be_entry_get_rw( op, gr_ndn, group_oc, group_at, 0, &e ); 791 } 792 if ( e != NULL ) { 793 int internal_op; 794 slap_callback cb; 795 796 internal_op = slapi_op_internal_p( op, &rs, &cb ); 797 798 cb.sc_response = NULL; 799 cb.sc_cleanup = NULL; 800 801 pb = SLAPI_OPERATION_PBLOCK( op ); 802 803 slapi_pblock_set( pb, SLAPI_X_GROUP_ENTRY, (void *)e ); 804 slapi_pblock_set( pb, SLAPI_X_GROUP_OPERATION_DN, (void *)op_ndn->bv_val ); 805 slapi_pblock_set( pb, SLAPI_X_GROUP_ATTRIBUTE, (void *)group_at->ad_cname.bv_val ); 806 slapi_pblock_set( pb, SLAPI_X_GROUP_TARGET_ENTRY, (void *)target ); 807 808 rc = slapi_over_call_plugins( pb, SLAPI_X_PLUGIN_PRE_GROUP_FN ); 809 if ( rc >= 0 ) /* 1 means no plugins called */ 810 rc = SLAP_CB_CONTINUE; 811 else 812 rc = pb->pb_rs->sr_err; 813 814 slapi_pblock_delete_param( pb, SLAPI_X_GROUP_ENTRY ); 815 slapi_pblock_delete_param( pb, SLAPI_X_GROUP_OPERATION_DN ); 816 slapi_pblock_delete_param( pb, SLAPI_X_GROUP_ATTRIBUTE ); 817 slapi_pblock_delete_param( pb, SLAPI_X_GROUP_TARGET_ENTRY ); 818 819 if ( !internal_op ) 820 slapi_pblock_destroy( pb ); 821 822 if ( e != target ) { 823 be_entry_release_r( op, e ); 824 } 825 826 op->o_callback = cb.sc_next; 827 } else { 828 rc = LDAP_NO_SUCH_OBJECT; /* return SLAP_CB_CONTINUE for correctness? */ 829 } 830 831 if ( op->o_tag != LDAP_REQ_BIND && !op->o_do_not_cache && 832 rc != SLAP_CB_CONTINUE ) { 833 g = op->o_tmpalloc( sizeof( GroupAssertion ) + gr_ndn->bv_len, 834 op->o_tmpmemctx ); 835 g->ga_be = op->o_bd; 836 g->ga_oc = group_oc; 837 g->ga_at = group_at; 838 g->ga_res = rc; 839 g->ga_len = gr_ndn->bv_len; 840 strcpy( g->ga_ndn, gr_ndn->bv_val ); 841 g->ga_next = op->o_groups; 842 op->o_groups = g; 843 } 844 /* 845 * XXX don't call POST_GROUP_FN, I have no idea what the point of 846 * that plugin function was anyway 847 */ 848 done: 849 op->o_bd = be; 850 return rc; 851 } 852 853 static int 854 slapi_over_db_open( 855 BackendDB *be, 856 ConfigReply *cr ) 857 { 858 Slapi_PBlock *pb; 859 int rc; 860 861 pb = slapi_pblock_new(); 862 863 rc = slapi_int_call_plugins( be, SLAPI_PLUGIN_START_FN, pb ); 864 865 slapi_pblock_destroy( pb ); 866 867 return rc; 868 } 869 870 static int 871 slapi_over_db_close( 872 BackendDB *be, 873 ConfigReply *cr ) 874 { 875 Slapi_PBlock *pb; 876 int rc; 877 878 pb = slapi_pblock_new(); 879 880 rc = slapi_int_call_plugins( be, SLAPI_PLUGIN_CLOSE_FN, pb ); 881 882 slapi_pblock_destroy( pb ); 883 884 return rc; 885 } 886 887 static int 888 slapi_over_init() 889 { 890 memset( &slapi, 0, sizeof(slapi) ); 891 892 slapi.on_bi.bi_type = SLAPI_OVERLAY_NAME; 893 894 slapi.on_bi.bi_op_bind = slapi_op_func; 895 slapi.on_bi.bi_op_unbind = slapi_op_func; 896 slapi.on_bi.bi_op_search = slapi_op_func; 897 slapi.on_bi.bi_op_compare = slapi_op_func; 898 slapi.on_bi.bi_op_modify = slapi_op_func; 899 slapi.on_bi.bi_op_modrdn = slapi_op_func; 900 slapi.on_bi.bi_op_add = slapi_op_func; 901 slapi.on_bi.bi_op_delete = slapi_op_func; 902 slapi.on_bi.bi_op_abandon = slapi_op_func; 903 slapi.on_bi.bi_op_cancel = slapi_op_func; 904 905 slapi.on_bi.bi_db_open = slapi_over_db_open; 906 slapi.on_bi.bi_db_close = slapi_over_db_close; 907 908 slapi.on_bi.bi_extended = slapi_over_extended; 909 slapi.on_bi.bi_access_allowed = slapi_over_access_allowed; 910 slapi.on_bi.bi_operational = slapi_over_aux_operational; 911 slapi.on_bi.bi_acl_group = slapi_over_acl_group; 912 913 return overlay_register( &slapi ); 914 } 915 916 int slapi_over_is_inst( BackendDB *be ) 917 { 918 return overlay_is_inst( be, SLAPI_OVERLAY_NAME ); 919 } 920 921 int slapi_over_config( BackendDB *be, ConfigReply *cr ) 922 { 923 if ( slapi_over_initialized == 0 ) { 924 int rc; 925 926 /* do global initializaiton */ 927 ldap_pvt_thread_mutex_init( &slapi_hn_mutex ); 928 ldap_pvt_thread_mutex_init( &slapi_time_mutex ); 929 ldap_pvt_thread_mutex_init( &slapi_printmessage_mutex ); 930 931 if ( slapi_log_file == NULL ) 932 slapi_log_file = slapi_ch_strdup( LDAP_RUNDIR LDAP_DIRSEP "errors" ); 933 934 rc = slapi_int_init_object_extensions(); 935 if ( rc != 0 ) 936 return rc; 937 938 rc = slapi_over_init(); 939 if ( rc != 0 ) 940 return rc; 941 942 slapi_over_initialized = 1; 943 } 944 945 return overlay_config( be, SLAPI_OVERLAY_NAME, -1, NULL, cr ); 946 } 947 948 #endif /* LDAP_SLAPI */ 949