/*
 * Attempt to modify an objectSID DSDB_CONTROL_REPLICATED_UPDATE_OID set
 * this should succeed
 */
static void test_modify_of_objectSID_replicated(void **state)
{
	struct ldbtest_ctx *test_ctx =
		talloc_get_type_abort(*state, struct ldbtest_ctx);
	struct ldb_context *ldb 		= test_ctx->ldb;
	struct ldb_message *msg			= ldb_msg_new(test_ctx);
	struct ldb_message_element *el		= NULL;
	struct ldb_request *request		= NULL;
	struct ldb_request *original_request	= NULL;
	int rc;

	msg->dn = ldb_dn_new(msg, ldb, "dc=test");
	add_sid(msg, LOCAL_SID);

	rc = ldb_build_mod_req(
		&request,
		test_ctx->ldb,
		test_ctx,
		msg,
		NULL,
		NULL,
		ldb_op_default_callback,
		NULL);
	assert_int_equal(rc, LDB_SUCCESS);
	assert_non_null(request);
	original_request = request;

	rc = ldb_request_add_control(
		request,
		DSDB_CONTROL_REPLICATED_UPDATE_OID,
		false,
		NULL);
	assert_int_equal(rc, LDB_SUCCESS);

	rc = unique_object_sids_modify(test_ctx->module, request);

	assert_int_equal(rc, LDB_SUCCESS);

	/*
	 * Check that a copy of the request was passed to the next module
	 * and not the original request
	 */
	assert_ptr_not_equal(last_request, original_request);

	/*
	 * Check the flag was set on the request passed to the next
	 * module
	 */
	el = ldb_msg_find_element(last_request->op.add.message, "objectSID");
	assert_non_null(el);
	assert_true(el->flags & LDB_FLAG_INTERNAL_FORCE_UNIQUE_INDEX);

	/*
	 * Check the flag was not  set on the original request
	 */
	el = ldb_msg_find_element(request->op.add.message, "objectSID");
	assert_non_null(el);
	assert_false(el->flags & LDB_FLAG_INTERNAL_FORCE_UNIQUE_INDEX);

}
/*
 * Attempt to modify an objectSID DSDB_CONTROL_REPLICATED_UPDATE_OID not set
 * this should fail with LDB_ERR_UNWILLING_TO_PERFORM
 */
static void test_modify_of_objectSID_not_replicated(void **state)
{
	struct ldbtest_ctx *test_ctx =
		talloc_get_type_abort(*state, struct ldbtest_ctx);
	struct ldb_context *ldb 		= test_ctx->ldb;
	struct ldb_message *msg			= ldb_msg_new(test_ctx);
	struct ldb_request *request		= NULL;
	int rc;

	msg->dn = ldb_dn_new(msg, ldb, "dc=test");
	add_sid(msg, LOCAL_SID);

	rc = ldb_build_mod_req(
		&request,
		test_ctx->ldb,
		test_ctx,
		msg,
		NULL,
		NULL,
		ldb_op_default_callback,
		NULL);

	assert_int_equal(rc, LDB_SUCCESS);
	assert_non_null(request);

	rc = unique_object_sids_modify(test_ctx->module, request);

	assert_int_equal(rc, LDB_ERR_UNWILLING_TO_PERFORM);
}
Example #3
0
/* Modify the local record. */
static int map_modify_do_local(struct map_context *ac)
{
	struct ldb_request *local_req;
	struct ldb_context *ldb;
	int ret;

	ldb = ldb_module_get_ctx(ac->module);

	if (ac->local_dn == NULL) {
		/* No local record present, add it instead */
		/* Add local 'IS_MAPPED' */
		/* TODO: use GUIDs here instead */
		if (ldb_msg_add_empty(ac->local_msg, IS_MAPPED,
					LDB_FLAG_MOD_ADD, NULL) != 0) {
			return LDB_ERR_OPERATIONS_ERROR;
		}
		ret = ldb_msg_add_linearized_dn(ac->local_msg, IS_MAPPED,
						ac->remote_req->op.mod.message->dn);
		if (ret != 0) {
			return LDB_ERR_OPERATIONS_ERROR;
		}

		/* Prepare the local operation */
		ret = ldb_build_add_req(&local_req, ldb, ac,
					ac->local_msg,
					ac->req->controls,
					ac,
					map_op_local_callback,
					ac->req);
		LDB_REQ_SET_LOCATION(local_req);
		if (ret != LDB_SUCCESS) {
			return LDB_ERR_OPERATIONS_ERROR;
		}
	} else {
		/* Prepare the local operation */
		ret = ldb_build_mod_req(&local_req, ldb, ac,
					ac->local_msg,
					ac->req->controls,
					ac,
					map_op_local_callback,
					ac->req);
		LDB_REQ_SET_LOCATION(local_req);
		if (ret != LDB_SUCCESS) {
			return LDB_ERR_OPERATIONS_ERROR;
		}
	}

	return ldb_next_request(ac->module, local_req);
}
/*
 * Test the a modify with no object SID is passed through correctly
 *
 */
