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