| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038 |
- /** 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
- /* filterentry.c - apply a filter to an entry */
- #include <stdio.h>
- #include <string.h>
- #include <sys/types.h>
- #ifndef _WIN32
- #include <sys/socket.h>
- #endif
- #include "slap.h"
- static int test_filter_list();
- static int test_extensible_filter();
- static int vattr_test_filter_list();
- static int test_filter_access( Slapi_PBlock *pb, Slapi_Entry*e,
- char * attr_type, struct berval *attr_val);
- static int slapi_vattr_filter_test_ext_internal( Slapi_PBlock *pb, Slapi_Entry *e,
- struct slapi_filter *f, int verify_access, int only_check_access, int *access_check_done);
- static char *opt_str = 0;
- static int opt = 0;
- static int optimise_filter_acl_tests()
- {
- if(!opt_str)
- {
- opt_str = getenv( "NS_DS_OPT_FILT_ACL_EVAL" );
- if(opt_str)
- opt = !strcasecmp(opt_str, "false");
- else
- opt = 0;
- if(!opt_str)
- opt_str = "dummy";
- }
- return opt;
- }
- /*
- * slapi_filter_test - test a filter against a single entry.
- * returns 0 filter matched
- * -1 filter did not match
- * >0 an ldap error code
- */
- int
- slapi_filter_test(
- Slapi_PBlock *pb,
- Slapi_Entry *e,
- struct slapi_filter *f,
- int verify_access
- )
- {
- return slapi_filter_test_ext(pb,e,f,verify_access,0);
- }
- /*
- * slapi_filter_test_simple - test without checking access control
- *
- * returns 0 filter matched
- * -1 filter did not match
- * >0 an ldap error code
- */
- int
- slapi_filter_test_simple(
- Slapi_Entry *e,
- struct slapi_filter *f
- )
- {
- return slapi_vattr_filter_test_ext(NULL,e,f,0,0);
- }
- /*
- * slapi_filter_test_ext - full-feature filter test function
- *
- * returns 0 filter matched
- * -1 filter did not match
- * >0 an ldap error code
- */
- int
- slapi_filter_test_ext_internal(
- Slapi_PBlock *pb,
- Slapi_Entry *e,
- struct slapi_filter *f,
- int verify_access,
- int only_check_access,
- int *access_check_done
- )
- {
- int rc;
- LDAPDebug( LDAP_DEBUG_FILTER, "=> slapi_filter_test_ext\n", 0, 0, 0 );
- /*
- * RJP: Not sure if this is semantically right, but we have to
- * return something if f is NULL. If there is no filter,
- * then we say that it did match and return 0.
- */
- if ( f == NULL) {
- return(0);
- }
- switch ( f->f_choice ) {
- case LDAP_FILTER_EQUALITY:
- LDAPDebug( LDAP_DEBUG_FILTER, " EQUALITY\n", 0, 0, 0 );
- rc = test_ava_filter( pb, e, e->e_attrs, &f->f_ava, LDAP_FILTER_EQUALITY,
- verify_access , only_check_access, access_check_done);
- break;
- case LDAP_FILTER_SUBSTRINGS:
- LDAPDebug( LDAP_DEBUG_FILTER, " SUBSTRINGS\n", 0, 0, 0 );
- rc = test_substring_filter( pb, e, f, verify_access , only_check_access, access_check_done);
- break;
- case LDAP_FILTER_GE:
- LDAPDebug( LDAP_DEBUG_FILTER, " GE\n", 0, 0, 0 );
- rc = test_ava_filter( pb, e, e->e_attrs, &f->f_ava, LDAP_FILTER_GE,
- verify_access , only_check_access, access_check_done);
- break;
- case LDAP_FILTER_LE:
- LDAPDebug( LDAP_DEBUG_FILTER, " LE\n", 0, 0, 0 );
- rc = test_ava_filter( pb, e, e->e_attrs, &f->f_ava, LDAP_FILTER_LE,
- verify_access , only_check_access, access_check_done);
- break;
- case LDAP_FILTER_PRESENT:
- LDAPDebug( LDAP_DEBUG_FILTER, " PRESENT\n", 0, 0, 0 );
- rc = test_presence_filter( pb, e, f->f_type, verify_access , only_check_access, access_check_done);
- break;
- case LDAP_FILTER_APPROX:
- LDAPDebug( LDAP_DEBUG_FILTER, " APPROX\n", 0, 0, 0 );
- rc = test_ava_filter( pb, e, e->e_attrs, &f->f_ava, LDAP_FILTER_APPROX,
- verify_access , only_check_access, access_check_done);
- break;
- case LDAP_FILTER_EXTENDED:
- LDAPDebug( LDAP_DEBUG_FILTER, " EXTENDED\n", 0, 0, 0 );
- rc = test_extensible_filter( pb, e, &f->f_mr, verify_access , only_check_access, access_check_done);
- break;
- case LDAP_FILTER_AND:
- LDAPDebug( LDAP_DEBUG_FILTER, " AND\n", 0, 0, 0 );
- rc = test_filter_list( pb, e, f->f_and,
- LDAP_FILTER_AND , verify_access, only_check_access, access_check_done);
- break;
- case LDAP_FILTER_OR:
- LDAPDebug( LDAP_DEBUG_FILTER, " OR\n", 0, 0, 0 );
- rc = test_filter_list( pb, e, f->f_or,
- LDAP_FILTER_OR , verify_access, only_check_access, access_check_done);
- break;
- case LDAP_FILTER_NOT:
- LDAPDebug( LDAP_DEBUG_FILTER, " NOT\n", 0, 0, 0 );
- rc = slapi_filter_test_ext_internal( pb, e, f->f_not , verify_access, only_check_access, access_check_done);
- if(!(verify_access && only_check_access)) /* dont play with access control return codes */
- {
- if(verify_access && !rc && !(*access_check_done))
- {
- /* the filter failed so access control was not checked
- * for NOT filters this is significant so we must ensure
- * access control is checked
- */
- /* check access control only */
- rc = slapi_filter_test_ext_internal( pb, e, f->f_not , verify_access, -1 /*only_check_access*/, access_check_done);
- /* preserve error code if any */
- if(!rc)
- rc = !rc;
- }
- else
- rc = !rc;
- }
- break;
- default:
- LDAPDebug( LDAP_DEBUG_ANY, " unknown filter type 0x%lX\n",
- f->f_choice, 0, 0 );
- rc = -1;
- }
- LDAPDebug( LDAP_DEBUG_FILTER, "<= slapi_filter_test %d\n", rc, 0, 0 );
- return( rc );
- }
- int
- slapi_filter_test_ext(
- Slapi_PBlock *pb,
- Slapi_Entry *e,
- struct slapi_filter *f,
- int verify_access,
- int only_check_access
- )
- {
- int rc = 0; /* a no op request succeeds */
- int access_check_done = 0;
- switch ( f->f_choice ) {
- case LDAP_FILTER_AND:
- case LDAP_FILTER_OR:
- case LDAP_FILTER_NOT:
- /*
- * optimize acl checking by only doing it once it is
- * known that the whole filter passes and so the entry
- * is eligible to be returned.
- * then we check the filter only for access
- *
- * complex filters really benefit from
- * separate stages, filter eval, followed by acl check...
- */
- if(!only_check_access)
- {
- rc = slapi_filter_test_ext_internal(pb,e,f,0,0, &access_check_done);
- }
- if(rc == 0 && verify_access)
- {
- rc = slapi_filter_test_ext_internal(pb,e,f,-1,-1, &access_check_done);
- }
- break;
- default:
- /*
- * ...but simple filters are better off doing eval and
- * acl check at once
- */
- rc = slapi_filter_test_ext_internal(pb,e,f,verify_access,only_check_access, &access_check_done);
- break;
- }
- return rc;
- }
- int test_ava_filter(
- Slapi_PBlock *pb,
- Slapi_Entry *e,
- Slapi_Attr *a,
- struct ava *ava,
- int ftype,
- int verify_access,
- int only_check_access,
- int *access_check_done
- )
- {
- int rc;
-
- LDAPDebug( LDAP_DEBUG_FILTER, "=> test_ava_filter\n", 0, 0, 0 );
- *access_check_done = 0;
- if(optimise_filter_acl_tests())
- {
- rc = 0;
- if(!only_check_access)
- {
- rc = -1;
- for ( ; a != NULL; a = a->a_next ) {
- if ( slapi_attr_type_cmp( ava->ava_type, a->a_type, SLAPI_TYPE_CMP_SUBTYPE ) == 0 ) {
- rc = plugin_call_syntax_filter_ava( a, ftype, ava );
- if ( rc == 0 ) {
- break;
- }
- }
- }
- }
- if ( rc == 0 && verify_access && pb != NULL ) {
- char *attrs[2] = { NULL, NULL };
- attrs[0] = ava->ava_type;
- rc = plugin_call_acl_plugin( pb, e, attrs, &ava->ava_value,
- SLAPI_ACL_SEARCH, ACLPLUGIN_ACCESS_DEFAULT, NULL );
- *access_check_done = -1;
- }
- }
- else
- {
- if ( verify_access && pb != NULL ) {
- char *attrs[2] = { NULL, NULL };
- attrs[0] = ava->ava_type;
- rc = plugin_call_acl_plugin( pb, e, attrs, &ava->ava_value,
- SLAPI_ACL_SEARCH, ACLPLUGIN_ACCESS_DEFAULT, NULL );
- *access_check_done = -1;
- if ( only_check_access || rc != LDAP_SUCCESS ) {
- LDAPDebug( LDAP_DEBUG_FILTER, "<= test_ava_filter %d\n",
- rc, 0, 0 );
- return( rc );
- }
- }
- rc = -1;
- for ( ; a != NULL; a = a->a_next ) {
- if ( slapi_attr_type_cmp( ava->ava_type, a->a_type, SLAPI_TYPE_CMP_SUBTYPE ) == 0 ) {
- rc = plugin_call_syntax_filter_ava( a, ftype, ava );
- if ( rc == 0 ) {
- break;
- }
- }
- }
- }
- LDAPDebug( LDAP_DEBUG_FILTER, "<= test_ava_filter %d\n", rc, 0, 0 );
- return( rc );
- }
- int
- test_presence_filter(
- Slapi_PBlock *pb,
- Slapi_Entry *e,
- char *type,
- int verify_access,
- int only_check_access,
- int *access_check_done
- )
- {
- int rc;
- void *hint = NULL;
- *access_check_done = 0;
- if(optimise_filter_acl_tests())
- {
- rc = 0;
- /* Use attrlist_find_ex to get subtype matching */
- if(!only_check_access)
- {
- rc = attrlist_find_ex( e->e_attrs, type,
- NULL, NULL, &hint ) != NULL ? 0 : -1;
- }
- if (rc == 0 && verify_access && pb != NULL) {
- char *attrs[2] = { NULL, NULL };
- attrs[0] = type;
- rc = plugin_call_acl_plugin( pb, e, attrs, NULL, SLAPI_ACL_SEARCH,
- ACLPLUGIN_ACCESS_DEFAULT, NULL );
- *access_check_done = -1;
- }
- }
- else
- {
- if (verify_access && pb != NULL) {
- char *attrs[2] = { NULL, NULL };
- attrs[0] = type;
- rc = plugin_call_acl_plugin( pb, e, attrs, NULL, SLAPI_ACL_SEARCH,
- ACLPLUGIN_ACCESS_DEFAULT, NULL );
- *access_check_done = -1;
- if ( only_check_access || rc != LDAP_SUCCESS ) {
- return( rc );
- }
- }
- /* Use attrlist_find_ex to get subtype matching */
- rc = attrlist_find_ex( e->e_attrs, type,
- NULL, NULL, &hint ) != NULL ? 0 : -1;
- }
- return rc;
- }
- /*
- * Convert a DN into a list of attribute values.
- * The caller must free the returned attributes.
- */
- static Slapi_Attr*
- dn2attrs(const char *dn)
- {
- int rc= 0;
- Slapi_Attr* dnAttrs = NULL;
- char** rdns = ldap_explode_dn (dn, 0);
- if (rdns)
- {
- char** rdn = rdns;
- for (; !rc && *rdn; ++rdn)
- {
- char** avas = ldap_explode_rdn (*rdn, 0);
- if (avas)
- {
- char** ava = avas;
- for (; !rc && *ava; ++ava)
- {
- char* val = strchr (*ava, '=');
- if (val)
- {
- struct berval bv;
- struct berval* bvec[] = {NULL, NULL};
- size_t type_len = val - *ava;
- char* type = slapi_ch_malloc (type_len + 1);
- memcpy (type, *ava, type_len);
- type[type_len] = '\0';
- ++val; /* skip the '=' */
- bv.bv_val = val;
- bv.bv_len = strlen(val);
- bvec[0] = &bv;
- attrlist_merge (&dnAttrs, type, bvec);
- slapi_ch_free_string( &type );
- }
- }
- slapi_ldap_value_free (avas);
- }
- }
- slapi_ldap_value_free (rdns);
- }
- return dnAttrs;
- }
- static int
- test_extensible_filter(
- Slapi_PBlock *callers_pb,
- Slapi_Entry *e,
- mr_filter_t *mrf,
- int verify_access,
- int only_check_access,
- int *access_check_done
- )
- {
- /*
- * The ABNF for extensible filters is
- *
- * attr [":dn"] [":" matchingrule] ":=" value
- * [":dn"] ":" matchingrule ":=" value
- *
- * So, sigh, there are six possible combinations:
- *
- * A) attr ":=" value
- * B) attr ":dn" ":=" value
- * C) attr ":" matchingrule ":=" value
- * D) attr ":dn" ":" matchingrule ":=" value
- * E) ":" matchingrule ":=" value
- * F) ":dn" ":" matchingrule ":=" value
- */
- int rc;
-
- LDAPDebug( LDAP_DEBUG_FILTER, "=> test_extensible_filter\n", 0, 0, 0 );
- *access_check_done = 0;
- if(optimise_filter_acl_tests())
- {
- rc = LDAP_SUCCESS;
- if(!only_check_access)
- {
- if (mrf->mrf_match==NULL)
- {
- /*
- * Could be A or B
- * No matching function. So use a regular equality filter.
- * Check the regular attributes for the attribute value.
- */
- struct ava a;
- a.ava_type= mrf->mrf_type;
- a.ava_value.bv_len= mrf->mrf_value.bv_len;
- a.ava_value.bv_val = mrf->mrf_value.bv_val;
- rc= test_ava_filter( callers_pb, e, e->e_attrs, &a, LDAP_FILTER_EQUALITY, 0 /* Don't Verify Access */ , 0 /* don't just verify access */, access_check_done );
- if(rc!=LDAP_SUCCESS && mrf->mrf_dnAttrs)
- {
- /* B) Also check the DN attributes for the attribute value */
- Slapi_Attr* dnattrs= dn2attrs(slapi_entry_get_dn_const(e));
- rc= test_ava_filter( callers_pb, e, dnattrs, &a, LDAP_FILTER_EQUALITY, 0 /* Don't Verify Access */ , 0 /* don't just verify access */, access_check_done );
- attrlist_free( dnattrs );
- }
- }
- else
- {
- /*
- * Could be C, D, E, or F
- * We have a matching rule.
- */
- rc = mrf->mrf_match (mrf->mrf_object, e, e->e_attrs);
- if(rc!=LDAP_SUCCESS && mrf->mrf_dnAttrs)
- {
- /* D & F) Also check the DN attributes for the attribute value */
- Slapi_Attr* dnattrs= dn2attrs(slapi_entry_get_dn_const(e));
- mrf->mrf_match (mrf->mrf_object, e, dnattrs);
- attrlist_free( dnattrs );
- }
- }
- }
- if(rc == 0 && mrf->mrf_type!=NULL && verify_access)
- {
- char *attrs[2] = { NULL, NULL };
- /* Could be A, B, C, or D */
- /* Check we have access to this attribute on this entry */
- attrs[0] = mrf->mrf_type;
- rc= plugin_call_acl_plugin (callers_pb, e, attrs, &(mrf->mrf_value),
- SLAPI_ACL_SEARCH, ACLPLUGIN_ACCESS_DEFAULT, NULL );
- *access_check_done = -1;
- }
- }
- else
- {
- rc = LDAP_SUCCESS;
- if(mrf->mrf_type!=NULL && verify_access)
- {
- char *attrs[2] = { NULL, NULL };
- /* Could be A, B, C, or D */
- /* Check we have access to this attribute on this entry */
- attrs[0] = mrf->mrf_type;
- rc= plugin_call_acl_plugin (callers_pb, e, attrs, &(mrf->mrf_value),
- SLAPI_ACL_SEARCH, ACLPLUGIN_ACCESS_DEFAULT, NULL );
- *access_check_done = -1;
- if ( only_check_access ) {
- return rc;
- }
- }
- if(rc==LDAP_SUCCESS)
- {
- if (mrf->mrf_match==NULL)
- {
- /*
- * Could be A or B
- * No matching function. So use a regular equality filter.
- * Check the regular attributes for the attribute value.
- */
- struct ava a;
- a.ava_type= mrf->mrf_type;
- a.ava_value.bv_len= mrf->mrf_value.bv_len;
- a.ava_value.bv_val = mrf->mrf_value.bv_val;
- rc= test_ava_filter( callers_pb, e, e->e_attrs, &a, LDAP_FILTER_EQUALITY, 0 /* Don't Verify Access */ , 0 /* don't just verify access */, access_check_done );
- if(rc!=LDAP_SUCCESS && mrf->mrf_dnAttrs)
- {
- /* B) Also check the DN attributes for the attribute value */
- Slapi_Attr* dnattrs= dn2attrs(slapi_entry_get_dn_const(e));
- rc= test_ava_filter( callers_pb, e, dnattrs, &a, LDAP_FILTER_EQUALITY, 0 /* Don't Verify Access */ , 0 /* don't just verify access */, access_check_done );
- attrlist_free( dnattrs );
- }
- }
- else
- {
- /*
- * Could be C, D, E, or F
- * We have a matching rule.
- */
- rc = mrf->mrf_match (mrf->mrf_object, e, e->e_attrs);
- if(rc!=LDAP_SUCCESS && mrf->mrf_dnAttrs)
- {
- /* D & F) Also check the DN attributes for the attribute value */
- Slapi_Attr* dnattrs= dn2attrs(slapi_entry_get_dn_const(e));
- mrf->mrf_match (mrf->mrf_object, e, dnattrs);
- attrlist_free( dnattrs );
- }
- }
- }
- }
- LDAPDebug( LDAP_DEBUG_FILTER, "<= test_extensible_filter %d\n", rc, 0, 0 );
- return( rc );
- }
- static int
- test_filter_list(
- Slapi_PBlock *pb,
- Slapi_Entry *e,
- struct slapi_filter *flist,
- int ftype,
- int verify_access,
- int only_check_access,
- int *access_check_done
- )
- {
- int nomatch;
- struct slapi_filter *f;
- int access_check_tmp = -1;
- LDAPDebug( LDAP_DEBUG_FILTER, "=> test_filter_list\n", 0, 0, 0 );
- *access_check_done = -1;
- nomatch = 1;
- for ( f = flist; f != NULL; f = f->f_next ) {
- if ( slapi_filter_test_ext_internal( pb, e, f, verify_access, only_check_access, &access_check_tmp ) != 0 ) {
- /* optimize AND evaluation */
- if ( ftype == LDAP_FILTER_AND ) {
- /* one false is failure */
- nomatch = 1;
- break;
- }
- } else {
- nomatch = 0;
- /* optimize OR evaluation too */
- if ( ftype == LDAP_FILTER_OR ) {
- /* only one needs to be true */
- break;
- }
- }
- if(!access_check_tmp)
- *access_check_done = 0;
- }
- LDAPDebug( LDAP_DEBUG_FILTER, "<= test_filter_list %d\n", nomatch, 0, 0 );
- return( nomatch );
- }
- void
- filter_strcpy_special( char *d, char *s )
- {
- for ( ; *s; s++ ) {
- switch ( *s ) {
- case '.':
- case '\\':
- case '[':
- case ']':
- case '*':
- case '+':
- case '^':
- case '$':
- *d++ = '\\';
- /* FALL */
- default:
- *d++ = *s;
- }
- }
- *d = '\0';
- }
- int test_substring_filter(
- Slapi_PBlock *pb,
- Slapi_Entry *e,
- struct slapi_filter *f,
- int verify_access,
- int only_check_access,
- int *access_check_done
- )
- {
- Slapi_Attr *a;
- int rc;
- LDAPDebug( LDAP_DEBUG_FILTER, "=> test_substring_filter\n", 0, 0, 0 );
- *access_check_done = 0;
- if(optimise_filter_acl_tests())
- {
- rc = 0;
- if(!only_check_access)
- {
- rc = -1;
- for ( a = e->e_attrs; a != NULL; a = a->a_next ) {
- if ( slapi_attr_type_cmp( f->f_sub_type, a->a_type, SLAPI_TYPE_CMP_SUBTYPE ) == 0 ) {
- rc = plugin_call_syntax_filter_sub( pb, a, &f->f_sub );
- if ( rc == 0 ) {
- break;
- }
- }
- }
- }
- if ( rc == 0 && verify_access && pb != NULL) {
- char *attrs[2] = { NULL, NULL };
- attrs[0] = f->f_sub_type;
- rc = plugin_call_acl_plugin( pb, e, attrs, NULL,
- SLAPI_ACL_SEARCH, ACLPLUGIN_ACCESS_DEFAULT, NULL );
- *access_check_done = -1;
- }
- }
- else
- {
- if ( verify_access && pb != NULL) {
- char *attrs[2] = { NULL, NULL };
- attrs[0] = f->f_sub_type;
- rc = plugin_call_acl_plugin( pb, e, attrs, NULL,
- SLAPI_ACL_SEARCH, ACLPLUGIN_ACCESS_DEFAULT, NULL );
- *access_check_done = -1;
- if ( only_check_access || rc != LDAP_SUCCESS ) {
- return( rc );
- }
- }
- rc = -1;
- for ( a = e->e_attrs; a != NULL; a = a->a_next ) {
- if ( slapi_attr_type_cmp( f->f_sub_type, a->a_type, SLAPI_TYPE_CMP_SUBTYPE ) == 0 ) {
- rc = plugin_call_syntax_filter_sub( pb, a, &f->f_sub );
- if ( rc == 0 || rc == LDAP_TIMELIMIT_EXCEEDED ) {
- break;
- }
- }
- }
- }
- LDAPDebug( LDAP_DEBUG_FILTER, "<= test_substring_filter %d\n",
- rc, 0, 0 );
- return( rc );
- }
- /*
- * Here's a duplicate vattr filter test code modified to support vattrs.
- */
- /*
- * slapi_vattr_filter_test - test a filter against a single entry.
- *
- * Supports the case where the filter mentions virtual attributes.
- * Performance for a real attr only filter is same as for slapi_filter_test()
- * No explicit support for vattrs in extended filters because:
- * 1. the matching rules must support virtual attributes themselves.
- * 2. if no matching rule is specified it defaults to equality so
- * could just use a normal filter with equality.
- * 3. virtual naming attributes are probably too complex to support.
- *
- * returns 0 filter matched
- * -1 filter did not match
- * >0 an ldap error code
- */
- int
- slapi_vattr_filter_test(
- Slapi_PBlock *pb,
- Slapi_Entry *e,
- struct slapi_filter *f,
- int verify_access
- )
- {
- return slapi_vattr_filter_test_ext(pb,e,f,verify_access,0);
- }
- /*
- * vattr_filter_test_ext - full-feature filter test function
- *
- * returns 0 filter matched
- * -1 filter did not match
- * >0 an ldap error code
- */
- int
- slapi_vattr_filter_test_ext(
- Slapi_PBlock *pb,
- Slapi_Entry *e,
- struct slapi_filter *f,
- int verify_access,
- int only_check_access
- )
- {
- int rc = 0; /* a no op request succeeds */
- int access_check_done = 0;
- switch ( f->f_choice ) {
- case LDAP_FILTER_AND:
- case LDAP_FILTER_OR:
- case LDAP_FILTER_NOT:
- /*
- * optimize acl checking by only doing it once it is
- * known that the whole filter passes and so the entry
- * is eligible to be returned.
- * then we check the filter only for access
- *
- * complex filters really benefit from
- * separate stages, filter eval, followed by acl check...
- */
- if(!only_check_access)
- {
- rc = slapi_vattr_filter_test_ext_internal(pb,e,f,0,0, &access_check_done);
- }
- if(rc == 0 && verify_access)
- {
- rc = slapi_vattr_filter_test_ext_internal(pb,e,f,-1,-1, &access_check_done);
- }
- break;
- default:
- /*
- * ...but simple filters are better off doing eval and
- * acl check at once
- */
- rc = slapi_vattr_filter_test_ext_internal(pb,e,f,verify_access,only_check_access, &access_check_done);
- break;
- }
- return rc;
- }
- static int
- slapi_vattr_filter_test_ext_internal(
- Slapi_PBlock *pb,
- Slapi_Entry *e,
- struct slapi_filter *f,
- int verify_access,
- int only_check_access,
- int *access_check_done
- )
- {
- int rc = LDAP_SUCCESS;
- LDAPDebug( LDAP_DEBUG_FILTER, "=> slapi_vattr_filter_test_ext\n", 0, 0, 0 );
- /*
- * RJP: Not sure if this is semantically right, but we have to
- * return something if f is NULL. If there is no filter,
- * then we say that it did match and return 0.
- */
- if ( f == NULL) {
- return(0);
- }
- LDAPDebug( LDAP_DEBUG_FILTER, "=> test_substring_filter\n", 0, 0, 0 );
- switch ( f->f_choice ) {
- case LDAP_FILTER_EQUALITY:
- LDAPDebug( LDAP_DEBUG_FILTER, " EQUALITY\n", 0, 0, 0 );
- if ( verify_access ) {
- rc = test_filter_access( pb, e, f->f_ava.ava_type,
- &f->f_ava.ava_value);
- *access_check_done = 1;
- }
- if ( only_check_access || rc != LDAP_SUCCESS ) {
- return( rc );
- }
- rc = vattr_test_filter( pb, e, f, FILTER_TYPE_AVA, f->f_ava.ava_type );
- break;
- case LDAP_FILTER_SUBSTRINGS:
- LDAPDebug( LDAP_DEBUG_FILTER, " SUBSTRINGS\n", 0, 0, 0 );
- if ( verify_access ) {
- rc = test_filter_access( pb, e, f->f_sub_type, NULL);
- *access_check_done = 1;
- }
- if ( only_check_access || rc != LDAP_SUCCESS ) {
- return( rc );
- }
- rc = vattr_test_filter( pb, e, f, FILTER_TYPE_SUBSTRING, f->f_sub_type);
- break;
- case LDAP_FILTER_GE:
- LDAPDebug( LDAP_DEBUG_FILTER, " GE\n", 0, 0, 0 );
- if ( verify_access ) {
- rc = test_filter_access( pb, e, f->f_ava.ava_type,
- &f->f_ava.ava_value);
- *access_check_done = 1;
- }
- if ( only_check_access || rc != LDAP_SUCCESS ) {
- return( rc );
- }
- rc = vattr_test_filter( pb, e, f, FILTER_TYPE_AVA, f->f_ava.ava_type);
- break;
- case LDAP_FILTER_LE:
- LDAPDebug( LDAP_DEBUG_FILTER, " LE\n", 0, 0, 0 );
- if ( verify_access ) {
- rc = test_filter_access( pb, e, f->f_ava.ava_type,
- &f->f_ava.ava_value);
- *access_check_done = 1;
- }
- if ( only_check_access || rc != LDAP_SUCCESS ) {
- return( rc );
- }
- rc = vattr_test_filter( pb, e, f, FILTER_TYPE_AVA, f->f_ava.ava_type);
- break;
- case LDAP_FILTER_PRESENT:
- LDAPDebug( LDAP_DEBUG_FILTER, " PRESENT\n", 0, 0, 0 );
- if ( verify_access ) {
- rc = test_filter_access( pb, e, f->f_type, NULL);
- *access_check_done = 1;
- }
- if ( only_check_access || rc != LDAP_SUCCESS ) {
- return( rc );
- }
- rc = vattr_test_filter( pb, e, f, FILTER_TYPE_PRES, f->f_type);
- break;
- case LDAP_FILTER_APPROX:
- LDAPDebug( LDAP_DEBUG_FILTER, " APPROX\n", 0, 0, 0 );
- if ( verify_access ) {
- rc = test_filter_access( pb, e, f->f_ava.ava_type,
- &f->f_ava.ava_value);
- *access_check_done = 1;
- }
- if ( only_check_access || rc != LDAP_SUCCESS ) {
- return( rc );
- }
- rc = vattr_test_filter( pb, e, f, FILTER_TYPE_AVA, f->f_ava.ava_type);
- break;
- case LDAP_FILTER_EXTENDED:
- LDAPDebug( LDAP_DEBUG_FILTER, " EXTENDED\n", 0, 0, 0 );
- rc = test_extensible_filter( pb, e, &f->f_mr, verify_access ,
- only_check_access, access_check_done);
- break;
- case LDAP_FILTER_AND:
- LDAPDebug( LDAP_DEBUG_FILTER, " AND\n", 0, 0, 0 );
- rc = vattr_test_filter_list( pb, e, f->f_and,
- LDAP_FILTER_AND , verify_access, only_check_access, access_check_done);
- break;
- case LDAP_FILTER_OR:
- LDAPDebug( LDAP_DEBUG_FILTER, " OR\n", 0, 0, 0 );
- rc = vattr_test_filter_list( pb, e, f->f_or,
- LDAP_FILTER_OR , verify_access, only_check_access, access_check_done);
- break;
- case LDAP_FILTER_NOT:
- LDAPDebug( LDAP_DEBUG_FILTER, " NOT\n", 0, 0, 0 );
- rc = slapi_vattr_filter_test_ext_internal( pb, e, f->f_not , verify_access, only_check_access, access_check_done);
- if(!(verify_access && only_check_access)) /* dont play with access control return codes */
- {
- if(verify_access && !rc && !(*access_check_done))
- {
- /* the filter failed so access control was not checked
- * for NOT filters this is significant so we must ensure
- * access control is checked
- */
- /* check access control only */
- rc = slapi_vattr_filter_test_ext_internal( pb, e, f->f_not , verify_access, -1 /*only_check_access*/, access_check_done);
- /* preserve error code if any */
- if(!rc)
- rc = !rc;
- }
- else
- rc = !rc;
- }
- break;
- default:
- LDAPDebug( LDAP_DEBUG_ANY, " unknown filter type 0x%lX\n",
- f->f_choice, 0, 0 );
- rc = -1;
- }
- LDAPDebug( LDAP_DEBUG_FILTER, "<= slapi_vattr_filter_test %d\n", rc, 0, 0 );
- return( rc );
- }
- static int test_filter_access( Slapi_PBlock *pb,
- Slapi_Entry *e,
- char *attr_type,
- struct berval *attr_val) {
- /*
- * attr_type--attr_type to test for.
- * attr_val--attr value to test for
- */
- int rc;
- char *attrs[2] = { NULL, NULL };
- attrs[0] = attr_type;
-
- rc = plugin_call_acl_plugin( pb, e, attrs, attr_val,
- SLAPI_ACL_SEARCH, ACLPLUGIN_ACCESS_DEFAULT, NULL );
- return(rc);
- }
- static int
- vattr_test_filter_list(
- Slapi_PBlock *pb,
- Slapi_Entry *e,
- struct slapi_filter *flist,
- int ftype,
- int verify_access,
- int only_check_access,
- int *access_check_done
- )
- {
- int nomatch;
- struct slapi_filter *f;
- LDAPDebug( LDAP_DEBUG_FILTER, "=> vattr_test_filter_list\n", 0, 0, 0 );
- nomatch = 1;
- for ( f = flist; f != NULL; f = f->f_next ) {
- if ( slapi_vattr_filter_test_ext_internal( pb, e, f, verify_access, only_check_access, access_check_done ) != 0 ) {
- /* optimize AND evaluation */
- if ( ftype == LDAP_FILTER_AND ) {
- /* one false is failure */
- nomatch = 1;
- break;
- }
- } else {
- nomatch = 0;
- /* optimize OR evaluation too */
- if ( ftype == LDAP_FILTER_OR ) {
- /* only one needs to be true */
- break;
- }
- }
- }
- LDAPDebug( LDAP_DEBUG_FILTER, "<= test_filter_list %d\n", nomatch, 0, 0 );
- return( nomatch );
- }
|