2009-08-30 16:07:44 -04:00
/*
2005-06-27 00:00:50 +00:00
ldb database library
r8037: a fairly major update to the internals of ldb. Changes are:
- moved the knowledge of attribute types out of ldb_tdb and into the
generic ldb code. This allows the ldb_match() message match logic
to be generic, so it can be used by other backend
- added the generic ability to load attribute handlers, for
canonicalisation, compare, ldif read and ldif write. In the future
this will be used by the schema module to allow us to correctly
obey the attributetype schema elements
- added attribute handlers for some of the core ldap attribute types,
Integer, DirectoryString, DN, ObjectClass etc
- added automatic registration of attribute handlers for well-known
attribute names 'cn', 'dc', 'dn', 'ou' and 'objectClass'
- converted the objectSid special handlers for Samba to the new system
- added more correct handling of indexing in tdb backend based on the
attribute canonicalisation function
- added generic support for subclasses, moving it out of the tdb
backend. This will be used in future by the schema module
- fixed several bugs in the dn_explode code. It still needs more
work, but doesn't corrupt ldb dbs any more.
(This used to be commit 944c5844ab441b96d8e5d7b2d151982139d1fab9)
2005-07-01 06:21:26 +00:00
Copyright ( C ) Simo Sorce 2005
2005-06-27 00:00:50 +00:00
* * NOTE ! The following LGPL license applies to the ldb
* * library . This does NOT imply that all of Samba is released
* * under the LGPL
2009-08-30 16:07:44 -04:00
2005-06-27 00:00:50 +00:00
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 02:46:15 +00:00
version 3 of the License , or ( at your option ) any later version .
2005-06-27 00:00:50 +00: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 03:42:26 +00:00
License along with this library ; if not , see < http : //www.gnu.org/licenses/>.
2005-06-27 00:00:50 +00:00
*/
/*
* Name : ldb
*
2006-11-22 00:59:34 +00:00
* Component : ldb dn creation and manipulation utility functions
2005-06-27 00:00:50 +00:00
*
* Description : - explode a dn into it ' s own basic elements
2006-11-22 00:59:34 +00:00
* and put them in a structure ( only if necessary )
2005-06-27 00:00:50 +00:00
* - manipulate ldb_dn structures
*
* Author : Simo Sorce
*/
2009-01-29 18:39:30 -05:00
# include "ldb_private.h"
2007-05-06 11:03:33 +00:00
# include <ctype.h>
2005-06-27 00:00:50 +00:00
r8037: a fairly major update to the internals of ldb. Changes are:
- moved the knowledge of attribute types out of ldb_tdb and into the
generic ldb code. This allows the ldb_match() message match logic
to be generic, so it can be used by other backend
- added the generic ability to load attribute handlers, for
canonicalisation, compare, ldif read and ldif write. In the future
this will be used by the schema module to allow us to correctly
obey the attributetype schema elements
- added attribute handlers for some of the core ldap attribute types,
Integer, DirectoryString, DN, ObjectClass etc
- added automatic registration of attribute handlers for well-known
attribute names 'cn', 'dc', 'dn', 'ou' and 'objectClass'
- converted the objectSid special handlers for Samba to the new system
- added more correct handling of indexing in tdb backend based on the
attribute canonicalisation function
- added generic support for subclasses, moving it out of the tdb
backend. This will be used in future by the schema module
- fixed several bugs in the dn_explode code. It still needs more
work, but doesn't corrupt ldb dbs any more.
(This used to be commit 944c5844ab441b96d8e5d7b2d151982139d1fab9)
2005-07-01 06:21:26 +00:00
# define LDB_DN_NULL_FAILED(x) if (!(x)) goto failed
2005-06-27 00:00:50 +00:00
2024-03-15 23:29:34 +13:00
# define LDB_FREE(x) TALLOC_FREE(x)
2005-08-18 15:02:01 +00:00
2006-11-01 23:31:26 +00:00
/**
internal ldb exploded dn structures
*/
struct ldb_dn_component {
2006-11-22 00:59:34 +00:00
char * name ;
2006-11-01 23:31:26 +00:00
struct ldb_val value ;
2006-11-22 00:59:34 +00:00
char * cf_name ;
struct ldb_val cf_value ;
2006-11-01 23:31:26 +00:00
} ;
2009-08-30 16:07:44 -04:00
struct ldb_dn_ext_component {
2008-12-16 08:19:07 +01:00
2016-06-17 13:28:59 +12:00
const char * name ;
2008-12-16 08:19:07 +01:00
struct ldb_val value ;
} ;
2006-11-01 23:31:26 +00:00
struct ldb_dn {
2006-11-22 00:59:34 +00:00
struct ldb_context * ldb ;
/* Special DNs are always linearized */
bool special ;
bool invalid ;
bool valid_case ;
char * linearized ;
2009-08-30 16:07:44 -04:00
char * ext_linearized ;
2006-11-22 00:59:34 +00:00
char * casefold ;
unsigned int comp_num ;
2006-11-01 23:31:26 +00:00
struct ldb_dn_component * components ;
2006-11-22 00:59:34 +00:00
2009-08-30 16:07:44 -04:00
unsigned int ext_comp_num ;
struct ldb_dn_ext_component * ext_components ;
2006-11-01 23:31:26 +00:00
} ;
2009-10-02 12:03:05 +10:00
/* it is helpful to be able to break on this in gdb */
static void ldb_dn_mark_invalid ( struct ldb_dn * dn )
{
dn - > invalid = true ;
}
2006-11-22 00:59:34 +00:00
/* strdn may be NULL */
2010-07-13 02:37:58 +03:00
struct ldb_dn * ldb_dn_from_ldb_val ( TALLOC_CTX * mem_ctx ,
2009-08-30 16:07:44 -04:00
struct ldb_context * ldb ,
const struct ldb_val * strdn )
2005-08-18 15:02:01 +00:00
{
2006-11-22 00:59:34 +00:00
struct ldb_dn * dn ;
2005-08-18 15:02:01 +00:00
2019-05-08 12:31:36 +12:00
if ( ldb = = NULL | | strdn = = NULL ) {
return NULL ;
}
if ( strdn - > data
2009-10-21 22:18:16 +11:00
& & ( strnlen ( ( const char * ) strdn - > data , strdn - > length ) ! = strdn - > length ) ) {
2009-09-22 14:37:58 -07:00
/* The RDN must not contain a character with value 0x0 */
return NULL ;
}
2006-11-22 00:59:34 +00:00
dn = talloc_zero ( mem_ctx , struct ldb_dn ) ;
LDB_DN_NULL_FAILED ( dn ) ;
2010-01-09 09:03:08 +11:00
dn - > ldb = talloc_get_type ( ldb , struct ldb_context ) ;
if ( dn - > ldb = = NULL ) {
/* the caller probably got the arguments to
ldb_dn_new ( ) mixed up */
talloc_free ( dn ) ;
return NULL ;
}
2006-11-22 00:59:34 +00:00
2008-08-21 19:24:58 +10:00
if ( strdn - > data & & strdn - > length ) {
2009-08-30 16:07:44 -04:00
const char * data = ( const char * ) strdn - > data ;
size_t length = strdn - > length ;
if ( data [ 0 ] = = ' @ ' ) {
2006-11-22 00:59:34 +00:00
dn - > special = true ;
2009-08-30 16:07:44 -04:00
}
dn - > ext_linearized = talloc_strndup ( dn , data , length ) ;
LDB_DN_NULL_FAILED ( dn - > ext_linearized ) ;
if ( data [ 0 ] = = ' < ' ) {
const char * p_save , * p = dn - > ext_linearized ;
2008-12-16 08:19:07 +01:00
do {
p_save = p ;
p = strstr ( p , " >; " ) ;
if ( p ) {
p = p + 2 ;
}
} while ( p ) ;
2009-08-30 16:07:44 -04:00
if ( p_save = = dn - > ext_linearized ) {
2008-12-16 08:19:07 +01:00
dn - > linearized = talloc_strdup ( dn , " " ) ;
} else {
dn - > linearized = talloc_strdup ( dn , p_save ) ;
}
LDB_DN_NULL_FAILED ( dn - > linearized ) ;
} else {
2009-08-30 16:07:44 -04:00
dn - > linearized = dn - > ext_linearized ;
dn - > ext_linearized = NULL ;
2006-11-22 00:59:34 +00:00
}
} else {
dn - > linearized = talloc_strdup ( dn , " " ) ;
2008-12-16 08:19:07 +01:00
LDB_DN_NULL_FAILED ( dn - > linearized ) ;
2006-11-22 00:59:34 +00:00
}
return dn ;
2005-08-18 15:02:01 +00:00
2006-11-22 00:59:34 +00:00
failed :
talloc_free ( dn ) ;
return NULL ;
2005-08-18 15:02:01 +00:00
}
2008-08-21 19:24:58 +10:00
/* strdn may be NULL */
2010-07-13 02:37:58 +03:00
struct ldb_dn * ldb_dn_new ( TALLOC_CTX * mem_ctx ,
2009-08-30 16:07:44 -04:00
struct ldb_context * ldb ,
const char * strdn )
2008-08-21 19:24:58 +10:00
{
struct ldb_val blob ;
2009-10-02 12:03:05 +10:00
blob . data = discard_const_p ( uint8_t , strdn ) ;
2008-08-21 19:24:58 +10:00
blob . length = strdn ? strlen ( strdn ) : 0 ;
return ldb_dn_from_ldb_val ( mem_ctx , ldb , & blob ) ;
}
2010-07-13 02:37:58 +03:00
struct ldb_dn * ldb_dn_new_fmt ( TALLOC_CTX * mem_ctx ,
2009-08-30 16:07:44 -04:00
struct ldb_context * ldb ,
const char * new_fmt , . . . )
2005-06-27 00:00:50 +00:00
{
2006-11-22 00:59:34 +00:00
char * strdn ;
va_list ap ;
2005-06-27 00:00:50 +00:00
2016-03-21 09:15:17 -04:00
if ( ! ldb ) return NULL ;
2006-11-22 00:59:34 +00:00
va_start ( ap , new_fmt ) ;
2008-12-16 08:19:07 +01:00
strdn = talloc_vasprintf ( mem_ctx , new_fmt , ap ) ;
2006-11-22 00:59:34 +00:00
va_end ( ap ) ;
2008-12-16 08:19:07 +01:00
if ( strdn ) {
struct ldb_dn * dn = ldb_dn_new ( mem_ctx , ldb , strdn ) ;
talloc_free ( strdn ) ;
return dn ;
}
2009-08-30 16:07:44 -04:00
2006-11-22 00:59:34 +00:00
return NULL ;
}
2009-11-13 17:48:35 +11:00
/* see RFC2253 section 2.4 */
2006-11-22 00:59:34 +00:00
static int ldb_dn_escape_internal ( char * dst , const char * src , int len )
{
2015-11-24 13:07:23 +13:00
char c ;
2006-11-22 00:59:34 +00:00
char * d ;
2015-11-24 13:07:23 +13:00
int i ;
2006-11-22 00:59:34 +00:00
d = dst ;
2005-06-27 00:00:50 +00:00
2015-11-24 13:07:23 +13:00
for ( i = 0 ; i < len ; i + + ) {
c = src [ i ] ;
switch ( c ) {
2009-11-13 17:48:35 +11:00
case ' ' :
2015-11-24 13:07:23 +13:00
if ( i = = 0 | | i = = len - 1 ) {
2009-11-13 17:48:35 +11:00
/* if at the beginning or end
* of the string then escape */
* d + + = ' \\ ' ;
2015-11-24 13:07:23 +13:00
* d + + = c ;
2009-11-13 17:48:35 +11:00
} else {
/* otherwise don't escape */
2015-11-24 13:07:23 +13:00
* d + + = c ;
2009-11-13 17:48:35 +11:00
}
break ;
2005-07-02 17:30:03 +00:00
2009-11-13 17:48:35 +11:00
case ' # ' :
/* despite the RFC, windows escapes a #
anywhere in the string */
case ' , ' :
case ' + ' :
case ' " ' :
case ' \\ ' :
case ' < ' :
case ' > ' :
case ' ? ' :
/* these must be escaped using \c form */
2005-06-27 00:00:50 +00:00
* d + + = ' \\ ' ;
2015-11-24 13:07:23 +13:00
* d + + = c ;
2009-11-13 17:48:35 +11:00
break ;
2015-11-24 13:07:23 +13:00
case ' ; ' :
case ' \r ' :
case ' \n ' :
case ' = ' :
case ' \0 ' : {
2009-11-13 17:48:35 +11:00
/* any others get \XX form */
unsigned char v ;
2015-11-24 13:07:23 +13:00
v = ( const unsigned char ) c ;
2009-11-13 17:48:35 +11:00
* d + + = ' \\ ' ;
2024-09-10 10:02:04 +02:00
* d + + = hexchars_upper [ v > > 4 ] ;
* d + + = hexchars_upper [ v & 0xF ] ;
2009-11-13 17:48:35 +11:00
break ;
}
2015-11-24 13:07:23 +13:00
default :
* d + + = c ;
2005-06-27 00:00:50 +00:00
}
}
2006-11-22 00:59:34 +00:00
/* return the length of the resulting string */
2015-11-24 13:07:23 +13:00
return ( d - dst ) ;
2009-08-30 16:07:44 -04:00
}
2005-06-27 00:00:50 +00:00
2010-07-13 02:37:58 +03:00
char * ldb_dn_escape_value ( TALLOC_CTX * mem_ctx , struct ldb_val value )
2005-06-27 00:00:50 +00:00
{
2006-11-22 00:59:34 +00:00
char * dst ;
2015-11-24 13:09:36 +13:00
size_t len ;
2006-11-22 00:59:34 +00:00
if ( ! value . length )
return NULL ;
2005-06-27 00:00:50 +00:00
2006-11-22 00:59:34 +00:00
/* allocate destination string, it will be at most 3 times the source */
dst = talloc_array ( mem_ctx , char , value . length * 3 + 1 ) ;
if ( ! dst ) {
talloc_free ( dst ) ;
return NULL ;
2005-06-27 00:00:50 +00:00
}
2015-11-24 13:09:36 +13:00
len = ldb_dn_escape_internal ( dst , ( const char * ) value . data , value . length ) ;
2006-11-23 22:06:07 +00:00
2015-11-24 13:09:36 +13:00
dst = talloc_realloc ( mem_ctx , dst , char , len + 1 ) ;
if ( ! dst ) {
talloc_free ( dst ) ;
return NULL ;
}
dst [ len ] = ' \0 ' ;
2006-11-22 00:59:34 +00:00
return dst ;
2005-06-27 00:00:50 +00:00
}
2006-11-22 00:59:34 +00:00
/*
explode a DN string into a ldb_dn structure
based on RFC4514 except that we don ' t support multiple valued RDNs
2009-09-21 17:14:06 -07:00
TODO : according to MS - ADTS : 3.1 .1 .5 .2 Naming Constraints
DN must be compliant with RFC2253
2006-11-22 00:59:34 +00:00
*/
static bool ldb_dn_explode ( struct ldb_dn * dn )
2005-07-02 17:30:03 +00:00
{
2013-12-10 17:45:58 +01:00
char * p , * ex_name = NULL , * ex_value = NULL , * data , * d , * dt , * t ;
2011-01-08 21:59:37 +01:00
bool trim = true ;
bool in_extended = true ;
2008-12-16 08:19:07 +01:00
bool in_ex_name = false ;
bool in_ex_value = false ;
2006-11-22 00:59:34 +00:00
bool in_attr = false ;
bool in_value = false ;
bool in_quote = false ;
bool is_oid = false ;
bool escape = false ;
2009-11-06 18:35:17 +01:00
unsigned int x ;
2013-12-10 17:45:58 +01:00
size_t l = 0 ;
2009-11-06 18:35:17 +01:00
int ret ;
2008-12-16 08:19:07 +01:00
char * parse_dn ;
2009-10-25 22:02:31 +11:00
bool is_index ;
2005-06-27 00:00:50 +00:00
2022-04-10 18:22:55 +02:00
if ( dn = = NULL | | dn - > invalid ) {
2019-08-22 10:59:07 +12:00
return false ;
}
2005-07-02 17:30:03 +00:00
2019-08-22 10:59:07 +12:00
if ( dn - > components ! = NULL ) {
2006-11-22 00:59:34 +00:00
return true ;
}
2005-06-27 00:00:50 +00:00
2019-08-22 10:59:07 +12:00
if ( dn - > ext_linearized ! = NULL ) {
2009-08-30 16:07:44 -04:00
parse_dn = dn - > ext_linearized ;
2008-12-16 08:19:07 +01:00
} else {
parse_dn = dn - > linearized ;
}
2019-08-22 10:59:07 +12:00
if ( parse_dn = = NULL ) {
2006-11-22 00:59:34 +00:00
return false ;
}
2005-07-02 17:30:03 +00:00
2009-10-25 22:02:31 +11:00
is_index = ( strncmp ( parse_dn , " DN=@INDEX: " , 10 ) = = 0 ) ;
2009-10-02 12:03:05 +10:00
2006-11-22 00:59:34 +00:00
/* Empty DNs */
2008-12-16 08:19:07 +01:00
if ( parse_dn [ 0 ] = = ' \0 ' ) {
2006-11-22 00:59:34 +00:00
return true ;
2005-07-02 17:30:03 +00:00
}
2006-11-22 00:59:34 +00:00
/* Special DNs case */
2022-04-10 18:22:55 +02:00
if ( dn - > special ) {
2006-11-22 00:59:34 +00:00
return true ;
}
2005-07-02 17:30:03 +00:00
2010-02-25 23:19:53 +01:00
LDB_FREE ( dn - > ext_components ) ;
dn - > ext_comp_num = 0 ;
2019-02-08 15:49:56 +13:00
dn - > comp_num = 0 ;
2008-12-16 08:19:07 +01:00
2006-11-22 00:59:34 +00:00
/* in the common case we have 3 or more components */
2009-08-30 16:07:44 -04:00
/* make sure all components are zeroed, other functions depend on it */
2006-11-22 00:59:34 +00:00
dn - > components = talloc_zero_array ( dn , struct ldb_dn_component , 3 ) ;
2019-08-22 10:59:07 +12:00
if ( dn - > components = = NULL ) {
2006-11-22 00:59:34 +00:00
return false ;
}
2005-07-02 17:30:03 +00:00
2006-11-22 00:59:34 +00:00
/* Components data space is allocated here once */
2008-12-16 08:19:07 +01:00
data = talloc_array ( dn - > components , char , strlen ( parse_dn ) + 1 ) ;
2019-08-22 10:59:07 +12:00
if ( data = = NULL ) {
2019-03-08 12:12:00 +13:00
goto failed ;
2006-11-25 17:19:42 +00:00
}
2005-07-02 17:30:03 +00:00
2008-12-16 08:19:07 +01:00
p = parse_dn ;
2006-11-22 00:59:34 +00:00
t = NULL ;
d = dt = data ;
2005-08-18 15:02:01 +00:00
2006-11-22 00:59:34 +00:00
while ( * p ) {
2022-04-10 18:22:55 +02:00
if ( in_extended ) {
2008-12-16 08:19:07 +01:00
if ( ! in_ex_name & & ! in_ex_value ) {
if ( p [ 0 ] = = ' < ' ) {
p + + ;
ex_name = d ;
in_ex_name = true ;
continue ;
} else {
in_extended = false ;
in_attr = true ;
dt = d ;
continue ;
}
}
2009-08-30 16:07:44 -04:00
2008-12-16 08:19:07 +01:00
if ( in_ex_name & & * p = = ' = ' ) {
* d + + = ' \0 ' ;
p + + ;
ex_value = d ;
in_ex_name = false ;
in_ex_value = true ;
continue ;
}
if ( in_ex_value & & * p = = ' > ' ) {
2019-07-31 10:27:37 +02:00
struct ldb_dn_ext_component * ext_comp = NULL ;
2009-08-30 16:07:44 -04:00
const struct ldb_dn_extended_syntax * ext_syntax ;
2008-12-16 08:19:07 +01:00
struct ldb_val ex_val = {
2009-08-30 16:07:44 -04:00
. data = ( uint8_t * ) ex_value ,
2008-12-16 08:19:07 +01:00
. length = d - ex_value
} ;
2009-08-30 16:07:44 -04:00
2008-12-16 08:19:07 +01:00
* d + + = ' \0 ' ;
p + + ;
in_ex_value = false ;
/* Process name and ex_value */
2019-07-31 10:27:37 +02:00
ext_comp = talloc_realloc (
dn ,
dn - > ext_components ,
struct ldb_dn_ext_component ,
dn - > ext_comp_num + 1 ) ;
if ( ext_comp = = NULL ) {
2008-12-16 08:19:07 +01:00
/* ouch ! */
goto failed ;
}
2019-07-31 10:27:37 +02:00
dn - > ext_components = ext_comp ;
2009-08-30 16:07:44 -04:00
ext_syntax = ldb_dn_extended_syntax_by_name ( dn - > ldb , ex_name ) ;
2019-08-22 10:59:07 +12:00
if ( ext_syntax = = NULL ) {
2008-12-16 08:19:07 +01:00
/* We don't know about this type of extended DN */
goto failed ;
}
2016-06-17 13:28:59 +12:00
dn - > ext_components [ dn - > ext_comp_num ] . name = ext_syntax - > name ;
2009-08-30 16:07:44 -04:00
ret = ext_syntax - > read_fn ( dn - > ldb , dn - > ext_components ,
& ex_val , & dn - > ext_components [ dn - > ext_comp_num ] . value ) ;
2008-12-16 08:19:07 +01:00
if ( ret ! = LDB_SUCCESS ) {
2009-10-02 12:03:05 +10:00
ldb_dn_mark_invalid ( dn ) ;
2008-12-16 08:19:07 +01:00
goto failed ;
}
2009-08-30 16:07:44 -04:00
dn - > ext_comp_num + + ;
2005-07-02 17:30:03 +00:00
2008-12-16 08:19:07 +01:00
if ( * p = = ' \0 ' ) {
/* We have reached the end (extended component only)! */
talloc_free ( data ) ;
return true ;
} else if ( * p = = ' ; ' ) {
p + + ;
continue ;
} else {
2009-10-02 12:03:05 +10:00
ldb_dn_mark_invalid ( dn ) ;
2008-12-16 08:19:07 +01:00
goto failed ;
}
}
* d + + = * p + + ;
continue ;
}
2022-04-10 18:22:55 +02:00
if ( in_attr ) {
if ( trim ) {
2006-11-22 00:59:34 +00:00
if ( * p = = ' ' ) {
p + + ;
continue ;
}
/* first char */
trim = false ;
2007-05-06 15:17:14 +00:00
if ( ! isascii ( * p ) ) {
/* attr names must be ascii only */
2009-10-02 12:03:05 +10:00
ldb_dn_mark_invalid ( dn ) ;
2007-05-06 15:17:14 +00:00
goto failed ;
}
2006-11-22 00:59:34 +00:00
if ( isdigit ( * p ) ) {
is_oid = true ;
} else
if ( ! isalpha ( * p ) ) {
2009-08-30 16:07:44 -04:00
/* not a digit nor an alpha,
* invalid attribute name */
2009-10-02 12:03:05 +10:00
ldb_dn_mark_invalid ( dn ) ;
2006-11-22 00:59:34 +00:00
goto failed ;
}
2009-08-30 16:07:44 -04:00
/* Copy this character across from parse_dn,
* now we have trimmed out spaces */
2006-11-22 00:59:34 +00:00
* d + + = * p + + ;
continue ;
}
2005-07-02 17:30:03 +00:00
2006-11-22 00:59:34 +00:00
if ( * p = = ' ' ) {
p + + ;
/* valid only if we are at the end */
trim = true ;
continue ;
}
2005-07-02 17:30:03 +00:00
2006-11-22 00:59:34 +00:00
if ( * p = = ' = ' ) {
/* attribute terminated */
in_attr = false ;
in_value = true ;
trim = true ;
l = 0 ;
2005-07-02 17:30:03 +00:00
2009-08-30 16:07:44 -04:00
/* Terminate this string in d
* ( which is a copy of parse_dn
* with spaces trimmed ) */
2006-11-22 00:59:34 +00:00
* d + + = ' \0 ' ;
2006-11-23 22:06:07 +00:00
dn - > components [ dn - > comp_num ] . name = talloc_strdup ( dn - > components , dt ) ;
2019-08-22 10:59:07 +12:00
if ( dn - > components [ dn - > comp_num ] . name = = NULL ) {
2006-11-23 22:06:07 +00:00
/* ouch */
goto failed ;
}
2006-11-22 00:59:34 +00:00
dt = d ;
2005-07-02 17:30:03 +00:00
2006-11-22 00:59:34 +00:00
p + + ;
continue ;
}
2005-07-02 17:30:03 +00:00
2007-05-06 15:17:14 +00:00
if ( ! isascii ( * p ) ) {
/* attr names must be ascii only */
2009-10-02 12:03:05 +10:00
ldb_dn_mark_invalid ( dn ) ;
2007-05-06 15:17:14 +00:00
goto failed ;
}
2022-04-10 18:22:55 +02:00
if ( is_oid & & ( ! ( isdigit ( * p ) | | ( * p = = ' . ' ) ) ) ) {
2009-08-30 16:07:44 -04:00
/* not a digit nor a dot,
* invalid attribute oid */
2009-10-02 12:03:05 +10:00
ldb_dn_mark_invalid ( dn ) ;
2006-11-22 00:59:34 +00:00
goto failed ;
} else
if ( ! ( isalpha ( * p ) | | isdigit ( * p ) | | ( * p = = ' - ' ) ) ) {
/* not ALPHA, DIGIT or HYPHEN */
2009-10-02 12:03:05 +10:00
ldb_dn_mark_invalid ( dn ) ;
2006-11-22 00:59:34 +00:00
goto failed ;
}
2005-06-27 00:00:50 +00:00
2006-11-22 00:59:34 +00:00
* d + + = * p + + ;
continue ;
2006-01-06 21:39:37 +00:00
}
2005-06-27 00:00:50 +00:00
2022-04-10 18:22:55 +02:00
if ( in_value ) {
if ( in_quote ) {
2006-11-22 00:59:34 +00:00
if ( * p = = ' \" ' ) {
if ( p [ - 1 ] ! = ' \\ ' ) {
p + + ;
in_quote = false ;
continue ;
}
}
* d + + = * p + + ;
l + + ;
continue ;
}
r8037: a fairly major update to the internals of ldb. Changes are:
- moved the knowledge of attribute types out of ldb_tdb and into the
generic ldb code. This allows the ldb_match() message match logic
to be generic, so it can be used by other backend
- added the generic ability to load attribute handlers, for
canonicalisation, compare, ldif read and ldif write. In the future
this will be used by the schema module to allow us to correctly
obey the attributetype schema elements
- added attribute handlers for some of the core ldap attribute types,
Integer, DirectoryString, DN, ObjectClass etc
- added automatic registration of attribute handlers for well-known
attribute names 'cn', 'dc', 'dn', 'ou' and 'objectClass'
- converted the objectSid special handlers for Samba to the new system
- added more correct handling of indexing in tdb backend based on the
attribute canonicalisation function
- added generic support for subclasses, moving it out of the tdb
backend. This will be used in future by the schema module
- fixed several bugs in the dn_explode code. It still needs more
work, but doesn't corrupt ldb dbs any more.
(This used to be commit 944c5844ab441b96d8e5d7b2d151982139d1fab9)
2005-07-01 06:21:26 +00:00
2022-04-10 18:22:55 +02:00
if ( trim ) {
2006-11-22 00:59:34 +00:00
if ( * p = = ' ' ) {
p + + ;
continue ;
}
2005-06-27 00:00:50 +00:00
2006-11-22 00:59:34 +00:00
/* first char */
trim = false ;
2005-06-27 00:00:50 +00:00
2006-11-22 00:59:34 +00:00
if ( * p = = ' \" ' ) {
in_quote = true ;
p + + ;
continue ;
}
}
2005-06-27 00:00:50 +00:00
2006-11-22 00:59:34 +00:00
switch ( * p ) {
2005-06-27 00:00:50 +00:00
2006-11-22 00:59:34 +00:00
/* TODO: support ber encoded values
case ' # ' :
*/
2005-06-27 00:00:50 +00:00
2006-11-22 00:59:34 +00:00
case ' , ' :
2022-04-10 18:22:55 +02:00
if ( escape ) {
2006-11-22 00:59:34 +00:00
* d + + = * p + + ;
l + + ;
escape = false ;
continue ;
}
/* ok found value terminator */
2005-06-27 00:00:50 +00:00
2019-08-22 10:59:07 +12:00
if ( t ! = NULL ) {
2006-11-22 00:59:34 +00:00
/* trim back */
d - = ( p - t ) ;
l - = ( p - t ) ;
CVE-2020-27840 ldb_dn: avoid head corruption in ldb_dn_explode
A DN string with lots of trailing space can cause ldb_dn_explode() to
put a zero byte in the wrong place in the heap.
When a DN string has a value represented with trailing spaces,
like this
"CN=foo ,DC=bar"
the whitespace is supposed to be ignored. We keep track of this in the
`t` pointer, which is NULL when we are not walking through trailing
spaces, and points to the first space when we are. We are walking with
the `p` pointer, writing the value to `d`, and keeping the length in
`l`.
"CN=foo ,DC= " ==> "foo "
^ ^ ^
t p d
--l---
The value is finished when we encounter a comma or the end of the
string. If `t` is not NULL at that point, we assume there are trailing
spaces and wind `d and `l` back by the correct amount. Then we switch
to expecting an attribute name (e.g. "CN"), until we get to an "=",
which puts us back into looking for a value.
Unfortunately, we forget to immediately tell `t` that we'd finished
the last value, we can end up like this:
"CN=foo ,DC= " ==> ""
^ ^ ^
t p d
l=0
where `p` is pointing to a new value that contains only spaces, while
`t` is still referring to the old value. `p` notices the value ends,
and we subtract `p - t` from `d`:
"CN=foo ,DC= " ==> ? ""
^ ^ ^
t p d
l ~= SIZE_MAX - 8
At that point `d` wants to terminate its string with a '\0', but
instead it terminates someone else's byte. This does not crash if the
number of trailing spaces is small, as `d` will point into a previous
value (a copy of "foo" in this example). Corrupting that value will
ultimately not matter, as we will soon try to allocate a buffer `l`
long, which will be greater than the available memory and the whole
operation will fail properly.
However, with more spaces, `d` will point into memory before the
beginning of the allocated buffer, with the exact offset depending on
the length of the earlier attributes and the number of spaces.
What about a longer DN with more attributes? For example,
"CN=foo ,DC= ,DC=example,DC=com" -- since `d` has moved out of
bounds, won't we continue to use it and write more DN values into
mystery memory? Fortunately not, because the aforementioned allocation
of `l` bytes must happen first, and `l` is now huge. The allocation
happens in a talloc_memdup(), which is by default restricted to
allocating 256MB.
So this allows a person who controls a string parsed by ldb_dn_explode
to corrupt heap memory by placing a single zero byte at a chosen
offset before the allocated buffer.
An LDAP bind request can send a string DN as a username. This DN is
necessarily parsed before the password is checked, so an attacker does
not need proper credentials. The attacker can easily cause a denial of
service and we cannot rule out more subtle attacks.
The immediate solution is to reset `t` to NULL when a comma is
encountered, indicating that we are no longer looking at trailing
whitespace.
Found with the help of Honggfuzz.
BUG: https://bugzilla.samba.org/show_bug.cgi?id=14595
Signed-off-by: Douglas Bagnall <douglas.bagnall@catalyst.net.nz>
Reviewed-by: Andrew Bartlett <abartlet@samba.org>
2020-12-11 16:32:25 +13:00
t = NULL ;
2006-11-22 00:59:34 +00:00
}
2005-10-12 08:51:12 +00:00
2006-11-22 00:59:34 +00:00
in_attr = true ;
in_value = false ;
trim = true ;
2005-08-18 15:02:01 +00:00
2006-11-22 00:59:34 +00:00
p + + ;
* d + + = ' \0 ' ;
2016-01-04 12:13:04 +13:00
/*
* This talloc_memdup ( ) is OK with the
* + 1 because * d has been set to ' \0 '
* just above
*/
2015-11-26 11:17:11 +13:00
dn - > components [ dn - > comp_num ] . value . data = \
( uint8_t * ) talloc_memdup ( dn - > components , dt , l + 1 ) ;
2006-11-22 00:59:34 +00:00
dn - > components [ dn - > comp_num ] . value . length = l ;
2019-08-22 10:59:07 +12:00
if ( dn - > components [ dn - > comp_num ] . value . data = = NULL ) {
2006-11-23 22:06:07 +00:00
/* ouch ! */
goto failed ;
}
2015-11-26 11:17:11 +13:00
talloc_set_name_const ( dn - > components [ dn - > comp_num ] . value . data ,
( const char * ) dn - > components [ dn - > comp_num ] . value . data ) ;
2006-11-23 22:06:07 +00:00
2006-11-22 00:59:34 +00:00
dt = d ;
dn - > comp_num + + ;
if ( dn - > comp_num > 2 ) {
dn - > components = talloc_realloc ( dn ,
dn - > components ,
struct ldb_dn_component ,
dn - > comp_num + 1 ) ;
2019-08-22 10:59:07 +12:00
if ( dn - > components = = NULL ) {
2006-11-22 00:59:34 +00:00
/* ouch ! */
goto failed ;
}
/* make sure all components are zeroed, other functions depend on this */
memset ( & dn - > components [ dn - > comp_num ] , ' \0 ' , sizeof ( struct ldb_dn_component ) ) ;
}
2005-06-27 00:00:50 +00:00
2006-11-22 00:59:34 +00:00
continue ;
2005-06-27 00:00:50 +00:00
2009-10-27 11:44:05 +11:00
case ' + ' :
2009-11-13 17:48:35 +11:00
case ' = ' :
2009-10-25 22:02:31 +11:00
/* to main compatibility with earlier
versions of ldb indexing , we have to
accept the base64 encoded binary index
2009-11-13 17:48:35 +11:00
values , which contain a ' + ' or ' = '
which should normally be escaped */
2022-04-10 18:22:55 +02:00
if ( is_index ) {
2019-08-22 10:59:07 +12:00
if ( t ! = NULL ) {
t = NULL ;
}
2009-10-25 22:02:31 +11:00
* d + + = * p + + ;
l + + ;
break ;
}
2017-07-27 15:17:21 +02:00
FALL_THROUGH ;
2009-11-13 17:48:35 +11:00
case ' \" ' :
2006-11-22 00:59:34 +00:00
case ' < ' :
case ' > ' :
case ' ; ' :
/* a string with not escaped specials is invalid (tested) */
2022-04-10 18:22:55 +02:00
if ( ! escape ) {
2009-10-02 12:03:05 +10:00
ldb_dn_mark_invalid ( dn ) ;
2006-11-22 00:59:34 +00:00
goto failed ;
}
escape = false ;
* d + + = * p + + ;
l + + ;
2019-08-22 10:59:07 +12:00
if ( t ! = NULL ) {
t = NULL ;
}
2006-11-22 00:59:34 +00:00
break ;
case ' \\ ' :
2022-04-10 18:22:55 +02:00
if ( ! escape ) {
2006-11-22 00:59:34 +00:00
escape = true ;
p + + ;
continue ;
}
escape = false ;
* d + + = * p + + ;
l + + ;
2019-08-22 10:59:07 +12:00
if ( t ! = NULL ) {
t = NULL ;
}
2006-11-22 00:59:34 +00:00
break ;
default :
2022-04-10 18:22:55 +02:00
if ( escape ) {
2009-11-13 17:48:35 +11:00
if ( isxdigit ( p [ 0 ] ) & & isxdigit ( p [ 1 ] ) ) {
if ( sscanf ( p , " %02x " , & x ) ! = 1 ) {
/* invalid escaping sequence */
ldb_dn_mark_invalid ( dn ) ;
goto failed ;
}
p + = 2 ;
* d + + = ( unsigned char ) x ;
} else {
* d + + = * p + + ;
2006-11-22 00:59:34 +00:00
}
2009-11-13 17:48:35 +11:00
escape = false ;
2006-11-22 00:59:34 +00:00
l + + ;
2019-08-22 10:59:07 +12:00
if ( t ! = NULL ) {
t = NULL ;
}
2006-11-22 00:59:34 +00:00
break ;
}
2009-08-30 16:07:44 -04:00
if ( * p = = ' ' ) {
2019-08-22 10:59:07 +12:00
if ( t = = NULL ) {
t = p ;
}
2006-11-22 00:59:34 +00:00
} else {
2019-08-22 10:59:07 +12:00
if ( t ! = NULL ) {
t = NULL ;
}
2006-11-22 00:59:34 +00:00
}
* d + + = * p + + ;
l + + ;
2009-08-30 16:07:44 -04:00
2006-11-22 00:59:34 +00:00
break ;
}
2005-06-27 00:00:50 +00:00
2006-11-22 00:59:34 +00:00
}
2005-07-02 18:34:13 +00:00
}
2022-04-10 18:22:55 +02:00
if ( in_attr | | in_quote ) {
2006-11-22 00:59:34 +00:00
/* invalid dn */
2009-10-02 12:03:05 +10:00
ldb_dn_mark_invalid ( dn ) ;
2005-07-02 17:30:03 +00:00
goto failed ;
2005-06-27 00:00:50 +00:00
}
2022-04-10 18:22:55 +02:00
if ( in_value ) {
2019-07-26 09:49:13 +12:00
/* save last element */
2019-08-22 10:59:07 +12:00
if ( t ! = NULL ) {
2019-07-26 09:49:13 +12:00
/* trim back */
d - = ( p - t ) ;
l - = ( p - t ) ;
}
2006-11-23 22:06:07 +00:00
2019-07-26 09:49:13 +12:00
* d + + = ' \0 ' ;
/*
* This talloc_memdup ( ) is OK with the
* + 1 because * d has been set to ' \0 '
* just above .
*/
dn - > components [ dn - > comp_num ] . value . length = l ;
dn - > components [ dn - > comp_num ] . value . data =
( uint8_t * ) talloc_memdup ( dn - > components , dt , l + 1 ) ;
2019-08-22 10:59:07 +12:00
if ( dn - > components [ dn - > comp_num ] . value . data = = NULL ) {
2019-07-26 09:49:13 +12:00
/* ouch */
goto failed ;
}
talloc_set_name_const ( dn - > components [ dn - > comp_num ] . value . data ,
( const char * ) dn - > components [ dn - > comp_num ] . value . data ) ;
2006-11-22 00:59:34 +00:00
2019-07-26 09:49:13 +12:00
dn - > comp_num + + ;
}
2006-11-23 22:06:07 +00:00
talloc_free ( data ) ;
2006-11-22 00:59:34 +00:00
return true ;
2005-06-27 00:00:50 +00:00
2005-07-02 17:30:03 +00:00
failed :
2010-11-18 08:57:00 +01:00
LDB_FREE ( dn - > components ) ; /* "data" is implicitly free'd */
2006-11-23 22:06:07 +00:00
dn - > comp_num = 0 ;
2010-11-17 08:58:21 +01:00
LDB_FREE ( dn - > ext_components ) ;
dn - > ext_comp_num = 0 ;
2006-11-22 00:59:34 +00:00
return false ;
2005-06-27 00:00:50 +00:00
}
2006-11-22 00:59:34 +00:00
bool ldb_dn_validate ( struct ldb_dn * dn )
2005-06-27 00:00:50 +00:00
{
2006-11-22 00:59:34 +00:00
return ldb_dn_explode ( dn ) ;
2005-08-18 15:02:01 +00:00
}
2006-11-22 00:59:34 +00:00
const char * ldb_dn_get_linearized ( struct ldb_dn * dn )
2005-08-18 15:02:01 +00:00
{
2009-11-06 18:35:17 +01:00
unsigned int i ;
size_t len ;
2006-11-22 00:59:34 +00:00
char * d , * n ;
if ( ! dn | | ( dn - > invalid ) ) return NULL ;
2005-08-18 15:02:01 +00:00
2006-11-23 22:11:47 +00:00
if ( dn - > linearized ) return dn - > linearized ;
2005-08-18 15:02:01 +00:00
2006-11-23 22:30:46 +00:00
if ( ! dn - > components ) {
2009-10-02 12:03:05 +10:00
ldb_dn_mark_invalid ( dn ) ;
2006-10-04 19:03:29 +00:00
return NULL ;
}
2006-11-22 00:59:34 +00:00
if ( dn - > comp_num = = 0 ) {
dn - > linearized = talloc_strdup ( dn , " " ) ;
if ( ! dn - > linearized ) return NULL ;
return dn - > linearized ;
2005-08-18 15:02:01 +00:00
}
2006-11-22 00:59:34 +00:00
/* calculate maximum possible length of DN */
for ( len = 0 , i = 0 ; i < dn - > comp_num ; i + + ) {
2009-08-30 16:07:44 -04:00
/* name len */
len + = strlen ( dn - > components [ i ] . name ) ;
/* max escaped data len */
len + = ( dn - > components [ i ] . value . length * 3 ) ;
2006-11-22 00:59:34 +00:00
len + = 2 ; /* '=' and ',' */
2005-07-12 12:04:54 +00:00
}
2006-11-22 00:59:34 +00:00
dn - > linearized = talloc_array ( dn , char , len ) ;
if ( ! dn - > linearized ) return NULL ;
2005-07-12 12:04:54 +00:00
2006-11-22 00:59:34 +00:00
d = dn - > linearized ;
2005-06-27 00:00:50 +00:00
2006-11-22 00:59:34 +00:00
for ( i = 0 ; i < dn - > comp_num ; i + + ) {
2005-06-27 00:00:50 +00:00
2006-11-22 00:59:34 +00:00
/* copy the name */
n = dn - > components [ i ] . name ;
while ( * n ) * d + + = * n + + ;
2005-06-27 00:00:50 +00:00
2006-11-22 00:59:34 +00:00
* d + + = ' = ' ;
2005-06-27 00:00:50 +00:00
2006-11-22 00:59:34 +00:00
/* and the value */
d + = ldb_dn_escape_internal ( d ,
( char * ) dn - > components [ i ] . value . data ,
dn - > components [ i ] . value . length ) ;
* d + + = ' , ' ;
}
2005-06-27 00:00:50 +00:00
2006-11-22 00:59:34 +00:00
* ( - - d ) = ' \0 ' ;
2005-06-27 00:00:50 +00:00
2006-11-22 00:59:34 +00:00
/* don't waste more memory than necessary */
2009-08-30 16:07:44 -04:00
dn - > linearized = talloc_realloc ( dn , dn - > linearized ,
char , ( d - dn - > linearized + 1 ) ) ;
2005-06-27 00:00:50 +00:00
2006-11-22 00:59:34 +00:00
return dn - > linearized ;
}
2005-06-27 00:00:50 +00:00
2009-12-10 22:45:36 +11:00
static int ldb_dn_extended_component_compare ( const void * p1 , const void * p2 )
{
const struct ldb_dn_ext_component * ec1 = ( const struct ldb_dn_ext_component * ) p1 ;
const struct ldb_dn_ext_component * ec2 = ( const struct ldb_dn_ext_component * ) p2 ;
return strcmp ( ec1 - > name , ec2 - > name ) ;
}
2010-07-13 02:37:58 +03:00
char * ldb_dn_get_extended_linearized ( TALLOC_CTX * mem_ctx , struct ldb_dn * dn , int mode )
2008-12-16 08:19:07 +01:00
{
const char * linearized = ldb_dn_get_linearized ( dn ) ;
2010-02-26 10:53:06 +01:00
char * p = NULL ;
2009-11-06 18:35:17 +01:00
unsigned int i ;
2008-12-16 08:19:07 +01:00
if ( ! linearized ) {
return NULL ;
}
if ( ! ldb_dn_has_extended ( dn ) ) {
return talloc_strdup ( mem_ctx , linearized ) ;
}
2009-08-30 16:07:44 -04:00
2008-12-16 08:19:07 +01:00
if ( ! ldb_dn_validate ( dn ) ) {
return NULL ;
}
2009-12-10 22:45:36 +11:00
/* sort the extended components by name. The idea is to make
* the resulting DNs consistent , plus to ensure that we put
* ' DELETED ' first , so it can be very quickly recognised
*/
2010-02-14 10:37:20 +11:00
TYPESAFE_QSORT ( dn - > ext_components , dn - > ext_comp_num ,
ldb_dn_extended_component_compare ) ;
2009-12-10 22:45:36 +11:00
2009-08-30 16:07:44 -04:00
for ( i = 0 ; i < dn - > ext_comp_num ; i + + ) {
const struct ldb_dn_extended_syntax * ext_syntax ;
const char * name = dn - > ext_components [ i ] . name ;
struct ldb_val ec_val = dn - > ext_components [ i ] . value ;
2008-12-16 08:19:07 +01:00
struct ldb_val val ;
int ret ;
2009-08-30 16:07:44 -04:00
ext_syntax = ldb_dn_extended_syntax_by_name ( dn - > ldb , name ) ;
2009-11-11 19:24:48 +11:00
if ( ! ext_syntax ) {
return NULL ;
}
2008-12-16 08:19:07 +01:00
if ( mode = = 1 ) {
2009-08-30 16:07:44 -04:00
ret = ext_syntax - > write_clear_fn ( dn - > ldb , mem_ctx ,
& ec_val , & val ) ;
2008-12-16 08:19:07 +01:00
} else if ( mode = = 0 ) {
2009-08-30 16:07:44 -04:00
ret = ext_syntax - > write_hex_fn ( dn - > ldb , mem_ctx ,
& ec_val , & val ) ;
2008-12-16 08:19:07 +01:00
} else {
ret = - 1 ;
}
if ( ret ! = LDB_SUCCESS ) {
return NULL ;
}
if ( i = = 0 ) {
2019-08-27 13:16:18 +12:00
p = talloc_asprintf ( mem_ctx , " <%s=%.*s> " ,
name ,
( int ) val . length ,
val . data ) ;
2008-12-16 08:19:07 +01:00
} else {
2022-11-30 14:44:13 +01:00
talloc_asprintf_addbuf ( & p , " ;<%s=%.*s> " ,
name ,
( int ) val . length ,
val . data ) ;
2008-12-16 08:19:07 +01:00
}
talloc_free ( val . data ) ;
}
2009-08-30 16:07:44 -04:00
if ( dn - > ext_comp_num & & * linearized ) {
2022-11-30 14:44:13 +01:00
talloc_asprintf_addbuf ( & p , " ;%s " , linearized ) ;
2008-12-16 08:19:07 +01:00
}
if ( ! p ) {
return NULL ;
}
return p ;
}
2009-12-10 23:44:44 +11:00
/*
filter out all but an acceptable list of extended DN components
*/
2010-12-06 11:06:27 +01:00
void ldb_dn_extended_filter ( struct ldb_dn * dn , const char * const * accept_list )
2009-12-10 23:44:44 +11:00
{
2009-11-06 18:35:17 +01:00
unsigned int i ;
2009-12-10 23:44:44 +11:00
for ( i = 0 ; i < dn - > ext_comp_num ; i + + ) {
2010-12-06 11:06:27 +01:00
if ( ! ldb_attr_in_list ( accept_list , dn - > ext_components [ i ] . name ) ) {
2020-03-26 11:11:35 +01:00
ARRAY_DEL_ELEMENT (
dn - > ext_components , i , dn - > ext_comp_num ) ;
2009-12-10 23:44:44 +11:00
dn - > ext_comp_num - - ;
i - - ;
}
}
2010-02-26 15:48:02 +01:00
LDB_FREE ( dn - > ext_linearized ) ;
2009-12-10 23:44:44 +11:00
}
2008-12-16 08:19:07 +01:00
2010-07-13 02:37:58 +03:00
char * ldb_dn_alloc_linearized ( TALLOC_CTX * mem_ctx , struct ldb_dn * dn )
2006-11-22 00:59:34 +00:00
{
return talloc_strdup ( mem_ctx , ldb_dn_get_linearized ( dn ) ) ;
2005-06-27 00:00:50 +00:00
}
2006-11-22 00:59:34 +00:00
/*
2009-08-30 16:07:44 -04:00
casefold a dn . We need to casefold the attribute names , and canonicalize
2006-11-22 00:59:34 +00:00
attribute values of case insensitive attributes .
*/
static bool ldb_dn_casefold_internal ( struct ldb_dn * dn )
2006-01-06 04:01:23 +00:00
{
2024-08-22 11:03:13 +12:00
unsigned int i , j ;
2009-11-06 18:35:17 +01:00
int ret ;
2006-01-06 04:01:23 +00:00
2006-11-22 00:59:34 +00:00
if ( ! dn | | dn - > invalid ) return false ;
2006-01-06 04:01:23 +00:00
2006-11-22 00:59:34 +00:00
if ( dn - > valid_case ) return true ;
2006-11-23 22:30:46 +00:00
if ( ( ! dn - > components ) & & ( ! ldb_dn_explode ( dn ) ) ) {
2006-11-22 00:59:34 +00:00
return false ;
}
2006-01-06 04:01:23 +00:00
2006-11-22 00:59:34 +00:00
for ( i = 0 ; i < dn - > comp_num ; i + + ) {
2006-12-15 13:08:57 +00:00
const struct ldb_schema_attribute * a ;
2006-01-06 04:01:23 +00:00
2009-08-30 16:07:44 -04:00
dn - > components [ i ] . cf_name =
ldb_attr_casefold ( dn - > components ,
dn - > components [ i ] . name ) ;
2006-11-22 00:59:34 +00:00
if ( ! dn - > components [ i ] . cf_name ) {
2006-11-23 22:06:07 +00:00
goto failed ;
2006-11-22 00:59:34 +00:00
}
2006-01-06 04:01:23 +00:00
2009-08-30 16:07:44 -04:00
a = ldb_schema_attribute_by_name ( dn - > ldb ,
dn - > components [ i ] . cf_name ) ;
2006-12-15 13:08:57 +00:00
ret = a - > syntax - > canonicalise_fn ( dn - > ldb , dn - > components ,
& ( dn - > components [ i ] . value ) ,
& ( dn - > components [ i ] . cf_value ) ) ;
2006-11-22 00:59:34 +00:00
if ( ret ! = 0 ) {
2024-08-22 11:03:13 +12:00
goto failed_1 ;
2006-11-22 00:59:34 +00:00
}
2006-01-06 04:01:23 +00:00
}
2006-11-23 22:06:07 +00:00
dn - > valid_case = true ;
2006-11-22 00:59:34 +00:00
return true ;
2024-08-22 11:03:13 +12:00
failed_1 :
/*
* Although we try to always initialise . cf_name and . cf . value . data to
* NULL , we want to avoid TALLOC_FREEing the values we have not just
* set here .
*/
TALLOC_FREE ( dn - > components [ i ] . cf_name ) ;
failed :
2024-12-23 13:07:40 +13:00
for ( j = 0 ; j < i ; j + + ) {
2024-08-22 11:03:13 +12:00
TALLOC_FREE ( dn - > components [ j ] . cf_name ) ;
TALLOC_FREE ( dn - > components [ j ] . cf_value . data ) ;
2006-11-23 22:06:07 +00:00
}
return false ;
2006-01-06 04:01:23 +00:00
}
2006-11-22 00:59:34 +00:00
const char * ldb_dn_get_casefold ( struct ldb_dn * dn )
2005-06-27 00:00:50 +00:00
{
2009-11-06 18:35:17 +01:00
unsigned int i ;
size_t len ;
2006-11-22 00:59:34 +00:00
char * d , * n ;
2005-08-18 15:02:01 +00:00
2006-11-25 14:59:59 +00:00
if ( dn - > casefold ) return dn - > casefold ;
2009-08-30 16:07:44 -04:00
if ( dn - > special ) {
2006-11-25 14:59:59 +00:00
dn - > casefold = talloc_strdup ( dn , dn - > linearized ) ;
if ( ! dn - > casefold ) return NULL ;
dn - > valid_case = true ;
return dn - > casefold ;
}
2006-11-22 00:59:34 +00:00
if ( ! ldb_dn_casefold_internal ( dn ) ) {
return NULL ;
2005-07-12 12:04:54 +00:00
}
2006-11-22 00:59:34 +00:00
if ( dn - > comp_num = = 0 ) {
2009-06-01 12:58:48 +10:00
dn - > casefold = talloc_strdup ( dn , " " ) ;
return dn - > casefold ;
2006-11-22 00:59:34 +00:00
}
2005-06-27 00:00:50 +00:00
2006-11-22 00:59:34 +00:00
/* calculate maximum possible length of DN */
for ( len = 0 , i = 0 ; i < dn - > comp_num ; i + + ) {
2009-08-30 16:07:44 -04:00
/* name len */
len + = strlen ( dn - > components [ i ] . cf_name ) ;
/* max escaped data len */
len + = ( dn - > components [ i ] . cf_value . length * 3 ) ;
2006-11-22 00:59:34 +00:00
len + = 2 ; /* '=' and ',' */
2005-06-27 00:00:50 +00:00
}
2006-11-22 00:59:34 +00:00
dn - > casefold = talloc_array ( dn , char , len ) ;
if ( ! dn - > casefold ) return NULL ;
2005-06-27 00:00:50 +00:00
2006-11-22 00:59:34 +00:00
d = dn - > casefold ;
2005-07-02 17:30:03 +00:00
2006-11-22 00:59:34 +00:00
for ( i = 0 ; i < dn - > comp_num ; i + + ) {
/* copy the name */
n = dn - > components [ i ] . cf_name ;
while ( * n ) * d + + = * n + + ;
* d + + = ' = ' ;
/* and the value */
d + = ldb_dn_escape_internal ( d ,
( char * ) dn - > components [ i ] . cf_value . data ,
dn - > components [ i ] . cf_value . length ) ;
* d + + = ' , ' ;
}
* ( - - d ) = ' \0 ' ;
2006-11-23 22:06:07 +00:00
/* don't waste more memory than necessary */
2009-08-30 16:07:44 -04:00
dn - > casefold = talloc_realloc ( dn , dn - > casefold ,
char , strlen ( dn - > casefold ) + 1 ) ;
2006-11-22 00:59:34 +00:00
return dn - > casefold ;
}
2010-07-13 02:37:58 +03:00
char * ldb_dn_alloc_casefold ( TALLOC_CTX * mem_ctx , struct ldb_dn * dn )
2006-11-22 00:59:34 +00:00
{
return talloc_strdup ( mem_ctx , ldb_dn_get_casefold ( dn ) ) ;
2005-06-27 00:00:50 +00:00
}
2006-06-08 01:00:46 +00:00
/* Determine if dn is below base, in the ldap tree. Used for
* evaluating a subtree search .
2024-04-10 16:48:39 +12:00
*
* 0 if they match , otherwise non - zero .
*
* This is not for use in a qsort ( ) - like function , as the comparison
* is not symmetric .
2006-06-08 01:00:46 +00:00
*/
2005-07-12 12:04:54 +00:00
2006-11-22 00:59:34 +00:00
int ldb_dn_compare_base ( struct ldb_dn * base , struct ldb_dn * dn )
2005-06-27 00:00:50 +00:00
{
2005-07-17 09:06:58 +00:00
int ret ;
2010-10-16 15:10:11 +02:00
unsigned int n_base , n_dn ;
2006-11-22 00:59:34 +00:00
if ( ! base | | base - > invalid ) return 1 ;
if ( ! dn | | dn - > invalid ) return - 1 ;
if ( ( ! base - > valid_case ) | | ( ! dn - > valid_case ) ) {
2011-07-13 12:24:25 +10:00
if ( base - > linearized & & dn - > linearized & & dn - > special = = base - > special ) {
2006-11-22 00:59:34 +00:00
/* try with a normal compare first, if we are lucky
2022-09-06 12:15:14 +02:00
* we will avoid exploding and casefolding */
2024-08-23 10:14:04 +12:00
size_t len_dn = strlen ( dn - > linearized ) ;
size_t len_base = strlen ( base - > linearized ) ;
if ( len_dn < len_base ) {
return - 1 ;
2009-08-30 16:07:44 -04:00
}
2024-08-23 10:14:04 +12:00
2009-08-30 16:07:44 -04:00
if ( strcmp ( base - > linearized ,
2024-08-23 10:14:04 +12:00
& dn - > linearized [ len_dn - len_base ] ) = = 0 ) {
2009-08-30 16:07:44 -04:00
return 0 ;
}
2006-11-22 00:59:34 +00:00
}
2005-06-27 00:00:50 +00:00
2006-11-22 00:59:34 +00:00
if ( ! ldb_dn_casefold_internal ( base ) ) {
return 1 ;
}
2006-06-08 01:00:46 +00:00
2006-11-22 00:59:34 +00:00
if ( ! ldb_dn_casefold_internal ( dn ) ) {
return - 1 ;
}
}
/* if base has more components,
* they don ' t have the same base */
r9318: fix searches with scope ONE and SUB,
the problem was that ldb_dn_compare_base() just looked at if
both dn's mtach some how, and the following happens:
basedn: CN=bar,DC=foo,DC=com
dn: DC=foo,DC=com
and dn: DC=foo,DC=com was return as result of a sub and base search
and also the ONE search with
basedn: DC=foo,DC=com
returned this
dn: CN=bla,CN=bar,DC=foo,DC=com
metze
(This used to be commit 2a107472c373e425013050e28b944c830f653a87)
2005-08-16 06:55:40 +00:00
if ( base - > comp_num > dn - > comp_num ) {
return ( dn - > comp_num - base - > comp_num ) ;
}
2010-05-08 10:19:14 +03:00
if ( ( dn - > comp_num = = 0 ) | | ( base - > comp_num = = 0 ) ) {
2006-11-22 00:59:34 +00:00
if ( dn - > special & & base - > special ) {
return strcmp ( base - > linearized , dn - > linearized ) ;
2006-11-23 22:06:07 +00:00
} else if ( dn - > special ) {
return - 1 ;
} else if ( base - > special ) {
return 1 ;
2006-11-22 00:59:34 +00:00
} else {
return 0 ;
2005-07-02 17:30:03 +00:00
}
2006-11-22 00:59:34 +00:00
}
n_base = base - > comp_num - 1 ;
n_dn = dn - > comp_num - 1 ;
2005-06-27 00:00:50 +00:00
2010-10-16 15:10:11 +02:00
while ( n_base ! = ( unsigned int ) - 1 ) {
2009-08-30 16:07:44 -04:00
char * b_name = base - > components [ n_base ] . cf_name ;
char * dn_name = dn - > components [ n_dn ] . cf_name ;
char * b_vdata = ( char * ) base - > components [ n_base ] . cf_value . data ;
char * dn_vdata = ( char * ) dn - > components [ n_dn ] . cf_value . data ;
size_t b_vlen = base - > components [ n_base ] . cf_value . length ;
size_t dn_vlen = dn - > components [ n_dn ] . cf_value . length ;
2006-11-22 00:59:34 +00:00
/* compare attr names */
2009-08-30 16:07:44 -04:00
ret = strcmp ( b_name , dn_name ) ;
2006-11-22 00:59:34 +00:00
if ( ret ! = 0 ) return ret ;
2009-08-30 16:07:44 -04:00
/* compare attr.cf_value. */
if ( b_vlen ! = dn_vlen ) {
2024-04-03 12:50:47 +13:00
return NUMERIC_CMP ( b_vlen , dn_vlen ) ;
2005-06-27 00:00:50 +00:00
}
2012-12-13 02:18:34 -08:00
ret = strncmp ( b_vdata , dn_vdata , b_vlen ) ;
2006-11-22 00:59:34 +00:00
if ( ret ! = 0 ) return ret ;
n_base - - ;
n_dn - - ;
2005-06-27 00:00:50 +00:00
}
r8037: a fairly major update to the internals of ldb. Changes are:
- moved the knowledge of attribute types out of ldb_tdb and into the
generic ldb code. This allows the ldb_match() message match logic
to be generic, so it can be used by other backend
- added the generic ability to load attribute handlers, for
canonicalisation, compare, ldif read and ldif write. In the future
this will be used by the schema module to allow us to correctly
obey the attributetype schema elements
- added attribute handlers for some of the core ldap attribute types,
Integer, DirectoryString, DN, ObjectClass etc
- added automatic registration of attribute handlers for well-known
attribute names 'cn', 'dc', 'dn', 'ou' and 'objectClass'
- converted the objectSid special handlers for Samba to the new system
- added more correct handling of indexing in tdb backend based on the
attribute canonicalisation function
- added generic support for subclasses, moving it out of the tdb
backend. This will be used in future by the schema module
- fixed several bugs in the dn_explode code. It still needs more
work, but doesn't corrupt ldb dbs any more.
(This used to be commit 944c5844ab441b96d8e5d7b2d151982139d1fab9)
2005-07-01 06:21:26 +00:00
return 0 ;
2005-06-27 00:00:50 +00:00
}
2009-08-30 16:07:44 -04:00
/* compare DNs using casefolding compare functions.
2006-06-08 01:00:46 +00:00
If they match , then return 0
*/
2006-11-22 00:59:34 +00:00
int ldb_dn_compare ( struct ldb_dn * dn0 , struct ldb_dn * dn1 )
2005-07-12 12:04:54 +00:00
{
2009-11-06 18:35:17 +01:00
unsigned int i ;
int ret ;
2024-04-07 15:04:43 +12:00
/*
* If used in sort , we shift NULL and invalid DNs to the end .
*
* If ldb_dn_casefold_internal ( ) fails , that goes to the end too , so
* we end up with :
*
* | normal DNs , sorted | casefold failed DNs | invalid DNs | NULLs |
*/
2005-08-18 15:02:01 +00:00
2024-04-26 15:24:47 +12:00
if ( dn0 = = dn1 ) {
/* this includes the both-NULL case */
2024-04-07 15:04:43 +12:00
return 0 ;
}
2024-04-26 15:24:47 +12:00
if ( dn0 = = NULL ) {
2024-04-07 15:04:43 +12:00
return 1 ;
}
2024-04-26 15:24:47 +12:00
if ( dn1 = = NULL ) {
return - 1 ;
}
if ( dn0 - > invalid & & dn1 - > invalid ) {
return 0 ;
}
if ( dn0 - > invalid ) {
return 1 ;
}
if ( dn1 - > invalid ) {
2009-08-30 16:07:44 -04:00
return - 1 ;
}
2005-07-12 12:04:54 +00:00
2006-11-22 00:59:34 +00:00
if ( ( ! dn0 - > valid_case ) | | ( ! dn1 - > valid_case ) ) {
2024-08-23 10:17:17 +12:00
bool ok0 , ok1 ;
2006-11-23 22:11:47 +00:00
if ( dn0 - > linearized & & dn1 - > linearized ) {
2006-11-22 00:59:34 +00:00
/* try with a normal compare first, if we are lucky
2022-09-06 12:15:14 +02:00
* we will avoid exploding and casefolding */
2009-08-30 16:07:44 -04:00
if ( strcmp ( dn0 - > linearized , dn1 - > linearized ) = = 0 ) {
return 0 ;
}
2006-11-22 00:59:34 +00:00
}
2024-08-23 10:17:17 +12:00
/*
* If a DN can ' t casefold , it goes to the end .
*/
ok0 = ldb_dn_casefold_internal ( dn0 ) ;
ok1 = ldb_dn_casefold_internal ( dn1 ) ;
if ( ! ok0 ) {
if ( ! ok1 ) {
return 0 ;
}
2006-11-22 00:59:34 +00:00
return 1 ;
}
2024-08-23 10:17:17 +12:00
if ( ! ok1 ) {
2006-11-22 00:59:34 +00:00
return - 1 ;
}
}
2024-03-15 15:03:44 +13:00
/*
* Notice that for comp_num , Samba reverses the usual order of
* comparison . A DN with fewer components is greater than one
* with more .
*/
if ( dn0 - > comp_num > dn1 - > comp_num ) {
return - 1 ;
} else if ( dn0 - > comp_num < dn1 - > comp_num ) {
return 1 ;
2006-11-22 00:59:34 +00:00
}
if ( dn0 - > comp_num = = 0 ) {
if ( dn0 - > special & & dn1 - > special ) {
return strcmp ( dn0 - > linearized , dn1 - > linearized ) ;
2006-11-23 22:06:07 +00:00
} else if ( dn0 - > special ) {
return 1 ;
} else if ( dn1 - > special ) {
return - 1 ;
2006-11-22 00:59:34 +00:00
} else {
return 0 ;
}
}
for ( i = 0 ; i < dn0 - > comp_num ; i + + ) {
2009-08-30 16:07:44 -04:00
char * dn0_name = dn0 - > components [ i ] . cf_name ;
char * dn1_name = dn1 - > components [ i ] . cf_name ;
char * dn0_vdata = ( char * ) dn0 - > components [ i ] . cf_value . data ;
char * dn1_vdata = ( char * ) dn1 - > components [ i ] . cf_value . data ;
size_t dn0_vlen = dn0 - > components [ i ] . cf_value . length ;
size_t dn1_vlen = dn1 - > components [ i ] . cf_value . length ;
2006-11-22 00:59:34 +00:00
/* compare attr names */
2009-08-30 16:07:44 -04:00
ret = strcmp ( dn0_name , dn1_name ) ;
if ( ret ! = 0 ) {
return ret ;
}
2006-11-22 00:59:34 +00:00
2009-08-30 16:07:44 -04:00
/* compare attr.cf_value. */
if ( dn0_vlen ! = dn1_vlen ) {
2024-04-03 12:51:04 +13:00
return NUMERIC_CMP ( dn0_vlen , dn1_vlen ) ;
2009-08-30 16:07:44 -04:00
}
2012-12-13 02:18:34 -08:00
ret = strncmp ( dn0_vdata , dn1_vdata , dn0_vlen ) ;
2009-08-30 16:07:44 -04:00
if ( ret ! = 0 ) {
return ret ;
2006-11-22 00:59:34 +00:00
}
}
return 0 ;
2005-07-12 12:04:54 +00:00
}
2009-08-30 16:07:44 -04:00
static struct ldb_dn_component ldb_dn_copy_component (
2010-07-13 02:37:58 +03:00
TALLOC_CTX * mem_ctx ,
2009-08-30 16:07:44 -04:00
struct ldb_dn_component * src )
2005-07-16 18:16:32 +00:00
{
2006-11-22 00:59:34 +00:00
struct ldb_dn_component dst ;
memset ( & dst , 0 , sizeof ( dst ) ) ;
2005-07-16 18:16:32 +00:00
2006-11-22 00:59:34 +00:00
if ( src = = NULL ) {
return dst ;
}
2005-08-18 15:02:01 +00:00
2006-11-22 00:59:34 +00:00
dst . value = ldb_val_dup ( mem_ctx , & ( src - > value ) ) ;
if ( dst . value . data = = NULL ) {
return dst ;
}
2005-07-16 18:16:32 +00:00
2006-11-22 00:59:34 +00:00
dst . name = talloc_strdup ( mem_ctx , src - > name ) ;
if ( dst . name = = NULL ) {
LDB_FREE ( dst . value . data ) ;
2006-11-23 22:06:07 +00:00
return dst ;
2005-07-16 18:16:32 +00:00
}
2006-11-22 00:59:34 +00:00
if ( src - > cf_value . data ) {
dst . cf_value = ldb_val_dup ( mem_ctx , & ( src - > cf_value ) ) ;
if ( dst . cf_value . data = = NULL ) {
LDB_FREE ( dst . value . data ) ;
LDB_FREE ( dst . name ) ;
return dst ;
}
2005-07-16 18:16:32 +00:00
2006-11-22 00:59:34 +00:00
dst . cf_name = talloc_strdup ( mem_ctx , src - > cf_name ) ;
if ( dst . cf_name = = NULL ) {
LDB_FREE ( dst . cf_name ) ;
LDB_FREE ( dst . value . data ) ;
LDB_FREE ( dst . name ) ;
return dst ;
}
} else {
dst . cf_value . data = NULL ;
dst . cf_name = NULL ;
}
2005-07-16 18:16:32 +00:00
2006-11-22 00:59:34 +00:00
return dst ;
2005-07-16 18:16:32 +00:00
}
2009-08-30 16:07:44 -04:00
static struct ldb_dn_ext_component ldb_dn_ext_copy_component (
2010-07-13 02:37:58 +03:00
TALLOC_CTX * mem_ctx ,
2009-08-30 16:07:44 -04:00
struct ldb_dn_ext_component * src )
2008-12-16 08:19:07 +01:00
{
2009-08-30 16:07:44 -04:00
struct ldb_dn_ext_component dst ;
2008-12-16 08:19:07 +01:00
memset ( & dst , 0 , sizeof ( dst ) ) ;
if ( src = = NULL ) {
return dst ;
}
dst . value = ldb_val_dup ( mem_ctx , & ( src - > value ) ) ;
if ( dst . value . data = = NULL ) {
return dst ;
}
dst . name = talloc_strdup ( mem_ctx , src - > name ) ;
if ( dst . name = = NULL ) {
LDB_FREE ( dst . value . data ) ;
return dst ;
}
return dst ;
}
2010-07-13 02:37:58 +03:00
struct ldb_dn * ldb_dn_copy ( TALLOC_CTX * mem_ctx , struct ldb_dn * dn )
2005-06-27 00:00:50 +00:00
{
2006-11-22 00:59:34 +00:00
struct ldb_dn * new_dn ;
2005-08-18 15:02:01 +00:00
2006-11-22 00:59:34 +00:00
if ( ! dn | | dn - > invalid ) {
2006-07-06 07:37:41 +00:00
return NULL ;
}
2005-06-27 00:00:50 +00:00
2006-11-22 00:59:34 +00:00
new_dn = talloc_zero ( mem_ctx , struct ldb_dn ) ;
if ( ! new_dn ) {
2006-07-06 05:51:39 +00:00
return NULL ;
}
2005-06-27 00:00:50 +00:00
2006-11-22 00:59:34 +00:00
* new_dn = * dn ;
2005-06-27 00:00:50 +00:00
2006-11-23 22:30:46 +00:00
if ( dn - > components ) {
2009-11-06 18:35:17 +01:00
unsigned int i ;
2006-11-22 00:59:34 +00:00
2009-08-30 16:07:44 -04:00
new_dn - > components =
talloc_zero_array ( new_dn ,
struct ldb_dn_component ,
dn - > comp_num ) ;
2006-11-22 00:59:34 +00:00
if ( ! new_dn - > components ) {
talloc_free ( new_dn ) ;
2006-07-06 05:51:39 +00:00
return NULL ;
}
2005-06-27 00:00:50 +00:00
2006-11-22 00:59:34 +00:00
for ( i = 0 ; i < dn - > comp_num ; i + + ) {
2009-08-30 16:07:44 -04:00
new_dn - > components [ i ] =
ldb_dn_copy_component ( new_dn - > components ,
& dn - > components [ i ] ) ;
2006-11-22 00:59:34 +00:00
if ( ! new_dn - > components [ i ] . value . data ) {
talloc_free ( new_dn ) ;
return NULL ;
}
2005-06-27 00:00:50 +00:00
}
2006-11-23 22:06:07 +00:00
}
2005-06-27 00:00:50 +00:00
2009-08-30 16:07:44 -04:00
if ( dn - > ext_components ) {
2009-11-06 18:35:17 +01:00
unsigned int i ;
2008-12-16 08:19:07 +01:00
2009-08-30 16:07:44 -04:00
new_dn - > ext_components =
talloc_zero_array ( new_dn ,
struct ldb_dn_ext_component ,
dn - > ext_comp_num ) ;
if ( ! new_dn - > ext_components ) {
2008-12-16 08:19:07 +01:00
talloc_free ( new_dn ) ;
return NULL ;
}
2009-08-30 16:07:44 -04:00
for ( i = 0 ; i < dn - > ext_comp_num ; i + + ) {
new_dn - > ext_components [ i ] =
ldb_dn_ext_copy_component (
new_dn - > ext_components ,
& dn - > ext_components [ i ] ) ;
if ( ! new_dn - > ext_components [ i ] . value . data ) {
2008-12-16 08:19:07 +01:00
talloc_free ( new_dn ) ;
return NULL ;
}
}
}
2006-11-23 22:06:07 +00:00
if ( dn - > casefold ) {
new_dn - > casefold = talloc_strdup ( new_dn , dn - > casefold ) ;
if ( ! new_dn - > casefold ) {
talloc_free ( new_dn ) ;
return NULL ;
2006-11-22 00:59:34 +00:00
}
2005-06-27 00:00:50 +00:00
}
2006-11-23 22:11:47 +00:00
if ( dn - > linearized ) {
2006-11-22 00:59:34 +00:00
new_dn - > linearized = talloc_strdup ( new_dn , dn - > linearized ) ;
if ( ! new_dn - > linearized ) {
talloc_free ( new_dn ) ;
return NULL ;
}
}
2009-08-30 16:07:44 -04:00
if ( dn - > ext_linearized ) {
new_dn - > ext_linearized = talloc_strdup ( new_dn ,
dn - > ext_linearized ) ;
if ( ! new_dn - > ext_linearized ) {
2008-12-16 08:19:07 +01:00
talloc_free ( new_dn ) ;
return NULL ;
}
}
2006-11-22 00:59:34 +00:00
return new_dn ;
2005-06-27 00:00:50 +00:00
}
2024-05-01 16:54:01 +12:00
struct ldb_dn * ldb_dn_copy_with_ldb_context ( TALLOC_CTX * mem_ctx ,
struct ldb_dn * dn ,
struct ldb_context * ldb )
{
struct ldb_dn * new_dn = NULL ;
new_dn = ldb_dn_copy ( mem_ctx , dn ) ;
if ( new_dn = = NULL ) {
return NULL ;
}
/* Set the ldb context. */
new_dn - > ldb = ldb ;
return new_dn ;
}
2006-11-22 00:59:34 +00:00
/* modify the given dn by adding a base.
*
* return true if successful and false if not
* if false is returned the dn may be marked invalid
*/
bool ldb_dn_add_base ( struct ldb_dn * dn , struct ldb_dn * base )
2005-07-12 12:04:54 +00:00
{
2006-11-22 00:59:34 +00:00
const char * s ;
char * t ;
2005-07-12 12:04:54 +00:00
2006-11-22 00:59:34 +00:00
if ( ! base | | base - > invalid | | ! dn | | dn - > invalid ) {
return false ;
}
2005-08-18 15:02:01 +00:00
2019-07-06 23:24:43 +12:00
if ( dn = = base ) {
return false ; /* or we will visit infinity */
}
2006-11-23 22:30:46 +00:00
if ( dn - > components ) {
2009-11-06 18:35:17 +01:00
unsigned int i ;
2005-07-12 12:04:54 +00:00
2006-11-22 00:59:34 +00:00
if ( ! ldb_dn_validate ( base ) ) {
return false ;
}
2005-08-18 15:02:01 +00:00
2006-11-22 00:59:34 +00:00
s = NULL ;
if ( dn - > valid_case ) {
if ( ! ( s = ldb_dn_get_casefold ( base ) ) ) {
return false ;
}
}
2005-08-18 15:02:01 +00:00
2006-11-22 00:59:34 +00:00
dn - > components = talloc_realloc ( dn ,
dn - > components ,
struct ldb_dn_component ,
dn - > comp_num + base - > comp_num ) ;
if ( ! dn - > components ) {
2009-10-02 12:03:05 +10:00
ldb_dn_mark_invalid ( dn ) ;
2006-11-22 00:59:34 +00:00
return false ;
}
2005-08-18 15:02:01 +00:00
2006-11-22 00:59:34 +00:00
for ( i = 0 ; i < base - > comp_num ; dn - > comp_num + + , i + + ) {
2009-08-30 16:07:44 -04:00
dn - > components [ dn - > comp_num ] =
ldb_dn_copy_component ( dn - > components ,
& base - > components [ i ] ) ;
2006-11-22 00:59:34 +00:00
if ( dn - > components [ dn - > comp_num ] . value . data = = NULL ) {
2009-10-02 12:03:05 +10:00
ldb_dn_mark_invalid ( dn ) ;
2006-11-22 00:59:34 +00:00
return false ;
}
}
2006-11-23 22:06:07 +00:00
if ( dn - > casefold & & s ) {
2006-12-28 03:31:18 +00:00
if ( * dn - > casefold ) {
2009-08-30 16:07:44 -04:00
t = talloc_asprintf ( dn , " %s,%s " ,
dn - > casefold , s ) ;
2006-12-28 03:31:18 +00:00
} else {
t = talloc_strdup ( dn , s ) ;
}
2006-11-22 00:59:34 +00:00
LDB_FREE ( dn - > casefold ) ;
dn - > casefold = t ;
}
2005-08-18 15:02:01 +00:00
}
2006-11-23 22:11:47 +00:00
if ( dn - > linearized ) {
2005-08-18 15:02:01 +00:00
2006-11-22 00:59:34 +00:00
s = ldb_dn_get_linearized ( base ) ;
if ( ! s ) {
return false ;
}
2009-08-30 16:07:44 -04:00
2006-12-28 03:31:18 +00:00
if ( * dn - > linearized ) {
2009-08-30 16:07:44 -04:00
t = talloc_asprintf ( dn , " %s,%s " ,
dn - > linearized , s ) ;
2006-12-28 03:31:18 +00:00
} else {
t = talloc_strdup ( dn , s ) ;
}
2006-11-22 00:59:34 +00:00
if ( ! t ) {
2009-10-02 12:03:05 +10:00
ldb_dn_mark_invalid ( dn ) ;
2006-11-22 00:59:34 +00:00
return false ;
}
LDB_FREE ( dn - > linearized ) ;
dn - > linearized = t ;
2005-08-18 15:02:01 +00:00
}
2009-08-30 16:07:44 -04:00
/* Wipe the ext_linearized DN,
* the GUID and SID are almost certainly no longer valid */
2010-02-26 15:48:02 +01:00
LDB_FREE ( dn - > ext_linearized ) ;
2009-08-30 16:07:44 -04:00
LDB_FREE ( dn - > ext_components ) ;
dn - > ext_comp_num = 0 ;
2010-06-29 22:04:24 +02:00
2006-11-22 00:59:34 +00:00
return true ;
2005-08-18 15:02:01 +00:00
}
2006-11-22 00:59:34 +00:00
/* modify the given dn by adding a base.
*
* return true if successful and false if not
* if false is returned the dn may be marked invalid
*/
bool ldb_dn_add_base_fmt ( struct ldb_dn * dn , const char * base_fmt , . . . )
2005-08-18 15:02:01 +00:00
{
2006-11-22 00:59:34 +00:00
struct ldb_dn * base ;
char * base_str ;
va_list ap ;
bool ret ;
2005-08-18 15:02:01 +00:00
2006-11-22 00:59:34 +00:00
if ( ! dn | | dn - > invalid ) {
return false ;
2005-08-18 15:02:01 +00:00
}
2006-11-22 00:59:34 +00:00
va_start ( ap , base_fmt ) ;
base_str = talloc_vasprintf ( dn , base_fmt , ap ) ;
va_end ( ap ) ;
2005-08-18 15:02:01 +00:00
2006-11-22 00:59:34 +00:00
if ( base_str = = NULL ) {
return false ;
2005-08-18 15:02:01 +00:00
}
2006-11-22 00:59:34 +00:00
base = ldb_dn_new ( base_str , dn - > ldb , base_str ) ;
2005-08-18 15:02:01 +00:00
2006-11-22 00:59:34 +00:00
ret = ldb_dn_add_base ( dn , base ) ;
talloc_free ( base_str ) ;
return ret ;
2009-08-30 16:07:44 -04:00
}
2006-11-22 00:59:34 +00:00
/* modify the given dn by adding children elements.
*
* return true if successful and false if not
* if false is returned the dn may be marked invalid
*/
bool ldb_dn_add_child ( struct ldb_dn * dn , struct ldb_dn * child )
2006-11-01 23:31:26 +00:00
{
2006-11-22 00:59:34 +00:00
const char * s ;
char * t ;
2006-11-01 23:31:26 +00:00
2006-11-22 00:59:34 +00:00
if ( ! child | | child - > invalid | | ! dn | | dn - > invalid ) {
return false ;
2006-11-01 23:31:26 +00:00
}
2006-11-23 22:30:46 +00:00
if ( dn - > components ) {
2009-11-06 18:35:17 +01:00
unsigned int n ;
2010-10-16 15:08:40 +02:00
unsigned int i , j ;
2006-11-01 23:31:26 +00:00
2010-06-19 14:49:23 +02:00
if ( dn - > comp_num = = 0 ) {
return false ;
}
2006-11-22 00:59:34 +00:00
if ( ! ldb_dn_validate ( child ) ) {
return false ;
}
2006-11-01 23:31:26 +00:00
2006-11-22 00:59:34 +00:00
s = NULL ;
if ( dn - > valid_case ) {
if ( ! ( s = ldb_dn_get_casefold ( child ) ) ) {
return false ;
}
}
n = dn - > comp_num + child - > comp_num ;
2005-08-18 15:02:01 +00:00
2006-11-22 00:59:34 +00:00
dn - > components = talloc_realloc ( dn ,
dn - > components ,
struct ldb_dn_component ,
n ) ;
if ( ! dn - > components ) {
2009-10-02 12:03:05 +10:00
ldb_dn_mark_invalid ( dn ) ;
2006-11-22 00:59:34 +00:00
return false ;
}
2005-08-18 15:02:01 +00:00
2010-10-16 15:08:40 +02:00
for ( i = dn - > comp_num - 1 , j = n - 1 ; i ! = ( unsigned int ) - 1 ;
i - - , j - - ) {
2006-11-22 00:59:34 +00:00
dn - > components [ j ] = dn - > components [ i ] ;
}
2005-08-18 15:02:01 +00:00
2009-08-30 16:07:44 -04:00
for ( i = 0 ; i < child - > comp_num ; i + + ) {
dn - > components [ i ] =
ldb_dn_copy_component ( dn - > components ,
& child - > components [ i ] ) ;
2006-11-22 00:59:34 +00:00
if ( dn - > components [ i ] . value . data = = NULL ) {
2009-10-02 12:03:05 +10:00
ldb_dn_mark_invalid ( dn ) ;
2006-11-22 00:59:34 +00:00
return false ;
}
}
2005-08-18 15:02:01 +00:00
2006-11-22 00:59:34 +00:00
dn - > comp_num = n ;
2005-08-18 15:02:01 +00:00
2006-11-23 22:06:07 +00:00
if ( dn - > casefold & & s ) {
2006-11-22 00:59:34 +00:00
t = talloc_asprintf ( dn , " %s,%s " , s , dn - > casefold ) ;
LDB_FREE ( dn - > casefold ) ;
dn - > casefold = t ;
2005-08-18 15:02:01 +00:00
}
}
2006-11-23 22:11:47 +00:00
if ( dn - > linearized ) {
2010-06-19 14:49:23 +02:00
if ( dn - > linearized [ 0 ] = = ' \0 ' ) {
return false ;
}
2005-08-18 15:02:01 +00:00
2006-11-22 00:59:34 +00:00
s = ldb_dn_get_linearized ( child ) ;
if ( ! s ) {
return false ;
}
2009-08-30 16:07:44 -04:00
2006-11-22 00:59:34 +00:00
t = talloc_asprintf ( dn , " %s,%s " , s , dn - > linearized ) ;
if ( ! t ) {
2009-10-02 12:03:05 +10:00
ldb_dn_mark_invalid ( dn ) ;
2006-11-22 00:59:34 +00:00
return false ;
}
LDB_FREE ( dn - > linearized ) ;
dn - > linearized = t ;
}
2005-08-18 15:02:01 +00:00
2009-08-30 16:07:44 -04:00
/* Wipe the ext_linearized DN,
* the GUID and SID are almost certainly no longer valid */
LDB_FREE ( dn - > ext_linearized ) ;
LDB_FREE ( dn - > ext_components ) ;
dn - > ext_comp_num = 0 ;
2008-12-16 08:19:07 +01:00
2006-11-22 00:59:34 +00:00
return true ;
2005-08-18 15:02:01 +00:00
}
2006-11-22 00:59:34 +00:00
/* modify the given dn by adding children elements.
*
* return true if successful and false if not
* if false is returned the dn may be marked invalid
*/
bool ldb_dn_add_child_fmt ( struct ldb_dn * dn , const char * child_fmt , . . . )
2005-08-18 15:02:01 +00:00
{
2006-11-22 00:59:34 +00:00
struct ldb_dn * child ;
char * child_str ;
va_list ap ;
bool ret ;
2005-08-18 15:02:01 +00:00
2006-11-22 00:59:34 +00:00
if ( ! dn | | dn - > invalid ) {
return false ;
}
2005-08-18 15:02:01 +00:00
2006-11-22 00:59:34 +00:00
va_start ( ap , child_fmt ) ;
child_str = talloc_vasprintf ( dn , child_fmt , ap ) ;
va_end ( ap ) ;
2005-08-18 15:02:01 +00:00
2006-11-22 00:59:34 +00:00
if ( child_str = = NULL ) {
return false ;
2005-08-18 15:02:01 +00:00
}
2006-11-22 00:59:34 +00:00
child = ldb_dn_new ( child_str , dn - > ldb , child_str ) ;
ret = ldb_dn_add_child ( dn , child ) ;
2005-08-18 15:02:01 +00:00
2006-11-22 00:59:34 +00:00
talloc_free ( child_str ) ;
2005-08-18 15:02:01 +00:00
2006-11-22 00:59:34 +00:00
return ret ;
2005-08-18 15:02:01 +00:00
}
2018-07-03 15:16:56 +12:00
/* modify the given dn by adding a single child element.
*
* return true if successful and false if not
* if false is returned the dn may be marked invalid
*/
bool ldb_dn_add_child_val ( struct ldb_dn * dn ,
const char * rdn ,
struct ldb_val value )
{
bool ret ;
int ldb_ret ;
struct ldb_dn * child = NULL ;
if ( ! dn | | dn - > invalid ) {
return false ;
}
child = ldb_dn_new ( dn , dn - > ldb , " X=Y " ) ;
ret = ldb_dn_add_child ( dn , child ) ;
if ( ret = = false ) {
return false ;
}
ldb_ret = ldb_dn_set_component ( dn ,
0 ,
rdn ,
value ) ;
if ( ldb_ret ! = LDB_SUCCESS ) {
return false ;
}
return true ;
}
2006-11-22 00:59:34 +00:00
bool ldb_dn_remove_base_components ( struct ldb_dn * dn , unsigned int num )
2005-08-18 15:02:01 +00:00
{
2010-10-16 15:04:57 +02:00
unsigned int i ;
2006-11-23 22:06:07 +00:00
2006-11-22 00:59:34 +00:00
if ( ! ldb_dn_validate ( dn ) ) {
return false ;
2005-08-18 15:02:01 +00:00
}
2006-11-22 00:59:34 +00:00
if ( dn - > comp_num < num ) {
return false ;
}
2005-08-18 15:02:01 +00:00
2006-11-23 22:06:07 +00:00
/* free components */
2010-10-16 15:04:57 +02:00
for ( i = dn - > comp_num - num ; i < dn - > comp_num ; i + + ) {
LDB_FREE ( dn - > components [ i ] . name ) ;
LDB_FREE ( dn - > components [ i ] . value . data ) ;
LDB_FREE ( dn - > components [ i ] . cf_name ) ;
LDB_FREE ( dn - > components [ i ] . cf_value . data ) ;
2006-11-23 22:06:07 +00:00
}
2009-08-30 16:07:44 -04:00
2006-11-22 00:59:34 +00:00
dn - > comp_num - = num ;
2005-08-18 15:02:01 +00:00
2006-11-23 22:06:07 +00:00
if ( dn - > valid_case ) {
for ( i = 0 ; i < dn - > comp_num ; i + + ) {
LDB_FREE ( dn - > components [ i ] . cf_name ) ;
LDB_FREE ( dn - > components [ i ] . cf_value . data ) ;
}
dn - > valid_case = false ;
}
2005-08-18 15:02:01 +00:00
2006-11-23 22:11:47 +00:00
LDB_FREE ( dn - > casefold ) ;
LDB_FREE ( dn - > linearized ) ;
2005-08-18 15:02:01 +00:00
2009-08-30 16:07:44 -04:00
/* Wipe the ext_linearized DN,
* the GUID and SID are almost certainly no longer valid */
LDB_FREE ( dn - > ext_linearized ) ;
LDB_FREE ( dn - > ext_components ) ;
dn - > ext_comp_num = 0 ;
2008-12-16 08:19:07 +01:00
2006-11-22 00:59:34 +00:00
return true ;
2005-08-18 15:02:01 +00:00
}
2006-11-22 00:59:34 +00:00
bool ldb_dn_remove_child_components ( struct ldb_dn * dn , unsigned int num )
2005-08-18 15:02:01 +00:00
{
2009-11-06 18:35:17 +01:00
unsigned int i , j ;
2005-08-18 15:02:01 +00:00
2006-11-22 00:59:34 +00:00
if ( ! ldb_dn_validate ( dn ) ) {
return false ;
2005-08-18 15:02:01 +00:00
}
2006-11-22 00:59:34 +00:00
if ( dn - > comp_num < num ) {
return false ;
2005-08-18 15:02:01 +00:00
}
2006-11-22 00:59:34 +00:00
for ( i = 0 , j = num ; j < dn - > comp_num ; i + + , j + + ) {
2006-11-23 22:06:07 +00:00
if ( i < num ) {
LDB_FREE ( dn - > components [ i ] . name ) ;
LDB_FREE ( dn - > components [ i ] . value . data ) ;
LDB_FREE ( dn - > components [ i ] . cf_name ) ;
LDB_FREE ( dn - > components [ i ] . cf_value . data ) ;
}
2006-11-22 00:59:34 +00:00
dn - > components [ i ] = dn - > components [ j ] ;
2005-08-18 15:02:01 +00:00
}
2006-11-22 00:59:34 +00:00
dn - > comp_num - = num ;
2005-08-18 15:02:01 +00:00
2006-11-23 22:06:07 +00:00
if ( dn - > valid_case ) {
for ( i = 0 ; i < dn - > comp_num ; i + + ) {
LDB_FREE ( dn - > components [ i ] . cf_name ) ;
LDB_FREE ( dn - > components [ i ] . cf_value . data ) ;
}
dn - > valid_case = false ;
}
2005-08-18 15:02:01 +00:00
2006-11-23 22:11:47 +00:00
LDB_FREE ( dn - > casefold ) ;
LDB_FREE ( dn - > linearized ) ;
2006-11-22 00:59:34 +00:00
2009-08-30 16:07:44 -04:00
/* Wipe the ext_linearized DN,
* the GUID and SID are almost certainly no longer valid */
LDB_FREE ( dn - > ext_linearized ) ;
LDB_FREE ( dn - > ext_components ) ;
dn - > ext_comp_num = 0 ;
2010-06-29 22:04:24 +02:00
2006-11-22 00:59:34 +00:00
return true ;
2005-08-18 15:02:01 +00:00
}
2011-08-01 12:24:13 +10:00
/* replace the components of a DN with those from another DN, without
* touching the extended components
*
* return true if successful and false if not
* if false is returned the dn may be marked invalid
*/
bool ldb_dn_replace_components ( struct ldb_dn * dn , struct ldb_dn * new_dn )
{
2016-07-29 14:00:10 +02:00
unsigned int i ;
2011-08-01 12:24:13 +10:00
if ( ! ldb_dn_validate ( dn ) | | ! ldb_dn_validate ( new_dn ) ) {
return false ;
}
/* free components */
for ( i = 0 ; i < dn - > comp_num ; i + + ) {
LDB_FREE ( dn - > components [ i ] . name ) ;
LDB_FREE ( dn - > components [ i ] . value . data ) ;
LDB_FREE ( dn - > components [ i ] . cf_name ) ;
LDB_FREE ( dn - > components [ i ] . cf_value . data ) ;
}
dn - > components = talloc_realloc ( dn ,
dn - > components ,
struct ldb_dn_component ,
new_dn - > comp_num ) ;
if ( dn - > components = = NULL ) {
ldb_dn_mark_invalid ( dn ) ;
return false ;
}
dn - > comp_num = new_dn - > comp_num ;
dn - > valid_case = new_dn - > valid_case ;
for ( i = 0 ; i < dn - > comp_num ; i + + ) {
dn - > components [ i ] = ldb_dn_copy_component ( dn - > components , & new_dn - > components [ i ] ) ;
if ( dn - > components [ i ] . name = = NULL ) {
ldb_dn_mark_invalid ( dn ) ;
return false ;
}
}
if ( new_dn - > linearized = = NULL ) {
dn - > linearized = NULL ;
} else {
dn - > linearized = talloc_strdup ( dn , new_dn - > linearized ) ;
if ( dn - > linearized = = NULL ) {
ldb_dn_mark_invalid ( dn ) ;
return false ;
}
}
return true ;
}
2010-07-13 02:37:58 +03:00
struct ldb_dn * ldb_dn_get_parent ( TALLOC_CTX * mem_ctx , struct ldb_dn * dn )
2005-08-18 15:02:01 +00:00
{
2006-11-22 00:59:34 +00:00
struct ldb_dn * new_dn ;
2005-08-18 15:02:01 +00:00
2006-11-22 00:59:34 +00:00
new_dn = ldb_dn_copy ( mem_ctx , dn ) ;
if ( ! new_dn ) {
return NULL ;
}
2005-08-18 16:18:48 +00:00
2006-11-22 00:59:34 +00:00
if ( ! ldb_dn_remove_child_components ( new_dn , 1 ) ) {
talloc_free ( new_dn ) ;
return NULL ;
}
2005-08-18 16:18:48 +00:00
2006-11-22 00:59:34 +00:00
return new_dn ;
2005-08-18 15:02:01 +00:00
}
2005-10-13 07:47:57 +00:00
/* Create a 'canonical name' string from a DN:
ie dc = samba , dc = org - > samba . org /
uid = administrator , ou = users , dc = samba , dc = org = samba . org / users / administrator
2009-08-30 16:07:44 -04:00
There are two formats ,
the EX format has the last ' / ' replaced with a newline ( \ n ) .
2005-10-13 07:47:57 +00:00
*/
2010-07-13 02:37:58 +03:00
static char * ldb_dn_canonical ( TALLOC_CTX * mem_ctx , struct ldb_dn * dn , int ex_format ) {
2010-10-16 14:47:42 +02:00
unsigned int i ;
2006-11-23 22:06:07 +00:00
TALLOC_CTX * tmpctx ;
2005-10-13 04:24:49 +00:00
char * cracked = NULL ;
2007-09-18 13:41:50 +00:00
const char * format = ( ex_format ? " \n " : " / " ) ;
2009-08-30 16:07:44 -04:00
2006-11-22 00:59:34 +00:00
if ( ! ldb_dn_validate ( dn ) ) {
return NULL ;
}
2006-11-23 22:06:07 +00:00
tmpctx = talloc_new ( mem_ctx ) ;
2005-10-13 07:47:57 +00:00
/* Walk backwards down the DN, grabbing 'dc' components at first */
2010-10-16 14:47:42 +02:00
for ( i = dn - > comp_num - 1 ; i ! = ( unsigned int ) - 1 ; i - - ) {
2005-10-14 02:05:51 +00:00
if ( ldb_attr_cmp ( dn - > components [ i ] . name , " dc " ) ! = 0 ) {
2005-10-13 04:24:49 +00:00
break ;
}
if ( cracked ) {
2006-11-23 22:06:07 +00:00
cracked = talloc_asprintf ( tmpctx , " %s.%s " ,
2009-08-30 16:07:44 -04:00
ldb_dn_escape_value ( tmpctx ,
dn - > components [ i ] . value ) ,
2005-10-13 04:24:49 +00:00
cracked ) ;
} else {
2009-08-30 16:07:44 -04:00
cracked = ldb_dn_escape_value ( tmpctx ,
dn - > components [ i ] . value ) ;
2005-10-13 04:24:49 +00:00
}
if ( ! cracked ) {
2006-11-23 22:06:07 +00:00
goto done ;
2005-10-13 04:24:49 +00:00
}
}
2005-10-13 07:47:57 +00:00
/* Only domain components? Finish here */
2010-10-16 14:47:42 +02:00
if ( i = = ( unsigned int ) - 1 ) {
2007-09-18 13:41:50 +00:00
cracked = talloc_strdup_append_buffer ( cracked , format ) ;
2006-11-23 22:06:07 +00:00
talloc_steal ( mem_ctx , cracked ) ;
goto done ;
2005-10-13 04:24:49 +00:00
}
2005-10-13 07:47:57 +00:00
/* Now walk backwards appending remaining components */
2005-10-13 04:24:49 +00:00
for ( ; i > 0 ; i - - ) {
2009-08-30 16:07:44 -04:00
cracked = talloc_asprintf_append_buffer ( cracked , " /%s " ,
ldb_dn_escape_value ( tmpctx ,
dn - > components [ i ] . value ) ) ;
2005-10-13 04:24:49 +00:00
if ( ! cracked ) {
2006-11-23 22:06:07 +00:00
goto done ;
2005-10-13 04:24:49 +00:00
}
}
2005-10-13 07:47:57 +00:00
/* Last one, possibly a newline for the 'ex' format */
2007-09-18 13:41:50 +00:00
cracked = talloc_asprintf_append_buffer ( cracked , " %s%s " , format ,
2009-08-30 16:07:44 -04:00
ldb_dn_escape_value ( tmpctx ,
dn - > components [ i ] . value ) ) ;
2006-11-23 22:06:07 +00:00
talloc_steal ( mem_ctx , cracked ) ;
done :
talloc_free ( tmpctx ) ;
2005-10-13 04:24:49 +00:00
return cracked ;
}
2005-10-13 07:47:57 +00:00
/* Wrapper functions for the above, for the two different string formats */
2010-07-13 02:37:58 +03:00
char * ldb_dn_canonical_string ( TALLOC_CTX * mem_ctx , struct ldb_dn * dn ) {
2005-10-13 04:24:49 +00:00
return ldb_dn_canonical ( mem_ctx , dn , 0 ) ;
}
2010-07-13 02:37:58 +03:00
char * ldb_dn_canonical_ex_string ( TALLOC_CTX * mem_ctx , struct ldb_dn * dn ) {
2005-10-13 04:24:49 +00:00
return ldb_dn_canonical ( mem_ctx , dn , 1 ) ;
}
2006-11-01 23:31:26 +00:00
2006-11-22 00:59:34 +00:00
int ldb_dn_get_comp_num ( struct ldb_dn * dn )
2006-11-01 23:31:26 +00:00
{
2006-11-22 00:59:34 +00:00
if ( ! ldb_dn_validate ( dn ) ) {
return - 1 ;
}
2006-11-01 23:31:26 +00:00
return dn - > comp_num ;
}
2011-01-13 11:07:15 +11:00
int ldb_dn_get_extended_comp_num ( struct ldb_dn * dn )
{
if ( ! ldb_dn_validate ( dn ) ) {
return - 1 ;
}
return dn - > ext_comp_num ;
}
2006-11-22 00:59:34 +00:00
const char * ldb_dn_get_component_name ( struct ldb_dn * dn , unsigned int num )
2006-11-01 23:31:26 +00:00
{
2006-11-22 00:59:34 +00:00
if ( ! ldb_dn_validate ( dn ) ) {
return NULL ;
}
2006-11-01 23:31:26 +00:00
if ( num > = dn - > comp_num ) return NULL ;
return dn - > components [ num ] . name ;
}
2009-08-30 16:07:44 -04:00
const struct ldb_val * ldb_dn_get_component_val ( struct ldb_dn * dn ,
unsigned int num )
2006-11-01 23:31:26 +00:00
{
2006-11-22 00:59:34 +00:00
if ( ! ldb_dn_validate ( dn ) ) {
return NULL ;
}
2006-11-01 23:31:26 +00:00
if ( num > = dn - > comp_num ) return NULL ;
return & dn - > components [ num ] . value ;
}
2006-11-22 00:59:34 +00:00
const char * ldb_dn_get_rdn_name ( struct ldb_dn * dn )
{
if ( ! ldb_dn_validate ( dn ) ) {
return NULL ;
}
2006-11-01 23:31:26 +00:00
if ( dn - > comp_num = = 0 ) return NULL ;
return dn - > components [ 0 ] . name ;
}
2006-11-22 00:59:34 +00:00
const struct ldb_val * ldb_dn_get_rdn_val ( struct ldb_dn * dn )
{
if ( ! ldb_dn_validate ( dn ) ) {
return NULL ;
}
2006-11-01 23:31:26 +00:00
if ( dn - > comp_num = = 0 ) return NULL ;
return & dn - > components [ 0 ] . value ;
}
2009-08-30 16:07:44 -04:00
int ldb_dn_set_component ( struct ldb_dn * dn , int num ,
const char * name , const struct ldb_val val )
2006-11-01 23:31:26 +00:00
{
char * n ;
struct ldb_val v ;
2006-11-22 00:59:34 +00:00
if ( ! ldb_dn_validate ( dn ) ) {
return LDB_ERR_OTHER ;
}
2016-07-29 14:00:10 +02:00
if ( num < 0 ) {
2006-11-01 23:31:26 +00:00
return LDB_ERR_OTHER ;
}
2016-07-29 14:00:10 +02:00
if ( ( unsigned ) num > = dn - > comp_num ) {
2016-01-04 12:13:40 +13:00
return LDB_ERR_OTHER ;
}
2016-01-14 21:10:39 +01:00
if ( val . length > val . length + 1 ) {
2016-01-04 12:13:40 +13:00
return LDB_ERR_OTHER ;
}
2006-11-01 23:31:26 +00:00
n = talloc_strdup ( dn , name ) ;
if ( ! n ) {
return LDB_ERR_OTHER ;
}
v . length = val . length ;
2016-01-04 12:12:37 +13:00
/*
* This is like talloc_memdup ( dn , v . data , v . length + 1 ) , but
* avoids the over - read
*/
v . data = ( uint8_t * ) talloc_size ( dn , v . length + 1 ) ;
2006-11-01 23:31:26 +00:00
if ( ! v . data ) {
2006-11-23 22:06:07 +00:00
talloc_free ( n ) ;
2006-11-01 23:31:26 +00:00
return LDB_ERR_OTHER ;
}
2016-01-04 12:12:37 +13:00
memcpy ( v . data , val . data , val . length ) ;
/*
* Enforce NUL termination outside the stated length , as is
* traditional in LDB
*/
v . data [ v . length ] = ' \0 ' ;
2006-11-01 23:31:26 +00:00
talloc_free ( dn - > components [ num ] . name ) ;
talloc_free ( dn - > components [ num ] . value . data ) ;
dn - > components [ num ] . name = n ;
dn - > components [ num ] . value = v ;
2006-11-23 22:06:07 +00:00
if ( dn - > valid_case ) {
2009-11-06 18:35:17 +01:00
unsigned int i ;
2006-11-23 22:06:07 +00:00
for ( i = 0 ; i < dn - > comp_num ; i + + ) {
LDB_FREE ( dn - > components [ i ] . cf_name ) ;
LDB_FREE ( dn - > components [ i ] . cf_value . data ) ;
}
dn - > valid_case = false ;
}
LDB_FREE ( dn - > casefold ) ;
2007-01-22 17:46:38 +00:00
LDB_FREE ( dn - > linearized ) ;
2006-11-22 00:59:34 +00:00
2009-08-30 16:07:44 -04:00
/* Wipe the ext_linearized DN,
* the GUID and SID are almost certainly no longer valid */
LDB_FREE ( dn - > ext_linearized ) ;
LDB_FREE ( dn - > ext_components ) ;
2010-06-29 22:04:24 +02:00
dn - > ext_comp_num = 0 ;
2006-11-01 23:31:26 +00:00
return LDB_SUCCESS ;
}
2006-11-22 00:59:34 +00:00
2009-08-30 16:07:44 -04:00
const struct ldb_val * ldb_dn_get_extended_component ( struct ldb_dn * dn ,
const char * name )
2008-12-16 08:19:07 +01:00
{
2009-11-06 18:35:17 +01:00
unsigned int i ;
2008-12-16 08:19:07 +01:00
if ( ! ldb_dn_validate ( dn ) ) {
return NULL ;
}
2009-08-30 16:07:44 -04:00
for ( i = 0 ; i < dn - > ext_comp_num ; i + + ) {
if ( ldb_attr_cmp ( dn - > ext_components [ i ] . name , name ) = = 0 ) {
return & dn - > ext_components [ i ] . value ;
2008-12-16 08:19:07 +01:00
}
}
return NULL ;
}
2009-08-30 16:07:44 -04:00
int ldb_dn_set_extended_component ( struct ldb_dn * dn ,
const char * name , const struct ldb_val * val )
2008-12-16 08:19:07 +01:00
{
2009-08-30 16:07:44 -04:00
struct ldb_dn_ext_component * p ;
2009-11-06 18:35:17 +01:00
unsigned int i ;
2009-12-10 17:23:00 +11:00
struct ldb_val v2 ;
2016-06-17 13:28:59 +12:00
const struct ldb_dn_extended_syntax * ext_syntax ;
2008-12-16 08:19:07 +01:00
if ( ! ldb_dn_validate ( dn ) ) {
return LDB_ERR_OTHER ;
}
2016-06-17 13:28:59 +12:00
ext_syntax = ldb_dn_extended_syntax_by_name ( dn - > ldb , name ) ;
if ( ext_syntax = = NULL ) {
2009-11-11 19:24:48 +11:00
/* We don't know how to handle this type of thing */
return LDB_ERR_INVALID_DN_SYNTAX ;
}
2009-08-30 16:07:44 -04:00
for ( i = 0 ; i < dn - > ext_comp_num ; i + + ) {
if ( ldb_attr_cmp ( dn - > ext_components [ i ] . name , name ) = = 0 ) {
2008-12-16 08:19:07 +01:00
if ( val ) {
2009-08-30 16:07:44 -04:00
dn - > ext_components [ i ] . value =
ldb_val_dup ( dn - > ext_components , val ) ;
2008-12-16 08:19:07 +01:00
2016-06-17 13:28:59 +12:00
dn - > ext_components [ i ] . name = ext_syntax - > name ;
if ( ! dn - > ext_components [ i ] . value . data ) {
2009-10-02 12:03:05 +10:00
ldb_dn_mark_invalid ( dn ) ;
2008-12-16 08:19:07 +01:00
return LDB_ERR_OPERATIONS_ERROR ;
}
} else {
2020-03-26 11:12:55 +01:00
ARRAY_DEL_ELEMENT (
dn - > ext_components ,
i ,
dn - > ext_comp_num ) ;
2009-08-30 16:07:44 -04:00
dn - > ext_comp_num - - ;
dn - > ext_components = talloc_realloc ( dn ,
dn - > ext_components ,
struct ldb_dn_ext_component ,
dn - > ext_comp_num ) ;
if ( ! dn - > ext_components ) {
2009-10-02 12:03:05 +10:00
ldb_dn_mark_invalid ( dn ) ;
2008-12-16 08:19:07 +01:00
return LDB_ERR_OPERATIONS_ERROR ;
}
}
2010-02-26 15:48:02 +01:00
LDB_FREE ( dn - > ext_linearized ) ;
2010-06-29 22:07:51 +02:00
return LDB_SUCCESS ;
2008-12-16 08:19:07 +01:00
}
}
2009-12-10 14:32:47 +11:00
if ( val = = NULL ) {
/* removing a value that doesn't exist is not an error */
return LDB_SUCCESS ;
}
2009-12-10 17:23:00 +11:00
v2 = * val ;
2009-08-30 16:07:44 -04:00
p = dn - > ext_components
2008-12-16 08:19:07 +01:00
= talloc_realloc ( dn ,
2009-08-30 16:07:44 -04:00
dn - > ext_components ,
struct ldb_dn_ext_component ,
dn - > ext_comp_num + 1 ) ;
if ( ! dn - > ext_components ) {
2009-10-02 12:03:05 +10:00
ldb_dn_mark_invalid ( dn ) ;
2008-12-16 08:19:07 +01:00
return LDB_ERR_OPERATIONS_ERROR ;
}
2009-08-30 16:07:44 -04:00
2009-12-10 17:23:00 +11:00
p [ dn - > ext_comp_num ] . value = ldb_val_dup ( dn - > ext_components , & v2 ) ;
2009-08-30 16:07:44 -04:00
p [ dn - > ext_comp_num ] . name = talloc_strdup ( p , name ) ;
if ( ! dn - > ext_components [ i ] . name | | ! dn - > ext_components [ i ] . value . data ) {
2009-10-02 12:03:05 +10:00
ldb_dn_mark_invalid ( dn ) ;
2008-12-16 08:19:07 +01:00
return LDB_ERR_OPERATIONS_ERROR ;
}
2009-08-30 16:07:44 -04:00
dn - > ext_components = p ;
dn - > ext_comp_num + + ;
2010-06-29 22:07:51 +02:00
LDB_FREE ( dn - > ext_linearized ) ;
2008-12-19 09:54:20 -05:00
return LDB_SUCCESS ;
2008-12-16 08:19:07 +01:00
}
void ldb_dn_remove_extended_components ( struct ldb_dn * dn )
{
2010-02-26 15:48:02 +01:00
LDB_FREE ( dn - > ext_linearized ) ;
2010-06-29 22:04:24 +02:00
LDB_FREE ( dn - > ext_components ) ;
dn - > ext_comp_num = 0 ;
2008-12-16 08:19:07 +01:00
}
2006-11-22 00:59:34 +00:00
bool ldb_dn_is_valid ( struct ldb_dn * dn )
{
if ( ! dn ) return false ;
return ! dn - > invalid ;
}
bool ldb_dn_is_special ( struct ldb_dn * dn )
{
if ( ! dn | | dn - > invalid ) return false ;
return dn - > special ;
}
2008-12-16 08:19:07 +01:00
bool ldb_dn_has_extended ( struct ldb_dn * dn )
{
if ( ! dn | | dn - > invalid ) return false ;
2009-11-05 17:06:45 +11:00
if ( dn - > ext_linearized & & ( dn - > ext_linearized [ 0 ] = = ' < ' ) ) return true ;
2009-08-30 16:07:44 -04:00
return dn - > ext_comp_num ! = 0 ;
2008-12-16 08:19:07 +01:00
}
2006-11-22 00:59:34 +00:00
bool ldb_dn_check_special ( struct ldb_dn * dn , const char * check )
{
if ( ! dn | | dn - > invalid ) return false ;
return ! strcmp ( dn - > linearized , check ) ;
}
bool ldb_dn_is_null ( struct ldb_dn * dn )
{
if ( ! dn | | dn - > invalid ) return false ;
2008-12-16 08:19:07 +01:00
if ( ldb_dn_has_extended ( dn ) ) return false ;
2006-11-23 22:30:46 +00:00
if ( dn - > linearized & & ( dn - > linearized [ 0 ] = = ' \0 ' ) ) return true ;
2006-11-22 00:59:34 +00:00
return false ;
}
2009-10-02 12:03:05 +10:00
2009-12-17 23:03:41 +11:00
/*
this updates dn - > components , taking the components from ref_dn .
This is used by code that wants to update the DN path of a DN
while not impacting on the extended DN components
*/
int ldb_dn_update_components ( struct ldb_dn * dn , const struct ldb_dn * ref_dn )
{
dn - > components = talloc_realloc ( dn , dn - > components ,
struct ldb_dn_component , ref_dn - > comp_num ) ;
if ( ! dn - > components ) {
return LDB_ERR_OPERATIONS_ERROR ;
}
memcpy ( dn - > components , ref_dn - > components ,
sizeof ( struct ldb_dn_component ) * ref_dn - > comp_num ) ;
dn - > comp_num = ref_dn - > comp_num ;
2010-06-29 22:10:14 +02:00
LDB_FREE ( dn - > casefold ) ;
LDB_FREE ( dn - > linearized ) ;
LDB_FREE ( dn - > ext_linearized ) ;
2009-12-17 23:03:41 +11:00
return LDB_SUCCESS ;
}
2011-01-13 12:13:42 +11:00
/*
minimise a DN . The caller must pass in a validated DN .
If the DN has an extended component then only the first extended
component is kept , the DN string is stripped .
The existing dn is modified
*/
bool ldb_dn_minimise ( struct ldb_dn * dn )
{
2011-01-14 09:38:41 +01:00
unsigned int i ;
2011-01-13 12:13:42 +11:00
if ( ! ldb_dn_validate ( dn ) ) {
return false ;
}
if ( dn - > ext_comp_num = = 0 ) {
return true ;
}
/* free components */
for ( i = 0 ; i < dn - > comp_num ; i + + ) {
LDB_FREE ( dn - > components [ i ] . name ) ;
LDB_FREE ( dn - > components [ i ] . value . data ) ;
LDB_FREE ( dn - > components [ i ] . cf_name ) ;
LDB_FREE ( dn - > components [ i ] . cf_value . data ) ;
}
dn - > comp_num = 0 ;
dn - > valid_case = false ;
LDB_FREE ( dn - > casefold ) ;
LDB_FREE ( dn - > linearized ) ;
/* note that we don't free dn->components as this there are
* several places in ldb_dn . c that rely on it being non - NULL
* for an exploded DN
*/
for ( i = 1 ; i < dn - > ext_comp_num ; i + + ) {
LDB_FREE ( dn - > ext_components [ i ] . value . data ) ;
}
dn - > ext_comp_num = 1 ;
dn - > ext_components = talloc_realloc ( dn , dn - > ext_components , struct ldb_dn_ext_component , 1 ) ;
if ( dn - > ext_components = = NULL ) {
ldb_dn_mark_invalid ( dn ) ;
return false ;
}
LDB_FREE ( dn - > ext_linearized ) ;
return true ;
}
2015-10-14 13:49:01 +13:00
struct ldb_context * ldb_dn_get_ldb_context ( struct ldb_dn * dn )
{
return dn - > ldb ;
}