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