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

« back to all changes in this revision

Viewing changes to servers/slapd/back-ndb/search.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
/* search.cpp - tools for slap tools */
 
2
/* $OpenLDAP: pkg/ldap/servers/slapd/back-ndb/search.cpp,v 1.3.2.2 2009/01/22 00:01:09 kurt 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/errno.h>
 
26
 
 
27
#include "lutil.h"
 
28
 
 
29
#include "back-ndb.h"
 
30
 
 
31
static int
 
32
ndb_dn2bound(
 
33
        NdbIndexScanOperation *myop,
 
34
        NdbRdns *rdns
 
35
)
 
36
{
 
37
        unsigned int i;
 
38
 
 
39
        /* Walk thru RDNs */
 
40
        for ( i=0; i<rdns->nr_num; i++ ) {
 
41
                /* Note: RDN_COLUMN offset not needed here */
 
42
                if ( myop->setBound( i, NdbIndexScanOperation::BoundEQ, rdns->nr_buf[i] ))
 
43
                        return LDAP_OTHER;
 
44
        }
 
45
        return i;
 
46
}
 
47
 
 
48
/* Check that all filter terms reside in the same table.
 
49
 *
 
50
 * If any of the filter terms are indexed, then only an IndexScan of the OL_index
 
51
 * will be performed. If none are indexed, but all the terms reside in a single
 
52
 * table, a Scan can be performed with the LDAP filter transformed into a ScanFilter.
 
53
 *
 
54
 * Otherwise, a full scan of the DB must be done with all filtering done by slapd.
 
55
 */
 
56
static int ndb_filter_check( struct ndb_info *ni, Filter *f,
 
57
        NdbOcInfo **oci, int *indexed, int *ocfilter )
 
58
{
 
59
        AttributeDescription *ad = NULL;
 
60
        ber_tag_t choice = f->f_choice;
 
61
        int rc = 0, undef = 0;
 
62
 
 
63
        if ( choice & SLAPD_FILTER_UNDEFINED ) {
 
64
                choice &= SLAPD_FILTER_MASK;
 
65
                undef = 1;
 
66
        }
 
67
        switch( choice ) {
 
68
        case LDAP_FILTER_AND:
 
69
        case LDAP_FILTER_OR:
 
70
        case LDAP_FILTER_NOT:
 
71
                for ( f = f->f_list; f; f=f->f_next ) {
 
72
                        rc = ndb_filter_check( ni, f, oci, indexed, ocfilter );
 
73
                        if ( rc ) return rc;
 
74
                }
 
75
                break;
 
76
        case LDAP_FILTER_PRESENT:
 
77
                ad = f->f_desc;
 
78
                break;
 
79
        case LDAP_FILTER_EQUALITY:
 
80
        case LDAP_FILTER_SUBSTRINGS:
 
81
        case LDAP_FILTER_GE:
 
82
        case LDAP_FILTER_LE:
 
83
        case LDAP_FILTER_APPROX:
 
84
                ad = f->f_av_desc;
 
85
                break;
 
86
        default:
 
87
                break;
 
88
        }
 
89
        if ( ad && !undef ) {
 
90
                NdbAttrInfo *ai;
 
91
                /* ObjectClass filtering is in dn2id table */
 
92
                if ( ad == slap_schema.si_ad_objectClass ) {
 
93
                        if ( choice == LDAP_FILTER_EQUALITY )
 
94
                                (*ocfilter)++;
 
95
                        return 0;
 
96
                }
 
97
                ai = ndb_ai_find( ni, ad->ad_type );
 
98
                if ( ai ) {
 
99
                        if ( ai->na_flag & NDB_INFO_INDEX )
 
100
                                (*indexed)++;
 
101
                        if ( *oci ) {
 
102
                                if ( ai->na_oi != *oci )
 
103
                                        rc = -1;
 
104
                        } else {
 
105
                                *oci = ai->na_oi;
 
106
                        }
 
107
                }
 
108
        }
 
109
        return rc;
 
110
}
 
111
 
 
112
static int ndb_filter_set( Operation *op, struct ndb_info *ni, Filter *f, int indexed,
 
113
        NdbIndexScanOperation *scan, NdbScanFilter *sf, int *bounds )
 
114
{
 
115
        AttributeDescription *ad = NULL;
 
116
        ber_tag_t choice = f->f_choice;
 
117
        int undef = 0;
 
118
 
 
119
        if ( choice & SLAPD_FILTER_UNDEFINED ) {
 
120
                choice &= SLAPD_FILTER_MASK;
 
121
                undef = 1;
 
122
        }
 
123
        switch( choice ) {
 
124
        case LDAP_FILTER_NOT:
 
125
                /* no indexing for these */
 
126
                break;
 
127
        case LDAP_FILTER_OR:
 
128
                /* FIXME: these bounds aren't right. */
 
129
                if ( indexed ) {
 
130
                        scan->end_of_bound( (*bounds)++ );
 
131
                }
 
132
        case LDAP_FILTER_AND:
 
133
                if ( sf ) {
 
134
                        sf->begin( choice == LDAP_FILTER_OR ? NdbScanFilter::OR : NdbScanFilter::AND );
 
135
                }
 
136
                for ( f = f->f_list; f; f=f->f_next ) {
 
137
                        if ( ndb_filter_set( op, ni, f, indexed, scan, sf, bounds ))
 
138
                                return -1;
 
139
                }
 
140
                if ( sf ) {
 
141
                        sf->end();
 
142
                }
 
143
                break;
 
144
        case LDAP_FILTER_PRESENT:
 
145
                ad = f->f_desc;
 
146
                break;
 
147
        case LDAP_FILTER_EQUALITY:
 
148
        case LDAP_FILTER_SUBSTRINGS:
 
149
        case LDAP_FILTER_GE:
 
150
        case LDAP_FILTER_LE:
 
151
        case LDAP_FILTER_APPROX:
 
152
                ad = f->f_av_desc;
 
153
                break;
 
154
        default:
 
155
                break;
 
156
        }
 
157
        if ( ad && !undef ) {
 
158
                NdbAttrInfo *ai;
 
159
                /* ObjectClass filtering is in dn2id table */
 
160
                if ( ad == slap_schema.si_ad_objectClass ) {
 
161
                        return 0;
 
162
                }
 
163
                ai = ndb_ai_find( ni, ad->ad_type );
 
164
                if ( ai ) {
 
165
                        int rc;
 
166
                        if ( ai->na_flag & NDB_INFO_INDEX ) {
 
167
                                char *buf, *ptr;
 
168
                                NdbIndexScanOperation::BoundType bt;
 
169
 
 
170
                                switch(choice) {
 
171
                                case LDAP_FILTER_PRESENT:
 
172
                                        rc = scan->setBound( ai->na_ixcol - IDX_COLUMN,
 
173
                                                NdbIndexScanOperation::BoundGT, NULL );
 
174
                                        break;
 
175
                                case LDAP_FILTER_EQUALITY:
 
176
                                case LDAP_FILTER_APPROX:
 
177
                                        bt = NdbIndexScanOperation::BoundEQ;
 
178
                                        goto setit;
 
179
                                case LDAP_FILTER_GE:
 
180
                                        bt = NdbIndexScanOperation::BoundGE;
 
181
                                        goto setit;
 
182
                                case LDAP_FILTER_LE:
 
183
                                        bt = NdbIndexScanOperation::BoundLE;
 
184
                                setit:
 
185
                                        rc = f->f_av_value.bv_len+1;
 
186
                                        if ( ai->na_len > 255 )
 
187
                                                rc++;
 
188
                                        buf = (char *)op->o_tmpalloc( rc, op->o_tmpmemctx );
 
189
                                        rc = f->f_av_value.bv_len;
 
190
                                        buf[0] = rc & 0xff;
 
191
                                        ptr = buf+1;
 
192
                                        if ( ai->na_len > 255 ) {
 
193
                                                buf[1] = (rc >> 8);
 
194
                                                ptr++;
 
195
                                        }
 
196
                                        memcpy( ptr, f->f_av_value.bv_val, f->f_av_value.bv_len );
 
197
                                        rc = scan->setBound( ai->na_ixcol - IDX_COLUMN, bt, buf );
 
198
                                        op->o_tmpfree( buf, op->o_tmpmemctx );
 
199
                                        break;
 
200
                                default:
 
201
                                        break;
 
202
                                }
 
203
                        } else if ( sf ) {
 
204
                                char *buf, *ptr;
 
205
                                NdbScanFilter::BinaryCondition bc;
 
206
 
 
207
                                switch(choice) {
 
208
                                case LDAP_FILTER_PRESENT:
 
209
                                        rc = sf->isnotnull( ai->na_column );
 
210
                                        break;
 
211
                                case LDAP_FILTER_EQUALITY:
 
212
                                case LDAP_FILTER_APPROX:
 
213
                                        bc = NdbScanFilter::COND_EQ;
 
214
                                        goto setf;
 
215
                                case LDAP_FILTER_GE:
 
216
                                        bc = NdbScanFilter::COND_GE;
 
217
                                        goto setf;
 
218
                                case LDAP_FILTER_LE:
 
219
                                        bc = NdbScanFilter::COND_LE;
 
220
                                setf:
 
221
                                        rc = sf->cmp( bc, ai->na_column, f->f_av_value.bv_val, f->f_av_value.bv_len );
 
222
                                        break;
 
223
                                case LDAP_FILTER_SUBSTRINGS:
 
224
                                        rc = 0;
 
225
                                        if ( f->f_sub_initial.bv_val )
 
226
                                                rc += f->f_sub_initial.bv_len + 1;
 
227
                                        if ( f->f_sub_any ) {
 
228
                                                int i;
 
229
                                                if ( !rc ) rc++;
 
230
                                                for (i=0; f->f_sub_any[i].bv_val; i++)
 
231
                                                        rc += f->f_sub_any[i].bv_len + 1;
 
232
                                        }
 
233
                                        if ( f->f_sub_final.bv_val ) {
 
234
                                                if ( !rc ) rc++;
 
235
                                                rc += f->f_sub_final.bv_len;
 
236
                                        }
 
237
                                        buf = (char *)op->o_tmpalloc( rc+1, op->o_tmpmemctx );
 
238
                                        ptr = buf;
 
239
                                        if ( f->f_sub_initial.bv_val ) {
 
240
                                                memcpy( ptr, f->f_sub_initial.bv_val, f->f_sub_initial.bv_len );
 
241
                                                ptr += f->f_sub_initial.bv_len;
 
242
                                                *ptr++ = '%';
 
243
                                        }
 
244
                                        if ( f->f_sub_any ) {
 
245
                                                int i;
 
246
                                                if ( ptr == buf )
 
247
                                                        *ptr++ = '%';
 
248
                                                for (i=0; f->f_sub_any[i].bv_val; i++) {
 
249
                                                        memcpy( ptr, f->f_sub_any[i].bv_val, f->f_sub_any[i].bv_len );
 
250
                                                        ptr += f->f_sub_any[i].bv_len;
 
251
                                                        *ptr++ = '%';
 
252
                                                }
 
253
                                        }
 
254
                                        if ( f->f_sub_final.bv_val ) {
 
255
                                                if ( ptr == buf )
 
256
                                                        *ptr++ = '%';
 
257
                                                memcpy( ptr, f->f_sub_final.bv_val, f->f_sub_final.bv_len );
 
258
                                                ptr += f->f_sub_final.bv_len;
 
259
                                        }
 
260
                                        *ptr = '\0';
 
261
                                        rc = sf->cmp( NdbScanFilter::COND_LIKE, ai->na_column, buf, ptr - buf );
 
262
                                        op->o_tmpfree( buf, op->o_tmpmemctx );
 
263
                                        break;
 
264
                                }
 
265
                        }
 
266
                }
 
267
        }
 
268
        return 0;
 
269
}
 
270
 
 
271
static int ndb_oc_search( Operation *op, SlapReply *rs, Ndb *ndb, NdbTransaction *txn,
 
272
        NdbRdns *rbase, NdbOcInfo *oci, int indexed )
 
273
{
 
274
        struct ndb_info *ni = (struct ndb_info *) op->o_bd->be_private;
 
275
        const NdbDictionary::Dictionary *myDict = ndb->getDictionary();
 
276
        const NdbDictionary::Table *myTable;
 
277
        const NdbDictionary::Index *myIndex;
 
278
        NdbIndexScanOperation *scan;
 
279
        NdbIndexOperation *ixop;
 
280
        NdbScanFilter *sf = NULL;
 
281
        struct berval *ocs;
 
282
        NdbRecAttr *scanID, *scanOC, *scanDN[NDB_MAX_RDNS];
 
283
        char dnBuf[2048], *ptr;
 
284
        NdbRdns rdns;
 
285
        NdbArgs NA;
 
286
        char idbuf[2*sizeof(ID)];
 
287
        char ocbuf[NDB_OC_BUFLEN];
 
288
        int i, rc, bounds;
 
289
        Entry e = {0};
 
290
        Uint64 eid;
 
291
        time_t stoptime;
 
292
        int manageDSAit;
 
293
 
 
294
        stoptime = op->o_time + op->ors_tlimit;
 
295
        manageDSAit = get_manageDSAit( op );
 
296
 
 
297
        myTable = myDict->getTable( oci->no_table.bv_val );
 
298
        if ( indexed ) { 
 
299
                scan = txn->getNdbIndexScanOperation( INDEX_NAME, DN2ID_TABLE );
 
300
                if ( !scan )
 
301
                        return LDAP_OTHER;
 
302
                scan->readTuples( NdbOperation::LM_CommittedRead );
 
303
        } else {
 
304
                myIndex = myDict->getIndex( "eid$unique", DN2ID_TABLE );
 
305
                if ( !myIndex ) {
 
306
                        Debug( LDAP_DEBUG_ANY, DN2ID_TABLE " eid index is missing!\n", 0, 0, 0 );
 
307
                        rs->sr_err = LDAP_OTHER;
 
308
                        goto leave;
 
309
                }
 
310
                scan = (NdbIndexScanOperation *)txn->getNdbScanOperation( myTable );
 
311
                if ( !scan )
 
312
                        return LDAP_OTHER;
 
313
                scan->readTuples( NdbOperation::LM_CommittedRead );
 
314
#if 1
 
315
                sf = new NdbScanFilter(scan);
 
316
                if ( !sf )
 
317
                        return LDAP_OTHER;
 
318
                switch ( op->ors_filter->f_choice ) {
 
319
                case LDAP_FILTER_AND:
 
320
                case LDAP_FILTER_OR:
 
321
                case LDAP_FILTER_NOT:
 
322
                        break;
 
323
                default:
 
324
                        if ( sf->begin() < 0 ) {
 
325
                                rc = LDAP_OTHER;
 
326
                                goto leave;
 
327
                        }
 
328
                }
 
329
#endif
 
330
        }
 
331
 
 
332
        bounds = 0;
 
333
        rc = ndb_filter_set( op, ni, op->ors_filter, indexed, scan, sf, &bounds );
 
334
        if ( rc )
 
335
                goto leave;
 
336
        if ( sf ) sf->end();
 
337
        
 
338
        scanID = scan->getValue( EID_COLUMN, idbuf );
 
339
        if ( indexed ) {
 
340
                scanOC = scan->getValue( OCS_COLUMN, ocbuf );
 
341
                for ( i=0; i<NDB_MAX_RDNS; i++ ) {
 
342
                        rdns.nr_buf[i][0] = '\0';
 
343
                        scanDN[i] = scan->getValue( RDN_COLUMN+i, rdns.nr_buf[i] );
 
344
                }
 
345
        }
 
346
 
 
347
        if ( txn->execute( NdbTransaction::NoCommit, NdbOperation::AbortOnError, 1 )) {
 
348
                rs->sr_err = LDAP_OTHER;
 
349
                goto leave;
 
350
        }
 
351
 
 
352
        e.e_name.bv_val = dnBuf;
 
353
        NA.e = &e;
 
354
        NA.ndb = ndb;
 
355
        while ( scan->nextResult( true, true ) == 0 ) {
 
356
                NdbTransaction *tx2;
 
357
                if ( op->o_abandon ) {
 
358
                        rs->sr_err = SLAPD_ABANDON;
 
359
                        break;
 
360
                }
 
361
                if ( slapd_shutdown ) {
 
362
                        rs->sr_err = LDAP_UNAVAILABLE;
 
363
                        break;
 
364
                }
 
365
                if ( op->ors_tlimit != SLAP_NO_LIMIT &&
 
366
                        slap_get_time() > stoptime ) {
 
367
                        rs->sr_err = LDAP_TIMELIMIT_EXCEEDED;
 
368
                        break;
 
369
                }
 
370
 
 
371
                eid = scanID->u_64_value();
 
372
                e.e_id = eid;
 
373
                if ( !indexed ) {
 
374
                        tx2 = ndb->startTransaction( myTable );
 
375
                        if ( !tx2 ) {
 
376
                                rs->sr_err = LDAP_OTHER;
 
377
                                goto leave;
 
378
                        }
 
379
 
 
380
                        ixop = tx2->getNdbIndexOperation( myIndex );
 
381
                        if ( !ixop ) {
 
382
                                tx2->close();
 
383
                                rs->sr_err = LDAP_OTHER;
 
384
                                goto leave;
 
385
                        }
 
386
                        ixop->readTuple( NdbOperation::LM_CommittedRead );
 
387
                        ixop->equal( EID_COLUMN, eid );
 
388
 
 
389
                        scanOC = ixop->getValue( OCS_COLUMN, ocbuf );
 
390
                        for ( i=0; i<NDB_MAX_RDNS; i++ ) {
 
391
                                rdns.nr_buf[i][0] = '\0';
 
392
                                scanDN[i] = ixop->getValue( RDN_COLUMN+i, rdns.nr_buf[i] );
 
393
                        }
 
394
                        rc = tx2->execute( NdbTransaction::Commit, NdbOperation::AbortOnError, 1 );
 
395
                        tx2->close();
 
396
                        if ( rc ) {
 
397
                                rs->sr_err = LDAP_OTHER;
 
398
                                goto leave;
 
399
                        }
 
400
                }
 
401
 
 
402
                ocs = ndb_ref2oclist( ocbuf, op->o_tmpmemctx );
 
403
                for ( i=0; i<NDB_MAX_RDNS; i++ ) {
 
404
                        if ( scanDN[i]->isNULL() || !rdns.nr_buf[i][0] )
 
405
                                break;
 
406
                }
 
407
                rdns.nr_num = i;
 
408
 
 
409
                /* entry must be subordinate to the base */
 
410
                if ( i < rbase->nr_num ) {
 
411
                        continue;
 
412
                }
 
413
 
 
414
                ptr = dnBuf;
 
415
                for ( --i; i>=0; i-- ) {
 
416
                        char *buf;
 
417
                        int len;
 
418
                        buf = rdns.nr_buf[i];
 
419
                        len = *buf++;
 
420
                        ptr = lutil_strncopy( ptr, buf, len );
 
421
                        if ( i ) *ptr++ = ',';
 
422
                }
 
423
                *ptr = '\0';
 
424
                e.e_name.bv_len = ptr - dnBuf;
 
425
 
 
426
                /* More scope checks */
 
427
                /* If indexed, these can be moved into the ScanFilter */
 
428
                switch( op->ors_scope ) {
 
429
                case LDAP_SCOPE_ONELEVEL:
 
430
                        if ( rdns.nr_num != rbase->nr_num+1 )
 
431
                                continue;
 
432
                case LDAP_SCOPE_SUBORDINATE:
 
433
                        if ( rdns.nr_num == rbase->nr_num )
 
434
                                continue;
 
435
                case LDAP_SCOPE_SUBTREE:
 
436
                default:
 
437
                        if ( e.e_name.bv_len <= op->o_req_dn.bv_len ) {
 
438
                                if ( op->ors_scope != LDAP_SCOPE_SUBTREE ||
 
439
                                        strcasecmp( op->o_req_dn.bv_val, e.e_name.bv_val ))
 
440
                                        continue;
 
441
                        } else if ( strcasecmp( op->o_req_dn.bv_val, e.e_name.bv_val +
 
442
                                e.e_name.bv_len - op->o_req_dn.bv_len ))
 
443
                                continue;
 
444
                }
 
445
 
 
446
                dnNormalize( 0, NULL, NULL, &e.e_name, &e.e_nname, op->o_tmpmemctx );
 
447
                {
 
448
#ifdef notdef           /* NDBapi is broken here */
 
449
                        Ndb::Key_part_ptr keys[2];
 
450
                        char xbuf[32];
 
451
                        keys[0].ptr = &eid;
 
452
                        keys[0].len = sizeof(eid);
 
453
                        keys[1].ptr = NULL;
 
454
                        keys[1].len = 0;
 
455
                        tx2 = ndb->startTransaction( myTable, keys, xbuf, sizeof(xbuf));
 
456
#else
 
457
                        tx2 = ndb->startTransaction( myTable );
 
458
#endif
 
459
                        if ( !tx2 ) {
 
460
                                rs->sr_err = LDAP_OTHER;
 
461
                                goto leave;
 
462
                        }
 
463
                        NA.txn = tx2;
 
464
                        NA.ocs = ocs;
 
465
                        rc = ndb_entry_get_data( op, &NA, 0 );
 
466
                        tx2->close();
 
467
                }
 
468
                ber_bvarray_free_x( ocs, op->o_tmpmemctx );
 
469
                if ( !manageDSAit && is_entry_referral( &e )) {
 
470
                        BerVarray erefs = get_entry_referrals( op, &e );
 
471
                        rs->sr_ref = referral_rewrite( erefs, &e.e_name, NULL,
 
472
                                op->ors_scope == LDAP_SCOPE_ONELEVEL ?
 
473
                                        LDAP_SCOPE_BASE : LDAP_SCOPE_SUBTREE );
 
474
                        rc = send_search_reference( op, rs );
 
475
                        ber_bvarray_free( rs->sr_ref );
 
476
                        ber_bvarray_free( erefs );
 
477
                        rs->sr_ref = NULL;
 
478
                } else if ( manageDSAit || !is_entry_glue( &e )) {
 
479
                        rc = test_filter( op, &e, op->ors_filter );
 
480
                        if ( rc == LDAP_COMPARE_TRUE ) {
 
481
                                rs->sr_entry = &e;
 
482
                                rs->sr_attrs = op->ors_attrs;
 
483
                                rs->sr_flags = 0;
 
484
                                rc = send_search_entry( op, rs );
 
485
                                rs->sr_entry = NULL;
 
486
                        } else {
 
487
                                rc = 0;
 
488
                        }
 
489
                }
 
490
                attrs_free( e.e_attrs );
 
491
                e.e_attrs = NULL;
 
492
                op->o_tmpfree( e.e_nname.bv_val, op->o_tmpmemctx );
 
493
                if ( rc ) break;
 
494
        }
 
495
leave:
 
496
        if ( sf ) delete sf;
 
497
        return rc;
 
498
}
 
499
 
 
500
extern "C"
 
501
int ndb_back_search( Operation *op, SlapReply *rs )
 
502
{
 
503
        struct ndb_info *ni = (struct ndb_info *) op->o_bd->be_private;
 
504
        NdbTransaction *txn;
 
505
        NdbIndexScanOperation *scan;
 
506
        NdbScanFilter *sf = NULL;
 
507
        Entry e = {0};
 
508
        int rc, i, ocfilter, indexed;
 
509
        struct berval matched;
 
510
        NdbRecAttr *scanID, *scanOC, *scanDN[NDB_MAX_RDNS];
 
511
        char dnBuf[2048], *ptr;
 
512
        char idbuf[2*sizeof(ID)];
 
513
        char ocbuf[NDB_OC_BUFLEN];
 
514
        NdbRdns rdns;
 
515
        NdbOcInfo *oci;
 
516
        NdbArgs NA;
 
517
        slap_mask_t mask;
 
518
        time_t stoptime;
 
519
        int manageDSAit;
 
520
 
 
521
        rc = ndb_thread_handle( op, &NA.ndb );
 
522
        rdns.nr_num = 0;
 
523
 
 
524
        manageDSAit = get_manageDSAit( op );
 
525
 
 
526
        txn = NA.ndb->startTransaction();
 
527
        if ( !txn ) {
 
528
                Debug( LDAP_DEBUG_TRACE,
 
529
                        LDAP_XSTRING(ndb_back_search) ": startTransaction failed: %s (%d)\n",
 
530
                        NA.ndb->getNdbError().message, NA.ndb->getNdbError().code, 0 );
 
531
                rs->sr_err = LDAP_OTHER;
 
532
                rs->sr_text = "internal error";
 
533
                goto leave;
 
534
        }
 
535
 
 
536
        NA.txn = txn;
 
537
        e.e_name = op->o_req_dn;
 
538
        e.e_nname = op->o_req_ndn;
 
539
        NA.e = &e;
 
540
        NA.rdns = &rdns;
 
541
        NA.ocs = NULL;
 
542
 
 
543
        rs->sr_err = ndb_entry_get_info( op, &NA, 0, &matched );
 
544
        if ( rs->sr_err ) {
 
545
                if ( rs->sr_err == LDAP_NO_SUCH_OBJECT ) {
 
546
                        rs->sr_matched = matched.bv_val;
 
547
                        if ( NA.ocs )
 
548
                                ndb_check_referral( op, rs, &NA );
 
549
                }
 
550
                goto leave;
 
551
        }
 
552
 
 
553
        if ( !access_allowed_mask( op, &e, slap_schema.si_ad_entry,
 
554
                NULL, ACL_SEARCH, NULL, &mask )) {
 
555
                if ( !ACL_GRANT( mask, ACL_DISCLOSE ))
 
556
                        rs->sr_err = LDAP_NO_SUCH_OBJECT;
 
557
                else
 
558
                        rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
 
559
                ber_bvarray_free_x( NA.ocs, op->o_tmpmemctx );
 
560
                goto leave;
 
561
        }
 
562
 
 
563
        rs->sr_err = ndb_entry_get_data( op, &NA, 0 );
 
564
        ber_bvarray_free_x( NA.ocs, op->o_tmpmemctx );
 
565
        if ( rs->sr_err )
 
566
                goto leave;
 
567
 
 
568
        if ( !manageDSAit && is_entry_referral( &e )) {
 
569
                rs->sr_ref = get_entry_referrals( op, &e );
 
570
                rs->sr_err = LDAP_REFERRAL;
 
571
                if ( rs->sr_ref )
 
572
                        rs->sr_flags |= REP_REF_MUSTBEFREED;
 
573
                rs->sr_matched = e.e_name.bv_val;
 
574
                attrs_free( e.e_attrs );
 
575
                e.e_attrs = NULL;
 
576
                goto leave;
 
577
        }
 
578
 
 
579
        if ( !manageDSAit && is_entry_glue( &e )) {
 
580
                rs->sr_err = LDAP_NO_SUCH_OBJECT;
 
581
                goto leave;
 
582
        }
 
583
 
 
584
        if ( get_assert( op ) && test_filter( op, &e, (Filter *)get_assertion( op )) !=
 
585
                LDAP_COMPARE_TRUE ) {
 
586
                rs->sr_err = LDAP_ASSERTION_FAILED;
 
587
                attrs_free( e.e_attrs );
 
588
                e.e_attrs = NULL;
 
589
                goto leave;
 
590
        }
 
591
 
 
592
        /* admin ignores tlimits */
 
593
        stoptime = op->o_time + op->ors_tlimit;
 
594
 
 
595
        if ( op->ors_scope == LDAP_SCOPE_BASE ) {
 
596
                rc = test_filter( op, &e, op->ors_filter );
 
597
                if ( rc == LDAP_COMPARE_TRUE ) {
 
598
                        rs->sr_entry = &e;
 
599
                        rs->sr_attrs = op->ors_attrs;
 
600
                        rs->sr_flags = 0;
 
601
                        send_search_entry( op, rs );
 
602
                        rs->sr_entry = NULL;
 
603
                }
 
604
                attrs_free( e.e_attrs );
 
605
                e.e_attrs = NULL;
 
606
                rs->sr_err = LDAP_SUCCESS;
 
607
                goto leave;
 
608
        } else {
 
609
                attrs_free( e.e_attrs );
 
610
                e.e_attrs = NULL;
 
611
                if ( rdns.nr_num == NDB_MAX_RDNS ) {
 
612
                        if ( op->ors_scope == LDAP_SCOPE_ONELEVEL ||
 
613
                                op->ors_scope == LDAP_SCOPE_CHILDREN )
 
614
                        rs->sr_err = LDAP_SUCCESS;
 
615
                        goto leave;
 
616
                }
 
617
        }
 
618
 
 
619
        /* See if we can handle the filter. Filtering on objectClass is only done
 
620
         * in the DN2ID table scan. If all other filter terms reside in one table,
 
621
         * then we scan the OC table instead of the DN2ID table.
 
622
         */
 
623
        oci = NULL;
 
624
        indexed = 0;
 
625
        ocfilter = 0;
 
626
        rc = ndb_filter_check( ni, op->ors_filter, &oci, &indexed, &ocfilter );
 
627
        if ( rc ) {
 
628
                Debug( LDAP_DEBUG_TRACE, "ndb_back_search: "
 
629
                        "filter attributes from multiple tables, indexing ignored\n",
 
630
                        0, 0, 0 );
 
631
        } else if ( oci ) {
 
632
                rc = ndb_oc_search( op, rs, NA.ndb, txn, &rdns, oci, indexed );
 
633
                goto leave;
 
634
        }
 
635
 
 
636
        scan = txn->getNdbIndexScanOperation( "PRIMARY", DN2ID_TABLE );
 
637
        scan->readTuples( NdbOperation::LM_CommittedRead );
 
638
        rc = ndb_dn2bound( scan, &rdns );
 
639
 
 
640
        /* TODO: if ( ocfilter ) set up scanfilter for objectclass matches
 
641
         * column COND_LIKE "% <class> %"
 
642
         */
 
643
 
 
644
        switch( op->ors_scope ) {
 
645
        case LDAP_SCOPE_ONELEVEL:
 
646
                sf = new NdbScanFilter(scan);
 
647
                if ( sf->begin() < 0 ||
 
648
                        sf->cmp(NdbScanFilter::COND_NOT_LIKE, rc+3, "_%",
 
649
                                STRLENOF("_%")) < 0 ||
 
650
                        sf->end() < 0 ) {
 
651
                        rs->sr_err = LDAP_OTHER;
 
652
                        goto leave;
 
653
                }
 
654
                /* FALLTHRU */
 
655
        case LDAP_SCOPE_CHILDREN:
 
656
                /* Note: RDN_COLUMN offset not needed here */
 
657
                scan->setBound( rc, NdbIndexScanOperation::BoundLT, "\0" );
 
658
                /* FALLTHRU */
 
659
        case LDAP_SCOPE_SUBTREE:
 
660
                break;
 
661
        }
 
662
        scanID = scan->getValue( EID_COLUMN, idbuf );
 
663
        scanOC = scan->getValue( OCS_COLUMN, ocbuf );
 
664
        for ( i=0; i<NDB_MAX_RDNS; i++ ) {
 
665
                rdns.nr_buf[i][0] = '\0';
 
666
                scanDN[i] = scan->getValue( RDN_COLUMN+i, rdns.nr_buf[i] );
 
667
        }
 
668
        if ( txn->execute( NdbTransaction::NoCommit, NdbOperation::AbortOnError, 1 )) {
 
669
                rs->sr_err = LDAP_OTHER;
 
670
                goto leave;
 
671
        }
 
672
 
 
673
        e.e_name.bv_val = dnBuf;
 
674
        while ( scan->nextResult( true, true ) == 0 ) {
 
675
                if ( op->o_abandon ) {
 
676
                        rs->sr_err = SLAPD_ABANDON;
 
677
                        break;
 
678
                }
 
679
                if ( slapd_shutdown ) {
 
680
                        rs->sr_err = LDAP_UNAVAILABLE;
 
681
                        break;
 
682
                }
 
683
                if ( op->ors_tlimit != SLAP_NO_LIMIT &&
 
684
                        slap_get_time() > stoptime ) {
 
685
                        rs->sr_err = LDAP_TIMELIMIT_EXCEEDED;
 
686
                        break;
 
687
                }
 
688
                e.e_id = scanID->u_64_value();
 
689
                NA.ocs = ndb_ref2oclist( ocbuf, op->o_tmpmemctx );
 
690
                for ( i=0; i<NDB_MAX_RDNS; i++ ) {
 
691
                        if ( scanDN[i]->isNULL() || !rdns.nr_buf[i][0] )
 
692
                                break;
 
693
                }
 
694
                ptr = dnBuf;
 
695
                rdns.nr_num = i;
 
696
                for ( --i; i>=0; i-- ) {
 
697
                        char *buf;
 
698
                        int len;
 
699
                        buf = rdns.nr_buf[i];
 
700
                        len = *buf++;
 
701
                        ptr = lutil_strncopy( ptr, buf, len );
 
702
                        if ( i ) *ptr++ = ',';
 
703
                }
 
704
                *ptr = '\0';
 
705
                e.e_name.bv_len = ptr - dnBuf;
 
706
                dnNormalize( 0, NULL, NULL, &e.e_name, &e.e_nname, op->o_tmpmemctx );
 
707
                NA.txn = NA.ndb->startTransaction();
 
708
                rc = ndb_entry_get_data( op, &NA, 0 );
 
709
                NA.txn->close();
 
710
                ber_bvarray_free_x( NA.ocs, op->o_tmpmemctx );
 
711
                if ( !manageDSAit && is_entry_referral( &e )) {
 
712
                        BerVarray erefs = get_entry_referrals( op, &e );
 
713
                        rs->sr_ref = referral_rewrite( erefs, &e.e_name, NULL,
 
714
                                op->ors_scope == LDAP_SCOPE_ONELEVEL ?
 
715
                                        LDAP_SCOPE_BASE : LDAP_SCOPE_SUBTREE );
 
716
                        rc = send_search_reference( op, rs );
 
717
                        ber_bvarray_free( rs->sr_ref );
 
718
                        ber_bvarray_free( erefs );
 
719
                        rs->sr_ref = NULL;
 
720
                } else if ( manageDSAit || !is_entry_glue( &e )) {
 
721
                        rc = test_filter( op, &e, op->ors_filter );
 
722
                        if ( rc == LDAP_COMPARE_TRUE ) {
 
723
                                rs->sr_entry = &e;
 
724
                                rs->sr_attrs = op->ors_attrs;
 
725
                                rs->sr_flags = 0;
 
726
                                rc = send_search_entry( op, rs );
 
727
                                rs->sr_entry = NULL;
 
728
                        } else {
 
729
                                rc = 0;
 
730
                        }
 
731
                }
 
732
                attrs_free( e.e_attrs );
 
733
                e.e_attrs = NULL;
 
734
                op->o_tmpfree( e.e_nname.bv_val, op->o_tmpmemctx );
 
735
                if ( rc ) break;
 
736
        }
 
737
leave:
 
738
        if ( sf )
 
739
                delete sf;
 
740
        if ( txn )
 
741
                txn->close();
 
742
        send_ldap_result( op, rs );
 
743
        return rs->sr_err;
 
744
}
 
745
 
 
746
extern NdbInterpretedCode *ndb_lastrow_code;    /* init.cpp */
 
747
 
 
748
extern "C" int
 
749
ndb_has_children(
 
750
        NdbArgs *NA,
 
751
        int *hasChildren
 
752
)
 
753
{
 
754
        NdbIndexScanOperation *scan;
 
755
        char idbuf[2*sizeof(ID)];
 
756
        int rc;
 
757
 
 
758
        if ( NA->rdns->nr_num >= NDB_MAX_RDNS ) {
 
759
                *hasChildren = LDAP_COMPARE_FALSE;
 
760
                return 0;
 
761
        }
 
762
 
 
763
        scan = NA->txn->getNdbIndexScanOperation( "PRIMARY", DN2ID_TABLE );
 
764
        if ( !scan )
 
765
                return LDAP_OTHER;
 
766
        scan->readTuples( NdbOperation::LM_Read, 0U, 0U, 1U );
 
767
        rc = ndb_dn2bound( scan, NA->rdns );
 
768
        if ( rc < NDB_MAX_RDNS ) {
 
769
                scan->setBound( rc, NdbIndexScanOperation::BoundLT, "\0" );
 
770
        }
 
771
#if 0
 
772
        scan->interpret_exit_last_row();
 
773
#else
 
774
        scan->setInterpretedCode(ndb_lastrow_code);
 
775
#endif
 
776
        scan->getValue( EID_COLUMN, idbuf );
 
777
        if ( NA->txn->execute( NdbTransaction::NoCommit, NdbOperation::AO_IgnoreError, 1 )) {
 
778
                return LDAP_OTHER;
 
779
        }
 
780
        if (rc < NDB_MAX_RDNS && scan->nextResult( true, true ) == 0 )
 
781
                *hasChildren = LDAP_COMPARE_TRUE;
 
782
        else
 
783
                *hasChildren = LDAP_COMPARE_FALSE;
 
784
        scan->close();
 
785
        return 0;
 
786
}
 
787
 
 
788
extern "C" int
 
789
ndb_has_subordinates(
 
790
        Operation *op,
 
791
        Entry *e,
 
792
        int *hasSubordinates )
 
793
{
 
794
        NdbArgs NA;
 
795
        NdbRdns rdns;
 
796
        int rc;
 
797
 
 
798
        NA.rdns = &rdns;
 
799
        rc = ndb_dn2rdns( &e->e_nname, &rdns );
 
800
 
 
801
        if ( rc == 0 ) {
 
802
                rc = ndb_thread_handle( op, &NA.ndb );
 
803
                NA.txn = NA.ndb->startTransaction();
 
804
                if ( NA.txn ) {
 
805
                        rc = ndb_has_children( &NA, hasSubordinates );
 
806
                        NA.txn->close();
 
807
                }
 
808
        }
 
809
 
 
810
        return rc;
 
811
}
 
812
 
 
813
/*
 
814
 * sets the supported operational attributes (if required)
 
815
 */
 
816
extern "C" int
 
817
ndb_operational(
 
818
        Operation       *op,
 
819
        SlapReply       *rs )
 
820
{
 
821
        Attribute       **ap;
 
822
 
 
823
        assert( rs->sr_entry != NULL );
 
824
 
 
825
        for ( ap = &rs->sr_operational_attrs; *ap; ap = &(*ap)->a_next )
 
826
                /* just count */ ;
 
827
 
 
828
        if ( SLAP_OPATTRS( rs->sr_attr_flags ) ||
 
829
                        ad_inlist( slap_schema.si_ad_hasSubordinates, rs->sr_attrs ) )
 
830
        {
 
831
                int     hasSubordinates, rc;
 
832
 
 
833
                rc = ndb_has_subordinates( op, rs->sr_entry, &hasSubordinates );
 
834
                if ( rc == LDAP_SUCCESS ) {
 
835
                        *ap = slap_operational_hasSubordinate( hasSubordinates == LDAP_COMPARE_TRUE );
 
836
                        assert( *ap != NULL );
 
837
 
 
838
                        ap = &(*ap)->a_next;
 
839
                }
 
840
        }
 
841
 
 
842
        return LDAP_SUCCESS;
 
843
}
 
844