]> git.sur5r.net Git - openldap/commitdiff
- added the capability to filter based on hasSubordinate attribute
authorPierangelo Masarati <ando@openldap.org>
Thu, 29 Aug 2002 10:55:48 +0000 (10:55 +0000)
committerPierangelo Masarati <ando@openldap.org>
Thu, 29 Aug 2002 10:55:48 +0000 (10:55 +0000)
  to back-bdb, back-ldbm and back-sql (the latter with limitations);
- added handling of ":dn" attributes to extended rfc2254 filters
  and to matched value filter
- altered the behavior of get_mra() when a matching rule is given:
  now it checks whether it is compatible with the attribute syntax
  and, in case it is, the given mr is used.  In case of no type,
  the check is delayed when filtering

20 files changed:
servers/slapd/back-bdb/search.c
servers/slapd/back-ldbm/search.c
servers/slapd/back-sql/back-sql.h
servers/slapd/back-sql/entry-id.c
servers/slapd/back-sql/init.c
servers/slapd/back-sql/modify.c
servers/slapd/back-sql/other.c
servers/slapd/back-sql/schema-map.c
servers/slapd/back-sql/schema-map.h
servers/slapd/back-sql/search.c
servers/slapd/back-sql/util.c
servers/slapd/back-sql/util.h
servers/slapd/dn.c
servers/slapd/filter.c
servers/slapd/filterentry.c
servers/slapd/matchedValues.c
servers/slapd/mra.c
servers/slapd/proto-slap.h
servers/slapd/result.c
servers/slapd/slap.h

index 462d8ec02745e742373cc6dd7649488df4667a07..72202268303854c857a8534ebefcb88457f2ee83 100644 (file)
@@ -59,6 +59,10 @@ bdb_search(
        struct slap_limits_set *limit = NULL;
        int isroot = 0;
 
+#ifdef SLAP_X_FILTER_HASSUBORDINATES
+       int             filter_hasSubordinates = 0;
+#endif /* SLAP_X_FILTER_HASSUBORDINATES */
+
        u_int32_t       locker;
        DB_LOCK         lock;
 
@@ -322,11 +326,22 @@ dn2entry_retry:
                }
        }
 
