]> git.sur5r.net Git - openldap/blob - servers/slapd/back-bdb/modrdn.c
01734bb1837aed6ac22761d41662ada23460ff7c
[openldap] / servers / slapd / back-bdb / modrdn.c
1 /* modrdn.c - bdb 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 #include "portable.h"
9
10 #include <stdio.h>
11 #include <ac/string.h>
12
13 #include "back-bdb.h"
14 #include "external.h"
15
16 int
17 bdb_modrdn( Operation   *op, SlapReply *rs )
18 {
19         struct bdb_info *bdb = (struct bdb_info *) op->o_bd->be_private;
20         AttributeDescription *children = slap_schema.si_ad_children;
21         AttributeDescription *entry = slap_schema.si_ad_entry;
22         struct berval   p_dn, p_ndn;
23         struct berval   new_dn = {0, NULL}, new_ndn = {0, NULL};
24         int             isroot = -1;
25         Entry           *e = NULL;
26         Entry           *p = NULL;
27         Entry           *matched;
28         /* LDAP v2 supporting correct attribute handling. */
29         LDAPRDN         new_rdn = NULL;
30         LDAPRDN         old_rdn = NULL;
31         char textbuf[SLAP_TEXT_BUFLEN];
32         size_t textlen = sizeof textbuf;
33         DB_TXN *        ltid = NULL;
34         struct bdb_op_info opinfo;
35
36         ID                      id;
37
38         Entry           *np = NULL;                     /* newSuperior Entry */
39         struct berval   *np_dn = NULL;                  /* newSuperior dn */
40         struct berval   *np_ndn = NULL;                 /* newSuperior ndn */
41         struct berval   *new_parent_dn = NULL;  /* np_dn, p_dn, or NULL */
42
43         /* Used to interface with bdb_modify_internal() */
44         Modifications   *mod = NULL;            /* Used to delete old rdn */
45
46         int             manageDSAit = get_manageDSAit( op );
47
48         u_int32_t       locker = 0;
49         DB_LOCK         lock;
50
51         int             noop = 0;
52
53 #if defined(LDAP_CLIENT_UPDATE) || defined(LDAP_SYNC)
54         Operation *ps_list;
55         struct psid_entry *pm_list, *pm_prev;
56 #endif
57
58 #ifdef NEW_LOGGING
59         LDAP_LOG ( OPERATION, ENTRY, "==>bdb_modrdn(%s,%s,%s)\n", 
60                 op->o_req_dn.bv_val,op->oq_modrdn.rs_newrdn.bv_val,
61                 op->oq_modrdn.rs_newSup ? op->oq_modrdn.rs_newSup->bv_val : "NULL" );
62 #else
63         Debug( LDAP_DEBUG_TRACE, "==>bdb_modrdn(%s,%s,%s)\n",
64                 op->o_req_dn.bv_val,op->oq_modrdn.rs_newrdn.bv_val,
65                 op->oq_modrdn.rs_newSup ? op->oq_modrdn.rs_newSup->bv_val : "NULL" );
66 #endif
67
68         if( 0 ) {
69 retry:  /* transaction retry */
70                 if (e != NULL) {
71                         bdb_cache_delete_entry(&bdb->bi_cache, e);
72                         bdb_unlocked_cache_return_entry_w(&bdb->bi_cache, e);
73                         e = NULL;
74                 }
75                 if (p != NULL) {
76                         bdb_unlocked_cache_return_entry_r(&bdb->bi_cache, p);
77                         p = NULL;
78                 }
79                 if (np != NULL) {
80                         bdb_unlocked_cache_return_entry_r(&bdb->bi_cache, np);
81                         np = NULL;
82                 }
83 #ifdef NEW_LOGGING
84                 LDAP_LOG ( OPERATION, DETAIL1, "==>bdb_modrdn: retrying...\n", 0, 0, 0);
85 #else
86                 Debug( LDAP_DEBUG_TRACE, "==>bdb_modrdn: retrying...\n", 0, 0, 0 );
87 #endif
88
89 #if defined(LDAP_CLIENT_UPDATE) || defined(LDAP_SYNC)
90                 pm_list = LDAP_LIST_FIRST(&op->o_pm_list);
91                 while ( pm_list != NULL ) {
92                         LDAP_LIST_REMOVE ( pm_list, ps_link );
93                         pm_prev = pm_list;
94                         pm_list = LDAP_LIST_NEXT ( pm_list, ps_link );
95                         ch_free( pm_prev );
96                 }
97 #endif
98
99                 rs->sr_err = TXN_ABORT( ltid );
100                 ltid = NULL;
101                 op->o_private = NULL;
102                 op->o_do_not_cache = opinfo.boi_acl_cache;
103                 if( rs->sr_err != 0 ) {
104                         rs->sr_err = LDAP_OTHER;
105                         rs->sr_text = "internal error";
106                         goto return_results;
107                 }
108                 ldap_pvt_thread_yield();
109         }
110
111         /* begin transaction */
112         rs->sr_err = TXN_BEGIN( bdb->bi_dbenv, NULL, &ltid, 
113                 bdb->bi_db_opflags );
114         rs->sr_text = NULL;
115         if( rs->sr_err != 0 ) {
116 #ifdef NEW_LOGGING
117                 LDAP_LOG ( OPERATION, ERR, 
118                         "==>bdb_modrdn: txn_begin failed: %s (%d)\n", 
119                         db_strerror(rs->sr_err), rs->sr_err, 0 );
120 #else
121                 Debug( LDAP_DEBUG_TRACE,
122                         "bdb_delete: txn_begin failed: %s (%d)\n",
123                         db_strerror(rs->sr_err), rs->sr_err, 0 );
124 #endif
125                 rs->sr_err = LDAP_OTHER;
126                 rs->sr_text = "internal error";
127                 goto return_results;
128         }
129
130         locker = TXN_ID ( ltid );
131
132         opinfo.boi_bdb = op->o_bd;
133         opinfo.boi_txn = ltid;
134         opinfo.boi_locker = locker;
135         opinfo.boi_err = 0;
136         opinfo.boi_acl_cache = op->o_do_not_cache;
137         op->o_private = &opinfo;
138
139         /* get entry */
140         rs->sr_err = bdb_dn2entry_w( op->o_bd, ltid, &op->o_req_ndn, &e, &matched, DB_RMW, locker, &lock );
141
142         switch( rs->sr_err ) {
143         case 0:
144         case DB_NOTFOUND:
145                 break;
146         case DB_LOCK_DEADLOCK:
147         case DB_LOCK_NOTGRANTED:
148                 goto retry;
149         case LDAP_BUSY:
150                 rs->sr_text = "ldap server busy";
151                 goto return_results;
152         default:
153                 rs->sr_err = LDAP_OTHER;
154                 rs->sr_text = "internal error";
155                 goto return_results;
156         }
157
158         if ( e == NULL ) {
159                 if( matched != NULL ) {
160                         rs->sr_matched = ch_strdup( matched->e_dn );
161                         rs->sr_ref = is_entry_referral( matched )
162                                 ? get_entry_referrals( op, matched )
163                                 : NULL;
164                         bdb_unlocked_cache_return_entry_r( &bdb->bi_cache, matched);
165                         matched = NULL;
166
167                 } else {
168                         rs->sr_ref = referral_rewrite( default_referral,
169                                 NULL, &op->o_req_dn, LDAP_SCOPE_DEFAULT );
170                 }
171
172                 rs->sr_err = LDAP_REFERRAL;
173                 send_ldap_result( op, rs );
174
175                 ber_bvarray_free( rs->sr_ref );
176                 free( (char *)rs->sr_matched );
177                 rs->sr_ref = NULL;
178                 rs->sr_matched = NULL;
179
180                 goto done;
181         }
182
183         /* check write on old entry */
184         rs->sr_err = access_allowed( op, e, entry, NULL, ACL_WRITE, NULL );
185
186         if ( ! rs->sr_err ) {
187                 switch( opinfo.boi_err ) {
188                 case DB_LOCK_DEADLOCK:
189                 case DB_LOCK_NOTGRANTED:
190                         goto retry;
191                 }
192
193 #ifdef NEW_LOGGING
194                 LDAP_LOG ( OPERATION, ERR, 
195                         "==>bdb_modrdn: no access to entry\n", 0, 0, 0 );
196 #else
197                 Debug( LDAP_DEBUG_TRACE, "no access to entry\n", 0,
198                         0, 0 );
199 #endif
200                 rs->sr_text = "no write access to old entry";
201                 rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
202                 goto return_results;
203         }
204
205 #ifndef BDB_HIER
206         rs->sr_err = bdb_dn2id_children( op->o_bd, ltid, &e->e_nname, 0 );
207         if ( rs->sr_err != DB_NOTFOUND ) {
208                 switch( rs->sr_err ) {
209                 case DB_LOCK_DEADLOCK:
210                 case DB_LOCK_NOTGRANTED:
211                         goto retry;
212                 case 0:
213 #ifdef NEW_LOGGING
214                         LDAP_LOG ( OPERATION, DETAIL1, 
215                                 "<=- bdb_modrdn: non-leaf %s\n", op->o_req_dn.bv_val, 0, 0 );
216 #else
217                         Debug(LDAP_DEBUG_ARGS,
218                                 "<=- bdb_modrdn: non-leaf %s\n",
219                                 op->o_req_dn.bv_val, 0, 0);
220 #endif
221                         rs->sr_err = LDAP_NOT_ALLOWED_ON_NONLEAF;
222                         rs->sr_text = "subtree rename not supported";
223                         break;
224                 default:
225 #ifdef NEW_LOGGING
226                         LDAP_LOG ( OPERATION, ERR, 
227                                 "<=- bdb_modrdn: has_children failed %s (%d)\n",
228                                 db_strerror(rs->sr_err), rs->sr_err, 0 );
229 #else
230                         Debug(LDAP_DEBUG_ARGS,
231                                 "<=- bdb_modrdn: has_children failed: %s (%d)\n",
232                                 db_strerror(rs->sr_err), rs->sr_err, 0 );
233 #endif
234                         rs->sr_err = LDAP_OTHER;
235                         rs->sr_text = "internal error";
236                 }
237                 goto return_results;
238         }
239 #endif
240         if (!manageDSAit && is_entry_referral( e ) ) {
241                 /* parent is a referral, don't allow add */
242                 rs->sr_ref = get_entry_referrals( op, e );
243
244 #ifdef NEW_LOGGING
245                 LDAP_LOG ( OPERATION, DETAIL1, 
246                         "==>bdb_modrdn: entry %s is referral \n", e->e_dn, 0, 0 );
247 #else
248                 Debug( LDAP_DEBUG_TRACE, "bdb_modrdn: entry %s is referral\n",
249                         e->e_dn, 0, 0 );
250 #endif
251
252                 rs->sr_err = LDAP_REFERRAL,
253                 rs->sr_matched = e->e_name.bv_val;
254                 send_ldap_result( op, rs );
255
256                 ber_bvarray_free( rs->sr_ref );
257                 rs->sr_ref = NULL;
258                 rs->sr_matched = NULL;
259                 goto done;
260         }
261
262         if ( be_issuffix( op->o_bd, &e->e_nname ) ) {
263                 p_ndn = slap_empty_bv;
264         } else {
265                 dnParent( &e->e_nname, &p_ndn );
266         }
267         np_ndn = &p_ndn;
268         if ( p_ndn.bv_len != 0 ) {
269                 /* Make sure parent entry exist and we can write its 
270                  * children.
271                  */
272                 rs->sr_err = bdb_dn2entry_r( op->o_bd, ltid, &p_ndn, &p, NULL, 0, locker, &lock );
273
274                 switch( rs->sr_err ) {
275                 case 0:
276                 case DB_NOTFOUND:
277                         break;
278                 case DB_LOCK_DEADLOCK:
279                 case DB_LOCK_NOTGRANTED:
280                         goto retry;
281                 case LDAP_BUSY:
282                         rs->sr_text = "ldap server busy";
283                         goto return_results;
284                 default:
285                         rs->sr_err = LDAP_OTHER;
286                         rs->sr_text = "internal error";
287                         goto return_results;
288                 }
289
290                 if( p == NULL) {
291 #ifdef NEW_LOGGING
292                         LDAP_LOG ( OPERATION, ERR, 
293                                 "==>bdb_modrdn: parent does not exist\n", 0, 0, 0 );
294 #else
295                         Debug( LDAP_DEBUG_TRACE, "bdb_modrdn: parent does not exist\n",
296                                 0, 0, 0);
297 #endif
298                         rs->sr_err = LDAP_OTHER;
299                         rs->sr_text = "old entry's parent does not exist";
300                         goto return_results;
301                 }
302
303                 /* check parent for "children" acl */
304                 rs->sr_err = access_allowed( op, p,
305                         children, NULL, ACL_WRITE, NULL );
306
307                 if ( ! rs->sr_err ) {
308                         switch( opinfo.boi_err ) {
309                         case DB_LOCK_DEADLOCK:
310                         case DB_LOCK_NOTGRANTED:
311                                 goto retry;
312                         }
313
314                         rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
315 #ifdef NEW_LOGGING
316                         LDAP_LOG ( OPERATION, ERR, 
317                                 "==>bdb_modrdn: no access to parent\n", 0, 0, 0 );
318 #else
319                         Debug( LDAP_DEBUG_TRACE, "no access to parent\n", 0,
320                                 0, 0 );
321 #endif
322                         rs->sr_text = "no write access to old parent's children";
323                         goto return_results;
324                 }
325
326 #ifdef NEW_LOGGING
327                 LDAP_LOG ( OPERATION, DETAIL1, 
328                         "==>bdb_modrdn: wr to children %s is OK\n", p_ndn.bv_val, 0, 0 );
329 #else
330                 Debug( LDAP_DEBUG_TRACE,
331                         "bdb_modrdn: wr to children of entry %s OK\n",
332                         p_ndn.bv_val, 0, 0 );
333 #endif
334                 
335                 if ( p_ndn.bv_val == slap_empty_bv.bv_val ) {
336                         p_dn = slap_empty_bv;
337                 } else {
338                         dnParent( &e->e_name, &p_dn );
339                 }
340
341 #ifdef NEW_LOGGING
342                 LDAP_LOG ( OPERATION, DETAIL1, 
343                         "==>bdb_modrdn: parent dn=%s\n", p_dn.bv_val, 0, 0 );
344 #else
345                 Debug( LDAP_DEBUG_TRACE,
346                         "bdb_modrdn: parent dn=%s\n",
347                         p_dn.bv_val, 0, 0 );
348 #endif
349
350         } else {
351                 /* no parent, modrdn entry directly under root */
352                 isroot = be_isroot( op->o_bd, &op->o_ndn );
353                 if ( ! isroot ) {
354                         if ( be_issuffix( op->o_bd, (struct berval *)&slap_empty_bv )
355                                 || be_isupdate( op->o_bd, &op->o_ndn ) ) {
356
357                                 p = (Entry *)&slap_entry_root;
358
359                                 /* check parent for "children" acl */
360                                 rs->sr_err = access_allowed( op, p,
361                                         children, NULL, ACL_WRITE, NULL );
362
363                                 p = NULL;
364
365                                 if ( ! rs->sr_err ) {
366                                         switch( opinfo.boi_err ) {
367                                         case DB_LOCK_DEADLOCK:
368                                         case DB_LOCK_NOTGRANTED:
369                                                 goto retry;
370                                         }
371
372                                         rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
373 #ifdef NEW_LOGGING
374                                         LDAP_LOG ( OPERATION, ERR, 
375                                                 "==>bdb_modrdn: no access to parent\n", 0, 0, 0 );
376 #else
377                                         Debug( LDAP_DEBUG_TRACE, 
378                                                 "no access to parent\n", 
379                                                 0, 0, 0 );
380 #endif
381                                         rs->sr_text = "no write access to old parent";
382                                         goto return_results;
383                                 }
384
385 #ifdef NEW_LOGGING
386                                 LDAP_LOG ( OPERATION, DETAIL1, 
387                                         "==>bdb_modrdn: wr to children of entry \"%s\" OK\n", 
388                                         p_dn.bv_val, 0, 0 );
389 #else
390                                 Debug( LDAP_DEBUG_TRACE,
391                                         "bdb_modrdn: wr to children of entry \"\" OK\n",
392                                         0, 0, 0 );
393 #endif
394                 
395                                 p_dn.bv_val = "";
396                                 p_dn.bv_len = 0;
397
398 #ifdef NEW_LOGGING
399                                 LDAP_LOG ( OPERATION, DETAIL1, 
400                                         "==>bdb_modrdn: parent dn=\"\" \n", 0, 0, 0 );
401 #else
402                                 Debug( LDAP_DEBUG_TRACE,
403                                         "bdb_modrdn: parent dn=\"\"\n",
404                                         0, 0, 0 );
405 #endif
406
407                         } else {
408 #ifdef NEW_LOGGING
409                                 LDAP_LOG ( OPERATION, ERR, 
410                                         "==>bdb_modrdn: no parent, not root &\"\" is not "
411                                         "suffix\n", 0, 0, 0 );
412 #else
413                                 Debug( LDAP_DEBUG_TRACE,
414                                         "bdb_modrdn: no parent, not root "
415                                         "& \"\" is not suffix\n",
416                                         0, 0, 0);
417 #endif
418                                 rs->sr_text = "no write access to old parent";
419                                 rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
420                                 goto return_results;
421                         }
422                 }
423         }
424
425         new_parent_dn = &p_dn;  /* New Parent unless newSuperior given */
426
427         if ( op->oq_modrdn.rs_newSup != NULL ) {
428 #ifdef NEW_LOGGING
429                 LDAP_LOG ( OPERATION, DETAIL1, 
430                         "==>bdb_modrdn: new parent \"%s\" requested...\n", 
431                         op->oq_modrdn.rs_newSup->bv_val, 0, 0 );
432 #else
433                 Debug( LDAP_DEBUG_TRACE, 
434                         "bdb_modrdn: new parent \"%s\" requested...\n",
435                         op->oq_modrdn.rs_newSup->bv_val, 0, 0 );
436 #endif
437
438                 /*  newSuperior == oldParent? */
439                 if( dn_match( &p_ndn, op->oq_modrdn.rs_nnewSup ) ) {
440 #ifdef NEW_LOGGING
441                         LDAP_LOG( BACK_BDB, INFO, "bdb_back_modrdn: "
442                                 "new parent \"%s\" same as the old parent \"%s\"\n",
443                                 op->oq_modrdn.rs_newSup->bv_val, p_dn.bv_val, 0 );
444 #else
445                         Debug( LDAP_DEBUG_TRACE, "bdb_back_modrdn: "
446                                 "new parent \"%s\" same as the old parent \"%s\"\n",
447                                 op->oq_modrdn.rs_newSup->bv_val, p_dn.bv_val, 0 );
448 #endif      
449                         op->oq_modrdn.rs_newSup = NULL; /* ignore newSuperior */
450                 }
451         }
452
453         if ( op->oq_modrdn.rs_newSup != NULL ) {
454                 if ( op->oq_modrdn.rs_newSup->bv_len ) {
455                         np_dn = op->oq_modrdn.rs_newSup;
456                         np_ndn = op->oq_modrdn.rs_nnewSup;
457
458                         /* newSuperior == oldParent?, if so ==> ERROR */
459                         /* newSuperior == entry being moved?, if so ==> ERROR */
460                         /* Get Entry with dn=newSuperior. Does newSuperior exist? */
461
462                         rs->sr_err = bdb_dn2entry_r( op->o_bd,
463                                 ltid, np_ndn, &np, NULL, 0, locker, &lock );
464
465                         switch( rs->sr_err ) {
466                         case 0:
467                         case DB_NOTFOUND:
468                                 break;
469                         case DB_LOCK_DEADLOCK:
470                         case DB_LOCK_NOTGRANTED:
471                                 goto retry;
472                         case LDAP_BUSY:
473                                 rs->sr_text = "ldap server busy";
474                                 goto return_results;
475                         default:
476                                 rs->sr_err = LDAP_OTHER;
477                                 rs->sr_text = "internal error";
478                                 goto return_results;
479                         }
480
481                         if( np == NULL) {
482 #ifdef NEW_LOGGING
483                                 LDAP_LOG ( OPERATION, DETAIL1, 
484                                         "==>bdb_modrdn: newSup(ndn=%s) not here!\n", 
485                                         np_ndn->bv_val, 0, 0 );
486 #else
487                                 Debug( LDAP_DEBUG_TRACE,
488                                         "bdb_modrdn: newSup(ndn=%s) not here!\n",
489                                         np_ndn->bv_val, 0, 0);
490 #endif
491                                 rs->sr_text = "new superior not found";
492                                 rs->sr_err = LDAP_OTHER;
493                                 goto return_results;
494                         }
495
496 #ifdef NEW_LOGGING
497                         LDAP_LOG ( OPERATION, DETAIL1, 
498                                 "==>bdb_modrdn: wr to new parent OK np=%p, id=%ld\n", 
499                                 np, (long) np->e_id, 0 );
500 #else
501                         Debug( LDAP_DEBUG_TRACE,
502                                 "bdb_modrdn: wr to new parent OK np=%p, id=%ld\n",
503                                 np, (long) np->e_id, 0 );
504 #endif
505
506                         /* check newSuperior for "children" acl */
507                         rs->sr_err = access_allowed( op, np, children,
508                                 NULL, ACL_WRITE, NULL );
509
510                         if( ! rs->sr_err ) {
511                                 switch( opinfo.boi_err ) {
512                                 case DB_LOCK_DEADLOCK:
513                                 case DB_LOCK_NOTGRANTED:
514                                         goto retry;
515                                 }
516
517 #ifdef NEW_LOGGING
518                                 LDAP_LOG ( OPERATION, DETAIL1, 
519                                         "==>bdb_modrdn: no wr to newSup children\n", 0, 0, 0 );
520 #else
521                                 Debug( LDAP_DEBUG_TRACE,
522                                         "bdb_modrdn: no wr to newSup children\n",
523                                         0, 0, 0 );
524 #endif
525                                 rs->sr_text = "no write access to new superior's children";
526                                 rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
527                                 goto return_results;
528                         }
529
530 #ifdef BDB_ALIASES
531                         if ( is_entry_alias( np ) ) {
532                                 /* parent is an alias, don't allow add */
533 #ifdef NEW_LOGGING
534                                 LDAP_LOG ( OPERATION, DETAIL1, 
535                                         "==>bdb_modrdn: entry is alias\n", 0, 0, 0 );
536 #else
537                                 Debug( LDAP_DEBUG_TRACE, "bdb_modrdn: entry is alias\n",
538                                         0, 0, 0 );
539 #endif
540                                 rs->sr_text = "new superior is an alias";
541                                 rs->sr_err = LDAP_ALIAS_PROBLEM;
542                                 goto return_results;
543                         }
544 #endif
545
546                         if ( is_entry_referral( np ) ) {
547                                 /* parent is a referral, don't allow add */
548 #ifdef NEW_LOGGING
549                                 LDAP_LOG ( OPERATION, DETAIL1, 
550                                         "==>bdb_modrdn: entry is referral\n", 0, 0, 0 );
551 #else
552                                 Debug( LDAP_DEBUG_TRACE, "bdb_modrdn: entry is referral\n",
553                                         0, 0, 0 );
554 #endif
555                                 rs->sr_text = "new superior is a referral";
556                                 rs->sr_err = LDAP_OTHER;
557                                 goto return_results;
558                         }
559
560                 } else {
561                         if ( isroot == -1 ) {
562                                 isroot = be_isroot( op->o_bd, &op->o_ndn );
563                         }
564                         
565                         np_dn = NULL;
566
567                         /* no parent, modrdn entry directly under root */
568                         if ( ! isroot ) {
569                                 if ( be_issuffix( op->o_bd, (struct berval *)&slap_empty_bv )
570                                         || be_isupdate( op->o_bd, &op->o_ndn ) ) {
571                                         np = (Entry *)&slap_entry_root;
572
573                                         /* check parent for "children" acl */
574                                         rs->sr_err = access_allowed( op, np,
575                                                 children, NULL, ACL_WRITE, NULL );
576
577                                         np = NULL;
578
579                                         if ( ! rs->sr_err ) {
580                                                 switch( opinfo.boi_err ) {
581                                                 case DB_LOCK_DEADLOCK:
582                                                 case DB_LOCK_NOTGRANTED:
583                                                         goto retry;
584                                                 }
585
586                                                 rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
587 #ifdef NEW_LOGGING
588                                                 LDAP_LOG ( OPERATION, ERR, 
589                                                         "==>bdb_modrdn: no access to superior\n", 0, 0, 0 );
590 #else
591                                                 Debug( LDAP_DEBUG_TRACE, 
592                                                         "no access to new superior\n", 
593                                                         0, 0, 0 );
594 #endif
595                                                 rs->sr_text = "no write access to new superior's children";
596                                                 goto return_results;
597                                         }
598
599 #ifdef NEW_LOGGING
600                                         LDAP_LOG ( OPERATION, DETAIL1, 
601                                                 "bdb_modrdn: wr to children entry \"\" OK\n", 0, 0, 0 );
602 #else
603                                         Debug( LDAP_DEBUG_TRACE,
604                                                 "bdb_modrdn: wr to children of entry \"\" OK\n",
605                                                 0, 0, 0 );
606 #endif
607                 
608                                 } else {
609 #ifdef NEW_LOGGING
610                                         LDAP_LOG ( OPERATION, ERR, 
611                                                 "bdb_modrdn: new superior=\"\", not root & \"\" "
612                                                 "is not suffix\n", 0, 0, 0 );
613 #else
614                                         Debug( LDAP_DEBUG_TRACE,
615                                                 "bdb_modrdn: new superior=\"\", not root "
616                                                 "& \"\" is not suffix\n",
617                                                 0, 0, 0);
618 #endif
619                                         rs->sr_text = "no write access to new superior's children";
620                                         rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
621                                         goto return_results;
622                                 }
623                         }
624
625 #ifdef NEW_LOGGING
626                         LDAP_LOG ( OPERATION, DETAIL1, 
627                                 "bdb_modrdn: new superior=\"\"\n", 0, 0, 0 );
628 #else
629                         Debug( LDAP_DEBUG_TRACE,
630                                 "bdb_modrdn: new superior=\"\"\n",
631                                 0, 0, 0 );
632 #endif
633                 }
634
635 #ifdef NEW_LOGGING
636                 LDAP_LOG ( OPERATION, DETAIL1, 
637                         "bdb_modrdn: wr to new parent's children OK\n", 0, 0, 0 );
638 #else
639                 Debug( LDAP_DEBUG_TRACE,
640                         "bdb_modrdn: wr to new parent's children OK\n",
641                         0, 0, 0 );
642 #endif
643
644                 new_parent_dn = np_dn;
645         }
646
647         /* Build target dn and make sure target entry doesn't exist already. */
648         if (!new_dn.bv_val) build_new_dn( &new_dn, new_parent_dn, &op->oq_modrdn.rs_newrdn ); 
649
650         if (!new_ndn.bv_val) dnNormalize2( NULL, &new_dn, &new_ndn, op->o_tmpmemctx );
651
652 #ifdef NEW_LOGGING
653         LDAP_LOG ( OPERATION, RESULTS, 
654                 "bdb_modrdn: new ndn=%s\n", new_ndn.bv_val, 0, 0 );
655 #else
656         Debug( LDAP_DEBUG_TRACE, "bdb_modrdn: new ndn=%s\n",
657                 new_ndn.bv_val, 0, 0 );
658 #endif
659
660         rs->sr_err = bdb_dn2id ( op->o_bd, ltid, &new_ndn, &id, 0 );
661         switch( rs->sr_err ) {
662         case DB_LOCK_DEADLOCK:
663         case DB_LOCK_NOTGRANTED:
664                 goto retry;
665         case DB_NOTFOUND:
666                 break;
667         case 0:
668                 rs->sr_err = LDAP_ALREADY_EXISTS;
669                 goto return_results;
670         default:
671                 rs->sr_err = LDAP_OTHER;
672                 rs->sr_text = "internal error";
673                 goto return_results;
674         }
675
676         /* Get attribute type and attribute value of our new rdn, we will
677          * need to add that to our new entry
678          */
679         if ( !new_rdn && ldap_bv2rdn_x( &op->oq_modrdn.rs_newrdn, &new_rdn, (char **)&rs->sr_text,
680                 LDAP_DN_FORMAT_LDAP, op->o_tmpmemctx ) )
681         {
682 #ifdef NEW_LOGGING
683                 LDAP_LOG ( OPERATION, ERR, 
684                         "bdb_modrdn: can't figure out "
685                         "type(s)/values(s) of newrdn\n", 
686                         0, 0, 0 );
687 #else
688                 Debug( LDAP_DEBUG_TRACE,
689                         "bdb_modrdn: can't figure out "
690                         "type(s)/values(s) of newrdn\n", 
691                         0, 0, 0 );
692 #endif
693                 rs->sr_err = LDAP_INVALID_DN_SYNTAX;
694                 rs->sr_text = "unknown type(s) used in RDN";
695                 goto return_results;
696         }
697
698 #ifdef NEW_LOGGING
699         LDAP_LOG ( OPERATION, RESULTS, 
700                 "bdb_modrdn: new_rdn_type=\"%s\", "
701                 "new_rdn_val=\"%s\"\n",
702                 new_rdn[ 0 ]->la_attr.bv_val, 
703                 new_rdn[ 0 ]->la_value.bv_val, 0 );
704 #else
705         Debug( LDAP_DEBUG_TRACE,
706                 "bdb_modrdn: new_rdn_type=\"%s\", "
707                 "new_rdn_val=\"%s\"\n",
708                 new_rdn[ 0 ]->la_attr.bv_val,
709                 new_rdn[ 0 ]->la_value.bv_val, 0 );
710 #endif
711
712         if ( op->oq_modrdn.rs_deleteoldrdn ) {
713                 if ( !old_rdn && ldap_bv2rdn_x( &op->o_req_dn, &old_rdn, (char **)&rs->sr_text,
714                         LDAP_DN_FORMAT_LDAP, op->o_tmpmemctx ) )
715                 {
716 #ifdef NEW_LOGGING
717                         LDAP_LOG ( OPERATION, ERR, 
718                                 "bdb_modrdn: can't figure out "
719                                 "type(s)/values(s) of old_rdn\n", 
720                                 0, 0, 0 );
721 #else
722                         Debug( LDAP_DEBUG_TRACE,
723                                 "bdb_modrdn: can't figure out "
724                                 "the old_rdn type(s)/value(s)\n", 
725                                 0, 0, 0 );
726 #endif
727                         rs->sr_err = LDAP_OTHER;
728                         rs->sr_text = "cannot parse RDN from old DN";
729                         goto return_results;            
730                 }
731         }
732
733         /* prepare modlist of modifications from old/new rdn */
734         if (!mod) {
735                 rs->sr_err = slap_modrdn2mods( op, rs, e, old_rdn, new_rdn, &mod );
736                 if ( rs->sr_err != LDAP_SUCCESS ) {
737                         goto return_results;
738                 }
739         }
740         
741         /* delete old one */
742         rs->sr_err = bdb_dn2id_delete( op->o_bd, ltid, p_ndn.bv_val, e );
743         if ( rs->sr_err != 0 ) {
744                 switch( rs->sr_err ) {
745                 case DB_LOCK_DEADLOCK:
746                 case DB_LOCK_NOTGRANTED:
747                         goto retry;
748                 }
749                 rs->sr_err = LDAP_OTHER;
750                 rs->sr_text = "DN index delete fail";
751                 goto return_results;
752         }
753
754         (void) bdb_cache_delete_entry(&bdb->bi_cache, e);
755
756         /* Binary format uses a single contiguous block, cannot
757          * free individual fields. But if a previous modrdn has
758          * already happened, must free the names.
759          */
760 #ifdef BDB_HIER
761         ch_free(e->e_name.bv_val);
762         e->e_name.bv_val = ch_malloc(new_dn.bv_len + new_ndn.bv_len + 2);
763         e->e_name.bv_len = new_dn.bv_len;
764         e->e_nname.bv_val = e->e_name.bv_val + new_dn.bv_len + 1;
765         e->e_nname.bv_len = new_ndn.bv_len;
766         strcpy(e->e_name.bv_val, new_dn.bv_val);
767         strcpy(e->e_nname.bv_val, new_ndn.bv_val);
768 #else
769         if( e->e_nname.bv_val < e->e_bv.bv_val || e->e_nname.bv_val >
770                 e->e_bv.bv_val + e->e_bv.bv_len ) {
771                 ch_free(e->e_name.bv_val);
772                 ch_free(e->e_nname.bv_val);
773                 e->e_name.bv_val = NULL;
774                 e->e_nname.bv_val = NULL;
775         }
776         e->e_name = new_dn;
777         e->e_nname = new_ndn;
778         new_dn.bv_val = NULL;
779         new_ndn.bv_val = NULL;
780 #endif
781         /* add new one */
782         rs->sr_err = bdb_dn2id_add( op->o_bd, ltid, np_ndn, e );
783         if ( rs->sr_err != 0 ) {
784                 switch( rs->sr_err ) {
785                 case DB_LOCK_DEADLOCK:
786                 case DB_LOCK_NOTGRANTED:
787                         goto retry;
788                 }
789                 rs->sr_err = LDAP_OTHER;
790                 rs->sr_text = "DN index add failed";
791                 goto return_results;
792         }
793
794 #if defined(LDAP_CLIENT_UPDATE) || defined(LDAP_SYNC)
795         if ( rs->sr_err == LDAP_SUCCESS && !op->o_noop ) {
796                 LDAP_LIST_FOREACH ( ps_list, &bdb->bi_psearch_list, o_ps_link ) {
797                         bdb_psearch( op, rs, ps_list, e, LDAP_PSEARCH_BY_PREMODIFY );
798                 }
799         }
800 #endif
801
802         /* modify entry */
803         rs->sr_err = bdb_modify_internal( op, ltid, &mod[0], e,
804                 &rs->sr_text, textbuf, textlen );
805
806         if( rs->sr_err != LDAP_SUCCESS ) {
807                 if ( ( rs->sr_err == LDAP_INSUFFICIENT_ACCESS ) && opinfo.boi_err ) {
808                         rs->sr_err = opinfo.boi_err;
809                 }
810                 switch( rs->sr_err ) {
811                 case DB_LOCK_DEADLOCK:
812                 case DB_LOCK_NOTGRANTED:
813                         goto retry;
814                 }
815                 goto return_results;
816         }
817         
818         /* id2entry index */
819         rs->sr_err = bdb_id2entry_update( op->o_bd, ltid, e );
820         if ( rs->sr_err != 0 ) {
821                 switch( rs->sr_err ) {
822                 case DB_LOCK_DEADLOCK:
823                 case DB_LOCK_NOTGRANTED:
824                         goto retry;
825                 }
826                 rs->sr_err = LDAP_OTHER;
827                 rs->sr_text = "entry update failed";
828                 goto return_results;
829         }
830
831         if( op->o_noop ) {
832                 if(( rs->sr_err=TXN_ABORT( ltid )) != 0 ) {
833                         rs->sr_text = "txn_abort (no-op) failed";
834                 } else {
835                         noop = 1;
836                         rs->sr_err = LDAP_SUCCESS;
837                 }
838
839         } else {
840                 char gid[DB_XIDDATASIZE];
841
842                 snprintf( gid, sizeof( gid ), "%s-%08lx-%08lx",
843                         bdb_uuid.bv_val, (long) op->o_connid, (long) op->o_opid );
844
845                 if(( rs->sr_err=TXN_PREPARE( ltid, gid )) != 0 ) {
846                         rs->sr_text = "txn_prepare failed";
847                 } else {
848                         if( bdb_cache_update_entry(&bdb->bi_cache, e) == -1 ) {
849                                 if(( rs->sr_err=TXN_ABORT( ltid )) != 0 ) {
850                                         rs->sr_text ="cache update & txn_abort failed";
851                                 } else {
852                                         rs->sr_err = LDAP_OTHER;
853                                         rs->sr_text = "cache update failed";
854                                 }
855
856                         } else {
857                                 bdb_cache_entry_commit( e );
858                                 if(( rs->sr_err=TXN_COMMIT( ltid, 0 )) != 0 ) {
859                                         rs->sr_text = "txn_commit failed";
860                                 } else {
861                                         rs->sr_err = LDAP_SUCCESS;
862                                 }
863                         }
864                 }
865         }
866  
867         ltid = NULL;
868         op->o_private = NULL;
869  
870         if( rs->sr_err == LDAP_SUCCESS ) {
871 #ifdef NEW_LOGGING
872                 LDAP_LOG ( OPERATION, RESULTS, 
873                         "bdb_modrdn: rdn modified%s id=%08lx dn=\"%s\"\n", 
874                         op->o_noop ? " (no-op)" : "", e->e_id, e->e_dn );
875 #else
876                 Debug(LDAP_DEBUG_TRACE,
877                         "bdb_modrdn: rdn modified%s id=%08lx dn=\"%s\"\n",
878                         op->o_noop ? " (no-op)" : "", e->e_id, e->e_dn );
879 #endif
880                 rs->sr_text = NULL;
881         } else {
882 #ifdef NEW_LOGGING
883                 LDAP_LOG ( OPERATION, RESULTS, "bdb_modrdn: %s : %s (%d)\n", 
884                         rs->sr_text, db_strerror(rs->sr_err), rs->sr_err );
885 #else
886                 Debug( LDAP_DEBUG_TRACE, "bdb_add: %s : %s (%d)\n",
887                         rs->sr_text, db_strerror(rs->sr_err), rs->sr_err );
888 #endif
889                 rs->sr_err = LDAP_OTHER;
890         }
891
892 return_results:
893         send_ldap_result( op, rs );
894
895 #if defined(LDAP_CLIENT_UPDATE) || defined(LDAP_SYNC)
896         if ( rs->sr_err == LDAP_SUCCESS && !op->o_noop ) {
897                 /* Loop through in-scope entries for each psearch spec */
898                 LDAP_LIST_FOREACH ( ps_list, &bdb->bi_psearch_list, o_ps_link ) {
899                         bdb_psearch( op, rs, ps_list, e, LDAP_PSEARCH_BY_MODIFY );
900                 }
901                 pm_list = LDAP_LIST_FIRST(&op->o_pm_list);
902                 while ( pm_list != NULL ) {
903                         bdb_psearch(op, rs, pm_list->ps_op,
904                                                 e, LDAP_PSEARCH_BY_SCOPEOUT);
905                         pm_prev = pm_list;
906                         LDAP_LIST_REMOVE ( pm_list, ps_link );
907                         pm_list = LDAP_LIST_NEXT ( pm_list, ps_link );
908                         ch_free( pm_prev );
909                 }
910         }
911 #endif
912
913         if( rs->sr_err == LDAP_SUCCESS && bdb->bi_txn_cp ) {
914                 ldap_pvt_thread_yield();
915                 TXN_CHECKPOINT( bdb->bi_dbenv,
916                         bdb->bi_txn_cp_kbyte, bdb->bi_txn_cp_min, 0 );
917         }
918
919 done:
920         if( new_dn.bv_val != NULL ) free( new_dn.bv_val );
921         if( new_ndn.bv_val != NULL ) free( new_ndn.bv_val );
922
923         /* LDAP v2 supporting correct attribute handling. */
924         if ( new_rdn != NULL ) {
925                 ldap_rdnfree( new_rdn );
926         }
927         if ( old_rdn != NULL ) {
928                 ldap_rdnfree( old_rdn );
929         }
930         if( mod != NULL ) {
931                 Modifications *tmp;
932                 for (; mod; mod=tmp ) {
933                         tmp = mod->sml_next;
934                         if ( mod->sml_nvalues ) free( mod->sml_nvalues[0].bv_val );
935                         free( mod );
936                 }
937         }
938
939         /* LDAP v3 Support */
940         if( np != NULL ) {
941                 /* free new parent and reader lock */
942                 bdb_unlocked_cache_return_entry_r(&bdb->bi_cache, np);
943         }
944
945         if( p != NULL ) {
946                 /* free parent and reader lock */
947                 bdb_unlocked_cache_return_entry_r(&bdb->bi_cache, p);
948         }
949
950         /* free entry */
951         if( e != NULL ) {
952                 bdb_unlocked_cache_return_entry_w( &bdb->bi_cache, e);
953         }
954
955         if( ltid != NULL ) {
956 #if defined(LDAP_CLIENT_UPDATE) || defined(LDAP_SYNC)
957                 pm_list = LDAP_LIST_FIRST(&op->o_pm_list);
958                 while ( pm_list != NULL ) {
959                         LDAP_LIST_REMOVE ( pm_list, ps_link );
960                         pm_prev = pm_list;
961                         pm_list = LDAP_LIST_NEXT ( pm_list, ps_link );
962                         ch_free( pm_prev );
963                 }
964 #endif
965                 TXN_ABORT( ltid );
966                 op->o_private = NULL;
967         }
968
969         return ( ( rs->sr_err == LDAP_SUCCESS ) ? noop : rs->sr_err );
970 }