]> git.sur5r.net Git - openldap/blob - servers/slapd/sets.c
e219f6da419266ba715a07b5a00897417226a43e
[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 /* Count the array members */
28 static long
29 slap_set_size( BerVarray set )
30 {
31         long    i = 0;
32
33         if ( set != NULL ) {
34                 while ( !BER_BVISNULL( &set[ i ] ) ) {
35                         i++;
36                 }
37         }
38
39         return i;
40 }
41
42 /* Return 0 if there is at least one array member, non-zero otherwise */
43 static int
44 slap_set_isempty( BerVarray set )
45 {
46         if ( set == NULL ) {
47                 return 1;
48         }
49
50         if ( !BER_BVISNULL( &set[ 0 ] ) ) {
51                 return 0;
52         }
53
54         return 1;
55 }
56
57 /* Dispose of the contents of the array and the array itself according
58  * to the flags value.  If SLAP_SET_REFVAL, don't dispose of values;
59  * if SLAP_SET_REFARR, don't dispose of the array itself.  In case of
60  * binary operators, there are LEFT flags and RIGHT flags, referring to
61  * the first and the second operator arguments, respectively.  In this
62  * case, flags must be transformed using macros SLAP_SET_LREF2REF() and
63  * SLAP_SET_RREF2REF() before calling this function.
64  */
65 static void
66 slap_set_dispose( SetCookie *cp, BerVarray set, unsigned flags )
67 {
68         if ( flags & SLAP_SET_REFVAL ) {
69                 if ( ! ( flags & SLAP_SET_REFARR ) ) {
70                         cp->set_op->o_tmpfree( set, cp->set_op->o_tmpmemctx );
71                 }
72
73         } else {
74                 ber_bvarray_free_x( set, cp->set_op->o_tmpmemctx );
75         }
76 }
77
78 /* Duplicate a set.  If SLAP_SET_REFARR, is not set, the original array
79  * with the original values is returned, otherwise the array is duplicated;
80  * if SLAP_SET_REFVAL is set, also the values are duplicated.
81  */
82 static BerVarray
83 set_dup( SetCookie *cp, BerVarray set, unsigned flags )
84 {
85         BerVarray       newset = NULL;
86
87         if ( set == NULL ) {
88                 return NULL;
89         }
90
91         if ( flags & SLAP_SET_REFARR ) {
92                 int     i;
93
94                 for ( i = 0; !BER_BVISNULL( &set[ i ] ); i++ )
95                         ;
96                 newset = cp->set_op->o_tmpcalloc( i + 1,
97                                 sizeof( struct berval ), 
98                                 cp->set_op->o_tmpmemctx );
99                 if ( newset == NULL ) {
100                         return NULL;
101                 }
102
103                 if ( flags & SLAP_SET_REFVAL ) {
104                         for ( i = 0; !BER_BVISNULL( &set[ i ] ); i++ ) {
105                                 ber_dupbv_x( &newset[ i ], &set[ i ],
106                                                 cp->set_op->o_tmpmemctx );
107                         }
108
109                 } else {
110                         AC_MEMCPY( newset, set, ( i + 1 ) * sizeof( struct berval ) );
111                 }
112                 
113         } else {
114                 newset = set;
115         }
116
117         return newset;
118 }
119
120 /* Join two sets according to operator op and flags op_flags.
121  * op can be:
122  *      '|' (or):       the union between the two sets is returned,
123  *                      eliminating diplicates
124  *      '&' (and):      the intersection between the two sets
125  *                      is returned
126  *      '+' (add):      the inner product of the two sets is returned,
127  *                      namely a set containing the concatenation of
128  *                      all combinations of the two sets members,
129  *                      except for duplicates.
130  * The two sets are disposed of according to the flags as described
131  * for slap_set_dispose().
132  */
133 BerVarray
134 slap_set_join(
135         SetCookie       *cp,
136         BerVarray       lset,
137         unsigned        op_flags,
138         BerVarray       rset )
139 {
140         BerVarray       set;
141         long            i, j, last, rlast;
142         unsigned        op = ( op_flags & SLAP_SET_OPMASK );
143
144         set = NULL;
145         switch ( op ) {
146         case '|':       /* union */
147                 if ( lset == NULL || BER_BVISNULL( &lset[ 0 ] ) ) {
148                         if ( rset == NULL ) {
149                                 if ( lset == NULL ) {
150                                         set = cp->set_op->o_tmpcalloc( 1,
151                                                         sizeof( struct berval ),
152                                                         cp->set_op->o_tmpmemctx );
153                                         BER_BVZERO( &set[ 0 ] );
154                                         goto done2;
155                                 }
156                                 set = set_dup( cp, lset, SLAP_SET_LREF2REF( op_flags ) );
157                                 goto done2;
158                         }
159                         slap_set_dispose( cp, lset, SLAP_SET_LREF2REF( op_flags ) );
160                         set = set_dup( cp, rset, SLAP_SET_RREF2REF( op_flags ) );
161                         goto done2;
162                 }
163                 if ( rset == NULL || BER_BVISNULL( &rset[ 0 ] ) ) {
164                         slap_set_dispose( cp, rset, SLAP_SET_RREF2REF( op_flags ) );
165                         set = set_dup( cp, lset, SLAP_SET_LREF2REF( op_flags ) );
166                         goto done2;
167                 }
168
169                 /* worst scenario: no duplicates */
170                 rlast = slap_set_size( rset );
171                 i = slap_set_size( lset ) + rlast + 1;
172                 set = cp->set_op->o_tmpcalloc( i, sizeof( struct berval ), cp->set_op->o_tmpmemctx );
173                 if ( set != NULL ) {
174                         /* set_chase() depends on this routine to
175                          * keep the first elements of the result
176                          * set the same (and in the same order)
177                          * as the left-set.
178                          */
179                         for ( i = 0; !BER_BVISNULL( &lset[ i ] ); i++ ) {
180                                 if ( op_flags & SLAP_SET_LREFVAL ) {
181                                         ber_dupbv_x( &set[ i ], &lset[ i ], cp->set_op->o_tmpmemctx );
182
183                                 } else {
184                                         set[ i ] = lset[ i ];
185                                 }
186                         }
187
188                         /* pointers to values have been used in set - don't free twice */
189                         op_flags |= SLAP_SET_LREFVAL;
190
191                         last = i;
192
193                         for ( i = 0; !BER_BVISNULL( &rset[ i ] ); i++ ) {
194                                 int     exists = 0;
195
196                                 for ( j = 0; !BER_BVISNULL( &set[ j ] ); j++ ) {
197                                         if ( bvmatch( &rset[ i ], &set[ j ] ) )
198                                         {
199                                                 if ( !( op_flags & SLAP_SET_RREFVAL ) ) {
200                                                         cp->set_op->o_tmpfree( rset[ i ].bv_val, cp->set_op->o_tmpmemctx );
201                                                         rset[ i ] = rset[ --rlast ];
202                                                         BER_BVZERO( &rset[ rlast ] );
203                                                 }
204                                                 exists = 1;
205                                                 break;
206                                         }
207                                 }
208
209                                 if ( !exists ) {
210                                         if ( op_flags & SLAP_SET_RREFVAL ) {
211                                                 ber_dupbv_x( &set[ last ], &rset[ i ], cp->set_op->o_tmpmemctx );
212
213                                         } else {
214                                                 set[ last ] = rset[ i ];
215                                         }
216                                         last++;
217                                 }
218                         }
219
220                         /* pointers to values have been used in set - don't free twice */
221                         op_flags |= SLAP_SET_RREFVAL;
222
223                         BER_BVZERO( &set[ last ] );
224                 }
225                 break;
226
227         case '&':       /* intersection */
228                 if ( lset == NULL || BER_BVISNULL( &lset[ 0 ] )
229                         || rset == NULL || BER_BVISNULL( &rset[ 0 ] ) )
230                 {
231                         set = cp->set_op->o_tmpcalloc( 1, sizeof( struct berval ),
232                                         cp->set_op->o_tmpmemctx );
233                         BER_BVZERO( &set[ 0 ] );
234                         break;
235
236                 } else {
237                         long llen, rlen;
238                         BerVarray sset;
239
240                         llen = slap_set_size( lset );
241                         rlen = slap_set_size( rset );
242
243                         /* dup the shortest */
244                         if ( llen < rlen ) {
245                                 last = llen;
246                                 set = set_dup( cp, lset, SLAP_SET_LREF2REF( op_flags ) );
247                                 lset = NULL;
248                                 sset = rset;
249
250                         } else {
251                                 last = rlen;
252                                 set = set_dup( cp, rset, SLAP_SET_RREF2REF( op_flags ) );
253                                 rset = NULL;
254                                 sset = lset;
255                         }
256
257                         if ( set == NULL ) {
258                                 break;
259                         }
260
261                         for ( i = 0; !BER_BVISNULL( &set[ i ] ); i++ ) {
262                                 for ( j = 0; !BER_BVISNULL( &sset[ j ] ); j++ ) {
263                                         if ( bvmatch( &set[ i ], &sset[ j ] ) ) {
264                                                 break;
265                                         }
266                                 }
267
268                                 if ( BER_BVISNULL( &sset[ j ] ) ) {
269                                         cp->set_op->o_tmpfree( set[ i ].bv_val, cp->set_op->o_tmpmemctx );
270                                         set[ i ] = set[ --last ];
271                                         BER_BVZERO( &set[ last ] );
272                                         i--;
273                                 }
274                         }
275                 }
276                 break;
277
278         case '+':       /* string concatenation */
279                 i = slap_set_size( rset );
280                 j = slap_set_size( lset );
281
282                 /* handle empty set cases */
283                 if ( i == 0 || j == 0 ) {
284                         set = cp->set_op->o_tmpcalloc( 1, sizeof( struct berval ),
285                                         cp->set_op->o_tmpmemctx );
286                         if ( set == NULL ) {
287                                 break;
288                         }
289                         BER_BVZERO( &set[ 0 ] );
290                         break;
291                 }
292
293                 set = cp->set_op->o_tmpcalloc( i * j + 1, sizeof( struct berval ),
294                                 cp->set_op->o_tmpmemctx );
295                 if ( set == NULL ) {
296                         break;
297                 }
298
299                 for ( last = 0, i = 0; !BER_BVISNULL( &lset[ i ] ); i++ ) {
300                         for ( j = 0; !BER_BVISNULL( &rset[ j ] ); j++ ) {
301                                 struct berval   bv;
302                                 long            k;
303
304                                 /* don't concatenate with the empty string */
305                                 if ( BER_BVISEMPTY( &lset[ i ] ) ) {
306                                         ber_dupbv_x( &bv, &rset[ j ], cp->set_op->o_tmpmemctx );
307                                         if ( bv.bv_val == NULL ) {
308                                                 ber_bvarray_free_x( set, cp->set_op->o_tmpmemctx );
309                                                 set = NULL;
310                                                 goto done;
311                                         }
312
313                                 } else if ( BER_BVISEMPTY( &rset[ j ] ) ) {
314                                         ber_dupbv_x( &bv, &lset[ i ], cp->set_op->o_tmpmemctx );
315                                         if ( bv.bv_val == NULL ) {
316                                                 ber_bvarray_free_x( set, cp->set_op->o_tmpmemctx );
317                                                 set = NULL;
318                                                 goto done;
319                                         }
320
321                                 } else {
322                                         bv.bv_len = lset[ i ].bv_len + rset[ j ].bv_len;
323                                         bv.bv_val = cp->set_op->o_tmpalloc( bv.bv_len + 1,
324                                                         cp->set_op->o_tmpmemctx );
325                                         if ( bv.bv_val == NULL ) {
326                                                 ber_bvarray_free_x( set, cp->set_op->o_tmpmemctx );
327                                                 set = NULL;
328                                                 goto done;
329                                         }
330                                         AC_MEMCPY( bv.bv_val, lset[ i ].bv_val, lset[ i ].bv_len );
331                                         AC_MEMCPY( &bv.bv_val[ lset[ i ].bv_len ], rset[ j ].bv_val, rset[ j ].bv_len );
332                                         bv.bv_val[ bv.bv_len ] = '\0';
333                                 }
334
335                                 for ( k = 0; k < last; k++ ) {
336                                         if ( bvmatch( &set[ k ], &bv ) ) {
337                                                 cp->set_op->o_tmpfree( bv.bv_val, cp->set_op->o_tmpmemctx );
338                                                 break;
339                                         }
340                                 }
341
342                                 if ( k == last ) {
343                                         set[ last++ ] = bv;
344                                 }
345                         }
346                 }
347                 BER_BVZERO( &set[ last ] );
348                 break;
349
350         default:
351                 break;
352         }
353
354 done:;
355         if ( lset ) slap_set_dispose( cp, lset, SLAP_SET_LREF2REF( op_flags ) );
356         if ( rset ) slap_set_dispose( cp, rset, SLAP_SET_RREF2REF( op_flags ) );
357
358 done2:;
359         if ( LogTest( LDAP_DEBUG_ACL ) ) {
360                 if ( BER_BVISNULL( set ) ) {
361                         Debug( LDAP_DEBUG_ACL, "  ACL set: empty\n", 0, 0, 0 );
362
363                 } else {
364                         for ( i = 0; !BER_BVISNULL( &set[ i ] ); i++ ) {
365                                 Debug( LDAP_DEBUG_ACL, "  ACL set[%ld]=%s\n", i, set[i].bv_val, 0 );
366                         }
367                 }
368         }
369
370         return set;
371 }
372
373 static BerVarray
374 set_chase( SLAP_SET_GATHER gatherer,
375         SetCookie *cp, BerVarray set, AttributeDescription *desc, int closure )
376 {
377         BerVarray       vals, nset;
378         int             i;
379
380         if ( set == NULL ) {
381                 set = cp->set_op->o_tmpcalloc( 1, sizeof( struct berval ),
382                                 cp->set_op->o_tmpmemctx );
383                 if ( set != NULL ) {
384                         BER_BVZERO( &set[ 0 ] );
385                 }
386                 return set;
387         }
388
389         if ( BER_BVISNULL( set ) ) {
390                 return set;
391         }
392
393         nset = cp->set_op->o_tmpcalloc( 1, sizeof( struct berval ), cp->set_op->o_tmpmemctx );
394         if ( nset == NULL ) {
395                 ber_bvarray_free_x( set, cp->set_op->o_tmpmemctx );
396                 return NULL;
397         }
398         for ( i = 0; !BER_BVISNULL( &set[ i ] ); i++ ) {
399                 vals = gatherer( cp, &set[ i ], desc );
400                 if ( vals != NULL ) {
401                         nset = slap_set_join( cp, nset, '|', vals );
402                 }
403         }
404         ber_bvarray_free_x( set, cp->set_op->o_tmpmemctx );
405
406         if ( closure ) {
407                 for ( i = 0; !BER_BVISNULL( &nset[ i ] ); i++ ) {
408                         vals = gatherer( cp, &nset[ i ], desc );
409                         if ( vals != NULL ) {
410                                 nset = slap_set_join( cp, nset, '|', vals );
411                                 if ( nset == NULL ) {
412                                         break;
413                                 }
414                         }
415                 }
416         }
417
418         return nset;
419 }
420
421
422 static BerVarray
423 set_parents( SetCookie *cp, BerVarray set )
424 {
425         int             i, j, last;
426         struct berval   bv, pbv;
427         BerVarray       nset, vals;
428
429         if ( set == NULL ) {
430                 set = cp->set_op->o_tmpcalloc( 1, sizeof( struct berval ),
431                                 cp->set_op->o_tmpmemctx );
432                 if ( set != NULL ) {
433                         BER_BVZERO( &set[ 0 ] );
434                 }
435                 return set;
436         }
437
438         if ( BER_BVISNULL( &set[ 0 ] ) ) {
439                 return set;
440         }
441
442         nset = cp->set_op->o_tmpcalloc( 1, sizeof( struct berval ), cp->set_op->o_tmpmemctx );
443         if ( nset == NULL ) {
444                 ber_bvarray_free_x( set, cp->set_op->o_tmpmemctx );
445                 return NULL;
446         }
447
448         BER_BVZERO( &nset[ 0 ] );
449
450         for ( i = 0; !BER_BVISNULL( &set[ i ] ); i++ ) {
451                 int     level = 1;
452
453                 pbv = bv = set[ i ];
454                 for ( ; !BER_BVISEMPTY( &pbv ); dnParent( &bv, &pbv ) ) {
455                         level++;
456                         bv = pbv;
457                 }
458
459                 vals = cp->set_op->o_tmpcalloc( level + 1, sizeof( struct berval ), cp->set_op->o_tmpmemctx );
460                 if ( vals == NULL ) {
461                         ber_bvarray_free_x( set, cp->set_op->o_tmpmemctx );
462                         ber_bvarray_free_x( nset, cp->set_op->o_tmpmemctx );
463                         return NULL;
464                 }
465                 BER_BVZERO( &vals[ 0 ] );
466                 last = 0;
467
468                 bv = set[ i ];
469                 for ( j = 0 ; j < level ; j++ ) {
470                         ber_dupbv_x( &vals[ last ], &bv, cp->set_op->o_tmpmemctx );
471                         last++;
472                         dnParent( &bv, &bv );
473                 }
474                 BER_BVZERO( &vals[ last ] );
475
476                 nset = slap_set_join( cp, nset, '|', vals );
477         }
478
479         ber_bvarray_free_x( set, cp->set_op->o_tmpmemctx );
480
481         return nset;
482 }
483
484
485
486 static BerVarray
487 set_parent( SetCookie *cp, BerVarray set, int level )
488 {
489         int             i, j, last;
490         struct berval   bv;
491         BerVarray       nset;
492
493         if ( set == NULL ) {
494                 set = cp->set_op->o_tmpcalloc( 1, sizeof( struct berval ),
495                                 cp->set_op->o_tmpmemctx );
496                 if ( set != NULL ) {
497                         BER_BVZERO( &set[ 0 ] );
498                 }
499                 return set;
500         }
501
502         if ( BER_BVISNULL( &set[ 0 ] ) ) {
503                 return set;
504         }
505
506         nset = cp->set_op->o_tmpcalloc( slap_set_size( set ) + 1, sizeof( struct berval ), cp->set_op->o_tmpmemctx );
507         if ( nset == NULL ) {
508                 ber_bvarray_free_x( set, cp->set_op->o_tmpmemctx );
509                 return NULL;
510         }
511
512         BER_BVZERO( &nset[ 0 ] );
513         last = 0;
514
515         for ( i = 0; !BER_BVISNULL( &set[ i ] ); i++ ) {
516                 bv = set[ i ];
517
518                 for ( j = 0 ; j < level ; j++ ) {
519                         dnParent( &bv, &bv );
520                 }
521
522                 for ( j = 0; !BER_BVISNULL( &nset[ j ] ); j++ ) {
523                         if ( bvmatch( &bv, &nset[ j ] ) )
524                         {
525                                 break;          
526                         }       
527                 }
528
529                 if ( BER_BVISNULL( &nset[ j ] ) ) {
530                         ber_dupbv_x( &nset[ last ], &bv, cp->set_op->o_tmpmemctx );
531                         last++;
532                 }
533         }
534
535         BER_BVZERO( &nset[ last ] );
536
537         ber_bvarray_free_x( set, cp->set_op->o_tmpmemctx );
538
539         return nset;
540 }
541
542 int
543 slap_set_filter( SLAP_SET_GATHER gatherer,
544         SetCookie *cp, struct berval *fbv,
545         struct berval *user, struct berval *target, BerVarray *results )
546 {
547 #define STACK_SIZE      64
548 #define IS_SET(x)       ( (unsigned long)(x) >= 256 )
549 #define IS_OP(x)        ( (unsigned long)(x) < 256 )
550 #define SF_ERROR(x)     do { rc = -1; goto _error; } while ( 0 )
551 #define SF_TOP()        ( (BerVarray)( ( stp < 0 ) ? 0 : stack[ stp ] ) )
552 #define SF_POP()        ( (BerVarray)( ( stp < 0 ) ? 0 : stack[ stp-- ] ) )
553 #define SF_PUSH(x)      do { \
554                 if ( stp >= ( STACK_SIZE - 1 ) ) SF_ERROR( overflow ); \
555                 stack[ ++stp ] = (BerVarray)(long)(x); \
556         } while ( 0 )
557
558         BerVarray       set, lset;
559         BerVarray       stack[ STACK_SIZE ] = { 0 };
560         int             len, rc, stp;
561         unsigned long   op;
562         char            c, *filter = fbv->bv_val;
563
564         if ( results ) {
565                 *results = NULL;
566         }
567
568         stp = -1;
569         while ( ( c = *filter++ ) ) {
570                 set = NULL;
571                 switch ( c ) {
572                 case ' ':
573                 case '\t':
574                 case '\x0A':
575                 case '\x0D':
576                         break;
577
578                 case '(' /* ) */ :
579                         if ( IS_SET( SF_TOP() ) ) {
580                                 SF_ERROR( syntax );
581                         }
582                         SF_PUSH( c );
583                         break;
584
585                 case /* ( */ ')':
586                         set = SF_POP();
587                         if ( IS_OP( set ) ) {
588                                 SF_ERROR( syntax );
589                         }
590                         if ( SF_TOP() == (void *)'(' /* ) */ ) {
591                                 SF_POP();
592                                 SF_PUSH( set );
593                                 set = NULL;
594
595                         } else if ( IS_OP( SF_TOP() ) ) {
596                                 op = (unsigned long)SF_POP();
597                                 lset = SF_POP();
598                                 SF_POP();
599                                 set = slap_set_join( cp, lset, op, set );
600                                 if ( set == NULL ) {
601                                         SF_ERROR( memory );
602                                 }
603                                 SF_PUSH( set );
604                                 set = NULL;
605
606                         } else {
607                                 SF_ERROR( syntax );
608                         }
609                         break;
610
611                 case '|':       /* union */
612                 case '&':       /* intersection */
613                 case '+':       /* string concatenation */
614                         set = SF_POP();
615                         if ( IS_OP( set ) ) {
616                                 SF_ERROR( syntax );
617                         }
618                         if ( SF_TOP() == 0 || SF_TOP() == (void *)'(' /* ) */ ) {
619                                 SF_PUSH( set );
620                                 set = NULL;
621
622                         } else if ( IS_OP( SF_TOP() ) ) {
623                                 op = (unsigned long)SF_POP();
624                                 lset = SF_POP();
625                                 set = slap_set_join( cp, lset, op, set );
626                                 if ( set == NULL ) {
627                                         SF_ERROR( memory );
628                                 }
629                                 SF_PUSH( set );
630                                 set = NULL;
631                                 
632                         } else {
633                                 SF_ERROR( syntax );
634                         }
635                         SF_PUSH( c );
636                         break;
637
638                 case '[' /* ] */:
639                         if ( ( SF_TOP() == (void *)'/' ) || IS_SET( SF_TOP() ) ) {
640                                 SF_ERROR( syntax );
641                         }
642                         for ( len = 0; ( c = *filter++ ) && ( c != /* [ */ ']' ); len++ )
643                                 ;
644                         if ( c == 0 ) {
645                                 SF_ERROR( syntax );
646                         }
647                         
648                         set = cp->set_op->o_tmpcalloc( 2, sizeof( struct berval ),
649                                         cp->set_op->o_tmpmemctx );
650                         if ( set == NULL ) {
651                                 SF_ERROR( memory );
652                         }
653                         set->bv_val = cp->set_op->o_tmpcalloc( len + 1, sizeof( char ),
654                                         cp->set_op->o_tmpmemctx );
655                         if ( BER_BVISNULL( set ) ) {
656                                 SF_ERROR( memory );
657                         }
658                         AC_MEMCPY( set->bv_val, &filter[ - len - 1 ], len );
659                         set->bv_len = len;
660                         SF_PUSH( set );
661                         set = NULL;
662                         break;
663
664                 case '-':
665                         if ( ( SF_TOP() == (void *)'/' )
666                                 && ( *filter == '*' || ASCII_DIGIT( *filter ) ) )
667                         {
668                                 SF_POP();
669
670                                 if ( *filter == '*' ) {
671                                         set = set_parents( cp, SF_POP() );
672                                         filter++;
673
674                                 } else {
675                                         char *next = NULL;
676                                         long parent = strtol( filter, &next, 10 );
677
678                                         if ( next == filter ) {
679                                                 SF_ERROR( syntax );
680                                         }
681
682                                         set = SF_POP();
683                                         if ( parent != 0 ) {
684                                                 set = set_parent( cp, set, parent );
685                                         }
686                                         filter = next;
687                                 }
688
689                                 if ( set == NULL ) {
690                                         SF_ERROR( memory );
691                                 }
692
693                                 SF_PUSH( set );
694                                 set = NULL;
695                                 break;
696                         } else {
697                                 c = *filter++;
698                                 if ( c != '>' ) {
699                                         SF_ERROR( syntax );
700                                 }
701                                 /* fall through to next case */
702                         }
703
704                 case '/':
705                         if ( IS_OP( SF_TOP() ) ) {
706                                 SF_ERROR( syntax );
707                         }
708                         SF_PUSH( '/' );
709                         break;
710
711                 default:
712                         if ( ( c != '_' )
713                                         && ( c < 'A' || c > 'Z' )
714                                         && ( c < 'a' || c > 'z' ) )
715                         {
716                                 SF_ERROR( syntax );
717                         }
718                         filter--;
719                         for ( len = 1;
720                                         ( c = filter[ len ] )
721                                                 && ( ( c >= '0' && c <= '9' )
722                                                         || ( c >= 'A' && c <= 'Z' )
723                                                         || ( c >= 'a' && c <= 'z' ) );
724                                         len++ )
725                                 /* count */ ;
726                         if ( len == 4
727                                 && memcmp( "this", filter, len ) == 0 )
728                         {
729                                 if ( ( SF_TOP() == (void *)'/' ) || IS_SET( SF_TOP() ) ) {
730                                         SF_ERROR( syntax );
731                                 }
732                                 set = cp->set_op->o_tmpcalloc( 2, sizeof( struct berval ),
733                                                 cp->set_op->o_tmpmemctx );
734                                 if ( set == NULL ) {
735                                         SF_ERROR( memory );
736                                 }
737                                 ber_dupbv_x( set, target, cp->set_op->o_tmpmemctx );
738                                 if ( BER_BVISNULL( set ) ) {
739                                         SF_ERROR( memory );
740                                 }
741                                 BER_BVZERO( &set[ 1 ] );
742                                 
743                         } else if ( len == 4
744                                 && memcmp( "user", filter, len ) == 0 ) 
745                         {
746                                 if ( ( SF_TOP() == (void *)'/' ) || IS_SET( SF_TOP() ) ) {
747                                         SF_ERROR( syntax );
748                                 }
749                                 set = cp->set_op->o_tmpcalloc( 2, sizeof( struct berval ),
750                                                 cp->set_op->o_tmpmemctx );
751                                 if ( set == NULL ) {
752                                         SF_ERROR( memory );
753                                 }
754                                 ber_dupbv_x( set, user, cp->set_op->o_tmpmemctx );
755                                 if ( BER_BVISNULL( set ) ) {
756                                         SF_ERROR( memory );
757                                 }
758                                 BER_BVZERO( &set[ 1 ] );
759                                 
760                         } else if ( SF_TOP() != (void *)'/' ) {
761                                 SF_ERROR( syntax );
762
763                         } else {
764                                 struct berval           fb2;
765                                 AttributeDescription    *ad = NULL;
766                                 const char              *text = NULL;
767
768                                 SF_POP();
769                                 fb2.bv_val = filter;
770                                 fb2.bv_len = len;
771
772                                 if ( slap_bv2ad( &fb2, &ad, &text ) != LDAP_SUCCESS ) {
773                                         SF_ERROR( syntax );
774                                 }
775
776                                 /* NOTE: ad must have distinguishedName syntax
777                                  * or expand in an LDAP URI if c == '*'
778                                  */
779                                 
780                                 set = set_chase( gatherer,
781                                         cp, SF_POP(), ad, c == '*' );
782                                 if ( set == NULL ) {
783                                         SF_ERROR( memory );
784                                 }
785                                 if ( c == '*' ) {
786                                         len++;
787                                 }
788                         }
789                         filter += len;
790                         SF_PUSH( set );
791                         set = NULL;
792                         break;
793                 }
794         }
795
796         set = SF_POP();
797         if ( IS_OP( set ) ) {
798                 SF_ERROR( syntax );
799         }
800         if ( SF_TOP() == 0 ) {
801                 /* FIXME: ok ? */ ;
802
803         } else if ( IS_OP( SF_TOP() ) ) {
804                 op = (unsigned long)SF_POP();
805                 lset = SF_POP();
806                 set = slap_set_join( cp, lset, op, set );
807                 if ( set == NULL ) {
808                         SF_ERROR( memory );
809                 }
810                 
811         } else {
812                 SF_ERROR( syntax );
813         }
814
815         rc = slap_set_isempty( set ) ? 0 : 1;
816         if ( results ) {
817                 *results = set;
818                 set = NULL;
819         }
820
821 _error:
822         if ( IS_SET( set ) ) {
823                 ber_bvarray_free_x( set, cp->set_op->o_tmpmemctx );
824         }
825         while ( ( set = SF_POP() ) ) {
826                 if ( IS_SET( set ) ) {
827                         ber_bvarray_free_x( set, cp->set_op->o_tmpmemctx );
828                 }
829         }
830         return rc;
831 }