2004-03-31 10:45:39 +04:00
/*
ldb database library
Copyright ( C ) Andrew Tridgell 2004
* * NOTE ! The following LGPL license applies to the ldb
* * library . This does NOT imply that all of Samba is released
* * under the LGPL
This library is free software ; you can redistribute it and / or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation ; either
2007-07-10 06:46:15 +04:00
version 3 of the License , or ( at your option ) any later version .
2004-03-31 10:45:39 +04:00
This library is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the GNU
Lesser General Public License for more details .
You should have received a copy of the GNU Lesser General Public
2007-07-10 07:42:26 +04:00
License along with this library ; if not , see < http : //www.gnu.org/licenses/>.
2004-03-31 10:45:39 +04:00
*/
/*
* Name : ldb
*
* Component : ldb expression parsing
*
* Description : parse LDAP - like search expressions
*
* Author : Andrew Tridgell
*/
/*
TODO :
- add RFC2254 binary string handling
- possibly add ~ = , < = and > = handling
- expand the test suite
- add better parse error handling
*/
2009-01-30 02:39:30 +03:00
# include "ldb_private.h"
2006-09-06 08:58:06 +04:00
# include "system/locale.h"
2004-03-31 10:45:39 +04:00
2020-04-21 06:37:40 +03:00
/*
* Maximum depth of the filter parse tree , the value chosen is small enough to
* avoid triggering ASAN stack overflow checks . But large enough to be useful .
*
* On Windows clients the maximum number of levels of recursion allowed is 100.
* In the LDAP server , Windows restricts clients to 512 nested
* ( eg ) OR statements .
*/
# define LDB_MAX_PARSE_TREE_DEPTH 128
2004-03-31 10:45:39 +04:00
/*
a filter is defined by :
< filter > : : = ' ( ' < filtercomp > ' ) '
< filtercomp > : : = < and > | < or > | < not > | < simple >
< and > : : = ' & ' < filterlist >
< or > : : = ' | ' < filterlist >
< not > : : = ' ! ' < filter >
< filterlist > : : = < filter > | < filter > < filterlist >
< simple > : : = < attributetype > < filtertype > < attributevalue >
< filtertype > : : = ' = ' | ' ~ = ' | ' < = ' | ' > = '
*/
2005-06-13 09:33:55 +04:00
/*
decode a RFC2254 binary string representation of a buffer .
Used in LDAP filters .
*/
2010-07-13 03:37:58 +04:00
struct ldb_val ldb_binary_decode ( TALLOC_CTX * mem_ctx , const char * str )
2005-06-13 09:33:55 +04:00
{
2009-11-06 20:35:17 +03:00
size_t i , j ;
2005-06-13 09:33:55 +04:00
struct ldb_val ret ;
2009-11-06 20:35:17 +03:00
size_t slen = str ? strlen ( str ) : 0 ;
2005-06-13 09:33:55 +04:00
2006-10-09 12:00:18 +04:00
ret . data = ( uint8_t * ) talloc_size ( mem_ctx , slen + 1 ) ;
2005-06-13 09:33:55 +04:00
ret . length = 0 ;
if ( ret . data = = NULL ) return ret ;
for ( i = j = 0 ; i < slen ; i + + ) {
if ( str [ i ] = = ' \\ ' ) {
2021-01-04 15:55:01 +03:00
uint8_t c ;
bool ok ;
2010-03-08 04:20:45 +03:00
2021-01-04 15:55:01 +03:00
ok = hex_byte ( & str [ i + 1 ] , & c ) ;
if ( ! ok ) {
2005-06-13 09:33:55 +04:00
talloc_free ( ret . data ) ;
memset ( & ret , 0 , sizeof ( ret ) ) ;
return ret ;
}
( ( uint8_t * ) ret . data ) [ j + + ] = c ;
i + = 2 ;
} else {
( ( uint8_t * ) ret . data ) [ j + + ] = str [ i ] ;
}
}
ret . length = j ;
2005-06-13 09:56:46 +04:00
( ( uint8_t * ) ret . data ) [ j ] = 0 ;
2005-06-13 09:33:55 +04:00
return ret ;
}
2012-09-11 20:06:45 +04:00
static bool need_encode ( unsigned char cval )
{
if ( cval < 0x20 | | cval > 0x7E | | strchr ( " *() \\ &|! \" " , cval ) ) {
return true ;
}
return false ;
}
2005-06-13 09:33:55 +04:00
/*
encode a blob as a RFC2254 binary string , escaping any
non - printable or ' \ ' characters
*/
2010-07-13 03:37:58 +04:00
char * ldb_binary_encode ( TALLOC_CTX * mem_ctx , struct ldb_val val )
2005-06-13 09:33:55 +04:00
{
2009-11-06 20:35:17 +03:00
size_t i ;
2005-06-13 09:33:55 +04:00
char * ret ;
2009-11-06 20:35:17 +03:00
size_t len = val . length ;
2005-06-13 09:33:55 +04:00
unsigned char * buf = val . data ;
for ( i = 0 ; i < val . length ; i + + ) {
2012-09-11 20:06:45 +04:00
if ( need_encode ( buf [ i ] ) ) {
2005-06-13 09:33:55 +04:00
len + = 2 ;
}
}
2005-06-13 13:10:17 +04:00
ret = talloc_array ( mem_ctx , char , len + 1 ) ;
2005-06-13 09:33:55 +04:00
if ( ret = = NULL ) return NULL ;
len = 0 ;
for ( i = 0 ; i < val . length ; i + + ) {
2012-09-11 20:06:45 +04:00
if ( need_encode ( buf [ i ] ) ) {
2005-06-13 09:33:55 +04:00
snprintf ( ret + len , 4 , " \\ %02X " , buf [ i ] ) ;
len + = 3 ;
} else {
ret [ len + + ] = buf [ i ] ;
}
}
ret [ len ] = 0 ;
return ret ;
}
2004-03-31 10:45:39 +04:00
2005-12-19 10:07:11 +03:00
/*
encode a string as a RFC2254 binary string , escaping any
non - printable or ' \ ' characters . This routine is suitable for use
in escaping user data in ldap filters .
*/
2010-07-13 03:37:58 +04:00
char * ldb_binary_encode_string ( TALLOC_CTX * mem_ctx , const char * string )
2005-12-19 10:07:11 +03:00
{
struct ldb_val val ;
2010-09-29 05:01:21 +04:00
if ( string = = NULL ) {
return NULL ;
}
2006-10-09 12:00:18 +04:00
val . data = discard_const_p ( uint8_t , string ) ;
2005-12-19 10:07:11 +03:00
val . length = strlen ( string ) ;
return ldb_binary_encode ( mem_ctx , val ) ;
}
2005-07-12 16:04:54 +04:00
/* find the first matching wildcard */
static char * ldb_parse_find_wildcard ( char * value )
{
while ( * value ) {
value = strpbrk ( value , " \\ * " ) ;
if ( value = = NULL ) return NULL ;
if ( value [ 0 ] = = ' \\ ' ) {
if ( value [ 1 ] = = ' \0 ' ) return NULL ;
value + = 2 ;
continue ;
}
if ( value [ 0 ] = = ' * ' ) return value ;
}
return NULL ;
}
/* return a NULL terminated list of binary strings representing the value
chunks separated by wildcards that makes the value portion of the filter
*/
2010-07-13 03:37:58 +04:00
static struct ldb_val * * ldb_wildcard_decode ( TALLOC_CTX * mem_ctx , const char * string )
2005-07-12 16:04:54 +04:00
{
struct ldb_val * * ret = NULL ;
2009-11-06 20:35:17 +03:00
unsigned int val = 0 ;
2005-07-12 16:04:54 +04:00
char * wc , * str ;
wc = talloc_strdup ( mem_ctx , string ) ;
if ( wc = = NULL ) return NULL ;
while ( wc & & * wc ) {
str = wc ;
wc = ldb_parse_find_wildcard ( str ) ;
if ( wc & & * wc ) {
if ( wc = = str ) {
wc + + ;
continue ;
}
* wc = 0 ;
wc + + ;
}
ret = talloc_realloc ( mem_ctx , ret , struct ldb_val * , val + 2 ) ;
if ( ret = = NULL ) return NULL ;
ret [ val ] = talloc ( mem_ctx , struct ldb_val ) ;
if ( ret [ val ] = = NULL ) return NULL ;
* ( ret [ val ] ) = ldb_binary_decode ( mem_ctx , str ) ;
if ( ( ret [ val ] ) - > data = = NULL ) return NULL ;
val + + ;
}
2006-03-15 08:50:15 +03:00
if ( ret ! = NULL ) {
ret [ val ] = NULL ;
}
2005-07-12 16:04:54 +04:00
return ret ;
}
2020-04-21 06:37:40 +03:00
static struct ldb_parse_tree * ldb_parse_filter (
TALLOC_CTX * mem_ctx ,
const char * * s ,
unsigned depth ,
unsigned max_depth ) ;
2004-03-31 10:45:39 +04:00
2005-06-14 05:35:44 +04:00
/*
parse an extended match
possible forms :
( attr : oid : = value )
( attr : dn : oid : = value )
( attr : dn : = value )
( : dn : oid : = value )
the ' : dn ' part sets the dnAttributes boolean if present
the oid sets the rule_id string
*/
static struct ldb_parse_tree * ldb_parse_extended ( struct ldb_parse_tree * ret ,
char * attr , char * value )
{
2005-07-19 13:09:00 +04:00
char * p1 , * p2 ;
2005-07-12 16:04:54 +04:00
2005-06-14 05:35:44 +04:00
ret - > operation = LDB_OP_EXTENDED ;
ret - > u . extended . value = ldb_binary_decode ( ret , value ) ;
2005-07-12 16:04:54 +04:00
if ( ret - > u . extended . value . data = = NULL ) goto failed ;
2005-06-14 05:35:44 +04:00
p1 = strchr ( attr , ' : ' ) ;
if ( p1 = = NULL ) goto failed ;
p2 = strchr ( p1 + 1 , ' : ' ) ;
* p1 = 0 ;
2005-07-19 13:09:00 +04:00
if ( p2 ) * p2 = 0 ;
2005-06-14 05:35:44 +04:00
2005-07-19 13:09:00 +04:00
ret - > u . extended . attr = attr ;
2005-06-14 05:35:44 +04:00
if ( strcmp ( p1 + 1 , " dn " ) = = 0 ) {
ret - > u . extended . dnAttributes = 1 ;
2005-07-19 13:09:00 +04:00
if ( p2 ) {
2005-06-14 05:35:44 +04:00
ret - > u . extended . rule_id = talloc_strdup ( ret , p2 + 1 ) ;
if ( ret - > u . extended . rule_id = = NULL ) goto failed ;
} else {
ret - > u . extended . rule_id = NULL ;
}
} else {
ret - > u . extended . dnAttributes = 0 ;
ret - > u . extended . rule_id = talloc_strdup ( ret , p1 + 1 ) ;
if ( ret - > u . extended . rule_id = = NULL ) goto failed ;
}
return ret ;
failed :
talloc_free ( ret ) ;
return NULL ;
}
2010-07-13 03:37:58 +04:00
static enum ldb_parse_op ldb_parse_filtertype ( TALLOC_CTX * mem_ctx , char * * type , char * * value , const char * * s )
2005-07-19 13:09:00 +04:00
{
enum ldb_parse_op filter = 0 ;
char * name , * val , * k ;
const char * p = * s ;
const char * t , * t1 ;
/* retrieve attributetype name */
t = p ;
2007-05-18 11:41:43 +04:00
if ( * p = = ' @ ' ) { /* for internal attributes the first char can be @ */
p + + ;
}
2009-09-16 01:07:43 +04:00
while ( ( isascii ( * p ) & & isalnum ( ( unsigned char ) * p ) ) | | ( * p = = ' - ' ) | | ( * p = = ' . ' ) ) {
/* attribute names can only be alphanums */
2005-07-19 13:09:00 +04:00
p + + ;
}
if ( * p = = ' : ' ) { /* but extended searches have : and . chars too */
p = strstr ( p , " := " ) ;
if ( p = = NULL ) { /* malformed attribute name */
return 0 ;
}
}
t1 = p ;
while ( isspace ( ( unsigned char ) * p ) ) p + + ;
if ( ! strchr ( " =<>~: " , * p ) ) {
return 0 ;
}
/* save name */
2006-10-09 12:00:18 +04:00
name = ( char * ) talloc_memdup ( mem_ctx , t , t1 - t + 1 ) ;
2005-07-19 13:09:00 +04:00
if ( name = = NULL ) return 0 ;
name [ t1 - t ] = ' \0 ' ;
/* retrieve filtertype */
if ( * p = = ' = ' ) {
filter = LDB_OP_EQUALITY ;
2019-04-12 01:46:37 +03:00
} else if ( * p ! = ' \0 ' & & * ( p + 1 ) = = ' = ' ) {
2005-07-19 13:09:00 +04:00
switch ( * p ) {
case ' < ' :
filter = LDB_OP_LESS ;
p + + ;
break ;
case ' > ' :
filter = LDB_OP_GREATER ;
p + + ;
break ;
case ' ~ ' :
filter = LDB_OP_APPROX ;
p + + ;
break ;
case ' : ' :
filter = LDB_OP_EXTENDED ;
p + + ;
break ;
}
}
if ( ! filter ) {
talloc_free ( name ) ;
2012-05-04 13:41:03 +04:00
return 0 ;
2005-07-19 13:09:00 +04:00
}
p + + ;
while ( isspace ( ( unsigned char ) * p ) ) p + + ;
2008-07-14 18:40:36 +04:00
/* retrieve value */
2005-07-19 13:09:00 +04:00
t = p ;
while ( * p & & ( ( * p ! = ' ) ' ) | | ( ( * p = = ' ) ' ) & & ( * ( p - 1 ) = = ' \\ ' ) ) ) ) p + + ;
2006-10-09 12:00:18 +04:00
val = ( char * ) talloc_memdup ( mem_ctx , t , p - t + 1 ) ;
2005-07-19 13:09:00 +04:00
if ( val = = NULL ) {
talloc_free ( name ) ;
return 0 ;
}
val [ p - t ] = ' \0 ' ;
k = & ( val [ p - t ] ) ;
/* remove trailing spaces from value */
while ( ( k > val ) & & ( isspace ( ( unsigned char ) * ( k - 1 ) ) ) ) k - - ;
* k = ' \0 ' ;
* type = name ;
* value = val ;
* s = p ;
return filter ;
}
2005-06-14 05:35:44 +04:00
2004-03-31 10:45:39 +04:00
/*
< simple > : : = < attributetype > < filtertype > < attributevalue >
*/
2010-07-13 03:37:58 +04:00
static struct ldb_parse_tree * ldb_parse_simple ( TALLOC_CTX * mem_ctx , const char * * s )
2004-03-31 10:45:39 +04:00
{
2005-07-19 13:09:00 +04:00
char * attr , * value ;
2004-03-31 10:45:39 +04:00
struct ldb_parse_tree * ret ;
2005-07-19 13:09:00 +04:00
enum ldb_parse_op filtertype ;
2004-03-31 10:45:39 +04:00
2019-02-19 00:25:24 +03:00
ret = talloc_zero ( mem_ctx , struct ldb_parse_tree ) ;
2005-01-02 10:49:29 +03:00
if ( ! ret ) {
errno = ENOMEM ;
return NULL ;
}
2005-07-19 13:09:00 +04:00
filtertype = ldb_parse_filtertype ( ret , & attr , & value , s ) ;
if ( ! filtertype ) {
2005-01-02 10:49:29 +03:00
talloc_free ( ret ) ;
2004-03-31 10:45:39 +04:00
return NULL ;
}
2005-07-19 13:09:00 +04:00
switch ( filtertype ) {
2004-03-31 10:45:39 +04:00
2005-10-01 03:14:30 +04:00
case LDB_OP_PRESENT :
ret - > operation = LDB_OP_PRESENT ;
ret - > u . present . attr = attr ;
break ;
2005-07-19 13:09:00 +04:00
case LDB_OP_EQUALITY :
2004-03-31 10:45:39 +04:00
2005-07-19 13:09:00 +04:00
if ( strcmp ( value , " * " ) = = 0 ) {
ret - > operation = LDB_OP_PRESENT ;
ret - > u . present . attr = attr ;
break ;
}
2005-06-14 05:35:44 +04:00
2005-07-19 13:09:00 +04:00
if ( ldb_parse_find_wildcard ( value ) ! = NULL ) {
ret - > operation = LDB_OP_SUBSTRING ;
ret - > u . substring . attr = attr ;
ret - > u . substring . start_with_wildcard = 0 ;
ret - > u . substring . end_with_wildcard = 0 ;
ret - > u . substring . chunks = ldb_wildcard_decode ( ret , value ) ;
if ( ret - > u . substring . chunks = = NULL ) {
talloc_free ( ret ) ;
return NULL ;
}
if ( value [ 0 ] = = ' * ' )
ret - > u . substring . start_with_wildcard = 1 ;
if ( value [ strlen ( value ) - 1 ] = = ' * ' )
ret - > u . substring . end_with_wildcard = 1 ;
talloc_free ( value ) ;
break ;
}
ret - > operation = LDB_OP_EQUALITY ;
ret - > u . equality . attr = attr ;
ret - > u . equality . value = ldb_binary_decode ( ret , value ) ;
if ( ret - > u . equality . value . data = = NULL ) {
talloc_free ( ret ) ;
return NULL ;
}
talloc_free ( value ) ;
break ;
case LDB_OP_GREATER :
ret - > operation = LDB_OP_GREATER ;
ret - > u . comparison . attr = attr ;
ret - > u . comparison . value = ldb_binary_decode ( ret , value ) ;
if ( ret - > u . comparison . value . data = = NULL ) {
talloc_free ( ret ) ;
return NULL ;
}
talloc_free ( value ) ;
break ;
case LDB_OP_LESS :
ret - > operation = LDB_OP_LESS ;
ret - > u . comparison . attr = attr ;
ret - > u . comparison . value = ldb_binary_decode ( ret , value ) ;
if ( ret - > u . comparison . value . data = = NULL ) {
talloc_free ( ret ) ;
return NULL ;
}
talloc_free ( value ) ;
break ;
case LDB_OP_APPROX :
ret - > operation = LDB_OP_APPROX ;
ret - > u . comparison . attr = attr ;
ret - > u . comparison . value = ldb_binary_decode ( ret , value ) ;
if ( ret - > u . comparison . value . data = = NULL ) {
talloc_free ( ret ) ;
return NULL ;
}
talloc_free ( value ) ;
break ;
2005-07-12 16:04:54 +04:00
2005-07-19 13:09:00 +04:00
case LDB_OP_EXTENDED :
2005-07-12 16:04:54 +04:00
2005-07-19 13:09:00 +04:00
ret = ldb_parse_extended ( ret , attr , value ) ;
break ;
2005-07-12 16:04:54 +04:00
2005-07-19 13:09:00 +04:00
default :
2005-07-12 16:04:54 +04:00
talloc_free ( ret ) ;
return NULL ;
}
2004-03-31 10:45:39 +04:00
return ret ;
}
/*
parse a filterlist
< and > : : = ' & ' < filterlist >
< or > : : = ' | ' < filterlist >
< filterlist > : : = < filter > | < filter > < filterlist >
*/
2020-04-21 06:37:40 +03:00
static struct ldb_parse_tree * ldb_parse_filterlist (
TALLOC_CTX * mem_ctx ,
const char * * s ,
unsigned depth ,
unsigned max_depth )
2004-03-31 10:45:39 +04:00
{
struct ldb_parse_tree * ret , * next ;
2005-07-19 13:09:00 +04:00
enum ldb_parse_op op ;
const char * p = * s ;
switch ( * p ) {
case ' & ' :
op = LDB_OP_AND ;
break ;
case ' | ' :
op = LDB_OP_OR ;
break ;
default :
return NULL ;
}
p + + ;
while ( isspace ( ( unsigned char ) * p ) ) p + + ;
2004-03-31 10:45:39 +04:00
2005-06-13 13:10:17 +04:00
ret = talloc ( mem_ctx , struct ldb_parse_tree ) ;
2004-03-31 10:45:39 +04:00
if ( ! ret ) {
errno = ENOMEM ;
return NULL ;
}
ret - > operation = op ;
ret - > u . list . num_elements = 1 ;
2005-01-12 19:00:01 +03:00
ret - > u . list . elements = talloc ( ret , struct ldb_parse_tree * ) ;
2004-03-31 10:45:39 +04:00
if ( ! ret - > u . list . elements ) {
errno = ENOMEM ;
2005-01-02 10:49:29 +03:00
talloc_free ( ret ) ;
2004-03-31 10:45:39 +04:00
return NULL ;
}
2020-04-21 06:37:40 +03:00
ret - > u . list . elements [ 0 ] =
ldb_parse_filter ( ret - > u . list . elements , & p , depth , max_depth ) ;
2004-03-31 10:45:39 +04:00
if ( ! ret - > u . list . elements [ 0 ] ) {
2005-01-02 10:49:29 +03:00
talloc_free ( ret ) ;
2004-03-31 10:45:39 +04:00
return NULL ;
}
2005-07-19 13:09:00 +04:00
while ( isspace ( ( unsigned char ) * p ) ) p + + ;
2004-03-31 10:45:39 +04:00
2011-07-28 09:51:31 +04:00
while ( * p ) {
2011-11-02 17:53:20 +04:00
struct ldb_parse_tree * * e ;
2011-07-28 09:51:31 +04:00
if ( * p = = ' ) ' ) {
break ;
}
2020-04-21 06:37:40 +03:00
next = ldb_parse_filter (
ret - > u . list . elements , & p , depth , max_depth ) ;
2011-07-28 09:51:31 +04:00
if ( next = = NULL ) {
/* an invalid filter element */
talloc_free ( ret ) ;
return NULL ;
}
2005-01-12 19:00:01 +03:00
e = talloc_realloc ( ret , ret - > u . list . elements ,
2005-01-02 10:49:29 +03:00
struct ldb_parse_tree * ,
2005-07-19 13:09:00 +04:00
ret - > u . list . num_elements + 1 ) ;
2004-03-31 10:45:39 +04:00
if ( ! e ) {
errno = ENOMEM ;
2005-01-02 10:49:29 +03:00
talloc_free ( ret ) ;
2004-03-31 10:45:39 +04:00
return NULL ;
}
ret - > u . list . elements = e ;
ret - > u . list . elements [ ret - > u . list . num_elements ] = next ;
ret - > u . list . num_elements + + ;
2005-07-19 13:09:00 +04:00
while ( isspace ( ( unsigned char ) * p ) ) p + + ;
2004-03-31 10:45:39 +04:00
}
2005-07-19 13:09:00 +04:00
* s = p ;
2004-03-31 10:45:39 +04:00
return ret ;
}
/*
< not > : : = ' ! ' < filter >
*/
2020-04-21 06:37:40 +03:00
static struct ldb_parse_tree * ldb_parse_not (
TALLOC_CTX * mem_ctx ,
const char * * s ,
unsigned depth ,
unsigned max_depth )
2004-03-31 10:45:39 +04:00
{
struct ldb_parse_tree * ret ;
2005-07-19 13:09:00 +04:00
const char * p = * s ;
if ( * p ! = ' ! ' ) {
return NULL ;
}
p + + ;
2004-03-31 10:45:39 +04:00
2005-06-13 13:10:17 +04:00
ret = talloc ( mem_ctx , struct ldb_parse_tree ) ;
2004-03-31 10:45:39 +04:00
if ( ! ret ) {
errno = ENOMEM ;
return NULL ;
}
ret - > operation = LDB_OP_NOT ;
2020-04-21 06:37:40 +03:00
ret - > u . isnot . child = ldb_parse_filter ( ret , & p , depth , max_depth ) ;
2005-07-13 09:55:28 +04:00
if ( ! ret - > u . isnot . child ) {
2005-01-02 10:49:29 +03:00
talloc_free ( ret ) ;
2004-03-31 10:45:39 +04:00
return NULL ;
}
2005-07-19 13:09:00 +04:00
* s = p ;
2004-03-31 10:45:39 +04:00
return ret ;
}
/*
parse a filtercomp
< filtercomp > : : = < and > | < or > | < not > | < simple >
*/
2020-04-21 06:37:40 +03:00
static struct ldb_parse_tree * ldb_parse_filtercomp (
TALLOC_CTX * mem_ctx ,
const char * * s ,
unsigned depth ,
unsigned max_depth )
2004-03-31 10:45:39 +04:00
{
2005-07-19 13:09:00 +04:00
struct ldb_parse_tree * ret ;
const char * p = * s ;
2004-03-31 10:45:39 +04:00
2005-07-19 13:09:00 +04:00
while ( isspace ( ( unsigned char ) * p ) ) p + + ;
switch ( * p ) {
2004-03-31 10:45:39 +04:00
case ' & ' :
2020-04-21 06:37:40 +03:00
ret = ldb_parse_filterlist ( mem_ctx , & p , depth , max_depth ) ;
2005-07-19 13:09:00 +04:00
break ;
2004-03-31 10:45:39 +04:00
case ' | ' :
2020-04-21 06:37:40 +03:00
ret = ldb_parse_filterlist ( mem_ctx , & p , depth , max_depth ) ;
2005-07-19 13:09:00 +04:00
break ;
2004-03-31 10:45:39 +04:00
case ' ! ' :
2020-04-21 06:37:40 +03:00
ret = ldb_parse_not ( mem_ctx , & p , depth , max_depth ) ;
2005-07-19 13:09:00 +04:00
break ;
2004-03-31 10:45:39 +04:00
case ' ( ' :
case ' ) ' :
return NULL ;
2005-07-19 13:09:00 +04:00
default :
ret = ldb_parse_simple ( mem_ctx , & p ) ;
2004-03-31 10:45:39 +04:00
}
2005-07-19 13:09:00 +04:00
* s = p ;
return ret ;
2004-03-31 10:45:39 +04:00
}
/*
< filter > : : = ' ( ' < filtercomp > ' ) '
*/
2020-04-21 06:37:40 +03:00
static struct ldb_parse_tree * ldb_parse_filter (
TALLOC_CTX * mem_ctx ,
const char * * s ,
unsigned depth ,
unsigned max_depth )
2004-03-31 10:45:39 +04:00
{
struct ldb_parse_tree * ret ;
2005-07-19 13:09:00 +04:00
const char * p = * s ;
2004-03-31 10:45:39 +04:00
2020-04-21 06:37:40 +03:00
/*
* Check the depth of the parse tree , and reject the input if
* max_depth exceeded . This avoids stack overflow
* issues .
*/
if ( depth > max_depth ) {
return NULL ;
}
depth + + ;
2005-07-19 13:09:00 +04:00
if ( * p ! = ' ( ' ) {
2004-03-31 10:45:39 +04:00
return NULL ;
}
2005-07-19 13:09:00 +04:00
p + + ;
2004-03-31 10:45:39 +04:00
2020-04-21 06:37:40 +03:00
ret = ldb_parse_filtercomp ( mem_ctx , & p , depth , max_depth ) ;
2004-03-31 10:45:39 +04:00
2005-07-19 13:09:00 +04:00
if ( * p ! = ' ) ' ) {
2004-03-31 10:45:39 +04:00
return NULL ;
}
2005-07-19 13:09:00 +04:00
p + + ;
2004-03-31 10:45:39 +04:00
2005-07-19 13:09:00 +04:00
while ( isspace ( ( unsigned char ) * p ) ) {
p + + ;
2004-03-31 10:45:39 +04:00
}
2005-07-19 13:09:00 +04:00
* s = p ;
2004-03-31 10:45:39 +04:00
return ret ;
}
/*
main parser entry point . Takes a search string and returns a parse tree
expression : : = < simple > | < filter >
*/
2010-07-13 03:37:58 +04:00
struct ldb_parse_tree * ldb_parse_tree ( TALLOC_CTX * mem_ctx , const char * s )
2004-03-31 10:45:39 +04:00
{
2020-04-21 06:37:40 +03:00
unsigned depth = 0 ;
2019-04-12 01:46:37 +03:00
while ( s & & isspace ( ( unsigned char ) * s ) ) s + + ;
2005-10-06 09:24:46 +04:00
if ( s = = NULL | | * s = = 0 ) {
2005-10-11 15:00:16 +04:00
s = " (|(objectClass=*)(distinguishedName=*)) " ;
2005-10-01 03:14:30 +04:00
}
2004-03-31 10:45:39 +04:00
if ( * s = = ' ( ' ) {
2020-04-21 06:37:40 +03:00
return ldb_parse_filter (
mem_ctx , & s , depth , LDB_MAX_PARSE_TREE_DEPTH ) ;
2004-03-31 10:45:39 +04:00
}
2005-07-19 13:09:00 +04:00
return ldb_parse_simple ( mem_ctx , & s ) ;
2004-03-31 10:45:39 +04:00
}
2005-06-13 10:52:48 +04:00
/*
construct a ldap parse filter given a parse tree
*/
2010-11-23 12:19:49 +03:00
char * ldb_filter_from_tree ( TALLOC_CTX * mem_ctx , const struct ldb_parse_tree * tree )
2005-06-13 10:52:48 +04:00
{
char * s , * s2 , * ret ;
2009-11-06 20:35:17 +03:00
unsigned int i ;
2005-06-13 10:52:48 +04:00
2005-10-01 03:14:30 +04:00
if ( tree = = NULL ) {
return NULL ;
}
2005-06-13 10:52:48 +04:00
switch ( tree - > operation ) {
2005-07-19 13:09:00 +04:00
case LDB_OP_AND :
case LDB_OP_OR :
2005-10-01 03:14:30 +04:00
ret = talloc_asprintf ( mem_ctx , " (%c " , tree - > operation = = LDB_OP_AND ? ' & ' : ' | ' ) ;
2005-07-19 13:09:00 +04:00
if ( ret = = NULL ) return NULL ;
for ( i = 0 ; i < tree - > u . list . num_elements ; i + + ) {
s = ldb_filter_from_tree ( mem_ctx , tree - > u . list . elements [ i ] ) ;
if ( s = = NULL ) {
talloc_free ( ret ) ;
return NULL ;
}
s2 = talloc_asprintf_append ( ret , " %s " , s ) ;
talloc_free ( s ) ;
if ( s2 = = NULL ) {
talloc_free ( ret ) ;
return NULL ;
}
ret = s2 ;
}
s = talloc_asprintf_append ( ret , " ) " ) ;
if ( s = = NULL ) {
talloc_free ( ret ) ;
return NULL ;
}
return s ;
case LDB_OP_NOT :
s = ldb_filter_from_tree ( mem_ctx , tree - > u . isnot . child ) ;
2005-06-13 10:52:48 +04:00
if ( s = = NULL ) return NULL ;
2005-07-19 13:09:00 +04:00
ret = talloc_asprintf ( mem_ctx , " (!%s) " , s ) ;
2005-06-13 10:52:48 +04:00
talloc_free ( s ) ;
return ret ;
2005-07-19 13:09:00 +04:00
case LDB_OP_EQUALITY :
s = ldb_binary_encode ( mem_ctx , tree - > u . equality . value ) ;
2005-06-14 05:35:44 +04:00
if ( s = = NULL ) return NULL ;
2005-07-19 13:09:00 +04:00
ret = talloc_asprintf ( mem_ctx , " (%s=%s) " ,
tree - > u . equality . attr , s ) ;
2005-06-14 05:35:44 +04:00
talloc_free ( s ) ;
return ret ;
2005-07-12 16:04:54 +04:00
case LDB_OP_SUBSTRING :
2005-10-06 09:41:32 +04:00
ret = talloc_asprintf ( mem_ctx , " (%s=%s " , tree - > u . substring . attr ,
tree - > u . substring . start_with_wildcard ? " * " : " " ) ;
2005-07-12 16:04:54 +04:00
if ( ret = = NULL ) return NULL ;
2013-06-22 11:01:02 +04:00
for ( i = 0 ; tree - > u . substring . chunks & & tree - > u . substring . chunks [ i ] ; i + + ) {
2005-07-12 16:04:54 +04:00
s2 = ldb_binary_encode ( mem_ctx , * ( tree - > u . substring . chunks [ i ] ) ) ;
if ( s2 = = NULL ) {
talloc_free ( ret ) ;
return NULL ;
}
2005-10-06 09:53:46 +04:00
if ( tree - > u . substring . chunks [ i + 1 ] | |
tree - > u . substring . end_with_wildcard ) {
s = talloc_asprintf_append ( ret , " %s* " , s2 ) ;
} else {
s = talloc_asprintf_append ( ret , " %s " , s2 ) ;
}
2005-07-12 16:04:54 +04:00
if ( s = = NULL ) {
talloc_free ( ret ) ;
return NULL ;
}
ret = s ;
}
2005-10-06 09:41:32 +04:00
s = talloc_asprintf_append ( ret , " ) " ) ;
if ( s = = NULL ) {
talloc_free ( ret ) ;
return NULL ;
}
ret = s ;
2005-07-12 16:04:54 +04:00
return ret ;
2005-07-19 13:09:00 +04:00
case LDB_OP_GREATER :
2023-02-14 04:18:45 +03:00
s = ldb_binary_encode ( mem_ctx , tree - > u . comparison . value ) ;
2005-07-19 13:09:00 +04:00
if ( s = = NULL ) return NULL ;
ret = talloc_asprintf ( mem_ctx , " (%s>=%s) " ,
2023-02-14 04:18:45 +03:00
tree - > u . comparison . attr , s ) ;
2005-07-19 13:09:00 +04:00
talloc_free ( s ) ;
return ret ;
case LDB_OP_LESS :
2023-02-14 04:18:45 +03:00
s = ldb_binary_encode ( mem_ctx , tree - > u . comparison . value ) ;
2005-07-19 13:09:00 +04:00
if ( s = = NULL ) return NULL ;
ret = talloc_asprintf ( mem_ctx , " (%s<=%s) " ,
2023-02-14 04:18:45 +03:00
tree - > u . comparison . attr , s ) ;
2005-07-19 13:09:00 +04:00
talloc_free ( s ) ;
return ret ;
2005-07-12 16:04:54 +04:00
case LDB_OP_PRESENT :
2005-10-01 03:14:30 +04:00
ret = talloc_asprintf ( mem_ctx , " (%s=*) " , tree - > u . present . attr ) ;
2005-07-12 16:04:54 +04:00
return ret ;
2005-07-19 13:09:00 +04:00
case LDB_OP_APPROX :
2023-02-14 04:18:45 +03:00
s = ldb_binary_encode ( mem_ctx , tree - > u . comparison . value ) ;
2005-06-13 10:52:48 +04:00
if ( s = = NULL ) return NULL ;
2005-07-19 13:09:00 +04:00
ret = talloc_asprintf ( mem_ctx , " (%s~=%s) " ,
2023-02-14 04:18:45 +03:00
tree - > u . comparison . attr , s ) ;
2005-07-19 13:09:00 +04:00
talloc_free ( s ) ;
return ret ;
case LDB_OP_EXTENDED :
s = ldb_binary_encode ( mem_ctx , tree - > u . extended . value ) ;
if ( s = = NULL ) return NULL ;
ret = talloc_asprintf ( mem_ctx , " (%s%s%s%s:=%s) " ,
tree - > u . extended . attr ? tree - > u . extended . attr : " " ,
tree - > u . extended . dnAttributes ? " :dn " : " " ,
tree - > u . extended . rule_id ? " : " : " " ,
tree - > u . extended . rule_id ? tree - > u . extended . rule_id : " " ,
s ) ;
2005-06-13 10:52:48 +04:00
talloc_free ( s ) ;
return ret ;
}
return NULL ;
}
2005-10-12 10:10:23 +04:00
/*
2011-08-01 11:46:39 +04:00
walk a parse tree , calling the provided callback on each node
2005-10-12 10:10:23 +04:00
*/
2011-08-01 11:46:39 +04:00
int ldb_parse_tree_walk ( struct ldb_parse_tree * tree ,
int ( * callback ) ( struct ldb_parse_tree * tree , void * ) ,
void * private_context )
2005-10-12 10:10:23 +04:00
{
2009-11-06 20:35:17 +03:00
unsigned int i ;
2011-08-01 11:46:39 +04:00
int ret ;
ret = callback ( tree , private_context ) ;
if ( ret ! = LDB_SUCCESS ) {
return ret ;
}
2005-10-12 10:10:23 +04:00
switch ( tree - > operation ) {
case LDB_OP_AND :
case LDB_OP_OR :
for ( i = 0 ; i < tree - > u . list . num_elements ; i + + ) {
2011-08-01 11:46:39 +04:00
ret = ldb_parse_tree_walk ( tree - > u . list . elements [ i ] , callback , private_context ) ;
if ( ret ! = LDB_SUCCESS ) {
return ret ;
}
2005-10-12 10:10:23 +04:00
}
break ;
case LDB_OP_NOT :
2011-08-01 11:46:39 +04:00
ret = ldb_parse_tree_walk ( tree - > u . isnot . child , callback , private_context ) ;
if ( ret ! = LDB_SUCCESS ) {
return ret ;
}
2005-10-12 10:10:23 +04:00
break ;
case LDB_OP_EQUALITY :
case LDB_OP_GREATER :
case LDB_OP_LESS :
case LDB_OP_APPROX :
2011-08-01 11:46:39 +04:00
case LDB_OP_SUBSTRING :
case LDB_OP_PRESENT :
case LDB_OP_EXTENDED :
break ;
}
return LDB_SUCCESS ;
}
struct parse_tree_attr_replace_ctx {
const char * attr ;
const char * replace ;
} ;
/*
callback for ldb_parse_tree_attr_replace ( )
*/
static int parse_tree_attr_replace ( struct ldb_parse_tree * tree , void * private_context )
{
struct parse_tree_attr_replace_ctx * ctx = private_context ;
switch ( tree - > operation ) {
case LDB_OP_EQUALITY :
2023-02-14 04:18:45 +03:00
if ( ldb_attr_cmp ( tree - > u . equality . attr , ctx - > attr ) = = 0 ) {
tree - > u . equality . attr = ctx - > replace ;
}
break ;
2011-08-01 11:46:39 +04:00
case LDB_OP_GREATER :
case LDB_OP_LESS :
case LDB_OP_APPROX :
2023-02-14 04:18:45 +03:00
if ( ldb_attr_cmp ( tree - > u . comparison . attr , ctx - > attr ) = = 0 ) {
tree - > u . comparison . attr = ctx - > replace ;
2005-10-12 10:10:23 +04:00
}
break ;
case LDB_OP_SUBSTRING :
2011-08-01 11:46:39 +04:00
if ( ldb_attr_cmp ( tree - > u . substring . attr , ctx - > attr ) = = 0 ) {
tree - > u . substring . attr = ctx - > replace ;
2005-10-12 10:10:23 +04:00
}
break ;
case LDB_OP_PRESENT :
2011-08-01 11:46:39 +04:00
if ( ldb_attr_cmp ( tree - > u . present . attr , ctx - > attr ) = = 0 ) {
tree - > u . present . attr = ctx - > replace ;
2005-10-12 10:10:23 +04:00
}
break ;
case LDB_OP_EXTENDED :
if ( tree - > u . extended . attr & &
2011-08-01 11:46:39 +04:00
ldb_attr_cmp ( tree - > u . extended . attr , ctx - > attr ) = = 0 ) {
tree - > u . extended . attr = ctx - > replace ;
2005-10-12 10:10:23 +04:00
}
break ;
2011-08-01 11:46:39 +04:00
default :
break ;
2005-10-12 10:10:23 +04:00
}
2011-08-01 11:46:39 +04:00
return LDB_SUCCESS ;
}
/*
replace any occurrences of an attribute name in the parse tree with a
new name
*/
void ldb_parse_tree_attr_replace ( struct ldb_parse_tree * tree ,
const char * attr ,
const char * replace )
{
struct parse_tree_attr_replace_ctx ctx ;
ctx . attr = attr ;
ctx . replace = replace ;
ldb_parse_tree_walk ( tree , parse_tree_attr_replace , & ctx ) ;
2005-10-12 10:10:23 +04:00
}
2009-09-20 07:41:42 +04:00
/*
shallow copy a tree - copying only the elements array so that the caller
can safely add new elements without changing the message
*/
struct ldb_parse_tree * ldb_parse_tree_copy_shallow ( TALLOC_CTX * mem_ctx ,
const struct ldb_parse_tree * ot )
{
2009-11-06 20:35:17 +03:00
unsigned int i ;
2009-09-20 07:41:42 +04:00
struct ldb_parse_tree * nt ;
nt = talloc ( mem_ctx , struct ldb_parse_tree ) ;
if ( ! nt ) {
return NULL ;
}
* nt = * ot ;
switch ( ot - > operation ) {
case LDB_OP_AND :
case LDB_OP_OR :
2009-09-20 14:47:52 +04:00
nt - > u . list . elements = talloc_array ( nt , struct ldb_parse_tree * ,
2009-09-20 07:41:42 +04:00
ot - > u . list . num_elements ) ;
if ( ! nt - > u . list . elements ) {
talloc_free ( nt ) ;
return NULL ;
}
for ( i = 0 ; i < ot - > u . list . num_elements ; i + + ) {
nt - > u . list . elements [ i ] =
ldb_parse_tree_copy_shallow ( nt - > u . list . elements ,
ot - > u . list . elements [ i ] ) ;
if ( ! nt - > u . list . elements [ i ] ) {
talloc_free ( nt ) ;
return NULL ;
}
}
break ;
case LDB_OP_NOT :
nt - > u . isnot . child = ldb_parse_tree_copy_shallow ( nt ,
ot - > u . isnot . child ) ;
if ( ! nt - > u . isnot . child ) {
talloc_free ( nt ) ;
return NULL ;
}
break ;
case LDB_OP_EQUALITY :
case LDB_OP_GREATER :
case LDB_OP_LESS :
case LDB_OP_APPROX :
case LDB_OP_SUBSTRING :
case LDB_OP_PRESENT :
case LDB_OP_EXTENDED :
break ;
}
return nt ;
}
2023-03-03 07:31:54 +03:00
/* Get the attribute (if any) associated with the top node of a parse tree. */
const char * ldb_parse_tree_get_attr ( const struct ldb_parse_tree * tree )
{
switch ( tree - > operation ) {
case LDB_OP_AND :
case LDB_OP_OR :
case LDB_OP_NOT :
return NULL ;
case LDB_OP_EQUALITY :
return tree - > u . equality . attr ;
case LDB_OP_SUBSTRING :
return tree - > u . substring . attr ;
case LDB_OP_GREATER :
case LDB_OP_LESS :
case LDB_OP_APPROX :
return tree - > u . comparison . attr ;
case LDB_OP_PRESENT :
return tree - > u . present . attr ;
case LDB_OP_EXTENDED :
return tree - > u . extended . attr ;
}
return NULL ;
}