]> git.sur5r.net Git - openldap/blob - servers/slapd/back-bdb/modrdn.c
Fix up last commits
[openldap] / servers / slapd / back-bdb / modrdn.c
1 /* modrdn.c - bdb backend modrdn routine */
2 /* $OpenLDAP$ */
3 /*
4  * Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved.
5  * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
6  */
7
8 #include "portable.h"
9
10 #include <stdio.h>
11 #include <ac/string.h>
12
13 #include "back-bdb.h"
14 #include "external.h"
15
16 int
17 bdb_modrdn(
18         Backend *be,
19         Connection      *conn,
20         Operation       *op,
21         struct berval   *dn,
22         struct berval   *ndn,
23         struct berval   *newrdn,
24         struct berval   *nnewrdn,
25         int             deleteoldrdn,
26         struct berval   *newSuperior,
27         struct berval   *nnewSuperior )
28 {
29         struct bdb_info *bdb = (struct bdb_info *) be->be_private;
30         AttributeDescription *children = slap_schema.si_ad_children;
31         AttributeDescription *entry = slap_schema.si_ad_entry;
32         struct berval   p_dn, p_ndn;
33         struct berval   new_dn = {0, NULL}, new_ndn = {0, NULL};
34         int             isroot = -1;
35         Entry           *e = NULL;
36         Entry           *p = NULL;
37         Entry           *matched;
38         /* LDAP v2 supporting correct attribute handling. */
39         LDAPRDN         *new_rdn = NULL;
40         LDAPRDN         *old_rdn = NULL;
41         int                     rc;
42         const char *text;
43         char textbuf[SLAP_TEXT_BUFLEN];
44         size_t textlen = sizeof textbuf;
45         DB_TXN *        ltid = NULL;
46         struct bdb_op_info opinfo;
47
48         ID                      id;
49
50         Entry           *np = NULL;                     /* newSuperior Entry */
51         struct berval   *np_dn = NULL;                  /* newSuperior dn */
52         struct berval   *np_ndn = NULL;                 /* newSuperior ndn */
53         struct berval   *new_parent_dn = NULL;  /* np_dn, p_dn, or NULL */
54
55         /* Used to interface with bdb_modify_internal() */
56         Modifications   *mod = NULL;            /* Used to delete old rdn */
57
58         int             manageDSAit = get_manageDSAit( op );
59
60         u_int32_t       locker;
61         DB_LOCK         lock;
62
63         int             noop = 0;
64
65 #ifdef NEW_LOGGING
66         LDAP_LOG ( OPERATION, ENTRY, "==>bdb_modrdn(%s,%s,%s)\n", 
67                 dn->bv_val,newrdn->bv_val, newSuperior ? newSuperior->bv_val : "NULL" );
68 #else
69         Debug( LDAP_DEBUG_TRACE, "==>bdb_modrdn(%s,%s,%s)\n",
70                 dn->bv_val, newrdn->bv_val,
71                 newSuperior ? newSuperior->bv_val : "NULL" );
72 #endif
73
74 #if 0
75         if( newSuperior != NULL ) {
76                 rc = LDAP_UNWILLING_TO_PERFORM;
77                 text = "newSuperior not implemented (yet)";
78                 goto return_results;
79         }
80 #endif
81
82         if( 0 ) {
83 retry:  /* transaction retry */
84                 if (e != NULL) {
85                         bdb_cache_delete_entry(&bdb->bi_cache, e);
86                         bdb_unlocked_cache_return_entry_w(&bdb->bi_cache, e);
87                 }
88                 if (p != NULL) {
89                         bdb_unlocked_cache_return_entry_r(&bdb->bi_cache, p);
90                 }
91                 if (np != NULL) {
92                         bdb_unlocked_cache_return_entry_r(&bdb->bi_cache, np);
93                 }
94 #ifdef NEW_LOGGING
95                 LDAP_LOG ( OPERATION, DETAIL1, "==>bdb_modrdn: retrying...\n", 0, 0, 0);
96 #else
97                 Debug( LDAP_DEBUG_TRACE, "==>bdb_modrdn: retrying...\n", 0, 0, 0 );
98 #endif
99                 rc = TXN_ABORT( ltid );
100                 ltid = NULL;
101                 op->o_private = NULL;
102                 if( rc != 0 ) {
103                         rc = LDAP_OTHER;
104                         text = "internal error";
105                         goto return_results;
106                 }
107                 ldap_pvt_thread_yield();
108         }
109
110         /* begin transaction */
111         rc = TXN_BEGIN( bdb->bi_dbenv, NULL, &ltid, 
112                 bdb->bi_db_opflags );
113         text = NULL;
114         if( rc != 0 ) {
115 #ifdef NEW_LOGGING
116                 LDAP_LOG ( OPERATION, ERR, 
117                         "==>bdb_modrdn: txn_begin failed: %s (%d)\n", 
118                         db_strerror(rc), rc, 0 );
119 #else
120                 Debug( LDAP_DEBUG_TRACE,
121                         "bdb_delete: txn_begin failed: %s (%d)\n",
122                         db_strerror(rc), rc, 0 );
123 #endif
124                 rc = LDAP_OTHER;
125                 text = "internal error";
126                 goto return_results;
127         }
128
129         locker = TXN_ID ( ltid );
130
131         opinfo.boi_bdb = be;
132         opinfo.boi_txn = ltid;
133         opinfo.boi_err = 0;
134         op->o_private = &opinfo;
135
136         /* get entry */
137         rc = bdb_dn2entry_w( be, ltid, ndn, &e, &matched, DB_RMW, locker, &lock );
138
139         switch( rc ) {
140         case 0:
141         case DB_NOTFOUND:
142                 break;
143         case DB_LOCK_DEADLOCK:
144         case DB_LOCK_NOTGRANTED:
145                 goto retry;
146         case LDAP_BUSY:
147                 text = "ldap server busy";
148                 goto return_results;
149         default:
150                 rc = LDAP_OTHER;
151                 text = "internal error";
152                 goto return_results;
153         }
154
155         if ( e == NULL ) {
156                 char* matched_dn = NULL;
157                 BerVarray refs;
158
159                 if( matched != NULL ) {
160                         matched_dn = ch_strdup( matched->e_dn );
161                         refs = is_entry_referral( matched )
162                                 ? get_entry_referrals( be, conn, op, matched )
163                                 : NULL;
164                         bdb_unlocked_cache_return_entry_r( &bdb->bi_cache, matched);
165                         matched = NULL;
166
167                 } else {
168                         refs = referral_rewrite( default_referral,
169                                 NULL, dn, LDAP_SCOPE_DEFAULT );
170                 }
171
172                 send_ldap_result( conn, op, rc = LDAP_REFERRAL,
173                         matched_dn, NULL, refs, NULL );
174
175                 ber_bvarray_free( refs );
176                 free( matched_dn );
177
178                 goto done;
179         }
180
181         /* check write on old entry */
182         rc = access_allowed( be, conn, op, e,
183                 entry, NULL, ACL_WRITE, NULL );
184
185         switch( opinfo.boi_err ) {
186         case DB_LOCK_DEADLOCK:
187         case DB_LOCK_NOTGRANTED:
188                 goto retry;
189         }
190
191         if ( ! rc ) {
192 #ifdef NEW_LOGGING
193                 LDAP_LOG ( OPERATION, ERR, 
194                         "==>bdb_modrdn: no access to entry\n", 0, 0, 0 );
195 #else
196                 Debug( LDAP_DEBUG_TRACE, "no access to entry\n", 0,
197                         0, 0 );
198 #endif
199                 rc = LDAP_INSUFFICIENT_ACCESS;
200                 goto return_results;
201         }
202
203         if (!manageDSAit && is_entry_referral( e ) ) {
204                 /* parent is a referral, don't allow add */
205                 /* parent is an alias, don't allow add */
206                 BerVarray refs = get_entry_referrals( be,
207                         conn, op, e );
208
209 #ifdef NEW_LOGGING
210                 LDAP_LOG ( OPERATION, DETAIL1, 
211                         "==>bdb_modrdn: entry %s is referral \n", e->e_dn, 0, 0 );
212 #else
213                 Debug( LDAP_DEBUG_TRACE, "bdb_modrdn: entry %s is referral\n",
214                         e->e_dn, 0, 0 );
215 #endif
216
217                 send_ldap_result( conn, op, rc = LDAP_REFERRAL,
218                         e->e_dn, NULL, refs, NULL );
219
220                 ber_bvarray_free( refs );
221                 goto done;
222         }
223
224         if ( be_issuffix( be, &e->e_nname ) ) {
225                 p_ndn = slap_empty_bv;
226         } else {
227                 dnParent( &e->e_nname, &p_ndn );
228         }
229         np_ndn = &p_ndn;
230         if ( p_ndn.bv_len != 0 ) {
231                 /* Make sure parent entry exist and we can write its 
232                  * children.
233                  */
234                 rc = bdb_dn2entry_r( be, ltid, &p_ndn, &p, NULL, 0, locker, &lock );
235
236                 switch( rc ) {
237                 case 0:
238                 case DB_NOTFOUND:
239                         break;
240                 case DB_LOCK_DEADLOCK:
241                 case DB_LOCK_NOTGRANTED:
242                         goto retry;
243                 case LDAP_BUSY:
244                         text = "ldap server busy";
245                         goto return_results;
246                 default:
247                         rc = LDAP_OTHER;
248                         text = "internal error";
249                         goto return_results;
250                 }
251
252                 if( p == NULL) {
253 #ifdef NEW_LOGGING
254                         LDAP_LOG ( OPERATION, ERR, 
255                                 "==>bdb_modrdn: parent does not exist\n", 0, 0, 0 );
256 #else
257                         Debug( LDAP_DEBUG_TRACE, "bdb_modrdn: parent does not exist\n",
258                                 0, 0, 0);
259 #endif
260                         rc = LDAP_OTHER;
261                         goto return_results;
262                 }
263
264                 /* check parent for "children" acl */
265                 if ( ! access_allowed( be, conn, op, p,
266                         children, NULL, ACL_WRITE, NULL ) )
267                 {
268 #ifdef NEW_LOGGING
269                         LDAP_LOG ( OPERATION, ERR, 
270                                 "==>bdb_modrdn: no access to parent\n", 0, 0, 0 );
271 #else
272                         Debug( LDAP_DEBUG_TRACE, "no access to parent\n", 0,
273                                 0, 0 );
274 #endif
275                         send_ldap_result( conn, op, LDAP_INSUFFICIENT_ACCESS,
276                                 NULL, NULL, NULL, NULL );
277                         goto return_results;
278                 }
279
280 #ifdef NEW_LOGGING
281                 LDAP_LOG ( OPERATION, DETAIL1, 
282                         "==>bdb_modrdn: wr to children %s is OK\n", p_ndn.bv_val, 0, 0 );
283 #else
284                 Debug( LDAP_DEBUG_TRACE,
285                         "bdb_modrdn: wr to children of entry %s OK\n",
286                         p_ndn.bv_val, 0, 0 );
287 #endif
288                 
289                 if ( p_ndn.bv_val == slap_empty_bv.bv_val ) {
290                         p_dn = slap_empty_bv;
291                 } else {
292                         dnParent( &e->e_name, &p_dn );
293                 }
294
295 #ifdef NEW_LOGGING
296                 LDAP_LOG ( OPERATION, DETAIL1, 
297                         "==>bdb_modrdn: parent dn=%s\n", p_dn.bv_val, 0, 0 );
298 #else
299                 Debug( LDAP_DEBUG_TRACE,
300                         "bdb_modrdn: parent dn=%s\n",
301                         p_dn.bv_val, 0, 0 );
302 #endif
303
304         } else {
305                 /* no parent, modrdn entry directly under root */
306                 isroot = be_isroot( be, &op->o_ndn );
307                 if ( ! isroot ) {
308                         if ( be_issuffix( be, (struct berval *)&slap_empty_bv )
309                                 || be_isupdate( be, &op->o_ndn ) ) {
310
311                                 p = (Entry *)&slap_entry_root;
312
313                                 /* check parent for "children" acl */
314                                 rc = access_allowed( be, conn, op, p,
315                                         children, NULL, ACL_WRITE, NULL );
316
317                                 p = NULL;
318
319                                 if ( ! rc )
320                                 {
321 #ifdef NEW_LOGGING
322                                         LDAP_LOG ( OPERATION, ERR, 
323                                                 "==>bdb_modrdn: no access to parent\n", 0, 0, 0 );
324 #else
325                                         Debug( LDAP_DEBUG_TRACE, 
326                                                 "no access to parent\n", 
327                                                 0, 0, 0 );
328 #endif
329                                         send_ldap_result( conn, op, 
330                                                 LDAP_INSUFFICIENT_ACCESS,
331                                                 NULL, NULL, NULL, NULL );
332                                         goto return_results;
333                                 }
334
335 #ifdef NEW_LOGGING
336                                 LDAP_LOG ( OPERATION, DETAIL1, 
337                                         "==>bdb_modrdn: wr to children of entry \"%s\" OK\n", 
338                                         p_dn.bv_val, 0, 0 );
339 #else
340                                 Debug( LDAP_DEBUG_TRACE,
341                                         "bdb_modrdn: wr to children of entry \"\" OK\n",
342                                         0, 0, 0 );
343 #endif
344                 
345                                 p_dn.bv_val = "";
346                                 p_dn.bv_len = 0;
347
348 #ifdef NEW_LOGGING
349                                 LDAP_LOG ( OPERATION, DETAIL1, 
350                                         "==>bdb_modrdn: parent dn=\"\" \n", 0, 0, 0 );
351 #else
352                                 Debug( LDAP_DEBUG_TRACE,
353                                         "bdb_modrdn: parent dn=\"\"\n",
354                                         0, 0, 0 );
355 #endif
356
357                         } else {
358 #ifdef NEW_LOGGING
359                                 LDAP_LOG ( OPERATION, ERR, 
360                                         "==>bdb_modrdn: no parent, not root &\"\" is not "
361                                         "suffix\n", 0, 0, 0 );
362 #else
363                                 Debug( LDAP_DEBUG_TRACE,
364                                         "bdb_modrdn: no parent, not root "
365                                         "& \"\" is not suffix\n",
366                                         0, 0, 0);
367 #endif
368                                 rc = LDAP_INSUFFICIENT_ACCESS;
369                                 goto return_results;
370                         }
371                 }
372         }
373
374         new_parent_dn = &p_dn;  /* New Parent unless newSuperior given */
375
376         if ( newSuperior != NULL ) {
377 #ifdef NEW_LOGGING
378                 LDAP_LOG ( OPERATION, DETAIL1, 
379                         "==>bdb_modrdn: new parent \"%s\" requested...\n", 
380                         newSuperior->bv_val, 0, 0 );
381 #else
382                 Debug( LDAP_DEBUG_TRACE, 
383                         "bdb_modrdn: new parent \"%s\" requested...\n",
384                         newSuperior->bv_val, 0, 0 );
385 #endif
386
387                 if ( newSuperior->bv_len ) {
388                         np_dn = newSuperior;
389                         np_ndn = nnewSuperior;
390
391                         /* newSuperior == oldParent?, if so ==> ERROR */
392                         /* newSuperior == entry being moved?, if so ==> ERROR */
393                         /* Get Entry with dn=newSuperior. Does newSuperior exist? */
394
395                         rc = bdb_dn2entry_r( be, ltid, nnewSuperior, &np, NULL, 0, locker, &lock );
396
397                         switch( rc ) {
398                         case 0:
399                         case DB_NOTFOUND:
400                                 break;
401                         case DB_LOCK_DEADLOCK:
402                         case DB_LOCK_NOTGRANTED:
403                                 goto retry;
404                         case LDAP_BUSY:
405                                 text = "ldap server busy";
406                                 goto return_results;
407                         default:
408                                 rc = LDAP_OTHER;
409                                 text = "internal error";
410                                 goto return_results;
411                         }
412
413                         if( np == NULL) {
414 #ifdef NEW_LOGGING
415                                 LDAP_LOG ( OPERATION, DETAIL1, 
416                                         "==>bdb_modrdn: newSup(ndn=%s) not here!\n", 
417                                         np_ndn->bv_val, 0, 0 );
418 #else
419                                 Debug( LDAP_DEBUG_TRACE,
420                                         "bdb_modrdn: newSup(ndn=%s) not here!\n",
421                                         np_ndn->bv_val, 0, 0);
422 #endif
423                                 rc = LDAP_OTHER;
424                                 goto return_results;
425                         }
426
427 #ifdef NEW_LOGGING
428                         LDAP_LOG ( OPERATION, DETAIL1, 
429                                 "==>bdb_modrdn: wr to new parent OK np=%p, id=%ld\n", 
430                                 np, (long) np->e_id, 0 );
431 #else
432                         Debug( LDAP_DEBUG_TRACE,
433                                 "bdb_modrdn: wr to new parent OK np=%p, id=%ld\n",
434                                 np, (long) np->e_id, 0 );
435 #endif
436
437                         /* check newSuperior for "children" acl */
438                         if ( !access_allowed( be, conn, op, np, children, NULL, ACL_WRITE, NULL ) ) {
439 #ifdef NEW_LOGGING
440                                 LDAP_LOG ( OPERATION, DETAIL1, 
441                                         "==>bdb_modrdn: no wr to newSup children\n", 0, 0, 0 );
442 #else
443                                 Debug( LDAP_DEBUG_TRACE,
444                                         "bdb_modrdn: no wr to newSup children\n",
445                                         0, 0, 0 );
446 #endif
447                                 rc = LDAP_INSUFFICIENT_ACCESS;
448                                 goto return_results;
449                         }
450
451 #ifdef BDB_ALIASES
452                         if ( is_entry_alias( np ) ) {
453                                 /* parent is an alias, don't allow add */
454 #ifdef NEW_LOGGING
455                                 LDAP_LOG ( OPERATION, DETAIL1, 
456                                         "==>bdb_modrdn: entry is alias\n", 0, 0, 0 );
457 #else
458                                 Debug( LDAP_DEBUG_TRACE, "bdb_modrdn: entry is alias\n",
459                                         0, 0, 0 );
460 #endif
461
462                                 rc = LDAP_ALIAS_PROBLEM;
463                                 goto return_results;
464                         }
465 #endif
466
467                         if ( is_entry_referral( np ) ) {
468                                 /* parent is a referral, don't allow add */
469 #ifdef NEW_LOGGING
470                                 LDAP_LOG ( OPERATION, DETAIL1, 
471                                         "==>bdb_modrdn: entry is referral\n", 0, 0, 0 );
472 #else
473                                 Debug( LDAP_DEBUG_TRACE, "bdb_modrdn: entry is referral\n",
474                                         0, 0, 0 );
475 #endif
476
477                                 rc = LDAP_OTHER;
478                                 goto return_results;
479                         }
480
481                 } else {
482                         if ( isroot == -1 ) {
483                                 isroot = be_isroot( be, &op->o_ndn );
484                         }
485                         
486                         np_dn = NULL;
487
488                         /* no parent, modrdn entry directly under root */
489                         if ( ! isroot ) {
490                                 if ( be_issuffix( be, (struct berval *)&slap_empty_bv )
491                                         || be_isupdate( be, &op->o_ndn ) ) {
492                                         np = (Entry *)&slap_entry_root;
493
494                                         /* check parent for "children" acl */
495                                         rc = access_allowed( be, conn, op, np,
496                                                 children, NULL, ACL_WRITE, NULL );
497
498                                         np = NULL;
499
500                                         if ( ! rc )
501                                         {
502 #ifdef NEW_LOGGING
503                                                 LDAP_LOG ( OPERATION, ERR, 
504                                                         "==>bdb_modrdn: no access to superior\n", 0, 0, 0 );
505 #else
506                                                 Debug( LDAP_DEBUG_TRACE, 
507                                                         "no access to new superior\n", 
508                                                         0, 0, 0 );
509 #endif
510                                                 send_ldap_result( conn, op, 
511                                                         LDAP_INSUFFICIENT_ACCESS,
512                                                         NULL, NULL, NULL, NULL );
513                                                 goto return_results;
514                                         }
515
516 #ifdef NEW_LOGGING
517                                         LDAP_LOG ( OPERATION, DETAIL1, 
518                                                 "bdb_modrdn: wr to children entry \"\" OK\n", 0, 0, 0 );
519 #else
520                                         Debug( LDAP_DEBUG_TRACE,
521                                                 "bdb_modrdn: wr to children of entry \"\" OK\n",
522                                                 0, 0, 0 );
523 #endif
524                 
525                                 } else {
526 #ifdef NEW_LOGGING
527                                         LDAP_LOG ( OPERATION, ERR, 
528                                                 "bdb_modrdn: new superior=\"\", not root & \"\" "
529                                                 "is not suffix\n", 0, 0, 0 );
530 #else
531                                         Debug( LDAP_DEBUG_TRACE,
532                                                 "bdb_modrdn: new superior=\"\", not root "
533                                                 "& \"\" is not suffix\n",
534                                                 0, 0, 0);
535 #endif
536                                         rc = LDAP_INSUFFICIENT_ACCESS;
537                                         goto return_results;
538                                 }
539                         }
540
541 #ifdef NEW_LOGGING
542                         LDAP_LOG ( OPERATION, DETAIL1, 
543                                 "bdb_modrdn: new superior=\"\"\n", 0, 0, 0 );
544 #else
545                         Debug( LDAP_DEBUG_TRACE,
546                                 "bdb_modrdn: new superior=\"\"\n",
547                                 0, 0, 0 );
548 #endif
549                 }
550
551 #ifdef NEW_LOGGING
552                 LDAP_LOG ( OPERATION, DETAIL1, 
553                         "bdb_modrdn: wr to new parent's children OK\n", 0, 0, 0 );
554 #else
555                 Debug( LDAP_DEBUG_TRACE,
556                         "bdb_modrdn: wr to new parent's children OK\n",
557                         0, 0, 0 );
558 #endif
559
560                 new_parent_dn = np_dn;
561         }
562
563         /* Build target dn and make sure target entry doesn't exist already. */
564         build_new_dn( &new_dn, new_parent_dn, newrdn ); 
565
566         dnNormalize2( NULL, &new_dn, &new_ndn );
567
568 #ifdef NEW_LOGGING
569         LDAP_LOG ( OPERATION, RESULTS, 
570                 "bdb_modrdn: new ndn=%s\n", new_ndn.bv_val, 0, 0 );
571 #else
572         Debug( LDAP_DEBUG_TRACE, "bdb_modrdn: new ndn=%s\n",
573                 new_ndn.bv_val, 0, 0 );
574 #endif
575
576         rc = bdb_dn2id ( be, ltid, &new_ndn, &id, 0 );
577         switch( rc ) {
578         case DB_LOCK_DEADLOCK:
579         case DB_LOCK_NOTGRANTED:
580                 goto retry;
581         case DB_NOTFOUND:
582                 break;
583         case 0:
584                 rc = LDAP_ALREADY_EXISTS;
585                 goto return_results;
586         default:
587                 rc = LDAP_OTHER;
588                 text = "internal error";
589                 goto return_results;
590         }
591
592 #ifdef NEW_LOGGING
593         LDAP_LOG ( OPERATION, ERR, 
594                 "bdb_modrdn: new ndn=%s does not exist\n", new_ndn.bv_val, 0, 0 );
595 #else
596         Debug( LDAP_DEBUG_TRACE,
597                 "bdb_modrdn: new ndn=%s does not exist\n",
598                 new_ndn.bv_val, 0, 0 );
599 #endif
600
601         /* Get attribute type and attribute value of our new rdn, we will
602          * need to add that to our new entry
603          */
604         if ( ldap_bv2rdn( newrdn, &new_rdn, (char **)&text,
605                 LDAP_DN_FORMAT_LDAP ) )
606         {
607 #ifdef NEW_LOGGING
608                 LDAP_LOG ( OPERATION, ERR, 
609                         "bdb_modrdn: can't figure out "
610                         "type(s)/values(s) of newrdn\n", 
611                         0, 0, 0 );
612 #else
613                 Debug( LDAP_DEBUG_TRACE,
614                         "bdb_modrdn: can't figure out "
615                         "type(s)/values(s) of newrdn\n", 
616                         0, 0, 0 );
617 #endif
618                 rc = LDAP_INVALID_DN_SYNTAX;
619                 text = "unknown type(s) used in RDN";
620                 goto return_results;
621         }
622
623 #ifdef NEW_LOGGING
624         LDAP_LOG ( OPERATION, RESULTS, 
625                 "bdb_modrdn: new_rdn_type=\"%s\", "
626                 "new_rdn_val=\"%s\"\n",
627                 new_rdn[ 0 ][ 0 ]->la_attr.bv_val, 
628                 new_rdn[ 0 ][ 0 ]->la_value.bv_val, 0 );
629 #else
630         Debug( LDAP_DEBUG_TRACE,
631                 "bdb_modrdn: new_rdn_type=\"%s\", "
632                 "new_rdn_val=\"%s\"\n",
633                 new_rdn[ 0 ][ 0 ]->la_attr.bv_val,
634                 new_rdn[ 0 ][ 0 ]->la_value.bv_val, 0 );
635 #endif
636
637         if ( deleteoldrdn ) {
638                 if ( ldap_bv2rdn( dn, &old_rdn, (char **)&text,
639                         LDAP_DN_FORMAT_LDAP ) )
640                 {
641 #ifdef NEW_LOGGING
642                         LDAP_LOG ( OPERATION, ERR, 
643                                 "bdb_modrdn: can't figure out "
644                                 "type(s)/values(s) of old_rdn\n", 
645                                 0, 0, 0 );
646 #else
647                         Debug( LDAP_DEBUG_TRACE,
648                                 "bdb_modrdn: can't figure out "
649                                 "the old_rdn type(s)/value(s)\n", 
650                                 0, 0, 0 );
651 #endif
652                         rc = LDAP_OTHER;
653                         text = "cannot parse RDN from old DN";
654                         goto return_results;            
655                 }
656         }
657
658         /* prepare modlist of modifications from old/new rdn */
659         rc = slap_modrdn2mods( be, conn, op, e, old_rdn, new_rdn, 
660                         deleteoldrdn, &mod );
661         if ( rc != LDAP_SUCCESS ) {
662                 goto return_results;
663         }
664         
665         /* delete old one */
666         rc = bdb_dn2id_delete( be, ltid, p_ndn.bv_val, e );
667         if ( rc != 0 ) {
668                 switch( rc ) {
669                 case DB_LOCK_DEADLOCK:
670                 case DB_LOCK_NOTGRANTED:
671                         goto retry;
672                 }
673                 rc = LDAP_OTHER;
674                 text = "DN index delete fail";
675                 goto return_results;
676         }
677
678         (void) bdb_cache_delete_entry(&bdb->bi_cache, e);
679
680         /* Binary format uses a single contiguous block, cannot
681          * free individual fields. Leave new_dn/new_ndn set so
682          * they can be individually freed later.
683          */
684         e->e_name = new_dn;
685         e->e_nname = new_ndn;
686
687         new_dn.bv_val = NULL;
688         new_ndn.bv_val = NULL;
689
690         /* add new one */
691         rc = bdb_dn2id_add( be, ltid, np_ndn, e );
692         if ( rc != 0 ) {
693                 switch( rc ) {
694                 case DB_LOCK_DEADLOCK:
695                 case DB_LOCK_NOTGRANTED:
696                         goto retry;
697                 }
698                 rc = LDAP_OTHER;
699                 text = "DN index add failed";
700                 goto return_results;
701         }
702
703         /* modify entry */
704         rc = bdb_modify_internal( be, conn, op, ltid, &mod[0], e,
705                 &text, textbuf, textlen );
706
707         if( rc != LDAP_SUCCESS ) {
708                 switch( rc ) {
709                 case DB_LOCK_DEADLOCK:
710                 case DB_LOCK_NOTGRANTED:
711                         goto retry;
712                 }
713                 goto return_results;
714         }
715         
716         /* id2entry index */
717         rc = bdb_id2entry_update( be, ltid, e );
718         if ( rc != 0 ) {
719                 switch( rc ) {
720                 case DB_LOCK_DEADLOCK:
721                 case DB_LOCK_NOTGRANTED:
722                         goto retry;
723                 }
724                 rc = LDAP_OTHER;
725                 text = "entry update failed";
726                 goto return_results;
727         }
728
729         if( op->o_noop ) {
730                 if(( rc=TXN_ABORT( ltid )) != 0 ) {
731                         text = "txn_abort (no-op) failed";
732                 } else {
733                         noop = 1;
734                         rc = LDAP_SUCCESS;
735                 }
736
737         } else {
738                 char gid[DB_XIDDATASIZE];
739
740                 snprintf( gid, sizeof( gid ), "%s-%08lx-%08lx",
741                         bdb_uuid.bv_val, (long) op->o_connid, (long) op->o_opid );
742
743                 if(( rc=TXN_PREPARE( ltid, gid )) != 0 ) {
744                         text = "txn_prepare failed";
745                 } else {
746                         if( bdb_cache_update_entry(&bdb->bi_cache, e) == -1 ) {
747                                 if(( rc=TXN_ABORT( ltid )) != 0 ) {
748                                         text ="cache update & txn_abort failed";
749                                 } else {
750                                         rc = LDAP_OTHER;
751                                         text = "cache update failed";
752                                 }
753
754                         } else {
755                                 if(( rc=TXN_COMMIT( ltid, 0 )) != 0 ) {
756                                         text = "txn_commit failed";
757                                 } else {
758                                         rc = LDAP_SUCCESS;
759                                 }
760                         }
761                 }
762         }
763  
764         ltid = NULL;
765         op->o_private = NULL;
766  
767         if( rc == LDAP_SUCCESS ) {
768 #ifdef NEW_LOGGING
769                 LDAP_LOG ( OPERATION, RESULTS, 
770                         "bdb_modrdn: rdn modified%s id=%08lx dn=\"%s\"\n", 
771                         op->o_noop ? " (no-op)" : "", e->e_id, e->e_dn );
772 #else
773                 Debug(LDAP_DEBUG_TRACE,
774                         "bdb_modrdn: rdn modified%s id=%08lx dn=\"%s\"\n",
775                         op->o_noop ? " (no-op)" : "", e->e_id, e->e_dn );
776 #endif
777                 text = NULL;
778                 if ( !noop ) {
779                         bdb_cache_entry_commit( e );
780                 }
781
782         } else {
783 #ifdef NEW_LOGGING
784                 LDAP_LOG ( OPERATION, RESULTS, "bdb_modrdn: %s : %s (%d)\n", 
785                         text, db_strerror(rc), rc );
786 #else
787                 Debug( LDAP_DEBUG_TRACE, "bdb_add: %s : %s (%d)\n",
788                         text, db_strerror(rc), rc );
789 #endif
790                 rc = LDAP_OTHER;
791         }
792
793 return_results:
794         send_ldap_result( conn, op, rc,
795                 NULL, text, NULL, NULL );
796
797         if( rc == LDAP_SUCCESS && bdb->bi_txn_cp ) {
798                 ldap_pvt_thread_yield();
799                 TXN_CHECKPOINT( bdb->bi_dbenv,
800                         bdb->bi_txn_cp_kbyte, bdb->bi_txn_cp_min, 0 );
801         }
802
803 done:
804         if( new_dn.bv_val != NULL ) free( new_dn.bv_val );
805         if( new_ndn.bv_val != NULL ) free( new_ndn.bv_val );
806
807         /* LDAP v2 supporting correct attribute handling. */
808         if ( new_rdn != NULL ) {
809                 ldap_rdnfree( new_rdn );
810         }
811         if ( old_rdn != NULL ) {
812                 ldap_rdnfree( old_rdn );
813         }
814         if( mod != NULL ) {
815                 Modifications *tmp;
816                 for (; mod; mod=tmp ) {
817                         tmp = mod->sml_next;
818                         free( mod );
819                 }
820         }
821
822         /* LDAP v3 Support */
823         if( np != NULL ) {
824                 /* free new parent and reader lock */
825                 bdb_unlocked_cache_return_entry_r(&bdb->bi_cache, np);
826         }
827
828         if( p != NULL ) {
829                 /* free parent and reader lock */
830                 bdb_unlocked_cache_return_entry_r(&bdb->bi_cache, p);
831         }
832
833         /* free entry */
834         if( e != NULL ) {
835                 bdb_unlocked_cache_return_entry_w( &bdb->bi_cache, e);
836         }
837
838         if( ltid != NULL ) {
839                 TXN_ABORT( ltid );
840                 op->o_private = NULL;
841         }
842
843         return ( ( rc == LDAP_SUCCESS ) ? noop : rc );
844 }