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