]> git.sur5r.net Git - openldap/blob - servers/slapd/filterentry.c
Yet another round of SLAPD_SCHEMA_NOT_COMPAT changes, including:
[openldap] / servers / slapd / filterentry.c
1 /* filterentry.c - apply a filter to an entry */
2 /* $OpenLDAP$ */
3 /*
4  * Copyright 1998-1999 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
12 #include <ac/socket.h>
13 #include <ac/string.h>
14
15 #ifndef SLAPD_SCHEMA_NOT_COMPAT
16 #include <ac/regex.h>
17 #endif
18
19 #include "slap.h"
20
21 static int      test_filter_and( Backend *be,
22         Connection *conn, Operation *op,
23         Entry *e, Filter *flist );
24 static int      test_filter_or( Backend *be,
25         Connection *conn, Operation *op,
26         Entry *e, Filter *flist );
27 static int      test_substring_filter( Backend *be,
28         Connection *conn, Operation *op,
29         Entry *e, Filter *f);
30 #ifdef SLAPD_SCHEMA_NOT_COMPAT
31 static int      test_ava_filter( Backend *be,
32         Connection *conn, Operation *op,
33         Entry *e, AttributeAssertion *ava, int type );
34 static int      test_mra_filter( Backend *be,
35         Connection *conn, Operation *op,
36         Entry *e, MatchingRuleAssertion *mra );
37 static int      test_presence_filter( Backend *be,
38         Connection *conn, Operation *op,
39         Entry *e, AttributeDescription *desc );
40 #else
41 static int      test_ava_filter(Backend *be,
42         Connection *conn, Operation *op,
43         Entry *e, Ava *ava, int type);
44 static int      test_approx_filter(Backend *be,
45         Connection *conn, Operation *op,
46         Entry *e, Ava *ava);
47 static int      test_presence_filter(Backend *be,
48         Connection *conn, Operation *op,
49         Entry *e, char *type);
50 #endif
51
52
53 /*
54  * test_filter - test a filter against a single entry.
55  * returns:
56  *              LDAP_COMPARE_TRUE       filter matched
57  *              LDAP_COMPARE_FALSE      filter did not match
58  *      or an ldap error code
59  */
60
61 int
62 test_filter(
63     Backend     *be,
64     Connection  *conn,
65     Operation   *op,
66     Entry       *e,
67     Filter      *f
68 )
69 {
70         int     rc;
71
72         Debug( LDAP_DEBUG_FILTER, "=> test_filter\n", 0, 0, 0 );
73
74         switch ( f->f_choice ) {
75         case LDAP_FILTER_EQUALITY:
76                 Debug( LDAP_DEBUG_FILTER, "    EQUALITY\n", 0, 0, 0 );
77 #ifdef SLAPD_SCHEMA_NOT_COMPAT
78                 rc = test_ava_filter( be, conn, op, e, f->f_ava,
79                     LDAP_FILTER_EQUALITY );
80 #else
81                 rc = test_ava_filter( be, conn, op, e, &f->f_ava,
82                     LDAP_FILTER_EQUALITY );
83 #endif
84                 break;
85
86         case LDAP_FILTER_SUBSTRINGS:
87                 Debug( LDAP_DEBUG_FILTER, "    SUBSTRINGS\n", 0, 0, 0 );
88                 rc = test_substring_filter( be, conn, op, e, f );
89                 break;
90
91         case LDAP_FILTER_GE:
92 #ifdef SLAPD_SCHEMA_NOT_COMPAT
93                 rc = test_ava_filter( be, conn, op, e, f->f_ava,
94                     LDAP_FILTER_GE );
95 #else
96                 Debug( LDAP_DEBUG_FILTER, "    GE\n", 0, 0, 0 );
97                 rc = test_ava_filter( be, conn, op, e, &f->f_ava,
98                     LDAP_FILTER_GE );
99 #endif
100                 break;
101
102         case LDAP_FILTER_LE:
103 #ifdef SLAPD_SCHEMA_NOT_COMPAT
104                 rc = test_ava_filter( be, conn, op, e, f->f_ava,
105                     LDAP_FILTER_LE );
106 #else
107                 Debug( LDAP_DEBUG_FILTER, "    LE\n", 0, 0, 0 );
108                 rc = test_ava_filter( be, conn, op, e, &f->f_ava,
109                     LDAP_FILTER_LE );
110 #endif
111                 break;
112
113         case LDAP_FILTER_PRESENT:
114                 Debug( LDAP_DEBUG_FILTER, "    PRESENT\n", 0, 0, 0 );
115 #ifdef SLAPD_SCHEMA_NOT_COMPAT
116                 rc = test_presence_filter( be, conn, op, e, f->f_desc );
117 #else
118                 rc = test_presence_filter( be, conn, op, e, f->f_type );
119 #endif
120                 break;
121
122         case LDAP_FILTER_APPROX:
123                 Debug( LDAP_DEBUG_FILTER, "    APPROX\n", 0, 0, 0 );
124 #ifdef SLAPD_SCHEMA_NOT_COMPAT
125                 rc = test_ava_filter( be, conn, op, e, f->f_ava,
126                     LDAP_FILTER_APPROX );
127 #else
128                 rc = test_approx_filter( be, conn, op, e, &f->f_ava );
129 #endif
130                 break;
131
132         case LDAP_FILTER_AND:
133                 Debug( LDAP_DEBUG_FILTER, "    AND\n", 0, 0, 0 );
134                 rc = test_filter_and( be, conn, op, e, f->f_and );
135                 break;
136
137         case LDAP_FILTER_OR:
138                 Debug( LDAP_DEBUG_FILTER, "    OR\n", 0, 0, 0 );
139                 rc = test_filter_or( be, conn, op, e, f->f_or );
140                 break;
141
142         case LDAP_FILTER_NOT:
143                 Debug( LDAP_DEBUG_FILTER, "    NOT\n", 0, 0, 0 );
144                 rc = test_filter( be, conn, op, e, f->f_not );
145
146                 switch( rc ) {
147                 case LDAP_COMPARE_TRUE:
148                         rc = LDAP_COMPARE_FALSE;
149                         break;
150                 case LDAP_COMPARE_FALSE:
151                         rc = LDAP_COMPARE_TRUE;
152                         break;
153                 }
154                 break;
155
156 #ifdef SLAPD_EXT_FILTERS
157         case LDAP_FILTER_EXT:
158                 Debug( LDAP_DEBUG_FILTER, "    EXT\n", 0, 0, 0 );
159 #if SLAPD_SCHEMA_NOT_COMPAT
160                 rc = test_mra_filter( be, conn, op, e, f->f_mra );
161 #else
162                 rc = -1;
163 #endif
164                 break;
165 #endif
166
167         case 0:
168                 Debug( LDAP_DEBUG_FILTER, "    UNDEFINED\n", 0, 0, 0 );
169                 rc = -1;
170                 break;
171
172         default:
173                 Debug( LDAP_DEBUG_ANY, "    unknown filter type %lu\n",
174                     f->f_choice, 0, 0 );
175                 rc = -1;
176         }
177
178         Debug( LDAP_DEBUG_FILTER, "<= test_filter %d\n", rc, 0, 0 );
179         return( rc );
180 }
181
182
183 static int
184 test_ava_filter(
185     Backend     *be,
186     Connection  *conn,
187     Operation   *op,
188     Entry       *e,
189 #ifdef SLAPD_SCHEMA_NOT_COMPAT
190         AttributeAssertion *ava,
191 #else
192     Ava         *ava,
193 #endif
194     int         type
195 )
196 {
197         int             i;
198         Attribute       *a;
199
200 #ifdef SLAPD_SCHEMA_NOT_COMPAT
201         if ( be != NULL && ! access_allowed( be, conn, op, e,
202                 ava->aa_desc, ava->aa_value, ACL_SEARCH ) )
203 #else
204
205         if ( be != NULL && ! access_allowed( be, conn, op, e,
206                 ava->ava_type, &ava->ava_value, ACL_SEARCH ) )
207 #endif
208         {
209                 return( -2 );
210         }
211
212 #ifdef SLAPD_SCHEMA_NOT_COMPAT
213         for(a = attrs_find( e->e_attrs, ava->aa_desc );
214                 a != NULL;
215                 a = attrs_find( a, ava->aa_desc ) )
216 #else
217         a = attr_find( e->e_attrs, ava->ava_type );
218         if ( a != NULL )
219 #endif
220         {
221 #ifndef SLAPD_SCHEMA_NOT_COMPAT
222                 if ( a->a_syntax == 0 ) {
223                         a->a_syntax = attr_syntax( ava->ava_type );
224                 }
225 #endif
226
227                 for ( i = 0; a->a_vals[i] != NULL; i++ ) {
228                         int rc;
229
230 #ifdef SLAPD_SCHEMA_NOT_COMPAT
231                         /* not yet implemented */
232                         rc = 0;
233 #else
234                         rc = value_cmp( a->a_vals[i], &ava->ava_value, a->a_syntax,
235                                 3 );
236 #endif
237
238                         switch ( type ) {
239                         case LDAP_FILTER_EQUALITY:
240                         case LDAP_FILTER_APPROX:
241                                 if ( rc == 0 ) {
242                                         return LDAP_COMPARE_TRUE;
243                                 }
244                                 break;
245
246                         case LDAP_FILTER_GE:
247                                 if ( rc >= 0 ) {
248                                         return LDAP_COMPARE_TRUE;
249                                 }
250                                 break;
251
252                         case LDAP_FILTER_LE:
253                                 if ( rc <= 0 ) {
254                                         return LDAP_COMPARE_TRUE;
255                                 }
256                                 break;
257                         }
258                 }
259         }
260
261         return( LDAP_COMPARE_FALSE );
262 }
263
264
265 static int
266 test_presence_filter(
267     Backend     *be,
268     Connection  *conn,
269     Operation   *op,
270     Entry       *e,
271 #ifdef SLAPD_SCHEMA_NOT_COMPAT
272         AttributeDescription *desc
273 #else
274     char        *desc
275 #endif
276 )
277 {
278         if ( be != NULL && ! access_allowed( be, conn, op, e,
279                 desc, NULL, ACL_SEARCH ) )
280         {
281                 return( -2 );
282         }
283
284 #ifdef SLAPD_SCHEMA_NOT_COMPAT
285         return attrs_find( e->e_attrs, desc ) != NULL
286 #else
287         return attr_find( e->e_attrs, desc ) != NULL
288 #endif
289                 ? LDAP_COMPARE_TRUE : LDAP_COMPARE_FALSE;
290 }
291
292 #ifndef SLAPD_SCHEMA_NOT_COMPAT
293 static int
294 test_approx_filter(
295     Backend     *be,
296     Connection  *conn,
297     Operation   *op,
298     Entry       *e,
299     Ava         *ava
300 )
301 {
302         char            *w1, *w2, *c1, *c2;
303         int             i;
304         Attribute       *a;
305
306         if ( be != NULL && ! access_allowed( be, conn, op, e,
307                 ava->ava_type, NULL, ACL_SEARCH ) )
308         {
309                 return( -2 );
310         }
311
312         a = attr_find( e->e_attrs, ava->ava_type );
313         if ( a != NULL ) {
314                 /* for each value in the attribute */
315                 for ( i = 0; a->a_vals[i] != NULL; i++ ) {
316                         /*
317                          * try to match words in the filter value in order
318                          * in the attribute value.
319                          */
320
321                         w2 = a->a_vals[i]->bv_val;
322                         /* for each word in the filter value */
323                         for ( w1 = first_word( ava->ava_value.bv_val ); w1 != NULL;
324                                 w1 = next_word( w1 ) ) {
325                                 if ( (c1 = phonetic( w1 )) == NULL ) {
326                                         break;
327                                 }
328
329                                 /*
330                                  * for each word in the attribute value from
331                                  * where we left off...
332                                  */
333                                 for ( w2 = first_word( w2 ); w2 != NULL;
334                                         w2 = next_word( w2 ) ) {
335                                         c2 = phonetic( w2 );
336                                         if ( strcmp( c1, c2 ) == 0 ) {
337                                                 free( c2 );
338                                                 break;
339                                         }
340                                         free( c2 );
341                                 }
342                                 free( c1 );
343
344                                 /*
345                                  * if we stopped because we ran out of words
346                                  * before making a match, go on to the next
347                                  * value.  otherwise try to keep matching
348                                  * words in this value from where we left off.
349                                  */
350                                 if ( w2 == NULL ) {
351                                         break;
352                                 } else {
353                                         w2 = next_word( w2 );
354                                 }
355                         }
356                         /*
357                          * if we stopped because we ran out of words we
358                          * have a match.
359                          */
360                         if ( w1 == NULL ) {
361                                 return LDAP_COMPARE_TRUE;
362                         }
363                 }
364         }
365
366         return LDAP_COMPARE_FALSE;
367 }
368 #endif
369
370 static int
371 test_filter_and(
372     Backend     *be,
373     Connection  *conn,
374     Operation   *op,
375     Entry       *e,
376     Filter      *flist
377 )
378 {
379         Filter  *f;
380         int rtn = LDAP_COMPARE_TRUE;
381
382         Debug( LDAP_DEBUG_FILTER, "=> test_filter_and\n", 0, 0, 0 );
383
384         for ( f = flist; f != NULL; f = f->f_next ) {
385                 int rc = test_filter( be, conn, op, e, f );
386
387                 if ( rc == LDAP_COMPARE_FALSE ) {
388                         rtn = LDAP_COMPARE_FALSE;
389                         break;
390                 }
391                 if ( rc != LDAP_COMPARE_TRUE ) {
392                         rtn = rc;
393                 }
394         }
395
396         Debug( LDAP_DEBUG_FILTER, "<= test_filter_and %d\n", rtn, 0, 0 );
397         return rtn;
398 }
399
400 static int
401 test_filter_or(
402     Backend     *be,
403     Connection  *conn,
404     Operation   *op,
405     Entry       *e,
406     Filter      *flist
407 )
408 {
409         Filter  *f;
410         int rtn = LDAP_COMPARE_FALSE;
411
412         Debug( LDAP_DEBUG_FILTER, "=> test_filter_or\n", 0, 0, 0 );
413
414         for ( f = flist; f != NULL; f = f->f_next ) {
415                 int rc = test_filter( be, conn, op, e, f );
416
417                 if ( rc == LDAP_COMPARE_TRUE ) {
418                         rtn = LDAP_COMPARE_TRUE;
419                         break;
420                 }
421                 if ( rc != LDAP_COMPARE_TRUE ) {
422                         rtn = rc;
423                 }
424         }
425
426         Debug( LDAP_DEBUG_FILTER, "<= test_filter_or %d\n", rtn, 0, 0 );
427         return rtn;
428 }
429
430 #ifndef SLAPD_SCHEMA_NOT_COMPAT
431 static void
432 strcpy_regex( char *d, char *s )
433 {
434         for ( ; *s; s++ ) {
435                 switch ( *s ) {
436                 case '^':
437                 case '.':
438                 case '[':
439                 case ']': /* ? */
440                 case '$':
441                 case '(':
442                 case ')': /* ? */
443                 case '|':
444                 case '*':
445                 case '+':
446                 case '?':
447                 case '{':
448                 case '}': /* ? */
449                 case '\\':
450                         *d++ = '\\';
451                         /* FALL */
452                 default:
453                         *d++ = *s;
454                 }
455         }
456         *d = '\0';
457 }
458 #endif
459
460 static int
461 test_substring_filter(
462     Backend     *be,
463     Connection  *conn,
464     Operation   *op,
465     Entry       *e,
466     Filter      *f
467 )
468 {
469 #ifndef SLAPD_SCHEMA_NOT_COMPAT
470         Attribute       *a;
471         int             i, rc;
472         char            *p, *end, *realval, *tmp;
473         char            pat[BUFSIZ];
474         char            buf[BUFSIZ];
475         struct berval   *val;
476         regex_t         re;
477
478         Debug( LDAP_DEBUG_FILTER, "begin test_substring_filter\n", 0, 0, 0 );
479
480         if ( be != NULL && ! access_allowed( be, conn, op, e,
481                 f->f_sub_type, NULL, ACL_SEARCH ) )
482         {
483                 return( -2 );
484         }
485
486         if ( (a = attr_find( e->e_attrs, f->f_sub_type )) == NULL ) {
487                 return LDAP_COMPARE_FALSE;
488         }
489
490         if ( a->a_syntax & SYNTAX_BIN ) {
491                 Debug( LDAP_DEBUG_FILTER, "test_substring_filter bin attr\n",
492                     0, 0, 0 );
493                 return( -1 );
494         }
495
496         /*
497          * construct a regular expression corresponding to the
498          * filter and let regex do the work
499          */
500
501         pat[0] = '\0';
502         p = pat;
503         end = pat + sizeof(pat) - 2;    /* leave room for null */
504         if ( f->f_sub_initial != NULL ) {
505                 strcpy( p, "^" );
506                 p = strchr( p, '\0' );
507                 /* 2 * in case every char is special */
508                 if ( p + 2 * f->f_sub_initial->bv_len > end ) {
509                         Debug( LDAP_DEBUG_ANY, "not enough pattern space\n",
510                             0, 0, 0 );
511                         return( -1 );
512                 }
513                 strcpy_regex( p, f->f_sub_initial->bv_val );
514                 p = strchr( p, '\0' );
515         }
516         if ( f->f_sub_any != NULL ) {
517                 for ( i = 0; f->f_sub_any[i] != NULL; i++ ) {
518                         /* ".*" + value */
519                         if ( p + 2 * f->f_sub_any[i]->bv_len + 2 > end ) {
520                                 Debug( LDAP_DEBUG_ANY,
521                                     "not enough pattern space\n", 0, 0, 0 );
522                                 return( -1 );
523                         }
524                         strcpy( p, ".*" );
525                         p = strchr( p, '\0' );
526                         strcpy_regex( p, f->f_sub_any[i]->bv_val );
527                         p = strchr( p, '\0' );
528                 }
529         }
530         if ( f->f_sub_final != NULL ) {
531                 /* ".*" + value */
532                 if ( p + 2 * f->f_sub_final->bv_len + 2 > end ) {
533                         Debug( LDAP_DEBUG_ANY, "not enough pattern space\n",
534                             0, 0, 0 );
535                         return( -1 );
536                 }
537                 strcpy( p, ".*" );
538                 p = strchr( p, '\0' );
539                 strcpy_regex( p, f->f_sub_final->bv_val );
540                 p = strchr( p, '\0' );
541                 strcpy( p, "$" );
542         }
543
544         /* compile the regex */
545         Debug( LDAP_DEBUG_FILTER, "test_substring_filter: regcomp pat: %s\n",
546                 pat, 0, 0 );
547         if ((rc = regcomp(&re, pat, REG_EXTENDED|REG_NOSUB))) {
548                 char error[512];
549
550                 regerror(rc, &re, error, sizeof(error));
551                 Debug( LDAP_DEBUG_ANY, "regcomp failed (%s) %s\n",
552                         p, error, 0 );
553                 return( -1 );
554         }
555
556         /* for each value in the attribute see if regex matches */
557         for ( i = 0; a->a_vals[i] != NULL; i++ ) {
558                 val = a->a_vals[i];
559                 tmp = NULL;
560                 if ( val->bv_len < sizeof(buf) ) {
561                         strcpy( buf, val->bv_val );
562                         realval = buf;
563                 } else {
564                         tmp = (char *) ch_malloc( val->bv_len + 1 );
565                         strcpy( tmp, val->bv_val );
566                         realval = tmp;
567                 }
568
569                 value_normalize( realval, a->a_syntax );
570
571                 rc = !regexec(&re, realval, 0, NULL, 0);
572
573                 if ( tmp != NULL ) {
574                         free( tmp );
575                 }
576                 if ( rc == 1 ) {
577                         regfree(&re);
578                         return LDAP_COMPARE_TRUE;
579                 }
580         }
581
582         regfree(&re);
583 #endif
584
585         Debug( LDAP_DEBUG_FILTER, "end test_substring_filter 1\n", 0, 0, 0 );
586         return LDAP_COMPARE_FALSE;
587 }