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