1 1.3 christos /* $NetBSD: conn.c,v 1.4 2025/09/05 21:16:28 christos Exp $ */ 2 1.2 christos 3 1.2 christos /* $OpenLDAP$ */ 4 1.1 lukem /* This work is part of OpenLDAP Software <http://www.openldap.org/>. 5 1.1 lukem * 6 1.4 christos * Copyright 1999-2024 The OpenLDAP Foundation. 7 1.1 lukem * Portions Copyright 2001-2003 Pierangelo Masarati. 8 1.1 lukem * Portions Copyright 1999-2003 Howard Chu. 9 1.1 lukem * All rights reserved. 10 1.1 lukem * 11 1.1 lukem * Redistribution and use in source and binary forms, with or without 12 1.1 lukem * modification, are permitted only as authorized by the OpenLDAP 13 1.1 lukem * Public License. 14 1.1 lukem * 15 1.1 lukem * A copy of this license is available in the file LICENSE in the 16 1.1 lukem * top-level directory of the distribution or, alternatively, at 17 1.1 lukem * <http://www.OpenLDAP.org/license.html>. 18 1.1 lukem */ 19 1.1 lukem /* ACKNOWLEDGEMENTS: 20 1.1 lukem * This work was initially developed by the Howard Chu for inclusion 21 1.1 lukem * in OpenLDAP Software and subsequently enhanced by Pierangelo 22 1.1 lukem * Masarati. 23 1.1 lukem */ 24 1.1 lukem 25 1.2 christos #include <sys/cdefs.h> 26 1.3 christos __RCSID("$NetBSD: conn.c,v 1.4 2025/09/05 21:16:28 christos Exp $"); 27 1.2 christos 28 1.1 lukem #include "portable.h" 29 1.1 lukem 30 1.1 lukem #include <stdio.h> 31 1.1 lukem 32 1.1 lukem #include <ac/errno.h> 33 1.1 lukem #include <ac/socket.h> 34 1.1 lukem #include <ac/string.h> 35 1.1 lukem 36 1.1 lukem 37 1.1 lukem #define AVL_INTERNAL 38 1.1 lukem #include "slap.h" 39 1.1 lukem #include "../back-ldap/back-ldap.h" 40 1.1 lukem #include "back-meta.h" 41 1.1 lukem 42 1.1 lukem /* 43 1.1 lukem * meta_back_conndn_cmp 44 1.1 lukem * 45 1.1 lukem * compares two struct metaconn based on the value of the conn pointer 46 1.1 lukem * and of the local DN; used by avl stuff 47 1.1 lukem */ 48 1.1 lukem int 49 1.1 lukem meta_back_conndn_cmp( 50 1.1 lukem const void *c1, 51 1.1 lukem const void *c2 ) 52 1.1 lukem { 53 1.1 lukem metaconn_t *mc1 = ( metaconn_t * )c1; 54 1.1 lukem metaconn_t *mc2 = ( metaconn_t * )c2; 55 1.1 lukem int rc; 56 1.1 lukem 57 1.1 lukem /* If local DNs don't match, it is definitely not a match */ 58 1.1 lukem /* For shared sessions, conn is NULL. Only explicitly 59 1.1 lukem * bound sessions will have non-NULL conn. 60 1.1 lukem */ 61 1.1 lukem rc = SLAP_PTRCMP( mc1->mc_conn, mc2->mc_conn ); 62 1.1 lukem if ( rc == 0 ) { 63 1.1 lukem rc = ber_bvcmp( &mc1->mc_local_ndn, &mc2->mc_local_ndn ); 64 1.1 lukem } 65 1.1 lukem 66 1.1 lukem return rc; 67 1.1 lukem } 68 1.1 lukem 69 1.1 lukem /* 70 1.1 lukem * meta_back_conndnmc_cmp 71 1.1 lukem * 72 1.1 lukem * compares two struct metaconn based on the value of the conn pointer, 73 1.1 lukem * the local DN and the struct pointer; used by avl stuff 74 1.1 lukem */ 75 1.1 lukem static int 76 1.1 lukem meta_back_conndnmc_cmp( 77 1.1 lukem const void *c1, 78 1.1 lukem const void *c2 ) 79 1.1 lukem { 80 1.1 lukem metaconn_t *mc1 = ( metaconn_t * )c1; 81 1.1 lukem metaconn_t *mc2 = ( metaconn_t * )c2; 82 1.1 lukem int rc; 83 1.1 lukem 84 1.1 lukem /* If local DNs don't match, it is definitely not a match */ 85 1.1 lukem /* For shared sessions, conn is NULL. Only explicitly 86 1.1 lukem * bound sessions will have non-NULL conn. 87 1.1 lukem */ 88 1.1 lukem rc = SLAP_PTRCMP( mc1->mc_conn, mc2->mc_conn ); 89 1.1 lukem if ( rc == 0 ) { 90 1.1 lukem rc = ber_bvcmp( &mc1->mc_local_ndn, &mc2->mc_local_ndn ); 91 1.1 lukem if ( rc == 0 ) { 92 1.1 lukem rc = SLAP_PTRCMP( mc1, mc2 ); 93 1.1 lukem } 94 1.1 lukem } 95 1.1 lukem 96 1.1 lukem return rc; 97 1.1 lukem } 98 1.1 lukem 99 1.1 lukem /* 100 1.1 lukem * meta_back_conn_cmp 101 1.1 lukem * 102 1.1 lukem * compares two struct metaconn based on the value of the conn pointer; 103 1.1 lukem * used by avl stuff 104 1.1 lukem */ 105 1.1 lukem int 106 1.1 lukem meta_back_conn_cmp( 107 1.1 lukem const void *c1, 108 1.1 lukem const void *c2 ) 109 1.1 lukem { 110 1.1 lukem metaconn_t *mc1 = ( metaconn_t * )c1; 111 1.1 lukem metaconn_t *mc2 = ( metaconn_t * )c2; 112 1.1 lukem 113 1.1 lukem /* For shared sessions, conn is NULL. Only explicitly 114 1.1 lukem * bound sessions will have non-NULL conn. 115 1.1 lukem */ 116 1.1 lukem return SLAP_PTRCMP( mc1->mc_conn, mc2->mc_conn ); 117 1.1 lukem } 118 1.1 lukem 119 1.1 lukem /* 120 1.1 lukem * meta_back_conndn_dup 121 1.1 lukem * 122 1.1 lukem * returns -1 in case a duplicate struct metaconn has been inserted; 123 1.1 lukem * used by avl stuff 124 1.1 lukem */ 125 1.1 lukem int 126 1.1 lukem meta_back_conndn_dup( 127 1.1 lukem void *c1, 128 1.1 lukem void *c2 ) 129 1.1 lukem { 130 1.1 lukem metaconn_t *mc1 = ( metaconn_t * )c1; 131 1.1 lukem metaconn_t *mc2 = ( metaconn_t * )c2; 132 1.1 lukem 133 1.1 lukem /* Cannot have more than one shared session with same DN */ 134 1.1 lukem if ( mc1->mc_conn == mc2->mc_conn && 135 1.1 lukem dn_match( &mc1->mc_local_ndn, &mc2->mc_local_ndn ) ) 136 1.1 lukem { 137 1.1 lukem return -1; 138 1.1 lukem } 139 1.1 lukem 140 1.1 lukem return 0; 141 1.1 lukem } 142 1.1 lukem 143 1.1 lukem /* 144 1.1 lukem * Debug stuff (got it from libavl) 145 1.1 lukem */ 146 1.1 lukem #if META_BACK_PRINT_CONNTREE > 0 147 1.1 lukem static void 148 1.1 lukem meta_back_print( metaconn_t *mc, char *avlstr ) 149 1.1 lukem { 150 1.1 lukem int i; 151 1.1 lukem 152 1.1 lukem fputs( "targets=[", stderr ); 153 1.1 lukem for ( i = 0; i < mc->mc_info->mi_ntargets; i++ ) { 154 1.1 lukem fputc( mc->mc_conns[ i ].msc_ld ? '*' : 'o', stderr); 155 1.1 lukem } 156 1.1 lukem fputc( ']', stderr ); 157 1.1 lukem 158 1.1 lukem fprintf( stderr, " mc=%p local=\"%s\" conn=%p refcnt=%d%s %s\n", 159 1.1 lukem (void *)mc, 160 1.1 lukem mc->mc_local_ndn.bv_val ? mc->mc_local_ndn.bv_val : "", 161 1.1 lukem (void *)mc->mc_conn, 162 1.1 lukem mc->mc_refcnt, 163 1.1 lukem LDAP_BACK_CONN_TAINTED( mc ) ? " tainted" : "", 164 1.1 lukem avlstr ); 165 1.1 lukem } 166 1.1 lukem 167 1.1 lukem static void 168 1.3 christos meta_back_ravl_print( TAvlnode *root, int depth ) 169 1.1 lukem { 170 1.1 lukem int i; 171 1.1 lukem 172 1.1 lukem if ( root == 0 ) { 173 1.1 lukem return; 174 1.1 lukem } 175 1.1 lukem 176 1.1 lukem meta_back_ravl_print( root->avl_right, depth + 1 ); 177 1.1 lukem 178 1.1 lukem for ( i = 0; i < depth; i++ ) { 179 1.1 lukem fprintf( stderr, "-" ); 180 1.1 lukem } 181 1.1 lukem fputc( ' ', stderr ); 182 1.1 lukem 183 1.1 lukem meta_back_print( (metaconn_t *)root->avl_data, 184 1.1 lukem avl_bf2str( root->avl_bf ) ); 185 1.1 lukem 186 1.1 lukem meta_back_ravl_print( root->avl_left, depth + 1 ); 187 1.1 lukem } 188 1.1 lukem 189 1.1 lukem /* NOTE: duplicate from back-ldap/bind.c */ 190 1.1 lukem static char* priv2str[] = { 191 1.1 lukem "privileged", 192 1.1 lukem "privileged/TLS", 193 1.1 lukem "anonymous", 194 1.1 lukem "anonymous/TLS", 195 1.1 lukem "bind", 196 1.1 lukem "bind/TLS", 197 1.1 lukem NULL 198 1.1 lukem }; 199 1.1 lukem 200 1.1 lukem void 201 1.1 lukem meta_back_print_conntree( metainfo_t *mi, char *msg ) 202 1.1 lukem { 203 1.1 lukem int c; 204 1.1 lukem 205 1.1 lukem fprintf( stderr, "========> %s\n", msg ); 206 1.1 lukem 207 1.1 lukem for ( c = LDAP_BACK_PCONN_FIRST; c < LDAP_BACK_PCONN_LAST; c++ ) { 208 1.1 lukem int i = 0; 209 1.1 lukem metaconn_t *mc; 210 1.1 lukem 211 1.1 lukem fprintf( stderr, " %s[%d]\n", priv2str[ c ], mi->mi_conn_priv[ c ].mic_num ); 212 1.1 lukem 213 1.1 lukem LDAP_TAILQ_FOREACH( mc, &mi->mi_conn_priv[ c ].mic_priv, mc_q ) 214 1.1 lukem { 215 1.1 lukem fprintf( stderr, " [%d] ", i ); 216 1.1 lukem meta_back_print( mc, "" ); 217 1.1 lukem i++; 218 1.1 lukem } 219 1.1 lukem } 220 1.1 lukem 221 1.1 lukem if ( mi->mi_conninfo.lai_tree == NULL ) { 222 1.1 lukem fprintf( stderr, "\t(empty)\n" ); 223 1.1 lukem 224 1.1 lukem } else { 225 1.1 lukem meta_back_ravl_print( mi->mi_conninfo.lai_tree, 0 ); 226 1.1 lukem } 227 1.1 lukem 228 1.1 lukem fprintf( stderr, "<======== %s\n", msg ); 229 1.1 lukem } 230 1.1 lukem #endif /* META_BACK_PRINT_CONNTREE */ 231 1.1 lukem /* 232 1.1 lukem * End of debug stuff 233 1.1 lukem */ 234 1.1 lukem 235 1.1 lukem /* 236 1.1 lukem * metaconn_alloc 237 1.1 lukem * 238 1.1 lukem * Allocates a connection structure, making room for all the referenced targets 239 1.1 lukem */ 240 1.1 lukem static metaconn_t * 241 1.1 lukem metaconn_alloc( 242 1.1 lukem Operation *op ) 243 1.1 lukem { 244 1.1 lukem metainfo_t *mi = ( metainfo_t * )op->o_bd->be_private; 245 1.1 lukem metaconn_t *mc; 246 1.1 lukem int ntargets = mi->mi_ntargets; 247 1.1 lukem 248 1.1 lukem assert( ntargets > 0 ); 249 1.1 lukem 250 1.1 lukem /* malloc all in one */ 251 1.1 lukem mc = ( metaconn_t * )ch_calloc( 1, sizeof( metaconn_t ) 252 1.1 lukem + sizeof( metasingleconn_t ) * ( ntargets - 1 ) ); 253 1.1 lukem if ( mc == NULL ) { 254 1.1 lukem return NULL; 255 1.1 lukem } 256 1.1 lukem 257 1.1 lukem mc->mc_info = mi; 258 1.1 lukem 259 1.1 lukem mc->mc_authz_target = META_BOUND_NONE; 260 1.1 lukem mc->mc_refcnt = 1; 261 1.1 lukem 262 1.1 lukem return mc; 263 1.1 lukem } 264 1.1 lukem 265 1.1 lukem /* 266 1.1 lukem * meta_back_init_one_conn 267 1.1 lukem * 268 1.1 lukem * Initializes one connection 269 1.1 lukem */ 270 1.1 lukem int 271 1.1 lukem meta_back_init_one_conn( 272 1.1 lukem Operation *op, 273 1.1 lukem SlapReply *rs, 274 1.1 lukem metaconn_t *mc, 275 1.1 lukem int candidate, 276 1.1 lukem int ispriv, 277 1.1 lukem ldap_back_send_t sendok, 278 1.1 lukem int dolock ) 279 1.1 lukem { 280 1.1 lukem metainfo_t *mi = ( metainfo_t * )op->o_bd->be_private; 281 1.1 lukem metatarget_t *mt = mi->mi_targets[ candidate ]; 282 1.1 lukem metasingleconn_t *msc = &mc->mc_conns[ candidate ]; 283 1.1 lukem int version; 284 1.1 lukem dncookie dc; 285 1.1 lukem int isauthz = ( candidate == mc->mc_authz_target ); 286 1.1 lukem int do_return = 0; 287 1.1 lukem #ifdef HAVE_TLS 288 1.1 lukem int is_ldaps = 0; 289 1.2 christos int do_start_tls = 0; 290 1.1 lukem #endif /* HAVE_TLS */ 291 1.1 lukem 292 1.1 lukem /* if the server is quarantined, and 293 1.1 lukem * - the current interval did not expire yet, or 294 1.1 lukem * - no more retries should occur, 295 1.1 lukem * don't return the connection */ 296 1.1 lukem if ( mt->mt_isquarantined ) { 297 1.1 lukem slap_retry_info_t *ri = &mt->mt_quarantine; 298 1.2 christos int dont_retry = 0; 299 1.1 lukem 300 1.1 lukem if ( mt->mt_quarantine.ri_interval ) { 301 1.1 lukem ldap_pvt_thread_mutex_lock( &mt->mt_quarantine_mutex ); 302 1.2 christos dont_retry = ( mt->mt_isquarantined > LDAP_BACK_FQ_NO ); 303 1.2 christos if ( dont_retry ) { 304 1.1 lukem dont_retry = ( ri->ri_num[ ri->ri_idx ] == SLAP_RETRYNUM_TAIL 305 1.1 lukem || slap_get_time() < ri->ri_last + ri->ri_interval[ ri->ri_idx ] ); 306 1.1 lukem if ( !dont_retry ) { 307 1.3 christos Debug(LDAP_DEBUG_ANY, 308 1.3 christos "%s meta_back_init_one_conn[%d]: quarantine " "retry block #%d try #%d.\n", 309 1.3 christos op->o_log_prefix, 310 1.3 christos candidate, ri->ri_idx, 311 1.3 christos ri->ri_count ); 312 1.2 christos 313 1.2 christos mt->mt_isquarantined = LDAP_BACK_FQ_RETRYING; 314 1.1 lukem } 315 1.1 lukem 316 1.1 lukem } 317 1.1 lukem ldap_pvt_thread_mutex_unlock( &mt->mt_quarantine_mutex ); 318 1.1 lukem } 319 1.1 lukem 320 1.1 lukem if ( dont_retry ) { 321 1.1 lukem rs->sr_err = LDAP_UNAVAILABLE; 322 1.1 lukem if ( op->o_conn && ( sendok & LDAP_BACK_SENDERR ) ) { 323 1.1 lukem rs->sr_text = "Target is quarantined"; 324 1.1 lukem send_ldap_result( op, rs ); 325 1.1 lukem } 326 1.1 lukem return rs->sr_err; 327 1.1 lukem } 328 1.1 lukem } 329 1.1 lukem 330 1.1 lukem retry_lock:; 331 1.1 lukem if ( dolock ) { 332 1.1 lukem ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex ); 333 1.1 lukem } 334 1.1 lukem 335 1.1 lukem /* 336 1.1 lukem * Already init'ed 337 1.1 lukem */ 338 1.1 lukem if ( LDAP_BACK_CONN_ISBOUND( msc ) 339 1.1 lukem || LDAP_BACK_CONN_ISANON( msc ) ) 340 1.1 lukem { 341 1.1 lukem assert( msc->msc_ld != NULL ); 342 1.1 lukem rs->sr_err = LDAP_SUCCESS; 343 1.1 lukem do_return = 1; 344 1.1 lukem 345 1.1 lukem } else if ( META_BACK_CONN_CREATING( msc ) 346 1.1 lukem || LDAP_BACK_CONN_BINDING( msc ) ) 347 1.1 lukem { 348 1.1 lukem if ( !LDAP_BACK_USE_TEMPORARIES( mi ) ) { 349 1.1 lukem if ( dolock ) { 350 1.1 lukem ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex ); 351 1.1 lukem } 352 1.1 lukem 353 1.1 lukem ldap_pvt_thread_yield(); 354 1.1 lukem goto retry_lock; 355 1.1 lukem } 356 1.1 lukem 357 1.1 lukem /* sounds more appropriate */ 358 1.1 lukem rs->sr_err = LDAP_BUSY; 359 1.1 lukem rs->sr_text = "No connections to target are available"; 360 1.1 lukem do_return = 1; 361 1.1 lukem 362 1.1 lukem } else if ( META_BACK_CONN_INITED( msc ) ) { 363 1.1 lukem assert( msc->msc_ld != NULL ); 364 1.1 lukem rs->sr_err = LDAP_SUCCESS; 365 1.1 lukem do_return = 1; 366 1.1 lukem 367 1.1 lukem } else { 368 1.1 lukem /* 369 1.1 lukem * creating... 370 1.1 lukem */ 371 1.1 lukem META_BACK_CONN_CREATING_SET( msc ); 372 1.1 lukem } 373 1.1 lukem 374 1.1 lukem if ( dolock ) { 375 1.1 lukem ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex ); 376 1.1 lukem } 377 1.1 lukem 378 1.1 lukem if ( do_return ) { 379 1.1 lukem if ( rs->sr_err != LDAP_SUCCESS 380 1.1 lukem && op->o_conn 381 1.1 lukem && ( sendok & LDAP_BACK_SENDERR ) ) 382 1.1 lukem { 383 1.1 lukem send_ldap_result( op, rs ); 384 1.1 lukem } 385 1.1 lukem 386 1.1 lukem return rs->sr_err; 387 1.1 lukem } 388 1.1 lukem 389 1.1 lukem assert( msc->msc_ld == NULL ); 390 1.1 lukem 391 1.1 lukem /* 392 1.1 lukem * Attempts to initialize the connection to the target ds 393 1.1 lukem */ 394 1.1 lukem ldap_pvt_thread_mutex_lock( &mt->mt_uri_mutex ); 395 1.1 lukem rs->sr_err = ldap_initialize( &msc->msc_ld, mt->mt_uri ); 396 1.1 lukem #ifdef HAVE_TLS 397 1.1 lukem is_ldaps = ldap_is_ldaps_url( mt->mt_uri ); 398 1.1 lukem #endif /* HAVE_TLS */ 399 1.1 lukem ldap_pvt_thread_mutex_unlock( &mt->mt_uri_mutex ); 400 1.1 lukem if ( rs->sr_err != LDAP_SUCCESS ) { 401 1.1 lukem goto error_return; 402 1.1 lukem } 403 1.1 lukem 404 1.1 lukem /* 405 1.1 lukem * Set LDAP version. This will always succeed: If the client 406 1.1 lukem * bound with a particular version, then so can we. 407 1.1 lukem */ 408 1.1 lukem if ( mt->mt_version != 0 ) { 409 1.1 lukem version = mt->mt_version; 410 1.1 lukem 411 1.1 lukem } else if ( op->o_conn->c_protocol != 0 ) { 412 1.1 lukem version = op->o_conn->c_protocol; 413 1.1 lukem 414 1.1 lukem } else { 415 1.1 lukem version = LDAP_VERSION3; 416 1.1 lukem } 417 1.1 lukem ldap_set_option( msc->msc_ld, LDAP_OPT_PROTOCOL_VERSION, &version ); 418 1.1 lukem ldap_set_urllist_proc( msc->msc_ld, mt->mt_urllist_f, mt->mt_urllist_p ); 419 1.1 lukem 420 1.1 lukem /* automatically chase referrals ("chase-referrals [{yes|no}]" statement) */ 421 1.1 lukem ldap_set_option( msc->msc_ld, LDAP_OPT_REFERRALS, 422 1.2 christos META_BACK_TGT_CHASE_REFERRALS( mt ) ? LDAP_OPT_ON : LDAP_OPT_OFF ); 423 1.2 christos 424 1.2 christos slap_client_keepalive(msc->msc_ld, &mt->mt_tls.sb_keepalive); 425 1.1 lukem 426 1.3 christos if ( mt->mt_tls.sb_tcp_user_timeout > 0 ) { 427 1.3 christos ldap_set_option( msc->msc_ld, LDAP_OPT_TCP_USER_TIMEOUT, 428 1.3 christos &mt->mt_tls.sb_tcp_user_timeout ); 429 1.3 christos } 430 1.3 christos 431 1.3 christos 432 1.3 christos 433 1.1 lukem #ifdef HAVE_TLS 434 1.2 christos { 435 1.2 christos slap_bindconf *sb = NULL; 436 1.2 christos 437 1.2 christos if ( ispriv ) { 438 1.2 christos sb = &mt->mt_idassert.si_bc; 439 1.2 christos } else { 440 1.2 christos sb = &mt->mt_tls; 441 1.2 christos } 442 1.2 christos 443 1.3 christos bindconf_tls_set( sb, msc->msc_ld ); 444 1.2 christos 445 1.2 christos if ( !is_ldaps ) { 446 1.3 christos if ( META_BACK_TGT_USE_TLS( mt ) 447 1.2 christos || ( op->o_conn->c_is_tls && META_BACK_TGT_PROPAGATE_TLS( mt ) ) ) 448 1.2 christos { 449 1.2 christos do_start_tls = 1; 450 1.2 christos } 451 1.2 christos } 452 1.2 christos } 453 1.2 christos 454 1.1 lukem /* start TLS ("tls [try-]{start|propagate}" statement) */ 455 1.2 christos if ( do_start_tls ) { 456 1.1 lukem #ifdef SLAP_STARTTLS_ASYNCHRONOUS 457 1.1 lukem /* 458 1.1 lukem * use asynchronous StartTLS; in case, chase referral 459 1.1 lukem * FIXME: OpenLDAP does not return referral on StartTLS yet 460 1.1 lukem */ 461 1.1 lukem int msgid; 462 1.1 lukem 463 1.1 lukem rs->sr_err = ldap_start_tls( msc->msc_ld, NULL, NULL, &msgid ); 464 1.1 lukem if ( rs->sr_err == LDAP_SUCCESS ) { 465 1.1 lukem LDAPMessage *res = NULL; 466 1.1 lukem int rc, nretries = mt->mt_nretries; 467 1.1 lukem struct timeval tv; 468 1.1 lukem 469 1.1 lukem LDAP_BACK_TV_SET( &tv ); 470 1.1 lukem 471 1.1 lukem retry:; 472 1.1 lukem rc = ldap_result( msc->msc_ld, msgid, LDAP_MSG_ALL, &tv, &res ); 473 1.1 lukem switch ( rc ) { 474 1.1 lukem case -1: 475 1.2 christos rs->sr_err = LDAP_UNAVAILABLE; 476 1.2 christos rs->sr_text = "Remote server down"; 477 1.1 lukem break; 478 1.1 lukem 479 1.1 lukem case 0: 480 1.1 lukem if ( nretries != 0 ) { 481 1.1 lukem if ( nretries > 0 ) { 482 1.1 lukem nretries--; 483 1.1 lukem } 484 1.1 lukem LDAP_BACK_TV_SET( &tv ); 485 1.1 lukem goto retry; 486 1.1 lukem } 487 1.1 lukem rs->sr_err = LDAP_OTHER; 488 1.2 christos rs->sr_text = "Timeout, no more retries"; 489 1.1 lukem break; 490 1.1 lukem 491 1.1 lukem default: 492 1.1 lukem /* only touch when activity actually took place... */ 493 1.1 lukem if ( mi->mi_idle_timeout != 0 && msc->msc_time < op->o_time ) { 494 1.1 lukem msc->msc_time = op->o_time; 495 1.1 lukem } 496 1.1 lukem break; 497 1.1 lukem } 498 1.1 lukem 499 1.1 lukem if ( rc == LDAP_RES_EXTENDED ) { 500 1.1 lukem struct berval *data = NULL; 501 1.1 lukem 502 1.1 lukem /* NOTE: right now, data is unused, so don't get it */ 503 1.1 lukem rs->sr_err = ldap_parse_extended_result( msc->msc_ld, 504 1.1 lukem res, NULL, NULL /* &data */ , 0 ); 505 1.1 lukem if ( rs->sr_err == LDAP_SUCCESS ) { 506 1.1 lukem int err; 507 1.1 lukem 508 1.1 lukem /* FIXME: matched? referrals? response controls? */ 509 1.1 lukem rs->sr_err = ldap_parse_result( msc->msc_ld, 510 1.1 lukem res, &err, NULL, NULL, NULL, NULL, 1 ); 511 1.1 lukem res = NULL; 512 1.1 lukem 513 1.1 lukem if ( rs->sr_err == LDAP_SUCCESS ) { 514 1.1 lukem rs->sr_err = err; 515 1.1 lukem } 516 1.2 christos rs->sr_err = slap_map_api2result( rs ); 517 1.1 lukem 518 1.1 lukem /* FIXME: in case a referral 519 1.1 lukem * is returned, should we try 520 1.1 lukem * using it instead of the 521 1.1 lukem * configured URI? */ 522 1.1 lukem if ( rs->sr_err == LDAP_SUCCESS ) { 523 1.3 christos rs->sr_err = ldap_install_tls( msc->msc_ld ); 524 1.1 lukem 525 1.1 lukem } else if ( rs->sr_err == LDAP_REFERRAL ) { 526 1.1 lukem /* FIXME: LDAP_OPERATIONS_ERROR? */ 527 1.1 lukem rs->sr_err = LDAP_OTHER; 528 1.1 lukem rs->sr_text = "Unwilling to chase referral " 529 1.1 lukem "returned by Start TLS exop"; 530 1.1 lukem } 531 1.1 lukem 532 1.1 lukem if ( data ) { 533 1.1 lukem ber_bvfree( data ); 534 1.1 lukem } 535 1.1 lukem } 536 1.1 lukem 537 1.1 lukem } else { 538 1.1 lukem rs->sr_err = LDAP_OTHER; 539 1.2 christos rs->sr_text = "Unknown response to StartTLS request :" 540 1.2 christos " an ExtendedResponse is expected"; 541 1.1 lukem } 542 1.1 lukem 543 1.1 lukem if ( res != NULL ) { 544 1.1 lukem ldap_msgfree( res ); 545 1.1 lukem } 546 1.1 lukem } 547 1.1 lukem #else /* ! SLAP_STARTTLS_ASYNCHRONOUS */ 548 1.1 lukem /* 549 1.1 lukem * use synchronous StartTLS 550 1.1 lukem */ 551 1.1 lukem rs->sr_err = ldap_start_tls_s( msc->msc_ld, NULL, NULL ); 552 1.1 lukem #endif /* ! SLAP_STARTTLS_ASYNCHRONOUS */ 553 1.1 lukem 554 1.1 lukem /* if StartTLS is requested, only attempt it if the URL 555 1.1 lukem * is not "ldaps://"; this may occur not only in case 556 1.1 lukem * of misconfiguration, but also when used in the chain 557 1.1 lukem * overlay, where the "uri" can be parsed out of a referral */ 558 1.1 lukem if ( rs->sr_err == LDAP_SERVER_DOWN 559 1.1 lukem || ( rs->sr_err != LDAP_SUCCESS 560 1.2 christos && META_BACK_TGT_TLS_CRITICAL( mt ) ) ) 561 1.1 lukem { 562 1.1 lukem 563 1.1 lukem #ifdef DEBUG_205 564 1.1 lukem Debug( LDAP_DEBUG_ANY, 565 1.1 lukem "### %s meta_back_init_one_conn(TLS) " 566 1.1 lukem "ldap_unbind_ext[%d] ld=%p\n", 567 1.1 lukem op->o_log_prefix, candidate, 568 1.1 lukem (void *)msc->msc_ld ); 569 1.1 lukem #endif /* DEBUG_205 */ 570 1.1 lukem 571 1.1 lukem /* need to trash a failed Start TLS */ 572 1.1 lukem meta_clear_one_candidate( op, mc, candidate ); 573 1.1 lukem goto error_return; 574 1.1 lukem } 575 1.1 lukem } 576 1.1 lukem #endif /* HAVE_TLS */ 577 1.1 lukem 578 1.1 lukem /* 579 1.1 lukem * Set the network timeout if set 580 1.1 lukem */ 581 1.1 lukem if ( mt->mt_network_timeout != 0 ) { 582 1.1 lukem struct timeval network_timeout; 583 1.1 lukem 584 1.1 lukem network_timeout.tv_usec = 0; 585 1.1 lukem network_timeout.tv_sec = mt->mt_network_timeout; 586 1.1 lukem 587 1.1 lukem ldap_set_option( msc->msc_ld, LDAP_OPT_NETWORK_TIMEOUT, 588 1.1 lukem (void *)&network_timeout ); 589 1.1 lukem } 590 1.1 lukem 591 1.1 lukem /* 592 1.1 lukem * If the connection DN is not null, an attempt to rewrite it is made 593 1.1 lukem */ 594 1.1 lukem 595 1.1 lukem if ( ispriv ) { 596 1.1 lukem if ( !BER_BVISNULL( &mt->mt_idassert_authcDN ) ) { 597 1.1 lukem ber_bvreplace( &msc->msc_bound_ndn, &mt->mt_idassert_authcDN ); 598 1.1 lukem if ( !BER_BVISNULL( &mt->mt_idassert_passwd ) ) { 599 1.1 lukem if ( !BER_BVISNULL( &msc->msc_cred ) ) { 600 1.1 lukem memset( msc->msc_cred.bv_val, 0, 601 1.1 lukem msc->msc_cred.bv_len ); 602 1.1 lukem } 603 1.1 lukem ber_bvreplace( &msc->msc_cred, &mt->mt_idassert_passwd ); 604 1.1 lukem } 605 1.2 christos LDAP_BACK_CONN_ISIDASSERT_SET( msc ); 606 1.1 lukem 607 1.1 lukem } else { 608 1.1 lukem ber_bvreplace( &msc->msc_bound_ndn, &slap_empty_bv ); 609 1.1 lukem } 610 1.1 lukem 611 1.1 lukem } else { 612 1.1 lukem if ( !BER_BVISNULL( &msc->msc_cred ) ) { 613 1.1 lukem memset( msc->msc_cred.bv_val, 0, msc->msc_cred.bv_len ); 614 1.1 lukem ber_memfree_x( msc->msc_cred.bv_val, NULL ); 615 1.1 lukem BER_BVZERO( &msc->msc_cred ); 616 1.1 lukem } 617 1.1 lukem if ( !BER_BVISNULL( &msc->msc_bound_ndn ) ) { 618 1.1 lukem ber_memfree_x( msc->msc_bound_ndn.bv_val, NULL ); 619 1.1 lukem BER_BVZERO( &msc->msc_bound_ndn ); 620 1.1 lukem } 621 1.1 lukem if ( !BER_BVISEMPTY( &op->o_ndn ) 622 1.1 lukem && SLAP_IS_AUTHZ_BACKEND( op ) 623 1.1 lukem && isauthz ) 624 1.1 lukem { 625 1.1 lukem dc.target = mt; 626 1.1 lukem dc.conn = op->o_conn; 627 1.1 lukem dc.rs = rs; 628 1.1 lukem dc.ctx = "bindDN"; 629 1.1 lukem 630 1.1 lukem /* 631 1.1 lukem * Rewrite the bind dn if needed 632 1.1 lukem */ 633 1.1 lukem if ( ldap_back_dn_massage( &dc, &op->o_conn->c_dn, 634 1.1 lukem &msc->msc_bound_ndn ) ) 635 1.1 lukem { 636 1.1 lukem 637 1.1 lukem #ifdef DEBUG_205 638 1.1 lukem Debug( LDAP_DEBUG_ANY, 639 1.1 lukem "### %s meta_back_init_one_conn(rewrite) " 640 1.1 lukem "ldap_unbind_ext[%d] ld=%p\n", 641 1.1 lukem op->o_log_prefix, candidate, 642 1.1 lukem (void *)msc->msc_ld ); 643 1.1 lukem #endif /* DEBUG_205 */ 644 1.1 lukem 645 1.1 lukem /* need to trash a connection not fully established */ 646 1.1 lukem meta_clear_one_candidate( op, mc, candidate ); 647 1.1 lukem goto error_return; 648 1.1 lukem } 649 1.1 lukem 650 1.1 lukem /* copy the DN if needed */ 651 1.1 lukem if ( msc->msc_bound_ndn.bv_val == op->o_conn->c_dn.bv_val ) { 652 1.1 lukem ber_dupbv( &msc->msc_bound_ndn, &op->o_conn->c_dn ); 653 1.1 lukem } 654 1.1 lukem 655 1.1 lukem assert( !BER_BVISNULL( &msc->msc_bound_ndn ) ); 656 1.1 lukem 657 1.1 lukem } else { 658 1.1 lukem ber_dupbv( &msc->msc_bound_ndn, (struct berval *)&slap_empty_bv ); 659 1.1 lukem } 660 1.1 lukem } 661 1.1 lukem 662 1.1 lukem assert( !BER_BVISNULL( &msc->msc_bound_ndn ) ); 663 1.1 lukem 664 1.1 lukem error_return:; 665 1.1 lukem if ( dolock ) { 666 1.1 lukem ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex ); 667 1.1 lukem } 668 1.1 lukem META_BACK_CONN_CREATING_CLEAR( msc ); 669 1.1 lukem if ( rs->sr_err == LDAP_SUCCESS ) { 670 1.1 lukem /* 671 1.1 lukem * Sets a cookie for the rewrite session 672 1.1 lukem */ 673 1.1 lukem ( void )rewrite_session_init( mt->mt_rwmap.rwm_rw, op->o_conn ); 674 1.1 lukem META_BACK_CONN_INITED_SET( msc ); 675 1.1 lukem } 676 1.1 lukem if ( dolock ) { 677 1.1 lukem ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex ); 678 1.1 lukem } 679 1.1 lukem 680 1.1 lukem if ( rs->sr_err != LDAP_SUCCESS ) { 681 1.2 christos /* Get the error message and print it in TRACE mode */ 682 1.2 christos if ( LogTest( LDAP_DEBUG_TRACE ) ) { 683 1.3 christos Log( LDAP_DEBUG_TRACE, ldap_syslog_level, "%s: meta_back_init_one_conn[%d] failed err=%d text=%s\n", 684 1.2 christos op->o_log_prefix, candidate, rs->sr_err, rs->sr_text ); 685 1.2 christos } 686 1.2 christos 687 1.1 lukem rs->sr_err = slap_map_api2result( rs ); 688 1.1 lukem if ( sendok & LDAP_BACK_SENDERR ) { 689 1.1 lukem send_ldap_result( op, rs ); 690 1.1 lukem } 691 1.1 lukem } 692 1.1 lukem 693 1.1 lukem return rs->sr_err; 694 1.1 lukem } 695 1.1 lukem 696 1.1 lukem /* 697 1.1 lukem * meta_back_retry 698 1.1 lukem * 699 1.1 lukem * Retries one connection 700 1.1 lukem */ 701 1.1 lukem int 702 1.1 lukem meta_back_retry( 703 1.1 lukem Operation *op, 704 1.1 lukem SlapReply *rs, 705 1.1 lukem metaconn_t **mcp, 706 1.1 lukem int candidate, 707 1.4 christos ldap_back_send_t sendok, 708 1.4 christos SlapReply *candidates ) 709 1.1 lukem { 710 1.1 lukem metainfo_t *mi = ( metainfo_t * )op->o_bd->be_private; 711 1.1 lukem metatarget_t *mt = mi->mi_targets[ candidate ]; 712 1.1 lukem metaconn_t *mc = *mcp; 713 1.1 lukem metasingleconn_t *msc = &mc->mc_conns[ candidate ]; 714 1.1 lukem int rc = LDAP_UNAVAILABLE, 715 1.1 lukem binding, 716 1.1 lukem quarantine = 1; 717 1.1 lukem 718 1.1 lukem ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex ); 719 1.1 lukem 720 1.1 lukem assert( !META_BACK_CONN_CREATING( msc ) ); 721 1.1 lukem binding = LDAP_BACK_CONN_BINDING( msc ); 722 1.1 lukem LDAP_BACK_CONN_BINDING_CLEAR( msc ); 723 1.1 lukem 724 1.1 lukem assert( mc->mc_refcnt > 0 ); 725 1.1 lukem if ( mc->mc_refcnt == 1 ) { 726 1.2 christos struct berval save_cred; 727 1.2 christos 728 1.1 lukem if ( LogTest( LDAP_DEBUG_ANY ) ) { 729 1.1 lukem /* this lock is required; however, 730 1.1 lukem * it's invoked only when logging is on */ 731 1.1 lukem ldap_pvt_thread_mutex_lock( &mt->mt_uri_mutex ); 732 1.3 christos Debug(LDAP_DEBUG_ANY, 733 1.3 christos "%s meta_back_retry[%d]: retrying URI=\"%s\" DN=\"%s\".\n", 734 1.3 christos op->o_log_prefix, candidate, mt->mt_uri, 735 1.3 christos BER_BVISNULL(&msc->msc_bound_ndn) ? "" : msc->msc_bound_ndn.bv_val ); 736 1.1 lukem ldap_pvt_thread_mutex_unlock( &mt->mt_uri_mutex ); 737 1.1 lukem } 738 1.1 lukem 739 1.2 christos /* save credentials, if any, for later use; 740 1.2 christos * meta_clear_one_candidate() would free them */ 741 1.2 christos save_cred = msc->msc_cred; 742 1.2 christos BER_BVZERO( &msc->msc_cred ); 743 1.2 christos 744 1.1 lukem meta_clear_one_candidate( op, mc, candidate ); 745 1.1 lukem LDAP_BACK_CONN_ISBOUND_CLEAR( msc ); 746 1.1 lukem 747 1.1 lukem ( void )rewrite_session_delete( mt->mt_rwmap.rwm_rw, op->o_conn ); 748 1.1 lukem 749 1.1 lukem /* mc here must be the regular mc, reset and ready for init */ 750 1.1 lukem rc = meta_back_init_one_conn( op, rs, mc, candidate, 751 1.1 lukem LDAP_BACK_CONN_ISPRIV( mc ), sendok, 0 ); 752 1.1 lukem 753 1.2 christos /* restore credentials, if any and if needed; 754 1.2 christos * meta_back_init_one_conn() restores msc_bound_ndn, if any; 755 1.2 christos * if no msc_bound_ndn is restored, destroy credentials */ 756 1.2 christos if ( !BER_BVISNULL( &msc->msc_bound_ndn ) 757 1.2 christos && BER_BVISNULL( &msc->msc_cred ) ) 758 1.2 christos { 759 1.2 christos msc->msc_cred = save_cred; 760 1.2 christos 761 1.2 christos } else if ( !BER_BVISNULL( &save_cred ) ) { 762 1.2 christos memset( save_cred.bv_val, 0, save_cred.bv_len ); 763 1.2 christos ber_memfree_x( save_cred.bv_val, NULL ); 764 1.2 christos } 765 1.2 christos 766 1.1 lukem /* restore the "binding" flag, in case */ 767 1.1 lukem if ( binding ) { 768 1.1 lukem LDAP_BACK_CONN_BINDING_SET( msc ); 769 1.1 lukem } 770 1.1 lukem 771 1.1 lukem if ( rc == LDAP_SUCCESS ) { 772 1.1 lukem quarantine = 0; 773 1.2 christos LDAP_BACK_CONN_BINDING_SET( msc ); binding = 1; 774 1.1 lukem rc = meta_back_single_dobind( op, rs, mcp, candidate, 775 1.1 lukem sendok, mt->mt_nretries, 0 ); 776 1.1 lukem 777 1.1 lukem Debug( LDAP_DEBUG_ANY, 778 1.1 lukem "%s meta_back_retry[%d]: " 779 1.1 lukem "meta_back_single_dobind=%d\n", 780 1.1 lukem op->o_log_prefix, candidate, rc ); 781 1.1 lukem if ( rc == LDAP_SUCCESS ) { 782 1.1 lukem if ( !BER_BVISNULL( &msc->msc_bound_ndn ) && 783 1.1 lukem !BER_BVISEMPTY( &msc->msc_bound_ndn ) ) 784 1.1 lukem { 785 1.1 lukem LDAP_BACK_CONN_ISBOUND_SET( msc ); 786 1.1 lukem 787 1.1 lukem } else { 788 1.1 lukem LDAP_BACK_CONN_ISANON_SET( msc ); 789 1.1 lukem } 790 1.1 lukem 791 1.1 lukem /* when bound, dispose of the "binding" flag */ 792 1.1 lukem if ( binding ) { 793 1.1 lukem LDAP_BACK_CONN_BINDING_CLEAR( msc ); 794 1.1 lukem } 795 1.1 lukem } 796 1.2 christos } 797 1.1 lukem 798 1.2 christos #if 0 /* ITS#7591, following stmt drops needed result msgs */ 799 1.1 lukem /* don't send twice */ 800 1.1 lukem sendok &= ~LDAP_BACK_SENDERR; 801 1.2 christos #endif 802 1.1 lukem } 803 1.1 lukem 804 1.1 lukem if ( rc != LDAP_SUCCESS ) { 805 1.1 lukem SlapReply *candidates = meta_back_candidates_get( op ); 806 1.1 lukem 807 1.1 lukem candidates[ candidate ].sr_err = rc; 808 1.1 lukem 809 1.1 lukem if ( *mcp != NULL ) { 810 1.1 lukem if ( mc->mc_refcnt == 1 ) { 811 1.1 lukem if ( binding ) { 812 1.1 lukem LDAP_BACK_CONN_BINDING_CLEAR( msc ); 813 1.1 lukem } 814 1.1 lukem (void)meta_clear_one_candidate( op, mc, candidate ); 815 1.1 lukem } 816 1.1 lukem 817 1.1 lukem LDAP_BACK_CONN_TAINTED_SET( mc ); 818 1.1 lukem /* only release if mandatory; otherwise 819 1.1 lukem * let the caller do what's best before 820 1.1 lukem * releasing */ 821 1.1 lukem if ( META_BACK_ONERR_STOP( mi ) ) { 822 1.1 lukem meta_back_release_conn_lock( mi, mc, 0 ); 823 1.1 lukem *mcp = NULL; 824 1.1 lukem 825 1.1 lukem } else { 826 1.1 lukem #if META_BACK_PRINT_CONNTREE > 0 827 1.1 lukem meta_back_print_conntree( mi, ">>> meta_back_retry" ); 828 1.1 lukem #endif /* META_BACK_PRINT_CONNTREE */ 829 1.1 lukem 830 1.1 lukem /* FIXME: could be done better, reworking meta_back_release_conn_lock() */ 831 1.1 lukem if ( LDAP_BACK_PCONN_ISPRIV( mc ) ) { 832 1.1 lukem if ( mc->mc_q.tqe_prev != NULL ) { 833 1.1 lukem assert( LDAP_BACK_CONN_CACHED( mc ) ); 834 1.1 lukem assert( mi->mi_conn_priv[ LDAP_BACK_CONN2PRIV( mc ) ].mic_num > 0 ); 835 1.1 lukem LDAP_TAILQ_REMOVE( &mi->mi_conn_priv[ LDAP_BACK_CONN2PRIV( mc ) ].mic_priv, 836 1.1 lukem mc, mc_q ); 837 1.1 lukem mi->mi_conn_priv[ LDAP_BACK_CONN2PRIV( mc ) ].mic_num--; 838 1.1 lukem LDAP_TAILQ_ENTRY_INIT( mc, mc_q ); 839 1.1 lukem 840 1.1 lukem } else { 841 1.1 lukem assert( !LDAP_BACK_CONN_CACHED( mc ) ); 842 1.1 lukem } 843 1.1 lukem 844 1.1 lukem } else { 845 1.1 lukem /* FIXME: check if in tree, for consistency? */ 846 1.3 christos (void)ldap_tavl_delete( &mi->mi_conninfo.lai_tree, 847 1.1 lukem ( caddr_t )mc, meta_back_conndnmc_cmp ); 848 1.1 lukem } 849 1.1 lukem LDAP_BACK_CONN_CACHED_CLEAR( mc ); 850 1.1 lukem 851 1.1 lukem #if META_BACK_PRINT_CONNTREE > 0 852 1.1 lukem meta_back_print_conntree( mi, "<<< meta_back_retry" ); 853 1.1 lukem #endif /* META_BACK_PRINT_CONNTREE */ 854 1.1 lukem } 855 1.1 lukem } 856 1.1 lukem 857 1.1 lukem if ( sendok & LDAP_BACK_SENDERR ) { 858 1.1 lukem rs->sr_err = rc; 859 1.1 lukem rs->sr_text = "Unable to retry"; 860 1.1 lukem send_ldap_result( op, rs ); 861 1.1 lukem } 862 1.1 lukem } 863 1.1 lukem 864 1.1 lukem if ( quarantine && META_BACK_TGT_QUARANTINE( mt ) ) { 865 1.1 lukem meta_back_quarantine( op, rs, candidate ); 866 1.1 lukem } 867 1.1 lukem 868 1.1 lukem ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex ); 869 1.1 lukem 870 1.1 lukem return rc == LDAP_SUCCESS ? 1 : 0; 871 1.1 lukem } 872 1.1 lukem 873 1.1 lukem /* 874 1.1 lukem * callback for unique candidate selection 875 1.1 lukem */ 876 1.1 lukem static int 877 1.1 lukem meta_back_conn_cb( Operation *op, SlapReply *rs ) 878 1.1 lukem { 879 1.1 lukem assert( op->o_tag == LDAP_REQ_SEARCH ); 880 1.1 lukem 881 1.1 lukem switch ( rs->sr_type ) { 882 1.1 lukem case REP_SEARCH: 883 1.1 lukem ((long *)op->o_callback->sc_private)[0] = (long)op->o_private; 884 1.1 lukem break; 885 1.1 lukem 886 1.1 lukem case REP_SEARCHREF: 887 1.1 lukem case REP_RESULT: 888 1.1 lukem break; 889 1.1 lukem 890 1.1 lukem default: 891 1.1 lukem return rs->sr_err; 892 1.1 lukem } 893 1.1 lukem 894 1.1 lukem return 0; 895 1.1 lukem } 896 1.1 lukem 897 1.1 lukem 898 1.1 lukem static int 899 1.1 lukem meta_back_get_candidate( 900 1.1 lukem Operation *op, 901 1.1 lukem SlapReply *rs, 902 1.1 lukem struct berval *ndn ) 903 1.1 lukem { 904 1.1 lukem metainfo_t *mi = ( metainfo_t * )op->o_bd->be_private; 905 1.1 lukem long candidate; 906 1.1 lukem 907 1.1 lukem /* 908 1.1 lukem * tries to get a unique candidate 909 1.1 lukem * (takes care of default target) 910 1.1 lukem */ 911 1.1 lukem candidate = meta_back_select_unique_candidate( mi, ndn ); 912 1.1 lukem 913 1.1 lukem /* 914 1.1 lukem * if any is found, inits the connection 915 1.1 lukem */ 916 1.1 lukem if ( candidate == META_TARGET_NONE ) { 917 1.1 lukem rs->sr_err = LDAP_NO_SUCH_OBJECT; 918 1.1 lukem rs->sr_text = "No suitable candidate target found"; 919 1.1 lukem 920 1.1 lukem } else if ( candidate == META_TARGET_MULTIPLE ) { 921 1.1 lukem Operation op2 = *op; 922 1.2 christos SlapReply rs2 = { REP_RESULT }; 923 1.1 lukem slap_callback cb2 = { 0 }; 924 1.1 lukem int rc; 925 1.1 lukem 926 1.1 lukem /* try to get a unique match for the request ndn 927 1.1 lukem * among the multiple candidates available */ 928 1.1 lukem op2.o_tag = LDAP_REQ_SEARCH; 929 1.1 lukem op2.o_req_dn = *ndn; 930 1.1 lukem op2.o_req_ndn = *ndn; 931 1.1 lukem op2.ors_scope = LDAP_SCOPE_BASE; 932 1.1 lukem op2.ors_deref = LDAP_DEREF_NEVER; 933 1.1 lukem op2.ors_attrs = slap_anlist_no_attrs; 934 1.1 lukem op2.ors_attrsonly = 0; 935 1.1 lukem op2.ors_limit = NULL; 936 1.1 lukem op2.ors_slimit = 1; 937 1.1 lukem op2.ors_tlimit = SLAP_NO_LIMIT; 938 1.1 lukem 939 1.1 lukem op2.ors_filter = (Filter *)slap_filter_objectClass_pres; 940 1.1 lukem op2.ors_filterstr = *slap_filterstr_objectClass_pres; 941 1.1 lukem 942 1.1 lukem op2.o_callback = &cb2; 943 1.1 lukem cb2.sc_response = meta_back_conn_cb; 944 1.1 lukem cb2.sc_private = (void *)&candidate; 945 1.1 lukem 946 1.1 lukem rc = op->o_bd->be_search( &op2, &rs2 ); 947 1.1 lukem 948 1.1 lukem switch ( rs2.sr_err ) { 949 1.1 lukem case LDAP_SUCCESS: 950 1.1 lukem default: 951 1.1 lukem rs->sr_err = rs2.sr_err; 952 1.1 lukem break; 953 1.1 lukem 954 1.1 lukem case LDAP_SIZELIMIT_EXCEEDED: 955 1.1 lukem /* if multiple candidates can serve the operation, 956 1.1 lukem * and a default target is defined, and it is 957 1.1 lukem * a candidate, try using it (FIXME: YMMV) */ 958 1.1 lukem if ( mi->mi_defaulttarget != META_DEFAULT_TARGET_NONE 959 1.1 lukem && meta_back_is_candidate( mi->mi_targets[ mi->mi_defaulttarget ], 960 1.1 lukem ndn, op->o_tag == LDAP_REQ_SEARCH ? op->ors_scope : LDAP_SCOPE_BASE ) ) 961 1.1 lukem { 962 1.1 lukem candidate = mi->mi_defaulttarget; 963 1.1 lukem rs->sr_err = LDAP_SUCCESS; 964 1.1 lukem rs->sr_text = NULL; 965 1.1 lukem 966 1.1 lukem } else { 967 1.1 lukem rs->sr_err = LDAP_UNWILLING_TO_PERFORM; 968 1.1 lukem rs->sr_text = "Unable to select unique candidate target"; 969 1.1 lukem } 970 1.1 lukem break; 971 1.1 lukem } 972 1.1 lukem 973 1.1 lukem } else { 974 1.1 lukem rs->sr_err = LDAP_SUCCESS; 975 1.1 lukem } 976 1.1 lukem 977 1.1 lukem return candidate; 978 1.1 lukem } 979 1.1 lukem 980 1.1 lukem SlapReply * 981 1.1 lukem meta_back_candidates_get( Operation *op ) 982 1.1 lukem { 983 1.1 lukem metainfo_t *mi = ( metainfo_t * )op->o_bd->be_private; 984 1.4 christos SlapReply *candidates; 985 1.1 lukem 986 1.4 christos candidates = op->o_tmpcalloc( mi->mi_ntargets, sizeof( SlapReply ), op->o_tmpmemctx ); 987 1.4 christos return candidates; 988 1.1 lukem } 989 1.1 lukem 990 1.1 lukem /* 991 1.1 lukem * meta_back_getconn 992 1.1 lukem * 993 1.1 lukem * Prepares the connection structure 994 1.1 lukem * 995 1.1 lukem * RATIONALE: 996 1.1 lukem * 997 1.1 lukem * - determine what DN is being requested: 998 1.1 lukem * 999 1.1 lukem * op requires candidate checks 1000 1.1 lukem * 1001 1.1 lukem * add unique parent of o_req_ndn 1002 1.1 lukem * bind unique^*[/all] o_req_ndn [no check] 1003 1.1 lukem * compare unique^+ o_req_ndn 1004 1.1 lukem * delete unique o_req_ndn 1005 1.1 lukem * modify unique o_req_ndn 1006 1.1 lukem * search any o_req_ndn 1007 1.1 lukem * modrdn unique[, unique] o_req_ndn[, orr_nnewSup] 1008 1.1 lukem * 1009 1.1 lukem * - for ops that require the candidate to be unique, in case of multiple 1010 1.1 lukem * occurrences an internal search with sizeLimit=1 is performed 1011 1.1 lukem * if a unique candidate can actually be determined. If none is found, 1012 1.1 lukem * the operation aborts; if multiple are found, the default target 1013 1.1 lukem * is used if defined and candidate; otherwise the operation aborts. 1014 1.1 lukem * 1015 1.1 lukem * *^note: actually, the bind operation is handled much like a search; 1016 1.1 lukem * i.e. the bind is broadcast to all candidate targets. 1017 1.1 lukem * 1018 1.1 lukem * +^note: actually, the compare operation is handled much like a search; 1019 1.1 lukem * i.e. the compare is broadcast to all candidate targets, while checking 1020 1.1 lukem * that exactly none (noSuchObject) or one (TRUE/FALSE/UNDEFINED) is 1021 1.1 lukem * returned. 1022 1.1 lukem */ 1023 1.1 lukem metaconn_t * 1024 1.1 lukem meta_back_getconn( 1025 1.4 christos Operation *op, 1026 1.1 lukem SlapReply *rs, 1027 1.1 lukem int *candidate, 1028 1.4 christos ldap_back_send_t sendok, 1029 1.4 christos SlapReply *candidates ) 1030 1.1 lukem { 1031 1.1 lukem metainfo_t *mi = ( metainfo_t * )op->o_bd->be_private; 1032 1.1 lukem metaconn_t *mc = NULL, 1033 1.2 christos mc_curr = {{ 0 }}; 1034 1.1 lukem int cached = META_TARGET_NONE, 1035 1.1 lukem i = META_TARGET_NONE, 1036 1.1 lukem err = LDAP_SUCCESS, 1037 1.1 lukem new_conn = 0, 1038 1.1 lukem ncandidates = 0; 1039 1.1 lukem 1040 1.1 lukem 1041 1.1 lukem meta_op_type op_type = META_OP_REQUIRE_SINGLE; 1042 1.1 lukem enum { 1043 1.1 lukem META_DNTYPE_ENTRY, 1044 1.1 lukem META_DNTYPE_PARENT, 1045 1.1 lukem META_DNTYPE_NEWPARENT 1046 1.1 lukem } dn_type = META_DNTYPE_ENTRY; 1047 1.1 lukem struct berval ndn = op->o_req_ndn, 1048 1.1 lukem pndn; 1049 1.1 lukem 1050 1.1 lukem /* Internal searches are privileged and shared. So is root. */ 1051 1.1 lukem if ( ( !BER_BVISEMPTY( &op->o_ndn ) && META_BACK_PROXYAUTHZ_ALWAYS( mi ) ) 1052 1.1 lukem || ( BER_BVISEMPTY( &op->o_ndn ) && META_BACK_PROXYAUTHZ_ANON( mi ) ) 1053 1.1 lukem || op->o_do_not_cache || be_isroot( op ) ) 1054 1.1 lukem { 1055 1.1 lukem LDAP_BACK_CONN_ISPRIV_SET( &mc_curr ); 1056 1.1 lukem mc_curr.mc_local_ndn = op->o_bd->be_rootndn; 1057 1.1 lukem LDAP_BACK_PCONN_ROOTDN_SET( &mc_curr, op ); 1058 1.1 lukem 1059 1.1 lukem } else if ( BER_BVISEMPTY( &op->o_ndn ) && META_BACK_PROXYAUTHZ_NOANON( mi ) ) 1060 1.1 lukem { 1061 1.1 lukem LDAP_BACK_CONN_ISANON_SET( &mc_curr ); 1062 1.1 lukem BER_BVSTR( &mc_curr.mc_local_ndn, "" ); 1063 1.1 lukem LDAP_BACK_PCONN_ANON_SET( &mc_curr, op ); 1064 1.1 lukem 1065 1.1 lukem } else { 1066 1.1 lukem mc_curr.mc_local_ndn = op->o_ndn; 1067 1.1 lukem 1068 1.1 lukem /* Explicit binds must not be shared */ 1069 1.1 lukem if ( !BER_BVISEMPTY( &op->o_ndn ) 1070 1.1 lukem || op->o_tag == LDAP_REQ_BIND 1071 1.1 lukem || SLAP_IS_AUTHZ_BACKEND( op ) ) 1072 1.1 lukem { 1073 1.1 lukem mc_curr.mc_conn = op->o_conn; 1074 1.1 lukem 1075 1.1 lukem } else { 1076 1.1 lukem LDAP_BACK_CONN_ISANON_SET( &mc_curr ); 1077 1.1 lukem LDAP_BACK_PCONN_ANON_SET( &mc_curr, op ); 1078 1.1 lukem } 1079 1.1 lukem } 1080 1.1 lukem 1081 1.1 lukem /* Explicit Bind requests always get their own conn */ 1082 1.1 lukem if ( sendok & LDAP_BACK_BINDING ) { 1083 1.1 lukem mc_curr.mc_conn = op->o_conn; 1084 1.1 lukem 1085 1.1 lukem } else { 1086 1.1 lukem /* Searches for a metaconn in the avl tree */ 1087 1.1 lukem retry_lock:; 1088 1.1 lukem ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex ); 1089 1.1 lukem if ( LDAP_BACK_PCONN_ISPRIV( &mc_curr ) ) { 1090 1.1 lukem /* lookup a conn that's not binding */ 1091 1.1 lukem LDAP_TAILQ_FOREACH( mc, 1092 1.1 lukem &mi->mi_conn_priv[ LDAP_BACK_CONN2PRIV( &mc_curr ) ].mic_priv, 1093 1.1 lukem mc_q ) 1094 1.1 lukem { 1095 1.1 lukem if ( !LDAP_BACK_CONN_BINDING( mc ) && mc->mc_refcnt == 0 ) { 1096 1.1 lukem break; 1097 1.1 lukem } 1098 1.1 lukem } 1099 1.1 lukem 1100 1.1 lukem if ( mc != NULL ) { 1101 1.2 christos /* move to tail of queue */ 1102 1.1 lukem if ( mc != LDAP_TAILQ_LAST( &mi->mi_conn_priv[ LDAP_BACK_CONN2PRIV( mc ) ].mic_priv, 1103 1.2 christos mc_conn_priv_q ) ) 1104 1.1 lukem { 1105 1.1 lukem LDAP_TAILQ_REMOVE( &mi->mi_conn_priv[ LDAP_BACK_CONN2PRIV( mc ) ].mic_priv, 1106 1.1 lukem mc, mc_q ); 1107 1.1 lukem LDAP_TAILQ_ENTRY_INIT( mc, mc_q ); 1108 1.1 lukem LDAP_TAILQ_INSERT_TAIL( &mi->mi_conn_priv[ LDAP_BACK_CONN2PRIV( mc ) ].mic_priv, 1109 1.1 lukem mc, mc_q ); 1110 1.1 lukem } 1111 1.1 lukem 1112 1.1 lukem } else if ( !LDAP_BACK_USE_TEMPORARIES( mi ) 1113 1.1 lukem && mi->mi_conn_priv[ LDAP_BACK_CONN2PRIV( &mc_curr ) ].mic_num == mi->mi_conn_priv_max ) 1114 1.1 lukem { 1115 1.1 lukem mc = LDAP_TAILQ_FIRST( &mi->mi_conn_priv[ LDAP_BACK_CONN2PRIV( &mc_curr ) ].mic_priv ); 1116 1.1 lukem } 1117 1.1 lukem 1118 1.1 lukem 1119 1.1 lukem } else { 1120 1.3 christos mc = (metaconn_t *)ldap_tavl_find( mi->mi_conninfo.lai_tree, 1121 1.1 lukem (caddr_t)&mc_curr, meta_back_conndn_cmp ); 1122 1.1 lukem } 1123 1.1 lukem 1124 1.1 lukem if ( mc ) { 1125 1.1 lukem /* catch taint errors */ 1126 1.1 lukem assert( !LDAP_BACK_CONN_TAINTED( mc ) ); 1127 1.1 lukem 1128 1.1 lukem /* Don't reuse connections while they're still binding 1129 1.1 lukem * NOTE: only makes sense for binds */ 1130 1.1 lukem if ( LDAP_BACK_CONN_BINDING( mc ) ) { 1131 1.1 lukem if ( !LDAP_BACK_USE_TEMPORARIES( mi ) ) { 1132 1.1 lukem ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex ); 1133 1.1 lukem 1134 1.1 lukem ldap_pvt_thread_yield(); 1135 1.1 lukem goto retry_lock; 1136 1.1 lukem } 1137 1.1 lukem 1138 1.1 lukem /* release conn, and create a temporary */ 1139 1.1 lukem mc = NULL; 1140 1.1 lukem 1141 1.1 lukem } else { 1142 1.2 christos if ( mc->mc_refcnt == 0 && (( mi->mi_conn_ttl != 0 && op->o_time > mc->mc_create_time + mi->mi_conn_ttl ) 1143 1.2 christos || ( mi->mi_idle_timeout != 0 && op->o_time > mc->mc_time + mi->mi_idle_timeout )) ) 1144 1.1 lukem { 1145 1.1 lukem #if META_BACK_PRINT_CONNTREE > 0 1146 1.1 lukem meta_back_print_conntree( mi, 1147 1.1 lukem ">>> meta_back_getconn(expired)" ); 1148 1.1 lukem #endif /* META_BACK_PRINT_CONNTREE */ 1149 1.1 lukem 1150 1.1 lukem /* don't let anyone else use this expired connection */ 1151 1.1 lukem if ( LDAP_BACK_PCONN_ISPRIV( mc ) ) { 1152 1.1 lukem if ( mc->mc_q.tqe_prev != NULL ) { 1153 1.1 lukem assert( LDAP_BACK_CONN_CACHED( mc ) ); 1154 1.1 lukem assert( mi->mi_conn_priv[ LDAP_BACK_CONN2PRIV( mc ) ].mic_num > 0 ); 1155 1.1 lukem LDAP_TAILQ_REMOVE( &mi->mi_conn_priv[ LDAP_BACK_CONN2PRIV( mc ) ].mic_priv, 1156 1.1 lukem mc, mc_q ); 1157 1.1 lukem mi->mi_conn_priv[ LDAP_BACK_CONN2PRIV( mc ) ].mic_num--; 1158 1.1 lukem LDAP_TAILQ_ENTRY_INIT( mc, mc_q ); 1159 1.1 lukem 1160 1.1 lukem } else { 1161 1.1 lukem assert( !LDAP_BACK_CONN_CACHED( mc ) ); 1162 1.1 lukem } 1163 1.1 lukem 1164 1.1 lukem } else { 1165 1.3 christos (void)ldap_tavl_delete( &mi->mi_conninfo.lai_tree, 1166 1.1 lukem (caddr_t)mc, meta_back_conndnmc_cmp ); 1167 1.1 lukem } 1168 1.1 lukem 1169 1.1 lukem #if META_BACK_PRINT_CONNTREE > 0 1170 1.1 lukem meta_back_print_conntree( mi, 1171 1.1 lukem "<<< meta_back_getconn(expired)" ); 1172 1.1 lukem #endif /* META_BACK_PRINT_CONNTREE */ 1173 1.1 lukem LDAP_BACK_CONN_TAINTED_SET( mc ); 1174 1.1 lukem LDAP_BACK_CONN_CACHED_CLEAR( mc ); 1175 1.1 lukem 1176 1.2 christos if ( LogTest( LDAP_DEBUG_TRACE ) ) { 1177 1.2 christos char buf[STRLENOF("4294967295U") + 1] = { 0 }; 1178 1.2 christos mi->mi_ldap_extra->connid2str( &mc->mc_base, buf, sizeof(buf) ); 1179 1.2 christos 1180 1.2 christos Debug( LDAP_DEBUG_TRACE, 1181 1.2 christos "%s meta_back_getconn: mc=%p conn=%s expired (tainted).\n", 1182 1.2 christos op->o_log_prefix, (void *)mc, buf ); 1183 1.2 christos } 1184 1.1 lukem } 1185 1.1 lukem 1186 1.1 lukem mc->mc_refcnt++; 1187 1.1 lukem } 1188 1.1 lukem } 1189 1.1 lukem ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex ); 1190 1.1 lukem } 1191 1.1 lukem 1192 1.1 lukem switch ( op->o_tag ) { 1193 1.1 lukem case LDAP_REQ_ADD: 1194 1.1 lukem /* if we go to selection, the entry must not exist, 1195 1.1 lukem * and we must be able to resolve the parent */ 1196 1.1 lukem dn_type = META_DNTYPE_PARENT; 1197 1.1 lukem dnParent( &ndn, &pndn ); 1198 1.1 lukem break; 1199 1.1 lukem 1200 1.1 lukem case LDAP_REQ_MODRDN: 1201 1.1 lukem /* if nnewSuperior is not NULL, it must resolve 1202 1.1 lukem * to the same candidate as the req_ndn */ 1203 1.1 lukem if ( op->orr_nnewSup ) { 1204 1.1 lukem dn_type = META_DNTYPE_NEWPARENT; 1205 1.1 lukem } 1206 1.1 lukem break; 1207 1.1 lukem 1208 1.1 lukem case LDAP_REQ_BIND: 1209 1.1 lukem /* if bound as rootdn, the backend must bind to all targets 1210 1.1 lukem * with the administrative identity 1211 1.1 lukem * (unless pseoudoroot-bind-defer is TRUE) */ 1212 1.1 lukem if ( op->orb_method == LDAP_AUTH_SIMPLE && be_isroot_pw( op ) ) { 1213 1.1 lukem op_type = META_OP_REQUIRE_ALL; 1214 1.1 lukem } 1215 1.1 lukem break; 1216 1.1 lukem 1217 1.1 lukem case LDAP_REQ_COMPARE: 1218 1.1 lukem case LDAP_REQ_DELETE: 1219 1.1 lukem case LDAP_REQ_MODIFY: 1220 1.1 lukem /* just a unique candidate */ 1221 1.1 lukem break; 1222 1.1 lukem 1223 1.1 lukem case LDAP_REQ_SEARCH: 1224 1.1 lukem /* allow multiple candidates for the searchBase */ 1225 1.1 lukem op_type = META_OP_ALLOW_MULTIPLE; 1226 1.1 lukem break; 1227 1.1 lukem 1228 1.1 lukem default: 1229 1.1 lukem /* right now, just break (exop?) */ 1230 1.1 lukem break; 1231 1.1 lukem } 1232 1.1 lukem 1233 1.1 lukem /* 1234 1.1 lukem * require all connections ... 1235 1.1 lukem */ 1236 1.1 lukem if ( op_type == META_OP_REQUIRE_ALL ) { 1237 1.1 lukem 1238 1.1 lukem /* Looks like we didn't get a bind. Open a new session... */ 1239 1.1 lukem if ( mc == NULL ) { 1240 1.1 lukem assert( new_conn == 0 ); 1241 1.1 lukem mc = metaconn_alloc( op ); 1242 1.1 lukem mc->mc_conn = mc_curr.mc_conn; 1243 1.1 lukem ber_dupbv( &mc->mc_local_ndn, &mc_curr.mc_local_ndn ); 1244 1.1 lukem new_conn = 1; 1245 1.1 lukem if ( sendok & LDAP_BACK_BINDING ) { 1246 1.1 lukem LDAP_BACK_CONN_BINDING_SET( mc ); 1247 1.1 lukem } 1248 1.1 lukem if ( LDAP_BACK_CONN_ISPRIV( &mc_curr ) ) { 1249 1.1 lukem LDAP_BACK_CONN_ISPRIV_SET( mc ); 1250 1.1 lukem 1251 1.1 lukem } else if ( LDAP_BACK_CONN_ISANON( &mc_curr ) ) { 1252 1.1 lukem LDAP_BACK_CONN_ISANON_SET( mc ); 1253 1.1 lukem } 1254 1.1 lukem 1255 1.1 lukem } else if ( 0 ) { 1256 1.1 lukem /* TODO: if any of the connections is binding, 1257 1.1 lukem * release mc and create a new one */ 1258 1.1 lukem } 1259 1.1 lukem 1260 1.1 lukem for ( i = 0; i < mi->mi_ntargets; i++ ) { 1261 1.1 lukem /* 1262 1.1 lukem * The target is activated; if needed, it is 1263 1.1 lukem * also init'd 1264 1.1 lukem */ 1265 1.1 lukem candidates[ i ].sr_err = meta_back_init_one_conn( op, 1266 1.1 lukem rs, mc, i, LDAP_BACK_CONN_ISPRIV( &mc_curr ), 1267 1.1 lukem LDAP_BACK_DONTSEND, !new_conn ); 1268 1.1 lukem if ( candidates[ i ].sr_err == LDAP_SUCCESS ) { 1269 1.1 lukem if ( new_conn && ( sendok & LDAP_BACK_BINDING ) ) { 1270 1.1 lukem LDAP_BACK_CONN_BINDING_SET( &mc->mc_conns[ i ] ); 1271 1.1 lukem } 1272 1.1 lukem META_CANDIDATE_SET( &candidates[ i ] ); 1273 1.1 lukem ncandidates++; 1274 1.1 lukem 1275 1.1 lukem } else { 1276 1.1 lukem 1277 1.1 lukem /* 1278 1.1 lukem * FIXME: in case one target cannot 1279 1.1 lukem * be init'd, should the other ones 1280 1.1 lukem * be tried? 1281 1.1 lukem */ 1282 1.1 lukem META_CANDIDATE_RESET( &candidates[ i ] ); 1283 1.1 lukem err = candidates[ i ].sr_err; 1284 1.1 lukem continue; 1285 1.1 lukem } 1286 1.1 lukem } 1287 1.1 lukem 1288 1.1 lukem if ( ncandidates == 0 ) { 1289 1.1 lukem if ( new_conn ) { 1290 1.1 lukem mc->mc_refcnt = 0; 1291 1.1 lukem meta_back_conn_free( mc ); 1292 1.1 lukem 1293 1.1 lukem } else { 1294 1.1 lukem meta_back_release_conn( mi, mc ); 1295 1.1 lukem } 1296 1.1 lukem 1297 1.1 lukem rs->sr_err = LDAP_NO_SUCH_OBJECT; 1298 1.1 lukem rs->sr_text = "Unable to select valid candidates"; 1299 1.1 lukem 1300 1.1 lukem if ( sendok & LDAP_BACK_SENDERR ) { 1301 1.1 lukem if ( rs->sr_err == LDAP_NO_SUCH_OBJECT ) { 1302 1.1 lukem rs->sr_matched = op->o_bd->be_suffix[ 0 ].bv_val; 1303 1.1 lukem } 1304 1.1 lukem send_ldap_result( op, rs ); 1305 1.1 lukem rs->sr_matched = NULL; 1306 1.1 lukem } 1307 1.1 lukem 1308 1.1 lukem return NULL; 1309 1.1 lukem } 1310 1.1 lukem 1311 1.1 lukem goto done; 1312 1.1 lukem } 1313 1.1 lukem 1314 1.1 lukem /* 1315 1.1 lukem * looks in cache, if any 1316 1.1 lukem */ 1317 1.1 lukem if ( mi->mi_cache.ttl != META_DNCACHE_DISABLED ) { 1318 1.1 lukem cached = i = meta_dncache_get_target( &mi->mi_cache, &op->o_req_ndn ); 1319 1.1 lukem } 1320 1.1 lukem 1321 1.1 lukem if ( op_type == META_OP_REQUIRE_SINGLE ) { 1322 1.1 lukem metatarget_t *mt = NULL; 1323 1.1 lukem metasingleconn_t *msc = NULL; 1324 1.1 lukem 1325 1.1 lukem int j; 1326 1.1 lukem 1327 1.1 lukem for ( j = 0; j < mi->mi_ntargets; j++ ) { 1328 1.1 lukem META_CANDIDATE_RESET( &candidates[ j ] ); 1329 1.1 lukem } 1330 1.1 lukem 1331 1.1 lukem /* 1332 1.1 lukem * tries to get a unique candidate 1333 1.1 lukem * (takes care of default target) 1334 1.1 lukem */ 1335 1.1 lukem if ( i == META_TARGET_NONE ) { 1336 1.1 lukem i = meta_back_get_candidate( op, rs, &ndn ); 1337 1.1 lukem 1338 1.1 lukem if ( rs->sr_err == LDAP_NO_SUCH_OBJECT && dn_type == META_DNTYPE_PARENT ) { 1339 1.1 lukem i = meta_back_get_candidate( op, rs, &pndn ); 1340 1.1 lukem } 1341 1.1 lukem 1342 1.1 lukem if ( i < 0 || rs->sr_err != LDAP_SUCCESS ) { 1343 1.1 lukem if ( mc != NULL ) { 1344 1.1 lukem meta_back_release_conn( mi, mc ); 1345 1.1 lukem } 1346 1.1 lukem 1347 1.1 lukem if ( sendok & LDAP_BACK_SENDERR ) { 1348 1.1 lukem if ( rs->sr_err == LDAP_NO_SUCH_OBJECT ) { 1349 1.1 lukem rs->sr_matched = op->o_bd->be_suffix[ 0 ].bv_val; 1350 1.1 lukem } 1351 1.1 lukem send_ldap_result( op, rs ); 1352 1.1 lukem rs->sr_matched = NULL; 1353 1.1 lukem } 1354 1.1 lukem 1355 1.1 lukem return NULL; 1356 1.1 lukem } 1357 1.1 lukem } 1358 1.1 lukem 1359 1.1 lukem if ( dn_type == META_DNTYPE_NEWPARENT && meta_back_get_candidate( op, rs, op->orr_nnewSup ) != i ) 1360 1.1 lukem { 1361 1.1 lukem if ( mc != NULL ) { 1362 1.1 lukem meta_back_release_conn( mi, mc ); 1363 1.1 lukem } 1364 1.1 lukem 1365 1.1 lukem rs->sr_err = LDAP_UNWILLING_TO_PERFORM; 1366 1.1 lukem rs->sr_text = "Cross-target rename not supported"; 1367 1.1 lukem if ( sendok & LDAP_BACK_SENDERR ) { 1368 1.1 lukem send_ldap_result( op, rs ); 1369 1.1 lukem } 1370 1.1 lukem 1371 1.1 lukem return NULL; 1372 1.1 lukem } 1373 1.1 lukem 1374 1.1 lukem Debug( LDAP_DEBUG_TRACE, 1375 1.1 lukem "==>meta_back_getconn: got target=%d for ndn=\"%s\" from cache\n", 1376 1.3 christos i, op->o_req_ndn.bv_val ); 1377 1.1 lukem 1378 1.1 lukem if ( mc == NULL ) { 1379 1.1 lukem /* Retries searching for a metaconn in the avl tree 1380 1.1 lukem * the reason is that the connection might have been 1381 1.1 lukem * created by meta_back_get_candidate() */ 1382 1.1 lukem if ( !( sendok & LDAP_BACK_BINDING ) ) { 1383 1.1 lukem retry_lock2:; 1384 1.1 lukem ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex ); 1385 1.3 christos mc = (metaconn_t *)ldap_tavl_find( mi->mi_conninfo.lai_tree, 1386 1.1 lukem (caddr_t)&mc_curr, meta_back_conndn_cmp ); 1387 1.1 lukem if ( mc != NULL ) { 1388 1.1 lukem /* catch taint errors */ 1389 1.1 lukem assert( !LDAP_BACK_CONN_TAINTED( mc ) ); 1390 1.1 lukem 1391 1.1 lukem /* Don't reuse connections while they're still binding */ 1392 1.1 lukem if ( META_BACK_CONN_CREATING( &mc->mc_conns[ i ] ) 1393 1.1 lukem || LDAP_BACK_CONN_BINDING( &mc->mc_conns[ i ] ) ) 1394 1.1 lukem { 1395 1.1 lukem if ( !LDAP_BACK_USE_TEMPORARIES( mi ) ) { 1396 1.1 lukem ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex ); 1397 1.1 lukem ldap_pvt_thread_yield(); 1398 1.1 lukem goto retry_lock2; 1399 1.1 lukem } 1400 1.1 lukem 1401 1.1 lukem mc = NULL; 1402 1.1 lukem 1403 1.1 lukem } else { 1404 1.1 lukem mc->mc_refcnt++; 1405 1.1 lukem } 1406 1.1 lukem } 1407 1.1 lukem ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex ); 1408 1.1 lukem } 1409 1.1 lukem 1410 1.1 lukem /* Looks like we didn't get a bind. Open a new session... */ 1411 1.1 lukem if ( mc == NULL ) { 1412 1.1 lukem assert( new_conn == 0 ); 1413 1.1 lukem mc = metaconn_alloc( op ); 1414 1.1 lukem mc->mc_conn = mc_curr.mc_conn; 1415 1.1 lukem ber_dupbv( &mc->mc_local_ndn, &mc_curr.mc_local_ndn ); 1416 1.1 lukem new_conn = 1; 1417 1.1 lukem if ( sendok & LDAP_BACK_BINDING ) { 1418 1.1 lukem LDAP_BACK_CONN_BINDING_SET( mc ); 1419 1.1 lukem } 1420 1.1 lukem if ( LDAP_BACK_CONN_ISPRIV( &mc_curr ) ) { 1421 1.1 lukem LDAP_BACK_CONN_ISPRIV_SET( mc ); 1422 1.1 lukem 1423 1.1 lukem } else if ( LDAP_BACK_CONN_ISANON( &mc_curr ) ) { 1424 1.1 lukem LDAP_BACK_CONN_ISANON_SET( mc ); 1425 1.1 lukem } 1426 1.1 lukem } 1427 1.1 lukem } 1428 1.1 lukem 1429 1.1 lukem /* 1430 1.1 lukem * Clear all other candidates 1431 1.1 lukem */ 1432 1.4 christos ( void )meta_clear_unused_candidates( op, i, candidates ); 1433 1.1 lukem 1434 1.1 lukem mt = mi->mi_targets[ i ]; 1435 1.1 lukem msc = &mc->mc_conns[ i ]; 1436 1.1 lukem 1437 1.1 lukem /* 1438 1.1 lukem * The target is activated; if needed, it is 1439 1.1 lukem * also init'd. In case of error, meta_back_init_one_conn 1440 1.1 lukem * sends the appropriate result. 1441 1.1 lukem */ 1442 1.1 lukem err = meta_back_init_one_conn( op, rs, mc, i, 1443 1.1 lukem LDAP_BACK_CONN_ISPRIV( &mc_curr ), sendok, !new_conn ); 1444 1.1 lukem if ( err != LDAP_SUCCESS ) { 1445 1.1 lukem /* 1446 1.1 lukem * FIXME: in case one target cannot 1447 1.1 lukem * be init'd, should the other ones 1448 1.1 lukem * be tried? 1449 1.1 lukem */ 1450 1.1 lukem META_CANDIDATE_RESET( &candidates[ i ] ); 1451 1.1 lukem if ( new_conn ) { 1452 1.1 lukem mc->mc_refcnt = 0; 1453 1.1 lukem meta_back_conn_free( mc ); 1454 1.1 lukem 1455 1.1 lukem } else { 1456 1.1 lukem meta_back_release_conn( mi, mc ); 1457 1.1 lukem } 1458 1.1 lukem return NULL; 1459 1.1 lukem } 1460 1.1 lukem 1461 1.1 lukem if ( new_conn && ( sendok & LDAP_BACK_BINDING ) ) { 1462 1.1 lukem LDAP_BACK_CONN_BINDING_SET( &mc->mc_conns[ i ] ); 1463 1.1 lukem } 1464 1.1 lukem 1465 1.1 lukem candidates[ i ].sr_err = LDAP_SUCCESS; 1466 1.1 lukem META_CANDIDATE_SET( &candidates[ i ] ); 1467 1.1 lukem ncandidates++; 1468 1.1 lukem 1469 1.1 lukem if ( candidate ) { 1470 1.1 lukem *candidate = i; 1471 1.1 lukem } 1472 1.1 lukem 1473 1.1 lukem /* 1474 1.1 lukem * if no unique candidate ... 1475 1.1 lukem */ 1476 1.1 lukem } else { 1477 1.1 lukem 1478 1.1 lukem /* Looks like we didn't get a bind. Open a new session... */ 1479 1.1 lukem if ( mc == NULL ) { 1480 1.1 lukem assert( new_conn == 0 ); 1481 1.1 lukem mc = metaconn_alloc( op ); 1482 1.1 lukem mc->mc_conn = mc_curr.mc_conn; 1483 1.1 lukem ber_dupbv( &mc->mc_local_ndn, &mc_curr.mc_local_ndn ); 1484 1.1 lukem new_conn = 1; 1485 1.1 lukem if ( LDAP_BACK_CONN_ISPRIV( &mc_curr ) ) { 1486 1.1 lukem LDAP_BACK_CONN_ISPRIV_SET( mc ); 1487 1.1 lukem 1488 1.1 lukem } else if ( LDAP_BACK_CONN_ISANON( &mc_curr ) ) { 1489 1.1 lukem LDAP_BACK_CONN_ISANON_SET( mc ); 1490 1.1 lukem } 1491 1.1 lukem } 1492 1.1 lukem 1493 1.1 lukem for ( i = 0; i < mi->mi_ntargets; i++ ) { 1494 1.1 lukem metatarget_t *mt = mi->mi_targets[ i ]; 1495 1.1 lukem 1496 1.1 lukem META_CANDIDATE_RESET( &candidates[ i ] ); 1497 1.1 lukem 1498 1.1 lukem if ( i == cached 1499 1.1 lukem || meta_back_is_candidate( mt, &op->o_req_ndn, 1500 1.2 christos op->o_tag == LDAP_REQ_SEARCH ? op->ors_scope : LDAP_SCOPE_SUBTREE ) ) 1501 1.1 lukem { 1502 1.1 lukem 1503 1.1 lukem /* 1504 1.1 lukem * The target is activated; if needed, it is 1505 1.1 lukem * also init'd 1506 1.1 lukem */ 1507 1.1 lukem int lerr = meta_back_init_one_conn( op, rs, mc, i, 1508 1.1 lukem LDAP_BACK_CONN_ISPRIV( &mc_curr ), 1509 1.1 lukem LDAP_BACK_DONTSEND, !new_conn ); 1510 1.1 lukem candidates[ i ].sr_err = lerr; 1511 1.1 lukem if ( lerr == LDAP_SUCCESS ) { 1512 1.1 lukem META_CANDIDATE_SET( &candidates[ i ] ); 1513 1.1 lukem ncandidates++; 1514 1.1 lukem 1515 1.1 lukem Debug( LDAP_DEBUG_TRACE, "%s: meta_back_getconn[%d]\n", 1516 1.3 christos op->o_log_prefix, i ); 1517 1.1 lukem 1518 1.1 lukem } else if ( lerr == LDAP_UNAVAILABLE && !META_BACK_ONERR_STOP( mi ) ) { 1519 1.1 lukem META_CANDIDATE_SET( &candidates[ i ] ); 1520 1.1 lukem 1521 1.1 lukem Debug( LDAP_DEBUG_TRACE, "%s: meta_back_getconn[%d] %s\n", 1522 1.1 lukem op->o_log_prefix, i, 1523 1.1 lukem mt->mt_isquarantined != LDAP_BACK_FQ_NO ? "quarantined" : "unavailable" ); 1524 1.1 lukem 1525 1.1 lukem } else { 1526 1.1 lukem 1527 1.1 lukem /* 1528 1.1 lukem * FIXME: in case one target cannot 1529 1.1 lukem * be init'd, should the other ones 1530 1.1 lukem * be tried? 1531 1.1 lukem */ 1532 1.1 lukem if ( new_conn ) { 1533 1.1 lukem ( void )meta_clear_one_candidate( op, mc, i ); 1534 1.1 lukem } 1535 1.1 lukem /* leave the target candidate, but record the error for later use */ 1536 1.1 lukem err = lerr; 1537 1.1 lukem 1538 1.1 lukem if ( lerr == LDAP_UNAVAILABLE && mt->mt_isquarantined != LDAP_BACK_FQ_NO ) { 1539 1.3 christos Log( LDAP_DEBUG_TRACE, ldap_syslog_level, "%s: meta_back_getconn[%d] quarantined err=%d text=%s\n", 1540 1.2 christos op->o_log_prefix, i, lerr, rs->sr_text ); 1541 1.1 lukem 1542 1.1 lukem } else { 1543 1.3 christos Log( LDAP_DEBUG_ANY, ldap_syslog, "%s: meta_back_getconn[%d] failed err=%d text=%s\n", 1544 1.2 christos op->o_log_prefix, i, lerr, rs->sr_text ); 1545 1.1 lukem } 1546 1.1 lukem 1547 1.1 lukem if ( META_BACK_ONERR_STOP( mi ) ) { 1548 1.1 lukem if ( sendok & LDAP_BACK_SENDERR ) { 1549 1.1 lukem send_ldap_result( op, rs ); 1550 1.1 lukem } 1551 1.1 lukem if ( new_conn ) { 1552 1.1 lukem mc->mc_refcnt = 0; 1553 1.1 lukem meta_back_conn_free( mc ); 1554 1.1 lukem 1555 1.1 lukem } else { 1556 1.1 lukem meta_back_release_conn( mi, mc ); 1557 1.1 lukem } 1558 1.1 lukem 1559 1.1 lukem return NULL; 1560 1.1 lukem } 1561 1.1 lukem 1562 1.1 lukem continue; 1563 1.1 lukem } 1564 1.1 lukem 1565 1.1 lukem } else { 1566 1.1 lukem if ( new_conn ) { 1567 1.1 lukem ( void )meta_clear_one_candidate( op, mc, i ); 1568 1.1 lukem } 1569 1.1 lukem } 1570 1.1 lukem } 1571 1.1 lukem 1572 1.1 lukem if ( ncandidates == 0 ) { 1573 1.1 lukem if ( new_conn ) { 1574 1.1 lukem mc->mc_refcnt = 0; 1575 1.1 lukem meta_back_conn_free( mc ); 1576 1.1 lukem 1577 1.1 lukem } else { 1578 1.1 lukem meta_back_release_conn( mi, mc ); 1579 1.1 lukem } 1580 1.1 lukem 1581 1.1 lukem if ( rs->sr_err == LDAP_SUCCESS ) { 1582 1.1 lukem rs->sr_err = LDAP_NO_SUCH_OBJECT; 1583 1.1 lukem rs->sr_text = "Unable to select valid candidates"; 1584 1.1 lukem } 1585 1.1 lukem 1586 1.1 lukem if ( sendok & LDAP_BACK_SENDERR ) { 1587 1.1 lukem if ( rs->sr_err == LDAP_NO_SUCH_OBJECT ) { 1588 1.1 lukem rs->sr_matched = op->o_bd->be_suffix[ 0 ].bv_val; 1589 1.1 lukem } 1590 1.1 lukem send_ldap_result( op, rs ); 1591 1.1 lukem rs->sr_matched = NULL; 1592 1.1 lukem } 1593 1.1 lukem 1594 1.1 lukem return NULL; 1595 1.1 lukem } 1596 1.1 lukem } 1597 1.1 lukem 1598 1.1 lukem done:; 1599 1.1 lukem /* clear out meta_back_init_one_conn non-fatal errors */ 1600 1.1 lukem rs->sr_err = LDAP_SUCCESS; 1601 1.1 lukem rs->sr_text = NULL; 1602 1.1 lukem 1603 1.1 lukem /* touch the timestamp */ 1604 1.1 lukem if ( mi->mi_idle_timeout != 0 ) { 1605 1.1 lukem mc->mc_time = op->o_time; 1606 1.1 lukem } 1607 1.1 lukem 1608 1.1 lukem if ( new_conn ) { 1609 1.1 lukem if ( mi->mi_conn_ttl ) { 1610 1.1 lukem mc->mc_create_time = op->o_time; 1611 1.1 lukem } 1612 1.1 lukem 1613 1.1 lukem /* 1614 1.1 lukem * Inserts the newly created metaconn in the avl tree 1615 1.1 lukem */ 1616 1.1 lukem ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex ); 1617 1.1 lukem #if META_BACK_PRINT_CONNTREE > 0 1618 1.1 lukem meta_back_print_conntree( mi, ">>> meta_back_getconn" ); 1619 1.1 lukem #endif /* META_BACK_PRINT_CONNTREE */ 1620 1.1 lukem 1621 1.1 lukem err = 0; 1622 1.1 lukem if ( LDAP_BACK_PCONN_ISPRIV( mc ) ) { 1623 1.1 lukem if ( mi->mi_conn_priv[ LDAP_BACK_CONN2PRIV( mc ) ].mic_num < mi->mi_conn_priv_max ) { 1624 1.1 lukem LDAP_TAILQ_INSERT_TAIL( &mi->mi_conn_priv[ LDAP_BACK_CONN2PRIV( mc ) ].mic_priv, mc, mc_q ); 1625 1.1 lukem mi->mi_conn_priv[ LDAP_BACK_CONN2PRIV( mc ) ].mic_num++; 1626 1.1 lukem LDAP_BACK_CONN_CACHED_SET( mc ); 1627 1.1 lukem 1628 1.1 lukem } else { 1629 1.1 lukem LDAP_BACK_CONN_TAINTED_SET( mc ); 1630 1.1 lukem } 1631 1.1 lukem rs->sr_err = 0; 1632 1.1 lukem 1633 1.1 lukem } else if ( !( sendok & LDAP_BACK_BINDING ) ) { 1634 1.3 christos err = ldap_tavl_insert( &mi->mi_conninfo.lai_tree, ( caddr_t )mc, 1635 1.1 lukem meta_back_conndn_cmp, meta_back_conndn_dup ); 1636 1.1 lukem LDAP_BACK_CONN_CACHED_SET( mc ); 1637 1.1 lukem } 1638 1.1 lukem 1639 1.1 lukem #if META_BACK_PRINT_CONNTREE > 0 1640 1.1 lukem meta_back_print_conntree( mi, "<<< meta_back_getconn" ); 1641 1.1 lukem #endif /* META_BACK_PRINT_CONNTREE */ 1642 1.1 lukem ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex ); 1643 1.1 lukem 1644 1.1 lukem if ( !LDAP_BACK_PCONN_ISPRIV( mc ) ) { 1645 1.1 lukem /* 1646 1.1 lukem * Err could be -1 in case a duplicate metaconn is inserted 1647 1.1 lukem */ 1648 1.1 lukem switch ( err ) { 1649 1.1 lukem case 0: 1650 1.1 lukem break; 1651 1.1 lukem 1652 1.1 lukem case -1: 1653 1.1 lukem LDAP_BACK_CONN_CACHED_CLEAR( mc ); 1654 1.1 lukem /* duplicate: free and try to get the newly created one */ 1655 1.1 lukem if ( !( sendok & LDAP_BACK_BINDING ) && !LDAP_BACK_USE_TEMPORARIES( mi ) ) { 1656 1.1 lukem mc->mc_refcnt = 0; 1657 1.1 lukem meta_back_conn_free( mc ); 1658 1.1 lukem 1659 1.1 lukem new_conn = 0; 1660 1.1 lukem goto retry_lock; 1661 1.1 lukem } 1662 1.1 lukem 1663 1.1 lukem LDAP_BACK_CONN_TAINTED_SET( mc ); 1664 1.1 lukem break; 1665 1.1 lukem 1666 1.1 lukem default: 1667 1.1 lukem LDAP_BACK_CONN_CACHED_CLEAR( mc ); 1668 1.2 christos if ( LogTest( LDAP_DEBUG_ANY ) ) { 1669 1.2 christos char buf[STRLENOF("4294967295U") + 1] = { 0 }; 1670 1.2 christos mi->mi_ldap_extra->connid2str( &mc->mc_base, buf, sizeof(buf) ); 1671 1.2 christos 1672 1.2 christos Debug( LDAP_DEBUG_ANY, 1673 1.2 christos "%s meta_back_getconn: candidates=%d conn=%s insert failed\n", 1674 1.2 christos op->o_log_prefix, ncandidates, buf ); 1675 1.2 christos } 1676 1.1 lukem 1677 1.1 lukem mc->mc_refcnt = 0; 1678 1.1 lukem meta_back_conn_free( mc ); 1679 1.1 lukem 1680 1.1 lukem rs->sr_err = LDAP_OTHER; 1681 1.1 lukem rs->sr_text = "Proxy bind collision"; 1682 1.1 lukem if ( sendok & LDAP_BACK_SENDERR ) { 1683 1.1 lukem send_ldap_result( op, rs ); 1684 1.1 lukem } 1685 1.1 lukem return NULL; 1686 1.1 lukem } 1687 1.1 lukem } 1688 1.1 lukem 1689 1.2 christos if ( LogTest( LDAP_DEBUG_TRACE ) ) { 1690 1.2 christos char buf[STRLENOF("4294967295U") + 1] = { 0 }; 1691 1.2 christos mi->mi_ldap_extra->connid2str( &mc->mc_base, buf, sizeof(buf) ); 1692 1.2 christos 1693 1.2 christos Debug( LDAP_DEBUG_TRACE, 1694 1.2 christos "%s meta_back_getconn: candidates=%d conn=%s inserted\n", 1695 1.2 christos op->o_log_prefix, ncandidates, buf ); 1696 1.2 christos } 1697 1.1 lukem 1698 1.1 lukem } else { 1699 1.2 christos if ( LogTest( LDAP_DEBUG_TRACE ) ) { 1700 1.2 christos char buf[STRLENOF("4294967295U") + 1] = { 0 }; 1701 1.2 christos mi->mi_ldap_extra->connid2str( &mc->mc_base, buf, sizeof(buf) ); 1702 1.2 christos 1703 1.2 christos Debug( LDAP_DEBUG_TRACE, 1704 1.2 christos "%s meta_back_getconn: candidates=%d conn=%s fetched\n", 1705 1.2 christos op->o_log_prefix, ncandidates, buf ); 1706 1.2 christos } 1707 1.1 lukem } 1708 1.1 lukem 1709 1.1 lukem return mc; 1710 1.1 lukem } 1711 1.1 lukem 1712 1.1 lukem void 1713 1.1 lukem meta_back_release_conn_lock( 1714 1.1 lukem metainfo_t *mi, 1715 1.1 lukem metaconn_t *mc, 1716 1.1 lukem int dolock ) 1717 1.1 lukem { 1718 1.1 lukem assert( mc != NULL ); 1719 1.1 lukem 1720 1.1 lukem if ( dolock ) { 1721 1.1 lukem ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex ); 1722 1.1 lukem } 1723 1.1 lukem assert( mc->mc_refcnt > 0 ); 1724 1.1 lukem mc->mc_refcnt--; 1725 1.1 lukem /* NOTE: the connection is removed if either it is tainted 1726 1.1 lukem * or if it is shared and no one else is using it. This needs 1727 1.1 lukem * to occur because for intrinsic reasons cached connections 1728 1.1 lukem * that are not privileged would live forever and pollute 1729 1.1 lukem * the connection space (and eat up resources). Maybe this 1730 1.1 lukem * should be configurable... */ 1731 1.1 lukem if ( LDAP_BACK_CONN_TAINTED( mc ) || !LDAP_BACK_CONN_CACHED( mc ) ) { 1732 1.1 lukem #if META_BACK_PRINT_CONNTREE > 0 1733 1.1 lukem meta_back_print_conntree( mi, ">>> meta_back_release_conn" ); 1734 1.1 lukem #endif /* META_BACK_PRINT_CONNTREE */ 1735 1.1 lukem 1736 1.1 lukem if ( LDAP_BACK_PCONN_ISPRIV( mc ) ) { 1737 1.1 lukem if ( mc->mc_q.tqe_prev != NULL ) { 1738 1.1 lukem assert( LDAP_BACK_CONN_CACHED( mc ) ); 1739 1.1 lukem assert( mi->mi_conn_priv[ LDAP_BACK_CONN2PRIV( mc ) ].mic_num > 0 ); 1740 1.1 lukem LDAP_TAILQ_REMOVE( &mi->mi_conn_priv[ LDAP_BACK_CONN2PRIV( mc ) ].mic_priv, mc, mc_q ); 1741 1.1 lukem mi->mi_conn_priv[ LDAP_BACK_CONN2PRIV( mc ) ].mic_num--; 1742 1.1 lukem LDAP_TAILQ_ENTRY_INIT( mc, mc_q ); 1743 1.1 lukem 1744 1.1 lukem } else { 1745 1.1 lukem assert( !LDAP_BACK_CONN_CACHED( mc ) ); 1746 1.1 lukem } 1747 1.1 lukem 1748 1.1 lukem } else if ( LDAP_BACK_CONN_CACHED( mc ) ) { 1749 1.1 lukem metaconn_t *tmpmc; 1750 1.1 lukem 1751 1.3 christos tmpmc = ldap_tavl_delete( &mi->mi_conninfo.lai_tree, 1752 1.1 lukem ( caddr_t )mc, meta_back_conndnmc_cmp ); 1753 1.1 lukem 1754 1.1 lukem /* Overparanoid, but useful... */ 1755 1.1 lukem assert( tmpmc == NULL || tmpmc == mc ); 1756 1.1 lukem } 1757 1.1 lukem 1758 1.1 lukem LDAP_BACK_CONN_CACHED_CLEAR( mc ); 1759 1.1 lukem 1760 1.1 lukem #if META_BACK_PRINT_CONNTREE > 0 1761 1.1 lukem meta_back_print_conntree( mi, "<<< meta_back_release_conn" ); 1762 1.1 lukem #endif /* META_BACK_PRINT_CONNTREE */ 1763 1.1 lukem 1764 1.1 lukem if ( mc->mc_refcnt == 0 ) { 1765 1.1 lukem meta_back_conn_free( mc ); 1766 1.1 lukem mc = NULL; 1767 1.1 lukem } 1768 1.1 lukem } 1769 1.1 lukem 1770 1.1 lukem if ( mc != NULL && LDAP_BACK_CONN_BINDING( mc ) ) { 1771 1.1 lukem LDAP_BACK_CONN_BINDING_CLEAR( mc ); 1772 1.1 lukem } 1773 1.1 lukem 1774 1.1 lukem if ( dolock ) { 1775 1.1 lukem ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex ); 1776 1.1 lukem } 1777 1.1 lukem } 1778 1.1 lukem 1779 1.1 lukem void 1780 1.1 lukem meta_back_quarantine( 1781 1.1 lukem Operation *op, 1782 1.1 lukem SlapReply *rs, 1783 1.1 lukem int candidate ) 1784 1.1 lukem { 1785 1.1 lukem metainfo_t *mi = (metainfo_t *)op->o_bd->be_private; 1786 1.1 lukem metatarget_t *mt = mi->mi_targets[ candidate ]; 1787 1.1 lukem 1788 1.1 lukem slap_retry_info_t *ri = &mt->mt_quarantine; 1789 1.1 lukem 1790 1.1 lukem ldap_pvt_thread_mutex_lock( &mt->mt_quarantine_mutex ); 1791 1.1 lukem 1792 1.1 lukem if ( rs->sr_err == LDAP_UNAVAILABLE ) { 1793 1.1 lukem time_t new_last = slap_get_time(); 1794 1.1 lukem 1795 1.1 lukem switch ( mt->mt_isquarantined ) { 1796 1.1 lukem case LDAP_BACK_FQ_NO: 1797 1.1 lukem if ( ri->ri_last == new_last ) { 1798 1.1 lukem goto done; 1799 1.1 lukem } 1800 1.1 lukem 1801 1.1 lukem Debug( LDAP_DEBUG_ANY, 1802 1.1 lukem "%s meta_back_quarantine[%d]: enter.\n", 1803 1.3 christos op->o_log_prefix, candidate ); 1804 1.1 lukem 1805 1.1 lukem ri->ri_idx = 0; 1806 1.1 lukem ri->ri_count = 0; 1807 1.1 lukem break; 1808 1.1 lukem 1809 1.1 lukem case LDAP_BACK_FQ_RETRYING: 1810 1.3 christos Debug(LDAP_DEBUG_ANY, 1811 1.3 christos "%s meta_back_quarantine[%d]: block #%d try #%d failed.\n", 1812 1.3 christos op->o_log_prefix, candidate, ri->ri_idx, 1813 1.3 christos ri->ri_count ); 1814 1.1 lukem 1815 1.1 lukem ++ri->ri_count; 1816 1.1 lukem if ( ri->ri_num[ ri->ri_idx ] != SLAP_RETRYNUM_FOREVER 1817 1.1 lukem && ri->ri_count == ri->ri_num[ ri->ri_idx ] ) 1818 1.1 lukem { 1819 1.1 lukem ri->ri_count = 0; 1820 1.1 lukem ++ri->ri_idx; 1821 1.1 lukem } 1822 1.1 lukem break; 1823 1.1 lukem 1824 1.1 lukem default: 1825 1.3 christos goto done; 1826 1.1 lukem } 1827 1.1 lukem 1828 1.1 lukem mt->mt_isquarantined = LDAP_BACK_FQ_YES; 1829 1.1 lukem ri->ri_last = new_last; 1830 1.1 lukem 1831 1.1 lukem } else if ( mt->mt_isquarantined == LDAP_BACK_FQ_RETRYING ) { 1832 1.1 lukem Debug( LDAP_DEBUG_ANY, 1833 1.1 lukem "%s meta_back_quarantine[%d]: exit.\n", 1834 1.3 christos op->o_log_prefix, candidate ); 1835 1.1 lukem 1836 1.1 lukem if ( mi->mi_quarantine_f ) { 1837 1.1 lukem (void)mi->mi_quarantine_f( mi, candidate, 1838 1.1 lukem mi->mi_quarantine_p ); 1839 1.1 lukem } 1840 1.1 lukem 1841 1.1 lukem ri->ri_count = 0; 1842 1.1 lukem ri->ri_idx = 0; 1843 1.1 lukem mt->mt_isquarantined = LDAP_BACK_FQ_NO; 1844 1.1 lukem } 1845 1.1 lukem 1846 1.1 lukem done:; 1847 1.1 lukem ldap_pvt_thread_mutex_unlock( &mt->mt_quarantine_mutex ); 1848 1.1 lukem } 1849