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