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