~ttx/openldap/lucid-gssapi-495418

« back to all changes in this revision

Viewing changes to servers/slapd/back-bdb/modify.c

  • Committer: Bazaar Package Importer
  • Author(s): Mathias Gug
  • Date: 2008-07-10 14:45:49 UTC
  • Revision ID: james.westby@ubuntu.com-20080710144549-wck73med0e72gfyo
Tags: upstream-2.4.10
ImportĀ upstreamĀ versionĀ 2.4.10

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* modify.c - bdb backend modify routine */
 
2
/* $OpenLDAP: pkg/ldap/servers/slapd/back-bdb/modify.c,v 1.156.2.11 2008/05/01 21:39:35 quanah Exp $ */
 
3
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
 
4
 *
 
5
 * Copyright 2000-2008 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
#include <ac/time.h>
 
22
 
 
23
#include "back-bdb.h"
 
24
 
 
25
static struct berval scbva[] = {
 
26
        BER_BVC("glue"),
 
27
        BER_BVNULL
 
28
};
 
29
 
 
30
int bdb_modify_internal(
 
31
        Operation *op,
 
32
        DB_TXN *tid,
 
33
        Modifications *modlist,
 
34
        Entry *e,
 
35
        const char **text,
 
36
        char *textbuf,
 
37
        size_t textlen )
 
