2 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
4 * Copyright 1999-2005 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 pe_id = BACKSQL_ENTRYID_INIT,
41 new_pe_id = BACKSQL_ENTRYID_INIT;
42 backsql_oc_map_rec *oc = NULL;
43 struct berval p_dn = BER_BVNULL, p_ndn = 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;
50 Modifications *mod = NULL;
51 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)" );
58 rs->sr_err = backsql_get_db_conn( op, &dbh );
59 if ( rs->sr_err != LDAP_SUCCESS ) {
60 Debug( LDAP_DEBUG_TRACE, " backsql_modrdn(): "
61 "could not get connection handle - exiting\n",
63 rs->sr_text = ( rs->sr_err == LDAP_OTHER )
64 ? "SQL-backend error" : NULL;
65 send_ldap_result( op, rs );
69 rs->sr_err = backsql_dn2id( op, rs, dbh, &op->o_req_ndn, &e_id, 0, 1 );
70 if ( rs->sr_err != LDAP_SUCCESS ) {
71 Debug( LDAP_DEBUG_TRACE, " backsql_modrdn(): "
72 "could not lookup entry id (%d)\n",
74 rs->sr_text = ( rs->sr_err == LDAP_OTHER )
75 ? "SQL-backend error" : NULL;
76 send_ldap_result( op, rs );
80 #ifdef BACKSQL_ARBITRARY_KEY
81 Debug( LDAP_DEBUG_TRACE, " backsql_modrdn(): entry id=%s\n",
82 e_id.eid_id.bv_val, 0, 0 );
83 #else /* ! BACKSQL_ARBITRARY_KEY */
84 Debug( LDAP_DEBUG_TRACE, " backsql_modrdn(): entry id=%ld\n",
86 #endif /* ! BACKSQL_ARBITRARY_KEY */
88 if ( backsql_has_children( bi, dbh, &op->o_req_ndn ) == LDAP_COMPARE_TRUE ) {
89 Debug( LDAP_DEBUG_TRACE, " backsql_modrdn(): "
90 "entry \"%s\" has children\n",
91 op->o_req_dn.bv_val, 0, 0 );
92 rs->sr_err = LDAP_NOT_ALLOWED_ON_NONLEAF;
93 rs->sr_text = "subtree rename not supported";
94 send_ldap_result( op, rs );
98 dnParent( &op->o_req_dn, &p_dn );
99 dnParent( &op->o_req_ndn, &p_ndn );
102 * namingContext "" is not supported
104 if ( p_dn.bv_len == 0 ) {
105 Debug( LDAP_DEBUG_TRACE, " backsql_modrdn(): "
106 "parent is \"\" - aborting\n", 0, 0, 0 );
107 rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
108 rs->sr_text = "not allowed within namingContext";
109 send_ldap_result( op, rs );
114 * Check for children access to parent
119 /* FIXME: need the whole entry (ITS#3480) */
120 if ( !access_allowed( op, &e, slap_schema.si_ad_children,
121 NULL, ACL_WRITE, NULL ) ) {
122 Debug( LDAP_DEBUG_TRACE, " no access to parent\n", 0, 0, 0 );
123 rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
129 * namingContext "" is not supported
131 if ( newSuperior->bv_len == 0 ) {
132 Debug( LDAP_DEBUG_TRACE, " backsql_modrdn(): "
133 "newSuperior is \"\" - aborting\n", 0, 0, 0 );
134 rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
135 rs->sr_text = "not allowed within namingContext";
136 send_ldap_result( op, rs );
140 new_pdn = newSuperior;
141 new_npdn = op->oq_modrdn.rs_nnewSup;
144 e.e_nname = *new_npdn;
147 * Check for children access to new parent
149 /* FIXME: need the whole entry (ITS#3480) */
150 if ( !access_allowed( op, &e, slap_schema.si_ad_children,
151 NULL, ACL_WRITE, NULL ) ) {
152 Debug( LDAP_DEBUG_TRACE, " backsql_modrdn(): "
153 "no access to new parent \"%s\"\n",
154 new_pdn->bv_val, 0, 0 );
155 rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
164 if ( newSuperior && dn_match( &p_ndn, new_npdn ) ) {
165 Debug( LDAP_DEBUG_TRACE, " backsql_modrdn(): "
166 "newSuperior is equal to old parent - ignored\n",
171 if ( newSuperior && dn_match( &op->o_req_ndn, new_npdn ) ) {
172 Debug( LDAP_DEBUG_TRACE, " backsql_modrdn(): "
173 "newSuperior is equal to entry being moved "
174 "- aborting\n", 0, 0, 0 );
175 rs->sr_err = LDAP_OTHER;
176 rs->sr_text = "newSuperior is equal to old DN";
177 send_ldap_result( op, rs );
181 build_new_dn( &new_dn, new_pdn, &op->oq_modrdn.rs_newrdn,
183 rs->sr_err = dnNormalize( 0, NULL, NULL, &new_dn, &new_ndn,
185 if ( rs->sr_err != LDAP_SUCCESS ) {
186 Debug( LDAP_DEBUG_TRACE, " backsql_modrdn(): "
187 "new dn is invalid (\"%s\") - aborting\n",
188 new_dn.bv_val, 0, 0 );
189 rs->sr_text = "unable to build new DN";
190 send_ldap_result( op, rs );
194 Debug( LDAP_DEBUG_TRACE, " backsql_modrdn(): new entry dn is \"%s\"\n",
195 new_dn.bv_val, 0, 0 );
197 rs->sr_err = backsql_dn2id( op, rs, dbh, &p_ndn, &pe_id, 0, 1 );
198 if ( rs->sr_err != LDAP_SUCCESS ) {
199 Debug( LDAP_DEBUG_TRACE, " backsql_modrdn(): "
200 "could not lookup old parent entry id\n", 0, 0, 0 );
201 rs->sr_text = ( rs->sr_err == LDAP_OTHER )
202 ? "SQL-backend error" : NULL;
203 send_ldap_result( op, rs );
207 #ifdef BACKSQL_ARBITRARY_KEY
208 Debug( LDAP_DEBUG_TRACE, " backsql_modrdn(): "
209 "old parent entry id is %s\n", pe_id.eid_id.bv_val, 0, 0 );
210 #else /* ! BACKSQL_ARBITRARY_KEY */
211 Debug( LDAP_DEBUG_TRACE, " backsql_modrdn(): "
212 "old parent entry id is %ld\n", pe_id.eid_id, 0, 0 );
213 #endif /* ! BACKSQL_ARBITRARY_KEY */
215 (void)backsql_free_entryID( &pe_id, 0 );
217 rs->sr_err = backsql_dn2id( op, rs, dbh, new_npdn, &new_pe_id, 0, 1 );
218 if ( rs->sr_err != LDAP_SUCCESS ) {
219 Debug( LDAP_DEBUG_TRACE, " backsql_modrdn(): "
220 "could not lookup new parent entry id\n", 0, 0, 0 );
221 rs->sr_text = ( rs->sr_err == LDAP_OTHER )
222 ? "SQL-backend error" : NULL;
223 send_ldap_result( op, rs );
227 #ifdef BACKSQL_ARBITRARY_KEY
228 Debug( LDAP_DEBUG_TRACE, " backsql_modrdn(): "
229 "new parent entry id=%s\n", new_pe_id.eid_id.bv_val, 0, 0 );
230 #else /* ! BACKSQL_ARBITRARY_KEY */
231 Debug( LDAP_DEBUG_TRACE, " backsql_modrdn(): "
232 "new parent entry id=%ld\n", new_pe_id.eid_id, 0, 0 );
233 #endif /* ! BACKSQL_ARBITRARY_KEY */
236 Debug( LDAP_DEBUG_TRACE, " backsql_modrdn(): "
237 "executing delentry_stmt\n", 0, 0, 0 );
239 rc = backsql_Prepare( dbh, &sth, bi->sql_delentry_stmt, 0 );
240 if ( rc != SQL_SUCCESS ) {
241 Debug( LDAP_DEBUG_TRACE,
242 " backsql_modrdn(): "
243 "error preparing delentry_stmt\n", 0, 0, 0 );
244 backsql_PrintErrors( bi->sql_db_env, dbh,
247 rs->sr_text = "SQL-backend error";
248 rs->sr_err = LDAP_OTHER;
252 rc = backsql_BindParamID( sth, 1, SQL_PARAM_INPUT, &e_id.eid_id );
253 if ( rc != SQL_SUCCESS ) {
254 Debug( LDAP_DEBUG_TRACE,
255 " backsql_delete(): "
256 "error binding entry ID parameter "
257 "for objectClass %s\n",
258 oc->bom_oc->soc_cname.bv_val, 0, 0 );
259 backsql_PrintErrors( bi->sql_db_env, dbh,
261 SQLFreeStmt( sth, SQL_DROP );
263 rs->sr_text = "SQL-backend error";
264 rs->sr_err = LDAP_OTHER;
268 rc = SQLExecute( sth );
269 if ( rc != SQL_SUCCESS ) {
270 Debug( LDAP_DEBUG_TRACE, " backsql_modrdn(): "
271 "failed to delete record from ldap_entries\n",
273 backsql_PrintErrors( bi->sql_db_env, dbh, sth, rc );
274 SQLFreeStmt( sth, SQL_DROP );
275 rs->sr_err = LDAP_OTHER;
276 rs->sr_text = "SQL-backend error";
277 send_ldap_result( op, rs );
281 SQLFreeStmt( sth, SQL_DROP );
283 Debug( LDAP_DEBUG_TRACE, " backsql_modrdn(): "
284 "executing insentry_stmt\n", 0, 0, 0 );
286 rc = backsql_Prepare( dbh, &sth, bi->sql_insentry_stmt, 0 );
287 if ( rc != SQL_SUCCESS ) {
288 Debug( LDAP_DEBUG_TRACE,
289 " backsql_modrdn(): "
290 "error preparing insentry_stmt\n", 0, 0, 0 );
291 backsql_PrintErrors( bi->sql_db_env, dbh,
294 rs->sr_text = "SQL-backend error";
295 rs->sr_err = LDAP_OTHER;
300 if ( backsql_api_dn2odbc( op, rs, &realnew_dn ) ) {
301 Debug( LDAP_DEBUG_TRACE, " backsql_modrdn(\"%s\"): "
302 "backsql_api_dn2odbc(\"%s\") failed\n",
303 op->o_req_dn.bv_val, realnew_dn.bv_val, 0 );
304 SQLFreeStmt( sth, SQL_DROP );
306 rs->sr_text = "SQL-backend error";
307 rs->sr_err = LDAP_OTHER;
311 rc = backsql_BindParamBerVal( sth, 1, SQL_PARAM_INPUT, &realnew_dn );
312 if ( rc != SQL_SUCCESS ) {
313 Debug( LDAP_DEBUG_TRACE,
314 " backsql_add_attr(): "
315 "error binding DN parameter for objectClass %s\n",
316 oc->bom_oc->soc_cname.bv_val, 0, 0 );
317 backsql_PrintErrors( bi->sql_db_env, dbh,
319 SQLFreeStmt( sth, SQL_DROP );
321 rs->sr_text = "SQL-backend error";
322 rs->sr_err = LDAP_OTHER;
326 rc = backsql_BindParamInt( sth, 2, SQL_PARAM_INPUT, &e_id.eid_oc_id );
327 if ( rc != SQL_SUCCESS ) {
328 Debug( LDAP_DEBUG_TRACE,
329 " backsql_add_attr(): "
330 "error binding objectClass ID parameter for objectClass %s\n",
331 oc->bom_oc->soc_cname.bv_val, 0, 0 );
332 backsql_PrintErrors( bi->sql_db_env, dbh,
334 SQLFreeStmt( sth, SQL_DROP );
336 rs->sr_text = "SQL-backend error";
337 rs->sr_err = LDAP_OTHER;
341 rc = backsql_BindParamID( sth, 3, SQL_PARAM_INPUT, &new_pe_id.eid_id );
342 if ( rc != SQL_SUCCESS ) {
343 Debug( LDAP_DEBUG_TRACE,
344 " backsql_add_attr(): "
345 "error binding parent ID parameter for objectClass %s\n",
346 oc->bom_oc->soc_cname.bv_val, 0, 0 );
347 backsql_PrintErrors( bi->sql_db_env, dbh,
349 SQLFreeStmt( sth, SQL_DROP );
351 rs->sr_text = "SQL-backend error";
352 rs->sr_err = LDAP_OTHER;
356 rc = backsql_BindParamID( sth, 4, SQL_PARAM_INPUT, &e_id.eid_keyval );
357 if ( rc != SQL_SUCCESS ) {
358 Debug( LDAP_DEBUG_TRACE,
359 " backsql_add_attr(): "
360 "error binding entry ID parameter for objectClass %s\n",
361 oc->bom_oc->soc_cname.bv_val, 0, 0 );
362 backsql_PrintErrors( bi->sql_db_env, dbh,
364 SQLFreeStmt( sth, SQL_DROP );
366 rs->sr_text = "SQL-backend error";
367 rs->sr_err = LDAP_OTHER;
371 rc = SQLExecute( sth );
372 if ( rc != SQL_SUCCESS ) {
373 Debug( LDAP_DEBUG_TRACE, " backsql_modrdn(): "
374 "could not insert ldap_entries record\n", 0, 0, 0 );
375 backsql_PrintErrors( bi->sql_db_env, dbh, sth, rc );
376 SQLFreeStmt( sth, SQL_DROP );
377 rs->sr_err = LDAP_OTHER;
378 rs->sr_text = "SQL-backend error";
379 send_ldap_result( op, rs );
382 SQLFreeStmt( sth, SQL_DROP );
385 * Get attribute type and attribute value of our new rdn,
386 * we will need to add that to our new entry
388 if ( ldap_bv2rdn( &op->oq_modrdn.rs_newrdn, &new_rdn, &next,
389 LDAP_DN_FORMAT_LDAP ) )
391 Debug( LDAP_DEBUG_TRACE,
392 " backsql_modrdn: can't figure out "
393 "type(s)/values(s) of newrdn\n",
395 rs->sr_err = LDAP_INVALID_DN_SYNTAX;
399 Debug( LDAP_DEBUG_TRACE,
400 " backsql_modrdn: new_rdn_type=\"%s\", "
401 "new_rdn_val=\"%s\"\n",
402 new_rdn[ 0 ]->la_attr.bv_val,
403 new_rdn[ 0 ]->la_value.bv_val, 0 );
405 if ( op->oq_modrdn.rs_deleteoldrdn ) {
406 if ( ldap_bv2rdn( &op->o_req_dn, &old_rdn, &next,
407 LDAP_DN_FORMAT_LDAP ) )
409 Debug( LDAP_DEBUG_TRACE,
410 " backsql_modrdn: can't figure out "
411 "the old_rdn type(s)/value(s)\n",
413 rs->sr_err = LDAP_OTHER;
420 rs->sr_err = slap_modrdn2mods( op, rs, &e, old_rdn, new_rdn, &mod );
421 if ( rs->sr_err != LDAP_SUCCESS ) {
425 /* FIXME: need the whole entry (ITS#3480) */
426 if ( !acl_check_modlist( op, &e, mod )) {
427 rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
431 oc = backsql_id2oc( bi, e_id.eid_oc_id );
432 rs->sr_err = backsql_modify_internal( op, rs, dbh, oc, &e_id, mod );
436 * Commit only if all operations succeed
438 if ( rs->sr_err == LDAP_SUCCESS && !op->o_noop ) {
439 SQLTransact( SQL_NULL_HENV, dbh, SQL_COMMIT );
442 SQLTransact( SQL_NULL_HENV, dbh, SQL_ROLLBACK );
446 if ( !BER_BVISNULL( &realnew_dn ) && realnew_dn.bv_val != new_dn.bv_val ) {
447 ch_free( realnew_dn.bv_val );
450 if ( !BER_BVISNULL( &new_dn ) ) {
451 slap_sl_free( new_dn.bv_val, op->o_tmpmemctx );
454 if ( !BER_BVISNULL( &new_ndn ) ) {
455 slap_sl_free( new_ndn.bv_val, op->o_tmpmemctx );
458 /* LDAP v2 supporting correct attribute handling. */
459 if ( new_rdn != NULL ) {
460 ldap_rdnfree( new_rdn );
462 if ( old_rdn != NULL ) {
463 ldap_rdnfree( old_rdn );
467 for (; mod; mod = tmp ) {
473 if ( !BER_BVISNULL( &new_pe_id.eid_ndn ) ) {
474 (void)backsql_free_entryID( &new_pe_id, 0 );
477 send_ldap_result( op, rs );
479 Debug( LDAP_DEBUG_TRACE, "<==backsql_modrdn()\n", 0, 0, 0 );