Пример #1
0
static int read_at_rootdse_record(struct ldb_context *ldb, struct ldb_module *module, TALLOC_CTX *mem_ctx,
				  struct ldb_message **msg, struct ldb_request *parent)
{
	int ret;
	static const char *rootdse_attrs[] = { "defaultNamingContext", "configurationNamingContext", "schemaNamingContext", NULL };
	struct ldb_result *rootdse_res;
	struct ldb_dn *rootdse_dn;
	TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
	if (!tmp_ctx) {
		return ldb_oom(ldb);
	}

	rootdse_dn = ldb_dn_new(tmp_ctx, ldb, "@ROOTDSE");
	if (!rootdse_dn) {
		talloc_free(tmp_ctx);
		return ldb_oom(ldb);
	}

	ret = dsdb_module_search_dn(module, tmp_ctx, &rootdse_res, rootdse_dn,
	                            rootdse_attrs, DSDB_FLAG_NEXT_MODULE, parent);
	if (ret != LDB_SUCCESS) {
		talloc_free(tmp_ctx);
		return ret;
	}

	talloc_steal(mem_ctx, rootdse_res->msgs);
	*msg = rootdse_res->msgs[0];

	talloc_free(tmp_ctx);

	return ret;
}
Пример #2
0
/*
  allocate a new range of RIDs in the RID Manager object
 */
static int ridalloc_rid_manager_allocate(struct ldb_module *module, struct ldb_dn *rid_manager_dn, uint64_t *new_pool,
					 struct ldb_request *parent)
{
	int ret;
	TALLOC_CTX *tmp_ctx = talloc_new(module);
	const char *attrs[] = { "rIDAvailablePool", NULL };
	uint64_t rid_pool, new_rid_pool, dc_pool;
	uint32_t rid_pool_lo, rid_pool_hi;
	struct ldb_result *res;
	struct ldb_context *ldb = ldb_module_get_ctx(module);
	const unsigned alloc_size = 500;

	ret = dsdb_module_search_dn(module, tmp_ctx, &res, rid_manager_dn,
	                            attrs, DSDB_FLAG_NEXT_MODULE, parent);
	if (ret != LDB_SUCCESS) {
		ldb_asprintf_errstring(ldb, "Failed to find rIDAvailablePool in %s - %s",
				       ldb_dn_get_linearized(rid_manager_dn), ldb_errstring(ldb));
		talloc_free(tmp_ctx);
		return ret;
	}

	rid_pool = ldb_msg_find_attr_as_uint64(res->msgs[0], "rIDAvailablePool", 0);
	rid_pool_lo = rid_pool & 0xFFFFFFFF;
	rid_pool_hi = rid_pool >> 32;
	if (rid_pool_lo >= rid_pool_hi) {
		ldb_asprintf_errstring(ldb, "Out of RIDs in RID Manager - rIDAvailablePool is %u-%u",
				       rid_pool_lo, rid_pool_hi);
		talloc_free(tmp_ctx);
		return ret;
	}

	/* lower part of new pool is the low part of the rIDAvailablePool */
	dc_pool = rid_pool_lo;

	/* allocate 500 RIDs to this DC */
	rid_pool_lo = MIN(rid_pool_hi, rid_pool_lo + alloc_size);

	/* work out upper part of new pool */
	dc_pool |= (((uint64_t)rid_pool_lo-1)<<32);

	/* and new rIDAvailablePool value */
	new_rid_pool = rid_pool_lo | (((uint64_t)rid_pool_hi)<<32);

	ret = dsdb_module_constrainted_update_uint64(module, rid_manager_dn, "rIDAvailablePool",
						     &rid_pool, &new_rid_pool, parent);
	if (ret != LDB_SUCCESS) {
		ldb_asprintf_errstring(ldb, "Failed to update rIDAvailablePool - %s",
				       ldb_errstring(ldb));
		talloc_free(tmp_ctx);
		return ret;
	}

	(*new_pool) = dc_pool;
	talloc_free(tmp_ctx);
	return LDB_SUCCESS;
}
Пример #3
0
static int construct_msds_isrodc_with_server_dn(struct ldb_module *module,
						struct ldb_message *msg,
						struct ldb_dn *dn,
						struct ldb_request *parent)
{
	struct ldb_dn *server_dn;
	const char *attr_obj_cat[] = { "objectCategory", NULL };
	struct ldb_result *res;
	struct ldb_message_element *object_category;
	int ret;

	server_dn = ldb_dn_copy(msg, dn);
	if (!ldb_dn_add_child_fmt(server_dn, "CN=NTDS Settings")) {
		DEBUG(4, (__location__ ": Failed to add child to %s \n",
			  ldb_dn_get_linearized(server_dn)));
		return ldb_operr(ldb_module_get_ctx(module));
	}

	ret = dsdb_module_search_dn(module, msg, &res, server_dn, attr_obj_cat,
	                            DSDB_FLAG_NEXT_MODULE, parent);
	if (ret == LDB_ERR_NO_SUCH_OBJECT) {
		DEBUG(4,(__location__ ": Can't get objectCategory for %s \n",
					 ldb_dn_get_linearized(server_dn)));
		return LDB_SUCCESS;
	} else if (ret != LDB_SUCCESS) {
		return ret;
	}

