From b4e37e518fa20227509b9bf464e1b6049ba82b0a Mon Sep 17 00:00:00 2001 From: Pierangelo Masarati Date: Sun, 16 Jan 2005 23:12:36 +0000 Subject: [PATCH] fixes for ITS#3480,3485,3489; implementation of DISCLOSE access for all operations (ITS#3472); ITS#3432.4; added value validate/pretty when applicable (see comments and #defines in back-sql.h) --- doc/man/man5/slapd-sql.5 | 16 ++ servers/slapd/back-sql/add.c | 101 +++++---- servers/slapd/back-sql/back-sql.h | 26 ++- servers/slapd/back-sql/compare.c | 8 + servers/slapd/back-sql/delete.c | 48 ++-- servers/slapd/back-sql/entry-id.c | 298 +++++++++++++++++++++++-- servers/slapd/back-sql/init.c | 4 +- servers/slapd/back-sql/modify.c | 94 ++++++-- servers/slapd/back-sql/modrdn.c | 325 ++++++++++++++++++---------- servers/slapd/back-sql/proto-sql.h | 2 +- servers/slapd/back-sql/schema-map.c | 35 ++- servers/slapd/back-sql/search.c | 67 ++++-- servers/slapd/back-sql/util.c | 39 ++-- 13 files changed, 785 insertions(+), 278 deletions(-) diff --git a/doc/man/man5/slapd-sql.5 b/doc/man/man5/slapd-sql.5 index ba1aae1a3e..34aa56172c 100644 --- a/doc/man/man5/slapd-sql.5 +++ b/doc/man/man5/slapd-sql.5 @@ -301,6 +301,22 @@ in table \fIldap_entries\fP needs a subsequent select to collect the automatically assigned ID, instead of being returned by a stored procedure. +.LP +.B fetch_attrs +.br +.B fetch_all_attrs { NO | yes } +.RS +The first statement allows to provide a list of attributes that +must always be fetched in addition to those requested by any specific +operation, because they are required for the proper usage of the +backend. For instance, all attributes used in ACLs should be listed +here. The second statement is a shortcut to require all attributes +to be always loaded. Note that the dynamically generated attributes, +e.g. \fIhasSubordinates\fP, \fIentryDN\fP and other implementation +dependent attributes are \fBNOT\fP generated at this point, for +consistency with the rest of slapd. This may change in the future. +.RE + .TP .B sqllayer [...] Loads the layer \fB\fP onto a stack of helpers that are used diff --git a/servers/slapd/back-sql/add.c b/servers/slapd/back-sql/add.c index c57d64e1f9..96a9ef10df 100644 --- a/servers/slapd/back-sql/add.c +++ b/servers/slapd/back-sql/add.c @@ -952,7 +952,6 @@ backsql_add( Operation *op, SlapReply *rs ) RETCODE rc; backsql_oc_map_rec *oc = NULL; backsql_srch_info bsi; - backsql_entryID parent_id = BACKSQL_ENTRYID_INIT; Entry p = { 0 }, *e = NULL; Attribute *at, *at_objectClass = NULL; @@ -1125,6 +1124,15 @@ backsql_add( Operation *op, SlapReply *rs ) goto done; } + if ( get_assert( op ) && + ( test_filter( op, op->oq_add.rs_e, get_assertion( op ) ) + != LDAP_COMPARE_TRUE ) ) + { + rs->sr_err = LDAP_ASSERTION_FAILED; + e = op->ora_e; + goto done; + } + if ( !access_allowed_mask( op, op->ora_e, slap_schema.si_ad_entry, NULL, ACL_WRITE, NULL, &mask ) ) @@ -1140,7 +1148,7 @@ backsql_add( Operation *op, SlapReply *rs ) * the id of the added row; otherwise the procedure * is expected to return the id as the first column of a select */ - rc = SQLAllocStmt( dbh, &sth ); + rc = backsql_Prepare( dbh, &sth, oc->bom_create_proc, 0 ); if ( rc != SQL_SUCCESS ) { rs->sr_err = LDAP_OTHER; rs->sr_text = "SQL-backend error"; @@ -1152,10 +1160,11 @@ backsql_add( Operation *op, SlapReply *rs ) if ( BACKSQL_IS_ADD( oc->bom_expect_return ) ) { rc = backsql_BindParamInt( sth, 1, SQL_PARAM_OUTPUT, &new_keyval ); if ( rc != SQL_SUCCESS ) { - Debug( LDAP_DEBUG_TRACE, - " backsql_add_attr(): " - "error binding keyval parameter for objectClass %s\n", - oc->bom_oc->soc_cname.bv_val, 0, 0 ); + Debug( LDAP_DEBUG_TRACE, " backsql_add(\"%s\"): " + "error binding keyval parameter " + "for objectClass %s\n", + op->ora_e->e_name.bv_val, + oc->bom_oc->soc_cname.bv_val, 0 ); backsql_PrintErrors( bi->sql_db_env, dbh, sth, rc ); SQLFreeStmt( sth, SQL_DROP ); @@ -1186,11 +1195,12 @@ backsql_add( Operation *op, SlapReply *rs ) oc->bom_create_hint->ad_cname.bv_val, 0, 0 ); } + colnum++; } Debug( LDAP_DEBUG_TRACE, " backsql_add(\"%s\"): executing \"%s\"\n", op->ora_e->e_name.bv_val, oc->bom_create_proc, 0 ); - rc = SQLExecDirect( sth, oc->bom_create_proc, SQL_NTS ); + rc = SQLExecute( sth ); if ( rc != SQL_SUCCESS ) { Debug( LDAP_DEBUG_TRACE, " backsql_add(\"%s\"): " "create_proc execution failed\n", @@ -1203,9 +1213,8 @@ backsql_add( Operation *op, SlapReply *rs ) goto done; } - if ( op->o_noop ) { - SQLTransact( SQL_NULL_HENV, dbh, SQL_ROLLBACK ); - } + /* FIXME: after SQLExecute(), the row is already inserted + * (at least with PostgreSQL and unixODBC); needs investigation */ if ( !BACKSQL_IS_ADD( oc->bom_expect_return ) ) { SWORD ncols; @@ -1213,7 +1222,8 @@ backsql_add( Operation *op, SlapReply *rs ) if ( BACKSQL_CREATE_NEEDS_SELECT( bi ) ) { SQLFreeStmt( sth, SQL_DROP ); - rc = SQLAllocStmt( dbh, &sth ); + + rc = backsql_Prepare( dbh, &sth, oc->bom_create_keyval, 0 ); if ( rc != SQL_SUCCESS ) { rs->sr_err = LDAP_OTHER; rs->sr_text = "SQL-backend error"; @@ -1221,7 +1231,7 @@ backsql_add( Operation *op, SlapReply *rs ) goto done; } - rc = SQLExecDirect( sth, oc->bom_create_keyval, SQL_NTS ); + rc = SQLExecute( sth ); if ( rc != SQL_SUCCESS ) { rs->sr_err = LDAP_OTHER; rs->sr_text = "SQL-backend error"; @@ -1340,10 +1350,10 @@ backsql_add( Operation *op, SlapReply *rs ) rc = backsql_BindParamBerVal( sth, 1, SQL_PARAM_INPUT, &realdn ); if ( rc != SQL_SUCCESS ) { - Debug( LDAP_DEBUG_TRACE, - " backsql_add_attr(): " + Debug( LDAP_DEBUG_TRACE, " backsql_add(\"%s\"): " "error binding DN parameter for objectClass %s\n", - oc->bom_oc->soc_cname.bv_val, 0, 0 ); + op->ora_e->e_name.bv_val, + oc->bom_oc->soc_cname.bv_val, 0 ); backsql_PrintErrors( bi->sql_db_env, dbh, sth, rc ); SQLFreeStmt( sth, SQL_DROP ); @@ -1356,10 +1366,11 @@ backsql_add( Operation *op, SlapReply *rs ) rc = backsql_BindParamInt( sth, 2, SQL_PARAM_INPUT, &oc->bom_id ); if ( rc != SQL_SUCCESS ) { - Debug( LDAP_DEBUG_TRACE, - " backsql_add_attr(): " - "error binding objectClass ID parameter for objectClass %s\n", - oc->bom_oc->soc_cname.bv_val, 0, 0 ); + Debug( LDAP_DEBUG_TRACE, " backsql_add(\"%s\"): " + "error binding objectClass ID parameter " + "for objectClass %s\n", + op->ora_e->e_name.bv_val, + oc->bom_oc->soc_cname.bv_val, 0 ); backsql_PrintErrors( bi->sql_db_env, dbh, sth, rc ); SQLFreeStmt( sth, SQL_DROP ); @@ -1370,12 +1381,13 @@ backsql_add( Operation *op, SlapReply *rs ) goto done; } - rc = backsql_BindParamID( sth, 3, SQL_PARAM_INPUT, &parent_id.eid_id ); + rc = backsql_BindParamID( sth, 3, SQL_PARAM_INPUT, &bsi.bsi_base_id.eid_id ); if ( rc != SQL_SUCCESS ) { - Debug( LDAP_DEBUG_TRACE, - " backsql_add_attr(): " - "error binding parent ID parameter for objectClass %s\n", - oc->bom_oc->soc_cname.bv_val, 0, 0 ); + Debug( LDAP_DEBUG_TRACE, " backsql_add(\"%s\"): " + "error binding parent ID parameter " + "for objectClass %s\n", + op->ora_e->e_name.bv_val, + oc->bom_oc->soc_cname.bv_val, 0 ); backsql_PrintErrors( bi->sql_db_env, dbh, sth, rc ); SQLFreeStmt( sth, SQL_DROP ); @@ -1388,10 +1400,11 @@ backsql_add( Operation *op, SlapReply *rs ) rc = backsql_BindParamInt( sth, 4, SQL_PARAM_INPUT, &new_keyval ); if ( rc != SQL_SUCCESS ) { - Debug( LDAP_DEBUG_TRACE, - " backsql_add_attr(): " - "error binding entry ID parameter for objectClass %s\n", - oc->bom_oc->soc_cname.bv_val, 0, 0 ); + Debug( LDAP_DEBUG_TRACE, " backsql_add(\"%s\"): " + "error binding entry ID parameter " + "for objectClass %s\n", + op->ora_e->e_name.bv_val, + oc->bom_oc->soc_cname.bv_val, 0 ); backsql_PrintErrors( bi->sql_db_env, dbh, sth, rc ); SQLFreeStmt( sth, SQL_DROP ); @@ -1406,12 +1419,12 @@ backsql_add( Operation *op, SlapReply *rs ) bi->sql_insentry_stmt, op->ora_e->e_name.bv_val, 0 ); #ifdef BACKSQL_ARBITRARY_KEY Debug( LDAP_DEBUG_TRACE, " for oc_map_id=%ld, " - "parent_id=%s, keyval=%ld\n", - oc->bom_id, parent_id.eid_id.bv_val, new_keyval ); + "p_id=%s, keyval=%ld\n", + oc->bom_id, bsi.bsi_base_id.eid_id.bv_val, new_keyval ); #else /* ! BACKSQL_ARBITRARY_KEY */ Debug( LDAP_DEBUG_TRACE, " for oc_map_id=%ld, " - "parent_id=%ld, keyval=%ld\n", - oc->bom_id, parent_id.eid_id, new_keyval ); + "p_id=%ld, keyval=%ld\n", + oc->bom_id, bsi.bsi_base_id.eid_id, new_keyval ); #endif /* ! BACKSQL_ARBITRARY_KEY */ rc = SQLExecute( sth ); if ( rc != SQL_SUCCESS ) { @@ -1430,26 +1443,29 @@ backsql_add( Operation *op, SlapReply *rs ) goto done; } - /* FIXME: need ldap_entries.id of newly added entry */ + SQLFreeStmt( sth, SQL_DROP ); + if ( at_objectClass ) { - rs->sr_err = backsql_add_attr( op, rs, dbh, oc, at_objectClass, new_keyval ); + rs->sr_err = backsql_add_attr( op, rs, dbh, oc, + at_objectClass, new_keyval ); if ( rs->sr_err != LDAP_SUCCESS ) { e = op->ora_e; goto done; } } - SQLFreeStmt( sth, SQL_DROP ); - done:; /* * Commit only if all operations succeed */ - if ( rs->sr_err == LDAP_SUCCESS && !op->o_noop ) { - SQLTransact( SQL_NULL_HENV, dbh, SQL_COMMIT ); + if ( sth != SQL_NULL_HSTMT ) { + SQLUSMALLINT CompletionType = SQL_ROLLBACK; - } else { - SQLTransact( SQL_NULL_HENV, dbh, SQL_ROLLBACK ); + if ( rs->sr_err == LDAP_SUCCESS && !op->o_noop ) { + CompletionType = SQL_COMMIT; + } + + SQLTransact( SQL_NULL_HENV, dbh, CompletionType ); } /* @@ -1497,7 +1513,10 @@ done:; { ch_free( realdn.bv_val ); } - (void)backsql_free_entryID( op, &parent_id, 0 ); + + if ( !BER_BVISNULL( &bsi.bsi_base_id.eid_ndn ) ) { + (void)backsql_free_entryID( op, &bsi.bsi_base_id, 0 ); + } if ( !BER_BVISNULL( &p.e_nname ) ) { entry_clean( &p ); diff --git a/servers/slapd/back-sql/back-sql.h b/servers/slapd/back-sql/back-sql.h index fb285c0c5e..e91736288b 100644 --- a/servers/slapd/back-sql/back-sql.h +++ b/servers/slapd/back-sql/back-sql.h @@ -76,13 +76,16 @@ * 1. id_query.patch applied (with changes) * 2. shortcut.patch applied (reworked) * 3. create_hint.patch applied - * 4. count_query.patch rejected (conflicts with other features) + * 4. count_query.patch applied (reworked) * 5. returncodes.patch applied (with sanity checks) * 6. connpool.patch under evaluation - * 7. modoc.patch under evaluation - * 8. miscfixes.patch applied (reworked; FIXME: other - * operations may need to load the - * entire entry for ACL purposes) + * 7. modoc.patch under evaluation (requires + * manageDSAit and "manage" + * access privileges) + * 8. miscfixes.patch applied (reworked; other + * operations need to load the + * entire entry for ACL purposes; + * see ITS#3480, now fixed) * * original description: @@ -195,6 +198,16 @@ typedef struct { */ #undef BACKSQL_TRACE +/* + * define to enable values counting for attributes + */ +#define BACKSQL_COUNTQUERY + +/* + * define to enable prettification/validation of values + */ +#define BACKSQL_PRETTY_VALIDATE + /* * define to enable varchars as unique keys in user tables * @@ -333,6 +346,9 @@ typedef struct backsql_at_map_rec { /* for optimization purposes attribute load query * is preconstructed from parts on schemamap load time */ char *bam_query; +#ifdef BACKSQL_COUNTQUERY + char *bam_countquery; +#endif /* BACKSQL_COUNTQUERY */ /* following flags are bitmasks (first bit used for add_proc, * second - for delete_proc) */ /* order of parameters for procedures above; diff --git a/servers/slapd/back-sql/compare.c b/servers/slapd/back-sql/compare.c index d339009fb6..4dfb365a0b 100644 --- a/servers/slapd/back-sql/compare.c +++ b/servers/slapd/back-sql/compare.c @@ -79,6 +79,14 @@ backsql_compare( Operation *op, SlapReply *rs ) goto return_results; } + if ( get_assert( op ) && + ( test_filter( op, &e, get_assertion( op ) ) + != LDAP_COMPARE_TRUE ) ) + { + rs->sr_err = LDAP_ASSERTION_FAILED; + goto return_results; + } + if ( is_at_operational( op->oq_compare.rs_ava->aa_desc->ad_type ) ) { SlapReply nrs = { 0 }; diff --git a/servers/slapd/back-sql/delete.c b/servers/slapd/back-sql/delete.c index c07ee3400b..e094fb5842 100644 --- a/servers/slapd/back-sql/delete.c +++ b/servers/slapd/back-sql/delete.c @@ -87,14 +87,13 @@ backsql_delete( Operation *op, SlapReply *rs ) RETCODE rc; int prc = LDAP_SUCCESS; backsql_oc_map_rec *oc = NULL; - backsql_srch_info bsi; + backsql_srch_info bsi = { 0 }; backsql_entryID e_id = { 0 }; Entry d = { 0 }, p = { 0 }, *e = NULL; struct berval pdn = BER_BVNULL; int manageDSAit = get_manageDSAit( op ); /* first parameter no */ SQLUSMALLINT pno; - SQLUSMALLINT CompletionType = SQL_ROLLBACK; Debug( LDAP_DEBUG_TRACE, "==>backsql_delete(): deleting entry \"%s\"\n", op->o_req_ndn.bv_val, 0, 0 ); @@ -114,12 +113,12 @@ backsql_delete( Operation *op, SlapReply *rs ) * Get the entry */ bsi.bsi_e = &d; - rc = backsql_init_search( &bsi, &op->o_req_ndn, + rs->sr_err = backsql_init_search( &bsi, &op->o_req_ndn, LDAP_SCOPE_BASE, SLAP_NO_LIMIT, SLAP_NO_LIMIT, (time_t)(-1), NULL, dbh, op, rs, slap_anlist_no_attrs, ( BACKSQL_ISF_MATCHED | BACKSQL_ISF_GET_ENTRY ) ); - switch ( rc ) { + switch ( rs->sr_err ) { case LDAP_SUCCESS: break; @@ -144,6 +143,22 @@ backsql_delete( Operation *op, SlapReply *rs ) Debug( LDAP_DEBUG_TRACE, "backsql_delete(): " "could not retrieve deleteDN ID - no such entry\n", 0, 0, 0 ); + if ( !BER_BVISNULL( &d.e_nname ) ) { + /* FIXME: should always be true! */ + e = &d; + + } else { + e = NULL; + } + goto done; + } + + if ( get_assert( op ) && + ( test_filter( op, &d, get_assertion( op ) ) + != LDAP_COMPARE_TRUE ) ) + { + rs->sr_err = LDAP_ASSERTION_FAILED; + e = &d; goto done; } @@ -204,12 +219,12 @@ backsql_delete( Operation *op, SlapReply *rs ) dnParent( &op->o_req_ndn, &pdn ); bsi.bsi_e = &p; e_id = bsi.bsi_base_id; - rc = backsql_init_search( &bsi, &pdn, + rs->sr_err = backsql_init_search( &bsi, &pdn, LDAP_SCOPE_BASE, SLAP_NO_LIMIT, SLAP_NO_LIMIT, (time_t)(-1), NULL, dbh, op, rs, slap_anlist_no_attrs, BACKSQL_ISF_GET_ENTRY ); - if ( rc != LDAP_SUCCESS ) { + if ( rs->sr_err != LDAP_SUCCESS ) { Debug( LDAP_DEBUG_TRACE, "backsql_delete(): " "could not retrieve deleteDN ID - no such entry\n", 0, 0, 0 ); @@ -471,22 +486,20 @@ backsql_delete( Operation *op, SlapReply *rs ) rs->sr_err = LDAP_SUCCESS; -done:; - /* * Commit only if all operations succeed - * - * FIXME: backsql_add() does not fail if add operations - * are not available for some attributes, or if - * a multiple value add actually results in a replace, - * or if a single operation on an attribute fails - * for any reason */ - if ( rs->sr_err == LDAP_SUCCESS && !op->o_noop ) { - CompletionType = SQL_COMMIT; + if ( sth != SQL_NULL_HSTMT ) { + SQLUSMALLINT CompletionType = SQL_ROLLBACK; + + if ( rs->sr_err == LDAP_SUCCESS && !op->o_noop ) { + CompletionType = SQL_COMMIT; + } + + SQLTransact( SQL_NULL_HENV, dbh, CompletionType ); } - SQLTransact( SQL_NULL_HENV, dbh, CompletionType ); +done:; #ifdef SLAP_ACL_HONOR_DISCLOSE if ( e != NULL ) { if ( !access_allowed( op, e, slap_schema.si_ad_entry, NULL, @@ -501,7 +514,6 @@ done:; } } } - #endif /* SLAP_ACL_HONOR_DISCLOSE */ send_ldap_result( op, rs ); diff --git a/servers/slapd/back-sql/entry-id.c b/servers/slapd/back-sql/entry-id.c index 18dbba5fd8..abfe702712 100644 --- a/servers/slapd/back-sql/entry-id.c +++ b/servers/slapd/back-sql/entry-id.c @@ -455,7 +455,21 @@ backsql_get_attr_vals( void *v_at, void *v_bsi ) RETCODE rc; SQLHSTMT sth = SQL_NULL_HSTMT; BACKSQL_ROW_NTS row; - int i; + unsigned long i, + k = 0, + oldcount = 0; +#ifdef BACKSQL_COUNTQUERY + unsigned long count, + countsize = sizeof( count ), + j; + Attribute *attr = NULL; + + slap_mr_normalize_func *normfunc = NULL; +#endif /* BACKSQL_COUNTQUERY */ +#ifdef BACKSQL_PRETTY_VALIDATE + slap_syntax_validate_func *validate = NULL; + slap_syntax_transform_func *pretty = NULL; +#endif /* BACKSQL_PRETTY_VALIDATE */ assert( at ); assert( bsi ); @@ -472,9 +486,141 @@ backsql_get_attr_vals( void *v_at, void *v_bsi ) bsi->bsi_c_eid->eid_keyval ); #endif /* ! BACKSQL_ARBITRARY_KEY */ +#ifdef BACKSQL_PRETTY_VALIDATE + validate = at->bam_ad->ad_type->sat_syntax->ssyn_validate; + pretty = at->bam_ad->ad_type->sat_syntax->ssyn_pretty; + + if ( validate == NULL && pretty == NULL ) { + return 1; + } +#endif /* BACKSQL_PRETTY_VALIDATE */ + +#ifdef BACKSQL_COUNTQUERY + if ( at->bam_ad->ad_type->sat_equality ) { + normfunc = at->bam_ad->ad_type->sat_equality->smr_normalize; + } + + /* Count how many rows will be returned. This avoids memory + * fragmentation that can result from loading the values in + * one by one and using realloc() + */ + rc = backsql_Prepare( bsi->bsi_dbh, &sth, at->bam_countquery, 0 ); + if ( rc != SQL_SUCCESS ) { + Debug( LDAP_DEBUG_TRACE, "backsql_get_attr_vals(): " + "error preparing count query: %s\n", + at->bam_countquery, 0, 0 ); + backsql_PrintErrors( bi->sql_db_env, bsi->bsi_dbh, sth, rc ); + return 1; + } + + rc = backsql_BindParamID( sth, 1, SQL_PARAM_INPUT, + &bsi->bsi_c_eid->eid_keyval ); + if ( rc != SQL_SUCCESS ) { + Debug( LDAP_DEBUG_TRACE, "backsql_get_attr_vals(): " + "error binding key value parameter\n", 0, 0, 0 ); + SQLFreeStmt( sth, SQL_DROP ); + return 1; + } + + rc = SQLExecute( sth ); + if ( ! BACKSQL_SUCCESS( rc ) ) { + Debug( LDAP_DEBUG_TRACE, "backsql_get_attr_vals(): " + "error executing attribute count query '%s'\n", + at->bam_countquery, 0, 0 ); + backsql_PrintErrors( bi->sql_db_env, bsi->bsi_dbh, sth, rc ); + SQLFreeStmt( sth, SQL_DROP ); + return 1; + } + + SQLBindCol( sth, (SQLUSMALLINT)1, SQL_C_LONG, + (SQLPOINTER)&count, + (SQLINTEGER)sizeof( count ), + &countsize ); + + rc = SQLFetch( sth ); + if ( rc != SQL_SUCCESS ) { + Debug( LDAP_DEBUG_TRACE, "backsql_get_attr_vals(): " + "error fetch results of count query: %s\n", + at->bam_countquery, 0, 0 ); + backsql_PrintErrors( bi->sql_db_env, bsi->bsi_dbh, sth, rc ); + SQLFreeStmt( sth, SQL_DROP ); + return 1; + } + + Debug( LDAP_DEBUG_TRACE, "backsql_get_attr_vals(): " + "number of values in query: %d\n", count, 0, 0 ); + SQLFreeStmt( sth, SQL_DROP ); + if ( count == 0 ) { + return 1; + } + + attr = attr_find( bsi->bsi_e->e_attrs, at->bam_ad ); + if ( attr != NULL ) { + BerVarray tmp; + + if ( attr->a_vals != NULL ) { + for ( ; !BER_BVISNULL( &attr->a_vals[ oldcount ] ); oldcount++ ) + /* just count */ ; + } + + tmp = ch_realloc( attr->a_vals, ( oldcount + count + 1 ) * sizeof( struct berval ) ); + if ( tmp == NULL ) { + return 1; + } + attr->a_vals = tmp; + memset( &attr->a_vals[ oldcount ], 0, ( count + 1 ) * sizeof( struct berval ) ); + + if ( normfunc ) { + tmp = ch_realloc( attr->a_nvals, ( oldcount + count + 1 ) * sizeof( struct berval ) ); + if ( tmp == NULL ) { + return 1; + } + attr->a_nvals = tmp; + memset( &attr->a_nvals[ oldcount ], 0, ( count + 1 ) * sizeof( struct berval ) ); + + } else { + attr->a_nvals = attr->a_vals; + } + + } else { + Attribute **ap; + + /* Make space for the array of values */ + attr = (Attribute *) ch_malloc( sizeof( Attribute ) ); + attr->a_desc = at->bam_ad; + attr->a_flags = 0; + attr->a_next = NULL; + attr->a_vals = ch_calloc( count + 1, sizeof( struct berval ) ); + if ( attr->a_vals == NULL ) { + Debug( LDAP_DEBUG_TRACE, "Out of memory!\n", 0,0,0 ); + ch_free( attr ); + return 1; + } + memset( attr->a_vals, 0, ( count + 1 ) * sizeof( struct berval ) ); + if ( normfunc ) { + attr->a_nvals = ch_calloc( count + 1, sizeof( struct berval ) ); + if ( attr->a_nvals == NULL ) { + ch_free( attr->a_vals ); + ch_free( attr ); + return 1; + + } else { + memset( attr->a_nvals, 0, ( count + 1 ) * sizeof( struct berval ) ); + } + + } else { + attr->a_nvals = attr->a_vals; + } + + for ( ap = &bsi->bsi_e->e_attrs; (*ap) != NULL; ap = &(*ap)->a_next ) + /* goto last */ ; + *ap = attr; + } +#endif /* BACKSQL_COUNTQUERY */ + rc = backsql_Prepare( bsi->bsi_dbh, &sth, at->bam_query, 0 ); if ( rc != SQL_SUCCESS ) { - Debug( LDAP_DEBUG_TRACE, "backsql_get_attr_values(): " + Debug( LDAP_DEBUG_TRACE, "backsql_get_attr_vals(): " "error preparing query: %s\n", at->bam_query, 0, 0 ); backsql_PrintErrors( bi->sql_db_env, bsi->bsi_dbh, sth, rc ); return 1; @@ -483,18 +629,18 @@ backsql_get_attr_vals( void *v_at, void *v_bsi ) rc = backsql_BindParamID( sth, 1, SQL_PARAM_INPUT, &bsi->bsi_c_eid->eid_keyval ); if ( rc != SQL_SUCCESS ) { - Debug( LDAP_DEBUG_TRACE, "backsql_get_attr_values(): " + Debug( LDAP_DEBUG_TRACE, "backsql_get_attr_vals(): " "error binding key value parameter\n", 0, 0, 0 ); return 1; } #ifdef BACKSQL_TRACE #ifdef BACKSQL_ARBITRARY_KEY - Debug( LDAP_DEBUG_TRACE, "backsql_get_attr_values(): " + Debug( LDAP_DEBUG_TRACE, "backsql_get_attr_vals(): " "query=\"%s\" keyval=%s\n", at->bam_query, bsi->bsi_c_eid->eid_keyval.bv_val, 0 ); #else /* !BACKSQL_ARBITRARY_KEY */ - Debug( LDAP_DEBUG_TRACE, "backsql_get_attr_values(): " + Debug( LDAP_DEBUG_TRACE, "backsql_get_attr_vals(): " "query=\"%s\" keyval=%d\n", at->bam_query, bsi->bsi_c_eid->eid_keyval, 0 ); #endif /* ! BACKSQL_ARBITRARY_KEY */ @@ -502,7 +648,7 @@ backsql_get_attr_vals( void *v_at, void *v_bsi ) rc = SQLExecute( sth ); if ( ! BACKSQL_SUCCESS( rc ) ) { - Debug( LDAP_DEBUG_TRACE, "backsql_get_attr_values(): " + Debug( LDAP_DEBUG_TRACE, "backsql_get_attr_vals(): " "error executing attribute query \"%s\"\n", at->bam_query, 0, 0 ); backsql_PrintErrors( bi->sql_db_env, bsi->bsi_dbh, sth, rc ); @@ -511,30 +657,146 @@ backsql_get_attr_vals( void *v_at, void *v_bsi ) } backsql_BindRowAsStrings( sth, &row ); - - rc = SQLFetch( sth ); - for ( ; BACKSQL_SUCCESS( rc ); rc = SQLFetch( sth ) ) { +#ifdef BACKSQL_COUNTQUERY + j = oldcount; +#endif /* BACKSQL_COUNTQUERY */ + for ( rc = SQLFetch( sth ), k = 0; + BACKSQL_SUCCESS( rc ); + rc = SQLFetch( sth ), k++ ) + { for ( i = 0; i < row.ncols; i++ ) { + if ( row.value_len[ i ] > 0 ) { - struct berval bv; + struct berval bv; + int retval; +#ifdef BACKSQL_TRACE + AttributeDescription *ad = NULL; + const char *text; + + retval = slap_bv2ad( &row.col_names[ i ], &ad, &text ); + if ( retval != LDAP_SUCCESS ) { + Debug( LDAP_DEBUG_ANY, + "==>backsql_get_attr_vals(\"%s\"): " + "unable to find AttributeDescription %s " + "in schema (%d)\n", + bsi->bsi_e->e_name.bv_val, + row.col_names[ i ].bv_val, retval ); + return 1; + } + + if ( ad != at->bam_ad ) { + Debug( LDAP_DEBUG_ANY, + "==>backsql_get_attr_vals(\"%s\"): " + "column name %s differs from " + "AttributeDescription %s\n", + bsi->bsi_e->e_name.bv_val, + ad->ad_cname.bv_val, + at->bam_ad->ad_cname.bv_val ); + return 1; + } +#endif /* BACKSQL_TRACE */ - bv.bv_val = row.cols[ i ]; -#if 0 - bv.bv_len = row.col_prec[ i ]; -#else /* * FIXME: what if a binary * is fetched? */ - bv.bv_len = strlen( row.cols[ i ] ); -#endif - backsql_entry_addattr( bsi->bsi_e, - &row.col_names[ i ], &bv, + ber_str2bv( row.cols[ i ], 0, 0, &bv ); + +#ifdef BACKSQL_PRETTY_VALIDATE + if ( pretty ) { + struct berval pbv; + + retval = pretty( at->bam_ad->ad_type->sat_syntax, + &bv, &pbv, bsi->bsi_op->o_tmpmemctx ); + bv = pbv; + + } else { + retval = validate( at->bam_ad->ad_type->sat_syntax, + &bv ); + } + + if ( retval != LDAP_SUCCESS ) { + char buf[ SLAP_TEXT_BUFLEN ]; + + /* FIXME: we're ignoring invalid values, + * but we're accepting the attributes; + * should we fail at all? */ + snprintf( buf, sizeof( buf ), + "unable to %s value #%d " + "of AttributeDescription %s", + pretty ? "prettify" : "validate", + at->bam_ad->ad_cname.bv_val, + k - oldcount ); + Debug( LDAP_DEBUG_TRACE, + "==>backsql_get_attr_vals(\"%s\"): " + "%s (%d)\n", + bsi->bsi_e->e_name.bv_val, buf, retval ); + continue; + } +#endif /* BACKSQL_PRETTY_VALIDATE */ + +#ifndef BACKSQL_COUNTQUERY + (void)backsql_entry_addattr( bsi->bsi_e, + at->bam_ad, &bv, + bsi->bsi_op->o_tmpmemctx ); + +#else /* BACKSQL_COUNTQUERY */ + if ( normfunc ) { + struct berval nbv; + + retval = (*normfunc)( SLAP_MR_VALUE_OF_ATTRIBUTE_SYNTAX, + at->bam_ad->ad_type->sat_syntax, + at->bam_ad->ad_type->sat_equality, + &bv, &nbv, bsi->bsi_op->o_tmpmemctx ); + if ( retval != LDAP_SUCCESS ) { + char buf[ SLAP_TEXT_BUFLEN ]; + + /* FIXME: we're ignoring invalid values, + * but we're accepting the attributes; + * should we fail at all? */ + snprintf( buf, sizeof( buf ), + "unable to normalize value #%d " + "of AttributeDescription %s", + at->bam_ad->ad_cname.bv_val, + k - oldcount ); + Debug( LDAP_DEBUG_TRACE, + "==>backsql_get_attr_vals(\"%s\"): " + "%s (%d)\n", + bsi->bsi_e->e_name.bv_val, buf, retval ); + +#ifdef BACKSQL_PRETTY_VALIDATE + if ( pretty ) { + bsi->bsi_op->o_tmpfree( bv.bv_val, + bsi->bsi_op->o_tmpmemctx ); + } +#endif /* BACKSQL_PRETTY_VALIDATE */ + + continue; + } + ber_dupbv( &attr->a_nvals[ j ], &nbv ); + bsi->bsi_op->o_tmpfree( nbv.bv_val, + bsi->bsi_op->o_tmpmemctx ); + } + + ber_dupbv( &attr->a_vals[ j ], &bv ); + + assert( j < oldcount + count ); + j++; +#endif /* BACKSQL_COUNTQUERY */ + +#ifdef BACKSQL_PRETTY_VALIDATE + if ( pretty ) { + bsi->bsi_op->o_tmpfree( bv.bv_val, + bsi->bsi_op->o_tmpmemctx ); + } +#endif /* BACKSQL_PRETTY_VALIDATE */ + #ifdef BACKSQL_TRACE Debug( LDAP_DEBUG_TRACE, "prec=%d\n", (int)row.col_prec[ i ], 0, 0 ); + } else { Debug( LDAP_DEBUG_TRACE, "NULL value " "in this row for attribute \"%s\"\n", diff --git a/servers/slapd/back-sql/init.c b/servers/slapd/back-sql/init.c index cf5de2117f..3ebdfea0a9 100644 --- a/servers/slapd/back-sql/init.c +++ b/servers/slapd/back-sql/init.c @@ -34,10 +34,10 @@ sql_back_initialize( BackendInfo *bi ) { static char *controls[] = { + LDAP_CONTROL_ASSERT, + LDAP_CONTROL_MANAGEDSAIT, #if 0 /* needs improvements */ -#ifdef LDAP_CONTROL_NOOP LDAP_CONTROL_NOOP, -#endif /* LDAP_CONTROL_NOOP */ #endif #ifdef LDAP_CONTROL_VALUESRETURNFILTER LDAP_CONTROL_VALUESRETURNFILTER, diff --git a/servers/slapd/back-sql/modify.c b/servers/slapd/back-sql/modify.c index 4ec90b2c3a..ac9a197155 100644 --- a/servers/slapd/back-sql/modify.c +++ b/servers/slapd/back-sql/modify.c @@ -36,7 +36,9 @@ backsql_modify( Operation *op, SlapReply *rs ) SQLHDBC dbh = SQL_NULL_HDBC; backsql_oc_map_rec *oc = NULL; backsql_srch_info bsi = { 0 }; - Entry e = { 0 }; + Entry m = { 0 }, *e = NULL; + int manageDSAit = get_manageDSAit( op ); + SQLUSMALLINT CompletionType = SQL_ROLLBACK; /* * FIXME: in case part of the operation cannot be performed @@ -60,19 +62,45 @@ backsql_modify( Operation *op, SlapReply *rs ) goto done; } - bsi.bsi_e = &e; + bsi.bsi_e = &m; rs->sr_err = backsql_init_search( &bsi, &op->o_req_ndn, LDAP_SCOPE_BASE, SLAP_NO_LIMIT, SLAP_NO_LIMIT, (time_t)(-1), NULL, dbh, op, rs, slap_anlist_all_attributes, - BACKSQL_ISF_GET_ENTRY ); - if ( rs->sr_err != LDAP_SUCCESS ) { + ( BACKSQL_ISF_MATCHED | BACKSQL_ISF_GET_ENTRY ) ); + switch ( rs->sr_err ) { + case LDAP_SUCCESS: + break; + + case LDAP_REFERRAL: + if ( !BER_BVISNULL( &bsi.bsi_e->e_nname ) && + dn_match( &op->o_req_ndn, &bsi.bsi_e->e_nname ) + && manageDSAit ) + { + rs->sr_err = LDAP_SUCCESS; + rs->sr_text = NULL; + rs->sr_matched = NULL; + if ( rs->sr_ref ) { + ber_bvarray_free( rs->sr_ref ); + rs->sr_ref = NULL; + } + break; + } + e = &m; + /* fallthru */ + + default: Debug( LDAP_DEBUG_TRACE, "backsql_modify(): " "could not retrieve modifyDN ID - no such entry\n", 0, 0, 0 ); - /* FIXME: we keep the error code - * set by backsql_init_search() */ + if ( !BER_BVISNULL( &m.e_nname ) ) { + /* FIXME: should always be true! */ + e = &m; + + } else { + e = NULL; + } goto done; } @@ -87,6 +115,15 @@ backsql_modify( Operation *op, SlapReply *rs ) bsi.bsi_base_id.eid_dn.bv_val, bsi.bsi_base_id.eid_id, 0 ); #endif /* ! BACKSQL_ARBITRARY_KEY */ + if ( get_assert( op ) && + ( test_filter( op, &m, get_assertion( op ) ) + != LDAP_COMPARE_TRUE )) + { + rs->sr_err = LDAP_ASSERTION_FAILED; + e = &m; + goto done; + } + oc = backsql_id2oc( bi, bsi.bsi_base_id.eid_oc_id ); if ( oc == NULL ) { Debug( LDAP_DEBUG_TRACE, " backsql_modify(): " @@ -102,28 +139,47 @@ backsql_modify( Operation *op, SlapReply *rs ) */ rs->sr_err = LDAP_OTHER; rs->sr_text = "SQL-backend error"; + e = NULL; goto done; } /* FIXME: need the whole entry (ITS#3480) */ - if ( !acl_check_modlist( op, &e, op->oq_modify.rs_modlist ) ) { + if ( !acl_check_modlist( op, &m, op->oq_modify.rs_modlist ) ) { rs->sr_err = LDAP_INSUFFICIENT_ACCESS; - - } else { - rs->sr_err = backsql_modify_internal( op, rs, dbh, oc, - &bsi.bsi_base_id, - op->oq_modify.rs_modlist ); + e = &m; + goto done; } - if ( rs->sr_err == LDAP_SUCCESS ) { - /* - * Commit only if all operations succeed - */ - SQLTransact( SQL_NULL_HENV, dbh, - op->o_noop ? SQL_ROLLBACK : SQL_COMMIT ); + rs->sr_err = backsql_modify_internal( op, rs, dbh, oc, + &bsi.bsi_base_id, + op->oq_modify.rs_modlist ); + + /* + * Commit only if all operations succeed + */ + if ( rs->sr_err == LDAP_SUCCESS && !op->o_noop ) { + CompletionType = SQL_COMMIT; } + SQLTransact( SQL_NULL_HENV, dbh, CompletionType ); + done:; +#ifdef SLAP_ACL_HONOR_DISCLOSE + if ( e != NULL ) { + if ( !access_allowed( op, e, slap_schema.si_ad_entry, NULL, + ACL_DISCLOSE, NULL ) ) + { + rs->sr_err = LDAP_NO_SUCH_OBJECT; + rs->sr_text = NULL; + rs->sr_matched = NULL; + if ( rs->sr_ref ) { + ber_bvarray_free( rs->sr_ref ); + rs->sr_ref = NULL; + } + } + } +#endif /* SLAP_ACL_HONOR_DISCLOSE */ + send_ldap_result( op, rs ); (void)backsql_free_entryID( op, &bsi.bsi_base_id, 0 ); @@ -138,6 +194,6 @@ done:; Debug( LDAP_DEBUG_TRACE, "<==backsql_modify()\n", 0, 0, 0 ); - return rs->sr_err != LDAP_SUCCESS ? rs->sr_err : op->o_noop; + return rs->sr_err; } diff --git a/servers/slapd/back-sql/modrdn.c b/servers/slapd/back-sql/modrdn.c index 046a726b12..a722e9f398 100644 --- a/servers/slapd/back-sql/modrdn.c +++ b/servers/slapd/back-sql/modrdn.c @@ -37,16 +37,20 @@ backsql_modrdn( Operation *op, SlapReply *rs ) SQLHSTMT sth = SQL_NULL_HSTMT; RETCODE rc; backsql_entryID e_id = BACKSQL_ENTRYID_INIT, - pe_id = BACKSQL_ENTRYID_INIT, - new_pe_id = BACKSQL_ENTRYID_INIT; + n_id = BACKSQL_ENTRYID_INIT; + backsql_srch_info bsi = { 0 }; backsql_oc_map_rec *oc = NULL; - struct berval p_dn = BER_BVNULL, p_ndn = BER_BVNULL, + struct berval pdn = BER_BVNULL, pndn = BER_BVNULL, *new_pdn = NULL, *new_npdn = NULL, new_dn = BER_BVNULL, new_ndn = BER_BVNULL, realnew_dn = BER_BVNULL; LDAPRDN new_rdn = NULL; LDAPRDN old_rdn = NULL; - Entry e = { 0 }; + Entry r = { 0 }, + p = { 0 }, + n = { 0 }, + *e = NULL; + int manageDSAit = get_manageDSAit( op ); Modifications *mod = NULL; struct berval *newSuperior = op->oq_modrdn.rs_newSup; char *next; @@ -55,6 +59,7 @@ backsql_modrdn( Operation *op, SlapReply *rs ) "newrdn=\"%s\", newSuperior=\"%s\"\n", op->o_req_dn.bv_val, op->oq_modrdn.rs_newrdn.bv_val, newSuperior ? newSuperior->bv_val : "(NULL)" ); + rs->sr_err = backsql_get_db_conn( op, &dbh ); if ( rs->sr_err != LDAP_SUCCESS ) { Debug( LDAP_DEBUG_TRACE, " backsql_modrdn(): " @@ -62,19 +67,50 @@ backsql_modrdn( Operation *op, SlapReply *rs ) 0, 0, 0 ); rs->sr_text = ( rs->sr_err == LDAP_OTHER ) ? "SQL-backend error" : NULL; - send_ldap_result( op, rs ); - return 1; + e = NULL; + goto done; } - rs->sr_err = backsql_dn2id( op, rs, dbh, &op->o_req_ndn, &e_id, 0, 1 ); - if ( rs->sr_err != LDAP_SUCCESS ) { - Debug( LDAP_DEBUG_TRACE, " backsql_modrdn(): " - "could not lookup entry id (%d)\n", - rs->sr_err, 0, 0 ); - rs->sr_text = ( rs->sr_err == LDAP_OTHER ) - ? "SQL-backend error" : NULL; - send_ldap_result( op, rs ); - return 1; + bsi.bsi_e = &r; + rs->sr_err = backsql_init_search( &bsi, &op->o_req_ndn, + LDAP_SCOPE_BASE, + SLAP_NO_LIMIT, SLAP_NO_LIMIT, + (time_t)(-1), NULL, dbh, op, rs, + slap_anlist_all_attributes, + ( BACKSQL_ISF_MATCHED | BACKSQL_ISF_GET_ENTRY ) ); + switch ( rs->sr_err ) { + case LDAP_SUCCESS: + break; + + case LDAP_REFERRAL: + if ( !BER_BVISNULL( &bsi.bsi_e->e_nname ) && + dn_match( &op->o_req_ndn, &bsi.bsi_e->e_nname ) + && manageDSAit ) + { + rs->sr_err = LDAP_SUCCESS; + rs->sr_text = NULL; + rs->sr_matched = NULL; + if ( rs->sr_ref ) { + ber_bvarray_free( rs->sr_ref ); + rs->sr_ref = NULL; + } + break; + } + e = &r; + /* fallthru */ + + default: + Debug( LDAP_DEBUG_TRACE, "backsql_modrdn(): " + "could not retrieve modrdnDN ID - no such entry\n", + 0, 0, 0 ); + if ( !BER_BVISNULL( &r.e_nname ) ) { + /* FIXME: should always be true! */ + e = &r; + + } else { + e = NULL; + } + goto done; } #ifdef BACKSQL_ARBITRARY_KEY @@ -85,58 +121,90 @@ backsql_modrdn( Operation *op, SlapReply *rs ) e_id.eid_id, 0, 0 ); #endif /* ! BACKSQL_ARBITRARY_KEY */ + if ( get_assert( op ) && + ( test_filter( op, &r, get_assertion( op ) ) + != LDAP_COMPARE_TRUE ) ) + { + rs->sr_err = LDAP_ASSERTION_FAILED; + e = &r; + goto done; + } + if ( backsql_has_children( bi, dbh, &op->o_req_ndn ) == LDAP_COMPARE_TRUE ) { Debug( LDAP_DEBUG_TRACE, " backsql_modrdn(): " "entry \"%s\" has children\n", op->o_req_dn.bv_val, 0, 0 ); rs->sr_err = LDAP_NOT_ALLOWED_ON_NONLEAF; rs->sr_text = "subtree rename not supported"; - send_ldap_result( op, rs ); - return 1; + e = &r; + goto done; } /* * Check for entry access to target */ - e.e_name = op->o_req_dn; - e.e_nname = op->o_req_ndn; - /* FIXME: need the whole entry (ITS#3480) */ - if ( !access_allowed( op, &e, slap_schema.si_ad_entry, + if ( !access_allowed( op, &r, slap_schema.si_ad_entry, NULL, ACL_WRITE, NULL ) ) { Debug( LDAP_DEBUG_TRACE, " no access to entry\n", 0, 0, 0 ); rs->sr_err = LDAP_INSUFFICIENT_ACCESS; - goto modrdn_return; + goto done; } - dnParent( &op->o_req_dn, &p_dn ); - dnParent( &op->o_req_ndn, &p_ndn ); + dnParent( &op->o_req_dn, &pdn ); + dnParent( &op->o_req_ndn, &pndn ); /* * namingContext "" is not supported */ - if ( BER_BVISEMPTY( &p_dn ) ) { + if ( BER_BVISEMPTY( &pdn ) ) { Debug( LDAP_DEBUG_TRACE, " backsql_modrdn(): " "parent is \"\" - aborting\n", 0, 0, 0 ); rs->sr_err = LDAP_UNWILLING_TO_PERFORM; rs->sr_text = "not allowed within namingContext"; - send_ldap_result( op, rs ); - goto modrdn_return; + e = NULL; + goto done; } /* * Check for children access to parent */ - e.e_name = p_dn; - e.e_nname = p_ndn; - /* FIXME: need the whole entry (ITS#3480) */ - if ( !access_allowed( op, &e, slap_schema.si_ad_children, + bsi.bsi_e = &p; + e_id = bsi.bsi_base_id; + rs->sr_err = backsql_init_search( &bsi, &pndn, + LDAP_SCOPE_BASE, + SLAP_NO_LIMIT, SLAP_NO_LIMIT, + (time_t)(-1), NULL, dbh, op, rs, + slap_anlist_all_attributes, + BACKSQL_ISF_GET_ENTRY ); + +#ifdef BACKSQL_ARBITRARY_KEY + Debug( LDAP_DEBUG_TRACE, " backsql_modrdn(): " + "old parent entry id is %s\n", + bsi.bsi_base_id.eid_id.bv_val, 0, 0 ); +#else /* ! BACKSQL_ARBITRARY_KEY */ + Debug( LDAP_DEBUG_TRACE, " backsql_modrdn(): " + "old parent entry id is %ld\n", + bsi.bsi_base_id.eid_id, 0, 0 ); +#endif /* ! BACKSQL_ARBITRARY_KEY */ + + if ( rs->sr_err != LDAP_SUCCESS ) { + Debug( LDAP_DEBUG_TRACE, "backsql_modrdn(): " + "could not retrieve renameDN ID - no such entry\n", + 0, 0, 0 ); + e = &p; + goto done; + } + + if ( !access_allowed( op, &p, slap_schema.si_ad_children, NULL, ACL_WRITE, NULL ) ) { Debug( LDAP_DEBUG_TRACE, " no access to parent\n", 0, 0, 0 ); rs->sr_err = LDAP_INSUFFICIENT_ACCESS; - goto modrdn_return; + goto done; } if ( newSuperior ) { + (void)backsql_free_entryID( op, &bsi.bsi_base_id, 0 ); + /* * namingContext "" is not supported */ @@ -145,8 +213,8 @@ backsql_modrdn( Operation *op, SlapReply *rs ) "newSuperior is \"\" - aborting\n", 0, 0, 0 ); rs->sr_err = LDAP_UNWILLING_TO_PERFORM; rs->sr_text = "not allowed within namingContext"; - send_ldap_result( op, rs ); - goto modrdn_return; + e = NULL; + goto done; } new_pdn = newSuperior; @@ -155,24 +223,50 @@ backsql_modrdn( Operation *op, SlapReply *rs ) /* * Check for children access to new parent */ - e.e_name = *new_pdn; - e.e_nname = *new_npdn; - /* FIXME: need the whole entry (ITS#3480) */ - if ( !access_allowed( op, &e, slap_schema.si_ad_children, + bsi.bsi_e = &n; + rs->sr_err = backsql_init_search( &bsi, new_npdn, + LDAP_SCOPE_BASE, + SLAP_NO_LIMIT, SLAP_NO_LIMIT, + (time_t)(-1), NULL, dbh, op, rs, + slap_anlist_all_attributes, + ( BACKSQL_ISF_MATCHED | BACKSQL_ISF_GET_ENTRY ) ); + if ( rs->sr_err != LDAP_SUCCESS ) { + Debug( LDAP_DEBUG_TRACE, "backsql_modrdn(): " + "could not retrieve renameDN ID - no such entry\n", + 0, 0, 0 ); + e = &n; + goto done; + } + + n_id = bsi.bsi_base_id; + +#ifdef BACKSQL_ARBITRARY_KEY + Debug( LDAP_DEBUG_TRACE, " backsql_modrdn(): " + "new parent entry id=%s\n", + n_id.eid_id.bv_val, 0, 0 ); +#else /* ! BACKSQL_ARBITRARY_KEY */ + Debug( LDAP_DEBUG_TRACE, " backsql_modrdn(): " + "new parent entry id=%ld\n", + n_id.eid_id, 0, 0 ); +#endif /* ! BACKSQL_ARBITRARY_KEY */ + + if ( !access_allowed( op, &n, slap_schema.si_ad_children, NULL, ACL_WRITE, NULL ) ) { Debug( LDAP_DEBUG_TRACE, " backsql_modrdn(): " "no access to new parent \"%s\"\n", new_pdn->bv_val, 0, 0 ); rs->sr_err = LDAP_INSUFFICIENT_ACCESS; - goto modrdn_return; + e = &n; + goto done; } } else { - new_pdn = &p_dn; - new_npdn = &p_ndn; + n_id = bsi.bsi_base_id; + new_pdn = &pdn; + new_npdn = &pndn; } - if ( newSuperior && dn_match( &p_ndn, new_npdn ) ) { + if ( newSuperior && dn_match( &pndn, new_npdn ) ) { Debug( LDAP_DEBUG_TRACE, " backsql_modrdn(): " "newSuperior is equal to old parent - ignored\n", 0, 0, 0 ); @@ -185,64 +279,18 @@ backsql_modrdn( Operation *op, SlapReply *rs ) "- aborting\n", 0, 0, 0 ); rs->sr_err = LDAP_OTHER; rs->sr_text = "newSuperior is equal to old DN"; - send_ldap_result( op, rs ); - goto modrdn_return; + e = &r; + goto done; } build_new_dn( &new_dn, new_pdn, &op->oq_modrdn.rs_newrdn, op->o_tmpmemctx ); - rs->sr_err = dnNormalize( 0, NULL, NULL, &new_dn, &new_ndn, + build_new_dn( &new_ndn, new_npdn, &op->oq_modrdn.rs_nnewrdn, op->o_tmpmemctx ); - if ( rs->sr_err != LDAP_SUCCESS ) { - Debug( LDAP_DEBUG_TRACE, " backsql_modrdn(): " - "new dn is invalid (\"%s\") - aborting\n", - new_dn.bv_val, 0, 0 ); - rs->sr_text = "unable to build new DN"; - send_ldap_result( op, rs ); - goto modrdn_return; - } Debug( LDAP_DEBUG_TRACE, " backsql_modrdn(): new entry dn is \"%s\"\n", new_dn.bv_val, 0, 0 ); - rs->sr_err = backsql_dn2id( op, rs, dbh, &p_ndn, &pe_id, 0, 1 ); - if ( rs->sr_err != LDAP_SUCCESS ) { - Debug( LDAP_DEBUG_TRACE, " backsql_modrdn(): " - "could not lookup old parent entry id\n", 0, 0, 0 ); - rs->sr_text = ( rs->sr_err == LDAP_OTHER ) - ? "SQL-backend error" : NULL; - send_ldap_result( op, rs ); - goto modrdn_return; - } - -#ifdef BACKSQL_ARBITRARY_KEY - Debug( LDAP_DEBUG_TRACE, " backsql_modrdn(): " - "old parent entry id is %s\n", pe_id.eid_id.bv_val, 0, 0 ); -#else /* ! BACKSQL_ARBITRARY_KEY */ - Debug( LDAP_DEBUG_TRACE, " backsql_modrdn(): " - "old parent entry id is %ld\n", pe_id.eid_id, 0, 0 ); -#endif /* ! BACKSQL_ARBITRARY_KEY */ - - (void)backsql_free_entryID( op, &pe_id, 0 ); - - rs->sr_err = backsql_dn2id( op, rs, dbh, new_npdn, &new_pe_id, 0, 1 ); - if ( rs->sr_err != LDAP_SUCCESS ) { - Debug( LDAP_DEBUG_TRACE, " backsql_modrdn(): " - "could not lookup new parent entry id\n", 0, 0, 0 ); - rs->sr_text = ( rs->sr_err == LDAP_OTHER ) - ? "SQL-backend error" : NULL; - send_ldap_result( op, rs ); - goto modrdn_return; - } - -#ifdef BACKSQL_ARBITRARY_KEY - Debug( LDAP_DEBUG_TRACE, " backsql_modrdn(): " - "new parent entry id=%s\n", new_pe_id.eid_id.bv_val, 0, 0 ); -#else /* ! BACKSQL_ARBITRARY_KEY */ - Debug( LDAP_DEBUG_TRACE, " backsql_modrdn(): " - "new parent entry id=%ld\n", new_pe_id.eid_id, 0, 0 ); -#endif /* ! BACKSQL_ARBITRARY_KEY */ - Debug( LDAP_DEBUG_TRACE, " backsql_modrdn(): " "executing delentry_stmt\n", 0, 0, 0 ); @@ -257,6 +305,7 @@ backsql_modrdn( Operation *op, SlapReply *rs ) rs->sr_text = "SQL-backend error"; rs->sr_err = LDAP_OTHER; + e = NULL; goto done; } @@ -267,12 +316,12 @@ backsql_modrdn( Operation *op, SlapReply *rs ) "error binding entry ID parameter " "for objectClass %s\n", oc->bom_oc->soc_cname.bv_val, 0, 0 ); - backsql_PrintErrors( bi->sql_db_env, dbh, - sth, rc ); + backsql_PrintErrors( bi->sql_db_env, dbh, sth, rc ); SQLFreeStmt( sth, SQL_DROP ); rs->sr_text = "SQL-backend error"; rs->sr_err = LDAP_OTHER; + e = NULL; goto done; } @@ -285,7 +334,7 @@ backsql_modrdn( Operation *op, SlapReply *rs ) SQLFreeStmt( sth, SQL_DROP ); rs->sr_err = LDAP_OTHER; rs->sr_text = "SQL-backend error"; - send_ldap_result( op, rs ); + e = NULL; goto done; } @@ -304,6 +353,7 @@ backsql_modrdn( Operation *op, SlapReply *rs ) rs->sr_text = "SQL-backend error"; rs->sr_err = LDAP_OTHER; + e = NULL; goto done; } @@ -316,6 +366,7 @@ backsql_modrdn( Operation *op, SlapReply *rs ) rs->sr_text = "SQL-backend error"; rs->sr_err = LDAP_OTHER; + e = NULL; goto done; } @@ -331,6 +382,7 @@ backsql_modrdn( Operation *op, SlapReply *rs ) rs->sr_text = "SQL-backend error"; rs->sr_err = LDAP_OTHER; + e = NULL; goto done; } @@ -346,10 +398,11 @@ backsql_modrdn( Operation *op, SlapReply *rs ) rs->sr_text = "SQL-backend error"; rs->sr_err = LDAP_OTHER; + e = NULL; goto done; } - rc = backsql_BindParamID( sth, 3, SQL_PARAM_INPUT, &new_pe_id.eid_id ); + rc = backsql_BindParamID( sth, 3, SQL_PARAM_INPUT, &n_id.eid_id ); if ( rc != SQL_SUCCESS ) { Debug( LDAP_DEBUG_TRACE, " backsql_add_attr(): " @@ -361,6 +414,7 @@ backsql_modrdn( Operation *op, SlapReply *rs ) rs->sr_text = "SQL-backend error"; rs->sr_err = LDAP_OTHER; + e = NULL; goto done; } @@ -376,6 +430,7 @@ backsql_modrdn( Operation *op, SlapReply *rs ) rs->sr_text = "SQL-backend error"; rs->sr_err = LDAP_OTHER; + e = NULL; goto done; } @@ -387,7 +442,7 @@ backsql_modrdn( Operation *op, SlapReply *rs ) SQLFreeStmt( sth, SQL_DROP ); rs->sr_err = LDAP_OTHER; rs->sr_text = "SQL-backend error"; - send_ldap_result( op, rs ); + e = NULL; goto done; } SQLFreeStmt( sth, SQL_DROP ); @@ -401,15 +456,15 @@ backsql_modrdn( Operation *op, SlapReply *rs ) { Debug( LDAP_DEBUG_TRACE, " backsql_modrdn: can't figure out " - "type(s)/values(s) of newrdn\n", + "type(s)/values(s) of new_rdn\n", 0, 0, 0 ); rs->sr_err = LDAP_INVALID_DN_SYNTAX; + e = &r; goto done; } - Debug( LDAP_DEBUG_TRACE, - " backsql_modrdn: new_rdn_type=\"%s\", " - "new_rdn_val=\"%s\"\n", + Debug( LDAP_DEBUG_TRACE, "backsql_modrdn: " + "new_rdn_type=\"%s\", new_rdn_val=\"%s\"\n", new_rdn[ 0 ]->la_attr.bv_val, new_rdn[ 0 ]->la_value.bv_val, 0 ); @@ -422,38 +477,53 @@ backsql_modrdn( Operation *op, SlapReply *rs ) "the old_rdn type(s)/value(s)\n", 0, 0, 0 ); rs->sr_err = LDAP_OTHER; - goto done; + e = NULL; + goto done; } } - e.e_name = new_dn; - e.e_nname = new_ndn; - rs->sr_err = slap_modrdn2mods( op, rs, &e, old_rdn, new_rdn, &mod ); + rs->sr_err = slap_modrdn2mods( op, rs, &r, old_rdn, new_rdn, &mod ); if ( rs->sr_err != LDAP_SUCCESS ) { - goto modrdn_return; - } - - /* FIXME: need the whole entry (ITS#3480) */ - if ( !acl_check_modlist( op, &e, mod )) { - rs->sr_err = LDAP_INSUFFICIENT_ACCESS; - goto modrdn_return; + e = &r; + goto done; } oc = backsql_id2oc( bi, e_id.eid_oc_id ); rs->sr_err = backsql_modify_internal( op, rs, dbh, oc, &e_id, mod ); + e = &r; done:; +#ifdef SLAP_ACL_HONOR_DISCLOSE + if ( e != NULL ) { + if ( !access_allowed( op, e, slap_schema.si_ad_entry, NULL, + ACL_DISCLOSE, NULL ) ) + { + rs->sr_err = LDAP_NO_SUCH_OBJECT; + rs->sr_text = NULL; + rs->sr_matched = NULL; + if ( rs->sr_ref ) { + ber_bvarray_free( rs->sr_ref ); + rs->sr_ref = NULL; + } + } + } +#endif /* SLAP_ACL_HONOR_DISCLOSE */ + + send_ldap_result( op, rs ); + /* * Commit only if all operations succeed */ - if ( rs->sr_err == LDAP_SUCCESS && !op->o_noop ) { - SQLTransact( SQL_NULL_HENV, dbh, SQL_COMMIT ); + if ( sth != SQL_NULL_HSTMT ) { + SQLUSMALLINT CompletionType = SQL_ROLLBACK; + + if ( rs->sr_err == LDAP_SUCCESS && !op->o_noop ) { + CompletionType = SQL_COMMIT; + } - } else { - SQLTransact( SQL_NULL_HENV, dbh, SQL_ROLLBACK ); + SQLTransact( SQL_NULL_HENV, dbh, CompletionType ); } -modrdn_return:; if ( !BER_BVISNULL( &realnew_dn ) && realnew_dn.bv_val != new_dn.bv_val ) { ch_free( realnew_dn.bv_val ); } @@ -481,11 +551,28 @@ modrdn_return:; } } - (void)backsql_free_entryID( op, &new_pe_id, 0 ); + if ( !BER_BVISNULL( &e_id.eid_ndn ) ) { + (void)backsql_free_entryID( op, &e_id, 0 ); + } + + if ( !BER_BVISNULL( &n_id.eid_ndn ) ) { + (void)backsql_free_entryID( op, &n_id, 0 ); + } - send_ldap_result( op, rs ); + if ( !BER_BVISNULL( &r.e_nname ) ) { + entry_clean( &r ); + } + + if ( !BER_BVISNULL( &p.e_nname ) ) { + entry_clean( &p ); + } + + if ( !BER_BVISNULL( &n.e_nname ) ) { + entry_clean( &n ); + } Debug( LDAP_DEBUG_TRACE, "<==backsql_modrdn()\n", 0, 0, 0 ); - return op->o_noop; + + return rs->sr_err; } diff --git a/servers/slapd/back-sql/proto-sql.h b/servers/slapd/back-sql/proto-sql.h index 86657d5b4f..e3cd9b82ff 100644 --- a/servers/slapd/back-sql/proto-sql.h +++ b/servers/slapd/back-sql/proto-sql.h @@ -237,7 +237,7 @@ extern char struct berbuf * backsql_strcat( struct berbuf *dest, ... ); struct berbuf * backsql_strfcat( struct berbuf *dest, const char *fmt, ... ); -int backsql_entry_addattr( Entry *e, struct berval *at_name, +int backsql_entry_addattr( Entry *e, AttributeDescription *ad, struct berval *at_val, void *memctx ); int backsql_merge_from_clause( struct berbuf *dest_from, diff --git a/servers/slapd/back-sql/schema-map.c b/servers/slapd/back-sql/schema-map.c index 2dbd05915e..618daf5d33 100644 --- a/servers/slapd/back-sql/schema-map.c +++ b/servers/slapd/back-sql/schema-map.c @@ -154,7 +154,30 @@ backsql_make_attr_query( #endif /* ! BACKSQL_ALIASING_QUOTE */ at_map->bam_query = bb.bb_val.bv_val; - + +#ifdef BACKSQL_COUNTQUERY + /* Query to count how many rows will be returned. */ + BER_BVZERO( &bb.bb_val ); + bb.bb_len = 0; + backsql_strfcat( &bb, "lblbcbl", + (ber_len_t)STRLENOF( "SELECT COUNT(*) FROM " ), + "SELECT COUNT(*) FROM ", + &at_map->bam_from_tbls, + (ber_len_t)STRLENOF( " WHERE " ), " WHERE ", + &oc_map->bom_keytbl, + '.', + &oc_map->bom_keycol, + (ber_len_t)STRLENOF( "=?" ), "=?" ); + + if ( !BER_BVISNULL( &at_map->bam_join_where ) ) { + backsql_strfcat( &bb, "lb", + (ber_len_t)STRLENOF( " AND " ), " AND ", + &at_map->bam_join_where ); + } + + at_map->bam_countquery = bb.bb_val.bv_val; +#endif /* BACKSQL_COUNTQUERY */ + return 0; } @@ -826,7 +849,7 @@ supad2at_f( void *v_at, void *v_arg ) struct supad2at_t *va = (struct supad2at_t *)v_arg; if ( is_at_subtype( at->bam_ad->ad_type, va->ad->ad_type ) ) { - backsql_at_map_rec **ret; + backsql_at_map_rec **ret = NULL; unsigned i; /* if already listed, holler! (should never happen) */ @@ -843,9 +866,11 @@ supad2at_f( void *v_at, void *v_arg ) } ret = ch_realloc( va->ret, - sizeof( backsql_at_map_rec *) * ( va->n + 2 ) ); + sizeof( backsql_at_map_rec * ) * ( va->n + 2 ) ); if ( ret == NULL ) { ch_free( va->ret ); + va->ret = NULL; + va->n = 0; return SUPAD2AT_STOP; } @@ -867,7 +892,7 @@ int backsql_supad2at( backsql_oc_map_rec *objclass, AttributeDescription *supad, backsql_at_map_rec ***pret ) { - struct supad2at_t va; + struct supad2at_t va = { 0 }; int rc; assert( objclass ); @@ -876,9 +901,7 @@ backsql_supad2at( backsql_oc_map_rec *objclass, AttributeDescription *supad, *pret = NULL; - va.ret = NULL; va.ad = supad; - va.n = 0; rc = avl_apply( objclass->bom_attrs, supad2at_f, &va, SUPAD2AT_STOP, AVL_INORDER ); diff --git a/servers/slapd/back-sql/search.c b/servers/slapd/back-sql/search.c index e501d1b3bc..d6524d1609 100644 --- a/servers/slapd/back-sql/search.c +++ b/servers/slapd/back-sql/search.c @@ -271,40 +271,50 @@ backsql_init_search( if ( BACKSQL_IS_GET_ID( flags ) ) { int matched = BACKSQL_IS_MATCHED( flags ); int getentry = BACKSQL_IS_GET_ENTRY( flags ); + int gotit = 0; assert( op->o_bd->be_private ); rc = backsql_dn2id( op, rs, dbh, nbase, &bsi->bsi_base_id, matched, 1 ); - + + /* the entry is collected either if requested for by getentry + * or if get noSuchObject and requested to climb the tree, + * so that a matchedDN or a referral can be returned */ if ( ( rc == LDAP_NO_SUCH_OBJECT && matched ) || getentry ) { if ( !BER_BVISNULL( &bsi->bsi_base_id.eid_ndn ) ) { assert( bsi->bsi_e != NULL ); - + + if ( dn_match( nbase, &bsi->bsi_base_id.eid_ndn ) ) + { + gotit = 1; + } + /* * let's see if it is a referral and, in case, get it */ backsql_attrlist_add( bsi, slap_schema.si_ad_ref ); rc = backsql_id2entry( bsi, &bsi->bsi_base_id ); - if ( rc == LDAP_SUCCESS && is_entry_referral( bsi->bsi_e ) ) - { - BerVarray erefs = get_entry_referrals( op, bsi->bsi_e ); - if ( erefs ) { - rc = rs->sr_err = LDAP_REFERRAL; - rs->sr_ref = referral_rewrite( erefs, - &bsi->bsi_e->e_nname, - &op->o_req_dn, - scope ); - ber_bvarray_free( erefs ); + if ( rc == LDAP_SUCCESS ) { + if ( is_entry_referral( bsi->bsi_e ) ) + { + BerVarray erefs = get_entry_referrals( op, bsi->bsi_e ); + if ( erefs ) { + rc = rs->sr_err = LDAP_REFERRAL; + rs->sr_ref = referral_rewrite( erefs, + &bsi->bsi_e->e_nname, + &op->o_req_dn, + scope ); + ber_bvarray_free( erefs ); + + } else { + rc = rs->sr_err = LDAP_OTHER; + rs->sr_text = "bad referral object"; + } - } else { - rc = rs->sr_err = LDAP_OTHER; - rs->sr_text = "bad referral object"; + } else if ( !gotit ) { + rc = rs->sr_err = LDAP_NO_SUCH_OBJECT; } - - } else { - rc = rs->sr_err = getentry ? - LDAP_SUCCESS : LDAP_NO_SUCH_OBJECT; } } else { @@ -1868,18 +1878,27 @@ backsql_search( Operation *op, SlapReply *rs ) * on searchBase object */ else { slap_mask_t mask; - - /* FIXME: need the whole entry (ITS#3480) */ + + if ( get_assert( op ) && + ( test_filter( op, &base_entry, get_assertion( op ) ) + != LDAP_COMPARE_TRUE ) ) + { + rs->sr_err = LDAP_ASSERTION_FAILED; + + } if ( ! access_allowed_mask( op, &base_entry, slap_schema.si_ad_entry, NULL, ACL_SEARCH, NULL, &mask ) ) { + if ( rs->sr_err == LDAP_SUCCESS ) { + rs->sr_err = LDAP_INSUFFICIENT_ACCESS; + } + } + + if ( rs->sr_err != LDAP_SUCCESS ) { if ( !ACL_GRANT( mask, ACL_DISCLOSE ) ) { rs->sr_err = LDAP_NO_SUCH_OBJECT; rs->sr_text = NULL; - - } else { - rs->sr_err = LDAP_INSUFFICIENT_ACCESS; } send_ldap_result( op, rs ); goto done; diff --git a/servers/slapd/back-sql/util.c b/servers/slapd/back-sql/util.c index cf2d222ce4..337b6bf975 100644 --- a/servers/slapd/back-sql/util.c +++ b/servers/slapd/back-sql/util.c @@ -245,44 +245,33 @@ backsql_strfcat( struct berbuf *dest, const char *fmt, ... ) int backsql_entry_addattr( - Entry *e, - struct berval *at_name, - struct berval *at_val, - void *memctx ) + Entry *e, + AttributeDescription *ad, + struct berval *val, + void *memctx ) { - AttributeDescription *ad; int rc; - const char *text; #ifdef BACKSQL_TRACE - Debug( LDAP_DEBUG_TRACE, "backsql_entry_addattr(): " - "at_name=\"%s\", at_val=\"%s\"\n", - at_name->bv_val, at_val->bv_val, 0 ); + Debug( LDAP_DEBUG_TRACE, "backsql_entry_addattr(\"%s\"): %s=%s\n", + e->e_name.bv_val, ad->ad_cname->bv_val, val->bv_val ); #endif /* BACKSQL_TRACE */ - ad = NULL; - rc = slap_bv2ad( at_name, &ad, &text ); - if ( rc != LDAP_SUCCESS ) { - Debug( LDAP_DEBUG_TRACE, "backsql_entry_addattr(): " - "failed to find AttributeDescription for \"%s\"\n", - at_name->bv_val, 0, 0 ); - return 0; - } - - rc = attr_merge_normalize_one( e, ad, at_val, memctx ); + rc = attr_merge_normalize_one( e, ad, val, memctx ); - if ( rc != 0 ) { - Debug( LDAP_DEBUG_TRACE, "backsql_entry_addattr(): " + if ( rc != LDAP_SUCCESS ) { + Debug( LDAP_DEBUG_TRACE, "backsql_entry_addattr(\"%s\"): " "failed to merge value \"%s\" for attribute \"%s\"\n", - at_val->bv_val, at_name->bv_val, 0 ); - return 0; + e->e_name.bv_val, val->bv_val, ad->ad_cname.bv_val ); + return rc; } #ifdef BACKSQL_TRACE - Debug( LDAP_DEBUG_TRACE, "<==backsql_query_addattr()\n", 0, 0, 0 ); + Debug( LDAP_DEBUG_TRACE, "<==backsql_entry_addattr(\"%s\")\n", + e->e_name.bv_val, 0, 0 ); #endif /* BACKSQL_TRACE */ - return 1; + return LDAP_SUCCESS; } static char * -- 2.39.5