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 );
99 * Check for entry access to target
101 e.e_name = op->o_req_dn;
102 e.e_nname = op->o_req_ndn;
103 /* FIXME: need the whole entry (ITS#3480) */
104 if ( !access_allowed( op, &e, slap_schema.si_ad_entry,
105 NULL, ACL_WRITE, NULL ) ) {
106 Debug( LDAP_DEBUG_TRACE, " no access to entry\n", 0, 0, 0 );
107 rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
111 dnParent( &op->o_req_dn, &p_dn );
112 dnParent( &op->o_req_ndn, &p_ndn );
115 * namingContext "" is not supported
117 if ( BER_BVISEMPTY( &p_dn ) ) {
118 Debug( LDAP_DEBUG_TRACE, " backsql_modrdn(): "
119 "parent is \"\" - aborting\n", 0, 0, 0 );
120 rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
121 rs->sr_text = "not allowed within namingContext";
122 send_ldap_result( op, rs );
127 * Check for children access to parent
131 /* FIXME: need the whole entry (ITS#3480) */
132 if ( !access_allowed( op, &e, slap_schema.si_ad_children,
133 NULL, ACL_WRITE, NULL ) ) {
134 Debug( LDAP_DEBUG_TRACE, " no access to parent\n", 0, 0, 0 );
135 rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
141 * namingContext "" is not supported
143 if ( BER_BVISEMPTY( newSuperior ) ) {
144 Debug( LDAP_DEBUG_TRACE, " backsql_modrdn(): "
145 "newSuperior is \"\" - aborting\n", 0, 0, 0 );
146 rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
147 rs->sr_text = "not allowed within namingContext";
148 send_ldap_result( op, rs );
152 new_pdn = newSuperior;
153 new_npdn = op->oq_modrdn.rs_nnewSup;
156 * Check for children access to new parent
159 e.e_nname = *new_npdn;
160 /* FIXME: need the whole entry (ITS#3480) */
161 if ( !access_allowed( op, &e, slap_schema.si_ad_children,
162 NULL, ACL_WRITE, NULL ) ) {
163 Debug( LDAP_DEBUG_TRACE, " backsql_modrdn(): "
164 "no access to new parent \"%s\"\n",
165 new_pdn->bv_val, 0, 0 );
166 rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
175 if ( newSuperior && dn_match( &p_ndn, new_npdn ) ) {
176 Debug( LDAP_DEBUG_TRACE, " backsql_modrdn(): "
177 "newSuperior is equal to old parent - ignored\n",
182 if ( newSuperior && dn_match( &op->o_req_ndn, new_npdn ) ) {
183 Debug( LDAP_DEBUG_TRACE, " backsql_modrdn(): "
184 "newSuperior is equal to entry being moved "
185 "- aborting\n", 0, 0, 0 );
186 rs->sr_err = LDAP_OTHER;
187 rs->sr_text = "newSuperior is equal to old DN";
188 send_ldap_result( op, rs );
192 build_new_dn( &new_dn, new_pdn, &op->oq_modrdn.rs_newrdn,
194 rs->sr_err = dnNormalize( 0, NULL, NULL, &new_dn, &new_ndn,
196 if ( rs->sr_err != LDAP_SUCCESS ) {
197 Debug( LDAP_DEBUG_TRACE, " backsql_modrdn(): "
198 "new dn is invalid (\"%s\") - aborting\n",
199 new_dn.bv_val, 0, 0 );
200 rs->sr_text = "unable to build new DN";
201 send_ldap_result( op, rs );
205 Debug( LDAP_DEBUG_TRACE, " backsql_modrdn(): new entry dn is \"%s\"\n",
206 new_dn.bv_val, 0, 0 );
208 rs->sr_err = backsql_dn2id( op, rs, dbh, &p_ndn, &pe_id, 0, 1 );
209 if ( rs->sr_err != LDAP_SUCCESS ) {
210 Debug( LDAP_DEBUG_TRACE, " backsql_modrdn(): "
211 "could not lookup old parent entry id\n", 0, 0, 0 );
212 rs->sr_text = ( rs->sr_err == LDAP_OTHER )
213 ? "SQL-backend error" : NULL;
214 send_ldap_result( op, rs );
218 #ifdef BACKSQL_ARBITRARY_KEY
219 Debug( LDAP_DEBUG_TRACE, " backsql_modrdn(): "
220 "old parent entry id is %s\n", pe_id.eid_id.bv_val, 0, 0 );
221 #else /* ! BACKSQL_ARBITRARY_KEY */
222 Debug( LDAP_DEBUG_TRACE, " backsql_modrdn(): "
223 "old parent entry id is %ld\n", pe_id.eid_id, 0, 0 );
224 #endif /* ! BACKSQL_ARBITRARY_KEY */
226 (void)backsql_free_entryID( &pe_id, 0 );
228 rs->sr_err = backsql_dn2id( op, rs, dbh, new_npdn, &new_pe_id, 0, 1 );
229 if ( rs->sr_err != LDAP_SUCCESS ) {
230 Debug( LDAP_DEBUG_TRACE, " backsql_modrdn(): "
231 "could not lookup new parent entry id\n", 0, 0, 0 );
232 rs->sr_text = ( rs->sr_err == LDAP_OTHER )
233 ? "SQL-backend error" : NULL;
234 send_ldap_result( op, rs );
238 #ifdef BACKSQL_ARBITRARY_KEY
239 Debug( LDAP_DEBUG_TRACE, " backsql_modrdn(): "
240 "new parent entry id=%s\n", new_pe_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", new_pe_id.eid_id, 0, 0 );
244 #endif /* ! BACKSQL_ARBITRARY_KEY */
247 Debug( LDAP_DEBUG_TRACE, " backsql_modrdn(): "
248 "executing delentry_stmt\n", 0, 0, 0 );
250 rc = backsql_Prepare( dbh, &sth, bi->sql_delentry_stmt, 0 );
251 if ( rc != SQL_SUCCESS ) {
252 Debug( LDAP_DEBUG_TRACE,
253 " backsql_modrdn(): "
254 "error preparing delentry_stmt\n", 0, 0, 0 );
255 backsql_PrintErrors( bi->sql_db_env, dbh,
258 rs->sr_text = "SQL-backend error";
259 rs->sr_err = LDAP_OTHER;
263 rc = backsql_BindParamID( sth, 1, SQL_PARAM_INPUT, &e_id.eid_id );
264 if ( rc != SQL_SUCCESS ) {
265 Debug( LDAP_DEBUG_TRACE,
266 " backsql_delete(): "
267 "error binding entry ID parameter "
268 "for objectClass %s\n",
269 oc->bom_oc->soc_cname.bv_val, 0, 0 );
270 backsql_PrintErrors( bi->sql_db_env, dbh,
272 SQLFreeStmt( sth, SQL_DROP );
274 rs->sr_text = "SQL-backend error";
275 rs->sr_err = LDAP_OTHER;
279 rc = SQLExecute( sth );
280 if ( rc != SQL_SUCCESS ) {
281 Debug( LDAP_DEBUG_TRACE, " backsql_modrdn(): "
282 "failed to delete record from ldap_entries\n",
284 backsql_PrintErrors( bi->sql_db_env, dbh, sth, rc );
285 SQLFreeStmt( sth, SQL_DROP );
286 rs->sr_err = LDAP_OTHER;
287 rs->sr_text = "SQL-backend error";
288 send_ldap_result( op, rs );
292 SQLFreeStmt( sth, SQL_DROP );
294 Debug( LDAP_DEBUG_TRACE, " backsql_modrdn(): "
295 "executing insentry_stmt\n", 0, 0, 0 );
297 rc = backsql_Prepare( dbh, &sth, bi->sql_insentry_stmt, 0 );
298 if ( rc != SQL_SUCCESS ) {
299 Debug( LDAP_DEBUG_TRACE,
300 " backsql_modrdn(): "
301 "error preparing insentry_stmt\n", 0, 0, 0 );
302 backsql_PrintErrors( bi->sql_db_env, dbh,
305 rs->sr_text = "SQL-backend error";
306 rs->sr_err = LDAP_OTHER;
311 if ( backsql_api_dn2odbc( op, rs, &realnew_dn ) ) {
312 Debug( LDAP_DEBUG_TRACE, " backsql_modrdn(\"%s\"): "
313 "backsql_api_dn2odbc(\"%s\") failed\n",
314 op->o_req_dn.bv_val, realnew_dn.bv_val, 0 );
315 SQLFreeStmt( sth, SQL_DROP );
317 rs->sr_text = "SQL-backend error";
318 rs->sr_err = LDAP_OTHER;
322 rc = backsql_BindParamBerVal( sth, 1, SQL_PARAM_INPUT, &realnew_dn );
323 if ( rc != SQL_SUCCESS ) {
324 Debug( LDAP_DEBUG_TRACE,
325 " backsql_add_attr(): "
326 "error binding DN parameter for objectClass %s\n",
327 oc->bom_oc->soc_cname.bv_val, 0, 0 );
328 backsql_PrintErrors( bi->sql_db_env, dbh,
330 SQLFreeStmt( sth, SQL_DROP );
332 rs->sr_text = "SQL-backend error";
333 rs->sr_err = LDAP_OTHER;
337 rc = backsql_BindParamInt( sth, 2, SQL_PARAM_INPUT, &e_id.eid_oc_id );
338 if ( rc != SQL_SUCCESS ) {
339 Debug( LDAP_DEBUG_TRACE,
340 " backsql_add_attr(): "
341 "error binding objectClass 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;
352 rc = backsql_BindParamID( sth, 3, SQL_PARAM_INPUT, &new_pe_id.eid_id );
353 if ( rc != SQL_SUCCESS ) {
354 Debug( LDAP_DEBUG_TRACE,
355 " backsql_add_attr(): "
356 "error binding parent 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;
367 rc = backsql_BindParamID( sth, 4, SQL_PARAM_INPUT, &e_id.eid_keyval );
368 if ( rc != SQL_SUCCESS ) {
369 Debug( LDAP_DEBUG_TRACE,
370 " backsql_add_attr(): "
371 "error binding entry ID parameter for objectClass %s\n",
372 oc->bom_oc->soc_cname.bv_val, 0, 0 );
373 backsql_PrintErrors( bi->sql_db_env, dbh,
375 SQLFreeStmt( sth, SQL_DROP );
377 rs->sr_text = "SQL-backend error";
378 rs->sr_err = LDAP_OTHER;
382 rc = SQLExecute( sth );
383 if ( rc != SQL_SUCCESS ) {
384 Debug( LDAP_DEBUG_TRACE, " backsql_modrdn(): "
385 "could not insert 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";
390 send_ldap_result( op, rs );
393 SQLFreeStmt( sth, SQL_DROP );
396 * Get attribute type and attribute value of our new rdn,
397 * we will need to add that to our new entry
399 if ( ldap_bv2rdn( &op->oq_modrdn.rs_newrdn, &new_rdn, &next,
400 LDAP_DN_FORMAT_LDAP ) )
402 Debug( LDAP_DEBUG_TRACE,
403 " backsql_modrdn: can't figure out "
404 "type(s)/values(s) of newrdn\n",
406 rs->sr_err = LDAP_INVALID_DN_SYNTAX;
410 Debug( LDAP_DEBUG_TRACE,
411 " backsql_modrdn: new_rdn_type=\"%s\", "
412 "new_rdn_val=\"%s\"\n",
413 new_rdn[ 0 ]->la_attr.bv_val,
414 new_rdn[ 0 ]->la_value.bv_val, 0 );
416 if ( op->oq_modrdn.rs_deleteoldrdn ) {
417 if ( ldap_bv2rdn( &op->o_req_dn, &old_rdn, &next,
418 LDAP_DN_FORMAT_LDAP ) )
420 Debug( LDAP_DEBUG_TRACE,
421 " backsql_modrdn: can't figure out "
422 "the old_rdn type(s)/value(s)\n",
424 rs->sr_err = LDAP_OTHER;
431 rs->sr_err = slap_modrdn2mods( op, rs, &e, old_rdn, new_rdn, &mod );
432 if ( rs->sr_err != LDAP_SUCCESS ) {
436 /* FIXME: need the whole entry (ITS#3480) */
437 if ( !acl_check_modlist( op, &e, mod )) {
438 rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
442 oc = backsql_id2oc( bi, e_id.eid_oc_id );
443 rs->sr_err = backsql_modify_internal( op, rs, dbh, oc, &e_id, mod );
447 * Commit only if all operations succeed
449 if ( rs->sr_err == LDAP_SUCCESS && !op->o_noop ) {
450 SQLTransact( SQL_NULL_HENV, dbh, SQL_COMMIT );
453 SQLTransact( SQL_NULL_HENV, dbh, SQL_ROLLBACK );
457 if ( !BER_BVISNULL( &realnew_dn ) && realnew_dn.bv_val != new_dn.bv_val ) {
458 ch_free( realnew_dn.bv_val );
461 if ( !BER_BVISNULL( &new_dn ) ) {
462 slap_sl_free( new_dn.bv_val, op->o_tmpmemctx );
465 if ( !BER_BVISNULL( &new_ndn ) ) {
466 slap_sl_free( new_ndn.bv_val, op->o_tmpmemctx );
469 /* LDAP v2 supporting correct attribute handling. */
470 if ( new_rdn != NULL ) {
471 ldap_rdnfree( new_rdn );
473 if ( old_rdn != NULL ) {
474 ldap_rdnfree( old_rdn );
478 for (; mod; mod = tmp ) {
484 if ( !BER_BVISNULL( &new_pe_id.eid_ndn ) ) {
485 (void)backsql_free_entryID( &new_pe_id, 0 );
488 send_ldap_result( op, rs );
490 Debug( LDAP_DEBUG_TRACE, "<==backsql_modrdn()\n", 0, 0, 0 );