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