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