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