| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491 |
- /** BEGIN COPYRIGHT BLOCK
- * This Program is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License as published by the Free Software
- * Foundation; version 2 of the License.
- *
- * This Program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
- * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this Program; if not, write to the Free Software Foundation, Inc., 59 Temple
- * Place, Suite 330, Boston, MA 02111-1307 USA.
- *
- * In addition, as a special exception, Red Hat, Inc. gives You the additional
- * right to link the code of this Program with code not covered under the GNU
- * General Public License ("Non-GPL Code") and to distribute linked combinations
- * including the two, subject to the limitations in this paragraph. Non-GPL Code
- * permitted under this exception must only link to the code of this Program
- * through those well defined interfaces identified in the file named EXCEPTION
- * found in the source code files (the "Approved Interfaces"). The files of
- * Non-GPL Code may instantiate templates or use macros or inline functions from
- * the Approved Interfaces without causing the resulting work to be covered by
- * the GNU General Public License. Only Red Hat, Inc. may make changes or
- * additions to the list of Approved Interfaces. You must obey the GNU General
- * Public License in all respects for all of the Program code and other code used
- * in conjunction with the Program except the Non-GPL Code covered by this
- * exception. If you modify this file, you may extend this exception to your
- * version of the file, but you are not obligated to do so. If you do not wish to
- * provide this exception without modification, you must delete this exception
- * statement from your version and license this file solely under the GPL without
- * exception.
- *
- *
- * Copyright (C) 2001 Sun Microsystems, Inc. Used by permission.
- * Copyright (C) 2005 Red Hat, Inc.
- * All rights reserved.
- * END COPYRIGHT BLOCK **/
- #ifdef HAVE_CONFIG_H
- # include <config.h>
- #endif
- /* search.c - ldbm backend search function */
- /* view with ts=4 */
- #include "back-ldbm.h"
- #include "vlv_srch.h"
- /* prototypes */
- static int build_candidate_list( Slapi_PBlock *pb, backend *be,
- struct backentry *e, const char * base, int scope,
- int *lookup_returned_allidsp, IDList** candidates);
- static IDList *base_candidates( Slapi_PBlock *pb, struct backentry *e );
- static IDList *onelevel_candidates( Slapi_PBlock *pb, backend *be, const char *base, struct backentry *e, Slapi_Filter *filter, int managedsait, int *lookup_returned_allidsp, int *err );
- static back_search_result_set* new_search_result_set(IDList* idl,int vlv, int lookthroughlimit);
- static void delete_search_result_set( back_search_result_set **sr );
- static int can_skip_filter_test( Slapi_PBlock *pb, struct slapi_filter *f,
- int scope, IDList *idl );
- /* This is for performance testing, allows us to disable ACL checking altogether */
- #if defined(DISABLE_ACL_CHECK)
- #define ACL_CHECK_FLAG 0
- #else
- #define ACL_CHECK_FLAG 1
- #endif
- #define ISLEGACY(be) (be?(be->be_instance_info?(((ldbm_instance *)be->be_instance_info)->inst_li?(((ldbm_instance *)be->be_instance_info)->inst_li->li_legacy_errcode):0):0):0)
- int
- compute_lookthrough_limit( Slapi_PBlock *pb, struct ldbminfo *li )
- {
- Slapi_Connection *conn = NULL;
- int limit;
- slapi_pblock_get( pb, SLAPI_CONNECTION, &conn);
- if ( slapi_reslimit_get_integer_limit( conn,
- li->li_reslimit_lookthrough_handle, &limit )
- != SLAPI_RESLIMIT_STATUS_SUCCESS ) {
- /*
- * no limit associated with binder/connection or some other error
- * occurred. use the default.
- */
- int isroot = 0;
- slapi_pblock_get( pb, SLAPI_REQUESTOR_ISROOT, &isroot );
- if (isroot) {
- limit = -1;
- } else {
- PR_Lock(li->li_config_mutex);
- limit = li->li_lookthroughlimit;
- PR_Unlock(li->li_config_mutex);
- }
- }
- return( limit );
- }
- /* don't free the berval, just clean it */
- static void
- berval_done(struct berval *val)
- {
- slapi_ch_free_string(&val->bv_val);
- }
- /*
- * We call this function as we exit ldbm_back_search
- */
- int ldbm_back_search_cleanup(Slapi_PBlock *pb, struct ldbminfo *li, sort_spec_thing *sort_control, int ldap_result, char* ldap_result_description, int function_result, Slapi_DN *sdn, struct vlv_request *vlv_request_control)
- {
- if(sort_control!=NULL)
- {
- sort_spec_free(sort_control);
- }
- if(ldap_result>=LDAP_SUCCESS)
- {
- slapi_send_ldap_result( pb, ldap_result, NULL, ldap_result_description, 0, NULL );
- }
- {
- /* hack hack --- code to free the result set if we don't need it */
- /* We get it and check to see if the structure was ever used */
- back_search_result_set *sr = NULL;
- slapi_pblock_get( pb, SLAPI_SEARCH_RESULT_SET, &sr );
- if ( (NULL != sr) && (function_result != 0) ) {
- /* in case paged results, clean up the conn */
- pagedresults_set_search_result(pb->pb_conn, NULL);
- slapi_pblock_set( pb, SLAPI_SEARCH_RESULT_SET, NULL );
- delete_search_result_set(&sr);
- }
- }
- slapi_sdn_done(sdn);
- if (vlv_request_control)
- {
- berval_done(&vlv_request_control->value);
- }
- return function_result;
- }
- /*
- * Return values from ldbm_back_search are:
- *
- * 0: Success. A result set is in the pblock. No results have been
- * sent to the client.
- * 1: Success. The result has already been sent to the client.
- * -1: An error occurred, and results have been sent to the client.
- * -2: Disk Full. Abandon ship!
- */
- int
- ldbm_back_search( Slapi_PBlock *pb )
- {
- /* Search stuff */
- backend *be;
- ldbm_instance *inst;
- struct ldbminfo *li;
- struct backentry *e;
- IDList *candidates= NULL;
- char *base;
- Slapi_DN basesdn;
- int scope;
- LDAPControl **controls = NULL;
- Slapi_Operation *operation;
- entry_address *addr;
- /* SORT control stuff */
- int sort = 0;
- int vlv = 0;
- struct berval *sort_spec = NULL;
- int is_sorting_critical = 0;
- int is_sorting_critical_orig = 0;
- sort_spec_thing *sort_control = NULL;
- /* VLV control stuff */
- int virtual_list_view = 0;
- struct berval *vlv_spec = NULL;
- int is_vlv_critical = 0;
- struct vlv_request vlv_request_control;
- back_search_result_set *sr = NULL;
- /* Fix for bugid #394184, SD, 20 Jul 00 */
- int tmp_err = -1; /* must be lower than LDAP_SUCCESS */
- char * tmp_desc = NULL;
- /* end Fix for defect #394184 */
- int lookup_returned_allids = 0;
- int backend_count = 1;
- static int print_once = 1;
- slapi_pblock_get( pb, SLAPI_BACKEND, &be );
- slapi_pblock_get( pb, SLAPI_OPERATION, &operation);
- slapi_pblock_get( pb, SLAPI_PLUGIN_PRIVATE, &li );
- slapi_pblock_get( pb, SLAPI_SEARCH_TARGET, &base );
- slapi_pblock_get( pb, SLAPI_TARGET_ADDRESS, &addr);
- slapi_pblock_get( pb, SLAPI_SEARCH_SCOPE, &scope );
- slapi_pblock_get( pb, SLAPI_REQCONTROLS, &controls );
- slapi_pblock_get( pb, SLAPI_BACKEND_COUNT, &backend_count );
-
- inst = (ldbm_instance *) be->be_instance_info;
- slapi_sdn_init_dn_ndn_byref(&basesdn,base); /* normalized by front end*/
- /* Initialize the result set structure here because we need to use it during search processing */
- /* Beware that if we exit this routine sideways, we might leak this structure */
- sr = new_search_result_set( NULL, 0,
- compute_lookthrough_limit( pb, li ));
- slapi_pblock_set( pb, SLAPI_SEARCH_RESULT_SET, sr );
-
- /* clear this out so we can free it later */
- memset(&vlv_request_control, 0, sizeof(vlv_request_control));
- if ( NULL != controls )
- {
- /* Are we being asked to sort the results ? */
- sort = slapi_control_present( controls, LDAP_CONTROL_SORTREQUEST, &sort_spec, &is_sorting_critical_orig );
- if(sort)
- {
- int r= parse_sort_spec(sort_spec, &sort_control);
- if(r!=0)
- {
- /* Badly formed SORT control */
- return ldbm_back_search_cleanup(pb, li, sort_control, LDAP_PROTOCOL_ERROR, "Sort Control", SLAPI_FAIL_GENERAL, &basesdn, NULL);
- }
- /* set this operation includes the server side sorting */
- operation->o_flags |= OP_FLAG_SERVER_SIDE_SORTING;
- }
- is_sorting_critical = is_sorting_critical_orig;
- /* Are we to provide a virtual view of the list? */
- if ((vlv = slapi_control_present( controls, LDAP_CONTROL_VLVREQUEST, &vlv_spec, &is_vlv_critical)))
- {
- if(sort)
- {
- int r = vlv_parse_request_control( be, vlv_spec, &vlv_request_control );
- if(r!=LDAP_SUCCESS)
- {
- /* Badly formed VLV control */
- return ldbm_back_search_cleanup(pb, li, sort_control, r, "VLV Control", SLAPI_FAIL_GENERAL, &basesdn, &vlv_request_control);
- }
- {
- /* Access Control Check to see if the client is allowed to use the VLV Control. */
- Slapi_Entry *feature;
- char dn[128];
- char *dummyAttr = "dummy#attr";
- char *dummyAttrs[2] = { NULL, NULL };
- dummyAttrs[0] = dummyAttr;
- PR_snprintf(dn,sizeof(dn),"dn: oid=%s,cn=features,cn=config",LDAP_CONTROL_VLVREQUEST);
- feature= slapi_str2entry(dn,0);
- r= plugin_call_acl_plugin (pb, feature, dummyAttrs, NULL, SLAPI_ACL_READ, ACLPLUGIN_ACCESS_DEFAULT, NULL);
- slapi_entry_free(feature);
- if(r!=LDAP_SUCCESS)
- {
- /* Client isn't allowed to do this. */
- return ldbm_back_search_cleanup(pb, li, sort_control, r, "VLV Control", SLAPI_FAIL_GENERAL, &basesdn, &vlv_request_control);
- }
- }
- /*
- * Sorting must always be critical for VLV; Force it be so.
- */
- is_sorting_critical= 1;
- virtual_list_view= 1;
- }
- else
- {
- /* Can't have a VLV control without a SORT control */
- return ldbm_back_search_cleanup(pb, li, sort_control, LDAP_SORT_CONTROL_MISSING, "VLV Control", SLAPI_FAIL_GENERAL, &basesdn, &vlv_request_control);
- }
- }
- }
- if ((virtual_list_view || sort) && backend_count > 0)
- {
- char *ctrlstr = NULL;
- struct vlv_response vlv_response = {0};
- if (virtual_list_view)
- {
- if (sort)
- {
- ctrlstr = "The VLV and sort controls cannot be processed";
- }
- else
- {
- ctrlstr = "The VLV control cannot be processed";
- }
- }
- else
- {
- if (sort)
- {
- ctrlstr = "The sort control cannot be processed";
- }
- }
- PR_ASSERT(NULL != ctrlstr);
- if (print_once)
- {
- LDAPDebug(LDAP_DEBUG_ANY,
- "ERROR: %s "
- "when more than one backend is involved. "
- "VLV indexes that will never be used should be removed.\n",
- ctrlstr, 0, 0);
- print_once = 0;
- }
- /* 402380: mapping tree must refuse VLV and SORT control
- * when several backends are impacted by a search */
- if (0 != is_vlv_critical)
- {
- vlv_response.result = LDAP_UNWILLING_TO_PERFORM;
- vlv_make_response_control(pb, &vlv_response);
- if (sort)
- {
- sort_make_sort_response_control(pb, LDAP_UNWILLING_TO_PERFORM, NULL);
- }
- if (ISLEGACY(be))
- {
- return ldbm_back_search_cleanup(pb, li, sort_control,
- LDAP_UNWILLING_TO_PERFORM, ctrlstr,
- SLAPI_FAIL_GENERAL, &basesdn, &vlv_request_control);
- }
- else
- {
- return ldbm_back_search_cleanup(pb, li, sort_control,
- LDAP_VIRTUAL_LIST_VIEW_ERROR, ctrlstr,
- SLAPI_FAIL_GENERAL, &basesdn, &vlv_request_control);
- }
- }
- else
- {
- if (0 != is_sorting_critical_orig)
- {
- if (virtual_list_view)
- {
- vlv_response.result = LDAP_UNWILLING_TO_PERFORM;
- vlv_make_response_control(pb, &vlv_response);
- }
- sort_make_sort_response_control(pb, LDAP_UNWILLING_TO_PERFORM, NULL);
- return ldbm_back_search_cleanup(pb, li, sort_control,
- LDAP_UNAVAILABLE_CRITICAL_EXTENSION, ctrlstr,
- SLAPI_FAIL_GENERAL, &basesdn, &vlv_request_control);
- }
- else /* vlv and sorting are not critical, so ignore the control */
- {
- if (virtual_list_view)
- {
- vlv_response.result = LDAP_UNWILLING_TO_PERFORM;
- vlv_make_response_control(pb, &vlv_response);
- }
- if (sort)
- {
- sort_make_sort_response_control(pb, LDAP_UNWILLING_TO_PERFORM, NULL);
- }
- sort = 0;
- virtual_list_view = 0;
- }
- }
- }
- /*
- * Get the base object for the search.
- * The entry "" will never be contained in the database,
- * so treat it as a special case.
- */
- if ( *base == '\0' )
- {
- e = NULL;
- }
- else
- {
- if ( ( e = find_entry( pb, be, addr, NULL )) == NULL )
- {
- /* error or referral sent by find_entry */
- return ldbm_back_search_cleanup(pb, li, sort_control, -1, NULL, 1, &basesdn, &vlv_request_control);
- }
- }
- /*
- * If this is a persistent search then the client is only
- * interested in entries that change, so we skip building
- * a candidate list.
- */
- if (operation_is_flag_set( operation, OP_FLAG_PS_CHANGESONLY ))
- {
- candidates = NULL;
- }
- else
- {
- time_t time_up= 0;
- int lookthrough_limit = 0;
- struct vlv_response vlv_response_control;
- int abandoned= 0;
- int vlv_rc;
- /*
- * Build a list of IDs for this entry and scope
- */
- if ((NULL != controls) && (sort) && (vlv)) {
- /* This candidate list is for vlv, no need for sort only. */
- switch (vlv_search_build_candidate_list(pb, &basesdn, &vlv_rc,
- sort_control,
- (vlv ? &vlv_request_control : NULL),
- &candidates, &vlv_response_control)) {
- case VLV_ACCESS_DENIED:
- return ldbm_back_search_cleanup(pb, li, sort_control,
- vlv_rc, "VLV Control",
- SLAPI_FAIL_GENERAL, &basesdn,
- &vlv_request_control);
- case VLV_BLD_LIST_FAILED:
- return ldbm_back_search_cleanup(pb, li, sort_control,
- vlv_response_control.result,
- NULL, SLAPI_FAIL_GENERAL,
- &basesdn, &vlv_request_control);
-
- case LDAP_SUCCESS:
- /* Log to the access log the particulars of this sort request */
- /* Log message looks like this: SORT <key list useful for input
- * to ldapsearch> <#candidates> | <unsortable> */
- sort_log_access(pb,sort_control,NULL);
- /* Since a pre-computed index was found for the VLV Search then
- * the candidate list now contains exactly what should be
- * returned.
- * There's no need to sort or trim the candidate list.
- *
- * However, the client will be expecting a Sort Response control
- */
- if (LDAP_SUCCESS !=
- sort_make_sort_response_control( pb, 0, NULL ) )
- {
- return ldbm_back_search_cleanup(pb, li, sort_control,
- LDAP_OPERATIONS_ERROR,
- "Sort Response Control",
- SLAPI_FAIL_GENERAL,
- &basesdn,
- &vlv_request_control);
- }
- }
- }
- if (candidates == NULL)
- {
- int rc = build_candidate_list(pb, be, e, base, scope,
- &lookup_returned_allids, &candidates);
- if (rc)
- {
- /* Error result sent by build_candidate_list */
- return ldbm_back_search_cleanup(pb, li, sort_control, -1,
- NULL, rc, &basesdn,
- &vlv_request_control);
- }
- /*
- * If we're sorting then we must check what administrative
- * limits should be imposed. Work out at what time to give
- * up, and how many entries we should sift through.
- */
- if (sort && (NULL != candidates))
- {
- time_t optime = 0;
- int tlimit = 0;
- slapi_pblock_get( pb, SLAPI_SEARCH_TIMELIMIT, &tlimit );
- slapi_pblock_get( pb, SLAPI_OPINITIATED_TIME, &optime );
- /*
- * (tlimit==-1) means no time limit
- */
- time_up = (tlimit==-1 ? -1 : optime + tlimit);
- lookthrough_limit = compute_lookthrough_limit( pb, li );
- }
- /*
- * If we're presenting a virtual list view, then apply the
- * search filter before sorting.
- */
- if (virtual_list_view && (NULL != candidates))
- {
- int r = 0;
- IDList *idl = NULL;
- Slapi_Filter *filter = NULL;
- slapi_pblock_get( pb, SLAPI_SEARCH_FILTER, &filter );
- r = vlv_filter_candidates(be, pb, candidates, &basesdn,
- scope, filter, &idl,
- lookthrough_limit, time_up);
- if(r == 0)
- {
- idl_free(candidates);
- candidates= idl;
- }
- else
- {
- return ldbm_back_search_cleanup(pb, li, sort_control,
- r, NULL, -1, &basesdn,
- &vlv_request_control);
- }
- }
- /*
- * Client wants the server to sort the results.
- */
- if (sort)
- {
- if (NULL == candidates)
- {
- /* Even if candidates is NULL, we have to return a sort
- * response control with the LDAP_SUCCESS return code. */
- if (LDAP_SUCCESS !=
- sort_make_sort_response_control( pb, LDAP_SUCCESS, NULL ))
- {
- return ldbm_back_search_cleanup(pb, li, sort_control,
- (abandoned?-1:LDAP_PROTOCOL_ERROR),
- "Sort Response Control", -1,
- &basesdn, &vlv_request_control);
- }
- }
- else
- {
- /* Before we haste off to sort the candidates, we need to
- * prepare some information for the purpose of imposing the
- * administrative limits.
- * We figure out the time when the time limit will be up.
- * We can't use the size limit because we might be sorting
- * a candidate list larger than the result set.
- * But, we can use the lookthrough limit---we count each
- * time we access an entry as one look and act accordingly.
- */
- char *sort_error_type = NULL;
- int sort_return_value = 0;
- /* Don't log internal operations */
- if (!operation_is_flag_set(operation, OP_FLAG_INTERNAL)) {
- /* Log to the access log the particulars of this
- * sort request */
- /* Log message looks like this: SORT <key list useful for
- * input to ldapsearch> <#candidates> | <unsortable> */
- sort_log_access(pb,sort_control,candidates);
- }
- sort_return_value = sort_candidates( be, lookthrough_limit,
- time_up, pb, candidates,
- sort_control,
- &sort_error_type );
- /* Fix for bugid # 394184, SD, 20 Jul 00 */
- /* replace the hard coded return value by the appropriate
- * LDAP error code */
- switch (sort_return_value) {
- case LDAP_SUCCESS: /* Everything OK */
- vlv_response_control.result= LDAP_SUCCESS;
- break;
- case LDAP_PROTOCOL_ERROR: /* A protocol error */
- return ldbm_back_search_cleanup(pb, li, sort_control,
- LDAP_PROTOCOL_ERROR,
- "Sort Control", -1,
- &basesdn,
- &vlv_request_control);
- case LDAP_UNWILLING_TO_PERFORM: /* Too hard */
- case LDAP_OPERATIONS_ERROR: /* Operation error */
- case LDAP_TIMELIMIT_EXCEEDED: /* Timeout */
- vlv_response_control.result= LDAP_TIMELIMIT_EXCEEDED;
- break;
- case LDAP_ADMINLIMIT_EXCEEDED: /* Admin limit exceeded */
- vlv_response_control.result = LDAP_ADMINLIMIT_EXCEEDED;
- break;
- case LDAP_OTHER: /* Abandoned */
- abandoned = 1; /* So that we don't return a result code */
- is_sorting_critical = 1; /* In order to have the results
- discarded */
- break;
- default: /* Should never get here */
- break;
- }
- /* End fix for bug # 394184 */
- /*
- * If the sort control was marked as critical, and there was
- * an error in sorting, don't return any entries, and return
- * unavailableCriticalExtension in the searchResultDone message.
- */
- /* Fix for bugid #394184, SD, 05 Jul 00 */
- /* we were not actually returning unavailableCriticalExtension;
- now fixed (hopefully !) */
- if (is_sorting_critical && (0 != sort_return_value))
- {
- idl_free(candidates);
- candidates = idl_alloc(0);
- tmp_err = LDAP_UNAVAILABLE_CRITICAL_EXTENSION;
- tmp_desc = "Sort Response Control";
- }
- /* end Fix for bugid #394184 */
- /* Generate the control returned to the client to indicate
- * sort result */
- if (LDAP_SUCCESS != sort_make_sort_response_control( pb,
- sort_return_value, sort_error_type ) )
- {
- return ldbm_back_search_cleanup(pb, li, sort_control,
- (abandoned?-1:LDAP_PROTOCOL_ERROR),
- "Sort Response Control", -1,
- &basesdn, &vlv_request_control);
- }
- }
- }
- /*
- * If we're presenting a virtual list view, then the candidate list
- * must be trimmed down to just the range of entries requested.
- */
- if (virtual_list_view)
- {
- if (NULL != candidates && candidates->b_nids>0)
- {
- IDList *idl= NULL;
- vlv_response_control.result =
- vlv_trim_candidates(be, candidates, sort_control,
- &vlv_request_control, &idl, &vlv_response_control);
- if(vlv_response_control.result==0)
- {
- idl_free(candidates);
- candidates = idl;
- }
- else
- {
- return ldbm_back_search_cleanup(pb, li, sort_control,
- vlv_response_control.result,
- NULL, -1, &basesdn,
- &vlv_request_control);
- }
- }
- else
- {
- vlv_response_control.targetPosition = 0;
- vlv_response_control.contentCount = 0;
- vlv_response_control.result = LDAP_SUCCESS;
- }
- }
- }
- if (virtual_list_view)
- {
- if(LDAP_SUCCESS !=
- vlv_make_response_control( pb, &vlv_response_control ))
- {
- return ldbm_back_search_cleanup(pb, li, sort_control,
- (abandoned?-1:LDAP_PROTOCOL_ERROR),
- "VLV Response Control", -1,
- &basesdn, &vlv_request_control);
- }
- /* Log the VLV operation */
- vlv_print_access_log(pb,&vlv_request_control,&vlv_response_control);
- }
- }
- cache_return( &inst->inst_cache, &e );
- /*
- * if the candidate list is an allids list, arrange for access log
- * to record that fact.
- */
- if ( NULL != candidates && ALLIDS( candidates )) {
- unsigned int opnote = SLAPI_OP_NOTE_UNINDEXED;
- int ri = 0;
- /*
- * Return error if nsslapd-require-index is set and
- * this is not an internal operation.
- * We hope the plugins know what they are doing!
- */
- if (!operation_is_flag_set(operation, OP_FLAG_INTERNAL)) {
- PR_Lock(inst->inst_config_mutex);
- ri = inst->require_index;
- PR_Unlock(inst->inst_config_mutex);
- if (ri) {
- idl_free(candidates);
- candidates = idl_alloc(0);
- tmp_err = LDAP_UNWILLING_TO_PERFORM;
- tmp_desc = "Search is not indexed";
- }
- }
- slapi_pblock_set( pb, SLAPI_OPERATION_NOTES, &opnote );
- }
- sr->sr_candidates = candidates;
- sr->sr_virtuallistview = virtual_list_view;
- /* check to see if we can skip the filter test */
- if ( li->li_filter_bypass && NULL != candidates && !virtual_list_view
- && !lookup_returned_allids ) {
- Slapi_Filter *filter = NULL;
- slapi_pblock_get( pb, SLAPI_SEARCH_FILTER, &filter );
- if ( can_skip_filter_test( pb, filter, scope, candidates)) {
- sr->sr_flags |= SR_FLAG_CAN_SKIP_FILTER_TEST;
- }
- }
- /* Fix for bugid #394184, SD, 05 Jul 00 */
- /* tmp_err == -1: no error */
- return ldbm_back_search_cleanup(pb, li, sort_control, tmp_err, tmp_desc,
- (tmp_err == -1 ? 0 : -1), &basesdn,
- &vlv_request_control);
- /* end Fix for bugid #394184 */
- }
- /*
- * Build a candidate list for this backentry and scope.
- * Could be a BASE, ONELEVEL, or SUBTREE search.
- *
- * Returns:
- * 0 - success
- * <0 - fail
- *
- */
- static int
- build_candidate_list( Slapi_PBlock *pb, backend *be, struct backentry *e,
- const char * base, int scope, int *lookup_returned_allidsp,
- IDList** candidates)
- {
- struct ldbminfo *li = (struct ldbminfo *) be->be_database->plg_private;
- int managedsait= 0;
- Slapi_Filter *filter= NULL;
- int err= 0;
- int r= 0;
- slapi_pblock_get( pb, SLAPI_SEARCH_FILTER, &filter );
- slapi_pblock_get( pb, SLAPI_MANAGEDSAIT, &managedsait );
- switch ( scope ) {
- case LDAP_SCOPE_BASE:
- *candidates = base_candidates( pb, e );
- break;
- case LDAP_SCOPE_ONELEVEL:
- *candidates = onelevel_candidates( pb, be, base, e, filter, managedsait,
- lookup_returned_allidsp, &err );
- break;
- case LDAP_SCOPE_SUBTREE:
- *candidates = subtree_candidates(pb, be, base, e, filter, managedsait,
- lookup_returned_allidsp, &err);
- break;
- default:
- slapi_send_ldap_result( pb, LDAP_PROTOCOL_ERROR, NULL, "Bad scope", 0, NULL );
- r = SLAPI_FAIL_GENERAL;
- }
- if ( 0 != err && DB_NOTFOUND != err ) {
- LDAPDebug( LDAP_DEBUG_ANY, "database error %d\n", err, 0, 0 );
- slapi_send_ldap_result( pb, LDAP_OPERATIONS_ERROR, NULL, NULL,
- 0, NULL );
- if (LDBM_OS_ERR_IS_DISKFULL(err)) r = return_on_disk_full(li);
- else r = SLAPI_FAIL_GENERAL;
- }
- /*
- * If requested, set a flag to indicate whether the indexed
- * lookup returned an ALLIDs block. Note that this is taken care of
- * above already for subtree searches.
- */
- if ( NULL != lookup_returned_allidsp ) {
- if ( 0 == err || DB_NOTFOUND == err ) {
- if ( !(*lookup_returned_allidsp) && LDAP_SCOPE_SUBTREE != scope ) {
- *lookup_returned_allidsp =
- ( NULL != *candidates && ALLIDS( *candidates ));
- }
- } else {
- *lookup_returned_allidsp = 0;
- }
- }
- LDAPDebug(LDAP_DEBUG_TRACE, "candidate list has %lu ids\n",
- *candidates ? (*candidates)->b_nids : 0L, 0, 0);
- return r;
- }
- /*
- * Build a candidate list for a BASE scope search.
- */
- static IDList *
- base_candidates(Slapi_PBlock *pb, struct backentry *e)
- {
- IDList *idl= idl_alloc( 1 );
- idl_append( idl, NULL == e ? 0 : e->ep_id );
- return( idl );
- }
- /*
- * Modify the filter to include entries of the referral objectclass
- *
- * make (|(originalfilter)(objectclass=referral))
- *
- * "focref, forr" are temporary filters which the caller must free
- * non-recursively when done with the returned filter.
- */
- static Slapi_Filter*
- create_referral_filter(Slapi_Filter* filter, Slapi_Filter** focref, Slapi_Filter** forr)
- {
- char *buf = slapi_ch_strdup( "objectclass=referral" );
- *focref = slapi_str2filter( buf );
- *forr = slapi_filter_join( LDAP_FILTER_OR, filter, *focref );
- slapi_ch_free((void **)&buf);
- return *forr;
- }
- /*
- * Modify the filter to be a one level search.
- *
- * (&(parentid=idofbase)(|(originalfilter)(objectclass=referral)))
- *
- * "fid2kids, focref, fand, forr" are temporary filters which the
- * caller must free'd non-recursively when done with the returned filter.
- *
- * This function is exported for the VLV code to use.
- */
- Slapi_Filter*
- create_onelevel_filter(Slapi_Filter* filter, const struct backentry *baseEntry, int managedsait, Slapi_Filter** fid2kids, Slapi_Filter** focref, Slapi_Filter** fand, Slapi_Filter** forr)
- {
- Slapi_Filter *ftop= filter;
- char buf[40];
- if ( !managedsait )
- {
- ftop= create_referral_filter(filter, focref, forr);
- }
- sprintf( buf, "parentid=%lu", (u_long)(baseEntry != NULL ? baseEntry->ep_id : 0) );
- *fid2kids = slapi_str2filter( buf );
- *fand = slapi_filter_join( LDAP_FILTER_AND, ftop, *fid2kids );
- return *fand;
- }
- /*
- * Build a candidate list for a ONELEVEL scope search.
- */
- static IDList *
- onelevel_candidates(
- Slapi_PBlock *pb,
- backend *be,
- const char *base,
- struct backentry *e,
- Slapi_Filter *filter,
- int managedsait,
- int *lookup_returned_allidsp,
- int *err
- )
- {
- Slapi_Filter *fid2kids= NULL;
- Slapi_Filter *focref= NULL;
- Slapi_Filter *fand= NULL;
- Slapi_Filter *forr= NULL;
- Slapi_Filter *ftop= NULL;
- IDList *candidates;
- /*
- * modify the filter to be something like this:
- *
- * (&(parentid=idofbase)(|(originalfilter)(objectclass=referral)))
- */
- ftop= create_onelevel_filter(filter, e, managedsait, &fid2kids, &focref, &fand, &forr);
- /* from here, it's just like subtree_candidates */
- candidates = filter_candidates( pb, be, base, ftop, NULL, 0, err );
- *lookup_returned_allidsp = slapi_be_is_flag_set(be, SLAPI_BE_FLAG_DONT_BYPASS_FILTERTEST);
- /* free up just the filter stuff we allocated above */
- slapi_filter_free( fid2kids, 0 );
- slapi_filter_free( fand, 0 );
- slapi_filter_free( forr, 0 );
- slapi_filter_free( focref, 0 );
- return( candidates );
- }
- /*
- * We need to modify the filter to be something like this:
- *
- * (|(originalfilter)(objectclass=referral))
- *
- * the "objectclass=referral" part is used to select referrals to return.
- * it is only included if the managedsait service control is not set.
- *
- * This function is exported for the VLV code to use.
- */
- Slapi_Filter*
- create_subtree_filter(Slapi_Filter* filter, int managedsait, Slapi_Filter** focref, Slapi_Filter** forr)
- {
- Slapi_Filter *ftop= filter;
- if ( !managedsait )
- {
- ftop= create_referral_filter(filter, focref, forr);
- }
- return ftop;
- }
- /*
- * Build a candidate list for a SUBTREE scope search.
- */
- IDList *
- subtree_candidates(
- Slapi_PBlock *pb,
- backend *be,
- const char *base,
- const struct backentry *e,
- Slapi_Filter *filter,
- int managedsait,
- int *allids_before_scopingp,
- int *err
- )
- {
- Slapi_Filter *focref= NULL;
- Slapi_Filter *forr= NULL;
- Slapi_Filter *ftop= NULL;
- IDList *candidates;
- PRBool has_tombstone_filter;
- int isroot = 0;
- /* make (|(originalfilter)(objectclass=referral)) */
- ftop= create_subtree_filter(filter, managedsait, &focref, &forr);
- /* Fetch a candidate list for the original filter */
- candidates = filter_candidates( pb, be, base, ftop, NULL, 0, err );
- slapi_filter_free( forr, 0 );
- slapi_filter_free( focref, 0 );
- /* set 'allids before scoping' flag */
- if ( NULL != allids_before_scopingp ) {
- *allids_before_scopingp = ( NULL != candidates && ALLIDS( candidates ));
- }
- has_tombstone_filter = (filter->f_flags & SLAPI_FILTER_TOMBSTONE);
- slapi_pblock_get( pb, SLAPI_REQUESTOR_ISROOT, &isroot );
- /*
- * Apply the DN components if the candidate list is greater than
- * our threshold, and if the filter is not "(objectclass=nstombstone)",
- * since tombstone entries are not indexed in the ancestorid index.
- */
- if(candidates!=NULL && ( idl_length(candidates)>FILTER_TEST_THRESHOLD) && !has_tombstone_filter)
- {
- IDList *tmp = candidates, *descendants = NULL;
- *err = ldbm_ancestorid_read(be, NULL, e->ep_id, &descendants);
- idl_insert(&descendants, e->ep_id);
- candidates = idl_intersection(be, candidates, descendants);
- idl_free(tmp);
- idl_free(descendants);
- }
- return( candidates );
- }
- static int grok_filter(struct slapi_filter *f);
- #if 0
- /* Helper for grok_filter() */
- static int
- grok_filter_list(struct slapi_filter *flist)
- {
- struct slapi_filter *f;
- /* Scan the clauses of the AND filter, if any of them fails the grok, then we fail */
- for ( f = flist; f != NULL; f = f->f_next ) {
- if ( !grok_filter(f) ) {
- return( 0 );
- }
- }
- return( 1 );
- }
- #endif
- /* Helper function for can_skip_filter_test() */
- static int grok_filter(struct slapi_filter *f)
- {
- switch ( f->f_choice ) {
- case LDAP_FILTER_EQUALITY:
- return 1; /* If there's an ID list and an equality filter, we can skip the filter test */
- case LDAP_FILTER_SUBSTRINGS:
- return 0;
- case LDAP_FILTER_GE:
- return 1;
- case LDAP_FILTER_LE:
- return 1;
- case LDAP_FILTER_PRESENT:
- return 1; /* If there's an ID list, and a presence filter, we can skip the filter test */
- case LDAP_FILTER_APPROX:
- return 0;
- case LDAP_FILTER_EXTENDED:
- return 0;
- case LDAP_FILTER_AND:
- return 0; /* Unless we check to see whether the presence and equality branches
- of the search filter were all indexed, we get things wrong here,
- so let's punt for now */
- /* return grok_filter_list(f->f_and); AND clauses are potentially OK */
- case LDAP_FILTER_OR:
- return 0;
- case LDAP_FILTER_NOT:
- return 0;
- default:
- return 0;
- }
- }
- /* Routine which says whether or not the indices produced a "correct" answer */
- static int
- can_skip_filter_test(
- Slapi_PBlock *pb,
- struct slapi_filter *f,
- int scope,
- IDList *idl
- )
- {
- int rc = 0;
- /* Is the ID list ALLIDS ? */
- if ( ALLIDS(idl)) {
- /* If so, then can't optimize */
- return rc;
- }
- /* Is this a base scope search? */
- if ( scope == LDAP_SCOPE_BASE ) {
- /*
- * If so, then we can't optimize. Why not? Because we only consult
- * the entrydn index in producing our 1 candidate, and that means
- * we have not used the filter to produce the candidate list.
- */
- return rc;
- }
- /* Grok the filter and tell me if it has only equality components in it */
- rc = grok_filter(f);
- /* If we haven't determined that we can't skip the filter test already,
- * do one last check for attribute subtypes. We don't need to worry
- * about any complex filters here since grok_filter() will have already
- * assumed that we can't skip the filter test in those cases. */
- if (rc != 0) {
- char *type = NULL;
- char *basetype = NULL;
- /* We don't need to free type since that's taken
- * care of when the filter is free'd later. We
- * do need to free basetype when we are done. */
- slapi_filter_get_attribute_type(f, &type);
- basetype = slapi_attr_basetype(type, NULL, 0);
- /* Is the filter using an attribute subtype? */
- if (strcasecmp(type, basetype) != 0) {
- /* If so, we can't optimize since attribute subtypes
- * are simply indexed under their basetype attribute.
- * The basetype index has no knowledge of the subtype
- * itself. In the future, we should add support for
- * indexing the subtypes so we can optimize this type
- * of search. */
- rc = 0;
- }
- slapi_ch_free_string(&basetype);
- }
- return rc;
- }
- /*
- * Return the next entry in the result set. The entry is returned
- * in the pblock.
- * Returns 0 normally. If -1 is returned, it means that some
- * exceptional condition, e.g. timelimit exceeded has occurred,
- * and this routine has sent a result to the client. If zero
- * is returned and no entry is available in the PBlock, then
- * we've iterated through all the entries.
- */
- int
- ldbm_back_next_search_entry( Slapi_PBlock *pb )
- {
- return ldbm_back_next_search_entry_ext( pb, 0 );
- }
- int
- ldbm_back_next_search_entry_ext( Slapi_PBlock *pb, int use_extension )
- {
- backend *be;
- ldbm_instance *inst;
- struct ldbminfo *li;
- int scope;
- int managedsait;
- Slapi_Attr *attr;
- Slapi_Filter *filter;
- char *base;
- back_search_result_set *sr;
- ID id;
- struct backentry *e;
- int nentries;
- time_t curtime, stoptime, optime;
- int tlimit, llimit, slimit, isroot;
- struct berval **urls = NULL;
- int err;
- Slapi_DN basesdn;
- char *target_uniqueid;
- int rc = 0;
- slapi_pblock_get( pb, SLAPI_BACKEND, &be );
- slapi_pblock_get( pb, SLAPI_PLUGIN_PRIVATE, &li );
- slapi_pblock_get( pb, SLAPI_SEARCH_SCOPE, &scope );
- slapi_pblock_get( pb, SLAPI_MANAGEDSAIT, &managedsait );
- slapi_pblock_get( pb, SLAPI_SEARCH_FILTER, &filter );
- slapi_pblock_get( pb, SLAPI_SEARCH_TARGET, &base );
- slapi_pblock_get( pb, SLAPI_NENTRIES, &nentries );
- slapi_pblock_get( pb, SLAPI_SEARCH_SIZELIMIT, &slimit );
- slapi_pblock_get( pb, SLAPI_SEARCH_TIMELIMIT, &tlimit );
- slapi_pblock_get( pb, SLAPI_OPINITIATED_TIME, &optime );
- slapi_pblock_get( pb, SLAPI_REQUESTOR_ISROOT, &isroot );
- slapi_pblock_get( pb, SLAPI_SEARCH_REFERRALS, &urls );
- slapi_pblock_get( pb, SLAPI_SEARCH_RESULT_SET, &sr );
- slapi_pblock_get( pb, SLAPI_TARGET_UNIQUEID, &target_uniqueid );
- if (sr->sr_current_sizelimit >= 0) {
- /*
- * sr_current_sizelimit contains the current sizelimit.
- * In case of paged results, getting one page is one operation,
- * while the results on each page are from same back_search_result_set.
- * To maintain sizelimit beyond operations, back_search_result_set
- * holds the current sizelimit value.
- * (The current sizelimit is valid inside an operation, as well.)
- */
- slimit = sr->sr_current_sizelimit;
- }
-
- inst = (ldbm_instance *) be->be_instance_info;
- slapi_sdn_init_dn_ndn_byref(&basesdn,base); /* normalized by front end */
- /* Return to the cache the entry we handed out last time */
- /* If we are using the extension, the front end will tell
- * us when to do this so we don't do it now */
- if ( !use_extension )
- {
- cache_return( &inst->inst_cache, &(sr->sr_entry) );
- }
- if(sr->sr_vlventry != NULL && !use_extension )
- {
- /* This empty entry was handed out last time because the ACL check failed on a VLV Search. */
- /* The empty entry has a pointer to the cache entry dn... make sure we don't free the dn */
- /* which belongs to the cache entry. */
- slapi_entry_free( sr->sr_vlventry );
- sr->sr_vlventry = NULL;
- }
- stoptime = optime + tlimit;
- llimit = sr->sr_lookthroughlimit;
- /* Find the next candidate entry and return it. */
- while ( 1 )
- {
- /* check for abandon */
- if ( slapi_op_abandoned( pb ))
- {
- /* in case paged results, clean up the conn */
- pagedresults_set_search_result(pb->pb_conn, NULL);
- slapi_pblock_set( pb, SLAPI_SEARCH_RESULT_SET, NULL );
- if ( use_extension ) {
- slapi_pblock_set( pb, SLAPI_SEARCH_RESULT_ENTRY_EXT, NULL );
- }
- slapi_pblock_set( pb, SLAPI_SEARCH_RESULT_ENTRY, NULL );
- delete_search_result_set( &sr );
- rc = SLAPI_FAIL_GENERAL;
- goto bail;
- }
- /* check time limit */
- curtime = current_time();
- if ( tlimit != -1 && curtime > stoptime )
- {
- slapi_send_ldap_result( pb, LDAP_TIMELIMIT_EXCEEDED, NULL, NULL, nentries, urls );
- /* in case paged results, clean up the conn */
- pagedresults_set_search_result(pb->pb_conn, NULL);
- slapi_pblock_set( pb, SLAPI_SEARCH_RESULT_SET, NULL );
- if ( use_extension ) {
- slapi_pblock_set( pb, SLAPI_SEARCH_RESULT_ENTRY_EXT, NULL );
- }
- slapi_pblock_set( pb, SLAPI_SEARCH_RESULT_ENTRY, NULL );
- delete_search_result_set( &sr );
- rc = SLAPI_FAIL_GENERAL;
- goto bail;
- }
-
- /* check lookthrough limit */
- if ( llimit != -1 && sr->sr_lookthroughcount >= llimit )
- {
- slapi_send_ldap_result( pb, LDAP_ADMINLIMIT_EXCEEDED, NULL, NULL, nentries, urls );
- /* in case paged results, clean up the conn */
- pagedresults_set_search_result(pb->pb_conn, NULL);
- slapi_pblock_set( pb, SLAPI_SEARCH_RESULT_SET, NULL );
- if ( use_extension ) {
- slapi_pblock_set( pb, SLAPI_SEARCH_RESULT_ENTRY_EXT, NULL );
- }
- slapi_pblock_set( pb, SLAPI_SEARCH_RESULT_ENTRY, NULL );
- delete_search_result_set( &sr );
- rc = SLAPI_FAIL_GENERAL;
- goto bail;
- }
-
- /* get the entry */
- id = idl_iterator_dereference_increment(&(sr->sr_current), sr->sr_candidates);
- if ( id == NOID )
- {
- /* No more entries */
- /* destroy back_search_result_set */
- /* in case paged results, clean up the conn */
- pagedresults_set_search_result(pb->pb_conn, NULL);
- slapi_pblock_set( pb, SLAPI_SEARCH_RESULT_SET, NULL );
- if ( use_extension ) {
- slapi_pblock_set( pb, SLAPI_SEARCH_RESULT_ENTRY_EXT, NULL );
- }
- slapi_pblock_set( pb, SLAPI_SEARCH_RESULT_ENTRY, NULL );
- delete_search_result_set( &sr );
- rc = 0;
- goto bail;
- }
- ++sr->sr_lookthroughcount; /* checked above */
- /* get the entry */
- if ( (e = id2entry( be, id, NULL, &err )) == NULL )
- {
- if ( err != 0 && err != DB_NOTFOUND )
- {
- LDAPDebug( LDAP_DEBUG_ANY, "next_search_entry db err %d\n", err, 0, 0 );
- if (LDBM_OS_ERR_IS_DISKFULL(err))
- {
- /* disk full in the middle of returning search results
- * is gonna be traumatic. unavoidable.
- */
- slapi_send_ldap_result(pb, LDAP_OPERATIONS_ERROR, NULL, NULL, 0, NULL);
- rc = return_on_disk_full(li);
- goto bail;
- }
- }
- LDAPDebug( LDAP_DEBUG_ARGS, "candidate %lu not found\n", (u_long)id, 0, 0 );
- if ( err == DB_NOTFOUND )
- {
- /* Since we didn't really look at this entry, we should
- * decrement the lookthrough counter (it was just incremented).
- * If we didn't do this, it would be possible to go over the
- * lookthrough limit when there are fewer entries in the database
- * than the lookthrough limit. This could happen on an ALLIDS
- * search after adding a bunch of entries and then deleting
- * them. */
- --sr->sr_lookthroughcount;
- }
- continue;
- }
- e->ep_vlventry = NULL;
- sr->sr_entry = e;
- /*
- * If it's a referral, return it without checking the
- * filter explicitly here since it's only a candidate anyway. Do
- * check the scope though.
- */
- if ( !managedsait && slapi_entry_attr_find( e->ep_entry, "ref", &attr ) == 0)
- {
- Slapi_Value **refs= attr_get_present_values(attr);
- if ( refs == NULL || refs[0] == NULL )
- {
- char ebuf[ BUFSIZ ];
- LDAPDebug( LDAP_DEBUG_ANY, "null ref in (%s)\n", escape_string( backentry_get_ndn(e), ebuf ), 0, 0 );
- }
- else if ( slapi_sdn_scope_test( backentry_get_sdn(e), &basesdn, scope ))
- {
- if ( use_extension ) {
- slapi_pblock_set( pb, SLAPI_SEARCH_RESULT_ENTRY_EXT, e );
- }
- slapi_pblock_set( pb, SLAPI_SEARCH_RESULT_ENTRY, e->ep_entry );
- rc = 0;
- goto bail;
- }
- }
- else
- {
- /*
- * As per slapi_filter_test:
- * 0 filter matched
- * -1 filter did not match
- * >0 an ldap error code
- */
- int filter_test = -1;
-
- if((slapi_entry_flag_is_set(e->ep_entry,SLAPI_ENTRY_LDAPSUBENTRY)
- && !filter_flag_is_set(filter,SLAPI_FILTER_LDAPSUBENTRY)) ||
- (slapi_entry_flag_is_set(e->ep_entry,SLAPI_ENTRY_FLAG_TOMBSTONE)
- && ((!isroot && !filter_flag_is_set(filter, SLAPI_FILTER_RUV)) ||
- !filter_flag_is_set(filter, SLAPI_FILTER_TOMBSTONE))))
- {
- /* If the entry is an LDAP subentry and filter don't filter subentries OR
- * the entry is a TombStone and filter don't filter Tombstone
- * don't return the entry. We make a special case to allow a non-root user
- * to search for the RUV entry using a filter of:
- *
- * "(&(objectclass=nstombstone)(nsuniqueid=ffffffff-ffffffff-ffffffff-ffffffff))"
- *
- * For this RUV case, we let the ACL check apply.
- */
- /* ugaston - we don't want to mistake this filter failure with the one below due to ACL,
- * because whereas the former should be read as 'no entry must be returned', the latter
- * might still lead to return an empty entry. */
- filter_test=-1;
- }
- else
- {
- /* it's a regular entry, check if it matches the filter, and passes the ACL check */
- if ( 0 != ( sr->sr_flags & SR_FLAG_CAN_SKIP_FILTER_TEST )) {
- /* Since we do access control checking in the filter test (?Why?) we need to check access now */
- LDAPDebug( LDAP_DEBUG_FILTER, "Bypassing filter test\n", 0, 0, 0 );
- if ( ACL_CHECK_FLAG ) {
- filter_test = slapi_vattr_filter_test_ext( pb, e->ep_entry, filter, ACL_CHECK_FLAG, 1 /* Only perform access checking, thank you */);
- } else {
- filter_test = 0;
- }
- if (li->li_filter_bypass_check) {
- int ft_rc;
-
- LDAPDebug( LDAP_DEBUG_FILTER, "Checking bypass\n", 0, 0, 0 );
- ft_rc = slapi_vattr_filter_test( pb, e->ep_entry, filter,
- ACL_CHECK_FLAG );
- if (filter_test != ft_rc) {
- /* Oops ! This means that we thought we could bypass the filter test, but noooo... */
- char ebuf[ BUFSIZ ];
- LDAPDebug( LDAP_DEBUG_ANY, "Filter bypass ERROR on entry %s\n", escape_string( backentry_get_ndn(e), ebuf ), 0, 0 );
- filter_test = ft_rc; /* Fix the error */
- }
- }
- } else {
- /* Old-style case---we need to do a filter test */
- filter_test = slapi_vattr_filter_test( pb, e->ep_entry, filter, ACL_CHECK_FLAG);
- }
- }
- if ( (filter_test == 0) || (sr->sr_virtuallistview && (filter_test != -1)) )
- /* ugaston - if filter failed due to subentries or tombstones (filter_test=-1),
- * just forget about it, since we don't want to return anything at all. */
- {
- if ( slapi_uniqueIDCompareString(target_uniqueid, e->ep_entry->e_uniqueid) ||
- slapi_sdn_scope_test( backentry_get_sdn(e), &basesdn, scope ))
- {
- /* check size limit */
- if ( slimit >= 0 )
- {
- if ( --slimit < 0 ) {
- cache_return( &inst->inst_cache, &e );
- /* in case paged results, clean up the conn */
- pagedresults_set_search_result(pb->pb_conn, NULL);
- slapi_pblock_set( pb, SLAPI_SEARCH_RESULT_SET, NULL );
- delete_search_result_set( &sr );
- slapi_send_ldap_result( pb, LDAP_SIZELIMIT_EXCEEDED, NULL, NULL, nentries, urls );
- rc = SLAPI_FAIL_GENERAL;
- goto bail;
- }
- slapi_pblock_set( pb, SLAPI_SEARCH_SIZELIMIT, &slimit );
- sr->sr_current_sizelimit = slimit;
- }
- if ( (filter_test != 0) && sr->sr_virtuallistview)
- {
- /* Slapi Filter Test failed.
- * Must be that the ACL check failed.
- * Send back an empty entry.
- */
- sr->sr_vlventry = slapi_entry_alloc();
- slapi_entry_init(sr->sr_vlventry,slapi_ch_strdup(slapi_entry_get_dn_const(e->ep_entry)),NULL);
- e->ep_vlventry = sr->sr_vlventry;
- if ( use_extension ) {
- slapi_pblock_set( pb, SLAPI_SEARCH_RESULT_ENTRY_EXT, e );
- }
- slapi_pblock_set( pb, SLAPI_SEARCH_RESULT_ENTRY, sr->sr_vlventry );
- } else {
- if ( use_extension ) {
- slapi_pblock_set( pb, SLAPI_SEARCH_RESULT_ENTRY_EXT, e );
- }
- slapi_pblock_set( pb, SLAPI_SEARCH_RESULT_ENTRY, e->ep_entry );
- }
- rc = 0;
- goto bail;
- }
- else
- {
- cache_return ( &inst->inst_cache, &(sr->sr_entry) );
- }
- }
- else
- {
- /* Failed the filter test, and this isn't a VLV Search */
- cache_return( &inst->inst_cache, &(sr->sr_entry) );
- if (LDAP_UNWILLING_TO_PERFORM == filter_test) {
- /* Need to catch this error to detect the vattr loop */
- slapi_send_ldap_result( pb, filter_test, NULL,
- "Failed the filter test", 0, NULL );
- rc = SLAPI_FAIL_GENERAL;
- goto bail;
- } else if (LDAP_TIMELIMIT_EXCEEDED == filter_test) {
- slapi_send_ldap_result( pb, LDAP_TIMELIMIT_EXCEEDED, NULL, NULL, nentries, urls );
- rc = SLAPI_FAIL_GENERAL;
- goto bail;
- }
- }
- }
- }
- bail:
- slapi_sdn_done(&basesdn);
- return rc;
- }
- /*
- * Move back the current position in the search result set by one.
- * Paged Results needs to read ahead one entry to catch the end of the search
- * result set at the last entry not to show the prompt when there is no more
- * entries.
- */
- void
- ldbm_back_prev_search_results( Slapi_PBlock *pb )
- {
- back_search_result_set *sr;
- slapi_pblock_get( pb, SLAPI_SEARCH_RESULT_SET, &sr );
- if (sr) {
- idl_iterator_decrement(&(sr->sr_current));
- }
- return;
- }
- static back_search_result_set*
- new_search_result_set(IDList *idl, int vlv, int lookthroughlimit)
- {
- back_search_result_set *p = (back_search_result_set *)slapi_ch_calloc( 1, sizeof( back_search_result_set ));
- p->sr_candidates = idl;
- p->sr_current = idl_iterator_init(idl);
- p->sr_lookthroughlimit = lookthroughlimit;
- p->sr_virtuallistview = vlv;
- p->sr_current_sizelimit = -1;
- return p;
- }
- static void
- delete_search_result_set( back_search_result_set **sr )
- {
- if ( NULL == sr || NULL == *sr)
- {
- return;
- }
- if ( NULL != (*sr)->sr_candidates )
- {
- idl_free( (*sr)->sr_candidates );
- }
- slapi_ch_free( (void**)sr );
- }
- void
- ldbm_back_search_results_release( void **sr )
- {
- delete_search_result_set( (back_search_result_set **)sr );
- }
- int
- ldbm_back_entry_release( Slapi_PBlock *pb, void *backend_info_ptr ) {
- backend *be;
- ldbm_instance *inst;
- if ( backend_info_ptr == NULL )
- return 1;
- slapi_pblock_get( pb, SLAPI_BACKEND, &be );
- inst = (ldbm_instance *) be->be_instance_info;
- cache_return( &inst->inst_cache, (struct backentry **)&backend_info_ptr );
- if( ((struct backentry *) backend_info_ptr)->ep_vlventry != NULL )
- {
- /* This entry was created during a vlv search whose acl check failed. It needs to be
- * freed here */
- slapi_entry_free( ((struct backentry *) backend_info_ptr)->ep_vlventry );
- ((struct backentry *) backend_info_ptr)->ep_vlventry = NULL;
- }
- return 0;
- }
|