From: Pierangelo Masarati Date: Sat, 2 Oct 2004 17:33:32 +0000 (+0000) Subject: add (and honor) a (configurable) baseObject to workaround ldap_entries view for RDBMS... X-Git-Tag: OPENLDAP_REL_ENG_2_3_0ALPHA~470 X-Git-Url: https://git.sur5r.net/?a=commitdiff_plain;h=796dce8657e7c1df68daa975b3da256272ad1f4a;p=openldap add (and honor) a (configurable) baseObject to workaround ldap_entries view for RDBMSes that do not support UNION in views --- diff --git a/doc/man/man5/slapd-sql.5 b/doc/man/man5/slapd-sql.5 index 7c5e33e5d6..e49b7c75f9 100644 --- a/doc/man/man5/slapd-sql.5 +++ b/doc/man/man5/slapd-sql.5 @@ -107,7 +107,7 @@ Note that the parameter number and order must not be changed. Specifies the name of a function that converts a given value to uppercase. This is used for CIS matching when the RDBMS is case sensitive. .TP -.B upper_needs_cast { yes | no } +.B upper_needs_cast { NO | yes} Set this directive to .B yes if @@ -151,7 +151,7 @@ This is .B experimental and may change in future releases. .TP -.B has_ldapinfo_dn_ru { yes | no } +.B has_ldapinfo_dn_ru { NO | yes } Explicitly inform the backend whether the SQL schema has dn_ru column (dn in reverse uppercased form) or not. Overrides automatic check (required by PostgreSQL/unixODBC). @@ -160,7 +160,7 @@ This is and may change in future releases. .TP -.B fail_if_no_mapping { yes | no } +.B fail_if_no_mapping { NO | yes } When set to .B yes it forces @@ -181,6 +181,37 @@ This is .B experimental and may change in future releases. +.TP +.B allow_orphans { NO | yes } +When set to +.B yes +orphaned entries (i.e. without the parent entry in the database) +can be added. This option should be used with care, possibly +in conjunction with some special rule on the RDBMS side that +dynamically creates the missing parent. + +.TP +.B baseObject [filename] +Instructs the database to create and manage an in-memory baseObject +entry instead of looking for one in the RDBMS. +If the (optional) +.B filename +argument is given, the entry is read from file +.B filename +in +.BR LDIF (5) +form. +This is particularly useful when +.B ldap_entries +information is stored in a view rather than in a table, and +.B union +is not supported for views, so that the view can only specify +one rule to compute the entry structure for one objectClass. +This topic is discussed further in section "METAINFORMATION USED". +This is +.B experimental +and may change in future releases. + .SH METAINFORMATION USED .LP Almost everything mentioned later is illustrated in examples located @@ -369,13 +400,26 @@ like this (by Robin Elfrink): .LP .nf CREATE VIEW ldap_entries (id, dn, oc_map_id, parent, keyval) - AS SELECT (1000000000+userid), + AS + SELECT 0, UPPER('o=MyCompany,c=NL'), + 3, 0, 'baseObject' FROM unixusers WHERE userid='root' UNION + SELECT (1000000000+userid), UPPER(CONCAT(CONCAT('cn=',gecos),',o=MyCompany,c=NL')), 1, 0, userid FROM unixusers UNION SELECT (2000000000+groupnummer), UPPER(CONCAT(CONCAT('cn=',groupnaam),',o=MyCompany,c=NL')), 2, 0, groupnummer FROM groups; .fi + +.LP +If your RDBMS does not support +.B unions +in views, only one objectClass can be mapped in +.BR ldap_entries , +and the baseObject cannot be created; in this case, see the +.B baseObject +directive for a possible workaround. + .LP .SH Typical SQL backend operation Having metainformation loaded, the SQL backend uses these tables to diff --git a/servers/slapd/back-sql/back-sql.h b/servers/slapd/back-sql/back-sql.h index 4e3803c9e4..fa74a36d2a 100644 --- a/servers/slapd/back-sql/back-sql.h +++ b/servers/slapd/back-sql/back-sql.h @@ -357,6 +357,19 @@ typedef struct { (!BER_BVISNULL( &(si)->sql_upper_func )) #define BACKSQL_ALLOW_ORPHANS(si) \ ((si)->sql_flags & BSQLF_ALLOW_ORPHANS) + + Entry *sql_baseObject; +#ifdef BACKSQL_ARBITRARY_KEY +#define BACKSQL_BASEOBJECT_IDSTR "baseObject" +#define BACKSQL_BASEOBJECT_KEYVAL BACKSQL_BASEOBJECT_IDSTR +#define BACKSQL_IS_BASEOBJECT_ID(id) (bvmatch((id), &backsql_baseObject_bv) +#else /* ! BACKSQL_ARBITRARY_KEY */ +#define BACKSQL_BASEOBJECT_ID 0 +#define BACKSQL_BASEOBJECT_IDSTR "0" +#define BACKSQL_BASEOBJECT_KEYVAL 0 +#define BACKSQL_IS_BASEOBJECT_ID(id) (*(id) == BACKSQL_BASEOBJECT_ID) +#endif /* ! BACKSQL_ARBITRARY_KEY */ +#define BACKSQL_BASEOBJECT_OC 0 Avlnode *sql_db_conns; Avlnode *sql_oc_by_oc; diff --git a/servers/slapd/back-sql/bind.c b/servers/slapd/back-sql/bind.c index 461ef8d18c..836b865fa4 100644 --- a/servers/slapd/back-sql/bind.c +++ b/servers/slapd/back-sql/bind.c @@ -73,7 +73,7 @@ backsql_bind( Operation *op, SlapReply *rs ) return 1; } - dn = op->o_req_dn; + dn = op->o_req_ndn; if ( backsql_api_dn2odbc( op, rs, &dn ) ) { Debug( LDAP_DEBUG_TRACE, "backsql_search(): " "backsql_api_dn2odbc failed\n", diff --git a/servers/slapd/back-sql/compare.c b/servers/slapd/back-sql/compare.c index 5296f46bed..ab2a2d0bda 100644 --- a/servers/slapd/back-sql/compare.c +++ b/servers/slapd/back-sql/compare.c @@ -58,7 +58,7 @@ backsql_compare( Operation *op, SlapReply *rs ) goto return_results; } - dn = op->o_req_dn; + dn = op->o_req_ndn; if ( backsql_api_dn2odbc( op, rs, &dn ) ) { Debug( LDAP_DEBUG_TRACE, "backsql_search(): " "backsql_api_dn2odbc failed\n", diff --git a/servers/slapd/back-sql/config.c b/servers/slapd/back-sql/config.c index 6fe8a91207..afc0dcf09a 100644 --- a/servers/slapd/back-sql/config.c +++ b/servers/slapd/back-sql/config.c @@ -27,8 +27,20 @@ #include #include "slap.h" +#include "ldif.h" #include "proto-sql.h" +static int +create_baseObject( + BackendDB *be, + const char *fname, + int lineno ); + +static int +read_baseObject( + BackendDB *be, + const char *fname ); + int backsql_db_config( BackendDB *be, @@ -389,6 +401,39 @@ backsql_db_config( "allow_orphans=%s\n", BACKSQL_ALLOW_ORPHANS( bi ) ? "yes" : "no", 0, 0 ); + } else if ( !strcasecmp( argv[ 0 ], "baseobject" ) ) { + if ( be->be_suffix == NULL ) { + Debug( LDAP_DEBUG_TRACE, + "<==backsql_db_config (%s line %d): : " + "must be defined after \"suffix\"\n", + fname, lineno, 0 ); + return 1; + } + + if ( bi->sql_baseObject ) { + Debug( LDAP_DEBUG_TRACE, + "<==backsql_db_config (%s line %d): : " + "\"baseObject\" already provided (will be overwritten)\n", + fname, lineno, 0 ); + entry_free( bi->sql_baseObject ); + } + + switch ( argc ) { + case 1: + return create_baseObject( be, fname, lineno ); + + case 2: + return read_baseObject( be, argv[ 1 ] ); + + default: + Debug( LDAP_DEBUG_TRACE, + "<==backsql_db_config (%s line %d): " + "trailing values " + "in \"baseObject\" directive?\n", + fname, lineno, 0 ); + return 1; + } + } else if ( !strcasecmp( argv[ 0 ], "sqllayer") ) { if ( backsql_api_config( bi, argv[ 1 ] ) ) { Debug( LDAP_DEBUG_TRACE, @@ -405,5 +450,207 @@ backsql_db_config( return 0; } +/* + * Read the entries specified in fname and merge the attributes + * to the user defined baseObject entry. Note that if we find any errors + * what so ever, we will discard the entire entries, print an + * error message and return. + */ +static int +read_baseObject( + BackendDB *be, + const char *fname ) +{ + backsql_info *bi = (backsql_info *)be->be_private; + FILE *fp; + int rc = 0, lineno = 0, lmax = 0; + char *buf = NULL; + + assert( fname ); + + fp = fopen( fname, "r" ); + if ( fp == NULL ) { + Debug( LDAP_DEBUG_ANY, + "could not open back-sql baseObject attr file \"%s\" - absolute path?\n", + fname, 0, 0 ); + perror( fname ); + return LDAP_OTHER; + } + + bi->sql_baseObject = (Entry *) SLAP_CALLOC( 1, sizeof(Entry) ); + if ( bi->sql_baseObject == NULL ) { + Debug( LDAP_DEBUG_ANY, + "read_baseObject_file: SLAP_CALLOC failed", 0, 0, 0 ); + fclose( fp ); + return LDAP_NO_MEMORY; + } + bi->sql_baseObject->e_name = be->be_suffix[0]; + bi->sql_baseObject->e_nname = be->be_nsuffix[0]; + bi->sql_baseObject->e_attrs = NULL; + + while ( ldif_read_record( fp, &lineno, &buf, &lmax ) ) { + Entry *e = str2entry( buf ); + Attribute *a; + + if( e == NULL ) { + fprintf( stderr, "back-sql baseObject: could not parse entry (line=%d)\n", + lineno ); + rc = LDAP_OTHER; + break; + } + + /* make sure the DN is the database's suffix */ + if ( !be_issuffix( be, &e->e_nname ) ) { + fprintf( stderr, + "back-sql: invalid baseObject - dn=\"%s\" (line=%d)\n", + e->e_dn, lineno ); + entry_free( e ); + rc = EXIT_FAILURE; + break; + } + + /* + * we found a valid entry, so walk thru all the attributes in the + * entry, and add each attribute type and description to baseObject + */ + for ( a = e->e_attrs; a != NULL; a = a->a_next ) { + if ( attr_merge( bi->sql_baseObject, a->a_desc, a->a_vals, + ( a->a_nvals == a->a_vals ) ? NULL : a->a_nvals ) ) + { + rc = LDAP_OTHER; + break; + } + } + + entry_free( e ); + if ( rc ) { + break; + } + } + + if ( rc ) { + entry_free( bi->sql_baseObject ); + bi->sql_baseObject = NULL; + } + + ch_free( buf ); + + fclose( fp ); + + Debug( LDAP_DEBUG_CONFIG, "back-sql baseObject file \"%s\" read.\n", fname, 0, 0 ); + + return rc; +} + +static int +create_baseObject( + BackendDB *be, + const char *fname, + int lineno ) +{ + backsql_info *bi = (backsql_info *)be->be_private; + LDAPRDN rdn; + char *p; + int rc, iAVA; + char buf[1024]; + + snprintf( buf, sizeof(buf), + "dn: %s\n" + "objectClass: extensibleObject\n" + "description: builtin baseObject for back-sql\n" + "description: all entries mapped in the \"ldap_entries\" table\n" + "description: must have \"" BACKSQL_BASEOBJECT_IDSTR "\" " + "in the \"parent\" column", + be->be_suffix[0].bv_val ); + + bi->sql_baseObject = str2entry( buf ); + if ( bi->sql_baseObject == NULL ) { + Debug( LDAP_DEBUG_TRACE, + "<==backsql_db_config (%s line %d): " + "unable to parse baseObject entry\n", + fname, lineno, 0 ); + return 1; + } + + if ( BER_BVISEMPTY( &be->be_suffix[ 0 ] ) ) { + return 0; + } + + rc = ldap_bv2rdn( &be->be_suffix[ 0 ], &rdn, (char **) &p, LDAP_DN_FORMAT_LDAP ); + if ( rc != LDAP_SUCCESS ) { + snprintf( buf, sizeof(buf), + "unable to extract RDN from baseObject DN \"%s\" (%d: %s)", + be->be_suffix[ 0 ].bv_val, rc, ldap_err2string( rc ) ); + Debug( LDAP_DEBUG_TRACE, + "<==backsql_db_config (%s line %d): %s\n", + fname, lineno, buf ); + return 1; + } + + for ( iAVA = 0; rdn[ iAVA ]; iAVA++ ) { + LDAPAVA *ava = rdn[ iAVA ]; + AttributeDescription *ad = NULL; + slap_syntax_transform_func *transf = NULL; + struct berval bv = BER_BVNULL; + const char *text = NULL; + + assert( ava ); + + rc = slap_bv2ad( &ava->la_attr, &ad, &text ); + if ( rc != LDAP_SUCCESS ) { + snprintf( buf, sizeof(buf), + "AttributeDescription of naming " + "attribute #%d from baseObject " + "DN \"%s\": %d: %s", + iAVA, be->be_suffix[ 0 ].bv_val, + rc, ldap_err2string( rc ) ); + Debug( LDAP_DEBUG_TRACE, + "<==backsql_db_config (%s line %d): %s\n", + fname, lineno, buf ); + return 1; + } + + transf = ad->ad_type->sat_syntax->ssyn_pretty; + if ( transf ) { + /* + * transform value by pretty function + * if value is empty, use empty_bv + */ + rc = ( *transf )( ad->ad_type->sat_syntax, + ava->la_value.bv_len + ? &ava->la_value + : (struct berval *) &slap_empty_bv, + &bv, NULL ); + + if ( rc != LDAP_SUCCESS ) { + snprintf( buf, sizeof(buf), + "prettying of attribute #%d from baseObject " + "DN \"%s\" failed: %d: %s", + iAVA, be->be_suffix[ 0 ].bv_val, + rc, ldap_err2string( rc ) ); + Debug( LDAP_DEBUG_TRACE, + "<==backsql_db_config (%s line %d): %s\n", + fname, lineno, buf ); + return 1; + } + } + + if ( !BER_BVISNULL( &bv ) ) { + if ( ava->la_flags & LDAP_AVA_FREE_VALUE ) { + ber_memfree( ava->la_value.bv_val ); + } + ava->la_value = bv; + ava->la_flags |= LDAP_AVA_FREE_VALUE; + } + + attr_merge_normalize_one( bi->sql_baseObject, + ad, &ava->la_value, NULL ); + } + + ldap_rdnfree( rdn ); + + return 0; +} + #endif /* SLAPD_SQL */ diff --git a/servers/slapd/back-sql/entry-id.c b/servers/slapd/back-sql/entry-id.c index 35108c34cb..13d9840dbb 100644 --- a/servers/slapd/back-sql/entry-id.c +++ b/servers/slapd/back-sql/entry-id.c @@ -29,6 +29,10 @@ #include "slap.h" #include "proto-sql.h" +#ifdef BACKSQL_ARBITRARY_KEY +struct berval backsql_baseObject_bv = BER_BVC( BACKSQL_BASEOBJECT_IDSTR ); +#endif /* BACKSQL_ARBITRARY_KEY */ + backsql_entryID * backsql_free_entryID( backsql_entryID *id, int freeit ) { @@ -40,15 +44,18 @@ backsql_free_entryID( backsql_entryID *id, int freeit ) if ( id->eid_dn.bv_val != NULL ) { free( id->eid_dn.bv_val ); + BER_BVZERO( &id->eid_dn ); } #ifdef BACKSQL_ARBITRARY_KEY if ( id->eid_id.bv_val ) { free( id->eid_id.bv_val ); + BER_BVZERO( &id->eid_id ); } if ( id->eid_keyval.bv_val ) { free( id->eid_keyval.bv_val ); + BER_BVZERO( &id->eid_keyval ); } #endif /* BACKSQL_ARBITRARY_KEY */ @@ -93,9 +100,29 @@ backsql_dn2id( dn->bv_val, dn->bv_len, BACKSQL_MAX_DN_LEN ); return LDAP_OTHER; } + + /* return baseObject if available and matches */ + if ( bi->sql_baseObject != NULL && bvmatch( dn, &bi->sql_baseObject->e_nname ) ) { + if ( id != NULL ) { +#ifdef BACKSQL_ARBITRARY_KEY + ber_dupbv( &id->eid_id, &backsql_baseObject_bv ); + ber_dupbv( &id->eid_keyval, &backsql_baseObject_bv ); +#else /* ! BACKSQL_ARBITRARY_KEY */ + id->eid_id = BACKSQL_BASEOBJECT_ID; + id->eid_keyval = BACKSQL_BASEOBJECT_KEYVAL; +#endif /* ! BACKSQL_ARBITRARY_KEY */ + id->eid_oc_id = BACKSQL_BASEOBJECT_OC; + + ber_dupbv( &id->eid_dn, &bi->sql_baseObject->e_nname ); + + id->eid_next = NULL; + } + + return LDAP_SUCCESS; + } /* begin TimesTen */ - Debug(LDAP_DEBUG_TRACE, "id_query \"%s\"\n", bi->sql_id_query, 0, 0); + Debug( LDAP_DEBUG_TRACE, "id_query \"%s\"\n", bi->sql_id_query, 0, 0 ); assert( bi->sql_id_query ); rc = backsql_Prepare( dbh, &sth, bi->sql_id_query, 0 ); if ( rc != SQL_SUCCESS ) { @@ -405,6 +432,7 @@ backsql_get_attr_vals( void *v_at, void *v_bsi ) int backsql_id2entry( backsql_srch_info *bsi, backsql_entryID *eid ) { + backsql_info *bi = (backsql_info *)bsi->bsi_op->o_bd->be_private; int i; int rc; AttributeDescription *ad_oc = slap_schema.si_ad_objectClass; @@ -415,6 +443,19 @@ backsql_id2entry( backsql_srch_info *bsi, backsql_entryID *eid ) memset( bsi->bsi_e, 0, sizeof( Entry ) ); + if ( bi->sql_baseObject && BACKSQL_IS_BASEOBJECT_ID( &eid->eid_id ) ) { + Entry *e; + + e = entry_dup( bi->sql_baseObject ); + if ( e == NULL ) { + return LDAP_NO_MEMORY; + } + + *bsi->bsi_e = *e; + free( e ); + goto done; + } + rc = dnPrettyNormal( NULL, &eid->eid_dn, &bsi->bsi_e->e_name, &bsi->bsi_e->e_nname, bsi->bsi_op->o_tmpmemctx ); @@ -528,6 +569,7 @@ next:; } } +done:; Debug( LDAP_DEBUG_TRACE, "<==backsql_id2entry()\n", 0, 0, 0 ); return LDAP_SUCCESS; diff --git a/servers/slapd/back-sql/init.c b/servers/slapd/back-sql/init.c index 45669f7236..e4eb0c5fcc 100644 --- a/servers/slapd/back-sql/init.c +++ b/servers/slapd/back-sql/init.c @@ -163,6 +163,11 @@ backsql_db_destroy( free( bi->sql_delentry_query ); free( bi->sql_delobjclasses_query ); free( bi->sql_delreferrals_query ); + + if ( bi->sql_baseObject ) { + entry_free( bi->sql_baseObject ); + } + free( bi ); Debug( LDAP_DEBUG_TRACE, "<==backsql_db_destroy()\n", 0, 0, 0 ); diff --git a/servers/slapd/back-sql/proto-sql.h b/servers/slapd/back-sql/proto-sql.h index 2f623900c4..a24b902e42 100644 --- a/servers/slapd/back-sql/proto-sql.h +++ b/servers/slapd/back-sql/proto-sql.h @@ -105,6 +105,9 @@ int backsql_api_odbc2dn( Operation *op, SlapReply *rs, struct berval *dn ); /* * entry-id.c */ +#ifdef BACKSQL_ARBITRARY_KEY +extern struct berval backsql_baseObject_bv; +#endif /* BACKSQL_ARBITRARY_KEY */ /* stores in *id the ID in table ldap_entries corresponding to DN, if any */ int backsql_dn2id( backsql_info *bi, backsql_entryID *id, diff --git a/servers/slapd/back-sql/search.c b/servers/slapd/back-sql/search.c index f87da1db5c..8e4f594795 100644 --- a/servers/slapd/back-sql/search.c +++ b/servers/slapd/back-sql/search.c @@ -184,6 +184,8 @@ backsql_init_search( bsi->bsi_filter_oc = NULL; if ( get_base_id ) { + assert( op->o_bd->be_private ); + rc = backsql_dn2id( (backsql_info *)op->o_bd->be_private, &bsi->bsi_base_id, dbh, base ); } @@ -1393,8 +1395,9 @@ backsql_oc_get_candidates( void *v_oc, void *v_bsi ) backsql_BindRowAsStrings( sth, &row ); rc = SQLFetch( sth ); for ( ; BACKSQL_SUCCESS( rc ); rc = SQLFetch( sth ) ) { - struct berval dn; + struct berval dn, ndn; backsql_entryID *c_id = NULL; + int ret; ber_str2bv( row.cols[ 3 ], 0, 0, &dn ); @@ -1402,6 +1405,20 @@ backsql_oc_get_candidates( void *v_oc, void *v_bsi ) continue; } + ret = dnNormalize( 0, NULL, NULL, &dn, &ndn, NULL ); + if ( dn.bv_val != row.cols[ 3 ] ) { + free( dn.bv_val ); + } + + if ( ret != LDAP_SUCCESS ) { + continue; + } + + if ( bi->sql_baseObject && bvmatch( &ndn, &bi->sql_baseObject->e_nname ) ) { + free( ndn.bv_val ); + continue; + } + c_id = (backsql_entryID *)ch_calloc( 1, sizeof( backsql_entryID ) ); #ifdef BACKSQL_ARBITRARY_KEY @@ -1413,10 +1430,10 @@ backsql_oc_get_candidates( void *v_oc, void *v_bsi ) #endif /* ! BACKSQL_ARBITRARY_KEY */ c_id->eid_oc_id = bsi->bsi_oc->bom_id; - if ( dn.bv_val == row.cols[ 3 ] ) { - ber_dupbv( &c_id->eid_dn, &dn ); + if ( ndn.bv_val == row.cols[ 3 ] ) { + ber_dupbv( &c_id->eid_dn, &ndn ); } else { - c_id->eid_dn = dn; + c_id->eid_dn = ndn; } /* append at end of list ... */ @@ -1459,7 +1476,7 @@ backsql_search( Operation *op, SlapReply *rs ) Entry user_entry = { 0 }; int manageDSAit; time_t stoptime = 0; - backsql_srch_info srch_info; + backsql_srch_info bsi; backsql_entryID *eid = NULL; struct berval base; @@ -1504,7 +1521,7 @@ backsql_search( Operation *op, SlapReply *rs ) /* compute it anyway; root does not use it */ stoptime = op->o_time + op->ors_tlimit; - base = op->o_req_dn; + base = op->o_req_ndn; if ( backsql_api_dn2odbc( op, rs, &base ) ) { Debug( LDAP_DEBUG_TRACE, "backsql_search(): " "backsql_api_dn2odbc failed\n", @@ -1516,7 +1533,7 @@ backsql_search( Operation *op, SlapReply *rs ) } /* init search */ - rs->sr_err = backsql_init_search( &srch_info, &base, + rs->sr_err = backsql_init_search( &bsi, &base, op->ors_scope, op->ors_slimit, op->ors_tlimit, stoptime, op->ors_filter, @@ -1526,20 +1543,47 @@ backsql_search( Operation *op, SlapReply *rs ) goto done; } - /* - * for each objectclass we try to construct query which gets IDs - * of entries matching LDAP query filter and scope (or at least - * candidates), and get the IDs - */ - srch_info.bsi_n_candidates = - ( op->ors_limit == NULL /* isroot == FALSE */ ? -2 : + bsi.bsi_n_candidates = + ( op->ors_limit == NULL /* isroot == TRUE */ ? -2 : ( op->ors_limit->lms_s_unchecked == -1 ? -2 : ( op->ors_limit->lms_s_unchecked ) ) ); - avl_apply( bi->sql_oc_by_oc, backsql_oc_get_candidates, - &srch_info, BACKSQL_AVL_STOP, AVL_INORDER ); - if ( op->ors_limit != NULL /* isroot == TRUE */ + + switch ( bsi.bsi_scope ) { + case LDAP_SCOPE_BASE: + case BACKSQL_SCOPE_BASE_LIKE: + /* + * probably already found... + */ + bsi.bsi_id_list = &bsi.bsi_base_id; + bsi.bsi_id_listtail = &bsi.bsi_base_id.eid_next; + break; + + case LDAP_SCOPE_SUBTREE: + /* + * if baseObject is defined, and if it is the root + * of the search, add it to the candidate list + */ + if ( bi->sql_baseObject && BACKSQL_IS_BASEOBJECT_ID( &bsi.bsi_base_id.eid_id ) ) + { + bsi.bsi_id_list = &bsi.bsi_base_id; + bsi.bsi_id_listtail = &bsi.bsi_base_id.eid_next; + } + + /* FALLTHRU */ + default: + + /* + * for each objectclass we try to construct query which gets IDs + * of entries matching LDAP query filter and scope (or at least + * candidates), and get the IDs + */ + avl_apply( bi->sql_oc_by_oc, backsql_oc_get_candidates, + &bsi, BACKSQL_AVL_STOP, AVL_INORDER ); + } + + if ( op->ors_limit != NULL /* isroot == FALSE */ && op->ors_limit->lms_s_unchecked != -1 - && srch_info.bsi_n_candidates == -1 ) + && bsi.bsi_n_candidates == -1 ) { rs->sr_err = LDAP_ADMINLIMIT_EXCEEDED; send_ldap_result( op, rs ); @@ -1549,15 +1593,16 @@ backsql_search( Operation *op, SlapReply *rs ) /* * now we load candidate entries (only those attributes * mentioned in attrs and filter), test it against full filter - * and then send to client + * and then send to client; don't free entry_id if baseObject... */ - for ( eid = srch_info.bsi_id_list; + for ( eid = bsi.bsi_id_list; eid != NULL; - eid = backsql_free_entryID( eid, 1 ) ) + eid = backsql_free_entryID( eid, eid == &bsi.bsi_base_id ? 0 : 1 ) ) { int rc; Attribute *hasSubordinate = NULL, *a = NULL; + Entry *e = NULL; /* check for abandon */ if ( op->o_abandon ) { @@ -1588,20 +1633,28 @@ backsql_search( Operation *op, SlapReply *rs ) eid->eid_id, eid->eid_oc_id, eid->eid_keyval ); #endif /* ! BACKSQL_ARBITRARY_KEY */ - srch_info.bsi_e = &user_entry; - rc = backsql_id2entry( &srch_info, eid ); - if ( rc != LDAP_SUCCESS ) { - Debug( LDAP_DEBUG_TRACE, "backsql_search(): " - "error %d in backsql_id2entry() " - "- skipping\n", rc, 0, 0 ); - continue; + /* don't recollect baseObject ... */ + if ( BACKSQL_IS_BASEOBJECT_ID( &eid->eid_id ) ) { + e = bi->sql_baseObject; + + } else { + bsi.bsi_e = &user_entry; + rc = backsql_id2entry( &bsi, eid ); + if ( rc != LDAP_SUCCESS ) { + Debug( LDAP_DEBUG_TRACE, "backsql_search(): " + "error %d in backsql_id2entry() " + "- skipping\n", rc, 0, 0 ); + continue; + } + + e = &user_entry; } /* check scope */ switch ( op->ors_scope ) { case LDAP_SCOPE_BASE: case BACKSQL_SCOPE_BASE_LIKE: - if ( !bvmatch( &user_entry.e_nname, &op->o_req_ndn ) ) { + if ( !bvmatch( &e->e_nname, &op->o_req_ndn ) ) { goto next_entry; } break; @@ -1617,7 +1670,7 @@ backsql_search( Operation *op, SlapReply *rs ) } case LDAP_SCOPE_SUBTREE: - if ( !dnIsSuffix( &user_entry.e_nname, &op->o_req_ndn ) ) { + if ( !dnIsSuffix( &e->e_nname, &op->o_req_ndn ) ) { goto next_entry; } break; @@ -1626,23 +1679,23 @@ backsql_search( Operation *op, SlapReply *rs ) if ( !manageDSAit && op->ors_scope != LDAP_SCOPE_BASE && op->ors_scope != BACKSQL_SCOPE_BASE_LIKE && - is_entry_referral( &user_entry ) ) + is_entry_referral( e ) ) { BerVarray refs; - refs = get_entry_referrals( op, &user_entry ); + refs = get_entry_referrals( op, e ); if ( !refs ) { - backsql_srch_info srch_info2 = { 0 }; + backsql_srch_info bsi2 = { 0 }; Entry user_entry2 = { 0 }; /* retry with the full entry... */ - (void)backsql_init_search( &srch_info2, - &user_entry.e_name, + (void)backsql_init_search( &bsi2, + &e->e_nname, LDAP_SCOPE_BASE, -1, -1, -1, NULL, dbh, op, rs, NULL, 0 ); - srch_info2.bsi_e = &user_entry2; - rc = backsql_id2entry( &srch_info2, eid ); + bsi2.bsi_e = &user_entry2; + rc = backsql_id2entry( &bsi2, eid ); if ( rc == LDAP_SUCCESS ) { if ( is_entry_referral( &user_entry2 ) ) { @@ -1655,7 +1708,7 @@ backsql_search( Operation *op, SlapReply *rs ) if ( refs ) { rs->sr_ref = referral_rewrite( refs, - &user_entry.e_name, + &e->e_name, &op->o_req_dn, op->ors_scope ); ber_bvarray_free( refs ); @@ -1681,8 +1734,8 @@ backsql_search( Operation *op, SlapReply *rs ) * anyway; we should have used the frontend API function * filter_has_subordinates() */ - if ( srch_info.bsi_flags & BSQL_SF_FILTER_HASSUBORDINATE ) { - rc = backsql_has_children( bi, dbh, &user_entry.e_nname ); + if ( bsi.bsi_flags & BSQL_SF_FILTER_HASSUBORDINATE ) { + rc = backsql_has_children( bi, dbh, &e->e_nname ); switch ( rc ) { case LDAP_COMPARE_TRUE: @@ -1708,9 +1761,9 @@ backsql_search( Operation *op, SlapReply *rs ) } } - if ( test_filter( op, &user_entry, op->ors_filter ) + if ( test_filter( op, e, op->ors_filter ) == LDAP_COMPARE_TRUE ) { - if ( hasSubordinate && !( srch_info.bsi_flags & BSQL_SF_ALL_OPER ) + if ( hasSubordinate && !( bsi.bsi_flags & BSQL_SF_ALL_OPER ) && !ad_inlist( slap_schema.si_ad_hasSubordinates, op->ors_attrs ) ) { a->a_next = NULL; attr_free( hasSubordinate ); @@ -1719,8 +1772,10 @@ backsql_search( Operation *op, SlapReply *rs ) rs->sr_attrs = op->ors_attrs; rs->sr_operational_attrs = NULL; - rs->sr_entry = &user_entry; - rs->sr_flags = REP_ENTRY_MODIFIABLE; + rs->sr_entry = e; + if ( e == &user_entry ) { + rs->sr_flags = REP_ENTRY_MODIFIABLE; + } sres = send_search_entry( op, rs ); rs->sr_entry = NULL; rs->sr_attrs = NULL; @@ -1764,7 +1819,7 @@ end_of_search:; : LDAP_REFERRAL; } else { - rs->sr_err = srch_info.bsi_status; + rs->sr_err = bsi.bsi_status; } send_ldap_result( op, rs ); @@ -1774,12 +1829,12 @@ end_of_search:; } done:; - if ( !BER_BVISNULL( &srch_info.bsi_base_id.eid_dn ) ) { - (void)backsql_free_entryID( &srch_info.bsi_base_id, 0 ); + if ( !BER_BVISNULL( &bsi.bsi_base_id.eid_dn ) ) { + (void)backsql_free_entryID( &bsi.bsi_base_id, 0 ); } - if ( srch_info.bsi_attrs ) { - ch_free( srch_info.bsi_attrs ); + if ( bsi.bsi_attrs ) { + ch_free( bsi.bsi_attrs ); } if ( base.bv_val != op->o_req_ndn.bv_val ) {