]> git.sur5r.net Git - openldap/blob - servers/slapd/sets.c
More changes to let BDB build without LDBM.
[openldap] / servers / slapd / sets.c
1 /* $OpenLDAP$ */
2 /*
3  * Copyright 2000 The OpenLDAP Foundation, All Rights Reserved.
4  * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
5  */
6
7 #include "portable.h"
8
9 #include <stdio.h>
10 #include <ac/string.h>
11
12 #include "slap.h"
13 #include "sets.h"
14
15 static char **set_join (char **lset, int op, char **rset);
16 static char **set_chase (SET_GATHER gatherer,
17         void *cookie, char **set, char *attr, int attrlen, int closure);
18 static int set_samedn (char *dn1, char *dn2);
19
20 long
21 set_size (char **set)
22 {
23         int i;
24
25         i = 0;
26         if (set != NULL) {
27                 while (set[i])
28                         i++;
29         }
30         return(i);
31 }
32
33 void
34 set_dispose (char **set)
35 {
36         int i;
37
38         if (set != NULL) {
39                 for (i = 0; set[i]; i++)
40                         ch_free(set[i]);
41                 ch_free(set);
42         }
43 }
44
45 static char **
46 set_join (char **lset, int op, char **rset)
47 {
48         char **set;
49         long i, j, last;
50
51         set = NULL;
52         if (op == '|') {
53                 if (lset == NULL || *lset == NULL) {
54                         if (rset == NULL) {
55                                 if (lset == NULL)
56                                         return(ch_calloc(1, sizeof(char *)));
57                                 return(lset);
58                         }
59                         set_dispose(lset);
60                         return(rset);
61                 }
62                 if (rset == NULL || *rset == NULL) {
63                         set_dispose(rset);
64                         return(lset);
65                 }
66
67                 i = set_size(lset) + set_size(rset) + 1;
68                 set = ch_calloc(i, sizeof(char *));
69                 if (set != NULL) {
70                         /* set_chase() depends on this routine to
71                          * keep the first elements of the result
72                          * set the same (and in the same order)
73                          * as the left-set.
74                          */
75                         for (i = 0; lset[i]; i++)
76                                 set[i] = lset[i];
77                         ch_free(lset);
78                         for (i = 0; rset[i]; i++) {
79                                 for (j = 0; set[j]; j++) {
80                                         if (set_samedn(rset[i], set[j])) {
81                                                 ch_free(rset[i]);
82                                                 rset[i] = NULL;
83                                                 break;          
84                                         }       
85                                 }
86                                 if (rset[i])
87                                         set[j] = rset[i];
88                         }
89                         ch_free(rset);
90                 }
91                 return(set);
92         }
93
94         if (op == '&') {
95                 if (lset == NULL || *lset == NULL || rset == NULL || *rset == NULL) {
96                         set = ch_calloc(1, sizeof(char *));
97                 } else {
98                         set = lset;
99                         lset = NULL;
100                         last = set_size(set) - 1;
101                         for (i = 0; set[i]; i++) {
102                                 for (j = 0; rset[j]; j++) {
103                                         if (set_samedn(set[i], rset[j]))
104                                                 break;
105                                 }
106                                 if (rset[j] == NULL) {
107                                         ch_free(set[i]);
108                                         set[i] = set[last];
109                                         set[last] = NULL;
110                                         last--;
111                                         i--;
112                                 }
113                         }
114                 }
115         }
116
117         set_dispose(lset);
118         set_dispose(rset);
119         return(set);
120 }
121
122 static char **
123 set_chase (SET_GATHER gatherer,
124         void *cookie, char **set, char *attr, int attrlen, int closure)
125 {
126         char **vals, **nset;
127         char attrstr[32];
128         int i;
129
130         if (set == NULL)
131                 return(ch_calloc(1, sizeof(char *)));
132
133         if (*set == NULL)
134                 return(set);
135
136         if (attrlen > (sizeof(attrstr) - 1)) {
137                 set_dispose(set);
138                 return(NULL);
139         }
140         AC_MEMCPY(attrstr, attr, attrlen);
141         attrstr[attrlen] = 0;
142
143         nset = ch_calloc(1, sizeof(char *));
144         if (nset == NULL) {
145                 set_dispose(set);
146                 return(NULL);
147         }
148         for (i = 0; set[i]; i++) {
149                 vals = (gatherer)(cookie, set[i], attrstr);
150                 if (vals != NULL)
151                         nset = set_join(nset, '|', vals);
152         }
153         set_dispose(set);
154
155         if (closure) {
156                 for (i = 0; nset[i]; i++) {
157                         vals = (gatherer)(cookie, nset[i], attrstr);
158                         if (vals != NULL) {
159                                 nset = set_join(nset, '|', vals);
160                                 if (nset == NULL)
161                                         break;
162                         }
163                 }
164         }
165         return(nset);
166 }
167
168 static int
169 set_samedn (char *dn1, char *dn2)
170 {
171         char c1, c2;
172
173         while (*dn1 == ' ') dn1++;
174         while (*dn2 == ' ') dn2++;
175         while (*dn1 || *dn2) {
176                 if (*dn1 != '=' && *dn1 != ','
177                         && *dn2 != '=' && *dn2 != ',')
178                 {
179                         c1 = *dn1++;
180                         c2 = *dn2++;
181                         if (c1 >= 'a' && c1 <= 'z')
182                                 c1 -= 'a' - 'A';
183                         if (c2 >= 'a' && c2 <= 'z')
184                                 c2 -= 'a' - 'A';
185                         if (c1 != c2)
186                                 return(0);
187                 } else {
188                         while (*dn1 == ' ') dn1++;
189                         while (*dn2 == ' ') dn2++;
190                         if (*dn1++ != *dn2++)
191                                 return(0);
192                         while (*dn1 == ' ') dn1++;
193                         while (*dn2 == ' ') dn2++;
194                 }
195         }
196         return(1);
197 }
198
199 int
200 set_filter (SET_GATHER gatherer,
201         void *cookie, char *filter, char *user, char *this, char ***results)
202 {
203 #define IS_SET(x)       ( (long)(x) >= 256 )
204 #define IS_OP(x)        ( (long)(x) < 256 )
205 #define SF_ERROR(x)     do { rc = -1; goto _error; } while (0)
206 #define SF_TOP()        ( (char **)( (stp < 0) ? 0 : stack[stp] ) )
207 #define SF_POP()        ( (char **)( (stp < 0) ? 0 : stack[stp--] ) )
208 #define SF_PUSH(x)      do { \
209                 if (stp >= 63) SF_ERROR(overflow); \
210                 stack[++stp] = (char **)(long)(x); \
211         } while (0)
212
213         char c;
214         char **set, **lset;
215         int len, op, rc, stp;
216         char **stack[64];
217
218         if (results)
219                 *results = NULL;
220
221         stp = -1;
222         while (c = *filter++) {
223                 set = NULL;
224                 switch (c) {
225                 case ' ':
226                 case '\t':
227                 case '\x0A':
228                 case '\x0D':
229                         break;
230
231                 case '(':
232                         if (IS_SET(SF_TOP()))
233                                 SF_ERROR(syntax);
234                         SF_PUSH(c);
235                         break;
236
237                 case ')':
238                         set = SF_POP();
239                         if (IS_OP(set))
240                                 SF_ERROR(syntax);
241                         if (SF_TOP() == (void *)'(') {
242                                 SF_POP();
243                                 SF_PUSH(set);
244                                 set = NULL;
245                         } else if (IS_OP(SF_TOP())) {
246                                 op = (long)SF_POP();
247                                 lset = SF_POP();
248                                 SF_POP();
249                                 set = set_join(lset, op, set);
250                                 if (set == NULL)
251                                         SF_ERROR(memory);
252                                 SF_PUSH(set);
253                                 set = NULL;
254                         } else {
255                                 SF_ERROR(syntax);
256                         }
257                         break;
258
259                 case '&':
260                 case '|':
261                         set = SF_POP();
262                         if (IS_OP(set))
263                                 SF_ERROR(syntax);
264                         if (SF_TOP() == 0 || SF_TOP() == (void *)'(') {
265                                 SF_PUSH(set);
266                                 set = NULL;
267                         } else if (IS_OP(SF_TOP())) {
268                                 op = (long)SF_POP();
269                                 lset = SF_POP();
270                                 set = set_join(lset, op, set);
271                                 if (set == NULL)
272                                         SF_ERROR(memory);
273                                 SF_PUSH(set);
274                                 set = NULL;
275                         } else {
276                                 SF_ERROR(syntax);
277                         }
278                         SF_PUSH(c);
279                         break;
280
281                 case '[':
282                         if ((SF_TOP() == (void *)'/') || IS_SET(SF_TOP()))
283                                 SF_ERROR(syntax);
284                         for (   len = 0;
285                                         (c = *filter++) && (c != ']');
286                                         len++)
287                         { }
288                         if (c == 0)
289                                 SF_ERROR(syntax);
290                         
291                         set = ch_calloc(2, sizeof(char *));
292                         if (set == NULL)
293                                 SF_ERROR(memory);
294                         *set = ch_calloc(len + 1, sizeof(char));
295                         if (*set == NULL)
296                                 SF_ERROR(memory);
297                         AC_MEMCPY(*set, &filter[-len - 1], len);
298                         SF_PUSH(set);
299                         set = NULL;
300                         break;
301
302                 case '-':
303                         c = *filter++;
304                         if (c != '>')
305                                 SF_ERROR(syntax);
306                         /* fall through to next case */
307
308                 case '/':
309                         if (IS_OP(SF_TOP()))
310                                 SF_ERROR(syntax);
311                         SF_PUSH('/');
312                         break;
313
314                 default:
315                         if ((c != '_')
316                                 && (c < 'A' || c > 'Z')
317                                 && (c < 'a' || c > 'z'))
318                         {
319                                 SF_ERROR(syntax);
320                         }
321                         filter--;
322                         for (   len = 1;
323                                         (c = filter[len])
324                                                 && ((c >= '0' && c <= '9')
325                                                         || (c >= 'A' && c <= 'Z')
326                                                         || (c >= 'a' && c <= 'z'));
327                                         len++)
328                         { }
329                         if (len == 4
330                                 && memcmp("this", filter, len) == 0)
331                         {
332                                 if ((SF_TOP() == (void *)'/') || IS_SET(SF_TOP()))
333                                         SF_ERROR(syntax);
334                                 set = ch_calloc(2, sizeof(char *));
335                                 if (set == NULL)
336                                         SF_ERROR(memory);
337                                 *set = ch_strdup(this);
338                                 if (*set == NULL)
339                                         SF_ERROR(memory);
340                         } else if (len == 4
341                                 && memcmp("user", filter, len) == 0) 
342                         {
343                                 if ((SF_TOP() == (void *)'/') || IS_SET(SF_TOP()))
344                                         SF_ERROR(syntax);
345                                 set = ch_calloc(2, sizeof(char *));
346                                 if (set == NULL)
347                                         SF_ERROR(memory);
348                                 *set = ch_strdup(user);
349                                 if (*set == NULL)
350                                         SF_ERROR(memory);
351                         } else if (SF_TOP() != (void *)'/') {
352                                 SF_ERROR(syntax);
353                         } else {
354                                 SF_POP();
355                                 set = set_chase(gatherer,
356                                         cookie, SF_POP(), filter, len, c == '*');
357                                 if (set == NULL)
358                                         SF_ERROR(memory);
359                                 if (c == '*')
360                                         len++;
361                         }
362                         filter += len;
363                         SF_PUSH(set);
364                         set = NULL;
365                         break;
366                 }
367         }
368
369         set = SF_POP();
370         if (IS_OP(set))
371                 SF_ERROR(syntax);
372         if (SF_TOP() == 0) {
373
374         } else if (IS_OP(SF_TOP())) {
375                 op = (long)SF_POP();
376                 lset = SF_POP();
377                 set = set_join(lset, op, set);
378                 if (set == NULL)
379                         SF_ERROR(memory);
380         } else {
381                 SF_ERROR(syntax);
382         }
383
384         rc = set_size(set);
385         if (results) {
386                 *results = set;
387                 set = NULL;
388         }
389
390 _error:
391         if (IS_SET(set))
392                 set_dispose(set);
393         while (set = SF_POP()) {
394                 if (IS_SET(set))
395                         set_dispose(set);
396         }
397         return(rc);
398 }