2010-10-21 12:47:57 +11:00
/*
Unix SMB / CIFS implementation .
dsdb module schema utility functions
Copyright ( C ) Kamen Mazdrashki < kamenim @ samba . org > 2010
Copyright ( C ) Andrew Tridgell 2010
Copyright ( C ) Andrew Bartlett < abartlet @ samba . org > 2010
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 .
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 , see < http : //www.gnu.org/licenses/>.
*/
# include "includes.h"
# include "dsdb/common/util.h"
# include "dsdb/samdb/samdb.h"
# include "dsdb/samdb/ldb_modules/util.h"
2011-02-10 14:12:51 +11:00
# include <ldb_module.h>
2010-10-21 12:47:57 +11:00
# include "librpc/gen_ndr/ndr_drsuapi.h"
# include "librpc/gen_ndr/ndr_drsblobs.h"
# include "param/param.h"
/**
* Reads schema_info structure from schemaInfo
* attribute on SCHEMA partition
*
* @ param dsdb_flags DSDB_FLAG_ . . . flag of 0
*/
int dsdb_module_schema_info_blob_read ( struct ldb_module * ldb_module ,
uint32_t dsdb_flags ,
TALLOC_CTX * mem_ctx ,
2011-01-17 13:12:15 +11:00
struct ldb_val * schema_info_blob ,
struct ldb_request * parent )
2010-10-21 12:47:57 +11:00
{
int ldb_err ;
const struct ldb_val * blob_val ;
struct ldb_dn * schema_dn ;
struct ldb_result * schema_res = NULL ;
static const char * schema_attrs [ ] = {
" schemaInfo " ,
NULL
} ;
schema_dn = ldb_get_schema_basedn ( ldb_module_get_ctx ( ldb_module ) ) ;
if ( ! schema_dn ) {
DEBUG ( 0 , ( " dsdb_module_schema_info_blob_read: no schema dn present! \n " ) ) ;
return ldb_operr ( ldb_module_get_ctx ( ldb_module ) ) ;
}
ldb_err = dsdb_module_search ( ldb_module , mem_ctx , & schema_res , schema_dn ,
2011-01-17 13:12:15 +11:00
LDB_SCOPE_BASE , schema_attrs , dsdb_flags , parent ,
NULL ) ;
2010-10-21 12:47:57 +11:00
if ( ldb_err = = LDB_ERR_NO_SUCH_OBJECT ) {
DEBUG ( 0 , ( " dsdb_module_schema_info_blob_read: Schema DN not found! \n " ) ) ;
talloc_free ( schema_res ) ;
return ldb_err ;
} else if ( ldb_err ! = LDB_SUCCESS ) {
DEBUG ( 0 , ( " dsdb_module_schema_info_blob_read: failed to find schemaInfo attribute \n " ) ) ;
talloc_free ( schema_res ) ;
return ldb_err ;
}
blob_val = ldb_msg_find_ldb_val ( schema_res - > msgs [ 0 ] , " schemaInfo " ) ;
if ( ! blob_val ) {
2010-10-21 18:17:59 +11:00
ldb_asprintf_errstring ( ldb_module_get_ctx ( ldb_module ) ,
" dsdb_module_schema_info_blob_read: no schemaInfo attribute found " ) ;
2010-10-21 12:47:57 +11:00
talloc_free ( schema_res ) ;
2010-10-21 18:17:59 +11:00
return LDB_ERR_NO_SUCH_ATTRIBUTE ;
2010-10-21 12:47:57 +11:00
}
/* transfer .data ownership to mem_ctx */
schema_info_blob - > length = blob_val - > length ;
schema_info_blob - > data = talloc_steal ( mem_ctx , blob_val - > data ) ;
talloc_free ( schema_res ) ;
return LDB_SUCCESS ;
}
/**
* Prepares ldb_msg to be used for updating schemaInfo value in DB
*/
static int dsdb_schema_info_write_prepare ( struct ldb_context * ldb ,
struct ldb_val * schema_info_blob ,
TALLOC_CTX * mem_ctx ,
struct ldb_message * * _msg )
{
int ldb_err ;
struct ldb_message * msg ;
struct ldb_dn * schema_dn ;
struct ldb_message_element * return_el ;
schema_dn = ldb_get_schema_basedn ( ldb ) ;
if ( ! schema_dn ) {
DEBUG ( 0 , ( " dsdb_schema_info_write_prepare: no schema dn present \n " ) ) ;
return ldb_operr ( ldb ) ;
}
/* prepare ldb_msg to update schemaInfo */
msg = ldb_msg_new ( mem_ctx ) ;
if ( msg = = NULL ) {
return ldb_oom ( ldb ) ;
}
msg - > dn = schema_dn ;
ldb_err = ldb_msg_add_value ( msg , " schemaInfo " , schema_info_blob , & return_el ) ;
if ( ldb_err ! = 0 ) {
ldb_asprintf_errstring ( ldb , " dsdb_schema_info_write_prepare: ldb_msg_add_value failed - %s \n " ,
ldb_strerror ( ldb_err ) ) ;
talloc_free ( msg ) ;
return ldb_err ;
}
/* mark schemaInfo element for replacement */
return_el - > flags = LDB_FLAG_MOD_REPLACE ;
* _msg = msg ;
return LDB_SUCCESS ;
}
/**
* Writes schema_info structure into schemaInfo
* attribute on SCHEMA partition
*
* @ param dsdb_flags DSDB_FLAG_ . . . flag of 0
*/
int dsdb_module_schema_info_blob_write ( struct ldb_module * ldb_module ,
uint32_t dsdb_flags ,
2011-01-17 13:12:15 +11:00
struct ldb_val * schema_info_blob ,
struct ldb_request * parent )
2010-10-21 12:47:57 +11:00
{
int ldb_err ;
2015-02-25 12:19:44 +00:00
struct ldb_message * msg = NULL ;
2010-10-21 12:47:57 +11:00
TALLOC_CTX * temp_ctx ;
temp_ctx = talloc_new ( ldb_module ) ;
if ( temp_ctx = = NULL ) {
return ldb_module_oom ( ldb_module ) ;
}
/* write serialized schemaInfo into LDB */
ldb_err = dsdb_schema_info_write_prepare ( ldb_module_get_ctx ( ldb_module ) ,
schema_info_blob ,
temp_ctx , & msg ) ;
if ( ldb_err ! = LDB_SUCCESS ) {
talloc_free ( temp_ctx ) ;
return ldb_err ;
}
2011-01-17 13:12:15 +11:00
ldb_err = dsdb_module_modify ( ldb_module , msg , dsdb_flags , parent ) ;
2010-10-21 12:47:57 +11:00
talloc_free ( temp_ctx ) ;
if ( ldb_err ! = LDB_SUCCESS ) {
ldb_asprintf_errstring ( ldb_module_get_ctx ( ldb_module ) ,
" dsdb_module_schema_info_blob_write: dsdb_replace failed: %s (%s) \n " ,
ldb_strerror ( ldb_err ) ,
ldb_errstring ( ldb_module_get_ctx ( ldb_module ) ) ) ;
return ldb_err ;
}
return LDB_SUCCESS ;
}
/**
* Reads schema_info structure from schemaInfo
* attribute on SCHEMA partition
*/
static int dsdb_module_schema_info_read ( struct ldb_module * ldb_module ,
uint32_t dsdb_flags ,
TALLOC_CTX * mem_ctx ,
2011-01-17 13:12:15 +11:00
struct dsdb_schema_info * * _schema_info ,
struct ldb_request * parent )
2010-10-21 12:47:57 +11:00
{
int ret ;
DATA_BLOB ndr_blob ;
TALLOC_CTX * temp_ctx ;
WERROR werr ;
temp_ctx = talloc_new ( mem_ctx ) ;
if ( temp_ctx = = NULL ) {
return ldb_module_oom ( ldb_module ) ;
}
/* read serialized schemaInfo from LDB */
2011-01-17 13:12:15 +11:00
ret = dsdb_module_schema_info_blob_read ( ldb_module , dsdb_flags , temp_ctx , & ndr_blob , parent ) ;
2010-10-21 12:47:57 +11:00
if ( ret ! = LDB_SUCCESS ) {
talloc_free ( temp_ctx ) ;
return ret ;
}
/* convert NDR blob to dsdb_schema_info object */
werr = dsdb_schema_info_from_blob ( & ndr_blob ,
mem_ctx ,
_schema_info ) ;
talloc_free ( temp_ctx ) ;
if ( W_ERROR_EQUAL ( werr , WERR_DS_NO_ATTRIBUTE_OR_VALUE ) ) {
return LDB_ERR_NO_SUCH_ATTRIBUTE ;
}
if ( ! W_ERROR_IS_OK ( werr ) ) {
ldb_asprintf_errstring ( ldb_module_get_ctx ( ldb_module ) , __location__ " : failed to get schema_info " ) ;
return ldb_operr ( ldb_module_get_ctx ( ldb_module ) ) ;
}
return LDB_SUCCESS ;
}
/**
* Writes schema_info structure into schemaInfo
* attribute on SCHEMA partition
*
* @ param dsdb_flags DSDB_FLAG_ . . . flag of 0
*/
static int dsdb_module_schema_info_write ( struct ldb_module * ldb_module ,
uint32_t dsdb_flags ,
2011-01-17 13:12:15 +11:00
const struct dsdb_schema_info * schema_info ,
struct ldb_request * parent )
2010-10-21 12:47:57 +11:00
{
WERROR werr ;
int ret ;
DATA_BLOB ndr_blob ;
TALLOC_CTX * temp_ctx ;
temp_ctx = talloc_new ( ldb_module ) ;
if ( temp_ctx = = NULL ) {
2015-06-23 14:44:05 +02:00
return ldb_module_oom ( ldb_module ) ;
2010-10-21 12:47:57 +11:00
}
/* convert schema_info to a blob */
werr = dsdb_blob_from_schema_info ( schema_info , temp_ctx , & ndr_blob ) ;
if ( ! W_ERROR_IS_OK ( werr ) ) {
talloc_free ( temp_ctx ) ;
ldb_asprintf_errstring ( ldb_module_get_ctx ( ldb_module ) , __location__ " : failed to get schema_info " ) ;
return ldb_operr ( ldb_module_get_ctx ( ldb_module ) ) ;
}
/* write serialized schemaInfo into LDB */
2011-01-17 13:12:15 +11:00
ret = dsdb_module_schema_info_blob_write ( ldb_module , dsdb_flags , & ndr_blob , parent ) ;
2010-10-21 12:47:57 +11:00
talloc_free ( temp_ctx ) ;
return ret ;
}
/**
* Increments schemaInfo revision and save it to DB
* setting our invocationID in the process
* NOTE : this function should be called in a transaction
* much in the same way prefixMap update function is called
*
* @ param ldb_module current module
* @ param schema schema cache
* @ param dsdb_flags DSDB_FLAG_ . . . flag of 0
*/
int dsdb_module_schema_info_update ( struct ldb_module * ldb_module ,
struct dsdb_schema * schema ,
2011-01-17 13:12:15 +11:00
int dsdb_flags , struct ldb_request * parent )
2010-10-21 12:47:57 +11:00
{
int ret ;
const struct GUID * invocation_id ;
struct dsdb_schema_info * schema_info ;
WERROR werr ;
TALLOC_CTX * temp_ctx = talloc_new ( schema ) ;
if ( temp_ctx = = NULL ) {
return ldb_module_oom ( ldb_module ) ;
}
invocation_id = samdb_ntds_invocation_id ( ldb_module_get_ctx ( ldb_module ) ) ;
if ( ! invocation_id ) {
talloc_free ( temp_ctx ) ;
return ldb_operr ( ldb_module_get_ctx ( ldb_module ) ) ;
}
/* read serialized schemaInfo from LDB */
2011-01-17 13:12:15 +11:00
ret = dsdb_module_schema_info_read ( ldb_module , dsdb_flags , temp_ctx , & schema_info , parent ) ;
2010-10-21 12:47:57 +11:00
if ( ret = = LDB_ERR_NO_SUCH_ATTRIBUTE ) {
/* make default value in case
* we have no schemaInfo value yet */
werr = dsdb_schema_info_new ( temp_ctx , & schema_info ) ;
if ( ! W_ERROR_IS_OK ( werr ) ) {
talloc_free ( temp_ctx ) ;
return ldb_module_oom ( ldb_module ) ;
}
ret = LDB_SUCCESS ;
}
if ( ret ! = LDB_SUCCESS ) {
talloc_free ( temp_ctx ) ;
return ret ;
}
/* update schemaInfo */
schema_info - > revision + + ;
schema_info - > invocation_id = * invocation_id ;
2011-01-17 13:12:15 +11:00
ret = dsdb_module_schema_info_write ( ldb_module , dsdb_flags , schema_info , parent ) ;
2010-10-21 12:47:57 +11:00
if ( ret ! = LDB_SUCCESS ) {
ldb_asprintf_errstring ( ldb_module_get_ctx ( ldb_module ) ,
" dsdb_module_schema_info_update: failed to save schemaInfo - %s \n " ,
ldb_strerror ( ret ) ) ;
talloc_free ( temp_ctx ) ;
return ret ;
}
2016-08-04 23:04:32 +02:00
/*
* We don ' t update the schema - > schema_info !
* as that would not represent the other information
* in schema - > *
*
* We ' re not sure if the current transaction will go through !
* E . g . schema changes are only allowed on the schema master ,
* otherwise they result in a UNWILLING_TO_PERFORM and a
*
* Note that schema might a global variable shared between
* multiple ldb_contexts . With process model " single " it
* means the drsuapi server also uses it .
*
* We keep it simple and just try to update the
* stored value .
*
* The next schema reload will pick it up , which
* then works for originating and replicated changes
* in the same way .
*/
2010-10-21 12:47:57 +11:00
talloc_free ( temp_ctx ) ;
return LDB_SUCCESS ;
}