]> git.sur5r.net Git - openldap/blob - servers/slapd/sets.c
4d55924bcd0c5798dc3b5b262630fb355d127084
[openldap] / servers / slapd / sets.c
1 /* $OpenLDAP$ */
2 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
3  *
4  * Copyright 2000-2004 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 static long
28 slap_set_size( BerVarray set )
29 {
30         long    i;
31
32         i = 0;
33         if ( set != NULL ) {
34                 while ( !BER_BVISNULL( &set[ i ] ) ) {
35                         i++;
36                 }
37         }
38         return i;
39 }
40
41 static int
42 slap_set_isempty( BerVarray set )
43 {
44         if ( set == NULL ) {
45                 return 1;
46         }
47
48         if ( !BER_BVISNULL( &set[ 0 ] ) ) {
49                 return 0;
50         }
51
52         return 1;
53 }
54
55 static void
56 slap_set_dispose( SetCookie *cp, BerVarray set, unsigned flags )
57 {
58         if ( flags & SLAP_SET_REFVAL ) {
59                 if ( ! ( flags & SLAP_SET_REFARR ) ) {
60                         cp->op->o_tmpfree( set, cp->op->o_tmpmemctx );
61                 }
62
63         } else {
64                 ber_bvarray_free_x( set, cp->op->o_tmpmemctx );
65         }
66 }
67
68 static BerVarray
69 set_dup( SetCookie *cp, BerVarray set, unsigned flags )
70 {
71         BerVarray       newset = NULL;
72
73         if ( set == NULL ) {
74                 return NULL;
75         }
76
77         if ( flags & SLAP_SET_REFARR ) {
78                 int     i;
79
80                 for ( i = 0; !BER_BVISNULL( &set[ i ] ); i++ )
81                         ;
82                 newset = cp->op->o_tmpcalloc( i + 1,
83                                 sizeof(struct berval), 
84                                 cp->op->o_tmpmemctx );
85                 if ( newset == NULL ) {
86                         return NULL;
87                 }
88
89                 if ( flags & SLAP_SET_REFVAL ) {
90                         for ( i = 0; !BER_BVISNULL( &set[ i ] ); i++ ) {
91                                 ber_dupbv_x( &newset[ i ], &set[ i ],
92                                                 cp->op->o_tmpmemctx );
93                         }
94
95                 } else {
96                         AC_MEMCPY( newset, set, ( i + 1 ) * sizeof( struct berval ) );
97                 }
98                 
99         } else {
100                 newset = set;
101         }
102
103         return newset;
104 }
105
106 BerVarray
107 slap_set_join(
108         SetCookie       *cp,
109         BerVarray       lset,
110         unsigned        op_flags,
111         BerVarray       rset )
112 {
113         BerVarray       set;
114         long            i, j, last;
115         unsigned        op = ( op_flags & SLAP_SET_OPMASK );
116
117         set = NULL;
118         switch ( op ) {
119         case '|':
120                 if ( lset == NULL || BER_BVISNULL( lset ) ) {
121                         if ( rset == NULL ) {
122                                 if ( lset == NULL ) {
123                                         return cp->op->o_tmpcalloc( 1,
124                                                         sizeof(struct berval),
125                                                         cp->op->o_tmpmemctx );
126                                 }
127                                 return set_dup( cp, lset, SLAP_SET_LREF2REF( op_flags ) );
128                         }
129                         slap_set_dispose( cp, lset, SLAP_SET_LREF2REF( op_flags ) );
130                         return set_dup( cp, rset, SLAP_SET_RREF2REF( op_flags ) );
131                 }
132                 if ( rset == NULL || BER_BVISNULL( rset ) ) {
133                         slap_set_dispose( cp, rset, SLAP_SET_RREF2REF( op_flags ) );
134                         return set_dup( cp, lset, SLAP_SET_LREF2REF( op_flags ) );
135                 }
136
137                 i = slap_set_size( lset ) + slap_set_size( rset ) + 1;
138                 set = cp->op->o_tmpcalloc( i, sizeof(struct berval), cp->op->o_tmpmemctx );
139                 if ( set != NULL ) {
140                         /* set_chase() depends on this routine to
141                          * keep the first elements of the result
142                          * set the same (and in the same order)
143                          * as the left-set.
144                          */
145                         for ( i = 0; !BER_BVISNULL( &lset[ i ] ); i++ ) {
146                                 if ( op_flags & SLAP_SET_LREFVAL ) {
147                                         ber_dupbv_x( &set[ i ], &lset[ i ], cp->op->o_tmpmemctx );
148
149                                 } else {
150                                         set[ i ] = lset[ i ];
151                                 }
152                         }
153
154                         for ( i = 0; !BER_BVISNULL( &rset[ i ] ); i++ ) {
155                                 int     exists = 0;
156                                 for ( j = 0; !BER_BVISNULL( &set[ j ] ); j++ ) {
157                                         if ( dn_match( &rset[ i ], &set[ j ] ) )
158                                         {
159                                                 if ( !( op_flags & SLAP_SET_RREFVAL ) ) {
160                                                         cp->op->o_tmpfree( rset[ i ].bv_val, cp->op->o_tmpmemctx );
161                                                         BER_BVZERO( &rset[ i ] );
162                                                 }
163                                                 exists = 1;
164                                                 break;          
165                                         }       
166                                 }
167
168                                 if ( !exists ) {
169                                         if ( op_flags & SLAP_SET_RREFVAL ) {
170                                                 ber_dupbv_x( &set[ j ], &rset[ i ], cp->op->o_tmpmemctx );
171
172                                         } else {
173                                                 set[ j ] = rset[ i ];
174                                         }
175                                 }
176                         }
177                 }
178                 break;
179
180         case '&':
181                 if ( lset == NULL || BER_BVISNULL( lset )
182                                 || rset == NULL || BER_BVISNULL( rset ) )
183                 {
184                         set = cp->op->o_tmpcalloc( 1, sizeof(struct berval),
185                                         cp->op->o_tmpmemctx );
186
187                 } else {
188                         set = set_dup( cp, lset, SLAP_SET_LREF2REF( op_flags ) );
189                         if ( set == NULL ) {
190                                 break;
191                         }
192                         lset = NULL;
193                         last = slap_set_size( set ) - 1;
194                         for ( i = 0; !BER_BVISNULL( &set[ i ] ); i++ ) {
195                                 for ( j = 0; !BER_BVISNULL( &rset[ j ] ); j++ ) {
196                                         if ( dn_match( &set[ i ], &rset[ j ] ) ) {
197                                                 break;
198                                         }
199                                 }
200
201                                 if ( BER_BVISNULL( &rset[ j ] ) ) {
202                                         cp->op->o_tmpfree( set[ i ].bv_val, cp->op->o_tmpmemctx );
203                                         set[ i ] = set[ last ];
204                                         BER_BVZERO( &set[ last ] );
205                                         last--;
206                                         i--;
207                                 }
208                         }
209                 }
210                 break;
211
212         default:
213                 break;
214         }
215
216         if ( !( op_flags & SLAP_SET_LREFARR ) && lset != NULL ) {
217                 cp->op->o_tmpfree( lset, cp->op->o_tmpmemctx );
218         }
219
220         if ( !( op_flags & SLAP_SET_RREFARR ) && rset != NULL ) {
221                 cp->op->o_tmpfree( rset, cp->op->o_tmpmemctx );
222         }
223
224         return set;
225 }
226
227 static BerVarray
228 set_chase( SLAP_SET_GATHER gatherer,
229         SetCookie *cp, BerVarray set, AttributeDescription *desc, int closure )
230 {
231         BerVarray       vals, nset;
232         int             i;
233
234         if ( set == NULL )
235                 return cp->op->o_tmpcalloc( 1, sizeof(struct berval),
236                                 cp->op->o_tmpmemctx );
237
238         if ( BER_BVISNULL( set ) )
239                 return set;
240
241         nset = cp->op->o_tmpcalloc( 1, sizeof(struct berval), cp->op->o_tmpmemctx );
242         if ( nset == NULL ) {
243                 slap_set_dispose( cp, set, 0 );
244                 return NULL;
245         }
246         for ( i = 0; !BER_BVISNULL( &set[ i ] ); i++ ) {
247                 vals = (gatherer)( cp, &set[ i ], desc );
248                 if ( vals != NULL ) {
249                         nset = slap_set_join( cp, nset, '|', vals );
250                 }
251         }
252         slap_set_dispose( cp, set, 0 );
253
254         if ( closure ) {
255                 for ( i = 0; !BER_BVISNULL( &nset[ i ] ); i++ ) {
256                         vals = (gatherer)( cp, &nset[ i ], desc );
257                         if ( vals != NULL ) {
258                                 nset = slap_set_join( cp, nset, '|', vals );
259                                 if ( nset == NULL ) {
260                                         break;
261                                 }
262                         }
263                 }
264         }
265
266         return nset;
267 }
268
269 int
270 slap_set_filter( SLAP_SET_GATHER gatherer,
271         SetCookie *cp, struct berval *fbv,
272         struct berval *user, struct berval *target, BerVarray *results )
273 {
274 #define IS_SET(x)       ( (unsigned long)(x) >= 256 )
275 #define IS_OP(x)        ( (unsigned long)(x) < 256 )
276 #define SF_ERROR(x)     do { rc = -1; goto _error; } while (0)
277 #define SF_TOP()        ( (BerVarray)( (stp < 0) ? 0 : stack[ stp ] ) )
278 #define SF_POP()        ( (BerVarray)( (stp < 0) ? 0 : stack[ stp-- ] ) )
279 #define SF_PUSH(x)      do { \
280                 if (stp >= 63) SF_ERROR(overflow); \
281                 stack[ ++stp ] = (BerVarray)(long)(x); \
282         } while (0)
283
284         BerVarray       set, lset;
285         BerVarray       stack[64] = { 0 };
286         int             len, rc, stp;
287         unsigned        op;
288         char            c, *filter = fbv->bv_val;
289
290         if ( results ) {
291                 *results = NULL;
292         }
293
294         stp = -1;
295         while ( ( c = *filter++ ) ) {
296                 set = NULL;
297                 switch ( c ) {
298                 case ' ':
299                 case '\t':
300                 case '\x0A':
301                 case '\x0D':
302                         break;
303
304                 case '(' /* ) */ :
305                         if ( IS_SET( SF_TOP() ) ) {
306                                 SF_ERROR( syntax );
307                         }
308                         SF_PUSH( c );
309                         break;
310
311                 case /* ( */ ')':
312                         set = SF_POP();
313                         if ( IS_OP( set ) ) {
314                                 SF_ERROR( syntax );
315                         }
316                         if ( SF_TOP() == (void *)'(' /* ) */ ) {
317                                 SF_POP();
318                                 SF_PUSH( set );
319                                 set = NULL;
320
321                         } else if ( IS_OP( SF_TOP() ) ) {
322                                 op = (unsigned)SF_POP();
323                                 lset = SF_POP();
324                                 SF_POP();
325                                 set = slap_set_join( cp, lset, op, set );
326                                 if ( set == NULL ) {
327                                         SF_ERROR(memory);
328                                 }
329                                 SF_PUSH( set );
330                                 set = NULL;
331
332                         } else {
333                                 SF_ERROR( syntax );
334                         }
335                         break;
336
337                 case '&':
338                 case '|':
339                         set = SF_POP();
340                         if ( IS_OP( set ) ) {
341                                 SF_ERROR( syntax );
342                         }
343                         if ( SF_TOP() == 0 || SF_TOP() == (void *)'(' /* ) */ ) {
344                                 SF_PUSH( set );
345                                 set = NULL;
346
347                         } else if ( IS_OP( SF_TOP() ) ) {
348                                 op = (unsigned)SF_POP();
349                                 lset = SF_POP();
350                                 set = slap_set_join( cp, lset, op, set );
351                                 if ( set == NULL ) {
352                                         SF_ERROR( memory );
353                                 }
354                                 SF_PUSH( set );
355                                 set = NULL;
356                                 
357                         } else {
358                                 SF_ERROR( syntax );
359                         }
360                         SF_PUSH( c );
361                         break;
362
363                 case '[' /* ] */:
364                         if ( ( SF_TOP() == (void *)'/' ) || IS_SET( SF_TOP() ) ) {
365                                 SF_ERROR( syntax );
366                         }
367                         for ( len = 0; ( c = *filter++ ) && (c != /* [ */ ']'); len++ )
368                                 ;
369                         if ( c == 0 ) {
370                                 SF_ERROR(syntax);
371                         }
372                         
373                         set = cp->op->o_tmpcalloc( 2, sizeof(struct berval),
374                                         cp->op->o_tmpmemctx );
375                         if ( set == NULL ) {
376                                 SF_ERROR(memory);
377                         }
378                         set->bv_val = cp->op->o_tmpcalloc( len + 1, sizeof(char),
379                                         cp->op->o_tmpmemctx );
380                         if ( BER_BVISNULL( set ) ) {
381                                 SF_ERROR( memory );
382                         }
383                         AC_MEMCPY( set->bv_val, &filter[ - len - 1 ], len );
384                         set->bv_len = len;
385                         SF_PUSH( set );
386                         set = NULL;
387                         break;
388
389                 case '-':
390                         c = *filter++;
391                         if ( c != '>' ) {
392                                 SF_ERROR( syntax );
393                         }
394                         /* fall through to next case */
395
396                 case '/':
397                         if ( IS_OP( SF_TOP() ) ) {
398                                 SF_ERROR( syntax );
399                         }
400                         SF_PUSH( '/' );
401                         break;
402
403                 default:
404                         if ( ( c != '_' )
405                                         && ( c < 'A' || c > 'Z' )
406                                         && ( c < 'a' || c > 'z' ) )
407                         {
408                                 SF_ERROR( syntax );
409                         }
410                         filter--;
411                         for ( len = 1;
412                                         ( c = filter[ len ] )
413                                                 && ( ( c >= '0' && c <= '9' )
414                                                         || ( c >= 'A' && c <= 'Z' )
415                                                         || ( c >= 'a' && c <= 'z' ) );
416                                         len++ )
417                                 /* count */ ;
418                         if ( len == 4
419                                 && memcmp( "this", filter, len ) == 0 )
420                         {
421                                 if ( ( SF_TOP() == (void *)'/' ) || IS_SET( SF_TOP() ) ) {
422                                         SF_ERROR( syntax );
423                                 }
424                                 set = cp->op->o_tmpcalloc( 2, sizeof(struct berval),
425                                                 cp->op->o_tmpmemctx );
426                                 if ( set == NULL ) {
427                                         SF_ERROR( memory );
428                                 }
429                                 ber_dupbv_x( set, target, cp->op->o_tmpmemctx );
430                                 if ( BER_BVISNULL( set ) ) {
431                                         SF_ERROR( memory );
432                                 }
433                                 
434                         } else if ( len == 4
435                                 && memcmp( "user", filter, len ) == 0 ) 
436                         {
437                                 if ( ( SF_TOP() == (void *)'/' ) || IS_SET( SF_TOP() ) ) {
438                                         SF_ERROR( syntax );
439                                 }
440                                 set = cp->op->o_tmpcalloc( 2, sizeof(struct berval),
441                                                 cp->op->o_tmpmemctx );
442                                 if ( set == NULL ) {
443                                         SF_ERROR( memory );
444                                 }
445                                 ber_dupbv_x( set, user, cp->op->o_tmpmemctx );
446                                 if ( BER_BVISNULL( set ) ) {
447                                         SF_ERROR( memory );
448                                 }
449                                 
450                         } else if ( SF_TOP() != (void *)'/' ) {
451                                 SF_ERROR( syntax );
452
453                         } else {
454                                 struct berval           fb2;
455                                 AttributeDescription    *ad = NULL;
456                                 const char              *text = NULL;
457
458                                 SF_POP();
459                                 fb2.bv_val = filter;
460                                 fb2.bv_len = len;
461
462                                 if ( slap_bv2ad( &fb2, &ad, &text ) != LDAP_SUCCESS ) {
463                                         SF_ERROR( syntax );
464                                 }
465
466                                 /* NOTE: ad must have distinguishedName syntax
467                                  * or expand in an LDAP URI if c == '*'
468                                  */
469                                 
470                                 set = set_chase( gatherer,
471                                         cp, SF_POP(), ad, c == '*' );
472                                 if ( set == NULL ) {
473                                         SF_ERROR( memory );
474                                 }
475                                 if ( c == '*' ) {
476                                         len++;
477                                 }
478                         }
479                         filter += len;
480                         SF_PUSH( set );
481                         set = NULL;
482                         break;
483                 }
484         }
485
486         set = SF_POP();
487         if ( IS_OP( set ) ) {
488                 SF_ERROR( syntax );
489         }
490         if ( SF_TOP() == 0 ) {
491                 /* FIXME: ok ? */ ;
492
493         } else if ( IS_OP( SF_TOP() ) ) {
494                 op = (unsigned)SF_POP();
495                 lset = SF_POP();
496                 set = slap_set_join( cp, lset, op, set );
497                 if ( set == NULL ) {
498                         SF_ERROR( memory );
499                 }
500                 
501         } else {
502                 SF_ERROR( syntax );
503         }
504
505         rc = slap_set_isempty( set ) ? 0 : 1;
506         if ( results ) {
507                 *results = set;
508                 set = NULL;
509         }
510
511 _error:
512         if ( IS_SET( set ) ) {
513                 slap_set_dispose( cp, set, 0 );
514         }
515         while ( ( set = SF_POP() ) ) {
516                 if ( IS_SET( set ) ) {
517                         slap_set_dispose( cp, set, 0 );
518                 }
519         }
520         return rc;
521 }