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