2 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
4 * Copyright 1999-2006 The OpenLDAP Foundation.
5 * Portions Copyright 1999 Dmitry Kovalev.
6 * Portions Copyright 2002 Pierangelo Masarati.
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted only as authorized by the OpenLDAP
13 * A copy of this license is available in the file LICENSE in the
14 * top-level directory of the distribution or, alternatively, at
15 * <http://www.OpenLDAP.org/license.html>.
18 * This work was initially developed by Dmitry Kovalev for inclusion
19 * by OpenLDAP Software. Additional significant contributors include
20 * Pierangelo Masarati.
26 #include <sys/types.h>
27 #include "ac/string.h"
30 #include "proto-sql.h"
33 backsql_modrdn( Operation *op, SlapReply *rs )
35 backsql_info *bi = (backsql_info*)op->o_bd->be_private;
36 SQLHDBC dbh = SQL_NULL_HDBC;
37 SQLHSTMT sth = SQL_NULL_HSTMT;
39 backsql_entryID e_id = BACKSQL_ENTRYID_INIT,
40 n_id = BACKSQL_ENTRYID_INIT;
41 backsql_srch_info bsi = { 0 };
42 backsql_oc_map_rec *oc = NULL;
43 struct berval pdn = BER_BVNULL, pndn = BER_BVNULL,
44 *new_pdn = NULL, *new_npdn = NULL,
45 new_dn = BER_BVNULL, new_ndn = BER_BVNULL,
46 realnew_dn = BER_BVNULL;
51 int manageDSAit = get_manageDSAit( op );
52 struct berval *newSuperior = op->oq_modrdn.rs_newSup;
55 Debug( LDAP_DEBUG_TRACE, "==>backsql_modrdn() renaming entry \"%s\", "
56 "newrdn=\"%s\", newSuperior=\"%s\"\n",
57 op->o_req_dn.bv_val, op->oq_modrdn.rs_newrdn.bv_val,
58 newSuperior ? newSuperior->bv_val : "(NULL)" );
60 rs->sr_err = backsql_get_db_conn( op, &dbh );
61 if ( rs->sr_err != LDAP_SUCCESS ) {
62 Debug( LDAP_DEBUG_TRACE, " backsql_modrdn(): "
63 "could not get connection handle - exiting\n",
65 rs->sr_text = ( rs->sr_err == LDAP_OTHER )
66 ? "SQL-backend error" : NULL;
72 rs->sr_err = backsql_init_search( &bsi, &op->o_req_ndn,
74 (time_t)(-1), NULL, dbh, op, rs,
75 slap_anlist_all_attributes,
76 ( BACKSQL_ISF_MATCHED | BACKSQL_ISF_GET_ENTRY ) );
77 switch ( rs->sr_err ) {
82 if ( manageDSAit && !BER_BVISNULL( &bsi.bsi_e->e_nname ) &&
83 dn_match( &op->o_req_ndn, &bsi.bsi_e->e_nname ) )
85 rs->sr_err = LDAP_SUCCESS;
87 rs->sr_matched = NULL;
89 ber_bvarray_free( rs->sr_ref );
98 Debug( LDAP_DEBUG_TRACE, "backsql_modrdn(): "
99 "could not retrieve modrdnDN ID - no such entry\n",
101 if ( !BER_BVISNULL( &r.e_nname ) ) {
102 /* FIXME: should always be true! */
111 #ifdef BACKSQL_ARBITRARY_KEY
112 Debug( LDAP_DEBUG_TRACE, " backsql_modrdn(): entry id=%s\n",
113 e_id.eid_id.bv_val, 0, 0 );
114 #else /* ! BACKSQL_ARBITRARY_KEY */
115 Debug( LDAP_DEBUG_TRACE, " backsql_modrdn(): entry id=%ld\n",
117 #endif /* ! BACKSQL_ARBITRARY_KEY */
119 if ( get_assert( op ) &&
120 ( test_filter( op, &r, get_assertion( op ) )
121 != LDAP_COMPARE_TRUE ) )
123 rs->sr_err = LDAP_ASSERTION_FAILED;
128 if ( backsql_has_children( op, dbh, &op->o_req_ndn ) == LDAP_COMPARE_TRUE ) {
129 Debug( LDAP_DEBUG_TRACE, " backsql_modrdn(): "
130 "entry \"%s\" has children\n",
131 op->o_req_dn.bv_val, 0, 0 );
132 rs->sr_err = LDAP_NOT_ALLOWED_ON_NONLEAF;
133 rs->sr_text = "subtree rename not supported";
139 * Check for entry access to target
141 if ( !access_allowed( op, &r, slap_schema.si_ad_entry,
142 NULL, ACL_WRITE, NULL ) ) {
143 Debug( LDAP_DEBUG_TRACE, " no access to entry\n", 0, 0, 0 );
144 rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
148 dnParent( &op->o_req_dn, &pdn );
149 dnParent( &op->o_req_ndn, &pndn );
152 * namingContext "" is not supported
154 if ( BER_BVISEMPTY( &pdn ) ) {
155 Debug( LDAP_DEBUG_TRACE, " backsql_modrdn(): "
156 "parent is \"\" - aborting\n", 0, 0, 0 );
157 rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
158 rs->sr_text = "not allowed within namingContext";
164 * Check for children access to parent
167 e_id = bsi.bsi_base_id;
168 rs->sr_err = backsql_init_search( &bsi, &pndn,
170 (time_t)(-1), NULL, dbh, op, rs,
171 slap_anlist_all_attributes,
172 BACKSQL_ISF_GET_ENTRY );
174 #ifdef BACKSQL_ARBITRARY_KEY
175 Debug( LDAP_DEBUG_TRACE, " backsql_modrdn(): "
176 "old parent entry id is %s\n",
177 bsi.bsi_base_id.eid_id.bv_val, 0, 0 );
178 #else /* ! BACKSQL_ARBITRARY_KEY */
179 Debug( LDAP_DEBUG_TRACE, " backsql_modrdn(): "
180 "old parent entry id is %ld\n",
181 bsi.bsi_base_id.eid_id, 0, 0 );
182 #endif /* ! BACKSQL_ARBITRARY_KEY */
184 if ( rs->sr_err != LDAP_SUCCESS ) {
185 Debug( LDAP_DEBUG_TRACE, "backsql_modrdn(): "
186 "could not retrieve renameDN ID - no such entry\n",
192 if ( !access_allowed( op, &p, slap_schema.si_ad_children, NULL,
193 newSuperior ? ACL_WDEL : ACL_WRITE, NULL ) )
195 Debug( LDAP_DEBUG_TRACE, " no access to parent\n", 0, 0, 0 );
196 rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
201 (void)backsql_free_entryID( op, &bsi.bsi_base_id, 0 );
204 * namingContext "" is not supported
206 if ( BER_BVISEMPTY( newSuperior ) ) {
207 Debug( LDAP_DEBUG_TRACE, " backsql_modrdn(): "
208 "newSuperior is \"\" - aborting\n", 0, 0, 0 );
209 rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
210 rs->sr_text = "not allowed within namingContext";
215 new_pdn = newSuperior;
216 new_npdn = op->oq_modrdn.rs_nnewSup;
219 * Check for children access to new parent
222 rs->sr_err = backsql_init_search( &bsi, new_npdn,
224 (time_t)(-1), NULL, dbh, op, rs,
225 slap_anlist_all_attributes,
226 ( BACKSQL_ISF_MATCHED | BACKSQL_ISF_GET_ENTRY ) );
227 if ( rs->sr_err != LDAP_SUCCESS ) {
228 Debug( LDAP_DEBUG_TRACE, "backsql_modrdn(): "
229 "could not retrieve renameDN ID - no such entry\n",
235 n_id = bsi.bsi_base_id;
237 #ifdef BACKSQL_ARBITRARY_KEY
238 Debug( LDAP_DEBUG_TRACE, " backsql_modrdn(): "
239 "new parent entry id=%s\n",
240 n_id.eid_id.bv_val, 0, 0 );
241 #else /* ! BACKSQL_ARBITRARY_KEY */
242 Debug( LDAP_DEBUG_TRACE, " backsql_modrdn(): "
243 "new parent entry id=%ld\n",
245 #endif /* ! BACKSQL_ARBITRARY_KEY */
247 if ( !access_allowed( op, &n, slap_schema.si_ad_children,
248 NULL, ACL_WADD, NULL ) ) {
249 Debug( LDAP_DEBUG_TRACE, " backsql_modrdn(): "
250 "no access to new parent \"%s\"\n",
251 new_pdn->bv_val, 0, 0 );
252 rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
258 n_id = bsi.bsi_base_id;
263 if ( newSuperior && dn_match( &pndn, new_npdn ) ) {
264 Debug( LDAP_DEBUG_TRACE, " backsql_modrdn(): "
265 "newSuperior is equal to old parent - ignored\n",
270 if ( newSuperior && dn_match( &op->o_req_ndn, new_npdn ) ) {
271 Debug( LDAP_DEBUG_TRACE, " backsql_modrdn(): "
272 "newSuperior is equal to entry being moved "
273 "- aborting\n", 0, 0, 0 );
274 rs->sr_err = LDAP_OTHER;
275 rs->sr_text = "newSuperior is equal to old DN";
280 build_new_dn( &new_dn, new_pdn, &op->oq_modrdn.rs_newrdn,
282 build_new_dn( &new_ndn, new_npdn, &op->oq_modrdn.rs_nnewrdn,
285 Debug( LDAP_DEBUG_TRACE, " backsql_modrdn(): new entry dn is \"%s\"\n",
286 new_dn.bv_val, 0, 0 );
289 if ( backsql_api_dn2odbc( op, rs, &realnew_dn ) ) {
290 Debug( LDAP_DEBUG_TRACE, " backsql_modrdn(\"%s\"): "
291 "backsql_api_dn2odbc(\"%s\") failed\n",
292 op->o_req_dn.bv_val, realnew_dn.bv_val, 0 );
293 SQLFreeStmt( sth, SQL_DROP );
295 rs->sr_text = "SQL-backend error";
296 rs->sr_err = LDAP_OTHER;
301 Debug( LDAP_DEBUG_TRACE, " backsql_modrdn(): "
302 "executing renentry_stmt\n", 0, 0, 0 );
304 rc = backsql_Prepare( dbh, &sth, bi->sql_renentry_stmt, 0 );
305 if ( rc != SQL_SUCCESS ) {
306 Debug( LDAP_DEBUG_TRACE,
307 " backsql_modrdn(): "
308 "error preparing renentry_stmt\n", 0, 0, 0 );
309 backsql_PrintErrors( bi->sql_db_env, dbh,
312 rs->sr_text = "SQL-backend error";
313 rs->sr_err = LDAP_OTHER;
318 rc = backsql_BindParamBerVal( sth, 1, SQL_PARAM_INPUT, &realnew_dn );
319 if ( rc != SQL_SUCCESS ) {
320 Debug( LDAP_DEBUG_TRACE,
321 " backsql_add_attr(): "
322 "error binding DN parameter for objectClass %s\n",
323 oc->bom_oc->soc_cname.bv_val, 0, 0 );
324 backsql_PrintErrors( bi->sql_db_env, dbh,
326 SQLFreeStmt( sth, SQL_DROP );
328 rs->sr_text = "SQL-backend error";
329 rs->sr_err = LDAP_OTHER;
334 rc = backsql_BindParamID( sth, 2, SQL_PARAM_INPUT, &n_id.eid_id );
335 if ( rc != SQL_SUCCESS ) {
336 Debug( LDAP_DEBUG_TRACE,
337 " backsql_add_attr(): "
338 "error binding parent ID parameter for objectClass %s\n",
339 oc->bom_oc->soc_cname.bv_val, 0, 0 );
340 backsql_PrintErrors( bi->sql_db_env, dbh,
342 SQLFreeStmt( sth, SQL_DROP );
344 rs->sr_text = "SQL-backend error";
345 rs->sr_err = LDAP_OTHER;
350 rc = backsql_BindParamID( sth, 3, SQL_PARAM_INPUT, &e_id.eid_keyval );
351 if ( rc != SQL_SUCCESS ) {
352 Debug( LDAP_DEBUG_TRACE,
353 " backsql_add_attr(): "
354 "error binding entry ID parameter for objectClass %s\n",
355 oc->bom_oc->soc_cname.bv_val, 0, 0 );
356 backsql_PrintErrors( bi->sql_db_env, dbh,
358 SQLFreeStmt( sth, SQL_DROP );
360 rs->sr_text = "SQL-backend error";
361 rs->sr_err = LDAP_OTHER;
366 rc = backsql_BindParamID( sth, 4, SQL_PARAM_INPUT, &e_id.eid_id );
367 if ( rc != SQL_SUCCESS ) {
368 Debug( LDAP_DEBUG_TRACE,
369 " backsql_add_attr(): "
370 "error binding ID parameter for objectClass %s\n",
371 oc->bom_oc->soc_cname.bv_val, 0, 0 );
372 backsql_PrintErrors( bi->sql_db_env, dbh,
374 SQLFreeStmt( sth, SQL_DROP );
376 rs->sr_text = "SQL-backend error";
377 rs->sr_err = LDAP_OTHER;
382 rc = SQLExecute( sth );
383 if ( rc != SQL_SUCCESS ) {
384 Debug( LDAP_DEBUG_TRACE, " backsql_modrdn(): "
385 "could not rename ldap_entries record\n", 0, 0, 0 );
386 backsql_PrintErrors( bi->sql_db_env, dbh, sth, rc );
387 SQLFreeStmt( sth, SQL_DROP );
388 rs->sr_err = LDAP_OTHER;
389 rs->sr_text = "SQL-backend error";
393 SQLFreeStmt( sth, SQL_DROP );
395 assert( op->orr_modlist != NULL );
397 slap_mods_opattrs( op, &op->orr_modlist, 1 );
399 oc = backsql_id2oc( bi, e_id.eid_oc_id );
400 rs->sr_err = backsql_modify_internal( op, rs, dbh, oc, &e_id, op->orr_modlist );
401 slap_graduate_commit_csn( op );
402 if ( rs->sr_err != LDAP_SUCCESS ) {
407 if ( BACKSQL_CHECK_SCHEMA( bi ) ) {
408 char textbuf[ SLAP_TEXT_BUFLEN ] = { '\0' };
410 backsql_entry_clean( op, &r );
411 (void)backsql_free_entryID( op, &e_id, 0 );
414 rs->sr_err = backsql_init_search( &bsi, &new_ndn,
416 (time_t)(-1), NULL, dbh, op, rs,
417 slap_anlist_all_attributes,
418 ( BACKSQL_ISF_MATCHED | BACKSQL_ISF_GET_ENTRY ) );
419 switch ( rs->sr_err ) {
424 if ( manageDSAit && !BER_BVISNULL( &bsi.bsi_e->e_nname ) &&
425 dn_match( &new_ndn, &bsi.bsi_e->e_nname ) )
427 rs->sr_err = LDAP_SUCCESS;
429 rs->sr_matched = NULL;
431 ber_bvarray_free( rs->sr_ref );
440 Debug( LDAP_DEBUG_TRACE, "backsql_modrdn(): "
441 "could not retrieve modrdnDN ID - no such entry\n",
443 if ( !BER_BVISNULL( &r.e_nname ) ) {
444 /* FIXME: should always be true! */
453 e_id = bsi.bsi_base_id;
455 rs->sr_err = entry_schema_check( op, &r, NULL, 0,
456 &rs->sr_text, textbuf, sizeof( textbuf ) );
457 if ( rs->sr_err != LDAP_SUCCESS ) {
458 Debug( LDAP_DEBUG_TRACE, " backsql_add(\"%s\"): "
459 "entry failed schema check -- aborting\n",
460 r.e_name.bv_val, 0, 0 );
467 #ifdef SLAP_ACL_HONOR_DISCLOSE
469 if ( !access_allowed( op, e, slap_schema.si_ad_entry, NULL,
470 ACL_DISCLOSE, NULL ) )
472 rs->sr_err = LDAP_NO_SUCH_OBJECT;
474 rs->sr_matched = NULL;
476 ber_bvarray_free( rs->sr_ref );
481 #endif /* SLAP_ACL_HONOR_DISCLOSE */
484 * Commit only if all operations succeed
486 if ( sth != SQL_NULL_HSTMT ) {
487 SQLUSMALLINT CompletionType = SQL_ROLLBACK;
489 if ( rs->sr_err == LDAP_SUCCESS && !op->o_noop ) {
490 CompletionType = SQL_COMMIT;
493 SQLTransact( SQL_NULL_HENV, dbh, CompletionType );
496 send_ldap_result( op, rs );
497 slap_graduate_commit_csn( op );
499 if ( !BER_BVISNULL( &realnew_dn ) && realnew_dn.bv_val != new_dn.bv_val ) {
500 ch_free( realnew_dn.bv_val );
503 if ( !BER_BVISNULL( &new_dn ) ) {
504 slap_sl_free( new_dn.bv_val, op->o_tmpmemctx );
507 if ( !BER_BVISNULL( &new_ndn ) ) {
508 slap_sl_free( new_ndn.bv_val, op->o_tmpmemctx );
511 if ( !BER_BVISNULL( &e_id.eid_ndn ) ) {
512 (void)backsql_free_entryID( op, &e_id, 0 );
515 if ( !BER_BVISNULL( &n_id.eid_ndn ) ) {
516 (void)backsql_free_entryID( op, &n_id, 0 );
519 if ( !BER_BVISNULL( &r.e_nname ) ) {
520 backsql_entry_clean( op, &r );
523 if ( !BER_BVISNULL( &p.e_nname ) ) {
524 backsql_entry_clean( op, &p );
527 if ( !BER_BVISNULL( &n.e_nname ) ) {
528 backsql_entry_clean( op, &n );
532 ber_bvarray_free( rs->sr_ref );
536 Debug( LDAP_DEBUG_TRACE, "<==backsql_modrdn()\n", 0, 0, 0 );