mirror of
https://github.com/samba-team/samba.git
synced 2025-02-23 09:57:40 +03:00
s4-dsdb: Take more care in handling of global schema memory
This reworks dsdb_replicated_objects_commit() to have a proper local tmp_ctx and to be more careful about what schema is set (only setting a global schema if the original schema was global). In particular, the new working_schema is not given a talloc reference to the old schema. This ensures that the old schema can go away when no longer used. Andrew Bartlett Autobuild-User(master): Andrew Bartlett <abartlet@samba.org> Autobuild-Date(master): Sat Aug 11 10:31:57 CEST 2012 on sn-devel-104
This commit is contained in:
parent
329e374938
commit
4631723c98
@ -543,8 +543,16 @@ WERROR dsdb_replicated_objects_commit(struct ldb_context *ldb,
|
||||
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 */
|
||||
|
||||
@ -561,6 +569,7 @@ WERROR dsdb_replicated_objects_commit(struct ldb_context *ldb,
|
||||
if (ret != LDB_SUCCESS) {
|
||||
DEBUG(0,(__location__ " Failed to load partition uSN\n"));
|
||||
ldb_transaction_cancel(ldb);
|
||||
TALLOC_FREE(tmp_ctx);
|
||||
return WERR_FOOBAR;
|
||||
}
|
||||
|
||||
@ -572,7 +581,8 @@ WERROR dsdb_replicated_objects_commit(struct ldb_context *ldb,
|
||||
*/
|
||||
if (working_schema) {
|
||||
/* store current schema so we can fall back in case of failure */
|
||||
cur_schema = dsdb_get_schema(ldb, working_schema);
|
||||
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) {
|
||||
@ -580,6 +590,7 @@ WERROR dsdb_replicated_objects_commit(struct ldb_context *ldb,
|
||||
ldb_strerror(ret)));
|
||||
/* TODO: Map LDB Error to NTSTATUS? */
|
||||
ldb_transaction_cancel(ldb);
|
||||
TALLOC_FREE(tmp_ctx);
|
||||
return WERR_INTERNAL_ERROR;
|
||||
}
|
||||
}
|
||||
@ -587,14 +598,16 @@ WERROR dsdb_replicated_objects_commit(struct ldb_context *ldb,
|
||||
ret = ldb_extended(ldb, DSDB_EXTENDED_REPLICATED_OBJECTS_OID, objects, &ext_res);
|
||||
if (ret != LDB_SUCCESS) {
|
||||
/* restore previous schema */
|
||||
if (cur_schema ) {
|
||||
if (used_global_schema) {
|
||||
dsdb_set_global_schema(ldb);
|
||||
} else if (cur_schema) {
|
||||
dsdb_reference_schema(ldb, cur_schema, false);
|
||||
dsdb_make_schema_global(ldb, cur_schema);
|
||||
}
|
||||
|
||||
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);
|
||||
@ -606,12 +619,14 @@ WERROR dsdb_replicated_objects_commit(struct ldb_context *ldb,
|
||||
working_schema);
|
||||
if (!W_ERROR_IS_OK(werr)) {
|
||||
/* restore previous schema */
|
||||
if (cur_schema ) {
|
||||
if (used_global_schema) {
|
||||
dsdb_set_global_schema(ldb);
|
||||
} else if (cur_schema ) {
|
||||
dsdb_reference_schema(ldb, cur_schema, false);
|
||||
dsdb_make_schema_global(ldb, cur_schema);
|
||||
}
|
||||
DEBUG(0,("Failed to save updated prefixMap: %s\n",
|
||||
win_errstr(werr)));
|
||||
TALLOC_FREE(tmp_ctx);
|
||||
return werr;
|
||||
}
|
||||
}
|
||||
@ -619,24 +634,28 @@ WERROR dsdb_replicated_objects_commit(struct ldb_context *ldb,
|
||||
ret = ldb_transaction_prepare_commit(ldb);
|
||||
if (ret != LDB_SUCCESS) {
|
||||
/* restore previous schema */
|
||||
if (cur_schema ) {
|
||||
if (used_global_schema) {
|
||||
dsdb_set_global_schema(ldb);
|
||||
} else if (cur_schema ) {
|
||||
dsdb_reference_schema(ldb, cur_schema, false);
|
||||
dsdb_make_schema_global(ldb, cur_schema);
|
||||
}
|
||||
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 (cur_schema ) {
|
||||
if (used_global_schema) {
|
||||
dsdb_set_global_schema(ldb);
|
||||
} else if (cur_schema ) {
|
||||
dsdb_reference_schema(ldb, cur_schema, false);
|
||||
dsdb_make_schema_global(ldb, cur_schema);
|
||||
}
|
||||
DEBUG(0,(__location__ " Failed to load partition uSN\n"));
|
||||
ldb_transaction_cancel(ldb);
|
||||
TALLOC_FREE(tmp_ctx);
|
||||
return WERR_FOOBAR;
|
||||
}
|
||||
|
||||
@ -650,11 +669,13 @@ WERROR dsdb_replicated_objects_commit(struct ldb_context *ldb,
|
||||
ret = ldb_transaction_commit(ldb);
|
||||
if (ret != LDB_SUCCESS) {
|
||||
/* restore previous schema */
|
||||
if (cur_schema ) {
|
||||
if (used_global_schema) {
|
||||
dsdb_set_global_schema(ldb);
|
||||
} else if (cur_schema ) {
|
||||
dsdb_reference_schema(ldb, cur_schema, false);
|
||||
dsdb_make_schema_global(ldb, cur_schema);
|
||||
}
|
||||
DEBUG(0,(__location__ " Failed to commit transaction\n"));
|
||||
TALLOC_FREE(tmp_ctx);
|
||||
return WERR_FOOBAR;
|
||||
}
|
||||
|
||||
@ -668,29 +689,43 @@ WERROR dsdb_replicated_objects_commit(struct ldb_context *ldb,
|
||||
|
||||
/* Force a reload */
|
||||
working_schema->last_refresh = 0;
|
||||
cur_schema = dsdb_get_schema(ldb, NULL);
|
||||
/* TODO: What we do in case dsdb_get_schema() fail?
|
||||
* We can't fallback at this point anymore */
|
||||
if (cur_schema) {
|
||||
dsdb_make_schema_global(ldb, cur_schema);
|
||||
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(ldb);
|
||||
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(msg);
|
||||
TALLOC_FREE(tmp_ctx);
|
||||
return WERR_NOMEM;
|
||||
}
|
||||
|
||||
ret = ldb_msg_add_string(msg, "schemaUpdateNow", "1");
|
||||
if (ret != LDB_SUCCESS) {
|
||||
talloc_free(msg);
|
||||
TALLOC_FREE(tmp_ctx);
|
||||
return WERR_INTERNAL_ERROR;
|
||||
}
|
||||
|
||||
ret = ldb_build_mod_req(&req, ldb, ldb,
|
||||
ret = ldb_build_mod_req(&req, ldb, objects,
|
||||
msg,
|
||||
LDB_SCOPE_BASE,
|
||||
NULL,
|
||||
@ -698,14 +733,13 @@ WERROR dsdb_replicated_objects_commit(struct ldb_context *ldb,
|
||||
NULL);
|
||||
|
||||
if (ret != LDB_SUCCESS) {
|
||||
talloc_free(msg);
|
||||
TALLOC_FREE(tmp_ctx);
|
||||
return WERR_DS_DRA_INTERNAL_ERROR;
|
||||
}
|
||||
|
||||
ret = ldb_transaction_start(ldb);
|
||||
if (ret != LDB_SUCCESS) {
|
||||
talloc_free(msg);
|
||||
talloc_free(req);
|
||||
TALLOC_FREE(tmp_ctx);
|
||||
DEBUG(0, ("Autotransaction start failed\n"));
|
||||
return WERR_DS_DRA_INTERNAL_ERROR;
|
||||
}
|
||||
@ -718,14 +752,13 @@ WERROR dsdb_replicated_objects_commit(struct ldb_context *ldb,
|
||||
if (ret == LDB_SUCCESS) {
|
||||
ret = ldb_transaction_commit(ldb);
|
||||
} else {
|
||||
DEBUG(0, ("Schema update now failed: %s\n", ldb_strerror(ret)));
|
||||
DEBUG(0, ("Schema update now failed: %s\n", ldb_errstring(ret)));
|
||||
ldb_transaction_cancel(ldb);
|
||||
}
|
||||
|
||||
talloc_free(msg);
|
||||
talloc_free(req);
|
||||
if (ret != LDB_SUCCESS) {
|
||||
DEBUG(0, ("Commit failed: %s\n", ldb_strerror(ret)));
|
||||
DEBUG(0, ("Commit failed: %s\n", ldb_errstring(ldb)));
|
||||
TALLOC_FREE(tmp_ctx);
|
||||
return WERR_DS_INTERNAL_FAILURE;
|
||||
}
|
||||
}
|
||||
@ -734,6 +767,7 @@ WERROR dsdb_replicated_objects_commit(struct ldb_context *ldb,
|
||||
objects->num_objects, objects->linked_attributes_count,
|
||||
ldb_dn_get_linearized(objects->partition_dn)));
|
||||
|
||||
TALLOC_FREE(tmp_ctx);
|
||||
return WERR_OK;
|
||||
}
|
||||
|
||||
|
@ -320,7 +320,9 @@ static int dsdb_schema_from_db(struct ldb_module *module, struct ldb_dn *schema_
|
||||
goto failed;
|
||||
}
|
||||
|
||||
/* Ensure this module won't go away before the callback */
|
||||
/* Ensure this module won't go away before the callback. This
|
||||
* causes every schema to have the LDB that originally loaded
|
||||
* the first schema as a talloc child. */
|
||||
if (talloc_reference(*schema, ldb) == NULL) {
|
||||
ldb_oom(ldb);
|
||||
ret = LDB_ERR_OPERATIONS_ERROR;
|
||||
|
Loading…
x
Reference in New Issue
Block a user