2006-08-17 08:49:57 +00:00
/*
ldb database library
2008-08-15 13:18:48 +10:00
Copyright ( C ) Andrew Bartlett 2006 - 2008
2006-08-17 08:49:57 +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
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 .
2006-08-17 08:49:57 +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/>.
2006-08-17 08:49:57 +00:00
*/
/*
* Name : ldb
*
* Component : ad2oLschema
*
* Description : utility to convert an AD schema into the format required by OpenLDAP
*
2007-12-27 07:44:57 -06:00
* Author : Andrew Bartlett
2006-08-17 08:49:57 +00:00
*/
# include "includes.h"
2007-05-05 19:54:21 +00:00
# include "ldb_includes.h"
2006-09-06 05:28:04 +00:00
# include "system/locale.h"
2008-07-02 21:30:08 +10:00
# include "lib/ldb/tools/cmdline.h"
2007-09-08 12:42:09 +00:00
# include "param/param.h"
2007-12-13 11:41:47 +01:00
# include "lib/cmdline/popt_common.h"
2008-07-02 21:30:08 +10:00
# include "dsdb/samdb/samdb.h"
2006-08-17 08:49:57 +00:00
struct schema_conv {
int count ;
int skipped ;
int failures ;
} ;
2006-08-18 03:52:50 +00:00
2006-08-17 08:49:57 +00:00
static void usage ( void )
{
printf ( " Usage: ad2oLschema <options> \n " ) ;
printf ( " \n Convert AD-like LDIF to OpenLDAP schema format \n \n " ) ;
printf ( " Options: \n " ) ;
printf ( " -I inputfile inputfile of mapped OIDs and skipped attributes/ObjectClasses " ) ;
printf ( " -H url LDB or LDAP server to read schmea from \n " ) ;
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 AD-like LDIF schema into an openLdap formatted schema \n \n " ) ;
exit ( 1 ) ;
2006-09-17 20:01:56 +00:00
}
2006-08-17 08:49:57 +00:00
2008-07-10 15:52:44 +10:00
static struct ldb_dn * find_schema_dn ( struct ldb_context * ldb , TALLOC_CTX * mem_ctx )
2006-08-18 03:52:50 +00:00
{
const char * rootdse_attrs [ ] = { " schemaNamingContext " , NULL } ;
struct ldb_dn * schemadn ;
2006-11-22 00:59:34 +00:00
struct ldb_dn * basedn = ldb_dn_new ( mem_ctx , ldb , NULL ) ;
2006-08-18 03:52:50 +00:00
struct ldb_result * rootdse_res ;
2008-07-10 15:52:44 +10:00
struct ldb_result * schema_res ;
2006-08-18 03:52:50 +00:00
int ldb_ret ;
2008-07-02 21:30:08 +10:00
2006-08-18 03:52:50 +00:00
if ( ! basedn ) {
return NULL ;
}
/* Search for rootdse */
2008-09-23 14:30:06 -04:00
ldb_ret = ldb_search ( ldb , mem_ctx , & rootdse_res ,
basedn , LDB_SCOPE_BASE , rootdse_attrs , NULL ) ;
2006-08-18 03:52:50 +00:00
if ( ldb_ret ! = LDB_SUCCESS ) {
2008-09-23 14:30:06 -04:00
ldb_ret = ldb_search ( ldb , mem_ctx , & schema_res , basedn , LDB_SCOPE_SUBTREE ,
NULL , " (&(objectClass=dMD)(cn=Schema)) " ) ;
2007-05-29 01:20:47 +00:00
if ( ldb_ret ) {
printf ( " cn=Schema Search failed: %s \n " , ldb_errstring ( ldb ) ) ;
return NULL ;
}
2008-07-10 15:52:44 +10:00
if ( schema_res - > count ! = 1 ) {
talloc_free ( schema_res ) ;
2007-05-29 01:20:47 +00:00
printf ( " Failed to find rootDSE " ) ;
return NULL ;
}
2008-07-10 15:52:44 +10:00
schemadn = talloc_steal ( mem_ctx , schema_res - > msgs [ 0 ] - > dn ) ;
talloc_free ( schema_res ) ;
2007-05-29 01:20:47 +00:00
return schemadn ;
2006-08-17 08:49:57 +00:00
}
2006-08-18 03:52:50 +00:00
if ( rootdse_res - > count ! = 1 ) {
printf ( " Failed to find rootDSE " ) ;
2008-07-10 15:52:44 +10:00
talloc_free ( rootdse_res ) ;
2006-08-18 03:52:50 +00:00
return NULL ;
}
2006-08-17 08:49:57 +00:00
2006-08-18 03:52:50 +00:00
/* Locate schema */
2006-11-22 00:59:34 +00:00
schemadn = ldb_msg_find_attr_as_dn ( ldb , mem_ctx , rootdse_res - > msgs [ 0 ] , " schemaNamingContext " ) ;
2008-07-10 15:52:44 +10:00
talloc_free ( rootdse_res ) ;
2006-08-18 03:52:50 +00:00
2008-07-10 15:52:44 +10:00
if ( ! schemadn ) {
2008-07-02 21:30:08 +10:00
return NULL ;
}
2006-08-18 03:52:50 +00:00
return schemadn ;
2006-08-17 08:49:57 +00:00
}
2008-07-02 15:15:54 +10:00
2008-08-15 20:40:57 +10:00
static struct schema_conv process_convert ( struct ldb_context * ldb , enum dsdb_schema_convert_target target , FILE * in , FILE * out )
2006-08-17 08:49:57 +00:00
{
/* Read list of attributes to skip, OIDs to map */
TALLOC_CTX * mem_ctx = talloc_new ( ldb ) ;
char * line ;
const char * * attrs_skip = NULL ;
int num_skip = 0 ;
struct oid_map {
char * old_oid ;
char * new_oid ;
} * oid_map = NULL ;
2007-04-24 05:57:56 +00:00
int num_oid_maps = 0 ;
struct attr_map {
char * old_attr ;
char * new_attr ;
} * attr_map = NULL ;
int num_attr_maps = 0 ;
2008-07-10 15:52:44 +10:00
struct dsdb_class * objectclass ;
struct dsdb_attribute * attribute ;
2006-08-18 03:52:50 +00:00
struct ldb_dn * schemadn ;
2006-08-17 08:49:57 +00:00
struct schema_conv ret ;
2008-07-02 21:30:08 +10:00
struct dsdb_schema * schema ;
2008-08-15 12:08:10 +10:00
const char * seperator ;
2008-07-02 21:30:08 +10:00
char * error_string ;
2006-08-18 03:52:50 +00:00
2008-07-10 15:52:44 +10:00
int ldb_ret ;
2006-08-17 08:49:57 +00:00
ret . count = 0 ;
ret . skipped = 0 ;
ret . failures = 0 ;
while ( ( line = afdgets ( fileno ( in ) , mem_ctx , 0 ) ) ) {
2006-08-18 06:14:21 +00:00
/* Blank Line */
if ( line [ 0 ] = = ' \0 ' ) {
continue ;
}
/* Comment */
if ( line [ 0 ] = = ' # ' ) {
continue ;
2006-08-17 08:49:57 +00:00
}
2006-08-18 06:14:21 +00:00
if ( isdigit ( line [ 0 ] ) ) {
2006-08-17 08:49:57 +00:00
char * p = strchr ( line , ' : ' ) ;
2008-08-15 13:18:48 +10:00
if ( ! p ) {
ret . failures + + ;
return ret ;
}
2006-08-18 06:14:21 +00:00
p [ 0 ] = ' \0 ' ;
2006-08-17 08:49:57 +00:00
p + + ;
2007-04-24 05:57:56 +00:00
oid_map = talloc_realloc ( mem_ctx , oid_map , struct oid_map , num_oid_maps + 2 ) ;
2006-08-18 06:14:21 +00:00
trim_string ( line , " " , " " ) ;
2007-04-24 05:57:56 +00:00
oid_map [ num_oid_maps ] . old_oid = talloc_move ( oid_map , & line ) ;
2006-08-18 06:14:21 +00:00
trim_string ( p , " " , " " ) ;
2007-04-24 05:57:56 +00:00
oid_map [ num_oid_maps ] . new_oid = p ;
num_oid_maps + + ;
oid_map [ num_oid_maps ] . old_oid = NULL ;
2006-08-17 08:49:57 +00:00
} else {
2007-04-24 05:57:56 +00:00
char * p = strchr ( line , ' : ' ) ;
if ( p ) {
/* remap attribute/objectClass */
p [ 0 ] = ' \0 ' ;
p + + ;
attr_map = talloc_realloc ( mem_ctx , attr_map , struct attr_map , num_attr_maps + 2 ) ;
trim_string ( line , " " , " " ) ;
attr_map [ num_attr_maps ] . old_attr = talloc_move ( attr_map , & line ) ;
trim_string ( p , " " , " " ) ;
attr_map [ num_attr_maps ] . new_attr = p ;
num_attr_maps + + ;
attr_map [ num_attr_maps ] . old_attr = NULL ;
} else {
/* skip attribute/objectClass */
attrs_skip = talloc_realloc ( mem_ctx , attrs_skip , const char * , num_skip + 2 ) ;
trim_string ( line , " " , " " ) ;
attrs_skip [ num_skip ] = talloc_move ( attrs_skip , & line ) ;
num_skip + + ;
attrs_skip [ num_skip ] = NULL ;
}
2006-08-17 08:49:57 +00:00
}
}
2008-07-10 15:52:44 +10:00
schemadn = find_schema_dn ( ldb , mem_ctx ) ;
2006-08-18 03:52:50 +00:00
if ( ! schemadn ) {
printf ( " Failed to find schema DN: %s \n " , ldb_errstring ( ldb ) ) ;
ret . failures = 1 ;
return ret ;
}
2008-07-10 15:52:44 +10:00
ldb_ret = dsdb_schema_from_schema_dn ( mem_ctx , ldb ,
lp_iconv_convenience ( cmdline_lp_ctx ) ,
schemadn , & schema , & error_string ) ;
2008-07-02 21:30:08 +10:00
if ( ldb_ret ! = LDB_SUCCESS ) {
printf ( " Failed to load schema: %s \n " , error_string ) ;
ret . failures = 1 ;
return ret ;
}
2006-08-22 10:49:54 +00:00
switch ( target ) {
case TARGET_OPENLDAP :
2008-08-15 12:08:10 +10:00
seperator = " \n " ;
2006-08-22 10:49:54 +00:00
break ;
case TARGET_FEDORA_DS :
2008-08-15 12:08:10 +10:00
seperator = " \n " ;
2006-08-22 10:49:54 +00:00
fprintf ( out , " dn: cn=schema \n " ) ;
break ;
}
2008-07-10 15:52:44 +10:00
for ( attribute = schema - > attributes ; attribute ; attribute = attribute - > next ) {
const char * name = attribute - > lDAPDisplayName ;
const char * oid = attribute - > attributeID_oid ;
const char * syntax = attribute - > attributeSyntax_oid ;
2008-08-15 20:40:57 +10:00
const char * equality = NULL , * substring = NULL ;
2008-07-10 15:52:44 +10:00
bool single_value = attribute - > isSingleValued ;
2006-08-18 06:14:21 +00:00
2008-08-18 10:16:45 +10:00
const struct dsdb_syntax * map = find_syntax_map_by_ad_syntax ( attribute - > oMSyntax ) ;
2006-08-17 08:49:57 +00:00
char * schema_entry = NULL ;
int j ;
/* We have been asked to skip some attributes/objectClasses */
2006-10-16 01:36:22 +00:00
if ( attrs_skip & & str_list_check_ci ( attrs_skip , name ) ) {
2006-08-17 08:49:57 +00:00
ret . skipped + + ;
continue ;
}
/* We might have been asked to remap this oid, due to a conflict */
2007-01-02 11:36:50 +00:00
for ( j = 0 ; oid & & oid_map & & oid_map [ j ] . old_oid ; j + + ) {
2007-04-28 16:39:24 +00:00
if ( strcasecmp ( oid , oid_map [ j ] . old_oid ) = = 0 ) {
2006-08-17 08:49:57 +00:00
oid = oid_map [ j ] . new_oid ;
break ;
}
}
2008-08-15 20:40:57 +10:00
if ( map ) {
2008-08-15 12:08:10 +10:00
/* We might have been asked to remap this oid,
* due to a conflict , or lack of
* implementation */
2008-08-18 10:16:45 +10:00
syntax = map - > ldap_oid ;
2008-08-15 20:40:57 +10:00
/* We might have been asked to remap this oid, due to a conflict */
for ( j = 0 ; syntax & & oid_map & & oid_map [ j ] . old_oid ; j + + ) {
if ( strcasecmp ( syntax , oid_map [ j ] . old_oid ) = = 0 ) {
syntax = oid_map [ j ] . new_oid ;
2008-08-15 12:08:10 +10:00
break ;
}
}
2008-08-15 20:40:57 +10:00
equality = map - > equality ;
substring = map - > substring ;
2006-08-18 03:52:50 +00:00
}
2006-08-17 08:49:57 +00:00
2007-04-24 05:57:56 +00:00
/* We might have been asked to remap this name, due to a conflict */
for ( j = 0 ; name & & attr_map & & attr_map [ j ] . old_attr ; j + + ) {
2007-04-28 16:39:24 +00:00
if ( strcasecmp ( name , attr_map [ j ] . old_attr ) = = 0 ) {
2007-04-24 05:57:56 +00:00
name = attr_map [ j ] . new_attr ;
break ;
}
}
2008-10-03 16:36:04 -07:00
schema_entry = schema_attribute_description ( mem_ctx ,
target ,
seperator ,
oid ,
name ,
equality ,
substring ,
syntax ,
single_value ,
2008-11-14 08:49:06 +01:00
false ,
NULL , NULL ,
NULL , NULL ,
false , false ) ;
2006-08-17 08:49:57 +00:00
2008-08-15 13:18:48 +10:00
if ( schema_entry = = NULL ) {
ret . failures + + ;
return ret ;
2006-08-17 08:49:57 +00:00
}
2006-08-22 10:49:54 +00:00
switch ( target ) {
case TARGET_OPENLDAP :
2008-08-15 13:18:48 +10:00
fprintf ( out , " attributetype %s \n \n " , schema_entry ) ;
2006-08-22 10:49:54 +00:00
break ;
case TARGET_FEDORA_DS :
2008-08-15 13:18:48 +10:00
fprintf ( out , " attributeTypes: %s \n " , schema_entry ) ;
2006-08-22 10:49:54 +00:00
break ;
}
2006-09-04 00:27:37 +00:00
ret . count + + ;
2006-08-17 08:49:57 +00:00
}
2008-07-10 15:52:44 +10:00
/* This is already sorted to have 'top' and similar classes first */
for ( objectclass = schema - > classes ; objectclass ; objectclass = objectclass - > next ) {
const char * name = objectclass - > lDAPDisplayName ;
const char * oid = objectclass - > governsID_oid ;
const char * subClassOf = objectclass - > subClassOf ;
int objectClassCategory = objectclass - > objectClassCategory ;
char * * must ;
char * * may ;
2006-08-18 03:52:50 +00:00
char * schema_entry = NULL ;
2008-07-10 15:52:44 +10:00
const char * objectclass_name_as_list [ ] = {
objectclass - > lDAPDisplayName ,
NULL
} ;
2006-08-18 03:52:50 +00:00
int j ;
2008-08-15 13:18:48 +10:00
int attr_idx ;
2008-07-10 15:52:44 +10:00
2006-08-18 03:52:50 +00:00
/* We have been asked to skip some attributes/objectClasses */
2006-10-16 01:36:22 +00:00
if ( attrs_skip & & str_list_check_ci ( attrs_skip , name ) ) {
2006-08-18 03:52:50 +00:00
ret . skipped + + ;
continue ;
}
/* We might have been asked to remap this oid, due to a conflict */
2008-05-06 11:02:40 +10:00
for ( j = 0 ; oid_map & & oid_map [ j ] . old_oid ; j + + ) {
2007-04-28 16:39:24 +00:00
if ( strcasecmp ( oid , oid_map [ j ] . old_oid ) = = 0 ) {
2006-08-18 03:52:50 +00:00
oid = oid_map [ j ] . new_oid ;
break ;
}
}
2008-08-15 12:08:10 +10:00
/* We might have been asked to remap this name, due to a conflict */
for ( j = 0 ; name & & attr_map & & attr_map [ j ] . old_attr ; j + + ) {
if ( strcasecmp ( name , attr_map [ j ] . old_attr ) = = 0 ) {
name = attr_map [ j ] . new_attr ;
break ;
}
}
may = dsdb_full_attribute_list ( mem_ctx , schema , objectclass_name_as_list , DSDB_SCHEMA_ALL_MAY ) ;
2008-08-15 13:18:48 +10:00
for ( j = 0 ; may & & may [ j ] ; j + + ) {
/* We might have been asked to remap this name, due to a conflict */
for ( attr_idx = 0 ; attr_map & & attr_map [ attr_idx ] . old_attr ; attr_idx + + ) {
if ( strcasecmp ( may [ j ] , attr_map [ attr_idx ] . old_attr ) = = 0 ) {
may [ j ] = attr_map [ attr_idx ] . new_attr ;
break ;
}
}
2006-08-18 03:52:50 +00:00
}
2008-08-15 13:18:48 +10:00
must = dsdb_full_attribute_list ( mem_ctx , schema , objectclass_name_as_list , DSDB_SCHEMA_ALL_MUST ) ;
2008-07-10 15:52:44 +10:00
2008-08-15 13:18:48 +10:00
for ( j = 0 ; must & & must [ j ] ; j + + ) {
/* We might have been asked to remap this name, due to a conflict */
for ( attr_idx = 0 ; attr_map & & attr_map [ attr_idx ] . old_attr ; attr_idx + + ) {
if ( strcasecmp ( must [ j ] , attr_map [ attr_idx ] . old_attr ) = = 0 ) {
must [ j ] = attr_map [ attr_idx ] . new_attr ;
break ;
}
}
2006-08-18 06:14:21 +00:00
}
2008-08-15 13:18:48 +10:00
schema_entry = schema_class_description ( mem_ctx , target ,
seperator ,
oid ,
name ,
2008-08-15 20:40:57 +10:00
NULL ,
2008-08-15 13:18:48 +10:00
subClassOf ,
objectClassCategory ,
must ,
2008-11-14 08:51:59 +01:00
may ,
NULL ) ;
2008-08-15 13:18:48 +10:00
if ( schema_entry = = NULL ) {
ret . failures + + ;
return ret ;
2006-08-18 03:52:50 +00:00
}
2006-08-22 10:49:54 +00:00
switch ( target ) {
case TARGET_OPENLDAP :
2008-08-15 13:18:48 +10:00
fprintf ( out , " objectclass %s \n \n " , schema_entry ) ;
2006-08-22 10:49:54 +00:00
break ;
case TARGET_FEDORA_DS :
2008-08-15 13:18:48 +10:00
fprintf ( out , " objectClasses: %s \n " , schema_entry ) ;
2006-08-22 10:49:54 +00:00
break ;
}
2006-09-04 00:27:37 +00:00
ret . count + + ;
2006-08-18 03:52:50 +00:00
}
return ret ;
2006-08-17 08:49:57 +00:00
}
int main ( int argc , const char * * argv )
{
TALLOC_CTX * ctx ;
struct ldb_cmdline * options ;
FILE * in = stdin ;
FILE * out = stdout ;
struct ldb_context * ldb ;
struct schema_conv ret ;
2006-08-18 03:52:50 +00:00
const char * target_str ;
2008-08-15 20:40:57 +10:00
enum dsdb_schema_convert_target target ;
2006-08-17 08:49:57 +00:00
ctx = talloc_new ( NULL ) ;
2008-06-14 11:24:17 -04:00
ldb = ldb_init ( ctx , NULL ) ;
2006-08-17 08:49:57 +00:00
options = ldb_cmdline_process ( ldb , argc , argv , usage ) ;
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 ) ;
}
}
2007-12-13 11:41:47 +01:00
target_str = lp_parm_string ( cmdline_lp_ctx , NULL , " convert " , " target " ) ;
2006-08-18 03:52:50 +00:00
if ( ! target_str | | strcasecmp ( target_str , " openldap " ) = = 0 ) {
target = TARGET_OPENLDAP ;
} else if ( strcasecmp ( target_str , " fedora-ds " ) = = 0 ) {
target = TARGET_FEDORA_DS ;
} else {
printf ( " Unsupported target: %s \n " , target_str ) ;
exit ( 1 ) ;
}
ret = process_convert ( ldb , target , in , out ) ;
2006-08-17 08:49:57 +00:00
fclose ( in ) ;
fclose ( out ) ;
2006-09-04 00:27:37 +00:00
printf ( " Converted %d records (skipped %d) with %d failures \n " , ret . count , ret . skipped , ret . failures ) ;
2006-08-17 08:49:57 +00:00
return 0 ;
}