1/* $NetBSD: chain.c,v 1.1.1.3 2010/12/12 15:23:04 adam Exp $ */ 2 3/* chain.c - chain LDAP operations */ 4/* OpenLDAP: pkg/ldap/servers/slapd/back-ldap/chain.c,v 1.52.2.12 2010/04/13 20:23:28 kurt Exp */ 5/* This work is part of OpenLDAP Software <http://www.openldap.org/>. 6 * 7 * Copyright 2003-2010 The OpenLDAP Foundation. 8 * Portions Copyright 2003 Howard Chu. 9 * All rights reserved. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted only as authorized by the OpenLDAP 13 * Public License. 14 * 15 * A copy of this license is available in the file LICENSE in the 16 * top-level directory of the distribution or, alternatively, at 17 * <http://www.OpenLDAP.org/license.html>. 18 */ 19/* ACKNOWLEDGEMENTS: 20 * This work was initially developed by the Howard Chu for inclusion 21 * in OpenLDAP Software. 22 * This work was subsequently modified by Pierangelo Masarati. 23 */ 24 25#include "portable.h" 26 27#include <stdio.h> 28 29#include <ac/string.h> 30#include <ac/socket.h> 31 32#include "lutil.h" 33#include "slap.h" 34#include "back-ldap.h" 35#include "config.h" 36 37#ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR 38#define SLAP_CHAINING_DEFAULT LDAP_CHAINING_PREFERRED 39#define SLAP_CH_RESOLVE_SHIFT SLAP_CONTROL_SHIFT 40#define SLAP_CH_RESOLVE_MASK (0x3 << SLAP_CH_RESOLVE_SHIFT) 41#define SLAP_CH_RESOLVE_CHAINING_PREFERRED (LDAP_CHAINING_PREFERRED << SLAP_CH_RESOLVE_SHIFT) 42#define SLAP_CH_RESOLVE_CHAINING_REQUIRED (LDAP_CHAINING_REQUIRED << SLAP_CH_RESOLVE_SHIFT) 43#define SLAP_CH_RESOLVE_REFERRALS_PREFERRED (LDAP_REFERRALS_PREFERRED << SLAP_CH_RESOLVE_SHIFT) 44#define SLAP_CH_RESOLVE_REFERRALS_REQUIRED (LDAP_REFERRALS_REQUIRED << SLAP_CH_RESOLVE_SHIFT) 45#define SLAP_CH_RESOLVE_DEFAULT (SLAP_CHAINING_DEFAULT << SLAP_CH_RESOLVE_SHIFT) 46#define SLAP_CH_CONTINUATION_SHIFT (SLAP_CH_RESOLVE_SHIFT + 2) 47#define SLAP_CH_CONTINUATION_MASK (0x3 << SLAP_CH_CONTINUATION_SHIFT) 48#define SLAP_CH_CONTINUATION_CHAINING_PREFERRED (LDAP_CHAINING_PREFERRED << SLAP_CH_CONTINUATION_SHIFT) 49#define SLAP_CH_CONTINUATION_CHAINING_REQUIRED (LDAP_CHAINING_REQUIRED << SLAP_CH_CONTINUATION_SHIFT) 50#define SLAP_CH_CONTINUATION_REFERRALS_PREFERRED (LDAP_REFERRALS_PREFERRED << SLAP_CH_CONTINUATION_SHIFT) 51#define SLAP_CH_CONTINUATION_REFERRALS_REQUIRED (LDAP_REFERRALS_REQUIRED << SLAP_CH_CONTINUATION_SHIFT) 52#define SLAP_CH_CONTINUATION_DEFAULT (SLAP_CHAINING_DEFAULT << SLAP_CH_CONTINUATION_SHIFT) 53 54#define o_chaining o_ctrlflag[sc_chainingBehavior] 55#define get_chaining(op) ((op)->o_chaining & SLAP_CONTROL_MASK) 56#define get_chainingBehavior(op) ((op)->o_chaining & (SLAP_CH_RESOLVE_MASK|SLAP_CH_CONTINUATION_MASK)) 57#define get_resolveBehavior(op) ((op)->o_chaining & SLAP_CH_RESOLVE_MASK) 58#define get_continuationBehavior(op) ((op)->o_chaining & SLAP_CH_CONTINUATION_MASK) 59 60static int sc_chainingBehavior; 61#endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */ 62 63typedef enum { 64 LDAP_CH_NONE = 0, 65 LDAP_CH_RES, 66 LDAP_CH_ERR 67} ldap_chain_status_t; 68 69static BackendInfo *lback; 70 71typedef struct ldap_chain_t { 72 /* 73 * A "template" ldapinfo_t gets all common configuration items; 74 * then, for each configured URI, an entry is created in the tree; 75 * all the specific configuration items get in the current URI 76 * structure. 77 * 78 * Then, for each referral, extract the URI and lookup the 79 * related structure. If configured to do so, allow URIs 80 * not found in the structure to create a temporary one 81 * that chains anonymously; maybe it can also be added to 82 * the tree? Should be all configurable. 83 */ 84 85 /* "common" configuration info (anything occurring before an "uri") */ 86 ldapinfo_t *lc_common_li; 87 88 /* current configuration info */ 89 ldapinfo_t *lc_cfg_li; 90 91 /* tree of configured[/generated?] "uri" info */ 92 ldap_avl_info_t lc_lai; 93 94 /* max depth in nested referrals chaining */ 95 int lc_max_depth; 96 97 unsigned lc_flags; 98#define LDAP_CHAIN_F_NONE (0x00U) 99#define LDAP_CHAIN_F_CHAINING (0x01U) 100#define LDAP_CHAIN_F_CACHE_URI (0x02U) 101#define LDAP_CHAIN_F_RETURN_ERR (0x04U) 102 103#define LDAP_CHAIN_ISSET(lc, f) ( ( (lc)->lc_flags & (f) ) == (f) ) 104#define LDAP_CHAIN_CHAINING( lc ) LDAP_CHAIN_ISSET( (lc), LDAP_CHAIN_F_CHAINING ) 105#define LDAP_CHAIN_CACHE_URI( lc ) LDAP_CHAIN_ISSET( (lc), LDAP_CHAIN_F_CACHE_URI ) 106#define LDAP_CHAIN_RETURN_ERR( lc ) LDAP_CHAIN_ISSET( (lc), LDAP_CHAIN_F_RETURN_ERR ) 107 108#ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR 109 LDAPControl lc_chaining_ctrl; 110 char lc_chaining_ctrlflag; 111#endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */ 112} ldap_chain_t; 113 114static int ldap_chain_db_init_common( BackendDB *be ); 115static int ldap_chain_db_init_one( BackendDB *be ); 116static int ldap_chain_db_open_one( BackendDB *be ); 117#define ldap_chain_db_close_one(be) (0) 118#define ldap_chain_db_destroy_one(be, rs) (lback)->bi_db_destroy( (be), (rs) ) 119 120typedef struct ldap_chain_cb_t { 121 ldap_chain_status_t lb_status; 122 ldap_chain_t *lb_lc; 123 BI_op_func *lb_op_f; 124 int lb_depth; 125} ldap_chain_cb_t; 126 127static int 128ldap_chain_op( 129 Operation *op, 130 SlapReply *rs, 131 BI_op_func *op_f, 132 BerVarray ref, 133 int depth ); 134 135static int 136ldap_chain_search( 137 Operation *op, 138 SlapReply *rs, 139 BerVarray ref, 140 int depth ); 141 142static slap_overinst ldapchain; 143 144#ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR 145static int 146chaining_control_add( 147 ldap_chain_t *lc, 148 Operation *op, 149 LDAPControl ***oldctrlsp ) 150{ 151 LDAPControl **ctrls = NULL; 152 int c = 0; 153 154 *oldctrlsp = op->o_ctrls; 155 156 /* default chaining control not defined */ 157 if ( !LDAP_CHAIN_CHAINING( lc ) ) { 158 return 0; 159 } 160 161 /* already present */ 162 if ( get_chaining( op ) > SLAP_CONTROL_IGNORED ) { 163 return 0; 164 } 165 166 /* FIXME: check other incompatibilities */ 167 168 /* add to other controls */ 169 if ( op->o_ctrls ) { 170 for ( c = 0; op->o_ctrls[ c ]; c++ ) 171 /* count them */ ; 172 } 173 174 ctrls = ch_calloc( sizeof( LDAPControl *), c + 2 ); 175 ctrls[ 0 ] = &lc->lc_chaining_ctrl; 176 if ( op->o_ctrls ) { 177 for ( c = 0; op->o_ctrls[ c ]; c++ ) { 178 ctrls[ c + 1 ] = op->o_ctrls[ c ]; 179 } 180 } 181 ctrls[ c + 1 ] = NULL; 182 183 op->o_ctrls = ctrls; 184 185 op->o_chaining = lc->lc_chaining_ctrlflag; 186 187 return 0; 188} 189 190static int 191chaining_control_remove( 192 Operation *op, 193 LDAPControl ***oldctrlsp ) 194{ 195 LDAPControl **oldctrls = *oldctrlsp; 196 197 /* we assume that the first control is the chaining control 198 * added by the chain overlay, so it's the only one we explicitly 199 * free */ 200 if ( op->o_ctrls != oldctrls ) { 201 assert( op->o_ctrls != NULL ); 202 assert( op->o_ctrls[ 0 ] != NULL ); 203 204 free( op->o_ctrls ); 205 206 op->o_chaining = 0; 207 op->o_ctrls = oldctrls; 208 } 209 210 *oldctrlsp = NULL; 211 212 return 0; 213} 214#endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */ 215 216static int 217ldap_chain_uri_cmp( const void *c1, const void *c2 ) 218{ 219 const ldapinfo_t *li1 = (const ldapinfo_t *)c1; 220 const ldapinfo_t *li2 = (const ldapinfo_t *)c2; 221 222 assert( li1->li_bvuri != NULL ); 223 assert( !BER_BVISNULL( &li1->li_bvuri[ 0 ] ) ); 224 assert( BER_BVISNULL( &li1->li_bvuri[ 1 ] ) ); 225 226 assert( li2->li_bvuri != NULL ); 227 assert( !BER_BVISNULL( &li2->li_bvuri[ 0 ] ) ); 228 assert( BER_BVISNULL( &li2->li_bvuri[ 1 ] ) ); 229 230 /* If local DNs don't match, it is definitely not a match */ 231 return ber_bvcmp( &li1->li_bvuri[ 0 ], &li2->li_bvuri[ 0 ] ); 232} 233 234static int 235ldap_chain_uri_dup( void *c1, void *c2 ) 236{ 237 ldapinfo_t *li1 = (ldapinfo_t *)c1; 238 ldapinfo_t *li2 = (ldapinfo_t *)c2; 239 240 assert( li1->li_bvuri != NULL ); 241 assert( !BER_BVISNULL( &li1->li_bvuri[ 0 ] ) ); 242 assert( BER_BVISNULL( &li1->li_bvuri[ 1 ] ) ); 243 244 assert( li2->li_bvuri != NULL ); 245 assert( !BER_BVISNULL( &li2->li_bvuri[ 0 ] ) ); 246 assert( BER_BVISNULL( &li2->li_bvuri[ 1 ] ) ); 247 248 /* Cannot have more than one shared session with same DN */ 249 if ( ber_bvcmp( &li1->li_bvuri[ 0 ], &li2->li_bvuri[ 0 ] ) == 0 ) { 250 return -1; 251 } 252 253 return 0; 254} 255 256/* 257 * Search specific response that strips entryDN from entries 258 */ 259static int 260ldap_chain_cb_search_response( Operation *op, SlapReply *rs ) 261{ 262 ldap_chain_cb_t *lb = (ldap_chain_cb_t *)op->o_callback->sc_private; 263 264 assert( op->o_tag == LDAP_REQ_SEARCH ); 265 266 /* if in error, don't proceed any further */ 267 if ( lb->lb_status == LDAP_CH_ERR ) { 268 return 0; 269 } 270 271 if ( rs->sr_type == REP_SEARCH ) { 272 Attribute **ap = &rs->sr_entry->e_attrs; 273 274 for ( ; *ap != NULL; ap = &(*ap)->a_next ) { 275 /* will be generated later by frontend 276 * (a cleaner solution would be that 277 * the frontend checks if it already exists */ 278 if ( ad_cmp( (*ap)->a_desc, slap_schema.si_ad_entryDN ) == 0 ) 279 { 280 Attribute *a = *ap; 281 282 *ap = (*ap)->a_next; 283 attr_free( a ); 284 285 /* there SHOULD be one only! */ 286 break; 287 } 288 } 289 290 /* tell the frontend not to add generated 291 * operational attributes */ 292 rs->sr_flags |= REP_NO_OPERATIONALS; 293 294 return SLAP_CB_CONTINUE; 295 296 } else if ( rs->sr_type == REP_SEARCHREF ) { 297 /* if we get it here, it means the library was unable 298 * to chase the referral... */ 299 if ( lb->lb_depth < lb->lb_lc->lc_max_depth && rs->sr_ref != NULL ) { 300 rs->sr_err = ldap_chain_search( op, rs, rs->sr_ref, lb->lb_depth ); 301 } 302 303#ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR 304 if ( rs->sr_err == LDAP_REFERRAL && get_chaining( op ) > SLAP_CONTROL_IGNORED ) { 305 switch ( get_continuationBehavior( op ) ) { 306 case SLAP_CH_RESOLVE_CHAINING_REQUIRED: 307 lb->lb_status = LDAP_CH_ERR; 308 return rs->sr_err = LDAP_X_CANNOT_CHAIN; 309 310 default: 311 break; 312 } 313 } 314#endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */ 315 return SLAP_CB_CONTINUE; 316 317 } else if ( rs->sr_type == REP_RESULT ) { 318 if ( rs->sr_err == LDAP_REFERRAL 319 && lb->lb_depth < lb->lb_lc->lc_max_depth 320 && rs->sr_ref != NULL ) 321 { 322 rs->sr_err = ldap_chain_op( op, rs, lb->lb_op_f, rs->sr_ref, lb->lb_depth ); 323 } 324 325 /* back-ldap tried to send result */ 326 lb->lb_status = LDAP_CH_RES; 327 } 328 329 return 0; 330} 331 332/* 333 * Dummy response that simply traces if back-ldap tried to send 334 * anything to the client 335 */ 336static int 337ldap_chain_cb_response( Operation *op, SlapReply *rs ) 338{ 339 ldap_chain_cb_t *lb = (ldap_chain_cb_t *)op->o_callback->sc_private; 340 341 /* if in error, don't proceed any further */ 342 if ( lb->lb_status == LDAP_CH_ERR ) { 343 return 0; 344 } 345 346 if ( rs->sr_type == REP_RESULT ) { 347retry:; 348 switch ( rs->sr_err ) { 349 case LDAP_COMPARE_TRUE: 350 case LDAP_COMPARE_FALSE: 351 if ( op->o_tag != LDAP_REQ_COMPARE ) { 352 return rs->sr_err; 353 } 354 /* fallthru */ 355 356 case LDAP_SUCCESS: 357 lb->lb_status = LDAP_CH_RES; 358 break; 359 360 case LDAP_REFERRAL: 361 if ( lb->lb_depth < lb->lb_lc->lc_max_depth && rs->sr_ref != NULL ) { 362 rs->sr_err = ldap_chain_op( op, rs, lb->lb_op_f, rs->sr_ref, lb->lb_depth ); 363 goto retry; 364 } 365 366#ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR 367 if ( get_chaining( op ) > SLAP_CONTROL_IGNORED ) { 368 switch ( get_continuationBehavior( op ) ) { 369 case SLAP_CH_RESOLVE_CHAINING_REQUIRED: 370 lb->lb_status = LDAP_CH_ERR; 371 return rs->sr_err = LDAP_X_CANNOT_CHAIN; 372 373 default: 374 break; 375 } 376 } 377#endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */ 378 break; 379 380 default: 381 return rs->sr_err; 382 } 383 384 } else if ( op->o_tag == LDAP_REQ_SEARCH && rs->sr_type == REP_SEARCH ) 385 { 386 /* strip the entryDN attribute, but keep returning results */ 387 (void)ldap_chain_cb_search_response( op, rs ); 388 } 389 390 return SLAP_CB_CONTINUE; 391} 392 393static int 394ldap_chain_op( 395 Operation *op, 396 SlapReply *rs, 397 BI_op_func *op_f, 398 BerVarray ref, 399 int depth ) 400{ 401 slap_overinst *on = (slap_overinst *) op->o_bd->bd_info; 402 ldap_chain_cb_t *lb = (ldap_chain_cb_t *)op->o_callback->sc_private; 403 ldap_chain_t *lc = (ldap_chain_t *)on->on_bi.bi_private; 404 ldapinfo_t li = { 0 }, *lip = NULL; 405 struct berval bvuri[ 2 ] = { { 0 } }; 406 407 /* NOTE: returned if ref is empty... */ 408 int rc = LDAP_OTHER, 409 first_rc; 410 411#ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR 412 LDAPControl **ctrls = NULL; 413 414 (void)chaining_control_add( lc, op, &ctrls ); 415#endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */ 416 417 li.li_bvuri = bvuri; 418 first_rc = -1; 419 for ( ; !BER_BVISNULL( ref ); ref++ ) { 420 SlapReply rs2 = { 0 }; 421 LDAPURLDesc *srv = NULL; 422 struct berval save_req_dn = op->o_req_dn, 423 save_req_ndn = op->o_req_ndn, 424 dn = BER_BVNULL, 425 pdn = BER_BVNULL, 426 ndn = BER_BVNULL; 427 int temporary = 0; 428 429 /* We're setting the URI of the first referral; 430 * what if there are more? 431 432Document: RFC 4511 433 4344.1.10. Referral 435 ... 436 If the client wishes to progress the operation, it MUST follow the 437 referral by contacting one of the supported services. If multiple 438 URIs are present, the client assumes that any supported URI may be 439 used to progress the operation. 440 441 * so we actually need to follow exactly one, 442 * and we can assume any is fine. 443 */ 444 445 /* parse reference and use 446 * proto://[host][:port]/ only */ 447 rc = ldap_url_parse_ext( ref->bv_val, &srv, LDAP_PVT_URL_PARSE_NONE ); 448 if ( rc != LDAP_URL_SUCCESS ) { 449 /* try next */ 450 rc = LDAP_OTHER; 451 continue; 452 } 453 454 /* normalize DN */ 455 rc = LDAP_SUCCESS; 456 srv->lud_scope = LDAP_SCOPE_DEFAULT; 457 if ( srv->lud_dn != NULL ) { 458 ber_str2bv( srv->lud_dn, 0, 0, &dn ); 459 rc = dnPrettyNormal( NULL, &dn, &pdn, &ndn, op->o_tmpmemctx ); 460 if ( rc == LDAP_SUCCESS ) { 461 /* remove DN essentially because later on 462 * ldap_initialize() will parse the URL 463 * as a comma-separated URL list */ 464 srv->lud_dn = ""; 465 } 466 467 } else { 468 srv->lud_dn = ""; 469 } 470 471 li.li_uri = ldap_url_desc2str( srv ); 472 srv->lud_dn = dn.bv_val; 473 ldap_free_urldesc( srv ); 474 475 if ( rc != LDAP_SUCCESS ) { 476 /* try next */ 477 rc = LDAP_OTHER; 478 continue; 479 } 480 481 if ( li.li_uri == NULL ) { 482 /* try next */ 483 rc = LDAP_OTHER; 484 goto further_cleanup; 485 } 486 487 op->o_req_dn = pdn; 488 op->o_req_ndn = ndn; 489 490 ber_str2bv( li.li_uri, 0, 0, &li.li_bvuri[ 0 ] ); 491 492 /* Searches for a ldapinfo in the avl tree */ 493 ldap_pvt_thread_mutex_lock( &lc->lc_lai.lai_mutex ); 494 lip = (ldapinfo_t *)avl_find( lc->lc_lai.lai_tree, 495 (caddr_t)&li, ldap_chain_uri_cmp ); 496 ldap_pvt_thread_mutex_unlock( &lc->lc_lai.lai_mutex ); 497 498 if ( lip != NULL ) { 499 op->o_bd->be_private = (void *)lip; 500 501 } else { 502 rc = ldap_chain_db_init_one( op->o_bd ); 503 if ( rc != 0 ) { 504 goto cleanup; 505 } 506 lip = (ldapinfo_t *)op->o_bd->be_private; 507 lip->li_uri = li.li_uri; 508 lip->li_bvuri = bvuri; 509 rc = ldap_chain_db_open_one( op->o_bd ); 510 if ( rc != 0 ) { 511 lip->li_uri = NULL; 512 lip->li_bvuri = NULL; 513 (void)ldap_chain_db_destroy_one( op->o_bd, NULL); 514 goto cleanup; 515 } 516 517 if ( LDAP_CHAIN_CACHE_URI( lc ) ) { 518 ldap_pvt_thread_mutex_lock( &lc->lc_lai.lai_mutex ); 519 if ( avl_insert( &lc->lc_lai.lai_tree, 520 (caddr_t)lip, ldap_chain_uri_cmp, ldap_chain_uri_dup ) ) 521 { 522 /* someone just inserted another; 523 * don't bother, use this and then 524 * just free it */ 525 temporary = 1; 526 } 527 ldap_pvt_thread_mutex_unlock( &lc->lc_lai.lai_mutex ); 528 529 } else { 530 temporary = 1; 531 } 532 } 533 534 lb->lb_op_f = op_f; 535 lb->lb_depth = depth + 1; 536 537 rc = op_f( op, &rs2 ); 538 539 /* note the first error */ 540 if ( first_rc == -1 ) { 541 first_rc = rc; 542 } 543 544cleanup:; 545 ldap_memfree( li.li_uri ); 546 li.li_uri = NULL; 547 548 if ( temporary ) { 549 lip->li_uri = NULL; 550 lip->li_bvuri = NULL; 551 (void)ldap_chain_db_close_one( op->o_bd ); 552 (void)ldap_chain_db_destroy_one( op->o_bd, NULL ); 553 } 554 555further_cleanup:; 556 if ( !BER_BVISNULL( &pdn ) ) { 557 op->o_tmpfree( pdn.bv_val, op->o_tmpmemctx ); 558 } 559 op->o_req_dn = save_req_dn; 560 561 if ( !BER_BVISNULL( &ndn ) ) { 562 op->o_tmpfree( ndn.bv_val, op->o_tmpmemctx ); 563 } 564 op->o_req_ndn = save_req_ndn; 565 566 if ( rc == LDAP_SUCCESS && rs2.sr_err == LDAP_SUCCESS ) { 567 *rs = rs2; 568 break; 569 } 570 571 rc = rs2.sr_err; 572 } 573 574#ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR 575 (void)chaining_control_remove( op, &ctrls ); 576#endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */ 577 578 if ( rc != LDAP_SUCCESS && first_rc > 0 ) { 579 rc = first_rc; 580 } 581 582 return rc; 583} 584 585static int 586ldap_chain_search( 587 Operation *op, 588 SlapReply *rs, 589 BerVarray ref, 590 int depth ) 591 592{ 593 slap_overinst *on = (slap_overinst *) op->o_bd->bd_info; 594 ldap_chain_cb_t *lb = (ldap_chain_cb_t *)op->o_callback->sc_private; 595 ldap_chain_t *lc = (ldap_chain_t *)on->on_bi.bi_private; 596 ldapinfo_t li = { 0 }, *lip = NULL; 597 struct berval bvuri[ 2 ] = { { 0 } }; 598 599 struct berval odn = op->o_req_dn, 600 ondn = op->o_req_ndn; 601 slap_response *save_response = op->o_callback->sc_response; 602 Entry *save_entry = rs->sr_entry; 603 slap_mask_t save_flags = rs->sr_flags; 604 605 int rc = LDAP_OTHER, 606 first_rc = -1; 607 608#ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR 609 LDAPControl **ctrls = NULL; 610 611 (void)chaining_control_add( lc, op, &ctrls ); 612#endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */ 613 614 rs->sr_type = REP_SEARCH; 615 616 op->o_callback->sc_response = ldap_chain_cb_search_response; 617 618 /* if we parse the URI then by no means 619 * we can cache stuff or reuse connections, 620 * because in back-ldap there's no caching 621 * based on the URI value, which is supposed 622 * to be set once for all (correct?) */ 623 li.li_bvuri = bvuri; 624 for ( ; !BER_BVISNULL( &ref[0] ); ref++ ) { 625 SlapReply rs2 = { 0 }; 626 LDAPURLDesc *srv; 627 struct berval save_req_dn = op->o_req_dn, 628 save_req_ndn = op->o_req_ndn, 629 dn, 630 pdn = BER_BVNULL, 631 ndn = BER_BVNULL; 632 int temporary = 0; 633 634 /* parse reference and use 635 * proto://[host][:port]/ only */ 636 rc = ldap_url_parse_ext( ref[0].bv_val, &srv, LDAP_PVT_URL_PARSE_NONE ); 637 if ( rc != LDAP_URL_SUCCESS ) { 638 /* try next */ 639 rs->sr_err = LDAP_OTHER; 640 continue; 641 } 642 643 /* normalize DN */ 644 rc = LDAP_INVALID_SYNTAX; 645 if ( srv->lud_dn != NULL ) { 646 ber_str2bv( srv->lud_dn, 0, 0, &dn ); 647 rc = dnPrettyNormal( NULL, &dn, &pdn, &ndn, op->o_tmpmemctx ); 648 if ( rc == LDAP_SUCCESS ) { 649 /* remove DN essentially because later on 650 * ldap_initialize() will parse the URL 651 * as a comma-separated URL list */ 652 srv->lud_dn = ""; 653 srv->lud_scope = LDAP_SCOPE_DEFAULT; 654 li.li_uri = ldap_url_desc2str( srv ); 655 srv->lud_dn = dn.bv_val; 656 } 657 } 658 ldap_free_urldesc( srv ); 659 660 if ( rc != LDAP_SUCCESS ) { 661 /* try next */ 662 rc = LDAP_OTHER; 663 continue; 664 } 665 666 if ( li.li_uri == NULL ) { 667 /* try next */ 668 rc = LDAP_OTHER; 669 goto further_cleanup; 670 } 671 672 op->o_req_dn = pdn; 673 op->o_req_ndn = ndn; 674 675 ber_str2bv( li.li_uri, 0, 0, &li.li_bvuri[ 0 ] ); 676 677 /* Searches for a ldapinfo in the avl tree */ 678 ldap_pvt_thread_mutex_lock( &lc->lc_lai.lai_mutex ); 679 lip = (ldapinfo_t *)avl_find( lc->lc_lai.lai_tree, 680 (caddr_t)&li, ldap_chain_uri_cmp ); 681 ldap_pvt_thread_mutex_unlock( &lc->lc_lai.lai_mutex ); 682 683 if ( lip != NULL ) { 684 op->o_bd->be_private = (void *)lip; 685 686 } else { 687 /* if none is found, create a temporary... */ 688 rc = ldap_chain_db_init_one( op->o_bd ); 689 if ( rc != 0 ) { 690 goto cleanup; 691 } 692 lip = (ldapinfo_t *)op->o_bd->be_private; 693 lip->li_uri = li.li_uri; 694 lip->li_bvuri = bvuri; 695 rc = ldap_chain_db_open_one( op->o_bd ); 696 if ( rc != 0 ) { 697 lip->li_uri = NULL; 698 lip->li_bvuri = NULL; 699 (void)ldap_chain_db_destroy_one( op->o_bd, NULL ); 700 goto cleanup; 701 } 702 703 if ( LDAP_CHAIN_CACHE_URI( lc ) ) { 704 ldap_pvt_thread_mutex_lock( &lc->lc_lai.lai_mutex ); 705 if ( avl_insert( &lc->lc_lai.lai_tree, 706 (caddr_t)lip, ldap_chain_uri_cmp, ldap_chain_uri_dup ) ) 707 { 708 /* someone just inserted another; 709 * don't bother, use this and then 710 * just free it */ 711 temporary = 1; 712 } 713 ldap_pvt_thread_mutex_unlock( &lc->lc_lai.lai_mutex ); 714 715 } else { 716 temporary = 1; 717 } 718 } 719 720 lb->lb_op_f = lback->bi_op_search; 721 lb->lb_depth = depth + 1; 722 723 /* FIXME: should we also copy filter and scope? 724 * according to RFC3296, no */ 725 rc = lback->bi_op_search( op, &rs2 ); 726 if ( first_rc == -1 ) { 727 first_rc = rc; 728 } 729 730cleanup:; 731 ldap_memfree( li.li_uri ); 732 li.li_uri = NULL; 733 734 if ( temporary ) { 735 lip->li_uri = NULL; 736 lip->li_bvuri = NULL; 737 (void)ldap_chain_db_close_one( op->o_bd ); 738 (void)ldap_chain_db_destroy_one( op->o_bd, NULL ); 739 } 740 741further_cleanup:; 742 if ( !BER_BVISNULL( &pdn ) ) { 743 op->o_tmpfree( pdn.bv_val, op->o_tmpmemctx ); 744 } 745 op->o_req_dn = save_req_dn; 746 747 if ( !BER_BVISNULL( &ndn ) ) { 748 op->o_tmpfree( ndn.bv_val, op->o_tmpmemctx ); 749 } 750 op->o_req_ndn = save_req_ndn; 751 752 if ( rc == LDAP_SUCCESS && rs2.sr_err == LDAP_SUCCESS ) { 753 *rs = rs2; 754 break; 755 } 756 757 rc = rs2.sr_err; 758 } 759 760#ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR 761 (void)chaining_control_remove( op, &ctrls ); 762#endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */ 763 764 op->o_req_dn = odn; 765 op->o_req_ndn = ondn; 766 op->o_callback->sc_response = save_response; 767 rs->sr_type = REP_SEARCHREF; 768 rs->sr_entry = save_entry; 769 rs->sr_flags = save_flags; 770 771 if ( rc != LDAP_SUCCESS ) { 772 /* couldn't chase any of the referrals */ 773 if ( first_rc != -1 ) { 774 rc = first_rc; 775 776 } else { 777 rc = SLAP_CB_CONTINUE; 778 } 779 } 780 781 return rc; 782} 783 784static int 785ldap_chain_response( Operation *op, SlapReply *rs ) 786{ 787 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info; 788 ldap_chain_t *lc = (ldap_chain_t *)on->on_bi.bi_private; 789 BackendDB db, *bd = op->o_bd; 790 ldap_chain_cb_t lb = { 0 }; 791 slap_callback *sc = op->o_callback, 792 sc2 = { 0 }; 793 int rc = 0; 794 const char *text = NULL; 795 const char *matched; 796 BerVarray ref; 797 struct berval ndn = op->o_ndn; 798 799 int sr_err = rs->sr_err; 800 slap_reply_t sr_type = rs->sr_type; 801#ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR 802 slap_mask_t chain_mask = 0; 803 ber_len_t chain_shift = 0; 804#endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */ 805 806 if ( rs->sr_err != LDAP_REFERRAL && rs->sr_type != REP_SEARCHREF ) { 807 return SLAP_CB_CONTINUE; 808 } 809 810#ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR 811 if ( rs->sr_err == LDAP_REFERRAL && get_chaining( op ) > SLAP_CONTROL_IGNORED ) { 812 switch ( get_resolveBehavior( op ) ) { 813 case SLAP_CH_RESOLVE_REFERRALS_PREFERRED: 814 case SLAP_CH_RESOLVE_REFERRALS_REQUIRED: 815 return SLAP_CB_CONTINUE; 816 817 default: 818 chain_mask = SLAP_CH_RESOLVE_MASK; 819 chain_shift = SLAP_CH_RESOLVE_SHIFT; 820 break; 821 } 822 823 } else if ( rs->sr_type == REP_SEARCHREF && get_chaining( op ) > SLAP_CONTROL_IGNORED ) { 824 switch ( get_continuationBehavior( op ) ) { 825 case SLAP_CH_CONTINUATION_REFERRALS_PREFERRED: 826 case SLAP_CH_CONTINUATION_REFERRALS_REQUIRED: 827 return SLAP_CB_CONTINUE; 828 829 default: 830 chain_mask = SLAP_CH_CONTINUATION_MASK; 831 chain_shift = SLAP_CH_CONTINUATION_SHIFT; 832 break; 833 } 834 } 835#endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */ 836 837 /* 838 * TODO: add checks on who/when chain operations; e.g.: 839 * a) what identities are authorized 840 * b) what request DN (e.g. only chain requests rooted at <DN>) 841 * c) what referral URIs 842 * d) what protocol scheme (e.g. only ldaps://) 843 * e) what ssf 844 */ 845 846 db = *op->o_bd; 847 SLAP_DBFLAGS( &db ) &= ~SLAP_DBFLAG_MONITORING; 848 op->o_bd = &db; 849 850 text = rs->sr_text; 851 rs->sr_text = NULL; 852 matched = rs->sr_matched; 853 rs->sr_matched = NULL; 854 ref = rs->sr_ref; 855 rs->sr_ref = NULL; 856 857 /* we need this to know if back-ldap returned any result */ 858 lb.lb_lc = lc; 859 sc2.sc_private = &lb; 860 sc2.sc_response = ldap_chain_cb_response; 861 op->o_callback = &sc2; 862 863 /* Chaining can be performed by a privileged user on behalf 864 * of normal users, using the ProxyAuthz control, by exploiting 865 * the identity assertion feature of back-ldap; see idassert-* 866 * directives in slapd-ldap(5). 867 * 868 * FIXME: the idassert-authcDN is one, will it be fine regardless 869 * of the URI we obtain from the referral? 870 */ 871 872 switch ( op->o_tag ) { 873 case LDAP_REQ_BIND: { 874 struct berval rndn = op->o_req_ndn; 875 Connection *conn = op->o_conn; 876 877 /* FIXME: can we really get a referral for binds? */ 878 op->o_req_ndn = slap_empty_bv; 879 op->o_conn = NULL; 880 rc = ldap_chain_op( op, rs, lback->bi_op_bind, ref, 0 ); 881 op->o_req_ndn = rndn; 882 op->o_conn = conn; 883 } 884 break; 885 886 case LDAP_REQ_ADD: 887 rc = ldap_chain_op( op, rs, lback->bi_op_add, ref, 0 ); 888 break; 889 890 case LDAP_REQ_DELETE: 891 rc = ldap_chain_op( op, rs, lback->bi_op_delete, ref, 0 ); 892 break; 893 894 case LDAP_REQ_MODRDN: 895 rc = ldap_chain_op( op, rs, lback->bi_op_modrdn, ref, 0 ); 896 break; 897 898 case LDAP_REQ_MODIFY: 899 rc = ldap_chain_op( op, rs, lback->bi_op_modify, ref, 0 ); 900 break; 901 902 case LDAP_REQ_COMPARE: 903 rc = ldap_chain_op( op, rs, lback->bi_op_compare, ref, 0 ); 904 if ( rs->sr_err == LDAP_COMPARE_TRUE || rs->sr_err == LDAP_COMPARE_FALSE ) { 905 rc = LDAP_SUCCESS; 906 } 907 break; 908 909 case LDAP_REQ_SEARCH: 910 if ( rs->sr_type == REP_SEARCHREF ) { 911 rc = ldap_chain_search( op, rs, ref, 0 ); 912 913 } else { 914 /* we might get here before any database actually 915 * performed a search; in those cases, we need 916 * to check limits, to make sure safe defaults 917 * are in place */ 918 if ( op->ors_limit != NULL || limits_check( op, rs ) == 0 ) { 919 rc = ldap_chain_op( op, rs, lback->bi_op_search, ref, 0 ); 920 921 } else { 922 rc = SLAP_CB_CONTINUE; 923 } 924 } 925 break; 926 927 case LDAP_REQ_EXTENDED: 928 rc = ldap_chain_op( op, rs, lback->bi_extended, ref, 0 ); 929 /* FIXME: ldap_back_extended() by design 930 * doesn't send result; frontend is expected 931 * to send it... */ 932 /* FIXME: what about chaining? */ 933 if ( rc != SLAPD_ABANDON ) { 934 rs->sr_err = rc; 935 send_ldap_extended( op, rs ); 936 rc = LDAP_SUCCESS; 937 } 938 lb.lb_status = LDAP_CH_RES; 939 break; 940 941 default: 942 rc = SLAP_CB_CONTINUE; 943 break; 944 } 945 946 switch ( rc ) { 947 case SLAPD_ABANDON: 948 goto dont_chain; 949 950 case LDAP_SUCCESS: 951 case LDAP_REFERRAL: 952 /* slapd-ldap sent response */ 953 if ( !op->o_abandon && lb.lb_status != LDAP_CH_RES ) { 954 /* FIXME: should we send response? */ 955 Debug( LDAP_DEBUG_ANY, 956 "%s: ldap_chain_response: " 957 "overlay should have sent result.\n", 958 op->o_log_prefix, 0, 0 ); 959 } 960 break; 961 962 default: 963#ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR 964 if ( lb.lb_status == LDAP_CH_ERR && rs->sr_err == LDAP_X_CANNOT_CHAIN ) { 965 goto cannot_chain; 966 } 967 968 switch ( ( get_chainingBehavior( op ) & chain_mask ) >> chain_shift ) { 969 case LDAP_CHAINING_REQUIRED: 970cannot_chain:; 971 op->o_callback = NULL; 972 send_ldap_error( op, rs, LDAP_X_CANNOT_CHAIN, 973 "operation cannot be completed without chaining" ); 974 goto dont_chain; 975 976 default: 977#endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */ 978 if ( LDAP_CHAIN_RETURN_ERR( lc ) ) { 979 rs->sr_err = rc; 980 rs->sr_type = sr_type; 981 982 } else { 983 rc = SLAP_CB_CONTINUE; 984 rs->sr_err = sr_err; 985 rs->sr_type = sr_type; 986 rs->sr_text = text; 987 rs->sr_matched = matched; 988 rs->sr_ref = ref; 989 } 990#ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR 991 break; 992 } 993#endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */ 994 } 995 996 if ( lb.lb_status == LDAP_CH_NONE && rc != SLAPD_ABANDON ) { 997 op->o_callback = NULL; 998 rc = rs->sr_err = slap_map_api2result( rs ); 999 send_ldap_result( op, rs ); 1000 } 1001 1002dont_chain:; 1003 rs->sr_err = sr_err; 1004 rs->sr_type = sr_type; 1005 rs->sr_text = text; 1006 rs->sr_matched = matched; 1007 rs->sr_ref = ref; 1008 op->o_bd = bd; 1009 op->o_callback = sc; 1010 op->o_ndn = ndn; 1011 1012 return rc; 1013} 1014 1015#ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR 1016static int 1017ldap_chain_parse_ctrl( 1018 Operation *op, 1019 SlapReply *rs, 1020 LDAPControl *ctrl ); 1021 1022static int 1023str2chain( const char *s ) 1024{ 1025 if ( strcasecmp( s, "chainingPreferred" ) == 0 ) { 1026 return LDAP_CHAINING_PREFERRED; 1027 1028 } else if ( strcasecmp( s, "chainingRequired" ) == 0 ) { 1029 return LDAP_CHAINING_REQUIRED; 1030 1031 } else if ( strcasecmp( s, "referralsPreferred" ) == 0 ) { 1032 return LDAP_REFERRALS_PREFERRED; 1033 1034 } else if ( strcasecmp( s, "referralsRequired" ) == 0 ) { 1035 return LDAP_REFERRALS_REQUIRED; 1036 } 1037 1038 return -1; 1039} 1040#endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */ 1041 1042/* 1043 * configuration... 1044 */ 1045 1046enum { 1047 CH_CHAINING = 1, 1048 CH_CACHE_URI, 1049 CH_MAX_DEPTH, 1050 CH_RETURN_ERR, 1051 1052 CH_LAST 1053}; 1054 1055static ConfigDriver chain_cf_gen; 1056static ConfigCfAdd chain_cfadd; 1057static ConfigLDAPadd chain_ldadd; 1058 1059static ConfigTable chaincfg[] = { 1060#ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR 1061 { "chain-chaining", "args", 1062 2, 4, 0, ARG_MAGIC|ARG_BERVAL|CH_CHAINING, chain_cf_gen, 1063 "( OLcfgOvAt:3.1 NAME 'olcChainingBehavior' " 1064 "DESC 'Chaining behavior control parameters (draft-sermersheim-ldap-chaining)' " 1065 "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL }, 1066#endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */ 1067 { "chain-cache-uri", "TRUE/FALSE", 1068 2, 2, 0, ARG_MAGIC|ARG_ON_OFF|CH_CACHE_URI, chain_cf_gen, 1069 "( OLcfgOvAt:3.2 NAME 'olcChainCacheURI' " 1070 "DESC 'Enables caching of URIs not present in configuration' " 1071 "SYNTAX OMsBoolean SINGLE-VALUE )", NULL, NULL }, 1072 { "chain-max-depth", "args", 1073 2, 2, 0, ARG_MAGIC|ARG_INT|CH_MAX_DEPTH, chain_cf_gen, 1074 "( OLcfgOvAt:3.3 NAME 'olcChainMaxReferralDepth' " 1075 "DESC 'max referral depth' " 1076 "SYNTAX OMsInteger " 1077 "EQUALITY integerMatch " 1078 "SINGLE-VALUE )", NULL, NULL }, 1079 { "chain-return-error", "TRUE/FALSE", 1080 2, 2, 0, ARG_MAGIC|ARG_ON_OFF|CH_RETURN_ERR, chain_cf_gen, 1081 "( OLcfgOvAt:3.4 NAME 'olcChainReturnError' " 1082 "DESC 'Errors are returned instead of the original referral' " 1083 "SYNTAX OMsBoolean SINGLE-VALUE )", NULL, NULL }, 1084 { NULL, NULL, 0, 0, 0, ARG_IGNORED } 1085}; 1086 1087static ConfigOCs chainocs[] = { 1088 { "( OLcfgOvOc:3.1 " 1089 "NAME 'olcChainConfig' " 1090 "DESC 'Chain configuration' " 1091 "SUP olcOverlayConfig " 1092 "MAY ( " 1093#ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR 1094 "olcChainingBehavior $ " 1095#endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */ 1096 "olcChainCacheURI $ " 1097 "olcChainMaxReferralDepth $ " 1098 "olcChainReturnError " 1099 ") )", 1100 Cft_Overlay, chaincfg, NULL, chain_cfadd }, 1101 { "( OLcfgOvOc:3.2 " 1102 "NAME 'olcChainDatabase' " 1103 "DESC 'Chain remote server configuration' " 1104 "AUXILIARY )", 1105 Cft_Misc, olcDatabaseDummy, chain_ldadd }, 1106 { NULL, 0, NULL } 1107}; 1108 1109static int 1110chain_ldadd( CfEntryInfo *p, Entry *e, ConfigArgs *ca ) 1111{ 1112 slap_overinst *on; 1113 ldap_chain_t *lc; 1114 1115 ldapinfo_t *li; 1116 1117 AttributeDescription *ad = NULL; 1118 Attribute *at; 1119 const char *text; 1120 1121 int rc; 1122 1123 if ( p->ce_type != Cft_Overlay 1124 || !p->ce_bi 1125 || p->ce_bi->bi_cf_ocs != chainocs ) 1126 { 1127 return LDAP_CONSTRAINT_VIOLATION; 1128 } 1129 1130 on = (slap_overinst *)p->ce_bi; 1131 lc = (ldap_chain_t *)on->on_bi.bi_private; 1132 1133 assert( ca->be == NULL ); 1134 ca->be = (BackendDB *)ch_calloc( 1, sizeof( BackendDB ) ); 1135 1136 ca->be->bd_info = (BackendInfo *)on; 1137 1138 rc = slap_str2ad( "olcDbURI", &ad, &text ); 1139 assert( rc == LDAP_SUCCESS ); 1140 1141 at = attr_find( e->e_attrs, ad ); 1142 if ( lc->lc_common_li == NULL && at != NULL ) { 1143 /* FIXME: we should generate an empty default entry 1144 * if none is supplied */ 1145 Debug( LDAP_DEBUG_ANY, "slapd-chain: " 1146 "first underlying database \"%s\" " 1147 "cannot contain attribute \"%s\".\n", 1148 e->e_name.bv_val, ad->ad_cname.bv_val, 0 ); 1149 rc = LDAP_CONSTRAINT_VIOLATION; 1150 goto done; 1151 1152 } else if ( lc->lc_common_li != NULL && at == NULL ) { 1153 /* FIXME: we should generate an empty default entry 1154 * if none is supplied */ 1155 Debug( LDAP_DEBUG_ANY, "slapd-chain: " 1156 "subsequent underlying database \"%s\" " 1157 "must contain attribute \"%s\".\n", 1158 e->e_name.bv_val, ad->ad_cname.bv_val, 0 ); 1159 rc = LDAP_CONSTRAINT_VIOLATION; 1160 goto done; 1161 } 1162 1163 if ( lc->lc_common_li == NULL ) { 1164 rc = ldap_chain_db_init_common( ca->be ); 1165 1166 } else { 1167 rc = ldap_chain_db_init_one( ca->be ); 1168 } 1169 1170 if ( rc != 0 ) { 1171 Debug( LDAP_DEBUG_ANY, "slapd-chain: " 1172 "unable to init %sunderlying database \"%s\".\n", 1173 lc->lc_common_li == NULL ? "common " : "", e->e_name.bv_val, 0 ); 1174 return LDAP_CONSTRAINT_VIOLATION; 1175 } 1176 1177 li = ca->be->be_private; 1178 1179 if ( lc->lc_common_li == NULL ) { 1180 lc->lc_common_li = li; 1181 1182 } else { 1183 li->li_uri = ch_strdup( at->a_vals[ 0 ].bv_val ); 1184 value_add_one( &li->li_bvuri, &at->a_vals[ 0 ] ); 1185 if ( avl_insert( &lc->lc_lai.lai_tree, (caddr_t)li, 1186 ldap_chain_uri_cmp, ldap_chain_uri_dup ) ) 1187 { 1188 Debug( LDAP_DEBUG_ANY, "slapd-chain: " 1189 "database \"%s\" insert failed.\n", 1190 e->e_name.bv_val, 0, 0 ); 1191 rc = LDAP_CONSTRAINT_VIOLATION; 1192 goto done; 1193 } 1194 } 1195 1196 ca->ca_private = on; 1197 1198done:; 1199 if ( rc != LDAP_SUCCESS ) { 1200 (void)ldap_chain_db_destroy_one( ca->be, NULL ); 1201 ch_free( ca->be ); 1202 ca->be = NULL; 1203 } 1204 1205 return rc; 1206} 1207 1208typedef struct ldap_chain_cfadd_apply_t { 1209 Operation *op; 1210 SlapReply *rs; 1211 Entry *p; 1212 ConfigArgs *ca; 1213 int count; 1214} ldap_chain_cfadd_apply_t; 1215 1216static int 1217ldap_chain_cfadd_apply( void *datum, void *arg ) 1218{ 1219 ldapinfo_t *li = (ldapinfo_t *)datum; 1220 ldap_chain_cfadd_apply_t *lca = (ldap_chain_cfadd_apply_t *)arg; 1221 1222 struct berval bv; 1223 1224 /* FIXME: should not hardcode "olcDatabase" here */ 1225 bv.bv_len = snprintf( lca->ca->cr_msg, sizeof( lca->ca->cr_msg ), 1226 "olcDatabase={%d}%s", lca->count, lback->bi_type ); 1227 bv.bv_val = lca->ca->cr_msg; 1228 1229 lca->ca->be->be_private = (void *)li; 1230 config_build_entry( lca->op, lca->rs, lca->p->e_private, lca->ca, 1231 &bv, lback->bi_cf_ocs, &chainocs[1] ); 1232 1233 lca->count++; 1234 1235 return 0; 1236} 1237 1238static int 1239chain_cfadd( Operation *op, SlapReply *rs, Entry *p, ConfigArgs *ca ) 1240{ 1241 CfEntryInfo *pe = p->e_private; 1242 slap_overinst *on = (slap_overinst *)pe->ce_bi; 1243 ldap_chain_t *lc = (ldap_chain_t *)on->on_bi.bi_private; 1244 void *priv = (void *)ca->be->be_private; 1245 1246 if ( lback->bi_cf_ocs ) { 1247 ldap_chain_cfadd_apply_t lca = { 0 }; 1248 1249 lca.op = op; 1250 lca.rs = rs; 1251 lca.p = p; 1252 lca.ca = ca; 1253 lca.count = 0; 1254 1255 (void)ldap_chain_cfadd_apply( (void *)lc->lc_common_li, (void *)&lca ); 1256 1257 (void)avl_apply( lc->lc_lai.lai_tree, ldap_chain_cfadd_apply, 1258 &lca, 1, AVL_INORDER ); 1259 1260 ca->be->be_private = priv; 1261 } 1262 1263 return 0; 1264} 1265 1266#ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR 1267static slap_verbmasks chaining_mode[] = { 1268 { BER_BVC("referralsRequired"), LDAP_REFERRALS_REQUIRED }, 1269 { BER_BVC("referralsPreferred"), LDAP_REFERRALS_PREFERRED }, 1270 { BER_BVC("chainingRequired"), LDAP_CHAINING_REQUIRED }, 1271 { BER_BVC("chainingPreferred"), LDAP_CHAINING_PREFERRED }, 1272 { BER_BVNULL, 0 } 1273}; 1274#endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */ 1275 1276static int 1277chain_cf_gen( ConfigArgs *c ) 1278{ 1279 slap_overinst *on = (slap_overinst *)c->bi; 1280 ldap_chain_t *lc = (ldap_chain_t *)on->on_bi.bi_private; 1281 1282 int rc = 0; 1283 1284 if ( c->op == SLAP_CONFIG_EMIT ) { 1285 switch( c->type ) { 1286#ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR 1287 case CH_CHAINING: { 1288 struct berval resolve = BER_BVNULL, 1289 continuation = BER_BVNULL; 1290 1291 if ( !LDAP_CHAIN_CHAINING( lc ) ) { 1292 return 1; 1293 } 1294 1295 enum_to_verb( chaining_mode, ( ( lc->lc_chaining_ctrlflag & SLAP_CH_RESOLVE_MASK ) >> SLAP_CH_RESOLVE_SHIFT ), &resolve ); 1296 enum_to_verb( chaining_mode, ( ( lc->lc_chaining_ctrlflag & SLAP_CH_CONTINUATION_MASK ) >> SLAP_CH_CONTINUATION_SHIFT ), &continuation ); 1297 1298 c->value_bv.bv_len = STRLENOF( "resolve=" ) + resolve.bv_len 1299 + STRLENOF( " " ) 1300 + STRLENOF( "continuation=" ) + continuation.bv_len; 1301 c->value_bv.bv_val = ch_malloc( c->value_bv.bv_len + 1 ); 1302 snprintf( c->value_bv.bv_val, c->value_bv.bv_len + 1, 1303 "resolve=%s continuation=%s", 1304 resolve.bv_val, continuation.bv_val ); 1305 1306 if ( lc->lc_chaining_ctrl.ldctl_iscritical ) { 1307 c->value_bv.bv_val = ch_realloc( c->value_bv.bv_val, 1308 c->value_bv.bv_len + STRLENOF( " critical" ) + 1 ); 1309 AC_MEMCPY( &c->value_bv.bv_val[ c->value_bv.bv_len ], 1310 " critical", STRLENOF( " critical" ) + 1 ); 1311 c->value_bv.bv_len += STRLENOF( " critical" ); 1312 } 1313 1314 break; 1315 } 1316#endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */ 1317 1318 case CH_CACHE_URI: 1319 c->value_int = LDAP_CHAIN_CACHE_URI( lc ); 1320 break; 1321 1322 case CH_MAX_DEPTH: 1323 c->value_int = lc->lc_max_depth; 1324 break; 1325 1326 case CH_RETURN_ERR: 1327 c->value_int = LDAP_CHAIN_RETURN_ERR( lc ); 1328 break; 1329 1330 default: 1331 assert( 0 ); 1332 rc = 1; 1333 } 1334 return rc; 1335 1336 } else if ( c->op == LDAP_MOD_DELETE ) { 1337 switch( c->type ) { 1338 case CH_CHAINING: 1339 return 1; 1340 1341 case CH_CACHE_URI: 1342 lc->lc_flags &= ~LDAP_CHAIN_F_CACHE_URI; 1343 break; 1344 1345 case CH_MAX_DEPTH: 1346 c->value_int = 0; 1347 break; 1348 1349 case CH_RETURN_ERR: 1350 lc->lc_flags &= ~LDAP_CHAIN_F_RETURN_ERR; 1351 break; 1352 1353 default: 1354 return 1; 1355 } 1356 return rc; 1357 } 1358 1359 switch( c->type ) { 1360 case CH_CHAINING: { 1361#ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR 1362 char **argv = c->argv; 1363 int argc = c->argc; 1364 BerElementBuffer berbuf; 1365 BerElement *ber = (BerElement *)&berbuf; 1366 int resolve = -1, 1367 continuation = -1, 1368 iscritical = 0; 1369 Operation op = { 0 }; 1370 SlapReply rs = { 0 }; 1371 1372 lc->lc_chaining_ctrlflag = 0; 1373 1374 for ( argc--, argv++; argc > 0; argc--, argv++ ) { 1375 if ( strncasecmp( argv[ 0 ], "resolve=", STRLENOF( "resolve=" ) ) == 0 ) { 1376 resolve = str2chain( argv[ 0 ] + STRLENOF( "resolve=" ) ); 1377 if ( resolve == -1 ) { 1378 Debug( LDAP_DEBUG_ANY, "%s: " 1379 "illegal <resolve> value %s " 1380 "in \"chain-chaining>\".\n", 1381 c->log, argv[ 0 ], 0 ); 1382 return 1; 1383 } 1384 1385 } else if ( strncasecmp( argv[ 0 ], "continuation=", STRLENOF( "continuation=" ) ) == 0 ) { 1386 continuation = str2chain( argv[ 0 ] + STRLENOF( "continuation=" ) ); 1387 if ( continuation == -1 ) { 1388 Debug( LDAP_DEBUG_ANY, "%s: " 1389 "illegal <continuation> value %s " 1390 "in \"chain-chaining\".\n", 1391 c->log, argv[ 0 ], 0 ); 1392 return 1; 1393 } 1394 1395 } else if ( strcasecmp( argv[ 0 ], "critical" ) == 0 ) { 1396 iscritical = 1; 1397 1398 } else { 1399 Debug( LDAP_DEBUG_ANY, "%s: " 1400 "unknown option in \"chain-chaining\".\n", 1401 c->log, 0, 0 ); 1402 return 1; 1403 } 1404 } 1405 1406 if ( resolve != -1 || continuation != -1 ) { 1407 int err; 1408 1409 if ( resolve == -1 ) { 1410 /* default */ 1411 resolve = SLAP_CHAINING_DEFAULT; 1412 } 1413 1414 ber_init2( ber, NULL, LBER_USE_DER ); 1415 1416 err = ber_printf( ber, "{e" /* } */, resolve ); 1417 if ( err == -1 ) { 1418 ber_free( ber, 1 ); 1419 Debug( LDAP_DEBUG_ANY, "%s: " 1420 "chaining behavior control encoding error!\n", 1421 c->log, 0, 0 ); 1422 return 1; 1423 } 1424 1425 if ( continuation > -1 ) { 1426 err = ber_printf( ber, "e", continuation ); 1427 if ( err == -1 ) { 1428 ber_free( ber, 1 ); 1429 Debug( LDAP_DEBUG_ANY, "%s: " 1430 "chaining behavior control encoding error!\n", 1431 c->log, 0, 0 ); 1432 return 1; 1433 } 1434 } 1435 1436 err = ber_printf( ber, /* { */ "N}" ); 1437 if ( err == -1 ) { 1438 ber_free( ber, 1 ); 1439 Debug( LDAP_DEBUG_ANY, "%s: " 1440 "chaining behavior control encoding error!\n", 1441 c->log, 0, 0 ); 1442 return 1; 1443 } 1444 1445 if ( ber_flatten2( ber, &lc->lc_chaining_ctrl.ldctl_value, 0 ) == -1 ) { 1446 exit( EXIT_FAILURE ); 1447 } 1448 1449 } else { 1450 BER_BVZERO( &lc->lc_chaining_ctrl.ldctl_value ); 1451 } 1452 1453 lc->lc_chaining_ctrl.ldctl_oid = LDAP_CONTROL_X_CHAINING_BEHAVIOR; 1454 lc->lc_chaining_ctrl.ldctl_iscritical = iscritical; 1455 1456 if ( ldap_chain_parse_ctrl( &op, &rs, &lc->lc_chaining_ctrl ) != LDAP_SUCCESS ) 1457 { 1458 Debug( LDAP_DEBUG_ANY, "%s: " 1459 "unable to parse chaining control%s%s.\n", 1460 c->log, rs.sr_text ? ": " : "", 1461 rs.sr_text ? rs.sr_text : "" ); 1462 return 1; 1463 } 1464 1465 lc->lc_chaining_ctrlflag = op.o_chaining; 1466 1467 lc->lc_flags |= LDAP_CHAIN_F_CHAINING; 1468 1469 rc = 0; 1470#else /* ! LDAP_CONTROL_X_CHAINING_BEHAVIOR */ 1471 Debug( LDAP_DEBUG_ANY, "%s: " 1472 "\"chaining\" control unsupported (ignored).\n", 1473 c->log, 0, 0 ); 1474#endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */ 1475 } break; 1476 1477 case CH_CACHE_URI: 1478 if ( c->value_int ) { 1479 lc->lc_flags |= LDAP_CHAIN_F_CACHE_URI; 1480 } else { 1481 lc->lc_flags &= ~LDAP_CHAIN_F_CACHE_URI; 1482 } 1483 break; 1484 1485 case CH_MAX_DEPTH: 1486 if ( c->value_int < 0 ) { 1487 snprintf( c->cr_msg, sizeof( c->cr_msg ), 1488 "<%s> invalid max referral depth %d", 1489 c->argv[0], c->value_int ); 1490 Debug( LDAP_DEBUG_ANY, "%s: %s.\n", 1491 c->log, c->cr_msg, 0 ); 1492 rc = 1; 1493 break; 1494 } 1495 lc->lc_max_depth = c->value_int; 1496 1497 case CH_RETURN_ERR: 1498 if ( c->value_int ) { 1499 lc->lc_flags |= LDAP_CHAIN_F_RETURN_ERR; 1500 } else { 1501 lc->lc_flags &= ~LDAP_CHAIN_F_RETURN_ERR; 1502 } 1503 break; 1504 1505 default: 1506 assert( 0 ); 1507 return 1; 1508 } 1509 return rc; 1510} 1511 1512static int 1513ldap_chain_db_init( 1514 BackendDB *be, 1515 ConfigReply *cr ) 1516{ 1517 slap_overinst *on = (slap_overinst *)be->bd_info; 1518 ldap_chain_t *lc = NULL; 1519 1520 if ( lback == NULL ) { 1521 lback = backend_info( "ldap" ); 1522 1523 if ( lback == NULL ) { 1524 return 1; 1525 } 1526 } 1527 1528 lc = ch_malloc( sizeof( ldap_chain_t ) ); 1529 if ( lc == NULL ) { 1530 return 1; 1531 } 1532 memset( lc, 0, sizeof( ldap_chain_t ) ); 1533 lc->lc_max_depth = 1; 1534 ldap_pvt_thread_mutex_init( &lc->lc_lai.lai_mutex ); 1535 1536 on->on_bi.bi_private = (void *)lc; 1537 1538 return 0; 1539} 1540 1541static int 1542ldap_chain_db_config( 1543 BackendDB *be, 1544 const char *fname, 1545 int lineno, 1546 int argc, 1547 char **argv ) 1548{ 1549 slap_overinst *on = (slap_overinst *)be->bd_info; 1550 ldap_chain_t *lc = (ldap_chain_t *)on->on_bi.bi_private; 1551 1552 int rc = SLAP_CONF_UNKNOWN; 1553 1554 if ( lc->lc_common_li == NULL ) { 1555 void *be_private = be->be_private; 1556 ldap_chain_db_init_common( be ); 1557 lc->lc_common_li = lc->lc_cfg_li = (ldapinfo_t *)be->be_private; 1558 be->be_private = be_private; 1559 } 1560 1561 /* Something for the chain database? */ 1562 if ( strncasecmp( argv[ 0 ], "chain-", STRLENOF( "chain-" ) ) == 0 ) { 1563 char *save_argv0 = argv[ 0 ]; 1564 BackendInfo *bd_info = be->bd_info; 1565 void *be_private = be->be_private; 1566 ConfigOCs *be_cf_ocs = be->be_cf_ocs; 1567 static char *allowed_argv[] = { 1568 /* special: put URI here, so in the meanwhile 1569 * it detects whether a new URI is being provided */ 1570 "uri", 1571 "nretries", 1572 "timeout", 1573 /* flags */ 1574 "tls", 1575 /* FIXME: maybe rebind-as-user should be allowed 1576 * only within known URIs... */ 1577 "rebind-as-user", 1578 "chase-referrals", 1579 "t-f-support", 1580 "proxy-whoami", 1581 NULL 1582 }; 1583 int which_argv = -1; 1584 1585 argv[ 0 ] += STRLENOF( "chain-" ); 1586 1587 for ( which_argv = 0; allowed_argv[ which_argv ]; which_argv++ ) { 1588 if ( strcasecmp( argv[ 0 ], allowed_argv[ which_argv ] ) == 0 ) { 1589 break; 1590 } 1591 } 1592 1593 if ( allowed_argv[ which_argv ] == NULL ) { 1594 which_argv = -1; 1595 1596 if ( lc->lc_cfg_li == lc->lc_common_li ) { 1597 Debug( LDAP_DEBUG_ANY, "%s: line %d: " 1598 "\"%s\" only allowed within a URI directive.\n.", 1599 fname, lineno, argv[ 0 ] ); 1600 return 1; 1601 } 1602 } 1603 1604 if ( which_argv == 0 ) { 1605 rc = ldap_chain_db_init_one( be ); 1606 if ( rc != 0 ) { 1607 Debug( LDAP_DEBUG_ANY, "%s: line %d: " 1608 "underlying slapd-ldap initialization failed.\n.", 1609 fname, lineno, 0 ); 1610 return 1; 1611 } 1612 lc->lc_cfg_li = be->be_private; 1613 } 1614 1615 /* TODO: add checks on what other slapd-ldap(5) args 1616 * should be put in the template; this is not quite 1617 * harmful, because attributes that shouldn't don't 1618 * get actually used, but the user should at least 1619 * be warned. 1620 */ 1621 1622 be->bd_info = lback; 1623 be->be_private = (void *)lc->lc_cfg_li; 1624 be->be_cf_ocs = lback->bi_cf_ocs; 1625 1626 rc = config_generic_wrapper( be, fname, lineno, argc, argv ); 1627 1628 argv[ 0 ] = save_argv0; 1629 be->be_cf_ocs = be_cf_ocs; 1630 be->be_private = be_private; 1631 be->bd_info = bd_info; 1632 1633 if ( which_argv == 0 ) { 1634private_destroy:; 1635 if ( rc != 0 ) { 1636 BackendDB db = *be; 1637 1638 db.bd_info = lback; 1639 db.be_private = (void *)lc->lc_cfg_li; 1640 ldap_chain_db_destroy_one( &db, NULL ); 1641 lc->lc_cfg_li = NULL; 1642 1643 } else { 1644 if ( lc->lc_cfg_li->li_bvuri == NULL 1645 || BER_BVISNULL( &lc->lc_cfg_li->li_bvuri[ 0 ] ) 1646 || !BER_BVISNULL( &lc->lc_cfg_li->li_bvuri[ 1 ] ) ) 1647 { 1648 Debug( LDAP_DEBUG_ANY, "%s: line %d: " 1649 "no URI list allowed in slapo-chain.\n", 1650 fname, lineno, 0 ); 1651 rc = 1; 1652 goto private_destroy; 1653 } 1654 1655 if ( avl_insert( &lc->lc_lai.lai_tree, 1656 (caddr_t)lc->lc_cfg_li, 1657 ldap_chain_uri_cmp, ldap_chain_uri_dup ) ) 1658 { 1659 Debug( LDAP_DEBUG_ANY, "%s: line %d: " 1660 "duplicate URI in slapo-chain.\n", 1661 fname, lineno, 0 ); 1662 rc = 1; 1663 goto private_destroy; 1664 } 1665 } 1666 } 1667 } 1668 1669 return rc; 1670} 1671 1672enum db_which { 1673 db_open = 0, 1674 db_close, 1675 db_destroy, 1676 1677 db_last 1678}; 1679 1680typedef struct ldap_chain_db_apply_t { 1681 BackendDB *be; 1682 BI_db_func *func; 1683} ldap_chain_db_apply_t; 1684 1685static int 1686ldap_chain_db_apply( void *datum, void *arg ) 1687{ 1688 ldapinfo_t *li = (ldapinfo_t *)datum; 1689 ldap_chain_db_apply_t *lca = (ldap_chain_db_apply_t *)arg; 1690 1691 lca->be->be_private = (void *)li; 1692 1693 return lca->func( lca->be, NULL ); 1694} 1695 1696static int 1697ldap_chain_db_func( 1698 BackendDB *be, 1699 enum db_which which 1700) 1701{ 1702 slap_overinst *on = (slap_overinst *)be->bd_info; 1703 ldap_chain_t *lc = (ldap_chain_t *)on->on_bi.bi_private; 1704 1705 int rc = 0; 1706 1707 if ( lc ) { 1708 BI_db_func *func = (&lback->bi_db_open)[ which ]; 1709 1710 if ( func != NULL && lc->lc_common_li != NULL ) { 1711 BackendDB db = *be; 1712 1713 db.bd_info = lback; 1714 db.be_private = lc->lc_common_li; 1715 1716 rc = func( &db, NULL ); 1717 1718 if ( rc != 0 ) { 1719 return rc; 1720 } 1721 1722 if ( lc->lc_lai.lai_tree != NULL ) { 1723 ldap_chain_db_apply_t lca; 1724 1725 lca.be = &db; 1726 lca.func = func; 1727 1728 rc = avl_apply( lc->lc_lai.lai_tree, 1729 ldap_chain_db_apply, (void *)&lca, 1730 1, AVL_INORDER ) != AVL_NOMORE; 1731 } 1732 } 1733 } 1734 1735 return rc; 1736} 1737 1738static int 1739ldap_chain_db_open( 1740 BackendDB *be, 1741 ConfigReply *cr ) 1742{ 1743 slap_overinst *on = (slap_overinst *) be->bd_info; 1744 ldap_chain_t *lc = (ldap_chain_t *)on->on_bi.bi_private; 1745 slap_mask_t monitoring; 1746 int rc = 0; 1747 1748#ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR 1749 rc = overlay_register_control( be, LDAP_CONTROL_X_CHAINING_BEHAVIOR ); 1750 if ( rc != 0 ) { 1751 return rc; 1752 } 1753#endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */ 1754 1755 if ( lc->lc_common_li == NULL ) { 1756 void *be_private = be->be_private; 1757 ldap_chain_db_init_common( be ); 1758 lc->lc_common_li = lc->lc_cfg_li = (ldapinfo_t *)be->be_private; 1759 be->be_private = be_private; 1760 } 1761 1762 /* filter out and restore monitoring */ 1763 monitoring = ( SLAP_DBFLAGS( be ) & SLAP_DBFLAG_MONITORING ); 1764 SLAP_DBFLAGS( be ) &= ~SLAP_DBFLAG_MONITORING; 1765 rc = ldap_chain_db_func( be, db_open ); 1766 SLAP_DBFLAGS( be ) |= monitoring; 1767 1768 return rc; 1769} 1770 1771static int 1772ldap_chain_db_close( 1773 BackendDB *be, 1774 ConfigReply *cr ) 1775{ 1776 return ldap_chain_db_func( be, db_close ); 1777} 1778 1779static int 1780ldap_chain_db_destroy( 1781 BackendDB *be, 1782 ConfigReply *cr ) 1783{ 1784 slap_overinst *on = (slap_overinst *) be->bd_info; 1785 ldap_chain_t *lc = (ldap_chain_t *)on->on_bi.bi_private; 1786 1787 int rc; 1788 1789 rc = ldap_chain_db_func( be, db_destroy ); 1790 1791 if ( lc ) { 1792 avl_free( lc->lc_lai.lai_tree, NULL ); 1793 ldap_pvt_thread_mutex_destroy( &lc->lc_lai.lai_mutex ); 1794 ch_free( lc ); 1795 } 1796 1797 return rc; 1798} 1799 1800/* 1801 * inits one instance of the slapd-ldap backend, and stores 1802 * the private info in be_private of the arg 1803 */ 1804static int 1805ldap_chain_db_init_common( 1806 BackendDB *be ) 1807{ 1808 BackendInfo *bi = be->bd_info; 1809 ldapinfo_t *li; 1810 int rc; 1811 1812 be->bd_info = lback; 1813 be->be_private = NULL; 1814 rc = lback->bi_db_init( be, NULL ); 1815 if ( rc != 0 ) { 1816 return rc; 1817 } 1818 li = (ldapinfo_t *)be->be_private; 1819 li->li_urllist_f = NULL; 1820 li->li_urllist_p = NULL; 1821 1822 be->bd_info = bi; 1823 1824 return 0; 1825} 1826 1827/* 1828 * inits one instance of the slapd-ldap backend, stores 1829 * the private info in be_private of the arg and fills 1830 * selected fields with data from the template. 1831 * 1832 * NOTE: add checks about the other fields of the template, 1833 * which are ignored and SHOULD NOT be configured by the user. 1834 */ 1835static int 1836ldap_chain_db_init_one( 1837 BackendDB *be ) 1838{ 1839 slap_overinst *on = (slap_overinst *)be->bd_info; 1840 ldap_chain_t *lc = (ldap_chain_t *)on->on_bi.bi_private; 1841 1842 BackendInfo *bi = be->bd_info; 1843 ldapinfo_t *li; 1844 1845 slap_op_t t; 1846 1847 be->bd_info = lback; 1848 be->be_private = NULL; 1849 t = lback->bi_db_init( be, NULL ); 1850 if ( t != 0 ) { 1851 return t; 1852 } 1853 li = (ldapinfo_t *)be->be_private; 1854 li->li_urllist_f = NULL; 1855 li->li_urllist_p = NULL; 1856 1857 /* copy common data */ 1858 li->li_nretries = lc->lc_common_li->li_nretries; 1859 li->li_flags = lc->lc_common_li->li_flags; 1860 li->li_version = lc->lc_common_li->li_version; 1861 for ( t = 0; t < SLAP_OP_LAST; t++ ) { 1862 li->li_timeout[ t ] = lc->lc_common_li->li_timeout[ t ]; 1863 } 1864 be->bd_info = bi; 1865 1866 return 0; 1867} 1868 1869static int 1870ldap_chain_db_open_one( 1871 BackendDB *be ) 1872{ 1873 if ( SLAP_DBMONITORING( be ) ) { 1874 ldapinfo_t *li = (ldapinfo_t *)be->be_private; 1875 1876 if ( li->li_uri == NULL ) { 1877 ber_str2bv( "cn=Common Connections", 0, 1, 1878 &li->li_monitor_info.lmi_rdn ); 1879 1880 } else { 1881 char *ptr; 1882 1883 li->li_monitor_info.lmi_rdn.bv_len 1884 = STRLENOF( "cn=" ) + strlen( li->li_uri ); 1885 ptr = li->li_monitor_info.lmi_rdn.bv_val 1886 = ch_malloc( li->li_monitor_info.lmi_rdn.bv_len + 1 ); 1887 ptr = lutil_strcopy( ptr, "cn=" ); 1888 ptr = lutil_strcopy( ptr, li->li_uri ); 1889 ptr[ 0 ] = '\0'; 1890 } 1891 } 1892 1893 return lback->bi_db_open( be, NULL ); 1894} 1895 1896typedef struct ldap_chain_conn_apply_t { 1897 BackendDB *be; 1898 Connection *conn; 1899} ldap_chain_conn_apply_t; 1900 1901static int 1902ldap_chain_conn_apply( void *datum, void *arg ) 1903{ 1904 ldapinfo_t *li = (ldapinfo_t *)datum; 1905 ldap_chain_conn_apply_t *lca = (ldap_chain_conn_apply_t *)arg; 1906 1907 lca->be->be_private = (void *)li; 1908 1909 return lback->bi_connection_destroy( lca->be, lca->conn ); 1910} 1911 1912static int 1913ldap_chain_connection_destroy( 1914 BackendDB *be, 1915 Connection *conn 1916) 1917{ 1918 slap_overinst *on = (slap_overinst *) be->bd_info; 1919 ldap_chain_t *lc = (ldap_chain_t *)on->on_bi.bi_private; 1920 void *private = be->be_private; 1921 ldap_chain_conn_apply_t lca; 1922 int rc; 1923 1924 be->be_private = NULL; 1925 lca.be = be; 1926 lca.conn = conn; 1927 ldap_pvt_thread_mutex_lock( &lc->lc_lai.lai_mutex ); 1928 rc = avl_apply( lc->lc_lai.lai_tree, ldap_chain_conn_apply, 1929 (void *)&lca, 1, AVL_INORDER ) != AVL_NOMORE; 1930 ldap_pvt_thread_mutex_unlock( &lc->lc_lai.lai_mutex ); 1931 be->be_private = private; 1932 1933 return rc; 1934} 1935 1936#ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR 1937static int 1938ldap_chain_parse_ctrl( 1939 Operation *op, 1940 SlapReply *rs, 1941 LDAPControl *ctrl ) 1942{ 1943 ber_tag_t tag; 1944 BerElement *ber; 1945 ber_int_t mode, 1946 behavior; 1947 1948 if ( get_chaining( op ) != SLAP_CONTROL_NONE ) { 1949 rs->sr_text = "Chaining behavior control specified multiple times"; 1950 return LDAP_PROTOCOL_ERROR; 1951 } 1952 1953 if ( op->o_pagedresults != SLAP_CONTROL_NONE ) { 1954 rs->sr_text = "Chaining behavior control specified with pagedResults control"; 1955 return LDAP_PROTOCOL_ERROR; 1956 } 1957 1958 if ( BER_BVISEMPTY( &ctrl->ldctl_value ) ) { 1959 mode = (SLAP_CH_RESOLVE_DEFAULT|SLAP_CH_CONTINUATION_DEFAULT); 1960 1961 } else { 1962 ber_len_t len; 1963 1964 /* Parse the control value 1965 * ChainingBehavior ::= SEQUENCE { 1966 * resolveBehavior Behavior OPTIONAL, 1967 * continuationBehavior Behavior OPTIONAL } 1968 * 1969 * Behavior :: = ENUMERATED { 1970 * chainingPreferred (0), 1971 * chainingRequired (1), 1972 * referralsPreferred (2), 1973 * referralsRequired (3) } 1974 */ 1975 1976 ber = ber_init( &ctrl->ldctl_value ); 1977 if( ber == NULL ) { 1978 rs->sr_text = "internal error"; 1979 return LDAP_OTHER; 1980 } 1981 1982 tag = ber_scanf( ber, "{e" /* } */, &behavior ); 1983 /* FIXME: since the whole SEQUENCE is optional, 1984 * should we accept no enumerations at all? */ 1985 if ( tag != LBER_ENUMERATED ) { 1986 rs->sr_text = "Chaining behavior control: resolveBehavior decoding error"; 1987 return LDAP_PROTOCOL_ERROR; 1988 } 1989 1990 switch ( behavior ) { 1991 case LDAP_CHAINING_PREFERRED: 1992 mode = SLAP_CH_RESOLVE_CHAINING_PREFERRED; 1993 break; 1994 1995 case LDAP_CHAINING_REQUIRED: 1996 mode = SLAP_CH_RESOLVE_CHAINING_REQUIRED; 1997 break; 1998 1999 case LDAP_REFERRALS_PREFERRED: 2000 mode = SLAP_CH_RESOLVE_REFERRALS_PREFERRED; 2001 break; 2002 2003 case LDAP_REFERRALS_REQUIRED: 2004 mode = SLAP_CH_RESOLVE_REFERRALS_REQUIRED; 2005 break; 2006 2007 default: 2008 rs->sr_text = "Chaining behavior control: unknown resolveBehavior"; 2009 return LDAP_PROTOCOL_ERROR; 2010 } 2011 2012 tag = ber_peek_tag( ber, &len ); 2013 if ( tag == LBER_ENUMERATED ) { 2014 tag = ber_scanf( ber, "e", &behavior ); 2015 if ( tag == LBER_ERROR ) { 2016 rs->sr_text = "Chaining behavior control: continuationBehavior decoding error"; 2017 return LDAP_PROTOCOL_ERROR; 2018 } 2019 } 2020 2021 if ( tag == LBER_DEFAULT ) { 2022 mode |= SLAP_CH_CONTINUATION_DEFAULT; 2023 2024 } else { 2025 switch ( behavior ) { 2026 case LDAP_CHAINING_PREFERRED: 2027 mode |= SLAP_CH_CONTINUATION_CHAINING_PREFERRED; 2028 break; 2029 2030 case LDAP_CHAINING_REQUIRED: 2031 mode |= SLAP_CH_CONTINUATION_CHAINING_REQUIRED; 2032 break; 2033 2034 case LDAP_REFERRALS_PREFERRED: 2035 mode |= SLAP_CH_CONTINUATION_REFERRALS_PREFERRED; 2036 break; 2037 2038 case LDAP_REFERRALS_REQUIRED: 2039 mode |= SLAP_CH_CONTINUATION_REFERRALS_REQUIRED; 2040 break; 2041 2042 default: 2043 rs->sr_text = "Chaining behavior control: unknown continuationBehavior"; 2044 return LDAP_PROTOCOL_ERROR; 2045 } 2046 } 2047 2048 if ( ( ber_scanf( ber, /* { */ "}") ) == LBER_ERROR ) { 2049 rs->sr_text = "Chaining behavior control: decoding error"; 2050 return LDAP_PROTOCOL_ERROR; 2051 } 2052 2053 (void) ber_free( ber, 1 ); 2054 } 2055 2056 op->o_chaining = mode | ( ctrl->ldctl_iscritical 2057 ? SLAP_CONTROL_CRITICAL 2058 : SLAP_CONTROL_NONCRITICAL ); 2059 2060 return LDAP_SUCCESS; 2061} 2062#endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */ 2063 2064int 2065chain_initialize( void ) 2066{ 2067 int rc; 2068 2069 /* Make sure we don't exceed the bits reserved for userland */ 2070 config_check_userland( CH_LAST ); 2071 2072#ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR 2073 rc = register_supported_control( LDAP_CONTROL_X_CHAINING_BEHAVIOR, 2074 /* SLAP_CTRL_GLOBAL| */ SLAP_CTRL_ACCESS|SLAP_CTRL_HIDE, NULL, 2075 ldap_chain_parse_ctrl, &sc_chainingBehavior ); 2076 if ( rc != LDAP_SUCCESS ) { 2077 Debug( LDAP_DEBUG_ANY, "slapd-chain: " 2078 "unable to register chaining behavior control: %d.\n", 2079 rc, 0, 0 ); 2080 return rc; 2081 } 2082#endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */ 2083 2084 ldapchain.on_bi.bi_type = "chain"; 2085 ldapchain.on_bi.bi_db_init = ldap_chain_db_init; 2086 ldapchain.on_bi.bi_db_config = ldap_chain_db_config; 2087 ldapchain.on_bi.bi_db_open = ldap_chain_db_open; 2088 ldapchain.on_bi.bi_db_close = ldap_chain_db_close; 2089 ldapchain.on_bi.bi_db_destroy = ldap_chain_db_destroy; 2090 2091 ldapchain.on_bi.bi_connection_destroy = ldap_chain_connection_destroy; 2092 2093 ldapchain.on_response = ldap_chain_response; 2094 2095 ldapchain.on_bi.bi_cf_ocs = chainocs; 2096 2097 rc = config_register_schema( chaincfg, chainocs ); 2098 if ( rc ) { 2099 return rc; 2100 } 2101 2102 return overlay_register( &ldapchain ); 2103} 2104 2105