]> git.sur5r.net Git - openldap/blob - servers/slapd/back-mdb/modrdn.c
Happy New Year!
[openldap] / servers / slapd / back-mdb / modrdn.c
1 /* modrdn.c - mdb backend modrdn routine */
2 /* $OpenLDAP$ */
3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
4  *
5  * Copyright 2000-2012 The OpenLDAP Foundation.
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted only as authorized by the OpenLDAP
10  * Public License.
11  *
12  * A copy of this license is available in the file LICENSE in the
13  * top-level directory of the distribution or, alternatively, at
14  * <http://www.OpenLDAP.org/license.html>.
15  */
16
17 #include "portable.h"
18
19 #include <stdio.h>
20 #include <ac/string.h>
21
22 #include "back-mdb.h"
23
24 int
25 mdb_modrdn( Operation   *op, SlapReply *rs )
26 {
27         struct mdb_info *mdb = (struct mdb_info *) op->o_bd->be_private;
28         AttributeDescription *children = slap_schema.si_ad_children;
29         AttributeDescription *entry = slap_schema.si_ad_entry;
30         struct berval   p_dn, p_ndn;
31         struct berval   new_dn = {0, NULL}, new_ndn = {0, NULL};
32         Entry           *e = NULL;
33         Entry           *p = NULL;
34         /* LDAP v2 supporting correct attribute handling. */
35         char textbuf[SLAP_TEXT_BUFLEN];
36         size_t textlen = sizeof textbuf;
37         MDB_txn         *txn = NULL;
38         MDB_cursor      *mc;
39         struct mdb_op_info opinfo = {{{ 0 }}}, *moi = &opinfo;
40         Entry dummy = {0};
41
42         Entry           *np = NULL;                     /* newSuperior Entry */
43         struct berval   *np_dn = NULL;                  /* newSuperior dn */
44         struct berval   *np_ndn = NULL;                 /* newSuperior ndn */
45         struct berval   *new_parent_dn = NULL;  /* np_dn, p_dn, or NULL */
46
47         int             manageDSAit = get_manageDSAit( op );
48
49         ID nid;
50         LDAPControl **preread_ctrl = NULL;
51         LDAPControl **postread_ctrl = NULL;
52         LDAPControl *ctrls[SLAP_MAX_RESPONSE_CONTROLS];
53         int num_ctrls = 0;
54
55         int parent_is_glue = 0;
56         int parent_is_leaf = 0;
57
58 #ifdef LDAP_X_TXN
59         int settle = 0;
60 #endif
61
62         Debug( LDAP_DEBUG_TRACE, "==>" LDAP_XSTRING(mdb_modrdn) "(%s,%s,%s)\n",
63                 op->o_req_dn.bv_val,op->oq_modrdn.rs_newrdn.bv_val,
64                 op->oq_modrdn.rs_newSup ? op->oq_modrdn.rs_newSup->bv_val : "NULL" );
65
66 #ifdef LDAP_X_TXN
67         if( op->o_txnSpec ) {
68                 /* acquire connection lock */
69                 ldap_pvt_thread_mutex_lock( &op->o_conn->c_mutex );
70                 if( op->o_conn->c_txn == CONN_TXN_INACTIVE ) {
71                         rs->sr_text = "invalid transaction identifier";
72                         rs->sr_err = LDAP_X_TXN_ID_INVALID;
73                         goto txnReturn;
74                 } else if( op->o_conn->c_txn == CONN_TXN_SETTLE ) {
75                         settle=1;
76                         goto txnReturn;
77                 }
78
79                 if( op->o_conn->c_txn_backend == NULL ) {
80                         op->o_conn->c_txn_backend = op->o_bd;
81
82                 } else if( op->o_conn->c_txn_backend != op->o_bd ) {
83                         rs->sr_text = "transaction cannot span multiple database contexts";
84                         rs->sr_err = LDAP_AFFECTS_MULTIPLE_DSAS;
85                         goto txnReturn;
86                 }
87
88                 /* insert operation into transaction */
89
90                 rs->sr_text = "transaction specified";
91                 rs->sr_err = LDAP_X_TXN_SPECIFY_OKAY;
92
93 txnReturn:
94                 /* release connection lock */
95                 ldap_pvt_thread_mutex_unlock( &op->o_conn->c_mutex );
96
97                 if( !settle ) {
98                         send_ldap_result( op, rs );
99                         return rs->sr_err;
100                 }
101         }
102 #endif
103
104         ctrls[num_ctrls] = NULL;
105
106         slap_mods_opattrs( op, &op->orr_modlist, 1 );
107
108         /* begin transaction */
109         rs->sr_err = mdb_opinfo_get( op, mdb, 0, &moi );
110         rs->sr_text = NULL;
111         if( rs->sr_err != 0 ) {
112                 Debug( LDAP_DEBUG_TRACE,
113                         LDAP_XSTRING(mdb_modrdn) ": txn_begin failed: "
114                         "%s (%d)\n", mdb_strerror(rs->sr_err), rs->sr_err, 0 );
115                 rs->sr_err = LDAP_OTHER;
116                 rs->sr_text = "internal error";
117                 goto return_results;
118         }
119
120         txn = moi->moi_txn;
121
122         if ( be_issuffix( op->o_bd, &op->o_req_ndn ) ) {
123 #ifdef MDB_MULTIPLE_SUFFIXES
124                 /* Allow renaming one suffix entry to another */
125                 p_ndn = slap_empty_bv;
126 #else
127                 /* There can only be one suffix entry */
128                 rs->sr_err = LDAP_NAMING_VIOLATION;
129                 rs->sr_text = "cannot rename suffix entry";
130                 goto return_results;
131 #endif
132         } else {
133                 dnParent( &op->o_req_ndn, &p_ndn );
134         }
135         np_ndn = &p_ndn;
136         /* Make sure parent entry exist and we can write its
137          * children.
138          */
139         rs->sr_err = mdb_cursor_open( txn, mdb->mi_dn2id, &mc );
140         if ( rs->sr_err != 0 ) {
141                 Debug(LDAP_DEBUG_TRACE,
142                         "<=- " LDAP_XSTRING(mdb_modrdn)
143                         ": cursor_open failed: %s (%d)\n",
144                         mdb_strerror(rs->sr_err), rs->sr_err, 0 );
145                 rs->sr_err = LDAP_OTHER;
146                 rs->sr_text = "DN cursor_open failed";
147                 goto return_results;
148         }
149         rs->sr_err = mdb_dn2entry( op, txn, mc, &p_ndn, &p, 0 );
150         switch( rs->sr_err ) {
151         case MDB_NOTFOUND:
152                 Debug( LDAP_DEBUG_TRACE, LDAP_XSTRING(mdb_modrdn)
153                         ": parent does not exist\n", 0, 0, 0);
154                 rs->sr_ref = referral_rewrite( default_referral, NULL,
155                                         &op->o_req_dn, LDAP_SCOPE_DEFAULT );
156                 rs->sr_err = LDAP_REFERRAL;
157
158                 send_ldap_result( op, rs );
159
160                 ber_bvarray_free( rs->sr_ref );
161                 goto done;
162         case 0:
163                 break;
164         case LDAP_BUSY:
165                 rs->sr_text = "ldap server busy";
166                 goto return_results;
167         default:
168                 rs->sr_err = LDAP_OTHER;
169                 rs->sr_text = "internal error";
170                 goto return_results;
171         }
172
173         /* check parent for "children" acl */
174         rs->sr_err = access_allowed( op, p,
175                 children, NULL,
176                 op->oq_modrdn.rs_newSup == NULL ?
177                         ACL_WRITE : ACL_WDEL,
178                 NULL );
179
180         if ( ! rs->sr_err ) {
181                 rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
182                 Debug( LDAP_DEBUG_TRACE, "no access to parent\n", 0,
183                         0, 0 );
184                 rs->sr_text = "no write access to parent's children";
185                 goto return_results;
186         }
187
188         Debug( LDAP_DEBUG_TRACE,
189                 LDAP_XSTRING(mdb_modrdn) ": wr to children "
190                 "of entry %s OK\n", p_ndn.bv_val, 0, 0 );
191
192         if ( p_ndn.bv_val == slap_empty_bv.bv_val ) {
193                 p_dn = slap_empty_bv;
194         } else {
195                 dnParent( &op->o_req_dn, &p_dn );
196         }
197
198         Debug( LDAP_DEBUG_TRACE,
199                 LDAP_XSTRING(mdb_modrdn) ": parent dn=%s\n",
200                 p_dn.bv_val, 0, 0 );
201
202         /* get entry */
203         rs->sr_err = mdb_dn2entry( op, txn, mc, &op->o_req_ndn, &e, 0 );
204         switch( rs->sr_err ) {
205         case MDB_NOTFOUND:
206                 e = p;
207                 p = NULL;
208         case 0:
209                 break;
210         case LDAP_BUSY:
211                 rs->sr_text = "ldap server busy";
212                 goto return_results;
213         default:
214                 rs->sr_err = LDAP_OTHER;
215                 rs->sr_text = "internal error";
216                 goto return_results;
217         }
218
219         /* FIXME: dn2entry() should return non-glue entry */
220         if (( rs->sr_err == MDB_NOTFOUND ) ||
221                 ( !manageDSAit && e && is_entry_glue( e )))
222         {
223                 if( e != NULL ) {
224                         rs->sr_matched = ch_strdup( e->e_dn );
225                         if ( is_entry_referral( e )) {
226                                 BerVarray ref = get_entry_referrals( op, e );
227                                 rs->sr_ref = referral_rewrite( ref, &e->e_name,
228                                         &op->o_req_dn, LDAP_SCOPE_DEFAULT );
229                                 ber_bvarray_free( ref );
230                         } else {
231                                 rs->sr_ref = NULL;
232                         }
233                         mdb_entry_return( op, e );
234                         e = NULL;
235
236                 } else {
237                         rs->sr_ref = referral_rewrite( default_referral, NULL,
238                                         &op->o_req_dn, LDAP_SCOPE_DEFAULT );
239                 }
240
241                 rs->sr_err = LDAP_REFERRAL;
242                 send_ldap_result( op, rs );
243
244                 ber_bvarray_free( rs->sr_ref );
245                 free( (char *)rs->sr_matched );
246                 rs->sr_ref = NULL;
247                 rs->sr_matched = NULL;
248
249                 goto done;
250         }
251
252         if ( get_assert( op ) &&
253                 ( test_filter( op, e, get_assertion( op )) != LDAP_COMPARE_TRUE ))
254         {
255                 rs->sr_err = LDAP_ASSERTION_FAILED;
256                 goto return_results;
257         }
258
259         /* check write on old entry */
260         rs->sr_err = access_allowed( op, e, entry, NULL, ACL_WRITE, NULL );
261         if ( ! rs->sr_err ) {
262                 Debug( LDAP_DEBUG_TRACE, "no access to entry\n", 0,
263                         0, 0 );
264                 rs->sr_text = "no write access to old entry";
265                 rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
266                 goto return_results;
267         }
268
269         if (!manageDSAit && is_entry_referral( e ) ) {
270                 /* entry is a referral, don't allow rename */
271                 rs->sr_ref = get_entry_referrals( op, e );
272
273                 Debug( LDAP_DEBUG_TRACE, LDAP_XSTRING(mdb_modrdn)
274                         ": entry %s is referral\n", e->e_dn, 0, 0 );
275
276                 rs->sr_err = LDAP_REFERRAL,
277                 rs->sr_matched = e->e_name.bv_val;
278                 send_ldap_result( op, rs );
279
280                 ber_bvarray_free( rs->sr_ref );
281                 rs->sr_ref = NULL;
282                 rs->sr_matched = NULL;
283                 goto done;
284         }
285
286         new_parent_dn = &p_dn;  /* New Parent unless newSuperior given */
287
288         if ( op->oq_modrdn.rs_newSup != NULL ) {
289                 Debug( LDAP_DEBUG_TRACE,
290                         LDAP_XSTRING(mdb_modrdn)
291                         ": new parent \"%s\" requested...\n",
292                         op->oq_modrdn.rs_newSup->bv_val, 0, 0 );
293
294                 /*  newSuperior == oldParent? */
295                 if( dn_match( &p_ndn, op->oq_modrdn.rs_nnewSup ) ) {
296                         Debug( LDAP_DEBUG_TRACE, "mdb_back_modrdn: "
297                                 "new parent \"%s\" same as the old parent \"%s\"\n",
298                                 op->oq_modrdn.rs_newSup->bv_val, p_dn.bv_val, 0 );
299                         op->oq_modrdn.rs_newSup = NULL; /* ignore newSuperior */
300                 }
301         }
302
303         /* There's a MDB_MULTIPLE_SUFFIXES case here that this code doesn't
304          * support. E.g., two suffixes dc=foo,dc=com and dc=bar,dc=net.
305          * We do not allow modDN
306          *   dc=foo,dc=com
307          *    newrdn dc=bar
308          *    newsup dc=net
309          * and we probably should. But since MULTIPLE_SUFFIXES is deprecated
310          * I'm ignoring this problem for now.
311          */
312         if ( op->oq_modrdn.rs_newSup != NULL ) {
313                 if ( op->oq_modrdn.rs_newSup->bv_len ) {
314                         np_dn = op->oq_modrdn.rs_newSup;
315                         np_ndn = op->oq_modrdn.rs_nnewSup;
316
317                         /* newSuperior == oldParent? - checked above */
318                         /* newSuperior == entry being moved?, if so ==> ERROR */
319                         if ( dnIsSuffix( np_ndn, &e->e_nname )) {
320                                 rs->sr_err = LDAP_NO_SUCH_OBJECT;
321                                 rs->sr_text = "new superior not found";
322                                 goto return_results;
323                         }
324                         /* Get Entry with dn=newSuperior. Does newSuperior exist? */
325                         rs->sr_err = mdb_dn2entry( op, txn, NULL, np_ndn, &np, 0 );
326
327                         switch( rs->sr_err ) {
328                         case 0:
329                                 break;
330                         case MDB_NOTFOUND:
331                                 Debug( LDAP_DEBUG_TRACE,
332                                         LDAP_XSTRING(mdb_modrdn)
333                                         ": newSup(ndn=%s) not here!\n",
334                                         np_ndn->bv_val, 0, 0);
335                                 rs->sr_text = "new superior not found";
336                                 rs->sr_err = LDAP_NO_SUCH_OBJECT;
337                                 goto return_results;
338                         case LDAP_BUSY:
339                                 rs->sr_text = "ldap server busy";
340                                 goto return_results;
341                         default:
342                                 rs->sr_err = LDAP_OTHER;
343                                 rs->sr_text = "internal error";
344                                 goto return_results;
345                         }
346
347                         /* check newSuperior for "children" acl */
348                         rs->sr_err = access_allowed( op, np, children,
349                                 NULL, ACL_WADD, NULL );
350
351                         if( ! rs->sr_err ) {
352                                 Debug( LDAP_DEBUG_TRACE,
353                                         LDAP_XSTRING(mdb_modrdn)
354                                         ": no wr to newSup children\n",
355                                         0, 0, 0 );
356                                 rs->sr_text = "no write access to new superior's children";
357                                 rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
358                                 goto return_results;
359                         }
360
361                         Debug( LDAP_DEBUG_TRACE,
362                                 LDAP_XSTRING(mdb_modrdn)
363                                 ": wr to new parent OK np=%p, id=%ld\n",
364                                 (void *) np, (long) np->e_id, 0 );
365
366                         if ( is_entry_alias( np ) ) {
367                                 /* parent is an alias, don't allow add */
368                                 Debug( LDAP_DEBUG_TRACE,
369                                         LDAP_XSTRING(mdb_modrdn)
370                                         ": entry is alias\n",
371                                         0, 0, 0 );
372                                 rs->sr_text = "new superior is an alias";
373                                 rs->sr_err = LDAP_ALIAS_PROBLEM;
374                                 goto return_results;
375                         }
376
377                         if ( is_entry_referral( np ) ) {
378                                 /* parent is a referral, don't allow add */
379                                 Debug( LDAP_DEBUG_TRACE,
380                                         LDAP_XSTRING(mdb_modrdn)
381                                         ": entry is referral\n",
382                                         0, 0, 0 );
383                                 rs->sr_text = "new superior is a referral";
384                                 rs->sr_err = LDAP_OTHER;
385                                 goto return_results;
386                         }
387                         new_parent_dn = &np->e_name;
388
389                 } else {
390                         np_dn = NULL;
391
392                         /* no parent, modrdn entry directly under root */
393                         if ( be_issuffix( op->o_bd, (struct berval *)&slap_empty_bv )
394                                 || be_isupdate( op ) ) {
395                                 np = (Entry *)&slap_entry_root;
396
397                                 /* check parent for "children" acl */
398                                 rs->sr_err = access_allowed( op, np,
399                                         children, NULL, ACL_WADD, NULL );
400
401                                 np = NULL;
402
403                                 if ( ! rs->sr_err ) {
404                                         rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
405                                         Debug( LDAP_DEBUG_TRACE,
406                                                 "no access to new superior\n",
407                                                 0, 0, 0 );
408                                         rs->sr_text =
409                                                 "no write access to new superior's children";
410                                         goto return_results;
411                                 }
412                         }
413                 }
414
415                 Debug( LDAP_DEBUG_TRACE,
416                         LDAP_XSTRING(mdb_modrdn)
417                         ": wr to new parent's children OK\n",
418                         0, 0, 0 );
419
420                 new_parent_dn = np_dn;
421         }
422
423         /* Build target dn and make sure target entry doesn't exist already. */
424         if (!new_dn.bv_val) {
425                 build_new_dn( &new_dn, new_parent_dn, &op->oq_modrdn.rs_newrdn, op->o_tmpmemctx );
426         }
427
428         if (!new_ndn.bv_val) {
429                 dnNormalize( 0, NULL, NULL, &new_dn, &new_ndn, op->o_tmpmemctx );
430         }
431
432         Debug( LDAP_DEBUG_TRACE, LDAP_XSTRING(mdb_modrdn) ": new ndn=%s\n",
433                 new_ndn.bv_val, 0, 0 );
434
435         /* Shortcut the search */
436         rs->sr_err = mdb_dn2id ( op, txn, NULL, &new_ndn, &nid, NULL, NULL );
437         switch( rs->sr_err ) {
438         case MDB_NOTFOUND:
439                 break;
440         case 0:
441                 /* Allow rename to same DN */
442                 if ( nid == e->e_id )
443                         break;
444                 rs->sr_err = LDAP_ALREADY_EXISTS;
445                 goto return_results;
446         default:
447                 rs->sr_err = LDAP_OTHER;
448                 rs->sr_text = "internal error";
449                 goto return_results;
450         }
451
452         assert( op->orr_modlist != NULL );
453
454         if( op->o_preread ) {
455                 if( preread_ctrl == NULL ) {
456                         preread_ctrl = &ctrls[num_ctrls++];
457                         ctrls[num_ctrls] = NULL;
458                 }
459                 if( slap_read_controls( op, rs, e,
460                         &slap_pre_read_bv, preread_ctrl ) )
461                 {
462                         Debug( LDAP_DEBUG_TRACE,
463                                 "<=- " LDAP_XSTRING(mdb_modrdn)
464                                 ": pre-read failed!\n", 0, 0, 0 );
465                         if ( op->o_preread & SLAP_CONTROL_CRITICAL ) {
466                                 /* FIXME: is it correct to abort
467                                  * operation if control fails? */
468                                 goto return_results;
469                         }
470                 }
471         }
472
473         /* delete old DN */
474         rs->sr_err = mdb_dn2id_delete( op, mc, e->e_id );
475         if ( rs->sr_err != 0 ) {
476                 Debug(LDAP_DEBUG_TRACE,
477                         "<=- " LDAP_XSTRING(mdb_modrdn)
478                         ": dn2id del failed: %s (%d)\n",
479                         mdb_strerror(rs->sr_err), rs->sr_err, 0 );
480                 rs->sr_err = LDAP_OTHER;
481                 rs->sr_text = "DN index delete fail";
482                 goto return_results;
483         }
484
485         /* copy the entry, then override some fields */
486         dummy = *e;
487         dummy.e_name = new_dn;
488         dummy.e_nname = new_ndn;
489         dummy.e_attrs = NULL;
490
491         /* add new DN */
492         rs->sr_err = mdb_dn2id_add( op, mc, mc, np ? np->e_id : p->e_id, &dummy );
493         if ( rs->sr_err != 0 ) {
494                 Debug(LDAP_DEBUG_TRACE,
495                         "<=- " LDAP_XSTRING(mdb_modrdn)
496                         ": dn2id add failed: %s (%d)\n",
497                         mdb_strerror(rs->sr_err), rs->sr_err, 0 );
498                 rs->sr_err = LDAP_OTHER;
499                 rs->sr_text = "DN index add failed";
500                 goto return_results;
501         }
502
503         dummy.e_attrs = e->e_attrs;
504
505         /* modify entry */
506         rs->sr_err = mdb_modify_internal( op, txn, op->orr_modlist, &dummy,
507                 &rs->sr_text, textbuf, textlen );
508         if( rs->sr_err != LDAP_SUCCESS ) {
509                 Debug(LDAP_DEBUG_TRACE,
510                         "<=- " LDAP_XSTRING(mdb_modrdn)
511                         ": modify failed: %s (%d)\n",
512                         mdb_strerror(rs->sr_err), rs->sr_err, 0 );
513                 if ( dummy.e_attrs == e->e_attrs ) dummy.e_attrs = NULL;
514                 goto return_results;
515         }
516
517         /* id2entry index */
518         rs->sr_err = mdb_id2entry_update( op, txn, NULL, &dummy );
519         if ( rs->sr_err != 0 ) {
520                 Debug(LDAP_DEBUG_TRACE,
521                         "<=- " LDAP_XSTRING(mdb_modrdn)
522                         ": id2entry failed: %s (%d)\n",
523                         mdb_strerror(rs->sr_err), rs->sr_err, 0 );
524                 rs->sr_err = LDAP_OTHER;
525                 rs->sr_text = "entry update failed";
526                 goto return_results;
527         }
528
529         if ( p_ndn.bv_len != 0 ) {
530                 parent_is_glue = is_entry_glue(p);
531                 rs->sr_err = mdb_dn2id_children( op, txn, p );
532                 if ( rs->sr_err != MDB_NOTFOUND ) {
533                         switch( rs->sr_err ) {
534                         case 0:
535                                 break;
536                         default:
537                                 Debug(LDAP_DEBUG_ARGS,
538                                         "<=- " LDAP_XSTRING(mdb_modrdn)
539                                         ": has_children failed: %s (%d)\n",
540                                         mdb_strerror(rs->sr_err), rs->sr_err, 0 );
541                                 rs->sr_err = LDAP_OTHER;
542                                 rs->sr_text = "internal error";
543                                 goto return_results;
544                         }
545                 } else {
546                         parent_is_leaf = 1;
547                 }
548                 mdb_entry_return( op, p );
549                 p = NULL;
550         }
551
552         if( op->o_postread ) {
553                 if( postread_ctrl == NULL ) {
554                         postread_ctrl = &ctrls[num_ctrls++];
555                         ctrls[num_ctrls] = NULL;
556                 }
557                 if( slap_read_controls( op, rs, &dummy,
558                         &slap_post_read_bv, postread_ctrl ) )
559                 {
560                         Debug( LDAP_DEBUG_TRACE,
561                                 "<=- " LDAP_XSTRING(mdb_modrdn)
562                                 ": post-read failed!\n", 0, 0, 0 );
563                         if ( op->o_postread & SLAP_CONTROL_CRITICAL ) {
564                                 /* FIXME: is it correct to abort
565                                  * operation if control fails? */
566                                 goto return_results;
567                         }
568                 }
569         }
570
571         if( moi == &opinfo ) {
572                 LDAP_SLIST_REMOVE( &op->o_extra, &opinfo.moi_oe, OpExtra, oe_next );
573                 opinfo.moi_oe.oe_key = NULL;
574                 if( op->o_noop ) {
575                         mdb_txn_abort( txn );
576                         rs->sr_err = LDAP_X_NO_OPERATION;
577                         txn = NULL;
578                         /* Only free attrs if they were dup'd.  */
579                         if ( dummy.e_attrs == e->e_attrs ) dummy.e_attrs = NULL;
580                         goto return_results;
581
582                 } else {
583                         if(( rs->sr_err=mdb_txn_commit( txn )) != 0 ) {
584                                 rs->sr_text = "txn_commit failed";
585                         } else {
586                                 rs->sr_err = LDAP_SUCCESS;
587                         }
588                         txn = NULL;
589                 }
590         }
591
592         if( rs->sr_err != LDAP_SUCCESS ) {
593                 Debug( LDAP_DEBUG_TRACE,
594                         LDAP_XSTRING(mdb_modrdn) ": %s : %s (%d)\n",
595                         rs->sr_text, mdb_strerror(rs->sr_err), rs->sr_err );
596                 rs->sr_err = LDAP_OTHER;
597
598                 goto return_results;
599         }
600
601         Debug(LDAP_DEBUG_TRACE,
602                 LDAP_XSTRING(mdb_modrdn)
603                 ": rdn modified%s id=%08lx dn=\"%s\"\n",
604                 op->o_noop ? " (no-op)" : "",
605                 dummy.e_id, op->o_req_dn.bv_val );
606         rs->sr_text = NULL;
607         if( num_ctrls ) rs->sr_ctrls = ctrls;
608
609 return_results:
610         if ( dummy.e_attrs ) {
611                 attrs_free( dummy.e_attrs );
612         }
613         send_ldap_result( op, rs );
614
615 #if 0
616         if( rs->sr_err == LDAP_SUCCESS && mdb->bi_txn_cp_kbyte ) {
617                 TXN_CHECKPOINT( mdb->bi_dbenv,
618                         mdb->bi_txn_cp_kbyte, mdb->bi_txn_cp_min, 0 );
619         }
620 #endif
621
622         if ( rs->sr_err == LDAP_SUCCESS && parent_is_glue && parent_is_leaf ) {
623                 op->o_delete_glue_parent = 1;
624         }
625
626 done:
627         slap_graduate_commit_csn( op );
628
629         if( new_ndn.bv_val != NULL ) op->o_tmpfree( new_ndn.bv_val, op->o_tmpmemctx );
630         if( new_dn.bv_val != NULL ) op->o_tmpfree( new_dn.bv_val, op->o_tmpmemctx );
631
632         /* LDAP v3 Support */
633         if( np != NULL ) {
634                 /* free new parent */
635                 mdb_entry_return( op, np );
636         }
637
638         if( p != NULL ) {
639                 /* free parent */
640                 mdb_entry_return( op, p );
641         }
642
643         /* free entry */
644         if( e != NULL ) {
645                 mdb_entry_return( op, e );
646         }
647
648         if( moi == &opinfo ) {
649                 if( txn != NULL ) {
650                         mdb_txn_abort( txn );
651                 }
652                 if ( opinfo.moi_oe.oe_key ) {
653                         LDAP_SLIST_REMOVE( &op->o_extra, &opinfo.moi_oe, OpExtra, oe_next );
654                 }
655         }
656
657         if( preread_ctrl != NULL && (*preread_ctrl) != NULL ) {
658                 slap_sl_free( (*preread_ctrl)->ldctl_value.bv_val, op->o_tmpmemctx );
659                 slap_sl_free( *preread_ctrl, op->o_tmpmemctx );
660         }
661         if( postread_ctrl != NULL && (*postread_ctrl) != NULL ) {
662                 slap_sl_free( (*postread_ctrl)->ldctl_value.bv_val, op->o_tmpmemctx );
663                 slap_sl_free( *postread_ctrl, op->o_tmpmemctx );
664         }
665         return rs->sr_err;
666 }