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