]> git.sur5r.net Git - openldap/blob - servers/slapd/str2filter.c
Initial revision
[openldap] / servers / slapd / str2filter.c
1 /* str2filter.c - parse an rfc 1588 string filter */
2
3 #include <stdio.h>
4 #include <string.h>
5 #include <sys/types.h>
6 #include <sys/socket.h>
7 #include "slap.h"
8
9 static char     *find_matching_paren();
10 static Filter   *str2list();
11 static Filter   *str2simple();
12 static int      str2subvals();
13
14 Filter *
15 str2filter( char *str )
16 {
17         Filter  *f;
18         char    *end;
19
20         Debug( LDAP_DEBUG_FILTER, "str2filter \"%s\"\n", str, 0, 0 );
21
22         if ( str == NULL || *str == '\0' ) {
23                 return( NULL );
24         }
25
26         switch ( *str ) {
27         case '(':
28                 if ( (end = find_matching_paren( str )) == NULL ) {
29                         filter_free( f );
30                         return( NULL );
31                 }
32                 *end = '\0';
33
34                 str++;
35                 switch ( *str ) {
36                 case '&':
37                         Debug( LDAP_DEBUG_FILTER, "str2filter: AND\n",
38                             0, 0, 0 );
39
40                         str++;
41                         f = str2list( str, LDAP_FILTER_AND );
42                         break;
43
44                 case '|':
45                         Debug( LDAP_DEBUG_FILTER, "put_filter: OR\n",
46                             0, 0, 0 );
47
48                         str++;
49                         f = str2list( str, LDAP_FILTER_OR );
50                         break;
51
52                 case '!':
53                         Debug( LDAP_DEBUG_FILTER, "put_filter: NOT\n",
54                             0, 0, 0 );
55
56                         str++;
57                         f = str2list( str, LDAP_FILTER_NOT );
58                         break;
59
60                 default:
61                         Debug( LDAP_DEBUG_FILTER, "str2filter: simple\n",
62                             0, 0, 0 );
63
64                         f = str2simple( str );
65                         break;
66                 }
67                 *end = ')';
68                 break;
69
70         default:        /* assume it's a simple type=value filter */
71                 Debug( LDAP_DEBUG_FILTER, "str2filter: default\n", 0, 0,
72                     0 );
73
74                 f = str2simple( str );
75                 break;
76         }
77
78         return( f );
79 }
80
81 /*
82  * Put a list of filters like this "(filter1)(filter2)..."
83  */
84
85 static Filter *
86 str2list( char *str, unsigned long ftype )
87 {
88         Filter  *f;
89         Filter  **fp;
90         char    *next;
91         char    save;
92
93         Debug( LDAP_DEBUG_FILTER, "str2list \"%s\"\n", str, 0, 0 );
94
95         f = (Filter *) ch_calloc( 1, sizeof(Filter) );
96         f->f_choice = ftype;
97         fp = &f->f_list;
98
99         while ( *str ) {
100                 while ( *str && isspace( *str ) )
101                         str++;
102                 if ( *str == '\0' )
103                         break;
104
105                 if ( (next = find_matching_paren( str )) == NULL ) {
106                         filter_free( f );
107                         return( NULL );
108                 }
109                 save = *++next;
110                 *next = '\0';
111
112                 /* now we have "(filter)" with str pointing to it */
113                 if ( (*fp = str2filter( str )) == NULL ) {
114                         filter_free( f );
115                         *next = save;
116                         return( NULL );
117                 }
118                 *next = save;
119
120                 str = next;
121                 fp = &(*fp)->f_next;
122         }
123         *fp = NULL;
124
125         return( f );
126 }
127
128 static Filter *
129 str2simple( char *str )
130 {
131         Filter          *f;
132         char            *s;
133         char            *value, savechar;
134
135         Debug( LDAP_DEBUG_FILTER, "str2simple \"%s\"\n", str, 0, 0 );
136
137         if ( (s = strchr( str, '=' )) == NULL ) {
138                 return( NULL );
139         }
140         value = s + 1;
141         *s-- = '\0';
142         savechar = *s;
143
144         f = (Filter *) ch_calloc( 1, sizeof(Filter) );
145
146         switch ( *s ) {
147         case '<':
148                 f->f_choice = LDAP_FILTER_LE;
149                 *s = '\0';
150                 break;
151         case '>':
152                 f->f_choice = LDAP_FILTER_GE;
153                 *s = '\0';
154                 break;
155         case '~':
156                 f->f_choice = LDAP_FILTER_APPROX;
157                 *s = '\0';
158                 break;
159         default:
160                 if ( strchr( value, '*' ) == NULL ) {
161                         f->f_choice = LDAP_FILTER_EQUALITY;
162                 } else if ( strcmp( value, "*" ) == 0 ) {
163                         f->f_choice = LDAP_FILTER_PRESENT;
164                 } else {
165                         f->f_choice = LDAP_FILTER_SUBSTRINGS;
166                         f->f_sub_type = strdup( str );
167                         if ( str2subvals( value, f ) != 0 ) {
168                                 filter_free( f );
169                                 *(value-1) = '=';
170                                 return( NULL );
171                         }
172                         *(value-1) = '=';
173                         return( f );
174                 }
175                 break;
176         }
177
178         if ( f->f_choice == LDAP_FILTER_PRESENT ) {
179                 f->f_type = strdup( str );
180         } else {
181                 f->f_avtype = strdup( str );
182                 f->f_avvalue.bv_val = strdup( value );
183                 f->f_avvalue.bv_len = strlen( value );
184         }
185
186         *s = savechar;
187         *(value-1) = '=';
188         return( f );
189 }
190
191 static int
192 str2subvals( char *val, Filter *f )
193 {
194         char    *nextstar;
195         int     gotstar;
196
197         Debug( LDAP_DEBUG_FILTER, "str2subvals \"%s\"\n", val, 0, 0 );
198
199         gotstar = 0;
200         while ( val != NULL && *val ) {
201                 if ( (nextstar = strchr( val, '*' )) != NULL )
202                         *nextstar++ = '\0';
203
204                 if ( gotstar == 0 ) {
205                         f->f_sub_initial = strdup( val );
206                 } else if ( nextstar == NULL ) {
207                         f->f_sub_final = strdup( val );
208                 } else {
209                         charray_add( &f->f_sub_any, strdup( val ) );
210                 }
211
212                 gotstar = 1;
213                 if ( nextstar != NULL )
214                         *(nextstar-1) = '*';
215                 val = nextstar;
216         }
217
218         return( 0 );
219 }
220
221 /*
222  * find_matching_paren - return a pointer to the right paren in s matching
223  * the left paren to which *s currently points
224  */
225
226 static char *
227 find_matching_paren( char *s )
228 {
229         int     balance, escape;
230
231         balance = 0;
232         escape = 0;
233         for ( ; *s; s++ ) {
234                 if ( escape == 0 ) {
235                         if ( *s == '(' )
236                                 balance++;
237                         else if ( *s == ')' )
238                                 balance--;
239                 }
240                 if ( balance == 0 ) {
241                         return( s );
242                 }
243                 if ( *s == '\\' && ! escape )
244                         escape = 1;
245                 else
246                         escape = 0;
247         }
248
249         return( NULL );
250 }