	object_category = ldb_msg_find_element(res->msgs[0], "objectCategory");
	if (!object_category) {
		DEBUG(4,(__location__ ": Can't find objectCategory for %s \n",
			 ldb_dn_get_linearized(res->msgs[0]->dn)));
		return LDB_SUCCESS;
	}
	return construct_msds_isrodc_with_dn(module, msg, object_category);
}
Пример #4
0
static int pdc_fsmo_init(struct ldb_module *module)
{
	struct ldb_context *ldb;
	TALLOC_CTX *mem_ctx;
	struct ldb_dn *pdc_dn;
	struct dsdb_pdc_fsmo *pdc_fsmo;
	struct ldb_result *pdc_res;
	int ret;
	static const char *pdc_attrs[] = {
		"fSMORoleOwner",
		NULL
	};

	ldb = ldb_module_get_ctx(module);

	mem_ctx = talloc_new(module);
	if (!mem_ctx) {
		return ldb_oom(ldb);
	}

	pdc_dn = ldb_get_default_basedn(ldb);
	if (!pdc_dn) {
		ldb_debug_set(ldb, LDB_DEBUG_FATAL,
			  "pdc_fsmo_init: could not determine default basedn");
		talloc_free(mem_ctx);
		return LDB_ERR_OPERATIONS_ERROR;
	}

	pdc_fsmo = talloc_zero(mem_ctx, struct dsdb_pdc_fsmo);
	if (!pdc_fsmo) {
		return ldb_oom(ldb);
	}
	ldb_module_set_private(module, pdc_fsmo);

	ret = dsdb_module_search_dn(module, mem_ctx, &pdc_res,
				    pdc_dn, 
				    pdc_attrs,
				    DSDB_FLAG_NEXT_MODULE, NULL);
	if (ret == LDB_ERR_NO_SUCH_OBJECT) {
		ldb_debug(ldb, LDB_DEBUG_TRACE,
			  "pdc_fsmo_init: no domain object present: (skip loading of domain details)");
		talloc_free(mem_ctx);
		return ldb_next_init(module);
	} else if (ret != LDB_SUCCESS) {
		ldb_debug_set(ldb, LDB_DEBUG_FATAL,
			      "pdc_fsmo_init: failed to search the domain object: %d:%s: %s",
			      ret, ldb_strerror(ret), ldb_errstring(ldb));
		talloc_free(mem_ctx);
		return ret;
	}

	pdc_fsmo->master_dn = ldb_msg_find_attr_as_dn(ldb, mem_ctx, pdc_res->msgs[0], "fSMORoleOwner");
	if (ldb_dn_compare(samdb_ntds_settings_dn(ldb), pdc_fsmo->master_dn) == 0) {
		pdc_fsmo->we_are_master = true;
	} else {
		pdc_fsmo->we_are_master = false;
	}

	if (ldb_set_opaque(ldb, "dsdb_pdc_fsmo", pdc_fsmo) != LDB_SUCCESS) {
		return ldb_oom(ldb);
	}

	talloc_steal(module, pdc_fsmo);

	ldb_debug(ldb, LDB_DEBUG_TRACE,
			  "pdc_fsmo_init: we are master: %s\n",
			  (pdc_fsmo->we_are_master?"yes":"no"));

	talloc_free(mem_ctx);
	return ldb_next_init(module);
}
Пример #5
0
static int samba_dsdb_init(struct ldb_module *module)
{
	struct ldb_context *ldb = ldb_module_get_ctx(module);
	int ret, len, i;
	TALLOC_CTX *tmp_ctx = talloc_new(module);
	struct ldb_result *res;
	struct ldb_message *rootdse_msg = NULL, *partition_msg;
	struct ldb_dn *samba_dsdb_dn, *partition_dn;
	struct ldb_module *backend_module, *module_chain;
	const char **final_module_list, **reverse_module_list;
	/*
	  Add modules to the list to activate them by default
	  beware often order is important

	  Some Known ordering constraints:
	  - rootdse must be first, as it makes redirects from "" -> cn=rootdse
	  - extended_dn_in must be before objectclass.c, as it resolves the DN
	  - objectclass must be before password_hash and samldb since these LDB
	    modules require the expanded "objectClass" list
	  - objectclass must be before descriptor and acl, as both assume that
	    objectClass values are sorted
	  - objectclass_attrs must be behind operational in order to see all
	    attributes (the operational module protects and therefore
	    suppresses per default some important ones)
	  - partition must be last
	  - each partition has its own module list then

	  The list is presented here as a set of declarations to show the
	  stack visually - the code below then handles the creation of the list
	  based on the parameters loaded from the database.
	*/
	static const char *modules_list1[] = {"resolve_oids",
					     "rootdse",
					     "schema_load",
					     "lazy_commit",
					     "dirsync",
					     "paged_results",
					     "ranged_results",
					     "anr",
					     "server_sort",
					     "asq",
					     "extended_dn_store",
					     NULL };
	/* extended_dn_in or extended_dn_in_openldap goes here */
	static const char *modules_list1a[] = {"objectclass",
					     "descriptor",
					     "acl",
					     "aclread",
					     "samldb",
					     "password_hash",
					     "operational",
					     "instancetype",
					     "objectclass_attrs",
					     NULL };

	const char **link_modules;
	static const char *fedora_ds_modules[] = {
		"rdn_name", NULL };
	static const char *openldap_modules[] = {
		NULL };
	static const char *tdb_modules_list[] = {
		"rdn_name",
		"subtree_delete",
		"repl_meta_data",
		"subtree_rename",
		"linked_attributes",
		NULL};

	const char *extended_dn_module;
	const char *extended_dn_module_ldb = "extended_dn_out_ldb";
	const char *extended_dn_module_fds = "extended_dn_out_fds";
	const char *extended_dn_module_openldap = "extended_dn_out_openldap";
	const char *extended_dn_in_module = "extended_dn_in";

	static const char *modules_list2[] = {"show_deleted",
					      "new_partition",
					      "partition",
					      NULL };

	const char **backend_modules;
	static const char *fedora_ds_backend_modules[] = {
		"nsuniqueid", "paged_searches", "simple_dn", NULL };
	static const char *openldap_backend_modules[] = {
		"entryuuid", "simple_dn", NULL };

	static const char *samba_dsdb_attrs[] = { "backendType", NULL };
	static const char *partition_attrs[] = { "ldapBackend", NULL };
	const char *backendType, *backendUrl;
	bool use_sasl_external = false;

	if (!tmp_ctx) {
		return ldb_oom(ldb);
	}

	ret = ldb_register_samba_handlers(ldb);
	if (ret != LDB_SUCCESS) {
		talloc_free(tmp_ctx);
		return ret;
	}

	samba_dsdb_dn = ldb_dn_new(tmp_ctx, ldb, "@SAMBA_DSDB");
	if (!samba_dsdb_dn) {
		talloc_free(tmp_ctx);
		return ldb_oom(ldb);
	}

	partition_dn = ldb_dn_new(tmp_ctx, ldb, DSDB_PARTITION_DN);
	if (!partition_dn) {
		talloc_free(tmp_ctx);
		return ldb_oom(ldb);
	}

#define CHECK_LDB_RET(check_ret)				\
	do {							\
		if (check_ret != LDB_SUCCESS) {			\
			talloc_free(tmp_ctx);			\
			return check_ret;			\
		}						\
	} while (0)

	ret = dsdb_module_search_dn(module, tmp_ctx, &res, samba_dsdb_dn,
	                            samba_dsdb_attrs, DSDB_FLAG_NEXT_MODULE, NULL);
	if (ret == LDB_ERR_NO_SUCH_OBJECT) {
		backendType = "ldb";
	} else if (ret == LDB_SUCCESS) {
		backendType = ldb_msg_find_attr_as_string(res->msgs[0], "backendType", "ldb");
	} else {
		talloc_free(tmp_ctx);
		return ret;
	}

	backend_modules = NULL;
	if (strcasecmp(backendType, "ldb") == 0) {
		extended_dn_module = extended_dn_module_ldb;
		link_modules = tdb_modules_list;
	} else {
		struct cli_credentials *cred;
		bool is_ldapi = false;

		ret = dsdb_module_search_dn(module, tmp_ctx, &res, partition_dn,
					    partition_attrs, DSDB_FLAG_NEXT_MODULE, NULL);
		if (ret == LDB_SUCCESS) {
			backendUrl = ldb_msg_find_attr_as_string(res->msgs[0], "ldapBackend", "ldapi://");
			if (!strncasecmp(backendUrl, "ldapi://", sizeof("ldapi://")-1)) {
				is_ldapi = true;
			}
		} else if (ret != LDB_ERR_NO_SUCH_OBJECT) {
			talloc_free(tmp_ctx);
			return ret;
		}
		if (strcasecmp(backendType, "fedora-ds") == 0) {
			link_modules = fedora_ds_modules;
			backend_modules = fedora_ds_backend_modules;
			extended_dn_module = extended_dn_module_fds;
		} else if (strcasecmp(backendType, "openldap") == 0) {
			link_modules = openldap_modules;
			backend_modules = openldap_backend_modules;
			extended_dn_module = extended_dn_module_openldap;
			extended_dn_in_module = "extended_dn_in_openldap";
			if (is_ldapi) {
				use_sasl_external = true;
			}
		} else {
			return ldb_error(ldb, LDB_ERR_OPERATIONS_ERROR, "invalid backend type");
		}
		ret = ldb_set_opaque(ldb, "readOnlySchema", (void*)1);
		if (ret != LDB_SUCCESS) {
			ldb_set_errstring(ldb, "Failed to set readOnlySchema opaque");
		}

		cred = ldb_get_opaque(ldb, "credentials");
		if (!cred || !cli_credentials_authentication_requested(cred)) {
			ret = set_ldap_credentials(ldb, use_sasl_external);
			if (ret != LDB_SUCCESS) {
				return ret;
			}
		}
	}

#define CHECK_MODULE_LIST \
	do {							\
		if (!final_module_list) {			\
			talloc_free(tmp_ctx);			\
			return ldb_oom(ldb);			\
		}						\
	} while (0)

	final_module_list = str_list_copy_const(tmp_ctx, modules_list1);
	CHECK_MODULE_LIST;

	final_module_list = str_list_add_const(final_module_list, extended_dn_in_module);
	CHECK_MODULE_LIST;

	final_module_list = str_list_append_const(final_module_list, modules_list1a);
	CHECK_MODULE_LIST;

	final_module_list = str_list_append_const(final_module_list, link_modules);
	CHECK_MODULE_LIST;

	final_module_list = str_list_add_const(final_module_list, extended_dn_module);
	CHECK_MODULE_LIST;

	final_module_list = str_list_append_const(final_module_list, modules_list2);
	CHECK_MODULE_LIST;


	ret = read_at_rootdse_record(ldb, module, tmp_ctx, &rootdse_msg, NULL);
	CHECK_LDB_RET(ret);

	partition_msg = ldb_msg_new(tmp_ctx);
	partition_msg->dn = ldb_dn_new(partition_msg, ldb, "@" DSDB_OPAQUE_PARTITION_MODULE_MSG_OPAQUE_NAME);

	ret = prepare_modules_line(ldb, tmp_ctx,
				   rootdse_msg,
				   partition_msg, "schemaNamingContext",
				   "schema_data", backend_modules);
	CHECK_LDB_RET(ret);

	ret = prepare_modules_line(ldb, tmp_ctx,
				   rootdse_msg,
				   partition_msg, NULL,
				   NULL, backend_modules);
	CHECK_LDB_RET(ret);

	ret = ldb_set_opaque(ldb, DSDB_OPAQUE_PARTITION_MODULE_MSG_OPAQUE_NAME, partition_msg);
	CHECK_LDB_RET(ret);

	talloc_steal(ldb, partition_msg);

	/* Now prepare the module chain.  Oddly, we must give it to ldb_load_modules_list in REVERSE */
	for (len = 0; final_module_list[len]; len++) { /* noop */};

	reverse_module_list = talloc_array(tmp_ctx, const char *, len+1);
	if (!reverse_module_list) {
		talloc_free(tmp_ctx);
		return ldb_oom(ldb);
	}
	for (i=0; i < len; i++) {
		reverse_module_list[i] = final_module_list[(len - 1) - i];
	}
	reverse_module_list[i] = NULL;

	/* The backend (at least until the partitions module
	 * reconfigures things) is the next module in the currently
	 * loaded chain */
	backend_module = ldb_module_next(module);
	ret = ldb_module_load_list(ldb, reverse_module_list, backend_module, &module_chain);
	CHECK_LDB_RET(ret);

	talloc_free(tmp_ctx);
	/* Set this as the 'next' module, so that we effectivly append it to module chain */
	ldb_module_set_next(module, module_chain);

	return ldb_next_init(module);
}
Пример #6
0
static int samba_dsdb_init(struct ldb_module *module)
{
	struct ldb_context *ldb = ldb_module_get_ctx(module);
	int ret, len, i;
	TALLOC_CTX *tmp_ctx = talloc_new(module);
	struct ldb_result *res;
	struct ldb_message *rootdse_msg, *partition_msg;
	struct ldb_dn *samba_dsdb_dn;
	struct ldb_module *backend_module, *module_chain;
	const char **final_module_list, **reverse_module_list;
	/*
	  Add modules to the list to activate them by default
	  beware often order is important

	  Some Known ordering constraints:
	  - rootdse must be first, as it makes redirects from "" -> cn=rootdse
	  - extended_dn_in must be before objectclass.c, as it resolves the DN
	  - objectclass must be before password_hash, because password_hash checks
	    that the objectclass is of type person (filled in by objectclass
	    module when expanding the objectclass list)
	  - partition must be last
	  - each partition has its own module list then

	  The list is presented here as a set of declarations to show the
	  stack visually - the code below then handles the creation of the list
	  based on the parameters loaded from the database.
	*/
	static const char *modules_list[] = {"resolve_oids",
					     "rootdse",
					     "lazy_commit",
					     "paged_results",
					     "ranged_results",
					     "anr",
					     "server_sort",
					     "asq",
					     "extended_dn_store",
					     "extended_dn_in",
					     "rdn_name",
					     "objectclass",
					     "descriptor",
					     "acl",
					     "samldb",
					     "password_hash",
					     "operational",
					     "kludge_acl",
					     "schema_load",
					     "instancetype",
					     NULL };

	const char *objectguid_module;
	/* if serverrole == "domain controller": */
	const char *repl_meta_data = "repl_meta_data";
	/*    else: */
        const char *objectguid = "objectguid";

	const char **link_modules;
	static const char *tdb_modules_list[] = {
		"subtree_rename",
		"subtree_delete",
		"linked_attributes",
		NULL};

	const char *extended_dn_module;
	const char *extended_dn_module_ldb = "extended_dn_out_ldb";
	const char *extended_dn_module_fds = "extended_dn_out_fds";
	const char *extended_dn_module_openldap = "extended_dn_out_openldap";

	static const char *modules_list2[] = {"show_deleted",
					      "new_partition",
					      "partition",
					      NULL };

	const char **backend_modules;
	static const char *fedora_ds_backend_modules[] = {
		"nsuniqueid", "paged_searches", NULL };
	static const char *openldap_backend_modules[] = {
		"entryuuid", "paged_searches", NULL };

	static const char *samba_dsdb_attrs[] = { "backendType", "serverRole", NULL };
	const char *backendType, *serverRole;

	if (!tmp_ctx) {
		ldb_oom(ldb);
		return LDB_ERR_OPERATIONS_ERROR;
	}

	samba_dsdb_dn = ldb_dn_new(tmp_ctx, ldb, "@SAMBA_DSDB");
	if (!samba_dsdb_dn) {
		talloc_free(tmp_ctx);
		ldb_oom(ldb);
		return LDB_ERR_OPERATIONS_ERROR;
	}

#define CHECK_LDB_RET(check_ret)				\
	do {							\
		if (check_ret != LDB_SUCCESS) {			\
			talloc_free(tmp_ctx);			\
			return check_ret;			\
		}						\
	} while (0)

	ret = dsdb_module_search_dn(module, tmp_ctx, &res, samba_dsdb_dn, samba_dsdb_attrs, 0);
	if (ret == LDB_ERR_NO_SUCH_OBJECT) {
		backendType = "ldb";
		serverRole = "domain controller";
	} else if (ret == LDB_SUCCESS) {
		backendType = ldb_msg_find_attr_as_string(res->msgs[0], "backendType", "ldb");
		serverRole = ldb_msg_find_attr_as_string(res->msgs[0], "serverRole", "domain controller");
	} else {
		talloc_free(tmp_ctx);
		return ret;
	}

	backend_modules = NULL;
	if (strcasecmp(backendType, "ldb") == 0) {
		if (strcasecmp(serverRole, "dc") == 0 || strcasecmp(serverRole, "domain controller") == 0) {
			objectguid_module = repl_meta_data;
		} else {
			objectguid_module = objectguid;
		}
		extended_dn_module = extended_dn_module_ldb;
		link_modules = tdb_modules_list;
	} else {
		objectguid_module = NULL;
		link_modules = NULL;
		if (strcasecmp(backendType, "fedora-ds") == 0) {
			backend_modules = fedora_ds_backend_modules;
			extended_dn_module = extended_dn_module_fds;
		} else if (strcasecmp(backendType, "openldap") == 0) {
			backend_modules = openldap_backend_modules;
			extended_dn_module = extended_dn_module_openldap;
		}
	}

#define CHECK_MODULE_LIST \
	do {							\
		if (!final_module_list) {			\
			talloc_free(tmp_ctx);			\
			ldb_oom(ldb);				\
			return LDB_ERR_OPERATIONS_ERROR;	\
		}						\
	} while (0)

	final_module_list = str_list_copy_const(tmp_ctx, modules_list);
	CHECK_MODULE_LIST;

	final_module_list = str_list_add_const(final_module_list, objectguid_module);
	CHECK_MODULE_LIST;

	final_module_list = str_list_append_const(final_module_list, link_modules);
	CHECK_MODULE_LIST;

	final_module_list = str_list_add_const(final_module_list, extended_dn_module);
	CHECK_MODULE_LIST;

	final_module_list = str_list_append_const(final_module_list, modules_list2);
	CHECK_MODULE_LIST;


	ret = read_at_rootdse_record(ldb, module, tmp_ctx, &rootdse_msg);
	CHECK_LDB_RET(ret);

	partition_msg = ldb_msg_new(tmp_ctx);
	partition_msg->dn = ldb_dn_new(partition_msg, ldb, "@" DSDB_OPAQUE_PARTITION_MODULE_MSG_OPAQUE_NAME);

	ret = prepare_modules_line(ldb, tmp_ctx,
				   rootdse_msg,
				   partition_msg, "defaultNamingContext",
				   "pdc_fsmo", backend_modules);
	CHECK_LDB_RET(ret);

	ret = prepare_modules_line(ldb, tmp_ctx,
				   rootdse_msg,
				   partition_msg, "configurationNamingContext",
				   "naming_fsmo", backend_modules);
	CHECK_LDB_RET(ret);

	ret = prepare_modules_line(ldb, tmp_ctx,
				   rootdse_msg,
				   partition_msg, "schemaNamingContext",
				   "schema_data", backend_modules);
	CHECK_LDB_RET(ret);

	ret = prepare_modules_line(ldb, tmp_ctx,
				   rootdse_msg,
				   partition_msg, NULL,
				   NULL, backend_modules);
	CHECK_LDB_RET(ret);

	ret = ldb_set_opaque(ldb, DSDB_OPAQUE_PARTITION_MODULE_MSG_OPAQUE_NAME, partition_msg);
	CHECK_LDB_RET(ret);

	talloc_steal(ldb, partition_msg);

	/* Now prepare the module chain.  Oddly, we must give it to ldb_load_modules_list in REVERSE */
	for (len = 0; final_module_list[len]; len++) { /* noop */};

	reverse_module_list = talloc_array(tmp_ctx, const char *, len+1);
	if (!reverse_module_list) {
		talloc_free(tmp_ctx);
		ldb_oom(ldb);
		return LDB_ERR_OPERATIONS_ERROR;
	}
	for (i=0; i < len; i++) {
		reverse_module_list[i] = final_module_list[(len - 1) - i];
	}
	reverse_module_list[i] = NULL;

	/* The backend (at least until the partitions module
	 * reconfigures things) is the next module in the currently
	 * loaded chain */
	backend_module = module->next;
	ret = ldb_load_modules_list(ldb, reverse_module_list, backend_module, &module_chain);
	CHECK_LDB_RET(ret);

	talloc_free(tmp_ctx);
	/* Set this as the 'next' module, so that we effectivly append it to module chain */
	module->next = module_chain;

	return ldb_next_init(module);
}
Пример #7
0
/*
  construct the parent GUID for an entry from a message
*/
static int construct_parent_guid(struct ldb_module *module,
				 struct ldb_message *msg, enum ldb_scope scope,
				 struct ldb_request *parent)
{
	struct ldb_result *res, *parent_res;
	const struct ldb_val *parent_guid;
	const char *attrs[] = { "instanceType", NULL };
	const char *attrs2[] = { "objectGUID", NULL };
	uint32_t instanceType;
	int ret;
	struct ldb_dn *parent_dn;
	struct ldb_val v;

