]> git.sur5r.net Git - openldap/blob - servers/slapd/sets.c
5a70092134fc5b4f04a962eff79b1e107ff4dbc1
[openldap] / servers / slapd / sets.c
1 /* $OpenLDAP$ */
2 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
3  *
4  * Copyright 2000-2017 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 duplicates
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                                                         i--;
204                                                 }
205                                                 exists = 1;
206                                                 break;
207                                         }
208                                 }
209
210                                 if ( !exists ) {
211                                         if ( op_flags & SLAP_SET_RREFVAL ) {
212                                                 ber_dupbv_x( &set[ last ], &rset[ i ], cp->set_op->o_tmpmemctx );
213
214                                         } else {
215                                                 set[ last ] = rset[ i ];
216                                         }
217                                         last++;
218                                 }
219                         }
220
221                         /* pointers to values have been used in set - don't free twice */
222                         op_flags |= SLAP_SET_RREFVAL;
223
224                         BER_BVZERO( &set[ last ] );
225                 }
226                 break;
227
228         case '&':       /* intersection */
229                 if ( lset == NULL || BER_BVISNULL( &lset[ 0 ] )
230                         || rset == NULL || BER_BVISNULL( &rset[ 0 ] ) )
231                 {
232                         set = cp->set_op->o_tmpcalloc( 1, sizeof( struct berval ),
233                                         cp->set_op->o_tmpmemctx );
234                         BER_BVZERO( &set[ 0 ] );
235                         break;
236
237                 } else {
238                         long llen, rlen;
239                         BerVarray sset;
240
241                         llen = slap_set_size( lset );
242                         rlen = slap_set_size( rset );
243
244                         /* dup the shortest */
245                         if ( llen < rlen ) {
246                                 last = llen;
247                                 set = set_dup( cp, lset, SLAP_SET_LREF2REF( op_flags ) );
248                                 lset = NULL;
249                                 sset = rset;
250
251                         } else {
252                                 last = rlen;
253                                 set = set_dup( cp, rset, SLAP_SET_RREF2REF( op_flags ) );
254                                 rset = NULL;
255                                 sset = lset;
256                         }
257
258                         if ( set == NULL ) {
259                                 break;
260                         }
261
262                         for ( i = 0; !BER_BVISNULL( &set[ i ] ); i++ ) {
263                                 for ( j = 0; !BER_BVISNULL( &sset[ j ] ); j++ ) {
264                                         if ( bvmatch( &set[ i ], &sset[ j ] ) ) {
265                                                 break;
266                                         }
267                                 }
268
269                                 if ( BER_BVISNULL( &sset[ j ] ) ) {
270                                         cp->set_op->o_tmpfree( set[ i ].bv_val, cp->set_op->o_tmpmemctx );
271                                         set[ i ] = set[ --last ];
272                                         BER_BVZERO( &set[ last ] );
273                                         i--;
274                                 }
275                         }
276                 }
277                 break;
278
279         case '+':       /* string concatenation */
280                 i = slap_set_size( rset );
281                 j = slap_set_size( lset );
282
283                 /* handle empty set cases */
284                 if ( i == 0 || j == 0 ) {
285                         set = cp->set_op->o_tmpcalloc( 1, sizeof( struct berval ),
286                                         cp->set_op->o_tmpmemctx );
287                         if ( set == NULL ) {
288                                 break;
289                         }
290                         BER_BVZERO( &set[ 0 ] );
291                         break;
292                 }
293
294                 set = cp->set_op->o_tmpcalloc( i * j + 1, sizeof( struct berval ),
295                                 cp->set_op->o_tmpmemctx );
296                 if ( set == NULL ) {
297                         break;
298                 }
299
300                 for ( last = 0, i = 0; !BER_BVISNULL( &lset[ i ] ); i++ ) {
301                         for ( j = 0; !BER_BVISNULL( &rset[ j ] ); j++ ) {
302                                 struct berval   bv;
303                                 long            k;
304
305                                 /* don't concatenate with the empty string */
306                                 if ( BER_BVISEMPTY( &lset[ i ] ) ) {
307                                         ber_dupbv_x( &bv, &rset[ j ], cp->set_op->o_tmpmemctx );
308                                         if ( bv.bv_val == NULL ) {
309                                                 ber_bvarray_free_x( set, cp->set_op->o_tmpmemctx );
310                                                 set = NULL;
311                                                 goto done;
312                                         }
313
314                                 } else if ( BER_BVISEMPTY( &rset[ j ] ) ) {
315                                         ber_dupbv_x( &bv, &lset[ i ], cp->set_op->o_tmpmemctx );
316                                         if ( bv.bv_val == NULL ) {
317                                                 ber_bvarray_free_x( set, cp->set_op->o_tmpmemctx );
318                                                 set = NULL;
319                                                 goto done;
320                                         }
321
322                                 } else {
323                                         bv.bv_len = lset[ i ].bv_len + rset[ j ].bv_len;
324                                         bv.bv_val = cp->set_op->o_tmpalloc( bv.bv_len + 1,
325                                                         cp->set_op->o_tmpmemctx );
326                                         if ( bv.bv_val == NULL ) {
327                                                 ber_bvarray_free_x( set, cp->set_op->o_tmpmemctx );
328                                                 set = NULL;
329                                                 goto done;
330                                         }
331                                         AC_MEMCPY( bv.bv_val, lset[ i ].bv_val, lset[ i ].bv_len );
332                                         AC_MEMCPY( &bv.bv_val[ lset[ i ].bv_len ], rset[ j ].bv_val, rset[ j ].bv_len );
333                                         bv.bv_val[ bv.bv_len ] = '\0';
334                                 }
335
336                                 for ( k = 0; k < last; k++ ) {
337                                         if ( bvmatch( &set[ k ], &bv ) ) {
338                                                 cp->set_op->o_tmpfree( bv.bv_val, cp->set_op->o_tmpmemctx );
339                                                 break;
340                                         }
341                                 }
342
343                                 if ( k == last ) {
344                                         set[ last++ ] = bv;
345                                 }
346                         }
347                 }
348                 BER_BVZERO( &set[ last ] );
349                 break;
350
351         default:
352                 break;
353         }
354
355 done:;
356         if ( lset ) slap_set_dispose( cp, lset, SLAP_SET_LREF2REF( op_flags ) );
357         if ( rset ) slap_set_dispose( cp, rset, SLAP_SET_RREF2REF( op_flags ) );
358
359 done2:;
360         if ( LogTest( LDAP_DEBUG_ACL ) ) {
361                 if ( !set || BER_BVISNULL( set ) ) {
362                         Debug( LDAP_DEBUG_ACL, "  ACL set: empty\n", 0, 0, 0 );
363
364                 } else {
365                         for ( i = 0; !BER_BVISNULL( &set[ i ] ); i++ ) {
366                                 Debug( LDAP_DEBUG_ACL, "  ACL set[%ld]=%s\n", i, set[i].bv_val, 0 );
367                         }
368                 }
369         }
370
371         return set;
372 }
373
374 static BerVarray
375 set_chase( SLAP_SET_GATHER gatherer,
376         SetCookie *cp, BerVarray set, AttributeDescription *desc, int closure )
377 {
378         BerVarray       vals, nset;
379         int             i;
380
381         if ( set == NULL ) {
382                 set = cp->set_op->o_tmpcalloc( 1, sizeof( struct berval ),
383                                 cp->set_op->o_tmpmemctx );
384                 if ( set != NULL ) {
385                         BER_BVZERO( &set[ 0 ] );
386                 }
387                 return set;
388         }
389
390         if ( BER_BVISNULL( set ) ) {
391                 return set;
392         }
393
394         nset = cp->set_op->o_tmpcalloc( 1, sizeof( struct berval ), cp->set_op->o_tmpmemctx );
395         if ( nset == NULL ) {
396                 ber_bvarray_free_x( set, cp->set_op->o_tmpmemctx );
397                 return NULL;
398         }
399         for ( i = 0; !BER_BVISNULL( &set[ i ] ); i++ ) {
400                 vals = gatherer( cp, &set[ i ], desc );
401                 if ( vals != NULL ) {
402                         nset = slap_set_join( cp, nset, '|', vals );
403                 }
404         }
405         ber_bvarray_free_x( set, cp->set_op->o_tmpmemctx );
406
407         if ( closure ) {
408                 for ( i = 0; !BER_BVISNULL( &nset[ i ] ); i++ ) {
409                         vals = gatherer( cp, &nset[ i ], desc );
410                         if ( vals != NULL ) {
411                                 nset = slap_set_join( cp, nset, '|', vals );
412                                 if ( nset == NULL ) {
413                                         break;
414                                 }
415                         }
416                 }
417         }
418
419         return nset;
420 }
421
422
423 static BerVarray
424 set_parents( SetCookie *cp, BerVarray set )
425 {
426         int             i, j, last;
427         struct berval   bv, pbv;
428         BerVarray       nset, vals;
429
430         if ( set == NULL ) {
431                 set = cp->set_op->o_tmpcalloc( 1, sizeof( struct berval ),
432                                 cp->set_op->o_tmpmemctx );
433                 if ( set != NULL ) {
434                         BER_BVZERO( &set[ 0 ] );
435                 }
436                 return set;
437         }
438
439         if ( BER_BVISNULL( &set[ 0 ] ) ) {
440                 return set;
441         }
442
443         nset = cp->set_op->o_tmpcalloc( 1, sizeof( struct berval ), cp->set_op->o_tmpmemctx );
444         if ( nset == NULL ) {
445                 ber_bvarray_free_x( set, cp->set_op->o_tmpmemctx );
446                 return NULL;
447         }
448
449         BER_BVZERO( &nset[ 0 ] );
450
451         for ( i = 0; !BER_BVISNULL( &set[ i ] ); i++ ) {
452                 int     level = 1;
453
454                 pbv = bv = set[ i ];
455                 for ( ; !BER_BVISEMPTY( &pbv ); dnParent( &bv, &pbv ) ) {
456                         level++;
457                         bv = pbv;
458                 }
459
460                 vals = cp->set_op->o_tmpcalloc( level + 1, sizeof( struct berval ), cp->set_op->o_tmpmemctx );
461                 if ( vals == NULL ) {
462                         ber_bvarray_free_x( set, cp->set_op->o_tmpmemctx );
463                         ber_bvarray_free_x( nset, cp->set_op->o_tmpmemctx );
464                         return NULL;
465                 }
466                 BER_BVZERO( &vals[ 0 ] );
467                 last = 0;
468
469                 bv = set[ i ];
470                 for ( j = 0 ; j < level ; j++ ) {
471                         ber_dupbv_x( &vals[ last ], &bv, cp->set_op->o_tmpmemctx );
472                         last++;
473                         dnParent( &bv, &bv );
474                 }
475                 BER_BVZERO( &vals[ last ] );
476
477                 nset = slap_set_join( cp, nset, '|', vals );
478         }
479
480         ber_bvarray_free_x( set, cp->set_op->o_tmpmemctx );
481
482         return nset;
483 }
484
485
486
487 static BerVarray
488 set_parent( SetCookie *cp, BerVarray set, int level )
489 {
490         int             i, j, last;
491         struct berval   bv;
492         BerVarray       nset;
493
494         if ( set == NULL ) {
495                 set = cp->set_op->o_tmpcalloc( 1, sizeof( struct berval ),
496                                 cp->set_op->o_tmpmemctx );
497                 if ( set != NULL ) {
498                         BER_BVZERO( &set[ 0 ] );
499                 }
500                 return set;
501         }
502
503         if ( BER_BVISNULL( &set[ 0 ] ) ) {
504                 return set;
505         }
506
507         nset = cp->set_op->o_tmpcalloc( slap_set_size( set ) + 1, sizeof( struct berval ), cp->set_op->o_tmpmemctx );
508         if ( nset == NULL ) {
509                 ber_bvarray_free_x( set, cp->set_op->o_tmpmemctx );
510                 return NULL;
511         }
512
513         BER_BVZERO( &nset[ 0 ] );
514         last = 0;
515
516         for ( i = 0; !BER_BVISNULL( &set[ i ] ); i++ ) {
517                 bv = set[ i ];
518
519                 for ( j = 0 ; j < level ; j++ ) {
520                         dnParent( &bv, &bv );
521                 }
522
523                 for ( j = 0; !BER_BVISNULL( &nset[ j ] ); j++ ) {
524                         if ( bvmatch( &bv, &nset[ j ] ) )
525                         {
526                                 break;          
527                         }       
528                 }
529
530                 if ( BER_BVISNULL( &nset[ j ] ) ) {
531                         ber_dupbv_x( &nset[ last ], &bv, cp->set_op->o_tmpmemctx );
532                         last++;
533                 }
534         }
535
536         BER_BVZERO( &nset[ last ] );
537
538         ber_bvarray_free_x( set, cp->set_op->o_tmpmemctx );
539
540         return nset;
541 }
542
543 int
544 slap_set_filter( SLAP_SET_GATHER gatherer,
545         SetCookie *cp, struct berval *fbv,
546         struct berval *user, struct berval *target, BerVarray *results )
547 {
548 #define STACK_SIZE      64
549 #define IS_SET(x)       ( (unsigned long)(x) >= 256 )
550 #define IS_OP(x)        ( (unsigned long)(x) < 256 )
551 #define SF_ERROR(x)     do { rc = -1; goto _error; } while ( 0 )
552 #define SF_TOP()        ( (BerVarray)( ( stp < 0 ) ? 0 : stack[ stp ] ) )
553 #define SF_POP()        ( (BerVarray)( ( stp < 0 ) ? 0 : stack[ stp-- ] ) )
554 #define SF_PUSH(x)      do { \
555                 if ( stp >= ( STACK_SIZE - 1 ) ) SF_ERROR( overflow ); \
556                 stack[ ++stp ] = (BerVarray)(long)(x); \
557         } while ( 0 )
558
559         BerVarray       set, lset;
560         BerVarray       stack[ STACK_SIZE ] = { 0 };
561         int             len, rc, stp;
562         unsigned long   op;
563         char            c, *filter = fbv->bv_val;
564
565         if ( results ) {
566                 *results = NULL;
567         }
568
569         stp = -1;
570         while ( ( c = *filter++ ) ) {
571                 set = NULL;
572                 switch ( c ) {
573                 case ' ':
574                 case '\t':
575                 case '\x0A':
576                 case '\x0D':
577                         break;
578
579                 case '(' /* ) */ :
580                         if ( IS_SET( SF_TOP() ) ) {
581                                 SF_ERROR( syntax );
582                         }
583                         SF_PUSH( c );
584                         break;
585
586                 case /* ( */ ')':
587                         set = SF_POP();
588                         if ( IS_OP( set ) ) {
589                                 SF_ERROR( syntax );
590                         }
591                         if ( SF_TOP() == (void *)'(' /* ) */ ) {
592                                 SF_POP();
593                                 SF_PUSH( set );
594                                 set = NULL;
595
596                         } else if ( IS_OP( SF_TOP() ) ) {
597                                 op = (unsigned long)SF_POP();
598                                 lset = SF_POP();
599                                 SF_POP();
600                                 set = slap_set_join( cp, lset, op, set );
601                                 if ( set == NULL ) {
602                                         SF_ERROR( memory );
603                                 }
604                                 SF_PUSH( set );
605                                 set = NULL;
606
607                         } else {
608                                 SF_ERROR( syntax );
609                         }
610                         break;
611
612                 case '|':       /* union */
613                 case '&':       /* intersection */
614                 case '+':       /* string concatenation */
615                         set = SF_POP();
616                         if ( IS_OP( set ) ) {
617                                 SF_ERROR( syntax );
618                         }
619                         if ( SF_TOP() == 0 || SF_TOP() == (void *)'(' /* ) */ ) {
620                                 SF_PUSH( set );
621                                 set = NULL;
622
623                         } else if ( IS_OP( SF_TOP() ) ) {
624                                 op = (unsigned long)SF_POP();
625                                 lset = SF_POP();
626                                 set = slap_set_join( cp, lset, op, set );
627                                 if ( set == NULL ) {
628                                         SF_ERROR( memory );
629                                 }
630                                 SF_PUSH( set );
631                                 set = NULL;
632                                 
633                         } else {
634                                 SF_ERROR( syntax );
635                         }
636                         SF_PUSH( c );
637                         break;
638
639                 case '[' /* ] */:
640                         if ( ( SF_TOP() == (void *)'/' ) || IS_SET( SF_TOP() ) ) {
641                                 SF_ERROR( syntax );
642                         }
643                         for ( len = 0; ( c = *filter++ ) && ( c != /* [ */ ']' ); len++ )
644                                 ;
645                         if ( c == 0 ) {
646                                 SF_ERROR( syntax );
647                         }
648                         
649                         set = cp->set_op->o_tmpcalloc( 2, sizeof( struct berval ),
650                                         cp->set_op->o_tmpmemctx );
651                         if ( set == NULL ) {
652                                 SF_ERROR( memory );
653                         }
654                         set->bv_val = cp->set_op->o_tmpcalloc( len + 1, sizeof( char ),
655                                         cp->set_op->o_tmpmemctx );
656                         if ( BER_BVISNULL( set ) ) {
657                                 SF_ERROR( memory );
658                         }
659                         AC_MEMCPY( set->bv_val, &filter[ - len - 1 ], len );
660                         set->bv_len = len;
661                         SF_PUSH( set );
662                         set = NULL;
663                         break;
664
665                 case '-':
666                         if ( ( SF_TOP() == (void *)'/' )
667                                 && ( *filter == '*' || ASCII_DIGIT( *filter ) ) )
668                         {
669                                 SF_POP();
670
671                                 if ( *filter == '*' ) {
672                                         set = set_parents( cp, SF_POP() );
673                                         filter++;
674
675                                 } else {
676                                         char *next = NULL;
677                                         long parent = strtol( filter, &next, 10 );
678
679                                         if ( next == filter ) {
680                                                 SF_ERROR( syntax );
681                                         }
682
683                                         set = SF_POP();
684                                         if ( parent != 0 ) {
685                                                 set = set_parent( cp, set, parent );
686                                         }
687                                         filter = next;
688                                 }
689
690                                 if ( set == NULL ) {
691                                         SF_ERROR( memory );
692                                 }
693
694                                 SF_PUSH( set );
695                                 set = NULL;
696                                 break;
697                         } else {
698                                 c = *filter++;
699                                 if ( c != '>' ) {
700                                         SF_ERROR( syntax );
701                                 }
702                                 /* fall through to next case */
703                         }
704
705                 case '/':
706                         if ( IS_OP( SF_TOP() ) ) {
707                                 SF_ERROR( syntax );
708                         }
709                         SF_PUSH( '/' );
710                         break;
711
712                 default:
713                         if ( !AD_LEADCHAR( c ) ) {
714                                 SF_ERROR( syntax );
715                         }
716                         filter--;
717                         for ( len = 1;
718                                 ( c = filter[ len ] ) && AD_CHAR( c );
719                                 len++ )
720                         {
721                                 /* count */
722                                 if ( c == '-' && !AD_CHAR( filter[ len + 1 ] ) ) {
723                                         break;
724                                 }
725                         }
726                         if ( len == 4
727                                 && memcmp( "this", filter, len ) == 0 )
728                         {
729                                 assert( !BER_BVISNULL( target ) );
730                                 if ( ( SF_TOP() == (void *)'/' ) || IS_SET( SF_TOP() ) ) {
731                                         SF_ERROR( syntax );
732                                 }
733                                 set = cp->set_op->o_tmpcalloc( 2, sizeof( struct berval ),
734                                                 cp->set_op->o_tmpmemctx );
735                                 if ( set == NULL ) {
736                                         SF_ERROR( memory );
737                                 }
738                                 ber_dupbv_x( set, target, cp->set_op->o_tmpmemctx );
739                                 if ( BER_BVISNULL( set ) ) {
740                                         SF_ERROR( memory );
741                                 }
742                                 BER_BVZERO( &set[ 1 ] );
743                                 
744                         } else if ( len == 4
745                                 && memcmp( "user", filter, len ) == 0 ) 
746                         {
747                                 if ( ( SF_TOP() == (void *)'/' ) || IS_SET( SF_TOP() ) ) {
748                                         SF_ERROR( syntax );
749                                 }
750                                 if ( BER_BVISNULL( user ) ) {
751                                         SF_ERROR( memory );
752                                 }
753                                 set = cp->set_op->o_tmpcalloc( 2, sizeof( struct berval ),
754                                                 cp->set_op->o_tmpmemctx );
755                                 if ( set == NULL ) {
756                                         SF_ERROR( memory );
757                                 }
758                                 ber_dupbv_x( set, user, cp->set_op->o_tmpmemctx );
759                                 BER_BVZERO( &set[ 1 ] );
760                                 
761                         } else if ( SF_TOP() != (void *)'/' ) {
762                                 SF_ERROR( syntax );
763
764                         } else {
765                                 struct berval           fb2;
766                                 AttributeDescription    *ad = NULL;
767                                 const char              *text = NULL;
768
769                                 SF_POP();
770                                 fb2.bv_val = filter;
771                                 fb2.bv_len = len;
772
773                                 if ( slap_bv2ad( &fb2, &ad, &text ) != LDAP_SUCCESS ) {
774                                         SF_ERROR( syntax );
775                                 }
776
777                                 /* NOTE: ad must have distinguishedName syntax
778                                  * or expand in an LDAP URI if c == '*'
779                                  */
780                                 
781                                 set = set_chase( gatherer,
782                                         cp, SF_POP(), ad, c == '*' );
783                                 if ( set == NULL ) {
784                                         SF_ERROR( memory );
785                                 }
786                                 if ( c == '*' ) {
787                                         len++;
788                                 }
789                         }
790                         filter += len;
791                         SF_PUSH( set );
792                         set = NULL;
793                         break;
794                 }
795         }
796
797         set = SF_POP();
798         if ( IS_OP( set ) ) {
799                 SF_ERROR( syntax );
800         }
801         if ( SF_TOP() == 0 ) {
802                 /* FIXME: ok ? */ ;
803
804         } else if ( IS_OP( SF_TOP() ) ) {
805                 op = (unsigned long)SF_POP();
806                 lset = SF_POP();
807                 set = slap_set_join( cp, lset, op, set );
808                 if ( set == NULL ) {
809                         SF_ERROR( memory );
810                 }
811                 
812         } else {
813                 SF_ERROR( syntax );
814         }
815
816         rc = slap_set_isempty( set ) ? 0 : 1;
817         if ( results ) {
818                 *results = set;
819                 set = NULL;
820         }
821
822 _error:
823         if ( IS_SET( set ) ) {
824                 ber_bvarray_free_x( set, cp->set_op->o_tmpmemctx );
825         }
826         while ( ( set = SF_POP() ) ) {
827                 if ( IS_SET( set ) ) {
828                         ber_bvarray_free_x( set, cp->set_op->o_tmpmemctx );
829                 }
830         }
831         return rc;
832 }