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