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