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