]> git.sur5r.net Git - openldap/blob - libraries/libldap/getfilter.c
More files that didn't get merged properly.
[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
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 "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                 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, char *prefix, 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( LDAPFiltDesc *lfdp, char *tagpat, char *value )
227 {
228     LDAPFiltList        *flp;
229         int                             rc;
230         regex_t                 re;
231
232     if ( lfdp->lfd_curvalcopy != NULL ) {
233         free( lfdp->lfd_curvalcopy );
234         free( lfdp->lfd_curvalwords );
235     }
236
237     lfdp->lfd_curval = value;
238     lfdp->lfd_curfip = NULL;
239
240         for ( flp = lfdp->lfd_filtlist; flp != NULL; flp = flp->lfl_next ) {
241                 /* compile tagpat, continue if we fail */
242                 if (regcomp(&re, tagpat, 0) != 0)
243                         continue;
244
245                 /* match tagpatern and tag, continue if we fail */
246                 rc = regexec(&re, flp->lfl_tag, 0, NULL, 0);
247                 regfree(&re);
248                 if (rc != 0)
249                         continue;
250
251                 /* compile flp->ifl_pattern, continue if we fail */
252                 if (regcomp(&re, flp->lfl_pattern, 0) != 0)
253                         continue;
254
255                 /* match ifl_pattern and lfd_curval, continue if we fail */
256                 rc = regexec(&re, lfdp->lfd_curval, 0, NULL, 0);
257                 regfree(&re);
258                 if (rc != 0)
259                         continue;
260
261                 /* we successfully compiled both patterns and matched both values */
262                 lfdp->lfd_curfip = flp->lfl_ilist;
263                 break;
264     }
265
266     if ( lfdp->lfd_curfip == NULL ) {
267         return( NULL );
268     }
269
270     if (( lfdp->lfd_curvalcopy = strdup( value )) == NULL ) {
271         return( NULL );
272     }
273
274     if ( break_into_words( lfdp->lfd_curvalcopy, flp->lfl_delims,
275                 &lfdp->lfd_curvalwords ) < 0 ) {
276         free( lfdp->lfd_curvalcopy );
277         lfdp->lfd_curvalcopy = NULL;
278         return( NULL );
279     }
280
281     return( ldap_getnextfilter( lfdp ));
282 }
283
284
285 LDAPFiltInfo *
286 ldap_getnextfilter( LDAPFiltDesc *lfdp )
287 {
288     LDAPFiltInfo        *fip;
289
290     fip = lfdp->lfd_curfip;
291
292     if ( fip == NULL ) {
293         return( NULL );
294     }
295
296     lfdp->lfd_curfip = fip->lfi_next;
297
298     ldap_build_filter( lfdp->lfd_filter, LDAP_FILT_MAXSIZ, fip->lfi_filter,
299             lfdp->lfd_filtprefix, lfdp->lfd_filtsuffix, NULL,
300             lfdp->lfd_curval, lfdp->lfd_curvalwords );
301     lfdp->lfd_retfi.lfi_filter = lfdp->lfd_filter;
302     lfdp->lfd_retfi.lfi_desc = fip->lfi_desc;
303     lfdp->lfd_retfi.lfi_scope = fip->lfi_scope;
304     lfdp->lfd_retfi.lfi_isexact = fip->lfi_isexact;
305
306     return( &lfdp->lfd_retfi );
307 }
308
309
310 void
311 ldap_build_filter( char *filtbuf, unsigned long buflen, char *pattern,
312         char *prefix, char *suffix, char *attr, char *value, char **valwords )
313 {
314         char    *p, *f;
315         size_t  slen;
316         int     i, wordcount, wordnum, endwordnum;
317         
318         if ( valwords == NULL ) {
319             wordcount = 0;
320         } else {
321             for ( wordcount = 0; valwords[ wordcount ] != NULL; ++wordcount ) {
322                 ;
323             }
324         }
325
326         f = filtbuf;
327
328         if ( prefix != NULL ) {
329             strcpy( f, prefix );
330             f += strlen( prefix );
331         }
332
333         for ( p = pattern; *p != '\0'; ++p ) {
334             if ( *p == '%' ) {
335                 ++p;
336                 if ( *p == 'v' ) {
337                     if ( isdigit( *(p+1))) {
338                         ++p;
339                         wordnum = *p - '1';
340                         if ( *(p+1) == '-' ) {
341                             ++p;
342                             if ( isdigit( *(p+1))) {
343                                 ++p;
344                                 endwordnum = *p - '1';  /* e.g., "%v2-4" */
345                                 if ( endwordnum > wordcount - 1 ) {
346                                     endwordnum = wordcount - 1;
347                                 }
348                             } else {
349                                 endwordnum = wordcount - 1;  /* e.g., "%v2-" */
350                             }
351                         } else {
352                             endwordnum = wordnum;       /* e.g., "%v2" */
353                         }
354
355                         if ( wordcount > 0 ) {
356                             for ( i = wordnum; i <= endwordnum; ++i ) {
357                                 if ( i > wordnum ) {  /* add blank btw words */
358                                     *f++ = ' ';
359                                 }
360                                 slen = strlen( valwords[ i ] );
361                                 SAFEMEMCPY( f, valwords[ i ], slen );
362                                 f += slen;
363                             }
364                         }
365                     } else if ( *(p+1) == '$' ) {
366                         ++p;
367                         if ( wordcount > 0 ) {
368                             wordnum = wordcount - 1;
369                             slen = strlen( valwords[ wordnum ] );
370                             SAFEMEMCPY( f, valwords[ wordnum ], slen );
371                             f += slen;
372                         }
373                     } else if ( value != NULL ) {
374                         slen = strlen( value );
375                         SAFEMEMCPY( f, value, slen );
376                         f += slen;
377                     }
378                 } else if ( *p == 'a' && attr != NULL ) {
379                     slen = strlen( attr );
380                     SAFEMEMCPY( f, attr, slen );
381                     f += slen;
382                 } else {
383                     *f++ = *p;
384                 }
385             } else {
386                 *f++ = *p;
387             }
388                 
389             if ( (unsigned long) (f - filtbuf) > buflen ) {
390                 /* sanity check */
391                 --f;
392                 break;
393             }
394         }
395
396         if ( suffix != NULL && (
397                 (unsigned long) ( f - filtbuf ) < buflen ) )
398         {
399             strcpy( f, suffix );
400         } else {
401             *f = '\0';
402         }
403 }
404
405
406 static int
407 break_into_words( char *str, char *delims, char ***wordsp )
408 {
409     char        *word, **words;
410     int         count;
411         
412     if (( words = (char **)calloc( 1, sizeof( char * ))) == NULL ) {
413         return( -1 );
414     }
415     count = 0;
416     words[ count ] = NULL;
417
418     word = strtok( str, delims );
419     while ( word != NULL ) {
420         if (( words = (char **)realloc( words,
421                 ( count + 2 ) * sizeof( char * ))) == NULL ) {
422             return( -1 );
423         }
424
425         words[ count ] = word;
426         words[ ++count ] = NULL;
427         word = strtok( NULL, delims );
428     }
429         
430     *wordsp = words;
431     return( count );
432 }