]> git.sur5r.net Git - openldap/blob - servers/slapd/back-ldbm/modrdn.c
cleanup bind
[openldap] / servers / slapd / back-ldbm / modrdn.c
1 /* modrdn.c - ldbm 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 /*
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     struct berval       *dn,
41     struct berval       *ndn,
42     struct berval       *newrdn,
43     struct berval       *nnewrdn,
44     int         deleteoldrdn,
45     struct berval       *newSuperior,
46     struct berval       *nnewSuperior
47 )
48 {
49         AttributeDescription *children = slap_schema.si_ad_children;
50         AttributeDescription *entry = slap_schema.si_ad_entry;
51         struct ldbminfo *li = (struct ldbminfo *) be->be_private;
52         struct berval   p_dn, p_ndn;
53         struct berval   new_dn = { 0, NULL}, new_ndn = { 0, NULL };
54         Entry           *e, *p = NULL;
55         Entry           *matched;
56         /* LDAP v2 supporting correct attribute handling. */
57         LDAPRDN         *new_rdn = NULL;
58         LDAPRDN         *old_rdn = NULL;
59         int             isroot = -1;
60 #define CAN_ROLLBACK    -1
61 #define MUST_DESTROY    1
62         int             rc = CAN_ROLLBACK;
63         int             rc_id = 0;
64         ID              id = NOID;
65         const char      *text = NULL;
66         char            textbuf[SLAP_TEXT_BUFLEN];
67         size_t          textlen = sizeof textbuf;
68         /* Added to support newSuperior */ 
69         Entry           *np = NULL;     /* newSuperior Entry */
70         struct berval   *np_ndn = NULL; /* newSuperior ndn */
71         struct berval   *new_parent_dn = NULL;  /* np_dn, p_dn, or NULL */
72         /* Used to interface with ldbm_modify_internal() */
73         Modifications   *mod = NULL;            /* Used to delete old/add new rdn */
74         int             manageDSAit = get_manageDSAit( op );
75
76 #ifdef NEW_LOGGING
77         LDAP_LOG( BACK_LDBM, ENTRY, 
78                 "ldbm_back_modrdn: dn: %s newSuperior=%s\n", 
79                 dn->bv_len ? dn->bv_val : "NULL",
80                 ( newSuperior && newSuperior->bv_len ) ? newSuperior->bv_val : "NULL",0 );
81 #else
82         Debug( LDAP_DEBUG_TRACE,
83                 "==>ldbm_back_modrdn: dn: %s newSuperior=%s\n", 
84                 dn->bv_len ? dn->bv_val : "NULL",
85                 ( newSuperior && newSuperior->bv_len )
86                         ? newSuperior->bv_val : "NULL", 0 );
87 #endif
88
89         /* grab giant lock for writing */
90         ldap_pvt_thread_rdwr_wlock(&li->li_giant_rwlock);
91
92         /* get entry with writer lock */
93         if ( (e = dn2entry_w( be, ndn, &matched )) == NULL ) {
94                 char* matched_dn = NULL;
95                 BerVarray refs;
96
97                 if( matched != NULL ) {
98                         matched_dn = strdup( matched->e_dn );
99                         refs = is_entry_referral( matched )
100                                 ? get_entry_referrals( be, conn, op, matched )
101                                 : NULL;
102                         cache_return_entry_r( &li->li_cache, matched );
103                 } else {
104                         refs = referral_rewrite( default_referral,
105                                 NULL, dn, LDAP_SCOPE_DEFAULT );
106                 }
107
108                 ldap_pvt_thread_rdwr_wunlock(&li->li_giant_rwlock);
109
110                 send_ldap_result( conn, op, LDAP_REFERRAL,
111                         matched_dn, NULL, refs, NULL );
112
113                 if ( refs ) ber_bvarray_free( refs );
114                 free( matched_dn );
115
116                 return( -1 );
117         }
118
119         /* check entry for "entry" acl */
120         if ( ! access_allowed( be, conn, op, e,
121                 entry, NULL, ACL_WRITE, NULL ) )
122         {
123 #ifdef NEW_LOGGING
124                 LDAP_LOG( BACK_LDBM, ERR, 
125                         "ldbm_back_modrdn: no write access to entry of (%s)\n", 
126                         dn->bv_val, 0, 0 );
127 #else
128                 Debug( LDAP_DEBUG_TRACE,
129                         "<=- ldbm_back_modrdn: no write access to entry\n", 0,
130                         0, 0 );
131 #endif
132
133                 send_ldap_result( conn, op, LDAP_INSUFFICIENT_ACCESS,
134                         NULL, "no write access to entry", NULL, NULL );
135
136                 goto return_results;
137         }
138
139         if (!manageDSAit && is_entry_referral( e ) ) {
140                 /* parent is a referral, don't allow add */
141                 /* parent is an alias, don't allow add */
142                 BerVarray refs = get_entry_referrals( be,
143                         conn, op, e );
144
145 #ifdef NEW_LOGGING
146                 LDAP_LOG( BACK_LDBM, INFO, 
147                         "ldbm_back_modrdn: entry %s is a referral\n", e->e_dn, 0, 0 );
148 #else
149                 Debug( LDAP_DEBUG_TRACE, "entry %s is referral\n", e->e_dn,
150                     0, 0 );
151 #endif
152
153                 send_ldap_result( conn, op, LDAP_REFERRAL,
154                     e->e_dn, NULL, refs, NULL );
155
156                 if ( refs ) ber_bvarray_free( refs );
157                 goto return_results;
158         }
159
160         if ( has_children( be, e ) ) {
161 #ifdef NEW_LOGGING
162                 LDAP_LOG( BACK_LDBM, INFO, 
163                         "ldbm_back_modrdn: entry %s has children\n", e->e_dn, 0, 0 );
164 #else
165                 Debug( LDAP_DEBUG_TRACE, "entry %s has children\n", e->e_dn,
166                     0, 0 );
167 #endif
168
169                 send_ldap_result( conn, op, LDAP_NOT_ALLOWED_ON_NONLEAF,
170                     NULL, "subtree rename not supported", NULL, NULL );
171                 goto return_results;
172         }
173
174         if ( be_issuffix( be, &e->e_nname ) ) {
175                 p_ndn = slap_empty_bv ;
176         } else {
177                 dnParent( &e->e_nname, &p_ndn );
178         }
179
180         if ( p_ndn.bv_len != 0 ) {
181                 /* Make sure parent entry exist and we can write its 
182                  * children.
183                  */
184
185                 if( (p = dn2entry_w( be, &p_ndn, NULL )) == NULL) {
186 #ifdef NEW_LOGGING
187                         LDAP_LOG( BACK_LDBM, INFO, 
188                                 "ldbm_back_modrdn: parent of %s does not exist\n", 
189                                 e->e_ndn, 0, 0 );
190 #else
191                         Debug( LDAP_DEBUG_TRACE, "parent does not exist\n",
192                                 0, 0, 0);
193 #endif
194
195                         send_ldap_result( conn, op, LDAP_OTHER,
196                                 NULL, "parent entry does not exist", NULL, NULL );
197
198                         goto return_results;
199                 }
200
201                 /* check parent for "children" acl */
202                 if ( ! access_allowed( be, conn, op, p,
203                         children, NULL, ACL_WRITE, NULL ) )
204                 {
205 #ifdef NEW_LOGGING
206                         LDAP_LOG( BACK_LDBM, INFO, 
207                                 "ldbm_back_modrdn: no access to parent of (%s)\n", 
208                                 e->e_dn, 0, 0 );
209 #else
210                         Debug( LDAP_DEBUG_TRACE, "no access to parent\n", 0,
211                                 0, 0 );
212 #endif
213
214                         send_ldap_result( conn, op, LDAP_INSUFFICIENT_ACCESS,
215                                 NULL, NULL, NULL, NULL );
216                         goto return_results;
217                 }
218
219 #ifdef NEW_LOGGING
220                 LDAP_LOG( BACK_LDBM, DETAIL1, 
221                         "ldbm_back_modrdn: wr to children of entry %s OK\n", 
222                         p_ndn.bv_val, 0, 0 );
223 #else
224                 Debug( LDAP_DEBUG_TRACE,
225                        "ldbm_back_modrdn: wr to children of entry %s OK\n",
226                        p_ndn.bv_val, 0, 0 );
227 #endif
228
229                 if ( p_ndn.bv_val == slap_empty_bv.bv_val ) {
230                         p_dn = slap_empty_bv;
231                 } else {
232                         dnParent( &e->e_name, &p_dn );
233                 }
234
235 #ifdef NEW_LOGGING
236                 LDAP_LOG( BACK_LDBM, DETAIL1, 
237                            "ldbm_back_modrdn: parent dn=%s\n", p_dn.bv_val, 0, 0 );
238 #else
239                 Debug( LDAP_DEBUG_TRACE, "ldbm_back_modrdn: parent dn=%s\n",
240                        p_dn.bv_val, 0, 0 );
241 #endif
242
243         } else {
244                 /* no parent, must be root to modify rdn */
245                 isroot = be_isroot( be, &op->o_ndn );
246                 if ( ! isroot ) {
247                         if ( be_issuffix( be, (struct berval *)&slap_empty_bv ) || be_isupdate( be, &op->o_ndn ) ) {
248                                 int     can_access;
249                                 p = (Entry *)&slap_entry_root;
250                                 
251                                 can_access = access_allowed( be, conn, op, p,
252                                                 children, NULL, ACL_WRITE, NULL );
253                                 p = NULL;
254                                                                 
255                                 /* check parent for "children" acl */
256                                 if ( ! can_access ) {
257 #ifdef NEW_LOGGING
258                                         LDAP_LOG( BACK_LDBM, ERR,
259                                                 "ldbm_back_modrdn: no access to parent \"\"\n", 0,0,0 );
260 #else
261                                         Debug( LDAP_DEBUG_TRACE,
262                                                 "<=- ldbm_back_modrdn: no "
263                                                 "access to parent\n", 0, 0, 0 );
264 #endif
265
266                                         send_ldap_result( conn, op, 
267                                                 LDAP_INSUFFICIENT_ACCESS,
268                                                 NULL, NULL, NULL, NULL );
269                                         goto return_results;
270                                 }
271
272                         } else {
273 #ifdef NEW_LOGGING
274                                 LDAP_LOG( BACK_LDBM, ERR, 
275                                         "ldbm_back_modrdn: (%s) has no parent & not a root.\n", 
276                                         dn, 0, 0 );
277 #else
278                                 Debug( LDAP_DEBUG_TRACE,
279                                         "<=- ldbm_back_modrdn: no parent & "
280                                         "not root\n", 0, 0, 0);
281 #endif
282
283                                 send_ldap_result( conn, op, 
284                                         LDAP_INSUFFICIENT_ACCESS,
285                                         NULL, NULL, NULL, NULL );
286                                 goto return_results;
287                         }
288                 }
289
290 #ifdef NEW_LOGGING
291                 LDAP_LOG( BACK_LDBM, INFO, 
292                    "ldbm_back_modrdn: (%s) no parent, locked root.\n", e->e_dn, 0, 0 );
293 #else
294                 Debug( LDAP_DEBUG_TRACE,
295                        "ldbm_back_modrdn: no parent, locked root\n",
296                        0, 0, 0 );
297 #endif
298         }
299
300         new_parent_dn = &p_dn;  /* New Parent unless newSuperior given */
301
302         if ( newSuperior != NULL ) {
303 #ifdef NEW_LOGGING
304                 LDAP_LOG( BACK_LDBM, DETAIL1, 
305                         "ldbm_back_modrdn: new parent \"%s\" requested\n",
306                         newSuperior->bv_val, 0, 0 );
307 #else
308                 Debug( LDAP_DEBUG_TRACE, 
309                         "ldbm_back_modrdn: new parent \"%s\" requested...\n",
310                         newSuperior->bv_val, 0, 0 );
311 #endif
312
313                 np_ndn = nnewSuperior;
314
315                 /* newSuperior == oldParent? */
316                 if ( dn_match( &p_ndn, np_ndn ) ) {
317 #ifdef NEW_LOGGING
318                         LDAP_LOG( BACK_LDBM, INFO, "ldbm_back_modrdn: "
319                                 "new parent\"%s\" seems to be the same as the "
320                                 "old parent \"%s\"\n", newSuperior->bv_val, p_dn.bv_val, 0 );
321 #else
322                         Debug( LDAP_DEBUG_TRACE, "ldbm_back_modrdn: "
323                                 "new parent\"%s\" seems to be the same as the "
324                                 "old parent \"%s\"\n",
325                                 newSuperior->bv_val, p_dn.bv_val, 0 );
326 #endif
327
328                         newSuperior = NULL; /* ignore newSuperior */
329                 }
330         }
331
332         if ( newSuperior != NULL ) {
333                 /* newSuperior == entry being moved?, if so ==> ERROR */
334                 /* Get Entry with dn=newSuperior. Does newSuperior exist? */
335
336                 if ( nnewSuperior->bv_len ) {
337                         if( (np = dn2entry_w( be, np_ndn, NULL )) == NULL) {
338 #ifdef NEW_LOGGING
339                                 LDAP_LOG( BACK_LDBM, ERR, 
340                                         "ldbm_back_modrdn: newSup(ndn=%s) not found.\n", 
341                                         np_ndn->bv_val, 0, 0 );
342 #else
343                                 Debug( LDAP_DEBUG_TRACE,
344                                     "ldbm_back_modrdn: newSup(ndn=%s) not here!\n",
345                                     np_ndn->bv_val, 0, 0);
346 #endif
347
348                                 send_ldap_result( conn, op, LDAP_OTHER,
349                                         NULL, "newSuperior not found", NULL, NULL );
350                                 goto return_results;
351                         }
352
353 #ifdef NEW_LOGGING
354                         LDAP_LOG( BACK_LDBM, DETAIL1,
355                                 "ldbm_back_modrdn: wr to new parent OK np=%p, id=%ld\n",
356                                 np, np->e_id, 0 );
357 #else
358                         Debug( LDAP_DEBUG_TRACE,
359                                 "ldbm_back_modrdn: wr to new parent OK np=%p, id=%ld\n",
360                                 np, np->e_id, 0 );
361 #endif
362
363                         /* check newSuperior for "children" acl */
364                         if ( !access_allowed( be, conn, op, np, children, NULL,
365                                               ACL_WRITE, NULL ) )
366                         {
367 #ifdef NEW_LOGGING
368                                 LDAP_LOG( BACK_LDBM, INFO,
369                                    "ldbm_back_modrdn: no wr to newSup children.\n", 0, 0, 0 );
370 #else
371                                 Debug( LDAP_DEBUG_TRACE,
372                                        "ldbm_back_modrdn: no wr to newSup children\n",
373                                        0, 0, 0 );
374 #endif
375
376                                 send_ldap_result( conn, op, LDAP_INSUFFICIENT_ACCESS,
377                                         NULL, NULL, NULL, NULL );
378                                 goto return_results;
379                         }
380
381                         if ( is_entry_alias( np ) ) {
382                                 /* parent is an alias, don't allow add */
383 #ifdef NEW_LOGGING
384                                 LDAP_LOG( BACK_LDBM, INFO,
385                                    "ldbm_back_modrdn: entry (%s) is an alias.\n", np->e_dn,0,0);
386 #else
387                                 Debug( LDAP_DEBUG_TRACE, "entry is alias\n", 0, 0, 0 );
388 #endif
389
390
391                                 send_ldap_result( conn, op, LDAP_ALIAS_PROBLEM,
392                                     NULL, "newSuperior is an alias", NULL, NULL );
393
394                                 goto return_results;
395                         }
396
397                         if ( is_entry_referral( np ) ) {
398                                 /* parent is a referral, don't allow add */
399 #ifdef NEW_LOGGING
400                                 LDAP_LOG( BACK_LDBM, INFO,
401                                         "ldbm_back_modrdn: entry (%s) is a referral\n",
402                                         np->e_dn, 0, 0 );
403 #else
404                                 Debug( LDAP_DEBUG_TRACE, "entry (%s) is referral\n",
405                                         np->e_dn, 0, 0 );
406 #endif
407
408                                 send_ldap_result( conn, op, LDAP_OTHER,
409                                     NULL, "newSuperior is a referral", NULL, NULL );
410
411                                 goto return_results;
412                         }
413
414                 } else {
415
416                         /* no parent, must be root to modify newSuperior */
417                         if ( isroot == -1 ) {
418                                 isroot = be_isroot( be, &op->o_ndn );
419                         }
420
421                         if ( ! isroot ) {
422                                 if ( be_issuffix( be, (struct berval *)&slap_empty_bv ) || be_isupdate( be, &op->o_ndn ) ) {
423                                         int     can_access;
424                                         np = (Entry *)&slap_entry_root;
425                                 
426                                         can_access = access_allowed( be, conn, op, np,
427                                                         children, NULL, ACL_WRITE, NULL );
428                                         np = NULL;
429                                                                 
430                                         /* check parent for "children" acl */
431                                         if ( ! can_access ) {
432 #ifdef NEW_LOGGING
433                                                 LDAP_LOG( BACK_LDBM, ERR,
434                                                         "ldbm_back_modrdn: no access "
435                                                         "to new superior \"\"\n", 0, 0, 0 );
436 #else
437                                                 Debug( LDAP_DEBUG_TRACE,
438                                                         "<=- ldbm_back_modrdn: no "
439                                                         "access to new superior\n", 0, 0, 0 );
440 #endif
441
442                                                 send_ldap_result( conn, op, 
443                                                         LDAP_INSUFFICIENT_ACCESS,
444                                                         NULL, NULL, NULL, NULL );
445                                                 goto return_results;
446                                         }
447
448                                 } else {
449 #ifdef NEW_LOGGING
450                                         LDAP_LOG( BACK_LDBM, ERR,
451                                                 "ldbm_back_modrdn: \"\" not allowed as new superior\n",
452                                                 0, 0, 0 );
453 #else
454                                         Debug( LDAP_DEBUG_TRACE,
455                                                 "<=- ldbm_back_modrdn: \"\" "
456                                                 "not allowed as new superior\n", 
457                                                 0, 0, 0);
458 #endif
459
460                                         send_ldap_result( conn, op, 
461                                                 LDAP_INSUFFICIENT_ACCESS,
462                                                 NULL, NULL, NULL, NULL );
463                                         goto return_results;
464                                 }
465                         }
466                 }
467
468 #ifdef NEW_LOGGING
469                 LDAP_LOG( BACK_LDBM, DETAIL1,
470                         "ldbm_back_modrdn: wr to new parent's children OK.\n", 0, 0, 0 );
471 #else
472                 Debug( LDAP_DEBUG_TRACE,
473                     "ldbm_back_modrdn: wr to new parent's children OK\n",
474                     0, 0, 0 );
475 #endif
476
477                 new_parent_dn = newSuperior;
478         }
479         
480         /* Build target dn and make sure target entry doesn't exist already. */
481         build_new_dn( &new_dn, new_parent_dn, newrdn ); 
482         dnNormalize2( NULL, &new_dn, &new_ndn );
483
484 #ifdef NEW_LOGGING
485         LDAP_LOG( BACK_LDBM, DETAIL1, "ldbm_back_modrdn: new ndn=%s\n", 
486                 new_ndn.bv_val, 0, 0 );
487 #else
488         Debug( LDAP_DEBUG_TRACE, "ldbm_back_modrdn: new ndn=%s\n",
489             new_ndn.bv_val, 0, 0 );
490 #endif
491
492         /* check for abandon */
493         if ( op->o_abandon ) {
494                 goto return_results;
495         }
496
497         if ( ( rc_id = dn2id ( be, &new_ndn, &id ) ) || id != NOID ) {
498                 /* if (rc_id) something bad happened to ldbm cache */
499                 send_ldap_result( conn, op, 
500                         rc_id ? LDAP_OTHER : LDAP_ALREADY_EXISTS,
501                         NULL, NULL, NULL, NULL );
502                 goto return_results;
503         }
504
505 #ifdef NEW_LOGGING
506         LDAP_LOG( BACK_LDBM, INFO, "ldbm_back_modrdn: new ndn (%s) does not exist\n",
507                 new_ndn.bv_val, 0, 0 );
508 #else
509         Debug( LDAP_DEBUG_TRACE,
510             "ldbm_back_modrdn: new ndn=%s does not exist\n",
511             new_ndn.bv_val, 0, 0 );
512 #endif
513
514         /* Get attribute type and attribute value of our new rdn, we will
515          * need to add that to our new entry
516          */
517         if ( ldap_bv2rdn( newrdn, &new_rdn, (char **)&text,
518                 LDAP_DN_FORMAT_LDAP ) )
519         {
520 #ifdef NEW_LOGGING
521                 LDAP_LOG ( OPERATION, ERR, 
522                         "ldbm_back_modrdn: can't figure out "
523                         "type(s)/values(s) of newrdn\n", 
524                         0, 0, 0 );
525 #else
526                 Debug( LDAP_DEBUG_TRACE,
527                         "ldbm_back_modrdn: can't figure out "
528                         "type(s)/values(s) of newrdn\n", 
529                         0, 0, 0 );
530 #endif
531                 goto return_results;            
532         }
533
534 #ifdef NEW_LOGGING
535         LDAP_LOG ( OPERATION, RESULTS, 
536                 "ldbm_back_modrdn: new_rdn_type=\"%s\", "
537                 "new_rdn_val=\"%s\"\n",
538                 new_rdn[ 0 ][ 0 ]->la_attr.bv_val, 
539                 new_rdn[ 0 ][ 0 ]->la_value.bv_val, 0 );
540 #else
541         Debug( LDAP_DEBUG_TRACE,
542                 "ldbm_back_modrdn: new_rdn_type=\"%s\", "
543                 "new_rdn_val=\"%s\"\n",
544                 new_rdn[ 0 ][ 0 ]->la_attr.bv_val,
545                 new_rdn[ 0 ][ 0 ]->la_value.bv_val, 0 );
546 #endif
547
548         if ( deleteoldrdn ) {
549                 if ( ldap_bv2rdn( dn, &old_rdn, (char **)&text,
550                         LDAP_DN_FORMAT_LDAP ) )
551                 {
552 #ifdef NEW_LOGGING
553                         LDAP_LOG ( OPERATION, ERR, 
554                                 "ldbm_back_modrdn: can't figure out "
555                                 "type(s)/values(s) of old_rdn\n", 
556                                 0, 0, 0 );
557 #else
558                         Debug( LDAP_DEBUG_TRACE,
559                                 "ldbm_back_modrdn: can't figure out "
560                                 "the old_rdn type(s)/value(s)\n", 
561                                 0, 0, 0 );
562 #endif
563                         goto return_results;            
564                 }
565         }
566
567 #ifdef NEW_LOGGING
568         LDAP_LOG( BACK_LDBM, DETAIL1, "ldbm_back_modrdn:  DN_X500\n", 0, 0, 0 );
569 #else
570         Debug( LDAP_DEBUG_TRACE, "ldbm_back_modrdn: DN_X500\n",
571                0, 0, 0 );
572 #endif
573         
574         if ( slap_modrdn2mods( be, conn, op, e, old_rdn, new_rdn, 
575                         deleteoldrdn, &mod ) != LDAP_SUCCESS ) {
576                 goto return_results;
577         }
578
579
580         /* check for abandon */
581         if ( op->o_abandon ) {
582                 goto return_results;
583         }
584
585         /* delete old one */
586         if ( dn2id_delete( be, &e->e_nname, e->e_id ) != 0 ) {
587                 send_ldap_result( conn, op, LDAP_OTHER,
588                         NULL, "DN index delete fail", NULL, NULL );
589                 goto return_results;
590         }
591
592         (void) cache_delete_entry( &li->li_cache, e );
593         rc = MUST_DESTROY;
594
595         /* XXX: there is no going back! */
596
597         free( e->e_dn );
598         free( e->e_ndn );
599         e->e_name = new_dn;
600         e->e_nname = new_ndn;
601         new_dn.bv_val = NULL;
602         new_ndn.bv_val = NULL;
603
604         /* NOTE: after this you must not free new_dn or new_ndn!
605          * They are used by cache.
606          */
607
608         /* add new one */
609         if ( dn2id_add( be, &e->e_nname, e->e_id ) != 0 ) {
610                 send_ldap_result( conn, op, LDAP_OTHER,
611                         NULL, "DN index add failed", NULL, NULL );
612                 goto return_results;
613         }
614
615         /* modify memory copy of entry */
616         rc_id = ldbm_modify_internal( be, conn, op, dn->bv_val, &mod[0], e,
617                 &text, textbuf, textlen );
618         switch ( rc_id ) {
619         case LDAP_SUCCESS:
620                 break;
621
622         case SLAPD_ABANDON:
623                 /* too late ... */
624                 send_ldap_result( conn, op, rc_id, NULL, text, NULL, NULL );
625                 goto return_results;
626         
627         default:
628                 /* here we may try to delete the newly added dn */
629                 if ( dn2id_delete( be, &e->e_nname, e->e_id ) != 0 ) {
630                         /* we already are in trouble ... */
631                         ;
632                 }
633                 goto return_results;
634         }
635         
636         (void) cache_update_entry( &li->li_cache, e );
637
638         /* id2entry index */
639         if ( id2entry_add( be, e ) != 0 ) {
640                 send_ldap_result( conn, op, LDAP_OTHER,
641                         NULL, "entry update failed", NULL, NULL );
642                 goto return_results;
643         }
644
645         send_ldap_result( conn, op, LDAP_SUCCESS,
646                 NULL, NULL, NULL, NULL );
647         rc = 0;
648         cache_entry_commit( e );
649
650 return_results:
651         if( new_dn.bv_val != NULL ) free( new_dn.bv_val );
652         if( new_ndn.bv_val != NULL ) free( new_ndn.bv_val );
653
654         /* LDAP v2 supporting correct attribute handling. */
655         if ( new_rdn != NULL ) {
656                 ldap_rdnfree( new_rdn );
657         }
658         if ( old_rdn != NULL ) {
659                 ldap_rdnfree( old_rdn );
660         }
661         if ( mod != NULL ) {
662                 Modifications *tmp;
663                 for (; mod; mod = tmp ) {
664                         tmp = mod->sml_next;
665                         free( mod );
666                 }
667         }
668
669         /* LDAP v3 Support */
670         if( np != NULL ) {
671                 /* free new parent and writer lock */
672                 cache_return_entry_w( &li->li_cache, np );
673         }
674
675         if( p != NULL ) {
676                 /* free parent and writer lock */
677                 cache_return_entry_w( &li->li_cache, p );
678         }
679
680         /* free entry and writer lock */
681         cache_return_entry_w( &li->li_cache, e );
682         if ( rc == MUST_DESTROY ) {
683                 /* if rc == MUST_DESTROY the entry is uncached 
684                  * and its private data is destroyed; 
685                  * the entry must be freed */
686                 entry_free( e );
687         }
688         ldap_pvt_thread_rdwr_wunlock(&li->li_giant_rwlock);
689         return( rc );
690 }