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