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