Back to index

lightning-sunbird  0.9+nobinonly
getfilter.c
Go to the documentation of this file.
00001 /* ***** BEGIN LICENSE BLOCK *****
00002  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00003  *
00004  * The contents of this file are subject to the Mozilla Public License Version
00005  * 1.1 (the "License"); you may not use this file except in compliance with
00006  * the License. You may obtain a copy of the License at
00007  * http://www.mozilla.org/MPL/
00008  *
00009  * Software distributed under the License is distributed on an "AS IS" basis,
00010  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00011  * for the specific language governing rights and limitations under the
00012  * License.
00013  *
00014  * The Original Code is Mozilla Communicator client code, released
00015  * March 31, 1998.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 1998-1999
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *
00024  * Alternatively, the contents of this file may be used under the terms of
00025  * either the GNU General Public License Version 2 or later (the "GPL"), or
00026  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00027  * in which case the provisions of the GPL or the LGPL are applicable instead
00028  * of those above. If you wish to allow use of your version of this file only
00029  * under the terms of either the GPL or the LGPL, and not to allow others to
00030  * use your version of this file under the terms of the MPL, indicate your
00031  * decision by deleting the provisions above and replace them with the notice
00032  * and other provisions required by the GPL or the LGPL. If you do not delete
00033  * the provisions above, a recipient may use your version of this file under
00034  * the terms of any one of the MPL, the GPL or the LGPL.
00035  *
00036  * ***** END LICENSE BLOCK ***** */
00037 /*
00038  *  Copyright (c) 1993 Regents of the University of Michigan.
00039  *  All rights reserved.
00040  */
00041 /*
00042  *  getfilter.c -- optional add-on to libldap
00043  */
00044 
00045 #if 0
00046 #ifndef lint 
00047 static char copyright[] = "@(#) Copyright (c) 1993 Regents of the University of Michigan.\nAll rights reserved.\n";
00048 #endif
00049 #endif
00050 
00051 #include "ldap-int.h"
00052 #include "regex.h"
00053 #include <stdio.h> /* sprintf */
00054 
00055 static int break_into_words( char *str, char *delims, char ***wordsp );
00056 int nsldapi_next_line_tokens( char **bufp, long *blenp, char ***toksp );
00057 void nsldapi_free_strarray( char **sap );
00058 
00059 #if !defined( macintosh ) && !defined( DOS )
00060 extern char   * LDAP_CALL re_comp();
00061 #endif
00062 
00063 #define FILT_MAX_LINE_LEN   1024
00064 
00065 LDAPFiltDesc *
00066 LDAP_CALL
00067 ldap_init_getfilter( char *fname )
00068 {
00069     FILE             *fp;
00070     char             *buf;
00071     long             rlen, len;
00072     int              eof;
00073     LDAPFiltDesc     *lfdp;
00074 
00075     if (( fp = fopen( fname, "r" )) == NULL ) {
00076        return( NULL );
00077     }
00078 
00079     if ( fseek( fp, 0L, SEEK_END ) != 0 ) {      /* move to end to get len */
00080        fclose( fp );
00081        return( NULL );
00082     }
00083 
00084     len = ftell( fp );
00085 
00086     if ( fseek( fp, 0L, SEEK_SET ) != 0 ) {      /* back to start of file */
00087        fclose( fp );
00088        return( NULL );
00089     }
00090 
00091     if (( buf = NSLDAPI_MALLOC( (size_t)len )) == NULL ) {
00092        fclose( fp );
00093        return( NULL );
00094     }
00095 
00096     rlen = fread( buf, 1, (size_t)len, fp );
00097     eof = feof( fp );
00098     fclose( fp );
00099 
00100     if ( rlen != len && !eof ) {   /* error:  didn't get the whole file */
00101        NSLDAPI_FREE( buf );
00102        return( NULL );
00103     }
00104 
00105 
00106     lfdp = ldap_init_getfilter_buf( buf, rlen );
00107     NSLDAPI_FREE( buf );
00108 
00109     return( lfdp );
00110 }
00111 
00112 
00113 LDAPFiltDesc *
00114 LDAP_CALL
00115 ldap_init_getfilter_buf( char *buf, long buflen )
00116 {
00117     LDAPFiltDesc     *lfdp;
00118     LDAPFiltList     *flp, *nextflp;
00119     LDAPFiltInfo     *fip, *nextfip;
00120     char             *tag, **tok;
00121     int                     tokcnt, i;
00122 
00123     if ( (buf == NULL) || (buflen < 0) ||
00124         ( lfdp = (LDAPFiltDesc *)NSLDAPI_CALLOC(1, sizeof( LDAPFiltDesc)))
00125         == NULL ) {
00126        return( NULL );
00127     }
00128 
00129     flp = nextflp = NULL;
00130     fip = NULL;
00131     tag = NULL;
00132 
00133     while ( buflen > 0 && ( tokcnt = nsldapi_next_line_tokens( &buf, &buflen,
00134            &tok )) > 0 ) {
00135        switch( tokcnt ) {
00136        case 1:              /* tag line */
00137            if ( tag != NULL ) {
00138               NSLDAPI_FREE( tag );
00139            }
00140            tag = tok[ 0 ];
00141            NSLDAPI_FREE( tok );
00142            break;
00143        case 4:
00144        case 5:              /* start of filter info. list */
00145            if (( nextflp = (LDAPFiltList *)NSLDAPI_CALLOC( 1,
00146                   sizeof( LDAPFiltList ))) == NULL ) {
00147               ldap_getfilter_free( lfdp );
00148               return( NULL );
00149            }
00150            nextflp->lfl_tag = nsldapi_strdup( tag );
00151            nextflp->lfl_pattern = tok[ 0 ];
00152            if ( re_comp( nextflp->lfl_pattern ) != NULL ) {
00153               char    msg[256];
00154               ldap_getfilter_free( lfdp );
00155               sprintf( msg, "bad regular expresssion %s\n",
00156                      nextflp->lfl_pattern );
00157               ber_err_print( msg );
00158               nsldapi_free_strarray( tok );
00159               return( NULL );
00160            }
00161               
00162            nextflp->lfl_delims = tok[ 1 ];
00163            nextflp->lfl_ilist = NULL;
00164            nextflp->lfl_next = NULL;
00165            if ( flp == NULL ) {    /* first one */
00166               lfdp->lfd_filtlist = nextflp;
00167            } else {
00168               flp->lfl_next = nextflp;
00169            }
00170            flp = nextflp;
00171            fip = NULL;
00172            for ( i = 2; i < 5; ++i ) {
00173               tok[ i - 2 ] = tok[ i ];
00174            }
00175            /* fall through */
00176 
00177        case 2:
00178        case 3:              /* filter, desc, and optional search scope */
00179            if ( nextflp != NULL ) { /* add to info list */
00180               if (( nextfip = (LDAPFiltInfo *)NSLDAPI_CALLOC( 1,
00181                      sizeof( LDAPFiltInfo ))) == NULL ) {
00182                   ldap_getfilter_free( lfdp );
00183                   nsldapi_free_strarray( tok );
00184                   return( NULL );
00185               }
00186               if ( fip == NULL ) { /* first one */
00187                   nextflp->lfl_ilist = nextfip;
00188               } else {
00189                   fip->lfi_next = nextfip;
00190               }
00191               fip = nextfip;
00192               nextfip->lfi_next = NULL;
00193               nextfip->lfi_filter = tok[ 0 ];
00194               nextfip->lfi_desc = tok[ 1 ];
00195               if ( tok[ 2 ] != NULL ) {
00196                   if ( strcasecmp( tok[ 2 ], "subtree" ) == 0 ) {
00197                      nextfip->lfi_scope = LDAP_SCOPE_SUBTREE;
00198                   } else if ( strcasecmp( tok[ 2 ], "onelevel" ) == 0 ) {
00199                      nextfip->lfi_scope = LDAP_SCOPE_ONELEVEL;
00200                   } else if ( strcasecmp( tok[ 2 ], "base" ) == 0 ) {
00201                      nextfip->lfi_scope = LDAP_SCOPE_BASE;
00202                   } else {
00203                      nsldapi_free_strarray( tok );
00204                      ldap_getfilter_free( lfdp );
00205                      return( NULL );
00206                   }
00207                   NSLDAPI_FREE( tok[ 2 ] );
00208                   tok[ 2 ] = NULL;
00209               } else {
00210                   nextfip->lfi_scope = LDAP_SCOPE_SUBTREE;     /* default */
00211               }
00212               nextfip->lfi_isexact = ( strchr( tok[ 0 ], '*' ) == NULL &&
00213                      strchr( tok[ 0 ], '~' ) == NULL );
00214               NSLDAPI_FREE( tok );
00215            }
00216            break;
00217 
00218        default:
00219            nsldapi_free_strarray( tok );
00220            ldap_getfilter_free( lfdp );
00221            return( NULL );
00222        }
00223     }
00224 
00225     if ( tag != NULL ) {
00226        NSLDAPI_FREE( tag );
00227     }
00228 
00229     return( lfdp );
00230 }
00231 
00232 
00233 int
00234 LDAP_CALL
00235 ldap_set_filter_additions( LDAPFiltDesc *lfdp, char *prefix, char *suffix )
00236 {
00237     if ( lfdp == NULL ) {
00238        return( LDAP_PARAM_ERROR );
00239     }
00240 
00241     if ( lfdp->lfd_filtprefix != NULL ) {
00242        NSLDAPI_FREE( lfdp->lfd_filtprefix );
00243     }
00244     lfdp->lfd_filtprefix = ( prefix == NULL ) ? NULL : nsldapi_strdup( prefix );
00245 
00246     if ( lfdp->lfd_filtsuffix != NULL ) {
00247        NSLDAPI_FREE( lfdp->lfd_filtsuffix );
00248     }
00249     lfdp->lfd_filtsuffix = ( suffix == NULL ) ? NULL : nsldapi_strdup( suffix );
00250 
00251     return( LDAP_SUCCESS );
00252 }
00253 
00254 
00255 /*
00256  * ldap_setfilteraffixes() is deprecated -- use ldap_set_filter_additions()
00257  */
00258 void
00259 LDAP_CALL
00260 ldap_setfilteraffixes( LDAPFiltDesc *lfdp, char *prefix, char *suffix )
00261 {
00262     (void)ldap_set_filter_additions( lfdp, prefix, suffix );
00263 }
00264 
00265 
00266 LDAPFiltInfo *
00267 LDAP_CALL
00268 ldap_getfirstfilter( LDAPFiltDesc *lfdp, char *tagpat, char *value )
00269 {
00270     LDAPFiltList     *flp;
00271 
00272     if ( lfdp == NULL || tagpat == NULL || value == NULL ) {
00273        return( NULL );      /* punt */
00274     }
00275 
00276     if ( lfdp->lfd_curvalcopy != NULL ) {
00277        NSLDAPI_FREE( lfdp->lfd_curvalcopy );
00278        NSLDAPI_FREE( lfdp->lfd_curvalwords );
00279     }
00280 
00281     lfdp->lfd_curval = value;
00282     lfdp->lfd_curfip = NULL;
00283 
00284     for ( flp = lfdp->lfd_filtlist; flp != NULL; flp = flp->lfl_next ) {
00285        if ( re_comp( tagpat ) == NULL && re_exec( flp->lfl_tag ) == 1
00286               && re_comp( flp->lfl_pattern ) == NULL
00287               && re_exec( lfdp->lfd_curval ) == 1 ) {
00288            lfdp->lfd_curfip = flp->lfl_ilist;
00289            break;
00290        }
00291     }
00292 
00293     if ( lfdp->lfd_curfip == NULL ) {
00294        return( NULL );
00295     }
00296 
00297     if (( lfdp->lfd_curvalcopy = nsldapi_strdup( value )) == NULL ) {
00298        return( NULL );
00299     }
00300 
00301     if ( break_into_words( lfdp->lfd_curvalcopy, flp->lfl_delims,
00302               &lfdp->lfd_curvalwords ) < 0 ) {
00303        NSLDAPI_FREE( lfdp->lfd_curvalcopy );
00304        lfdp->lfd_curvalcopy = NULL;
00305        return( NULL );
00306     }
00307 
00308     return( ldap_getnextfilter( lfdp ));
00309 }
00310 
00311 
00312 LDAPFiltInfo *
00313 LDAP_CALL
00314 ldap_getnextfilter( LDAPFiltDesc *lfdp )
00315 {
00316     LDAPFiltInfo     *fip;
00317 
00318     if ( lfdp == NULL || ( fip = lfdp->lfd_curfip ) == NULL ) {
00319        return( NULL );
00320     }
00321 
00322     lfdp->lfd_curfip = fip->lfi_next;
00323 
00324     ldap_build_filter( lfdp->lfd_filter, LDAP_FILT_MAXSIZ, fip->lfi_filter,
00325            lfdp->lfd_filtprefix, lfdp->lfd_filtsuffix, NULL,
00326            lfdp->lfd_curval, lfdp->lfd_curvalwords );
00327     lfdp->lfd_retfi.lfi_filter = lfdp->lfd_filter;
00328     lfdp->lfd_retfi.lfi_desc = fip->lfi_desc;
00329     lfdp->lfd_retfi.lfi_scope = fip->lfi_scope;
00330     lfdp->lfd_retfi.lfi_isexact = fip->lfi_isexact;
00331 
00332     return( &lfdp->lfd_retfi );
00333 }
00334 
00335 
00336 static char*
00337 filter_add_strn( char *f, char *flimit, char *v, size_t vlen )
00338      /* Copy v into f.  If flimit is too small, return NULL;
00339       * otherwise return (f + vlen).
00340       */
00341 {
00342     auto size_t flen = flimit - f;
00343     if ( vlen > flen ) { /* flimit is too small */
00344        if ( flen > 0 ) SAFEMEMCPY( f, v, flen );
00345        return NULL;
00346     }
00347     if ( vlen > 0 ) SAFEMEMCPY( f, v, vlen );
00348     return f + vlen;
00349 }
00350 
00351 static char*
00352 filter_add_value( char *f, char *flimit, char *v, int escape_all )
00353      /* Copy v into f, but with parentheses escaped.  But only escape * and \
00354       * if escape_all is non-zero so that either "*" or "\2a" can be used in
00355       * v, with different meanings.
00356       * If flimit is too small, return NULL; otherwise
00357       * return (f + the number of bytes copied).
00358       */
00359 {
00360     auto char x[4];
00361     auto size_t slen;
00362     while ( f && *v ) {
00363        switch ( *v ) {
00364        case '*':
00365            if ( escape_all ) {
00366               f = filter_add_strn( f, flimit, "\\2a", 3 );
00367               v++;
00368            } else {
00369               if ( f < flimit ) {
00370                   *f++ = *v++;
00371               } else {
00372                   f = NULL; /* overflow */
00373               }
00374            }
00375            break;
00376 
00377        case '(':
00378        case ')':
00379            sprintf( x, "\\%02x", (unsigned)*v );
00380            f = filter_add_strn( f, flimit, x, 3 );
00381            v++;
00382            break;
00383 
00384        case '\\':
00385            if ( escape_all ) {
00386               f = filter_add_strn( f, flimit, "\\5c", 3 );
00387               v++;
00388            } else {
00389               slen = (ldap_utf8isxdigit( v+1 ) &&
00390                      ldap_utf8isxdigit( v+2 )) ? 3 : (v[1] ? 2 : 1);
00391               f = filter_add_strn( f, flimit, v, slen );
00392               v += slen;
00393            }
00394            break;
00395            
00396        default:
00397            if ( f < flimit ) {
00398               *f++ = *v++;
00399            } else {
00400               f = NULL; /* overflow */
00401            }
00402            break;
00403        }
00404     }
00405     return f;
00406 }
00407 
00408 int
00409 LDAP_CALL
00410 ldap_create_filter( char *filtbuf, unsigned long buflen, char *pattern,
00411        char *prefix, char *suffix, char *attr, char *value, char **valwords )
00412 {
00413        char   *p, *f, *flimit;
00414        int    i, wordcount, wordnum, endwordnum, escape_all;
00415 
00416     /* 
00417      * there is some confusion on what to create for a filter if 
00418      * attr or value are null pointers.  For now we just leave them
00419      * as TO BE DEALT with
00420      */
00421 
00422        if ( filtbuf == NULL || buflen == 0 || pattern == NULL ){
00423               return( LDAP_PARAM_ERROR );
00424        }
00425        
00426        if ( valwords == NULL ) {
00427            wordcount = 0;
00428        } else {
00429            for ( wordcount = 0; valwords[ wordcount ] != NULL; ++wordcount ) {
00430               ;
00431            }
00432        }
00433 
00434        f = filtbuf;
00435        flimit = filtbuf + buflen - 1;
00436 
00437        if ( prefix != NULL ) {
00438            f = filter_add_strn( f, flimit, prefix, strlen( prefix ));
00439        }
00440 
00441        for ( p = pattern; f != NULL && *p != '\0'; ++p ) {
00442            if ( *p == '%' ) {
00443               ++p;
00444               if ( *p == 'v' || *p == 'e' ) {
00445                   escape_all = ( *p == 'e' );
00446                   if ( ldap_utf8isdigit( p+1 )) {
00447                      ++p;
00448                      wordnum = *p - '1';
00449                      if ( *(p+1) == '-' ) {
00450                          ++p;
00451                          if ( ldap_utf8isdigit( p+1 )) {
00452                             ++p;
00453                             endwordnum = *p - '1';      /* e.g., "%v2-4" */
00454                             if ( endwordnum > wordcount - 1 ) {
00455                                 endwordnum = wordcount - 1;
00456                             }
00457                          } else {
00458                             endwordnum = wordcount - 1;  /* e.g., "%v2-" */
00459                          }
00460                      } else {
00461                          endwordnum = wordnum;   /* e.g., "%v2" */
00462                      }
00463 
00464                      if ( wordcount > 0 ) {
00465                          for ( i = wordnum; i <= endwordnum; ++i ) {
00466                             if ( i > wordnum ) {  /* add blank btw words */
00467                                 f = filter_add_strn( f, flimit, " ", 1 );
00468                                 if ( f == NULL ) break;
00469                             }
00470                             f = filter_add_value( f, flimit, valwords[ i ],
00471                                    escape_all );
00472                             if ( f == NULL ) break;
00473                          }
00474                      }
00475                   } else if ( *(p+1) == '$' ) {
00476                      ++p;
00477                      if ( wordcount > 0 ) {
00478                          wordnum = wordcount - 1;
00479                          f = filter_add_value( f, flimit,
00480                                 valwords[ wordnum ], escape_all );
00481                      }
00482                   } else if ( value != NULL ) {
00483                      f = filter_add_value( f, flimit, value, escape_all );
00484                   }
00485               } else if ( *p == 'a' && attr != NULL ) {
00486                   f = filter_add_strn( f, flimit, attr, strlen( attr ));
00487               } else {
00488                   *f++ = *p;
00489               }
00490            } else {
00491               *f++ = *p;
00492            }
00493            if ( f > flimit ) { /* overflow */
00494               f = NULL;
00495            }
00496        }
00497 
00498        if ( suffix != NULL && f != NULL) {
00499            f = filter_add_strn( f, flimit, suffix, strlen( suffix ));
00500        }
00501 
00502        if ( f == NULL ) {
00503            *flimit = '\0';
00504            return( LDAP_SIZELIMIT_EXCEEDED );
00505        }
00506        *f = '\0';
00507        return( LDAP_SUCCESS );
00508 }
00509 
00510 
00511 /*
00512  * ldap_build_filter() is deprecated -- use ldap_create_filter() instead
00513  */
00514 void
00515 LDAP_CALL
00516 ldap_build_filter( char *filtbuf, unsigned long buflen, char *pattern,
00517        char *prefix, char *suffix, char *attr, char *value, char **valwords )
00518 {
00519     (void)ldap_create_filter( filtbuf, buflen, pattern, prefix, suffix, attr,
00520            value, valwords );
00521 }
00522 
00523 
00524 static int
00525 break_into_words( char *str, char *delims, char ***wordsp )
00526 {
00527     char      *word, **words;
00528     int              count;
00529     char      *lasts;
00530        
00531     if (( words = (char **)NSLDAPI_CALLOC( 1, sizeof( char * ))) == NULL ) {
00532        return( -1 );
00533     }
00534     count = 0;
00535     words[ count ] = NULL;
00536 
00537     word = ldap_utf8strtok_r( str, delims, &lasts );
00538     while ( word != NULL ) {
00539        if (( words = (char **)NSLDAPI_REALLOC( words,
00540               ( count + 2 ) * sizeof( char * ))) == NULL ) {
00541            return( -1 );
00542        }
00543 
00544        words[ count ] = word;
00545        words[ ++count ] = NULL;
00546        word = ldap_utf8strtok_r( NULL, delims, &lasts );
00547     }
00548        
00549     *wordsp = words;
00550     return( count );
00551 }