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