~ubuntu-branches/ubuntu/maverick/openldap/maverick-proposed

« back to all changes in this revision

Viewing changes to servers/slapd/back-ndb/modify.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Mathias Gug, Steve Langasek, Mathias Gug
  • Date: 2009-02-18 18:44:00 UTC
  • mfrom: (1.1.2 upstream) (0.1.2 lenny)
  • Revision ID: james.westby@ubuntu.com-20090218184400-zw4mjse9eywt5566
Tags: 2.4.14-0ubuntu1
[ Steve Langasek ]
* New upstream version
  - Fixes a bug with the pcache overlay not returning cached entries
    (closes: #497697)
  - Update evolution-ntlm patch to apply to current Makefiles.
  - (tentatively) drop gnutls-ciphers, since this bug was reported to be
    fixed upstream in 2.4.8.  The fix applied in 2.4.8 didn't match the
    patch from the bug report, so this should be watched for regressions.
* Build against db4.7 instead of db4.2 at last!  Closes: #421946.
* Build with --disable-ndb, to avoid a misbuild when libmysqlclient is
  installed in the build environment.
* New patch, no-crlcheck-for-gnutls, to fix a build failure when using
  --with-tls=gnutls.

[ Mathias Gug ]
* Merge from debian unstable, remaining changes:
  - debian/apparmor-profile: add AppArmor profile
  - debian/slapd.postinst: Reload AA profile on configuration
  - updated debian/slapd.README.Debian for note on AppArmor
  - debian/control: Recommends apparmor >= 2.1+1075-0ubuntu6
  - debian/control: Conflicts with apparmor-profiles << 2.1+1075-0ubuntu4
    to make sure that if earlier version of apparmour-profiles gets
    installed it won't overwrite our profile.
  - Modify Maintainer value to match the DebianMaintainerField
    speficication.
  - follow ApparmorProfileMigration and force apparmor compalin mode on 
    some upgrades (LP: #203529)
  - debian/slapd.dirs: add etc/apparmor.d/force-complain
  - debian/slapd.preinst: create symlink for force-complain on pre-feisty
    upgrades, upgrades where apparmor-profiles profile is unchanged (ie
    non-enforcing) and upgrades where apparmor profile does not exist.
  - debian/slapd.postrm: remove symlink in force-complain/ on purge
  - debian/patches/fix-ucred-libc due to changes how newer glibc handle
    the ucred struct now.
  - debian/control:
    - Build-depend on libltdl7-dev rather then libltdl3-dev.
  - debian/patches/autogen.sh:
    - Call libtoolize with the --install option to install config.{guess,sub}
      files.
  - Don't use local statement in config script as it fails if /bin/sh
    points to bash (LP: #286063).
  - Disable the testsuite on hppa. Allows building of packages on this
    architecture again, once this package is in the archive.
    LP: #288908.
  - debian/slapd.postinst, debian/slapd.script-common: set correct ownership
    and permissions on /var/lib/ldap, /etc/ldap/slapd.d (group readable) and
    /var/run/slapd (world readable). (LP: #257667).
  - debian/patches/nssov-build, debian/rules: 
    Build and package the nss overlay.
    debian/schema/misc.ldif: add ldif file for the misc schema, which defines
    rfc822MailMember (required by the nss overlay).
  - debian/{control,rules}: enable PIE hardening
  - Use cn=config as the default configuration backend instead of 
    slapd.conf. Migrate slapd.conf  file to /etc/ldap/slapd.d/ on upgrade
    asking the end user to enter a new password to control the access to the
    cn=config tree.
* debian/patches/corrupt-contextCSN: The contextCSN can get corrupted at
  times. (ITS: #5947)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* modify.cpp - ndb backend modify routine */
 
2
/* $OpenLDAP: pkg/ldap/servers/slapd/back-ndb/modify.cpp,v 1.3.2.3 2009/02/05 19:35:54 quanah Exp $ */
 
3
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
 
4
 *
 
5
 * Copyright 2008-2009 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
/* ACKNOWLEDGEMENTS:
 
17
 * This work was initially developed by Howard Chu for inclusion
 
18
 * in OpenLDAP Software. This work was sponsored by MySQL.
 
19
 */
 
20
 
 
21
#include "portable.h"
 
22
 
 
23
#include <stdio.h>
 
24
#include <ac/string.h>
 
25
#include <ac/time.h>
 
26
 
 
27
#include "back-ndb.h"
 
28
 
 
29
/* This is a copy from slapd/mods.c, but with compaction tweaked
 
30
 * to swap values from the tail into deleted slots, to reduce the
 
31
 * overall update traffic.
 
32
 */
 
33
static int
 
34
ndb_modify_delete(
 
35
        Entry   *e,
 
36
        Modification    *mod,
 
37
        int     permissive,
 
38
        const char      **text,
 
39
        char *textbuf, size_t textlen,
 
40
        int *idx )
 
41
{
 
42
        Attribute       *a;
 
43
        MatchingRule    *mr = mod->sm_desc->ad_type->sat_equality;
 
44
        struct berval *cvals;
 
45
        int             *id2 = NULL;
 
46
        int             i, j, rc = 0, num;
 
47
        unsigned flags;
 
48
        char            dummy = '\0';
 
49
 
 
50
        /* For ordered vals, we have no choice but to preserve order */
 
51
        if ( mod->sm_desc->ad_type->sat_flags & SLAP_AT_ORDERED_VAL )
 
52
                return modify_delete_vindex( e, mod, permissive, text,
 
53
                        textbuf, textlen, idx );
 
54
 
 
55
        /*
 
56
         * If permissive is set, then the non-existence of an 
 
57
         * attribute is not treated as an error.
 
58
         */
 
59
 
 
60
        /* delete the entire attribute */
 
61
        if ( mod->sm_values == NULL ) {
 
62
                rc = attr_delete( &e->e_attrs, mod->sm_desc );
 
63
 
 
64
                if( permissive ) {
 
65
                        rc = LDAP_SUCCESS;
 
66
                } else if( rc != LDAP_SUCCESS ) {
 
67
                        *text = textbuf;
 
68
                        snprintf( textbuf, textlen,
 
69
                                "modify/delete: %s: no such attribute",
 
70
                                mod->sm_desc->ad_cname.bv_val );
 
71
                        rc = LDAP_NO_SUCH_ATTRIBUTE;
 
72
                }
 
73
                return rc;
 
74
        }
 
75
 
 
76
        /* FIXME: Catch old code that doesn't set sm_numvals.
 
77
         */
 
78
        if ( !BER_BVISNULL( &mod->sm_values[mod->sm_numvals] )) {
 
79
                for ( i = 0; !BER_BVISNULL( &mod->sm_values[i] ); i++ );
 
80
                assert( mod->sm_numvals == i );
 
81
        }
 
82
        if ( !idx ) {
 
83
                id2 = (int *)ch_malloc( mod->sm_numvals * sizeof( int ));
 
84
                idx = id2;
 
85
        }
 
86
 
 
87
        if( mr == NULL || !mr->smr_match ) {
 
88
                /* disallow specific attributes from being deleted if
 
89
                        no equality rule */
 
90
                *text = textbuf;
 
91
                snprintf( textbuf, textlen,
 
92
                        "modify/delete: %s: no equality matching rule",
 
93
                        mod->sm_desc->ad_cname.bv_val );
 
94
                rc = LDAP_INAPPROPRIATE_MATCHING;
 
95
                goto return_result;
 
96
        }
 
97
 
 
98
        /* delete specific values - find the attribute first */
 
99
        if ( (a = attr_find( e->e_attrs, mod->sm_desc )) == NULL ) {
 
100
                if( permissive ) {
 
101
                        rc = LDAP_SUCCESS;
 
102
                        goto return_result;
 
103
                }
 
104
                *text = textbuf;
 
105
                snprintf( textbuf, textlen,
 
106
                        "modify/delete: %s: no such attribute",
 
107
                        mod->sm_desc->ad_cname.bv_val );
 
108
                rc = LDAP_NO_SUCH_ATTRIBUTE;
 
109
                goto return_result;
 
110
        }
 
111
 
 
112
        if ( mod->sm_nvalues ) {
 
113
                flags = SLAP_MR_EQUALITY | SLAP_MR_VALUE_OF_ASSERTION_SYNTAX
 
114
                        | SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH
 
115
                        | SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH;
 
116
                cvals = mod->sm_nvalues;
 
117
        } else {
 
118
                flags = SLAP_MR_EQUALITY | SLAP_MR_VALUE_OF_ASSERTION_SYNTAX;
 
119
                cvals = mod->sm_values;
 
120
        }
 
121
 
 
122
        /* Locate values to delete */
 
123
        for ( i = 0; !BER_BVISNULL( &mod->sm_values[i] ); i++ ) {
 
124
                unsigned sort;
 
125
                rc = attr_valfind( a, flags, &cvals[i], &sort, NULL );
 
126
                if ( rc == LDAP_SUCCESS ) {
 
127
                        idx[i] = sort;
 
128
                } else if ( rc == LDAP_NO_SUCH_ATTRIBUTE ) {
 
129
                        if ( permissive ) {
 
130
                                idx[i] = -1;
 
131
                                continue;
 
132
                        }
 
133
                        *text = textbuf;
 
134
                        snprintf( textbuf, textlen,
 
135
                                "modify/delete: %s: no such value",
 
136
                                mod->sm_desc->ad_cname.bv_val );
 
137
                        goto return_result;
 
138
                } else {
 
139
                        *text = textbuf;
 
140
                        snprintf( textbuf, textlen,
 
141
                                "modify/delete: %s: matching rule failed",
 
142
                                mod->sm_desc->ad_cname.bv_val );
 
143
                        goto return_result;
 
144
                }
 
145
        }
 
146
 
 
147
        num = a->a_numvals;
 
148
 
 
149
        /* Delete the values */
 
150
        for ( i = 0; i < mod->sm_numvals; i++ ) {
 
151
                /* Skip permissive values that weren't found */
 
152
                if ( idx[i] < 0 )
 
153
                        continue;
 
154
                /* Skip duplicate delete specs */
 
155
                if ( a->a_vals[idx[i]].bv_val == &dummy )
 
156
                        continue;
 
157
                /* delete value and mark it as gone */
 
158
                free( a->a_vals[idx[i]].bv_val );
 
159
                a->a_vals[idx[i]].bv_val = &dummy;
 
160
                if( a->a_nvals != a->a_vals ) {
 
161
                        free( a->a_nvals[idx[i]].bv_val );
 
162
                        a->a_nvals[idx[i]].bv_val = &dummy;
 
163
                }
 
164
                a->a_numvals--;
 
165
        }
 
166
 
 
167
        /* compact array */
 
168
        for ( i=0; i<num; i++ ) {
 
169
                if ( a->a_vals[i].bv_val != &dummy )
 
170
                        continue;
 
171
                for ( --num; num > i && a->a_vals[num].bv_val == &dummy; num-- )
 
172
                        ;
 
173
                a->a_vals[i] = a->a_vals[num];
 
174
                if ( a->a_nvals != a->a_vals )
 
175
                        a->a_nvals[i] = a->a_nvals[num];
 
176
        }
 
177
 
 
178
        BER_BVZERO( &a->a_vals[num] );
 
179
        if (a->a_nvals != a->a_vals) {
 
180
                BER_BVZERO( &a->a_nvals[num] );
 
181
        }
 
182
 
 
183
        /* if no values remain, delete the entire attribute */
 
184
        if ( !a->a_numvals ) {
 
185
                if ( attr_delete( &e->e_attrs, mod->sm_desc ) ) {
 
186
                        /* Can never happen */
 
187
                        *text = textbuf;
 
188
                        snprintf( textbuf, textlen,
 
189
                                "modify/delete: %s: no such attribute",
 
190
                                mod->sm_desc->ad_cname.bv_val );
 
191
                        rc = LDAP_NO_SUCH_ATTRIBUTE;
 
192
                }
 
193
        }
 
194
return_result:
 
195
        if ( id2 )
 
196
                ch_free( id2 );
 
197
        return rc;
 
198
}
 
199
 
 
200
int ndb_modify_internal(
 
201
        Operation *op,
 
202
        NdbArgs *NA,
 
203
        const char **text,
 
204
        char *textbuf,
 
205
        size_t textlen )
 
206
{
 
207
        struct ndb_info *ni = (struct ndb_info *) op->o_bd->be_private;
 
208
        Modification    *mod;
 
209
        Modifications   *ml;
 
210
        Modifications   *modlist = op->orm_modlist;
 
211
        NdbAttrInfo **modai, *atmp;
 
212
        const NdbDictionary::Dictionary *myDict;
 
213
        const NdbDictionary::Table *myTable;
 
214
        int got_oc = 0, nmods = 0, nai = 0, i, j;
 
215
        int rc, indexed = 0;
 
216
        Attribute *old = NULL;
 
217
 
 
218
        Debug( LDAP_DEBUG_TRACE, "ndb_modify_internal: 0x%08lx: %s\n",
 
219
                NA->e->e_id, NA->e->e_dn, 0);
 
220
 
 
221
        if ( !acl_check_modlist( op, NA->e, modlist )) {
 
222
                return LDAP_INSUFFICIENT_ACCESS;
 
223
        }
 
224
 
 
225
        old = attrs_dup( NA->e->e_attrs );
 
226
 
 
227
        for ( ml = modlist; ml != NULL; ml = ml->sml_next ) {
 
228
                mod = &ml->sml_mod;
 
229
                nmods++;
 
230
 
 
231
                switch ( mod->sm_op ) {
 
232
                case LDAP_MOD_ADD:
 
233
                        Debug(LDAP_DEBUG_ARGS,
 
234
                                "ndb_modify_internal: add %s\n",
 
235
                                mod->sm_desc->ad_cname.bv_val, 0, 0);
 
236
                        rc = modify_add_values( NA->e, mod, get_permissiveModify(op),
 
237
                                text, textbuf, textlen );
 
238
                        if( rc != LDAP_SUCCESS ) {
 
239
                                Debug(LDAP_DEBUG_ARGS, "ndb_modify_internal: %d %s\n",
 
240
                                        rc, *text, 0);
 
241
                        }
 
242
                        break;
 
243
 
 
244
                case LDAP_MOD_DELETE:
 
245
                        Debug(LDAP_DEBUG_ARGS,
 
246
                                "ndb_modify_internal: delete %s\n",
 
247
                                mod->sm_desc->ad_cname.bv_val, 0, 0);
 
248
                        rc = ndb_modify_delete( NA->e, mod, get_permissiveModify(op),
 
249
                                text, textbuf, textlen, NULL );
 
250
                        assert( rc != LDAP_TYPE_OR_VALUE_EXISTS );
 
251
                        if( rc != LDAP_SUCCESS ) {
 
252
                                Debug(LDAP_DEBUG_ARGS, "ndb_modify_internal: %d %s\n",
 
253
                                        rc, *text, 0);
 
254
                        }
 
255
                        break;
 
256
 
 
257
                case LDAP_MOD_REPLACE:
 
258
                        Debug(LDAP_DEBUG_ARGS,
 
259
                                "ndb_modify_internal: replace %s\n",
 
260
                                mod->sm_desc->ad_cname.bv_val, 0, 0);
 
261
                        rc = modify_replace_values( NA->e, mod, get_permissiveModify(op),
 
262
                                text, textbuf, textlen );
 
263
                        if( rc != LDAP_SUCCESS ) {
 
264
                                Debug(LDAP_DEBUG_ARGS, "ndb_modify_internal: %d %s\n",
 
265
                                        rc, *text, 0);
 
266
                        }
 
267
                        break;
 
268
 
 
269
                case LDAP_MOD_INCREMENT:
 
270
                        Debug(LDAP_DEBUG_ARGS,
 
271
                                "ndb_modify_internal: increment %s\n",
 
272
                                mod->sm_desc->ad_cname.bv_val, 0, 0);
 
273
                        rc = modify_increment_values( NA->e, mod, get_permissiveModify(op),
 
274
                                text, textbuf, textlen );
 
275
                        if( rc != LDAP_SUCCESS ) {
 
276
                                Debug(LDAP_DEBUG_ARGS,
 
277
                                        "ndb_modify_internal: %d %s\n",
 
278
                                        rc, *text, 0);
 
279
                        }
 
280
                        break;
 
281
 
 
282
                case SLAP_MOD_SOFTADD:
 
283
                        Debug(LDAP_DEBUG_ARGS,
 
284
                                "ndb_modify_internal: softadd %s\n",
 
285
                                mod->sm_desc->ad_cname.bv_val, 0, 0);
 
286
                        mod->sm_op = LDAP_MOD_ADD;
 
287
 
 
288
                        rc = modify_add_values( NA->e, mod, get_permissiveModify(op),
 
289
                                text, textbuf, textlen );
 
290
 
 
291
                        mod->sm_op = SLAP_MOD_SOFTADD;
 
292
 
 
293
                        if ( rc == LDAP_TYPE_OR_VALUE_EXISTS ) {
 
294
                                rc = LDAP_SUCCESS;
 
295
                        }
 
296
 
 
297
                        if( rc != LDAP_SUCCESS ) {
 
298
                                Debug(LDAP_DEBUG_ARGS, "ndb_modify_internal: %d %s\n",
 
299
                                        rc, *text, 0);
 
300
                        }
 
301
                        break;
 
302
 
 
303
                default:
 
304
                        Debug(LDAP_DEBUG_ANY, "ndb_modify_internal: invalid op %d\n",
 
305
                                mod->sm_op, 0, 0);
 
306
                        *text = "Invalid modify operation";
 
307
                        rc = LDAP_OTHER;
 
308
                        Debug(LDAP_DEBUG_ARGS, "ndb_modify_internal: %d %s\n",
 
309
                                rc, *text, 0);
 
310
                }
 
311
 
 
312
                if ( rc != LDAP_SUCCESS ) {
 
313
                        attrs_free( old );
 
314
                        return rc; 
 
315
                }
 
316
 
 
317
                /* If objectClass was modified, reset the flags */
 
318
                if ( mod->sm_desc == slap_schema.si_ad_objectClass ) {
 
319
                        NA->e->e_ocflags = 0;
 
320
                        got_oc = 1;
 
321
                }
 
322
        }
 
323
 
 
324
        /* check that the entry still obeys the schema */
 
325
        rc = entry_schema_check( op, NA->e, NULL, get_relax(op), 0, NULL,
 
326
                text, textbuf, textlen );
 
327
        if ( rc != LDAP_SUCCESS || op->o_noop ) {
 
328
                if ( rc != LDAP_SUCCESS ) {
 
329
                        Debug( LDAP_DEBUG_ANY,
 
330
                                "entry failed schema check: %s\n",
 
331
                                *text, 0, 0 );
 
332
                }
 
333
                attrs_free( old );
 
334
                return rc;
 
335
        }
 
336
 
 
337
        /* apply modifications to DB */
 
338
        modai = (NdbAttrInfo **)op->o_tmpalloc( nmods * sizeof(NdbAttrInfo*), op->o_tmpmemctx );
 
339
 
 
340
        /* Get the unique list of modified attributes */
 
341
        ldap_pvt_thread_rdwr_rlock( &ni->ni_ai_rwlock );
 
342
        for ( ml = modlist; ml != NULL; ml = ml->sml_next ) {
 
343
                /* Already took care of objectclass */
 
344
                if ( ml->sml_desc == slap_schema.si_ad_objectClass )
 
345
                        continue;
 
346
                for ( i=0; i<nai; i++ ) {
 
347
                        if ( ml->sml_desc->ad_type == modai[i]->na_attr )
 
348
                                break;
 
349
                }
 
350
                /* This attr was already updated */
 
351
                if ( i < nai )
 
352
                        continue;
 
353
                modai[nai] = ndb_ai_find( ni, ml->sml_desc->ad_type );
 
354
                if ( modai[nai]->na_flag & NDB_INFO_INDEX )
 
355
                        indexed++;
 
356
                nai++;
 
357
        }
 
358
        ldap_pvt_thread_rdwr_runlock( &ni->ni_ai_rwlock );
 
359
 
 
360
        if ( got_oc || indexed ) {
 
361
                rc = ndb_entry_put_info( op->o_bd, NA, 1 );
 
362
                if ( rc ) {
 
363
                        attrs_free( old );
 
364
                        return rc;
 
365
                }
 
366
        }
 
367
 
 
368
        myDict = NA->ndb->getDictionary();
 
369
 
 
370
        /* sort modai so that OcInfo's are contiguous */
 
371
        {
 
372
                int j, k;
 
373
                for ( i=0; i<nai; i++ ) {
 
374
                        for ( j=i+1; j<nai; j++ ) {
 
375
                                if ( modai[i]->na_oi == modai[j]->na_oi )
 
376
                                        continue;
 
377
                                for ( k=j+1; k<nai; k++ ) {
 
378
                                        if ( modai[i]->na_oi == modai[k]->na_oi ) {
 
379
                                                atmp = modai[j];
 
380
                                                modai[j] = modai[k];
 
381
                                                modai[k] = atmp;
 
382
                                                break;
 
383
                                        }
 
384
                                }
 
385
                                /* there are no more na_oi's that match modai[i] */
 
386
                                if ( k == nai ) {
 
387
                                        i = j;
 
388
                                }
 
389
                        }
 
390
                }
 
391
        }
 
392
 
 
393
        /* One call per table... */
 
394
        for ( i=0; i<nai; i += j ) {
 
395
                atmp = modai[i];
 
396
                for ( j=i+1; j<nai; j++ )
 
397
                        if ( atmp->na_oi != modai[j]->na_oi )
 
398
                                break;
 
399
                j -= i;
 
400
                myTable = myDict->getTable( atmp->na_oi->no_table.bv_val );
 
401
                if ( !myTable )
 
402
                        continue;
 
403
                rc = ndb_oc_attrs( NA->txn, myTable, NA->e, atmp->na_oi, &modai[i], j, old );
 
404
                if ( rc ) break;
 
405
        }
 
406
        attrs_free( old );
 
407
        return rc;
 
408
}
 
409
 
 
410
 
 
411
int
 
412
ndb_back_modify( Operation *op, SlapReply *rs )
 
413
{
 
414
        struct ndb_info *ni = (struct ndb_info *) op->o_bd->be_private;
 
415
        Entry           e = {0};
 
416
        int             manageDSAit = get_manageDSAit( op );
 
417
        char textbuf[SLAP_TEXT_BUFLEN];
 
418
        size_t textlen = sizeof textbuf;
 
419
 
 
420
        int             num_retries = 0;
 
421
 
 
422
        NdbArgs NA;
 
423
        NdbRdns rdns;
 
424
        struct berval matched;
 
425
 
 
426
        LDAPControl **preread_ctrl = NULL;
 
427
        LDAPControl **postread_ctrl = NULL;
 
428
        LDAPControl *ctrls[SLAP_MAX_RESPONSE_CONTROLS];
 
429
        int num_ctrls = 0;
 
430
 
 
431
        Debug( LDAP_DEBUG_ARGS, LDAP_XSTRING(ndb_back_modify) ": %s\n",
 
432
                op->o_req_dn.bv_val, 0, 0 );
 
433
 
 
434
        ctrls[num_ctrls] = NULL;
 
435
 
 
436
        slap_mods_opattrs( op, &op->orm_modlist, 1 );
 
437
 
 
438
        e.e_name = op->o_req_dn;
 
439
        e.e_nname = op->o_req_ndn;
 
440
 
 
441
        /* Get our NDB handle */
 
442
        rs->sr_err = ndb_thread_handle( op, &NA.ndb );
 
443
        rdns.nr_num = 0;
 
444
        NA.rdns = &rdns;
 
445
        NA.e = &e;
 
446
 
 
447
        if( 0 ) {
 
448
retry:  /* transaction retry */
 
449
                NA.txn->close();
 
450
                NA.txn = NULL;
 
451
                if( e.e_attrs ) {
 
452
                        attrs_free( e.e_attrs );
 
453
                        e.e_attrs = NULL;
 
454
                }
 
455
                Debug(LDAP_DEBUG_TRACE,
 
456
                        LDAP_XSTRING(ndb_back_modify) ": retrying...\n", 0, 0, 0);
 
457
                if ( op->o_abandon ) {
 
458
                        rs->sr_err = SLAPD_ABANDON;
 
459
                        goto return_results;
 
460
                }
 
461
                if ( NA.ocs ) {
 
462
                        ber_bvarray_free_x( NA.ocs, op->o_tmpmemctx );
 
463
                }
 
464
                ndb_trans_backoff( ++num_retries );
 
465
        }
 
466
        NA.ocs = NULL;
 
467
 
 
468
        /* begin transaction */
 
469
        NA.txn = NA.ndb->startTransaction();
 
470
        rs->sr_text = NULL;
 
471
        if( !NA.txn ) {
 
472
                Debug( LDAP_DEBUG_TRACE,
 
473
                        LDAP_XSTRING(ndb_back_modify) ": startTransaction failed: %s (%d)\n",
 
474
                        NA.ndb->getNdbError().message, NA.ndb->getNdbError().code, 0 );
 
475
                rs->sr_err = LDAP_OTHER;
 
476
                rs->sr_text = "internal error";
 
477
                goto return_results;
 
478
        }
 
479
 
 
480
        /* get entry or ancestor */
 
481
        rs->sr_err = ndb_entry_get_info( op, &NA, 0, &matched );
 
482
        switch( rs->sr_err ) {
 
483
        case 0:
 
484
                break;
 
485
        case LDAP_NO_SUCH_OBJECT:
 
486
                Debug( LDAP_DEBUG_ARGS,
 
487
                        "<=- ndb_back_modify: no such object %s\n",
 
488
                        op->o_req_dn.bv_val, 0, 0 );
 
489
                rs->sr_matched = matched.bv_val;
 
490
                if (NA.ocs )
 
491
                        ndb_check_referral( op, rs, &NA );
 
492
                goto return_results;
 
493
#if 0
 
494
        case DB_LOCK_DEADLOCK:
 
495
        case DB_LOCK_NOTGRANTED:
 
496
                goto retry;
 
497
#endif
 
498
        case LDAP_BUSY:
 
499
                rs->sr_text = "ldap server busy";
 
500
                goto return_results;
 
501
        default:
 
502
                rs->sr_err = LDAP_OTHER;
 
503
                rs->sr_text = "internal error";
 
504
                goto return_results;
 
505
        }
 
506
 
 
507
        /* acquire and lock entry */
 
508
        rs->sr_err = ndb_entry_get_data( op, &NA, 1 );
 
509
 
 
510
        if ( !manageDSAit && is_entry_referral( &e ) ) {
 
511
                /* entry is a referral, don't allow modify */
 
512
                rs->sr_ref = get_entry_referrals( op, &e );
 
513
 
 
514
                Debug( LDAP_DEBUG_TRACE,
 
515
                        LDAP_XSTRING(ndb_back_modify) ": entry is referral\n",
 
516
                        0, 0, 0 );
 
517
 
 
518
                rs->sr_err = LDAP_REFERRAL;
 
519
                rs->sr_matched = e.e_name.bv_val;
 
520
                rs->sr_flags = REP_REF_MUSTBEFREED;
 
521
                goto return_results;
 
522
        }
 
523
 
 
524
        if ( get_assert( op ) &&
 
525
                ( test_filter( op, &e, (Filter*)get_assertion( op )) != LDAP_COMPARE_TRUE ))
 
526
        {
 
527
                rs->sr_err = LDAP_ASSERTION_FAILED;
 
528
                goto return_results;
 
529
        }
 
530
 
 
531
        if( op->o_preread ) {
 
532
                if( preread_ctrl == NULL ) {
 
533
                        preread_ctrl = &ctrls[num_ctrls++];
 
534
                        ctrls[num_ctrls] = NULL;
 
535
                }
 
536
                if ( slap_read_controls( op, rs, &e,
 
537
                        &slap_pre_read_bv, preread_ctrl ) )
 
538
                {
 
539
                        Debug( LDAP_DEBUG_TRACE,
 
540
                                "<=- " LDAP_XSTRING(ndb_back_modify) ": pre-read "
 
541
                                "failed!\n", 0, 0, 0 );
 
542
                        if ( op->o_preread & SLAP_CONTROL_CRITICAL ) {
 
543
                                /* FIXME: is it correct to abort
 
544
                                 * operation if control fails? */
 
545
                                goto return_results;
 
546
                        }
 
547
                }
 
548
        }
 
549
 
 
550
        /* Modify the entry */
 
551
        rs->sr_err = ndb_modify_internal( op, &NA, &rs->sr_text, textbuf, textlen );
 
552
 
 
553
        if( rs->sr_err != LDAP_SUCCESS ) {
 
554
                Debug( LDAP_DEBUG_TRACE,
 
555
                        LDAP_XSTRING(ndb_back_modify) ": modify failed (%d)\n",
 
556
                        rs->sr_err, 0, 0 );
 
557
#if 0
 
558
                switch( rs->sr_err ) {
 
559
                case DB_LOCK_DEADLOCK:
 
560
                case DB_LOCK_NOTGRANTED:
 
561
                        goto retry;
 
562
                }
 
563
#endif
 
564
                goto return_results;
 
565
        }
 
566
 
 
567
        if( op->o_postread ) {
 
568
                if( postread_ctrl == NULL ) {
 
569
                        postread_ctrl = &ctrls[num_ctrls++];
 
570
                        ctrls[num_ctrls] = NULL;
 
571
                }
 
572
                if( slap_read_controls( op, rs, &e,
 
573
                        &slap_post_read_bv, postread_ctrl ) )
 
574
                {
 
575
                        Debug( LDAP_DEBUG_TRACE,
 
576
                                "<=- " LDAP_XSTRING(ndb_back_modify)
 
577
                                ": post-read failed!\n", 0, 0, 0 );
 
578
                        if ( op->o_postread & SLAP_CONTROL_CRITICAL ) {
 
579
                                /* FIXME: is it correct to abort
 
580
                                 * operation if control fails? */
 
581
                                goto return_results;
 
582
                        }
 
583
                }
 
584
        }
 
585
 
 
586
        if( op->o_noop ) {
 
587
                if (( rs->sr_err=NA.txn->execute( NdbTransaction::Rollback,
 
588
                        NdbOperation::AbortOnError, 1 )) != 0 ) {
 
589
                        rs->sr_text = "txn_abort (no-op) failed";
 
590
                } else {
 
591
                        rs->sr_err = LDAP_X_NO_OPERATION;
 
592
                }
 
593
        } else {
 
594
                if (( rs->sr_err=NA.txn->execute( NdbTransaction::Commit,
 
595
                        NdbOperation::AbortOnError, 1 )) != 0 ) {
 
596
                        rs->sr_text = "txn_commit failed";
 
597
                } else {
 
598
                        rs->sr_err = LDAP_SUCCESS;
 
599
                }
 
600
        }
 
601
 
 
602
        if( rs->sr_err != LDAP_SUCCESS && rs->sr_err != LDAP_X_NO_OPERATION ) {
 
603
                Debug( LDAP_DEBUG_TRACE,
 
604
                        LDAP_XSTRING(ndb_back_modify) ": txn_%s failed: %s (%d)\n",
 
605
                        op->o_noop ? "abort (no-op)" : "commit",
 
606
                        NA.txn->getNdbError().message, NA.txn->getNdbError().code );
 
607
                rs->sr_err = LDAP_OTHER;
 
608
                goto return_results;
 
609
        }
 
610
        NA.txn->close();
 
611
        NA.txn = NULL;
 
612
 
 
613
        Debug( LDAP_DEBUG_TRACE,
 
614
                LDAP_XSTRING(ndb_back_modify) ": updated%s id=%08lx dn=\"%s\"\n",
 
615
                op->o_noop ? " (no-op)" : "",
 
616
                e.e_id, op->o_req_dn.bv_val );
 
617
 
 
618
        rs->sr_err = LDAP_SUCCESS;
 
619
        rs->sr_text = NULL;
 
620
        if( num_ctrls ) rs->sr_ctrls = ctrls;
 
621
 
 
622
return_results:
 
623
        if ( NA.ocs ) {
 
624
                ber_bvarray_free_x( NA.ocs, op->o_tmpmemctx );
 
625
                NA.ocs = NULL;
 
626
        }
 
627
 
 
628
        if ( e.e_attrs != NULL ) {
 
629
                attrs_free( e.e_attrs );
 
630
                e.e_attrs = NULL;
 
631
        }
 
632
 
 
633
        if( NA.txn != NULL ) {
 
634
                NA.txn->execute( Rollback );
 
635
                NA.txn->close();
 
636
        }
 
637
 
 
638
        send_ldap_result( op, rs );
 
639
        slap_graduate_commit_csn( op );
 
640
 
 
641
        if( preread_ctrl != NULL && (*preread_ctrl) != NULL ) {
 
642
                slap_sl_free( (*preread_ctrl)->ldctl_value.bv_val, op->o_tmpmemctx );
 
643
                slap_sl_free( *preread_ctrl, op->o_tmpmemctx );
 
644
        }
 
645
        if( postread_ctrl != NULL && (*postread_ctrl) != NULL ) {
 
646
                slap_sl_free( (*postread_ctrl)->ldctl_value.bv_val, op->o_tmpmemctx );
 
647
                slap_sl_free( *postread_ctrl, op->o_tmpmemctx );
 
648
        }
 
649
 
 
650
        rs->sr_text = NULL;
 
651
        return rs->sr_err;
 
652
}