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