38
{
 
39
        int rc, err;
 
40
        Modification    *mod;
 
41
        Modifications   *ml;
 
42
        Attribute       *save_attrs;
 
43
        Attribute       *ap;
 
44
        int                     glue_attr_delete = 0;
 
45
        int                     got_delete;
 
46
        AttrInfo *ai;
 
47
 
 
48
        Debug( LDAP_DEBUG_TRACE, "bdb_modify_internal: 0x%08lx: %s\n",
 
49
                e->e_id, e->e_dn, 0);
 
50
 
 
51
        if ( !acl_check_modlist( op, e, modlist )) {
 
52
                return LDAP_INSUFFICIENT_ACCESS;
 
53
        }
 
54
 
 
55
        /* save_attrs will be disposed of by bdb_cache_modify */
 
56
        save_attrs = e->e_attrs;
 
57
        e->e_attrs = attrs_dup( e->e_attrs );
 
58
 
 
59
        for ( ml = modlist; ml != NULL; ml = ml->sml_next ) {
 
60
                int match;
 
61
                mod = &ml->sml_mod;
 
62
                switch( mod->sm_op ) {
 
63
                case LDAP_MOD_ADD:
 
64
                case LDAP_MOD_REPLACE:
 
65
                        if ( mod->sm_desc == slap_schema.si_ad_structuralObjectClass ) {
 
66
                                value_match( &match, slap_schema.si_ad_structuralObjectClass,
 
67
                                        slap_schema.si_ad_structuralObjectClass->
 
68
                                                ad_type->sat_equality,
 
69
                                        SLAP_MR_VALUE_OF_ATTRIBUTE_SYNTAX,
 
70
                                        &mod->sm_values[0], &scbva[0], text );
 
71
                                if ( !match ) glue_attr_delete = 1;
 
72
                        }
 
73
                }
 
74
                if ( glue_attr_delete )
 
75
                        break;
 
76
        }
 
77
 
 
78
        if ( glue_attr_delete ) {
 
79
                Attribute       **app = &e->e_attrs;
 
80
                while ( *app != NULL ) {
 
81
                        if ( !is_at_operational( (*app)->a_desc->ad_type )) {
 
82
                                Attribute *save = *app;
 
83
                                *app = (*app)->a_next;
 
84
                                attr_free( save );
 
85
                                continue;
 
86
                        }
 
87
                        app = &(*app)->a_next;
 
88
                }
 
89
        }
 
90
 
 
91
        for ( ml = modlist; ml != NULL; ml = ml->sml_next ) {
 
92
                struct berval ix_at;
 
93
                mod = &ml->sml_mod;
 
94
                got_delete = 0;
 
95
 
 
96
                switch ( mod->sm_op ) {
 
97
                case LDAP_MOD_ADD:
 
98
                        Debug(LDAP_DEBUG_ARGS,
 
99
                                "bdb_modify_internal: add %s\n",
 
100
                                mod->sm_desc->ad_cname.bv_val, 0, 0);
 
101
                        err = modify_add_values( e, mod, get_permissiveModify(op),
 
102
                                text, textbuf, textlen );
 
103
                        if( err != LDAP_SUCCESS ) {
 
104
                                Debug(LDAP_DEBUG_ARGS, "bdb_modify_internal: %d %s\n",
 
105
                                        err, *text, 0);
 
106
                        }
 
107
                        break;
 
108
 
 
109
                case LDAP_MOD_DELETE:
 
110
                        if ( glue_attr_delete ) {
 
111
                                err = LDAP_SUCCESS;
 
112
                                break;
 
113
                        }
 
114
 
 
115
                        Debug(LDAP_DEBUG_ARGS,
 
116
                                "bdb_modify_internal: delete %s\n",
 
117
                                mod->sm_desc->ad_cname.bv_val, 0, 0);
 
118
                        err = modify_delete_values( e, mod, get_permissiveModify(op),
 
119
                                text, textbuf, textlen );
 
120
                        assert( err != LDAP_TYPE_OR_VALUE_EXISTS );
 
121
                        if( err != LDAP_SUCCESS ) {
 
122
                                Debug(LDAP_DEBUG_ARGS, "bdb_modify_internal: %d %s\n",
 
123
                                        err, *text, 0);
 
124
                        } else {
 
125
                                got_delete = 1;
 
126
                        }
 
127
                        break;
 
128
 
 
129
                case LDAP_MOD_REPLACE:
 
130
                        Debug(LDAP_DEBUG_ARGS,
 
131
                                "bdb_modify_internal: replace %s\n",
 
132
                                mod->sm_desc->ad_cname.bv_val, 0, 0);
 
133
                        err = modify_replace_values( e, mod, get_permissiveModify(op),
 
134
                                text, textbuf, textlen );
 
135
                        if( err != LDAP_SUCCESS ) {
 
136
                                Debug(LDAP_DEBUG_ARGS, "bdb_modify_internal: %d %s\n",
 
137
                                        err, *text, 0);
 
138
                        } else {
 
139
                                got_delete = 1;
 
140
                        }
 
141
                        break;
 
142
 
 
143
                case LDAP_MOD_INCREMENT:
 
144
                        Debug(LDAP_DEBUG_ARGS,
 
145
                                "bdb_modify_internal: increment %s\n",
 
146
                                mod->sm_desc->ad_cname.bv_val, 0, 0);
 
147
                        err = modify_increment_values( e, mod, get_permissiveModify(op),
 
148
                                text, textbuf, textlen );
 
149
                        if( err != LDAP_SUCCESS ) {
 
150
                                Debug(LDAP_DEBUG_ARGS,
 
151
                                        "bdb_modify_internal: %d %s\n",
 
152
                                        err, *text, 0);
 
153
                        } else {
 
154
                                got_delete = 1;
 
155
                        }
 
156
                        break;
 
157
 
 
158
                case SLAP_MOD_SOFTADD:
 
159
                        Debug(LDAP_DEBUG_ARGS,
 
160
                                "bdb_modify_internal: softadd %s\n",
 
161
                                mod->sm_desc->ad_cname.bv_val, 0, 0);
 
162
                        /* Avoid problems in index_add_mods()
 
163
                         * We need to add index if necessary.
 
164
                         */
 
165
                        mod->sm_op = LDAP_MOD_ADD;
 
166
 
 
167
                        err = modify_add_values( e, mod, get_permissiveModify(op),
 
168
                                text, textbuf, textlen );
 
169
 
 
170
                        mod->sm_op = SLAP_MOD_SOFTADD;
 
171
 
 
172
                        if ( err == LDAP_TYPE_OR_VALUE_EXISTS ) {
 
173
                                err = LDAP_SUCCESS;
 
174
                        }
 
175
 
 
176
                        if( err != LDAP_SUCCESS ) {
 
177
                                Debug(LDAP_DEBUG_ARGS, "bdb_modify_internal: %d %s\n",
 
178
                                        err, *text, 0);
 
179
                        }
 
180
                        break;
 
181
 
 
182
                default:
 
183
                        Debug(LDAP_DEBUG_ANY, "bdb_modify_internal: invalid op %d\n",
 
184
                                mod->sm_op, 0, 0);
 
185
                        *text = "Invalid modify operation";
 
186
                        err = LDAP_OTHER;
 
187
                        Debug(LDAP_DEBUG_ARGS, "bdb_modify_internal: %d %s\n",
 
188
                                err, *text, 0);
 
189
                }
 
190
 
 
191
                if ( err != LDAP_SUCCESS ) {
 
192
                        attrs_free( e->e_attrs );
 
193
                        e->e_attrs = save_attrs;
 
194
                        /* unlock entry, delete from cache */
 
195
                        return err; 
 
196
                }
 
197
 
 
198
                /* If objectClass was modified, reset the flags */
 
199
                if ( mod->sm_desc == slap_schema.si_ad_objectClass ) {
 
200
                        e->e_ocflags = 0;
 
201
                }
 
202
 
 
203
                if ( glue_attr_delete ) e->e_ocflags = 0;
 
204
 
 
205
                /* check if modified attribute was indexed
 
206
                 * but not in case of NOOP... */
 
207
                ai = bdb_index_mask( op->o_bd, mod->sm_desc, &ix_at );
 
208
                if ( ai && !op->o_noop ) {
 
209
                        if ( got_delete ) {
 
210
                                struct berval ix2;
 
211
 
 
212
                                ap = attr_find( save_attrs, mod->sm_desc );
 
213
                                if ( ap ) ap->a_flags |= SLAP_ATTR_IXDEL;
 
214
 
 
215
                                /* Find all other attrs that index to same slot */
 
216
                                for ( ap = e->e_attrs; ap; ap=ap->a_next ) {
 
217
                                        ai = bdb_index_mask( op->o_bd, ap->a_desc, &ix2 );
 
218
                                        if ( ai && ix2.bv_val == ix_at.bv_val )
 
219
                                                ap->a_flags |= SLAP_ATTR_IXADD;
 
220
                                }
 
221
                        } else {
 
222
                                ap = attr_find( e->e_attrs, mod->sm_desc );
 
223
                                if ( ap ) ap->a_flags |= SLAP_ATTR_IXADD;
 
224
                        }
 
225
                }
 
226
        }
 
227
 
 
228
        /* check that the entry still obeys the schema */
 
229
        rc = entry_schema_check( op, e, save_attrs, get_relax(op), 0,
 
230
                text, textbuf, textlen );
 
231
        if ( rc != LDAP_SUCCESS || op->o_noop ) {
 
232
                attrs_free( e->e_attrs );
 
233
                /* clear the indexing flags */
 
234
                for ( ap = save_attrs; ap != NULL; ap = ap->a_next ) {
 
235
                        ap->a_flags &= ~(SLAP_ATTR_IXADD|SLAP_ATTR_IXDEL);
 
236
                }
 
237
                e->e_attrs = save_attrs;
 
238
 
 
239
                if ( rc != LDAP_SUCCESS ) {
 
240
                        Debug( LDAP_DEBUG_ANY,
 
241
                                "entry failed schema check: %s\n",
 
242
                                *text, 0, 0 );
 
243
                }
 
244
 
 
245
                /* if NOOP then silently revert to saved attrs */
 
246
                return rc;
 
247
        }
 
248
 
 
249
        /* update the indices of the modified attributes */
 
250
 
 
251
        /* start with deleting the old index entries */
 
252
        for ( ap = save_attrs; ap != NULL; ap = ap->a_next ) {
 
253
                if ( ap->a_flags & SLAP_ATTR_IXDEL ) {
 
254
                        struct berval *vals;
 
255
                        Attribute *a2;
 
256
                        ap->a_flags &= ~SLAP_ATTR_IXDEL;
 
257
                        a2 = attr_find( e->e_attrs, ap->a_desc );
 
258
                        if ( a2 ) {
 
259
                                /* need to detect which values were deleted */
 
260
                                int i, j;
 
261
                                struct berval tmp;
 
262
                                j = ap->a_numvals;
 
263
                                for ( i=0; i<j; ) {
 
264
                                        rc = attr_valfind( a2, SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH,
 
265
                                                &ap->a_nvals[i], NULL, op->o_tmpmemctx );
 
266
                                        /* Move deleted values to end of array */
 
267
                                        if ( rc == LDAP_NO_SUCH_ATTRIBUTE ) {
 
268
                                                j--;
 
269
                                                if ( i != j ) {
 
270
                                                        tmp = ap->a_nvals[j];
 
271
                                                        ap->a_nvals[j] = ap->a_nvals[i];
 
272
                                                        ap->a_nvals[i] = tmp;
 
273
                                                        tmp = ap->a_vals[j];
 
274
                                                        ap->a_vals[j] = ap->a_vals[i];
 
275
                                                        ap->a_vals[i] = tmp;
 
276
                                                }
 
277
                                                continue;
 
278
                                        }
 
279
                                        i++;
 
280
                                }
 
281
                                vals = &ap->a_nvals[j];
 
282
                        } else {
 
283
                                /* attribute was completely deleted */
 
284
                                vals = ap->a_nvals;
 
285
                        }
 
286
                        if ( !BER_BVISNULL( vals )) {
 
287
                                rc = bdb_index_values( op, tid, ap->a_desc,
 
288
                                        vals, e->e_id, SLAP_INDEX_DELETE_OP );
 
289
                                if ( rc != LDAP_SUCCESS ) {
 
290
                                        attrs_free( e->e_attrs );
 
291
                                        e->e_attrs = save_attrs;
 
292
                                        Debug( LDAP_DEBUG_ANY,
 
293
                                                   "Attribute index delete failure",
 
294
                                                   0, 0, 0 );
 
295
                                        return rc;
 
296
                                }
 
297
                        }
 
298
                }
 
299
        }
 
300
 
 
301
        /* add the new index entries */
 
302
        for ( ap = e->e_attrs; ap != NULL; ap = ap->a_next ) {
 
303
                if (ap->a_flags & SLAP_ATTR_IXADD) {
 
304
                        ap->a_flags &= ~SLAP_ATTR_IXADD;
 
305
                        rc = bdb_index_values( op, tid, ap->a_desc,
 
306
                                ap->a_nvals,
 
307
                                e->e_id, SLAP_INDEX_ADD_OP );
 
308
                        if ( rc != LDAP_SUCCESS ) {
 
309
                                attrs_free( e->e_attrs );
 
310
                                e->e_attrs = save_attrs;
 
311
                                Debug( LDAP_DEBUG_ANY,
 
312
                                       "Attribute index add failure",
 
313
                                       0, 0, 0 );
 
314
                                return rc;
 
315
                        }
 
316
                }
 
317
        }
 
318
 
 
319
        return rc;
 
320
}
 
321
 
 
322
 
 
323
int
 
324
bdb_modify( Operation *op, SlapReply *rs )
 
325
{
 
326
        struct bdb_info *bdb = (struct bdb_info *) op->o_bd->be_private;
 
327
        Entry           *e = NULL;
 
328
        EntryInfo       *ei = NULL;
 
329
        int             manageDSAit = get_manageDSAit( op );
 
330
        char textbuf[SLAP_TEXT_BUFLEN];
 
331
        size_t textlen = sizeof textbuf;
 
332
        DB_TXN  *ltid = NULL, *lt2;
 
333
        struct bdb_op_info opinfo = {0};
 
334
        Entry           dummy = {0};
 
335
        int                     fakeroot = 0;
 
336
 
 
337
        BDB_LOCKER      locker = 0;
 
338
        DB_LOCK         lock;
 
339
 
 
340
        int             num_retries = 0;
 
341
 
 
342
        LDAPControl **preread_ctrl = NULL;
 
343
        LDAPControl **postread_ctrl = NULL;
 
344
        LDAPControl *ctrls[SLAP_MAX_RESPONSE_CONTROLS];
 
345
        int num_ctrls = 0;
 
346
 
 
347
        int rc;
 
348
 
 
349
#ifdef LDAP_X_TXN
 
350
        int settle = 0;
 
351
#endif
 
352
 
 
353
        Debug( LDAP_DEBUG_ARGS, LDAP_XSTRING(bdb_modify) ": %s\n",
 
354
                op->o_req_dn.bv_val, 0, 0 );
 
355
 
 
356
#ifdef LDAP_X_TXN
 
357
        if( op->o_txnSpec ) {
 
358
                /* acquire connection lock */
 
359
                ldap_pvt_thread_mutex_lock( &op->o_conn->c_mutex );
 
360
                if( op->o_conn->c_txn == CONN_TXN_INACTIVE ) {
 
361
                        rs->sr_text = "invalid transaction identifier";
 
362
                        rs->sr_err = LDAP_X_TXN_ID_INVALID;
 
363
                        goto txnReturn;
 
364
                } else if( op->o_conn->c_txn == CONN_TXN_SETTLE ) {
 
365
                        settle=1;
 
366
                        goto txnReturn;
 
367
                }
 
368
 
 
369
                if( op->o_conn->c_txn_backend == NULL ) {
 
370
                        op->o_conn->c_txn_backend = op->o_bd;
 
371
 
 
372
                } else if( op->o_conn->c_txn_backend != op->o_bd ) {
 
373
                        rs->sr_text = "transaction cannot span multiple database contexts";
 
374
                        rs->sr_err = LDAP_AFFECTS_MULTIPLE_DSAS;
 
375
                        goto txnReturn;
 
376
                }
 
377
 
 
378
                /* insert operation into transaction */
 
379
 
 
380
                rs->sr_text = "transaction specified";
 
381
                rs->sr_err = LDAP_X_TXN_SPECIFY_OKAY;
 
382
 
 
383
txnReturn:
 
384
                /* release connection lock */
 
385
                ldap_pvt_thread_mutex_unlock( &op->o_conn->c_mutex );
 
386
 
 
387
                if( !settle ) {
 
388
                        send_ldap_result( op, rs );
 
389
                        return rs->sr_err;
 
390
                }
 
391
        }
 
392
#endif
 
393
 
 
394
        ctrls[num_ctrls] = NULL;
 
395
 
 
396
        slap_mods_opattrs( op, &op->orm_modlist, 1 );
 
397
 
 
398
        if( 0 ) {
 
399
retry:  /* transaction retry */
 
400
                if ( dummy.e_attrs ) {
 
401
                        attrs_free( dummy.e_attrs );
 
402
                        dummy.e_attrs = NULL;
 
403
                }
 
404
                if( e != NULL ) {
 
405
                        bdb_unlocked_cache_return_entry_w(&bdb->bi_cache, e);
 
406
                        e = NULL;
 
407
                }
 
408
                Debug(LDAP_DEBUG_TRACE,
 
409
                        LDAP_XSTRING(bdb_modify) ": retrying...\n", 0, 0, 0);
 
410
 
 
411
                rs->sr_err = TXN_ABORT( ltid );
 
412
                ltid = NULL;
 
413
                LDAP_SLIST_REMOVE( &op->o_extra, &opinfo.boi_oe, OpExtra, oe_next );
 
414
                opinfo.boi_oe.oe_key = NULL;
 
415
                op->o_do_not_cache = opinfo.boi_acl_cache;
 
416
                if( rs->sr_err != 0 ) {
 
417
                        rs->sr_err = LDAP_OTHER;
 
418
                        rs->sr_text = "internal error";
 
419
                        goto return_results;
 
420
                }
 
421
                if ( op->o_abandon ) {
 
422
                        rs->sr_err = SLAPD_ABANDON;
 
423
                        goto return_results;
 
424
                }
 
425
                bdb_trans_backoff( ++num_retries );
 
426
        }
 
427
 
 
428
        /* begin transaction */
 
429
        rs->sr_err = TXN_BEGIN( bdb->bi_dbenv, NULL, &ltid, 
 
430
                bdb->bi_db_opflags );
 
431
        rs->sr_text = NULL;
 
432
        if( rs->sr_err != 0 ) {
 
433
                Debug( LDAP_DEBUG_TRACE,
 
434
                        LDAP_XSTRING(bdb_modify) ": txn_begin failed: "
 
435
                        "%s (%d)\n", db_strerror(rs->sr_err), rs->sr_err, 0 );
 
436
                rs->sr_err = LDAP_OTHER;
 
437
                rs->sr_text = "internal error";
 
438
                goto return_results;
 
439
        }
 
440
 
 
441
        locker = TXN_ID ( ltid );
 
442
 
 
443
        opinfo.boi_oe.oe_key = bdb;
 
444
        opinfo.boi_txn = ltid;
 
445
        opinfo.boi_err = 0;
 
446
        opinfo.boi_acl_cache = op->o_do_not_cache;
 
447
        LDAP_SLIST_INSERT_HEAD( &op->o_extra, &opinfo.boi_oe, oe_next );
 
448
 
 
449
        /* get entry or ancestor */
 
450
        rs->sr_err = bdb_dn2entry( op, ltid, &op->o_req_ndn, &ei, 1,
 
451
                locker, &lock );
 
452
 
 
453
        if ( rs->sr_err != 0 ) {
 
454
                Debug( LDAP_DEBUG_TRACE,
 
455
                        LDAP_XSTRING(bdb_modify) ": dn2entry failed (%d)\n",
 
456
                        rs->sr_err, 0, 0 );
 
457
                switch( rs->sr_err ) {
 
458
                case DB_LOCK_DEADLOCK:
 
459
                case DB_LOCK_NOTGRANTED:
 
460
                        goto retry;
 
461
                case DB_NOTFOUND:
 
462
                        if ( BER_BVISEMPTY( &op->o_req_ndn )) {
 
463
                                struct berval gluebv = BER_BVC("glue");
 
464
                                e = ch_calloc( 1, sizeof(Entry));
 
465
                                e->e_name.bv_val = ch_strdup( "" );
 
466
                                ber_dupbv( &e->e_nname, &e->e_name );
 
467
                                attr_merge_one( e, slap_schema.si_ad_objectClass,
 
468
                                        &gluebv, NULL );
 
469
                                attr_merge_one( e, slap_schema.si_ad_structuralObjectClass,
 
470
                                        &gluebv, NULL );
 
471
                                e->e_private = ei;
 
472
                                fakeroot = 1;
 
473
                                rs->sr_err = 0;
 
474
                        }
 
475
                        break;
 
476
                case LDAP_BUSY:
 
477
                        rs->sr_text = "ldap server busy";
 
478
                        goto return_results;
 
479
                default:
 
480
                        rs->sr_err = LDAP_OTHER;
 
481
                        rs->sr_text = "internal error";
 
482
                        goto return_results;
 
483
                }
 
484
        }
 
485
 
 
486
        if ( !fakeroot ) {
 
487
                e = ei->bei_e;
 
488
        }
 
489
 
 
490
        /* acquire and lock entry */
 
491
        /* FIXME: dn2entry() should return non-glue entry */
 
492
        if (( rs->sr_err == DB_NOTFOUND ) ||
 
493
                ( !manageDSAit && e && is_entry_glue( e )))
 
494
        {
 
495
                if ( e != NULL ) {
 
496
                        rs->sr_matched = ch_strdup( e->e_dn );
 
497
                        rs->sr_ref = is_entry_referral( e )
 
498
                                ? get_entry_referrals( op, e )
 
499
                                : NULL;
 
500
                        bdb_unlocked_cache_return_entry_r (&bdb->bi_cache, e);
 
501
                        e = NULL;
 
502
 
 
503
                } else {
 
504
                        rs->sr_ref = referral_rewrite( default_referral, NULL,
 
505
                                &op->o_req_dn, LDAP_SCOPE_DEFAULT );
 
506
                }
 
507
 
 
508
                rs->sr_err = LDAP_REFERRAL;
 
509
                send_ldap_result( op, rs );
 
510
 
 
511
                if ( rs->sr_ref != default_referral ) {
 
512
                        ber_bvarray_free( rs->sr_ref );
 
513
                }
 
514
                free( (char *)rs->sr_matched );
 
515
                rs->sr_ref = NULL;
 
516
                rs->sr_matched = NULL;
 
517
 
 
518
                goto done;
 
519
        }
 
520
 
 
521
        if ( !manageDSAit && is_entry_referral( e ) ) {
 
522
                /* entry is a referral, don't allow modify */
 
523
                rs->sr_ref = get_entry_referrals( op, e );
 
524
 
 
525
                Debug( LDAP_DEBUG_TRACE,
 
526
                        LDAP_XSTRING(bdb_modify) ": entry is referral\n",
 
527
                        0, 0, 0 );
 
528
 
 
529
                rs->sr_err = LDAP_REFERRAL;
 
530
                rs->sr_matched = e->e_name.bv_val;
 
531
                send_ldap_result( op, rs );
 
532
 
 
533
                ber_bvarray_free( rs->sr_ref );
 
534
                rs->sr_ref = NULL;
 
535
                rs->sr_matched = NULL;
 
536
                goto done;
 
537
        }
 
538
 
 
539
        if ( get_assert( op ) &&
 
540
                ( test_filter( op, e, get_assertion( op )) != LDAP_COMPARE_TRUE ))
 
541
        {
 
542
                rs->sr_err = LDAP_ASSERTION_FAILED;
 
543
                goto return_results;
 
544
        }
 
545
 
 
546
        if( op->o_preread ) {
 
547
                if( preread_ctrl == NULL ) {
 
548
                        preread_ctrl = &ctrls[num_ctrls++];
 
549
                        ctrls[num_ctrls] = NULL;
 
550
                }
 
551
                if ( slap_read_controls( op, rs, e,
 
552
                        &slap_pre_read_bv, preread_ctrl ) )
 
553
                {
 
554
                        Debug( LDAP_DEBUG_TRACE,
 
555
                                "<=- " LDAP_XSTRING(bdb_modify) ": pre-read "
 
556
                                "failed!\n", 0, 0, 0 );
 
557
                        if ( op->o_preread & SLAP_CONTROL_CRITICAL ) {
 
558
                                /* FIXME: is it correct to abort
 
559
                                 * operation if control fails? */
 
560
                                goto return_results;
 
561
                        }
 
562
                }
 
563
        }
 
564
 
 
565
        /* nested transaction */
 
566
        rs->sr_err = TXN_BEGIN( bdb->bi_dbenv, ltid, &lt2, bdb->bi_db_opflags );
 
567
        rs->sr_text = NULL;
 
568
        if( rs->sr_err != 0 ) {
 
569
                Debug( LDAP_DEBUG_TRACE,
 
570
                        LDAP_XSTRING(bdb_modify) ": txn_begin(2) failed: " "%s (%d)\n",
 
571
                        db_strerror(rs->sr_err), rs->sr_err, 0 );
 
572
                rs->sr_err = LDAP_OTHER;
 
573
                rs->sr_text = "internal error";
 
574
                goto return_results;
 
575
        }
 
576
        /* Modify the entry */
 
577
        dummy = *e;
 
578
        rs->sr_err = bdb_modify_internal( op, lt2, op->orm_modlist,
 
579
                &dummy, &rs->sr_text, textbuf, textlen );
 
580
 
 
581
        if( rs->sr_err != LDAP_SUCCESS ) {
 
582
                Debug( LDAP_DEBUG_TRACE,
 
583
                        LDAP_XSTRING(bdb_modify) ": modify failed (%d)\n",
 
584
                        rs->sr_err, 0, 0 );
 
585
                if ( (rs->sr_err == LDAP_INSUFFICIENT_ACCESS) && opinfo.boi_err ) {
 
586
                        rs->sr_err = opinfo.boi_err;
 
587
                }
 
588
                /* Only free attrs if they were dup'd.  */
 
589
                if ( dummy.e_attrs == e->e_attrs ) dummy.e_attrs = NULL;
 
590
                switch( rs->sr_err ) {
 
591
                case DB_LOCK_DEADLOCK:
 
592
                case DB_LOCK_NOTGRANTED:
 
593
                        goto retry;
 
594
                }
 
595
                goto return_results;
 
596
        }
 
597
 
 
598
        /* change the entry itself */
 
599
        rs->sr_err = bdb_id2entry_update( op->o_bd, lt2, &dummy );
 
600
        if ( rs->sr_err != 0 ) {
 
601
                Debug( LDAP_DEBUG_TRACE,
 
602
                        LDAP_XSTRING(bdb_modify) ": id2entry update failed " "(%d)\n",
 
603
                        rs->sr_err, 0, 0 );
 
604
                switch( rs->sr_err ) {
 
605
                case DB_LOCK_DEADLOCK:
 
606
                case DB_LOCK_NOTGRANTED:
 
607
                        goto retry;
 
608
                }
 
609
                rs->sr_text = "entry update failed";
 
610
                goto return_results;
 
611
        }
 
612
 
 
613
        if ( TXN_COMMIT( lt2, 0 ) != 0 ) {
 
614
                rs->sr_err = LDAP_OTHER;
 
615
                rs->sr_text = "txn_commit(2) failed";
 
616
                goto return_results;
 
617
        }
 
618
 
 
619
        if( op->o_postread ) {
 
620
                if( postread_ctrl == NULL ) {
 
621
                        postread_ctrl = &ctrls[num_ctrls++];
 
622
                        ctrls[num_ctrls] = NULL;
 
623
                }
 
624
                if( slap_read_controls( op, rs, &dummy,
 
625
                        &slap_post_read_bv, postread_ctrl ) )
 
626
                {
 
627
                        Debug( LDAP_DEBUG_TRACE,
 
628
                                "<=- " LDAP_XSTRING(bdb_modify)
 
629
                                ": post-read failed!\n", 0, 0, 0 );
 
630
                        if ( op->o_postread & SLAP_CONTROL_CRITICAL ) {
 
631
                                /* FIXME: is it correct to abort
 
632
                                 * operation if control fails? */
 
633
                                goto return_results;
 
634
                        }
 
635
                }
 
636
        }
 
637
 
 
638
        if( op->o_noop ) {
 
639
                if ( ( rs->sr_err = TXN_ABORT( ltid ) ) != 0 ) {
 
640
                        rs->sr_text = "txn_abort (no-op) failed";
 
641
                } else {
 
642
                        rs->sr_err = LDAP_X_NO_OPERATION;
 
643
                        ltid = NULL;
 
644
                        /* Only free attrs if they were dup'd.  */
 
645
                        if ( dummy.e_attrs == e->e_attrs ) dummy.e_attrs = NULL;
 
646
                        goto return_results;
 
647
                }
 
648
        } else {
 
649
                /* may have changed in bdb_modify_internal() */
 
650
                e->e_ocflags = dummy.e_ocflags;
 
651
                if ( fakeroot ) {
 
652
                        e->e_private = NULL;
 
653
                        entry_free( e );
 
654
                        e = NULL;
 
655
                        attrs_free( dummy.e_attrs );
 
656
 
 
657
                } else {
 
658
                        rc = bdb_cache_modify( bdb, e, dummy.e_attrs, locker, &lock );
 
659
                        switch( rc ) {
 
660
                        case DB_LOCK_DEADLOCK:
 
661
                        case DB_LOCK_NOTGRANTED:
 
662
                                goto retry;
 
663
                        }
 
664
                }
 
665
                dummy.e_attrs = NULL;
 
666
 
 
667
                rs->sr_err = TXN_COMMIT( ltid, 0 );
 
668
        }
 
669
        ltid = NULL;
 
670
        LDAP_SLIST_REMOVE( &op->o_extra, &opinfo.boi_oe, OpExtra, oe_next );
 
671
        opinfo.boi_oe.oe_key = NULL;
 
672
 
 
673
        if( rs->sr_err != 0 ) {
 
674
                Debug( LDAP_DEBUG_TRACE,
 
675
                        LDAP_XSTRING(bdb_modify) ": txn_%s failed: %s (%d)\n",
 
676
                        op->o_noop ? "abort (no-op)" : "commit",
 
677
                        db_strerror(rs->sr_err), rs->sr_err );
 
678
                rs->sr_err = LDAP_OTHER;
 
679
                rs->sr_text = "commit failed";
 
680
 
 
681
                goto return_results;
 
682
        }
 
683
 
 
684
        Debug( LDAP_DEBUG_TRACE,
 
685
                LDAP_XSTRING(bdb_modify) ": updated%s id=%08lx dn=\"%s\"\n",
 
686
                op->o_noop ? " (no-op)" : "",
 
687
                dummy.e_id, op->o_req_dn.bv_val );
 
688
 
 
689
        rs->sr_err = LDAP_SUCCESS;
 
690
        rs->sr_text = NULL;
 
691
        if( num_ctrls ) rs->sr_ctrls = ctrls;
 
692
 
 
693
return_results:
 
694
        if( dummy.e_attrs ) {
 
695
                attrs_free( dummy.e_attrs );
 
696
        }
 
697
        send_ldap_result( op, rs );
 
698
 
 
699
        if( rs->sr_err == LDAP_SUCCESS && bdb->bi_txn_cp_kbyte ) {
 
700
                TXN_CHECKPOINT( bdb->bi_dbenv,
 
701
                        bdb->bi_txn_cp_kbyte, bdb->bi_txn_cp_min, 0 );
 
702
        }
 
703
 
 
704
done:
 
705
        slap_graduate_commit_csn( op );
 
706
 
 
707
        if( ltid != NULL ) {
 
708
                TXN_ABORT( ltid );
 
709
        }
 
710
        if ( opinfo.boi_oe.oe_key ) {
 
711
                LDAP_SLIST_REMOVE( &op->o_extra, &opinfo.boi_oe, OpExtra, oe_next );
 
712
        }
 
713
 
 
714
        if( e != NULL ) {
 
715
                bdb_unlocked_cache_return_entry_w (&bdb->bi_cache, e);
 
716
        }
 
717
 
 
718
        if( preread_ctrl != NULL && (*preread_ctrl) != NULL ) {
 
719
                slap_sl_free( (*preread_ctrl)->ldctl_value.bv_val, op->o_tmpmemctx );
 
720
                slap_sl_free( *preread_ctrl, op->o_tmpmemctx );
 
721
        }
 
722
        if( postread_ctrl != NULL && (*postread_ctrl) != NULL ) {
 
723
                slap_sl_free( (*postread_ctrl)->ldctl_value.bv_val, op->o_tmpmemctx );
 
724
                slap_sl_free( *postread_ctrl, op->o_tmpmemctx );
 
725
        }
 
726
 
 
727
        rs->sr_text = NULL;
 
728
 
 
729
        return rs->sr_err;
 
730
}