📄 search.c
字号:
/* $OpenLDAP: pkg/ldap/servers/slapd/back-meta/search.c,v 1.84.2.33 2007/08/14 09:59:44 ando Exp $ *//* This work is part of OpenLDAP Software <http://www.openldap.org/>. * * Copyright 1999-2007 The OpenLDAP Foundation. * Portions Copyright 2001-2003 Pierangelo Masarati. * Portions Copyright 1999-2003 Howard Chu. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted only as authorized by the OpenLDAP * Public License. * * A copy of this license is available in the file LICENSE in the * top-level directory of the distribution or, alternatively, at * <http://www.OpenLDAP.org/license.html>. *//* ACKNOWLEDGEMENTS: * This work was initially developed by the Howard Chu for inclusion * in OpenLDAP Software and subsequently enhanced by Pierangelo * Masarati. */#include "portable.h"#include <stdio.h>#include <ac/socket.h>#include <ac/string.h>#include <ac/time.h>#include "lutil.h"#include "slap.h"#include "../back-ldap/back-ldap.h"#include "back-meta.h"#undef ldap_debug /* silence a warning in ldap-int.h */#include "ldap_log.h"#include "../../../libraries/libldap/ldap-int.h"/* IGNORE means that target does not (no longer) participate * in the search; * NOTREADY means the search on that target has not been initialized yet */#define META_MSGID_IGNORE (-1)#define META_MSGID_NEED_BIND (-2)static intmeta_send_entry( Operation *op, SlapReply *rs, metaconn_t *mc, int i, LDAPMessage *e );typedef enum meta_search_candidate_t { META_SEARCH_UNDEFINED = -2, META_SEARCH_ERR = -1, META_SEARCH_NOT_CANDIDATE, META_SEARCH_CANDIDATE, META_SEARCH_BINDING, META_SEARCH_NEED_BIND} meta_search_candidate_t;/* * meta_search_dobind_init() * * initiates bind for a candidate target of a search. */static meta_search_candidate_tmeta_search_dobind_init( Operation *op, SlapReply *rs, metaconn_t **mcp, int candidate, SlapReply *candidates ){ metaconn_t *mc = *mcp; metainfo_t *mi = ( metainfo_t * )op->o_bd->be_private; metatarget_t *mt = mi->mi_targets[ candidate ]; metasingleconn_t *msc = &mc->mc_conns[ candidate ]; struct berval binddn = msc->msc_bound_ndn, cred = msc->msc_cred; int method; int rc; meta_search_candidate_t retcode; Debug( LDAP_DEBUG_TRACE, "%s >>> meta_search_dobind_init[%d]\n", op->o_log_prefix, candidate, 0 ); /* * all the targets are already bound as pseudoroot */ if ( mc->mc_authz_target == META_BOUND_ALL ) { return META_SEARCH_CANDIDATE; } retcode = META_SEARCH_BINDING; ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex ); if ( LDAP_BACK_CONN_ISBOUND( msc ) || LDAP_BACK_CONN_ISANON( msc ) ) { /* already bound (or anonymous) */#ifdef DEBUG_205 char buf[ SLAP_TEXT_BUFLEN ] = { '\0' }; int bound = 0; if ( LDAP_BACK_CONN_ISBOUND( msc ) ) { bound = 1; } snprintf( buf, sizeof( buf ), " mc=%p ld=%p%s DN=\"%s\"", (void *)mc, (void *)msc->msc_ld, bound ? " bound" : " anonymous", bound == 0 ? "" : msc->msc_bound_ndn.bv_val ); Debug( LDAP_DEBUG_ANY, "### %s meta_search_dobind_init[%d]%s\n", op->o_log_prefix, candidate, buf );#endif /* DEBUG_205 */ retcode = META_SEARCH_CANDIDATE; } else if ( META_BACK_CONN_CREATING( msc ) || LDAP_BACK_CONN_BINDING( msc ) ) { /* another thread is binding the target for this conn; wait */#ifdef DEBUG_205 char buf[ SLAP_TEXT_BUFLEN ] = { '\0' }; snprintf( buf, sizeof( buf ), " mc=%p ld=%p needbind", (void *)mc, (void *)msc->msc_ld ); Debug( LDAP_DEBUG_ANY, "### %s meta_search_dobind_init[%d]%s\n", op->o_log_prefix, candidate, buf );#endif /* DEBUG_205 */ candidates[ candidate ].sr_msgid = META_MSGID_NEED_BIND; retcode = META_SEARCH_NEED_BIND; } else { /* we'll need to bind the target for this conn */#ifdef DEBUG_205 char buf[ SLAP_TEXT_BUFLEN ]; snprintf( buf, sizeof( buf ), " mc=%p ld=%p binding", (void *)mc, (void *)msc->msc_ld ); Debug( LDAP_DEBUG_ANY, "### %s meta_search_dobind_init[%d]%s\n", op->o_log_prefix, candidate, buf );#endif /* DEBUG_205 */ if ( msc->msc_ld == NULL ) { /* for some reason (e.g. because formerly in "binding" * state, with eventual connection expiration or invalidation) * it was not initialized as expected */ Debug( LDAP_DEBUG_ANY, "%s meta_search_dobind_init[%d] mc=%p ld=NULL\n", op->o_log_prefix, candidate, (void *)mc ); rc = meta_back_init_one_conn( op, rs, *mcp, candidate, LDAP_BACK_CONN_ISPRIV( *mcp ), LDAP_BACK_DONTSEND, 0 ); switch ( rc ) { case LDAP_SUCCESS: assert( msc->msc_ld != NULL ); break; case LDAP_SERVER_DOWN: case LDAP_UNAVAILABLE: ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex ); goto down; default: ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex ); goto other; } } LDAP_BACK_CONN_BINDING_SET( msc ); } ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex ); if ( retcode != META_SEARCH_BINDING ) { return retcode; } /* NOTE: this obsoletes pseudorootdn */ if ( op->o_conn != NULL && !op->o_do_not_cache && ( BER_BVISNULL( &msc->msc_bound_ndn ) || BER_BVISEMPTY( &msc->msc_bound_ndn ) || ( mt->mt_idassert_flags & LDAP_BACK_AUTH_OVERRIDE ) ) ) { rc = meta_back_proxy_authz_cred( mc, candidate, op, rs, LDAP_BACK_DONTSEND, &binddn, &cred, &method ); if ( rc != LDAP_SUCCESS ) { goto down; } /* NOTE: we copy things here, even if bind didn't succeed yet, * because the connection is not shared until bind is over */ if ( !BER_BVISNULL( &binddn ) ) { ber_bvreplace( &msc->msc_bound_ndn, &binddn ); if ( LDAP_BACK_SAVECRED( mi ) && !BER_BVISNULL( &cred ) ) { if ( !BER_BVISNULL( &msc->msc_cred ) ) { memset( msc->msc_cred.bv_val, 0, msc->msc_cred.bv_len ); } ber_bvreplace( &msc->msc_cred, &cred ); } } if ( LDAP_BACK_CONN_ISBOUND( msc ) ) { /* apparently, idassert was configured with SASL bind, * so bind occurred inside meta_back_proxy_authz_cred() */ ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex ); LDAP_BACK_CONN_BINDING_CLEAR( msc ); ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex ); return META_SEARCH_CANDIDATE; } /* paranoid */ switch ( method ) { case LDAP_AUTH_NONE: case LDAP_AUTH_SIMPLE: /* do a simple bind with binddn, cred */ break; default: assert( 0 ); break; } } assert( msc->msc_ld != NULL );retry:; rc = ldap_sasl_bind( msc->msc_ld, binddn.bv_val, LDAP_SASL_SIMPLE, &cred, NULL, NULL, &candidates[ candidate ].sr_msgid );#ifdef DEBUG_205 { char buf[ SLAP_TEXT_BUFLEN ]; snprintf( buf, sizeof( buf ), "meta_search_dobind_init[%d] mc=%p ld=%p rc=%d", candidate, (void *)mc, (void *)mc->mc_conns[ candidate ].msc_ld, rc ); Debug( LDAP_DEBUG_ANY, "### %s %s\n", op->o_log_prefix, buf, 0 ); }#endif /* DEBUG_205 */ switch ( rc ) { case LDAP_SUCCESS: assert( candidates[ candidate ].sr_msgid >= 0 ); META_BINDING_SET( &candidates[ candidate ] ); return META_SEARCH_BINDING; case LDAP_SERVER_DOWN:down:; /* This is the worst thing that could happen: * the search will wait until the retry is over. */ if ( !META_IS_RETRYING( &candidates[ candidate ] ) ) { META_RETRYING_SET( &candidates[ candidate ] ); ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex ); assert( mc->mc_refcnt > 0 ); if ( StatslogTest( LDAP_DEBUG_ANY ) ) { char buf[ SLAP_TEXT_BUFLEN ]; /* this lock is required; however, * it's invoked only when logging is on */ ldap_pvt_thread_mutex_lock( &mt->mt_uri_mutex ); snprintf( buf, sizeof( buf ), "retrying URI=\"%s\" DN=\"%s\"", mt->mt_uri, BER_BVISNULL( &msc->msc_bound_ndn ) ? "" : msc->msc_bound_ndn.bv_val ); ldap_pvt_thread_mutex_unlock( &mt->mt_uri_mutex ); Debug( LDAP_DEBUG_ANY, "%s meta_search_dobind_init[%d]: %s.\n", op->o_log_prefix, candidate, buf ); } meta_clear_one_candidate( op, mc, candidate ); LDAP_BACK_CONN_ISBOUND_CLEAR( msc ); ( void )rewrite_session_delete( mt->mt_rwmap.rwm_rw, op->o_conn ); /* mc here must be the regular mc, reset and ready for init */ rc = meta_back_init_one_conn( op, rs, mc, candidate, LDAP_BACK_CONN_ISPRIV( mc ), LDAP_BACK_DONTSEND, 0 ); if ( rc == LDAP_SUCCESS ) { LDAP_BACK_CONN_BINDING_SET( msc ); } ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex ); if ( rc == LDAP_SUCCESS ) { candidates[ candidate ].sr_msgid = META_MSGID_IGNORE; goto retry; } } if ( *mcp == NULL ) { retcode = META_SEARCH_ERR; rs->sr_err = LDAP_UNAVAILABLE; candidates[ candidate ].sr_msgid = META_MSGID_IGNORE; break; } /* fall thru */ default:other:; rs->sr_err = rc; rc = slap_map_api2result( rs ); ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex ); meta_clear_one_candidate( op, mc, candidate ); candidates[ candidate ].sr_err = rc; if ( META_BACK_ONERR_STOP( mi ) ) { LDAP_BACK_CONN_TAINTED_SET( mc ); meta_back_release_conn_lock( mi, mc, 0 ); *mcp = NULL; rs->sr_err = rc; retcode = META_SEARCH_ERR; } else { retcode = META_SEARCH_NOT_CANDIDATE; } candidates[ candidate ].sr_msgid = META_MSGID_IGNORE; ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex ); break; } return retcode;}static meta_search_candidate_tmeta_search_dobind_result( Operation *op, SlapReply *rs, metaconn_t **mcp, int candidate, SlapReply *candidates, LDAPMessage *res ){ metainfo_t *mi = ( metainfo_t * )op->o_bd->be_private; metaconn_t *mc = *mcp; metasingleconn_t *msc = &mc->mc_conns[ candidate ]; meta_search_candidate_t retcode = META_SEARCH_NOT_CANDIDATE; int rc; assert( msc->msc_ld != NULL ); /* FIXME: matched? referrals? response controls? */ rc = ldap_parse_result( msc->msc_ld, res, &candidates[ candidate ].sr_err, NULL, NULL, NULL, NULL, 0 ); if ( rc != LDAP_SUCCESS ) { candidates[ candidate ].sr_err = rc; } else { rc = slap_map_api2result( &candidates[ candidate ] ); } ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex ); LDAP_BACK_CONN_BINDING_CLEAR( msc ); if ( rc != LDAP_SUCCESS ) { meta_clear_one_candidate( op, mc, candidate ); candidates[ candidate ].sr_err = rc; if ( META_BACK_ONERR_STOP( mi ) ) { LDAP_BACK_CONN_TAINTED_SET( mc ); meta_back_release_conn_lock( mi, mc, 0 ); *mcp = NULL; retcode = META_SEARCH_ERR; rs->sr_err = rc; } } else { /* FIXME: check if bound as idassert authcDN! */ if ( BER_BVISNULL( &msc->msc_bound_ndn ) || BER_BVISEMPTY( &msc->msc_bound_ndn ) ) { LDAP_BACK_CONN_ISANON_SET( msc ); } else { LDAP_BACK_CONN_ISBOUND_SET( msc ); } retcode = META_SEARCH_CANDIDATE; } candidates[ candidate ].sr_msgid = META_MSGID_IGNORE; META_BINDING_CLEAR( &candidates[ candidate ] ); ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex ); return retcode;}static meta_search_candidate_tmeta_back_search_start( Operation *op, SlapReply *rs, dncookie *dc, metaconn_t **mcp, int candidate, SlapReply *candidates ){ metainfo_t *mi = ( metainfo_t * )op->o_bd->be_private; metatarget_t *mt = mi->mi_targets[ candidate ]; metasingleconn_t *msc = &(*mcp)->mc_conns[ candidate ]; struct berval realbase = op->o_req_dn; int realscope = op->ors_scope; struct berval mbase = BER_BVNULL; struct berval mfilter = BER_BVNULL; char **mapped_attrs = NULL; int rc; meta_search_candidate_t retcode; struct timeval tv, *tvp = NULL; int nretries = 1; LDAPControl **ctrls = NULL; /* this should not happen; just in case... */ if ( msc->msc_ld == NULL ) { Debug( LDAP_DEBUG_ANY, "%s: meta_back_search_start candidate=%d ld=NULL%s.\n", op->o_log_prefix, candidate, META_BACK_ONERR_STOP( mi ) ? "" : " (ignored)" ); candidates[ candidate ].sr_err = LDAP_OTHER; if ( META_BACK_ONERR_STOP( mi ) ) { return META_SEARCH_ERR; } candidates[ candidate ].sr_msgid = META_MSGID_IGNORE; return META_SEARCH_NOT_CANDIDATE; } Debug( LDAP_DEBUG_TRACE, "%s >>> meta_back_search_start[%d]\n", op->o_log_prefix, candidate, 0 ); /* * modifies the base according to the scope, if required */ if ( mt->mt_nsuffix.bv_len > op->o_req_ndn.bv_len ) { switch ( op->ors_scope ) { case LDAP_SCOPE_SUBTREE: /* * make the target suffix the new base * FIXME: this is very forgiving, because * "illegal" searchBases may be turned * into the suffix of the target; however, * the requested searchBase already passed * thru the candidate analyzer... */ if ( dnIsSuffix( &mt->mt_nsuffix, &op->o_req_ndn ) ) { realbase = mt->mt_nsuffix; if ( mt->mt_scope == LDAP_SCOPE_SUBORDINATE ) { realscope = LDAP_SCOPE_SUBORDINATE; } } else { /* * this target is no longer candidate */ retcode = META_SEARCH_NOT_CANDIDATE; goto doreturn; } break; case LDAP_SCOPE_SUBORDINATE: case LDAP_SCOPE_ONELEVEL: { struct berval rdn = mt->mt_nsuffix; rdn.bv_len -= op->o_req_ndn.bv_len + STRLENOF( "," ); if ( dnIsOneLevelRDN( &rdn ) && dnIsSuffix( &mt->mt_nsuffix, &op->o_req_ndn ) ) { /* * if there is exactly one level, * make the target suffix the new * base, and make scope "base" */ realbase = mt->mt_nsuffix; if ( op->ors_scope == LDAP_SCOPE_SUBORDINATE ) { if ( mt->mt_scope == LDAP_SCOPE_SUBORDINATE ) { realscope = LDAP_SCOPE_SUBORDINATE; } else { realscope = LDAP_SCOPE_SUBTREE; } } else { realscope = LDAP_SCOPE_BASE; } break; } /* else continue with the next case */ } case LDAP_SCOPE_BASE: /* * this target is no longer candidate */ retcode = META_SEARCH_NOT_CANDIDATE; goto doreturn; } } /* initiate dobind */ retcode = meta_search_dobind_init( op, rs, mcp, candidate, candidates ); Debug( LDAP_DEBUG_TRACE, "%s <<< meta_search_dobind_init[%d]=%d\n", op->o_log_prefix, candidate, retcode ); if ( retcode != META_SEARCH_CANDIDATE ) { goto doreturn; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -