]> git.sur5r.net Git - openldap/blob - servers/slapd/back-bdb2/search.c
MSVC5 cleanup...
[openldap] / servers / slapd / back-bdb2 / search.c
1 /* search.c - bdb2 backend search function */
2
3 #include "portable.h"
4
5 #include <stdio.h>
6
7 #include <ac/string.h>
8 #include <ac/socket.h>
9 #include <ac/time.h>
10
11 #include "slap.h"
12 #include "back-bdb2.h"
13 #include "proto-back-bdb2.h"
14
15 static ID_BLOCK *base_candidates(BackendDB *be, Connection *conn, Operation *op, char *base, Filter *filter, char **attrs, int attrsonly, char **matched, int *err);
16 static ID_BLOCK *onelevel_candidates(BackendDB *be, Connection *conn, Operation *op, char *base, Filter *filter, char **attrs, int attrsonly, char **matched, int *err);
17 static ID_BLOCK *subtree_candidates(BackendDB *be, Connection *conn, Operation *op, char *base, Filter *filter, char **attrs, int attrsonly, char **matched, Entry *e, int *err, int lookupbase);
18
19 #define GRABSIZE        BUFSIZ
20
21 #define MAKE_SPACE( n ) { \
22         if ( rcur + n > rbuf + rmaxsize ) { \
23                 int     offset = rcur - rbuf; \
24                 rbuf =  ch_realloc( rbuf, rmaxsize + GRABSIZE ); \
25                 rmaxsize += GRABSIZE; \
26                 rcur = rbuf + offset; \
27         } \
28 }
29
30 static int
31 bdb2i_back_search_internal(
32     BackendDB   *be,
33     Connection  *conn,
34     Operation   *op,
35     char        *base,
36     int         scope,
37     int         deref,
38     int         slimit,
39     int         tlimit,
40     Filter      *filter,
41     char        *filterstr,
42     char        **attrs,
43     int         attrsonly
44 )
45 {
46         struct ldbminfo *li = (struct ldbminfo *) be->be_private;
47         int             err;
48         time_t          stoptime;
49         ID_BLOCK                *candidates;
50         ID              id;
51         Entry           *e;
52         Attribute       *ref;
53         char            *matched = NULL;
54         int             rmaxsize, nrefs;
55         char            *rbuf, *rcur;
56         int             nentries = 0;
57         char            *realBase;
58
59         Debug(LDAP_DEBUG_ARGS, "=> bdb2i_back_search\n", 0, 0, 0);
60
61         if ( tlimit == 0 && be_isroot( be, op->o_ndn ) ) {
62                 tlimit = -1;    /* allow root to set no limit */
63         } else {
64                 tlimit = (tlimit > be->be_timelimit || tlimit < 1) ?
65                     be->be_timelimit : tlimit;
66                 stoptime = op->o_time + tlimit;
67         }
68         if ( slimit == 0 && be_isroot( be, op->o_ndn ) ) {
69                 slimit = -1;    /* allow root to set no limit */
70         } else {
71                 slimit = (slimit > be->be_sizelimit || slimit < 1) ?
72                     be->be_sizelimit : slimit;
73         }
74
75         /*
76          * check and apply aliasing where the dereferencing applies to
77          * the subordinates of the base
78          */
79
80         switch ( deref ) {
81         case LDAP_DEREF_FINDING:
82         case LDAP_DEREF_ALWAYS:
83                 realBase = bdb2i_derefDN ( be, conn, op, base );
84                 break;
85         default:
86                 realBase = ch_strdup(base);
87         }
88
89         (void) dn_normalize_case( realBase );
90
91         Debug( LDAP_DEBUG_TRACE, "using base \"%s\"\n",
92                 realBase, 0, 0 );
93
94         switch ( scope ) {
95         case LDAP_SCOPE_BASE:
96                 candidates = base_candidates( be, conn, op, realBase, filter,
97                     attrs, attrsonly, &matched, &err );
98                 break;
99
100         case LDAP_SCOPE_ONELEVEL:
101                 candidates = onelevel_candidates( be, conn, op, realBase, filter,
102                     attrs, attrsonly, &matched, &err );
103                 break;
104
105         case LDAP_SCOPE_SUBTREE:
106                 candidates = subtree_candidates( be, conn, op, realBase, filter,
107                     attrs, attrsonly, &matched, NULL, &err, 1 );
108                 break;
109
110         default:
111                 send_ldap_result( conn, op, LDAP_PROTOCOL_ERROR, "",
112                     "Bad scope" );
113                 if( realBase != NULL) {
114                         free( realBase );
115                 }
116                 return( -1 );
117         }
118
119         /* null candidates means we could not find the base object */
120         if ( candidates == NULL ) {
121                 send_ldap_result( conn, op, err, matched, "" );
122                 if ( matched != NULL ) {
123                         free( matched );
124                 }
125                 if( realBase != NULL) {
126                         free( realBase );
127                 }
128                 return( -1 );
129         }
130
131         if ( matched != NULL ) {
132                 free( matched );
133         }
134
135         rmaxsize = 0;
136         nrefs = 0;
137         rbuf = rcur = NULL;
138         MAKE_SPACE( sizeof("Referral:") + 1 );
139         strcpy( rbuf, "Referral:" );
140         rcur = strchr( rbuf, '\0' );
141         for ( id = bdb2i_idl_firstid( candidates ); id != NOID;
142             id = bdb2i_idl_nextid( candidates, id ) ) {
143                 /* check for abandon */
144                 ldap_pvt_thread_mutex_lock( &op->o_abandonmutex );
145                 if ( op->o_abandon ) {
146                         ldap_pvt_thread_mutex_unlock( &op->o_abandonmutex );
147                         bdb2i_idl_free( candidates );
148                         free( rbuf );
149                         if( realBase != NULL) {
150                                 free( realBase );
151                         }
152                         return( 0 );
153                 }
154                 ldap_pvt_thread_mutex_unlock( &op->o_abandonmutex );
155
156                 /* check time limit */
157                 ldap_pvt_thread_mutex_lock( &currenttime_mutex );
158                 time( &currenttime );
159                 if ( tlimit != -1 && currenttime > stoptime ) {
160                         ldap_pvt_thread_mutex_unlock( &currenttime_mutex );
161                         send_ldap_search_result( conn, op,
162                             LDAP_TIMELIMIT_EXCEEDED, NULL, nrefs > 0 ? rbuf :
163                             NULL, nentries );
164                         bdb2i_idl_free( candidates );
165                         free( rbuf );
166                         if( realBase != NULL) {
167                                 free( realBase );
168                         }
169                         return( 0 );
170                 }
171                 ldap_pvt_thread_mutex_unlock( &currenttime_mutex );
172
173                 /* get the entry with reader lock */
174                 if ( (e = bdb2i_id2entry_r( be, id )) == NULL ) {
175                         Debug( LDAP_DEBUG_ARGS, "candidate %ld not found\n",
176                                id, 0, 0 );
177                         continue;
178                 }
179
180                 /*
181                  * if it's a referral, add it to the list of referrals. only do
182                  * this for subtree searches, and don't check the filter explicitly
183                  * here since it's only a candidate anyway.
184                  */
185                 if ( scope == LDAP_SCOPE_SUBTREE &&
186                         e->e_ndn != NULL &&
187                         strncmp( e->e_ndn, "REF=", 4 ) == 0 &&
188                         (ref = attr_find( e->e_attrs, "ref" )) != NULL )
189                 {
190                         int     i;
191
192                         if ( ref->a_vals == NULL ) {
193                                 Debug( LDAP_DEBUG_ANY, "null ref in (%s)\n", 
194                                         e->e_dn, 0, 0 );
195                         } else {
196                                 for ( i = 0; ref->a_vals[i] != NULL; i++ ) {
197                                         /* referral + newline + null */
198                                         MAKE_SPACE( ref->a_vals[i]->bv_len + 2 );
199                                         *rcur++ = '\n';
200                                         strncpy( rcur, ref->a_vals[i]->bv_val,
201                                                 ref->a_vals[i]->bv_len );
202                                         rcur = rcur + ref->a_vals[i]->bv_len;
203                                         *rcur = '\0';
204                                         nrefs++;
205                                 }
206                         }
207
208                 /* otherwise it's an entry - see if it matches the filter */
209                 } else {
210                         /* if it matches the filter and scope, send it */
211                         if ( test_filter( be, conn, op, e, filter ) == 0 ) {
212                                 int             scopeok;
213                                 char    *dn;
214
215                                 /* check scope */
216                                 scopeok = 1;
217                                 if ( scope == LDAP_SCOPE_ONELEVEL ) {
218                                         if ( (dn = dn_parent( be, e->e_dn )) != NULL ) {
219                                                 (void) dn_normalize_case( dn );
220                                                 scopeok = (dn == realBase)
221                                                         ? 1
222                                                         : (strcmp( dn, realBase ) ? 0 : 1 );
223                                                 free( dn );
224                                         } else {
225                                                 scopeok = (realBase == NULL || *realBase == '\0');
226                                         }
227                                 } else if ( scope == LDAP_SCOPE_SUBTREE ) {
228                                         dn = ch_strdup( e->e_ndn );
229                                         scopeok = dn_issuffix( dn, realBase );
230                                         free( dn );
231                                 }
232
233                                 if ( scopeok ) {
234                                         /* check size limit */
235                                         if ( --slimit == -1 ) {
236                                                 bdb2i_cache_return_entry_r( &li->li_cache, e );
237                                                 send_ldap_search_result( conn, op,
238                                                         LDAP_SIZELIMIT_EXCEEDED, NULL,
239                                                         nrefs > 0 ? rbuf : NULL, nentries );
240                                                 bdb2i_idl_free( candidates );
241                                                 free( rbuf );
242
243                                                 if( realBase != NULL) {
244                                                         free( realBase );
245                                                 }
246                                                 return( 0 );
247                                         }
248
249                                         /*
250                                          * check and apply aliasing where the dereferencing applies to
251                                          * the subordinates of the base
252                                          */
253                                         switch ( deref ) {
254                                         case LDAP_DEREF_SEARCHING:
255                                         case LDAP_DEREF_ALWAYS:
256                                                 {
257                                                         Entry *newe = bdb2i_derefAlias_r( be, conn, op, e );
258                                                         if ( newe == NULL ) { /* problem with the alias */
259                                                                 bdb2i_cache_return_entry_r( &li->li_cache, e );
260                                                                 e = NULL;
261                                                         }
262                                                         else if ( newe != e ) { /* reassign e */
263                                                                 bdb2i_cache_return_entry_r( &li->li_cache, e );
264                                                                 e = newe;
265                                                         }
266                                                 }
267                                                 break;
268                                         }
269
270                                         if (e) {
271                                                 switch ( send_search_entry( be, conn, op, e,
272                                                         attrs, attrsonly ) ) {
273                                                 case 0:         /* entry sent ok */
274                                                         nentries++;
275                                                         break;
276                                                 case 1:         /* entry not sent */
277                                                         break;
278                                                 case -1:        /* connection closed */
279                                                         bdb2i_cache_return_entry_r( &li->li_cache, e );
280                                                         bdb2i_idl_free( candidates );
281                                                         free( rbuf );
282
283                                                         if( realBase != NULL) {
284                                                                 free( realBase );
285                                                         }
286                                                         return( 0 );
287                                                 }
288                                         }
289                                 }
290                         }
291                 }
292
293                 if( e != NULL ) {
294                         /* free reader lock */
295                         bdb2i_cache_return_entry_r( &li->li_cache, e );
296                 }
297
298                 ldap_pvt_thread_yield();
299         }
300         bdb2i_idl_free( candidates );
301         if ( nrefs > 0 ) {
302                 send_ldap_search_result( conn, op, LDAP_PARTIAL_RESULTS, NULL,
303                     rbuf, nentries );
304         } else {
305                 send_ldap_search_result( conn, op, LDAP_SUCCESS, NULL, NULL,
306                     nentries );
307         }
308         free( rbuf );
309
310         if( realBase != NULL) {
311                 free( realBase );
312         }
313
314         return( 0 );
315 }
316
317
318 int
319 bdb2_back_search(
320     BackendDB   *be,
321     Connection  *conn,
322     Operation   *op,
323     char        *base,
324     int         scope,
325     int         deref,
326     int         slimit,
327     int         tlimit,
328     Filter      *filter,
329     char        *filterstr,
330     char        **attrs,
331     int         attrsonly
332 )
333 {
334         DB_LOCK         lock;
335         struct ldbminfo *li = (struct ldbminfo *) be->be_private;
336         struct timeval  time1;
337         int             ret;
338
339         bdb2i_start_timing( be->bd_info, &time1 );
340
341         if ( bdb2i_enter_backend_r( &lock ) != 0 ) {
342
343                 send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, "", "" );
344                 return( -1 );
345
346         }
347
348         ret = bdb2i_back_search_internal( be, conn, op, base, scope, deref,
349                                         slimit, tlimit, filter, filterstr, attrs, attrsonly );
350
351         (void) bdb2i_leave_backend_r( lock );
352         bdb2i_stop_timing( be->bd_info, time1, "SRCH", conn, op );
353
354         return( ret );
355 }
356
357
358 static ID_BLOCK *
359 base_candidates(
360     BackendDB   *be,
361     Connection  *conn,
362     Operation   *op,
363     char        *base,
364     Filter      *filter,
365     char        **attrs,
366     int         attrsonly,
367     char        **matched,
368     int         *err
369 )
370 {
371         struct ldbminfo *li = (struct ldbminfo *) be->be_private;
372         ID_BLOCK                *idl;
373         Entry           *e;
374
375         Debug(LDAP_DEBUG_TRACE, "base_candidates: base: \"%s\"\n", base, 0, 0);
376
377         *err = LDAP_SUCCESS;
378
379         /* get entry with reader lock */
380         if ( (e = bdb2i_dn2entry_r( be, base, matched )) == NULL ) {
381                 *err = LDAP_NO_SUCH_OBJECT;
382                 return( NULL );
383         }
384
385         /* check for deleted */
386
387         idl = bdb2i_idl_alloc( 1 );
388         bdb2i_idl_insert( &idl, e->e_id, 1 );
389
390
391         /* free reader lock */
392         bdb2i_cache_return_entry_r( &li->li_cache, e );
393
394         return( idl );
395 }
396
397 static ID_BLOCK *
398 onelevel_candidates(
399     BackendDB   *be,
400     Connection  *conn,
401     Operation   *op,
402     char        *base,
403     Filter      *filter,
404     char        **attrs,
405     int         attrsonly,
406     char        **matched,
407     int         *err
408 )
409 {
410         struct ldbminfo *li = (struct ldbminfo *) be->be_private;
411         Entry           *e = NULL;
412         Filter          *f;
413         char            buf[20];
414         ID_BLOCK                *candidates;
415
416         Debug(LDAP_DEBUG_TRACE, "onelevel_candidates: base: \"%s\"\n", base, 0, 0);
417
418         *err = LDAP_SUCCESS;
419
420         /* get the base object with reader lock */
421         if ( base != NULL && *base != '\0' &&
422                 (e = bdb2i_dn2entry_r( be, base, matched )) == NULL )
423         {
424                 *err = LDAP_NO_SUCH_OBJECT;
425                 return( NULL );
426         }
427
428         /*
429          * modify the filter to be something like this:
430          *
431          *      parent=baseobject & originalfilter
432          */
433
434         f = (Filter *) ch_malloc( sizeof(Filter) );
435         f->f_next = NULL;
436         f->f_choice = LDAP_FILTER_AND;
437         f->f_and = (Filter *) ch_malloc( sizeof(Filter) );
438         f->f_and->f_choice = LDAP_FILTER_EQUALITY;
439         f->f_and->f_ava.ava_type = ch_strdup( "id2children" );
440         sprintf( buf, "%ld", e != NULL ? e->e_id : 0 );
441         f->f_and->f_ava.ava_value.bv_val = ch_strdup( buf );
442         f->f_and->f_ava.ava_value.bv_len = strlen( buf );
443         f->f_and->f_next = filter;
444
445         /* from here, it's just like subtree_candidates */
446         candidates = subtree_candidates( be, conn, op, base, f, attrs,
447             attrsonly, matched, e, err, 0 );
448
449         /* free up just the filter stuff we allocated above */
450         f->f_and->f_next = NULL;
451         filter_free( f );
452
453         /* free entry and reader lock */
454         if( e != NULL ) {
455                 bdb2i_cache_return_entry_r( &li->li_cache, e );
456         }
457         return( candidates );
458 }
459
460 static ID_BLOCK *
461 subtree_candidates(
462     BackendDB   *be,
463     Connection  *conn,
464     Operation   *op,
465     char        *base,
466     Filter      *filter,
467     char        **attrs,
468     int         attrsonly,
469     char        **matched,
470     Entry       *e,
471     int         *err,
472     int         lookupbase
473 )
474 {
475         struct ldbminfo *li = (struct ldbminfo *) be->be_private;
476         Filter          *f, **filterarg_ptr;
477         ID_BLOCK                *candidates;
478
479         Debug(LDAP_DEBUG_TRACE, "subtree_candidates: base: \"%s\" %s\n",
480                 base ? base : "NULL", lookupbase ? "lookupbase" : "", 0);
481
482         /*
483          * get the base object - unless we already have it (from one-level).
484          * also, unless this is a one-level search or a subtree search
485          * starting at the very top of our subtree, we need to modify the
486          * filter to be something like this:
487          *
488          *      dn=*baseobjectdn & (originalfilter | ref=*)
489          *
490          * the "objectclass=referral" part is used to select referrals to return
491          */
492
493         *err = LDAP_SUCCESS;
494         f = NULL;
495         if ( lookupbase ) {
496                 e = NULL;
497
498                 if ( base != NULL && *base != '\0' &&
499                         (e = bdb2i_dn2entry_r( be, base, matched )) == NULL )
500                 {
501                         *err = LDAP_NO_SUCH_OBJECT;
502                         return( NULL );
503                 }
504
505                 if (e) {
506                         bdb2i_cache_return_entry_r( &li->li_cache, e );
507                 }
508
509                 f = (Filter *) ch_malloc( sizeof(Filter) );
510                 f->f_next = NULL;
511                 f->f_choice = LDAP_FILTER_OR;
512                 f->f_or = (Filter *) ch_malloc( sizeof(Filter) );
513                 f->f_or->f_choice = LDAP_FILTER_EQUALITY;
514                 f->f_or->f_avtype = ch_strdup( "objectclass" );
515                 /* Patch to use normalized uppercase */
516                 f->f_or->f_avvalue.bv_val = ch_strdup( "REFERRAL" );
517                 f->f_or->f_avvalue.bv_len = strlen( "REFERRAL" );
518                 filterarg_ptr = &f->f_or->f_next;
519                 *filterarg_ptr = filter;
520                 filter = f;
521
522                 if ( ! be_issuffix( be, base ) ) {
523                         f = (Filter *) ch_malloc( sizeof(Filter) );
524                         f->f_next = NULL;
525                         f->f_choice = LDAP_FILTER_AND;
526                         f->f_and = (Filter *) ch_malloc( sizeof(Filter) );
527                         f->f_and->f_choice = LDAP_FILTER_SUBSTRINGS;
528                         f->f_and->f_sub_type = ch_strdup( "dn" );
529                         f->f_and->f_sub_initial = NULL;
530                         f->f_and->f_sub_any = NULL;
531                         f->f_and->f_sub_final = ch_strdup( base );
532                         value_normalize( f->f_and->f_sub_final, SYNTAX_CIS );
533                         f->f_and->f_next = filter;
534                         filter = f;
535                 }
536         }
537
538         candidates = bdb2i_filter_candidates( be, filter );
539
540         /* free up just the parts we allocated above */
541         if ( f != NULL ) {
542                 *filterarg_ptr = NULL;
543                 filter_free( f );
544         }
545
546         return( candidates );
547 }