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