From 9d1f8bcca9e39d1e0caa9377f30c290b0738f080 Mon Sep 17 00:00:00 2001 From: Kamen Mazdrashki Date: Tue, 23 Mar 2010 16:44:02 +0200 Subject: s4/dsdb: dsdb_schema_info object implementation --- source4/dsdb/config.mk | 3 +- source4/dsdb/schema/schema_info_attr.c | 383 +++++++++++++++++++++++++++++++++ 2 files changed, 385 insertions(+), 1 deletion(-) create mode 100644 source4/dsdb/schema/schema_info_attr.c diff --git a/source4/dsdb/config.mk b/source4/dsdb/config.mk index 2bd19e987d..4363399bc3 100644 --- a/source4/dsdb/config.mk +++ b/source4/dsdb/config.mk @@ -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 diff --git a/source4/dsdb/schema/schema_info_attr.c b/source4/dsdb/schema/schema_info_attr.c new file mode 100644 index 0000000000..2d3dfc827c --- /dev/null +++ b/source4/dsdb/schema/schema_info_attr.c @@ -0,0 +1,383 @@ +/* + Unix SMB/CIFS implementation. + + SCHEMA::schemaInfo implementation + + Copyright (C) Kamen Mazdrashki 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 . +*/ + +#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; +} -- cgit