]> git.sur5r.net Git - openldap/blob - servers/slapd/sets.c
ed21a85bb516c4b7997bfa91a2c3755459556806
[openldap] / servers / slapd / sets.c
1 /* $OpenLDAP$ */
2 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
3  *
4  * Copyright 2000-2007 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, unsigned flags )
57 {
58         if ( flags & SLAP_SET_REFVAL ) {
59                 if ( ! ( flags & SLAP_SET_REFARR ) ) {
60                         cp->set_op->o_tmpfree( set, cp->set_op->o_tmpmemctx );
61                 }
62
63         } else {
64                 ber_bvarray_free_x( set, cp->set_op->o_tmpmemctx );
65         }
66 }
67
68 static BerVarray
69 set_dup( SetCookie *cp, BerVarray set, unsigned flags )
70 {
71         BerVarray       newset = NULL;
72
73         if ( set == NULL ) {
74                 return NULL;
75         }
76
77         if ( flags & SLAP_SET_REFARR ) {
78                 int     i;
79
80                 for ( i = 0; !BER_BVISNULL( &set[ i ] ); i++ )
81                         ;
82                 newset = cp->set_op->o_tmpcalloc( i + 1,
83                                 sizeof( struct berval ), 
84                                 cp->set_op->o_tmpmemctx );
85                 if ( newset == NULL ) {
86                         return NULL;
87                 }
88
89                 if ( flags & SLAP_SET_REFVAL ) {
90                         for ( i = 0; !BER_BVISNULL( &set[ i ] ); i++ ) {
91                                 ber_dupbv_x( &newset[ i ], &set[ i ],
92                                                 cp->set_op->o_tmpmemctx );
93                         }
94
95                 } else {
96                         AC_MEMCPY( newset, set, ( i + 1 ) * sizeof( struct berval ) );
97                 }
98                 
99         } else {
100                 newset = set;
101         }
102
103         return newset;
104 }
105
106 BerVarray
107 slap_set_join(
108         SetCookie       *cp,
109         BerVarray       lset,
110         unsigned        op_flags,
111         BerVarray       rset )
112 {
113         BerVarray       set;
114         long            i, j, last;
115         unsigned        op = ( op_flags & SLAP_SET_OPMASK );
116
117         set = NULL;
118         switch ( op ) {
119         case '|':       /* union */
120                 if ( lset == NULL || BER_BVISNULL( lset ) ) {
121                         if ( rset == NULL ) {
122                                 if ( lset == NULL ) {
123                                         set = cp->set_op->o_tmpcalloc( 1,
124                                                         sizeof( struct berval ),
125                                                         cp->set_op->o_tmpmemctx );
126                                         BER_BVZERO( set );
127                                         return set;
128                                 }
129                                 return set_dup( cp, lset, SLAP_SET_LREF2REF( op_flags ) );
130                         }
131                         slap_set_dispose( cp, lset, SLAP_SET_LREF2REF( op_flags ) );
132                         return set_dup( cp, rset, SLAP_SET_RREF2REF( op_flags ) );
133                 }
134                 if ( rset == NULL || BER_BVISNULL( rset ) ) {
135                         slap_set_dispose( cp, rset, SLAP_SET_RREF2REF( op_flags ) );
136                         return set_dup( cp, lset, SLAP_SET_LREF2REF( op_flags ) );
137                 }
138
139                 i = slap_set_size( lset ) + slap_set_size( rset ) + 1;
140                 set = cp->set_op->o_tmpcalloc( i, sizeof( struct berval ), cp->set_op->o_tmpmemctx );
141                 if ( set != NULL ) {
142                         /* set_chase() depends on this routine to
143                          * keep the first elements of the result
144                          * set the same (and in the same order)
145                          * as the left-set.
146                          */
147                         for ( i = 0; !BER_BVISNULL( &lset[ i ] ); i++ ) {
148                                 if ( op_flags & SLAP_SET_LREFVAL ) {
149                                         ber_dupbv_x( &set[ i ], &lset[ i ], cp->set_op->o_tmpmemctx );
150
151                                 } else {
152                                         set[ i ] = lset[ i ];
153                                 }
154                         }
155
156                         last = i;
157
158                         for ( i = 0; !BER_BVISNULL( &rset[ i ] ); i++ ) {
159                                 int     exists = 0;
160
161                                 for ( j = 0; !BER_BVISNULL( &set[ j ] ); j++ ) {
162                                         if ( bvmatch( &rset[ i ], &set[ j ] ) )
163                                         {
164                                                 if ( !( op_flags & SLAP_SET_RREFVAL ) ) {
165                                                         cp->set_op->o_tmpfree( rset[ i ].bv_val, cp->set_op->o_tmpmemctx );
166                                                         BER_BVZERO( &rset[ i ] );
167                                                 }
168                                                 exists = 1;
169                                                 break;          
170                                         }       
171                                 }
172
173                                 if ( !exists ) {
174                                         if ( op_flags & SLAP_SET_RREFVAL ) {
175                                                 ber_dupbv_x( &set[ last ], &rset[ i ], cp->set_op->o_tmpmemctx );
176
177                                         } else {
178                                                 set[ last ] = rset[ i ];
179                                         }
180                                         last++;
181                                 }
182                         }
183                         BER_BVZERO( &set[ last ] );
184                 }
185                 break;
186
187         case '&':       /* intersection */
188                 if ( lset == NULL || BER_BVISNULL( lset )
189                                 || rset == NULL || BER_BVISNULL( rset ) )
190                 {
191                         set = cp->set_op->o_tmpcalloc( 1, sizeof( struct berval ),
192                                         cp->set_op->o_tmpmemctx );
193                         BER_BVZERO( set );
194
195                 } else {
196                         set = set_dup( cp, lset, SLAP_SET_LREF2REF( op_flags ) );
197                         if ( set == NULL ) {
198                                 break;
199                         }
200                         lset = NULL;
201                         last = slap_set_size( set ) - 1;
202                         for ( i = 0; !BER_BVISNULL( &set[ i ] ); i++ ) {
203                                 for ( j = 0; !BER_BVISNULL( &rset[ j ] ); j++ ) {
204                                         if ( bvmatch( &set[ i ], &rset[ j ] ) ) {
205                                                 break;
206                                         }
207                                 }
208
209                                 if ( BER_BVISNULL( &rset[ j ] ) ) {
210                                         cp->set_op->o_tmpfree( set[ i ].bv_val, cp->set_op->o_tmpmemctx );
211                                         set[ i ] = set[ last ];
212                                         BER_BVZERO( &set[ last ] );
213                                         last--;
214                                         i--;
215                                 }
216                         }
217                 }
218                 break;
219
220         case '+':       /* string concatenation */
221                 i = slap_set_size( rset );
222                 j = slap_set_size( lset );
223
224                 set = cp->set_op->o_tmpcalloc( i * j + 1, sizeof( struct berval ),
225                                 cp->set_op->o_tmpmemctx );
226                 if ( set == NULL ) {
227                         break;
228                 }
229
230                 for ( last = 0, i = 0; !BER_BVISNULL( &lset[ i ] ); i++ ) {
231                         for ( j = 0; !BER_BVISNULL( &rset[ j ] ); j++ ) {
232                                 struct berval   bv;
233                                 long            k;
234
235                                 bv.bv_len = lset[ i ].bv_len + rset[ j ].bv_len;
236                                 bv.bv_val = cp->set_op->o_tmpalloc( bv.bv_len + 1,
237                                                 cp->set_op->o_tmpmemctx );
238                                 if ( bv.bv_val == NULL ) {
239                                         slap_set_dispose( cp, set, 0 );
240                                         set = NULL;
241                                         goto done;
242                                 }
243                                 AC_MEMCPY( bv.bv_val, lset[ i ].bv_val, lset[ i ].bv_len );
244                                 AC_MEMCPY( &bv.bv_val[ lset[ i ].bv_len ], rset[ j ].bv_val, rset[ j ].bv_len );
245                                 bv.bv_val[ bv.bv_len ] = '\0';
246
247                                 for ( k = 0; k < last; k++ ) {
248                                         if ( bvmatch( &set[ k ], &bv ) ) {
249                                                 cp->set_op->o_tmpfree( bv.bv_val, cp->set_op->o_tmpmemctx );
250                                                 break;
251                                         }
252                                 }
253
254                                 if ( k == last ) {
255                                         set[ last++ ] = bv;
256                                 }
257                         }
258                 }
259                 BER_BVZERO( &set[ last ] );
260                 break;
261
262         default:
263                 break;
264         }
265
266 done:;
267         if ( !( op_flags & SLAP_SET_LREFARR ) && lset != NULL ) {
268                 if ( !( op_flags & SLAP_SET_LREFVAL ))
269                         cp->set_op->o_tmpfree( lset->bv_val, cp->set_op->o_tmpmemctx );
270                 cp->set_op->o_tmpfree( lset, cp->set_op->o_tmpmemctx );
271         }
272
273         if ( !( op_flags & SLAP_SET_RREFARR ) && rset != NULL ) {
274                 if ( !( op_flags & SLAP_SET_RREFVAL ))
275                         cp->set_op->o_tmpfree( rset->bv_val, cp->set_op->o_tmpmemctx );
276                 cp->set_op->o_tmpfree( rset, cp->set_op->o_tmpmemctx );
277         }
278
279         return set;
280 }
281
282 static BerVarray
283 set_chase( SLAP_SET_GATHER gatherer,
284         SetCookie *cp, BerVarray set, AttributeDescription *desc, int closure )
285 {
286         BerVarray       vals, nset;
287         int             i;
288
289         if ( set == NULL ) {
290                 set = cp->set_op->o_tmpcalloc( 1, sizeof( struct berval ),
291                                 cp->set_op->o_tmpmemctx );
292                 BER_BVZERO( set );
293                 return set;
294         }
295
296         if ( BER_BVISNULL( set ) ) {
297                 return set;
298         }
299
300         nset = cp->set_op->o_tmpcalloc( 1, sizeof( struct berval ), cp->set_op->o_tmpmemctx );
301         if ( nset == NULL ) {
302                 slap_set_dispose( cp, set, 0 );
303                 return NULL;
304         }
305         for ( i = 0; !BER_BVISNULL( &set[ i ] ); i++ ) {
306                 vals = gatherer( cp, &set[ i ], desc );
307                 if ( vals != NULL ) {
308                         nset = slap_set_join( cp, nset, '|', vals );
309                 }
310         }
311         slap_set_dispose( cp, set, 0 );
312
313         if ( closure ) {
314                 for ( i = 0; !BER_BVISNULL( &nset[ i ] ); i++ ) {
315                         vals = gatherer( cp, &nset[ i ], desc );
316                         if ( vals != NULL ) {
317                                 nset = slap_set_join( cp, nset, '|', vals );
318                                 if ( nset == NULL ) {
319                                         break;
320                                 }
321                         }
322                 }
323         }
324
325         return nset;
326 }
327
328
329 static BerVarray
330 set_parents( SetCookie *cp, BerVarray set )
331 {
332         int             i, j, last;
333         struct berval   bv, pbv;
334         BerVarray       nset, vals;
335
336         if ( set == NULL ) {
337                 set = cp->set_op->o_tmpcalloc( 1, sizeof( struct berval ),
338                                 cp->set_op->o_tmpmemctx );
339                 if ( set != NULL ) {
340                         BER_BVZERO( &set[ 0 ] );
341                 }
342                 return set;
343         }
344
345         if ( BER_BVISNULL( &set[ 0 ] ) ) {
346                 return set;
347         }
348
349         nset = cp->set_op->o_tmpcalloc( 1, sizeof( struct berval ), cp->set_op->o_tmpmemctx );
350         if ( nset == NULL ) {
351                 slap_set_dispose( cp, set, 0 );
352                 return NULL;
353         }
354
355         BER_BVZERO( &nset[ 0 ] );
356
357         for ( i = 0; !BER_BVISNULL( &set[ i ] ); i++ ) {
358                 int     level = 1;
359
360                 pbv = bv = set[ i ];
361                 for ( ; !BER_BVISEMPTY( &pbv ); dnParent( &bv, &pbv ) ) {
362                         level++;
363                         bv = pbv;
364                 }
365
366                 vals = cp->set_op->o_tmpcalloc( level + 1, sizeof( struct berval ), cp->set_op->o_tmpmemctx );
367                 if ( vals == NULL ) {
368                         slap_set_dispose( cp, set, 0 );
369                         slap_set_dispose( cp, nset, 0 );
370                         return NULL;
371                 }
372                 BER_BVZERO( &vals[ 0 ] );
373                 last = 0;
374
375                 bv = set[ i ];
376                 for ( j = 0 ; j < level ; j++ ) {
377                         ber_dupbv_x( &vals[ last ], &bv, cp->set_op->o_tmpmemctx );
378                         last++;
379                         dnParent( &bv, &bv );
380                 }
381                 BER_BVZERO( &vals[ last ] );
382
383                 nset = slap_set_join( cp, nset, '|', vals );
384         }
385
386         slap_set_dispose( cp, set, 0 );
387
388         return nset;
389 }
390
391
392
393 static BerVarray
394 set_parent( SetCookie *cp, BerVarray set, int level )
395 {
396         int             i, j, last;
397         struct berval   bv;
398         BerVarray       nset;
399
400         if ( set == NULL ) {
401                 set = cp->set_op->o_tmpcalloc( 1, sizeof( struct berval ),
402                                 cp->set_op->o_tmpmemctx );
403                 if ( set != NULL ) {
404                         BER_BVZERO( &set[ 0 ] );
405                 }
406                 return set;
407         }
408
409         if ( BER_BVISNULL( &set[ 0 ] ) ) {
410                 return set;
411         }
412
413         nset = cp->set_op->o_tmpcalloc( slap_set_size( set ) + 1, sizeof( struct berval ), cp->set_op->o_tmpmemctx );
414         if ( nset == NULL ) {
415                 slap_set_dispose( cp, set, 0 );
416                 return NULL;
417         }
418
419         BER_BVZERO( &nset[ 0 ] );
420         last = 0;
421
422         for ( i = 0; !BER_BVISNULL( &set[ i ] ); i++ ) {
423                 bv = set[ i ];
424
425                 for ( j = 0 ; j < level ; j++ ) {
426                         dnParent( &bv, &bv );
427                 }
428
429                 for ( j = 0; !BER_BVISNULL( &nset[ j ] ); j++ ) {
430                         if ( bvmatch( &bv, &nset[ j ] ) )
431                         {
432                                 break;          
433                         }       
434                 }
435
436                 if ( BER_BVISNULL( &nset[ j ] ) ) {
437                         ber_dupbv_x( &nset[ last ], &bv, cp->set_op->o_tmpmemctx );
438                         last++;
439                 }
440         }
441
442         BER_BVZERO( &nset[ last ] );
443
444         slap_set_dispose( cp, set, 0 );
445
446         return nset;
447 }
448
449 int
450 slap_set_filter( SLAP_SET_GATHER gatherer,
451         SetCookie *cp, struct berval *fbv,
452         struct berval *user, struct berval *target, BerVarray *results )
453 {
454 #define STACK_SIZE      64
455 #define IS_SET(x)       ( (unsigned long)(x) >= 256 )
456 #define IS_OP(x)        ( (unsigned long)(x) < 256 )
457 #define SF_ERROR(x)     do { rc = -1; goto _error; } while ( 0 )
458 #define SF_TOP()        ( (BerVarray)( ( stp < 0 ) ? 0 : stack[ stp ] ) )
459 #define SF_POP()        ( (BerVarray)( ( stp < 0 ) ? 0 : stack[ stp-- ] ) )
460 #define SF_PUSH(x)      do { \
461                 if ( stp >= ( STACK_SIZE - 1 ) ) SF_ERROR( overflow ); \
462                 stack[ ++stp ] = (BerVarray)(long)(x); \
463         } while ( 0 )
464
465         BerVarray       set, lset;
466         BerVarray       stack[ STACK_SIZE ] = { 0 };
467         int             len, rc, stp;
468         unsigned long   op;
469         char            c, *filter = fbv->bv_val;
470
471         if ( results ) {
472                 *results = NULL;
473         }
474
475         stp = -1;
476         while ( ( c = *filter++ ) ) {
477                 set = NULL;
478                 switch ( c ) {
479                 case ' ':
480                 case '\t':
481                 case '\x0A':
482                 case '\x0D':
483                         break;
484
485                 case '(' /* ) */ :
486                         if ( IS_SET( SF_TOP() ) ) {
487                                 SF_ERROR( syntax );
488                         }
489                         SF_PUSH( c );
490                         break;
491
492                 case /* ( */ ')':
493                         set = SF_POP();
494                         if ( IS_OP( set ) ) {
495                                 SF_ERROR( syntax );
496                         }
497                         if ( SF_TOP() == (void *)'(' /* ) */ ) {
498                                 SF_POP();
499                                 SF_PUSH( set );
500                                 set = NULL;
501
502                         } else if ( IS_OP( SF_TOP() ) ) {
503                                 op = (unsigned long)SF_POP();
504                                 lset = SF_POP();
505                                 SF_POP();
506                                 set = slap_set_join( cp, lset, op, set );
507                                 if ( set == NULL ) {
508                                         SF_ERROR( memory );
509                                 }
510                                 SF_PUSH( set );
511                                 set = NULL;
512
513                         } else {
514                                 SF_ERROR( syntax );
515                         }
516                         break;
517
518                 case '|':       /* union */
519                 case '&':       /* intersection */
520                 case '+':       /* string concatenation */
521                         set = SF_POP();
522                         if ( IS_OP( set ) ) {
523                                 SF_ERROR( syntax );
524                         }
525                         if ( SF_TOP() == 0 || SF_TOP() == (void *)'(' /* ) */ ) {
526                                 SF_PUSH( set );
527                                 set = NULL;
528
529                         } else if ( IS_OP( SF_TOP() ) ) {
530                                 op = (unsigned long)SF_POP();
531                                 lset = SF_POP();
532                                 set = slap_set_join( cp, lset, op, set );
533                                 if ( set == NULL ) {
534                                         SF_ERROR( memory );
535                                 }
536                                 SF_PUSH( set );
537                                 set = NULL;
538                                 
539                         } else {
540                                 SF_ERROR( syntax );
541                         }
542                         SF_PUSH( c );
543                         break;
544
545                 case '[' /* ] */:
546                         if ( ( SF_TOP() == (void *)'/' ) || IS_SET( SF_TOP() ) ) {
547                                 SF_ERROR( syntax );
548                         }
549                         for ( len = 0; ( c = *filter++ ) && ( c != /* [ */ ']' ); len++ )
550                                 ;
551                         if ( c == 0 ) {
552                                 SF_ERROR( syntax );
553                         }
554                         
555                         set = cp->set_op->o_tmpcalloc( 2, sizeof( struct berval ),
556                                         cp->set_op->o_tmpmemctx );
557                         if ( set == NULL ) {
558                                 SF_ERROR( memory );
559                         }
560                         set->bv_val = cp->set_op->o_tmpcalloc( len + 1, sizeof( char ),
561                                         cp->set_op->o_tmpmemctx );
562                         if ( BER_BVISNULL( set ) ) {
563                                 SF_ERROR( memory );
564                         }
565                         AC_MEMCPY( set->bv_val, &filter[ - len - 1 ], len );
566                         set->bv_len = len;
567                         SF_PUSH( set );
568                         set = NULL;
569                         break;
570
571                 case '-':
572                         if ( ( SF_TOP() == (void *)'/' )
573                                         && ( *filter >= '0' || *filter <= '9' ) )
574                         {
575                                 int parent = 0;
576                                 int count = 1;
577                                 int i;
578                                 for ( len = 1;
579                                                 ( c = filter[ len ] )
580                                                         && ( c >= '0' && c <= '9' );
581                                                 len++ )
582                                         /* count */ ;
583                                 for ( i = len ; i > 0 ; i-- ) {
584                                         parent += (int)( filter[ i - 1 ] - '0' ) * count;
585                                         count *= 10;
586                                 }
587                                 SF_POP();
588                                 if ( parent == 0 ) {
589                                         set = set_parents( cp, SF_POP() );
590                                 } else {
591                                         set = set_parent( cp, SF_POP(), parent );
592                                 }
593                                 filter += len;
594                                 SF_PUSH( set );
595                                 set = NULL;
596                                 break;
597                         } else {
598                                 c = *filter++;
599                                 if ( c != '>' ) {
600                                         SF_ERROR( syntax );
601                                 }
602                                 /* fall through to next case */
603                         }
604
605                 case '/':
606                         if ( IS_OP( SF_TOP() ) ) {
607                                 SF_ERROR( syntax );
608                         }
609                         SF_PUSH( '/' );
610                         break;
611
612                 default:
613                         if ( ( c != '_' )
614                                         && ( c < 'A' || c > 'Z' )
615                                         && ( c < 'a' || c > 'z' ) )
616                         {
617                                 SF_ERROR( syntax );
618                         }
619                         filter--;
620                         for ( len = 1;
621                                         ( c = filter[ len ] )
622                                                 && ( ( c >= '0' && c <= '9' )
623                                                         || ( c >= 'A' && c <= 'Z' )
624                                                         || ( c >= 'a' && c <= 'z' ) );
625                                         len++ )
626                                 /* count */ ;
627                         if ( len == 4
628                                 && memcmp( "this", filter, len ) == 0 )
629                         {
630                                 if ( ( SF_TOP() == (void *)'/' ) || IS_SET( SF_TOP() ) ) {
631                                         SF_ERROR( syntax );
632                                 }
633                                 set = cp->set_op->o_tmpcalloc( 2, sizeof( struct berval ),
634                                                 cp->set_op->o_tmpmemctx );
635                                 if ( set == NULL ) {
636                                         SF_ERROR( memory );
637                                 }
638                                 ber_dupbv_x( set, target, cp->set_op->o_tmpmemctx );
639                                 if ( BER_BVISNULL( set ) ) {
640                                         SF_ERROR( memory );
641                                 }
642                                 BER_BVZERO( &set[ 1 ] );
643                                 
644                         } else if ( len == 4
645                                 && memcmp( "user", filter, len ) == 0 ) 
646                         {
647                                 if ( ( SF_TOP() == (void *)'/' ) || IS_SET( SF_TOP() ) ) {
648                                         SF_ERROR( syntax );
649                                 }
650                                 set = cp->set_op->o_tmpcalloc( 2, sizeof( struct berval ),
651                                                 cp->set_op->o_tmpmemctx );
652                                 if ( set == NULL ) {
653                                         SF_ERROR( memory );
654                                 }
655                                 ber_dupbv_x( set, user, cp->set_op->o_tmpmemctx );
656                                 if ( BER_BVISNULL( set ) ) {
657                                         SF_ERROR( memory );
658                                 }
659                                 BER_BVZERO( &set[ 1 ] );
660                                 
661                         } else if ( SF_TOP() != (void *)'/' ) {
662                                 SF_ERROR( syntax );
663
664                         } else {
665                                 struct berval           fb2;
666                                 AttributeDescription    *ad = NULL;
667                                 const char              *text = NULL;
668
669                                 SF_POP();
670                                 fb2.bv_val = filter;
671                                 fb2.bv_len = len;
672
673                                 if ( slap_bv2ad( &fb2, &ad, &text ) != LDAP_SUCCESS ) {
674                                         SF_ERROR( syntax );
675                                 }
676
677                                 /* NOTE: ad must have distinguishedName syntax
678                                  * or expand in an LDAP URI if c == '*'
679                                  */
680                                 
681                                 set = set_chase( gatherer,
682                                         cp, SF_POP(), ad, c == '*' );
683                                 if ( set == NULL ) {
684                                         SF_ERROR( memory );
685                                 }
686                                 if ( c == '*' ) {
687                                         len++;
688                                 }
689                         }
690                         filter += len;
691                         SF_PUSH( set );
692                         set = NULL;
693                         break;
694                 }
695         }
696
697         set = SF_POP();
698         if ( IS_OP( set ) ) {
699                 SF_ERROR( syntax );
700         }
701         if ( SF_TOP() == 0 ) {
702                 /* FIXME: ok ? */ ;
703
704         } else if ( IS_OP( SF_TOP() ) ) {
705                 op = (unsigned long)SF_POP();
706                 lset = SF_POP();
707                 set = slap_set_join( cp, lset, op, set );
708                 if ( set == NULL ) {
709                         SF_ERROR( memory );
710                 }
711                 
712         } else {
713                 SF_ERROR( syntax );
714         }
715
716         rc = slap_set_isempty( set ) ? 0 : 1;
717         if ( results ) {
718                 *results = set;
719                 set = NULL;
720         }
721
722 _error:
723         if ( IS_SET( set ) ) {
724                 slap_set_dispose( cp, set, 0 );
725         }
726         while ( ( set = SF_POP() ) ) {
727                 if ( IS_SET( set ) ) {
728                         slap_set_dispose( cp, set, 0 );
729                 }
730         }
731         return rc;
732 }