]> git.sur5r.net Git - openldap/blob - servers/slapd/back-bdb/modrdn.c
- partial attribute replication tested ok
[openldap] / servers / slapd / back-bdb / modrdn.c
1 /* modrdn.c - bdb backend modrdn routine */
2 /* $OpenLDAP$ */
3 /*
4  * Copyright 1998-2003 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( Operation   *op, SlapReply *rs )
18 {
19         struct bdb_info *bdb = (struct bdb_info *) op->o_bd->be_private;
20         AttributeDescription *children = slap_schema.si_ad_children;
21         AttributeDescription *entry = slap_schema.si_ad_entry;
22         struct berval   p_dn, p_ndn;
23         struct berval   new_dn = {0, NULL}, new_ndn = {0, NULL};
24         int             isroot = -1;
25         Entry           *e = NULL;
26         Entry           *p = NULL;
27         EntryInfo       *ei = NULL, *eip = NULL, *nei = NULL, *neip = NULL;
28         /* LDAP v2 supporting correct attribute handling. */
29         LDAPRDN         new_rdn = NULL;
30         LDAPRDN         old_rdn = NULL;
31         char textbuf[SLAP_TEXT_BUFLEN];
32         size_t textlen = sizeof textbuf;
33         DB_TXN          *ltid = NULL, *lt2;
34         struct bdb_op_info opinfo;
35         Entry dummy, *save;
36
37         ID                      id;
38
39         Entry           *np = NULL;                     /* newSuperior Entry */
40         struct berval   *np_dn = NULL;                  /* newSuperior dn */
41         struct berval   *np_ndn = NULL;                 /* newSuperior ndn */
42         struct berval   *new_parent_dn = NULL;  /* np_dn, p_dn, or NULL */
43
44         /* Used to interface with bdb_modify_internal() */
45         Modifications   *mod = NULL;            /* Used to delete old rdn */
46
47         int             manageDSAit = get_manageDSAit( op );
48
49         u_int32_t       locker = 0;
50         DB_LOCK         lock, plock, nplock;
51
52         int             noop = 0;
53
54         int             num_retries = 0;
55
56 #ifdef LDAP_SYNC
57         Operation *ps_list;
58         struct psid_entry *pm_list, *pm_prev;
59 #endif
60
61 #ifdef NEW_LOGGING
62         LDAP_LOG ( OPERATION, ENTRY, "==>bdb_modrdn(%s,%s,%s)\n", 
63                 op->o_req_dn.bv_val,op->oq_modrdn.rs_newrdn.bv_val,
64                 op->oq_modrdn.rs_newSup ? op->oq_modrdn.rs_newSup->bv_val : "NULL" );
65 #else
66         Debug( LDAP_DEBUG_TRACE, "==>bdb_modrdn(%s,%s,%s)\n",
67                 op->o_req_dn.bv_val,op->oq_modrdn.rs_newrdn.bv_val,
68                 op->oq_modrdn.rs_newSup ? op->oq_modrdn.rs_newSup->bv_val : "NULL" );
69 #endif
70
71         if( 0 ) {
72 retry:  /* transaction retry */
73                 if (e != NULL) {
74                         bdb_unlocked_cache_return_entry_w(&bdb->bi_cache, e);
75                         e = NULL;
76                 }
77                 if (p != NULL) {
78                         bdb_unlocked_cache_return_entry_r(&bdb->bi_cache, p);
79                         p = NULL;
80                 }
81                 if (np != NULL) {
82                         bdb_unlocked_cache_return_entry_r(&bdb->bi_cache, np);
83                         np = NULL;
84                 }
85 #ifdef NEW_LOGGING
86                 LDAP_LOG ( OPERATION, DETAIL1, "==>bdb_modrdn: retrying...\n", 0, 0, 0);
87 #else
88                 Debug( LDAP_DEBUG_TRACE, "==>bdb_modrdn: retrying...\n", 0, 0, 0 );
89 #endif
90
91 #ifdef LDAP_SYNC
92                 pm_list = LDAP_LIST_FIRST(&op->o_pm_list);
93                 while ( pm_list != NULL ) {
94                         LDAP_LIST_REMOVE ( pm_list, ps_link );
95                         pm_prev = pm_list;
96                         pm_list = LDAP_LIST_NEXT ( pm_list, ps_link );
97                         ch_free( pm_prev );
98                 }
99 #endif
100
101                 rs->sr_err = TXN_ABORT( ltid );
102                 ltid = NULL;
103                 op->o_private = NULL;
104                 op->o_do_not_cache = opinfo.boi_acl_cache;
105                 if( rs->sr_err != 0 ) {
106                         rs->sr_err = LDAP_OTHER;
107                         rs->sr_text = "internal error";
108                         goto return_results;
109                 }
110                 bdb_trans_backoff( ++num_retries );
111                 ldap_pvt_thread_yield();
112         }
113
114         /* begin transaction */
115         rs->sr_err = TXN_BEGIN( bdb->bi_dbenv, NULL, &ltid, 
116                 bdb->bi_db_opflags );
117         rs->sr_text = NULL;
118         if( rs->sr_err != 0 ) {
119 #ifdef NEW_LOGGING
120                 LDAP_LOG ( OPERATION, ERR, 
121                         "==>bdb_modrdn: txn_begin failed: %s (%d)\n", 
122                         db_strerror(rs->sr_err), rs->sr_err, 0 );
123 #else
124                 Debug( LDAP_DEBUG_TRACE,
125                         "bdb_delete: txn_begin failed: %s (%d)\n",
126                         db_strerror(rs->sr_err), rs->sr_err, 0 );
127 #endif
128                 rs->sr_err = LDAP_OTHER;
129                 rs->sr_text = "internal error";
130                 goto return_results;
131         }
132
133         locker = TXN_ID ( ltid );
134
135         opinfo.boi_bdb = op->o_bd;
136         opinfo.boi_txn = ltid;
137         opinfo.boi_locker = locker;
138         opinfo.boi_err = 0;
139         opinfo.boi_acl_cache = op->o_do_not_cache;
140         op->o_private = &opinfo;
141
142         /* get entry */
143         rs->sr_err = bdb_dn2entry( op, ltid, &op->o_req_ndn, &ei, 1,
144                 locker, &lock );
145
146         switch( rs->sr_err ) {
147         case 0:
148         case DB_NOTFOUND:
149                 break;
150         case DB_LOCK_DEADLOCK:
151         case DB_LOCK_NOTGRANTED:
152                 goto retry;
153         case LDAP_BUSY:
154                 rs->sr_text = "ldap server busy";
155                 goto return_results;
156         default:
157                 rs->sr_err = LDAP_OTHER;
158                 rs->sr_text = "internal error";
159                 goto return_results;
160         }
161
162         e = ei->bei_e;
163 #ifdef LDAP_SYNCREPL
164         if ( rs->sr_err == DB_NOTFOUND || !e ||
165                         ( !manageDSAit && is_entry_glue( e ))) {
166                 if( e != NULL && !is_entry_glue( e )) {
167 #else
168         if ( rs->sr_err == DB_NOTFOUND ) {
169                 if( e != NULL ) {
170 #endif
171                         rs->sr_matched = ch_strdup( e->e_dn );
172                         rs->sr_ref = is_entry_referral( e )
173                                 ? get_entry_referrals( op, e )
174                                 : NULL;
175                         bdb_unlocked_cache_return_entry_r( &bdb->bi_cache, e);
176                         e = NULL;
177
178                 } else {
179 #ifdef LDAP_SYNCREPL
180                         BerVarray deref = op->o_bd->syncinfo ?
181                                                           op->o_bd->syncinfo->provideruri_bv : default_referral;
182 #else
183                         BerVarray deref = default_referral;
184 #endif
185                         rs->sr_ref = referral_rewrite( deref, NULL, &op->o_req_dn, LDAP_SCOPE_DEFAULT );
186                 }
187
188                 rs->sr_err = LDAP_REFERRAL;
189                 send_ldap_result( op, rs );
190
191                 ber_bvarray_free( rs->sr_ref );
192                 free( (char *)rs->sr_matched );
193                 rs->sr_ref = NULL;
194                 rs->sr_matched = NULL;
195
196                 goto done;
197         }
198
199         if ( get_assert( op ) &&
200                 ( test_filter( op, e, get_assertion( op )) != LDAP_COMPARE_TRUE ))
201         {
202                 rs->sr_err = LDAP_ASSERTION_FAILED;
203                 goto return_results;
204         }
205
206         /* check write on old entry */
207         rs->sr_err = access_allowed( op, e, entry, NULL, ACL_WRITE, NULL );
208         if ( ! rs->sr_err ) {
209                 switch( opinfo.boi_err ) {
210                 case DB_LOCK_DEADLOCK:
211                 case DB_LOCK_NOTGRANTED:
212                         goto retry;
213                 }
214
215 #ifdef NEW_LOGGING
216                 LDAP_LOG ( OPERATION, ERR, 
217                         "==>bdb_modrdn: no access to entry\n", 0, 0, 0 );
218 #else
219                 Debug( LDAP_DEBUG_TRACE, "no access to entry\n", 0,
220                         0, 0 );
221 #endif
222                 rs->sr_text = "no write access to old entry";
223                 rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
224                 goto return_results;
225         }
226
227 #ifndef BDB_HIER
228         rs->sr_err = bdb_cache_children( op, ltid, e );
229         if ( rs->sr_err != DB_NOTFOUND ) {
230                 switch( rs->sr_err ) {
231                 case DB_LOCK_DEADLOCK:
232                 case DB_LOCK_NOTGRANTED:
233                         goto retry;
234                 case 0:
235 #ifdef NEW_LOGGING
236                         LDAP_LOG ( OPERATION, DETAIL1, 
237                                 "<=- bdb_modrdn: non-leaf %s\n", op->o_req_dn.bv_val, 0, 0 );
238 #else
239                         Debug(LDAP_DEBUG_ARGS,
240                                 "<=- bdb_modrdn: non-leaf %s\n",
241                                 op->o_req_dn.bv_val, 0, 0);
242 #endif
243                         rs->sr_err = LDAP_NOT_ALLOWED_ON_NONLEAF;
244                         rs->sr_text = "subtree rename not supported";
245                         break;
246                 default:
247 #ifdef NEW_LOGGING
248                         LDAP_LOG ( OPERATION, ERR, 
249                                 "<=- bdb_modrdn: has_children failed %s (%d)\n",
250                                 db_strerror(rs->sr_err), rs->sr_err, 0 );
251 #else
252                         Debug(LDAP_DEBUG_ARGS,
253                                 "<=- bdb_modrdn: has_children failed: %s (%d)\n",
254                                 db_strerror(rs->sr_err), rs->sr_err, 0 );
255 #endif
256                         rs->sr_err = LDAP_OTHER;
257                         rs->sr_text = "internal error";
258                 }
259                 goto return_results;
260         }
261         ei->bei_state |= CACHE_ENTRY_NO_KIDS;
262 #endif
263         if (!manageDSAit && is_entry_referral( e ) ) {
264                 /* parent is a referral, don't allow add */
265                 rs->sr_ref = get_entry_referrals( op, e );
266
267 #ifdef NEW_LOGGING
268                 LDAP_LOG ( OPERATION, DETAIL1, 
269                         "==>bdb_modrdn: entry %s is referral \n", e->e_dn, 0, 0 );
270 #else
271                 Debug( LDAP_DEBUG_TRACE, "bdb_modrdn: entry %s is referral\n",
272                         e->e_dn, 0, 0 );
273 #endif
274
275                 rs->sr_err = LDAP_REFERRAL,
276                 rs->sr_matched = e->e_name.bv_val;
277                 send_ldap_result( op, rs );
278
279                 ber_bvarray_free( rs->sr_ref );
280                 rs->sr_ref = NULL;
281                 rs->sr_matched = NULL;
282                 goto done;
283         }
284
285         if ( be_issuffix( op->o_bd, &e->e_nname ) ) {
286                 p_ndn = slap_empty_bv;
287         } else {
288                 dnParent( &e->e_nname, &p_ndn );
289         }
290         np_ndn = &p_ndn;
291         if ( p_ndn.bv_len != 0 ) {
292                 /* Make sure parent entry exist and we can write its 
293                  * children.
294                  */
295                 eip = ei->bei_parent;
296                 rs->sr_err = bdb_cache_find_id( op, ltid,
297                         eip->bei_id, &eip, 0, locker, &plock );
298
299                 switch( rs->sr_err ) {
300                 case 0:
301                 case DB_NOTFOUND:
302                         break;
303                 case DB_LOCK_DEADLOCK:
304                 case DB_LOCK_NOTGRANTED:
305                         goto retry;
306                 case LDAP_BUSY:
307                         rs->sr_text = "ldap server busy";
308                         goto return_results;
309                 default:
310                         rs->sr_err = LDAP_OTHER;
311                         rs->sr_text = "internal error";
312                         goto return_results;
313                 }
314
315                 p = eip->bei_e;
316                 if( p == NULL) {
317 #ifdef NEW_LOGGING
318                         LDAP_LOG ( OPERATION, ERR, 
319                                 "==>bdb_modrdn: parent does not exist\n", 0, 0, 0 );
320 #else
321                         Debug( LDAP_DEBUG_TRACE, "bdb_modrdn: parent does not exist\n",
322                                 0, 0, 0);
323 #endif
324                         rs->sr_err = LDAP_OTHER;
325                         rs->sr_text = "old entry's parent does not exist";
326                         goto return_results;
327                 }
328
329                 /* check parent for "children" acl */
330                 rs->sr_err = access_allowed( op, p,
331                         children, NULL, ACL_WRITE, NULL );
332
333                 if ( ! rs->sr_err ) {
334                         switch( opinfo.boi_err ) {
335                         case DB_LOCK_DEADLOCK:
336                         case DB_LOCK_NOTGRANTED:
337                                 goto retry;
338                         }
339
340                         rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
341 #ifdef NEW_LOGGING
342                         LDAP_LOG ( OPERATION, ERR, 
343                                 "==>bdb_modrdn: no access to parent\n", 0, 0, 0 );
344 #else
345                         Debug( LDAP_DEBUG_TRACE, "no access to parent\n", 0,
346                                 0, 0 );
347 #endif
348                         rs->sr_text = "no write access to old parent's children";
349                         goto return_results;
350                 }
351
352 #ifdef NEW_LOGGING
353                 LDAP_LOG ( OPERATION, DETAIL1, 
354                         "==>bdb_modrdn: wr to children %s is OK\n", p_ndn.bv_val, 0, 0 );
355 #else
356                 Debug( LDAP_DEBUG_TRACE,
357                         "bdb_modrdn: wr to children of entry %s OK\n",
358                         p_ndn.bv_val, 0, 0 );
359 #endif
360                 
361                 if ( p_ndn.bv_val == slap_empty_bv.bv_val ) {
362                         p_dn = slap_empty_bv;
363                 } else {
364                         dnParent( &e->e_name, &p_dn );
365                 }
366
367 #ifdef NEW_LOGGING
368                 LDAP_LOG ( OPERATION, DETAIL1, 
369                         "==>bdb_modrdn: parent dn=%s\n", p_dn.bv_val, 0, 0 );
370 #else
371                 Debug( LDAP_DEBUG_TRACE,
372                         "bdb_modrdn: parent dn=%s\n",
373                         p_dn.bv_val, 0, 0 );
374 #endif
375
376         } else {
377                 /* no parent, modrdn entry directly under root */
378                 isroot = be_isroot( op->o_bd, &op->o_ndn );
379                 if ( ! isroot ) {
380                         if ( be_issuffix( op->o_bd, (struct berval *)&slap_empty_bv )
381                                 || be_isupdate( op->o_bd, &op->o_ndn ) ) {
382
383                                 p = (Entry *)&slap_entry_root;
384
385                                 /* check parent for "children" acl */
386                                 rs->sr_err = access_allowed( op, p,
387                                         children, NULL, ACL_WRITE, NULL );
388
389                                 p = NULL;
390
391                                 if ( ! rs->sr_err ) {
392                                         switch( opinfo.boi_err ) {
393                                         case DB_LOCK_DEADLOCK:
394                                         case DB_LOCK_NOTGRANTED:
395                                                 goto retry;
396                                         }
397
398                                         rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
399 #ifdef NEW_LOGGING
400                                         LDAP_LOG ( OPERATION, ERR, 
401                                                 "==>bdb_modrdn: no access to parent\n", 0, 0, 0 );
402 #else
403                                         Debug( LDAP_DEBUG_TRACE, 
404                                                 "no access to parent\n", 
405                                                 0, 0, 0 );
406 #endif
407                                         rs->sr_text = "no write access to old parent";
408                                         goto return_results;
409                                 }
410
411 #ifdef NEW_LOGGING
412                                 LDAP_LOG ( OPERATION, DETAIL1, 
413                                         "==>bdb_modrdn: wr to children of entry \"%s\" OK\n", 
414                                         p_dn.bv_val, 0, 0 );
415 #else
416                                 Debug( LDAP_DEBUG_TRACE,
417                                         "bdb_modrdn: wr to children of entry \"\" OK\n",
418                                         0, 0, 0 );
419 #endif
420                 
421                                 p_dn.bv_val = "";
422                                 p_dn.bv_len = 0;
423
424 #ifdef NEW_LOGGING
425                                 LDAP_LOG ( OPERATION, DETAIL1, 
426                                         "==>bdb_modrdn: parent dn=\"\" \n", 0, 0, 0 );
427 #else
428                                 Debug( LDAP_DEBUG_TRACE,
429                                         "bdb_modrdn: parent dn=\"\"\n",
430                                         0, 0, 0 );
431 #endif
432
433                         } else {
434 #ifdef NEW_LOGGING
435                                 LDAP_LOG ( OPERATION, ERR, 
436                                         "==>bdb_modrdn: no parent, not root &\"\" is not "
437                                         "suffix\n", 0, 0, 0 );
438 #else
439                                 Debug( LDAP_DEBUG_TRACE,
440                                         "bdb_modrdn: no parent, not root "
441                                         "& \"\" is not suffix\n",
442                                         0, 0, 0);
443 #endif
444                                 rs->sr_text = "no write access to old parent";
445                                 rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
446                                 goto return_results;
447                         }
448                 }
449         }
450
451         new_parent_dn = &p_dn;  /* New Parent unless newSuperior given */
452
453         if ( op->oq_modrdn.rs_newSup != NULL ) {
454 #ifdef NEW_LOGGING
455                 LDAP_LOG ( OPERATION, DETAIL1, 
456                         "==>bdb_modrdn: new parent \"%s\" requested...\n", 
457                         op->oq_modrdn.rs_newSup->bv_val, 0, 0 );
458 #else
459                 Debug( LDAP_DEBUG_TRACE, 
460                         "bdb_modrdn: new parent \"%s\" requested...\n",
461                         op->oq_modrdn.rs_newSup->bv_val, 0, 0 );
462 #endif
463
464                 /*  newSuperior == oldParent? */
465                 if( dn_match( &p_ndn, op->oq_modrdn.rs_nnewSup ) ) {
466 #ifdef NEW_LOGGING
467                         LDAP_LOG( BACK_BDB, INFO, "bdb_back_modrdn: "
468                                 "new parent \"%s\" same as the old parent \"%s\"\n",
469                                 op->oq_modrdn.rs_newSup->bv_val, p_dn.bv_val, 0 );
470 #else
471                         Debug( LDAP_DEBUG_TRACE, "bdb_back_modrdn: "
472                                 "new parent \"%s\" same as the old parent \"%s\"\n",
473                                 op->oq_modrdn.rs_newSup->bv_val, p_dn.bv_val, 0 );
474 #endif      
475                         op->oq_modrdn.rs_newSup = NULL; /* ignore newSuperior */
476                 }
477         }
478
479         if ( op->oq_modrdn.rs_newSup != NULL ) {
480                 if ( op->oq_modrdn.rs_newSup->bv_len ) {
481                         np_dn = op->oq_modrdn.rs_newSup;
482                         np_ndn = op->oq_modrdn.rs_nnewSup;
483
484                         /* newSuperior == oldParent?, if so ==> ERROR */
485                         /* newSuperior == entry being moved?, if so ==> ERROR */
486                         /* Get Entry with dn=newSuperior. Does newSuperior exist? */
487
488                         rs->sr_err = bdb_dn2entry( op, ltid, np_ndn,
489                                 &neip, 0, locker, &nplock );
490
491                         switch( rs->sr_err ) {
492                         case 0: np = neip->bei_e;
493                         case DB_NOTFOUND:
494                                 break;
495                         case DB_LOCK_DEADLOCK:
496                         case DB_LOCK_NOTGRANTED:
497                                 goto retry;
498                         case LDAP_BUSY:
499                                 rs->sr_text = "ldap server busy";
500                                 goto return_results;
501                         default:
502                                 rs->sr_err = LDAP_OTHER;
503                                 rs->sr_text = "internal error";
504                                 goto return_results;
505                         }
506
507                         if( np == NULL) {
508 #ifdef NEW_LOGGING
509                                 LDAP_LOG ( OPERATION, DETAIL1, 
510                                         "==>bdb_modrdn: newSup(ndn=%s) not here!\n", 
511                                         np_ndn->bv_val, 0, 0 );
512 #else
513                                 Debug( LDAP_DEBUG_TRACE,
514                                         "bdb_modrdn: newSup(ndn=%s) not here!\n",
515                                         np_ndn->bv_val, 0, 0);
516 #endif
517                                 rs->sr_text = "new superior not found";
518                                 rs->sr_err = LDAP_OTHER;
519                                 goto return_results;
520                         }
521
522 #ifdef NEW_LOGGING
523                         LDAP_LOG ( OPERATION, DETAIL1, 
524                                 "==>bdb_modrdn: wr to new parent OK np=%p, id=%ld\n", 
525                                 (void *) np, (long) np->e_id, 0 );
526 #else
527                         Debug( LDAP_DEBUG_TRACE,
528                                 "bdb_modrdn: wr to new parent OK np=%p, id=%ld\n",
529                                 (void *) np, (long) np->e_id, 0 );
530 #endif
531
532                         /* check newSuperior for "children" acl */
533                         rs->sr_err = access_allowed( op, np, children,
534                                 NULL, ACL_WRITE, NULL );
535
536                         if( ! rs->sr_err ) {
537                                 switch( opinfo.boi_err ) {
538                                 case DB_LOCK_DEADLOCK:
539                                 case DB_LOCK_NOTGRANTED:
540                                         goto retry;
541                                 }
542
543 #ifdef NEW_LOGGING
544                                 LDAP_LOG ( OPERATION, DETAIL1, 
545                                         "==>bdb_modrdn: no wr to newSup children\n", 0, 0, 0 );
546 #else
547                                 Debug( LDAP_DEBUG_TRACE,
548                                         "bdb_modrdn: no wr to newSup children\n",
549                                         0, 0, 0 );
550 #endif
551                                 rs->sr_text = "no write access to new superior's children";
552                                 rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
553                                 goto return_results;
554                         }
555
556 #ifdef BDB_ALIASES
557                         if ( is_entry_alias( np ) ) {
558                                 /* parent is an alias, don't allow add */
559 #ifdef NEW_LOGGING
560                                 LDAP_LOG ( OPERATION, DETAIL1, 
561                                         "==>bdb_modrdn: entry is alias\n", 0, 0, 0 );
562 #else
563                                 Debug( LDAP_DEBUG_TRACE, "bdb_modrdn: entry is alias\n",
564                                         0, 0, 0 );
565 #endif
566                                 rs->sr_text = "new superior is an alias";
567                                 rs->sr_err = LDAP_ALIAS_PROBLEM;
568                                 goto return_results;
569                         }
570 #endif
571
572                         if ( is_entry_referral( np ) ) {
573                                 /* parent is a referral, don't allow add */
574 #ifdef NEW_LOGGING
575                                 LDAP_LOG ( OPERATION, DETAIL1, 
576                                         "==>bdb_modrdn: entry is referral\n", 0, 0, 0 );
577 #else
578                                 Debug( LDAP_DEBUG_TRACE, "bdb_modrdn: entry is referral\n",
579                                         0, 0, 0 );
580 #endif
581                                 rs->sr_text = "new superior is a referral";
582                                 rs->sr_err = LDAP_OTHER;
583                                 goto return_results;
584                         }
585
586                 } else {
587                         if ( isroot == -1 ) {
588                                 isroot = be_isroot( op->o_bd, &op->o_ndn );
589                         }
590                         
591                         np_dn = NULL;
592
593                         /* no parent, modrdn entry directly under root */
594                         if ( ! isroot ) {
595                                 if ( be_issuffix( op->o_bd, (struct berval *)&slap_empty_bv )
596                                         || be_isupdate( op->o_bd, &op->o_ndn ) ) {
597                                         np = (Entry *)&slap_entry_root;
598
599                                         /* check parent for "children" acl */
600                                         rs->sr_err = access_allowed( op, np,
601                                                 children, NULL, ACL_WRITE, NULL );
602
603                                         np = NULL;
604
605                                         if ( ! rs->sr_err ) {
606                                                 switch( opinfo.boi_err ) {
607                                                 case DB_LOCK_DEADLOCK:
608                                                 case DB_LOCK_NOTGRANTED:
609                                                         goto retry;
610                                                 }
611
612                                                 rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
613 #ifdef NEW_LOGGING
614                                                 LDAP_LOG ( OPERATION, ERR, 
615                                                         "==>bdb_modrdn: no access to superior\n", 0, 0, 0 );
616 #else
617                                                 Debug( LDAP_DEBUG_TRACE, 
618                                                         "no access to new superior\n", 
619                                                         0, 0, 0 );
620 #endif
621                                                 rs->sr_text = "no write access to new superior's children";
622                                                 goto return_results;
623                                         }
624
625 #ifdef NEW_LOGGING
626                                         LDAP_LOG ( OPERATION, DETAIL1, 
627                                                 "bdb_modrdn: wr to children entry \"\" OK\n", 0, 0, 0 );
628 #else
629                                         Debug( LDAP_DEBUG_TRACE,
630                                                 "bdb_modrdn: wr to children of entry \"\" OK\n",
631                                                 0, 0, 0 );
632 #endif
633                 
634                                 } else {
635 #ifdef NEW_LOGGING
636                                         LDAP_LOG ( OPERATION, ERR, 
637                                                 "bdb_modrdn: new superior=\"\", not root & \"\" "
638                                                 "is not suffix\n", 0, 0, 0 );
639 #else
640                                         Debug( LDAP_DEBUG_TRACE,
641                                                 "bdb_modrdn: new superior=\"\", not root "
642                                                 "& \"\" is not suffix\n",
643                                                 0, 0, 0);
644 #endif
645                                         rs->sr_text = "no write access to new superior's children";
646                                         rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
647                                         goto return_results;
648                                 }
649                         }
650
651 #ifdef NEW_LOGGING
652                         LDAP_LOG ( OPERATION, DETAIL1, 
653                                 "bdb_modrdn: new superior=\"\"\n", 0, 0, 0 );
654 #else
655                         Debug( LDAP_DEBUG_TRACE,
656                                 "bdb_modrdn: new superior=\"\"\n",
657                                 0, 0, 0 );
658 #endif
659                 }
660
661 #ifdef NEW_LOGGING
662                 LDAP_LOG ( OPERATION, DETAIL1, 
663                         "bdb_modrdn: wr to new parent's children OK\n", 0, 0, 0 );
664 #else
665                 Debug( LDAP_DEBUG_TRACE,
666                         "bdb_modrdn: wr to new parent's children OK\n",
667                         0, 0, 0 );
668 #endif
669
670                 new_parent_dn = np_dn;
671         }
672
673         /* Build target dn and make sure target entry doesn't exist already. */
674         if (!new_dn.bv_val) build_new_dn( &new_dn, new_parent_dn, &op->oq_modrdn.rs_newrdn ); 
675
676         if (!new_ndn.bv_val) {
677                 struct berval bv = {0, NULL};
678                 dnNormalize( 0, NULL, NULL, &new_dn, &bv, op->o_tmpmemctx );
679                 ber_dupbv( &new_ndn, &bv );
680         }
681
682 #ifdef NEW_LOGGING
683         LDAP_LOG ( OPERATION, RESULTS, 
684                 "bdb_modrdn: new ndn=%s\n", new_ndn.bv_val, 0, 0 );
685 #else
686         Debug( LDAP_DEBUG_TRACE, "bdb_modrdn: new ndn=%s\n",
687                 new_ndn.bv_val, 0, 0 );
688 #endif
689
690         /* Shortcut the search */
691         nei = neip ? neip : eip;
692         rs->sr_err = bdb_cache_find_ndn ( op, ltid, &new_ndn, &nei, locker );
693         if ( nei ) bdb_cache_entryinfo_unlock( nei );
694         switch( rs->sr_err ) {
695         case DB_LOCK_DEADLOCK:
696         case DB_LOCK_NOTGRANTED:
697                 goto retry;
698         case DB_NOTFOUND:
699                 break;
700         case 0:
701                 rs->sr_err = LDAP_ALREADY_EXISTS;
702                 goto return_results;
703         default:
704                 rs->sr_err = LDAP_OTHER;
705                 rs->sr_text = "internal error";
706                 goto return_results;
707         }
708
709         /* Get attribute type and attribute value of our new rdn, we will
710          * need to add that to our new entry
711          */
712         if ( !new_rdn && ldap_bv2rdn_x( &op->oq_modrdn.rs_newrdn, &new_rdn, (char **)&rs->sr_text,
713                 LDAP_DN_FORMAT_LDAP, op->o_tmpmemctx ) )
714         {
715 #ifdef NEW_LOGGING
716                 LDAP_LOG ( OPERATION, ERR, 
717                         "bdb_modrdn: can't figure out "
718                         "type(s)/values(s) of newrdn\n", 
719                         0, 0, 0 );
720 #else
721                 Debug( LDAP_DEBUG_TRACE,
722                         "bdb_modrdn: can't figure out "
723                         "type(s)/values(s) of newrdn\n", 
724                         0, 0, 0 );
725 #endif
726                 rs->sr_err = LDAP_INVALID_DN_SYNTAX;
727                 rs->sr_text = "unknown type(s) used in RDN";
728                 goto return_results;
729         }
730
731 #ifdef NEW_LOGGING
732         LDAP_LOG ( OPERATION, RESULTS, 
733                 "bdb_modrdn: new_rdn_type=\"%s\", "
734                 "new_rdn_val=\"%s\"\n",
735                 new_rdn[ 0 ]->la_attr.bv_val, 
736                 new_rdn[ 0 ]->la_value.bv_val, 0 );
737 #else
738         Debug( LDAP_DEBUG_TRACE,
739                 "bdb_modrdn: new_rdn_type=\"%s\", "
740                 "new_rdn_val=\"%s\"\n",
741                 new_rdn[ 0 ]->la_attr.bv_val,
742                 new_rdn[ 0 ]->la_value.bv_val, 0 );
743 #endif
744
745         if ( op->oq_modrdn.rs_deleteoldrdn ) {
746                 if ( !old_rdn && ldap_bv2rdn_x( &op->o_req_dn, &old_rdn, (char **)&rs->sr_text,
747                         LDAP_DN_FORMAT_LDAP, op->o_tmpmemctx ) )
748                 {
749 #ifdef NEW_LOGGING
750                         LDAP_LOG ( OPERATION, ERR, 
751                                 "bdb_modrdn: can't figure out "
752                                 "type(s)/values(s) of old_rdn\n", 
753                                 0, 0, 0 );
754 #else
755                         Debug( LDAP_DEBUG_TRACE,
756                                 "bdb_modrdn: can't figure out "
757                                 "the old_rdn type(s)/value(s)\n", 
758                                 0, 0, 0 );
759 #endif
760                         rs->sr_err = LDAP_OTHER;
761                         rs->sr_text = "cannot parse RDN from old DN";
762                         goto return_results;            
763                 }
764         }
765
766         /* prepare modlist of modifications from old/new rdn */
767         if (!mod) {
768                 rs->sr_err = slap_modrdn2mods( op, rs, e, old_rdn, new_rdn, &mod );
769                 if ( rs->sr_err != LDAP_SUCCESS ) {
770                         goto return_results;
771                 }
772         }
773
774         /* nested transaction */
775         rs->sr_err = TXN_BEGIN( bdb->bi_dbenv, ltid, &lt2, 
776                 bdb->bi_db_opflags );
777         rs->sr_text = NULL;
778         if( rs->sr_err != 0 ) {
779 #ifdef NEW_LOGGING
780                 LDAP_LOG ( OPERATION, ERR, 
781                         "bdb_modrdn: txn_begin(2) failed: %s (%d)\n", db_strerror(rs->sr_err), rs->sr_err, 0 );
782 #else
783                 Debug( LDAP_DEBUG_TRACE,
784                         "bdb_modrdn: txn_begin(2) failed: %s (%d)\n",
785                         db_strerror(rs->sr_err), rs->sr_err, 0 );
786 #endif
787                 rs->sr_err = LDAP_OTHER;
788                 rs->sr_text = "internal error";
789                 goto return_results;
790         }
791
792         dummy = *e;
793         save = e;
794         e = &dummy;
795
796         /* delete old one */
797         rs->sr_err = bdb_dn2id_delete( op, lt2, eip, e );
798         if ( rs->sr_err != 0 ) {
799 #ifdef NEW_LOGGING
800                 LDAP_LOG ( OPERATION, ERR, 
801                         "<=- bdb_modrdn: dn2id del failed: %s (%d)\n",
802                         db_strerror(rs->sr_err), rs->sr_err, 0 );
803 #else
804                 Debug(LDAP_DEBUG_TRACE,
805                         "<=- bdb_modrdn: dn2id del failed: %s (%d)\n",
806                         db_strerror(rs->sr_err), rs->sr_err, 0 );
807 #endif
808                 switch( rs->sr_err ) {
809                 case DB_LOCK_DEADLOCK:
810                 case DB_LOCK_NOTGRANTED:
811                         goto retry;
812                 }
813                 rs->sr_err = LDAP_OTHER;
814                 rs->sr_text = "DN index delete fail";
815                 goto return_results;
816         }
817
818         /* Binary format uses a single contiguous block, cannot
819          * free individual fields. But if a previous modrdn has
820          * already happened, must free the names. The frees are
821          * done in bdb_cache_modrdn().
822          */
823         if( e->e_nname.bv_val < e->e_bv.bv_val || e->e_nname.bv_val >
824                 e->e_bv.bv_val + e->e_bv.bv_len ) {
825                 e->e_name.bv_val = NULL;
826                 e->e_nname.bv_val = NULL;
827         }
828         e->e_name = new_dn;
829         e->e_nname = new_ndn;
830         new_dn.bv_val = NULL;
831         new_ndn.bv_val = NULL;
832
833         /* add new one */
834         rs->sr_err = bdb_dn2id_add( op, lt2, neip ? neip : eip, e );
835         if ( rs->sr_err != 0 ) {
836 #ifdef NEW_LOGGING
837                 LDAP_LOG ( OPERATION, ERR, 
838                         "<=- bdb_modrdn: dn2id add failed: %s (%d)\n",
839                         db_strerror(rs->sr_err), rs->sr_err, 0 );
840 #else
841                 Debug(LDAP_DEBUG_TRACE,
842                         "<=- bdb_modrdn: dn2id add failed: %s (%d)\n",
843                         db_strerror(rs->sr_err), rs->sr_err, 0 );
844 #endif
845                 switch( rs->sr_err ) {
846                 case DB_LOCK_DEADLOCK:
847                 case DB_LOCK_NOTGRANTED:
848                         goto retry;
849                 }
850                 rs->sr_err = LDAP_OTHER;
851                 rs->sr_text = "DN index add failed";
852                 goto return_results;
853         }
854
855 #ifdef LDAP_SYNC
856         if ( rs->sr_err == LDAP_SUCCESS && !op->o_noop ) {
857                 LDAP_LIST_FOREACH ( ps_list, &bdb->bi_psearch_list, o_ps_link ) {
858                         bdb_psearch( op, rs, ps_list, e, LDAP_PSEARCH_BY_PREMODIFY );
859                 }
860         }
861 #endif
862
863         /* modify entry */
864         rs->sr_err = bdb_modify_internal( op, lt2, &mod[0], e,
865                 &rs->sr_text, textbuf, textlen );
866
867         if( rs->sr_err != LDAP_SUCCESS ) {
868 #ifdef NEW_LOGGING
869                 LDAP_LOG ( OPERATION, ERR, 
870                         "<=- bdb_modrdn: modify failed: %s (%d)\n",
871                         db_strerror(rs->sr_err), rs->sr_err, 0 );
872 #else
873                 Debug(LDAP_DEBUG_TRACE,
874                         "<=- bdb_modrdn: modify failed: %s (%d)\n",
875                         db_strerror(rs->sr_err), rs->sr_err, 0 );
876 #endif
877                 if ( ( rs->sr_err == LDAP_INSUFFICIENT_ACCESS ) && opinfo.boi_err ) {
878                         rs->sr_err = opinfo.boi_err;
879                 }
880                 switch( rs->sr_err ) {
881                 case DB_LOCK_DEADLOCK:
882                 case DB_LOCK_NOTGRANTED:
883                         goto retry;
884                 }
885                 goto return_results;
886         }
887         
888         /* id2entry index */
889         rs->sr_err = bdb_id2entry_update( op->o_bd, lt2, e );
890         if ( rs->sr_err != 0 ) {
891 #ifdef NEW_LOGGING
892                 LDAP_LOG ( OPERATION, ERR, 
893                         "<=- bdb_modrdn: id2entry failed: %s (%d)\n",
894                         db_strerror(rs->sr_err), rs->sr_err, 0 );
895 #else
896                 Debug(LDAP_DEBUG_TRACE,
897                         "<=- bdb_modrdn: id2entry failed: %s (%d)\n",
898                         db_strerror(rs->sr_err), rs->sr_err, 0 );
899 #endif
900                 switch( rs->sr_err ) {
901                 case DB_LOCK_DEADLOCK:
902                 case DB_LOCK_NOTGRANTED:
903                         goto retry;
904                 }
905                 rs->sr_err = LDAP_OTHER;
906                 rs->sr_text = "entry update failed";
907                 goto return_results;
908         }
909         if ( TXN_COMMIT( lt2, 0 ) != 0 ) {
910                 rs->sr_err = LDAP_OTHER;
911                 rs->sr_text = "txn_commit(2) failed";
912                 goto return_results;
913         }
914
915         if( op->o_noop ) {
916                 if(( rs->sr_err=TXN_ABORT( ltid )) != 0 ) {
917                         rs->sr_text = "txn_abort (no-op) failed";
918                 } else {
919                         noop = 1;
920                         rs->sr_err = LDAP_SUCCESS;
921                 }
922
923         } else {
924                 char gid[DB_XIDDATASIZE];
925
926                 snprintf( gid, sizeof( gid ), "%s-%08lx-%08lx",
927                         bdb_uuid.bv_val, (long) op->o_connid, (long) op->o_opid );
928
929                 if(( rs->sr_err=TXN_PREPARE( ltid, gid )) != 0 ) {
930                         rs->sr_text = "txn_prepare failed";
931                 } else {
932                         bdb_cache_modrdn( save, &op->orr_nnewrdn, e, neip,
933                                 bdb->bi_dbenv, locker, &lock );
934                         if(( rs->sr_err=TXN_COMMIT( ltid, 0 )) != 0 ) {
935                                 rs->sr_text = "txn_commit failed";
936                         } else {
937                                 rs->sr_err = LDAP_SUCCESS;
938                         }
939                 }
940         }
941  
942         ltid = NULL;
943         op->o_private = NULL;
944  
945         if( rs->sr_err == LDAP_SUCCESS ) {
946 #ifdef NEW_LOGGING
947                 LDAP_LOG ( OPERATION, RESULTS, 
948                         "bdb_modrdn: rdn modified%s id=%08lx dn=\"%s\"\n", 
949                         op->o_noop ? " (no-op)" : "", e->e_id, e->e_dn );
950 #else
951                 Debug(LDAP_DEBUG_TRACE,
952                         "bdb_modrdn: rdn modified%s id=%08lx dn=\"%s\"\n",
953                         op->o_noop ? " (no-op)" : "", e->e_id, e->e_dn );
954 #endif
955                 rs->sr_text = NULL;
956         } else {
957 #ifdef NEW_LOGGING
958                 LDAP_LOG ( OPERATION, RESULTS, "bdb_modrdn: %s : %s (%d)\n", 
959                         rs->sr_text, db_strerror(rs->sr_err), rs->sr_err );
960 #else
961                 Debug( LDAP_DEBUG_TRACE, "bdb_add: %s : %s (%d)\n",
962                         rs->sr_text, db_strerror(rs->sr_err), rs->sr_err );
963 #endif
964                 rs->sr_err = LDAP_OTHER;
965         }
966
967 return_results:
968         send_ldap_result( op, rs );
969
970 #ifdef LDAP_SYNC
971         if ( rs->sr_err == LDAP_SUCCESS && !op->o_noop ) {
972                 /* Loop through in-scope entries for each psearch spec */
973                 LDAP_LIST_FOREACH ( ps_list, &bdb->bi_psearch_list, o_ps_link ) {
974                         bdb_psearch( op, rs, ps_list, e, LDAP_PSEARCH_BY_MODIFY );
975                 }
976                 pm_list = LDAP_LIST_FIRST(&op->o_pm_list);
977                 while ( pm_list != NULL ) {
978                         bdb_psearch(op, rs, pm_list->ps_op,
979                                                 e, LDAP_PSEARCH_BY_SCOPEOUT);
980                         pm_prev = pm_list;
981                         LDAP_LIST_REMOVE ( pm_list, ps_link );
982                         pm_list = LDAP_LIST_NEXT ( pm_list, ps_link );
983                         ch_free( pm_prev );
984                 }
985         }
986 #endif
987
988         if( rs->sr_err == LDAP_SUCCESS && bdb->bi_txn_cp ) {
989                 ldap_pvt_thread_yield();
990                 TXN_CHECKPOINT( bdb->bi_dbenv,
991                         bdb->bi_txn_cp_kbyte, bdb->bi_txn_cp_min, 0 );
992         }
993
994 done:
995         if( new_dn.bv_val != NULL ) free( new_dn.bv_val );
996         if( new_ndn.bv_val != NULL ) free( new_ndn.bv_val );
997
998         /* LDAP v2 supporting correct attribute handling. */
999         if ( new_rdn != NULL ) {
1000                 ldap_rdnfree_x( new_rdn, op->o_tmpmemctx );
1001         }
1002         if ( old_rdn != NULL ) {
1003                 ldap_rdnfree_x( old_rdn, op->o_tmpmemctx );
1004         }
1005         if( mod != NULL ) {
1006                 Modifications *tmp;
1007                 for (; mod; mod=tmp ) {
1008                         tmp = mod->sml_next;
1009                         if ( mod->sml_nvalues ) free( mod->sml_nvalues[0].bv_val );
1010                         free( mod );
1011                 }
1012         }
1013
1014         /* LDAP v3 Support */
1015         if( np != NULL ) {
1016                 /* free new parent and reader lock */
1017                 bdb_unlocked_cache_return_entry_r(&bdb->bi_cache, np);
1018         }
1019
1020         if( p != NULL ) {
1021                 /* free parent and reader lock */
1022                 bdb_unlocked_cache_return_entry_r(&bdb->bi_cache, p);
1023         }
1024
1025         /* free entry */
1026         if( e != NULL ) {
1027                 bdb_unlocked_cache_return_entry_w( &bdb->bi_cache, e);
1028         }
1029
1030         if( ltid != NULL ) {
1031 #ifdef LDAP_SYNC
1032                 pm_list = LDAP_LIST_FIRST(&op->o_pm_list);
1033                 while ( pm_list != NULL ) {
1034                         LDAP_LIST_REMOVE ( pm_list, ps_link );
1035                         pm_prev = pm_list;
1036                         pm_list = LDAP_LIST_NEXT ( pm_list, ps_link );
1037                         ch_free( pm_prev );
1038                 }
1039 #endif
1040                 TXN_ABORT( ltid );
1041                 op->o_private = NULL;
1042         }
1043
1044         return ( ( rs->sr_err == LDAP_SUCCESS ) ? noop : rs->sr_err );
1045 }