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