	/* determine if the object is NC by instance type */
	ret = dsdb_module_search_dn(module, msg, &res, msg->dn, attrs,
	                            DSDB_FLAG_NEXT_MODULE |
	                            DSDB_SEARCH_SHOW_RECYCLED, parent);
	if (ret != LDB_SUCCESS) {
		return ret;
	}

	instanceType = ldb_msg_find_attr_as_uint(res->msgs[0],
						 "instanceType", 0);
	talloc_free(res);
	if (instanceType & INSTANCE_TYPE_IS_NC_HEAD) {
		DEBUG(4,(__location__ ": Object %s is NC\n",
			 ldb_dn_get_linearized(msg->dn)));
		return LDB_SUCCESS;
	}
	parent_dn = ldb_dn_get_parent(msg, msg->dn);

	if (parent_dn == NULL) {
		DEBUG(4,(__location__ ": Failed to find parent for dn %s\n",
					 ldb_dn_get_linearized(msg->dn)));
		return LDB_SUCCESS;
	}
	ret = dsdb_module_search_dn(module, msg, &parent_res, parent_dn, attrs2,
	                            DSDB_FLAG_NEXT_MODULE |
	                            DSDB_SEARCH_SHOW_RECYCLED, parent);
	talloc_free(parent_dn);

	/* not NC, so the object should have a parent*/
	if (ret == LDB_ERR_NO_SUCH_OBJECT) {
		return ldb_error(ldb_module_get_ctx(module), LDB_ERR_OPERATIONS_ERROR, 
				 talloc_asprintf(msg, "Parent dn for %s does not exist", 
						 ldb_dn_get_linearized(msg->dn)));
	} else if (ret != LDB_SUCCESS) {
		return ret;
	}

