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