2005-08-21 14:26:03 +00:00
/*
ldb database library
Copyright ( C ) Simo Sorce 2005
* * NOTE ! The following LGPL license applies to the ldb
* * library . This does NOT imply that all of Samba is released
* * under the LGPL
This library is free software ; you can redistribute it and / or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation ; either
2007-07-10 02:46:15 +00:00
version 3 of the License , or ( at your option ) any later version .
2005-08-21 14:26:03 +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-08-21 14:26:03 +00:00
*/
/*
* Name : ldb
*
2006-08-17 08:31:19 +00:00
* Component : oLschema2ldif
2005-08-21 14:26:03 +00:00
*
2006-08-17 08:31:19 +00:00
* Description : utility to convert an OpenLDAP schema into AD LDIF
2005-08-21 14:26:03 +00:00
*
2006-08-17 08:31:19 +00:00
* Author : Simo Sorce
2005-08-21 14:26:03 +00:00
*/
2008-08-15 21:20:05 +10:00
# include "includes.h"
2009-01-29 18:39:30 -05:00
# include "ldb.h"
2008-08-15 21:20:05 +10:00
# include "dsdb/samdb/samdb.h"
2009-11-13 09:58:20 -06:00
# include "../lib/crypto/sha256.h"
# include "../librpc/gen_ndr/ndr_misc.h"
2010-03-25 15:45:08 +11:00
# include "lib/cmdline/popt_common.h"
2005-08-21 14:26:03 +00:00
# define SCHEMA_UNKNOWN 0
# define SCHEMA_NAME 1
# define SCHEMA_SUP 2
# define SCHEMA_STRUCTURAL 3
# define SCHEMA_ABSTRACT 4
# define SCHEMA_AUXILIARY 5
# define SCHEMA_MUST 6
# define SCHEMA_MAY 7
# define SCHEMA_SINGLE_VALUE 8
# define SCHEMA_EQUALITY 9
2005-08-21 17:20:34 +00:00
# define SCHEMA_ORDERING 10
# define SCHEMA_SUBSTR 11
# define SCHEMA_SYNTAX 12
# define SCHEMA_DESC 13
2005-08-21 14:26:03 +00:00
struct schema_conv {
int count ;
int failures ;
} ;
2006-09-10 11:16:09 +00:00
struct schema_token {
2005-08-21 14:26:03 +00:00
int type ;
char * value ;
} ;
struct ldb_context * ldb_ctx ;
struct ldb_dn * basedn ;
static int check_braces ( const char * string )
{
int b ;
char * c ;
b = 0 ;
if ( ( c = strchr ( string , ' ( ' ) ) = = NULL ) {
return - 1 ;
}
b + + ;
c + + ;
while ( b ) {
c = strpbrk ( c , " () " ) ;
if ( c = = NULL ) return 1 ;
if ( * c = = ' ( ' ) b + + ;
2012-04-15 14:02:41 -07:00
if ( * c = = ' ) ' ) {
b - - ;
if ( * ( c - 1 ) ! = ' ' & & c & & ( * ( c + 1 ) = = ' \0 ' ) ) {
return 2 ;
}
}
2005-08-21 14:26:03 +00:00
c + + ;
}
return 0 ;
}
static char * skip_spaces ( char * string ) {
return ( string + strspn ( string , " \t \n " ) ) ;
}
2005-10-12 06:10:23 +00:00
static int add_multi_string ( struct ldb_message * msg , const char * attr , char * values )
2005-08-21 14:26:03 +00:00
{
char * c ;
char * s ;
int n ;
c = skip_spaces ( values ) ;
while ( * c ) {
n = strcspn ( c , " \t $ " ) ;
s = talloc_strndup ( msg , c , n ) ;
2005-10-12 06:10:23 +00:00
if ( ldb_msg_add_string ( msg , attr , s ) ! = 0 ) {
2005-08-21 14:26:03 +00:00
return - 1 ;
}
c + = n ;
c + = strspn ( c , " \t $ " ) ;
}
return 0 ;
}
2005-10-12 06:10:23 +00:00
# define MSG_ADD_STRING(a, v) do { if (ldb_msg_add_string(msg, a, v) != 0) goto failed; } while(0)
# define MSG_ADD_M_STRING(a, v) do { if (add_multi_string(msg, a, v) != 0) goto failed; } while(0)
2005-08-21 14:26:03 +00:00
static char * get_def_value ( TALLOC_CTX * ctx , char * * string )
{
char * c = * string ;
char * value ;
int n ;
if ( * c = = ' \' ' ) {
c + + ;
n = strcspn ( c , " \' " ) ;
value = talloc_strndup ( ctx , c , n ) ;
c + = n ;
c + + ; /* skip closing \' */
} else {
n = strcspn ( c , " \t \n " ) ;
value = talloc_strndup ( ctx , c , n ) ;
c + = n ;
}
* string = c ;
return value ;
}
2006-09-10 11:16:09 +00:00
static struct schema_token * get_next_schema_token ( TALLOC_CTX * ctx , char * * string )
2005-08-21 14:26:03 +00:00
{
char * c = skip_spaces ( * string ) ;
char * type ;
2006-09-10 11:16:09 +00:00
struct schema_token * token ;
2005-08-21 14:26:03 +00:00
int n ;
2006-09-10 11:16:09 +00:00
token = talloc ( ctx , struct schema_token ) ;
2005-08-21 14:26:03 +00:00
n = strcspn ( c , " \t \n " ) ;
type = talloc_strndup ( token , c , n ) ;
c + = n ;
c = skip_spaces ( c ) ;
if ( strcasecmp ( " NAME " , type ) = = 0 ) {
talloc_free ( type ) ;
token - > type = SCHEMA_NAME ;
/* we do not support aliases so we get only the first name given and skip others */
if ( * c = = ' ( ' ) {
char * s = strchr ( c , ' ) ' ) ;
if ( s = = NULL ) return NULL ;
s = skip_spaces ( s ) ;
* string = s ;
c + + ;
c = skip_spaces ( c ) ;
}
token - > value = get_def_value ( ctx , & c ) ;
if ( * string < c ) { /* single name */
c = skip_spaces ( c ) ;
* string = c ;
}
return token ;
}
if ( strcasecmp ( " SUP " , type ) = = 0 ) {
talloc_free ( type ) ;
token - > type = SCHEMA_SUP ;
2005-08-21 17:20:34 +00:00
if ( * c = = ' ( ' ) {
c + + ;
n = strcspn ( c , " ) " ) ;
token - > value = talloc_strndup ( ctx , c , n ) ;
c + = n ;
c + + ;
} else {
token - > value = get_def_value ( ctx , & c ) ;
}
2005-08-21 14:26:03 +00:00
c = skip_spaces ( c ) ;
* string = c ;
return token ;
}
if ( strcasecmp ( " STRUCTURAL " , type ) = = 0 ) {
talloc_free ( type ) ;
token - > type = SCHEMA_STRUCTURAL ;
* string = c ;
return token ;
}
if ( strcasecmp ( " ABSTRACT " , type ) = = 0 ) {
talloc_free ( type ) ;
token - > type = SCHEMA_ABSTRACT ;
* string = c ;
return token ;
}
if ( strcasecmp ( " AUXILIARY " , type ) = = 0 ) {
talloc_free ( type ) ;
token - > type = SCHEMA_AUXILIARY ;
* string = c ;
return token ;
}
if ( strcasecmp ( " MUST " , type ) = = 0 ) {
talloc_free ( type ) ;
token - > type = SCHEMA_MUST ;
if ( * c = = ' ( ' ) {
c + + ;
n = strcspn ( c , " ) " ) ;
token - > value = talloc_strndup ( ctx , c , n ) ;
c + = n ;
c + + ;
} else {
token - > value = get_def_value ( ctx , & c ) ;
}
c = skip_spaces ( c ) ;
* string = c ;
return token ;
}
if ( strcasecmp ( " MAY " , type ) = = 0 ) {
talloc_free ( type ) ;
token - > type = SCHEMA_MAY ;
if ( * c = = ' ( ' ) {
c + + ;
n = strcspn ( c , " ) " ) ;
token - > value = talloc_strndup ( ctx , c , n ) ;
c + = n ;
c + + ;
} else {
token - > value = get_def_value ( ctx , & c ) ;
}
c = skip_spaces ( c ) ;
* string = c ;
return token ;
}
if ( strcasecmp ( " SINGLE-VALUE " , type ) = = 0 ) {
talloc_free ( type ) ;
token - > type = SCHEMA_SINGLE_VALUE ;
* string = c ;
return token ;
}
if ( strcasecmp ( " EQUALITY " , type ) = = 0 ) {
talloc_free ( type ) ;
token - > type = SCHEMA_EQUALITY ;
token - > value = get_def_value ( ctx , & c ) ;
c = skip_spaces ( c ) ;
* string = c ;
return token ;
}
2005-08-21 17:20:34 +00:00
if ( strcasecmp ( " ORDERING " , type ) = = 0 ) {
talloc_free ( type ) ;
token - > type = SCHEMA_ORDERING ;
token - > value = get_def_value ( ctx , & c ) ;
c = skip_spaces ( c ) ;
* string = c ;
return token ;
}
2005-08-21 14:26:03 +00:00
if ( strcasecmp ( " SUBSTR " , type ) = = 0 ) {
talloc_free ( type ) ;
token - > type = SCHEMA_SUBSTR ;
token - > value = get_def_value ( ctx , & c ) ;
c = skip_spaces ( c ) ;
* string = c ;
return token ;
}
if ( strcasecmp ( " SYNTAX " , type ) = = 0 ) {
talloc_free ( type ) ;
token - > type = SCHEMA_SYNTAX ;
token - > value = get_def_value ( ctx , & c ) ;
c = skip_spaces ( c ) ;
* string = c ;
return token ;
}
if ( strcasecmp ( " DESC " , type ) = = 0 ) {
talloc_free ( type ) ;
token - > type = SCHEMA_DESC ;
token - > value = get_def_value ( ctx , & c ) ;
c = skip_spaces ( c ) ;
* string = c ;
return token ;
}
token - > type = SCHEMA_UNKNOWN ;
token - > value = type ;
if ( * c = = ' ) ' ) {
* string = c ;
return token ;
}
if ( * c = = ' \' ' ) {
c = strchr ( + + c , ' \' ' ) ;
c + + ;
} else {
c + = strcspn ( c , " \t \n " ) ;
}
c = skip_spaces ( c ) ;
* string = c ;
return token ;
}
static struct ldb_message * process_entry ( TALLOC_CTX * mem_ctx , const char * entry )
{
TALLOC_CTX * ctx ;
struct ldb_message * msg ;
2006-09-10 11:16:09 +00:00
struct schema_token * token ;
2005-08-21 14:26:03 +00:00
char * c , * s ;
int n ;
2009-11-13 09:58:20 -06:00
SHA256_CTX sha256_context ;
uint8_t digest [ SHA256_DIGEST_LENGTH ] ;
struct GUID guid ;
bool isAttribute = false ;
bool single_valued = false ;
2005-08-21 14:26:03 +00:00
ctx = talloc_new ( mem_ctx ) ;
2013-11-09 16:40:18 +01:00
if ( ctx = = NULL ) {
return NULL ;
}
2005-08-21 14:26:03 +00:00
msg = ldb_msg_new ( ctx ) ;
2013-11-09 16:40:18 +01:00
if ( msg = = NULL ) {
goto failed ;
}
2005-08-21 14:26:03 +00:00
2005-10-12 06:10:23 +00:00
ldb_msg_add_string ( msg , " objectClass " , " top " ) ;
2005-08-21 14:26:03 +00:00
c = talloc_strdup ( ctx , entry ) ;
if ( ! c ) return NULL ;
c = skip_spaces ( c ) ;
switch ( * c ) {
case ' a ' :
if ( strncmp ( c , " attributetype " , 13 ) = = 0 ) {
c + = 13 ;
MSG_ADD_STRING ( " objectClass " , " attributeSchema " ) ;
2009-11-13 09:58:20 -06:00
isAttribute = true ;
2005-08-21 14:26:03 +00:00
break ;
}
goto failed ;
case ' o ' :
if ( strncmp ( c , " objectclass " , 11 ) = = 0 ) {
c + = 11 ;
MSG_ADD_STRING ( " objectClass " , " classSchema " ) ;
break ;
}
goto failed ;
default :
goto failed ;
}
c = strchr ( c , ' ( ' ) ;
if ( c = = NULL ) goto failed ;
c + + ;
c = skip_spaces ( c ) ;
/* get attributeID */
n = strcspn ( c , " \t " ) ;
s = talloc_strndup ( msg , c , n ) ;
2009-11-13 09:58:20 -06:00
if ( isAttribute ) {
MSG_ADD_STRING ( " attributeID " , s ) ;
} else {
MSG_ADD_STRING ( " governsID " , s ) ;
}
2011-04-06 14:36:21 +10:00
samba_SHA256_Init ( & sha256_context ) ;
samba_SHA256_Update ( & sha256_context , ( uint8_t * ) s , strlen ( s ) ) ;
samba_SHA256_Final ( digest , & sha256_context ) ;
2009-11-13 09:58:20 -06:00
memcpy ( & guid , digest , sizeof ( struct GUID ) ) ;
2009-11-25 17:01:55 -03:00
if ( dsdb_msg_add_guid ( msg , & guid , " schemaIdGuid " ) ! = 0 ) {
2009-11-13 09:58:20 -06:00
goto failed ;
}
2005-08-21 14:26:03 +00:00
c + = n ;
c = skip_spaces ( c ) ;
while ( * c ! = ' ) ' ) {
token = get_next_schema_token ( msg , & c ) ;
if ( ! token ) goto failed ;
switch ( token - > type ) {
case SCHEMA_NAME :
MSG_ADD_STRING ( " cn " , token - > value ) ;
MSG_ADD_STRING ( " name " , token - > value ) ;
MSG_ADD_STRING ( " lDAPDisplayName " , token - > value ) ;
2006-11-22 00:59:34 +00:00
msg - > dn = ldb_dn_copy ( msg , basedn ) ;
ldb_dn_add_child_fmt ( msg - > dn , " CN=%s,CN=Schema,CN=Configuration " , token - > value ) ;
2005-08-21 14:26:03 +00:00
break ;
case SCHEMA_SUP :
2005-08-21 17:20:34 +00:00
MSG_ADD_M_STRING ( " subClassOf " , token - > value ) ;
2005-08-21 14:26:03 +00:00
break ;
case SCHEMA_STRUCTURAL :
MSG_ADD_STRING ( " objectClassCategory " , " 1 " ) ;
break ;
case SCHEMA_ABSTRACT :
MSG_ADD_STRING ( " objectClassCategory " , " 2 " ) ;
break ;
case SCHEMA_AUXILIARY :
MSG_ADD_STRING ( " objectClassCategory " , " 3 " ) ;
break ;
case SCHEMA_MUST :
MSG_ADD_M_STRING ( " mustContain " , token - > value ) ;
break ;
case SCHEMA_MAY :
MSG_ADD_M_STRING ( " mayContain " , token - > value ) ;
break ;
case SCHEMA_SINGLE_VALUE :
2009-11-13 09:58:20 -06:00
single_valued = true ;
2005-08-21 14:26:03 +00:00
break ;
case SCHEMA_EQUALITY :
/* TODO */
break ;
2005-08-21 17:20:34 +00:00
case SCHEMA_ORDERING :
/* TODO */
break ;
2005-08-21 14:26:03 +00:00
case SCHEMA_SUBSTR :
/* TODO */
break ;
case SCHEMA_SYNTAX :
2006-08-17 08:31:19 +00:00
{
2009-11-13 09:58:20 -06:00
char * syntax_oid ;
const struct dsdb_syntax * map ;
char * oMSyntax ;
n = strcspn ( token - > value , " { " ) ;
syntax_oid = talloc_strndup ( ctx , token - > value , n ) ;
map = find_syntax_map_by_standard_oid ( syntax_oid ) ;
2006-08-17 08:31:19 +00:00
if ( ! map ) {
break ;
}
2009-11-13 09:58:20 -06:00
2008-08-18 10:16:45 +10:00
MSG_ADD_STRING ( " attributeSyntax " , map - > attributeSyntax_oid ) ;
2009-11-13 09:58:20 -06:00
oMSyntax = talloc_asprintf ( msg , " %d " , map - > oMSyntax ) ;
MSG_ADD_STRING ( " oMSyntax " , oMSyntax ) ;
2005-08-21 14:26:03 +00:00
break ;
2006-08-17 08:31:19 +00:00
}
2005-08-21 14:26:03 +00:00
case SCHEMA_DESC :
MSG_ADD_STRING ( " description " , token - > value ) ;
break ;
default :
fprintf ( stderr , " Unknown Definition: %s \n " , token - > value ) ;
}
}
2009-11-13 09:58:20 -06:00
if ( isAttribute ) {
MSG_ADD_STRING ( " isSingleValued " , single_valued ? " TRUE " : " FALSE " ) ;
} else {
MSG_ADD_STRING ( " defaultObjectCategory " , ldb_dn_get_linearized ( msg - > dn ) ) ;
}
2005-08-21 14:26:03 +00:00
talloc_steal ( mem_ctx , msg ) ;
talloc_free ( ctx ) ;
return msg ;
failed :
talloc_free ( ctx ) ;
return NULL ;
}
2005-10-12 06:10:23 +00:00
static struct schema_conv process_file ( FILE * in , FILE * out )
2005-08-21 14:26:03 +00:00
{
TALLOC_CTX * ctx ;
struct schema_conv ret ;
char * entry ;
int c , t , line ;
struct ldb_ldif ldif ;
ldif . changetype = LDB_CHANGETYPE_NONE ;
ctx = talloc_new ( NULL ) ;
ret . count = 0 ;
ret . failures = 0 ;
line = 0 ;
while ( ( c = fgetc ( in ) ) ! = EOF ) {
line + + ;
/* fprintf(stderr, "Parsing line %d\n", line); */
if ( c = = ' # ' ) {
do {
c = fgetc ( in ) ;
} while ( c ! = EOF & & c ! = ' \n ' ) ;
continue ;
}
if ( c = = ' \n ' ) {
continue ;
}
t = 0 ;
entry = talloc_array ( ctx , char , 1024 ) ;
if ( entry = = NULL ) exit ( - 1 ) ;
do {
if ( c = = ' \n ' ) {
2012-04-15 14:02:41 -07:00
int ret2 = 0 ;
entry [ t ] = ' \0 ' ;
ret2 = check_braces ( entry ) ;
if ( ret2 = = 0 ) {
2005-08-21 14:26:03 +00:00
ret . count + + ;
ldif . msg = process_entry ( ctx , entry ) ;
if ( ldif . msg = = NULL ) {
ret . failures + + ;
fprintf ( stderr , " No valid msg from entry \n [%s] \n at line %d \n " , entry , line ) ;
break ;
}
ldb_ldif_write_file ( ldb_ctx , out , & ldif ) ;
break ;
}
2012-04-15 14:02:41 -07:00
if ( ret2 = = 2 ) {
2014-03-30 04:01:06 +02:00
fprintf ( stderr , " Invalid entry %s, closing braces need to be preceded by a space \n " , entry ) ;
2012-04-15 14:02:41 -07:00
ret . failures + + ;
break ;
}
2005-08-21 14:26:03 +00:00
line + + ;
} else {
entry [ t ] = c ;
t + + ;
}
if ( ( t % 1023 ) = = 0 ) {
entry = talloc_realloc ( ctx , entry , char , t + 1024 ) ;
if ( entry = = NULL ) exit ( - 1 ) ;
}
} while ( ( c = fgetc ( in ) ) ! = EOF ) ;
if ( c ! = ' \n ' ) {
entry [ t ] = ' \0 ' ;
if ( check_braces ( entry ) = = 0 ) {
ret . count + + ;
ldif . msg = process_entry ( ctx , entry ) ;
if ( ldif . msg = = NULL ) {
ret . failures + + ;
fprintf ( stderr , " No valid msg from entry \n [%s] \n at line %d \n " , entry , line ) ;
break ;
}
ldb_ldif_write_file ( ldb_ctx , out , & ldif ) ;
} else {
fprintf ( stderr , " malformed entry on line %d \n " , line ) ;
ret . failures + + ;
}
}
if ( c = = EOF ) break ;
}
return ret ;
}
2010-03-25 15:45:08 +11:00
static struct options {
const char * basedn ;
const char * input ;
const char * output ;
} options ;
static struct poptOption popt_options [ ] = {
POPT_AUTOHELP
{ " basedn " , ' b ' , POPT_ARG_STRING , & options . basedn , 0 , " base DN " , " DN " } ,
{ " input " , ' I ' , POPT_ARG_STRING , & options . input , 0 ,
" inputfile of OpenLDAP style schema otherwise STDIN " , " inputfile " } ,
{ " output " , ' O ' , POPT_ARG_STRING , & options . output , 0 ,
" outputfile otherwise STDOUT " , " outputfile " } ,
POPT_COMMON_VERSION
{ NULL }
} ;
2005-08-21 14:26:03 +00:00
static void usage ( void )
{
2010-03-25 15:45:08 +11:00
poptContext pc ;
printf ( " Usage: oLschema2ldif <options> \n " ) ;
2006-08-17 08:31:19 +00:00
printf ( " \n Convert OpenLDAP schema to AD-like LDIF format \n \n " ) ;
2005-08-21 14:26:03 +00:00
printf ( " Converts records from an openLdap formatted schema to an ldif schema \n \n " ) ;
2010-03-25 15:45:08 +11:00
pc = poptGetContext ( " oLschema2ldif " , 0 , NULL , popt_options ,
POPT_CONTEXT_KEEP_FIRST ) ;
poptPrintHelp ( pc , stdout , 0 ) ;
2005-08-21 14:26:03 +00:00
exit ( 1 ) ;
}
2010-03-25 15:45:08 +11:00
2005-08-21 14:26:03 +00:00
int main ( int argc , const char * * argv )
{
TALLOC_CTX * ctx ;
struct schema_conv ret ;
FILE * in = stdin ;
FILE * out = stdout ;
2010-03-25 15:45:08 +11:00
poptContext pc ;
int opt ;
2005-08-21 14:26:03 +00:00
ctx = talloc_new ( NULL ) ;
2008-06-14 11:24:17 -04:00
ldb_ctx = ldb_init ( ctx , NULL ) ;
2005-08-21 14:26:03 +00:00
setenv ( " LDB_URL " , " NONE " , 1 ) ;
2010-03-25 15:45:08 +11:00
pc = poptGetContext ( argv [ 0 ] , argc , argv , popt_options ,
POPT_CONTEXT_KEEP_FIRST ) ;
while ( ( opt = poptGetNextOpt ( pc ) ) ! = - 1 ) {
fprintf ( stderr , " Invalid option %s: %s \n " ,
poptBadOption ( pc , 0 ) , poptStrerror ( opt ) ) ;
usage ( ) ;
}
if ( options . basedn = = NULL ) {
printf ( " Base DN not specified \n " ) ;
usage ( ) ;
2005-08-21 14:26:03 +00:00
exit ( 1 ) ;
} else {
2010-03-25 15:45:08 +11:00
basedn = ldb_dn_new ( ctx , ldb_ctx , options . basedn ) ;
2006-11-22 00:59:34 +00:00
if ( ! ldb_dn_validate ( basedn ) ) {
2010-03-25 15:45:08 +11:00
printf ( " Malformed Base DN \n " ) ;
usage ( ) ;
2005-08-21 14:26:03 +00:00
exit ( 1 ) ;
}
}
2010-03-25 15:45:08 +11:00
if ( options . input ) {
in = fopen ( options . input , " r " ) ;
2005-08-21 14:26:03 +00:00
if ( ! in ) {
2010-03-25 15:45:08 +11:00
perror ( options . input ) ;
usage ( ) ;
2005-08-21 14:26:03 +00:00
exit ( 1 ) ;
}
}
2010-03-25 15:45:08 +11:00
if ( options . output ) {
out = fopen ( options . output , " w " ) ;
2005-08-21 14:26:03 +00:00
if ( ! out ) {
2010-03-25 15:45:08 +11:00
perror ( options . output ) ;
usage ( ) ;
2005-08-21 14:26:03 +00:00
exit ( 1 ) ;
}
}
ret = process_file ( in , out ) ;
fclose ( in ) ;
fclose ( out ) ;
printf ( " Converted %d records with %d failures \n " , ret . count , ret . failures ) ;
return 0 ;
}