	parent_guid = ldb_msg_find_ldb_val(parent_res->msgs[0], "objectGUID");
	if (!parent_guid) {
		talloc_free(parent_res);
		return LDB_SUCCESS;
	}

	v = data_blob_dup_talloc(parent_res, *parent_guid);
	if (!v.data) {
		talloc_free(parent_res);
		return ldb_oom(ldb_module_get_ctx(module));
	}
	ret = ldb_msg_add_steal_value(msg, "parentGUID", &v);
	talloc_free(parent_res);
	return ret;
}
Пример #8
0
/*
  called by DSDB_EXTENDED_ALLOCATE_RID_POOL extended operation in samldb
 */
int ridalloc_allocate_rid_pool_fsmo(struct ldb_module *module, struct dsdb_fsmo_extended_op *exop,
				    struct ldb_request *parent)
{
	struct ldb_dn *ntds_dn, *server_dn, *machine_dn, *rid_set_dn;
	struct ldb_dn *rid_manager_dn;
	TALLOC_CTX *tmp_ctx = talloc_new(module);
	int ret;
	struct ldb_context *ldb = ldb_module_get_ctx(module);
	struct ldb_result *res;
	struct ldb_message *msg;
	struct ridalloc_ridset_values oridset, nridset;

	ret = dsdb_module_dn_by_guid(module, tmp_ctx, &exop->destination_dsa_guid, &ntds_dn, parent);
	if (ret != LDB_SUCCESS) {
		ldb_asprintf_errstring(ldb, __location__ ": Unable to find NTDS object for guid %s - %s\n",
				       GUID_string(tmp_ctx, &exop->destination_dsa_guid), ldb_errstring(ldb));
		talloc_free(tmp_ctx);
		return ret;
	}

