]> git.sur5r.net Git - openldap/blob - servers/slapd/back-ldbm/modrdn.c
More "entry" level ACLs for entry add, delete, and rename.
[openldap] / servers / slapd / back-ldbm / modrdn.c
1 /* modrdn.c - ldbm 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 /*
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                                 p = (Entry *)&slap_entry_root;
249                                 
250                                 rc = access_allowed( be, conn, op, p,
251                                                 children, NULL, ACL_WRITE, NULL );
252                                 p = NULL;
253                                                                 
254                                 /* check parent for "children" acl */
255                                 if ( ! rc ) {
256 #ifdef NEW_LOGGING
257                                         LDAP_LOG( BACK_LDBM, ERR,
258                                                 "ldbm_back_modrdn: no access to parent \"\"\n", 0,0,0 );
259 #else
260                                         Debug( LDAP_DEBUG_TRACE,
261                                                 "<=- ldbm_back_modrdn: no "
262                                                 "access to parent\n", 0, 0, 0 );
263 #endif
264
265                                         send_ldap_result( conn, op, 
266                                                 LDAP_INSUFFICIENT_ACCESS,
267                                                 NULL, NULL, NULL, NULL );
268                                         goto return_results;
269                                 }
270
271                         } else {
272 #ifdef NEW_LOGGING
273                                 LDAP_LOG( BACK_LDBM, ERR, 
274                                         "ldbm_back_modrdn: (%s) has no parent & not a root.\n", 
275                                         dn, 0, 0 );
276 #else
277                                 Debug( LDAP_DEBUG_TRACE,
278                                         "<=- ldbm_back_modrdn: no parent & "
279                                         "not root\n", 0, 0, 0);
280 #endif
281
282                                 send_ldap_result( conn, op, 
283                                         LDAP_INSUFFICIENT_ACCESS,
284                                         NULL, NULL, NULL, NULL );
285                                 goto return_results;
286                         }
287                 }
288
289 #ifdef NEW_LOGGING
290                 LDAP_LOG( BACK_LDBM, INFO, 
291                    "ldbm_back_modrdn: (%s) no parent, locked root.\n", e->e_dn, 0, 0 );
292 #else
293                 Debug( LDAP_DEBUG_TRACE,
294                        "ldbm_back_modrdn: no parent, locked root\n",
295                        0, 0, 0 );
296 #endif
297         }
298
299         new_parent_dn = &p_dn;  /* New Parent unless newSuperior given */
300
301         if ( newSuperior != NULL ) {
302 #ifdef NEW_LOGGING
303                 LDAP_LOG( BACK_LDBM, DETAIL1, 
304                         "ldbm_back_modrdn: new parent \"%s\" requested\n",
305                         newSuperior->bv_val, 0, 0 );
306 #else
307                 Debug( LDAP_DEBUG_TRACE, 
308                         "ldbm_back_modrdn: new parent \"%s\" requested...\n",
309                         newSuperior->bv_val, 0, 0 );
310 #endif
311
312                 np_ndn = nnewSuperior;
313
314                 /* newSuperior == oldParent? */
315                 if ( dn_match( &p_ndn, np_ndn ) ) {
316 #ifdef NEW_LOGGING
317                         LDAP_LOG( BACK_LDBM, INFO, "ldbm_back_modrdn: "
318                                 "new parent\"%s\" seems to be the same as the "
319                                 "old parent \"%s\"\n", newSuperior->bv_val, p_dn.bv_val, 0 );
320 #else
321                         Debug( LDAP_DEBUG_TRACE, "ldbm_back_modrdn: "
322                                 "new parent\"%s\" seems to be the same as the "
323                                 "old parent \"%s\"\n",
324                                 newSuperior->bv_val, p_dn.bv_val, 0 );
325 #endif
326
327                         newSuperior = NULL; /* ignore newSuperior */
328                 }
329         }
330
331         if ( newSuperior != NULL ) {
332                 /* newSuperior == entry being moved?, if so ==> ERROR */
333                 /* Get Entry with dn=newSuperior. Does newSuperior exist? */
334
335                 if ( nnewSuperior->bv_len ) {
336                         if( (np = dn2entry_w( be, np_ndn, NULL )) == NULL) {
337 #ifdef NEW_LOGGING
338                                 LDAP_LOG( BACK_LDBM, ERR, 
339                                         "ldbm_back_modrdn: newSup(ndn=%s) not found.\n", 
340                                         np_ndn->bv_val, 0, 0 );
341 #else
342                                 Debug( LDAP_DEBUG_TRACE,
343                                     "ldbm_back_modrdn: newSup(ndn=%s) not here!\n",
344                                     np_ndn->bv_val, 0, 0);
345 #endif
346
347                                 send_ldap_result( conn, op, LDAP_OTHER,
348                                         NULL, "newSuperior not found", NULL, NULL );
349                                 goto return_results;
350                         }
351
352 #ifdef NEW_LOGGING
353                         LDAP_LOG( BACK_LDBM, DETAIL1,
354                                 "ldbm_back_modrdn: wr to new parent OK np=%p, id=%ld\n",
355                                 np, np->e_id, 0 );
356 #else
357                         Debug( LDAP_DEBUG_TRACE,
358                                 "ldbm_back_modrdn: wr to new parent OK np=%p, id=%ld\n",
359                                 np, np->e_id, 0 );
360 #endif
361
362                         /* check newSuperior for "children" acl */
363                         if ( !access_allowed( be, conn, op, np, children, NULL,
364                                               ACL_WRITE, NULL ) )
365                         {
366 #ifdef NEW_LOGGING
367                                 LDAP_LOG( BACK_LDBM, INFO,
368                                    "ldbm_back_modrdn: no wr to newSup children.\n", 0, 0, 0 );
369 #else
370                                 Debug( LDAP_DEBUG_TRACE,
371                                        "ldbm_back_modrdn: no wr to newSup children\n",
372                                        0, 0, 0 );
373 #endif
374
375                                 send_ldap_result( conn, op, LDAP_INSUFFICIENT_ACCESS,
376                                         NULL, NULL, NULL, NULL );
377                                 goto return_results;
378                         }
379
380                         if ( is_entry_alias( np ) ) {
381                                 /* parent is an alias, don't allow add */
382 #ifdef NEW_LOGGING
383                                 LDAP_LOG( BACK_LDBM, INFO,
384                                    "ldbm_back_modrdn: entry (%s) is an alias.\n", np->e_dn,0,0);
385 #else
386                                 Debug( LDAP_DEBUG_TRACE, "entry is alias\n", 0, 0, 0 );
387 #endif
388
389
390                                 send_ldap_result( conn, op, LDAP_ALIAS_PROBLEM,
391                                     NULL, "newSuperior is an alias", NULL, NULL );
392
393                                 goto return_results;
394                         }
395
396                         if ( is_entry_referral( np ) ) {
397                                 /* parent is a referral, don't allow add */
398 #ifdef NEW_LOGGING
399                                 LDAP_LOG( BACK_LDBM, INFO,
400                                         "ldbm_back_modrdn: entry (%s) is a referral\n",
401                                         np->e_dn, 0, 0 );
402 #else
403                                 Debug( LDAP_DEBUG_TRACE, "entry (%s) is referral\n",
404                                         np->e_dn, 0, 0 );
405 #endif
406
407                                 send_ldap_result( conn, op, LDAP_OTHER,
408                                     NULL, "newSuperior is a referral", NULL, NULL );
409
410                                 goto return_results;
411                         }
412
413                 } else {
414
415                         /* no parent, must be root to modify newSuperior */
416                         if ( isroot == -1 ) {
417                                 isroot = be_isroot( be, &op->o_ndn );
418                         }
419
420                         if ( ! isroot ) {
421                                 if ( be_issuffix( be, (struct berval *)&slap_empty_bv ) || be_isupdate( be, &op->o_ndn ) ) {
422                                         np = (Entry *)&slap_entry_root;
423                                 
424                                         rc = access_allowed( be, conn, op, np,
425                                                         children, NULL, ACL_WRITE, NULL );
426                                         np = NULL;
427                                                                 
428                                         /* check parent for "children" acl */
429                                         if ( ! rc ) {
430 #ifdef NEW_LOGGING
431                                                 LDAP_LOG( BACK_LDBM, ERR,
432                                                         "ldbm_back_modrdn: no access "
433                                                         "to new superior \"\"\n", 0, 0, 0 );
434 #else
435                                                 Debug( LDAP_DEBUG_TRACE,
436                                                         "<=- ldbm_back_modrdn: no "
437                                                         "access to new superior\n", 0, 0, 0 );
438 #endif
439
440                                                 send_ldap_result( conn, op, 
441                                                         LDAP_INSUFFICIENT_ACCESS,
442                                                         NULL, NULL, NULL, NULL );
443                                                 goto return_results;
444                                         }
445
446                                 } else {
447 #ifdef NEW_LOGGING
448                                         LDAP_LOG( BACK_LDBM, ERR,
449                                                 "ldbm_back_modrdn: \"\" not allowed as new superior\n",
450                                                 0, 0, 0 );
451 #else
452                                         Debug( LDAP_DEBUG_TRACE,
453                                                 "<=- ldbm_back_modrdn: \"\" "
454                                                 "not allowed as new superior\n", 
455                                                 0, 0, 0);
456 #endif
457
458                                         send_ldap_result( conn, op, 
459                                                 LDAP_INSUFFICIENT_ACCESS,
460                                                 NULL, NULL, NULL, NULL );
461                                         goto return_results;
462                                 }
463                         }
464                 }
465
466 #ifdef NEW_LOGGING
467                 LDAP_LOG( BACK_LDBM, DETAIL1,
468                         "ldbm_back_modrdn: wr to new parent's children OK.\n", 0, 0, 0 );
469 #else
470                 Debug( LDAP_DEBUG_TRACE,
471                     "ldbm_back_modrdn: wr to new parent's children OK\n",
472                     0, 0, 0 );
473 #endif
474
475                 new_parent_dn = newSuperior;
476         }
477         
478         /* Build target dn and make sure target entry doesn't exist already. */
479         build_new_dn( &new_dn, new_parent_dn, newrdn ); 
480         dnNormalize2( NULL, &new_dn, &new_ndn );
481
482 #ifdef NEW_LOGGING
483         LDAP_LOG( BACK_LDBM, DETAIL1, "ldbm_back_modrdn: new ndn=%s\n", 
484                 new_ndn.bv_val, 0, 0 );
485 #else
486         Debug( LDAP_DEBUG_TRACE, "ldbm_back_modrdn: new ndn=%s\n",
487             new_ndn.bv_val, 0, 0 );
488 #endif
489
490         /* check for abandon */
491         if ( op->o_abandon ) {
492                 goto return_results;
493         }
494
495         if ( ( rc_id = dn2id ( be, &new_ndn, &id ) ) || id != NOID ) {
496                 /* if (rc_id) something bad happened to ldbm cache */
497                 send_ldap_result( conn, op, 
498                         rc_id ? LDAP_OTHER : LDAP_ALREADY_EXISTS,
499                         NULL, NULL, NULL, NULL );
500                 goto return_results;
501         }
502
503 #ifdef NEW_LOGGING
504         LDAP_LOG( BACK_LDBM, INFO, "ldbm_back_modrdn: new ndn (%s) does not exist\n",
505                 new_ndn.bv_val, 0, 0 );
506 #else
507         Debug( LDAP_DEBUG_TRACE,
508             "ldbm_back_modrdn: new ndn=%s does not exist\n",
509             new_ndn.bv_val, 0, 0 );
510 #endif
511
512         /* Get attribute type and attribute value of our new rdn, we will
513          * need to add that to our new entry
514          */
515         if ( ldap_bv2rdn( newrdn, &new_rdn, (char **)&text,
516                 LDAP_DN_FORMAT_LDAP ) )
517         {
518 #ifdef NEW_LOGGING
519                 LDAP_LOG ( OPERATION, ERR, 
520                         "ldbm_back_modrdn: can't figure out "
521                         "type(s)/values(s) of newrdn\n", 
522                         0, 0, 0 );
523 #else
524                 Debug( LDAP_DEBUG_TRACE,
525                         "ldbm_back_modrdn: can't figure out "
526                         "type(s)/values(s) of newrdn\n", 
527                         0, 0, 0 );
528 #endif
529                 rc = LDAP_INVALID_DN_SYNTAX;
530                 text = "unknown type(s) used in RDN";
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                         rc = LDAP_OTHER;
564                         text = "cannot parse RDN from old DN";
565                         goto return_results;            
566                 }
567         }
568
569 #ifdef NEW_LOGGING
570         LDAP_LOG( BACK_LDBM, DETAIL1, "ldbm_back_modrdn:  DN_X500\n", 0, 0, 0 );
571 #else
572         Debug( LDAP_DEBUG_TRACE, "ldbm_back_modrdn: DN_X500\n",
573                0, 0, 0 );
574 #endif
575         
576         rc = slap_modrdn2mods( be, conn, op, e, old_rdn, new_rdn, 
577                         deleteoldrdn, &mod );
578         if ( rc != LDAP_SUCCESS ) {
579                 goto return_results;
580         }
581
582
583         /* check for abandon */
584         if ( op->o_abandon ) {
585                 goto return_results;
586         }
587
588         /* delete old one */
589         if ( dn2id_delete( be, &e->e_nname, e->e_id ) != 0 ) {
590                 send_ldap_result( conn, op, LDAP_OTHER,
591                         NULL, "DN index delete fail", NULL, NULL );
592                 goto return_results;
593         }
594
595         (void) cache_delete_entry( &li->li_cache, e );
596         rc = MUST_DESTROY;
597
598         /* XXX: there is no going back! */
599
600         free( e->e_dn );
601         free( e->e_ndn );
602         e->e_name = new_dn;
603         e->e_nname = new_ndn;
604         new_dn.bv_val = NULL;
605         new_ndn.bv_val = NULL;
606
607         /* add new one */
608         if ( dn2id_add( be, &e->e_nname, e->e_id ) != 0 ) {
609                 send_ldap_result( conn, op, LDAP_OTHER,
610                         NULL, "DN index add failed", NULL, NULL );
611                 goto return_results;
612         }
613
614         /* modify memory copy of entry */
615         rc = ldbm_modify_internal( be, conn, op, dn->bv_val, &mod[0], e,
616                 &text, textbuf, textlen );
617
618         if( rc != LDAP_SUCCESS ) {
619                 if( rc != SLAPD_ABANDON ) {
620                         send_ldap_result( conn, op, rc,
621                                 NULL, text, NULL, NULL );
622                 }
623
624                 /* here we may try to delete the newly added dn */
625                 if ( dn2id_delete( be, &e->e_nname, e->e_id ) != 0 ) {
626                         /* we already are in trouble ... */
627                         ;
628                 }
629             
630                 goto return_results;
631         }
632         
633         (void) cache_update_entry( &li->li_cache, e );
634
635         /* NOTE: after this you must not free new_dn or new_ndn!
636          * They are used by cache.
637          */
638
639         /* id2entry index */
640         if ( id2entry_add( be, e ) != 0 ) {
641                 send_ldap_result( conn, op, LDAP_OTHER,
642                         NULL, "entry update failed", NULL, NULL );
643                 goto return_results;
644         }
645
646         send_ldap_result( conn, op, LDAP_SUCCESS,
647                 NULL, NULL, NULL, NULL );
648         rc = 0;
649         cache_entry_commit( e );
650
651 return_results:
652         if( new_dn.bv_val != NULL ) free( new_dn.bv_val );
653         if( new_ndn.bv_val != NULL ) free( new_ndn.bv_val );
654
655         /* LDAP v2 supporting correct attribute handling. */
656         if ( new_rdn != NULL ) {
657                 ldap_rdnfree( new_rdn );
658         }
659         if ( old_rdn != NULL ) {
660                 ldap_rdnfree( old_rdn );
661         }
662         if ( mod != NULL ) {
663                 Modifications *tmp;
664                 for (; mod; mod = tmp ) {
665                         tmp = mod->sml_next;
666                         free( mod );
667                 }
668         }
669
670         /* LDAP v3 Support */
671         if( np != NULL ) {
672                 /* free new parent and writer lock */
673                 cache_return_entry_w( &li->li_cache, np );
674         }
675
676         if( p != NULL ) {
677                 /* free parent and writer lock */
678                 cache_return_entry_w( &li->li_cache, p );
679         }
680
681         /* free entry and writer lock */
682         cache_return_entry_w( &li->li_cache, e );
683         if ( rc == MUST_DESTROY ) {
684                 /* if rc == MUST_DESTROY the entry is uncached 
685                  * and its private data is destroyed; 
686                  * the entry must be freed */
687                 entry_free( e );
688         }
689         ldap_pvt_thread_rdwr_wunlock(&li->li_giant_rwlock);
690         return( rc );
691 }