+#ifdef SLAP_X_FILTER_HASSUBORDINATES
+       /*
+        * is hasSubordinates used in the filter ?
+        * FIXME: we may compute this directly when parsing the filter
+        */
+       filter_hasSubordinates = filter_has_subordinates( filter );
+#endif /* SLAP_X_FILTER_HASSUBORDINATES */
+
        for ( id = bdb_idl_first( candidates, &cursor );
                id != NOID;
                id = bdb_idl_next( candidates, &cursor ) )
        {
                int             scopeok = 0;
+#ifdef SLAP_X_FILTER_HASSUBORDINATES
+               Attribute       *hasSubordinates = NULL;
+#endif /* SLAP_X_FILTER_HASSUBORDINATES */
 
                /* check for abandon */
                if ( op->o_abandon ) {
@@ -490,8 +505,47 @@ id2entry_retry:
                        goto loop_continue;
                }
 
+#ifdef SLAP_X_FILTER_HASSUBORDINATES
+               /*
+                * if hasSubordinates is used in the filter,
+                * append it to the entry's attributes
+                */
+               if ( filter_hasSubordinates ) {
+                       int     hs;
+
+                       rc = bdb_hasSubordinates( be, conn, op, e, &hs);
+                       if ( rc != LDAP_SUCCESS ) {
+                               goto loop_continue;
+                       }
+
+                       hasSubordinates = slap_operational_hasSubordinate( hs == LDAP_COMPARE_TRUE );
+                       if ( hasSubordinates == NULL ) {
+                               goto loop_continue;
+                       }
+
+                       hasSubordinates->a_next = e->e_attrs;
+                       e->e_attrs = hasSubordinates;
+               }
+#endif /* SLAP_X_FILTER_HASSUBORDINATES */
+
                /* if it matches the filter and scope, send it */
                rc = test_filter( be, conn, op, e, filter );
+
+#ifdef SLAP_X_FILTER_HASSUBORDINATES
+               if ( hasSubordinates ) {
+                       /*
+                        * FIXME: this is fairly inefficient, because 
+                        * if hasSubordinates is among the required
+                        * attrs, it will be added again later;
+                        * maybe we should leave it and check
+                        * check later if it's already present,
+                        * if required
+                        */
+                       e->e_attrs = e->e_attrs->a_next;
+                       attr_free( hasSubordinates );
+               }
+#endif /* SLAP_X_FILTER_HASSUBORDINATES */
+
                if ( rc == LDAP_COMPARE_TRUE ) {
                        struct berval   dn;
 
@@ -557,8 +611,8 @@ id2entry_retry:
                        }
                } else {
 #ifdef NEW_LOGGING
-                               LDAP_LOG ( OPERATION, RESULTS,
-                                       "bdb_search: %ld does match filter\n", (long) id, 0, 0);
+                       LDAP_LOG ( OPERATION, RESULTS,
+                               "bdb_search: %ld does match filter\n", (long) id, 0, 0);
 #else
                        Debug( LDAP_DEBUG_TRACE,
                                "bdb_search: %ld does match filter\n",
@@ -774,3 +828,4 @@ static int search_candidates(
 
        return rc;
 }
+
index 87f4b9278b1676360089b3b42d5fd18445464e53..eac5f831e9cc125a7bba4b4bb83afe27462ce404 100644 (file)
@@ -57,6 +57,10 @@ ldbm_back_search(
        struct slap_limits_set *limit = NULL;
        int isroot = 0;
                
+#ifdef SLAP_X_FILTER_HASSUBORDINATES
+       int             filter_hasSubordinates = 0;
+#endif /* SLAP_X_FILTER_HASSUBORDINATES */
+
 #ifdef NEW_LOGGING
        LDAP_LOG( BACK_LDBM, ENTRY, "ldbm_back_search: enter\n", 0, 0, 0 );
 #else
@@ -288,10 +292,22 @@ searchit:
        /* compute it anyway; root does not use it */
        stoptime = op->o_time + tlimit;
 
+#ifdef SLAP_X_FILTER_HASSUBORDINATES
+       /*
+        * is hasSubordinates used in the filter ?
+        * FIXME: we may compute this directly when parsing the filter
+        */
+       filter_hasSubordinates = filter_has_subordinates( filter );
+#endif /* SLAP_X_FILTER_HASSUBORDINATES */
+
        for ( id = idl_firstid( candidates, &cursor ); id != NOID;
            id = idl_nextid( candidates, &cursor ) )
        {
                int scopeok = 0;
+               int result = 0;
+#ifdef SLAP_X_FILTER_HASSUBORDINATES
+               Attribute       *hasSubordinates = NULL;
+#endif /* SLAP_X_FILTER_HASSUBORDINATES */
 
                /* check for abandon */
                if ( op->o_abandon ) {
@@ -420,8 +436,44 @@ searchit:
                        goto loop_continue;
                }
 
+#ifdef SLAP_X_FILTER_HASSUBORDINATES
+               /*
+                * if hasSubordinates is used in the filter,
+                * append it to the entry's attributes
+                */
+               if ( filter_hasSubordinates ) {
+                       int     hs;
+
+                       hs = has_children( be, e );
+                       hasSubordinates = slap_operational_hasSubordinate( hs );
+                       if ( hasSubordinates == NULL ) {
+                               goto loop_continue;
+                       }
+
+                       hasSubordinates->a_next = e->e_attrs;
+                       e->e_attrs = hasSubordinates;
+               }
+#endif /* SLAP_X_FILTER_HASSUBORDINATES */
+
                /* if it matches the filter and scope, send it */
-               if ( test_filter( be, conn, op, e, filter ) == LDAP_COMPARE_TRUE ) {
+               result = test_filter( be, conn, op, e, filter );
+
+#ifdef SLAP_X_FILTER_HASSUBORDINATES
+               if ( hasSubordinates ) {
+                       /*
+                        * FIXME: this is fairly inefficient, because 
+                        * if hasSubordinates is among the required
+                        * attrs, it will be added again later;
+                        * maybe we should leave it and check
+                        * check later if it's already present,
+                        * if required
+                        */
+                       e->e_attrs = e->e_attrs->a_next;
+                       attr_free( hasSubordinates );
+               }
+#endif /* SLAP_X_FILTER_HASSUBORDINATES */
+
+               if ( result == LDAP_COMPARE_TRUE ) {
                        struct berval   dn;
 
                        /* check scope */
@@ -452,7 +504,7 @@ searchit:
                                }
 
                                if (e) {
-                                       int result = send_search_entry(be, conn, op,
+                                       result = send_search_entry(be, conn, op,
                                                e, attrs, attrsonly, NULL);
 
                                        switch (result) {
index a456351479103a1cf41e4786d451930daf1331e0..2fb550867065986bdd19c4b9b6e66a4f4216fc0b 100644 (file)
  *                             statements (needed by PostgreSQL)
  *       - upper_needs_cast    cast the argument of upper when required
  *                             (basically when building dn substring queries)
+ *   - added noop control
+ *   - added values return filter control
+ *   - hasSubordinate can be used in search filters (with limitations)
+ *   - eliminated oc->name; use oc->oc->soc_cname instead
  * 
  * Todo:
  *   - add security checks for SQL statements that can be injected (?)
@@ -80,7 +84,6 @@
  */
 #undef BACKSQL_TRACE
 
-
 typedef struct {
        char            *dbhost;
        int             dbport;
index 90564463acf41fdccb85d7a275e12c162760725d..e1a45c7f1e9b6b36f8d0a89d4162bb168a508027 100644 (file)
@@ -14,6 +14,7 @@
 #include <stdio.h>
 #include <sys/types.h>
 #include "ac/string.h"
+#include "lber_pvt.h"
 #include "ldap_pvt.h"
 #include "slap.h"
 #include "back-sql.h"
@@ -255,8 +256,7 @@ backsql_get_attr_vals( backsql_at_map_rec *at, backsql_srch_info *bsi )
  
        Debug( LDAP_DEBUG_TRACE, "==>backsql_get_attr_vals(): "
                "oc='%s' attr='%s' keyval=%ld\n",
-               // bsi->oc->name.bv_val, at->name.bv_val, 
-               bsi->oc->oc->soc_names[0], at->ad->ad_cname.bv_val, 
+               BACKSQL_OC_NAME( bsi->oc ), at->ad->ad_cname.bv_val, 
                bsi->c_eid->keyval );
 
        rc = backsql_Prepare( bsi->dbh, &sth, at->query, 0 );
@@ -363,7 +363,7 @@ backsql_id2entry( backsql_srch_info *bsi, Entry *e, backsql_entryID *eid )
 #if 0
                                backsql_entry_addattr( bsi->e, 
                                                &bv_n_objectclass,
-                                               &bsi->oc->name );
+                                               BACKSQL_OC_NAME( bsi->oc ) );
 #endif
                                continue;
                        }
@@ -376,7 +376,7 @@ backsql_id2entry( backsql_srch_info *bsi, Entry *e, backsql_entryID *eid )
                                        "attribute '%s' is not defined "
                                        "for objectlass '%s'\n",
                                        attr->an_name.bv_val, 
-                                       bsi->oc->name.bv_val, 0 );
+                                       BACKSQL_OC_NAME( bsi->oc ), 0 );
                        }
                }
 
@@ -387,7 +387,7 @@ backsql_id2entry( backsql_srch_info *bsi, Entry *e, backsql_entryID *eid )
                                bsi, 0, AVL_INORDER );
        }
 
-       if ( attr_merge_one( bsi->e, ad_oc, &bsi->oc->name ) ) {
+       if ( attr_merge_one( bsi->e, ad_oc, &bsi->oc->oc->soc_cname ) ) {
                entry_free( e );
                return NULL;
        }
@@ -396,7 +396,7 @@ backsql_id2entry( backsql_srch_info *bsi, Entry *e, backsql_entryID *eid )
                const char      *text = NULL;
                char            textbuf[ 1024 ];
                size_t          textlen = sizeof( textbuf );
-               struct berval   bv[ 2 ] = { bsi->oc->name, { 0, NULL } };
+               struct berval   bv[ 2 ] = { bsi->oc->oc->soc_cname, BER_BVNULL };
                struct berval   soc;
                AttributeDescription    *ad_soc
                        = slap_schema.si_ad_structuralObjectClass;
@@ -408,7 +408,7 @@ backsql_id2entry( backsql_srch_info *bsi, Entry *e, backsql_entryID *eid )
                        return NULL;
                }
 
-               if ( bsi->attr_flags | BSQL_SF_ALL_OPER 
+               if ( bsi->bsi_flags | BSQL_SF_ALL_OPER 
                                || an_find( bsi->attrs, &AllOper ) ) {
                        if ( attr_merge_one( bsi->e, ad_soc, &soc ) ) {
                                entry_free( e );
index 3d4e30242fbbda57de828d00eec374d8b2a62a57..301646ccdab519c1d86c343cfa541499b7d1adc3 100644 (file)
@@ -43,6 +43,18 @@ int
 sql_back_initialize(
        BackendInfo     *bi )
 { 
+       static char *controls[] = {
+#ifdef LDAP_CONTROL_NOOP
+               LDAP_CONTROL_NOOP,
+#endif
+#ifdef LDAP_CONTROL_VALUESRETURNFILTER
+               LDAP_CONTROL_VALUESRETURNFILTER,
+#endif
+               NULL
+       };
+
+       bi->bi_controls = controls;
+
        Debug( LDAP_DEBUG_TRACE,"==>backsql_initialize()\n", 0, 0, 0 );
        
        bi->bi_open = 0;
index 6966c2c6fdb5bf136f361b0e63c3881631b8a67c..bff2f9f8ed8bf009cc40b39e3f5fde60058d6658 100644 (file)
@@ -549,9 +549,10 @@ backsql_modify(
                 * or if a single operation on an attribute fails 
                 * for any reason
                 */
-               SQLTransact( SQL_NULL_HENV, dbh, SQL_COMMIT );
+               SQLTransact( SQL_NULL_HENV, dbh, 
+                               op->o_noop ? SQL_ROLLBACK : SQL_COMMIT );
        }
-       send_ldap_result( conn, op, res, "", text, NULL, NULL );
+       send_ldap_result( conn, op, res, NULL, text, NULL, NULL );
        Debug( LDAP_DEBUG_TRACE, "<==backsql_modify()\n", 0, 0, 0 );
 
        return 0;
@@ -865,7 +866,8 @@ backsql_modrdn(
                 * or if a single operation on an attribute fails for any
                 * reason
                 */
-               SQLTransact( SQL_NULL_HENV, dbh, SQL_COMMIT );
+               SQLTransact( SQL_NULL_HENV, dbh,
+                               op->o_noop ? SQL_ROLLBACK : SQL_COMMIT );
        }
 
 modrdn_return:
@@ -1239,7 +1241,7 @@ backsql_add(
                                "attribute '%s' is not registered "
                                "in objectclass '%s'\n",
                                at->a_desc->ad_cname.bv_val,
-                               oc->name.bv_val, 0 );
+                               BACKSQL_OC_NAME( oc ), 0 );
 
                        if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) {
                                send_ldap_result( conn, op, 
@@ -1312,7 +1314,7 @@ backsql_add(
                         * to build the entry
                         */
                        if ( at->a_desc == slap_schema.si_ad_objectClass ) {
-                               if ( ber_bvcmp( at_val, &oc->name ) == 0 ) {
+                               if ( bvmatch( at_val, &oc->oc->soc_cname ) ) {
                                        continue;
                                }
                        }
@@ -1411,7 +1413,8 @@ backsql_add(
         * or if a single operation on an attribute fails 
         * for any reason
         */
-       SQLTransact( SQL_NULL_HENV, dbh, SQL_COMMIT );
+       SQLTransact( SQL_NULL_HENV, dbh, 
+                               op->o_noop ? SQL_ROLLBACK : SQL_COMMIT );
 
        send_ldap_result( conn, op, LDAP_SUCCESS, "",
                        NULL, NULL, NULL );
@@ -1570,7 +1573,8 @@ backsql_delete(
         * or if a single operation on an attribute fails 
         * for any reason
         */
-       SQLTransact( SQL_NULL_HENV, dbh, SQL_COMMIT );
+       SQLTransact( SQL_NULL_HENV, dbh, 
+                               op->o_noop ? SQL_ROLLBACK : SQL_COMMIT );
 
        send_ldap_result( conn, op, LDAP_SUCCESS, "", NULL, NULL, NULL );
        Debug( LDAP_DEBUG_TRACE, "<==backsql_delete()\n", 0, 0, 0 );
index 1629a086e30b2b7f57619ec1f678cb83fc635935..b2638960f4c697c6b7f0ea3991e64db1183e92d4 100644 (file)
@@ -63,13 +63,18 @@ backsql_operational(
        backsql_info            *bi = (backsql_info*)be->be_private;
        SQLHDBC                 dbh = SQL_NULL_HDBC;
        Attribute               **aa = a;
-       int                     rc;
+       int                     rc = 0;
 
        Debug( LDAP_DEBUG_TRACE, "==>backsql_operational(): entry '%s'\n",
                        e->e_nname.bv_val, 0, 0 );
 
 
-       if ( opattrs || ad_inlist( slap_schema.si_ad_hasSubordinates, attrs ) ) {
+       if ( ( opattrs || ad_inlist( slap_schema.si_ad_hasSubordinates, attrs ) ) 
+#ifdef SLAP_X_FILTER_HASSUBORDINATES
+                       && attr_find( e->e_attrs, slap_schema.si_ad_hasSubordinates ) == NULL
+#endif /* SLAP_X_FILTER_HASSUBORDINATES */
+                       ) {
+               
                rc = backsql_get_db_conn( be, conn, &dbh );
                if ( rc != LDAP_SUCCESS ) {
                        goto no_connection;
index eaa63ab69228919cf43f04952db6cba74bc7e243..d3a7956dcda41e3ce1115b8e08894019d7edceb1 100644 (file)
 #include <sys/types.h>
 #include <string.h>
 #include "slap.h"
+#include "lber_pvt.h"
 #include "ldap_pvt.h"
 #include "back-sql.h"
 #include "sql-wrap.h"
 #include "schema-map.h"
 #include "util.h"
 
-/*
- * Deprecated
- */
-#if 0
-static int
-backsql_cmp_oc_name( backsql_oc_map_rec *m1, backsql_oc_map_rec *m2 )
-{
-       return BACKSQL_NCMP( &m1->name, &m2->name );
-}
-#endif
-
 /*
  * Uses the pointer to the ObjectClass structure
  */
@@ -47,17 +37,6 @@ backsql_cmp_oc_id( backsql_oc_map_rec *m1, backsql_oc_map_rec *m2 )
        return ( m1->id < m2->id ? -1 : ( m1->id > m2->id ? 1 : 0 ) );
 }
 
-/*
- * Deprecated
- */
-#if 0
-static int
-backsql_cmp_attr_name( backsql_at_map_rec *m1, backsql_at_map_rec *m2 )
-{
-       return BACKSQL_NCMP( &m1->name, &m2->name );
-}
-#endif
-
 /*
  * Uses the pointer to the AttributeDescription structure
  */
@@ -72,7 +51,7 @@ backsql_make_attr_query(
        backsql_oc_map_rec      *oc_map,
        backsql_at_map_rec      *at_map )
 {
-       struct berval   tmps = { 0, NULL };
+       struct berval   tmps = BER_BVNULL;
        ber_len_t       tmpslen = 0;
 
        backsql_strfcat( &tmps, &tmpslen, "lblblblbcbl", 
@@ -250,12 +229,11 @@ backsql_load_schema_map( backsql_info *si, SQLHDBC dbh )
 
                oc_map->id = strtol( oc_row.cols[ 0 ], NULL, 0 );
 
-               ber_str2bv( oc_row.cols[ 1 ], 0, 1, &oc_map->name );
-               oc_map->oc = oc_bvfind( &oc_map->name );
+               oc_map->oc = oc_find( oc_row.cols[ 1 ] );
                if ( oc_map->oc == NULL ) {
                        Debug( LDAP_DEBUG_TRACE, "load_schema_map(): "
                                "objectClass '%s' is not defined in schema\n", 
-                               oc_map->name.bv_val, 0, 0 );
+                               oc_row.cols[ 1 ], 0, 0 );
                        return LDAP_OTHER;      /* undefined objectClass ? */
                }
                
@@ -288,7 +266,7 @@ backsql_load_schema_map( backsql_info *si, SQLHDBC dbh )
                oc_id = oc_map->id;
                Debug( LDAP_DEBUG_TRACE, "load_schema_map(): "
                        "objectClass '%s': keytbl='%s' keycol='%s'\n",
-                       oc_map->name.bv_val, 
+                       BACKSQL_OC_NAME( oc_map ),
                        oc_map->keytbl.bv_val, oc_map->keycol.bv_val );
                if ( oc_map->create_proc ) {
                        Debug( LDAP_DEBUG_TRACE, "create_proc='%s'\n",
@@ -349,7 +327,7 @@ backsql_load_schema_map( backsql_info *si, SQLHDBC dbh )
                                        "attribute '%s' for objectClass '%s' "
                                        "is not defined in schema: %s\n", 
                                        at_map->ad->ad_cname.bv_val, 
-                                       oc_map->name.bv_val, text );
+                                       BACKSQL_OC_NAME( oc_map ), text );
                                return LDAP_CONSTRAINT_VIOLATION;
                        }
                                
@@ -415,7 +393,8 @@ backsql_oc2oc( backsql_info *si, ObjectClass *oc )
 #ifdef BACKSQL_TRACE
        if ( res != NULL ) {
                Debug( LDAP_DEBUG_TRACE, "<==backsql_oc2oc(): "
-                       "found name='%s', id=%d\n", res->name, res->id, 0 );
+                       "found name='%s', id=%d\n", 
+                       BACKSQL_OC_NAME( res ), res->id, 0 );
        } else {
                Debug( LDAP_DEBUG_TRACE, "<==backsql_oc2oc(): "
                        "not found\n", 0, 0, 0 );
@@ -425,9 +404,6 @@ backsql_oc2oc( backsql_info *si, ObjectClass *oc )
        return res;
 }
 
-/*
- * Deprecated
- */
 backsql_oc_map_rec *
 backsql_name2oc( backsql_info *si, struct berval *oc_name )
 {
@@ -449,7 +425,8 @@ backsql_name2oc( backsql_info *si, struct berval *oc_name )
 #ifdef BACKSQL_TRACE
        if ( res != NULL ) {
                Debug( LDAP_DEBUG_TRACE, "<==oc_with_name(): "
-                       "found name='%s', id=%d\n", res->name, res->id, 0 );
+                       "found name='%s', id=%d\n", 
+                       BACKSQL_OC_NAME( res ), res->id, 0 );
        } else {
                Debug( LDAP_DEBUG_TRACE, "<==oc_with_name(): "
                        "not found\n", 0, 0, 0 );
@@ -476,7 +453,8 @@ backsql_id2oc( backsql_info *si, unsigned long id )
 #ifdef BACKSQL_TRACE
        if ( res != NULL ) {
                Debug( LDAP_DEBUG_TRACE, "<==oc_with_name(): "
-                       "found name='%s', id=%d\n", res->name, res->id, 0 );
+                       "found name='%s', id=%d\n",
+                       BACKSQL_OC_NAME( res ), res->id, 0 );
        } else {
                Debug( LDAP_DEBUG_TRACE, "<==oc_with_name(): "
                        "not found\n", 0, 0, 0 );
@@ -494,7 +472,7 @@ backsql_ad2at( backsql_oc_map_rec* objclass, AttributeDescription *ad )
 #ifdef BACKSQL_TRACE
        Debug( LDAP_DEBUG_TRACE, "==>backsql_ad2at(): "
                "searching for attribute '%s' for objectclass '%s'\n",
-               attr, objclass->name, 0 );
+               attr, BACKSQL_OC_NAME( objclass ), 0 );
 #endif /* BACKSQL_TRACE */
 
        tmp.ad = ad;
@@ -505,7 +483,7 @@ backsql_ad2at( backsql_oc_map_rec* objclass, AttributeDescription *ad )
        if ( res != NULL ) {
                Debug( LDAP_DEBUG_TRACE, "<==backsql_ad2at(): "
                        "found name='%s', sel_expr='%s'\n",
-                       res->name, res->sel_expr.bv_val, 0 );
+                       res->ad->ad_cname.bv_val, res->sel_expr.bv_val, 0 );
        } else {
                Debug( LDAP_DEBUG_TRACE, "<==backsql_ad2at(): "
                        "not found\n", 0, 0, 0 );
@@ -527,7 +505,7 @@ backsql_name2at( backsql_oc_map_rec* objclass, struct berval *attr )
 #ifdef BACKSQL_TRACE
        Debug( LDAP_DEBUG_TRACE, "==>backsql_name2at(): "
                "searching for attribute '%s' for objectclass '%s'\n",
-               attr, objclass->name, 0 );
+               attr, BACKSQL_OC_NAME( objclass ), 0 );
 #endif /* BACKSQL_TRACE */
 
        if ( slap_bv2ad( attr, &tmp.ad, &text ) != LDAP_SUCCESS ) {
@@ -587,9 +565,8 @@ static void
 backsql_free_oc( backsql_oc_map_rec *oc )
 {
        Debug( LDAP_DEBUG_TRACE, "==>free_oc(): '%s'\n", 
-                       oc->name.bv_val, 0, 0 );
+                       BACKSQL_OC_NAME( oc ), 0, 0 );
        avl_free( oc->attrs, (AVL_FREE)backsql_free_attr );
-       ch_free( oc->name.bv_val );
        ch_free( oc->keytbl.bv_val );
        ch_free( oc->keycol.bv_val );
        if ( oc->create_proc != NULL ) {
index 7c7f0cf39efeba05a3e81fb77c01ed49784c0041..5467523fad8bd2ec28b249ce1d522788ab019c4d 100644 (file)
  */
 
 typedef struct {
-       /*
-        * FIXME: we explicitly keep the objectClass name because
-        * the ObjectClass structure does not use bervals (yet?)
-        */
-       struct berval   name;
        /*
         * Structure of corresponding LDAP objectClass definition
         */
        ObjectClass     *oc;
+#define BACKSQL_OC_NAME(ocmap) ((ocmap)->oc->soc_cname.bv_val)
+       
        struct berval   keytbl;
        struct berval   keycol;
        /* expected to return keyval of newly created entry */
index ffd1856fd8715168f192d75b725c450b36f10d0d..ed48753a083afb7aac43c0134c35e823082a1224 100644 (file)
@@ -23,6 +23,8 @@
 #include "entry-id.h"
 #include "util.h"
 
+static int backsql_process_filter( backsql_srch_info *bsi, Filter *f );
+
 static int
 backsql_attrlist_add( backsql_srch_info *bsi, AttributeDescription *ad )
 {
@@ -33,6 +35,15 @@ backsql_attrlist_add( backsql_srch_info *bsi, AttributeDescription *ad )
                return 1;
        }
 
+       /*
+        * clear the list (retrieve all attrs)
+        */
+       if ( ad == NULL ) {
+               ch_free( bsi->attrs );
+               bsi->attrs = NULL;
+               return 1;
+       }
+
        for ( ; bsi->attrs[ n_attrs ].an_name.bv_val; n_attrs++ ) {
                an = &bsi->attrs[ n_attrs ];
                
@@ -94,12 +105,8 @@ backsql_init_search(
        bsi->be = be;
        bsi->conn = conn;
        bsi->op = op;
-       bsi->attr_flags = 0;
+       bsi->bsi_flags = 0;
 
-       /*
-        * FIXME: need to discover how to deal with 1.1 (NoAttrs)
-        */
-       
        /*
         * handle "*"
         */
@@ -114,13 +121,13 @@ backsql_init_search(
                
                for ( p = attrs; p->an_name.bv_val; p++ ) {
                        /*
-                        * ignore "+"
+                        * ignore "1.1"; handle "+"
                         */
                        if ( BACKSQL_NCMP( &p->an_name, &AllOper ) == 0 ) {
+                               bsi->bsi_flags |= BSQL_SF_ALL_OPER;
                                continue;
 
                        } else if ( BACKSQL_NCMP( &p->an_name, &NoAttrs ) == 0 ) {
-                               bsi->attr_flags |= BSQL_SF_ALL_OPER;
                                continue;
                        }
 
@@ -149,7 +156,7 @@ backsql_init_search(
        bsi->status = LDAP_SUCCESS;
 }
 
-int
+static int
 backsql_process_filter_list( backsql_srch_info *bsi, Filter *f, int op )
 {
        int             res;
@@ -195,7 +202,7 @@ backsql_process_filter_list( backsql_srch_info *bsi, Filter *f, int op )
        return 1;
 }
 
-int
+static int
 backsql_process_sub_filter( backsql_srch_info *bsi, Filter *f )
 {
        int                     i;
@@ -301,13 +308,13 @@ backsql_process_sub_filter( backsql_srch_info *bsi, Filter *f )
        return 1;
 }
 
-int
+static int
 backsql_process_filter( backsql_srch_info *bsi, Filter *f )
 {
        backsql_at_map_rec      *at;
        backsql_at_map_rec      oc_attr = {
                slap_schema.si_ad_objectClass, BER_BVC(""), BER_BVC(""), 
-               { 0, NULL }, NULL, NULL, NULL };
+               BER_BVNULL, NULL, NULL, NULL };
        AttributeDescription    *ad = NULL;
        int                     done = 0;
        ber_len_t               len = 0;
@@ -328,7 +335,7 @@ backsql_process_filter( backsql_srch_info *bsi, Filter *f )
                
        case LDAP_FILTER_AND:
                rc = backsql_process_filter_list( bsi, f->f_and,
-                               LDAP_FILTER_AND);
+                               LDAP_FILTER_AND );
                done = 1;
                break;
 
@@ -346,6 +353,10 @@ backsql_process_filter( backsql_srch_info *bsi, Filter *f )
                ad = f->f_desc;
                break;
                
+       case LDAP_FILTER_EXT:
+               ad = f->f_mra->ma_desc;
+               break;
+               
        default:
                ad = f->f_av_desc;
                break;
@@ -360,23 +371,58 @@ backsql_process_filter( backsql_srch_info *bsi, Filter *f )
                goto done;
        }
 
-       if ( ad != slap_schema.si_ad_objectClass ) {
-               at = backsql_ad2at( bsi->oc, ad );
-
-       } else {
+       /*
+        * Turn structuralObjectClass into objectClass
+        */
+       if ( ad == slap_schema.si_ad_objectClass 
+                       || ad == slap_schema.si_ad_structuralObjectClass ) {
                at = &oc_attr;
                backsql_strfcat( &at->sel_expr, &len, "cbc",
                                '\'', 
-                               &bsi->oc->name, 
+                               &bsi->oc->oc->soc_cname, 
                                '\'' );
+
+#if defined(SLAP_X_FILTER_HASSUBORDINATES) || defined(SLAP_X_MRA_MATCH_DNATTRS)
+       } else if ( ad == slap_schema.si_ad_hasSubordinates || ad == NULL ) {
+               /*
+                * FIXME: this is not robust; e.g. a filter
+                * '(!(hasSubordinates=TRUE))' fails because
+                * in SQL it would read 'NOT (1=1)' instead 
+                * of no condition.  
+                * Note however that hasSubordinates is boolean, 
+                * so a more appropriate filter would be 
+                * '(hasSubordinates=FALSE)'
+                */
+               backsql_strfcat( &bsi->flt_where, &bsi->fwhere_len, "l",
+                               (ber_len_t)sizeof( "1=1" ) - 1, "1=1" );
+               if ( ad != NULL ) {
+                       /*
+                        * We use this flag since we need to parse
+                        * the filter anyway; we should have used
+                        * the frontend API function
+                        * filter_has_subordinates()
+                        */
+                       bsi->bsi_flags |= BSQL_SF_FILTER_HASSUBORDINATE;
+               } else {
+                       /*
+                        * clear attributes to fetch, to require ALL
+                        * and try extended match on all attributes
+                        */
+                       backsql_attrlist_add( bsi, NULL );
+               }
+               goto done;
+#endif /* SLAP_X_FILTER_HASSUBORDINATES || SLAP_X_MRA_MATCH_DNATTRS */
+               
+       } else {
+               at = backsql_ad2at( bsi->oc, ad );
        }
 
        if ( at == NULL ) {
                Debug( LDAP_DEBUG_TRACE, "backsql_process_filter(): "
                        "attribute '%s' is not defined for objectclass '%s'\n",
-                       ad->ad_cname.bv_val, bsi->oc->name.bv_val, 0 );
+                       ad->ad_cname.bv_val, BACKSQL_OC_NAME( bsi->oc ), 0 );
                backsql_strfcat( &bsi->flt_where, &bsi->fwhere_len, "l",
-                               (ber_len_t)sizeof( " 1=0 " ) - 1, " 1=0 " );
+                               (ber_len_t)sizeof( "1=0" ) - 1, "1=0" );
                goto impossible;
        }
 
@@ -461,6 +507,9 @@ backsql_process_filter( backsql_srch_info *bsi, Filter *f )
                break;
 
        case LDAP_FILTER_GE:
+               /*
+                * FIXME: should we uppercase the operands?
+                */
                backsql_strfcat( &bsi->flt_where, &bsi->fwhere_len, "cblbc",
                                '(' /* ) */ ,
                                &at->sel_expr,
@@ -470,6 +519,9 @@ backsql_process_filter( backsql_srch_info *bsi, Filter *f )
                break;
                
        case LDAP_FILTER_LE:
+               /*
+                * FIXME: should we uppercase the operands?
+                */
                backsql_strfcat( &bsi->flt_where, &bsi->fwhere_len, "cblbc",
                                '(' /* ) */ ,
                                &at->sel_expr,
@@ -558,13 +610,13 @@ backsql_srch_query( backsql_srch_info *bsi, struct berval *query )
                                &bi->strcast_func, 
                                (ber_len_t)sizeof( "('" /* ') */ ) - 1,
                                        "('" /* ') */ ,
-                               &bsi->oc->name,
+                               &bsi->oc->oc->soc_cname,
                                (ber_len_t)sizeof( /* (' */ "')" ) - 1,
                                        /* (' */ "')" );
        } else {
                backsql_strfcat( &bsi->sel, &bsi->sel_len, "cbc",
                                '\'',
-                               &bsi->oc->name,
+                               &bsi->oc->oc->soc_cname,
                                '\'' );
        }
        backsql_strfcat( &bsi->sel, &bsi->sel_len, "l",
@@ -669,7 +721,7 @@ backsql_oc_get_candidates( backsql_oc_map_rec *oc, backsql_srch_info *bsi )
        int                     j;
  
        Debug(  LDAP_DEBUG_TRACE, "==>backsql_oc_get_candidates(): oc='%s'\n",
-                       oc->name.bv_val, 0, 0 );
+                       BACKSQL_OC_NAME( oc ), 0, 0 );
 
        if ( bsi->n_candidates == -1 ) {
                Debug( LDAP_DEBUG_TRACE, "backsql_oc_get_candidates(): "
@@ -998,6 +1050,10 @@ backsql_search(
         */
        for ( eid = srch_info.id_list; eid != NULL; 
                        eid = backsql_free_entryID( eid, 1 ) ) {
+#ifdef SLAP_X_FILTER_HASSUBORDINATES
+               Attribute       *hasSubordinate = NULL,
+                               *a = NULL;
+#endif /* SLAP_X_FILTER_HASSUBORDINATES */
 
                /* check for abandon */
                if ( op->o_abandon ) {
@@ -1035,10 +1091,68 @@ backsql_search(
                        continue;
                }
 
+#ifdef SLAP_X_FILTER_HASSUBORDINATES
+               /*
+                * We use this flag since we need to parse the filter
+                * anyway; we should have used the frontend API function
+                * filter_has_subordinates()
+                */
+               if ( srch_info.bsi_flags & BSQL_SF_FILTER_HASSUBORDINATE ) {
+                       int             rc;
+
+                       rc = backsql_has_children( bi, dbh, &entry->e_nname );
+
+                       switch( rc ) {
+                       case LDAP_COMPARE_TRUE:
+                       case LDAP_COMPARE_FALSE:
+                               hasSubordinate = slap_operational_hasSubordinate( rc == LDAP_COMPARE_TRUE );
+                               if ( hasSubordinate != NULL ) {
+                                       for ( a = entry->e_attrs; 
+                                                       a && a->a_next; 
+                                                       a = a->a_next );
+
+                                       a->a_next = hasSubordinate;
+                               }
+                               rc = 0;
+                               break;
+
+                       default:
+                               Debug(LDAP_DEBUG_TRACE, 
+                                       "backsql_search(): "
+                                       "has_children failed( %d)\n", 
+                                       rc, 0, 0 );
+                               rc = 1;
+                               break;
+                       }
+
+                       if ( rc ) {
+                               continue;
+                       }
+               }
+#endif /* SLAP_X_FILTER_HASSUBORDINATES */
+
                if ( test_filter( be, conn, op, entry, filter ) 
                                == LDAP_COMPARE_TRUE ) {
-                       sres = send_search_entry( be, conn, op, entry,
-                                       attrs, attrsonly, NULL );
+#ifdef SLAP_X_FILTER_HASSUBORDINATES
+                       if ( hasSubordinate && !( srch_info.bsi_flags & BSQL_SF_ALL_OPER ) 
+                                       && !ad_inlist( slap_schema.si_ad_hasSubordinates, attrs ) ) {
+                               a->a_next = NULL;
+                               attr_free( hasSubordinate );
+                               hasSubordinate = NULL;
+                       }
+#endif /* SLAP_X_FILTER_HASSUBORDINATES */
+
+#if 0  /* noop is masked SLAP_CTRL_UPDATE */
+                       if ( op->o_noop ) {
+                               sres = 0;
+                       } else {
+#endif
+                               sres = send_search_entry( be, conn, op, entry,
+                                               attrs, attrsonly, NULL );
+#if 0
+                       }
+#endif
+
                        switch ( sres ) {
                        case 0:
                                nentries++;
index ffd10efc9516e7f813661025ee440e895a0aeb3f..402d36fbab5aa077fa292080e8129bc5fcd5aa50 100644 (file)
@@ -273,7 +273,7 @@ char *
 backsql_get_table_spec( char **p )
 {
        char            *s, *q;
-       struct berval   res = { 0, NULL };
+       struct berval   res = BER_BVNULL;
        ber_len_t       res_len = 0;
 
        assert( p );
index a9f1042d03d0e34836d97358f4da73587041d284..06e38d5824b19db090b7f251c87e2b291609a3d7 100644 (file)
@@ -42,14 +42,14 @@ typedef struct backsql_srch_info {
        Connection              *conn;
        Operation               *op;
        AttributeName           *attrs;
-       int                     attr_flags;
-#define        BSQL_SF_ALL_OPER        0x0001
+       int                     bsi_flags;
+#define        BSQL_SF_ALL_OPER                0x0001
+#define BSQL_SF_FILTER_HASSUBORDINATE  0x0002
        Entry                   *e;
        /* 1 if the db is TimesTen; 0 if it's not */
        int                     use_reverse_dn; 
 } backsql_srch_info;
 
-int backsql_process_filter( backsql_srch_info *bsi, Filter *f );
 void backsql_init_search( backsql_srch_info *bsi, backsql_info *bi,
                struct berval *nbase, int scope, int slimit, int tlimit,
                time_t stoptime, Filter *filter, SQLHDBC dbh,
index 9194a9cb536847b75b6430c535321b77cd075072..0084a7c80a22776a1e22295055ac06dea866f300 100644 (file)
 
 const struct berval slap_empty_bv = { 0, "" };
 
-#define SLAP_LDAPDN_PRETTY 0x1
-
-#define SLAP_LDAPDN_MAXLEN 8192
-
 /*
  * The DN syntax-related functions take advantage of the dn representation
  * handling functions ldap_str2dn/ldap_dn2str.  The latter are not schema-
@@ -493,6 +489,60 @@ dnPretty2(
        return LDAP_SUCCESS;
 }
 
+int
+dnPrettyNormalDN(
+       Syntax *syntax,
+       struct berval *val,
+       LDAPDN **dn,
+       int flags )
+{
+       assert( val );
+       assert( dn );
+
+#ifdef NEW_LOGGING
+       LDAP_LOG( OPERATION, ARGS, ">>> dn%sDN: <%s>\n", 
+                       flags == SLAP_LDAPDN_PRETTY ? "Pretty" : "Normal", 
+                       val->bv_val, 0 );
+#else
+       Debug( LDAP_DEBUG_TRACE, ">>> dn%sDN: <%s>\n", 
+                       flags == SLAP_LDAPDN_PRETTY ? "Pretty" : "Normal", 
+                       val->bv_val, 0 );
+#endif
+
+       if ( val->bv_len == 0 ) {
+               return LDAP_SUCCESS;
+
+       } else if ( val->bv_len > SLAP_LDAPDN_MAXLEN ) {
+               return LDAP_INVALID_SYNTAX;
+
+       } else {
+               int             rc;
+
+               /* FIXME: should be liberal in what we accept */
+               rc = ldap_bv2dn( val, dn, LDAP_DN_FORMAT_LDAP );
+               if ( rc != LDAP_SUCCESS ) {
+                       return LDAP_INVALID_SYNTAX;
+               }
+
+               assert( strlen( val->bv_val ) == val->bv_len );
+
+               /*
+                * Schema-aware rewrite
+                */
+               if ( LDAPDN_rewrite( *dn, flags ) != LDAP_SUCCESS ) {
+                       ldap_dnfree( *dn );
+                       *dn = NULL;
+                       return LDAP_INVALID_SYNTAX;
+               }
+       }
+
+       Debug( LDAP_DEBUG_TRACE, "<<< dn%sDN\n", 
+                       flags == SLAP_LDAPDN_PRETTY ? "Pretty" : "Normal",
+                       0, 0 );
+
+       return LDAP_SUCCESS;
+}
+
 /*
  * Combination of both dnPretty and dnNormalize
  */
index 69a26bf34bd30a3fe0fed81e8f50b53c701b903a..608b732c847c4c1cf26d4a5404b7dce1dccbd9b6 100644 (file)
@@ -744,7 +744,7 @@ filter2bv( Filter *f, struct berval *fstr )
 
        case LDAP_FILTER_EXT:
                filter_escape_value( &f->f_mr_value, &tmp );
-
+#ifndef SLAP_X_MRA_MATCH_DNATTRS
                fstr->bv_len = f->f_mr_desc->ad_cname.bv_len +
                        ( f->f_mr_dnattrs ? sizeof(":dn")-1 : 0 ) +
                        ( f->f_mr_rule_text.bv_len ? f->f_mr_rule_text.bv_len+1 : 0 ) +
@@ -757,6 +757,31 @@ filter2bv( Filter *f, struct berval *fstr )
                        f->f_mr_rule_text.bv_len ? ":" : "",
                        f->f_mr_rule_text.bv_len ? f->f_mr_rule_text.bv_val : "",
                        tmp.bv_val );
+#else /* SLAP_X_MRA_MATCH_DNATTRS */
+               {
+               struct berval ad;
+
+               if ( f->f_mr_desc ) {
+                       ad = f->f_mr_desc->ad_cname;
+               } else {
+                       ad.bv_len = 0;
+                       ad.bv_val = "";
+               }
+                       
+               fstr->bv_len = ad.bv_len +
+                       ( f->f_mr_dnattrs ? sizeof(":dn")-1 : 0 ) +
+                       ( f->f_mr_rule_text.bv_len ? f->f_mr_rule_text.bv_len+1 : 0 ) +
+                       tmp.bv_len + ( sizeof("(:=)") - 1 );
+               fstr->bv_val = malloc( fstr->bv_len + 1 );
+
+               snprintf( fstr->bv_val, fstr->bv_len + 1, "(%s%s%s%s:=%s)",
+                       ad.bv_val,
+                       f->f_mr_dnattrs ? ":dn" : "",
+                       f->f_mr_rule_text.bv_len ? ":" : "",
+                       f->f_mr_rule_text.bv_len ? f->f_mr_rule_text.bv_val : "",
+                       tmp.bv_val );
+               }
+#endif /* SLAP_X_MRA_MATCH_DNATTRS */
                ber_memfree( tmp.bv_val );
                break;
 
@@ -1286,6 +1311,7 @@ simple_vrFilter2bv( ValuesReturnFilter *f, struct berval *fstr )
        case LDAP_FILTER_EXT:
                filter_escape_value( &f->f_mr_value, &tmp );
 
+#ifndef SLAP_X_MRA_MATCH_DNATTRS
                fstr->bv_len = f->f_mr_desc->ad_cname.bv_len +
                        ( f->f_mr_dnattrs ? sizeof(":dn")-1 : 0 ) +
                        ( f->f_mr_rule_text.bv_len ? f->f_mr_rule_text.bv_len+1 : 0 ) +
@@ -1298,6 +1324,32 @@ simple_vrFilter2bv( ValuesReturnFilter *f, struct berval *fstr )
                        f->f_mr_rule_text.bv_len ? ":" : "",
                        f->f_mr_rule_text.bv_len ? f->f_mr_rule_text.bv_val : "",
                        tmp.bv_val );
+#else /* SLAP_X_MRA_MATCH_DNATTRS */
+               {
+               struct berval ad;
+
+               if ( f->f_mr_desc ) {
+                       ad = f->f_mr_desc->ad_cname;
+               } else {
+                       ad.bv_len = 0;
+                       ad.bv_val = "";
+               }
+                       
+               fstr->bv_len = ad.bv_len +
+                       ( f->f_mr_dnattrs ? sizeof(":dn")-1 : 0 ) +
+                       ( f->f_mr_rule_text.bv_len ? f->f_mr_rule_text.bv_len+1 : 0 ) +
+                       tmp.bv_len + ( sizeof("(:=)") - 1 );
+               fstr->bv_val = malloc( fstr->bv_len + 1 );
+
+               snprintf( fstr->bv_val, fstr->bv_len + 1, "(%s%s%s%s:=%s)",
+                       ad.bv_val,
+                       f->f_mr_dnattrs ? ":dn" : "",
+                       f->f_mr_rule_text.bv_len ? ":" : "",
+                       f->f_mr_rule_text.bv_len ? f->f_mr_rule_text.bv_val : "",
+                       tmp.bv_val );
+               }
+#endif /* SLAP_X_MRA_MATCH_DNATTRS */
+
                ber_memfree( tmp.bv_val );
                break;
 
@@ -1514,3 +1566,92 @@ return_error:
        return( LDAP_SUCCESS );
 }
 
+#ifdef SLAP_X_FILTER_HASSUBORDINATES
+static int filter_has_subordinates_list(
+       Filter          *filter );
+
+/*
+ * FIXME: we could detect the need to filter
+ * for hasSubordinates when parsing the filter ...
+ */
+
+static int
+filter_has_subordinates_list(
+       Filter          *fl )
+{
+       Filter                  *f;
+
+       for ( f = fl; f != NULL; f = f->f_next ) {
+               int     rc;
+
+               rc = filter_has_subordinates( f );
+
+               if ( rc ) {
+                       return rc;
+               }
+       }
+
+       return 0;
+}
+
+int
+filter_has_subordinates(
+       Filter          *f )
+{
+       AttributeDescription    *ad = NULL;
+
+       switch ( f->f_choice ) {
+       case LDAP_FILTER_PRESENT:
+               ad = f->f_desc;
+               break;
+
+       case LDAP_FILTER_EQUALITY:
+       case LDAP_FILTER_APPROX:
+       case LDAP_FILTER_GE:
+       case LDAP_FILTER_LE:
+               ad = f->f_ava->aa_desc;
+               break;
+
+       case LDAP_FILTER_SUBSTRINGS:
+               ad = f->f_sub_desc;
+               break;
+
+       case LDAP_FILTER_EXT:
+               /* could be null; however here it is harmless */
+               ad = f->f_mra->ma_desc;
+               break;
+
+       case LDAP_FILTER_NOT:
+               return filter_has_subordinates( f->f_not );
+
+       case LDAP_FILTER_AND:
+               return filter_has_subordinates_list( f->f_and );
+
+       case LDAP_FILTER_OR:
+               return filter_has_subordinates_list( f->f_or );
+
+       case SLAPD_FILTER_COMPUTED:
+               /*
+                * something wrong?
+                */
+               return 0;
+
+       default:
+               /*
+                * this means a new type of filter has been implemented,
+                * which is not handled yet in this function; we should
+                * issue a developer's warning, e.g. an assertion
+                */
+               assert( 0 );
+               return -1;
+       }
+
+       if ( ad == slap_schema.si_ad_hasSubordinates ) {
+               return 1;
+       }
+
+       return 0;
+}
+
+#endif /* SLAP_X_FILTER_HASSUBORDINATES */
+
index 672915cb8cde4a6ff3db6717e74d401c4d1592bb..111e258e61554acf70b6f6a9b0cc7ef880da75a1 100644 (file)
@@ -215,36 +215,174 @@ static int test_mra_filter(
 {
        Attribute       *a;
 
+#ifndef SLAP_X_MRA_MATCH_DNATTRS
        if( !access_allowed( be, conn, op, e,
                mra->ma_desc, &mra->ma_value, ACL_SEARCH, NULL ) )
        {
                return LDAP_INSUFFICIENT_ACCESS;
        }
+#else /* SLAP_X_MRA_MATCH_DNATTRS */
+       if ( mra->ma_desc ) {
+               /*
+                * if ma_desc is available, then we're filtering for
+                * one attribute, and SEARCH permissions can be checked
+                * directly.
+                */
+               if( !access_allowed( be, conn, op, e,
+                       mra->ma_desc, &mra->ma_value, ACL_SEARCH, NULL ) )
+               {
+                       return LDAP_INSUFFICIENT_ACCESS;
+               }
+#endif /* SLAP_X_MRA_MATCH_DNATTRS */
+
+               for(a = attrs_find( e->e_attrs, mra->ma_desc );
+                       a != NULL;
+                       a = attrs_find( a->a_next, mra->ma_desc ) )
+               {
+                       struct berval *bv;
+                       for ( bv = a->a_vals; bv->bv_val != NULL; bv++ ) {
+                               int ret;
+                               int rc;
+                               const char *text;
+       
+                               rc = value_match( &ret, a->a_desc, mra->ma_rule,
+                                       SLAP_MR_ASSERTION_SYNTAX_MATCH,
+                                       bv, &mra->ma_value, &text );
+       
+                               if( rc != LDAP_SUCCESS ) {
+                                       return rc;
+                               }
+       
+                               if ( ret == 0 ) {
+                                       return LDAP_COMPARE_TRUE;
+                               }
+                       }
+               }
+#ifdef SLAP_X_MRA_MATCH_DNATTRS
+       } else {
 
-       for(a = attrs_find( e->e_attrs, mra->ma_desc );
-               a != NULL;
-               a = attrs_find( a->a_next, mra->ma_desc ) )
-       {
-               struct berval *bv;
-               for ( bv = a->a_vals; bv->bv_val != NULL; bv++ ) {
-                       int ret;
-                       int rc;
-                       const char *text;
+               /*
+                * No attribute description: test all
+                */
+               for ( a = e->e_attrs; a != NULL; a = a->a_next ) {
+                       struct berval   *bv, value;
+                       const char      *text = NULL;
+                       int             rc;
+
+                       /* check if matching is appropriate */
+                       if ( strcmp( mra->ma_rule->smr_syntax->ssyn_oid,
+                               a->a_desc->ad_type->sat_syntax->ssyn_oid ) != 0 ) {
+                               continue;
+                       }
 
-                       rc = value_match( &ret, a->a_desc, mra->ma_rule,
-                               SLAP_MR_ASSERTION_SYNTAX_MATCH,
-                               bv, &mra->ma_value,
-                               &text );
+                       /* normalize for equality */
+                       rc = value_validate_normalize( a->a_desc, 
+                               SLAP_MR_EQUALITY,
+                               &mra->ma_value, &value, &text );
+                       if ( rc != LDAP_SUCCESS ) {
+                               continue;
+                       }
 
-                       if( rc != LDAP_SUCCESS ) {
-                               return rc;
+                       /* check search access */
+                       if ( !access_allowed( be, conn, op, e,
+                               a->a_desc, &value, ACL_SEARCH, NULL ) ) {
+                               continue;
                        }
 
-                       if ( ret == 0 ) {
-                               return LDAP_COMPARE_TRUE;
+                       /* check match */
+                       for ( bv = a->a_vals; bv->bv_val != NULL; bv++ ) {
+                               int ret;
+                               int rc;
+       
+                               rc = value_match( &ret, a->a_desc, mra->ma_rule,
+                                       SLAP_MR_ASSERTION_SYNTAX_MATCH,
+                                       bv, &value, &text );
+       
+                               if( rc != LDAP_SUCCESS ) {
+                                       return rc;
+                               }
+       
+                               if ( ret == 0 ) {
+                                       return LDAP_COMPARE_TRUE;
+                               }
+                       }
+               }
+       }
+
+       /* check attrs in DN AVAs if required */
+       if ( mra->ma_dnattrs ) {
+               LDAPDN          *dn = NULL;
+               int             iRDN, iAVA;
+               int             rc;
+
+               /* parse and pretty the dn */
+               rc = dnPrettyDN( NULL, &e->e_name, &dn );
+               if ( rc != LDAP_SUCCESS ) {
+                       return LDAP_INVALID_SYNTAX;
+               }
+
+               /* for each AVA of each RDN ... */
+               for ( iRDN = 0; dn[ 0 ][ iRDN ]; iRDN++ ) {
+                       LDAPRDN         *rdn = dn[ 0 ][ iRDN ];
+
+                       for ( iAVA = 0; rdn[ 0 ][ iAVA ]; iAVA++ ) {
+                               LDAPAVA         *ava = rdn[ 0 ][ iAVA ];
+                               struct berval   *bv = &ava->la_value, value;
+                               AttributeDescription *ad = (AttributeDescription *)ava->la_private;
+                               int ret;
+                               int rc;
+                               const char *text;
+
+                               assert( ad );
+
+                               if ( mra->ma_desc ) {
+                                       /* have a mra type? check for subtype */
+                                       if ( !is_ad_subtype( ad, mra->ma_desc ) ) {
+                                               continue;
+                                       }
+                                       value = mra->ma_value;
+
+                               } else {
+                                       const char      *text = NULL;
+
+                                       /* check if matching is appropriate */
+                                       if ( strcmp( mra->ma_rule->smr_syntax->ssyn_oid,
+                                               ad->ad_type->sat_syntax->ssyn_oid ) != 0 ) {
+                                               continue;
+                                       }
+
+                                       /* normalize for equality */
+                                       rc = value_validate_normalize( ad, SLAP_MR_EQUALITY,
+                                               &mra->ma_value, &value, &text );
+                                       if ( rc != LDAP_SUCCESS ) {
+                                               continue;
+                                       }
+
+                                       /* check search access */
+                                       if ( !access_allowed( be, conn, op, e,
+                                               ad, &value, ACL_SEARCH, NULL ) ) {
+                                               continue;
+                                       }
+                               }
+
+                               /* check match */
+                               rc = value_match( &ret, ad, mra->ma_rule,
+                                       SLAP_MR_ASSERTION_SYNTAX_MATCH,
+                                       bv, &value, &text );
+
+                               if( rc != LDAP_SUCCESS ) {
+                                       ldap_dnfree( dn );
+                                       return rc;
+                               }
+
+                               if ( ret == 0 ) {
+                                       ldap_dnfree( dn );
+                                       return LDAP_COMPARE_TRUE;
+                               }
                        }
                }
        }
+#endif /* SLAP_X_MRA_MATCH_DNATTRS */
 
        return LDAP_COMPARE_FALSE;
 }
index 170977d0eeb46b61ee4b0f014d2a5b8a7bb70d1e..51c223e97d0ad71787f20f803395313361af352e 100644 (file)
@@ -19,7 +19,8 @@
 
 #include "../../libraries/liblber/lber-int.h"
 
-static int test_mra_vrFilter(
+static int
+test_mra_vrFilter(
        Backend         *be,
        Connection      *conn,
        Operation       *op,
@@ -342,7 +343,8 @@ test_substrings_vrFilter(
        return LDAP_SUCCESS;
 }
 
-static int test_mra_vrFilter(
+static int
+test_mra_vrFilter(
        Backend         *be,
        Connection      *conn,
        Operation       *op,
@@ -354,11 +356,40 @@ static int test_mra_vrFilter(
        int i, j;
 
        for ( i=0; a != NULL; a = a->a_next, i++ ) {
-               struct berval *bv;
-       
+               struct berval *bv, value;
+
+#ifndef SLAP_X_MRA_MATCH_DNATTRS
                if ( !is_ad_subtype( a->a_desc, mra->ma_desc ) ) {
                        return( LDAP_SUCCESS );
                }
+               value = mra->ma_value;
+
+#else /* SLAP_X_MRA_MATCH_DNATTRS */
+               if ( mra->ma_desc ) {
+                       if ( !is_ad_subtype( a->a_desc, mra->ma_desc ) ) {
+                               return( LDAP_SUCCESS );
+                       }
+                       value = mra->ma_value;
+
+               } else {
+                       const char      *text = NULL;
+
+                       /* check if matching is appropriate */
+                       if ( strcmp( mra->ma_rule->smr_syntax->ssyn_oid,
+                               a->a_desc->ad_type->sat_syntax->ssyn_oid ) != 0 ) {
+                               continue;
+                       }
+
+                       /* normalize for equality */
+                       if ( value_validate_normalize( a->a_desc, 
+                               SLAP_MR_EQUALITY,
+                               &mra->ma_value, &value,
+                               &text ) != LDAP_SUCCESS ) {
+                               continue;
+                       }
+
+               }
+#endif /* SLAP_X_MRA_MATCH_DNATTRS */
 
                for ( bv = a->a_vals, j = 0; bv->bv_val != NULL; bv++, j++ ) {
                        int ret;
@@ -367,7 +398,7 @@ static int test_mra_vrFilter(
 
                        rc = value_match( &ret, a->a_desc, mra->ma_rule,
                                SLAP_MR_ASSERTION_SYNTAX_MATCH,
-                               bv, &mra->ma_value,
+                               bv, &value,
                                &text );
 
                        if( rc != LDAP_SUCCESS ) {
index eca939b02674fd8b17def10f75c736b76a158c53..d4e331f194ad36fce2c3bc049dad5a1ce1e54b59 100644 (file)
@@ -170,10 +170,15 @@ get_mra(
                return SLAPD_DISCONNECT;
        }
 
+#ifndef SLAP_X_MRA_MATCH_DNATTRS
+       /*
+        * Let's try to implement it
+        */
        if( ma->ma_dnattrs ) {
                *text = "matching with \":dn\" not supported";
                return LDAP_INAPPROPRIATE_MATCHING;
        }
+#endif /* !SLAP_X_MRA_MATCH_DNATTRS */
 
        if( type.bv_val != NULL ) {
                rc = slap_bv2ad( &type, &ma->ma_desc, text );
@@ -182,9 +187,11 @@ get_mra(
                        return rc;
                }
 
+#ifndef SLAP_X_MRA_MATCH_DNATTRS
        } else {
                *text = "matching without attribute description rule not supported";
                return LDAP_INAPPROPRIATE_MATCHING;
+#endif /* !SLAP_X_MRA_MATCH_DNATTRS */
        }
 
        if( ma->ma_rule_text.bv_val != NULL ) {
@@ -196,6 +203,40 @@ get_mra(
                }
        }
 
+       /*
+        * FIXME: is it correct that ma->ma_rule_text, if present,
+        * is looked-up, checked, and then replaced by the sat_equality
+        * of the given attribute?  I'd rather do smtg like use
+        * the attribute's equality rule only if no matching rule
+        * was given, otherwise I don't see any extension ...
+        */
+
+#if 1
+       if ( ma->ma_rule == NULL ) {
+#ifdef SLAP_X_MRA_MATCH_DNATTRS
+               /*
+                * Need either type or rule ...
+                */
+               if ( ma->ma_desc == NULL ) {
+                       mra_free( ma, 1 );
+                       *text = "matching rule not recognized";
+                       return LDAP_INAPPROPRIATE_MATCHING;
+               }
+#endif /* !SLAP_X_MRA_MATCH_DNATTRS */
+
+               if ( ma->ma_desc->ad_type->sat_equality != NULL &&
+                       ma->ma_desc->ad_type->sat_equality->smr_usage & SLAP_MR_EXT )
+               {
+                       /* no matching rule was provided, use the attribute's
+                          equality rule if it supports extensible matching. */
+                       ma->ma_rule = ma->ma_desc->ad_type->sat_equality;
+
+               } else {
+                       mra_free( ma, 1 );
+                       return LDAP_INAPPROPRIATE_MATCHING;
+               }
+       }
+#else
        if( ma->ma_desc != NULL &&
                ma->ma_desc->ad_type->sat_equality != NULL &&
                ma->ma_desc->ad_type->sat_equality->smr_usage & SLAP_MR_EXT )
@@ -208,24 +249,38 @@ get_mra(
                mra_free( ma, 1 );
                return LDAP_INAPPROPRIATE_MATCHING;
        }
+#endif
 
-       /* check to see if the matching rule is appropriate for
-          the syntax of the attribute.  This check will need
-          to be extended to support other kinds of extensible
-          matching rules */
-       if( strcmp( ma->ma_rule->smr_syntax->ssyn_oid,
-               ma->ma_desc->ad_type->sat_syntax->ssyn_oid ) != 0 )
-       {
-               mra_free( ma, 1 );
-               return LDAP_INAPPROPRIATE_MATCHING;
-       }
+#ifdef SLAP_X_MRA_MATCH_DNATTRS
+       if ( ma->ma_desc != NULL ) {
+#endif /* SLAP_X_MRA_MATCH_DNATTRS */
+               /* check to see if the matching rule is appropriate for
+                 the syntax of the attribute.  This check will need
+                  to be extended to support other kinds of extensible
+                  matching rules */
+               if( strcmp( ma->ma_rule->smr_syntax->ssyn_oid,
+                       ma->ma_desc->ad_type->sat_syntax->ssyn_oid ) != 0 )
+               {
+                       mra_free( ma, 1 );
+                       return LDAP_INAPPROPRIATE_MATCHING;
+               }
 
-       /*
-        * OK, if no matching rule, normalize for equality, otherwise
-        * normalize for the matching rule.
-        */
-       rc = value_validate_normalize( ma->ma_desc, SLAP_MR_EQUALITY,
-               &value, &ma->ma_value, text );
+               /*
+                * OK, if no matching rule, normalize for equality, otherwise
+                * normalize for the matching rule.
+                */
+               rc = value_validate_normalize( ma->ma_desc, SLAP_MR_EQUALITY,
+                       &value, &ma->ma_value, text );
+#ifdef SLAP_X_MRA_MATCH_DNATTRS
+       } else {
+               /*
+                * Need to normalize, but how?
+                */
+               ma->ma_value = value;
+               rc = value_validate( ma->ma_rule, &ma->ma_value, text );
+
+       }
+#endif /* SLAP_X_MRA_MATCH_DNATTRS */
 
        if( rc != LDAP_SUCCESS ) {
                mra_free( ma, 1 );
index 95720738d06d439a1ecb2cad4fa6906c52148f96..a3bde2cedc39270bedcdad24259878f310fe24eb 100644 (file)
@@ -395,6 +395,13 @@ LDAP_SLAPD_F (int) dnX509normalize LDAP_P(( void *x509_name, struct berval *out
 
 LDAP_SLAPD_F (int) dnX509peerNormalize LDAP_P(( void *ssl, struct berval *dn ));
 
+LDAP_SLAPD_F (int) dnPrettyNormalDN LDAP_P(( Syntax *syntax, struct berval *val, LDAPDN **dn, int flags ));
+#define dnPrettyDN(syntax, val, dn) \
+       dnPrettyNormalDN((syntax),(val),(dn), SLAP_LDAPDN_PRETTY)
+#define dnNormalDN(syntax, val, dn) \
+       dnPrettyNormalDN((syntax),(val),(dn), 0)
+
+
 /*
  * entry.c
  */
@@ -451,17 +458,31 @@ LDAP_SLAPD_F (int) get_filter LDAP_P((
 LDAP_SLAPD_F (void) filter_free LDAP_P(( Filter *f ));
 LDAP_SLAPD_F (void) filter2bv LDAP_P(( Filter *f, struct berval *bv ));
 
-LDAP_SLAPD_F (int) get_vrFilter( Connection *conn, BerElement *ber,
+LDAP_SLAPD_F (int) get_vrFilter LDAP_P(( Connection *conn, BerElement *ber,
        ValuesReturnFilter **f,
-       const char **text );
+       const char **text ));
 
-LDAP_SLAPD_F (void) vrFilter_free( ValuesReturnFilter *f );
-LDAP_SLAPD_F (void) vrFilter2bv( ValuesReturnFilter *f, struct berval *fstr );
+LDAP_SLAPD_F (void) vrFilter_free LDAP_P(( ValuesReturnFilter *f ));
+LDAP_SLAPD_F (void) vrFilter2bv LDAP_P(( ValuesReturnFilter *f, struct berval *fstr ));
 
+/*
+ * define to honor hasSubordinates operational attribute in search filters
+ */
+#define SLAP_X_FILTER_HASSUBORDINATES
+
+#ifdef SLAP_X_FILTER_HASSUBORDINATES
+LDAP_SLAPD_F (int) filter_has_subordinates LDAP_P(( Filter *filter ));
+#endif /* SLAP_X_FILTER_HASSUBORDINATES */
 
 /*
  * filterentry.c
  */
+
+/*
+ * define to enable dn components match in extended filter matching
+ */
+#define SLAP_X_MRA_MATCH_DNATTRS
+
 LDAP_SLAPD_F (int) test_filter LDAP_P((
        Backend *be, Connection *conn, Operation *op,
        Entry *e, Filter *f ));
index bdba964126fff98737750547d8e89015d2037d8c..074b1c6b6d9ea26fee4d1d4768a5a9d270ec60dd 100644 (file)
@@ -770,6 +770,7 @@ send_search_entry(
                }
                e_flags = ch_calloc ( 1, i * sizeof(char *) + k );
                a_flags = (char *)(e_flags + i);
+               memset( a_flags, 0, k );
                for ( a = e->e_attrs, i=0; a != NULL; a = a->a_next, i++ ) {
                        for ( j = 0; a->a_vals[j].bv_val != NULL; j++ );
                        e_flags[i] = a_flags;
@@ -909,25 +910,45 @@ send_search_entry(
                }
        }
 
-       /* free e_flags */
-       if ( e_flags ) {
-               free( e_flags );
-               e_flags = NULL;
-       }
-
        /* eventually will loop through generated operational attributes */
        /* only have subschemaSubentry implemented */
        aa = backend_operational( be, conn, op, e, attrs, opattrs );
 
        if ( aa != NULL && op->vrFilter != NULL ) {
                int k = 0;
-               char *a_flags;
+               char *a_flags, **tmp;
 
                for ( a = aa, i=0; a != NULL; a = a->a_next, i++ ) {
                        for ( j = 0; a->a_vals[j].bv_val != NULL; j++ ) k++;
                }
-               e_flags = ch_calloc ( 1, i * sizeof(char *) + k );
+               /*
+                * Reuse previous memory - we likely need less space
+                * for operational attributes
+                */
+               tmp = ch_realloc ( e_flags, i * sizeof(char *) + k );
+               if ( tmp == NULL ) {
+#ifdef NEW_LOGGING
+                       LDAP_LOG( OPERATION, ERR, 
+                               "send_search_entry: conn %lu "
+                               "not enough memory "
+                               "for matched values filtering\n", 
+                               conn ? conn->c_connid : 0, 0, 0);
+#else
+                       Debug( LDAP_DEBUG_ANY,
+                               "send_search_entry: conn %lu "
+                               "not enough memory "
+                               "for matched values filtering\n",
+                               conn ? conn->c_connid : 0, 0, 0 );
+#endif
+                       ber_free( ber, 1 );
+
+                       send_ldap_result( conn, op, LDAP_NO_MEMORY,
+                               NULL, NULL, NULL, NULL );
+                       goto error_return;
+               }
+               e_flags = tmp;
                a_flags = (char *)(e_flags + i);
+               memset( a_flags, 0, k );
                for ( a = aa, i=0; a != NULL; a = a->a_next, i++ ) {
                        for ( j = 0; a->a_vals[j].bv_val != NULL; j++ );
                        e_flags[i] = a_flags;
@@ -942,7 +963,7 @@ send_search_entry(
                                "matched values filtering failed\n", 
                                conn ? conn->c_connid : 0, 0, 0);
 #else
-               Debug( LDAP_DEBUG_ANY,
+                       Debug( LDAP_DEBUG_ANY,
                                "matched values filtering failed\n", 0, 0, 0 );
 #endif
                        ber_free( ber, 1 );
index 92ac6fdd8f73b364f0ac344559ecc078b90e4a37..f23101680e2040654629546975f376d5a93865f3 100644 (file)
@@ -1683,6 +1683,12 @@ enum {
 };
 #endif /* SLAPD_MONITOR */
 
+/*
+ * Better know these all around slapd
+ */
+#define SLAP_LDAPDN_PRETTY 0x1
+#define SLAP_LDAPDN_MAXLEN 8192
+
 LDAP_END_DECL
 
 #include "proto-slap.h"