static int ext_candidates( Operation *op, MDB_txn *rtxn, MatchingRuleAssertion *mra, ID *ids, ID *tmp, ID *stack) { #ifdef LDAP_COMP_MATCH /* * Currently Only Component Indexing for componentFilterMatch is supported * Indexing for an extensible filter is not supported yet */ if ( mra->ma_cf ) { return comp_candidates ( op, rtxn, mra, mra->ma_cf, ids, tmp, stack); } #endif if ( mra->ma_desc == slap_schema.si_ad_entryDN ) { int rc; ID id; MDB_IDL_ZERO( ids ); if ( mra->ma_rule == slap_schema.si_mr_distinguishedNameMatch ) { base: rc = mdb_dn2id( op, rtxn, NULL, &mra->ma_value, &id, NULL, NULL, NULL ); if ( rc == MDB_SUCCESS ) { mdb_idl_insert( ids, id ); } return 0; } else if ( mra->ma_rule && mra->ma_rule->smr_match == dnRelativeMatch && dnIsSuffix( &mra->ma_value, op->o_bd->be_nsuffix )) { int scope; if ( mra->ma_rule == slap_schema.si_mr_dnSuperiorMatch ) { mdb_dn2sups( op, rtxn, &mra->ma_value, ids ); return 0; } if ( mra->ma_rule == slap_schema.si_mr_dnSubtreeMatch ) scope = LDAP_SCOPE_SUBTREE; else if ( mra->ma_rule == slap_schema.si_mr_dnOneLevelMatch ) scope = LDAP_SCOPE_ONELEVEL; else if ( mra->ma_rule == slap_schema.si_mr_dnSubordinateMatch ) scope = LDAP_SCOPE_SUBORDINATE; else goto base; /* scope = LDAP_SCOPE_BASE; */ #if 0 if ( scope > LDAP_SCOPE_BASE ) { ei = NULL; rc = mdb_cache_find_ndn( op, rtxn, &mra->ma_value, &ei ); if ( ei ) mdb_cache_entryinfo_unlock( ei ); if ( rc == LDAP_SUCCESS ) { int sc = op->ors_scope; op->ors_scope = scope; rc = mdb_dn2idl( op, rtxn, &mra->ma_value, ei, ids, stack ); op->ors_scope = sc; } return 0; } #endif } } MDB_IDL_ALL( ids ); return 0; }
/* 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; }
/* 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, MDB_txn *txn, ID *tmp, ID *visited ) { struct berval ndn; 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 (MDB_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 && mdb_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 ( mdb_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 = mdb_dn2entry( op, txn, NULL, &ndn, &e, NULL, 0 ); if (rs->sr_err) { 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. */ mdb_entry_return( op, *matched ); /* We found a regular entry. Return this to the caller. */ if (!is_entry_alias(e)) { rs->sr_err = LDAP_SUCCESS; rs->sr_text = NULL; break; } } return e; }
/* return IDs from root to parent of DN */ int mdb_dn2sups( Operation *op, MDB_txn *txn, struct berval *in, ID *ids ) { struct mdb_info *mdb = (struct mdb_info *) op->o_bd->be_private; MDB_cursor *cursor; MDB_dbi dbi = mdb->mi_dn2id; MDB_val key, data; int rc = 0, nrlen; diskNode *d; char *ptr; ID pid, nid; struct berval tmp; Debug( LDAP_DEBUG_TRACE, "=> mdb_dn2sups(\"%s\")\n", in->bv_val ); if ( !in->bv_len ) { goto done; } tmp = *in; nrlen = tmp.bv_len - op->o_bd->be_nsuffix[0].bv_len; tmp.bv_val += nrlen; tmp.bv_len = op->o_bd->be_nsuffix[0].bv_len; nid = 0; key.mv_size = sizeof(ID); rc = mdb_cursor_open( txn, dbi, &cursor ); if ( rc ) goto done; for (;;) { key.mv_data = &pid; pid = nid; data.mv_size = sizeof(diskNode) + tmp.bv_len; d = op->o_tmpalloc( data.mv_size, op->o_tmpmemctx ); d->nrdnlen[1] = tmp.bv_len & 0xff; d->nrdnlen[0] = (tmp.bv_len >> 8) | 0x80; ptr = lutil_strncopy( d->nrdn, tmp.bv_val, tmp.bv_len ); *ptr = '\0'; data.mv_data = d; rc = mdb_cursor_get( cursor, &key, &data, MDB_GET_BOTH ); op->o_tmpfree( d, op->o_tmpmemctx ); if ( rc ) { mdb_cursor_close( cursor ); break; } ptr = (char *) data.mv_data + data.mv_size - 2*sizeof(ID); memcpy( &nid, ptr, sizeof(ID)); if ( pid ) mdb_idl_insert( ids, pid ); if ( tmp.bv_val > in->bv_val ) { for (ptr = tmp.bv_val - 2; ptr > in->bv_val && !DN_SEPARATOR(*ptr); ptr--) /* empty */; if ( ptr >= in->bv_val ) { if (DN_SEPARATOR(*ptr)) ptr++; tmp.bv_len = tmp.bv_val - ptr - 1; tmp.bv_val = ptr; } } else { break; } } done: if( rc != 0 ) { Debug( LDAP_DEBUG_TRACE, "<= mdb_dn2sups: get failed: %s (%d)\n", mdb_strerror( rc ), rc ); } return rc; }