search.c

来自「ldap服务器源码」· C语言 代码 · 共 578 行

C
578
字号
/* search.c - ldbm backend search function *//* $OpenLDAP: pkg/ldap/servers/slapd/back-ldbm/search.c,v 1.128.2.8 2007/01/02 21:44:03 kurt Exp $ *//* This work is part of OpenLDAP Software <http://www.openldap.org/>. * * Copyright 1998-2007 The OpenLDAP Foundation. * 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>. */#include "portable.h"#include <stdio.h>#include <ac/string.h>#include <ac/socket.h>#include "slap.h"#include "back-ldbm.h"#include "proto-back-ldbm.h"static ID_BLOCK	*base_candidate(	Backend *be, Entry *e );static ID_BLOCK	*search_candidates(	Operation *op, Entry *e, Filter *filter,	int scope, int deref, int manageDSAit );intldbm_back_search(    Operation	*op,    SlapReply	*rs ){	struct ldbminfo	*li = (struct ldbminfo *) op->o_bd->be_private;	int		rc;	time_t		stoptime;	ID_BLOCK		*candidates;	ID		id, cursor;	Entry		*e;	Entry	*matched = NULL;	struct berval	realbase = BER_BVNULL;	int		manageDSAit = get_manageDSAit( op );#ifdef SLAP_ACL_HONOR_DISCLOSE	slap_mask_t	mask;#endif	Debug(LDAP_DEBUG_TRACE, "=> ldbm_back_search\n", 0, 0, 0);	/* grab giant lock for reading */	ldap_pvt_thread_rdwr_rlock(&li->li_giant_rwlock);	if ( op->o_req_ndn.bv_len == 0 ) {		/* DIT root special case */		e = (Entry *) &slap_entry_root;		/* need normalized dn below */		ber_dupbv( &realbase, &e->e_nname );		candidates = search_candidates( op, e, op->ors_filter,			op->ors_scope, op->ors_deref,			manageDSAit || get_domainScope(op) );		goto searchit;			} else if ( op->ors_deref & LDAP_DEREF_FINDING ) {		/* deref dn and get entry with reader lock */		e = deref_dn_r( op->o_bd, &op->o_req_ndn,			&rs->sr_err, &matched, &rs->sr_text );		if( rs->sr_err == LDAP_NO_SUCH_OBJECT ) rs->sr_err = LDAP_REFERRAL;	} else {		/* get entry with reader lock */		e = dn2entry_r( op->o_bd, &op->o_req_ndn, &matched );		rs->sr_err = e != NULL ? LDAP_SUCCESS : LDAP_REFERRAL;		rs->sr_text = NULL;	}	if ( e == NULL ) {		struct berval matched_dn = BER_BVNULL;		if ( matched != NULL ) {			BerVarray erefs = NULL;#ifdef SLAP_ACL_HONOR_DISCLOSE			if ( ! access_allowed( op, matched,						slap_schema.si_ad_entry,						NULL, ACL_DISCLOSE, NULL ) )			{				rs->sr_err = LDAP_NO_SUCH_OBJECT;			} else#endif /* SLAP_ACL_HONOR_DISCLOSE */			{				ber_dupbv( &matched_dn, &matched->e_name );				erefs = is_entry_referral( matched )					? get_entry_referrals( op, matched )					: NULL;			}			cache_return_entry_r( &li->li_cache, matched );			if ( erefs ) {				rs->sr_ref = referral_rewrite( erefs, &matched_dn,					&op->o_req_dn, op->ors_scope );				ber_bvarray_free( erefs );			}		} else {			rs->sr_ref = referral_rewrite( default_referral,				NULL, &op->o_req_dn, op->ors_scope );		}		ldap_pvt_thread_rdwr_runlock(&li->li_giant_rwlock);		rs->sr_matched = matched_dn.bv_val;		send_ldap_result( op, rs );		ber_bvarray_free( rs->sr_ref );		ber_memfree( matched_dn.bv_val );		rs->sr_ref = NULL;		rs->sr_matched = NULL;		return rs->sr_err;	}#ifdef SLAP_ACL_HONOR_DISCLOSE	/* NOTE: __NEW__ "search" access is required	 * on searchBase object */	if ( ! access_allowed_mask( op, e, slap_schema.si_ad_entry,				NULL, ACL_SEARCH, NULL, &mask ) )	{		if ( !ACL_GRANT( mask, ACL_DISCLOSE ) ) {			rs->sr_err = LDAP_NO_SUCH_OBJECT;		} else {			rs->sr_err = LDAP_INSUFFICIENT_ACCESS;		}		cache_return_entry_r( &li->li_cache, e );		ldap_pvt_thread_rdwr_runlock(&li->li_giant_rwlock);		send_ldap_result( op, rs );		return rs->sr_err;	}#endif /* SLAP_ACL_HONOR_DISCLOSE */	if ( !manageDSAit && is_entry_referral( e ) ) {		/* entry is a referral, don't allow add */		struct berval	matched_dn = BER_BVNULL;		BerVarray	erefs = NULL;		rs->sr_ref = NULL;		rs->sr_err = LDAP_OTHER;		rs->sr_text = "bad referral object";		ber_dupbv( &matched_dn, &e->e_name );		erefs = get_entry_referrals( op, e );		cache_return_entry_r( &li->li_cache, e );		ldap_pvt_thread_rdwr_runlock(&li->li_giant_rwlock);		Debug( LDAP_DEBUG_TRACE,			"ldbm_search: entry is referral\n",			0, 0, 0 );		if ( erefs ) {			rs->sr_ref = referral_rewrite( erefs, &matched_dn,				&op->o_req_dn, op->ors_scope );			ber_bvarray_free( erefs );						if ( rs->sr_ref ) {				rs->sr_err = LDAP_REFERRAL;				rs->sr_text = NULL;			}		}		rs->sr_matched = matched_dn.bv_val;		send_ldap_result( op, rs );		ber_bvarray_free( rs->sr_ref );		ber_memfree( matched_dn.bv_val );		rs->sr_ref = NULL;		rs->sr_matched = NULL;		return rs->sr_err;	}	if ( is_entry_alias( e ) ) {		/* don't deref */		op->ors_deref = LDAP_DEREF_NEVER;	}	if ( op->ors_scope == LDAP_SCOPE_BASE ) {		candidates = base_candidate( op->o_bd, e );	} else {		candidates = search_candidates( op, e, op->ors_filter,		    op->ors_scope, op->ors_deref, manageDSAit );	}	/* need normalized dn below */	ber_dupbv( &realbase, &e->e_nname );	cache_return_entry_r( &li->li_cache, e );searchit:	if ( candidates == NULL ) {		/* no candidates */		Debug( LDAP_DEBUG_TRACE, "ldbm_search: no candidates\n",			0, 0, 0 );		rs->sr_err = LDAP_SUCCESS;		send_ldap_result( op, rs );		rc = LDAP_SUCCESS;		goto done;	}	/* if candidates exceed to-be-checked entries, abort */	if ( op->ors_limit	/* isroot == FALSE */			&& op->ors_limit->lms_s_unchecked != -1			&& ID_BLOCK_NIDS( candidates ) > (unsigned) op->ors_limit->lms_s_unchecked )	{		send_ldap_error( op, rs, LDAP_ADMINLIMIT_EXCEEDED, NULL );		rc = LDAP_SUCCESS;		goto done;	}		/* compute it anyway; root does not use it */	stoptime = op->o_time + op->ors_tlimit;	rs->sr_attrs = op->ors_attrs;	for ( id = idl_firstid( candidates, &cursor ); id != NOID;	    id = idl_nextid( candidates, &cursor ) )	{		int scopeok = 0;		int result = 0;		/* check for abandon */		if ( op->o_abandon ) {			rc = SLAPD_ABANDON;			goto done;		}		/* check time limit */		if ( op->ors_tlimit != SLAP_NO_LIMIT				&& slap_get_time() > stoptime )		{			rs->sr_err = LDAP_TIMELIMIT_EXCEEDED;			send_ldap_result( op, rs );			rc = LDAP_SUCCESS;			goto done;		}		/* get the entry with reader lock */		e = id2entry_r( op->o_bd, id );		if ( e == NULL ) {			Debug( LDAP_DEBUG_TRACE,				"ldbm_search: candidate %ld not found\n",				id, 0, 0 );			goto loop_continue;		}		rs->sr_entry = e;#ifdef LDBM_SUBENTRIES		if ( is_entry_subentry( e ) ) {			if( op->ors_scope != LDAP_SCOPE_BASE ) {				if(!get_subentries_visibility( op )) {					/* only subentries are visible */					goto loop_continue;				}			} else if ( get_subentries( op ) &&				!get_subentries_visibility( op ))			{				/* only subentries are visible */				goto loop_continue;			}		} else if ( get_subentries_visibility( op )) {			/* only subentries are visible */			goto loop_continue;		}#endif		if ( op->ors_deref & LDAP_DEREF_SEARCHING &&			is_entry_alias( e ) )		{			Entry *matched;			int err;			const char *text;						e = deref_entry_r( op->o_bd, e, &err, &matched, &text );			if( e == NULL ) {				e = matched;				goto loop_continue;			}			if( e->e_id == id ) {				/* circular loop */				goto loop_continue;			}			/* need to skip alias which deref into scope */			if( op->ors_scope == LDAP_SCOPE_ONELEVEL ) {				struct berval pdn;				dnParent( &e->e_nname, &pdn );				if ( ber_bvcmp( &pdn, &realbase ) ) {					goto loop_continue;				}			} else if ( dnIsSuffix( &e->e_nname, &realbase ) ) {				/* alias is within scope */				Debug( LDAP_DEBUG_TRACE,					"ldbm_search: alias \"%s\" in subtree\n",					e->e_dn, 0, 0 );				goto loop_continue;			}			rs->sr_entry = e;			scopeok = 1;		}		/*		 * If it's a referral, add it to the list of referrals.		 * Only do this for non-base searches, and don't check		 * the filter explicitly here since it's only a candidate		 * anyway.		 */		if ( !manageDSAit && op->ors_scope != LDAP_SCOPE_BASE &&			is_entry_referral( e ) )		{			struct berval	dn;			/* check scope */			if ( !scopeok && op->ors_scope == LDAP_SCOPE_ONELEVEL ) {				if ( !be_issuffix( op->o_bd, &e->e_nname ) ) {					dnParent( &e->e_nname, &dn );					scopeok = dn_match( &dn, &realbase );				} else {					scopeok = (realbase.bv_len == 0);				}			} else if ( !scopeok				&& op->ors_scope == LDAP_SCOPE_SUBTREE )			{				scopeok = dnIsSuffix( &e->e_nname, &realbase );#ifdef LDAP_SCOPE_SUBORDINATE			} else if ( !scopeok				&& op->ors_scope == LDAP_SCOPE_SUBORDINATE )			{				scopeok = !dn_match( &e->e_nname, &realbase )					&& dnIsSuffix( &e->e_nname, &realbase );#endif			} else {				scopeok = 1;			}			if( scopeok ) {				BerVarray erefs = get_entry_referrals( op, e );				rs->sr_ref = referral_rewrite( erefs,					&e->e_name, NULL,					op->ors_scope == LDAP_SCOPE_ONELEVEL						? LDAP_SCOPE_BASE						: LDAP_SCOPE_SUBTREE );				ber_bvarray_free( erefs );				send_search_reference( op, rs );				ber_bvarray_free( rs->sr_ref );				rs->sr_ref = NULL;			} else {				Debug( LDAP_DEBUG_TRACE,					"ldbm_search: candidate referral %ld scope not okay\n",					id, 0, 0 );			}			goto loop_continue;		}		if ( !manageDSAit && is_entry_glue( e )) {			goto loop_continue;		}		/* if it matches the filter and scope, send it */		result = test_filter( op, e, op->ors_filter );		if ( result == LDAP_COMPARE_TRUE ) {			struct berval	dn;			/* check scope */			if ( !scopeok && op->ors_scope == LDAP_SCOPE_ONELEVEL ) {				if ( !be_issuffix( op->o_bd, &e->e_nname ) ) {					dnParent( &e->e_nname, &dn );					scopeok = dn_match( &dn, &realbase );				} else {					scopeok = (realbase.bv_len == 0);				}			} else if ( !scopeok &&				op->ors_scope == LDAP_SCOPE_SUBTREE )			{				scopeok = dnIsSuffix( &e->e_nname, &realbase );			} else if ( !scopeok &&				op->ors_scope == LDAP_SCOPE_SUBORDINATE )			{				scopeok = !dn_match( &e->e_nname, &realbase )					&& dnIsSuffix( &e->e_nname, &realbase );			} else {				scopeok = 1;			}			if ( scopeok ) {				if (e) {					rs->sr_flags = 0;					rs->sr_err = send_search_entry( op, rs );					switch ( rs->sr_err ) {					case LDAP_UNAVAILABLE:	/* connection closed */						cache_return_entry_r( &li->li_cache, e );						rc = LDAP_SUCCESS;						goto done;					case LDAP_SIZELIMIT_EXCEEDED:						cache_return_entry_r( &li->li_cache, e );						rc = rs->sr_err;						rs->sr_entry = NULL;						send_ldap_result( op, rs );						rc = LDAP_SUCCESS;						goto done;					}				}			} else {				Debug( LDAP_DEBUG_TRACE,					"ldbm_search: candidate entry %ld scope not okay\n",					id, 0, 0 );			}		} else {			Debug( LDAP_DEBUG_TRACE,				"ldbm_search: candidate entry %ld does not match filter\n",				id, 0, 0 );		}loop_continue:		if( e != NULL ) {			/* free reader lock */			cache_return_entry_r( &li->li_cache, e );		}		ldap_pvt_thread_yield();	}	rs->sr_err = rs->sr_v2ref ? LDAP_REFERRAL : LDAP_SUCCESS;	rs->sr_ref = rs->sr_v2ref;	send_ldap_result( op, rs );	rc = LDAP_SUCCESS;done:	ldap_pvt_thread_rdwr_runlock(&li->li_giant_rwlock);	if( candidates != NULL )		idl_free( candidates );	if( rs->sr_v2ref ) ber_bvarray_free( rs->sr_v2ref );	if( realbase.bv_val ) free( realbase.bv_val );	return rc;}static ID_BLOCK *base_candidate(    Backend	*be,	Entry	*e ){	ID_BLOCK		*idl;	Debug(LDAP_DEBUG_TRACE, "base_candidates: base: \"%s\"\n",		e->e_dn, 0, 0);	idl = idl_alloc( 1 );	idl_insert( &idl, e->e_id, 1 );	return( idl );}static ID_BLOCK *search_candidates(    Operation	*op,    Entry	*e,    Filter	*filter,    int		scope,	int		deref,	int		manageDSAit ){	ID_BLOCK		*candidates;	Filter		f, fand, rf, af, xf;    AttributeAssertion aa_ref, aa_alias;	struct berval bv_ref = { sizeof("referral")-1, "referral" };	struct berval bv_alias = { sizeof("alias")-1, "alias" };#ifdef LDBM_SUBENTRIES	Filter  sf;	AttributeAssertion aa_subentry;#endif	Debug(LDAP_DEBUG_TRACE,		"search_candidates: base=\"%s\" s=%d d=%d\n",		e->e_ndn, scope, deref );	xf.f_or = filter;	xf.f_choice = LDAP_FILTER_OR;	xf.f_next = NULL;	if( !manageDSAit ) {		/* match referrals */		rf.f_choice = LDAP_FILTER_EQUALITY;		rf.f_ava = &aa_ref;		rf.f_av_desc = slap_schema.si_ad_objectClass;		rf.f_av_value = bv_ref;		rf.f_next = xf.f_or;		xf.f_or = &rf;	}	if( deref & LDAP_DEREF_SEARCHING ) {		/* match aliases */		af.f_choice = LDAP_FILTER_EQUALITY;		af.f_ava = &aa_alias;		af.f_av_desc = slap_schema.si_ad_objectClass;		af.f_av_value = bv_alias;		af.f_next = xf.f_or;		xf.f_or = &af;	}	f.f_next = NULL;	f.f_choice = LDAP_FILTER_AND;	f.f_and = &fand;	fand.f_choice = scope == LDAP_SCOPE_ONELEVEL		? SLAPD_FILTER_DN_ONE		: SLAPD_FILTER_DN_SUBTREE;	fand.f_dn = &e->e_nname;	fand.f_next = xf.f_or == filter ? filter : &xf ;#ifdef LDBM_SUBENTRIES	if ( get_subentries_visibility( op )) {		struct berval bv_subentry = { sizeof("SUBENTRY")-1, "SUBENTRY" };		sf.f_choice = LDAP_FILTER_EQUALITY;		sf.f_ava = &aa_subentry;		sf.f_av_desc = slap_schema.si_ad_objectClass;		sf.f_av_value = bv_subentry;		sf.f_next = fand.f_next;		fand.f_next = &sf;	}#endif	candidates = filter_candidates( op, &f );	return( candidates );}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?