]> git.sur5r.net Git - openldap/blob - servers/slapd/back-bdb/modrdn.c
using write lock in accessing pslist
[openldap] / servers / slapd / back-bdb / modrdn.c
1 /* modrdn.c - bdb backend modrdn routine */
2 /* $OpenLDAP$ */
3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
4  *
5  * Copyright 2000-2004 The OpenLDAP Foundation.
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted only as authorized by the OpenLDAP
10  * Public License.
11  *
12  * A copy of this license is available in the file LICENSE in the
13  * top-level directory of the distribution or, alternatively, at
14  * <http://www.OpenLDAP.org/license.html>.
15  */
16
17 #include "portable.h"
18
19 #include <stdio.h>
20 #include <ac/string.h>
21
22 #include "back-bdb.h"
23 #include "external.h"
24
25 int
26 bdb_modrdn( Operation   *op, SlapReply *rs )
27 {
28         struct bdb_info *bdb = (struct bdb_info *) op->o_bd->be_private;
29         AttributeDescription *children = slap_schema.si_ad_children;
30         AttributeDescription *entry = slap_schema.si_ad_entry;
31         struct berval   p_dn, p_ndn;
32         struct berval   new_dn = {0, NULL}, new_ndn = {0, NULL};
33         int             isroot = -1;
34         Entry           *e = NULL;
35         Entry           *p = NULL;
36         EntryInfo       *ei = NULL, *eip = NULL, *nei = NULL, *neip = NULL;
37         /* LDAP v2 supporting correct attribute handling. */
38         LDAPRDN         new_rdn = NULL;
39         LDAPRDN         old_rdn = NULL;
40         char textbuf[SLAP_TEXT_BUFLEN];
41         size_t textlen = sizeof textbuf;
42         DB_TXN          *ltid = NULL, *lt2;
43         struct bdb_op_info opinfo;
44         Entry dummy, *save;
45
46         ID                      id;
47
48         Entry           *np = NULL;                     /* newSuperior Entry */
49         struct berval   *np_dn = NULL;                  /* newSuperior dn */
50         struct berval   *np_ndn = NULL;                 /* newSuperior ndn */
51         struct berval   *new_parent_dn = NULL;  /* np_dn, p_dn, or NULL */
52
53         /* Used to interface with bdb_modify_internal() */
54         Modifications   *mod = NULL;            /* Used to delete old rdn */
55
56         int             manageDSAit = get_manageDSAit( op );
57
58         u_int32_t       locker = 0;
59         DB_LOCK         lock, plock, nplock;
60
61         int             num_retries = 0;
62
63         LDAPControl *ctrls[SLAP_MAX_RESPONSE_CONTROLS];
64         int num_ctrls = 0;
65
66         Operation *ps_list;
67         struct psid_entry *pm_list, *pm_prev;
68         int     rc;
69         EntryInfo       *suffix_ei;
70         Entry           *ctxcsn_e;
71         int                     ctxcsn_added = 0;
72
73         int parent_is_glue = 0;
74         int parent_is_leaf = 0;
75
76 #ifdef NEW_LOGGING
77         LDAP_LOG ( OPERATION, ENTRY, "==>bdb_modrdn(%s,%s,%s)\n", 
78                 op->o_req_dn.bv_val,op->oq_modrdn.rs_newrdn.bv_val,
79                 op->oq_modrdn.rs_newSup ? op->oq_modrdn.rs_newSup->bv_val : "NULL" );
80 #else
81         Debug( LDAP_DEBUG_TRACE, "==>bdb_modrdn(%s,%s,%s)\n",
82                 op->o_req_dn.bv_val,op->oq_modrdn.rs_newrdn.bv_val,
83                 op->oq_modrdn.rs_newSup ? op->oq_modrdn.rs_newSup->bv_val : "NULL" );
84 #endif
85
86         if( 0 ) {
87 retry:  /* transaction retry */
88                 if (e != NULL) {
89                         bdb_unlocked_cache_return_entry_w(&bdb->bi_cache, e);
90                         e = NULL;
91                 }
92                 if (p != NULL) {
93                         bdb_unlocked_cache_return_entry_r(&bdb->bi_cache, p);
94                         p = NULL;
95                 }
96                 if (np != NULL) {
97                         bdb_unlocked_cache_return_entry_r(&bdb->bi_cache, np);
98                         np = NULL;
99                 }
100 #ifdef NEW_LOGGING
101                 LDAP_LOG ( OPERATION, DETAIL1, "==>bdb_modrdn: retrying...\n", 0, 0, 0);
102 #else
103                 Debug( LDAP_DEBUG_TRACE, "==>bdb_modrdn: retrying...\n", 0, 0, 0 );
104 #endif
105                 pm_list = LDAP_LIST_FIRST(&op->o_pm_list);
106                 while ( pm_list != NULL ) {
107                         LDAP_LIST_REMOVE ( pm_list, ps_link );
108                         pm_prev = pm_list;
109                         pm_list = LDAP_LIST_NEXT ( pm_list, ps_link );
110                         ch_free( pm_prev );
111                 }
112
113                 rs->sr_err = TXN_ABORT( ltid );
114                 ltid = NULL;
115                 op->o_private = NULL;
116                 op->o_do_not_cache = opinfo.boi_acl_cache;
117                 if( rs->sr_err != 0 ) {
118                         rs->sr_err = LDAP_OTHER;
119                         rs->sr_text = "internal error";
120                         goto return_results;
121                 }
122                 parent_is_glue = 0;
123                 parent_is_leaf = 0;
124                 ldap_pvt_thread_yield();
125                 bdb_trans_backoff( ++num_retries );
126         }
127
128         /* begin transaction */
129         rs->sr_err = TXN_BEGIN( bdb->bi_dbenv, NULL, &ltid, 
130                 bdb->bi_db_opflags );
131         rs->sr_text = NULL;
132         if( rs->sr_err != 0 ) {
133 #ifdef NEW_LOGGING
134                 LDAP_LOG ( OPERATION, ERR, 
135                         "==>bdb_modrdn: txn_begin failed: %s (%d)\n", 
136                         db_strerror(rs->sr_err), rs->sr_err, 0 );
137 #else
138                 Debug( LDAP_DEBUG_TRACE,
139                         "bdb_delete: txn_begin failed: %s (%d)\n",
140                         db_strerror(rs->sr_err), rs->sr_err, 0 );
141 #endif
142                 rs->sr_err = LDAP_OTHER;
143                 rs->sr_text = "internal error";
144                 goto return_results;
145         }
146
147         locker = TXN_ID ( ltid );
148
149         opinfo.boi_bdb = op->o_bd;
150         opinfo.boi_txn = ltid;
151         opinfo.boi_locker = locker;
152         opinfo.boi_err = 0;
153         opinfo.boi_acl_cache = op->o_do_not_cache;
154         op->o_private = &opinfo;
155
156         /* get entry */
157         rs->sr_err = bdb_dn2entry( op, ltid, &op->o_req_ndn, &ei, 1,
158                 locker, &lock );
159
160         switch( rs->sr_err ) {
161         case 0:
162         case DB_NOTFOUND:
163                 break;
164         case DB_LOCK_DEADLOCK:
165         case DB_LOCK_NOTGRANTED:
166                 goto retry;
167         case LDAP_BUSY:
168                 rs->sr_text = "ldap server busy";
169                 goto return_results;
170         default:
171                 rs->sr_err = LDAP_OTHER;
172                 rs->sr_text = "internal error";
173                 goto return_results;
174         }
175
176         e = ei->bei_e;
177         /* FIXME: dn2entry() should return non-glue entry */
178         if (( rs->sr_err == DB_NOTFOUND ) ||
179                 ( !manageDSAit && e && is_entry_glue( e )))
180         {
181                 if( e != NULL ) {
182                         rs->sr_matched = ch_strdup( e->e_dn );
183                         rs->sr_ref = is_entry_referral( e )
184                                 ? get_entry_referrals( op, e )
185                                 : NULL;
186                         bdb_unlocked_cache_return_entry_r( &bdb->bi_cache, e);
187                         e = NULL;
188
189                 } else {
190                         BerVarray deref = NULL;
191                         if ( !LDAP_STAILQ_EMPTY( &op->o_bd->be_syncinfo )) {
192                                 syncinfo_t *si;
193                                 LDAP_STAILQ_FOREACH( si, &op->o_bd->be_syncinfo, si_next ) {
194                                         struct berval tmpbv;
195                                         ber_dupbv( &tmpbv, &si->si_provideruri_bv[0] );
196                                         ber_bvarray_add( &deref, &tmpbv );
197                 }
198                         } else {
199                                 deref = default_referral;
200                         }
201                         rs->sr_ref = referral_rewrite( deref, NULL, &op->o_req_dn,
202                                 LDAP_SCOPE_DEFAULT );
203                 }
204
205                 rs->sr_err = LDAP_REFERRAL;
206                 send_ldap_result( op, rs );
207
208                 ber_bvarray_free( rs->sr_ref );
209                 free( (char *)rs->sr_matched );
210                 rs->sr_ref = NULL;
211                 rs->sr_matched = NULL;
212
213                 goto done;
214         }
215
216         if ( get_assert( op ) &&
217                 ( test_filter( op, e, get_assertion( op )) != LDAP_COMPARE_TRUE ))
218         {
219                 rs->sr_err = LDAP_ASSERTION_FAILED;
220                 goto return_results;
221         }
222
223         /* check write on old entry */
224         rs->sr_err = access_allowed( op, e, entry, NULL, ACL_WRITE, NULL );
225         if ( ! rs->sr_err ) {
226                 switch( opinfo.boi_err ) {
227                 case DB_LOCK_DEADLOCK:
228                 case DB_LOCK_NOTGRANTED:
229                         goto retry;
230                 }
231
232 #ifdef NEW_LOGGING
233                 LDAP_LOG ( OPERATION, ERR, 
234                         "==>bdb_modrdn: no access to entry\n", 0, 0, 0 );
235 #else
236                 Debug( LDAP_DEBUG_TRACE, "no access to entry\n", 0,
237                         0, 0 );
238 #endif
239                 rs->sr_text = "no write access to old entry";
240                 rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
241                 goto return_results;
242         }
243
244 #ifndef BDB_HIER
245         rs->sr_err = bdb_cache_children( op, ltid, e );
246         if ( rs->sr_err != DB_NOTFOUND ) {
247                 switch( rs->sr_err ) {
248                 case DB_LOCK_DEADLOCK:
249                 case DB_LOCK_NOTGRANTED:
250                         goto retry;
251                 case 0:
252 #ifdef NEW_LOGGING
253                         LDAP_LOG ( OPERATION, DETAIL1, 
254                                 "<=- bdb_modrdn: non-leaf %s\n", op->o_req_dn.bv_val, 0, 0 );
255 #else
256                         Debug(LDAP_DEBUG_ARGS,
257                                 "<=- bdb_modrdn: non-leaf %s\n",
258                                 op->o_req_dn.bv_val, 0, 0);
259 #endif
260                         rs->sr_err = LDAP_NOT_ALLOWED_ON_NONLEAF;
261                         rs->sr_text = "subtree rename not supported";
262                         break;
263                 default:
264 #ifdef NEW_LOGGING
265                         LDAP_LOG ( OPERATION, ERR, 
266                                 "<=- bdb_modrdn: has_children failed %s (%d)\n",
267                                 db_strerror(rs->sr_err), rs->sr_err, 0 );
268 #else
269                         Debug(LDAP_DEBUG_ARGS,
270                                 "<=- bdb_modrdn: has_children failed: %s (%d)\n",
271                                 db_strerror(rs->sr_err), rs->sr_err, 0 );
272 #endif
273                         rs->sr_err = LDAP_OTHER;
274                         rs->sr_text = "internal error";
275                 }
276                 goto return_results;
277         }
278         ei->bei_state |= CACHE_ENTRY_NO_KIDS;
279 #endif
280
281         if (!manageDSAit && is_entry_referral( e ) ) {
282                 /* parent is a referral, don't allow add */
283                 rs->sr_ref = get_entry_referrals( op, e );
284
285 #ifdef NEW_LOGGING
286                 LDAP_LOG ( OPERATION, DETAIL1, 
287                         "==>bdb_modrdn: entry %s is referral \n", e->e_dn, 0, 0 );
288 #else
289                 Debug( LDAP_DEBUG_TRACE, "bdb_modrdn: entry %s is referral\n",
290                         e->e_dn, 0, 0 );
291 #endif
292
293                 rs->sr_err = LDAP_REFERRAL,
294                 rs->sr_matched = e->e_name.bv_val;
295                 send_ldap_result( op, rs );
296
297                 ber_bvarray_free( rs->sr_ref );
298                 rs->sr_ref = NULL;
299                 rs->sr_matched = NULL;
300                 goto done;
301         }
302
303         if ( be_issuffix( op->o_bd, &e->e_nname ) ) {
304                 p_ndn = slap_empty_bv;
305         } else {
306                 dnParent( &e->e_nname, &p_ndn );
307         }
308         np_ndn = &p_ndn;
309         if ( p_ndn.bv_len != 0 ) {
310                 /* Make sure parent entry exist and we can write its 
311                  * children.
312                  */
313                 eip = ei->bei_parent;
314                 rs->sr_err = bdb_cache_find_id( op, ltid,
315                         eip->bei_id, &eip, 0, locker, &plock );
316
317                 switch( rs->sr_err ) {
318                 case 0:
319                 case DB_NOTFOUND:
320                         break;
321                 case DB_LOCK_DEADLOCK:
322                 case DB_LOCK_NOTGRANTED:
323                         goto retry;
324                 case LDAP_BUSY:
325                         rs->sr_text = "ldap server busy";
326                         goto return_results;
327                 default:
328                         rs->sr_err = LDAP_OTHER;
329                         rs->sr_text = "internal error";
330                         goto return_results;
331                 }
332
333                 p = eip->bei_e;
334                 if( p == NULL) {
335 #ifdef NEW_LOGGING
336                         LDAP_LOG ( OPERATION, ERR, 
337                                 "==>bdb_modrdn: parent does not exist\n", 0, 0, 0 );
338 #else
339                         Debug( LDAP_DEBUG_TRACE, "bdb_modrdn: parent does not exist\n",
340                                 0, 0, 0);
341 #endif
342                         rs->sr_err = LDAP_OTHER;
343                         rs->sr_text = "old entry's parent does not exist";
344                         goto return_results;
345                 }
346
347                 /* check parent for "children" acl */
348                 rs->sr_err = access_allowed( op, p,
349                         children, NULL, ACL_WRITE, NULL );
350
351                 if ( ! rs->sr_err ) {
352                         switch( opinfo.boi_err ) {
353                         case DB_LOCK_DEADLOCK:
354                         case DB_LOCK_NOTGRANTED:
355                                 goto retry;
356                         }
357
358                         rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
359 #ifdef NEW_LOGGING
360                         LDAP_LOG ( OPERATION, ERR, 
361                                 "==>bdb_modrdn: no access to parent\n", 0, 0, 0 );
362 #else
363                         Debug( LDAP_DEBUG_TRACE, "no access to parent\n", 0,
364                                 0, 0 );
365 #endif
366                         rs->sr_text = "no write access to old parent's children";
367                         goto return_results;
368                 }
369
370 #ifdef NEW_LOGGING
371                 LDAP_LOG ( OPERATION, DETAIL1, 
372                         "==>bdb_modrdn: wr to children %s is OK\n", p_ndn.bv_val, 0, 0 );
373 #else
374                 Debug( LDAP_DEBUG_TRACE,
375                         "bdb_modrdn: wr to children of entry %s OK\n",
376                         p_ndn.bv_val, 0, 0 );
377 #endif
378                 
379                 if ( p_ndn.bv_val == slap_empty_bv.bv_val ) {
380                         p_dn = slap_empty_bv;
381                 } else {
382                         dnParent( &e->e_name, &p_dn );
383                 }
384
385 #ifdef NEW_LOGGING
386                 LDAP_LOG ( OPERATION, DETAIL1, 
387                         "==>bdb_modrdn: parent dn=%s\n", p_dn.bv_val, 0, 0 );
388 #else
389                 Debug( LDAP_DEBUG_TRACE,
390                         "bdb_modrdn: parent dn=%s\n",
391                         p_dn.bv_val, 0, 0 );
392 #endif
393
394         } else {
395                 /* no parent, modrdn entry directly under root */
396                 isroot = be_isroot( op );
397                 if ( ! isroot ) {
398                         if ( be_issuffix( op->o_bd, (struct berval *)&slap_empty_bv )
399                                 || be_shadow_update( op ) ) {
400
401                                 p = (Entry *)&slap_entry_root;
402
403                                 /* check parent for "children" acl */
404                                 rs->sr_err = access_allowed( op, p,
405                                         children, NULL, ACL_WRITE, NULL );
406
407                                 p = NULL;
408
409                                 if ( ! rs->sr_err ) {
410                                         switch( opinfo.boi_err ) {
411                                         case DB_LOCK_DEADLOCK:
412                                         case DB_LOCK_NOTGRANTED:
413                                                 goto retry;
414                                         }
415
416                                         rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
417 #ifdef NEW_LOGGING
418                                         LDAP_LOG ( OPERATION, ERR, 
419                                                 "==>bdb_modrdn: no access to parent\n", 0, 0, 0 );
420 #else
421                                         Debug( LDAP_DEBUG_TRACE, 
422                                                 "no access to parent\n", 
423                                                 0, 0, 0 );
424 #endif
425                                         rs->sr_text = "no write access to old parent";
426                                         goto return_results;
427                                 }
428
429 #ifdef NEW_LOGGING
430                                 LDAP_LOG ( OPERATION, DETAIL1, 
431                                         "==>bdb_modrdn: wr to children of entry \"%s\" OK\n", 
432                                         p_dn.bv_val, 0, 0 );
433 #else
434                                 Debug( LDAP_DEBUG_TRACE,
435                                         "bdb_modrdn: wr to children of entry \"\" OK\n",
436                                         0, 0, 0 );
437 #endif
438                 
439                                 p_dn.bv_val = "";
440                                 p_dn.bv_len = 0;
441
442 #ifdef NEW_LOGGING
443                                 LDAP_LOG ( OPERATION, DETAIL1, 
444                                         "==>bdb_modrdn: parent dn=\"\" \n", 0, 0, 0 );
445 #else
446                                 Debug( LDAP_DEBUG_TRACE,
447                                         "bdb_modrdn: parent dn=\"\"\n",
448                                         0, 0, 0 );
449 #endif
450
451                         } else {
452 #ifdef NEW_LOGGING
453                                 LDAP_LOG ( OPERATION, ERR, 
454                                         "==>bdb_modrdn: no parent, not root &\"\" is not "
455                                         "suffix\n", 0, 0, 0 );
456 #else
457                                 Debug( LDAP_DEBUG_TRACE,
458                                         "bdb_modrdn: no parent, not root "
459                                         "& \"\" is not suffix\n",
460                                         0, 0, 0);
461 #endif
462                                 rs->sr_text = "no write access to old parent";
463                                 rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
464                                 goto return_results;
465                         }
466                 }
467         }
468
469         new_parent_dn = &p_dn;  /* New Parent unless newSuperior given */
470
471         if ( op->oq_modrdn.rs_newSup != NULL ) {
472 #ifdef NEW_LOGGING
473                 LDAP_LOG ( OPERATION, DETAIL1, 
474                         "==>bdb_modrdn: new parent \"%s\" requested...\n", 
475                         op->oq_modrdn.rs_newSup->bv_val, 0, 0 );
476 #else
477                 Debug( LDAP_DEBUG_TRACE, 
478                         "bdb_modrdn: new parent \"%s\" requested...\n",
479                         op->oq_modrdn.rs_newSup->bv_val, 0, 0 );
480 #endif
481
482                 /*  newSuperior == oldParent? */
483                 if( dn_match( &p_ndn, op->oq_modrdn.rs_nnewSup ) ) {
484 #ifdef NEW_LOGGING
485                         LDAP_LOG( BACK_BDB, INFO, "bdb_back_modrdn: "
486                                 "new parent \"%s\" same as the old parent \"%s\"\n",
487                                 op->oq_modrdn.rs_newSup->bv_val, p_dn.bv_val, 0 );
488 #else
489                         Debug( LDAP_DEBUG_TRACE, "bdb_back_modrdn: "
490                                 "new parent \"%s\" same as the old parent \"%s\"\n",
491                                 op->oq_modrdn.rs_newSup->bv_val, p_dn.bv_val, 0 );
492 #endif      
493                         op->oq_modrdn.rs_newSup = NULL; /* ignore newSuperior */
494                 }
495         }
496
497         if ( op->oq_modrdn.rs_newSup != NULL ) {
498                 if ( op->oq_modrdn.rs_newSup->bv_len ) {
499                         np_dn = op->oq_modrdn.rs_newSup;
500                         np_ndn = op->oq_modrdn.rs_nnewSup;
501
502                         /* newSuperior == oldParent?, if so ==> ERROR */
503                         /* newSuperior == entry being moved?, if so ==> ERROR */
504                         /* Get Entry with dn=newSuperior. Does newSuperior exist? */
505
506                         rs->sr_err = bdb_dn2entry( op, ltid, np_ndn,
507                                 &neip, 0, locker, &nplock );
508
509                         switch( rs->sr_err ) {
510                         case 0: np = neip->bei_e;
511                         case DB_NOTFOUND:
512                                 break;
513                         case DB_LOCK_DEADLOCK:
514                         case DB_LOCK_NOTGRANTED:
515                                 goto retry;
516                         case LDAP_BUSY:
517                                 rs->sr_text = "ldap server busy";
518                                 goto return_results;
519                         default:
520                                 rs->sr_err = LDAP_OTHER;
521                                 rs->sr_text = "internal error";
522                                 goto return_results;
523                         }
524
525                         if( np == NULL) {
526 #ifdef NEW_LOGGING
527                                 LDAP_LOG ( OPERATION, DETAIL1, 
528                                         "==>bdb_modrdn: newSup(ndn=%s) not here!\n", 
529                                         np_ndn->bv_val, 0, 0 );
530 #else
531                                 Debug( LDAP_DEBUG_TRACE,
532                                         "bdb_modrdn: newSup(ndn=%s) not here!\n",
533                                         np_ndn->bv_val, 0, 0);
534 #endif
535                                 rs->sr_text = "new superior not found";
536                                 rs->sr_err = LDAP_OTHER;
537                                 goto return_results;
538                         }
539
540 #ifdef NEW_LOGGING
541                         LDAP_LOG ( OPERATION, DETAIL1, 
542                                 "==>bdb_modrdn: wr to new parent OK np=%p, id=%ld\n", 
543                                 (void *) np, (long) np->e_id, 0 );
544 #else
545                         Debug( LDAP_DEBUG_TRACE,
546                                 "bdb_modrdn: wr to new parent OK np=%p, id=%ld\n",
547                                 (void *) np, (long) np->e_id, 0 );
548 #endif
549
550                         /* check newSuperior for "children" acl */
551                         rs->sr_err = access_allowed( op, np, children,
552                                 NULL, ACL_WRITE, NULL );
553
554                         if( ! rs->sr_err ) {
555                                 switch( opinfo.boi_err ) {
556                                 case DB_LOCK_DEADLOCK:
557                                 case DB_LOCK_NOTGRANTED:
558                                         goto retry;
559                                 }
560
561 #ifdef NEW_LOGGING
562                                 LDAP_LOG ( OPERATION, DETAIL1, 
563                                         "==>bdb_modrdn: no wr to newSup children\n", 0, 0, 0 );
564 #else
565                                 Debug( LDAP_DEBUG_TRACE,
566                                         "bdb_modrdn: no wr to newSup children\n",
567                                         0, 0, 0 );
568 #endif
569                                 rs->sr_text = "no write access to new superior's children";
570                                 rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
571                                 goto return_results;
572                         }
573
574 #ifdef BDB_ALIASES
575                         if ( is_entry_alias( np ) ) {
576                                 /* parent is an alias, don't allow add */
577 #ifdef NEW_LOGGING
578                                 LDAP_LOG ( OPERATION, DETAIL1, 
579                                         "==>bdb_modrdn: entry is alias\n", 0, 0, 0 );
580 #else
581                                 Debug( LDAP_DEBUG_TRACE, "bdb_modrdn: entry is alias\n",
582                                         0, 0, 0 );
583 #endif
584                                 rs->sr_text = "new superior is an alias";
585                                 rs->sr_err = LDAP_ALIAS_PROBLEM;
586                                 goto return_results;
587                         }
588 #endif
589
590                         if ( is_entry_referral( np ) ) {
591                                 /* parent is a referral, don't allow add */
592 #ifdef NEW_LOGGING
593                                 LDAP_LOG ( OPERATION, DETAIL1, 
594                                         "==>bdb_modrdn: entry is referral\n", 0, 0, 0 );
595 #else
596                                 Debug( LDAP_DEBUG_TRACE, "bdb_modrdn: entry is referral\n",
597                                         0, 0, 0 );
598 #endif
599                                 rs->sr_text = "new superior is a referral";
600                                 rs->sr_err = LDAP_OTHER;
601                                 goto return_results;
602                         }
603
604                 } else {
605                         if ( isroot == -1 ) {
606                                 isroot = be_isroot( op );
607                         }
608                         
609                         np_dn = NULL;
610
611                         /* no parent, modrdn entry directly under root */
612                         if ( ! isroot ) {
613                                 if ( be_issuffix( op->o_bd, (struct berval *)&slap_empty_bv )
614                                         || be_isupdate( op ) ) {
615                                         np = (Entry *)&slap_entry_root;
616
617                                         /* check parent for "children" acl */
618                                         rs->sr_err = access_allowed( op, np,
619                                                 children, NULL, ACL_WRITE, NULL );
620
621                                         np = NULL;
622
623                                         if ( ! rs->sr_err ) {
624                                                 switch( opinfo.boi_err ) {
625                                                 case DB_LOCK_DEADLOCK:
626                                                 case DB_LOCK_NOTGRANTED:
627                                                         goto retry;
628                                                 }
629
630                                                 rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
631 #ifdef NEW_LOGGING
632                                                 LDAP_LOG ( OPERATION, ERR, 
633                                                         "==>bdb_modrdn: no access to superior\n", 0, 0, 0 );
634 #else
635                                                 Debug( LDAP_DEBUG_TRACE, 
636                                                         "no access to new superior\n", 
637                                                         0, 0, 0 );
638 #endif
639                                                 rs->sr_text =
640                                                         "no write access to new superior's children";
641                                                 goto return_results;
642                                         }
643
644 #ifdef NEW_LOGGING
645                                         LDAP_LOG ( OPERATION, DETAIL1, 
646                                                 "bdb_modrdn: wr to children entry \"\" OK\n", 0, 0, 0 );
647 #else
648                                         Debug( LDAP_DEBUG_TRACE,
649                                                 "bdb_modrdn: wr to children of entry \"\" OK\n",
650                                                 0, 0, 0 );
651 #endif
652                 
653                                 } else {
654 #ifdef NEW_LOGGING
655                                         LDAP_LOG ( OPERATION, ERR, 
656                                                 "bdb_modrdn: new superior=\"\", not root & \"\" "
657                                                 "is not suffix\n", 0, 0, 0 );
658 #else
659                                         Debug( LDAP_DEBUG_TRACE,
660                                                 "bdb_modrdn: new superior=\"\", not root "
661                                                 "& \"\" is not suffix\n",
662                                                 0, 0, 0);
663 #endif
664                                         rs->sr_text = "no write access to new superior's children";
665                                         rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
666                                         goto return_results;
667                                 }
668                         }
669
670 #ifdef NEW_LOGGING
671                         LDAP_LOG ( OPERATION, DETAIL1, 
672                                 "bdb_modrdn: new superior=\"\"\n", 0, 0, 0 );
673 #else
674                         Debug( LDAP_DEBUG_TRACE,
675                                 "bdb_modrdn: new superior=\"\"\n",
676                                 0, 0, 0 );
677 #endif
678                 }
679
680 #ifdef NEW_LOGGING
681                 LDAP_LOG ( OPERATION, DETAIL1, 
682                         "bdb_modrdn: wr to new parent's children OK\n", 0, 0, 0 );
683 #else
684                 Debug( LDAP_DEBUG_TRACE,
685                         "bdb_modrdn: wr to new parent's children OK\n",
686                         0, 0, 0 );
687 #endif
688
689                 new_parent_dn = np_dn;
690         }
691
692         /* Build target dn and make sure target entry doesn't exist already. */
693         if (!new_dn.bv_val) {
694                 build_new_dn( &new_dn, new_parent_dn, &op->oq_modrdn.rs_newrdn, NULL ); 
695         }
696
697         if (!new_ndn.bv_val) {
698                 struct berval bv = {0, NULL};
699                 dnNormalize( 0, NULL, NULL, &new_dn, &bv, op->o_tmpmemctx );
700                 ber_dupbv( &new_ndn, &bv );
701         }
702
703 #ifdef NEW_LOGGING
704         LDAP_LOG ( OPERATION, RESULTS, 
705                 "bdb_modrdn: new ndn=%s\n", new_ndn.bv_val, 0, 0 );
706 #else
707         Debug( LDAP_DEBUG_TRACE, "bdb_modrdn: new ndn=%s\n",
708                 new_ndn.bv_val, 0, 0 );
709 #endif
710
711         /* Shortcut the search */
712         nei = neip ? neip : eip;
713         rs->sr_err = bdb_cache_find_ndn ( op, ltid, &new_ndn, &nei );
714         if ( nei ) bdb_cache_entryinfo_unlock( nei );
715         switch( rs->sr_err ) {
716         case DB_LOCK_DEADLOCK:
717         case DB_LOCK_NOTGRANTED:
718                 goto retry;
719         case DB_NOTFOUND:
720                 break;
721         case 0:
722                 rs->sr_err = LDAP_ALREADY_EXISTS;
723                 goto return_results;
724         default:
725                 rs->sr_err = LDAP_OTHER;
726                 rs->sr_text = "internal error";
727                 goto return_results;
728         }
729
730         /* Get attribute type and attribute value of our new rdn, we will
731          * need to add that to our new entry
732          */
733         if ( !new_rdn && ldap_bv2rdn_x( &op->oq_modrdn.rs_newrdn, &new_rdn,
734                 (char **)&rs->sr_text, LDAP_DN_FORMAT_LDAP, op->o_tmpmemctx ) )
735         {
736 #ifdef NEW_LOGGING
737                 LDAP_LOG ( OPERATION, ERR, 
738                         "bdb_modrdn: can't figure out "
739                         "type(s)/values(s) of newrdn\n", 
740                         0, 0, 0 );
741 #else
742                 Debug( LDAP_DEBUG_TRACE,
743                         "bdb_modrdn: can't figure out "
744                         "type(s)/values(s) of newrdn\n", 
745                         0, 0, 0 );
746 #endif
747                 rs->sr_err = LDAP_INVALID_DN_SYNTAX;
748                 rs->sr_text = "unknown type(s) used in RDN";
749                 goto return_results;
750         }
751
752 #ifdef NEW_LOGGING
753         LDAP_LOG ( OPERATION, RESULTS, 
754                 "bdb_modrdn: new_rdn_type=\"%s\", new_rdn_val=\"%s\"\n",
755                 new_rdn[ 0 ]->la_attr.bv_val, new_rdn[ 0 ]->la_value.bv_val, 0 );
756 #else
757         Debug( LDAP_DEBUG_TRACE,
758                 "bdb_modrdn: new_rdn_type=\"%s\", new_rdn_val=\"%s\"\n",
759                 new_rdn[ 0 ]->la_attr.bv_val, new_rdn[ 0 ]->la_value.bv_val, 0 );
760 #endif
761
762         if ( op->oq_modrdn.rs_deleteoldrdn ) {
763                 if ( !old_rdn && ldap_bv2rdn_x( &op->o_req_dn, &old_rdn,
764                         (char **)&rs->sr_text, LDAP_DN_FORMAT_LDAP, op->o_tmpmemctx ) )
765                 {
766 #ifdef NEW_LOGGING
767                         LDAP_LOG ( OPERATION, ERR, 
768                                 "bdb_modrdn: can't figure out "
769                                 "type(s)/values(s) of old_rdn\n", 
770                                 0, 0, 0 );
771 #else
772                         Debug( LDAP_DEBUG_TRACE,
773                                 "bdb_modrdn: can't figure out "
774                                 "the old_rdn type(s)/value(s)\n", 
775                                 0, 0, 0 );
776 #endif
777                         rs->sr_err = LDAP_OTHER;
778                         rs->sr_text = "cannot parse RDN from old DN";
779                         goto return_results;            
780                 }
781         }
782
783         /* prepare modlist of modifications from old/new rdn */
784         if (!mod) {
785                 rs->sr_err = slap_modrdn2mods( op, rs, e, old_rdn, new_rdn, &mod );
786                 if ( rs->sr_err != LDAP_SUCCESS ) {
787                         goto return_results;
788                 }
789         }
790
791         if( op->o_preread ) {
792                 if( slap_read_controls( op, rs, e,
793                         &slap_pre_read_bv, &ctrls[num_ctrls] ) )
794                 {
795 #ifdef NEW_LOGGING                                   
796                         LDAP_LOG ( OPERATION, DETAIL1,
797                                 "<=- bdb_modrdn: post-read failed!\n", 0, 0, 0 );
798 #else
799                         Debug( LDAP_DEBUG_TRACE,        
800                                 "<=- bdb_modrdn: post-read failed!\n", 0, 0, 0 );
801 #endif
802                         goto return_results;
803                 }                   
804                 ctrls[++num_ctrls] = NULL;
805                 op->o_preread = 0;  /* prevent redo on retry */
806         }
807
808         /* nested transaction */
809         rs->sr_err = TXN_BEGIN( bdb->bi_dbenv, ltid, &lt2, bdb->bi_db_opflags );
810         rs->sr_text = NULL;
811         if( rs->sr_err != 0 ) {
812 #ifdef NEW_LOGGING
813                 LDAP_LOG ( OPERATION, ERR, 
814                         "bdb_modrdn: txn_begin(2) failed: %s (%d)\n",
815                         db_strerror(rs->sr_err), rs->sr_err, 0 );
816 #else
817                 Debug( LDAP_DEBUG_TRACE,
818                         "bdb_modrdn: txn_begin(2) failed: %s (%d)\n",
819                         db_strerror(rs->sr_err), rs->sr_err, 0 );
820 #endif
821                 rs->sr_err = LDAP_OTHER;
822                 rs->sr_text = "internal error";
823                 goto return_results;
824         }
825
826         dummy = *e;
827         save = e;
828         e = &dummy;
829
830         /* delete old one */
831         rs->sr_err = bdb_dn2id_delete( op, lt2, eip, e );
832         if ( rs->sr_err != 0 ) {
833 #ifdef NEW_LOGGING
834                 LDAP_LOG ( OPERATION, ERR, 
835                         "<=- bdb_modrdn: dn2id del failed: %s (%d)\n",
836                         db_strerror(rs->sr_err), rs->sr_err, 0 );
837 #else
838                 Debug(LDAP_DEBUG_TRACE,
839                         "<=- bdb_modrdn: dn2id del failed: %s (%d)\n",
840                         db_strerror(rs->sr_err), rs->sr_err, 0 );
841 #endif
842                 switch( rs->sr_err ) {
843                 case DB_LOCK_DEADLOCK:
844                 case DB_LOCK_NOTGRANTED:
845                         goto retry;
846                 }
847                 rs->sr_err = LDAP_OTHER;
848                 rs->sr_text = "DN index delete fail";
849                 goto return_results;
850         }
851
852         /* Binary format uses a single contiguous block, cannot
853          * free individual fields. But if a previous modrdn has
854          * already happened, must free the names. The frees are
855          * done in bdb_cache_modrdn().
856          */
857         if( e->e_nname.bv_val < e->e_bv.bv_val ||
858                 e->e_nname.bv_val > e->e_bv.bv_val + e->e_bv.bv_len )
859         {
860                 e->e_name.bv_val = NULL;
861                 e->e_nname.bv_val = NULL;
862         }
863         e->e_name = new_dn;
864         e->e_nname = new_ndn;
865         new_dn.bv_val = NULL;
866         new_ndn.bv_val = NULL;
867
868         /* add new one */
869         rs->sr_err = bdb_dn2id_add( op, lt2, neip ? neip : eip, e );
870         if ( rs->sr_err != 0 ) {
871 #ifdef NEW_LOGGING
872                 LDAP_LOG ( OPERATION, ERR, 
873                         "<=- bdb_modrdn: dn2id add failed: %s (%d)\n",
874                         db_strerror(rs->sr_err), rs->sr_err, 0 );
875 #else
876                 Debug(LDAP_DEBUG_TRACE,
877                         "<=- bdb_modrdn: dn2id add failed: %s (%d)\n",
878                         db_strerror(rs->sr_err), rs->sr_err, 0 );
879 #endif
880                 switch( rs->sr_err ) {
881                 case DB_LOCK_DEADLOCK:
882                 case DB_LOCK_NOTGRANTED:
883                         goto retry;
884                 }
885                 rs->sr_err = LDAP_OTHER;
886                 rs->sr_text = "DN index add failed";
887                 goto return_results;
888         }
889
890         if ( rs->sr_err == LDAP_SUCCESS && !op->o_noop && !op->o_no_psearch ) {
891                 ldap_pvt_thread_rdwr_wlock( &bdb->bi_pslist_rwlock );
892                 LDAP_LIST_FOREACH ( ps_list, &bdb->bi_psearch_list, o_ps_link ) {
893                         bdb_psearch( op, rs, ps_list, e, LDAP_PSEARCH_BY_PREMODIFY );
894                 }
895                 ldap_pvt_thread_rdwr_wunlock( &bdb->bi_pslist_rwlock );
896         }
897
898         /* modify entry */
899         rs->sr_err = bdb_modify_internal( op, lt2, &mod[0], e,
900                 &rs->sr_text, textbuf, textlen );
901         if( rs->sr_err != LDAP_SUCCESS ) {
902 #ifdef NEW_LOGGING
903                 LDAP_LOG ( OPERATION, ERR, 
904                         "<=- bdb_modrdn: modify failed: %s (%d)\n",
905                         db_strerror(rs->sr_err), rs->sr_err, 0 );
906 #else
907                 Debug(LDAP_DEBUG_TRACE,
908                         "<=- bdb_modrdn: modify failed: %s (%d)\n",
909                         db_strerror(rs->sr_err), rs->sr_err, 0 );
910 #endif
911                 if ( ( rs->sr_err == LDAP_INSUFFICIENT_ACCESS ) && opinfo.boi_err ) {
912                         rs->sr_err = opinfo.boi_err;
913                 }
914                 switch( rs->sr_err ) {
915                 case DB_LOCK_DEADLOCK:
916                 case DB_LOCK_NOTGRANTED:
917                         goto retry;
918                 }
919                 goto return_results;
920         }
921
922         if( op->o_postread ) {
923                 if( slap_read_controls( op, rs, e,
924                         &slap_post_read_bv, &ctrls[num_ctrls] ) )
925                 {
926 #ifdef NEW_LOGGING                                   
927                         LDAP_LOG ( OPERATION, DETAIL1,
928                                 "<=- bdb_modrdn: post-read failed!\n", 0, 0, 0 );
929 #else
930                         Debug( LDAP_DEBUG_TRACE,        
931                                 "<=- bdb_modrdn: post-read failed!\n", 0, 0, 0 );
932 #endif
933                         goto return_results;
934                 }                   
935                 ctrls[++num_ctrls] = NULL;
936                 op->o_postread = 0;  /* prevent redo on retry */
937                 /* FIXME: should read entry on the last retry */
938         }
939
940         /* id2entry index */
941         rs->sr_err = bdb_id2entry_update( op->o_bd, lt2, e );
942         if ( rs->sr_err != 0 ) {
943 #ifdef NEW_LOGGING
944                 LDAP_LOG ( OPERATION, ERR, 
945                         "<=- bdb_modrdn: id2entry failed: %s (%d)\n",
946                         db_strerror(rs->sr_err), rs->sr_err, 0 );
947 #else
948                 Debug(LDAP_DEBUG_TRACE,
949                         "<=- bdb_modrdn: id2entry failed: %s (%d)\n",
950                         db_strerror(rs->sr_err), rs->sr_err, 0 );
951 #endif
952                 switch( rs->sr_err ) {
953                 case DB_LOCK_DEADLOCK:
954                 case DB_LOCK_NOTGRANTED:
955                         goto retry;
956                 }
957                 rs->sr_err = LDAP_OTHER;
958                 rs->sr_text = "entry update failed";
959                 goto return_results;
960         }
961
962         bdb_cache_find_id( op, lt2, eip->bei_id, &eip, 0, locker, &plock );
963     if ( eip ) p = eip->bei_e;
964     if ( p_ndn.bv_len != 0 ) {
965         parent_is_glue = is_entry_glue(p);
966         rs->sr_err = bdb_cache_children( op, lt2, p );
967         if ( rs->sr_err != DB_NOTFOUND ) {
968             switch( rs->sr_err ) {
969             case DB_LOCK_DEADLOCK:
970             case DB_LOCK_NOTGRANTED:
971                 goto retry;
972             case 0:
973                 break;
974             default:
975 #ifdef NEW_LOGGING
976                 LDAP_LOG ( OPERATION, ERR,
977                     "<=- bdb_modrdn: has_children failed %s (%d)\n",
978                     db_strerror(rs->sr_err), rs->sr_err, 0 );
979 #else
980                 Debug(LDAP_DEBUG_ARGS,
981                     "<=- bdb_modrdn: has_children failed: %s (%d)\n",
982                     db_strerror(rs->sr_err), rs->sr_err, 0 );
983 #endif
984                 rs->sr_err = LDAP_OTHER;
985                 rs->sr_text = "internal error";
986                 goto return_results;
987             }
988             parent_is_leaf = 1;
989         }
990         bdb_unlocked_cache_return_entry_r(&bdb->bi_cache, p);
991         p = NULL;
992     }
993
994         if ( TXN_COMMIT( lt2, 0 ) != 0 ) {
995                 rs->sr_err = LDAP_OTHER;
996                 rs->sr_text = "txn_commit(2) failed";
997                 goto return_results;
998         }
999
1000         if ( LDAP_STAILQ_EMPTY( &op->o_bd->be_syncinfo )) {
1001                 rc = bdb_csn_commit( op, rs, ltid, ei, &suffix_ei,
1002                         &ctxcsn_e, &ctxcsn_added, locker );
1003                 switch ( rc ) {
1004                 case BDB_CSN_ABORT :
1005                         goto return_results;
1006                 case BDB_CSN_RETRY :
1007                         goto retry;
1008                 }
1009         }
1010
1011         if( op->o_noop ) {
1012                 if(( rs->sr_err=TXN_ABORT( ltid )) != 0 ) {
1013                         rs->sr_text = "txn_abort (no-op) failed";
1014                 } else {
1015                         rs->sr_err = LDAP_SUCCESS;
1016                         goto return_results;
1017                 }
1018
1019         } else {
1020                 rc = bdb_cache_modrdn( save, &op->orr_nnewrdn, e, neip,
1021                         bdb->bi_dbenv, locker, &lock );
1022                 switch( rc ) {
1023                 case DB_LOCK_DEADLOCK:
1024                 case DB_LOCK_NOTGRANTED:
1025                         goto retry;
1026                 }
1027
1028                 if ( LDAP_STAILQ_EMPTY( &op->o_bd->be_syncinfo )) {
1029                         if ( ctxcsn_added ) {
1030                                 bdb_cache_add( bdb, suffix_ei, ctxcsn_e,
1031                                         (struct berval *)&slap_ldapsync_cn_bv, locker );
1032                         }
1033                 }
1034
1035                 if ( rs->sr_err == LDAP_SUCCESS ) {
1036                         /* Loop through in-scope entries for each psearch spec */
1037                         ldap_pvt_thread_rdwr_wlock( &bdb->bi_pslist_rwlock );
1038                         LDAP_LIST_FOREACH ( ps_list, &bdb->bi_psearch_list, o_ps_link ) {
1039                                 bdb_psearch( op, rs, ps_list, e, LDAP_PSEARCH_BY_MODIFY );
1040                         }
1041                         pm_list = LDAP_LIST_FIRST(&op->o_pm_list);
1042                         while ( pm_list != NULL ) {
1043                                 bdb_psearch(op, rs, pm_list->ps_op,
1044                                                         e, LDAP_PSEARCH_BY_SCOPEOUT);
1045                                 pm_prev = pm_list;
1046                                 LDAP_LIST_REMOVE ( pm_list, ps_link );
1047                                 pm_list = LDAP_LIST_NEXT ( pm_list, ps_link );
1048                                 ch_free( pm_prev );
1049                         }
1050                         ldap_pvt_thread_rdwr_wunlock( &bdb->bi_pslist_rwlock );
1051                 }
1052
1053                 if(( rs->sr_err=TXN_COMMIT( ltid, 0 )) != 0 ) {
1054                         rs->sr_text = "txn_commit failed";
1055                 } else {
1056                         rs->sr_err = LDAP_SUCCESS;
1057                 }
1058         }
1059  
1060         ltid = NULL;
1061         op->o_private = NULL;
1062  
1063         if( rs->sr_err != LDAP_SUCCESS ) {
1064 #ifdef NEW_LOGGING
1065                 LDAP_LOG ( OPERATION, RESULTS, "bdb_modrdn: %s : %s (%d)\n", 
1066                         rs->sr_text, db_strerror(rs->sr_err), rs->sr_err );
1067 #else
1068                 Debug( LDAP_DEBUG_TRACE, "bdb_add: %s : %s (%d)\n",
1069                         rs->sr_text, db_strerror(rs->sr_err), rs->sr_err );
1070 #endif
1071                 rs->sr_err = LDAP_OTHER;
1072
1073                 goto return_results;
1074         }
1075
1076 #ifdef NEW_LOGGING
1077         LDAP_LOG ( OPERATION, RESULTS, 
1078                 "bdb_modrdn: rdn modified%s id=%08lx dn=\"%s\"\n", 
1079                 op->o_noop ? " (no-op)" : "",
1080                 e->e_id, e->e_dn );
1081 #else
1082         Debug(LDAP_DEBUG_TRACE,
1083                 "bdb_modrdn: rdn modified%s id=%08lx dn=\"%s\"\n",
1084                 op->o_noop ? " (no-op)" : "",
1085                 e->e_id, e->e_dn );
1086 #endif
1087         rs->sr_text = NULL;
1088         if( num_ctrls ) rs->sr_ctrls = ctrls;
1089
1090 return_results:
1091         send_ldap_result( op, rs );
1092
1093         if( rs->sr_err == LDAP_SUCCESS && bdb->bi_txn_cp ) {
1094                 ldap_pvt_thread_yield();
1095                 TXN_CHECKPOINT( bdb->bi_dbenv,
1096                         bdb->bi_txn_cp_kbyte, bdb->bi_txn_cp_min, 0 );
1097         }
1098         
1099         if ( rs->sr_err == LDAP_SUCCESS && parent_is_glue && parent_is_leaf ) {
1100                 op->o_delete_glue_parent = 1;
1101         }
1102
1103 done:
1104         if( new_dn.bv_val != NULL ) free( new_dn.bv_val );
1105         if( new_ndn.bv_val != NULL ) free( new_ndn.bv_val );
1106
1107         /* LDAP v2 supporting correct attribute handling. */
1108         if ( new_rdn != NULL ) {
1109                 ldap_rdnfree_x( new_rdn, op->o_tmpmemctx );
1110         }
1111         if ( old_rdn != NULL ) {
1112                 ldap_rdnfree_x( old_rdn, op->o_tmpmemctx );
1113         }
1114         if( mod != NULL ) {
1115                 Modifications *tmp;
1116                 for (; mod; mod=tmp ) {
1117                         tmp = mod->sml_next;
1118                         /* slap_modrdn2mods does things one way,
1119                          * slap_mods_opattrs does it differently
1120                          */
1121                         if ( mod->sml_op != SLAP_MOD_SOFTADD &&
1122                                 mod->sml_op != LDAP_MOD_DELETE ) break;
1123                         if ( mod->sml_nvalues ) free( mod->sml_nvalues[0].bv_val );
1124                         free( mod );
1125                 }
1126                 slap_mods_free( mod );
1127         }
1128
1129         /* LDAP v3 Support */
1130         if( np != NULL ) {
1131                 /* free new parent and reader lock */
1132                 bdb_unlocked_cache_return_entry_r(&bdb->bi_cache, np);
1133         }
1134
1135         if( p != NULL ) {
1136                 /* free parent and reader lock */
1137                 bdb_unlocked_cache_return_entry_r(&bdb->bi_cache, p);
1138         }
1139
1140         /* free entry */
1141         if( e != NULL ) {
1142                 bdb_unlocked_cache_return_entry_w( &bdb->bi_cache, e);
1143         }
1144
1145         if( ltid != NULL ) {
1146                 pm_list = LDAP_LIST_FIRST(&op->o_pm_list);
1147                 while ( pm_list != NULL ) {
1148                         LDAP_LIST_REMOVE ( pm_list, ps_link );
1149                         pm_prev = pm_list;
1150                         pm_list = LDAP_LIST_NEXT ( pm_list, ps_link );
1151                         ch_free( pm_prev );
1152                 }
1153                 TXN_ABORT( ltid );
1154                 op->o_private = NULL;
1155         }
1156
1157         return rs->sr_err;
1158 }