]> git.sur5r.net Git - openldap/blob - libraries/libldap/getfilter.c
ITS#1730
[openldap] / libraries / libldap / getfilter.c
1 /* $OpenLDAP$ */
2 /*
3  * Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved.
4  * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
5  */
6 /*  Portions
7  *  Copyright (c) 1993 Regents of the University of Michigan.
8  *  All rights reserved.
9  *
10  *  getfilter.c -- optional add-on to libldap
11  */
12
13 #include "portable.h"
14
15 #include <stdio.h>
16
17 #include <ac/stdlib.h>
18
19 #include <ac/errno.h>
20 #include <ac/regex.h>
21 #include <ac/string.h>
22 #include <ac/time.h>
23 #include <ac/unistd.h>
24
25 #ifdef HAVE_SYS_FILE_H
26 #include <sys/file.h>
27 #endif
28
29 #include "ldap-int.h"
30
31 static int break_into_words LDAP_P((
32         /* LDAP_CONST */ char *str,
33         LDAP_CONST char *delims,
34         char ***wordsp ));
35
36 #define FILT_MAX_LINE_LEN       1024
37
38 static LDAPFiltDesc *
39 ldap_init_getfilter_buf( char *buf, ber_len_t buflen )
40 {
41     LDAPFiltDesc        *lfdp;
42     LDAPFiltList        *flp, *nextflp;
43     LDAPFiltInfo        *fip, *nextfip;
44     char                        *tag, **tok;
45     int                         tokcnt, i;
46         int                             rc;
47         regex_t                 re;
48
49     if (( lfdp = (LDAPFiltDesc *)LDAP_CALLOC( 1, sizeof( LDAPFiltDesc))) == NULL ) {
50         return( NULL );
51     }
52
53     flp = nextflp = NULL;
54     fip = NULL;
55     tag = NULL;
56
57     while ( buflen > 0 && ( tokcnt = ldap_int_next_line_tokens( &buf, &buflen, &tok ))
58             > 0 ) {
59
60         switch( tokcnt ) {
61         case 1:         /* tag line */
62             if ( tag != NULL ) {
63                 LDAP_FREE( tag );
64             }
65             tag = tok[ 0 ];
66             LDAP_FREE( tok );
67             break;
68         case 4:
69         case 5:         /* start of filter info. list */
70             if (( nextflp = (LDAPFiltList *)LDAP_CALLOC( 1, sizeof( LDAPFiltList )))
71                     == NULL ) {
72                 ldap_getfilter_free( lfdp );
73                 return( NULL );
74             }
75             nextflp->lfl_tag = LDAP_STRDUP( tag );
76             nextflp->lfl_pattern = tok[ 0 ];
77             if ( (rc = regcomp( &re, nextflp->lfl_pattern, 0 )) != 0 ) {
78                 char error[512];
79                 regerror(rc, &re, error, sizeof(error));
80                 ldap_getfilter_free( lfdp );
81 #ifdef NEW_LOGGING
82                 LDAP_LOG (( "getfilter", LDAP_LEVEL_ERR, 
83                         "ldap_init_get_filter_buf: bad regular expression %s, %s\n",
84                         nextflp->lfl_pattern, error ));
85 #else
86                 Debug( LDAP_DEBUG_ANY, "ldap_init_get_filter_buf: "
87                         "bad regular expression %s, %s\n",
88                         nextflp->lfl_pattern, error, 0 );
89 #endif
90                 errno = EINVAL;
91                 LDAP_VFREE( tok );
92                 return( NULL );
93             }
94                 regfree(&re);
95                 
96             nextflp->lfl_delims = tok[ 1 ];
97             nextflp->lfl_ilist = NULL;
98             nextflp->lfl_next = NULL;
99             if ( flp == NULL ) {        /* first one */
100                 lfdp->lfd_filtlist = nextflp;
101             } else {
102                 flp->lfl_next = nextflp;
103             }
104             flp = nextflp;
105             fip = NULL;
106             for ( i = 2; i < 5; ++i ) {
107                 tok[ i - 2 ] = tok[ i ];
108             }
109             /* fall through */
110
111         case 2:
112         case 3:         /* filter, desc, and optional search scope */
113             if ( nextflp != NULL ) { /* add to info list */
114                 if (( nextfip = (LDAPFiltInfo *)LDAP_CALLOC( 1,
115                         sizeof( LDAPFiltInfo ))) == NULL ) {
116                     ldap_getfilter_free( lfdp );
117                     LDAP_VFREE( tok );
118                     return( NULL );
119                 }
120                 if ( fip == NULL ) {    /* first one */
121                     nextflp->lfl_ilist = nextfip;
122                 } else {
123                     fip->lfi_next = nextfip;
124                 }
125                 fip = nextfip;
126                 nextfip->lfi_next = NULL;
127                 nextfip->lfi_filter = tok[ 0 ];
128                 nextfip->lfi_desc = tok[ 1 ];
129                 if ( tok[ 2 ] != NULL ) {
130                     if ( strcasecmp( tok[ 2 ], "subtree" ) == 0 ) {
131                         nextfip->lfi_scope = LDAP_SCOPE_SUBTREE;
132                     } else if ( strcasecmp( tok[ 2 ], "onelevel" ) == 0 ) {
133                         nextfip->lfi_scope = LDAP_SCOPE_ONELEVEL;
134                     } else if ( strcasecmp( tok[ 2 ], "base" ) == 0 ) {
135                         nextfip->lfi_scope = LDAP_SCOPE_BASE;
136                     } else {
137                         LDAP_VFREE( tok );
138                         ldap_getfilter_free( lfdp );
139                         errno = EINVAL;
140                         return( NULL );
141                     }
142                     LDAP_FREE( tok[ 2 ] );
143                     tok[ 2 ] = NULL;
144                 } else {
145                     nextfip->lfi_scope = LDAP_SCOPE_SUBTREE;    /* default */
146                 }
147                 nextfip->lfi_isexact = ( strchr( tok[ 0 ], '*' ) == NULL &&
148                         strchr( tok[ 0 ], '~' ) == NULL );
149                 LDAP_FREE( tok );
150             }
151             break;
152
153         default:
154             LDAP_VFREE( tok );
155             ldap_getfilter_free( lfdp );
156             errno = EINVAL;
157             return( NULL );
158         }
159     }
160
161     if ( tag != NULL ) {
162         LDAP_FREE( tag );
163     }
164
165     return( lfdp );
166 }
167
168 LDAPFiltDesc *
169 ldap_init_getfilter( LDAP_CONST char *fname )
170 {
171     FILE                *fp;
172     char                *buf;
173     long                rlen, len;
174     int                 eof;
175     LDAPFiltDesc        *lfdp;
176
177     if (( fp = fopen( fname, "r" )) == NULL ) {
178         return( NULL );
179     }
180
181     if ( fseek( fp, 0L, SEEK_END ) != 0 ) {     /* move to end to get len */
182         fclose( fp );
183         return( NULL );
184     }
185
186     len = ftell( fp );
187
188     if ( fseek( fp, 0L, SEEK_SET ) != 0 ) {     /* back to start of file */
189         fclose( fp );
190         return( NULL );
191     }
192
193     if (( buf = LDAP_MALLOC( (size_t)len )) == NULL ) {
194         fclose( fp );
195         return( NULL );
196     }
197
198     rlen = fread( buf, 1, (size_t)len, fp );
199     eof = feof( fp );
200     fclose( fp );
201
202     if ( rlen != len && !eof ) {        /* error:  didn't get the whole file */
203         LDAP_FREE( buf );
204         return( NULL );
205     }
206
207
208     lfdp = ldap_init_getfilter_buf( buf, rlen );
209     LDAP_FREE( buf );
210
211     return( lfdp );
212 }
213
214 LDAPFiltInfo *
215 ldap_getfirstfilter(
216         LDAPFiltDesc *lfdp,
217         /* LDAP_CONST */ char *tagpat,
218         /* LDAP_CONST */ char *value )
219 {
220     LDAPFiltList        *flp;
221         int                             rc;
222         regex_t                 re;
223
224     if ( lfdp->lfd_curvalcopy != NULL ) {
225         LDAP_FREE( lfdp->lfd_curvalcopy );
226         LDAP_FREE( lfdp->lfd_curvalwords );
227     }
228
229     lfdp->lfd_curval = value;
230     lfdp->lfd_curfip = NULL;
231
232         for ( flp = lfdp->lfd_filtlist; flp != NULL; flp = flp->lfl_next ) {
233                 /* compile tagpat, continue if we fail */
234                 if (regcomp(&re, tagpat, REG_EXTENDED|REG_NOSUB) != 0)
235                         continue;
236
237                 /* match tagpattern and tag, continue if we fail */
238                 rc = regexec(&re, flp->lfl_tag, 0, NULL, 0);
239                 regfree(&re);
240                 if (rc != 0)
241                         continue;
242
243                 /* compile flp->ifl_pattern, continue if we fail */
244                 if (regcomp(&re, flp->lfl_pattern, REG_EXTENDED|REG_NOSUB) != 0)
245                         continue;
246
247                 /* match ifl_pattern and lfd_curval, continue if we fail */
248                 rc = regexec(&re, lfdp->lfd_curval, 0, NULL, 0);
249                 regfree(&re);
250                 if (rc != 0)
251                         continue;
252
253                 /* we successfully compiled both patterns and matched both values */
254                 lfdp->lfd_curfip = flp->lfl_ilist;
255                 break;
256     }
257
258     if ( lfdp->lfd_curfip == NULL ) {
259         return( NULL );
260     }
261
262     if (( lfdp->lfd_curvalcopy = LDAP_STRDUP( value )) == NULL ) {
263         return( NULL );
264     }
265
266     if ( break_into_words( lfdp->lfd_curvalcopy, flp->lfl_delims,
267                 &lfdp->lfd_curvalwords ) < 0 ) {
268         LDAP_FREE( lfdp->lfd_curvalcopy );
269         lfdp->lfd_curvalcopy = NULL;
270         return( NULL );
271     }
272
273     return( ldap_getnextfilter( lfdp ));
274 }
275
276 static void
277 ldap_build_filter(
278         char *filtbuf,
279         ber_len_t buflen,
280         LDAP_CONST char *pattern,
281         LDAP_CONST char *prefix,
282         LDAP_CONST char *suffix,
283         LDAP_CONST char *attr,
284         LDAP_CONST char *value,
285         char **valwords );
286
287 LDAPFiltInfo *
288 ldap_getnextfilter( LDAPFiltDesc *lfdp )
289 {
290     LDAPFiltInfo        *fip;
291
292     fip = lfdp->lfd_curfip;
293
294     if ( fip == NULL ) {
295         return( NULL );
296     }
297
298     lfdp->lfd_curfip = fip->lfi_next;
299
300     ldap_build_filter( lfdp->lfd_filter, LDAP_FILT_MAXSIZ, fip->lfi_filter,
301             lfdp->lfd_filtprefix, lfdp->lfd_filtsuffix, NULL,
302             lfdp->lfd_curval, lfdp->lfd_curvalwords );
303     lfdp->lfd_retfi.lfi_filter = lfdp->lfd_filter;
304     lfdp->lfd_retfi.lfi_desc = fip->lfi_desc;
305     lfdp->lfd_retfi.lfi_scope = fip->lfi_scope;
306     lfdp->lfd_retfi.lfi_isexact = fip->lfi_isexact;
307
308     return( &lfdp->lfd_retfi );
309 }
310
311 static void
312 ldap_build_filter(
313         char *filtbuf,
314         ber_len_t buflen,
315         LDAP_CONST char *pattern,
316         LDAP_CONST char *prefix,
317         LDAP_CONST char *suffix,
318         LDAP_CONST char *attr,
319         LDAP_CONST char *value,
320         char **valwords )
321 {
322         const char *p;
323         char *f;
324         size_t  slen;
325         int     i, wordcount, wordnum, endwordnum;
326         
327         if ( valwords == NULL ) {
328             wordcount = 0;
329         } else {
330             for ( wordcount = 0; valwords[ wordcount ] != NULL; ++wordcount ) {
331                 ;
332             }
333         }
334
335         f = filtbuf;
336
337         if ( prefix != NULL ) {
338             strcpy( f, prefix );
339             f += strlen( prefix );
340         }
341
342         for ( p = pattern; *p != '\0'; ++p ) {
343             if ( *p == '%' ) {
344                 ++p;
345                 if ( *p == 'v' ) {
346                     if ( LDAP_DIGIT( (unsigned char) p[1] )) {
347                         ++p;
348                         wordnum = *p - '1';
349                         if ( *(p+1) == '-' ) {
350                             ++p;
351                             if ( LDAP_DIGIT( (unsigned char) p[1] )) {
352                                 ++p;
353                                 endwordnum = *p - '1';  /* e.g., "%v2-4" */
354                                 if ( endwordnum > wordcount - 1 ) {
355                                     endwordnum = wordcount - 1;
356                                 }
357                             } else {
358                                 endwordnum = wordcount - 1;  /* e.g., "%v2-" */
359                             }
360                         } else {
361                             endwordnum = wordnum;       /* e.g., "%v2" */
362                         }
363
364                         if ( wordcount > 0 ) {
365                             for ( i = wordnum; i <= endwordnum; ++i ) {
366                                 if ( i > wordnum ) {  /* add blank btw words */
367                                     *f++ = ' ';
368                                 }
369                                 slen = strlen( valwords[ i ] );
370                                 AC_MEMCPY( f, valwords[ i ], slen );
371                                 f += slen;
372                             }
373                         }
374                     } else if ( *(p+1) == '$' ) {
375                         ++p;
376                         if ( wordcount > 0 ) {
377                             wordnum = wordcount - 1;
378                             slen = strlen( valwords[ wordnum ] );
379                             AC_MEMCPY( f, valwords[ wordnum ], slen );
380                             f += slen;
381                         }
382                     } else if ( value != NULL ) {
383                         slen = strlen( value );
384                         AC_MEMCPY( f, value, slen );
385                         f += slen;
386                     }
387                 } else if ( *p == 'a' && attr != NULL ) {
388                     slen = strlen( attr );
389                     AC_MEMCPY( f, attr, slen );
390                     f += slen;
391                 } else {
392                     *f++ = *p;
393                 }
394             } else {
395                 *f++ = *p;
396             }
397                 
398             if ( (size_t) (f - filtbuf) > buflen ) {
399                 /* sanity check */
400                 --f;
401                 break;
402             }
403         }
404
405         if ( suffix != NULL && ( (size_t) (f - filtbuf) < buflen ) )
406         {
407             strcpy( f, suffix );
408         } else {
409             *f = '\0';
410         }
411 }
412
413 static int
414 break_into_words( /* LDAP_CONST */ char *str, LDAP_CONST char *delims, char ***wordsp )
415 {
416     char        *word, **words;
417     int         count;
418     char        *tok_r; 
419
420     if (( words = (char **)LDAP_CALLOC( 1, sizeof( char * ))) == NULL ) {
421         return( -1 );
422     }
423     count = 0;
424     words[ count ] = NULL;
425
426     word = ldap_pvt_strtok( str, delims, &tok_r );
427     while ( word != NULL ) {
428         if (( words = (char **)LDAP_REALLOC( words,
429                 ( count + 2 ) * sizeof( char * ))) == NULL ) {
430             return( -1 );
431         }
432
433         words[ count ] = word;
434         words[ ++count ] = NULL;
435         word = ldap_pvt_strtok( NULL, delims, &tok_r );
436     }
437         
438     *wordsp = words;
439     return( count );
440 }