]> git.sur5r.net Git - openldap/blob - servers/slapd/back-ldbm/search.c
Replace strdup() with ch_strdup() such that exit() will be called
[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;
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_dn ) ) {
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_dn ) ) {
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         switch ( deref ) {
80         case LDAP_DEREF_FINDING:
81         case LDAP_DEREF_ALWAYS:
82                 free (realBase);
83                 realBase = derefDN ( be, conn, op, base );
84                 break;
85         default:
86                 realBase = ch_strdup(base);
87         }
88
89         (void) dn_normalize (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                 return( -1 );
114         }
115
116         /* null candidates means we could not find the base object */
117         if ( candidates == NULL ) {
118                 send_ldap_result( conn, op, err, matched, "" );
119                 if ( matched != NULL ) {
120                         free( matched );
121                 }
122                 return( -1 );
123         }
124
125         rmaxsize = 0;
126         nrefs = 0;
127         rbuf = rcur = NULL;
128         MAKE_SPACE( sizeof("Referral:") + 1 );
129         strcpy( rbuf, "Referral:" );
130         rcur = strchr( rbuf, '\0' );
131         for ( id = idl_firstid( candidates ); id != NOID;
132             id = idl_nextid( candidates, id ) ) {
133                 /* check for abandon */
134                 pthread_mutex_lock( &op->o_abandonmutex );
135                 if ( op->o_abandon ) {
136                         pthread_mutex_unlock( &op->o_abandonmutex );
137                         idl_free( candidates );
138                         free( rbuf );
139                         return( 0 );
140                 }
141                 pthread_mutex_unlock( &op->o_abandonmutex );
142
143                 /* check time limit */
144                 pthread_mutex_lock( &currenttime_mutex );
145                 time( &currenttime );
146                 if ( tlimit != -1 && currenttime > stoptime ) {
147                         pthread_mutex_unlock( &currenttime_mutex );
148                         send_ldap_search_result( conn, op,
149                             LDAP_TIMELIMIT_EXCEEDED, NULL, nrefs > 0 ? rbuf :
150                             NULL, nentries );
151                         idl_free( candidates );
152                         free( rbuf );
153                         return( 0 );
154                 }
155                 pthread_mutex_unlock( &currenttime_mutex );
156
157                 /* get the entry with reader lock */
158                 if ( (e = id2entry_r( be, id )) == NULL ) {
159                         Debug( LDAP_DEBUG_ARGS, "candidate %lu not found\n",
160                                id, 0, 0 );
161                         continue;
162                 }
163
164                 /*
165                  * if it's a referral, add it to the list of referrals. only do
166                  * this for subtree searches, and don't check the filter explicitly
167                  * here since it's only a candidate anyway.
168                  */
169                 if ( e->e_dn != NULL &&
170                         strncasecmp( e->e_dn, "ref=", 4 ) == 0 &&
171                         (ref = attr_find( e->e_attrs, "ref" )) != NULL &&
172                         scope == LDAP_SCOPE_SUBTREE )
173                 {
174                         int     i, len;
175
176                         if ( ref->a_vals == NULL ) {
177                                 Debug( LDAP_DEBUG_ANY, "null ref in (%s)\n", 
178                                         e->e_dn, 0, 0 );
179                         } else {
180                                 for ( i = 0; ref->a_vals[i] != NULL; i++ ) {
181                                         /* referral + newline + null */
182                                         MAKE_SPACE( ref->a_vals[i]->bv_len + 2 );
183                                         *rcur++ = '\n';
184                                         strncpy( rcur, ref->a_vals[i]->bv_val,
185                                                 ref->a_vals[i]->bv_len );
186                                         rcur = rcur + ref->a_vals[i]->bv_len;
187                                         *rcur = '\0';
188                                         nrefs++;
189                                 }
190                         }
191
192                 /* otherwise it's an entry - see if it matches the filter */
193                 } else {
194                         /* if it matches the filter and scope, send it */
195                         if ( test_filter( be, conn, op, e, filter ) == 0 ) {
196                                 int             scopeok;
197                                 char    *dn;
198
199                                 /* check scope */
200                                 scopeok = 1;
201                                 if ( scope == LDAP_SCOPE_ONELEVEL ) {
202                                         if ( (dn = dn_parent( be, e->e_dn )) != NULL ) {
203                                                 (void) dn_normalize( dn );
204                                                 scopeok = (dn == realBase) ? 1 : (! strcasecmp( dn, realBase ));
205                                         } else {
206                                                 scopeok = (realBase == NULL || *realBase == '\0');
207                                         }
208                                         free( dn );
209                                 } else if ( scope == LDAP_SCOPE_SUBTREE ) {
210                                         dn = ch_strdup( e->e_dn );
211                                         (void) dn_normalize( dn );
212                                         scopeok = dn_issuffix( dn, realBase );
213                                         free( dn );
214                                 }
215
216                                 if ( scopeok ) {
217                                         /* check size limit */
218                                         if ( --slimit == -1 ) {
219                                                 cache_return_entry_r( &li->li_cache, e );
220                                                 send_ldap_search_result( conn, op,
221                                                         LDAP_SIZELIMIT_EXCEEDED, NULL,
222                                                         nrefs > 0 ? rbuf : NULL, nentries );
223                                                 idl_free( candidates );
224                                                 free( rbuf );
225                                                 return( 0 );
226                                         }
227
228                                         /*
229                                          * check and apply aliasing where the dereferencing applies to
230                                          * the subordinates of the base
231                                          */
232                                         switch ( deref ) {
233                                         case LDAP_DEREF_SEARCHING:
234                                         case LDAP_DEREF_ALWAYS:
235                                                 {
236                                                         Entry *newe = derefAlias_r( be, conn, op, e );
237                                                         cache_return_entry_r( &li->li_cache, e );
238                                                         e = newe;
239                                                 }
240                                                 break;
241                                         }
242
243                                         switch ( send_search_entry( be, conn, op, e,
244                                                 attrs, attrsonly ) ) {
245                                         case 0:         /* entry sent ok */
246                                                 nentries++;
247                                                 break;
248                                         case 1:         /* entry not sent */
249                                                 break;
250                                         case -1:        /* connection closed */
251                                                 cache_return_entry_r( &li->li_cache, e );
252                                                 idl_free( candidates );
253                                                 free( rbuf );
254                                                 return( 0 );
255                                         }
256                                 }
257                         }
258                 }
259
260                 if( e != NULL ) {
261                         /* free reader lock */
262                         cache_return_entry_r( &li->li_cache, e );
263                 }
264
265                 pthread_yield();
266         }
267         idl_free( candidates );
268         if ( nrefs > 0 ) {
269                 send_ldap_search_result( conn, op, LDAP_PARTIAL_RESULTS, NULL,
270                     rbuf, nentries );
271         } else {
272                 send_ldap_search_result( conn, op, LDAP_SUCCESS, NULL, NULL,
273                     nentries );
274         }
275         free( rbuf );
276
277         return( 0 );
278 }
279
280 static IDList *
281 base_candidates(
282     Backend     *be,
283     Connection  *conn,
284     Operation   *op,
285     char        *base,
286     Filter      *filter,
287     char        **attrs,
288     int         attrsonly,
289     char        **matched,
290     int         *err
291 )
292 {
293         struct ldbminfo *li = (struct ldbminfo *) be->be_private;
294         int             rc;
295         ID              id;
296         IDList          *idl;
297         Entry           *e;
298
299         Debug(LDAP_DEBUG_TRACE, "base_candidates: base: %s\n", base, 0, 0);
300
301         *err = LDAP_SUCCESS;
302
303         /* get entry with reader lock */
304         if ( (e = dn2entry_r( be, base, matched )) == NULL ) {
305                 *err = LDAP_NO_SUCH_OBJECT;
306                 return( NULL );
307         }
308
309         /* check for deleted */
310
311         idl = idl_alloc( 1 );
312         idl_insert( &idl, e->e_id, 1 );
313
314
315         /* free reader lock */
316         cache_return_entry_r( &li->li_cache, e );
317
318         return( idl );
319 }
320
321 static IDList *
322 onelevel_candidates(
323     Backend     *be,
324     Connection  *conn,
325     Operation   *op,
326     char        *base,
327     Filter      *filter,
328     char        **attrs,
329     int         attrsonly,
330     char        **matched,
331     int         *err
332 )
333 {
334         struct ldbminfo *li = (struct ldbminfo *) be->be_private;
335         Entry           *e;
336         Filter          *f;
337         char            buf[20];
338         IDList          *candidates;
339
340         Debug(LDAP_DEBUG_TRACE, "onelevel_candidates: base: %s\n", base, 0, 0);
341
342         *err = LDAP_SUCCESS;
343         e = NULL;
344         /* get the base object with reader lock */
345         if ( base != NULL && *base != '\0' &&
346                 (e = dn2entry_r( be, base, matched )) == NULL )
347         {
348                 *err = LDAP_NO_SUCH_OBJECT;
349                 return( NULL );
350         }
351
352         /*
353          * modify the filter to be something like this:
354          *
355          *      parent=baseobject & originalfilter
356          */
357
358         f = (Filter *) ch_malloc( sizeof(Filter) );
359         f->f_next = NULL;
360         f->f_choice = LDAP_FILTER_AND;
361         f->f_and = (Filter *) ch_malloc( sizeof(Filter) );
362         f->f_and->f_choice = LDAP_FILTER_EQUALITY;
363         f->f_and->f_ava.ava_type = ch_strdup( "id2children" );
364         sprintf( buf, "%ld", e != NULL ? e->e_id : 0 );
365         f->f_and->f_ava.ava_value.bv_val = ch_strdup( buf );
366         f->f_and->f_ava.ava_value.bv_len = strlen( buf );
367         f->f_and->f_next = filter;
368
369         /* from here, it's just like subtree_candidates */
370         candidates = subtree_candidates( be, conn, op, base, f, attrs,
371             attrsonly, matched, e, err, 0 );
372
373         /* free up just the filter stuff we allocated above */
374         f->f_and->f_next = NULL;
375         filter_free( f );
376
377         /* free entry and reader lock */
378         cache_return_entry_r( &li->li_cache, e );
379         return( candidates );
380 }
381
382 static IDList *
383 subtree_candidates(
384     Backend     *be,
385     Connection  *conn,
386     Operation   *op,
387     char        *base,
388     Filter      *filter,
389     char        **attrs,
390     int         attrsonly,
391     char        **matched,
392     Entry       *e,
393     int         *err,
394     int         lookupbase
395 )
396 {
397         struct ldbminfo *li = (struct ldbminfo *) be->be_private;
398         Filter          *f;
399         IDList          *candidates;
400
401         Debug(LDAP_DEBUG_TRACE, "subtree_candidates: base: %s\n",
402                 base ? base : "NULL", 0, 0);
403
404         /*
405          * get the base object - unless we already have it (from one-level).
406          * also, unless this is a one-level search or a subtree search
407          * starting at the very top of our subtree, we need to modify the
408          * filter to be something like this:
409          *
410          *      dn=*baseobjectdn & (originalfilter | ref=*)
411          *
412          * the "objectclass=referral" part is used to select referrals to return
413          */
414
415         *err = LDAP_SUCCESS;
416         f = NULL;
417         if ( lookupbase ) {
418                 if ( base != NULL && *base != '\0' &&
419                         (e = dn2entry_r( be, base, matched )) == NULL )
420                 {
421                         *err = LDAP_NO_SUCH_OBJECT;
422                         return( NULL );
423                 }
424
425                 if (e) {
426                         cache_return_entry_r( &li->li_cache, e );
427                 }
428
429                 f = (Filter *) ch_malloc( sizeof(Filter) );
430                 f->f_next = NULL;
431                 f->f_choice = LDAP_FILTER_OR;
432                 f->f_or = (Filter *) ch_malloc( sizeof(Filter) );
433                 f->f_or->f_choice = LDAP_FILTER_EQUALITY;
434                 f->f_or->f_avtype = ch_strdup( "objectclass" );
435                 /* Patch to use normalized uppercase */
436                 f->f_or->f_avvalue.bv_val = ch_strdup( "REFERRAL" );
437                 f->f_or->f_avvalue.bv_len = strlen( "REFERRAL" );
438                 f->f_or->f_next = filter;
439                 filter = f;
440
441                 if ( ! be_issuffix( be, base ) ) {
442                         f = (Filter *) ch_malloc( sizeof(Filter) );
443                         f->f_next = NULL;
444                         f->f_choice = LDAP_FILTER_AND;
445                         f->f_and = (Filter *) ch_malloc( sizeof(Filter) );
446                         f->f_and->f_choice = LDAP_FILTER_SUBSTRINGS;
447                         f->f_and->f_sub_type = ch_strdup( "dn" );
448                         f->f_and->f_sub_initial = NULL;
449                         f->f_and->f_sub_any = NULL;
450                         f->f_and->f_sub_final = ch_strdup( base );
451                         value_normalize( f->f_and->f_sub_final, SYNTAX_CIS );
452                         f->f_and->f_next = filter;
453                         filter = f;
454                 }
455         }
456
457         candidates = filter_candidates( be, filter );
458
459         /* free up just the parts we allocated above */
460         if ( f != NULL ) {
461                 f->f_and->f_next = NULL;
462                 filter_free( f );
463         }
464
465         return( candidates );
466 }