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