Back to index

openldap  2.4.31
sets.c
Go to the documentation of this file.
00001 /* $OpenLDAP$ */
00002 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
00003  *
00004  * Copyright 2000-2012 The OpenLDAP Foundation.
00005  * All rights reserved.
00006  *
00007  * Redistribution and use in source and binary forms, with or without
00008  * modification, are permitted only as authorized by the OpenLDAP
00009  * Public License.
00010  *
00011  * A copy of this license is available in the file LICENSE in the
00012  * top-level directory of the distribution or, alternatively, at
00013  * <http://www.OpenLDAP.org/license.html>.
00014  */
00015 
00016 #include "portable.h"
00017 
00018 #include <stdio.h>
00019 #include <ac/string.h>
00020 
00021 #include "slap.h"
00022 #include "sets.h"
00023 
00024 static BerVarray set_chase( SLAP_SET_GATHER gatherer,
00025        SetCookie *cookie, BerVarray set, AttributeDescription *desc, int closure );
00026 
00027 /* Count the array members */
00028 static long
00029 slap_set_size( BerVarray set )
00030 {
00031        long   i = 0;
00032 
00033        if ( set != NULL ) {
00034               while ( !BER_BVISNULL( &set[ i ] ) ) {
00035                      i++;
00036               }
00037        }
00038 
00039        return i;
00040 }
00041 
00042 /* Return 0 if there is at least one array member, non-zero otherwise */
00043 static int
00044 slap_set_isempty( BerVarray set )
00045 {
00046        if ( set == NULL ) {
00047               return 1;
00048        }
00049 
00050        if ( !BER_BVISNULL( &set[ 0 ] ) ) {
00051               return 0;
00052        }
00053 
00054        return 1;
00055 }
00056 
00057 /* Dispose of the contents of the array and the array itself according
00058  * to the flags value.  If SLAP_SET_REFVAL, don't dispose of values;
00059  * if SLAP_SET_REFARR, don't dispose of the array itself.  In case of
00060  * binary operators, there are LEFT flags and RIGHT flags, referring to
00061  * the first and the second operator arguments, respectively.  In this
00062  * case, flags must be transformed using macros SLAP_SET_LREF2REF() and
00063  * SLAP_SET_RREF2REF() before calling this function.
00064  */
00065 static void
00066 slap_set_dispose( SetCookie *cp, BerVarray set, unsigned flags )
00067 {
00068        if ( flags & SLAP_SET_REFVAL ) {
00069               if ( ! ( flags & SLAP_SET_REFARR ) ) {
00070                      cp->set_op->o_tmpfree( set, cp->set_op->o_tmpmemctx );
00071               }
00072 
00073        } else {
00074               ber_bvarray_free_x( set, cp->set_op->o_tmpmemctx );
00075        }
00076 }
00077 
00078 /* Duplicate a set.  If SLAP_SET_REFARR, is not set, the original array
00079  * with the original values is returned, otherwise the array is duplicated;
00080  * if SLAP_SET_REFVAL is set, also the values are duplicated.
00081  */
00082 static BerVarray
00083 set_dup( SetCookie *cp, BerVarray set, unsigned flags )
00084 {
00085        BerVarray     newset = NULL;
00086 
00087        if ( set == NULL ) {
00088               return NULL;
00089        }
00090 
00091        if ( flags & SLAP_SET_REFARR ) {
00092               int    i;
00093 
00094               for ( i = 0; !BER_BVISNULL( &set[ i ] ); i++ )
00095                      ;
00096               newset = cp->set_op->o_tmpcalloc( i + 1,
00097                             sizeof( struct berval ), 
00098                             cp->set_op->o_tmpmemctx );
00099               if ( newset == NULL ) {
00100                      return NULL;
00101               }
00102 
00103               if ( flags & SLAP_SET_REFVAL ) {
00104                      for ( i = 0; !BER_BVISNULL( &set[ i ] ); i++ ) {
00105                             ber_dupbv_x( &newset[ i ], &set[ i ],
00106                                           cp->set_op->o_tmpmemctx );
00107                      }
00108 
00109               } else {
00110                      AC_MEMCPY( newset, set, ( i + 1 ) * sizeof( struct berval ) );
00111               }
00112               
00113        } else {
00114               newset = set;
00115        }
00116 
00117        return newset;
00118 }
00119 
00120 /* Join two sets according to operator op and flags op_flags.
00121  * op can be:
00122  *     '|' (or):     the union between the two sets is returned,
00123  *                   eliminating duplicates
00124  *     '&' (and):    the intersection between the two sets
00125  *                   is returned
00126  *     '+' (add):    the inner product of the two sets is returned,
00127  *                   namely a set containing the concatenation of
00128  *                   all combinations of the two sets members,
00129  *                   except for duplicates.
00130  * The two sets are disposed of according to the flags as described
00131  * for slap_set_dispose().
00132  */
00133 BerVarray
00134 slap_set_join(
00135        SetCookie     *cp,
00136        BerVarray     lset,
00137        unsigned      op_flags,
00138        BerVarray     rset )
00139 {
00140        BerVarray     set;
00141        long          i, j, last, rlast;
00142        unsigned      op = ( op_flags & SLAP_SET_OPMASK );
00143 
00144        set = NULL;
00145        switch ( op ) {
00146        case '|':     /* union */
00147               if ( lset == NULL || BER_BVISNULL( &lset[ 0 ] ) ) {
00148                      if ( rset == NULL ) {
00149                             if ( lset == NULL ) {
00150                                    set = cp->set_op->o_tmpcalloc( 1,
00151                                                  sizeof( struct berval ),
00152                                                  cp->set_op->o_tmpmemctx );
00153                                    BER_BVZERO( &set[ 0 ] );
00154                                    goto done2;
00155                             }
00156                             set = set_dup( cp, lset, SLAP_SET_LREF2REF( op_flags ) );
00157                             goto done2;
00158                      }
00159                      slap_set_dispose( cp, lset, SLAP_SET_LREF2REF( op_flags ) );
00160                      set = set_dup( cp, rset, SLAP_SET_RREF2REF( op_flags ) );
00161                      goto done2;
00162               }
00163               if ( rset == NULL || BER_BVISNULL( &rset[ 0 ] ) ) {
00164                      slap_set_dispose( cp, rset, SLAP_SET_RREF2REF( op_flags ) );
00165                      set = set_dup( cp, lset, SLAP_SET_LREF2REF( op_flags ) );
00166                      goto done2;
00167               }
00168 
00169               /* worst scenario: no duplicates */
00170               rlast = slap_set_size( rset );
00171               i = slap_set_size( lset ) + rlast + 1;
00172               set = cp->set_op->o_tmpcalloc( i, sizeof( struct berval ), cp->set_op->o_tmpmemctx );
00173               if ( set != NULL ) {
00174                      /* set_chase() depends on this routine to
00175                       * keep the first elements of the result
00176                       * set the same (and in the same order)
00177                       * as the left-set.
00178                       */
00179                      for ( i = 0; !BER_BVISNULL( &lset[ i ] ); i++ ) {
00180                             if ( op_flags & SLAP_SET_LREFVAL ) {
00181                                    ber_dupbv_x( &set[ i ], &lset[ i ], cp->set_op->o_tmpmemctx );
00182 
00183                             } else {
00184                                    set[ i ] = lset[ i ];
00185                             }
00186                      }
00187 
00188                      /* pointers to values have been used in set - don't free twice */
00189                      op_flags |= SLAP_SET_LREFVAL;
00190 
00191                      last = i;
00192 
00193                      for ( i = 0; !BER_BVISNULL( &rset[ i ] ); i++ ) {
00194                             int    exists = 0;
00195 
00196                             for ( j = 0; !BER_BVISNULL( &set[ j ] ); j++ ) {
00197                                    if ( bvmatch( &rset[ i ], &set[ j ] ) )
00198                                    {
00199                                           if ( !( op_flags & SLAP_SET_RREFVAL ) ) {
00200                                                  cp->set_op->o_tmpfree( rset[ i ].bv_val, cp->set_op->o_tmpmemctx );
00201                                                  rset[ i ] = rset[ --rlast ];
00202                                                  BER_BVZERO( &rset[ rlast ] );
00203                                                  i--;
00204                                           }
00205                                           exists = 1;
00206                                           break;
00207                                    }
00208                             }
00209 
00210                             if ( !exists ) {
00211                                    if ( op_flags & SLAP_SET_RREFVAL ) {
00212                                           ber_dupbv_x( &set[ last ], &rset[ i ], cp->set_op->o_tmpmemctx );
00213 
00214                                    } else {
00215                                           set[ last ] = rset[ i ];
00216                                    }
00217                                    last++;
00218                             }
00219                      }
00220 
00221                      /* pointers to values have been used in set - don't free twice */
00222                      op_flags |= SLAP_SET_RREFVAL;
00223 
00224                      BER_BVZERO( &set[ last ] );
00225               }
00226               break;
00227 
00228        case '&':     /* intersection */
00229               if ( lset == NULL || BER_BVISNULL( &lset[ 0 ] )
00230                      || rset == NULL || BER_BVISNULL( &rset[ 0 ] ) )
00231               {
00232                      set = cp->set_op->o_tmpcalloc( 1, sizeof( struct berval ),
00233                                    cp->set_op->o_tmpmemctx );
00234                      BER_BVZERO( &set[ 0 ] );
00235                      break;
00236 
00237               } else {
00238                      long llen, rlen;
00239                      BerVarray sset;
00240 
00241                      llen = slap_set_size( lset );
00242                      rlen = slap_set_size( rset );
00243 
00244                      /* dup the shortest */
00245                      if ( llen < rlen ) {
00246                             last = llen;
00247                             set = set_dup( cp, lset, SLAP_SET_LREF2REF( op_flags ) );
00248                             lset = NULL;
00249                             sset = rset;
00250 
00251                      } else {
00252                             last = rlen;
00253                             set = set_dup( cp, rset, SLAP_SET_RREF2REF( op_flags ) );
00254                             rset = NULL;
00255                             sset = lset;
00256                      }
00257 
00258                      if ( set == NULL ) {
00259                             break;
00260                      }
00261 
00262                      for ( i = 0; !BER_BVISNULL( &set[ i ] ); i++ ) {
00263                             for ( j = 0; !BER_BVISNULL( &sset[ j ] ); j++ ) {
00264                                    if ( bvmatch( &set[ i ], &sset[ j ] ) ) {
00265                                           break;
00266                                    }
00267                             }
00268 
00269                             if ( BER_BVISNULL( &sset[ j ] ) ) {
00270                                    cp->set_op->o_tmpfree( set[ i ].bv_val, cp->set_op->o_tmpmemctx );
00271                                    set[ i ] = set[ --last ];
00272                                    BER_BVZERO( &set[ last ] );
00273                                    i--;
00274                             }
00275                      }
00276               }
00277               break;
00278 
00279        case '+':     /* string concatenation */
00280               i = slap_set_size( rset );
00281               j = slap_set_size( lset );
00282 
00283               /* handle empty set cases */
00284               if ( i == 0 || j == 0 ) {
00285                      set = cp->set_op->o_tmpcalloc( 1, sizeof( struct berval ),
00286                                    cp->set_op->o_tmpmemctx );
00287                      if ( set == NULL ) {
00288                             break;
00289                      }
00290                      BER_BVZERO( &set[ 0 ] );
00291                      break;
00292               }
00293 
00294               set = cp->set_op->o_tmpcalloc( i * j + 1, sizeof( struct berval ),
00295                             cp->set_op->o_tmpmemctx );
00296               if ( set == NULL ) {
00297                      break;
00298               }
00299 
00300               for ( last = 0, i = 0; !BER_BVISNULL( &lset[ i ] ); i++ ) {
00301                      for ( j = 0; !BER_BVISNULL( &rset[ j ] ); j++ ) {
00302                             struct berval bv;
00303                             long          k;
00304 
00305                             /* don't concatenate with the empty string */
00306                             if ( BER_BVISEMPTY( &lset[ i ] ) ) {
00307                                    ber_dupbv_x( &bv, &rset[ j ], cp->set_op->o_tmpmemctx );
00308                                    if ( bv.bv_val == NULL ) {
00309                                           ber_bvarray_free_x( set, cp->set_op->o_tmpmemctx );
00310                                           set = NULL;
00311                                           goto done;
00312                                    }
00313 
00314                             } else if ( BER_BVISEMPTY( &rset[ j ] ) ) {
00315                                    ber_dupbv_x( &bv, &lset[ i ], cp->set_op->o_tmpmemctx );
00316                                    if ( bv.bv_val == NULL ) {
00317                                           ber_bvarray_free_x( set, cp->set_op->o_tmpmemctx );
00318                                           set = NULL;
00319                                           goto done;
00320                                    }
00321 
00322                             } else {
00323                                    bv.bv_len = lset[ i ].bv_len + rset[ j ].bv_len;
00324                                    bv.bv_val = cp->set_op->o_tmpalloc( bv.bv_len + 1,
00325                                                  cp->set_op->o_tmpmemctx );
00326                                    if ( bv.bv_val == NULL ) {
00327                                           ber_bvarray_free_x( set, cp->set_op->o_tmpmemctx );
00328                                           set = NULL;
00329                                           goto done;
00330                                    }
00331                                    AC_MEMCPY( bv.bv_val, lset[ i ].bv_val, lset[ i ].bv_len );
00332                                    AC_MEMCPY( &bv.bv_val[ lset[ i ].bv_len ], rset[ j ].bv_val, rset[ j ].bv_len );
00333                                    bv.bv_val[ bv.bv_len ] = '\0';
00334                             }
00335 
00336                             for ( k = 0; k < last; k++ ) {
00337                                    if ( bvmatch( &set[ k ], &bv ) ) {
00338                                           cp->set_op->o_tmpfree( bv.bv_val, cp->set_op->o_tmpmemctx );
00339                                           break;
00340                                    }
00341                             }
00342 
00343                             if ( k == last ) {
00344                                    set[ last++ ] = bv;
00345                             }
00346                      }
00347               }
00348               BER_BVZERO( &set[ last ] );
00349               break;
00350 
00351        default:
00352               break;
00353        }
00354 
00355 done:;
00356        if ( lset ) slap_set_dispose( cp, lset, SLAP_SET_LREF2REF( op_flags ) );
00357        if ( rset ) slap_set_dispose( cp, rset, SLAP_SET_RREF2REF( op_flags ) );
00358 
00359 done2:;
00360        if ( LogTest( LDAP_DEBUG_ACL ) ) {
00361               if ( BER_BVISNULL( set ) ) {
00362                      Debug( LDAP_DEBUG_ACL, "  ACL set: empty\n", 0, 0, 0 );
00363 
00364               } else {
00365                      for ( i = 0; !BER_BVISNULL( &set[ i ] ); i++ ) {
00366                             Debug( LDAP_DEBUG_ACL, "  ACL set[%ld]=%s\n", i, set[i].bv_val, 0 );
00367                      }
00368               }
00369        }
00370 
00371        return set;
00372 }
00373 
00374 static BerVarray
00375 set_chase( SLAP_SET_GATHER gatherer,
00376        SetCookie *cp, BerVarray set, AttributeDescription *desc, int closure )
00377 {
00378        BerVarray     vals, nset;
00379        int           i;
00380 
00381        if ( set == NULL ) {
00382               set = cp->set_op->o_tmpcalloc( 1, sizeof( struct berval ),
00383                             cp->set_op->o_tmpmemctx );
00384               if ( set != NULL ) {
00385                      BER_BVZERO( &set[ 0 ] );
00386               }
00387               return set;
00388        }
00389 
00390        if ( BER_BVISNULL( set ) ) {
00391               return set;
00392        }
00393 
00394        nset = cp->set_op->o_tmpcalloc( 1, sizeof( struct berval ), cp->set_op->o_tmpmemctx );
00395        if ( nset == NULL ) {
00396               ber_bvarray_free_x( set, cp->set_op->o_tmpmemctx );
00397               return NULL;
00398        }
00399        for ( i = 0; !BER_BVISNULL( &set[ i ] ); i++ ) {
00400               vals = gatherer( cp, &set[ i ], desc );
00401               if ( vals != NULL ) {
00402                      nset = slap_set_join( cp, nset, '|', vals );
00403               }
00404        }
00405        ber_bvarray_free_x( set, cp->set_op->o_tmpmemctx );
00406 
00407        if ( closure ) {
00408               for ( i = 0; !BER_BVISNULL( &nset[ i ] ); i++ ) {
00409                      vals = gatherer( cp, &nset[ i ], desc );
00410                      if ( vals != NULL ) {
00411                             nset = slap_set_join( cp, nset, '|', vals );
00412                             if ( nset == NULL ) {
00413                                    break;
00414                             }
00415                      }
00416               }
00417        }
00418 
00419        return nset;
00420 }
00421 
00422 
00423 static BerVarray
00424 set_parents( SetCookie *cp, BerVarray set )
00425 {
00426        int           i, j, last;
00427        struct berval bv, pbv;
00428        BerVarray     nset, vals;
00429 
00430        if ( set == NULL ) {
00431               set = cp->set_op->o_tmpcalloc( 1, sizeof( struct berval ),
00432                             cp->set_op->o_tmpmemctx );
00433               if ( set != NULL ) {
00434                      BER_BVZERO( &set[ 0 ] );
00435               }
00436               return set;
00437        }
00438 
00439        if ( BER_BVISNULL( &set[ 0 ] ) ) {
00440               return set;
00441        }
00442 
00443        nset = cp->set_op->o_tmpcalloc( 1, sizeof( struct berval ), cp->set_op->o_tmpmemctx );
00444        if ( nset == NULL ) {
00445               ber_bvarray_free_x( set, cp->set_op->o_tmpmemctx );
00446               return NULL;
00447        }
00448 
00449        BER_BVZERO( &nset[ 0 ] );
00450 
00451        for ( i = 0; !BER_BVISNULL( &set[ i ] ); i++ ) {
00452               int    level = 1;
00453 
00454               pbv = bv = set[ i ];
00455               for ( ; !BER_BVISEMPTY( &pbv ); dnParent( &bv, &pbv ) ) {
00456                      level++;
00457                      bv = pbv;
00458               }
00459 
00460               vals = cp->set_op->o_tmpcalloc( level + 1, sizeof( struct berval ), cp->set_op->o_tmpmemctx );
00461               if ( vals == NULL ) {
00462                      ber_bvarray_free_x( set, cp->set_op->o_tmpmemctx );
00463                      ber_bvarray_free_x( nset, cp->set_op->o_tmpmemctx );
00464                      return NULL;
00465               }
00466               BER_BVZERO( &vals[ 0 ] );
00467               last = 0;
00468 
00469               bv = set[ i ];
00470               for ( j = 0 ; j < level ; j++ ) {
00471                      ber_dupbv_x( &vals[ last ], &bv, cp->set_op->o_tmpmemctx );
00472                      last++;
00473                      dnParent( &bv, &bv );
00474               }
00475               BER_BVZERO( &vals[ last ] );
00476 
00477               nset = slap_set_join( cp, nset, '|', vals );
00478        }
00479 
00480        ber_bvarray_free_x( set, cp->set_op->o_tmpmemctx );
00481 
00482        return nset;
00483 }
00484 
00485 
00486 
00487 static BerVarray
00488 set_parent( SetCookie *cp, BerVarray set, int level )
00489 {
00490        int           i, j, last;
00491        struct berval bv;
00492        BerVarray     nset;
00493 
00494        if ( set == NULL ) {
00495               set = cp->set_op->o_tmpcalloc( 1, sizeof( struct berval ),
00496                             cp->set_op->o_tmpmemctx );
00497               if ( set != NULL ) {
00498                      BER_BVZERO( &set[ 0 ] );
00499               }
00500               return set;
00501        }
00502 
00503        if ( BER_BVISNULL( &set[ 0 ] ) ) {
00504               return set;
00505        }
00506 
00507        nset = cp->set_op->o_tmpcalloc( slap_set_size( set ) + 1, sizeof( struct berval ), cp->set_op->o_tmpmemctx );
00508        if ( nset == NULL ) {
00509               ber_bvarray_free_x( set, cp->set_op->o_tmpmemctx );
00510               return NULL;
00511        }
00512 
00513        BER_BVZERO( &nset[ 0 ] );
00514        last = 0;
00515 
00516        for ( i = 0; !BER_BVISNULL( &set[ i ] ); i++ ) {
00517               bv = set[ i ];
00518 
00519               for ( j = 0 ; j < level ; j++ ) {
00520                      dnParent( &bv, &bv );
00521               }
00522 
00523               for ( j = 0; !BER_BVISNULL( &nset[ j ] ); j++ ) {
00524                      if ( bvmatch( &bv, &nset[ j ] ) )
00525                      {
00526                             break;        
00527                      }      
00528               }
00529 
00530               if ( BER_BVISNULL( &nset[ j ] ) ) {
00531                      ber_dupbv_x( &nset[ last ], &bv, cp->set_op->o_tmpmemctx );
00532                      last++;
00533               }
00534        }
00535 
00536        BER_BVZERO( &nset[ last ] );
00537 
00538        ber_bvarray_free_x( set, cp->set_op->o_tmpmemctx );
00539 
00540        return nset;
00541 }
00542 
00543 int
00544 slap_set_filter( SLAP_SET_GATHER gatherer,
00545        SetCookie *cp, struct berval *fbv,
00546        struct berval *user, struct berval *target, BerVarray *results )
00547 {
00548 #define STACK_SIZE   64
00549 #define IS_SET(x)    ( (unsigned long)(x) >= 256 )
00550 #define IS_OP(x)     ( (unsigned long)(x) < 256 )
00551 #define SF_ERROR(x)  do { rc = -1; goto _error; } while ( 0 )
00552 #define SF_TOP()     ( (BerVarray)( ( stp < 0 ) ? 0 : stack[ stp ] ) )
00553 #define SF_POP()     ( (BerVarray)( ( stp < 0 ) ? 0 : stack[ stp-- ] ) )
00554 #define SF_PUSH(x)   do { \
00555               if ( stp >= ( STACK_SIZE - 1 ) ) SF_ERROR( overflow ); \
00556               stack[ ++stp ] = (BerVarray)(long)(x); \
00557        } while ( 0 )
00558 
00559        BerVarray     set, lset;
00560        BerVarray     stack[ STACK_SIZE ] = { 0 };
00561        int           len, rc, stp;
00562        unsigned long op;
00563        char          c, *filter = fbv->bv_val;
00564 
00565        if ( results ) {
00566               *results = NULL;
00567        }
00568 
00569        stp = -1;
00570        while ( ( c = *filter++ ) ) {
00571               set = NULL;
00572               switch ( c ) {
00573               case ' ':
00574               case '\t':
00575               case '\x0A':
00576               case '\x0D':
00577                      break;
00578 
00579               case '(' /* ) */ :
00580                      if ( IS_SET( SF_TOP() ) ) {
00581                             SF_ERROR( syntax );
00582                      }
00583                      SF_PUSH( c );
00584                      break;
00585 
00586               case /* ( */ ')':
00587                      set = SF_POP();
00588                      if ( IS_OP( set ) ) {
00589                             SF_ERROR( syntax );
00590                      }
00591                      if ( SF_TOP() == (void *)'(' /* ) */ ) {
00592                             SF_POP();
00593                             SF_PUSH( set );
00594                             set = NULL;
00595 
00596                      } else if ( IS_OP( SF_TOP() ) ) {
00597                             op = (unsigned long)SF_POP();
00598                             lset = SF_POP();
00599                             SF_POP();
00600                             set = slap_set_join( cp, lset, op, set );
00601                             if ( set == NULL ) {
00602                                    SF_ERROR( memory );
00603                             }
00604                             SF_PUSH( set );
00605                             set = NULL;
00606 
00607                      } else {
00608                             SF_ERROR( syntax );
00609                      }
00610                      break;
00611 
00612               case '|':     /* union */
00613               case '&':     /* intersection */
00614               case '+':     /* string concatenation */
00615                      set = SF_POP();
00616                      if ( IS_OP( set ) ) {
00617                             SF_ERROR( syntax );
00618                      }
00619                      if ( SF_TOP() == 0 || SF_TOP() == (void *)'(' /* ) */ ) {
00620                             SF_PUSH( set );
00621                             set = NULL;
00622 
00623                      } else if ( IS_OP( SF_TOP() ) ) {
00624                             op = (unsigned long)SF_POP();
00625                             lset = SF_POP();
00626                             set = slap_set_join( cp, lset, op, set );
00627                             if ( set == NULL ) {
00628                                    SF_ERROR( memory );
00629                             }
00630                             SF_PUSH( set );
00631                             set = NULL;
00632                             
00633                      } else {
00634                             SF_ERROR( syntax );
00635                      }
00636                      SF_PUSH( c );
00637                      break;
00638 
00639               case '[' /* ] */:
00640                      if ( ( SF_TOP() == (void *)'/' ) || IS_SET( SF_TOP() ) ) {
00641                             SF_ERROR( syntax );
00642                      }
00643                      for ( len = 0; ( c = *filter++ ) && ( c != /* [ */ ']' ); len++ )
00644                             ;
00645                      if ( c == 0 ) {
00646                             SF_ERROR( syntax );
00647                      }
00648                      
00649                      set = cp->set_op->o_tmpcalloc( 2, sizeof( struct berval ),
00650                                    cp->set_op->o_tmpmemctx );
00651                      if ( set == NULL ) {
00652                             SF_ERROR( memory );
00653                      }
00654                      set->bv_val = cp->set_op->o_tmpcalloc( len + 1, sizeof( char ),
00655                                    cp->set_op->o_tmpmemctx );
00656                      if ( BER_BVISNULL( set ) ) {
00657                             SF_ERROR( memory );
00658                      }
00659                      AC_MEMCPY( set->bv_val, &filter[ - len - 1 ], len );
00660                      set->bv_len = len;
00661                      SF_PUSH( set );
00662                      set = NULL;
00663                      break;
00664 
00665               case '-':
00666                      if ( ( SF_TOP() == (void *)'/' )
00667                             && ( *filter == '*' || ASCII_DIGIT( *filter ) ) )
00668                      {
00669                             SF_POP();
00670 
00671                             if ( *filter == '*' ) {
00672                                    set = set_parents( cp, SF_POP() );
00673                                    filter++;
00674 
00675                             } else {
00676                                    char *next = NULL;
00677                                    long parent = strtol( filter, &next, 10 );
00678 
00679                                    if ( next == filter ) {
00680                                           SF_ERROR( syntax );
00681                                    }
00682 
00683                                    set = SF_POP();
00684                                    if ( parent != 0 ) {
00685                                           set = set_parent( cp, set, parent );
00686                                    }
00687                                    filter = next;
00688                             }
00689 
00690                             if ( set == NULL ) {
00691                                    SF_ERROR( memory );
00692                             }
00693 
00694                             SF_PUSH( set );
00695                             set = NULL;
00696                             break;
00697                      } else {
00698                             c = *filter++;
00699                             if ( c != '>' ) {
00700                                    SF_ERROR( syntax );
00701                             }
00702                             /* fall through to next case */
00703                      }
00704 
00705               case '/':
00706                      if ( IS_OP( SF_TOP() ) ) {
00707                             SF_ERROR( syntax );
00708                      }
00709                      SF_PUSH( '/' );
00710                      break;
00711 
00712               default:
00713                      if ( !AD_LEADCHAR( c ) ) {
00714                             SF_ERROR( syntax );
00715                      }
00716                      filter--;
00717                      for ( len = 1;
00718                             ( c = filter[ len ] ) && AD_CHAR( c );
00719                             len++ )
00720                      {
00721                             /* count */
00722                             if ( c == '-' && !AD_CHAR( filter[ len + 1 ] ) ) {
00723                                    break;
00724                             }
00725                      }
00726                      if ( len == 4
00727                             && memcmp( "this", filter, len ) == 0 )
00728                      {
00729                             assert( !BER_BVISNULL( target ) );
00730                             if ( ( SF_TOP() == (void *)'/' ) || IS_SET( SF_TOP() ) ) {
00731                                    SF_ERROR( syntax );
00732                             }
00733                             set = cp->set_op->o_tmpcalloc( 2, sizeof( struct berval ),
00734                                           cp->set_op->o_tmpmemctx );
00735                             if ( set == NULL ) {
00736                                    SF_ERROR( memory );
00737                             }
00738                             ber_dupbv_x( set, target, cp->set_op->o_tmpmemctx );
00739                             if ( BER_BVISNULL( set ) ) {
00740                                    SF_ERROR( memory );
00741                             }
00742                             BER_BVZERO( &set[ 1 ] );
00743                             
00744                      } else if ( len == 4
00745                             && memcmp( "user", filter, len ) == 0 ) 
00746                      {
00747                             if ( ( SF_TOP() == (void *)'/' ) || IS_SET( SF_TOP() ) ) {
00748                                    SF_ERROR( syntax );
00749                             }
00750                             if ( BER_BVISNULL( user ) ) {
00751                                    SF_ERROR( memory );
00752                             }
00753                             set = cp->set_op->o_tmpcalloc( 2, sizeof( struct berval ),
00754                                           cp->set_op->o_tmpmemctx );
00755                             if ( set == NULL ) {
00756                                    SF_ERROR( memory );
00757                             }
00758                             ber_dupbv_x( set, user, cp->set_op->o_tmpmemctx );
00759                             BER_BVZERO( &set[ 1 ] );
00760                             
00761                      } else if ( SF_TOP() != (void *)'/' ) {
00762                             SF_ERROR( syntax );
00763 
00764                      } else {
00765                             struct berval        fb2;
00766                             AttributeDescription *ad = NULL;
00767                             const char           *text = NULL;
00768 
00769                             SF_POP();
00770                             fb2.bv_val = filter;
00771                             fb2.bv_len = len;
00772 
00773                             if ( slap_bv2ad( &fb2, &ad, &text ) != LDAP_SUCCESS ) {
00774                                    SF_ERROR( syntax );
00775                             }
00776 
00777                             /* NOTE: ad must have distinguishedName syntax
00778                              * or expand in an LDAP URI if c == '*'
00779                              */
00780                             
00781                             set = set_chase( gatherer,
00782                                    cp, SF_POP(), ad, c == '*' );
00783                             if ( set == NULL ) {
00784                                    SF_ERROR( memory );
00785                             }
00786                             if ( c == '*' ) {
00787                                    len++;
00788                             }
00789                      }
00790                      filter += len;
00791                      SF_PUSH( set );
00792                      set = NULL;
00793                      break;
00794               }
00795        }
00796 
00797        set = SF_POP();
00798        if ( IS_OP( set ) ) {
00799               SF_ERROR( syntax );
00800        }
00801        if ( SF_TOP() == 0 ) {
00802               /* FIXME: ok ? */ ;
00803 
00804        } else if ( IS_OP( SF_TOP() ) ) {
00805               op = (unsigned long)SF_POP();
00806               lset = SF_POP();
00807               set = slap_set_join( cp, lset, op, set );
00808               if ( set == NULL ) {
00809                      SF_ERROR( memory );
00810               }
00811               
00812        } else {
00813               SF_ERROR( syntax );
00814        }
00815 
00816        rc = slap_set_isempty( set ) ? 0 : 1;
00817        if ( results ) {
00818               *results = set;
00819               set = NULL;
00820        }
00821 
00822 _error:
00823        if ( IS_SET( set ) ) {
00824               ber_bvarray_free_x( set, cp->set_op->o_tmpmemctx );
00825        }
00826        while ( ( set = SF_POP() ) ) {
00827               if ( IS_SET( set ) ) {
00828                      ber_bvarray_free_x( set, cp->set_op->o_tmpmemctx );
00829               }
00830        }
00831        return rc;
00832 }