]> git.sur5r.net Git - openldap/blob - servers/slapd/back-sql/modrdn.c
fix couple of bugs in recent 'disclose' commits; prepare for sending matchedDN when...
[openldap] / servers / slapd / back-sql / modrdn.c
1 /* $OpenLDAP$ */
2 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
3  *
4  * Copyright 1999-2005 The OpenLDAP Foundation.
5  * Portions Copyright 1999 Dmitry Kovalev.
6  * Portions Copyright 2002 Pierangelo Masarati.
7  * All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted only as authorized by the OpenLDAP
11  * Public License.
12  *
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>.
16  */
17 /* ACKNOWLEDGEMENTS:
18  * This work was initially developed by Dmitry Kovalev for inclusion
19  * by OpenLDAP Software.  Additional significant contributors include
20  * Pierangelo Masarati.
21  */
22
23 #include "portable.h"
24
25 #include <stdio.h>
26 #include <sys/types.h>
27 #include "ac/string.h"
28
29 #include "slap.h"
30 #include "proto-sql.h"
31
32 int
33 backsql_modrdn( Operation *op, SlapReply *rs )
34 {
35         backsql_info            *bi = (backsql_info*)op->o_bd->be_private;
36         SQLHDBC                 dbh = SQL_NULL_HDBC;
37         SQLHSTMT                sth = SQL_NULL_HSTMT;
38         RETCODE                 rc;
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;
49         Entry                   e;
50         Modifications           *mod = NULL;
51         struct berval           *newSuperior = op->oq_modrdn.rs_newSup;
52         char                    *next;
53  
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", 
62                         0, 0, 0 );
63                 rs->sr_text = ( rs->sr_err == LDAP_OTHER )
64                         ?  "SQL-backend error" : NULL;
65                 send_ldap_result( op, rs );
66                 return 1;
67         }
68
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",
73                         rs->sr_err, 0, 0 );
74                 rs->sr_text = ( rs->sr_err == LDAP_OTHER )
75                         ?  "SQL-backend error" : NULL;
76                 send_ldap_result( op, rs );
77                 return 1;
78         }
79
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",
85                 e_id.eid_id, 0, 0 );
86 #endif /* ! BACKSQL_ARBITRARY_KEY */
87
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 );
95                 return 1;
96         }
97
98         dnParent( &op->o_req_dn, &p_dn );
99         dnParent( &op->o_req_ndn, &p_ndn );
100
101         /*
102          * namingContext "" is not supported
103          */
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 );
110                 goto modrdn_return;
111         }
112
113         /*
114          * Check for children access to parent
115          */
116         e.e_attrs = NULL;
117         e.e_name = p_dn;
118         e.e_nname = p_ndn;
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;
124                 goto modrdn_return;
125         }
126
127         if ( newSuperior ) {
128                 /*
129                  * namingContext "" is not supported
130                  */
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 );
137                         goto modrdn_return;
138                 }
139
140                 new_pdn = newSuperior;
141                 new_npdn = op->oq_modrdn.rs_nnewSup;
142
143                 e.e_name = *new_pdn;
144                 e.e_nname = *new_npdn;
145
146                 /*
147                  * Check for children access to new parent
148                  */
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;
156                         goto modrdn_return;
157                 }
158
159         } else {
160                 new_pdn = &p_dn;
161                 new_npdn = &p_ndn;
162         }
163
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",
167                         0, 0, 0 );
168                 newSuperior = NULL;
169         }
170
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 );
178                 goto modrdn_return;
179         }
180
181         build_new_dn( &new_dn, new_pdn, &op->oq_modrdn.rs_newrdn,
182                         op->o_tmpmemctx );
183         rs->sr_err = dnNormalize( 0, NULL, NULL, &new_dn, &new_ndn,
184                         op->o_tmpmemctx );
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 );
191                 goto modrdn_return;
192         }
193         
194         Debug( LDAP_DEBUG_TRACE, "   backsql_modrdn(): new entry dn is \"%s\"\n",
195                         new_dn.bv_val, 0, 0 );
196
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 );
204                 goto modrdn_return;
205         }
206
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 */
214
215         (void)backsql_free_entryID( &pe_id, 0 );
216
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 );
224                 goto modrdn_return;
225         }
226
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 */
234
235  
236         Debug(  LDAP_DEBUG_TRACE, "   backsql_modrdn(): "
237                 "executing delentry_stmt\n", 0, 0, 0 );
238
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, 
245                                 sth, rc );
246
247                 rs->sr_text = "SQL-backend error";
248                 rs->sr_err = LDAP_OTHER;
249                 goto done;
250         }
251
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, 
260                         sth, rc );
261                 SQLFreeStmt( sth, SQL_DROP );
262
263                 rs->sr_text = "SQL-backend error";
264                 rs->sr_err = LDAP_OTHER;
265                 goto done;
266         }
267
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",
272                         0, 0, 0 );
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 );
278                 goto done;
279         }
280
281         SQLFreeStmt( sth, SQL_DROP );
282
283         Debug( LDAP_DEBUG_TRACE, "   backsql_modrdn(): "
284                 "executing insentry_stmt\n", 0, 0, 0 );
285
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, 
292                                 sth, rc );
293
294                 rs->sr_text = "SQL-backend error";
295                 rs->sr_err = LDAP_OTHER;
296                 goto done;
297         }
298
299         realnew_dn = new_dn;
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 );
305
306                 rs->sr_text = "SQL-backend error";
307                 rs->sr_err = LDAP_OTHER;
308                 goto done;
309         }
310
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, 
318                         sth, rc );
319                 SQLFreeStmt( sth, SQL_DROP );
320
321                 rs->sr_text = "SQL-backend error";
322                 rs->sr_err = LDAP_OTHER;
323                 goto done;
324         }
325
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, 
333                         sth, rc );
334                 SQLFreeStmt( sth, SQL_DROP );
335
336                 rs->sr_text = "SQL-backend error";
337                 rs->sr_err = LDAP_OTHER;
338                 goto done;
339         }
340
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, 
348                         sth, rc );
349                 SQLFreeStmt( sth, SQL_DROP );
350
351                 rs->sr_text = "SQL-backend error";
352                 rs->sr_err = LDAP_OTHER;
353                 goto done;
354         }
355
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, 
363                         sth, rc );
364                 SQLFreeStmt( sth, SQL_DROP );
365
366                 rs->sr_text = "SQL-backend error";
367                 rs->sr_err = LDAP_OTHER;
368                 goto done;
369         }
370
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 );
380                 goto done;
381         }
382         SQLFreeStmt( sth, SQL_DROP );
383
384         /*
385          * Get attribute type and attribute value of our new rdn,
386          * we will need to add that to our new entry
387          */
388         if ( ldap_bv2rdn( &op->oq_modrdn.rs_newrdn, &new_rdn, &next, 
389                                 LDAP_DN_FORMAT_LDAP ) )
390         {
391                 Debug( LDAP_DEBUG_TRACE,
392                         "   backsql_modrdn: can't figure out "
393                         "type(s)/values(s) of newrdn\n", 
394                         0, 0, 0 );
395                 rs->sr_err = LDAP_INVALID_DN_SYNTAX;
396                 goto done;
397         }
398
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 );
404
405         if ( op->oq_modrdn.rs_deleteoldrdn ) {
406                 if ( ldap_bv2rdn( &op->o_req_dn, &old_rdn, &next,
407                                         LDAP_DN_FORMAT_LDAP ) )
408                 {
409                         Debug( LDAP_DEBUG_TRACE,
410                                 "   backsql_modrdn: can't figure out "
411                                 "the old_rdn type(s)/value(s)\n", 
412                                 0, 0, 0 );
413                         rs->sr_err = LDAP_OTHER;
414                         goto done;              
415                 }
416         }
417
418         e.e_name = new_dn;
419         e.e_nname = new_ndn;
420         rs->sr_err = slap_modrdn2mods( op, rs, &e, old_rdn, new_rdn, &mod );
421         if ( rs->sr_err != LDAP_SUCCESS ) {
422                 goto modrdn_return;
423         }
424
425         /* FIXME: need the whole entry (ITS#3480) */
426         if ( !acl_check_modlist( op, &e, mod )) {
427                 rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
428                 goto modrdn_return;
429         }
430
431         oc = backsql_id2oc( bi, e_id.eid_oc_id );
432         rs->sr_err = backsql_modify_internal( op, rs, dbh, oc, &e_id, mod );
433
434 done:;
435         /*
436          * Commit only if all operations succeed
437          */
438         if ( rs->sr_err == LDAP_SUCCESS && !op->o_noop ) {
439                 SQLTransact( SQL_NULL_HENV, dbh, SQL_COMMIT );
440
441         } else {
442                 SQLTransact( SQL_NULL_HENV, dbh, SQL_ROLLBACK );
443         }
444
445 modrdn_return:;
446         if ( !BER_BVISNULL( &realnew_dn ) && realnew_dn.bv_val != new_dn.bv_val ) {
447                 ch_free( realnew_dn.bv_val );
448         }
449
450         if ( !BER_BVISNULL( &new_dn ) ) {
451                 slap_sl_free( new_dn.bv_val, op->o_tmpmemctx );
452         }
453         
454         if ( !BER_BVISNULL( &new_ndn ) ) {
455                 slap_sl_free( new_ndn.bv_val, op->o_tmpmemctx );
456         }
457         
458         /* LDAP v2 supporting correct attribute handling. */
459         if ( new_rdn != NULL ) {
460                 ldap_rdnfree( new_rdn );
461         }
462         if ( old_rdn != NULL ) {
463                 ldap_rdnfree( old_rdn );
464         }
465         if ( mod != NULL ) {
466                 Modifications *tmp;
467                 for (; mod; mod = tmp ) {
468                         tmp = mod->sml_next;
469                         free( mod );
470                 }
471         }
472
473         if ( !BER_BVISNULL( &new_pe_id.eid_ndn ) ) {
474                 (void)backsql_free_entryID( &new_pe_id, 0 );
475         }
476
477         send_ldap_result( op, rs );
478
479         Debug( LDAP_DEBUG_TRACE, "<==backsql_modrdn()\n", 0, 0, 0 );
480         return op->o_noop;
481 }
482