📄 search.c
字号:
/* * Rewrite the search base, if required */ dc->target = mt; dc->ctx = "searchBase"; switch ( ldap_back_dn_massage( dc, &realbase, &mbase ) ) { case LDAP_SUCCESS: break; case LDAP_UNWILLING_TO_PERFORM: rs->sr_err = LDAP_UNWILLING_TO_PERFORM; rs->sr_text = "Operation not allowed"; send_ldap_result( op, rs ); retcode = META_SEARCH_ERR; goto doreturn; default: /* * this target is no longer candidate */ retcode = META_SEARCH_NOT_CANDIDATE; goto doreturn; } /* * Maps filter */ rc = ldap_back_filter_map_rewrite( dc, op->ors_filter, &mfilter, BACKLDAP_MAP ); switch ( rc ) { case LDAP_SUCCESS: break; case LDAP_COMPARE_FALSE: default: /* * this target is no longer candidate */ retcode = META_SEARCH_NOT_CANDIDATE; goto done; } /* * Maps required attributes */ rc = ldap_back_map_attrs( &mt->mt_rwmap.rwm_at, op->ors_attrs, BACKLDAP_MAP, &mapped_attrs ); if ( rc != LDAP_SUCCESS ) { /* * this target is no longer candidate */ retcode = META_SEARCH_NOT_CANDIDATE; goto done; } /* should we check return values? */ if ( op->ors_deref != -1 ) { assert( msc->msc_ld != NULL ); (void)ldap_set_option( msc->msc_ld, LDAP_OPT_DEREF, ( void * )&op->ors_deref ); } if ( op->ors_tlimit != SLAP_NO_LIMIT ) { tv.tv_sec = op->ors_tlimit > 0 ? op->ors_tlimit : 1; tv.tv_usec = 0; tvp = &tv; }retry:; ctrls = op->o_ctrls; if ( ldap_back_proxy_authz_ctrl( &msc->msc_bound_ndn, mt->mt_version, &mt->mt_idassert, op, rs, &ctrls ) != LDAP_SUCCESS ) { candidates[ candidate ].sr_msgid = META_MSGID_IGNORE; retcode = META_SEARCH_NOT_CANDIDATE; goto done; } /* * Starts the search */ assert( msc->msc_ld != NULL ); rc = ldap_search_ext( msc->msc_ld, mbase.bv_val, realscope, mfilter.bv_val, mapped_attrs, op->ors_attrsonly, ctrls, NULL, tvp, op->ors_slimit, &candidates[ candidate ].sr_msgid ); switch ( rc ) { case LDAP_SUCCESS: retcode = META_SEARCH_CANDIDATE; break; case LDAP_SERVER_DOWN: if ( nretries && meta_back_retry( op, rs, mcp, candidate, LDAP_BACK_DONTSEND ) ) { nretries = 0; /* if the identity changed, there might be need to re-authz */ (void)ldap_back_proxy_authz_ctrl_free( op, &ctrls ); goto retry; } if ( *mcp == NULL ) { retcode = META_SEARCH_ERR; candidates[ candidate ].sr_msgid = META_MSGID_IGNORE; break; } /* fall thru */ default: candidates[ candidate ].sr_msgid = META_MSGID_IGNORE; retcode = META_SEARCH_NOT_CANDIDATE; }done:; (void)ldap_back_proxy_authz_ctrl_free( op, &ctrls ); if ( mapped_attrs ) { free( mapped_attrs ); } if ( mfilter.bv_val != op->ors_filterstr.bv_val ) { free( mfilter.bv_val ); } if ( mbase.bv_val != realbase.bv_val ) { free( mbase.bv_val ); }doreturn:; Debug( LDAP_DEBUG_TRACE, "%s <<< meta_back_search_start[%d]=%d\n", op->o_log_prefix, candidate, retcode ); return retcode;}intmeta_back_search( Operation *op, SlapReply *rs ){ metainfo_t *mi = ( metainfo_t * )op->o_bd->be_private; metaconn_t *mc; struct timeval save_tv = { 0, 0 }, tv; time_t stoptime = (time_t)(-1), lastres_time = slap_get_time(), timeout = 0; int rc = 0, sres = LDAP_SUCCESS; char *matched = NULL; int last = 0, ncandidates = 0, initial_candidates = 0, candidate_match = 0, needbind = 0; ldap_back_send_t sendok = LDAP_BACK_SENDERR; long i; dncookie dc; int is_ok = 0; void *savepriv; SlapReply *candidates = meta_back_candidates_get( op ); /* * controls are set in ldap_back_dobind() * * FIXME: in case of values return filter, we might want * to map attrs and maybe rewrite value */getconn:; mc = meta_back_getconn( op, rs, NULL, sendok ); if ( !mc ) { return rs->sr_err; } dc.conn = op->o_conn; dc.rs = rs; /* * Inits searches */ for ( i = 0; i < mi->mi_ntargets; i++ ) { /* reset sr_msgid; it is used in most loops * to check if that target is still to be considered */ candidates[ i ].sr_msgid = META_MSGID_IGNORE; /* a target is marked as candidate by meta_back_getconn(); * if for any reason (an error, it's over or so) it is * no longer active, sr_msgid is set to META_MSGID_IGNORE * but it remains candidate, which means it has been active * at some point during the operation. This allows to * use its response code and more to compute the final * response */ if ( !META_IS_CANDIDATE( &candidates[ i ] ) ) { continue; } candidates[ i ].sr_matched = NULL; candidates[ i ].sr_text = NULL; candidates[ i ].sr_ref = NULL; candidates[ i ].sr_ctrls = NULL; /* get largest timeout among candidates */ if ( mi->mi_targets[ i ]->mt_timeout[ SLAP_OP_SEARCH ] && mi->mi_targets[ i ]->mt_timeout[ SLAP_OP_SEARCH ] > timeout ) { timeout = mi->mi_targets[ i ]->mt_timeout[ SLAP_OP_SEARCH ]; } } for ( i = 0; i < mi->mi_ntargets; i++ ) { if ( !META_IS_CANDIDATE( &candidates[ i ] ) || candidates[ i ].sr_err != LDAP_SUCCESS ) { continue; } switch ( meta_back_search_start( op, rs, &dc, &mc, i, candidates ) ) { case META_SEARCH_NOT_CANDIDATE: candidates[ i ].sr_msgid = META_MSGID_IGNORE; break; case META_SEARCH_NEED_BIND: ++needbind; /* fallthru */ case META_SEARCH_CANDIDATE: case META_SEARCH_BINDING: candidates[ i ].sr_type = REP_INTERMEDIATE; ++ncandidates; break; case META_SEARCH_ERR: savepriv = op->o_private; op->o_private = (void *)i; send_ldap_result( op, rs ); op->o_private = savepriv; rc = -1; goto finish; default: assert( 0 ); break; } } if ( ncandidates > 0 && needbind == ncandidates ) { /* * give up the second time... * * NOTE: this should not occur the second time, since a fresh * connection has ben created; however, targets may also * need bind because the bind timed out or so. */ if ( sendok & LDAP_BACK_BINDING ) { Debug( LDAP_DEBUG_ANY, "%s meta_back_search: unable to initialize conn\n", op->o_log_prefix, 0, 0 ); rs->sr_err = LDAP_UNAVAILABLE; rs->sr_text = "unable to initialize connection to remote targets"; send_ldap_result( op, rs ); rc = -1; goto finish; } /* FIXME: better create a separate connection? */ sendok |= LDAP_BACK_BINDING;#ifdef DEBUG_205 Debug( LDAP_DEBUG_ANY, "*** %s drop mc=%p create new connection\n", op->o_log_prefix, (void *)mc, 0 );#endif /* DEBUG_205 */ meta_back_release_conn( mi, mc ); mc = NULL; needbind = 0; ncandidates = 0; goto getconn; } initial_candidates = ncandidates; if ( StatslogTest( LDAP_DEBUG_TRACE ) ) { char cnd[ SLAP_TEXT_BUFLEN ]; int c; for ( c = 0; c < mi->mi_ntargets; c++ ) { if ( META_IS_CANDIDATE( &candidates[ c ] ) ) { cnd[ c ] = '*'; } else { cnd[ c ] = ' '; } } cnd[ c ] = '\0'; Debug( LDAP_DEBUG_TRACE, "%s meta_back_search: ncandidates=%d " "cnd=\"%s\"\n", op->o_log_prefix, ncandidates, cnd ); } if ( initial_candidates == 0 ) { /* NOTE: here we are not sending any matchedDN; * this is intended, because if the back-meta * is serving this search request, but no valid * candidate could be looked up, it means that * there is a hole in the mapping of the targets * and thus no knowledge of any remote superior * is available */ Debug( LDAP_DEBUG_ANY, "%s meta_back_search: " "base=\"%s\" scope=%d: " "no candidate could be selected\n", op->o_log_prefix, op->o_req_dn.bv_val, op->ors_scope ); /* FIXME: we're sending the first error we encounter; * maybe we should pick the worst... */ rc = LDAP_NO_SUCH_OBJECT; for ( i = 0; i < mi->mi_ntargets; i++ ) { if ( META_IS_CANDIDATE( &candidates[ i ] ) && candidates[ i ].sr_err != LDAP_SUCCESS ) { rc = candidates[ i ].sr_err; break; } } send_ldap_error( op, rs, rc, NULL ); goto finish; } /* We pull apart the ber result, stuff it into a slapd entry, and * let send_search_entry stuff it back into ber format. Slow & ugly, * but this is necessary for version matching, and for ACL processing. */ if ( op->ors_tlimit != SLAP_NO_LIMIT ) { stoptime = op->o_time + op->ors_tlimit; } /* * In case there are no candidates, no cycle takes place... * * FIXME: we might use a queue, to better balance the load * among the candidates */ for ( rc = 0; ncandidates > 0; ) { int gotit = 0, doabandon = 0, alreadybound = ncandidates; /* check timeout */ if ( timeout && lastres_time > 0 && ( slap_get_time() - lastres_time ) > timeout ) { doabandon = 1; rs->sr_text = "Operation timed out"; rc = rs->sr_err = op->o_protocol >= LDAP_VERSION3 ? LDAP_ADMINLIMIT_EXCEEDED : LDAP_OTHER; savepriv = op->o_private; op->o_private = (void *)i; send_ldap_result( op, rs ); op->o_private = savepriv; goto finish; } /* check time limit */ if ( op->ors_tlimit != SLAP_NO_LIMIT && slap_get_time() > stoptime ) { doabandon = 1; rc = rs->sr_err = LDAP_TIMELIMIT_EXCEEDED; savepriv = op->o_private; op->o_private = (void *)i; send_ldap_result( op, rs ); op->o_private = savepriv; goto finish; } for ( i = 0; i < mi->mi_ntargets; i++ ) { meta_search_candidate_t retcode = META_SEARCH_UNDEFINED; metasingleconn_t *msc = &mc->mc_conns[ i ]; LDAPMessage *res = NULL, *msg; /* if msgid is invalid, don't ldap_result() */ if ( candidates[ i ].sr_msgid == META_MSGID_IGNORE ) { continue; } /* if target still needs bind, retry */ if ( candidates[ i ].sr_msgid == META_MSGID_NEED_BIND ) { /* initiate dobind */ retcode = meta_search_dobind_init( op, rs, &mc, i, candidates ); Debug( LDAP_DEBUG_TRACE, "%s <<< meta_search_dobind_init[%ld]=%d\n", op->o_log_prefix, i, retcode ); switch ( retcode ) { case META_SEARCH_NEED_BIND: alreadybound--; /* fallthru */ case META_SEARCH_BINDING: break; case META_SEARCH_ERR: candidates[ i ].sr_err = rs->sr_err; if ( META_BACK_ONERR_STOP( mi ) ) { savepriv = op->o_private; op->o_private = (void *)i; send_ldap_result( op, rs ); op->o_private = savepriv; goto finish; } /* fallthru */ case META_SEARCH_NOT_CANDIDATE: /* * When no candidates are left, * the outer cycle finishes */ candidates[ i ].sr_msgid = META_MSGID_IGNORE; assert( ncandidates > 0 ); --ncandidates; break; case META_SEARCH_CANDIDATE: candidates[ i ].sr_msgid = META_MSGID_IGNORE; switch ( meta_back_search_start( op, rs, &dc, &mc, i, candidates ) ) { case META_SEARCH_CANDIDATE: assert( candidates[ i ].sr_msgid >= 0 ); break; case META_SEARCH_ERR: candidates[ i ].sr_err = rs->sr_err; if ( META_BACK_ONERR_STOP( mi ) ) { savepriv = op->o_private; op->o_private = (void *)i; send_ldap_result( op, rs ); op->o_private = savepriv; goto finish; } /* fallthru */ case META_SEARCH_NOT_CANDIDATE: /* means that meta_back_search_start() * failed but onerr == continue */ candidates[ i ].sr_msgid = META_MSGID_IGNORE; assert( ncandidates > 0 ); --ncandidates; break; default: /* impossible */ assert( 0 ); break; } break; default: /* impossible */ assert( 0 ); break; } continue; } /* check for abandon */ if ( op->o_abandon || LDAP_BACK_CONN_ABANDON( mc ) ) { break; }#ifdef DEBUG_205 if ( msc->msc_ld == NULL ) { char buf[ SLAP_TEXT_BUFLEN ]; ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex ); snprintf( buf, sizeof( buf ), "%s meta_back_search[%ld] mc=%p msgid=%d%s%s%s\n", op->o_log_prefix, (long)i, (void *)mc, candidates[ i ].sr_msgid, META_IS_BINDING( &candidates[ i ] ) ? " binding" : "", LDAP_BACK_CONN_BINDING( &mc->mc_conns[ i ] ) ? " connbinding" : "", META_BACK_CONN_CREATING( &mc->mc_conns[ i ] ) ? " conncreating" : "" ); ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex ); Debug( LDAP_DEBUG_ANY, "!!! %s\n", buf, 0, 0 ); }#endif /* DEBUG_205 */ /* * FIXME: handle time limit as well? * Note that target servers are likely * to handle it, so at some time we'll * get a LDAP_TIMELIMIT_EXCEEDED from * one of them ... */ tv = save_tv; rc = ldap_result( msc->msc_ld, candidates[ i ].sr_msgid, LDAP_MSG_RECEIVED, &tv, &res ); switch ( rc ) { case 0: /* FIXME: res should not need to be freed */ assert( res == NULL ); continue; case -1:really_bad:; /* something REALLY bad happened! */ if ( candidates[ i ].sr_type == REP_INTERMEDIATE ) { candidates[ i ].sr_type = REP_RESULT; if ( meta_back_retry( op, rs, &mc, i, LDAP_BACK_DONTSEND ) ) { candidates[ i ].sr_msgid = META_MSGID_IGNORE; switch ( meta_back_search_start( op, rs, &dc, &mc, i, candidates ) ) { /* means that failed but onerr == continue */ case META_SEARCH_NOT_CANDIDATE:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -