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