]> git.sur5r.net Git - openldap/blob - libraries/libldap/getfilter.c
VC++ Port: round 1
[openldap] / libraries / libldap / getfilter.c
1 /*
2  *  Copyright (c) 1993 Regents of the University of Michigan.
3  *  All rights reserved.
4  *
5  *  getfilter.c -- optional add-on to libldap
6  */
7
8 #include "portable.h"
9
10 #ifndef lint 
11 static char copyright[] = "@(#) Copyright (c) 1993 Regents of the University of Michigan.\nAll rights reserved.\n";
12 #endif
13
14 #include <stdio.h>
15 #include <stdlib.h>
16 #include <ctype.h>
17
18 #include <ac/errno.h>
19 #include <ac/regex.h>
20 #include <ac/string.h>
21 #include <ac/unistd.h>
22
23 #include <sys/types.h>
24 #ifdef HAVE_SYS_FILE_H
25 #include <sys/file.h>
26 #endif
27
28 #include "lber.h"
29 #include "ldap.h"
30
31 static int break_into_words LDAP_P(( char *str, char *delims, char ***wordsp ));
32 int next_line_tokens LDAP_P(( char **bufp, long *blenp, char ***toksp ));
33 void free_strarray LDAP_P(( char **sap ));
34
35 #define FILT_MAX_LINE_LEN       1024
36
37 LDAPFiltDesc *
38 ldap_init_getfilter( 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 expresssion %s, %s\n",
129                         nextflp->lfl_pattern, error );
130 #if !defined( MACOS ) && !defined( DOS )
131                 errno = EINVAL;
132 #endif
133 #endif /* LDAP_LIBUI */
134                 free_strarray( 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 *)calloc( 1,
158                         sizeof( LDAPFiltInfo ))) == NULL ) {
159                     ldap_getfilter_free( lfdp );
160                     free_strarray( 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                         free_strarray( tok );
181                         ldap_getfilter_free( lfdp );
182 #if !defined( MACOS ) && !defined( DOS )
183                         errno = EINVAL;
184 #endif
185                         return( NULL );
186                     }
187                     free( tok[ 2 ] );
188                     tok[ 2 ] = NULL;
189                 } else {
190                     nextfip->lfi_scope = LDAP_SCOPE_SUBTREE;    /* default */
191                 }
192                 nextfip->lfi_isexact = ( strchr( tok[ 0 ], '*' ) == NULL &&
193                         strchr( tok[ 0 ], '~' ) == NULL );
194                 free( tok );
195             }
196             break;
197
198         default:
199             free_strarray( tok );
200             ldap_getfilter_free( lfdp );
201 #if !defined( MACOS ) && !defined( DOS )
202             errno = EINVAL;
203 #endif
204             return( NULL );
205         }
206     }
207
208     if ( tag != NULL ) {
209         free( tag );
210     }
211
212     return( lfdp );
213 }
214
215
216 void
217 ldap_setfilteraffixes( LDAPFiltDesc *lfdp, char *prefix, char *suffix )
218 {
219     if ( lfdp->lfd_filtprefix != NULL ) {
220         free( lfdp->lfd_filtprefix );
221     }
222     lfdp->lfd_filtprefix = ( prefix == NULL ) ? NULL : strdup( prefix );
223
224     if ( lfdp->lfd_filtsuffix != NULL ) {
225         free( lfdp->lfd_filtsuffix );
226     }
227     lfdp->lfd_filtsuffix = ( suffix == NULL ) ? NULL : strdup( suffix );
228 }
229
230
231 LDAPFiltInfo *
232 ldap_getfirstfilter( LDAPFiltDesc *lfdp, char *tagpat, char *value )
233 {
234     LDAPFiltList        *flp;
235         int                             rc;
236         regex_t                 re;
237
238     if ( lfdp->lfd_curvalcopy != NULL ) {
239         free( lfdp->lfd_curvalcopy );
240         free( lfdp->lfd_curvalwords );
241     }
242
243     lfdp->lfd_curval = value;
244     lfdp->lfd_curfip = NULL;
245
246         for ( flp = lfdp->lfd_filtlist; flp != NULL; flp = flp->lfl_next ) {
247                 /* compile tagpat, continue if we fail */
248                 if (regcomp(&re, tagpat, 0) != 0)
249                         continue;
250
251                 /* match tagpatern and tag, continue if we fail */
252                 rc = regexec(&re, flp->lfl_tag, 0, NULL, 0);
253                 regfree(&re);
254                 if (rc != 0)
255                         continue;
256
257                 /* compile flp->ifl_pattern, continue if we fail */
258                 if (regcomp(&re, flp->lfl_pattern, 0) != 0)
259                         continue;
260
261                 /* match ifl_pattern and lfd_curval, continue if we fail */
262                 rc = regexec(&re, lfdp->lfd_curval, 0, NULL, 0);
263                 regfree(&re);
264                 if (rc != 0)
265                         continue;
266
267                 /* we successfully compiled both patterns and matched both values */
268                 lfdp->lfd_curfip = flp->lfl_ilist;
269                 break;
270     }
271
272     if ( lfdp->lfd_curfip == NULL ) {
273         return( NULL );
274     }
275
276     if (( lfdp->lfd_curvalcopy = strdup( value )) == NULL ) {
277         return( NULL );
278     }
279
280     if ( break_into_words( lfdp->lfd_curvalcopy, flp->lfl_delims,
281                 &lfdp->lfd_curvalwords ) < 0 ) {
282         free( lfdp->lfd_curvalcopy );
283         lfdp->lfd_curvalcopy = NULL;
284         return( NULL );
285     }
286
287     return( ldap_getnextfilter( lfdp ));
288 }
289
290
291 LDAPFiltInfo *
292 ldap_getnextfilter( LDAPFiltDesc *lfdp )
293 {
294     LDAPFiltInfo        *fip;
295
296     fip = lfdp->lfd_curfip;
297
298     if ( fip == NULL ) {
299         return( NULL );
300     }
301
302     lfdp->lfd_curfip = fip->lfi_next;
303
304     ldap_build_filter( lfdp->lfd_filter, LDAP_FILT_MAXSIZ, fip->lfi_filter,
305             lfdp->lfd_filtprefix, lfdp->lfd_filtsuffix, NULL,
306             lfdp->lfd_curval, lfdp->lfd_curvalwords );
307     lfdp->lfd_retfi.lfi_filter = lfdp->lfd_filter;
308     lfdp->lfd_retfi.lfi_desc = fip->lfi_desc;
309     lfdp->lfd_retfi.lfi_scope = fip->lfi_scope;
310     lfdp->lfd_retfi.lfi_isexact = fip->lfi_isexact;
311
312     return( &lfdp->lfd_retfi );
313 }
314
315
316 void
317 ldap_build_filter( char *filtbuf, unsigned long buflen, char *pattern,
318         char *prefix, char *suffix, char *attr, char *value, char **valwords )
319 {
320         char    *p, *f;
321         size_t  slen;
322         int     i, wordcount, wordnum, endwordnum;
323         
324         if ( valwords == NULL ) {
325             wordcount = 0;
326         } else {
327             for ( wordcount = 0; valwords[ wordcount ] != NULL; ++wordcount ) {
328                 ;
329             }
330         }
331
332         f = filtbuf;
333
334         if ( prefix != NULL ) {
335             strcpy( f, prefix );
336             f += strlen( prefix );
337         }
338
339         for ( p = pattern; *p != '\0'; ++p ) {
340             if ( *p == '%' ) {
341                 ++p;
342                 if ( *p == 'v' ) {
343                     if ( isdigit( *(p+1))) {
344                         ++p;
345                         wordnum = *p - '1';
346                         if ( *(p+1) == '-' ) {
347                             ++p;
348                             if ( isdigit( *(p+1))) {
349                                 ++p;
350                                 endwordnum = *p - '1';  /* e.g., "%v2-4" */
351                                 if ( endwordnum > wordcount - 1 ) {
352                                     endwordnum = wordcount - 1;
353                                 }
354                             } else {
355                                 endwordnum = wordcount - 1;  /* e.g., "%v2-" */
356                             }
357                         } else {
358                             endwordnum = wordnum;       /* e.g., "%v2" */
359                         }
360
361                         if ( wordcount > 0 ) {
362                             for ( i = wordnum; i <= endwordnum; ++i ) {
363                                 if ( i > wordnum ) {  /* add blank btw words */
364                                     *f++ = ' ';
365                                 }
366                                 slen = strlen( valwords[ i ] );
367                                 SAFEMEMCPY( f, valwords[ i ], slen );
368                                 f += slen;
369                             }
370                         }
371                     } else if ( *(p+1) == '$' ) {
372                         ++p;
373                         if ( wordcount > 0 ) {
374                             wordnum = wordcount - 1;
375                             slen = strlen( valwords[ wordnum ] );
376                             SAFEMEMCPY( f, valwords[ wordnum ], slen );
377                             f += slen;
378                         }
379                     } else if ( value != NULL ) {
380                         slen = strlen( value );
381                         SAFEMEMCPY( f, value, slen );
382                         f += slen;
383                     }
384                 } else if ( *p == 'a' && attr != NULL ) {
385                     slen = strlen( attr );
386                     SAFEMEMCPY( f, attr, slen );
387                     f += slen;
388                 } else {
389                     *f++ = *p;
390                 }
391             } else {
392                 *f++ = *p;
393             }
394                 
395             if ( (unsigned long) (f - filtbuf) > buflen ) {
396                 /* sanity check */
397                 --f;
398                 break;
399             }
400         }
401
402         if ( suffix != NULL && (
403                 (unsigned long) ( f - filtbuf ) < buflen ) )
404         {
405             strcpy( f, suffix );
406         } else {
407             *f = '\0';
408         }
409 }
410
411
412 static int
413 break_into_words( char *str, char *delims, char ***wordsp )
414 {
415     char        *word, **words;
416     int         count;
417         
418     if (( words = (char **)calloc( 1, sizeof( char * ))) == NULL ) {
419         return( -1 );
420     }
421     count = 0;
422     words[ count ] = NULL;
423
424     word = strtok( str, delims );
425     while ( word != NULL ) {
426         if (( words = (char **)realloc( words,
427                 ( count + 2 ) * sizeof( char * ))) == NULL ) {
428             return( -1 );
429         }
430
431         words[ count ] = word;
432         words[ ++count ] = NULL;
433         word = strtok( NULL, delims );
434     }
435         
436     *wordsp = words;
437     return( count );
438 }