How to process schemaUpdateNow ldap request
Anatoliy Atanasov
anatoliy.atanasov at postpath.com
Fri Jul 11 13:29:27 GMT 2008
Hi metze
> Now about the dsdb_create_prefix_mapping():
>
> - Why didn't you follow the comments I added to the stub function?
>
> - This function should only change the on disk value.
>
Sorry, i misunderstood here. I saw that you have passed the schema and one of the comments says:
"- (maybe) update schema->prefixes", and then i made up the rest of it. Your proposal is absolutely correct.
> - It should not modify the schema->prefixes array!
>
> - You need to read the on disk value first then
> check that the mapping doesn't already exist
> in the on disk version.
>
> - If it's not already in the on disk version
> then you need to add a new mapping only to the on disk
> version.
>
>
No the dsdb_create_prefix_mapping does just that and the schema reloading will happen on schemaUpdateNow event.
> About the schemaUpdateNow patch:
>
> - You need to let partition_extended() forward the operation
> to the schema partition.
>
> - First just get it to the stage where the extended op arrive in
> the schema_fsmo module, then we can really implement it as a 2nd
> step.
>
> metze
I suppose that the next step will be updating the prefixMap in the schema cache?
Regards,
Anatoliy
-------------- next part --------------
diff --git a/source/dsdb/schema/schema_init.c b/source/dsdb/schema/schema_init.c
index 826f91b..1a4957c 100644
--- a/source/dsdb/schema/schema_init.c
+++ b/source/dsdb/schema/schema_init.c
@@ -339,22 +339,248 @@ WERROR dsdb_map_int2oid(const struct dsdb_schema *schema, uint32_t in, TALLOC_CT
*/
WERROR dsdb_create_prefix_mapping(struct ldb_context *ldb, struct dsdb_schema *schema, const char *full_oid)
{
- /*
- * TODO:
- * - (maybe) read the old prefixMap attribute and parse it
- *
- * - recheck the prefix doesn't exist (because the ldb
- * has maybe a more uptodate value than schem->prefixes
- *
- * - calculate a new mapping for the oid prefix of full_oid
- * - store the new prefixMap attribute
- *
- * - (maybe) update schema->prefixes
- * or
- * - better find a way to indicate a schema reload,
- * so that other processes also notice the schema change
- */
- return WERR_NOT_SUPPORTED;
+ WERROR status;
+ uint32_t num_prefixes;
+ struct dsdb_schema_oid_prefix *prefixes;
+ struct ldb_val ndr_blob;
+ TALLOC_CTX *mem_ctx;
+
+ mem_ctx = talloc_new(ldb);
+ W_ERROR_HAVE_NO_MEMORY(mem_ctx);
+
+ /* Read prefixes from disk*/
+ status = dsdb_read_prefixes_from_ldb( mem_ctx, ldb, &num_prefixes, &prefixes );
+ if ( !W_ERROR_IS_OK( status ) ) {
+ DEBUG(0,("dsdb_create_prefix_mapping: dsdb_read_prefixes_from_ldb failed\n"));
+ talloc_free(mem_ctx);
+ return status;
+ }
+
+ /* Check if there is a prefix for the oid in the prefixes array*/
+ status = dsdb_check_prefixes_for_oid( num_prefixes, prefixes, full_oid );
+ if ( W_ERROR_IS_OK( status ) ) {
+ /* prefix found*/
+ talloc_free(mem_ctx);
+ return status;
+ }
+ /* Update prefix map in ldb*/
+ /* Update the prefixes */
+ status = dsdb_prefix_map_update(mem_ctx, &num_prefixes, &prefixes, full_oid);
+ if ( !W_ERROR_IS_OK( status ) ) {
+ DEBUG(0,("dsdb_create_prefix_mapping: dsdb_prefix_map_update failed\n"));
+ talloc_free(mem_ctx);
+ return status;
+ }
+ /* Convert prefixes in ndr blob*/
+ status = dsdb_write_prefixes_to_ndr( mem_ctx, ldb, num_prefixes, prefixes, &ndr_blob );
+ if ( !W_ERROR_IS_OK( status ) ) {
+ DEBUG(0,("dsdb_create_prefix_mapping: dsdb_write_prefixes_to_ndr failed\n"));
+ talloc_free(mem_ctx);
+ return status;
+ }
+
+ /* Update prefixMap in ldb*/
+ status = dsdb_write_prefixes_to_ldb( mem_ctx, ldb, &ndr_blob );
+ if ( !W_ERROR_IS_OK( status ) ) {
+ DEBUG(0,("dsdb_create_prefix_mapping: dsdb_write_prefixes_to_ldb failed\n"));
+ talloc_free(mem_ctx);
+ return status;
+ }
+
+ talloc_free(mem_ctx);
+ return status;
+}
+
+WERROR dsdb_check_prefixes_for_oid(uint32_t num_prefixes, const struct dsdb_schema_oid_prefix *prefixes, const char *full_oid)
+{
+ uint32_t i;
+
+ for (i=0; i<num_prefixes; ++i) {
+ if (strncmp(prefixes[i].oid, full_oid, prefixes[i].oid_len) == 0) {
+ /* prefix is found, proceed */
+ return WERR_OK;
+ }
+ }
+
+ return WERR_NOT_FOUND;
+}
+
+WERROR dsdb_write_prefixes_to_ldb(TALLOC_CTX *mem_ctx, struct ldb_context *ldb, struct ldb_val *ndr_blob)
+{
+ struct ldb_message msg;
+ struct ldb_dn *schema_dn;
+ struct ldb_message_element el;
+ int ret;
+
+ schema_dn = samdb_schema_dn(ldb);
+ if (!schema_dn) {
+ DEBUG(0,("dsdb_write_prefixes_to_ldb: no schema dn present\n"));
+ return WERR_FOOBAR;
+ }
+
+ el.num_values = 1;
+ el.values = ndr_blob;
+ el.flags = LDB_FLAG_MOD_REPLACE;
+ el.name = talloc_strdup(mem_ctx, "prefixMap");
+
+ msg.dn = ldb_dn_copy(mem_ctx, schema_dn);
+ msg.num_elements = 1;
+ msg.elements = ⪙
+
+ ret = ldb_modify( ldb, &msg );
+ if (ret != 0) {
+ DEBUG(0,("dsdb_write_prefixes_to_ldb: ldb_modify failed\n"));
+ return WERR_FOOBAR;
+ }
+
+ return WERR_OK;
+}
+
+WERROR dsdb_prefix_map_update(TALLOC_CTX *mem_ctx, uint32_t *num_prefixes, struct dsdb_schema_oid_prefix **prefixes, const char *oid)
+{
+ uint32_t new_num_prefixes, index_new_prefix, new_entry_id;
+ const char* lastDotOffset;
+ size_t size;
+
+ new_num_prefixes = *num_prefixes + 1;
+ index_new_prefix = *num_prefixes;
+ new_entry_id = (*num_prefixes)<<16;
+
+ /* Extract the prefix from the oid*/
+ lastDotOffset = strrchr(oid, '.');
+ if (lastDotOffset == NULL) {
+ DEBUG(0,("dsdb_prefix_map_update: failed to find the last dot\n"));
+ return WERR_NOT_FOUND;
+ }
+
+ /* Calculate the size of the remainig string that should be the prefix of it */
+ size = strlen(oid) - strlen(lastDotOffset);
+ if (size <= 0) {
+ DEBUG(0,("dsdb_prefix_map_update: size of the remaining string invalid\n"));
+ return WERR_FOOBAR;
+ }
+ /* Add one because we need to copy the dot */
+ size += 1;
+
+ /* Create a spot in the prefixMap for one more prefix*/
+ (*prefixes) = talloc_realloc(mem_ctx, *prefixes, struct dsdb_schema_oid_prefix, new_num_prefixes);
+ W_ERROR_HAVE_NO_MEMORY(*prefixes);
+
+ /* Add the new prefix entry*/
+ (*prefixes)[index_new_prefix].id = new_entry_id;
+ (*prefixes)[index_new_prefix].oid = talloc_strndup(mem_ctx, oid, size);
+ (*prefixes)[index_new_prefix].oid_len = strlen((*prefixes)[index_new_prefix].oid);
+
+ /* Increase num_prefixes because new prefix has been added */
+ ++(*num_prefixes);
+
+ return WERR_OK;
+}
+
+WERROR dsdb_write_prefixes_to_ndr(TALLOC_CTX *mem_ctx, struct ldb_context *ldb, uint32_t num_prefixes, const struct dsdb_schema_oid_prefix *prefixes, struct ldb_val *out)
+{
+ struct prefixMapBlob *blob;
+ enum ndr_err_code ndr_err;
+ uint32_t i;
+
+ blob = talloc_zero(mem_ctx, struct prefixMapBlob);
+ W_ERROR_HAVE_NO_MEMORY(blob);
+
+ blob->version = PREFIX_MAP_VERSION_DSDB;
+ blob->ctr.dsdb.num_mappings = num_prefixes;
+ blob->ctr.dsdb.mappings = talloc_realloc(blob,
+ blob->ctr.dsdb.mappings,
+ struct drsuapi_DsReplicaOIDMapping,
+ blob->ctr.dsdb.num_mappings);
+ if (!blob->ctr.dsdb.mappings) {
+ return WERR_NOMEM;
+ }
+
+ for (i=0; i < num_prefixes; i++) {
+ blob->ctr.dsdb.mappings[i].id_prefix = prefixes[i].id>>16;
+ blob->ctr.dsdb.mappings[i].oid.oid = talloc_strdup(blob->ctr.dsdb.mappings, prefixes[i].oid);
+ }
+
+ ndr_err = ndr_push_struct_blob(out, ldb,
+ lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")),
+ blob,
+ (ndr_push_flags_fn_t)ndr_push_prefixMapBlob);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ return WERR_FOOBAR;
+ }
+
+ return WERR_OK;
+}
+
+WERROR dsdb_read_prefixes_from_ldb(TALLOC_CTX *mem_ctx, struct ldb_context *ldb, uint32_t* num_prefixes, struct dsdb_schema_oid_prefix **prefixes)
+{
+ struct prefixMapBlob *blob;
+ enum ndr_err_code ndr_err;
+ uint32_t i;
+ const struct ldb_val *prefix_val;
+ struct ldb_dn *schema_dn;
+ struct ldb_result *schema_res;
+ int ret;
+ static const char *schema_attrs[] = {
+ "prefixMap",
+ NULL
+ };
+
+ schema_dn = samdb_schema_dn(ldb);
+ if (!schema_dn) {
+ DEBUG(0,("dsdb_read_prefixes_from_ldb: no schema dn present\n"));
+ return WERR_FOOBAR;
+ }
+
+ ret = ldb_search(ldb, schema_dn, LDB_SCOPE_BASE,NULL, schema_attrs,&schema_res);
+ if (ret == LDB_ERR_NO_SUCH_OBJECT) {
+ DEBUG(0,("dsdb_read_prefixes_from_ldb: no prefix map present\n"));
+ return WERR_FOOBAR;
+ } else if (ret != LDB_SUCCESS) {
+ DEBUG(0,("dsdb_read_prefixes_from_ldb: failed to search the schema head\n"));
+ return WERR_FOOBAR;
+ }
+
+ prefix_val = ldb_msg_find_ldb_val(schema_res->msgs[0], "prefixMap");
+ if (!prefix_val) {
+ DEBUG(0,("dsdb_read_prefixes_from_ldb: no prefixMap attribute found\n"));
+ return WERR_FOOBAR;
+ }
+
+ blob = talloc(mem_ctx, struct prefixMapBlob);
+ W_ERROR_HAVE_NO_MEMORY(blob);
+
+ ndr_err = ndr_pull_struct_blob(prefix_val, blob,
+ lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")),
+ blob,
+ (ndr_pull_flags_fn_t)ndr_pull_prefixMapBlob);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ DEBUG(0,("dsdb_read_prefixes_from_ldb: ndr_pull_struct_blob failed\n"));
+ talloc_free(blob);
+ return WERR_FOOBAR;
+ }
+
+ if (blob->version != PREFIX_MAP_VERSION_DSDB) {
+ DEBUG(0,("dsdb_read_prefixes_from_ldb: blob->version incorect\n"));
+ talloc_free(blob);
+ return WERR_FOOBAR;
+ }
+
+ *num_prefixes = blob->ctr.dsdb.num_mappings;
+ *prefixes = talloc_array(mem_ctx, struct dsdb_schema_oid_prefix, *num_prefixes);
+ if(!(*prefixes)) {
+ talloc_free(blob);
+ return WERR_NOMEM;
+ }
+ for (i=0; i < blob->ctr.dsdb.num_mappings; i++) {
+ (*prefixes)[i].id = blob->ctr.dsdb.mappings[i].id_prefix<<16;
+ (*prefixes)[i].oid = talloc_strdup(mem_ctx, blob->ctr.dsdb.mappings[i].oid.oid);
+ (*prefixes)[i].oid = talloc_asprintf_append((*prefixes)[i].oid, ".");
+ (*prefixes)[i].oid_len = strlen(blob->ctr.dsdb.mappings[i].oid.oid);
+ }
+
+ talloc_free(blob);
+ return WERR_OK;
}
#define GET_STRING_LDB(msg, attr, mem_ctx, p, elem, strict) do { \
-------------- next part --------------
diff --git a/source/dsdb/samdb/ldb_modules/partition.c b/source/dsdb/samdb/ldb_modules/partition.c
index 7f13633..026cd04 100644
--- a/source/dsdb/samdb/ldb_modules/partition.c
+++ b/source/dsdb/samdb/ldb_modules/partition.c
@@ -694,6 +694,49 @@ static int partition_extended_replicated_objects(struct ldb_module *module, stru
return partition_replicate(module, req, ext->partition_dn);
}
+static int partition_extended_schema_update_now(struct ldb_module *module, struct ldb_request *req)
+{
+ struct dsdb_control_current_partition *partition;
+ struct partition_private_data *data;
+ struct ldb_dn *schema_dn;
+ struct partition_context *ac;
+ struct ldb_module *backend;
+ int ret;
+
+ schema_dn = talloc_get_type(req->op.extended.data, struct ldb_dn);
+ if (!schema_dn) {
+ ldb_debug(module->ldb, LDB_DEBUG_FATAL, "partition_extended: invalid extended data\n");
+ return LDB_ERR_PROTOCOL_ERROR;
+ }
+
+ data = talloc_get_type(module->private_data, struct partition_private_data);
+ if (!data) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ partition = find_partition( data, schema_dn );
+ if (!partition) {
+ return ldb_next_request(module, req);
+ }
+
+ ac = partition_init_handle(req, module);
+ if (!ac) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ backend = make_module_for_next_request(req, module->ldb, partition->module);
+ if (!backend) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ ret = ldb_request_add_control(req, DSDB_CONTROL_CURRENT_PARTITION_OID, false, partition);
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+
+ return ldb_next_request(backend, req);
+}
+
/* extended */
static int partition_extended(struct ldb_module *module, struct ldb_request *req)
{
@@ -703,6 +746,11 @@ static int partition_extended(struct ldb_module *module, struct ldb_request *req
return partition_extended_replicated_objects(module, req);
}
+ /* forward schemaUpdateNow operation to schema_fsmo module*/
+ if (strcmp(req->op.extended.oid, DSDB_EXTENDED_SCHEMA_UPDATE_NOW) == 0) {
+ return partition_extended_schema_update_now( module, req );
+ }
+
/*
* as the extended operation has no dn
* we need to send it to all partitions
diff --git a/source/dsdb/samdb/ldb_modules/rootdse.c b/source/dsdb/samdb/ldb_modules/rootdse.c
index 75f99a1..c59248f 100644
--- a/source/dsdb/samdb/ldb_modules/rootdse.c
+++ b/source/dsdb/samdb/ldb_modules/rootdse.c
@@ -391,9 +391,38 @@ static int rootdse_init(struct ldb_module *module)
return ldb_next_init(module);
}
+static int rootdse_modify(struct ldb_module *module, struct ldb_request *req)
+{
+ struct ldb_result *ext_res;
+ int ret;
+ struct ldb_dn *schema_dn;
+
+ const char *schemaUpdateNowAttr = samdb_result_string(req->op.mod.message, "schemaUpdateNow", NULL);
+ if (!schemaUpdateNowAttr) {
+ return ldb_next_request(module, req);
+ }
+
+ schema_dn = samdb_schema_dn(module->ldb);
+ if (!schema_dn) {
+ ldb_reset_err_string(module->ldb);
+ ldb_debug(module->ldb, LDB_DEBUG_WARNING,
+ "rootdse_modify: no schema dn present: (skip ldb_extended call)\n");
+ return ldb_next_request(module, req);
+ }
+
+ ret = ldb_extended(module->ldb, DSDB_EXTENDED_SCHEMA_UPDATE_NOW, schema_dn, &ext_res);
+ if (ret != LDB_SUCCESS) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ talloc_free(ext_res);
+ return ret;
+}
+
_PUBLIC_ const struct ldb_module_ops ldb_rootdse_module_ops = {
.name = "rootdse",
.init_context = rootdse_init,
.search = rootdse_search,
- .request = rootdse_request
+ .request = rootdse_request,
+ .modify = rootdse_modify
};
diff --git a/source/dsdb/samdb/ldb_modules/schema_fsmo.c b/source/dsdb/samdb/ldb_modules/schema_fsmo.c
index 6f65c19..4f6df98 100644
--- a/source/dsdb/samdb/ldb_modules/schema_fsmo.c
+++ b/source/dsdb/samdb/ldb_modules/schema_fsmo.c
@@ -215,8 +215,20 @@ static int schema_fsmo_add(struct ldb_module *module, struct ldb_request *req)
return ldb_next_request(module, req);
}
+static int schema_fsmo_extended(struct ldb_module *module, struct ldb_request *req)
+{
+ if (strcmp(req->op.extended.oid, DSDB_EXTENDED_SCHEMA_UPDATE_NOW) != 0) {
+ return ldb_next_request(module, req);
+ }
+
+ /* TODO: Triger schema reload */
+
+ return LDB_SUCCESS;
+}
+
_PUBLIC_ const struct ldb_module_ops ldb_schema_fsmo_module_ops = {
.name = "schema_fsmo",
.init_context = schema_fsmo_init,
- .add = schema_fsmo_add
+ .add = schema_fsmo_add,
+ .extended = schema_fsmo_extended
};
diff --git a/source/dsdb/samdb/samdb.h b/source/dsdb/samdb/samdb.h
index 75aa819..5a5fe3c 100644
--- a/source/dsdb/samdb/samdb.h
+++ b/source/dsdb/samdb/samdb.h
@@ -90,4 +90,6 @@ struct dsdb_pdc_fsmo {
struct ldb_dn *master_dn;
};
+#define DSDB_EXTENDED_SCHEMA_UPDATE_NOW "1.3.6.1.4.1.7165.4.4.2"
+
#endif /* __SAMDB_H__ */
More information about the samba-technical
mailing list