static void test_modify_no_objectSID(void **state)
{
	struct ldbtest_ctx *test_ctx =
		talloc_get_type_abort(*state, struct ldbtest_ctx);
	struct ldb_context *ldb			= test_ctx->ldb;
	struct ldb_message *msg			= ldb_msg_new(test_ctx);
	struct ldb_request *request		= NULL;
	struct ldb_request *original_request	= NULL;
	int rc;

	msg->dn = ldb_dn_new(msg, ldb, "dc=test");
	assert_int_equal(LDB_SUCCESS, ldb_msg_add_string(msg, "cn", "test"));

	rc = ldb_build_mod_req(
		&request,
		test_ctx->ldb,
		test_ctx,
		msg,
		NULL,
		NULL,
		ldb_op_default_callback,
		NULL);

	assert_int_equal(rc, LDB_SUCCESS);
	assert_non_null(request);
	original_request = request;

	rc = unique_object_sids_modify(test_ctx->module, request);
	assert_int_equal(rc, LDB_SUCCESS);

	/*
	 * Check that the original request was passed to the next module
	 * and not a copy
	 */
	assert_ptr_equal(last_request, original_request);

}
Example #5
0
/**
 * Commits a list of replicated objects.
 *
 * @param working_schema dsdb_schema to be used for resolving
 * 			 Classes/Attributes during Schema replication. If not NULL,
 * 			 it will be set on ldb and used while committing replicated objects
 */
