2004-10-03 21:17:45 +00:00
/*
Unix SMB / CIFS implementation .
LDAP server
Copyright ( C ) Simo Sorce 2004
This program is free software ; you can redistribute it and / or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation ; either version 2 of the License , or
( at your option ) any later version .
This program 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 General Public License for more details .
You should have received a copy of the GNU General Public License
along with this program ; if not , write to the Free Software
Foundation , Inc . , 675 Mass Ave , Cambridge , MA 0213 9 , USA .
*/
# include "includes.h"
# include "ldap_parse.h"
2004-10-05 11:10:26 +00:00
static char char_from_hex ( char a , char b ) {
2004-10-04 21:02:00 +00:00
char m , l ;
if ( ' 0 ' < = a & & a < = ' 9 ' ) {
m = a - ' 0 ' ;
} else if ( ' A ' < = a & & a < = ' F ' ) {
m = 10 + ( a - ' A ' ) ;
} else if ( ' a ' < = a & & a < = ' f ' ) {
m = 10 + ( a - ' a ' ) ;
} else {
return a ;
}
if ( ' 0 ' < = b & & b < = ' 9 ' ) {
l = b - ' 0 ' ;
} else if ( ' A ' < = b & & b < = ' F ' ) {
l = 10 + ( b - ' A ' ) ;
} else if ( ' a ' < = b & & b < = ' f ' ) {
l = 10 + ( b - ' a ' ) ;
} else {
return a ;
}
return ( ( m < < 4 ) + l ) ;
}
2004-10-05 11:10:26 +00:00
static char * parse_slash ( char * p , char * end ) {
2004-10-04 21:02:00 +00:00
switch ( * ( p + 1 ) ) {
case ' , ' :
case ' = ' :
case ' \n ' :
case ' + ' :
case ' < ' :
case ' > ' :
case ' # ' :
case ' ; ' :
case ' \\ ' :
case ' " ' :
memmove ( p , p + 1 , end - ( p + 1 ) ) ;
return ( end - 1 ) ;
default :
* p = char_from_hex ( * ( p + 1 ) , * ( p + 2 ) ) ;
memmove ( p + 1 , p + 3 , end - ( p + 3 ) ) ;
return ( end - 2 ) ;
}
}
2004-10-20 23:12:30 +00:00
# define LDAP_PARSE_DN_INVALID(x) do {\
if ( x ) { \
dn - > comp_num = - 1 ; \
return dn ; \
} \
} while ( 0 )
2004-10-04 21:02:00 +00:00
2004-11-15 11:40:27 +00:00
#if 0
static void ldap_parse_attributetypedescription ( struct ldap_schema * schema , DATA_BLOB * data )
{
char * desc ;
2005-01-27 07:08:20 +00:00
desc = talloc_array ( schema , char , data - > lenght + 1 ) ;
2004-11-15 11:40:27 +00:00
memcpy ( desc , data - > data , data - > lenght ) ;
desc [ data - > lenght ] = ' \0 ' ;
}
static void ldap_parse_objectclassdescription ( struct ldap_schema * schema , DATA_BLOB * data )
{
char * desc ;
2005-01-27 07:08:20 +00:00
desc = talloc_array ( schema , char , data - > lenght + 1 ) ;
2004-11-15 11:40:27 +00:00
memcpy ( desc , data - > data , data - > lenght ) ;
desc [ data - > lenght ] = ' \0 ' ;
}
static struct ldap_schema * ldap_get_schema ( void * mem_ctx , struct ldap_schema * schema , struct ldb_context * ldb )
{
NTSTATUS status ;
struct ldap_schema * local_schema ;
struct ldb_message * * res ;
const char * errstr ;
const char * schema_dn = " cn=schema " ;
const char * attr_filter = " attributeTypeDescription=* " ;
const char * class_filter = " objectClassDescription=* " ;
const char * attrs = " attributeTypeDescription " ;
const char * classes = " objectClassDescription " ;
enum ldb_scope scope = LDAP_SCOPE_SUBTREE ;
int count , i , j , k ;
local_schema = schema ;
if ( local_schema = = NULL ) {
2005-01-27 07:08:20 +00:00
local_schema = talloc ( mem_ctx , struct ldap_schema ) ;
2004-11-15 11:40:27 +00:00
ALLOC_CHECK ( local_schema ) ;
}
count = ldb_search ( ldb , schema_dn , scope , attr_filter , attrs , & res ) ;
for ( i = 0 ; i < count ; i + + ) {
if ( res [ i ] - > num_elements = = 0 ) {
goto attr_done ;
}
for ( j = 0 ; j < res [ i ] - > num_elements ; j + + ) {
for ( k = 0 ; res [ i ] - > elements [ j ] . num_values ; k + + ) {
ldap_parse_attributetypedescription ( local_schema , & ( res [ i ] - > elements [ j ] . values [ k ] ) ) ;
}
}
attr_done :
}
count = ldb_search ( ldb , schema_dn , scope , class_filter , classes , & res ) ;
for ( i = 0 ; i < count ; i + + ) {
if ( res [ i ] - > num_elements = = 0 ) {
goto class_done ;
}
for ( j = 0 ; j < res [ i ] - > num_elements ; j + + ) {
for ( k = 0 ; res [ i ] - > elements [ j ] . num_values ; k + + ) {
ldap_parse_objectclassdescription ( local_schema , & ( res [ i ] - > elements [ j ] . values [ k ] ) ) ;
}
}
class_done :
}
return local_schema ;
}
# endif
struct ldap_dn * ldap_parse_dn ( void * mem_ctx , const char * orig_dn )
2004-10-03 21:17:45 +00:00
{
struct ldap_dn * dn ;
struct dn_component * component ;
struct dn_attribute * attribute ;
char * p , * start , * separator , * src , * dest , * dn_copy , * dn_end ;
2004-10-20 23:12:30 +00:00
int i , size , orig_len ;
2004-10-03 21:17:45 +00:00
2005-01-27 07:08:20 +00:00
dn = talloc ( mem_ctx , struct ldap_dn ) ;
2004-10-03 21:17:45 +00:00
dn - > comp_num = 0 ;
2005-01-27 07:08:20 +00:00
dn - > components = talloc_array ( dn , struct dn_component * , 1 ) ;
component = talloc ( dn , struct dn_component ) ;
2004-10-03 21:17:45 +00:00
component - > attr_num = 0 ;
2004-10-20 23:12:30 +00:00
orig_len = strlen ( orig_dn ) ;
if ( orig_len = = 0 ) {
dn - > dn = talloc_strdup ( dn , orig_dn ) ;
return dn ;
}
2004-10-03 21:17:45 +00:00
dn_copy = p = talloc_strdup ( mem_ctx , orig_dn ) ;
2004-10-20 23:12:30 +00:00
dn_end = dn_copy + orig_len + 1 ;
2004-10-03 21:17:45 +00:00
do {
2005-01-27 07:08:20 +00:00
component - > attributes = talloc_array ( component , struct dn_attribute * , 1 ) ;
attribute = talloc ( component , struct dn_attribute ) ;
2004-10-03 21:17:45 +00:00
/* skip "spaces" */
while ( * p = = ' ' | | * p = = ' \n ' ) {
p + + ;
}
/* start parsing this component */
do {
start = p ;
/* find out key separator '=' */
while ( * p & & * p ! = ' = ' ) {
if ( * p = = ' \\ ' ) {
2004-10-04 21:02:00 +00:00
dn_end = parse_slash ( p , dn_end ) ;
2004-10-03 21:17:45 +00:00
}
p + + ;
}
separator = p ;
/* remove spaces */
while ( * ( p - 1 ) = = ' ' | | * ( p - 1 ) = = ' \n ' ) {
p - - ;
}
/* save key name */
2004-10-20 23:12:30 +00:00
LDAP_PARSE_DN_INVALID ( ( p - start ) < 1 ) ;
2004-10-03 21:17:45 +00:00
attribute - > name = talloc_strndup ( attribute , start , p - start ) ;
DEBUG ( 10 , ( " attribute name: [%s] \n " , attribute - > name ) ) ;
p = separator + 1 ;
/* skip spaces past the separator */
p = separator + strspn ( p , " \n " ) + 1 ;
start = p ;
/* check if the value is enclosed in QUOTATION */
if ( * p = = ' " ' ) {
start = p + 1 ;
while ( * p & & * p ! = ' " ' ) {
if ( * p = = ' \\ ' ) {
2004-10-04 21:02:00 +00:00
dn_end = parse_slash ( p , dn_end ) ;
2004-10-03 21:17:45 +00:00
}
p + + ;
}
/* skip spaces until the separator */
separator = p + strspn ( p , " \n " ) ;
if ( * separator ! = ' , ' & & * separator ! = ' ; ' & & * separator ! = ' + ' ) { /* there must be a separator here */
/* Error Malformed DN */
DEBUG ( 0 , ( " Error: Malformed DN! \n " ) ) ;
break ;
}
} else {
while ( * p & & ! ( * p = = ' , ' | | * p = = ' ; ' | | * p = = ' + ' ) ) {
if ( * p = = ' \\ ' ) {
2004-10-04 21:02:00 +00:00
dn_end = parse_slash ( p , dn_end ) ;
2004-10-03 21:17:45 +00:00
}
p + + ;
} /* found separator */
separator = p ;
/* remove spaces */
while ( * ( p - 1 ) = = ' ' | | * ( p - 1 ) = = ' \n ' ) {
p - - ;
}
}
/* save the value */
2004-10-20 23:12:30 +00:00
LDAP_PARSE_DN_INVALID ( ( p - start ) < 1 ) ;
2004-10-03 21:17:45 +00:00
attribute - > value = talloc_strndup ( attribute , start , p - start ) ;
DEBUG ( 10 , ( " attribute value: [%s] \n " , attribute - > value ) ) ;
attribute - > attribute = talloc_asprintf ( attribute , " %s=%s " , attribute - > name , attribute - > value ) ;
DEBUG ( 10 , ( " attribute: [%s] \n " , attribute - > attribute ) ) ;
/* save the attribute */
component - > attributes [ component - > attr_num ] = attribute ;
component - > attr_num + + ;
if ( * separator = = ' + ' ) { /* expect other attributes in this component */
2005-01-27 07:08:20 +00:00
component - > attributes = talloc_realloc ( component , component - > attributes , struct dn_attribute * , component - > attr_num + 1 ) ;
2004-10-03 21:17:45 +00:00
/* allocate new attribute structure */
2005-01-27 07:08:20 +00:00
attribute = talloc ( component , struct dn_attribute ) ;
2004-10-03 21:17:45 +00:00
/* skip spaces past the separator */
p = separator + strspn ( p , " \n " ) ;
}
} while ( * separator = = ' + ' ) ;
/* found component bounds */
for ( i = 0 , size = 0 ; i < component - > attr_num ; i + + ) {
size = size + strlen ( component - > attributes [ i ] - > attribute ) + 1 ;
}
/* rebuild the normlaized component and put it here */
2005-01-06 03:06:58 +00:00
component - > component = dest = talloc_size ( component , size ) ;
2004-10-03 21:17:45 +00:00
for ( i = 0 ; i < component - > attr_num ; i + + ) {
if ( i ! = 0 ) {
* dest = ' + ' ;
dest + + ;
}
src = component - > attributes [ i ] - > attribute ;
do {
* ( dest + + ) = * ( src + + ) ;
} while ( * src ) ;
* dest = ' \0 ' ;
}
DEBUG ( 10 , ( " component: [%s] \n " , component - > component ) ) ;
dn - > components [ dn - > comp_num ] = component ;
dn - > comp_num + + ;
if ( * separator = = ' , ' | | * separator = = ' ; ' ) {
2005-01-27 07:08:20 +00:00
dn - > components = talloc_realloc ( dn , dn - > components , struct dn_component * , dn - > comp_num + 1 ) ;
component = talloc ( dn , struct dn_component ) ;
2004-10-03 21:17:45 +00:00
component - > attr_num = 0 ;
}
p = separator + 1 ;
} while ( * separator = = ' , ' | | * separator = = ' ; ' ) ;
for ( i = 0 , size = 0 ; i < dn - > comp_num ; i + + ) {
size = size + strlen ( dn - > components [ i ] - > component ) + 1 ;
}
/* rebuild the normlaized dn and put it here */
2005-01-06 03:06:58 +00:00
dn - > dn = dest = talloc_size ( dn , size ) ;
2004-10-03 21:17:45 +00:00
for ( i = 0 ; i < dn - > comp_num ; i + + ) {
if ( i ! = 0 ) {
* dest = ' , ' ;
dest + + ;
}
src = dn - > components [ i ] - > component ;
do {
* ( dest + + ) = * ( src + + ) ;
} while ( * src ) ;
* dest = ' \0 ' ;
}
DEBUG ( 10 , ( " dn: [%s] \n " , dn - > dn ) ) ;
talloc_free ( dn_copy ) ;
return dn ;
}