2010-07-16 15:27:30 +04:00
/*
Unix SMB / CIFS implementation .
2008-08-20 07:22:16 +04:00
DSDB schema header
2010-07-16 15:27:30 +04:00
2008-08-20 07:22:16 +04:00
Copyright ( C ) Stefan Metzmacher < metze @ samba . org > 2006 - 2007
Copyright ( C ) Andrew Bartlett < abartlet @ samba . org > 2006 - 2008
2011-05-22 23:41:56 +04:00
Copyright ( C ) Matthieu Patou < mat @ matws . net > 2011
2008-08-20 07:22:16 +04:00
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 3 of the License , or
( at your option ) any later version .
2010-07-16 15:27:30 +04:00
2008-08-20 07:22:16 +04:00
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 .
2010-07-16 15:27:30 +04:00
2008-08-20 07:22:16 +04:00
You should have received a copy of the GNU General Public License
along with this program . If not , see < http : //www.gnu.org/licenses/>.
2010-07-16 15:27:30 +04:00
2008-08-20 07:22:16 +04:00
*/
# include "includes.h"
2009-06-18 03:21:35 +04:00
# include "lib/util/dlinklist.h"
2008-08-20 07:22:16 +04:00
# include "dsdb/samdb/samdb.h"
2011-02-10 06:12:51 +03:00
# include <ldb_module.h>
2008-08-20 07:22:16 +04:00
# include "param/param.h"
2009-11-16 10:48:46 +03:00
# include "librpc/ndr/libndr.h"
# include "librpc/gen_ndr/ndr_misc.h"
2010-02-13 04:59:43 +03:00
# include "lib/util/tsort.h"
2008-08-20 07:22:16 +04:00
2020-08-07 23:27:39 +03:00
# undef strcasecmp
2011-08-09 10:54:36 +04:00
/* change this when we change something in our schema code that
* requires a re - index of the database
*/
2019-03-14 08:05:23 +03:00
# define SAMDB_INDEXING_VERSION "3"
2011-08-09 10:54:36 +04:00
2009-04-02 09:42:21 +04:00
/*
override the name to attribute handler function
*/
2010-07-16 15:27:30 +04:00
const struct ldb_schema_attribute * dsdb_attribute_handler_override ( struct ldb_context * ldb ,
2009-04-02 09:42:21 +04:00
void * private_data ,
const char * name )
{
struct dsdb_schema * schema = talloc_get_type_abort ( private_data , struct dsdb_schema ) ;
const struct dsdb_attribute * a = dsdb_attribute_by_lDAPDisplayName ( schema , name ) ;
if ( a = = NULL ) {
/* this will fall back to ldb internal handling */
return NULL ;
}
return a - > ldb_schema_attribute ;
}
2017-11-22 02:37:07 +03:00
2012-08-10 02:44:04 +04:00
/*
* Set the attribute handlers onto the LDB , and potentially write the
* @ INDEXLIST , @ IDXONE and @ ATTRIBUTES records . The @ ATTRIBUTES records
* are required so we can operate on a schema - less database ( say the
* backend during emergency fixes ) and during the schema load .
*/
2017-05-03 23:53:14 +03:00
int dsdb_schema_set_indices_and_attributes ( struct ldb_context * ldb ,
struct dsdb_schema * schema ,
2017-11-22 02:34:01 +03:00
enum schema_set_enum mode )
2008-08-20 09:46:46 +04:00
{
int ret = LDB_SUCCESS ;
2008-08-21 06:58:00 +04:00
struct ldb_result * res ;
struct ldb_result * res_idx ;
2008-08-20 09:46:46 +04:00
struct dsdb_attribute * attr ;
2008-08-21 06:58:00 +04:00
struct ldb_message * mod_msg ;
2009-04-02 09:42:21 +04:00
TALLOC_CTX * mem_ctx ;
2008-08-21 06:58:00 +04:00
struct ldb_message * msg ;
struct ldb_message * msg_idx ;
2017-08-15 06:58:57 +03:00
struct loadparm_context * lp_ctx =
talloc_get_type ( ldb_get_opaque ( ldb , " loadparm " ) ,
struct loadparm_context ) ;
2019-05-22 05:07:19 +03:00
bool guid_indexing = true ;
2019-05-23 11:13:05 +03:00
bool declare_ordered_integer_in_attributes = true ;
uint32_t pack_format_override ;
2019-05-22 05:07:19 +03:00
if ( lp_ctx ! = NULL ) {
/*
* GUID indexing is wanted by Samba by default . This allows
* an override in a specific case for downgrades .
*/
guid_indexing = lpcfg_parm_bool ( lp_ctx ,
NULL ,
" dsdb " ,
" guid index " ,
true ) ;
2019-05-23 11:13:05 +03:00
/*
* If the pack format has been overridden to a previous
* version , then act like ORDERED_INTEGER doesn ' t exist ,
* because it ' s a new type and we don ' t want to deal with
* possible issues with databases containing version 1 pack
* format and ordered types .
*
* This approach means that the @ ATTRIBUTES will be
* incorrect for integers . Many other @ ATTRIBUTES
* values are gross simplifications , but the presence
* of the ORDERED_INTEGER keyword prevents the old
* Samba from starting and then forcing a reindex .
*
* It is too difficult to override the actual index
* formatter , but this doesn ' t matter in practice .
*/
pack_format_override =
( intptr_t ) ldb_get_opaque ( ldb , " pack_format_override " ) ;
if ( pack_format_override = = LDB_PACKING_FORMAT | |
pack_format_override = = LDB_PACKING_FORMAT_NODN ) {
declare_ordered_integer_in_attributes = false ;
}
2019-05-22 05:07:19 +03:00
}
2009-04-02 09:42:21 +04:00
/* setup our own attribute name to schema handler */
ldb_schema_attribute_set_override_handler ( ldb , dsdb_attribute_handler_override , schema ) ;
2017-03-30 03:25:35 +03:00
ldb_schema_set_override_indexlist ( ldb , true ) ;
2019-05-22 05:07:19 +03:00
if ( guid_indexing ) {
2017-08-15 06:58:57 +03:00
ldb_schema_set_override_GUID_index ( ldb , " objectGUID " , " GUID " ) ;
}
2009-04-02 09:42:21 +04:00
2017-11-22 02:34:01 +03:00
if ( mode = = SCHEMA_MEMORY_ONLY ) {
2009-04-02 09:42:21 +04:00
return ret ;
}
mem_ctx = talloc_new ( ldb ) ;
2008-08-21 06:58:00 +04:00
if ( ! mem_ctx ) {
2010-07-06 07:21:54 +04:00
return ldb_oom ( ldb ) ;
2008-08-21 06:58:00 +04:00
}
msg = ldb_msg_new ( mem_ctx ) ;
if ( ! msg ) {
ldb_oom ( ldb ) ;
2009-04-02 09:42:21 +04:00
goto op_error ;
2008-08-21 06:58:00 +04:00
}
msg_idx = ldb_msg_new ( mem_ctx ) ;
if ( ! msg_idx ) {
ldb_oom ( ldb ) ;
2009-04-02 09:42:21 +04:00
goto op_error ;
2008-08-21 06:58:00 +04:00
}
msg - > dn = ldb_dn_new ( msg , ldb , " @ATTRIBUTES " ) ;
if ( ! msg - > dn ) {
ldb_oom ( ldb ) ;
2009-04-02 09:42:21 +04:00
goto op_error ;
2008-08-21 06:58:00 +04:00
}
2010-06-21 00:31:43 +04:00
msg_idx - > dn = ldb_dn_new ( msg_idx , ldb , " @INDEXLIST " ) ;
2008-08-21 06:58:00 +04:00
if ( ! msg_idx - > dn ) {
ldb_oom ( ldb ) ;
2009-04-02 09:42:21 +04:00
goto op_error ;
2008-08-21 06:58:00 +04:00
}
2009-05-28 10:08:49 +04:00
ret = ldb_msg_add_string ( msg_idx , " @IDXONE " , " 1 " ) ;
if ( ret ! = LDB_SUCCESS ) {
goto op_error ;
}
2019-05-22 05:07:19 +03:00
if ( guid_indexing ) {
2017-08-15 06:58:57 +03:00
ret = ldb_msg_add_string ( msg_idx , " @IDXGUID " , " objectGUID " ) ;
if ( ret ! = LDB_SUCCESS ) {
goto op_error ;
}
ret = ldb_msg_add_string ( msg_idx , " @IDX_DN_GUID " , " GUID " ) ;
if ( ret ! = LDB_SUCCESS ) {
goto op_error ;
}
}
2011-08-09 10:54:36 +04:00
2017-09-08 06:31:55 +03:00
ret = ldb_msg_add_string ( msg_idx , " @SAMDB_INDEXING_VERSION " , SAMDB_INDEXING_VERSION ) ;
2011-08-09 10:54:36 +04:00
if ( ret ! = LDB_SUCCESS ) {
goto op_error ;
}
2017-02-03 06:13:43 +03:00
ret = ldb_msg_add_string ( msg_idx , SAMBA_FEATURES_SUPPORTED_FLAG , " 1 " ) ;
if ( ret ! = LDB_SUCCESS ) {
goto op_error ;
}
2008-08-20 09:46:46 +04:00
for ( attr = schema - > attributes ; attr ; attr = attr - > next ) {
2008-08-21 06:58:00 +04:00
const char * syntax = attr - > syntax - > ldb_syntax ;
2010-07-16 15:27:30 +04:00
2008-08-21 06:58:00 +04:00
if ( ! syntax ) {
syntax = attr - > syntax - > ldap_oid ;
}
2010-07-16 15:27:30 +04:00
/*
* Write out a rough approximation of the schema
2019-05-22 05:07:19 +03:00
* as an @ ATTRIBUTES value , for bootstrapping .
* Only write ORDERED_INTEGER if we ' re using GUID indexes ,
2010-07-16 15:27:30 +04:00
*/
2008-08-21 06:58:00 +04:00
if ( strcmp ( syntax , LDB_SYNTAX_INTEGER ) = = 0 ) {
ret = ldb_msg_add_string ( msg , attr - > lDAPDisplayName , " INTEGER " ) ;
2019-03-25 03:52:42 +03:00
} else if ( strcmp ( syntax , LDB_SYNTAX_ORDERED_INTEGER ) = = 0 ) {
2019-05-23 11:13:05 +03:00
if ( declare_ordered_integer_in_attributes & &
guid_indexing ) {
/*
* The normal production case
*/
2019-05-22 05:07:19 +03:00
ret = ldb_msg_add_string ( msg ,
attr - > lDAPDisplayName ,
" ORDERED_INTEGER " ) ;
} else {
2019-05-23 11:13:05 +03:00
/*
* For this mode , we are going back to
* before GUID indexing so we write it out
* as INTEGER
*
* Down in LDB , the special handler
* ( index_format_fn ) that made
* ORDERED_INTEGER and INTEGER
* different has been disabled .
*/
2019-05-22 05:07:19 +03:00
ret = ldb_msg_add_string ( msg ,
attr - > lDAPDisplayName ,
" INTEGER " ) ;
}
2008-08-21 06:58:00 +04:00
} else if ( strcmp ( syntax , LDB_SYNTAX_DIRECTORY_STRING ) = = 0 ) {
2019-05-23 11:13:05 +03:00
ret = ldb_msg_add_string ( msg , attr - > lDAPDisplayName ,
" CASE_INSENSITIVE " ) ;
2010-07-16 15:27:30 +04:00
}
2008-08-21 06:58:00 +04:00
if ( ret ! = LDB_SUCCESS ) {
2008-09-12 01:45:28 +04:00
break ;
2008-08-21 06:58:00 +04:00
}
if ( attr - > searchFlags & SEARCH_FLAG_ATTINDEX ) {
2019-05-23 11:13:05 +03:00
/*
* When preparing to downgrade Samba , we need to write
* out an LDB without the new key word ORDERED_INTEGER .
*/
if ( strcmp ( syntax , LDB_SYNTAX_ORDERED_INTEGER ) = = 0
& & ! declare_ordered_integer_in_attributes ) {
/*
* Ugly , but do nothing , the best
* thing is to omit the reference
* entirely , the next transaction will
* spot this and rewrite everything .
*
* This way nothing will look at the
* index for this attribute until
* Samba starts and this is all
* rewritten .
*/
} else {
ret = ldb_msg_add_string ( msg_idx , " @IDXATTR " , attr - > lDAPDisplayName ) ;
if ( ret ! = LDB_SUCCESS ) {
break ;
}
2008-08-21 06:58:00 +04:00
}
}
2008-08-20 09:46:46 +04:00
}
2009-04-02 09:42:21 +04:00
if ( ret ! = LDB_SUCCESS ) {
2008-08-21 06:58:00 +04:00
talloc_free ( mem_ctx ) ;
return ret ;
}
2010-07-16 15:27:30 +04:00
/*
* Try to avoid churning the attributes too much ,
* we only want to do this if they have changed
*/
2010-07-03 16:05:04 +04:00
ret = ldb_search ( ldb , mem_ctx , & res , msg - > dn , LDB_SCOPE_BASE , NULL ,
NULL ) ;
2008-08-21 06:58:00 +04:00
if ( ret = = LDB_ERR_NO_SUCH_OBJECT ) {
2017-11-22 02:34:01 +03:00
if ( mode = = SCHEMA_COMPARE ) {
/* We are probably not in a transaction */
goto wrong_mode ;
}
2008-08-21 06:58:00 +04:00
ret = ldb_add ( ldb , msg ) ;
} else if ( ret ! = LDB_SUCCESS ) {
2008-09-12 01:45:28 +04:00
} else if ( res - > count ! = 1 ) {
2017-11-22 02:34:01 +03:00
if ( mode = = SCHEMA_COMPARE ) {
/* We are probably not in a transaction */
goto wrong_mode ;
}
2008-09-12 01:45:28 +04:00
ret = ldb_add ( ldb , msg ) ;
2008-08-21 06:58:00 +04:00
} else {
2008-08-21 10:42:03 +04:00
/* Annoyingly added to our search results */
ldb_msg_remove_attr ( res - > msgs [ 0 ] , " distinguishedName " ) ;
2010-07-16 15:27:30 +04:00
2010-07-16 14:26:45 +04:00
ret = ldb_msg_difference ( ldb , mem_ctx ,
res - > msgs [ 0 ] , msg , & mod_msg ) ;
if ( ret ! = LDB_SUCCESS ) {
goto op_error ;
}
2008-08-21 06:58:00 +04:00
if ( mod_msg - > num_elements > 0 ) {
2017-06-07 01:44:50 +03:00
/*
2017-09-11 06:22:23 +03:00
* Do the replace with the difference , as we
* are under the read lock and we wish to do a
* delete of any removed / renamed attributes
2017-06-07 01:44:50 +03:00
*/
2017-11-22 02:34:01 +03:00
if ( mode = = SCHEMA_COMPARE ) {
/* We are probably not in a transaction */
goto wrong_mode ;
}
2017-09-11 06:22:23 +03:00
ret = dsdb_modify ( ldb , mod_msg , 0 ) ;
2008-08-21 06:58:00 +04:00
}
2010-06-24 21:48:07 +04:00
talloc_free ( mod_msg ) ;
2008-08-21 06:58:00 +04:00
}
2009-11-11 11:25:32 +03:00
if ( ret = = LDB_ERR_OPERATIONS_ERROR | | ret = = LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS | | ret = = LDB_ERR_INVALID_DN_SYNTAX ) {
/* We might be on a read-only DB or LDAP */
2008-09-12 01:45:28 +04:00
ret = LDB_SUCCESS ;
}
if ( ret ! = LDB_SUCCESS ) {
2017-06-09 03:06:37 +03:00
DBG_ERR ( " Failed to set schema into @ATTRIBUTES: %s \n " ,
ldb_errstring ( ldb ) ) ;
2008-08-21 06:58:00 +04:00
talloc_free ( mem_ctx ) ;
return ret ;
}
2010-07-16 15:27:30 +04:00
/* Now write out the indexes, as found in the schema (if they have changed) */
2008-08-21 06:58:00 +04:00
2010-07-03 16:05:04 +04:00
ret = ldb_search ( ldb , mem_ctx , & res_idx , msg_idx - > dn , LDB_SCOPE_BASE ,
NULL , NULL ) ;
2008-08-21 06:58:00 +04:00
if ( ret = = LDB_ERR_NO_SUCH_OBJECT ) {
2017-11-22 02:34:01 +03:00
if ( mode = = SCHEMA_COMPARE ) {
/* We are probably not in a transaction */
goto wrong_mode ;
}
2008-08-21 06:58:00 +04:00
ret = ldb_add ( ldb , msg_idx ) ;
} else if ( ret ! = LDB_SUCCESS ) {
2009-07-03 16:24:40 +04:00
} else if ( res_idx - > count ! = 1 ) {
2017-11-22 02:34:01 +03:00
if ( mode = = SCHEMA_COMPARE ) {
/* We are probably not in a transaction */
goto wrong_mode ;
}
2008-09-12 01:45:28 +04:00
ret = ldb_add ( ldb , msg_idx ) ;
2008-08-21 06:58:00 +04:00
} else {
2008-08-21 10:42:03 +04:00
/* Annoyingly added to our search results */
ldb_msg_remove_attr ( res_idx - > msgs [ 0 ] , " distinguishedName " ) ;
2010-07-16 14:26:45 +04:00
ret = ldb_msg_difference ( ldb , mem_ctx ,
res_idx - > msgs [ 0 ] , msg_idx , & mod_msg ) ;
if ( ret ! = LDB_SUCCESS ) {
goto op_error ;
}
2017-08-01 01:26:34 +03:00
/*
* We don ' t want to re - index just because we didn ' t
* see this flag
*
* DO NOT backport this logic earlier than 4.7 , it
* isn ' t needed and would be dangerous before 4.6 ,
* where we add logic to samba_dsdb to manage
* @ SAMBA_FEATURES_SUPPORTED and need to know if the
* DB has been re - opened by an earlier version .
*
*/
if ( mod_msg - > num_elements = = 1
& & ldb_attr_cmp ( mod_msg - > elements [ 0 ] . name ,
SAMBA_FEATURES_SUPPORTED_FLAG ) = = 0 ) {
/*
* Ignore only adding
* @ SAMBA_FEATURES_SUPPORTED
*/
} else if ( mod_msg - > num_elements > 0 ) {
2017-09-11 06:22:23 +03:00
2017-06-07 01:44:50 +03:00
/*
2017-09-11 06:22:23 +03:00
* Do the replace with the difference , as we
* are under the read lock and we wish to do a
* delete of any removed / renamed attributes
2017-06-07 01:44:50 +03:00
*/
2017-11-22 02:34:01 +03:00
if ( mode = = SCHEMA_COMPARE ) {
/* We are probably not in a transaction */
goto wrong_mode ;
}
2017-09-11 06:22:23 +03:00
ret = dsdb_modify ( ldb , mod_msg , 0 ) ;
2008-08-21 06:58:00 +04:00
}
2010-06-24 21:48:07 +04:00
talloc_free ( mod_msg ) ;
2008-08-21 06:58:00 +04:00
}
2009-11-11 11:25:32 +03:00
if ( ret = = LDB_ERR_OPERATIONS_ERROR | | ret = = LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS | | ret = = LDB_ERR_INVALID_DN_SYNTAX ) {
2008-08-21 06:58:00 +04:00
/* We might be on a read-only DB */
2008-09-11 14:51:26 +04:00
ret = LDB_SUCCESS ;
2008-08-21 06:58:00 +04:00
}
2017-06-09 03:06:37 +03:00
if ( ret ! = LDB_SUCCESS ) {
DBG_ERR ( " Failed to set schema into @INDEXLIST: %s \n " ,
ldb_errstring ( ldb ) ) ;
}
2008-08-21 06:58:00 +04:00
talloc_free ( mem_ctx ) ;
return ret ;
2009-04-02 09:42:21 +04:00
op_error :
talloc_free ( mem_ctx ) ;
2010-07-06 07:21:54 +04:00
return ldb_operr ( ldb ) ;
2017-11-22 02:34:01 +03:00
wrong_mode :
talloc_free ( mem_ctx ) ;
return LDB_ERR_BUSY ;
2009-04-02 09:42:21 +04:00
}
2011-08-09 05:47:25 +04:00
/*
create extra attribute shortcuts
*/
static void dsdb_setup_attribute_shortcuts ( struct ldb_context * ldb , struct dsdb_schema * schema )
{
struct dsdb_attribute * attribute ;
/* setup fast access to one_way_link and DN format */
for ( attribute = schema - > attributes ; attribute ; attribute = attribute - > next ) {
attribute - > dn_format = dsdb_dn_oid_to_format ( attribute - > syntax - > ldap_oid ) ;
if ( attribute - > dn_format = = DSDB_INVALID_DN ) {
attribute - > one_way_link = false ;
continue ;
}
/* these are not considered to be one way links for
the purpose of DN link fixups */
if ( ldb_attr_cmp ( " distinguishedName " , attribute - > lDAPDisplayName ) = = 0 | |
ldb_attr_cmp ( " objectCategory " , attribute - > lDAPDisplayName ) = = 0 ) {
attribute - > one_way_link = false ;
continue ;
}
if ( attribute - > linkID = = 0 ) {
attribute - > one_way_link = true ;
continue ;
}
/* handle attributes with a linkID but no backlink */
2011-10-07 06:19:48 +04:00
if ( ( attribute - > linkID & 1 ) = = 0 & &
dsdb_attribute_by_linkID ( schema , attribute - > linkID + 1 ) = = NULL ) {
2011-08-09 05:47:25 +04:00
attribute - > one_way_link = true ;
continue ;
}
attribute - > one_way_link = false ;
}
}
2009-12-21 15:36:23 +03:00
static int uint32_cmp ( uint32_t c1 , uint32_t c2 )
{
if ( c1 = = c2 ) return 0 ;
return c1 > c2 ? 1 : - 1 ;
}
2009-04-02 09:42:21 +04:00
static int dsdb_compare_class_by_lDAPDisplayName ( struct dsdb_class * * c1 , struct dsdb_class * * c2 )
{
return strcasecmp ( ( * c1 ) - > lDAPDisplayName , ( * c2 ) - > lDAPDisplayName ) ;
}
static int dsdb_compare_class_by_governsID_id ( struct dsdb_class * * c1 , struct dsdb_class * * c2 )
{
2009-12-21 15:36:23 +03:00
return uint32_cmp ( ( * c1 ) - > governsID_id , ( * c2 ) - > governsID_id ) ;
2009-04-02 09:42:21 +04:00
}
static int dsdb_compare_class_by_governsID_oid ( struct dsdb_class * * c1 , struct dsdb_class * * c2 )
{
return strcasecmp ( ( * c1 ) - > governsID_oid , ( * c2 ) - > governsID_oid ) ;
}
static int dsdb_compare_class_by_cn ( struct dsdb_class * * c1 , struct dsdb_class * * c2 )
{
return strcasecmp ( ( * c1 ) - > cn , ( * c2 ) - > cn ) ;
}
static int dsdb_compare_attribute_by_lDAPDisplayName ( struct dsdb_attribute * * a1 , struct dsdb_attribute * * a2 )
{
return strcasecmp ( ( * a1 ) - > lDAPDisplayName , ( * a2 ) - > lDAPDisplayName ) ;
}
static int dsdb_compare_attribute_by_attributeID_id ( struct dsdb_attribute * * a1 , struct dsdb_attribute * * a2 )
{
2009-12-21 15:36:23 +03:00
return uint32_cmp ( ( * a1 ) - > attributeID_id , ( * a2 ) - > attributeID_id ) ;
2009-04-02 09:42:21 +04:00
}
2010-08-10 22:05:47 +04:00
static int dsdb_compare_attribute_by_msDS_IntId ( struct dsdb_attribute * * a1 , struct dsdb_attribute * * a2 )
{
return uint32_cmp ( ( * a1 ) - > msDS_IntId , ( * a2 ) - > msDS_IntId ) ;
}
2009-04-02 09:42:21 +04:00
static int dsdb_compare_attribute_by_attributeID_oid ( struct dsdb_attribute * * a1 , struct dsdb_attribute * * a2 )
{
return strcasecmp ( ( * a1 ) - > attributeID_oid , ( * a2 ) - > attributeID_oid ) ;
}
static int dsdb_compare_attribute_by_linkID ( struct dsdb_attribute * * a1 , struct dsdb_attribute * * a2 )
{
2009-12-21 15:36:23 +03:00
return uint32_cmp ( ( * a1 ) - > linkID , ( * a2 ) - > linkID ) ;
2009-04-02 09:42:21 +04:00
}
2010-06-19 13:30:36 +04:00
/**
* Clean up Classes and Attributes accessor arrays
*/
static void dsdb_sorted_accessors_free ( struct dsdb_schema * schema )
{
/* free classes accessors */
TALLOC_FREE ( schema - > classes_by_lDAPDisplayName ) ;
TALLOC_FREE ( schema - > classes_by_governsID_id ) ;
TALLOC_FREE ( schema - > classes_by_governsID_oid ) ;
TALLOC_FREE ( schema - > classes_by_cn ) ;
/* free attribute accessors */
TALLOC_FREE ( schema - > attributes_by_lDAPDisplayName ) ;
TALLOC_FREE ( schema - > attributes_by_attributeID_id ) ;
TALLOC_FREE ( schema - > attributes_by_msDS_IntId ) ;
TALLOC_FREE ( schema - > attributes_by_attributeID_oid ) ;
TALLOC_FREE ( schema - > attributes_by_linkID ) ;
}
2009-04-02 09:42:21 +04:00
/*
create the sorted accessor arrays for the schema
*/
2010-09-24 01:46:50 +04:00
int dsdb_setup_sorted_accessors ( struct ldb_context * ldb ,
struct dsdb_schema * schema )
2009-04-02 09:42:21 +04:00
{
struct dsdb_class * cur ;
struct dsdb_attribute * a ;
2009-11-06 22:14:41 +03:00
unsigned int i ;
2010-06-19 01:00:08 +04:00
unsigned int num_int_id ;
2011-08-09 06:55:57 +04:00
int ret ;
2009-04-02 09:42:21 +04:00
2013-01-27 11:42:10 +04:00
for ( i = 0 ; i < schema - > classes_to_remove_size ; i + + ) {
DLIST_REMOVE ( schema - > classes , schema - > classes_to_remove [ i ] ) ;
TALLOC_FREE ( schema - > classes_to_remove [ i ] ) ;
}
for ( i = 0 ; i < schema - > attributes_to_remove_size ; i + + ) {
DLIST_REMOVE ( schema - > attributes , schema - > attributes_to_remove [ i ] ) ;
TALLOC_FREE ( schema - > attributes_to_remove [ i ] ) ;
}
TALLOC_FREE ( schema - > classes_to_remove ) ;
2013-06-10 12:46:41 +04:00
schema - > classes_to_remove_size = 0 ;
TALLOC_FREE ( schema - > attributes_to_remove ) ;
schema - > attributes_to_remove_size = 0 ;
2013-01-27 11:42:10 +04:00
2010-06-19 13:30:36 +04:00
/* free all caches */
dsdb_sorted_accessors_free ( schema ) ;
2009-04-02 09:42:21 +04:00
/* count the classes */
for ( i = 0 , cur = schema - > classes ; cur ; i + + , cur = cur - > next ) /* noop */ ;
schema - > num_classes = i ;
/* setup classes_by_* */
schema - > classes_by_lDAPDisplayName = talloc_array ( schema , struct dsdb_class * , i ) ;
schema - > classes_by_governsID_id = talloc_array ( schema , struct dsdb_class * , i ) ;
schema - > classes_by_governsID_oid = talloc_array ( schema , struct dsdb_class * , i ) ;
schema - > classes_by_cn = talloc_array ( schema , struct dsdb_class * , i ) ;
if ( schema - > classes_by_lDAPDisplayName = = NULL | |
schema - > classes_by_governsID_id = = NULL | |
schema - > classes_by_governsID_oid = = NULL | |
schema - > classes_by_cn = = NULL ) {
goto failed ;
}
for ( i = 0 , cur = schema - > classes ; cur ; i + + , cur = cur - > next ) {
schema - > classes_by_lDAPDisplayName [ i ] = cur ;
schema - > classes_by_governsID_id [ i ] = cur ;
schema - > classes_by_governsID_oid [ i ] = cur ;
schema - > classes_by_cn [ i ] = cur ;
}
/* sort the arrays */
2010-02-13 04:59:43 +03:00
TYPESAFE_QSORT ( schema - > classes_by_lDAPDisplayName , schema - > num_classes , dsdb_compare_class_by_lDAPDisplayName ) ;
TYPESAFE_QSORT ( schema - > classes_by_governsID_id , schema - > num_classes , dsdb_compare_class_by_governsID_id ) ;
TYPESAFE_QSORT ( schema - > classes_by_governsID_oid , schema - > num_classes , dsdb_compare_class_by_governsID_oid ) ;
TYPESAFE_QSORT ( schema - > classes_by_cn , schema - > num_classes , dsdb_compare_class_by_cn ) ;
2009-04-02 09:42:21 +04:00
/* now build the attribute accessor arrays */
2010-06-19 01:00:08 +04:00
/* count the attributes
* and attributes with msDS - IntId set */
num_int_id = 0 ;
for ( i = 0 , a = schema - > attributes ; a ; i + + , a = a - > next ) {
if ( a - > msDS_IntId ! = 0 ) {
num_int_id + + ;
}
}
2009-04-02 09:42:21 +04:00
schema - > num_attributes = i ;
2010-06-19 01:00:08 +04:00
schema - > num_int_id_attr = num_int_id ;
2009-04-02 09:42:21 +04:00
/* setup attributes_by_* */
schema - > attributes_by_lDAPDisplayName = talloc_array ( schema , struct dsdb_attribute * , i ) ;
schema - > attributes_by_attributeID_id = talloc_array ( schema , struct dsdb_attribute * , i ) ;
2010-06-19 01:00:08 +04:00
schema - > attributes_by_msDS_IntId = talloc_array ( schema ,
struct dsdb_attribute * , num_int_id ) ;
2009-04-02 09:42:21 +04:00
schema - > attributes_by_attributeID_oid = talloc_array ( schema , struct dsdb_attribute * , i ) ;
schema - > attributes_by_linkID = talloc_array ( schema , struct dsdb_attribute * , i ) ;
if ( schema - > attributes_by_lDAPDisplayName = = NULL | |
schema - > attributes_by_attributeID_id = = NULL | |
2010-06-19 01:00:08 +04:00
schema - > attributes_by_msDS_IntId = = NULL | |
2009-04-02 09:42:21 +04:00
schema - > attributes_by_attributeID_oid = = NULL | |
schema - > attributes_by_linkID = = NULL ) {
goto failed ;
}
2010-06-19 01:00:08 +04:00
num_int_id = 0 ;
2009-04-02 09:42:21 +04:00
for ( i = 0 , a = schema - > attributes ; a ; i + + , a = a - > next ) {
schema - > attributes_by_lDAPDisplayName [ i ] = a ;
schema - > attributes_by_attributeID_id [ i ] = a ;
schema - > attributes_by_attributeID_oid [ i ] = a ;
schema - > attributes_by_linkID [ i ] = a ;
2010-06-19 01:00:08 +04:00
/* append attr-by-msDS-IntId values */
if ( a - > msDS_IntId ! = 0 ) {
schema - > attributes_by_msDS_IntId [ num_int_id ] = a ;
num_int_id + + ;
}
2009-04-02 09:42:21 +04:00
}
2010-06-19 01:00:08 +04:00
SMB_ASSERT ( num_int_id = = schema - > num_int_id_attr ) ;
2009-04-02 09:42:21 +04:00
/* sort the arrays */
2010-02-13 04:59:43 +03:00
TYPESAFE_QSORT ( schema - > attributes_by_lDAPDisplayName , schema - > num_attributes , dsdb_compare_attribute_by_lDAPDisplayName ) ;
TYPESAFE_QSORT ( schema - > attributes_by_attributeID_id , schema - > num_attributes , dsdb_compare_attribute_by_attributeID_id ) ;
2010-08-10 22:05:47 +04:00
TYPESAFE_QSORT ( schema - > attributes_by_msDS_IntId , schema - > num_int_id_attr , dsdb_compare_attribute_by_msDS_IntId ) ;
2010-02-13 04:59:43 +03:00
TYPESAFE_QSORT ( schema - > attributes_by_attributeID_oid , schema - > num_attributes , dsdb_compare_attribute_by_attributeID_oid ) ;
TYPESAFE_QSORT ( schema - > attributes_by_linkID , schema - > num_attributes , dsdb_compare_attribute_by_linkID ) ;
2009-04-02 09:42:21 +04:00
2011-08-09 05:47:25 +04:00
dsdb_setup_attribute_shortcuts ( ldb , schema ) ;
2011-08-09 06:55:57 +04:00
ret = schema_fill_constructed ( schema ) ;
if ( ret ! = LDB_SUCCESS ) {
dsdb_sorted_accessors_free ( schema ) ;
return ret ;
}
2009-04-02 09:42:21 +04:00
return LDB_SUCCESS ;
failed :
2010-06-19 13:30:36 +04:00
dsdb_sorted_accessors_free ( schema ) ;
2010-07-06 07:21:54 +04:00
return ldb_oom ( ldb ) ;
2008-08-20 09:46:46 +04:00
}
2014-05-14 12:12:03 +04:00
/**
* Attach the schema to an opaque pointer on the ldb ,
* so ldb modules can find it
*/
int dsdb_set_schema_refresh_function ( struct ldb_context * ldb ,
dsdb_schema_refresh_fn refresh_fn ,
struct ldb_module * module )
{
int ret = ldb_set_opaque ( ldb , " dsdb_schema_refresh_fn " , refresh_fn ) ;
if ( ret ! = LDB_SUCCESS ) {
return ret ;
}
ret = ldb_set_opaque ( ldb , " dsdb_schema_refresh_fn_private_data " , module ) ;
if ( ret ! = LDB_SUCCESS ) {
return ret ;
}
return LDB_SUCCESS ;
}
2008-08-20 07:22:16 +04:00
/**
2010-07-16 15:27:30 +04:00
* Attach the schema to an opaque pointer on the ldb ,
* so ldb modules can find it
2008-08-20 07:22:16 +04:00
*/
2017-05-03 23:53:14 +03:00
int dsdb_set_schema ( struct ldb_context * ldb ,
struct dsdb_schema * schema ,
2017-11-22 02:34:01 +03:00
enum schema_set_enum write_indices_and_attributes )
2008-08-20 07:22:16 +04:00
{
2010-06-30 17:25:32 +04:00
struct dsdb_schema * old_schema ;
2008-08-20 07:22:16 +04:00
int ret ;
2009-04-02 09:42:21 +04:00
ret = dsdb_setup_sorted_accessors ( ldb , schema ) ;
if ( ret ! = LDB_SUCCESS ) {
return ret ;
}
2010-06-30 17:25:32 +04:00
old_schema = ldb_get_opaque ( ldb , " dsdb_schema " ) ;
2016-07-04 05:06:10 +03:00
ret = ldb_set_opaque ( ldb , " dsdb_use_global_schema " , NULL ) ;
2008-08-20 07:22:16 +04:00
if ( ret ! = LDB_SUCCESS ) {
return ret ;
}
2010-07-03 14:36:34 +04:00
2016-07-04 05:06:10 +03:00
ret = ldb_set_opaque ( ldb , " dsdb_schema " , schema ) ;
2010-03-22 08:03:33 +03:00
if ( ret ! = LDB_SUCCESS ) {
return ret ;
}
2016-07-04 05:06:10 +03:00
talloc_steal ( ldb , schema ) ;
2008-08-21 06:58:00 +04:00
/* Set the new attributes based on the new schema */
2017-05-03 23:53:14 +03:00
ret = dsdb_schema_set_indices_and_attributes ( ldb , schema ,
write_indices_and_attributes ) ;
2008-08-20 09:46:46 +04:00
if ( ret ! = LDB_SUCCESS ) {
return ret ;
}
2016-07-04 05:06:10 +03:00
/*
* Remove the reference to the schema we just overwrote - if there was
* none , NULL is harmless here .
*/
if ( old_schema ! = schema ) {
talloc_unlink ( ldb , old_schema ) ;
}
return ret ;
2008-08-20 07:22:16 +04:00
}
/**
* Global variable to hold one copy of the schema , used to avoid memory bloat
*/
static struct dsdb_schema * global_schema ;
/**
2009-08-13 03:58:38 +04:00
* Make this ldb use a specified schema , already fully calculated and belonging to another ldb
2012-08-10 02:44:04 +04:00
*
* The write_indices_and_attributes controls writing of the @ records
* because we cannot write to a database that does not yet exist on
* disk .
2008-08-20 07:22:16 +04:00
*/
2009-08-13 08:33:57 +04:00
int dsdb_reference_schema ( struct ldb_context * ldb , struct dsdb_schema * schema ,
2017-11-22 02:34:01 +03:00
enum schema_set_enum write_indices_and_attributes )
2008-08-20 07:22:16 +04:00
{
int ret ;
2018-11-27 01:07:44 +03:00
void * ptr ;
2021-08-25 00:41:11 +03:00
void * schema_parent = NULL ;
bool is_already_parent ;
2010-06-30 17:25:32 +04:00
struct dsdb_schema * old_schema ;
old_schema = ldb_get_opaque ( ldb , " dsdb_schema " ) ;
2009-08-13 03:58:38 +04:00
ret = ldb_set_opaque ( ldb , " dsdb_schema " , schema ) ;
2008-08-20 07:22:16 +04:00
if ( ret ! = LDB_SUCCESS ) {
return ret ;
}
2010-07-03 16:07:44 +04:00
/* Remove the reference to the schema we just overwrote - if there was
* none , NULL is harmless here */
2010-06-30 17:25:32 +04:00
talloc_unlink ( ldb , old_schema ) ;
2018-11-27 01:07:44 +03:00
/* Reference schema on ldb if it wasn't done already */
2021-08-25 00:41:11 +03:00
schema_parent = talloc_parent ( schema ) ;
is_already_parent = ( schema_parent = = ldb ) ;
if ( ! is_already_parent ) {
2018-11-27 01:07:44 +03:00
ptr = talloc_reference ( ldb , schema ) ;
if ( ptr = = NULL ) {
return ldb_oom ( ldb ) ;
}
2010-06-09 14:21:19 +04:00
}
2010-12-09 05:31:14 +03:00
/* Make this ldb use local schema preferably */
ret = ldb_set_opaque ( ldb , " dsdb_use_global_schema " , NULL ) ;
if ( ret ! = LDB_SUCCESS ) {
return ret ;
}
2014-05-14 12:12:03 +04:00
ret = ldb_set_opaque ( ldb , " dsdb_refresh_fn " , NULL ) ;
if ( ret ! = LDB_SUCCESS ) {
return ret ;
}
ret = ldb_set_opaque ( ldb , " dsdb_refresh_fn_private_data " , NULL ) ;
if ( ret ! = LDB_SUCCESS ) {
return ret ;
}
2012-08-10 02:44:04 +04:00
ret = dsdb_schema_set_indices_and_attributes ( ldb , schema , write_indices_and_attributes ) ;
2010-06-09 14:21:19 +04:00
if ( ret ! = LDB_SUCCESS ) {
return ret ;
}
2008-08-20 07:22:16 +04:00
return LDB_SUCCESS ;
}
2009-08-13 03:58:38 +04:00
/**
* Make this ldb use the ' global ' schema , setup to avoid having multiple copies in this process
*/
int dsdb_set_global_schema ( struct ldb_context * ldb )
{
2010-03-22 08:03:33 +03:00
int ret ;
void * use_global_schema = ( void * ) 1 ;
2018-11-27 01:07:44 +03:00
void * ptr ;
2016-08-04 06:25:52 +03:00
struct dsdb_schema * old_schema = ldb_get_opaque ( ldb , " dsdb_schema " ) ;
2010-03-22 08:03:33 +03:00
ret = ldb_set_opaque ( ldb , " dsdb_use_global_schema " , use_global_schema ) ;
if ( ret ! = LDB_SUCCESS ) {
return ret ;
}
2014-05-14 12:12:03 +04:00
if ( global_schema = = NULL ) {
return LDB_SUCCESS ;
}
2016-08-04 06:25:52 +03:00
/* Remove any pointer to a previous schema */
ret = ldb_set_opaque ( ldb , " dsdb_schema " , NULL ) ;
if ( ret ! = LDB_SUCCESS ) {
return ret ;
}
/* Remove the reference to the schema we just overwrote - if there was
* none , NULL is harmless here */
talloc_unlink ( ldb , old_schema ) ;
2010-03-22 08:03:33 +03:00
/* Set the new attributes based on the new schema */
2017-11-22 02:34:01 +03:00
/* Don't write indices and attributes, it's expensive */
ret = dsdb_schema_set_indices_and_attributes ( ldb , global_schema , SCHEMA_MEMORY_ONLY ) ;
2010-03-22 08:03:33 +03:00
if ( ret = = LDB_SUCCESS ) {
2021-08-25 00:41:11 +03:00
void * schema_parent = talloc_parent ( global_schema ) ;
bool is_already_parent =
( schema_parent = = ldb ) ;
if ( ! is_already_parent ) {
2018-11-27 01:07:44 +03:00
ptr = talloc_reference ( ldb , global_schema ) ;
if ( ptr = = NULL ) {
return ldb_oom ( ldb ) ;
}
ret = ldb_set_opaque ( ldb , " dsdb_schema " , global_schema ) ;
2010-03-22 08:03:33 +03:00
}
}
return ret ;
2009-08-13 03:58:38 +04:00
}
2010-10-12 21:53:47 +04:00
bool dsdb_uses_global_schema ( struct ldb_context * ldb )
{
return ( ldb_get_opaque ( ldb , " dsdb_use_global_schema " ) ! = NULL ) ;
}
2008-08-20 07:22:16 +04:00
/**
* Find the schema object for this ldb
2010-03-16 06:41:51 +03:00
*
* If reference_ctx is not NULL , then talloc_reference onto that context
2008-08-20 07:22:16 +04:00
*/
2010-03-16 06:41:51 +03:00
struct dsdb_schema * dsdb_get_schema ( struct ldb_context * ldb , TALLOC_CTX * reference_ctx )
2008-08-20 07:22:16 +04:00
{
const void * p ;
2014-05-14 12:12:03 +04:00
struct dsdb_schema * schema_out = NULL ;
struct dsdb_schema * schema_in = NULL ;
dsdb_schema_refresh_fn refresh_fn ;
struct ldb_module * loaded_from_module ;
2010-03-22 08:03:33 +03:00
bool use_global_schema ;
2010-06-30 17:25:32 +04:00
TALLOC_CTX * tmp_ctx = talloc_new ( reference_ctx ) ;
2014-05-14 12:12:03 +04:00
if ( tmp_ctx = = NULL ) {
2010-06-30 17:25:32 +04:00
return NULL ;
}
2008-08-20 07:22:16 +04:00
/* see if we have a cached copy */
2010-10-12 21:53:47 +04:00
use_global_schema = dsdb_uses_global_schema ( ldb ) ;
2010-03-22 08:03:33 +03:00
if ( use_global_schema ) {
schema_in = global_schema ;
} else {
p = ldb_get_opaque ( ldb , " dsdb_schema " ) ;
2014-05-14 12:12:03 +04:00
if ( p ! = NULL ) {
schema_in = talloc_get_type_abort ( p , struct dsdb_schema ) ;
2010-03-22 08:03:33 +03:00
}
2008-08-20 07:22:16 +04:00
}
2014-05-14 12:12:03 +04:00
refresh_fn = ldb_get_opaque ( ldb , " dsdb_schema_refresh_fn " ) ;
if ( refresh_fn ) {
loaded_from_module = ldb_get_opaque ( ldb , " dsdb_schema_refresh_fn_private_data " ) ;
SMB_ASSERT ( loaded_from_module & & ( ldb_module_get_ctx ( loaded_from_module ) = = ldb ) ) ;
}
if ( refresh_fn ) {
2019-03-27 05:37:54 +03:00
/* We need to guard against recursive calls here */
2014-05-14 12:12:03 +04:00
if ( ldb_set_opaque ( ldb , " dsdb_schema_refresh_fn " , NULL ) ! = LDB_SUCCESS ) {
ldb_debug_set ( ldb , LDB_DEBUG_FATAL ,
" dsdb_get_schema: clearing dsdb_schema_refresh_fn failed " ) ;
} else {
schema_out = refresh_fn ( loaded_from_module ,
ldb_get_event_context ( ldb ) ,
schema_in ,
use_global_schema ) ;
}
if ( ldb_set_opaque ( ldb , " dsdb_schema_refresh_fn " , refresh_fn ) ! = LDB_SUCCESS ) {
ldb_debug_set ( ldb , LDB_DEBUG_FATAL ,
" dsdb_get_schema: re-setting dsdb_schema_refresh_fn failed " ) ;
}
if ( ! schema_out ) {
schema_out = schema_in ;
ldb_debug_set ( ldb , LDB_DEBUG_FATAL ,
" dsdb_get_schema: refresh_fn() failed " ) ;
2010-06-30 17:25:32 +04:00
}
2010-03-22 08:03:33 +03:00
} else {
schema_out = schema_in ;
2008-08-20 07:22:16 +04:00
}
2010-06-30 17:25:32 +04:00
/* This removes the extra reference above */
talloc_free ( tmp_ctx ) ;
2018-11-27 01:07:44 +03:00
2021-08-25 00:41:11 +03:00
/*
* If ref ctx exists and doesn ' t already reference schema , then add
* a reference . Otherwise , just return schema .
*
* We must use talloc_parent ( ) , which is not quite free ( there
* is no direct parent pointer in talloc , only one on the
* first child within a linked list ) , but is much cheaper than
* talloc_is_parent ( ) which walks the whole tree up to the top
* looking for a potential grand - grand ( etc ) - parent .
*/
if ( reference_ctx = = NULL ) {
2010-03-22 08:03:33 +03:00
return schema_out ;
2010-03-16 06:41:51 +03:00
} else {
2021-08-25 00:41:11 +03:00
void * schema_parent = talloc_parent ( schema_out ) ;
bool is_already_parent =
schema_parent = = reference_ctx ;
if ( is_already_parent ) {
return schema_out ;
} else {
return talloc_reference ( reference_ctx ,
schema_out ) ;
}
2010-03-16 06:41:51 +03:00
}
2008-08-20 07:22:16 +04:00
}
/**
* Make the schema found on this ldb the ' global ' schema
*/
2010-03-22 08:03:33 +03:00
void dsdb_make_schema_global ( struct ldb_context * ldb , struct dsdb_schema * schema )
2008-08-20 07:22:16 +04:00
{
if ( ! schema ) {
return ;
}
if ( global_schema ) {
2017-07-24 22:50:50 +03:00
talloc_unlink ( NULL , global_schema ) ;
2008-08-20 07:22:16 +04:00
}
2010-03-22 08:03:33 +03:00
/* we want the schema to be around permanently */
2017-07-24 22:50:50 +03:00
talloc_reparent ( ldb , NULL , schema ) ;
2008-08-20 07:22:16 +04:00
global_schema = schema ;
2010-03-22 08:03:33 +03:00
/* This calls the talloc_reference() of the global schema back onto the ldb */
2008-08-20 07:22:16 +04:00
dsdb_set_global_schema ( ldb ) ;
}
2010-07-16 15:27:30 +04:00
/**
* When loading the schema from LDIF files , we don ' t get the extended DNs .
*
* We need to set these up , so that from the moment we start the provision ,
* the defaultObjectCategory links are set up correctly .
2009-11-16 10:48:46 +03:00
*/
int dsdb_schema_fill_extended_dn ( struct ldb_context * ldb , struct dsdb_schema * schema )
{
struct dsdb_class * cur ;
const struct dsdb_class * target_class ;
for ( cur = schema - > classes ; cur ; cur = cur - > next ) {
const struct ldb_val * rdn ;
struct ldb_val guid ;
2009-12-10 06:36:12 +03:00
NTSTATUS status ;
2019-09-03 11:35:33 +03:00
int ret ;
2009-11-16 10:48:46 +03:00
struct ldb_dn * dn = ldb_dn_new ( NULL , ldb , cur - > defaultObjectCategory ) ;
2009-12-10 06:36:12 +03:00
2009-11-16 10:48:46 +03:00
if ( ! dn ) {
return LDB_ERR_INVALID_DN_SYNTAX ;
}
rdn = ldb_dn_get_component_val ( dn , 0 ) ;
if ( ! rdn ) {
talloc_free ( dn ) ;
return LDB_ERR_INVALID_DN_SYNTAX ;
}
target_class = dsdb_class_by_cn_ldb_val ( schema , rdn ) ;
if ( ! target_class ) {
talloc_free ( dn ) ;
return LDB_ERR_CONSTRAINT_VIOLATION ;
}
2010-07-16 15:27:30 +04:00
2009-12-10 06:36:12 +03:00
status = GUID_to_ndr_blob ( & target_class - > objectGUID , dn , & guid ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
2009-11-16 10:48:46 +03:00
talloc_free ( dn ) ;
2010-07-06 07:21:54 +04:00
return ldb_operr ( ldb ) ;
2009-11-16 10:48:46 +03:00
}
2019-09-03 11:35:33 +03:00
ret = ldb_dn_set_extended_component ( dn , " GUID " , & guid ) ;
if ( ret ! = LDB_SUCCESS ) {
ret = ldb_error ( ldb , ret , " Could not set GUID " ) ;
talloc_free ( dn ) ;
return ret ;
}
2009-11-16 10:48:46 +03:00
cur - > defaultObjectCategory = ldb_dn_get_extended_linearized ( cur , dn , 1 ) ;
talloc_free ( dn ) ;
}
return LDB_SUCCESS ;
}
2010-07-16 15:27:30 +04:00
/**
2013-01-27 11:42:10 +04:00
* @ brief Add a new element to the schema and checks if it ' s a duplicate
*
* This function will add a new element to the schema and checks for existing
* duplicates .
*
* @ param [ in ] ldb A pointer to an LDB context
*
* @ param [ in ] schema A pointer to the dsdb_schema where the element
* will be added .
*
* @ param [ in ] msg The ldb_message object representing the element
* to add .
*
* @ param [ in ] checkdups A boolean to indicate if checks for duplicates
* should be done .
*
* @ return A WERROR code
2009-11-09 12:40:21 +03:00
*/
2013-01-27 11:42:10 +04:00
WERROR dsdb_schema_set_el_from_ldb_msg_dups ( struct ldb_context * ldb , struct dsdb_schema * schema ,
struct ldb_message * msg , bool checkdups )
2009-11-09 12:40:21 +03:00
{
2012-05-23 03:25:50 +04:00
const char * tstring ;
time_t ts ;
tstring = ldb_msg_find_attr_as_string ( msg , " whenChanged " , NULL ) ;
/* keep a trace of the ts of the most recently changed object */
if ( tstring ) {
ts = ldb_string_to_time ( tstring ) ;
if ( ts > schema - > ts_last_change ) {
schema - > ts_last_change = ts ;
}
}
2012-12-07 13:34:58 +04:00
if ( samdb_find_attribute ( ldb , msg ,
" objectclass " , " attributeSchema " ) ! = NULL ) {
2013-01-27 11:42:10 +04:00
return dsdb_set_attribute_from_ldb_dups ( ldb , schema , msg , checkdups ) ;
2012-12-07 13:34:58 +04:00
} else if ( samdb_find_attribute ( ldb , msg ,
" objectclass " , " classSchema " ) ! = NULL ) {
2013-01-27 11:42:10 +04:00
return dsdb_set_class_from_ldb_dups ( schema , msg , checkdups ) ;
2012-12-07 13:34:58 +04:00
}
2009-11-09 12:40:21 +03:00
/* Don't fail on things not classes or attributes */
return WERR_OK ;
}
2008-08-20 07:22:16 +04:00
2013-01-27 11:42:10 +04:00
WERROR dsdb_schema_set_el_from_ldb_msg ( struct ldb_context * ldb ,
struct dsdb_schema * schema ,
struct ldb_message * msg )
{
return dsdb_schema_set_el_from_ldb_msg_dups ( ldb , schema , msg , false ) ;
}
2008-08-20 07:22:16 +04:00
/**
* Rather than read a schema from the LDB itself , read it from an ldif
* file . This allows schema to be loaded and used while adding the
* schema itself to the directory .
2017-11-22 02:46:31 +03:00
*
* Should be called with a transaction ( or failing that , have no concurrent
* access while called ) .
2008-08-20 07:22:16 +04:00
*/
2011-11-11 19:35:59 +04:00
WERROR dsdb_set_schema_from_ldif ( struct ldb_context * ldb ,
const char * pf , const char * df ,
const char * dn )
2008-08-20 07:22:16 +04:00
{
struct ldb_ldif * ldif ;
struct ldb_message * msg ;
TALLOC_CTX * mem_ctx ;
WERROR status ;
int ret ;
struct dsdb_schema * schema ;
const struct ldb_val * prefix_val ;
const struct ldb_val * info_val ;
struct ldb_val info_val_default ;
2009-11-09 12:40:21 +03:00
2008-08-20 07:22:16 +04:00
mem_ctx = talloc_new ( ldb ) ;
if ( ! mem_ctx ) {
goto nomem ;
}
2010-05-09 19:20:01 +04:00
schema = dsdb_new_schema ( mem_ctx ) ;
2011-11-11 19:35:59 +04:00
if ( ! schema ) {
goto nomem ;
}
2008-08-20 07:22:16 +04:00
schema - > fsmo . we_are_master = true ;
2011-11-11 15:12:17 +04:00
schema - > fsmo . update_allowed = true ;
2011-11-11 19:35:59 +04:00
schema - > fsmo . master_dn = ldb_dn_new ( schema , ldb , " @PROVISION_SCHEMA_MASTER " ) ;
2008-08-20 07:22:16 +04:00
if ( ! schema - > fsmo . master_dn ) {
goto nomem ;
}
/*
* load the prefixMap attribute from pf
*/
ldif = ldb_ldif_read_string ( ldb , & pf ) ;
if ( ! ldif ) {
2015-12-03 17:24:26 +03:00
status = WERR_INVALID_PARAMETER ;
2008-08-20 07:22:16 +04:00
goto failed ;
}
talloc_steal ( mem_ctx , ldif ) ;
2010-07-16 14:59:40 +04:00
ret = ldb_msg_normalize ( ldb , mem_ctx , ldif - > msg , & msg ) ;
if ( ret ! = LDB_SUCCESS ) {
2008-08-20 07:22:16 +04:00
goto nomem ;
}
talloc_free ( ldif ) ;
prefix_val = ldb_msg_find_ldb_val ( msg , " prefixMap " ) ;
if ( ! prefix_val ) {
2015-12-03 17:24:26 +03:00
status = WERR_INVALID_PARAMETER ;
2008-08-20 07:22:16 +04:00
goto failed ;
}
info_val = ldb_msg_find_ldb_val ( msg , " schemaInfo " ) ;
if ( ! info_val ) {
2010-04-22 18:24:15 +04:00
status = dsdb_schema_info_blob_new ( mem_ctx , & info_val_default ) ;
2010-04-08 06:31:35 +04:00
W_ERROR_NOT_OK_GOTO ( status , failed ) ;
2008-08-20 07:22:16 +04:00
info_val = & info_val_default ;
}
status = dsdb_load_oid_mappings_ldb ( schema , prefix_val , info_val ) ;
if ( ! W_ERROR_IS_OK ( status ) ) {
2010-04-08 06:31:35 +04:00
DEBUG ( 0 , ( " ERROR: dsdb_load_oid_mappings_ldb() failed with %s \n " , win_errstr ( status ) ) ) ;
2008-08-20 07:22:16 +04:00
goto failed ;
}
2012-05-23 03:25:50 +04:00
schema - > ts_last_change = 0 ;
2010-07-16 15:27:30 +04:00
/* load the attribute and class definitions out of df */
2008-08-20 07:22:16 +04:00
while ( ( ldif = ldb_ldif_read_string ( ldb , & df ) ) ) {
talloc_steal ( mem_ctx , ldif ) ;
2010-07-16 14:59:40 +04:00
ret = ldb_msg_normalize ( ldb , ldif , ldif - > msg , & msg ) ;
if ( ret ! = LDB_SUCCESS ) {
2008-08-20 07:22:16 +04:00
goto nomem ;
}
2009-11-09 12:40:21 +03:00
status = dsdb_schema_set_el_from_ldb_msg ( ldb , schema , msg ) ;
2008-08-20 07:22:16 +04:00
talloc_free ( ldif ) ;
2009-11-09 12:40:21 +03:00
if ( ! W_ERROR_IS_OK ( status ) ) {
goto failed ;
2008-08-20 07:22:16 +04:00
}
}
2017-11-22 02:46:31 +03:00
/*
* TODO We may need a transaction here , otherwise this causes races .
*
* To do so may require an ldb_in_transaction function . In the
* meantime , assume that this is always called with a transaction or in
* isolation .
*/
2017-11-22 02:34:01 +03:00
ret = dsdb_set_schema ( ldb , schema , SCHEMA_WRITE ) ;
2008-08-20 07:22:16 +04:00
if ( ret ! = LDB_SUCCESS ) {
status = WERR_FOOBAR ;
2017-05-23 06:56:55 +03:00
DEBUG ( 0 , ( " ERROR: dsdb_set_schema() failed with %s / %s \n " ,
ldb_strerror ( ret ) , ldb_errstring ( ldb ) ) ) ;
2008-08-20 07:22:16 +04:00
goto failed ;
}
2009-11-16 10:48:46 +03:00
ret = dsdb_schema_fill_extended_dn ( ldb , schema ) ;
if ( ret ! = LDB_SUCCESS ) {
status = WERR_FOOBAR ;
goto failed ;
}
2008-08-20 07:22:16 +04:00
goto done ;
nomem :
2015-12-03 17:24:18 +03:00
status = WERR_NOT_ENOUGH_MEMORY ;
2008-08-20 07:22:16 +04:00
failed :
done :
talloc_free ( mem_ctx ) ;
return status ;
}