WERROR dsdb_replicated_objects_commit(struct ldb_context *ldb,
				      struct dsdb_schema *working_schema,
				      struct dsdb_extended_replicated_objects *objects,
				      uint64_t *notify_uSN)
{
	WERROR werr;
	struct ldb_result *ext_res;
	struct dsdb_schema *cur_schema = NULL;
	struct dsdb_schema *new_schema = NULL;
	int ret;
	uint64_t seq_num1, seq_num2;
	bool used_global_schema = false;

	TALLOC_CTX *tmp_ctx = talloc_new(objects);
	if (!tmp_ctx) {
		DEBUG(0,("Failed to start talloc\n"));
		return WERR_NOMEM;
	}

	/* TODO: handle linked attributes */

	/* wrap the extended operation in a transaction 
	   See [MS-DRSR] 3.3.2 Transactions
	 */
	ret = ldb_transaction_start(ldb);
	if (ret != LDB_SUCCESS) {
		DEBUG(0,(__location__ " Failed to start transaction\n"));
		return WERR_FOOBAR;
	}

	ret = dsdb_load_partition_usn(ldb, objects->partition_dn, &seq_num1, NULL);
	if (ret != LDB_SUCCESS) {
		DEBUG(0,(__location__ " Failed to load partition uSN\n"));
		ldb_transaction_cancel(ldb);
		TALLOC_FREE(tmp_ctx);
		return WERR_FOOBAR;		
	}

	/*
	 * Set working_schema for ldb in case we are replicating from Schema NC.
	 * Schema won't be reloaded during Replicated Objects commit, as it is
	 * done in a transaction. So we need some way to search for newly
	 * added Classes and Attributes
	 */
	if (working_schema) {
		/* store current schema so we can fall back in case of failure */
		cur_schema = dsdb_get_schema(ldb, tmp_ctx);
		used_global_schema = dsdb_uses_global_schema(ldb);

		ret = dsdb_reference_schema(ldb, working_schema, false);
		if (ret != LDB_SUCCESS) {
			DEBUG(0,(__location__ "Failed to reference working schema - %s\n",
				 ldb_strerror(ret)));
			/* TODO: Map LDB Error to NTSTATUS? */
			ldb_transaction_cancel(ldb);
			TALLOC_FREE(tmp_ctx);
			return WERR_INTERNAL_ERROR;
		}
	}

	ret = ldb_extended(ldb, DSDB_EXTENDED_REPLICATED_OBJECTS_OID, objects, &ext_res);
	if (ret != LDB_SUCCESS) {
		/* restore previous schema */
		if (used_global_schema) { 
			dsdb_set_global_schema(ldb);
		} else if (cur_schema) {
			dsdb_reference_schema(ldb, cur_schema, false);
		}

		DEBUG(0,("Failed to apply records: %s: %s\n",
			 ldb_errstring(ldb), ldb_strerror(ret)));
		ldb_transaction_cancel(ldb);
		TALLOC_FREE(tmp_ctx);
		return WERR_FOOBAR;
	}
	talloc_free(ext_res);

	/* Save our updated prefixMap */
	if (working_schema) {
		werr = dsdb_write_prefixes_from_schema_to_ldb(working_schema,
							      ldb,
							      working_schema);
		if (!W_ERROR_IS_OK(werr)) {
			/* restore previous schema */
			if (used_global_schema) { 
				dsdb_set_global_schema(ldb);
			} else if (cur_schema ) {
				dsdb_reference_schema(ldb, cur_schema, false);
			}
			DEBUG(0,("Failed to save updated prefixMap: %s\n",
				 win_errstr(werr)));
			TALLOC_FREE(tmp_ctx);
			return werr;
		}
	}

	ret = ldb_transaction_prepare_commit(ldb);
	if (ret != LDB_SUCCESS) {
		/* restore previous schema */
		if (used_global_schema) { 
			dsdb_set_global_schema(ldb);
		} else if (cur_schema ) {
			dsdb_reference_schema(ldb, cur_schema, false);
		}
		DEBUG(0,(__location__ " Failed to prepare commit of transaction: %s\n",
			 ldb_errstring(ldb)));
		TALLOC_FREE(tmp_ctx);
		return WERR_FOOBAR;
	}

	ret = dsdb_load_partition_usn(ldb, objects->partition_dn, &seq_num2, NULL);
	if (ret != LDB_SUCCESS) {
		/* restore previous schema */
		if (used_global_schema) { 
			dsdb_set_global_schema(ldb);
		} else if (cur_schema ) {
			dsdb_reference_schema(ldb, cur_schema, false);
		}
		DEBUG(0,(__location__ " Failed to load partition uSN\n"));
		ldb_transaction_cancel(ldb);
		TALLOC_FREE(tmp_ctx);
		return WERR_FOOBAR;		
	}

	ret = ldb_transaction_commit(ldb);
	if (ret != LDB_SUCCESS) {
		/* restore previous schema */
		if (used_global_schema) { 
			dsdb_set_global_schema(ldb);
		} else if (cur_schema ) {
			dsdb_reference_schema(ldb, cur_schema, false);
		}
		DEBUG(0,(__location__ " Failed to commit transaction\n"));
		TALLOC_FREE(tmp_ctx);
		return WERR_FOOBAR;
	}

	/* if this replication partner didn't need to be notified
	   before this transaction then it still doesn't need to be
	   notified, as the changes came from this server */
	if (seq_num2 > seq_num1 && seq_num1 <= *notify_uSN) {
		*notify_uSN = seq_num2;
	}

	/*
	 * Reset the Schema used by ldb. This will lead to
	 * a schema cache being refreshed from database.
	 */
	if (working_schema) {
		struct ldb_message *msg;
		struct ldb_request *req;

		/* Force a reload */
		working_schema->last_refresh = 0;
		new_schema = dsdb_get_schema(ldb, tmp_ctx);
		/* TODO: 
		 * If dsdb_get_schema() fails, we just fall back
		 * to what we had.  However, the database is probably
		 * unable to operate for other users from this
		 * point... */
		if (new_schema && used_global_schema) {
			dsdb_make_schema_global(ldb, new_schema);
		} else if (used_global_schema) { 
			DEBUG(0,("Failed to re-load schema after commit of transaction\n"));
			dsdb_set_global_schema(ldb);
			TALLOC_FREE(tmp_ctx);
			return WERR_INTERNAL_ERROR;
		} else {
			DEBUG(0,("Failed to re-load schema after commit of transaction\n"));
			dsdb_reference_schema(ldb, cur_schema, false);
			TALLOC_FREE(tmp_ctx);
			return WERR_INTERNAL_ERROR;
		}
		msg = ldb_msg_new(tmp_ctx);
		if (msg == NULL) {
			TALLOC_FREE(tmp_ctx);
			return WERR_NOMEM;
		}
		msg->dn = ldb_dn_new(msg, ldb, "");
		if (msg->dn == NULL) {
			TALLOC_FREE(tmp_ctx);
			return WERR_NOMEM;
		}

		ret = ldb_msg_add_string(msg, "schemaUpdateNow", "1");
		if (ret != LDB_SUCCESS) {
			TALLOC_FREE(tmp_ctx);
			return WERR_INTERNAL_ERROR;
		}

		ret = ldb_build_mod_req(&req, ldb, objects,
				msg,
				NULL,
				NULL,
				ldb_op_default_callback,
				NULL);

		if (ret != LDB_SUCCESS) {
			TALLOC_FREE(tmp_ctx);
			return WERR_DS_DRA_INTERNAL_ERROR;
		}

		ret = ldb_transaction_start(ldb);
		if (ret != LDB_SUCCESS) {
			TALLOC_FREE(tmp_ctx);
			DEBUG(0, ("Autotransaction start failed\n"));
			return WERR_DS_DRA_INTERNAL_ERROR;
		}

		ret = ldb_request(ldb, req);
		if (ret == LDB_SUCCESS) {
			ret = ldb_wait(req->handle, LDB_WAIT_ALL);
		}

		if (ret == LDB_SUCCESS) {
			ret = ldb_transaction_commit(ldb);
		} else {
			DEBUG(0, ("Schema update now failed: %s\n",
				  ldb_errstring(ldb)));
			ldb_transaction_cancel(ldb);
		}

		if (ret != LDB_SUCCESS) {
			DEBUG(0, ("Commit failed: %s\n", ldb_errstring(ldb)));
			TALLOC_FREE(tmp_ctx);
			return WERR_DS_INTERNAL_FAILURE;
		}
	}

	DEBUG(2,("Replicated %u objects (%u linked attributes) for %s\n",
		 objects->num_objects, objects->linked_attributes_count,
		 ldb_dn_get_linearized(objects->partition_dn)));
		 
	TALLOC_FREE(tmp_ctx);
	return WERR_OK;
}
Example #6
0
static int rdn_rename_callback(struct ldb_request *req, struct ldb_reply *ares)
{
	struct ldb_context *ldb;
	struct rename_context *ac;
	struct ldb_request *mod_req;
	const char *rdn_name;
	struct ldb_val rdn_val;
	struct ldb_message *msg;
	int ret;

	ac = talloc_get_type(req->context, struct rename_context);
	ldb = ldb_module_get_ctx(ac->module);

	if (!ares) {
		goto error;
	}
	if (ares->error != LDB_SUCCESS) {
		return ldb_module_done(ac->req, ares->controls,
					ares->response, ares->error);
	}

	/* the only supported reply right now is a LDB_REPLY_DONE */
	if (ares->type != LDB_REPLY_DONE) {
		goto error;
	}

	/* save reply for caller */
	ac->ares = talloc_steal(ac, ares);

	msg = ldb_msg_new(ac);
	if (msg == NULL) {
		goto error;
	}
	msg->dn = ldb_dn_copy(msg, ac->req->op.rename.newdn);
	if (msg->dn == NULL) {
		goto error;
	}
	rdn_name = ldb_dn_get_rdn_name(ac->req->op.rename.newdn);
	if (rdn_name == NULL) {
		goto error;
	}
	
	rdn_val = ldb_val_dup(msg, ldb_dn_get_rdn_val(ac->req->op.rename.newdn));
	
	if (ldb_msg_add_empty(msg, rdn_name, LDB_FLAG_MOD_REPLACE, NULL) != 0) {
		goto error;
	}
	if (ldb_msg_add_value(msg, rdn_name, &rdn_val, NULL) != 0) {
		goto error;
	}
	if (ldb_msg_add_empty(msg, "name", LDB_FLAG_MOD_REPLACE, NULL) != 0) {
		goto error;
	}
	if (ldb_msg_add_value(msg, "name", &rdn_val, NULL) != 0) {
		goto error;
	}

	ret = ldb_build_mod_req(&mod_req, ldb,
				ac, msg, NULL,
				ac, rdn_modify_callback,
				req);
	if (ret != LDB_SUCCESS) {
		return ldb_module_done(ac->req, NULL, NULL, ret);
	}
	talloc_steal(mod_req, msg);

	/* go on with the call chain */
	return ldb_next_request(ac->module, mod_req);

error:
	return ldb_module_done(ac->req, NULL, NULL,
						 LDB_ERR_OPERATIONS_ERROR);
}
Example #7
0
/* Modify a record. */
int ldb_map_modify(struct ldb_module *module, struct ldb_request *req)
{
	const struct ldb_message *msg = req->op.mod.message;
	struct ldb_request *search_req = NULL;
	struct ldb_message *remote_msg;
	struct ldb_context *ldb;
	struct map_context *ac;
	int ret;

	ldb = ldb_module_get_ctx(module);

	/* Do not manipulate our control entries */
	if (ldb_dn_is_special(msg->dn)) {
		return ldb_next_request(module, req);
	}

	/* No mapping requested (perhaps no DN mapping specified), skip to next module */
	if (!ldb_dn_check_local(module, msg->dn)) {
		return ldb_next_request(module, req);
	}

	/* No mapping needed, skip to next module */
	/* TODO: What if the remote part exists, the local doesn't,
	 *	 and this request wants to modify local data and thus
	 *	 add the local record? */
	if (!ldb_msg_check_remote(module, msg)) {
		return LDB_ERR_OPERATIONS_ERROR;
	}

	/* Prepare context and handle */
	ac = map_init_context(module, req);
	if (ac == NULL) {
		return LDB_ERR_OPERATIONS_ERROR;
	}

	/* Prepare the local message */
	ac->local_msg = ldb_msg_new(ac);
	if (ac->local_msg == NULL) {
		map_oom(module);
		return LDB_ERR_OPERATIONS_ERROR;
	}
	ac->local_msg->dn = msg->dn;

	/* Prepare the remote message */
	remote_msg = ldb_msg_new(ac->remote_req);
	if (remote_msg == NULL) {
		map_oom(module);
		return LDB_ERR_OPERATIONS_ERROR;
	}
	remote_msg->dn = ldb_dn_map_local(ac->module, remote_msg, msg->dn);

	/* Split local from remote message */
	ldb_msg_partition(module, req->operation, ac->local_msg, remote_msg, msg);

	/* Prepare the remote operation */
	ret = ldb_build_mod_req(&ac->remote_req, ldb,
				ac, remote_msg,
				req->controls,
				ac, map_op_remote_callback,
				req);
	LDB_REQ_SET_LOCATION(ac->remote_req);
	if (ret != LDB_SUCCESS) {
		return LDB_ERR_OPERATIONS_ERROR;
	}

	if ((ac->local_msg->num_elements == 0) ||
	    ( ! map_check_local_db(ac->module))) {
		/* No local data or db, just run the remote request */
		return ldb_next_remote_request(ac->module, ac->remote_req);
	}

	/* prepare the search operation */
	ret = map_search_self_req(&search_req, ac, msg->dn);
	if (ret != LDB_SUCCESS) {
		return LDB_ERR_OPERATIONS_ERROR;
	}

	return ldb_next_request(module, search_req);
}