📄 search.c
字号:
/* search.c - search operation *//* $OpenLDAP: pkg/ldap/servers/slapd/back-bdb/search.c,v 1.221.2.15 2007/01/02 21:44:00 kurt Exp $ *//* This work is part of OpenLDAP Software <http://www.openldap.org/>. * * Copyright 2000-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 "back-bdb.h"#include "idl.h"static int base_candidate( BackendDB *be, Entry *e, ID *ids );static int search_candidates( Operation *op, SlapReply *rs, Entry *e, u_int32_t locker, ID *ids, ID *scopes );static int parse_paged_cookie( Operation *op, SlapReply *rs );static void send_paged_response( Operation *op, SlapReply *rs, ID *lastid, int tentries );/* Dereference aliases for a single alias entry. Return the final * dereferenced entry on success, NULL on any failure. */static Entry * deref_base ( Operation *op, SlapReply *rs, Entry *e, Entry **matched, u_int32_t locker, DB_LOCK *lock, ID *tmp, ID *visited ){ struct bdb_info *bdb = (struct bdb_info *) op->o_bd->be_private; struct berval ndn; EntryInfo *ei; DB_LOCK lockr; rs->sr_err = LDAP_ALIAS_DEREF_PROBLEM; rs->sr_text = "maximum deref depth exceeded"; for (;;) { /* Remember the last entry we looked at, so we can * report broken links */ *matched = e; if (BDB_IDL_N(tmp) >= op->o_bd->be_max_deref_depth) { e = NULL; break; } /* If this is part of a subtree or onelevel search, * have we seen this ID before? If so, quit. */ if ( visited && bdb_idl_insert( visited, e->e_id ) ) { e = NULL; break; } /* If we've seen this ID during this deref iteration, * we've hit a loop. */ if ( bdb_idl_insert( tmp, e->e_id ) ) { rs->sr_err = LDAP_ALIAS_PROBLEM; rs->sr_text = "circular alias"; e = NULL; break; } /* If there was a problem getting the aliasedObjectName, * get_alias_dn will have set the error status. */ if ( get_alias_dn(e, &ndn, &rs->sr_err, &rs->sr_text) ) { e = NULL; break; } rs->sr_err = bdb_dn2entry( op, NULL, &ndn, &ei, 0, locker, &lockr ); if ( ei ) { e = ei->bei_e; } else { e = NULL; } if (!e) { rs->sr_err = LDAP_ALIAS_PROBLEM; rs->sr_text = "aliasedObject not found"; break; } /* Free the previous entry, continue to work with the * one we just retrieved. */ bdb_cache_return_entry_r( bdb->bi_dbenv, &bdb->bi_cache, *matched, lock); *lock = lockr; /* We found a regular entry. Return this to the caller. The * entry is still locked for Read. */ if (!is_entry_alias(e)) { rs->sr_err = LDAP_SUCCESS; rs->sr_text = NULL; break; } } return e;}/* Look for and dereference all aliases within the search scope. Adds * the dereferenced entries to the "ids" list. Requires "stack" to be * able to hold 8 levels of DB_SIZE IDLs. Of course we're hardcoded to * require a minimum of 8 UM_SIZE IDLs so this is never a problem. */static int search_aliases( Operation *op, SlapReply *rs, Entry *e, u_int32_t locker, ID *ids, ID *scopes, ID *stack ){ struct bdb_info *bdb = (struct bdb_info *) op->o_bd->be_private; ID *aliases, *curscop, *subscop, *visited, *newsubs, *oldsubs, *tmp; ID cursora, ida, cursoro, ido, *subscop2; Entry *matched, *a; EntryInfo *ei; struct berval bv_alias = BER_BVC( "alias" );#ifdef LDAP_COMP_MATCH AttributeAssertion aa_alias = { NULL, BER_BVNULL, NULL };#else AttributeAssertion aa_alias = { NULL, BER_BVNULL };#endif Filter af; DB_LOCK locka, lockr; int first = 1; aliases = stack; /* IDL of all aliases in the database */ curscop = aliases + BDB_IDL_DB_SIZE; /* Aliases in the current scope */ subscop = curscop + BDB_IDL_DB_SIZE; /* The current scope */ visited = subscop + BDB_IDL_DB_SIZE; /* IDs we've seen in this search */ newsubs = visited + BDB_IDL_DB_SIZE; /* New subtrees we've added */ oldsubs = newsubs + BDB_IDL_DB_SIZE; /* Subtrees added previously */ tmp = oldsubs + BDB_IDL_DB_SIZE; /* Scratch space for deref_base() */ /* A copy of subscop, because subscop gets clobbered by * the bdb_idl_union/intersection routines */ subscop2 = tmp + BDB_IDL_DB_SIZE; 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 = NULL; /* Find all aliases in database */ BDB_IDL_ZERO( aliases ); rs->sr_err = bdb_filter_candidates( op, &af, aliases, curscop, visited ); if (rs->sr_err != LDAP_SUCCESS) { return rs->sr_err; } oldsubs[0] = 1; oldsubs[1] = e->e_id; BDB_IDL_ZERO( ids ); BDB_IDL_ZERO( visited ); BDB_IDL_ZERO( newsubs ); cursoro = 0; ido = bdb_idl_first( oldsubs, &cursoro ); for (;;) { /* Set curscop to only the aliases in the current scope. Start with * all the aliases, obtain the IDL for the current scope, and then * get the intersection of these two IDLs. Add the current scope * to the cumulative list of candidates. */ BDB_IDL_CPY( curscop, aliases ); rs->sr_err = bdb_dn2idl( op, e, subscop, subscop2+BDB_IDL_DB_SIZE ); if (first) { first = 0; } else { bdb_cache_return_entry_r (bdb->bi_dbenv, &bdb->bi_cache, e, &locka); } BDB_IDL_CPY(subscop2, subscop); rs->sr_err = bdb_idl_intersection(curscop, subscop); bdb_idl_union( ids, subscop2 ); /* Dereference all of the aliases in the current scope. */ cursora = 0; for (ida = bdb_idl_first(curscop, &cursora); ida != NOID; ida = bdb_idl_next(curscop, &cursora)) { ei = NULL;retry1: rs->sr_err = bdb_cache_find_id(op, NULL, ida, &ei, 0, locker, &lockr ); if (rs->sr_err != LDAP_SUCCESS) { if ( rs->sr_err == DB_LOCK_DEADLOCK || rs->sr_err == DB_LOCK_NOTGRANTED ) goto retry1; continue; } a = ei->bei_e; /* This should only happen if the curscop IDL has maxed out and * turned into a range that spans IDs indiscriminately */ if (!is_entry_alias(a)) { bdb_cache_return_entry_r (bdb->bi_dbenv, &bdb->bi_cache, a, &lockr); continue; } /* Actually dereference the alias */ BDB_IDL_ZERO(tmp); a = deref_base( op, rs, a, &matched, locker, &lockr, tmp, visited ); if (a) { /* If the target was not already in our current candidates, * make note of it in the newsubs list. Also * set it in the scopes list so that bdb_search * can check it. */ if (bdb_idl_insert(ids, a->e_id) == 0) { bdb_idl_insert(newsubs, a->e_id); bdb_idl_insert(scopes, a->e_id); } bdb_cache_return_entry_r( bdb->bi_dbenv, &bdb->bi_cache, a, &lockr); } else if (matched) { /* Alias could not be dereferenced, or it deref'd to * an ID we've already seen. Ignore it. */ bdb_cache_return_entry_r( bdb->bi_dbenv, &bdb->bi_cache, matched, &lockr ); rs->sr_text = NULL; } } /* If this is a OneLevel search, we're done; oldsubs only had one * ID in it. For a Subtree search, oldsubs may be a list of scope IDs. */ if ( op->ors_scope == LDAP_SCOPE_ONELEVEL ) break;nextido: ido = bdb_idl_next( oldsubs, &cursoro ); /* If we're done processing the old scopes, did we add any new * scopes in this iteration? If so, go back and do those now. */ if (ido == NOID) { if (BDB_IDL_IS_ZERO(newsubs)) break; BDB_IDL_CPY(oldsubs, newsubs); BDB_IDL_ZERO(newsubs); cursoro = 0; ido = bdb_idl_first( oldsubs, &cursoro ); } /* Find the entry corresponding to the next scope. If it can't * be found, ignore it and move on. This should never happen; * we should never see the ID of an entry that doesn't exist. * Set the name so that the scope's IDL can be retrieved. */ ei = NULL;sameido: rs->sr_err = bdb_cache_find_id(op, NULL, ido, &ei, 0, locker, &locka ); if ( rs->sr_err != LDAP_SUCCESS ) { if ( rs->sr_err == DB_LOCK_DEADLOCK || rs->sr_err == DB_LOCK_NOTGRANTED ) goto sameido; goto nextido; } e = ei->bei_e; } return rs->sr_err;}intbdb_search( Operation *op, SlapReply *rs ){ struct bdb_info *bdb = (struct bdb_info *) op->o_bd->be_private; time_t stoptime; ID id, cursor; ID candidates[BDB_IDL_UM_SIZE]; ID scopes[BDB_IDL_DB_SIZE]; Entry *e = NULL, base, e_root = {0}; Entry *matched = NULL; EntryInfo *ei, ei_root = {0}; struct berval realbase = BER_BVNULL;#ifdef SLAP_ACL_HONOR_DISCLOSE slap_mask_t mask;#endif int manageDSAit; int tentries = 0; ID lastid = NOID; AttributeName *attrs; u_int32_t locker = 0; DB_LOCK lock; struct bdb_op_info *opinfo = NULL; DB_TXN *ltid = NULL; Debug( LDAP_DEBUG_TRACE, "=> " LDAP_XSTRING(bdb_search) "\n", 0, 0, 0); attrs = op->oq_search.rs_attrs; opinfo = (struct bdb_op_info *) op->o_private; manageDSAit = get_manageDSAit( op ); if ( opinfo && opinfo->boi_txn ) { ltid = opinfo->boi_txn; locker = TXN_ID( ltid ); } else { rs->sr_err = LOCK_ID( bdb->bi_dbenv, &locker ); switch(rs->sr_err) { case 0: break; default: send_ldap_error( op, rs, LDAP_OTHER, "internal error" ); return rs->sr_err; } } if ( op->o_req_ndn.bv_len == 0 ) { /* DIT root special case */ ei_root.bei_e = &e_root; ei_root.bei_parent = &ei_root; e_root.e_private = &ei_root; e_root.e_id = 0; BER_BVSTR( &e_root.e_nname, "" ); BER_BVSTR( &e_root.e_name, "" ); ei = &ei_root; rs->sr_err = LDAP_SUCCESS; } else { if ( op->ors_deref & LDAP_DEREF_FINDING ) { BDB_IDL_ZERO(candidates); }dn2entry_retry: /* get entry with reader lock */ rs->sr_err = bdb_dn2entry( op, ltid, &op->o_req_ndn, &ei, 1, locker, &lock ); } switch(rs->sr_err) { case DB_NOTFOUND: matched = ei->bei_e; break; case 0: e = ei->bei_e; break; case LDAP_BUSY: send_ldap_error( op, rs, LDAP_BUSY, "ldap server busy" ); if ( !opinfo ) LOCK_ID_FREE (bdb->bi_dbenv, locker ); return LDAP_BUSY; case DB_LOCK_DEADLOCK: case DB_LOCK_NOTGRANTED: goto dn2entry_retry; default: send_ldap_error( op, rs, LDAP_OTHER, "internal error" ); if ( !opinfo ) LOCK_ID_FREE (bdb->bi_dbenv, locker ); return rs->sr_err; } if ( op->ors_deref & LDAP_DEREF_FINDING ) { if ( matched && is_entry_alias( matched )) { struct berval stub; stub.bv_val = op->o_req_ndn.bv_val; stub.bv_len = op->o_req_ndn.bv_len - matched->e_nname.bv_len - 1; e = deref_base( op, rs, matched, &matched, locker, &lock, candidates, NULL ); if ( e ) { build_new_dn( &op->o_req_ndn, &e->e_nname, &stub, op->o_tmpmemctx ); bdb_cache_return_entry_r (bdb->bi_dbenv, &bdb->bi_cache, e, &lock); matched = NULL; goto dn2entry_retry; } } else if ( e && is_entry_alias( e )) { e = deref_base( op, rs, e, &matched, locker, &lock, candidates, NULL ); } } if ( e == NULL ) { struct berval matched_dn = BER_BVNULL; if ( matched != NULL ) { BerVarray erefs = NULL;#ifdef SLAP_ACL_HONOR_DISCLOSE /* return referral only if "disclose" * is granted on the object */ if ( ! access_allowed( op, matched, slap_schema.si_ad_entry, NULL, ACL_DISCLOSE, NULL ) ) { rs->sr_err = LDAP_NO_SUCH_OBJECT;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -