From fbc11bd16a6a6ab4016495c73dd458b1d89e7ed5 Mon Sep 17 00:00:00 2001 From: Pierangelo Masarati Date: Thu, 29 Aug 2002 10:55:48 +0000 Subject: [PATCH] - added the capability to filter based on hasSubordinate attribute 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 --- servers/slapd/back-bdb/search.c | 59 +++++++++- servers/slapd/back-ldbm/search.c | 56 ++++++++- servers/slapd/back-sql/back-sql.h | 5 +- servers/slapd/back-sql/entry-id.c | 14 +-- servers/slapd/back-sql/init.c | 12 ++ servers/slapd/back-sql/modify.c | 18 +-- servers/slapd/back-sql/other.c | 9 +- servers/slapd/back-sql/schema-map.c | 55 +++------ servers/slapd/back-sql/schema-map.h | 7 +- servers/slapd/back-sql/search.c | 162 ++++++++++++++++++++++---- servers/slapd/back-sql/util.c | 2 +- servers/slapd/back-sql/util.h | 6 +- servers/slapd/dn.c | 58 +++++++++- servers/slapd/filter.c | 143 ++++++++++++++++++++++- servers/slapd/filterentry.c | 172 +++++++++++++++++++++++++--- servers/slapd/matchedValues.c | 41 ++++++- servers/slapd/mra.c | 87 +++++++++++--- servers/slapd/proto-slap.h | 29 ++++- servers/slapd/result.c | 39 +++++-- servers/slapd/slap.h | 6 + 20 files changed, 831 insertions(+), 149 deletions(-) diff --git a/servers/slapd/back-bdb/search.c b/servers/slapd/back-bdb/search.c index 462d8ec027..7220226830 100644 --- a/servers/slapd/back-bdb/search.c +++ b/servers/slapd/back-bdb/search.c @@ -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; } + diff --git a/servers/slapd/back-ldbm/search.c b/servers/slapd/back-ldbm/search.c index 87f4b9278b..eac5f831e9 100644 --- a/servers/slapd/back-ldbm/search.c +++ b/servers/slapd/back-ldbm/search.c @@ -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) { diff --git a/servers/slapd/back-sql/back-sql.h b/servers/slapd/back-sql/back-sql.h index a456351479..2fb5508670 100644 --- a/servers/slapd/back-sql/back-sql.h +++ b/servers/slapd/back-sql/back-sql.h @@ -49,6 +49,10 @@ * 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; diff --git a/servers/slapd/back-sql/entry-id.c b/servers/slapd/back-sql/entry-id.c index 90564463ac..e1a45c7f1e 100644 --- a/servers/slapd/back-sql/entry-id.c +++ b/servers/slapd/back-sql/entry-id.c @@ -14,6 +14,7 @@ #include #include #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 ); diff --git a/servers/slapd/back-sql/init.c b/servers/slapd/back-sql/init.c index 3d4e30242f..301646ccda 100644 --- a/servers/slapd/back-sql/init.c +++ b/servers/slapd/back-sql/init.c @@ -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; diff --git a/servers/slapd/back-sql/modify.c b/servers/slapd/back-sql/modify.c index 6966c2c6fd..bff2f9f8ed 100644 --- a/servers/slapd/back-sql/modify.c +++ b/servers/slapd/back-sql/modify.c @@ -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 ); diff --git a/servers/slapd/back-sql/other.c b/servers/slapd/back-sql/other.c index 1629a086e3..b2638960f4 100644 --- a/servers/slapd/back-sql/other.c +++ b/servers/slapd/back-sql/other.c @@ -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; diff --git a/servers/slapd/back-sql/schema-map.c b/servers/slapd/back-sql/schema-map.c index eaa63ab692..d3a7956dcd 100644 --- a/servers/slapd/back-sql/schema-map.c +++ b/servers/slapd/back-sql/schema-map.c @@ -15,23 +15,13 @@ #include #include #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 ) { diff --git a/servers/slapd/back-sql/schema-map.h b/servers/slapd/back-sql/schema-map.h index 7c7f0cf39e..5467523fad 100644 --- a/servers/slapd/back-sql/schema-map.h +++ b/servers/slapd/back-sql/schema-map.h @@ -11,15 +11,12 @@ */ 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 */ diff --git a/servers/slapd/back-sql/search.c b/servers/slapd/back-sql/search.c index ffd1856fd8..ed48753a08 100644 --- a/servers/slapd/back-sql/search.c +++ b/servers/slapd/back-sql/search.c @@ -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++; diff --git a/servers/slapd/back-sql/util.c b/servers/slapd/back-sql/util.c index ffd10efc95..402d36fbab 100644 --- a/servers/slapd/back-sql/util.c +++ b/servers/slapd/back-sql/util.c @@ -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 ); diff --git a/servers/slapd/back-sql/util.h b/servers/slapd/back-sql/util.h index a9f1042d03..06e38d5824 100644 --- a/servers/slapd/back-sql/util.h +++ b/servers/slapd/back-sql/util.h @@ -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, diff --git a/servers/slapd/dn.c b/servers/slapd/dn.c index 9194a9cb53..0084a7c80a 100644 --- a/servers/slapd/dn.c +++ b/servers/slapd/dn.c @@ -22,10 +22,6 @@ 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 */ diff --git a/servers/slapd/filter.c b/servers/slapd/filter.c index 69a26bf34b..608b732c84 100644 --- a/servers/slapd/filter.c +++ b/servers/slapd/filter.c @@ -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 */ + diff --git a/servers/slapd/filterentry.c b/servers/slapd/filterentry.c index 672915cb8c..111e258e61 100644 --- a/servers/slapd/filterentry.c +++ b/servers/slapd/filterentry.c @@ -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; } diff --git a/servers/slapd/matchedValues.c b/servers/slapd/matchedValues.c index 170977d0ee..51c223e97d 100644 --- a/servers/slapd/matchedValues.c +++ b/servers/slapd/matchedValues.c @@ -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 ) { diff --git a/servers/slapd/mra.c b/servers/slapd/mra.c index eca939b026..d4e331f194 100644 --- a/servers/slapd/mra.c +++ b/servers/slapd/mra.c @@ -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 ); diff --git a/servers/slapd/proto-slap.h b/servers/slapd/proto-slap.h index 95720738d0..a3bde2cedc 100644 --- a/servers/slapd/proto-slap.h +++ b/servers/slapd/proto-slap.h @@ -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 )); diff --git a/servers/slapd/result.c b/servers/slapd/result.c index bdba964126..074b1c6b6d 100644 --- a/servers/slapd/result.c +++ b/servers/slapd/result.c @@ -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 ); diff --git a/servers/slapd/slap.h b/servers/slapd/slap.h index 92ac6fdd8f..f23101680e 100644 --- a/servers/slapd/slap.h +++ b/servers/slapd/slap.h @@ -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" -- 2.39.5