/* Look for and dereference all aliases within the search scope. * Requires "stack" to be able to hold 6 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, ID e_id, IdScopes *isc, MDB_cursor *mci, ID *stack ) { ID *aliases, *curscop, *visited, *newsubs, *oldsubs, *tmp; ID cursora, ida, cursoro, ido; Entry *matched, *a; struct berval bv_alias = BER_BVC( "alias" ); AttributeAssertion aa_alias = ATTRIBUTEASSERTION_INIT; Filter af; int first = 1; aliases = stack; /* IDL of all aliases in the database */ curscop = aliases + MDB_IDL_DB_SIZE; /* Aliases in the current scope */ visited = curscop + MDB_IDL_DB_SIZE; /* IDs we've seen in this search */ newsubs = visited + MDB_IDL_DB_SIZE; /* New subtrees we've added */ oldsubs = newsubs + MDB_IDL_DB_SIZE; /* Subtrees added previously */ tmp = oldsubs + MDB_IDL_DB_SIZE; /* Scratch space for deref_base() */ 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 */ MDB_IDL_ZERO( aliases ); rs->sr_err = mdb_filter_candidates( op, isc->mt, &af, aliases, curscop, visited ); if (rs->sr_err != LDAP_SUCCESS || MDB_IDL_IS_ZERO( aliases )) { return rs->sr_err; } oldsubs[0] = 1; oldsubs[1] = e_id; MDB_IDL_ZERO( visited ); MDB_IDL_ZERO( newsubs ); cursoro = 0; ido = mdb_idl_first( oldsubs, &cursoro ); for (;;) { /* Set curscop to only the aliases in the current scope. Start with * all the aliases, then get the intersection with the scope. */ rs->sr_err = mdb_idscope( op, isc->mt, e_id, aliases, curscop ); /* Dereference all of the aliases in the current scope. */ cursora = 0; for (ida = mdb_idl_first(curscop, &cursora); ida != NOID; ida = mdb_idl_next(curscop, &cursora)) { rs->sr_err = mdb_id2entry(op, mci, ida, &a); if (rs->sr_err != LDAP_SUCCESS) { continue; } /* 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)) { mdb_entry_return(op, a); continue; } /* Actually dereference the alias */ MDB_IDL_ZERO(tmp); a = deref_base( op, rs, a, &matched, isc->mt, tmp, visited ); if (a) { /* If the target was not already in our current scopes, * make note of it in the newsubs list. */ ID2 mid; mid.mid = a->e_id; mid.mval.mv_data = NULL; if (op->ors_scope == LDAP_SCOPE_SUBTREE) { isc->id = a->e_id; /* if ID is a child of any of our current scopes, * ignore it, it's already included. */ if (mdb_idscopechk(op, isc)) goto skip; } if (mdb_id2l_insert(isc->scopes, &mid) == 0) { mdb_idl_insert(newsubs, a->e_id); } skip: mdb_entry_return( op, a ); } else if (matched) { /* Alias could not be dereferenced, or it deref'd to * an ID we've already seen. Ignore it. */ mdb_entry_return( op, matched ); rs->sr_text = NULL; rs->sr_err = 0; } } /* 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 = mdb_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 (MDB_IDL_IS_ZERO(newsubs)) break; MDB_IDL_CPY(oldsubs, newsubs); MDB_IDL_ZERO(newsubs); cursoro = 0; ido = mdb_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. */ { MDB_val edata; rs->sr_err = mdb_id2edata(op, mci, ido, &edata); if ( rs->sr_err != MDB_SUCCESS ) { goto nextido; } e_id = ido; } } return rs->sr_err; }
static int list_candidates( Operation *op, MDB_txn *rtxn, Filter *flist, int ftype, ID *ids, ID *tmp, ID *save ) { int rc = 0; Filter *f; Debug( LDAP_DEBUG_FILTER, "=> mdb_list_candidates 0x%x\n", ftype, 0, 0 ); for ( f = flist; f != NULL; f = f->f_next ) { /* ignore precomputed scopes */ if ( f->f_choice == SLAPD_FILTER_COMPUTED && f->f_result == LDAP_SUCCESS ) { continue; } MDB_IDL_ZERO( save ); rc = mdb_filter_candidates( op, rtxn, f, save, tmp, save+MDB_IDL_UM_SIZE ); if ( rc != 0 ) { if ( ftype == LDAP_FILTER_AND ) { rc = 0; continue; } break; } if ( ftype == LDAP_FILTER_AND ) { if ( f == flist ) { MDB_IDL_CPY( ids, save ); } else { mdb_idl_intersection( ids, save ); } if( MDB_IDL_IS_ZERO( ids ) ) break; } else { if ( f == flist ) { MDB_IDL_CPY( ids, save ); } else { mdb_idl_union( ids, save ); } } } if( rc == LDAP_SUCCESS ) { Debug( LDAP_DEBUG_FILTER, "<= mdb_list_candidates: id=%ld first=%ld last=%ld\n", (long) ids[0], (long) MDB_IDL_FIRST(ids), (long) MDB_IDL_LAST(ids) ); } else { Debug( LDAP_DEBUG_FILTER, "<= mdb_list_candidates: undefined rc=%d\n", rc, 0, 0 ); } return rc; }
static int search_candidates( Operation *op, SlapReply *rs, Entry *e, IdScopes *isc, MDB_cursor *mci, ID *ids, ID *stack ) { struct mdb_info *mdb = (struct mdb_info *) op->o_bd->be_private; int rc, depth = 1; Filter *f, rf, xf, nf, sf; AttributeAssertion aa_ref = ATTRIBUTEASSERTION_INIT; AttributeAssertion aa_subentry = ATTRIBUTEASSERTION_INIT; /* * This routine takes as input a filter (user-filter) * and rewrites it as follows: * (&(scope=DN)[(objectClass=subentry)] * (|[(objectClass=referral)](user-filter)) */ Debug(LDAP_DEBUG_TRACE, "search_candidates: base=\"%s\" (0x%08lx) scope=%d\n", e->e_nname.bv_val, (long) e->e_id, op->oq_search.rs_scope ); f = op->oq_search.rs_filter; /* If the user's filter uses objectClass=*, * these clauses are redundant. */ if (!oc_filter(op->oq_search.rs_filter, 1, &depth) && !get_subentries_visibility(op)) { if( !get_manageDSAit(op) && !get_domainScope(op) ) { /* match referral objects */ struct berval bv_ref = BER_BVC( "referral" ); 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 = f; xf.f_or = &rf; xf.f_choice = LDAP_FILTER_OR; xf.f_next = NULL; f = &xf; depth++; } } if( get_subentries_visibility( op ) ) { struct berval bv_subentry = BER_BVC( "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 = f; nf.f_choice = LDAP_FILTER_AND; nf.f_and = &sf; nf.f_next = NULL; f = &nf; depth++; } /* Allocate IDL stack, plus 1 more for former tmp */ if ( depth+1 > mdb->mi_search_stack_depth ) { stack = ch_malloc( (depth + 1) * MDB_IDL_UM_SIZE * sizeof( ID ) ); } if( op->ors_deref & LDAP_DEREF_SEARCHING ) { rc = search_aliases( op, rs, e->e_id, isc, mci, stack ); } else { rc = LDAP_SUCCESS; } if ( rc == LDAP_SUCCESS ) { rc = mdb_filter_candidates( op, isc->mt, f, ids, stack, stack+MDB_IDL_UM_SIZE ); } if ( depth+1 > mdb->mi_search_stack_depth ) { ch_free( stack ); } if( rc ) { Debug(LDAP_DEBUG_TRACE, "mdb_search_candidates: failed (rc=%d)\n", rc, NULL, NULL ); } else { Debug(LDAP_DEBUG_TRACE, "mdb_search_candidates: id=%ld first=%ld last=%ld\n", (long) ids[0], (long) MDB_IDL_FIRST(ids), (long) MDB_IDL_LAST(ids) ); } return rc; }