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