	server_dn = ldb_dn_get_parent(tmp_ctx, ntds_dn);
	if (!server_dn) {
		talloc_free(tmp_ctx);
		return ldb_module_oom(module);
	}

	ret = dsdb_module_reference_dn(module, tmp_ctx, server_dn, "serverReference", &machine_dn, parent);
	if (ret != LDB_SUCCESS) {
		ldb_asprintf_errstring(ldb, __location__ ": Failed to find serverReference in %s - %s",
				       ldb_dn_get_linearized(server_dn), ldb_errstring(ldb));
		talloc_free(tmp_ctx);
		return ret;
	}

	ret = dsdb_module_rid_manager_dn(module, tmp_ctx, &rid_manager_dn, parent);
	if (ret != LDB_SUCCESS) {
		ldb_asprintf_errstring(ldb, __location__ ": Failed to find RID Manager object - %s",
				       ldb_errstring(ldb));
		talloc_free(tmp_ctx);
		return ret;
	}

	ret = dsdb_module_reference_dn(module, tmp_ctx, machine_dn, "rIDSetReferences", &rid_set_dn, parent);
	if (ret == LDB_ERR_NO_SUCH_ATTRIBUTE) {
		ret = ridalloc_create_rid_set_ntds(module, tmp_ctx, rid_manager_dn, ntds_dn, &rid_set_dn, parent);
		talloc_free(tmp_ctx);
		return ret;
	}

	if (ret != LDB_SUCCESS) {
		ldb_asprintf_errstring(ldb, "Failed to find rIDSetReferences in %s - %s",
				       ldb_dn_get_linearized(machine_dn), ldb_errstring(ldb));
		talloc_free(tmp_ctx);
		return ret;
	}

	ret = dsdb_module_search_dn(module, tmp_ctx, &res, rid_set_dn,
				    ridalloc_ridset_attrs, DSDB_FLAG_NEXT_MODULE, parent);
	if (ret != LDB_SUCCESS) {
		ldb_asprintf_errstring(ldb, __location__ ": No RID Set %s",
				       ldb_dn_get_linearized(rid_set_dn));
		talloc_free(tmp_ctx);
		return ret;
	}

	ridalloc_get_ridset_values(res->msgs[0], &oridset);
	if (oridset.alloc_pool == UINT64_MAX) {
		ldb_asprintf_errstring(ldb, __location__ ": Bad RID Set %s",
				       ldb_dn_get_linearized(rid_set_dn));
		talloc_free(tmp_ctx);
		return LDB_ERR_OPERATIONS_ERROR;
	}

	nridset = oridset;

	if (exop->fsmo_info != 0) {

		if (nridset.alloc_pool != exop->fsmo_info) {
			/* it has already been updated */
			DEBUG(2,(__location__ ": rIDAllocationPool fsmo_info mismatch - already changed (0x%llx 0x%llx)\n",
				 (unsigned long long)exop->fsmo_info,
				 (unsigned long long)nridset.alloc_pool));
			talloc_free(tmp_ctx);
			return LDB_SUCCESS;
		}
	}

	/* grab a pool from the RID Manager object */
	ret = ridalloc_rid_manager_allocate(module, rid_manager_dn, &nridset.alloc_pool, parent);
	if (ret != LDB_SUCCESS) {
		talloc_free(tmp_ctx);
		return ret;
	}

