]> git.sur5r.net Git - openldap/blob - servers/slapd/back-bdb/search.c
Remove lint
[openldap] / servers / slapd / back-bdb / search.c
1 /* search.c - search operation */
2 /* $OpenLDAP$ */
3 /*
4  * Copyright 1998-2000 The OpenLDAP Foundation, All Rights Reserved.
5  * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
6  */
7
8 #include "portable.h"
9
10 #include <stdio.h>
11 #include <ac/string.h>
12
13 #include "back-bdb.h"
14 #include "idl.h"
15 #include "external.h"
16
17 static int base_candidate(
18         BackendDB       *be,
19         Entry   *e,
20         ID              *ids );
21 static int search_candidates(
22         BackendDB *be,
23         Entry *e,
24         Filter *filter,
25         int scope,
26         int deref,
27         int manageDSAit,
28         ID      *ids );
29
30 int
31 bdb_search(
32         BackendDB       *be,
33         Connection      *conn,
34         Operation       *op,
35         const char      *base,
36         const char      *nbase,
37         int             scope,
38         int             deref,
39         int             slimit,
40         int             tlimit,
41         Filter  *filter,
42         const char      *filterstr,
43         char    **attrs,
44         int             attrsonly )
45 {
46         struct bdb_info *bdb = (struct bdb_info *) be->be_private;
47         int              abandon;
48         int             rc;
49         const char *text = NULL;
50         time_t          stoptime;
51         ID              id, cursor;
52         ID              candidates[BDB_IDL_UM_SIZE];
53         Entry           *e = NULL;
54         struct berval **v2refs = NULL;
55         Entry   *matched = NULL;
56         char    *realbase = NULL;
57         int             nentries = 0;
58         int             manageDSAit;
59
60         struct slap_limits_set *limit = NULL;
61         int isroot = 0;
62
63         Debug( LDAP_DEBUG_TRACE, "=> bdb_back_search\n",
64                 0, 0, 0);
65
66         manageDSAit = get_manageDSAit( op );
67
68 #ifdef BDB_ALIASES
69         /* get entry with reader lock */
70         if ( deref & LDAP_DEREF_FINDING ) {
71                 e = deref_dn_r( be, nbase, &err, &matched, &text );
72
73         } else
74 #endif
75         {
76                 rc = bdb_dn2entry( be, NULL, nbase, &e, &matched, 0 );
77         }
78
79         switch(rc) {
80         case DB_NOTFOUND:
81         case 0:
82                 break;
83         default:
84                 send_ldap_result( conn, op, rc=LDAP_OTHER,
85                         NULL, "internal error", NULL, NULL );
86                 return rc;
87         }
88
89         if ( e == NULL ) {
90                 char *matched_dn = NULL;
91                 struct berval **refs = NULL;
92
93                 if ( matched != NULL ) {
94                         struct berval **erefs;
95                         matched_dn = ch_strdup( matched->e_dn );
96
97                         erefs = is_entry_referral( matched )
98                                 ? get_entry_referrals( be, conn, op, matched,
99                                         base, scope )
100                                 : NULL;
101
102                         bdb_entry_return( be, matched );
103                         matched = NULL;
104
105                         if( erefs ) {
106                                 refs = referral_rewrite( erefs, matched_dn,
107                                         base, scope );
108                                 ber_bvecfree( erefs );
109                         }
110
111                 } else {
112                         refs = referral_rewrite( default_referral,
113                                 NULL, base, scope );
114                 }
115
116                 send_ldap_result( conn, op,     rc=LDAP_REFERRAL ,
117                         matched_dn, text, refs, NULL );
118
119                 ber_bvecfree( refs );
120                 free( matched_dn );
121
122                 return rc;
123         }
124
125         if (!manageDSAit && is_entry_referral( e ) ) {
126                 /* entry is a referral, don't allow add */
127                 char *matched_dn = ch_strdup( e->e_dn );
128                 struct berval **erefs = get_entry_referrals( be,
129                         conn, op, e, base, scope );
130                 struct berval **refs = NULL;
131
132                 bdb_entry_return( be, e );
133                 e = NULL;
134
135                 if( erefs ) {
136                         refs = referral_rewrite( erefs, matched_dn,
137                                 base, scope );
138                         ber_bvecfree( erefs );
139                 }
140
141                 Debug( LDAP_DEBUG_TRACE, "bdb_search: entry is referral\n",
142                         0, 0, 0 );
143
144                 send_ldap_result( conn, op, LDAP_REFERRAL,
145                         matched_dn, refs ? NULL : "bad referral object",
146                         refs, NULL );
147
148                 ber_bvecfree( refs );
149                 free( matched_dn );
150
151                 return 1;
152         }
153
154         /* if not root, get appropriate limits */
155         if ( be_isroot( be, op->o_ndn ) ) {
156                 isroot = 1;
157         } else {
158                 ( void ) get_limits( be, op->o_ndn, &limit );
159         }
160
161         /* The time/size limits come first because they require very little
162          * effort, so there's no chance the candidates are selected and then 
163          * the request is not honored only because of time/size constraints */
164
165         /* if no time limit requested, use soft limit (unless root!) */
166         if ( tlimit <= 0 ) {
167                 if ( isroot ) {
168                         tlimit = -1;        /* allow root to set no limit */
169                 } else {
170                         tlimit = limit->lms_t_soft;
171                 }
172
173         /* if requested limit higher than hard limit, abort */
174         } else if ( tlimit > limit->lms_t_hard ) {
175                 /* no hard limit means use soft instead */
176                 if ( limit->lms_t_hard == 0 ) {
177                         tlimit = limit->lms_t_soft;
178
179                 /* positive hard limit means abort */
180                 } else if ( limit->lms_t_hard > 0 ) {
181                         send_search_result( conn, op, 
182                                         LDAP_UNWILLING_TO_PERFORM,
183                                         NULL, NULL, NULL, NULL, 0 );
184                         rc = 0;
185                         goto done;
186                 }
187                 
188                 /* negative hard limit means no limit */
189         }
190
191         /* compute it anyway; root does not use it */
192         stoptime = op->o_time + tlimit;
193         
194         /* if no size limit requested, use soft limit (unless root!) */
195         if ( slimit == 0 ) {
196                 if ( isroot ) {
197                         slimit = -1;        /* allow root to set no limit */
198                 } else {
199                         slimit = limit->lms_s_soft;
200                 }
201
202         /* if requested limit higher than hard limit, abort */
203         } else if ( slimit > limit->lms_s_hard ) {
204                 /* no hard limit means use soft instead */
205                 if ( limit->lms_s_hard == 0 ) {
206                         slimit = limit->lms_s_soft;
207
208                 /* positive hard limit means abort */
209                 } else if ( limit->lms_s_hard > 0 ) {
210                         send_search_result( conn, op, 
211                                         LDAP_UNWILLING_TO_PERFORM,
212                                         NULL, NULL, NULL, NULL, 0 );
213                         rc = 0; 
214                         goto done;
215                 }
216                 
217                 /* negative hard limit means no limit */
218         }
219
220         /* select candidates */
221         if ( scope == LDAP_SCOPE_BASE ) {
222                 rc = base_candidate( be, e, candidates );
223
224         } else {
225                 rc = search_candidates( be, e, filter,
226                         scope, deref, manageDSAit, candidates );
227         }
228
229         /* need normalized dn below */
230         realbase = ch_strdup( e->e_ndn );
231
232         /* start cursor at base entry's id */
233         cursor = e->e_id;
234
235         bdb_entry_return( be, e );
236         e = NULL;
237
238         if ( candidates[0] == 0 ) {
239                 Debug( LDAP_DEBUG_TRACE, "bdb_search: no candidates\n",
240                         0, 0, 0 );
241
242                 send_search_result( conn, op,
243                         LDAP_SUCCESS,
244                         NULL, NULL, NULL, NULL, 0 );
245
246                 rc = 1;
247                 goto done;
248         }
249
250         /* if not root and candidates exceed to-be-checked entries, abort */
251         if ( !isroot && limit->lms_s_unchecked != -1 ) {
252                 if ( BDB_IDL_N(candidates) > limit->lms_s_unchecked ) {
253                         send_search_result( conn, op, 
254                                         LDAP_UNWILLING_TO_PERFORM,
255                                         NULL, NULL, NULL, NULL, 0 );
256                         rc = 1;
257                         goto done;
258                 }
259         }
260
261         for ( id = bdb_idl_first( candidates, &cursor );
262                 id != NOID;
263                 id = bdb_idl_next( candidates, &cursor ) )
264         {
265                 int             scopeok = 0;
266
267                 /* check for abandon */
268                 ldap_pvt_thread_mutex_lock( &op->o_abandonmutex );
269                 abandon = op->o_abandon;
270                 ldap_pvt_thread_mutex_unlock( &op->o_abandonmutex );
271
272                 if ( abandon ) {
273                         rc = 0;
274                         goto done;
275                 }
276
277                 /* check time limit */
278                 if ( tlimit != -1 && slap_get_time() > stoptime ) {
279                         send_search_result( conn, op, rc = LDAP_TIMELIMIT_EXCEEDED,
280                                 NULL, NULL, v2refs, NULL, nentries );
281                         goto done;
282                 }
283
284                 /* get the entry with reader lock */
285                 rc = bdb_id2entry( be, NULL, id, &e );
286
287                 if ( e == NULL ) {
288                         if( !BDB_IDL_IS_RANGE(candidates) ) {
289                                 /* only complain for non-range IDLs */
290                                 Debug( LDAP_DEBUG_TRACE,
291                                         "bdb_search: candidate %ld not found\n",
292                                         (long) id, 0, 0 );
293                         }
294
295                         goto loop_continue;
296                 }
297
298 #ifdef BDB_ALIASES
299                 if ( deref & LDAP_DEREF_SEARCHING && is_entry_alias( e ) ) {
300                         Entry *matched;
301                         int err;
302                         const char *text;
303                         
304                         e = deref_entry_r( be, e, &err, &matched, &text );
305
306                         if( e == NULL ) {
307                                 e = matched;
308                                 goto loop_continue;
309                         }
310
311                         if( e->e_id == id ) {
312                                 /* circular loop */
313                                 goto loop_continue;
314                         }
315
316                         /* need to skip alias which deref into scope */
317                         if( scope & LDAP_SCOPE_ONELEVEL ) {
318                                 char *pdn = dn_parent( NULL, e->e_ndn );
319                                 if ( pdn != NULL ) {
320                                         if( strcmp( pdn, realbase ) ) {
321                                                 free( pdn );
322                                                 goto loop_continue;
323                                         }
324                                         free(pdn);
325                                 }
326
327                         } else if ( dn_issuffix( e->e_ndn, realbase ) ) {
328                                 /* alias is within scope */
329                                 Debug( LDAP_DEBUG_TRACE,
330                                         "bdb_search: \"%s\" in subtree\n",
331                                         e->e_dn, 0, 0 );
332                                 goto loop_continue;
333                         }
334
335                         scopeok = 1;
336                 }
337 #endif
338
339                 /*
340                  * if it's a referral, add it to the list of referrals. only do
341                  * this for non-base searches, and don't check the filter
342                  * explicitly here since it's only a candidate anyway.
343                  */
344                 if ( !manageDSAit && scope != LDAP_SCOPE_BASE &&
345                         is_entry_referral( e ) )
346                 {
347                         struct berval **refs = get_entry_referrals(
348                                 be, conn, op, e, NULL, scope );
349
350                         send_search_reference( be, conn, op,
351                                 e, refs, NULL, &v2refs );
352
353                         ber_bvecfree( refs );
354
355                         goto loop_continue;
356                 }
357
358                 /* if it matches the filter and scope, send it */
359                 rc = test_filter( be, conn, op, e, filter );
360                 if ( rc == LDAP_COMPARE_TRUE ) {
361                         char    *dn;
362
363                         /* check scope */
364                         if ( !scopeok && scope == LDAP_SCOPE_ONELEVEL ) {
365                                 if ( (dn = dn_parent( be, e->e_ndn )) != NULL ) {
366                                         (void) dn_normalize( dn );
367                                         scopeok = (dn == realbase)
368                                                 ? 1
369                                                 : (strcmp( dn, realbase ) ? 0 : 1 );
370                                         free( dn );
371
372                                 } else {
373                                         scopeok = (realbase == NULL || *realbase == '\0');
374                                 }
375
376                         } else if ( !scopeok && scope == LDAP_SCOPE_SUBTREE ) {
377                                 dn = ch_strdup( e->e_ndn );
378                                 scopeok = dn_issuffix( dn, realbase );
379                                 free( dn );
380
381                         } else {
382                                 scopeok = 1;
383                         }
384
385                         if ( scopeok ) {
386                                 /* check size limit */
387                                 if ( --slimit == -1 ) {
388                                         bdb_entry_return( be, e );
389                                         e = NULL;
390                                         send_search_result( conn, op,
391                                                 rc = LDAP_SIZELIMIT_EXCEEDED, NULL, NULL,
392                                                 v2refs, NULL, nentries );
393                                         goto done;
394                                 }
395
396                                 if (e) {
397                                         int result = send_search_entry( be, conn, op,
398                                                 e, attrs, attrsonly, NULL);
399
400                                         switch (result) {
401                                         case 0:         /* entry sent ok */
402                                                 nentries++;
403                                                 break;
404                                         case 1:         /* entry not sent */
405                                                 break;
406                                         case -1:        /* connection closed */
407                                                 bdb_entry_return( be, e );
408                                                 e = NULL;
409                                                 rc = LDAP_OTHER;
410                                                 goto done;
411                                         }
412                                 }
413                         } else {
414                                 Debug( LDAP_DEBUG_TRACE,
415                                         "bdb_search: %ld scope not okay\n",
416                                         (long) id, 0, 0 );
417                         }
418                 } else {
419                         Debug( LDAP_DEBUG_TRACE,
420                                 "bdb_search: %ld does match filter\n",
421                                 (long) id, 0, 0 );
422                 }
423
424 loop_continue:
425                 if( e != NULL ) {
426                         /* free reader lock */
427                         bdb_entry_return( be, e );
428                 }
429
430                 ldap_pvt_thread_yield();
431         }
432         send_search_result( conn, op,
433                 v2refs == NULL ? LDAP_SUCCESS : LDAP_REFERRAL,
434                 NULL, NULL, v2refs, NULL, nentries );
435
436         rc = 0;
437
438 done:
439         ber_bvecfree( v2refs );
440         if( realbase ) ch_free( realbase );
441
442         return rc;
443 }
444
445
446 static int base_candidate(
447         BackendDB       *be,
448         Entry   *e,
449         ID              *ids )
450 {
451         Debug(LDAP_DEBUG_ARGS, "base_candidates: base: \"%s\" (0x%08lx)\n",
452                 e->e_dn, (long) e->e_id, 0);
453
454         ids[0] = 1;
455         ids[1] = e->e_id;
456         return 0;
457 }
458
459 static int search_candidates(
460         BackendDB *be,
461         Entry *e,
462         Filter *filter,
463         int scope,
464         int deref,
465         int manageDSAit,
466         ID      *ids )
467 {
468         int rc;
469         Filter          f, fand, rf, xf;
470         AttributeAssertion aa_ref;
471         struct bdb_info *bdb = (struct bdb_info *) be->be_private;
472 #ifdef BDB_ALIASES
473         Filter  af;
474         AttributeAssertion aa_alias;
475 #endif
476
477         Debug(LDAP_DEBUG_TRACE,
478                 "search_candidates: base=\"%s\" (0x%08lx) scope=%d\n",
479                 e->e_dn, (long) e->e_id, scope );
480
481         xf.f_or = filter;
482         xf.f_choice = LDAP_FILTER_OR;
483         xf.f_next = NULL;
484
485         if( !manageDSAit ) {
486                 /* match referrals */
487                 static struct berval bv_ref = { sizeof("REFERRAL")-1, "REFERRAL" };
488                 rf.f_choice = LDAP_FILTER_EQUALITY;
489                 rf.f_ava = &aa_ref;
490                 rf.f_av_desc = slap_schema.si_ad_objectClass;
491                 rf.f_av_value = &bv_ref;
492                 rf.f_next = xf.f_or;
493                 xf.f_or = &rf;
494         }
495
496 #ifdef BDB_ALIASES
497         if( deref & LDAP_DEREF_SEARCHING ) {
498                 /* match aliases */
499                 static struct berval bv_alias = { sizeof("ALIAS")-1, "ALIAS" };
500                 af.f_choice = LDAP_FILTER_EQUALITY;
501                 af.f_ava = &aa_alias;
502                 af.f_av_desc = slap_schema.si_ad_objectClass;
503                 af.f_av_value = &bv_alias;
504                 af.f_next = xf.f_or;
505                 xf.f_or = &af;
506         }
507 #endif
508
509         f.f_next = NULL;
510         f.f_choice = LDAP_FILTER_AND;
511         f.f_and = &fand;
512         fand.f_choice = scope == LDAP_SCOPE_SUBTREE
513                 ? SLAPD_FILTER_DN_SUBTREE
514                 : SLAPD_FILTER_DN_ONE;
515         fand.f_dn = e->e_ndn;
516         fand.f_next = xf.f_or == filter ? filter : &xf ;
517
518
519 #ifdef BDB_FILTER_INDICES
520         rc = bdb_filter_candidates( be, &f, ids );
521 #else
522         BDB_IDL_ID( bdb, ids, e->e_id );
523         rc = 0;
524 #endif
525
526         Debug(LDAP_DEBUG_TRACE,
527                 "bdb_search_candidates: id=%ld first=%ld last=%ld\n",
528                 (long) ids[0],
529                 (long) BDB_IDL_FIRST(ids),
530                 (long) BDB_IDL_LAST(ids) );
531
532         return rc;
533 }