2 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
4 * Copyright 1999-2011 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;
54 Debug( LDAP_DEBUG_TRACE, "==>backsql_modrdn() renaming entry \"%s\", "
55 "newrdn=\"%s\", newSuperior=\"%s\"\n",
56 op->o_req_dn.bv_val, op->oq_modrdn.rs_newrdn.bv_val,
57 newSuperior ? newSuperior->bv_val : "(NULL)" );
59 rs->sr_err = backsql_get_db_conn( op, &dbh );
60 if ( rs->sr_err != LDAP_SUCCESS ) {
61 Debug( LDAP_DEBUG_TRACE, " backsql_modrdn(): "
62 "could not get connection handle - exiting\n",
64 rs->sr_text = ( rs->sr_err == LDAP_OTHER )
65 ? "SQL-backend error" : NULL;
71 rs->sr_err = backsql_init_search( &bsi, &op->o_req_ndn,
73 (time_t)(-1), NULL, dbh, op, rs,
74 slap_anlist_all_attributes,
75 ( BACKSQL_ISF_MATCHED | BACKSQL_ISF_GET_ENTRY | BACKSQL_ISF_GET_OC ) );
76 switch ( rs->sr_err ) {
81 if ( manageDSAit && !BER_BVISNULL( &bsi.bsi_e->e_nname ) &&
82 dn_match( &op->o_req_ndn, &bsi.bsi_e->e_nname ) )
84 rs->sr_err = LDAP_SUCCESS;
86 rs->sr_matched = NULL;
88 ber_bvarray_free( rs->sr_ref );
97 Debug( LDAP_DEBUG_TRACE, "backsql_modrdn(): "
98 "could not retrieve modrdnDN ID - no such entry\n",
100 if ( !BER_BVISNULL( &r.e_nname ) ) {
101 /* FIXME: should always be true! */
110 Debug( LDAP_DEBUG_TRACE,
111 " backsql_modrdn(): entry id=" BACKSQL_IDFMT "\n",
112 BACKSQL_IDARG(e_id.eid_id), 0, 0 );
114 if ( get_assert( op ) &&
115 ( test_filter( op, &r, get_assertion( op ) )
116 != LDAP_COMPARE_TRUE ) )
118 rs->sr_err = LDAP_ASSERTION_FAILED;
123 if ( backsql_has_children( op, dbh, &op->o_req_ndn ) == LDAP_COMPARE_TRUE ) {
124 Debug( LDAP_DEBUG_TRACE, " backsql_modrdn(): "
125 "entry \"%s\" has children\n",
126 op->o_req_dn.bv_val, 0, 0 );
127 rs->sr_err = LDAP_NOT_ALLOWED_ON_NONLEAF;
128 rs->sr_text = "subtree rename not supported";
134 * Check for entry access to target
136 if ( !access_allowed( op, &r, slap_schema.si_ad_entry,
137 NULL, ACL_WRITE, NULL ) ) {
138 Debug( LDAP_DEBUG_TRACE, " no access to entry\n", 0, 0, 0 );
139 rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
143 dnParent( &op->o_req_dn, &pdn );
144 dnParent( &op->o_req_ndn, &pndn );
147 * namingContext "" is not supported
149 if ( BER_BVISEMPTY( &pdn ) ) {
150 Debug( LDAP_DEBUG_TRACE, " backsql_modrdn(): "
151 "parent is \"\" - aborting\n", 0, 0, 0 );
152 rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
153 rs->sr_text = "not allowed within namingContext";
159 * Check for children access to parent
162 e_id = bsi.bsi_base_id;
163 memset( &bsi.bsi_base_id, 0, sizeof( bsi.bsi_base_id ) );
164 rs->sr_err = backsql_init_search( &bsi, &pndn,
166 (time_t)(-1), NULL, dbh, op, rs,
167 slap_anlist_all_attributes,
168 BACKSQL_ISF_GET_ENTRY );
170 Debug( LDAP_DEBUG_TRACE,
171 " backsql_modrdn(): old parent entry id is " BACKSQL_IDFMT "\n",
172 BACKSQL_IDARG(bsi.bsi_base_id.eid_id), 0, 0 );
174 if ( rs->sr_err != LDAP_SUCCESS ) {
175 Debug( LDAP_DEBUG_TRACE, "backsql_modrdn(): "
176 "could not retrieve renameDN ID - no such entry\n",
182 if ( !access_allowed( op, &p, slap_schema.si_ad_children, NULL,
183 newSuperior ? ACL_WDEL : ACL_WRITE, NULL ) )
185 Debug( LDAP_DEBUG_TRACE, " no access to parent\n", 0, 0, 0 );
186 rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
191 (void)backsql_free_entryID( &bsi.bsi_base_id, 0, op->o_tmpmemctx );
194 * namingContext "" is not supported
196 if ( BER_BVISEMPTY( newSuperior ) ) {
197 Debug( LDAP_DEBUG_TRACE, " backsql_modrdn(): "
198 "newSuperior is \"\" - aborting\n", 0, 0, 0 );
199 rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
200 rs->sr_text = "not allowed within namingContext";
205 new_pdn = newSuperior;
206 new_npdn = op->oq_modrdn.rs_nnewSup;
209 * Check for children access to new parent
212 rs->sr_err = backsql_init_search( &bsi, new_npdn,
214 (time_t)(-1), NULL, dbh, op, rs,
215 slap_anlist_all_attributes,
216 ( BACKSQL_ISF_MATCHED | BACKSQL_ISF_GET_ENTRY ) );
217 if ( rs->sr_err != LDAP_SUCCESS ) {
218 Debug( LDAP_DEBUG_TRACE, "backsql_modrdn(): "
219 "could not retrieve renameDN ID - no such entry\n",
225 n_id = bsi.bsi_base_id;
227 Debug( LDAP_DEBUG_TRACE,
228 " backsql_modrdn(): new parent entry id=" BACKSQL_IDFMT "\n",
229 BACKSQL_IDARG(n_id.eid_id), 0, 0 );
231 if ( !access_allowed( op, &n, slap_schema.si_ad_children,
232 NULL, ACL_WADD, NULL ) ) {
233 Debug( LDAP_DEBUG_TRACE, " backsql_modrdn(): "
234 "no access to new parent \"%s\"\n",
235 new_pdn->bv_val, 0, 0 );
236 rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
242 n_id = bsi.bsi_base_id;
247 memset( &bsi.bsi_base_id, 0, sizeof( bsi.bsi_base_id ) );
249 if ( newSuperior && dn_match( &pndn, new_npdn ) ) {
250 Debug( LDAP_DEBUG_TRACE, " backsql_modrdn(): "
251 "newSuperior is equal to old parent - ignored\n",
256 if ( newSuperior && dn_match( &op->o_req_ndn, new_npdn ) ) {
257 Debug( LDAP_DEBUG_TRACE, " backsql_modrdn(): "
258 "newSuperior is equal to entry being moved "
259 "- aborting\n", 0, 0, 0 );
260 rs->sr_err = LDAP_OTHER;
261 rs->sr_text = "newSuperior is equal to old DN";
266 build_new_dn( &new_dn, new_pdn, &op->oq_modrdn.rs_newrdn,
268 build_new_dn( &new_ndn, new_npdn, &op->oq_modrdn.rs_nnewrdn,
271 Debug( LDAP_DEBUG_TRACE, " backsql_modrdn(): new entry dn is \"%s\"\n",
272 new_dn.bv_val, 0, 0 );
275 if ( backsql_api_dn2odbc( op, rs, &realnew_dn ) ) {
276 Debug( LDAP_DEBUG_TRACE, " backsql_modrdn(\"%s\"): "
277 "backsql_api_dn2odbc(\"%s\") failed\n",
278 op->o_req_dn.bv_val, realnew_dn.bv_val, 0 );
279 SQLFreeStmt( sth, SQL_DROP );
281 rs->sr_text = "SQL-backend error";
282 rs->sr_err = LDAP_OTHER;
287 Debug( LDAP_DEBUG_TRACE, " backsql_modrdn(): "
288 "executing renentry_stmt\n", 0, 0, 0 );
290 rc = backsql_Prepare( dbh, &sth, bi->sql_renentry_stmt, 0 );
291 if ( rc != SQL_SUCCESS ) {
292 Debug( LDAP_DEBUG_TRACE,
293 " backsql_modrdn(): "
294 "error preparing renentry_stmt\n", 0, 0, 0 );
295 backsql_PrintErrors( bi->sql_db_env, dbh,
298 rs->sr_text = "SQL-backend error";
299 rs->sr_err = LDAP_OTHER;
304 rc = backsql_BindParamBerVal( sth, 1, SQL_PARAM_INPUT, &realnew_dn );
305 if ( rc != SQL_SUCCESS ) {
306 Debug( LDAP_DEBUG_TRACE,
307 " backsql_modrdn(): "
308 "error binding DN parameter for objectClass %s\n",
309 oc->bom_oc->soc_cname.bv_val, 0, 0 );
310 backsql_PrintErrors( bi->sql_db_env, dbh,
312 SQLFreeStmt( sth, SQL_DROP );
314 rs->sr_text = "SQL-backend error";
315 rs->sr_err = LDAP_OTHER;
320 rc = backsql_BindParamID( sth, 2, SQL_PARAM_INPUT, &n_id.eid_id );
321 if ( rc != SQL_SUCCESS ) {
322 Debug( LDAP_DEBUG_TRACE,
323 " backsql_modrdn(): "
324 "error binding parent ID parameter for objectClass %s\n",
325 oc->bom_oc->soc_cname.bv_val, 0, 0 );
326 backsql_PrintErrors( bi->sql_db_env, dbh,
328 SQLFreeStmt( sth, SQL_DROP );
330 rs->sr_text = "SQL-backend error";
331 rs->sr_err = LDAP_OTHER;
336 rc = backsql_BindParamID( sth, 3, SQL_PARAM_INPUT, &e_id.eid_keyval );
337 if ( rc != SQL_SUCCESS ) {
338 Debug( LDAP_DEBUG_TRACE,
339 " backsql_modrdn(): "
340 "error binding entry ID parameter for objectClass %s\n",
341 oc->bom_oc->soc_cname.bv_val, 0, 0 );
342 backsql_PrintErrors( bi->sql_db_env, dbh,
344 SQLFreeStmt( sth, SQL_DROP );
346 rs->sr_text = "SQL-backend error";
347 rs->sr_err = LDAP_OTHER;
352 rc = backsql_BindParamID( sth, 4, SQL_PARAM_INPUT, &e_id.eid_id );
353 if ( rc != SQL_SUCCESS ) {
354 Debug( LDAP_DEBUG_TRACE,
355 " backsql_modrdn(): "
356 "error binding ID parameter for objectClass %s\n",
357 oc->bom_oc->soc_cname.bv_val, 0, 0 );
358 backsql_PrintErrors( bi->sql_db_env, dbh,
360 SQLFreeStmt( sth, SQL_DROP );
362 rs->sr_text = "SQL-backend error";
363 rs->sr_err = LDAP_OTHER;
368 rc = SQLExecute( sth );
369 if ( rc != SQL_SUCCESS ) {
370 Debug( LDAP_DEBUG_TRACE, " backsql_modrdn(): "
371 "could not rename ldap_entries record\n", 0, 0, 0 );
372 backsql_PrintErrors( bi->sql_db_env, dbh, sth, rc );
373 SQLFreeStmt( sth, SQL_DROP );
374 rs->sr_err = LDAP_OTHER;
375 rs->sr_text = "SQL-backend error";
379 SQLFreeStmt( sth, SQL_DROP );
381 assert( op->orr_modlist != NULL );
383 slap_mods_opattrs( op, &op->orr_modlist, 1 );
385 assert( e_id.eid_oc != NULL );
387 rs->sr_err = backsql_modify_internal( op, rs, dbh, oc, &e_id, op->orr_modlist );
388 slap_graduate_commit_csn( op );
389 if ( rs->sr_err != LDAP_SUCCESS ) {
394 if ( BACKSQL_CHECK_SCHEMA( bi ) ) {
395 char textbuf[ SLAP_TEXT_BUFLEN ] = { '\0' };
397 backsql_entry_clean( op, &r );
398 (void)backsql_free_entryID( &e_id, 0, op->o_tmpmemctx );
401 rs->sr_err = backsql_init_search( &bsi, &new_ndn,
403 (time_t)(-1), NULL, dbh, op, rs,
404 slap_anlist_all_attributes,
405 ( BACKSQL_ISF_MATCHED | BACKSQL_ISF_GET_ENTRY ) );
406 switch ( rs->sr_err ) {
411 if ( manageDSAit && !BER_BVISNULL( &bsi.bsi_e->e_nname ) &&
412 dn_match( &new_ndn, &bsi.bsi_e->e_nname ) )
414 rs->sr_err = LDAP_SUCCESS;
416 rs->sr_matched = NULL;
418 ber_bvarray_free( rs->sr_ref );
427 Debug( LDAP_DEBUG_TRACE, "backsql_modrdn(): "
428 "could not retrieve modrdnDN ID - no such entry\n",
430 if ( !BER_BVISNULL( &r.e_nname ) ) {
431 /* FIXME: should always be true! */
440 e_id = bsi.bsi_base_id;
442 rs->sr_err = entry_schema_check( op, &r, NULL, 0, 0, NULL,
443 &rs->sr_text, textbuf, sizeof( textbuf ) );
444 if ( rs->sr_err != LDAP_SUCCESS ) {
445 Debug( LDAP_DEBUG_TRACE, " backsql_modrdn(\"%s\"): "
446 "entry failed schema check -- aborting\n",
447 r.e_name.bv_val, 0, 0 );
455 if ( !access_allowed( op, e, slap_schema.si_ad_entry, NULL,
456 ACL_DISCLOSE, NULL ) )
458 rs->sr_err = LDAP_NO_SUCH_OBJECT;
460 rs->sr_matched = NULL;
462 ber_bvarray_free( rs->sr_ref );
469 * Commit only if all operations succeed
471 if ( sth != SQL_NULL_HSTMT ) {
472 SQLUSMALLINT CompletionType = SQL_ROLLBACK;
474 if ( rs->sr_err == LDAP_SUCCESS && !op->o_noop ) {
475 CompletionType = SQL_COMMIT;
478 SQLTransact( SQL_NULL_HENV, dbh, CompletionType );
481 if ( op->o_noop && rs->sr_err == LDAP_SUCCESS ) {
482 rs->sr_err = LDAP_X_NO_OPERATION;
485 send_ldap_result( op, rs );
486 slap_graduate_commit_csn( op );
488 if ( !BER_BVISNULL( &realnew_dn ) && realnew_dn.bv_val != new_dn.bv_val ) {
489 ch_free( realnew_dn.bv_val );
492 if ( !BER_BVISNULL( &new_dn ) ) {
493 slap_sl_free( new_dn.bv_val, op->o_tmpmemctx );
496 if ( !BER_BVISNULL( &new_ndn ) ) {
497 slap_sl_free( new_ndn.bv_val, op->o_tmpmemctx );
500 if ( !BER_BVISNULL( &e_id.eid_ndn ) ) {
501 (void)backsql_free_entryID( &e_id, 0, op->o_tmpmemctx );
504 if ( !BER_BVISNULL( &n_id.eid_ndn ) ) {
505 (void)backsql_free_entryID( &n_id, 0, op->o_tmpmemctx );
508 if ( !BER_BVISNULL( &r.e_nname ) ) {
509 backsql_entry_clean( op, &r );
512 if ( !BER_BVISNULL( &p.e_nname ) ) {
513 backsql_entry_clean( op, &p );
516 if ( !BER_BVISNULL( &n.e_nname ) ) {
517 backsql_entry_clean( op, &n );
521 ber_bvarray_free( rs->sr_ref );
525 Debug( LDAP_DEBUG_TRACE, "<==backsql_modrdn()\n", 0, 0, 0 );