	/*
	 * update the values
	 */
	msg = ldb_msg_new(tmp_ctx);
	if (msg == NULL) {
		return ldb_module_oom(module);
	}
	msg->dn = rid_set_dn;

	ret = ridalloc_set_ridset_values(module, msg,
					 &oridset, &nridset);
	if (ret != LDB_SUCCESS) {
		talloc_free(tmp_ctx);
		return ret;
	}

	ret = dsdb_module_modify(module, msg, DSDB_FLAG_NEXT_MODULE, parent);
	if (ret != LDB_SUCCESS) {
		ldb_asprintf_errstring(ldb, "Failed to modify RID Set object %s - %s",
				       ldb_dn_get_linearized(rid_set_dn), ldb_errstring(ldb));
		talloc_free(tmp_ctx);
		return ret;
	}

	talloc_free(tmp_ctx);
	return LDB_SUCCESS;
}
Пример #9
0
/* allocate a RID using our RID Set
   If we run out of RIDs then allocate a new pool
   either locally or by contacting the RID Manager
*/
int ridalloc_allocate_rid(struct ldb_module *module, uint32_t *rid, struct ldb_request *parent)
{
	struct ldb_context *ldb;
	int ret;
	struct ldb_dn *rid_set_dn;
	struct ldb_result *res;
	struct ldb_message *msg;
	struct ridalloc_ridset_values oridset;
	struct ridalloc_ridset_values nridset;
	uint32_t prev_pool_lo, prev_pool_hi;
	TALLOC_CTX *tmp_ctx = talloc_new(module);

	(*rid) = 0;
	ldb = ldb_module_get_ctx(module);

	ret = samdb_rid_set_dn(ldb, tmp_ctx, &rid_set_dn);
	if (ret == LDB_ERR_NO_SUCH_ATTRIBUTE) {
		ret = ridalloc_create_own_rid_set(module, tmp_ctx, &rid_set_dn, parent);
	}
	if (ret != LDB_SUCCESS) {
		ldb_asprintf_errstring(ldb, __location__ ": No RID Set DN - %s",
				       ldb_errstring(ldb));
		talloc_free(tmp_ctx);
		return ret;
	}

	ret = dsdb_module_search_dn(module, tmp_ctx, &res, rid_set_dn,
				    ridalloc_ridset_attrs, DSDB_FLAG_NEXT_MODULE, parent);
	if (ret != LDB_SUCCESS) {
		ldb_asprintf_errstring(ldb, __location__ ": No RID Set %s",
				       ldb_dn_get_linearized(rid_set_dn));
		talloc_free(tmp_ctx);
		return ret;
	}

	ridalloc_get_ridset_values(res->msgs[0], &oridset);
	if (oridset.alloc_pool == UINT64_MAX) {
		ldb_asprintf_errstring(ldb, __location__ ": Bad RID Set %s",
				       ldb_dn_get_linearized(rid_set_dn));
		talloc_free(tmp_ctx);
		return LDB_ERR_OPERATIONS_ERROR;
	}

	nridset = oridset;

	/*
	 * If we never used a pool, setup out first pool
	 */
	if (nridset.prev_pool == UINT64_MAX ||
	    nridset.next_rid == UINT32_MAX) {
		nridset.prev_pool = nridset.alloc_pool;
		nridset.next_rid = nridset.prev_pool & 0xFFFFFFFF;
	}

	/*
	 * Now check if our current pool is still usable
	 */
	nridset.next_rid += 1;
	prev_pool_lo = nridset.prev_pool & 0xFFFFFFFF;
	prev_pool_hi = nridset.prev_pool >> 32;
	if (nridset.next_rid > prev_pool_hi) {
		/*
		 * We need a new pool, check if we already have a new one
		 * Otherwise we need to get a new pool.
		 */
		if (nridset.alloc_pool == nridset.prev_pool) {
			/*
			 * if we are the RID Manager,
			 * we can get a new pool localy.
			 * Otherwise we fail the operation and
			 * ask async for a new pool.
			 */
			ret = ridalloc_new_own_pool(module, &nridset.alloc_pool, parent);
			if (ret == LDB_ERR_UNWILLING_TO_PERFORM) {
				ridalloc_poke_rid_manager(module);
				talloc_free(tmp_ctx);
				return ret;
			}
			if (ret != LDB_SUCCESS) {
				talloc_free(tmp_ctx);
				return ret;
			}
		}

		/*
		 * increment the rIDUsedPool attribute
		 *
		 * Note: w2k8r2 doesn't update this attribute,
		 *       at least if it's itself the rid master.
		 */
		nridset.used_pool += 1;

		/* now use the new pool */
		nridset.prev_pool = nridset.alloc_pool;
		prev_pool_lo = nridset.prev_pool & 0xFFFFFFFF;
		prev_pool_hi = nridset.prev_pool >> 32;
		nridset.next_rid = prev_pool_lo;
	}

	if (nridset.next_rid < prev_pool_lo || nridset.next_rid > prev_pool_hi) {
		ldb_asprintf_errstring(ldb, __location__ ": Bad rid chosen %u from range %u-%u",
				       (unsigned)nridset.next_rid,
				       (unsigned)prev_pool_lo,
				       (unsigned)prev_pool_hi);
		talloc_free(tmp_ctx);
		return LDB_ERR_OPERATIONS_ERROR;
	}

	/*
	 * if we are half-exhausted then try to get a new pool.
	 */
	if (nridset.next_rid > (prev_pool_hi + prev_pool_lo)/2) {
		/*
		 * if we are the RID Manager,
		 * we can get a new pool localy.
		 * Otherwise we fail the operation and
		 * ask async for a new pool.
		 */
		ret = ridalloc_new_own_pool(module, &nridset.alloc_pool, parent);
		if (ret == LDB_ERR_UNWILLING_TO_PERFORM) {
			ridalloc_poke_rid_manager(module);
			ret = LDB_SUCCESS;
		}
		if (ret != LDB_SUCCESS) {
			talloc_free(tmp_ctx);
			return ret;
		}
	}

	/*
	 * update the values
	 */
	msg = ldb_msg_new(tmp_ctx);
	if (msg == NULL) {
		return ldb_module_oom(module);
	}
	msg->dn = rid_set_dn;

	ret = ridalloc_set_ridset_values(module, msg,
					 &oridset, &nridset);
	if (ret != LDB_SUCCESS) {
		talloc_free(tmp_ctx);
		return ret;
	}

	ret = dsdb_module_modify(module, msg, DSDB_FLAG_NEXT_MODULE, parent);
	if (ret != LDB_SUCCESS) {
		talloc_free(tmp_ctx);
		return ret;
	}

	talloc_free(tmp_ctx);
	*rid = nridset.next_rid;
	return LDB_SUCCESS;
}
Пример #10
0
/* allocate a RID using our RID Set
   If we run out of RIDs then allocate a new pool
   either locally or by contacting the RID Manager
*/
int ridalloc_allocate_rid(struct ldb_module *module, uint32_t *rid)
{
	struct ldb_context *ldb;
	static const char * const attrs[] = { "rIDAllocationPool", "rIDPreviousAllocationPool",
					      "rIDNextRID" , "rIDUsedPool", NULL };
	int ret;
	struct ldb_dn *rid_set_dn;
	struct ldb_result *res;
	uint64_t alloc_pool, prev_alloc_pool;
	uint32_t prev_alloc_pool_lo, prev_alloc_pool_hi;
	uint32_t rid_used_pool;
	int prev_rid;
	TALLOC_CTX *tmp_ctx = talloc_new(module);

	(*rid) = 0;
	ldb = ldb_module_get_ctx(module);

	ret = samdb_rid_set_dn(ldb, tmp_ctx, &rid_set_dn);
	if (ret == LDB_ERR_NO_SUCH_ATTRIBUTE) {
		ret = ridalloc_create_own_rid_set(module, tmp_ctx, &rid_set_dn);
	}
	if (ret != LDB_SUCCESS) {
		ldb_asprintf_errstring(ldb, __location__ ": No RID Set DN - %s",
				       ldb_errstring(ldb));
		talloc_free(tmp_ctx);
		return ret;
	}

	ret = dsdb_module_search_dn(module, tmp_ctx, &res, rid_set_dn, attrs, 0);
	if (ret != LDB_SUCCESS) {
		ldb_asprintf_errstring(ldb, __location__ ": No RID Set %s",
				       ldb_dn_get_linearized(rid_set_dn));
		talloc_free(tmp_ctx);
		return ret;
	}

	prev_alloc_pool = ldb_msg_find_attr_as_uint64(res->msgs[0], "rIDPreviousAllocationPool", 0);
	alloc_pool = ldb_msg_find_attr_as_uint64(res->msgs[0], "rIDAllocationPool", 0);
	prev_rid = ldb_msg_find_attr_as_int(res->msgs[0], "rIDNextRID", 0);
	rid_used_pool = ldb_msg_find_attr_as_int(res->msgs[0], "rIDUsedPool", 0);
	if (alloc_pool == 0) {
		ldb_asprintf_errstring(ldb, __location__ ": Bad RID Set %s",
				       ldb_dn_get_linearized(rid_set_dn));
		talloc_free(tmp_ctx);
		return LDB_ERR_OPERATIONS_ERROR;
	}

	prev_alloc_pool_lo = prev_alloc_pool & 0xFFFFFFFF;
	prev_alloc_pool_hi = prev_alloc_pool >> 32;
	if (prev_rid >= prev_alloc_pool_hi) {
		if (prev_alloc_pool == 0) {
			ret = dsdb_module_set_integer(module, rid_set_dn, "rIDPreviousAllocationPool", alloc_pool);
		} else {
			ret = dsdb_module_constrainted_update_integer(module, rid_set_dn, "rIDPreviousAllocationPool",
								      prev_alloc_pool, alloc_pool);
		}
		if (ret != LDB_SUCCESS) {
			ldb_asprintf_errstring(ldb, __location__ ": Failed to update rIDPreviousAllocationPool on %s - %s",
					       ldb_dn_get_linearized(rid_set_dn), ldb_errstring(ldb));
			talloc_free(tmp_ctx);
			return ret;
		}
		prev_alloc_pool = alloc_pool;
		prev_alloc_pool_lo = prev_alloc_pool & 0xFFFFFFFF;
		prev_alloc_pool_hi = prev_alloc_pool >> 32;

		/* update the rIDUsedPool attribute */
		ret = dsdb_module_set_integer(module, rid_set_dn, "rIDUsedPool", rid_used_pool+1);
		if (ret != LDB_SUCCESS) {
			ldb_asprintf_errstring(ldb, __location__ ": Failed to update rIDUsedPool on %s - %s",
					       ldb_dn_get_linearized(rid_set_dn), ldb_errstring(ldb));
			talloc_free(tmp_ctx);
			return ret;
		}

		(*rid) = prev_alloc_pool_lo;
	}

	/* see if we are still out of RIDs, and if so then ask
	   the RID Manager to give us more */
	if (prev_rid >= prev_alloc_pool_hi) {
		uint64_t new_pool;
		ret = ridalloc_refresh_own_pool(module, &new_pool);
		if (ret != LDB_SUCCESS) {
			return ret;
		}
		ret = dsdb_module_constrainted_update_integer(module, rid_set_dn, "rIDPreviousAllocationPool",
							      prev_alloc_pool, new_pool);
		if (ret != LDB_SUCCESS) {
			ldb_asprintf_errstring(ldb, __location__ ": Failed to update rIDPreviousAllocationPool on %s - %s",
					       ldb_dn_get_linearized(rid_set_dn), ldb_errstring(ldb));
			talloc_free(tmp_ctx);
			return ret;
		}
		prev_alloc_pool = new_pool;
		prev_alloc_pool_lo = prev_alloc_pool & 0xFFFFFFFF;
		prev_alloc_pool_hi = prev_alloc_pool >> 32;
		(*rid) = prev_alloc_pool_lo;
	} else {
Пример #11
0
/*
  create a RID Set object for the specified DC
 */
static int ridalloc_create_rid_set_ntds(struct ldb_module *module, TALLOC_CTX *mem_ctx,
					struct ldb_dn *rid_manager_dn,
					struct ldb_dn *ntds_dn, struct ldb_dn **dn,
					struct ldb_request *parent)
{
	TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
	struct ldb_dn *server_dn, *machine_dn, *rid_set_dn;
	int ret;
	struct ldb_message *msg;
	struct ldb_context *ldb = ldb_module_get_ctx(module);
	static const struct ridalloc_ridset_values o = {
		.alloc_pool	= UINT64_MAX,
		.prev_pool	= UINT64_MAX,
		.next_rid	= UINT32_MAX,
		.used_pool	= UINT32_MAX,
	};
	struct ridalloc_ridset_values n = {
		.alloc_pool	= 0,
		.prev_pool	= 0,
		.next_rid	= 0,
		.used_pool	= 0,
	};
	const char *no_attrs[] = { NULL };
	struct ldb_result *res;

	/*
	  steps:

	  find the machine object for the DC
	  construct the RID Set DN
	  load rIDAvailablePool to find next available set
	  modify RID Manager object to update rIDAvailablePool
	  add the RID Set object
	  link to the RID Set object in machine object
	 */

	server_dn = ldb_dn_get_parent(tmp_ctx, ntds_dn);
	if (!server_dn) {
		talloc_free(tmp_ctx);
		return ldb_module_oom(module);
	}

	ret = dsdb_module_reference_dn(module, tmp_ctx, server_dn, "serverReference", &machine_dn, parent);
	if (ret != LDB_SUCCESS) {
		ldb_asprintf_errstring(ldb, "Failed to find serverReference in %s - %s",
				       ldb_dn_get_linearized(server_dn), ldb_errstring(ldb));
		talloc_free(tmp_ctx);
		return ret;
	}

	rid_set_dn = ldb_dn_copy(tmp_ctx, machine_dn);
	if (rid_set_dn == NULL) {
		talloc_free(tmp_ctx);
		return ldb_module_oom(module);
	}

	if (! ldb_dn_add_child_fmt(rid_set_dn, "CN=RID Set")) {
		talloc_free(tmp_ctx);
		return ldb_module_oom(module);
	}

	/* grab a pool from the RID Manager object */
	ret = ridalloc_rid_manager_allocate(module, rid_manager_dn, &n.alloc_pool, parent);
	if (ret != LDB_SUCCESS) {
		talloc_free(tmp_ctx);
		return ret;
	}

	/* create the RID Set object */
	msg = ldb_msg_new(tmp_ctx);
	msg->dn = rid_set_dn;

	ret = ldb_msg_add_string(msg, "objectClass", "rIDSet");
	if (ret != LDB_SUCCESS) {
		talloc_free(tmp_ctx);
		return ret;
	}

	ret = ridalloc_set_ridset_values(module, msg, &o, &n);
	if (ret != LDB_SUCCESS) {
		talloc_free(tmp_ctx);
		return ret;
	}

	/* we need this to go all the way to the top of the module
	 * stack, as we need all the extra attributes added (including
	 * complex ones like ntsecuritydescriptor).  We must do this
	 * as system, otherwise a user might end up owning the RID
	 * set, and that would be bad... */
	ret = dsdb_module_add(module, msg,
			      DSDB_FLAG_TOP_MODULE | DSDB_FLAG_AS_SYSTEM
			      | DSDB_MODIFY_RELAX, parent);
	if (ret != LDB_SUCCESS) {
		ldb_asprintf_errstring(ldb, "Failed to add RID Set %s - %s",
				       ldb_dn_get_linearized(msg->dn),
				       ldb_errstring(ldb));
		talloc_free(tmp_ctx);
		return ret;
	}

	/* add the rIDSetReferences link */
	msg = ldb_msg_new(tmp_ctx);
	msg->dn = machine_dn;

	/* we need the extended DN of the RID Set object for
	 * rIDSetReferences */
	ret = dsdb_module_search_dn(module, msg, &res, rid_set_dn, no_attrs,
				    DSDB_FLAG_NEXT_MODULE | DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT, parent);
	if (ret != LDB_SUCCESS) {
		ldb_asprintf_errstring(ldb, "Failed to find extended DN of RID Set %s - %s",
				       ldb_dn_get_linearized(msg->dn),
				       ldb_errstring(ldb));
		talloc_free(tmp_ctx);
		return ret;
	}
	rid_set_dn = res->msgs[0]->dn;


	ret = ldb_msg_add_string(msg, "rIDSetReferences", ldb_dn_get_extended_linearized(msg, rid_set_dn, 1));
	if (ret != LDB_SUCCESS) {
		talloc_free(tmp_ctx);
		return ret;
	}
	msg->elements[0].flags = LDB_FLAG_MOD_ADD;

	ret = dsdb_module_modify(module, msg, DSDB_FLAG_NEXT_MODULE, parent);
	if (ret != LDB_SUCCESS) {
		ldb_asprintf_errstring(ldb, "Failed to add rIDSetReferences to %s - %s",
				       ldb_dn_get_linearized(msg->dn),
				       ldb_errstring(ldb));
		talloc_free(tmp_ctx);
		return ret;
	}

	(*dn) = talloc_steal(mem_ctx, rid_set_dn);

	talloc_free(tmp_ctx);
	return LDB_SUCCESS;
}


/*
  create a RID Set object for this DC
 */
int ridalloc_create_own_rid_set(struct ldb_module *module, TALLOC_CTX *mem_ctx,
				struct ldb_dn **dn, struct ldb_request *parent)
{
	TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
	struct ldb_dn *rid_manager_dn, *fsmo_role_dn;
	int ret;
	struct ldb_context *ldb = ldb_module_get_ctx(module);
	struct GUID fsmo_role_guid;
	const struct GUID *our_ntds_guid;
	NTSTATUS status;

	/* work out who is the RID Manager */
	ret = dsdb_module_rid_manager_dn(module, tmp_ctx, &rid_manager_dn, parent);
	if (ret != LDB_SUCCESS) {
		ldb_asprintf_errstring(ldb, "Failed to find RID Manager object - %s",
				       ldb_errstring(ldb));
		talloc_free(tmp_ctx);
		return ret;
	}

	/* find the DN of the RID Manager */
	ret = dsdb_module_reference_dn(module, tmp_ctx, rid_manager_dn, "fSMORoleOwner", &fsmo_role_dn, parent);
	if (ret != LDB_SUCCESS) {
		ldb_asprintf_errstring(ldb, "Failed to find fSMORoleOwner in RID Manager object - %s",
				       ldb_errstring(ldb));
		talloc_free(tmp_ctx);
		return ret;
	}

	status = dsdb_get_extended_dn_guid(fsmo_role_dn, &fsmo_role_guid, "GUID");
	if (!NT_STATUS_IS_OK(status)) {
		talloc_free(tmp_ctx);
		return ldb_operr(ldb_module_get_ctx(module));
	}

	our_ntds_guid = samdb_ntds_objectGUID(ldb_module_get_ctx(module));
	if (!our_ntds_guid) {
		talloc_free(tmp_ctx);
		return ldb_operr(ldb_module_get_ctx(module));
	}

	if (!GUID_equal(&fsmo_role_guid, our_ntds_guid)) {
		ret = ridalloc_poke_rid_manager(module);
		if (ret != LDB_SUCCESS) {
			ldb_asprintf_errstring(ldb,
					"Request for remote creation of "
					"RID Set for this DC failed: %s",
					ldb_errstring(ldb));
		} else {
			ldb_asprintf_errstring(ldb,
					"Remote RID Set creation needed");
		}
		talloc_free(tmp_ctx);
		return LDB_ERR_UNWILLING_TO_PERFORM;
	}

	ret = ridalloc_create_rid_set_ntds(module, mem_ctx, rid_manager_dn, fsmo_role_dn, dn, parent);
	talloc_free(tmp_ctx);
	return ret;
}