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