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;
47 LDAPRDN new_rdn = NULL;
48 LDAPRDN old_rdn = NULL;
53 int manageDSAit = get_manageDSAit( op );
54 Modifications *mod = NULL;
55 struct berval *newSuperior = op->oq_modrdn.rs_newSup;
58 Debug( LDAP_DEBUG_TRACE, "==>backsql_modrdn() renaming entry \"%s\", "
59 "newrdn=\"%s\", newSuperior=\"%s\"\n",
60 op->o_req_dn.bv_val, op->oq_modrdn.rs_newrdn.bv_val,
61 newSuperior ? newSuperior->bv_val : "(NULL)" );
63 rs->sr_err = backsql_get_db_conn( op, &dbh );
64 if ( rs->sr_err != LDAP_SUCCESS ) {
65 Debug( LDAP_DEBUG_TRACE, " backsql_modrdn(): "
66 "could not get connection handle - exiting\n",
68 rs->sr_text = ( rs->sr_err == LDAP_OTHER )
69 ? "SQL-backend error" : NULL;
75 rs->sr_err = backsql_init_search( &bsi, &op->o_req_ndn,
77 (time_t)(-1), NULL, dbh, op, rs,
78 slap_anlist_all_attributes,
79 ( BACKSQL_ISF_MATCHED | BACKSQL_ISF_GET_ENTRY ) );
80 switch ( rs->sr_err ) {
85 if ( manageDSAit && !BER_BVISNULL( &bsi.bsi_e->e_nname ) &&
86 dn_match( &op->o_req_ndn, &bsi.bsi_e->e_nname ) )
88 rs->sr_err = LDAP_SUCCESS;
90 rs->sr_matched = NULL;
92 ber_bvarray_free( rs->sr_ref );
101 Debug( LDAP_DEBUG_TRACE, "backsql_modrdn(): "
102 "could not retrieve modrdnDN ID - no such entry\n",
104 if ( !BER_BVISNULL( &r.e_nname ) ) {
105 /* FIXME: should always be true! */
114 #ifdef BACKSQL_ARBITRARY_KEY
115 Debug( LDAP_DEBUG_TRACE, " backsql_modrdn(): entry id=%s\n",
116 e_id.eid_id.bv_val, 0, 0 );
117 #else /* ! BACKSQL_ARBITRARY_KEY */
118 Debug( LDAP_DEBUG_TRACE, " backsql_modrdn(): entry id=%ld\n",
120 #endif /* ! BACKSQL_ARBITRARY_KEY */
122 if ( get_assert( op ) &&
123 ( test_filter( op, &r, get_assertion( op ) )
124 != LDAP_COMPARE_TRUE ) )
126 rs->sr_err = LDAP_ASSERTION_FAILED;
131 if ( backsql_has_children( op, dbh, &op->o_req_ndn ) == LDAP_COMPARE_TRUE ) {
132 Debug( LDAP_DEBUG_TRACE, " backsql_modrdn(): "
133 "entry \"%s\" has children\n",
134 op->o_req_dn.bv_val, 0, 0 );
135 rs->sr_err = LDAP_NOT_ALLOWED_ON_NONLEAF;
136 rs->sr_text = "subtree rename not supported";
142 * Check for entry access to target
144 if ( !access_allowed( op, &r, slap_schema.si_ad_entry,
145 NULL, ACL_WRITE, NULL ) ) {
146 Debug( LDAP_DEBUG_TRACE, " no access to entry\n", 0, 0, 0 );
147 rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
151 dnParent( &op->o_req_dn, &pdn );
152 dnParent( &op->o_req_ndn, &pndn );
155 * namingContext "" is not supported
157 if ( BER_BVISEMPTY( &pdn ) ) {
158 Debug( LDAP_DEBUG_TRACE, " backsql_modrdn(): "
159 "parent is \"\" - aborting\n", 0, 0, 0 );
160 rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
161 rs->sr_text = "not allowed within namingContext";
167 * Check for children access to parent
170 e_id = bsi.bsi_base_id;
171 rs->sr_err = backsql_init_search( &bsi, &pndn,
173 (time_t)(-1), NULL, dbh, op, rs,
174 slap_anlist_all_attributes,
175 BACKSQL_ISF_GET_ENTRY );
177 #ifdef BACKSQL_ARBITRARY_KEY
178 Debug( LDAP_DEBUG_TRACE, " backsql_modrdn(): "
179 "old parent entry id is %s\n",
180 bsi.bsi_base_id.eid_id.bv_val, 0, 0 );
181 #else /* ! BACKSQL_ARBITRARY_KEY */
182 Debug( LDAP_DEBUG_TRACE, " backsql_modrdn(): "
183 "old parent entry id is %ld\n",
184 bsi.bsi_base_id.eid_id, 0, 0 );
185 #endif /* ! BACKSQL_ARBITRARY_KEY */
187 if ( rs->sr_err != LDAP_SUCCESS ) {
188 Debug( LDAP_DEBUG_TRACE, "backsql_modrdn(): "
189 "could not retrieve renameDN ID - no such entry\n",
195 if ( !access_allowed( op, &p, slap_schema.si_ad_children, NULL,
196 newSuperior ? ACL_WDEL : ACL_WRITE, NULL ) )
198 Debug( LDAP_DEBUG_TRACE, " no access to parent\n", 0, 0, 0 );
199 rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
204 (void)backsql_free_entryID( op, &bsi.bsi_base_id, 0 );
207 * namingContext "" is not supported
209 if ( BER_BVISEMPTY( newSuperior ) ) {
210 Debug( LDAP_DEBUG_TRACE, " backsql_modrdn(): "
211 "newSuperior is \"\" - aborting\n", 0, 0, 0 );
212 rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
213 rs->sr_text = "not allowed within namingContext";
218 new_pdn = newSuperior;
219 new_npdn = op->oq_modrdn.rs_nnewSup;
222 * Check for children access to new parent
225 rs->sr_err = backsql_init_search( &bsi, new_npdn,
227 (time_t)(-1), NULL, dbh, op, rs,
228 slap_anlist_all_attributes,
229 ( BACKSQL_ISF_MATCHED | BACKSQL_ISF_GET_ENTRY ) );
230 if ( rs->sr_err != LDAP_SUCCESS ) {
231 Debug( LDAP_DEBUG_TRACE, "backsql_modrdn(): "
232 "could not retrieve renameDN ID - no such entry\n",
238 n_id = bsi.bsi_base_id;
240 #ifdef BACKSQL_ARBITRARY_KEY
241 Debug( LDAP_DEBUG_TRACE, " backsql_modrdn(): "
242 "new parent entry id=%s\n",
243 n_id.eid_id.bv_val, 0, 0 );
244 #else /* ! BACKSQL_ARBITRARY_KEY */
245 Debug( LDAP_DEBUG_TRACE, " backsql_modrdn(): "
246 "new parent entry id=%ld\n",
248 #endif /* ! BACKSQL_ARBITRARY_KEY */
250 if ( !access_allowed( op, &n, slap_schema.si_ad_children,
251 NULL, ACL_WADD, NULL ) ) {
252 Debug( LDAP_DEBUG_TRACE, " backsql_modrdn(): "
253 "no access to new parent \"%s\"\n",
254 new_pdn->bv_val, 0, 0 );
255 rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
261 n_id = bsi.bsi_base_id;
266 if ( newSuperior && dn_match( &pndn, new_npdn ) ) {
267 Debug( LDAP_DEBUG_TRACE, " backsql_modrdn(): "
268 "newSuperior is equal to old parent - ignored\n",
273 if ( newSuperior && dn_match( &op->o_req_ndn, new_npdn ) ) {
274 Debug( LDAP_DEBUG_TRACE, " backsql_modrdn(): "
275 "newSuperior is equal to entry being moved "
276 "- aborting\n", 0, 0, 0 );
277 rs->sr_err = LDAP_OTHER;
278 rs->sr_text = "newSuperior is equal to old DN";
283 build_new_dn( &new_dn, new_pdn, &op->oq_modrdn.rs_newrdn,
285 build_new_dn( &new_ndn, new_npdn, &op->oq_modrdn.rs_nnewrdn,
288 Debug( LDAP_DEBUG_TRACE, " backsql_modrdn(): new entry dn is \"%s\"\n",
289 new_dn.bv_val, 0, 0 );
292 if ( backsql_api_dn2odbc( op, rs, &realnew_dn ) ) {
293 Debug( LDAP_DEBUG_TRACE, " backsql_modrdn(\"%s\"): "
294 "backsql_api_dn2odbc(\"%s\") failed\n",
295 op->o_req_dn.bv_val, realnew_dn.bv_val, 0 );
296 SQLFreeStmt( sth, SQL_DROP );
298 rs->sr_text = "SQL-backend error";
299 rs->sr_err = LDAP_OTHER;
304 Debug( LDAP_DEBUG_TRACE, " backsql_modrdn(): "
305 "executing renentry_stmt\n", 0, 0, 0 );
307 rc = backsql_Prepare( dbh, &sth, bi->sql_renentry_stmt, 0 );
308 if ( rc != SQL_SUCCESS ) {
309 Debug( LDAP_DEBUG_TRACE,
310 " backsql_modrdn(): "
311 "error preparing renentry_stmt\n", 0, 0, 0 );
312 backsql_PrintErrors( bi->sql_db_env, dbh,
315 rs->sr_text = "SQL-backend error";
316 rs->sr_err = LDAP_OTHER;
321 rc = backsql_BindParamBerVal( sth, 1, SQL_PARAM_INPUT, &realnew_dn );
322 if ( rc != SQL_SUCCESS ) {
323 Debug( LDAP_DEBUG_TRACE,
324 " backsql_add_attr(): "
325 "error binding DN parameter for objectClass %s\n",
326 oc->bom_oc->soc_cname.bv_val, 0, 0 );
327 backsql_PrintErrors( bi->sql_db_env, dbh,
329 SQLFreeStmt( sth, SQL_DROP );
331 rs->sr_text = "SQL-backend error";
332 rs->sr_err = LDAP_OTHER;
337 rc = backsql_BindParamID( sth, 2, SQL_PARAM_INPUT, &n_id.eid_id );
338 if ( rc != SQL_SUCCESS ) {
339 Debug( LDAP_DEBUG_TRACE,
340 " backsql_add_attr(): "
341 "error binding parent ID parameter for objectClass %s\n",
342 oc->bom_oc->soc_cname.bv_val, 0, 0 );
343 backsql_PrintErrors( bi->sql_db_env, dbh,
345 SQLFreeStmt( sth, SQL_DROP );
347 rs->sr_text = "SQL-backend error";
348 rs->sr_err = LDAP_OTHER;
353 rc = backsql_BindParamID( sth, 3, SQL_PARAM_INPUT, &e_id.eid_keyval );
354 if ( rc != SQL_SUCCESS ) {
355 Debug( LDAP_DEBUG_TRACE,
356 " backsql_add_attr(): "
357 "error binding entry ID parameter for objectClass %s\n",
358 oc->bom_oc->soc_cname.bv_val, 0, 0 );
359 backsql_PrintErrors( bi->sql_db_env, dbh,
361 SQLFreeStmt( sth, SQL_DROP );
363 rs->sr_text = "SQL-backend error";
364 rs->sr_err = LDAP_OTHER;
369 rc = backsql_BindParamID( sth, 4, SQL_PARAM_INPUT, &e_id.eid_id );
370 if ( rc != SQL_SUCCESS ) {
371 Debug( LDAP_DEBUG_TRACE,
372 " backsql_add_attr(): "
373 "error binding ID parameter for objectClass %s\n",
374 oc->bom_oc->soc_cname.bv_val, 0, 0 );
375 backsql_PrintErrors( bi->sql_db_env, dbh,
377 SQLFreeStmt( sth, SQL_DROP );
379 rs->sr_text = "SQL-backend error";
380 rs->sr_err = LDAP_OTHER;
385 rc = SQLExecute( sth );
386 if ( rc != SQL_SUCCESS ) {
387 Debug( LDAP_DEBUG_TRACE, " backsql_modrdn(): "
388 "could not rename ldap_entries record\n", 0, 0, 0 );
389 backsql_PrintErrors( bi->sql_db_env, dbh, sth, rc );
390 SQLFreeStmt( sth, SQL_DROP );
391 rs->sr_err = LDAP_OTHER;
392 rs->sr_text = "SQL-backend error";
396 SQLFreeStmt( sth, SQL_DROP );
399 * Get attribute type and attribute value of our new rdn,
400 * we will need to add that to our new entry
402 if ( ldap_bv2rdn( &op->oq_modrdn.rs_newrdn, &new_rdn, &next,
403 LDAP_DN_FORMAT_LDAP ) )
405 Debug( LDAP_DEBUG_TRACE,
406 " backsql_modrdn: can't figure out "
407 "type(s)/values(s) of new_rdn\n",
409 rs->sr_err = LDAP_INVALID_DN_SYNTAX;
414 Debug( LDAP_DEBUG_TRACE, "backsql_modrdn: "
415 "new_rdn_type=\"%s\", new_rdn_val=\"%s\"\n",
416 new_rdn[ 0 ]->la_attr.bv_val,
417 new_rdn[ 0 ]->la_value.bv_val, 0 );
419 if ( op->oq_modrdn.rs_deleteoldrdn ) {
420 if ( ldap_bv2rdn( &op->o_req_dn, &old_rdn, &next,
421 LDAP_DN_FORMAT_LDAP ) )
423 Debug( LDAP_DEBUG_TRACE,
424 " backsql_modrdn: can't figure out "
425 "the old_rdn type(s)/value(s)\n",
427 rs->sr_err = LDAP_OTHER;
433 rs->sr_err = slap_modrdn2mods( op, rs, &r, old_rdn, new_rdn, &mod );
434 if ( rs->sr_err != LDAP_SUCCESS ) {
439 oc = backsql_id2oc( bi, e_id.eid_oc_id );
440 rs->sr_err = backsql_modify_internal( op, rs, dbh, oc, &e_id, mod );
441 slap_graduate_commit_csn( op );
442 if ( rs->sr_err != LDAP_SUCCESS ) {
447 if ( BACKSQL_CHECK_SCHEMA( bi ) ) {
448 char textbuf[ SLAP_TEXT_BUFLEN ] = { '\0' };
450 backsql_entry_clean( op, &r );
451 (void)backsql_free_entryID( op, &e_id, 0 );
454 rs->sr_err = backsql_init_search( &bsi, &new_ndn,
456 (time_t)(-1), NULL, dbh, op, rs,
457 slap_anlist_all_attributes,
458 ( BACKSQL_ISF_MATCHED | BACKSQL_ISF_GET_ENTRY ) );
459 switch ( rs->sr_err ) {
464 if ( manageDSAit && !BER_BVISNULL( &bsi.bsi_e->e_nname ) &&
465 dn_match( &new_ndn, &bsi.bsi_e->e_nname ) )
467 rs->sr_err = LDAP_SUCCESS;
469 rs->sr_matched = NULL;
471 ber_bvarray_free( rs->sr_ref );
480 Debug( LDAP_DEBUG_TRACE, "backsql_modrdn(): "
481 "could not retrieve modrdnDN ID - no such entry\n",
483 if ( !BER_BVISNULL( &r.e_nname ) ) {
484 /* FIXME: should always be true! */
493 e_id = bsi.bsi_base_id;
495 rs->sr_err = entry_schema_check( op, &r, NULL, 0,
496 &rs->sr_text, textbuf, sizeof( textbuf ) );
497 if ( rs->sr_err != LDAP_SUCCESS ) {
498 Debug( LDAP_DEBUG_TRACE, " backsql_add(\"%s\"): "
499 "entry failed schema check -- aborting\n",
500 r.e_name.bv_val, 0, 0 );
507 #ifdef SLAP_ACL_HONOR_DISCLOSE
509 if ( !access_allowed( op, e, slap_schema.si_ad_entry, NULL,
510 ACL_DISCLOSE, NULL ) )
512 rs->sr_err = LDAP_NO_SUCH_OBJECT;
514 rs->sr_matched = NULL;
516 ber_bvarray_free( rs->sr_ref );
521 #endif /* SLAP_ACL_HONOR_DISCLOSE */
524 * Commit only if all operations succeed
526 if ( sth != SQL_NULL_HSTMT ) {
527 SQLUSMALLINT CompletionType = SQL_ROLLBACK;
529 if ( rs->sr_err == LDAP_SUCCESS && !op->o_noop ) {
530 CompletionType = SQL_COMMIT;
533 SQLTransact( SQL_NULL_HENV, dbh, CompletionType );
536 if ( op->o_noop && rs->sr_err == LDAP_SUCCESS ) {
537 rs->sr_err = LDAP_X_NO_OPERATION;
540 send_ldap_result( op, rs );
541 slap_graduate_commit_csn( op );
543 if ( !BER_BVISNULL( &realnew_dn ) && realnew_dn.bv_val != new_dn.bv_val ) {
544 ch_free( realnew_dn.bv_val );
547 if ( !BER_BVISNULL( &new_dn ) ) {
548 slap_sl_free( new_dn.bv_val, op->o_tmpmemctx );
551 if ( !BER_BVISNULL( &new_ndn ) ) {
552 slap_sl_free( new_ndn.bv_val, op->o_tmpmemctx );
555 /* LDAP v2 supporting correct attribute handling. */
556 if ( new_rdn != NULL ) {
557 ldap_rdnfree( new_rdn );
559 if ( old_rdn != NULL ) {
560 ldap_rdnfree( old_rdn );
564 for (; mod; mod = tmp ) {
570 if ( !BER_BVISNULL( &e_id.eid_ndn ) ) {
571 (void)backsql_free_entryID( op, &e_id, 0 );
574 if ( !BER_BVISNULL( &n_id.eid_ndn ) ) {
575 (void)backsql_free_entryID( op, &n_id, 0 );
578 if ( !BER_BVISNULL( &r.e_nname ) ) {
579 backsql_entry_clean( op, &r );
582 if ( !BER_BVISNULL( &p.e_nname ) ) {
583 backsql_entry_clean( op, &p );
586 if ( !BER_BVISNULL( &n.e_nname ) ) {
587 backsql_entry_clean( op, &n );
591 ber_bvarray_free( rs->sr_ref );
595 Debug( LDAP_DEBUG_TRACE, "<==backsql_modrdn()\n", 0, 0, 0 );