1/* $NetBSD: search.c,v 1.2 2021/08/14 16:14:59 christos Exp $ */ 2 3/* search.c - search request handler for back-asyncmeta */ 4/* $OpenLDAP$ */ 5/* This work is part of OpenLDAP Software <http://www.openldap.org/>. 6 * 7 * Copyright 2016-2021 The OpenLDAP Foundation. 8 * Portions Copyright 2016 Symas Corporation. 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 20/* ACKNOWLEDGEMENTS: 21 * This work was developed by Symas Corporation 22 * based on back-meta module for inclusion in OpenLDAP Software. 23 * This work was sponsored by Ericsson. */ 24 25#include <sys/cdefs.h> 26__RCSID("$NetBSD: search.c,v 1.2 2021/08/14 16:14:59 christos Exp $"); 27 28#include "portable.h" 29 30#include <stdio.h> 31 32#include <ac/socket.h> 33#include <ac/string.h> 34#include <ac/time.h> 35#include "slap.h" 36#include "../../../libraries/liblber/lber-int.h" 37#include "../../../libraries/libldap/ldap-int.h" 38#include "lutil.h" 39#include "../back-ldap/back-ldap.h" 40#include "back-asyncmeta.h" 41 42static void 43asyncmeta_handle_onerr_stop(Operation *op, 44 SlapReply *rs, 45 a_metaconn_t *mc, 46 bm_context_t *bc, 47 int candidate) 48{ 49 a_metainfo_t *mi = mc->mc_info; 50 int j; 51 ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex); 52 if (asyncmeta_bc_in_queue(mc,bc) == NULL || bc->bc_active > 1) { 53 bc->bc_active--; 54 ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex); 55 return; 56 } 57 asyncmeta_drop_bc(mc, bc); 58 for (j=0; j<mi->mi_ntargets; j++) { 59 if (j != candidate && bc->candidates[j].sr_msgid >= 0 60 && mc->mc_conns[j].msc_ld != NULL && !META_BACK_CONN_CREATING( &mc->mc_conns[j] )) { 61 asyncmeta_back_cancel( mc, op, 62 bc->candidates[ j ].sr_msgid, j ); 63 } 64 } 65 slap_sl_mem_setctx(op->o_threadctx, op->o_tmpmemctx); 66 ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex); 67 send_ldap_result(op, rs); 68} 69 70static int 71asyncmeta_int_filter2bv( a_dncookie *dc, 72 Filter *f, 73 struct berval *fstr ) 74{ 75 int i; 76 Filter *p; 77 struct berval atmp, 78 vtmp, 79 ntmp, 80 *tmp; 81 static struct berval 82 /* better than nothing... */ 83 ber_bvfalse = BER_BVC( "(!(objectClass=*))" ), 84 ber_bvtf_false = BER_BVC( "(|)" ), 85 /* better than nothing... */ 86 ber_bvtrue = BER_BVC( "(objectClass=*)" ), 87 ber_bvtf_true = BER_BVC( "(&)" ), 88 ber_bverror = BER_BVC( "(?=error)" ), 89 ber_bvunknown = BER_BVC( "(?=unknown)" ), 90 ber_bvnone = BER_BVC( "(?=none)" ); 91 ber_len_t len; 92 void *memctx = dc->memctx; 93 94 assert( fstr != NULL ); 95 BER_BVZERO( fstr ); 96 97 if ( f == NULL ) { 98 ber_dupbv_x( fstr, &ber_bvnone, memctx ); 99 return LDAP_OTHER; 100 } 101 102 switch ( ( f->f_choice & SLAPD_FILTER_MASK ) ) { 103 case LDAP_FILTER_EQUALITY: 104 if ( f->f_av_desc->ad_type->sat_syntax == slap_schema.si_syn_distinguishedName ) { 105 asyncmeta_dn_massage( dc, &f->f_av_value, &vtmp ); 106 } else { 107 vtmp = f->f_av_value; 108 } 109 110 filter_escape_value_x( &vtmp, &ntmp, memctx ); 111 fstr->bv_len = f->f_av_desc->ad_cname.bv_len + ntmp.bv_len 112 + ( sizeof("(=)") - 1 ); 113 fstr->bv_val = dc->op->o_tmpalloc( fstr->bv_len + 1, memctx ); 114 115 snprintf( fstr->bv_val, fstr->bv_len + 1, "(%s=%s)", 116 f->f_av_desc->ad_cname.bv_val, ntmp.bv_len ? ntmp.bv_val : "" ); 117 118 ber_memfree_x( ntmp.bv_val, memctx ); 119 break; 120 121 case LDAP_FILTER_GE: 122 filter_escape_value_x( &f->f_av_value, &ntmp, memctx ); 123 fstr->bv_len = f->f_av_desc->ad_cname.bv_len + ntmp.bv_len 124 + ( sizeof("(>=)") - 1 ); 125 fstr->bv_val = dc->op->o_tmpalloc( fstr->bv_len + 1, memctx ); 126 127 snprintf( fstr->bv_val, fstr->bv_len + 1, "(%s>=%s)", 128 f->f_av_desc->ad_cname.bv_val, ntmp.bv_len ? ntmp.bv_val : "" ); 129 130 ber_memfree_x( ntmp.bv_val, memctx ); 131 break; 132 133 case LDAP_FILTER_LE: 134 filter_escape_value_x( &f->f_av_value, &ntmp, memctx ); 135 fstr->bv_len = f->f_av_desc->ad_cname.bv_len + ntmp.bv_len 136 + ( sizeof("(<=)") - 1 ); 137 fstr->bv_val = dc->op->o_tmpalloc( fstr->bv_len + 1, memctx ); 138 139 snprintf( fstr->bv_val, fstr->bv_len + 1, "(%s<=%s)", 140 f->f_av_desc->ad_cname.bv_val, ntmp.bv_len ? ntmp.bv_val : "" ); 141 142 ber_memfree_x( ntmp.bv_val, memctx ); 143 break; 144 145 case LDAP_FILTER_APPROX: 146 filter_escape_value_x( &f->f_av_value, &ntmp, memctx ); 147 fstr->bv_len = f->f_av_desc->ad_cname.bv_len + ntmp.bv_len 148 + ( sizeof("(~=)") - 1 ); 149 fstr->bv_val = dc->op->o_tmpalloc( fstr->bv_len + 1, memctx ); 150 151 snprintf( fstr->bv_val, fstr->bv_len + 1, "(%s~=%s)", 152 f->f_av_desc->ad_cname.bv_val, ntmp.bv_len ? ntmp.bv_val : "" ); 153 154 ber_memfree_x( ntmp.bv_val, memctx ); 155 break; 156 157 case LDAP_FILTER_SUBSTRINGS: 158 fstr->bv_len = f->f_sub_desc->ad_cname.bv_len + ( STRLENOF( "(=*)" ) ); 159 fstr->bv_val = dc->op->o_tmpalloc( fstr->bv_len + 128, memctx ); /* FIXME: why 128 ? */ 160 161 snprintf( fstr->bv_val, fstr->bv_len + 1, "(%s=*)", 162 f->f_sub_desc->ad_cname.bv_val ); 163 164 if ( !BER_BVISNULL( &f->f_sub_initial ) ) { 165 len = fstr->bv_len; 166 167 filter_escape_value_x( &f->f_sub_initial, &ntmp, memctx ); 168 169 fstr->bv_len += ntmp.bv_len; 170 fstr->bv_val = dc->op->o_tmprealloc( fstr->bv_val, fstr->bv_len + 1, memctx ); 171 172 snprintf( &fstr->bv_val[len - 2], ntmp.bv_len + 3, 173 /* "(attr=" */ "%s*)", 174 ntmp.bv_len ? ntmp.bv_val : "" ); 175 176 ber_memfree_x( ntmp.bv_val, memctx ); 177 } 178 179 if ( f->f_sub_any != NULL ) { 180 for ( i = 0; !BER_BVISNULL( &f->f_sub_any[i] ); i++ ) { 181 len = fstr->bv_len; 182 filter_escape_value_x( &f->f_sub_any[i], &ntmp, memctx ); 183 184 fstr->bv_len += ntmp.bv_len + 1; 185 fstr->bv_val = dc->op->o_tmprealloc( fstr->bv_val, fstr->bv_len + 1, memctx ); 186 187 snprintf( &fstr->bv_val[len - 1], ntmp.bv_len + 3, 188 /* "(attr=[init]*[any*]" */ "%s*)", 189 ntmp.bv_len ? ntmp.bv_val : "" ); 190 ber_memfree_x( ntmp.bv_val, memctx ); 191 } 192 } 193 194 if ( !BER_BVISNULL( &f->f_sub_final ) ) { 195 len = fstr->bv_len; 196 197 filter_escape_value_x( &f->f_sub_final, &ntmp, memctx ); 198 199 fstr->bv_len += ntmp.bv_len; 200 fstr->bv_val = dc->op->o_tmprealloc( fstr->bv_val, fstr->bv_len + 1, memctx ); 201 202 snprintf( &fstr->bv_val[len - 1], ntmp.bv_len + 3, 203 /* "(attr=[init*][any*]" */ "%s)", 204 ntmp.bv_len ? ntmp.bv_val : "" ); 205 206 ber_memfree_x( ntmp.bv_val, memctx ); 207 } 208 209 break; 210 211 case LDAP_FILTER_PRESENT: 212 fstr->bv_len = f->f_desc->ad_cname.bv_len + ( STRLENOF( "(=*)" ) ); 213 fstr->bv_val = dc->op->o_tmpalloc( fstr->bv_len + 1, memctx ); 214 215 snprintf( fstr->bv_val, fstr->bv_len + 1, "(%s=*)", 216 f->f_desc->ad_cname.bv_val ); 217 break; 218 219 case LDAP_FILTER_AND: 220 case LDAP_FILTER_OR: 221 case LDAP_FILTER_NOT: 222 fstr->bv_len = STRLENOF( "(%)" ); 223 fstr->bv_val = dc->op->o_tmpalloc( fstr->bv_len + 128, memctx ); /* FIXME: why 128? */ 224 225 snprintf( fstr->bv_val, fstr->bv_len + 1, "(%c)", 226 f->f_choice == LDAP_FILTER_AND ? '&' : 227 f->f_choice == LDAP_FILTER_OR ? '|' : '!' ); 228 229 for ( p = f->f_list; p != NULL; p = p->f_next ) { 230 int rc; 231 232 len = fstr->bv_len; 233 234 rc = asyncmeta_int_filter2bv( dc, p, &vtmp ); 235 if ( rc != LDAP_SUCCESS ) { 236 return rc; 237 } 238 239 fstr->bv_len += vtmp.bv_len; 240 fstr->bv_val = dc->op->o_tmprealloc( fstr->bv_val, fstr->bv_len + 1, memctx ); 241 242 snprintf( &fstr->bv_val[len-1], vtmp.bv_len + 2, 243 /*"("*/ "%s)", vtmp.bv_len ? vtmp.bv_val : "" ); 244 245 ber_memfree_x( vtmp.bv_val, memctx ); 246 } 247 248 break; 249 250 case LDAP_FILTER_EXT: 251 if ( f->f_mr_desc ) { 252 atmp = f->f_mr_desc->ad_cname; 253 254 } else { 255 BER_BVSTR( &atmp, "" ); 256 } 257 filter_escape_value_x( &f->f_mr_value, &ntmp, memctx ); 258 259 /* FIXME: cleanup (less ?: operators...) */ 260 fstr->bv_len = atmp.bv_len + 261 ( f->f_mr_dnattrs ? STRLENOF( ":dn" ) : 0 ) + 262 ( !BER_BVISEMPTY( &f->f_mr_rule_text ) ? f->f_mr_rule_text.bv_len + 1 : 0 ) + 263 ntmp.bv_len + ( STRLENOF( "(:=)" ) ); 264 fstr->bv_val = dc->op->o_tmpalloc( fstr->bv_len + 1, memctx ); 265 266 snprintf( fstr->bv_val, fstr->bv_len + 1, "(%s%s%s%s:=%s)", 267 atmp.bv_val, 268 f->f_mr_dnattrs ? ":dn" : "", 269 !BER_BVISEMPTY( &f->f_mr_rule_text ) ? ":" : "", 270 !BER_BVISEMPTY( &f->f_mr_rule_text ) ? f->f_mr_rule_text.bv_val : "", 271 ntmp.bv_len ? ntmp.bv_val : "" ); 272 ber_memfree_x( ntmp.bv_val, memctx ); 273 break; 274 275 case SLAPD_FILTER_COMPUTED: 276 switch ( f->f_result ) { 277 /* FIXME: treat UNDEFINED as FALSE */ 278 case SLAPD_COMPARE_UNDEFINED: 279 if ( META_BACK_TGT_NOUNDEFFILTER( dc->target ) ) { 280 return LDAP_COMPARE_FALSE; 281 } 282 /* fallthru */ 283 284 case LDAP_COMPARE_FALSE: 285 if ( META_BACK_TGT_T_F( dc->target ) ) { 286 tmp = &ber_bvtf_false; 287 break; 288 } 289 tmp = &ber_bvfalse; 290 break; 291 292 case LDAP_COMPARE_TRUE: 293 if ( META_BACK_TGT_T_F( dc->target ) ) { 294 tmp = &ber_bvtf_true; 295 break; 296 } 297 298 tmp = &ber_bvtrue; 299 break; 300 301 default: 302 tmp = &ber_bverror; 303 break; 304 } 305 306 ber_dupbv_x( fstr, tmp, memctx ); 307 break; 308 309 default: 310 ber_dupbv_x( fstr, &ber_bvunknown, memctx ); 311 break; 312 } 313 314 return 0; 315} 316meta_search_candidate_t 317asyncmeta_back_search_start( 318 Operation *op, 319 SlapReply *rs, 320 a_metaconn_t *mc, 321 bm_context_t *bc, 322 int candidate, 323 struct berval *prcookie, 324 ber_int_t prsize, 325 int do_lock) 326{ 327 SlapReply *candidates = bc->candidates; 328 a_metainfo_t *mi = ( a_metainfo_t * )mc->mc_info; 329 a_metatarget_t *mt = mi->mi_targets[ candidate ]; 330 a_metasingleconn_t *msc = &mc->mc_conns[ candidate ]; 331 a_dncookie dc; 332 struct berval realbase = op->o_req_dn; 333 char **attrs; 334 int realscope = op->ors_scope; 335 struct berval mbase = BER_BVNULL; 336 int rc; 337 struct berval filterbv = BER_BVNULL; 338 meta_search_candidate_t retcode; 339 int timelimit; 340 LDAPControl **ctrls = NULL; 341 BerElement *ber = NULL; 342 ber_int_t msgid; 343 ber_socket_t s = -1; 344#ifdef SLAPD_META_CLIENT_PR 345 LDAPControl **save_ctrls = NULL; 346#endif /* SLAPD_META_CLIENT_PR */ 347 348 /* this should not happen; just in case... */ 349 if ( msc->msc_ld == NULL ) { 350 Debug( LDAP_DEBUG_ANY, 351 "%s: asyncmeta_back_search_start candidate=%d ld=NULL%s.\n", 352 op->o_log_prefix, candidate, 353 META_BACK_ONERR_STOP( mi ) ? "" : " (ignored)" ); 354 candidates[ candidate ].sr_err = LDAP_OTHER; 355 if ( META_BACK_ONERR_STOP( mi ) ) { 356 return META_SEARCH_ERR; 357 } 358 candidates[ candidate ].sr_msgid = META_MSGID_IGNORE; 359 return META_SEARCH_NOT_CANDIDATE; 360 } 361 362 Debug( LDAP_DEBUG_TRACE, "%s >>> asyncmeta_back_search_start: dn=%s filter=%s\n", 363 op->o_log_prefix, op->o_req_dn.bv_val, op->ors_filterstr.bv_val ); 364 /* 365 * modifies the base according to the scope, if required 366 */ 367 if ( mt->mt_nsuffix.bv_len > op->o_req_ndn.bv_len ) { 368 switch ( op->ors_scope ) { 369 case LDAP_SCOPE_SUBTREE: 370 /* 371 * make the target suffix the new base 372 * FIXME: this is very forgiving, because 373 * "illegal" searchBases may be turned 374 * into the suffix of the target; however, 375 * the requested searchBase already passed 376 * thru the candidate analyzer... 377 */ 378 if ( dnIsSuffix( &mt->mt_nsuffix, &op->o_req_ndn ) ) { 379 realbase = mt->mt_nsuffix; 380 if ( mt->mt_scope == LDAP_SCOPE_SUBORDINATE ) { 381 realscope = LDAP_SCOPE_SUBORDINATE; 382 } 383 384 } else { 385 /* 386 * this target is no longer candidate 387 */ 388 retcode = META_SEARCH_NOT_CANDIDATE; 389 goto doreturn; 390 } 391 break; 392 393 case LDAP_SCOPE_SUBORDINATE: 394 case LDAP_SCOPE_ONELEVEL: 395 { 396 struct berval rdn = mt->mt_nsuffix; 397 rdn.bv_len -= op->o_req_ndn.bv_len + STRLENOF( "," ); 398 if ( dnIsOneLevelRDN( &rdn ) 399 && dnIsSuffix( &mt->mt_nsuffix, &op->o_req_ndn ) ) 400 { 401 /* 402 * if there is exactly one level, 403 * make the target suffix the new 404 * base, and make scope "base" 405 */ 406 realbase = mt->mt_nsuffix; 407 if ( op->ors_scope == LDAP_SCOPE_SUBORDINATE ) { 408 if ( mt->mt_scope == LDAP_SCOPE_SUBORDINATE ) { 409 realscope = LDAP_SCOPE_SUBORDINATE; 410 } else { 411 realscope = LDAP_SCOPE_SUBTREE; 412 } 413 } else { 414 realscope = LDAP_SCOPE_BASE; 415 } 416 break; 417 } /* else continue with the next case */ 418 } 419 420 case LDAP_SCOPE_BASE: 421 /* 422 * this target is no longer candidate 423 */ 424 retcode = META_SEARCH_NOT_CANDIDATE; 425 goto doreturn; 426 } 427 } 428 429 /* check filter expression */ 430 if ( mt->mt_filter ) { 431 metafilter_t *mf; 432 for ( mf = mt->mt_filter; mf; mf = mf->mf_next ) { 433 if ( regexec( &mf->mf_regex, op->ors_filterstr.bv_val, 0, NULL, 0 ) == 0 ) 434 break; 435 } 436 /* nothing matched, this target is no longer a candidate */ 437 if ( !mf ) { 438 retcode = META_SEARCH_NOT_CANDIDATE; 439 goto doreturn; 440 } 441 } 442 443 /* 444 * Rewrite the search base, if required 445 */ 446 dc.op = op; 447 dc.target = mt; 448 dc.memctx = op->o_tmpmemctx; 449 dc.to_from = MASSAGE_REQ; 450 asyncmeta_dn_massage( &dc, &realbase, &mbase ); 451 452 attrs = anlist2charray_x( op->ors_attrs, 0, op->o_tmpmemctx ); 453 454 if ( op->ors_tlimit != SLAP_NO_LIMIT ) { 455 timelimit = op->ors_tlimit > 0 ? op->ors_tlimit : 1; 456 } else { 457 timelimit = -1; /* no limit */ 458 } 459 460#ifdef SLAPD_META_CLIENT_PR 461 save_ctrls = op->o_ctrls; 462 { 463 LDAPControl *pr_c = NULL; 464 int i = 0, nc = 0; 465 466 if ( save_ctrls ) { 467 for ( ; save_ctrls[i] != NULL; i++ ); 468 nc = i; 469 pr_c = ldap_control_find( LDAP_CONTROL_PAGEDRESULTS, save_ctrls, NULL ); 470 } 471 472 if ( pr_c != NULL ) nc--; 473 if ( mt->mt_ps > 0 || prcookie != NULL ) nc++; 474 475 if ( mt->mt_ps > 0 || prcookie != NULL || pr_c != NULL ) { 476 int src = 0, dst = 0; 477 BerElementBuffer berbuf; 478 BerElement *ber = (BerElement *)&berbuf; 479 struct berval val = BER_BVNULL; 480 ber_len_t len; 481 482 len = sizeof( LDAPControl * )*( nc + 1 ) + sizeof( LDAPControl ); 483 484 if ( mt->mt_ps > 0 || prcookie != NULL ) { 485 struct berval nullcookie = BER_BVNULL; 486 ber_tag_t tag; 487 488 if ( prsize == 0 && mt->mt_ps > 0 ) prsize = mt->mt_ps; 489 if ( prcookie == NULL ) prcookie = &nullcookie; 490 491 ber_init2( ber, NULL, LBER_USE_DER ); 492 tag = ber_printf( ber, "{iO}", prsize, prcookie ); 493 if ( tag == LBER_ERROR ) { 494 /* error */ 495 (void) ber_free_buf( ber ); 496 goto done_pr; 497 } 498 499 tag = ber_flatten2( ber, &val, 0 ); 500 if ( tag == LBER_ERROR ) { 501 /* error */ 502 (void) ber_free_buf( ber ); 503 goto done_pr; 504 } 505 506 len += val.bv_len + 1; 507 } 508 509 op->o_ctrls = op->o_tmpalloc( len, op->o_tmpmemctx ); 510 if ( save_ctrls ) { 511 for ( ; save_ctrls[ src ] != NULL; src++ ) { 512 if ( save_ctrls[ src ] != pr_c ) { 513 op->o_ctrls[ dst ] = save_ctrls[ src ]; 514 dst++; 515 } 516 } 517 } 518 519 if ( mt->mt_ps > 0 || prcookie != NULL ) { 520 op->o_ctrls[ dst ] = (LDAPControl *)&op->o_ctrls[ nc + 1 ]; 521 522 op->o_ctrls[ dst ]->ldctl_oid = LDAP_CONTROL_PAGEDRESULTS; 523 op->o_ctrls[ dst ]->ldctl_iscritical = 1; 524 525 op->o_ctrls[ dst ]->ldctl_value.bv_val = (char *)&op->o_ctrls[ dst ][ 1 ]; 526 AC_MEMCPY( op->o_ctrls[ dst ]->ldctl_value.bv_val, val.bv_val, val.bv_len + 1 ); 527 op->o_ctrls[ dst ]->ldctl_value.bv_len = val.bv_len; 528 dst++; 529 530 (void)ber_free_buf( ber ); 531 } 532 533 op->o_ctrls[ dst ] = NULL; 534 } 535done_pr:; 536 } 537#endif /* SLAPD_META_CLIENT_PR */ 538 539 asyncmeta_set_msc_time(msc); 540 ctrls = op->o_ctrls; 541 542 if ( asyncmeta_controls_add( op, rs, mc, candidate, bc->is_root, &ctrls ) 543 != LDAP_SUCCESS ) 544 { 545 candidates[ candidate ].sr_msgid = META_MSGID_IGNORE; 546 retcode = META_SEARCH_NOT_CANDIDATE; 547 goto done; 548 } 549 550 /* 551 * Starts the search 552 */ 553 /* someone reset the connection */ 554 if (!( LDAP_BACK_CONN_ISBOUND( msc ) 555 || LDAP_BACK_CONN_ISANON( msc )) || msc->msc_ld == NULL ) { 556 Debug( asyncmeta_debug, "msc %p not initialized at %s:%d\n", msc, __FILE__, __LINE__ ); 557 goto error_unavailable; 558 } 559 rc = asyncmeta_int_filter2bv( &dc, op->ors_filter, &filterbv ); 560 if ( rc ) { 561 retcode = META_SEARCH_ERR; 562 goto done; 563 } 564 565 ber = ldap_build_search_req( msc->msc_ld, 566 mbase.bv_val, realscope, filterbv.bv_val, 567 attrs, op->ors_attrsonly, 568 ctrls, NULL, timelimit, op->ors_slimit, op->ors_deref, 569 &msgid ); 570 if (!ber) { 571 Debug( asyncmeta_debug, "%s asyncmeta_back_search_start: Operation encoding failed with errno %d\n", 572 op->o_log_prefix, msc->msc_ld->ld_errno ); 573 rs->sr_err = LDAP_OPERATIONS_ERROR; 574 rs->sr_text = "Failed to encode proxied request"; 575 retcode = META_SEARCH_ERR; 576 goto done; 577 } 578 579 if (ber) { 580 struct timeval tv = {0, mt->mt_network_timeout*1000}; 581 582 if (!( LDAP_BACK_CONN_ISBOUND( msc ) 583 || LDAP_BACK_CONN_ISANON( msc )) || msc->msc_ld == NULL ) { 584 Debug( asyncmeta_debug, "msc %p not initialized at %s:%d\n", msc, __FILE__, __LINE__ ); 585 goto error_unavailable; 586 } 587 588 ldap_get_option( msc->msc_ld, LDAP_OPT_DESC, &s ); 589 if (s < 0) { 590 Debug( asyncmeta_debug, "msc %p not initialized at %s:%d\n", msc, __FILE__, __LINE__ ); 591 goto error_unavailable; 592 } 593 594 rc = ldap_int_poll( msc->msc_ld, s, &tv, 1); 595 if (rc < 0) { 596 Debug( asyncmeta_debug, "msc %p not writable within network timeout %s:%d\n", msc, __FILE__, __LINE__ ); 597 if ((msc->msc_result_time + META_BACK_RESULT_INTERVAL) < slap_get_time()) { 598 rc = LDAP_SERVER_DOWN; 599 } else { 600 goto error_unavailable; 601 } 602 } else { 603 candidates[ candidate ].sr_msgid = msgid; 604 rc = ldap_send_initial_request( msc->msc_ld, LDAP_REQ_SEARCH, 605 mbase.bv_val, ber, msgid ); 606 if (rc == msgid) 607 rc = LDAP_SUCCESS; 608 else 609 rc = LDAP_SERVER_DOWN; 610 ber = NULL; 611 } 612 613 switch ( rc ) { 614 case LDAP_SUCCESS: 615 retcode = META_SEARCH_CANDIDATE; 616 asyncmeta_set_msc_time(msc); 617 goto done; 618 619 case LDAP_SERVER_DOWN: 620 /* do not lock if called from asyncmeta_handle_bind_result. Also do not reset the connection */ 621 if (do_lock > 0) { 622 ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex); 623 asyncmeta_reset_msc(NULL, mc, candidate, 0, __FUNCTION__); 624 ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex); 625 } 626 Debug( asyncmeta_debug, "msc %p ldap_send_initial_request failed. %s:%d\n", msc, __FILE__, __LINE__ ); 627 goto error_unavailable; 628 629 default: 630 candidates[ candidate ].sr_msgid = META_MSGID_IGNORE; 631 retcode = META_SEARCH_NOT_CANDIDATE; 632 goto done; 633 } 634 } 635 636error_unavailable: 637 if (ber) 638 ber_free(ber, 1); 639 switch (bc->nretries[candidate]) { 640 case -1: /* nretries = forever */ 641 retcode = META_SEARCH_NEED_BIND; 642 ldap_pvt_thread_yield(); 643 break; 644 case 0: /* no retries left */ 645 candidates[ candidate ].sr_msgid = META_MSGID_IGNORE; 646 rs->sr_err = LDAP_UNAVAILABLE; 647 rs->sr_text = "Unable to send search request to target"; 648 retcode = META_SEARCH_ERR; 649 break; 650 default: /* more retries left - try to rebind and go again */ 651 retcode = META_SEARCH_NEED_BIND; 652 bc->nretries[candidate]--; 653 ldap_pvt_thread_yield(); 654 break; 655 } 656done:; 657#if 0 658 (void)mi->mi_ldap_extra->controls_free( op, rs, &ctrls ); 659#endif 660#ifdef SLAPD_META_CLIENT_PR 661 if ( save_ctrls != op->o_ctrls ) { 662 op->o_tmpfree( op->o_ctrls, op->o_tmpmemctx ); 663 op->o_ctrls = save_ctrls; 664 } 665#endif /* SLAPD_META_CLIENT_PR */ 666 667 if ( mbase.bv_val != realbase.bv_val ) { 668 op->o_tmpfree( mbase.bv_val, op->o_tmpmemctx ); 669 } 670 671doreturn:; 672 Debug( LDAP_DEBUG_TRACE, "%s <<< asyncmeta_back_search_start[%p] (fd %d)=%d\n", op->o_log_prefix, msc, s, candidates[candidate].sr_msgid ); 673 return retcode; 674} 675 676int 677asyncmeta_back_search( Operation *op, SlapReply *rs ) 678{ 679 a_metainfo_t *mi = ( a_metainfo_t * )op->o_bd->be_private; 680 time_t timeout = 0; 681 int rc = 0; 682 int ncandidates = 0, initial_candidates = 0; 683 long i; 684 SlapReply *candidates = NULL; 685 void *thrctx = op->o_threadctx; 686 bm_context_t *bc; 687 a_metaconn_t *mc; 688 int msc_decr = 0; 689 int max_pending_ops = (mi->mi_max_pending_ops == 0) ? META_BACK_CFG_MAX_PENDING_OPS : mi->mi_max_pending_ops; 690 int check_bind = 0; 691 692 rs_assert_ready( rs ); 693 rs->sr_flags &= ~REP_ENTRY_MASK; /* paranoia, we can set rs = non-entry */ 694 695 /* 696 * controls are set in ldap_back_dobind() 697 * 698 * FIXME: in case of values return filter, we might want 699 * to map attrs and maybe rewrite value 700 */ 701 702 asyncmeta_new_bm_context(op, rs, &bc, mi->mi_ntargets, mi ); 703 if (bc == NULL) { 704 rs->sr_err = LDAP_OTHER; 705 send_ldap_result(op, rs); 706 return rs->sr_err; 707 } 708 709 candidates = bc->candidates; 710 mc = asyncmeta_getconn( op, rs, candidates, NULL, LDAP_BACK_DONTSEND, 0); 711 if ( !mc || rs->sr_err != LDAP_SUCCESS) { 712 send_ldap_result(op, rs); 713 return rs->sr_err; 714 } 715 716 /* 717 * Inits searches 718 */ 719 720 for ( i = 0; i < mi->mi_ntargets; i++ ) { 721 /* reset sr_msgid; it is used in most loops 722 * to check if that target is still to be considered */ 723 candidates[i].sr_msgid = META_MSGID_UNDEFINED; 724 /* a target is marked as candidate by asyncmeta_getconn(); 725 * if for any reason (an error, it's over or so) it is 726 * no longer active, sr_msgid is set to META_MSGID_IGNORE 727 * but it remains candidate, which means it has been active 728 * at some point during the operation. This allows to 729 * use its response code and more to compute the final 730 * response */ 731 if ( !META_IS_CANDIDATE( &candidates[ i ] ) ) { 732 continue; 733 } 734 735 candidates[ i ].sr_matched = NULL; 736 candidates[ i ].sr_text = NULL; 737 candidates[ i ].sr_ref = NULL; 738 candidates[ i ].sr_ctrls = NULL; 739 candidates[ i ].sr_nentries = 0; 740 candidates[ i ].sr_type = -1; 741 742 /* get largest timeout among candidates */ 743 if ( mi->mi_targets[ i ]->mt_timeout[ SLAP_OP_SEARCH ] 744 && mi->mi_targets[ i ]->mt_timeout[ SLAP_OP_SEARCH ] > timeout ) 745 { 746 timeout = mi->mi_targets[ i ]->mt_timeout[ SLAP_OP_SEARCH ]; 747 } 748 } 749 750 if ( op->ors_tlimit != SLAP_NO_LIMIT && (timeout == 0 || op->ors_tlimit < timeout)) { 751 bc->searchtime = 1; 752 bc->timeout = op->ors_tlimit; 753 } else { 754 bc->timeout = timeout; 755 } 756 757 bc->stoptime = op->o_time + bc->timeout; 758 bc->bc_active = 1; 759 760 if (mc->pending_ops >= max_pending_ops) { 761 rs->sr_err = LDAP_BUSY; 762 rs->sr_text = "Maximum pending ops limit exceeded"; 763 send_ldap_result(op, rs); 764 return rs->sr_err; 765 } 766 767 ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex); 768 rc = asyncmeta_add_message_queue(mc, bc); 769 for ( i = 0; i < mi->mi_ntargets; i++ ) { 770 mc->mc_conns[i].msc_active++; 771 } 772 ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex); 773 774 if (rc != LDAP_SUCCESS) { 775 rs->sr_err = LDAP_BUSY; 776 rs->sr_text = "Maximum pending ops limit exceeded"; 777 send_ldap_result(op, rs); 778 goto finish; 779 } 780 781 for ( i = 0; i < mi->mi_ntargets; i++ ) { 782 if ( !META_IS_CANDIDATE( &candidates[ i ] ) 783 || candidates[ i ].sr_err != LDAP_SUCCESS ) 784 { 785 continue; 786 } 787retry: 788 if (bc->timeout && bc->stoptime < slap_get_time() && META_BACK_ONERR_STOP( mi )) { 789 int timeout_err; 790 const char *timeout_text; 791 if (bc->searchtime) { 792 timeout_err = LDAP_TIMELIMIT_EXCEEDED; 793 timeout_text = NULL; 794 } else { 795 timeout_err = op->o_protocol >= LDAP_VERSION3 ? 796 LDAP_ADMINLIMIT_EXCEEDED : LDAP_OTHER; 797 timeout_text = "Operation timed out before it was sent to target"; 798 } 799 rs->sr_err = timeout_err; 800 rs->sr_text = timeout_text; 801 asyncmeta_handle_onerr_stop(op,rs,mc,bc,i); 802 goto finish; 803 804 } 805 806 if (op->o_abandon) { 807 rs->sr_err = SLAPD_ABANDON; 808 asyncmeta_handle_onerr_stop(op,rs,mc,bc,i); 809 goto finish; 810 } 811 812 rc = asyncmeta_dobind_init_with_retry(op, rs, bc, mc, i); 813 switch (rc) 814 { 815 case META_SEARCH_CANDIDATE: 816 /* target is already bound, just send the search request */ 817 ncandidates++; 818 Debug( LDAP_DEBUG_TRACE, "%s asyncmeta_back_search: IS_CANDIDATE " 819 "cnd=\"%ld\"\n", op->o_log_prefix, i ); 820 821 rc = asyncmeta_back_search_start( op, rs, mc, bc, i, NULL, 0 , 1); 822 if (rc == META_SEARCH_ERR) { 823 META_CANDIDATE_CLEAR(&candidates[i]); 824 candidates[ i ].sr_msgid = META_MSGID_IGNORE; 825 if ( META_BACK_ONERR_STOP( mi ) ) { 826 asyncmeta_handle_onerr_stop(op,rs,mc,bc,i); 827 goto finish; 828 } 829 else { 830 continue; 831 } 832 } else if (rc == META_SEARCH_NEED_BIND) { 833 goto retry; 834 } 835 break; 836 case META_SEARCH_NOT_CANDIDATE: 837 Debug( LDAP_DEBUG_TRACE, "%s asyncmeta_back_search: NOT_CANDIDATE " 838 "cnd=\"%ld\"\n", op->o_log_prefix, i ); 839 candidates[ i ].sr_msgid = META_MSGID_IGNORE; 840 break; 841 842 case META_SEARCH_NEED_BIND: 843 case META_SEARCH_BINDING: 844 Debug( LDAP_DEBUG_TRACE, "%s asyncmeta_back_search: BINDING " 845 "cnd=\"%ld\" mc %p msc %p\n", op->o_log_prefix, i , mc, &mc->mc_conns[i]); 846 check_bind++; 847 ncandidates++; 848 /* Todo add the context to the message queue but do not send the request 849 the receiver must send this when we are done binding */ 850 /* question - how would do receiver know to which targets??? */ 851 break; 852 853 case META_SEARCH_ERR: 854 Debug( LDAP_DEBUG_TRACE, "%s asyncmeta_back_search: SEARCH_ERR " 855 "cnd=\"%ldd\"\n", op->o_log_prefix, i ); 856 candidates[ i ].sr_msgid = META_MSGID_IGNORE; 857 candidates[ i ].sr_type = REP_RESULT; 858 859 if ( META_BACK_ONERR_STOP( mi ) ) { 860 asyncmeta_handle_onerr_stop(op,rs,mc,bc,i); 861 goto finish; 862 } 863 else { 864 continue; 865 } 866 break; 867 868 default: 869 assert( 0 ); 870 break; 871 } 872 } 873 874 initial_candidates = ncandidates; 875 876 if ( LogTest( LDAP_DEBUG_TRACE ) ) { 877 char cnd[ SLAP_TEXT_BUFLEN ]; 878 int c; 879 880 for ( c = 0; c < mi->mi_ntargets; c++ ) { 881 if ( META_IS_CANDIDATE( &candidates[ c ] ) ) { 882 cnd[ c ] = '*'; 883 } else { 884 cnd[ c ] = ' '; 885 } 886 } 887 cnd[ c ] = '\0'; 888 889 Debug( LDAP_DEBUG_TRACE, "%s asyncmeta_back_search: ncandidates=%d " 890 "cnd=\"%s\"\n", op->o_log_prefix, ncandidates, cnd ); 891 } 892 893 if ( initial_candidates == 0 ) { 894 /* NOTE: here we are not sending any matchedDN; 895 * this is intended, because if the back-meta 896 * is serving this search request, but no valid 897 * candidate could be looked up, it means that 898 * there is a hole in the mapping of the targets 899 * and thus no knowledge of any remote superior 900 * is available */ 901 Debug( LDAP_DEBUG_ANY, "%s asyncmeta_back_search: " 902 "base=\"%s\" scope=%d: " 903 "no candidate could be selected\n", 904 op->o_log_prefix, op->o_req_dn.bv_val, 905 op->ors_scope ); 906 907 /* FIXME: we're sending the first error we encounter; 908 * maybe we should pick the worst... */ 909 rc = LDAP_NO_SUCH_OBJECT; 910 for ( i = 0; i < mi->mi_ntargets; i++ ) { 911 if ( META_IS_CANDIDATE( &candidates[ i ] ) 912 && candidates[ i ].sr_err != LDAP_SUCCESS ) 913 { 914 rc = candidates[ i ].sr_err; 915 break; 916 } 917 } 918 rs->sr_err = rc; 919 ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex); 920 asyncmeta_drop_bc(mc, bc); 921 ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex); 922 send_ldap_result(op, rs); 923 goto finish; 924 } 925 926 /* If we were processing many targets the result from a pending Bind 927 * on an earlier target may have arrived while we were sending to a 928 * later target. See if we can now send our pending request. 929 */ 930 if ( check_bind ) { 931 for ( i = 0; i < mi->mi_ntargets; i++ ) { 932 if ( candidates[ i ].sr_msgid == META_MSGID_GOT_BIND ) { 933 rc = asyncmeta_back_search_start( op, rs, mc, bc, i, NULL, 0, 1 ); 934 if ( rc == META_SEARCH_ERR ) { 935 META_CANDIDATE_CLEAR( &candidates[i] ); 936 candidates[ i ].sr_msgid = META_MSGID_IGNORE; 937 if ( META_BACK_ONERR_STOP( mi ) ) { 938 asyncmeta_handle_onerr_stop(op,rs,mc,bc,i); 939 goto finish; 940 } 941 } 942 } 943 } 944 } 945 946 ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex); 947 for ( i = 0; i < mi->mi_ntargets; i++ ) { 948 mc->mc_conns[i].msc_active--; 949 } 950 msc_decr = 1; 951 952 asyncmeta_start_listeners(mc, candidates, bc); 953 bc->bc_active--; 954 ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex); 955 rs->sr_err = SLAPD_ASYNCOP; 956 957finish: 958 /* we ended up straight here due to error and need to reset the msc_active*/ 959 if (msc_decr == 0) { 960 ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex); 961 for ( i = 0; i < mi->mi_ntargets; i++ ) { 962 mc->mc_conns[i].msc_active--; 963 } 964 ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex); 965 } 966 return rs->sr_err; 967} 968