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