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