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"
2007-05-05 18:50:56 +00:00
# include "ldb_includes.h"
# include "tools/cmdline.h"
2008-08-15 21:20:05 +10:00
# include "dsdb/samdb/samdb.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 + + ;
if ( * c = = ' ) ' ) b - - ;
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 ;
ctx = talloc_new ( mem_ctx ) ;
msg = ldb_msg_new ( ctx ) ;
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 " ) ;
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 ) ;
MSG_ADD_STRING ( " attributeID " , s ) ;
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 :
MSG_ADD_STRING ( " isSingleValued " , " TRUE " ) ;
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
{
2008-08-18 10:16:45 +10:00
const struct dsdb_syntax * map =
2006-08-17 08:31:19 +00:00
find_syntax_map_by_standard_oid ( token - > value ) ;
if ( ! map ) {
break ;
}
2008-08-18 10:16:45 +10:00
MSG_ADD_STRING ( " attributeSyntax " , map - > attributeSyntax_oid ) ;
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 ) ;
}
}
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 ' ) {
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 ) ;
break ;
}
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 ;
}
static void usage ( void )
{
2006-08-17 08:31:19 +00:00
printf ( " Usage: oLschema2ldif -H NONE <options> \n " ) ;
printf ( " \n Convert OpenLDAP schema to AD-like LDIF format \n \n " ) ;
2005-08-21 14:26:03 +00:00
printf ( " Options: \n " ) ;
2006-08-17 08:31:19 +00:00
printf ( " -I inputfile inputfile of OpenLDAP style schema otherwise STDIN \n " ) ;
2005-08-21 14:26:03 +00:00
printf ( " -O outputfile outputfile otherwise STDOUT \n " ) ;
printf ( " -o options pass options like modules to activate \n " ) ;
printf ( " e.g: -o modules:timestamps \n " ) ;
printf ( " \n " ) ;
printf ( " Converts records from an openLdap formatted schema to an ldif schema \n \n " ) ;
exit ( 1 ) ;
}
int main ( int argc , const char * * argv )
{
TALLOC_CTX * ctx ;
struct schema_conv ret ;
struct ldb_cmdline * options ;
FILE * in = stdin ;
FILE * out = stdout ;
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 ) ;
options = ldb_cmdline_process ( ldb_ctx , argc , argv , usage ) ;
if ( options - > basedn = = NULL ) {
perror ( " Base DN not specified " ) ;
exit ( 1 ) ;
} else {
2006-11-22 00:59:34 +00:00
basedn = ldb_dn_new ( ctx , ldb_ctx , options - > basedn ) ;
if ( ! ldb_dn_validate ( basedn ) ) {
2005-08-21 14:26:03 +00:00
perror ( " Malformed Base DN " ) ;
exit ( 1 ) ;
}
}
if ( options - > input ) {
in = fopen ( options - > input , " r " ) ;
if ( ! in ) {
perror ( options - > input ) ;
exit ( 1 ) ;
}
}
if ( options - > output ) {
out = fopen ( options - > output , " w " ) ;
if ( ! out ) {
perror ( options - > output ) ;
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 ;
}