diff options
Diffstat (limited to 'ldap/c-sdk/libldap/getfilter.c')
-rw-r--r-- | ldap/c-sdk/libldap/getfilter.c | 553 |
1 files changed, 553 insertions, 0 deletions
diff --git a/ldap/c-sdk/libldap/getfilter.c b/ldap/c-sdk/libldap/getfilter.c new file mode 100644 index 000000000..ff2ee77f9 --- /dev/null +++ b/ldap/c-sdk/libldap/getfilter.c @@ -0,0 +1,553 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ +/* + * Copyright (c) 1993 Regents of the University of Michigan. + * All rights reserved. + */ +/* + * getfilter.c -- optional add-on to libldap + */ + +#if 0 +#ifndef lint +static char copyright[] = "@(#) Copyright (c) 1993 Regents of the University of Michigan.\nAll rights reserved.\n"; +#endif +#endif + +#include "ldap-int.h" +#include "regex.h" + +static int break_into_words( char *str, char *delims, char ***wordsp ); + +#if !defined( macintosh ) && !defined( DOS ) +extern char * LDAP_CALL re_comp(); +#endif + +#define FILT_MAX_LINE_LEN 1024 + +LDAPFiltDesc * +LDAP_CALL +ldap_init_getfilter( char *fname ) +{ + FILE *fp; + char *buf; + long rlen, len; + int eof; + LDAPFiltDesc *lfdp; + + if (( fp = NSLDAPI_FOPEN( fname, "r" )) == NULL ) { + return( NULL ); + } + + if ( fseek( fp, 0L, SEEK_END ) != 0 ) { /* move to end to get len */ + fclose( fp ); + return( NULL ); + } + + len = ftell( fp ); + + if ( fseek( fp, 0L, SEEK_SET ) != 0 ) { /* back to start of file */ + fclose( fp ); + return( NULL ); + } + + if (( buf = NSLDAPI_MALLOC( (size_t)len )) == NULL ) { + fclose( fp ); + return( NULL ); + } + + rlen = fread( buf, 1, (size_t)len, fp ); + eof = feof( fp ); + fclose( fp ); + + if ( rlen != len && !eof ) { /* error: didn't get the whole file */ + NSLDAPI_FREE( buf ); + return( NULL ); + } + + + lfdp = ldap_init_getfilter_buf( buf, rlen ); + NSLDAPI_FREE( buf ); + + return( lfdp ); +} + + +LDAPFiltDesc * +LDAP_CALL +ldap_init_getfilter_buf( char *buf, long buflen ) +{ + LDAPFiltDesc *lfdp; + LDAPFiltList *flp, *nextflp; + LDAPFiltInfo *fip, *nextfip; + char *errmsg, *tag, **tok; + int tokcnt, i; + + if ( (buf == NULL) || (buflen < 0) || + ( lfdp = (LDAPFiltDesc *)NSLDAPI_CALLOC(1, sizeof( LDAPFiltDesc))) + == NULL ) { + return( NULL ); + } + + flp = nextflp = NULL; + fip = NULL; + tag = NULL; + + while ( buflen > 0 && ( tokcnt = nsldapi_next_line_tokens( &buf, &buflen, + &tok )) > 0 ) { + switch( tokcnt ) { + case 1: /* tag line */ + if ( tag != NULL ) { + NSLDAPI_FREE( tag ); + } + tag = tok[ 0 ]; + NSLDAPI_FREE( tok ); + break; + case 4: + case 5: /* start of filter info. list */ + if (( nextflp = (LDAPFiltList *)NSLDAPI_CALLOC( 1, + sizeof( LDAPFiltList ))) == NULL ) { + ldap_getfilter_free( lfdp ); + return( NULL ); + } + nextflp->lfl_tag = nsldapi_strdup( tag ); + nextflp->lfl_pattern = tok[ 0 ]; + if (( errmsg = re_comp( nextflp->lfl_pattern )) != NULL ) { + char msg[512]; + ldap_getfilter_free( lfdp ); + snprintf( msg, sizeof(msg), + "bad regular expression \"%s\" - %s\n", + nextflp->lfl_pattern, errmsg ); + ber_err_print( msg ); + nsldapi_free_strarray( tok ); + return( NULL ); + } + + nextflp->lfl_delims = tok[ 1 ]; + nextflp->lfl_ilist = NULL; + nextflp->lfl_next = NULL; + if ( flp == NULL ) { /* first one */ + lfdp->lfd_filtlist = nextflp; + } else { + flp->lfl_next = nextflp; + } + flp = nextflp; + fip = NULL; + for ( i = 2; i < 5; ++i ) { + tok[ i - 2 ] = tok[ i ]; + } + /* fall through */ + + case 2: + case 3: /* filter, desc, and optional search scope */ + if ( nextflp != NULL ) { /* add to info list */ + if (( nextfip = (LDAPFiltInfo *)NSLDAPI_CALLOC( 1, + sizeof( LDAPFiltInfo ))) == NULL ) { + ldap_getfilter_free( lfdp ); + nsldapi_free_strarray( tok ); + return( NULL ); + } + if ( fip == NULL ) { /* first one */ + nextflp->lfl_ilist = nextfip; + } else { + fip->lfi_next = nextfip; + } + fip = nextfip; + nextfip->lfi_next = NULL; + nextfip->lfi_filter = tok[ 0 ]; + nextfip->lfi_desc = tok[ 1 ]; + if ( tok[ 2 ] != NULL ) { + if ( strcasecmp( tok[ 2 ], "subtree" ) == 0 ) { + nextfip->lfi_scope = LDAP_SCOPE_SUBTREE; + } else if ( strcasecmp( tok[ 2 ], "onelevel" ) == 0 ) { + nextfip->lfi_scope = LDAP_SCOPE_ONELEVEL; + } else if ( strcasecmp( tok[ 2 ], "base" ) == 0 ) { + nextfip->lfi_scope = LDAP_SCOPE_BASE; + } else { + nsldapi_free_strarray( tok ); + ldap_getfilter_free( lfdp ); + return( NULL ); + } + NSLDAPI_FREE( tok[ 2 ] ); + tok[ 2 ] = NULL; + } else { + nextfip->lfi_scope = LDAP_SCOPE_SUBTREE; /* default */ + } + nextfip->lfi_isexact = ( strchr( tok[ 0 ], '*' ) == NULL && + strchr( tok[ 0 ], '~' ) == NULL ); + NSLDAPI_FREE( tok ); + } + break; + + default: + nsldapi_free_strarray( tok ); + ldap_getfilter_free( lfdp ); + return( NULL ); + } + } + + if ( tag != NULL ) { + NSLDAPI_FREE( tag ); + } + + return( lfdp ); +} + + +int +LDAP_CALL +ldap_set_filter_additions( LDAPFiltDesc *lfdp, char *prefix, char *suffix ) +{ + if ( lfdp == NULL ) { + return( LDAP_PARAM_ERROR ); + } + + if ( lfdp->lfd_filtprefix != NULL ) { + NSLDAPI_FREE( lfdp->lfd_filtprefix ); + } + lfdp->lfd_filtprefix = ( prefix == NULL ) ? NULL : nsldapi_strdup( prefix ); + + if ( lfdp->lfd_filtsuffix != NULL ) { + NSLDAPI_FREE( lfdp->lfd_filtsuffix ); + } + lfdp->lfd_filtsuffix = ( suffix == NULL ) ? NULL : nsldapi_strdup( suffix ); + + return( LDAP_SUCCESS ); +} + + +/* + * ldap_setfilteraffixes() is deprecated -- use ldap_set_filter_additions() + */ +void +LDAP_CALL +ldap_setfilteraffixes( LDAPFiltDesc *lfdp, char *prefix, char *suffix ) +{ + (void)ldap_set_filter_additions( lfdp, prefix, suffix ); +} + + +LDAPFiltInfo * +LDAP_CALL +ldap_getfirstfilter( LDAPFiltDesc *lfdp, char *tagpat, char *value ) +{ + LDAPFiltList *flp; + + if ( lfdp == NULL || tagpat == NULL || value == NULL ) { + return( NULL ); /* punt */ + } + + if ( lfdp->lfd_curvalcopy != NULL ) { + NSLDAPI_FREE( lfdp->lfd_curvalcopy ); + NSLDAPI_FREE( lfdp->lfd_curvalwords ); + } + + NSLDAPI_FREE(lfdp->lfd_curval); + if ((lfdp->lfd_curval = nsldapi_strdup(value)) == NULL) { + return( NULL ); + } + + lfdp->lfd_curfip = NULL; + + for ( flp = lfdp->lfd_filtlist; flp != NULL; flp = flp->lfl_next ) { + if ( re_comp( tagpat ) == NULL && re_exec( flp->lfl_tag ) == 1 + && re_comp( flp->lfl_pattern ) == NULL + && re_exec( lfdp->lfd_curval ) == 1 ) { + lfdp->lfd_curfip = flp->lfl_ilist; + break; + } + } + + if ( lfdp->lfd_curfip == NULL ) { + return( NULL ); + } + + if (( lfdp->lfd_curvalcopy = nsldapi_strdup( value )) == NULL ) { + return( NULL ); + } + + if ( break_into_words( lfdp->lfd_curvalcopy, flp->lfl_delims, + &lfdp->lfd_curvalwords ) < 0 ) { + NSLDAPI_FREE( lfdp->lfd_curvalcopy ); + lfdp->lfd_curvalcopy = NULL; + return( NULL ); + } + + return( ldap_getnextfilter( lfdp )); +} + + +LDAPFiltInfo * +LDAP_CALL +ldap_getnextfilter( LDAPFiltDesc *lfdp ) +{ + LDAPFiltInfo *fip; + + if ( lfdp == NULL || ( fip = lfdp->lfd_curfip ) == NULL ) { + return( NULL ); + } + + lfdp->lfd_curfip = fip->lfi_next; + + ldap_build_filter( lfdp->lfd_filter, LDAP_FILT_MAXSIZ, fip->lfi_filter, + lfdp->lfd_filtprefix, lfdp->lfd_filtsuffix, NULL, + lfdp->lfd_curval, lfdp->lfd_curvalwords ); + lfdp->lfd_retfi.lfi_filter = lfdp->lfd_filter; + lfdp->lfd_retfi.lfi_desc = fip->lfi_desc; + lfdp->lfd_retfi.lfi_scope = fip->lfi_scope; + lfdp->lfd_retfi.lfi_isexact = fip->lfi_isexact; + + return( &lfdp->lfd_retfi ); +} + + +static char* +filter_add_strn( char *f, char *flimit, char *v, size_t vlen ) + /* Copy v into f. If flimit is too small, return NULL; + * otherwise return (f + vlen). + */ +{ + auto size_t flen = flimit - f; + if ( vlen > flen ) { /* flimit is too small */ + if ( flen > 0 ) SAFEMEMCPY( f, v, flen ); + return NULL; + } + if ( vlen > 0 ) SAFEMEMCPY( f, v, vlen ); + return f + vlen; +} + +static char* +filter_add_value( char *f, char *flimit, char *v, int escape_all ) + /* Copy v into f, but with parentheses escaped. But only escape * and \ + * if escape_all is non-zero so that either "*" or "\2a" can be used in + * v, with different meanings. + * If flimit is too small, return NULL; otherwise + * return (f + the number of bytes copied). + */ +{ + auto char x[4]; + auto size_t slen; + while ( f && *v ) { + switch ( *v ) { + case '*': + if ( escape_all ) { + f = filter_add_strn( f, flimit, "\\2a", 3 ); + v++; + } else { + if ( f < flimit ) { + *f++ = *v++; + } else { + f = NULL; /* overflow */ + } + } + break; + + case '(': + case ')': + sprintf( x, "\\%02x", (unsigned)*v ); + f = filter_add_strn( f, flimit, x, 3 ); + v++; + break; + + case '\\': + if ( escape_all ) { + f = filter_add_strn( f, flimit, "\\5c", 3 ); + v++; + } else { + slen = (ldap_utf8isxdigit( v+1 ) && + ldap_utf8isxdigit( v+2 )) ? 3 : (v[1] ? 2 : 1); + f = filter_add_strn( f, flimit, v, slen ); + v += slen; + } + break; + + default: + if ( f < flimit ) { + *f++ = *v++; + } else { + f = NULL; /* overflow */ + } + break; + } + } + return f; +} + +int +LDAP_CALL +ldap_create_filter( char *filtbuf, unsigned long buflen, char *pattern, + char *prefix, char *suffix, char *attr, char *value, char **valwords ) +{ + char *p, *f, *flimit; + int i, wordcount, wordnum, endwordnum, escape_all; + + /* + * there is some confusion on what to create for a filter if + * attr or value are null pointers. For now we just leave them + * as TO BE DEALT with + */ + + if ( filtbuf == NULL || buflen == 0 || pattern == NULL ){ + return( LDAP_PARAM_ERROR ); + } + + if ( valwords == NULL ) { + wordcount = 0; + } else { + for ( wordcount = 0; valwords[ wordcount ] != NULL; ++wordcount ) { + ; + } + } + + f = filtbuf; + flimit = filtbuf + buflen - 1; + + if ( prefix != NULL ) { + f = filter_add_strn( f, flimit, prefix, strlen( prefix )); + } + + for ( p = pattern; f != NULL && *p != '\0'; ++p ) { + if ( *p == '%' ) { + ++p; + if ( *p == 'v' || *p == 'e' ) { + escape_all = ( *p == 'e' ); + if ( ldap_utf8isdigit( p+1 )) { + ++p; + wordnum = *p - '1'; + if ( *(p+1) == '-' ) { + ++p; + if ( ldap_utf8isdigit( p+1 )) { + ++p; + endwordnum = *p - '1'; /* e.g., "%v2-4" */ + if ( endwordnum > wordcount - 1 ) { + endwordnum = wordcount - 1; + } + } else { + endwordnum = wordcount - 1; /* e.g., "%v2-" */ + } + } else { + endwordnum = wordnum; /* e.g., "%v2" */ + } + + if ( wordcount > 0 ) { + for ( i = wordnum; i <= endwordnum; ++i ) { + if ( i > wordnum ) { /* add blank btw words */ + f = filter_add_strn( f, flimit, " ", 1 ); + if ( f == NULL ) break; + } + f = filter_add_value( f, flimit, valwords[ i ], + escape_all ); + if ( f == NULL ) break; + } + } + } else if ( *(p+1) == '$' ) { + ++p; + if ( wordcount > 0 ) { + wordnum = wordcount - 1; + f = filter_add_value( f, flimit, + valwords[ wordnum ], escape_all ); + } + } else if ( value != NULL ) { + f = filter_add_value( f, flimit, value, escape_all ); + } + } else if ( *p == 'a' && attr != NULL ) { + f = filter_add_strn( f, flimit, attr, strlen( attr )); + } else { + *f++ = *p; + } + } else { + *f++ = *p; + } + if ( f > flimit ) { /* overflow */ + f = NULL; + } + } + + if ( suffix != NULL && f != NULL) { + f = filter_add_strn( f, flimit, suffix, strlen( suffix )); + } + + if ( f == NULL ) { + *flimit = '\0'; + return( LDAP_SIZELIMIT_EXCEEDED ); + } + *f = '\0'; + return( LDAP_SUCCESS ); +} + + +/* + * ldap_build_filter() is deprecated -- use ldap_create_filter() instead + */ +void +LDAP_CALL +ldap_build_filter( char *filtbuf, unsigned long buflen, char *pattern, + char *prefix, char *suffix, char *attr, char *value, char **valwords ) +{ + (void)ldap_create_filter( filtbuf, buflen, pattern, prefix, suffix, attr, + value, valwords ); +} + + +static int +break_into_words( char *str, char *delims, char ***wordsp ) +{ + char *word, **words; + int count; + char *lasts; + + if (( words = (char **)NSLDAPI_CALLOC( 1, sizeof( char * ))) == NULL ) { + return( -1 ); + } + count = 0; + words[ count ] = NULL; + + word = ldap_utf8strtok_r( str, delims, &lasts ); + while ( word != NULL ) { + if (( words = (char **)NSLDAPI_REALLOC( words, + ( count + 2 ) * sizeof( char * ))) == NULL ) { + return( -1 ); + } + + words[ count ] = word; + words[ ++count ] = NULL; + word = ldap_utf8strtok_r( NULL, delims, &lasts ); + } + + *wordsp = words; + return( count ); +} |