1 /* $OpenLDAP: pkg/ldap/servers/slapd/back-sql/modrdn.c,v 1.39.2.5 2008/02/11 23:26:48 kurt Exp $ */
2 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
4 * Copyright 1999-2008 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 #ifdef BACKSQL_ARBITRARY_KEY
111 Debug( LDAP_DEBUG_TRACE
, " backsql_modrdn(): entry id=%s\n",
112 e_id
.eid_id
.bv_val
, 0, 0 );
113 #else /* ! BACKSQL_ARBITRARY_KEY */
114 Debug( LDAP_DEBUG_TRACE
, " backsql_modrdn(): entry id=%ld\n",
116 #endif /* ! BACKSQL_ARBITRARY_KEY */
118 if ( get_assert( op
) &&
119 ( test_filter( op
, &r
, get_assertion( op
) )
120 != LDAP_COMPARE_TRUE
) )
122 rs
->sr_err
= LDAP_ASSERTION_FAILED
;
127 if ( backsql_has_children( op
, dbh
, &op
->o_req_ndn
) == LDAP_COMPARE_TRUE
) {
128 Debug( LDAP_DEBUG_TRACE
, " backsql_modrdn(): "
129 "entry \"%s\" has children\n",
130 op
->o_req_dn
.bv_val
, 0, 0 );
131 rs
->sr_err
= LDAP_NOT_ALLOWED_ON_NONLEAF
;
132 rs
->sr_text
= "subtree rename not supported";
138 * Check for entry access to target
140 if ( !access_allowed( op
, &r
, slap_schema
.si_ad_entry
,
141 NULL
, ACL_WRITE
, NULL
) ) {
142 Debug( LDAP_DEBUG_TRACE
, " no access to entry\n", 0, 0, 0 );
143 rs
->sr_err
= LDAP_INSUFFICIENT_ACCESS
;
147 dnParent( &op
->o_req_dn
, &pdn
);
148 dnParent( &op
->o_req_ndn
, &pndn
);
151 * namingContext "" is not supported
153 if ( BER_BVISEMPTY( &pdn
) ) {
154 Debug( LDAP_DEBUG_TRACE
, " backsql_modrdn(): "
155 "parent is \"\" - aborting\n", 0, 0, 0 );
156 rs
->sr_err
= LDAP_UNWILLING_TO_PERFORM
;
157 rs
->sr_text
= "not allowed within namingContext";
163 * Check for children access to parent
166 e_id
= bsi
.bsi_base_id
;
167 memset( &bsi
.bsi_base_id
, 0, sizeof( 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( &bsi
.bsi_base_id
, 0, op
->o_tmpmemctx
);
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 memset( &bsi
.bsi_base_id
, 0, sizeof( bsi
.bsi_base_id
) );
265 if ( newSuperior
&& dn_match( &pndn
, new_npdn
) ) {
266 Debug( LDAP_DEBUG_TRACE
, " backsql_modrdn(): "
267 "newSuperior is equal to old parent - ignored\n",
272 if ( newSuperior
&& dn_match( &op
->o_req_ndn
, new_npdn
) ) {
273 Debug( LDAP_DEBUG_TRACE
, " backsql_modrdn(): "
274 "newSuperior is equal to entry being moved "
275 "- aborting\n", 0, 0, 0 );
276 rs
->sr_err
= LDAP_OTHER
;
277 rs
->sr_text
= "newSuperior is equal to old DN";
282 build_new_dn( &new_dn
, new_pdn
, &op
->oq_modrdn
.rs_newrdn
,
284 build_new_dn( &new_ndn
, new_npdn
, &op
->oq_modrdn
.rs_nnewrdn
,
287 Debug( LDAP_DEBUG_TRACE
, " backsql_modrdn(): new entry dn is \"%s\"\n",
288 new_dn
.bv_val
, 0, 0 );
291 if ( backsql_api_dn2odbc( op
, rs
, &realnew_dn
) ) {
292 Debug( LDAP_DEBUG_TRACE
, " backsql_modrdn(\"%s\"): "
293 "backsql_api_dn2odbc(\"%s\") failed\n",
294 op
->o_req_dn
.bv_val
, realnew_dn
.bv_val
, 0 );
295 SQLFreeStmt( sth
, SQL_DROP
);
297 rs
->sr_text
= "SQL-backend error";
298 rs
->sr_err
= LDAP_OTHER
;
303 Debug( LDAP_DEBUG_TRACE
, " backsql_modrdn(): "
304 "executing renentry_stmt\n", 0, 0, 0 );
306 rc
= backsql_Prepare( dbh
, &sth
, bi
->sql_renentry_stmt
, 0 );
307 if ( rc
!= SQL_SUCCESS
) {
308 Debug( LDAP_DEBUG_TRACE
,
309 " backsql_modrdn(): "
310 "error preparing renentry_stmt\n", 0, 0, 0 );
311 backsql_PrintErrors( bi
->sql_db_env
, dbh
,
314 rs
->sr_text
= "SQL-backend error";
315 rs
->sr_err
= LDAP_OTHER
;
320 rc
= backsql_BindParamBerVal( sth
, 1, SQL_PARAM_INPUT
, &realnew_dn
);
321 if ( rc
!= SQL_SUCCESS
) {
322 Debug( LDAP_DEBUG_TRACE
,
323 " backsql_add_attr(): "
324 "error binding DN 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
, 2, SQL_PARAM_INPUT
, &n_id
.eid_id
);
337 if ( rc
!= SQL_SUCCESS
) {
338 Debug( LDAP_DEBUG_TRACE
,
339 " backsql_add_attr(): "
340 "error binding parent 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
, 3, SQL_PARAM_INPUT
, &e_id
.eid_keyval
);
353 if ( rc
!= SQL_SUCCESS
) {
354 Debug( LDAP_DEBUG_TRACE
,
355 " backsql_add_attr(): "
356 "error binding entry 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
= backsql_BindParamID( sth
, 4, SQL_PARAM_INPUT
, &e_id
.eid_id
);
369 if ( rc
!= SQL_SUCCESS
) {
370 Debug( LDAP_DEBUG_TRACE
,
371 " backsql_add_attr(): "
372 "error binding ID parameter for objectClass %s\n",
373 oc
->bom_oc
->soc_cname
.bv_val
, 0, 0 );
374 backsql_PrintErrors( bi
->sql_db_env
, dbh
,
376 SQLFreeStmt( sth
, SQL_DROP
);
378 rs
->sr_text
= "SQL-backend error";
379 rs
->sr_err
= LDAP_OTHER
;
384 rc
= SQLExecute( sth
);
385 if ( rc
!= SQL_SUCCESS
) {
386 Debug( LDAP_DEBUG_TRACE
, " backsql_modrdn(): "
387 "could not rename ldap_entries record\n", 0, 0, 0 );
388 backsql_PrintErrors( bi
->sql_db_env
, dbh
, sth
, rc
);
389 SQLFreeStmt( sth
, SQL_DROP
);
390 rs
->sr_err
= LDAP_OTHER
;
391 rs
->sr_text
= "SQL-backend error";
395 SQLFreeStmt( sth
, SQL_DROP
);
397 assert( op
->orr_modlist
!= NULL
);
399 slap_mods_opattrs( op
, &op
->orr_modlist
, 1 );
401 assert( e_id
.eid_oc
!= NULL
);
403 rs
->sr_err
= backsql_modify_internal( op
, rs
, dbh
, oc
, &e_id
, op
->orr_modlist
);
404 slap_graduate_commit_csn( op
);
405 if ( rs
->sr_err
!= LDAP_SUCCESS
) {
410 if ( BACKSQL_CHECK_SCHEMA( bi
) ) {
411 char textbuf
[ SLAP_TEXT_BUFLEN
] = { '\0' };
413 backsql_entry_clean( op
, &r
);
414 (void)backsql_free_entryID( &e_id
, 0, op
->o_tmpmemctx
);
417 rs
->sr_err
= backsql_init_search( &bsi
, &new_ndn
,
419 (time_t)(-1), NULL
, dbh
, op
, rs
,
420 slap_anlist_all_attributes
,
421 ( BACKSQL_ISF_MATCHED
| BACKSQL_ISF_GET_ENTRY
) );
422 switch ( rs
->sr_err
) {
427 if ( manageDSAit
&& !BER_BVISNULL( &bsi
.bsi_e
->e_nname
) &&
428 dn_match( &new_ndn
, &bsi
.bsi_e
->e_nname
) )
430 rs
->sr_err
= LDAP_SUCCESS
;
432 rs
->sr_matched
= NULL
;
434 ber_bvarray_free( rs
->sr_ref
);
443 Debug( LDAP_DEBUG_TRACE
, "backsql_modrdn(): "
444 "could not retrieve modrdnDN ID - no such entry\n",
446 if ( !BER_BVISNULL( &r
.e_nname
) ) {
447 /* FIXME: should always be true! */
456 e_id
= bsi
.bsi_base_id
;
458 rs
->sr_err
= entry_schema_check( op
, &r
, NULL
, 0, 0,
459 &rs
->sr_text
, textbuf
, sizeof( textbuf
) );
460 if ( rs
->sr_err
!= LDAP_SUCCESS
) {
461 Debug( LDAP_DEBUG_TRACE
, " backsql_modrdn(\"%s\"): "
462 "entry failed schema check -- aborting\n",
463 r
.e_name
.bv_val
, 0, 0 );
471 if ( !access_allowed( op
, e
, slap_schema
.si_ad_entry
, NULL
,
472 ACL_DISCLOSE
, NULL
) )
474 rs
->sr_err
= LDAP_NO_SUCH_OBJECT
;
476 rs
->sr_matched
= NULL
;
478 ber_bvarray_free( rs
->sr_ref
);
485 * Commit only if all operations succeed
487 if ( sth
!= SQL_NULL_HSTMT
) {
488 SQLUSMALLINT CompletionType
= SQL_ROLLBACK
;
490 if ( rs
->sr_err
== LDAP_SUCCESS
&& !op
->o_noop
) {
491 CompletionType
= SQL_COMMIT
;
494 SQLTransact( SQL_NULL_HENV
, dbh
, CompletionType
);
497 if ( op
->o_noop
&& rs
->sr_err
== LDAP_SUCCESS
) {
498 rs
->sr_err
= LDAP_X_NO_OPERATION
;
501 send_ldap_result( op
, rs
);
502 slap_graduate_commit_csn( op
);
504 if ( !BER_BVISNULL( &realnew_dn
) && realnew_dn
.bv_val
!= new_dn
.bv_val
) {
505 ch_free( realnew_dn
.bv_val
);
508 if ( !BER_BVISNULL( &new_dn
) ) {
509 slap_sl_free( new_dn
.bv_val
, op
->o_tmpmemctx
);
512 if ( !BER_BVISNULL( &new_ndn
) ) {
513 slap_sl_free( new_ndn
.bv_val
, op
->o_tmpmemctx
);
516 if ( !BER_BVISNULL( &e_id
.eid_ndn
) ) {
517 (void)backsql_free_entryID( &e_id
, 0, op
->o_tmpmemctx
);
520 if ( !BER_BVISNULL( &n_id
.eid_ndn
) ) {
521 (void)backsql_free_entryID( &n_id
, 0, op
->o_tmpmemctx
);
524 if ( !BER_BVISNULL( &r
.e_nname
) ) {
525 backsql_entry_clean( op
, &r
);
528 if ( !BER_BVISNULL( &p
.e_nname
) ) {
529 backsql_entry_clean( op
, &p
);
532 if ( !BER_BVISNULL( &n
.e_nname
) ) {
533 backsql_entry_clean( op
, &n
);
537 ber_bvarray_free( rs
->sr_ref
);
541 Debug( LDAP_DEBUG_TRACE
, "<==backsql_modrdn()\n", 0, 0, 0 );