]> git.sur5r.net Git - openldap/blob - servers/slapd/sets.c
To conform to the SLAPI spec, slapi_filter_get_ava() should not duplicate
[openldap] / servers / slapd / sets.c
1 /* $OpenLDAP$ */
2 /*
3  * Copyright 2000-2003 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 BerVarray set_join (BerVarray lset, int op, BerVarray rset);
16 static BerVarray set_chase (SLAP_SET_GATHER gatherer,
17         void *cookie, BerVarray set, struct berval *attr, int closure);
18 static int set_samedn (char *dn1, char *dn2);
19
20 long
21 slap_set_size (BerVarray set)
22 {
23         long    i;
24
25         i = 0;
26         if (set != NULL) {
27                 while (set[i].bv_val)
28                         i++;
29         }
30         return i;
31 }
32
33 void
34 slap_set_dispose (BerVarray set)
35 {
36         ber_bvarray_free(set);
37 }
38
39 static BerVarray
40 set_join (BerVarray lset, int op, BerVarray rset)
41 {
42         BerVarray set;
43         long i, j, last;
44
45         set = NULL;
46         if (op == '|') {
47                 if (lset == NULL || lset->bv_val == NULL) {
48                         if (rset == NULL) {
49                                 if (lset == NULL)
50                                         return(SLAP_CALLOC(1, sizeof(struct berval)));
51                                 return(lset);
52                         }
53                         slap_set_dispose(lset);
54                         return(rset);
55                 }
56                 if (rset == NULL || rset->bv_val == NULL) {
57                         slap_set_dispose(rset);
58                         return(lset);
59                 }
60
61                 i = slap_set_size(lset) + slap_set_size(rset) + 1;
62                 set = SLAP_CALLOC(i, sizeof(struct berval));
63                 if (set != NULL) {
64                         /* set_chase() depends on this routine to
65                          * keep the first elements of the result
66                          * set the same (and in the same order)
67                          * as the left-set.
68                          */
69                         for (i = 0; lset[i].bv_val; i++)
70                                 set[i] = lset[i];
71                         ch_free(lset);
72                         for (i = 0; rset[i].bv_val; i++) {
73                                 for (j = 0; set[j].bv_val; j++) {
74                                         if (set_samedn(rset[i].bv_val, set[j].bv_val)) {
75                                                 ch_free(rset[i].bv_val);
76                                                 rset[i].bv_val = NULL;
77                                                 break;          
78                                         }       
79                                 }
80                                 if (rset[i].bv_val)
81                                         set[j] = rset[i];
82                         }
83                         ch_free(rset);
84                 }
85                 return(set);
86         }
87
88         if (op == '&') {
89                 if (lset == NULL || lset->bv_val == NULL || rset == NULL || rset->bv_val == NULL) {
90                         set = SLAP_CALLOC(1, sizeof(struct berval));
91                 } else {
92                         set = lset;
93                         lset = NULL;
94                         last = slap_set_size(set) - 1;
95                         for (i = 0; set[i].bv_val; i++) {
96                                 for (j = 0; rset[j].bv_val; j++) {
97                                         if (set_samedn(set[i].bv_val, rset[j].bv_val))
98                                                 break;
99                                 }
100                                 if (rset[j].bv_val == NULL) {
101                                         ch_free(set[i].bv_val);
102                                         set[i] = set[last];
103                                         set[last].bv_val = NULL;
104                                         last--;
105                                         i--;
106                                 }
107                         }
108                 }
109         }
110
111         slap_set_dispose(lset);
112         slap_set_dispose(rset);
113         return(set);
114 }
115
116 static BerVarray
117 set_chase (SLAP_SET_GATHER gatherer,
118         void *cookie, BerVarray set, struct berval *attr, int closure)
119 {
120         BerVarray vals, nset;
121         char attrstr[32];
122         struct berval bv;
123         int i;
124
125         bv.bv_len = attr->bv_len;
126         bv.bv_val = attrstr;
127
128         if (set == NULL)
129                 return(SLAP_CALLOC(1, sizeof(struct berval)));
130
131         if (set->bv_val == NULL)
132                 return(set);
133
134         if (attr->bv_len > (sizeof(attrstr) - 1)) {
135                 slap_set_dispose(set);
136                 return(NULL);
137         }
138         AC_MEMCPY(attrstr, attr->bv_val, attr->bv_len);
139         attrstr[attr->bv_len] = 0;
140
141         nset = SLAP_CALLOC(1, sizeof(struct berval));
142         if (nset == NULL) {
143                 slap_set_dispose(set);
144                 return(NULL);
145         }
146         for (i = 0; set[i].bv_val; i++) {
147                 vals = (gatherer)(cookie, &set[i], &bv);
148                 if (vals != NULL)
149                         nset = set_join(nset, '|', vals);
150         }
151         slap_set_dispose(set);
152
153         if (closure) {
154                 for (i = 0; nset[i].bv_val; i++) {
155                         vals = (gatherer)(cookie, &nset[i], &bv);
156                         if (vals != NULL) {
157                                 nset = set_join(nset, '|', vals);
158                                 if (nset == NULL)
159                                         break;
160                         }
161                 }
162         }
163         return(nset);
164 }
165
166 static int
167 set_samedn (char *dn1, char *dn2)
168 {
169         char c1, c2;
170
171         while (*dn1 == ' ') dn1++;
172         while (*dn2 == ' ') dn2++;
173         while (*dn1 || *dn2) {
174                 if (*dn1 != '=' && *dn1 != ','
175                         && *dn2 != '=' && *dn2 != ',')
176                 {
177                         c1 = *dn1++;
178                         c2 = *dn2++;
179                         if (c1 >= 'a' && c1 <= 'z')
180                                 c1 -= 'a' - 'A';
181                         if (c2 >= 'a' && c2 <= 'z')
182                                 c2 -= 'a' - 'A';
183                         if (c1 != c2)
184                                 return(0);
185                 } else {
186                         while (*dn1 == ' ') dn1++;
187                         while (*dn2 == ' ') dn2++;
188                         if (*dn1++ != *dn2++)
189                                 return(0);
190                         while (*dn1 == ' ') dn1++;
191                         while (*dn2 == ' ') dn2++;
192                 }
193         }
194         return(1);
195 }
196
197 int
198 slap_set_filter (SLAP_SET_GATHER gatherer,
199         void *cookie, struct berval *fbv,
200         struct berval *user, struct berval *this, BerVarray *results)
201 {
202 #define IS_SET(x)       ( (long)(x) >= 256 )
203 #define IS_OP(x)        ( (long)(x) < 256 )
204 #define SF_ERROR(x)     do { rc = -1; goto _error; } while (0)
205 #define SF_TOP()        ( (BerVarray)( (stp < 0) ? 0 : stack[stp] ) )
206 #define SF_POP()        ( (BerVarray)( (stp < 0) ? 0 : stack[stp--] ) )
207 #define SF_PUSH(x)      do { \
208                 if (stp >= 63) SF_ERROR(overflow); \
209                 stack[++stp] = (BerVarray)(long)(x); \
210         } while (0)
211
212         BerVarray set, lset;
213         BerVarray stack[64];
214         int len, op, rc, stp;
215         char c, *filter = fbv->bv_val;
216
217         if (results)
218                 *results = NULL;
219
220         stp = -1;
221         while ((c = *filter++)) {
222                 set = NULL;
223                 switch (c) {
224                 case ' ':
225                 case '\t':
226                 case '\x0A':
227                 case '\x0D':
228                         break;
229
230                 case '(':
231                         if (IS_SET(SF_TOP()))
232                                 SF_ERROR(syntax);
233                         SF_PUSH(c);
234                         break;
235
236                 case ')':
237                         set = SF_POP();
238                         if (IS_OP(set))
239                                 SF_ERROR(syntax);
240                         if (SF_TOP() == (void *)'(') {
241                                 SF_POP();
242                                 SF_PUSH(set);
243                                 set = NULL;
244                         } else if (IS_OP(SF_TOP())) {
245                                 op = (long)SF_POP();
246                                 lset = SF_POP();
247                                 SF_POP();
248                                 set = set_join(lset, op, set);
249                                 if (set == NULL)
250                                         SF_ERROR(memory);
251                                 SF_PUSH(set);
252                                 set = NULL;
253                         } else {
254                                 SF_ERROR(syntax);
255                         }
256                         break;
257
258                 case '&':
259                 case '|':
260                         set = SF_POP();
261                         if (IS_OP(set))
262                                 SF_ERROR(syntax);
263                         if (SF_TOP() == 0 || SF_TOP() == (void *)'(') {
264                                 SF_PUSH(set);
265                                 set = NULL;
266                         } else if (IS_OP(SF_TOP())) {
267                                 op = (long)SF_POP();
268                                 lset = SF_POP();
269                                 set = set_join(lset, op, set);
270                                 if (set == NULL)
271                                         SF_ERROR(memory);
272                                 SF_PUSH(set);
273                                 set = NULL;
274                         } else {
275                                 SF_ERROR(syntax);
276                         }
277                         SF_PUSH(c);
278                         break;
279
280                 case '[':
281                         if ((SF_TOP() == (void *)'/') || IS_SET(SF_TOP()))
282                                 SF_ERROR(syntax);
283                         for (   len = 0;
284                                         (c = *filter++) && (c != ']');
285                                         len++)
286                         { }
287                         if (c == 0)
288                                 SF_ERROR(syntax);
289                         
290                         set = SLAP_CALLOC(2, sizeof(struct berval));
291                         if (set == NULL)
292                                 SF_ERROR(memory);
293                         set->bv_val = SLAP_CALLOC(len + 1, sizeof(char));
294                         if (set->bv_val == NULL)
295                                 SF_ERROR(memory);
296                         AC_MEMCPY(set->bv_val, &filter[-len - 1], len);
297                         set->bv_len = 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 = SLAP_CALLOC(2, sizeof(struct berval));
335                                 if (set == NULL)
336                                         SF_ERROR(memory);
337                                 ber_dupbv( set, this );
338                                 if (set->bv_val == 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 = SLAP_CALLOC(2, sizeof(struct berval));
346                                 if (set == NULL)
347                                         SF_ERROR(memory);
348                                 ber_dupbv( set, user );
349                                 if (set->bv_val == NULL)
350                                         SF_ERROR(memory);
351                         } else if (SF_TOP() != (void *)'/') {
352                                 SF_ERROR(syntax);
353                         } else {
354                                 struct berval fb2;
355                                 SF_POP();
356                                 fb2.bv_val = filter;
357                                 fb2.bv_len = len;
358                                 set = set_chase(gatherer,
359                                         cookie, SF_POP(), &fb2, c == '*');
360                                 if (set == NULL)
361                                         SF_ERROR(memory);
362                                 if (c == '*')
363                                         len++;
364                         }
365                         filter += len;
366                         SF_PUSH(set);
367                         set = NULL;
368                         break;
369                 }
370         }
371
372         set = SF_POP();
373         if (IS_OP(set))
374                 SF_ERROR(syntax);
375         if (SF_TOP() == 0) {
376
377         } else if (IS_OP(SF_TOP())) {
378                 op = (long)SF_POP();
379                 lset = SF_POP();
380                 set = set_join(lset, op, set);
381                 if (set == NULL)
382                         SF_ERROR(memory);
383         } else {
384                 SF_ERROR(syntax);
385         }
386
387         rc = slap_set_size(set) > 0 ? 1 : 0;
388         if (results) {
389                 *results = set;
390                 set = NULL;
391         }
392
393 _error:
394         if (IS_SET(set))
395                 slap_set_dispose(set);
396         while ((set = SF_POP())) {
397                 if (IS_SET(set))
398                         slap_set_dispose(set);
399         }
400         return(rc);
401 }