]> git.sur5r.net Git - openldap/blob - servers/slapd/back-ldbm/modrdn.c
Misc updates for NT4
[openldap] / servers / slapd / back-ldbm / modrdn.c
1 /* modrdn.c - ldbm backend modrdn routine */
2 /* $OpenLDAP$ */
3 /*
4  * Copyright 1998-2000 The OpenLDAP Foundation, All Rights Reserved.
5  * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
6  */
7
8 /*
9  * LDAP v3 newSuperior support. Add new rdn as an attribute.
10  * (Full support for v2 also used software/ideas contributed
11  * by Roy Hooper rhooper@cyberus.ca, thanks to him for his
12  * submission!.)
13  *
14  * Copyright 1999, Juan C. Gomez, All rights reserved.
15  * This software is not subject to any license of Silicon Graphics 
16  * Inc. or Purdue University.
17  *
18  * Redistribution and use in source and binary forms are permitted
19  * without restriction or fee of any kind as long as this notice
20  * is preserved.
21  *
22  */
23
24 #include "portable.h"
25
26 #include <stdio.h>
27
28 #include <ac/string.h>
29 #include <ac/socket.h>
30
31 #include "slap.h"
32 #include "back-ldbm.h"
33 #include "proto-back-ldbm.h"
34
35 int
36 ldbm_back_modrdn(
37     Backend     *be,
38     Connection  *conn,
39     Operation   *op,
40     const char  *dn,
41     const char  *ndn,
42     const char  *newrdn,
43     int         deleteoldrdn,
44     const char  *newSuperior
45 )
46 {
47         AttributeDescription *children = slap_schema.si_ad_children;
48         struct ldbminfo *li = (struct ldbminfo *) be->be_private;
49         char            *p_dn = NULL, *p_ndn = NULL;
50         char            *new_dn = NULL, *new_ndn = NULL;
51         Entry           *e, *p = NULL;
52         Entry           *matched;
53         int                     rootlock = 0;
54         int                     rc = -1;
55         const char *text = NULL;
56         char textbuf[SLAP_TEXT_BUFLEN];
57         size_t textlen = sizeof textbuf;
58         /* Added to support LDAP v2 correctly (deleteoldrdn thing) */
59         char            *new_rdn_val = NULL;    /* Val of new rdn */
60         char            *new_rdn_type = NULL;   /* Type of new rdn */
61         char            *old_rdn = NULL;        /* Old rdn's attr type & val */
62         char            *old_rdn_type = NULL;   /* Type of old rdn attr. */
63         char            *old_rdn_val = NULL;    /* Old rdn attribute value */
64         /* Added to support newSuperior */ 
65         Entry           *np = NULL;     /* newSuperior Entry */
66         char            *np_dn = NULL;  /* newSuperior dn */
67         char            *np_ndn = NULL; /* newSuperior ndn */
68         char            *new_parent_dn = NULL;  /* np_dn, p_dn, or NULL */
69         /* Used to interface with ldbm_modify_internal() */
70         struct berval   add_bv;                 /* Stores new rdn att */
71         struct berval   *add_bvals[2];          /* Stores new rdn att */
72         struct berval   del_bv;                 /* Stores old rdn att */
73         struct berval   *del_bvals[2];          /* Stores old rdn att */
74         Modifications   mod[2];                 /* Used to delete old rdn */
75         int             manageDSAit = get_manageDSAit( op );
76
77 #ifdef NEW_LOGGING
78         LDAP_LOG(( "backend", LDAP_LEVEL_ENTRY,
79                    "ldbm_back_modrdn: dn: %s newSuperior=%s\n", 
80                    dn ? dn : "NULL", newSuperior ? newSuperior : "NULL" ));
81 #else
82         Debug( LDAP_DEBUG_TRACE, "==>ldbm_back_modrdn(newSuperior=%s)\n",
83                (newSuperior ? newSuperior : "NULL"),
84                0, 0 );
85 #endif
86
87         /* get entry with writer lock */
88         if ( (e = dn2entry_w( be, ndn, &matched )) == NULL ) {
89                 char* matched_dn = NULL;
90                 struct berval** refs = NULL;
91
92                 if( matched != NULL ) {
93                         matched_dn = strdup( matched->e_dn );
94                         refs = is_entry_referral( matched )
95                                 ? get_entry_referrals( be, conn, op, matched )
96                                 : NULL;
97                         cache_return_entry_r( &li->li_cache, matched );
98                 } else {
99                         refs = default_referral;
100                 }
101
102                 send_ldap_result( conn, op, LDAP_REFERRAL,
103                         matched_dn, NULL, refs, NULL );
104
105                 if ( matched != NULL ) {
106                         ber_bvecfree( refs );
107                         free( matched_dn );
108                 }
109
110                 return( -1 );
111         }
112
113         if (!manageDSAit && is_entry_referral( e ) ) {
114                 /* parent is a referral, don't allow add */
115                 /* parent is an alias, don't allow add */
116                 struct berval **refs = get_entry_referrals( be,
117                         conn, op, e );
118
119 #ifdef NEW_LOGGING
120                 LDAP_LOG(( "backend", LDAP_LEVEL_INFO,
121                            "ldbm_back_modrdn: entry %s is a referral\n", e->e_dn ));
122 #else
123                 Debug( LDAP_DEBUG_TRACE, "entry is referral\n", 0,
124                     0, 0 );
125 #endif
126
127                 send_ldap_result( conn, op, LDAP_REFERRAL,
128                     e->e_dn, NULL, refs, NULL );
129
130                 ber_bvecfree( refs );
131                 goto return_results;
132         }
133
134         if ( has_children( be, e ) ) {
135 #ifdef NEW_LOGGING
136                 LDAP_LOG(( "backend", LDAP_LEVEL_INFO,
137                            "ldbm_back_modrdn: entry %s has children\n", e->e_dn ));
138 #else
139                 Debug( LDAP_DEBUG_TRACE, "entry %s referral\n", 0,
140                     0, 0 );
141 #endif
142
143                 send_ldap_result( conn, op, LDAP_NOT_ALLOWED_ON_NONLEAF,
144                     NULL, "subtree rename not supported", NULL, NULL );
145                 goto return_results;
146         }
147
148         if ( (p_ndn = dn_parent( be, e->e_ndn )) != NULL ) {
149                 /* Make sure parent entry exist and we can write its 
150                  * children.
151                  */
152
153                 if( (p = dn2entry_w( be, p_ndn, NULL )) == NULL) {
154 #ifdef NEW_LOGGING
155                         LDAP_LOG(( "backend", LDAP_LEVEL_INFO,
156                                    "ldbm_back_modrdn: parent of %s does not exist\n", e->e_ndn ));
157 #else
158                         Debug( LDAP_DEBUG_TRACE, "parent does not exist\n",
159                                 0, 0, 0);
160 #endif
161
162                         send_ldap_result( conn, op, LDAP_OTHER,
163                                 NULL, "parent entry does not exist", NULL, NULL );
164
165                         goto return_results;
166                 }
167
168                 /* check parent for "children" acl */
169                 if ( ! access_allowed( be, conn, op, p,
170                         children, NULL, ACL_WRITE ) )
171                 {
172 #ifdef NEW_LOGGING
173                         LDAP_LOG(( "backend", LDAP_LEVEL_INFO,
174                                    "ldbm_back_modrdn: no access to parent of (%s)\n", e->e_dn ));
175 #else
176                         Debug( LDAP_DEBUG_TRACE, "no access to parent\n", 0,
177                                 0, 0 );
178 #endif
179
180                         send_ldap_result( conn, op, LDAP_INSUFFICIENT_ACCESS,
181                                 NULL, NULL, NULL, NULL );
182                         goto return_results;
183                 }
184
185 #ifdef NEW_LOGGING
186                 LDAP_LOG(( "backend", LDAP_LEVEL_DETAIL1,
187                            "ldbm_back_modrdn: wr to children of entry %s OK\n",
188                            p_ndn ));
189 #else
190                 Debug( LDAP_DEBUG_TRACE,
191                        "ldbm_back_modrdn: wr to children of entry %s OK\n",
192                        p_ndn, 0, 0 );
193 #endif
194
195                 p_dn = dn_parent( be, e->e_dn );
196
197 #ifdef NEW_LOGGING
198                 LDAP_LOG(( "backend", LDAP_LEVEL_DETAIL1,
199                            "ldbm_back_modrdn: parent dn=%s\n", p_dn ));
200 #else
201                 Debug( LDAP_DEBUG_TRACE, "ldbm_back_modrdn: parent dn=%s\n",
202                        p_dn, 0, 0 );
203 #endif
204
205         } else {
206                 /* no parent, modrdn entry directly under root */
207                 if( ! be_isroot( be, op->o_ndn ) ) {
208 #ifdef NEW_LOGGING
209                         LDAP_LOG(( "backend", LDAP_LEVEL_INFO,
210                                    "ldbm_back_modrdn: (%s) no parent & not a root.\n",
211                                    e->e_dn ));
212 #else
213                         Debug( LDAP_DEBUG_TRACE, "no parent & not root\n",
214                                 0, 0, 0);
215 #endif
216
217                         send_ldap_result( conn, op, LDAP_INSUFFICIENT_ACCESS,
218                                 NULL, NULL, NULL, NULL );
219                         goto return_results;
220                 }
221
222                 ldap_pvt_thread_mutex_lock(&li->li_root_mutex);
223                 rootlock = 1;
224                 
225 #ifdef NEW_LOGGING
226                 LDAP_LOG(( "backend", LDAP_LEVEL_INFO,
227                            "ldbm_back_modrdn: (%s) no parent, locked root.\n", e->e_dn ));
228 #else
229                 Debug( LDAP_DEBUG_TRACE,
230                        "ldbm_back_modrdn: no parent, locked root\n",
231                        0, 0, 0 );
232 #endif
233         }
234
235         new_parent_dn = p_dn;   /* New Parent unless newSuperior given */
236
237         if ( newSuperior != NULL ) {
238 #ifdef NEW_LOGGING
239                 LDAP_LOG(( "backend", LDAP_LEVEL_DETAIL1,
240                            "ldbm_back_modrdn: new parent \"%s\" requested\n", newSuperior ));
241 #else
242                 Debug( LDAP_DEBUG_TRACE, 
243                         "ldbm_back_modrdn: new parent \"%s\" requested...\n",
244                         newSuperior, 0, 0 );
245 #endif
246
247                 np_dn = ch_strdup( newSuperior );
248                 np_ndn = ch_strdup( np_dn );
249                 (void) dn_normalize( np_ndn );
250
251                 /* newSuperior == oldParent? */
252                 if ( strcmp( p_ndn, np_ndn ) == 0 ) {
253 #ifdef NEW_LOGGING
254                         LDAP_LOG(( "backend", LDAP_LEVEL_INFO,
255                                    "ldbm_back_modrdn: new parent\"%s\" seems to be the same as the old parent \"%s\"\n",
256                                    newSuperior, p_dn ));
257 #else
258                         Debug( LDAP_DEBUG_TRACE, 
259                                "ldbm_back_modrdn: new parent \"%s\" seems to be the same as old parent \"%s\"...\n",
260                                newSuperior, p_dn, 0 );
261 #endif
262
263                         newSuperior = NULL; /* ignore newSuperior */
264                 }
265         }
266
267         if ( newSuperior != NULL ) {
268                 /* newSuperior == entry being moved?, if so ==> ERROR */
269                 /* Get Entry with dn=newSuperior. Does newSuperior exist? */
270
271                 if( (np = dn2entry_w( be, np_ndn, NULL )) == NULL) {
272 #ifdef NEW_LOGGING
273                         LDAP_LOG(( "backend", LDAP_LEVEL_ERR,
274                                    "ldbm_back_modrdn: newSup(ndn=%s) not found.\n", np_ndn ));
275 #else
276                         Debug( LDAP_DEBUG_TRACE,
277                                "ldbm_back_modrdn: newSup(ndn=%s) not here!\n",
278                                np_ndn, 0, 0);
279 #endif
280
281                         send_ldap_result( conn, op, LDAP_OTHER,
282                                 NULL, "newSuperior not found", NULL, NULL );
283                         goto return_results;
284                 }
285
286 #ifdef NEW_LOGGING
287                 LDAP_LOG(( "backend", LDAP_LEVEL_DETAIL1,
288                            "ldbm_back_modrdn: wr to new parent OK np=%p, id=%ld\n",
289                            np, np->e_id ));
290 #else
291                 Debug( LDAP_DEBUG_TRACE,
292                        "ldbm_back_modrdn: wr to new parent OK np=%p, id=%ld\n",
293                        np, np->e_id, 0 );
294 #endif
295
296                 /* check newSuperior for "children" acl */
297                 if ( !access_allowed( be, conn, op, np, children, NULL,
298                                       ACL_WRITE ) )
299                 {
300 #ifdef NEW_LOGGING
301                         LDAP_LOG(( "backend", LDAP_LEVEL_INFO,
302                                    "ldbm_back_modrdn: no wr to newSup children.\n" ));
303 #else
304                         Debug( LDAP_DEBUG_TRACE,
305                                "ldbm_back_modrdn: no wr to newSup children\n",
306                                0, 0, 0 );
307 #endif
308
309                         send_ldap_result( conn, op, LDAP_INSUFFICIENT_ACCESS,
310                                 NULL, NULL, NULL, NULL );
311                         goto return_results;
312                 }
313
314                 if ( is_entry_alias( np ) ) {
315                         /* entry is an alias, don't allow bind */
316 #ifdef NEW_LOGGING
317                         LDAP_LOG(( "backend", LDAP_LEVEL_INFO,
318                                    "ldbm_back_modrdn: entry (%s) is an alias.\n", np->e_dn ));
319 #else
320                         Debug( LDAP_DEBUG_TRACE, "entry is alias\n", 0,
321                             0, 0 );
322 #endif
323
324
325                         send_ldap_result( conn, op, LDAP_ALIAS_PROBLEM,
326                             NULL, "newSuperior is an alias", NULL, NULL );
327
328                         goto return_results;
329                 }
330
331                 if ( is_entry_referral( np ) ) {
332                         /* parent is a referral, don't allow add */
333                         /* parent is an alias, don't allow add */
334 #ifdef NEW_LOGGING
335                         LDAP_LOG(( "backend", LDAP_LEVEL_INFO,
336                                    "ldbm_back_modrdn: entry (%s) is a referral\n",
337                                    np->e_dn ));
338 #else
339                         Debug( LDAP_DEBUG_TRACE, "entry is referral\n", 0,
340                                 0, 0 );
341 #endif
342
343                         send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR,
344                             NULL, "newSuperior is a referral", NULL, NULL );
345
346                         goto return_results;
347                 }
348
349 #ifdef NEW_LOGGING
350                 LDAP_LOG(( "backend", LDAP_LEVEL_DETAIL1,
351                            "ldbm_back_modrdn: wr to new parent's children OK.\n" ));
352 #else
353                 Debug( LDAP_DEBUG_TRACE,
354                        "ldbm_back_modrdn: wr to new parent's children OK\n",
355                        0, 0 , 0 );
356 #endif
357
358                 new_parent_dn = np_dn;
359         }
360         
361         /* Build target dn and make sure target entry doesn't exist already. */
362         build_new_dn( &new_dn, e->e_dn, new_parent_dn, newrdn ); 
363
364         new_ndn = ch_strdup(new_dn);
365         (void) dn_normalize( new_ndn );
366
367 #ifdef NEW_LOGGING
368         LDAP_LOG(( "backend", LDAP_LEVEL_DETAIL1,
369                    "ldbm_back_modrdn: new ndn=%s\n", new_ndn ));
370 #else
371         Debug( LDAP_DEBUG_TRACE, "ldbm_back_modrdn: new ndn=%s\n",
372                new_ndn, 0, 0 );
373 #endif
374
375         /* check for abandon */
376         ldap_pvt_thread_mutex_lock( &op->o_abandonmutex );
377         if ( op->o_abandon ) {
378                 ldap_pvt_thread_mutex_unlock( &op->o_abandonmutex );
379                 goto return_results;
380         }
381
382         ldap_pvt_thread_mutex_unlock( &op->o_abandonmutex );
383         if (dn2id ( be, new_ndn ) != NOID) {
384                 send_ldap_result( conn, op, LDAP_ALREADY_EXISTS,
385                         NULL, NULL, NULL, NULL );
386                 goto return_results;
387         }
388
389 #ifdef NEW_LOGGING
390         LDAP_LOG(( "backend", LDAP_LEVEL_INFO,
391                    "ldbm_back_modrdn: new ndn (%s) does not exist\n", new_ndn ));
392 #else
393         Debug( LDAP_DEBUG_TRACE,
394                "ldbm_back_modrdn: new ndn=%s does not exist\n",
395                new_ndn, 0, 0 );
396 #endif
397
398         /* Get attribute type and attribute value of our new rdn, we will
399          * need to add that to our new entry
400          */
401         if ( (new_rdn_type = rdn_attr_type( newrdn )) == NULL ) {
402 #ifdef NEW_LOGGING
403                 LDAP_LOG(( "backend", LDAP_LEVEL_INFO,
404                            "ldbm_back_modrdn: can't figure out type of newrdn\n" ));
405 #else
406                 Debug( LDAP_DEBUG_TRACE,
407                        "ldbm_back_modrdn: can't figure out type of newrdn\n",
408                        0, 0, 0 );
409 #endif
410
411                 send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR,
412                         NULL, "unknown type used in RDN", NULL, NULL );
413                 goto return_results;            
414         }
415
416         if ( (new_rdn_val = rdn_attr_value( newrdn )) == NULL ) {
417 #ifdef NEW_LOGGING
418                 LDAP_LOG(( "backend", LDAP_LEVEL_INFO,
419                            "ldbm_back_modrdn: can't figure out val of newrdn\n"));
420 #else
421                 Debug( LDAP_DEBUG_TRACE,
422                        "ldbm_back_modrdn: can't figure out val of newrdn\n",
423                        0, 0, 0 );
424 #endif
425
426                 send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR,
427                         NULL, "could not parse RDN value", NULL, NULL );
428                 goto return_results;            
429         }
430
431 #ifdef NEW_LOGGING
432         LDAP_LOG(( "backend", LDAP_LEVEL_DETAIL1,
433                    "ldbm_back_modrdn: new_rdn_val=\"%s\", new_rdn_type=\"%s\"\n",
434                    new_rdn_val, new_rdn_type ));
435 #else
436         Debug( LDAP_DEBUG_TRACE,
437                "ldbm_back_modrdn: new_rdn_val=\"%s\", new_rdn_type=\"%s\"\n",
438                new_rdn_val, new_rdn_type, 0 );
439 #endif
440
441         /* Retrieve the old rdn from the entry's dn */
442         if ( (old_rdn = dn_rdn( be, dn )) == NULL ) {
443 #ifdef NEW_LOGGING
444                 LDAP_LOG(( "backend", LDAP_LEVEL_INFO,
445                            "ldbm_back_modrdn: can't figure out old_rdn from dn (%s)\n",
446                            dn ));
447 #else
448                 Debug( LDAP_DEBUG_TRACE,
449                        "ldbm_back_modrdn: can't figure out old_rdn from dn\n",
450                        0, 0, 0 );
451 #endif
452
453                 send_ldap_result( conn, op, LDAP_OTHER,
454                         NULL, "could not parse old DN", NULL, NULL );
455                 goto return_results;            
456         }
457
458         if ( (old_rdn_type = rdn_attr_type( old_rdn )) == NULL ) {
459 #ifdef NEW_LOGGING
460                 LDAP_LOG(( "backend", LDAP_LEVEL_INFO,
461                            "ldbm_back_modrdn: can't figure out the old_rdn type.\n" ));
462 #else
463                 Debug( LDAP_DEBUG_TRACE,
464                        "ldbm_back_modrdn: can't figure out the old_rdn type\n",
465                        0, 0, 0 );
466 #endif
467
468                 send_ldap_result( conn, op, LDAP_OTHER,
469                         NULL, "count parse RDN from old DN", NULL, NULL );
470                 goto return_results;            
471         }
472         
473         if ( newSuperior == NULL
474                 && strcasecmp( old_rdn_type, new_rdn_type ) != 0 )
475         {
476             /* Not a big deal but we may say something */
477 #ifdef NEW_LOGGING
478             LDAP_LOG(( "backend", LDAP_LEVEL_INFO,
479                        "ldbm_back_modrdn: old_rdn_type=%s new_rdn_type-%s\n",
480                        old_rdn_type, new_rdn_type ));
481 #else
482             Debug( LDAP_DEBUG_TRACE,
483                    "ldbm_back_modrdn: old_rdn_type=%s, new_rdn_type=%s!\n",
484                    old_rdn_type, new_rdn_type, 0 );
485 #endif
486         }               
487
488 #ifdef NEW_LOGGING
489         LDAP_LOG(( "backend", LDAP_LEVEL_DETAIL1,
490                    "ldbm_back_modrdn:  DN_X500\n" ));
491 #else
492                 Debug( LDAP_DEBUG_TRACE, "ldbm_back_modrdn: DN_X500\n",
493                        0, 0, 0 );
494 #endif
495                 
496                 /* Add new attribute value to the entry.
497                  */
498
499                 add_bvals[0] = &add_bv;         /* Array of bervals */
500                 add_bvals[1] = NULL;
501
502                 add_bv.bv_val = new_rdn_val;
503                 add_bv.bv_len = strlen(new_rdn_val);
504                 
505                 {
506                         int rc;
507
508                         mod[0].sml_desc = NULL;
509                         rc = slap_str2ad( new_rdn_type, &mod[0].sml_desc, &text );
510
511                         if( rc != LDAP_SUCCESS ) {
512 #ifdef NEW_LOGGING
513                                 LDAP_LOG(( "backend", LDAP_LEVEL_INFO,
514                                            "ldbm_back_modrdn: slap_str2ad error: %s (%s)\n",
515                                            text, new_rdn_type ));
516 #else
517                                 Debug( LDAP_DEBUG_TRACE,
518                                         "ldbm_back_modrdn: %s: %s (new)\n",
519                                         text, new_rdn_type, 0 );
520 #endif
521
522                                 send_ldap_result( conn, op, rc,
523                                         NULL, text, NULL, NULL );
524                                 goto return_results;            
525                         }
526                 }
527
528                 mod[0].sml_bvalues = add_bvals;
529                 mod[0].sml_op = SLAP_MOD_SOFTADD;
530                 mod[0].sml_next = NULL;
531
532                 /* Remove old rdn value if required */
533                 if (deleteoldrdn) {
534                         /* Get value of old rdn */
535         
536                         if ((old_rdn_val = rdn_attr_value( old_rdn )) == NULL) {
537 #ifdef NEW_LOGGING
538                                 LDAP_LOG(( "backend", LDAP_LEVEL_INFO,
539                                            "ldbm_back_modrdn: can't figure out old_rdn_val from old_rdn\n" ));
540 #else
541                                 Debug( LDAP_DEBUG_TRACE,
542                                        "ldbm_back_modrdn: can't figure out old_rdn_val from old_rdn\n",
543                                        0, 0, 0 );
544 #endif
545
546                                 send_ldap_result( conn, op, LDAP_OTHER,
547                                         NULL, "could not parse value from old RDN", NULL, NULL );
548                                 goto return_results;            
549                         }
550
551                         del_bvals[0] = &del_bv;         /* Array of bervals */
552                         del_bvals[1] = NULL;
553
554                         /* Remove old value of rdn as an attribute. */
555                     
556                         del_bv.bv_val = old_rdn_val;
557                         del_bv.bv_len = strlen(old_rdn_val);
558
559                         {
560                                 int rc;
561
562                                 mod[1].sml_desc = NULL;
563                                 rc = slap_str2ad( old_rdn_type, &mod[1].sml_desc, &text );
564
565                                 if( rc != LDAP_SUCCESS ) {
566 #ifdef NEW_LOGGING
567                                         LDAP_LOG(( "backend", LDAP_LEVEL_INFO,
568                                                    "ldbm_back_modrdn: %s: %s (old)\n",
569                                                    text, old_rdn_type ));
570 #else
571                                         Debug( LDAP_DEBUG_TRACE,
572                                                 "ldbm_back_modrdn: %s: %s (old)\n",
573                                                 text, old_rdn_type, 0 );
574 #endif
575
576                                         send_ldap_result( conn, op, rc,
577                                                 NULL, text, NULL, NULL );
578                                         goto return_results;            
579                                 }
580                         }
581
582                         mod[0].sml_next = &mod[1];
583                         mod[1].sml_bvalues = del_bvals;
584                         mod[1].sml_op = LDAP_MOD_DELETE;
585                         mod[1].sml_next = NULL;
586
587 #ifdef NEW_LOGGING
588                         LDAP_LOG(( "backend", LDAP_LEVEL_DETAIL1,
589                                    "ldbm_back_modrdn: removing old_rdn_val=%s\n", old_rdn_val ));
590 #else
591                         Debug( LDAP_DEBUG_TRACE,
592                                "ldbm_back_modrdn: removing old_rdn_val=%s\n",
593                                old_rdn_val, 0, 0 );
594 #endif
595                 }
596         
597         /* check for abandon */
598         ldap_pvt_thread_mutex_lock( &op->o_abandonmutex );
599         if ( op->o_abandon ) {
600                 ldap_pvt_thread_mutex_unlock( &op->o_abandonmutex );
601                 goto return_results;
602         }
603         ldap_pvt_thread_mutex_unlock( &op->o_abandonmutex );
604
605         /* delete old one */
606         if ( dn2id_delete( be, e->e_ndn, e->e_id ) != 0 ) {
607                 send_ldap_result( conn, op, LDAP_OTHER,
608                         NULL, "DN index delete fail", NULL, NULL );
609                 goto return_results;
610         }
611
612         (void) cache_delete_entry( &li->li_cache, e );
613
614         /* XXX: there is no going back! */
615
616         free( e->e_dn );
617         free( e->e_ndn );
618         e->e_dn = new_dn;
619         e->e_ndn = new_ndn;
620         new_dn = NULL;
621         new_ndn = NULL;
622
623         /* add new one */
624         if ( dn2id_add( be, e->e_ndn, e->e_id ) != 0 ) {
625                 send_ldap_result( conn, op, LDAP_OTHER,
626                         NULL, "DN index add failed", NULL, NULL );
627                 goto return_results;
628         }
629
630         /* modify memory copy of entry */
631         rc = ldbm_modify_internal( be, conn, op, dn, &mod[0], e,
632                 &text, textbuf, textlen );
633
634         if( rc != LDAP_SUCCESS ) {
635                 if( rc != SLAPD_ABANDON ) {
636                         send_ldap_result( conn, op, rc,
637                                 NULL, text, NULL, NULL );
638                 }
639             
640             goto return_results;
641         }
642         
643         (void) cache_update_entry( &li->li_cache, e );
644
645         /* NOTE: after this you must not free new_dn or new_ndn!
646          * They are used by cache.
647          */
648
649         /* id2entry index */
650         if ( id2entry_add( be, e ) != 0 ) {
651                 entry_free( e );
652                 send_ldap_result( conn, op, LDAP_OTHER,
653                         NULL, "entry update failed", NULL, NULL );
654                 goto return_results;
655         }
656
657         send_ldap_result( conn, op, LDAP_SUCCESS,
658                 NULL, NULL, NULL, NULL );
659         rc = 0;
660
661 return_results:
662         if( new_dn != NULL ) free( new_dn );
663         if( new_ndn != NULL ) free( new_ndn );
664
665         if( p_dn != NULL ) free( p_dn );
666         if( p_ndn != NULL ) free( p_ndn );
667
668         /* LDAP v2 supporting correct attribute handling. */
669         if( new_rdn_type != NULL ) free(new_rdn_type);
670         if( new_rdn_val != NULL ) free(new_rdn_val);
671         if( old_rdn != NULL ) free(old_rdn);
672         if( old_rdn_type != NULL ) free(old_rdn_type);
673         if( old_rdn_val != NULL ) free(old_rdn_val);
674
675         /* LDAP v3 Support */
676         if ( np_dn != NULL ) free( np_dn );
677         if ( np_ndn != NULL ) free( np_ndn );
678
679         if( np != NULL ) {
680                 /* free new parent and writer lock */
681                 cache_return_entry_w( &li->li_cache, np );
682         }
683
684         if( p != NULL ) {
685                 /* free parent and writer lock */
686                 cache_return_entry_w( &li->li_cache, p );
687         }
688
689         if ( rootlock ) {
690                 /* release root writer lock */
691                 ldap_pvt_thread_mutex_unlock(&li->li_root_mutex);
692         }
693
694         /* free entry and writer lock */
695         cache_return_entry_w( &li->li_cache, e );
696         return( rc );
697 }