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 = &el;
+
+	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