mirror of
https://github.com/samba-team/samba.git
synced 2025-01-26 10:04:02 +03:00
s4/dsdb: dsdb_schema_info object implementation
This commit is contained in:
parent
37a6b66344
commit
9d1f8bcca9
@ -42,7 +42,8 @@ SAMDB_SCHEMA_OBJ_FILES = $(addprefix $(dsdbsrcdir)/schema/, \
|
||||
schema_description.o \
|
||||
schema_convert_to_ol.o \
|
||||
schema_inferiors.o \
|
||||
schema_prefixmap.o)
|
||||
schema_prefixmap.o \
|
||||
schema_info_attr.o)
|
||||
|
||||
$(eval $(call proto_header_template,$(dsdbsrcdir)/schema/proto.h,$(SAMDB_SCHEMA_OBJ_FILES:.o=.c)))
|
||||
# PUBLIC_HEADERS += dsdb/schema/schema.h
|
||||
|
383
source4/dsdb/schema/schema_info_attr.c
Normal file
383
source4/dsdb/schema/schema_info_attr.c
Normal file
@ -0,0 +1,383 @@
|
||||
/*
|
||||
Unix SMB/CIFS implementation.
|
||||
|
||||
SCHEMA::schemaInfo implementation
|
||||
|
||||
Copyright (C) Kamen Mazdrashki <kamenim@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"
|
||||
#include "lib/ldb/include/ldb_module.h"
|
||||
#include "librpc/gen_ndr/ndr_drsuapi.h"
|
||||
#include "librpc/gen_ndr/ndr_drsblobs.h"
|
||||
#include "param/param.h"
|
||||
|
||||
|
||||
/**
|
||||
* Parse schemaInfo structure from a data_blob
|
||||
* (DATA_BLOB or ldb_val).
|
||||
* Suitable for parsing blobs that comes from
|
||||
* DRS interface of from LDB database
|
||||
*/
|
||||
WERROR dsdb_schema_info_from_blob(const DATA_BLOB *blob,
|
||||
TALLOC_CTX *mem_ctx, struct dsdb_schema_info **_schema_info)
|
||||
{
|
||||
TALLOC_CTX *temp_ctx;
|
||||
enum ndr_err_code ndr_err;
|
||||
struct dsdb_schema_info *schema_info;
|
||||
struct schemaInfoBlob schema_info_blob;
|
||||
|
||||
if (!blob || !blob->data) {
|
||||
return WERR_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
if (blob->length != 21) {
|
||||
return WERR_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
/* schemaInfo blob should start with 0xFF */
|
||||
if (blob->data[0] != 0xFF) {
|
||||
return WERR_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
temp_ctx = talloc_new(mem_ctx);
|
||||
W_ERROR_HAVE_NO_MEMORY(temp_ctx);
|
||||
|
||||
ndr_err = ndr_pull_struct_blob_all(blob, temp_ctx,
|
||||
lp_iconv_convenience(NULL), &schema_info_blob,
|
||||
(ndr_pull_flags_fn_t)ndr_pull_schemaInfoBlob);
|
||||
if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
|
||||
NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
|
||||
talloc_free(temp_ctx);
|
||||
return ntstatus_to_werror(nt_status);
|
||||
}
|
||||
|
||||
/* revision must be not less than 1 */
|
||||
if (schema_info_blob.revision < 1) {
|
||||
talloc_free(temp_ctx);
|
||||
return WERR_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
schema_info = talloc(mem_ctx, struct dsdb_schema_info);
|
||||
if (!schema_info) {
|
||||
talloc_free(temp_ctx);
|
||||
return WERR_NOMEM;
|
||||
}
|
||||
schema_info->revision = schema_info_blob.revision;
|
||||
schema_info->invocation_id = schema_info_blob.invocation_id;
|
||||
*_schema_info = schema_info;
|
||||
|
||||
talloc_free(temp_ctx);
|
||||
return WERR_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a blob from schemaInfo structure
|
||||
* Suitable for packing schemaInfo into a blob
|
||||
* which is to be used in DRS interface of LDB database
|
||||
*/
|
||||
WERROR dsdb_blob_from_schema_info(const struct dsdb_schema_info *schema_info,
|
||||
TALLOC_CTX *mem_ctx, DATA_BLOB *blob)
|
||||
{
|
||||
enum ndr_err_code ndr_err;
|
||||
struct schemaInfoBlob schema_info_blob;
|
||||
|
||||
if (schema_info->revision < 1) {
|
||||
return WERR_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
schema_info_blob.marker = 0xFF;
|
||||
schema_info_blob.revision = schema_info->revision;
|
||||
schema_info_blob.invocation_id = schema_info->invocation_id;
|
||||
|
||||
ndr_err = ndr_push_struct_blob(blob, mem_ctx,
|
||||
lp_iconv_convenience(NULL), &schema_info_blob,
|
||||
(ndr_push_flags_fn_t)ndr_push_schemaInfoBlob);
|
||||
if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
|
||||
NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
|
||||
return ntstatus_to_werror(nt_status);
|
||||
}
|
||||
|
||||
return WERR_OK;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Reads schema_info structure from schemaInfo
|
||||
* attribute on SCHEMA partition
|
||||
*
|
||||
* @param dsdb_flags DSDB_FLAG_... flag of 0
|
||||
*/
|
||||
WERROR dsdb_module_schema_info_blob_read(struct ldb_module *ldb_module,
|
||||
uint32_t dsdb_flags,
|
||||
TALLOC_CTX *mem_ctx, DATA_BLOB *schema_info_blob)
|
||||
{
|
||||
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 = samdb_schema_dn(ldb_module_get_ctx(ldb_module));
|
||||
if (!schema_dn) {
|
||||
DEBUG(0,("dsdb_module_schema_info_blob_read: no schema dn present!\n"));
|
||||
return WERR_INTERNAL_DB_CORRUPTION;
|
||||
}
|
||||
|
||||
ldb_err = dsdb_module_search(ldb_module, mem_ctx, &schema_res, schema_dn,
|
||||
LDB_SCOPE_BASE, schema_attrs, dsdb_flags, NULL);
|
||||
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 WERR_INTERNAL_DB_CORRUPTION;
|
||||
} 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 WERR_INTERNAL_DB_CORRUPTION;
|
||||
}
|
||||
|
||||
blob_val = ldb_msg_find_ldb_val(schema_res->msgs[0], "schemaInfo");
|
||||
if (!blob_val) {
|
||||
DEBUG(0,("dsdb_module_schema_info_blob_read: no schemaInfo attribute found\n"));
|
||||
talloc_free(schema_res);
|
||||
return WERR_DS_NO_ATTRIBUTE_OR_VALUE;
|
||||
}
|
||||
|
||||
/* 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 WERR_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes schema_info structure into schemaInfo
|
||||
* attribute on SCHEMA partition
|
||||
*
|
||||
* @param dsdb_flags DSDB_FLAG_... flag of 0
|
||||
*/
|
||||
WERROR dsdb_module_schema_info_blob_write(struct ldb_module *ldb_module,
|
||||
uint32_t dsdb_flags,
|
||||
DATA_BLOB *schema_info_blob)
|
||||
{
|
||||
int ldb_err;
|
||||
struct ldb_message *msg;
|
||||
struct ldb_dn *schema_dn;
|
||||
struct ldb_message_element *return_el;
|
||||
TALLOC_CTX *temp_ctx;
|
||||
|
||||
schema_dn = samdb_schema_dn(ldb_module_get_ctx(ldb_module));
|
||||
if (!schema_dn) {
|
||||
DEBUG(0,("dsdb_module_schema_info_blob_write: no schema dn present\n"));
|
||||
return WERR_INTERNAL_DB_CORRUPTION;
|
||||
}
|
||||
|
||||
temp_ctx = talloc_new(ldb_module);
|
||||
W_ERROR_HAVE_NO_MEMORY(temp_ctx);
|
||||
|
||||
/* write serialized schemaInfo into LDB */
|
||||
msg = ldb_msg_new(temp_ctx);
|
||||
if (!msg) {
|
||||
talloc_free(temp_ctx);
|
||||
return WERR_NOMEM;
|
||||
}
|
||||
|
||||
msg->dn = schema_dn;
|
||||
ldb_err = ldb_msg_add_value(msg, "schemaInfo", schema_info_blob, &return_el);
|
||||
if (ldb_err != 0) {
|
||||
talloc_free(temp_ctx);
|
||||
DEBUG(0,("dsdb_module_schema_info_blob_write: ldb_msg_add_value failed\n"));
|
||||
return WERR_NOMEM;
|
||||
}
|
||||
|
||||
/* mark schemaInfo element for replacement */
|
||||
return_el->flags = LDB_FLAG_MOD_REPLACE;
|
||||
|
||||
ldb_err = dsdb_module_modify(ldb_module, msg, dsdb_flags | DSDB_MODIFY_PERMISSIVE);
|
||||
|
||||
talloc_free(temp_ctx);
|
||||
|
||||
if (ldb_err != 0) {
|
||||
DEBUG(0,("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 WERR_INTERNAL_DB_ERROR;
|
||||
}
|
||||
|
||||
return WERR_OK;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Reads schema_info structure from schemaInfo
|
||||
* attribute on SCHEMA partition
|
||||
*/
|
||||
static WERROR dsdb_module_schema_info_read(struct ldb_module *ldb_module,
|
||||
uint32_t dsdb_flags,
|
||||
TALLOC_CTX *mem_ctx,
|
||||
struct dsdb_schema_info **_schema_info)
|
||||
{
|
||||
WERROR werr;
|
||||
DATA_BLOB ndr_blob;
|
||||
TALLOC_CTX *temp_ctx;
|
||||
|
||||
temp_ctx = talloc_new(mem_ctx);
|
||||
W_ERROR_HAVE_NO_MEMORY(temp_ctx);
|
||||
|
||||
/* read serialized schemaInfo from LDB */
|
||||
werr = dsdb_module_schema_info_blob_read(ldb_module, dsdb_flags, temp_ctx, &ndr_blob);
|
||||
if (!W_ERROR_IS_OK(werr)) {
|
||||
talloc_free(temp_ctx);
|
||||
return werr;
|
||||
}
|
||||
|
||||
/* convert NDR blob to dsdb_schema_info object */
|
||||
werr = dsdb_schema_info_from_blob(&ndr_blob,
|
||||
mem_ctx,
|
||||
_schema_info);
|
||||
talloc_free(temp_ctx);
|
||||
|
||||
return werr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes schema_info structure into schemaInfo
|
||||
* attribute on SCHEMA partition
|
||||
*
|
||||
* @param dsdb_flags DSDB_FLAG_... flag of 0
|
||||
*/
|
||||
static WERROR dsdb_module_schema_info_write(struct ldb_module *ldb_module,
|
||||
uint32_t dsdb_flags,
|
||||
const struct dsdb_schema_info *schema_info)
|
||||
{
|
||||
WERROR werr;
|
||||
DATA_BLOB ndr_blob;
|
||||
TALLOC_CTX *temp_ctx;
|
||||
|
||||
temp_ctx = talloc_new(ldb_module);
|
||||
W_ERROR_HAVE_NO_MEMORY(temp_ctx);
|
||||
|
||||
/* 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);
|
||||
return werr;
|
||||
}
|
||||
|
||||
/* write serialized schemaInfo into LDB */
|
||||
werr = dsdb_module_schema_info_blob_write(ldb_module, dsdb_flags, &ndr_blob);
|
||||
|
||||
talloc_free(temp_ctx);
|
||||
|
||||
return werr;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Creates new dsdb_schema_info object using
|
||||
* invocationId from supplied ldb
|
||||
*/
|
||||
WERROR dsdb_schema_info_create(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, struct dsdb_schema_info **_schema_info)
|
||||
{
|
||||
const struct GUID *invocation_id;
|
||||
struct dsdb_schema_info *schema_info;
|
||||
|
||||
/* try to determine invocationId from ldb */
|
||||
invocation_id = samdb_ntds_invocation_id(ldb);
|
||||
|
||||
schema_info = talloc(mem_ctx, struct dsdb_schema_info);
|
||||
if (!schema_info) {
|
||||
return WERR_NOMEM;
|
||||
}
|
||||
|
||||
schema_info->revision = 1;
|
||||
if (invocation_id) {
|
||||
schema_info->invocation_id = *invocation_id;
|
||||
} else {
|
||||
schema_info->invocation_id = GUID_zero();
|
||||
}
|
||||
|
||||
*_schema_info = schema_info;
|
||||
|
||||
return WERR_OK;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
WERROR dsdb_module_schema_info_update(struct ldb_module *ldb_module,
|
||||
struct dsdb_schema *schema,
|
||||
int dsdb_flags)
|
||||
{
|
||||
WERROR werr;
|
||||
const struct GUID *invocation_id;
|
||||
struct dsdb_schema_info *schema_info;
|
||||
|
||||
TALLOC_CTX *mem_ctx = talloc_new(schema);
|
||||
W_ERROR_HAVE_NO_MEMORY(mem_ctx);
|
||||
|
||||
invocation_id = samdb_ntds_invocation_id(ldb_module_get_ctx(ldb_module));
|
||||
if (!invocation_id) {
|
||||
return WERR_INTERNAL_DB_CORRUPTION;
|
||||
}
|
||||
|
||||
werr = dsdb_module_schema_info_read(ldb_module, dsdb_flags,
|
||||
mem_ctx, &schema_info);
|
||||
if (!W_ERROR_IS_OK(werr)) {
|
||||
DEBUG(0,("dsdb_module_schema_info_update: failed to reload schemaInfo - %s\n",
|
||||
win_errstr(werr)));
|
||||
talloc_free(mem_ctx);
|
||||
return werr;
|
||||
}
|
||||
|
||||
/* update schemaInfo */
|
||||
schema_info->revision++;
|
||||
schema_info->invocation_id = *invocation_id;
|
||||
|
||||
werr = dsdb_module_schema_info_write(ldb_module, dsdb_flags, schema_info);
|
||||
if (!W_ERROR_IS_OK(werr)) {
|
||||
DEBUG(0,("dsdb_module_schema_info_update: failed to save schemaInfo - %s\n",
|
||||
win_errstr(werr)));
|
||||
talloc_free(mem_ctx);
|
||||
return werr;
|
||||
}
|
||||
|
||||
/* finally, update schema_info in the cache */
|
||||
/* TODO: update schema_info in dsdb_schema cache */
|
||||
/*
|
||||
talloc_unlink(schema, discard_const(schema->schema_info));
|
||||
schema->schema_info = talloc_steal(schema, schema_info);
|
||||
*/
|
||||
|
||||
talloc_free(mem_ctx);
|
||||
return WERR_OK;
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user