static PyObject *py_dsdb_set_schema_from_ldb(PyObject *self, PyObject *args) { PyObject *py_ldb; struct ldb_context *ldb; PyObject *py_from_ldb; struct ldb_context *from_ldb; struct dsdb_schema *schema; int ret; char write_indices_and_attributes = true; if (!PyArg_ParseTuple(args, "OO|b", &py_ldb, &py_from_ldb, &write_indices_and_attributes)) return NULL; PyErr_LDB_OR_RAISE(py_ldb, ldb); PyErr_LDB_OR_RAISE(py_from_ldb, from_ldb); schema = dsdb_get_schema(from_ldb, NULL); if (!schema) { PyErr_SetString(PyExc_RuntimeError, "Failed to set find a schema on 'from' ldb!\n"); return NULL; } ret = dsdb_reference_schema(ldb, schema, write_indices_and_attributes); PyErr_LDB_ERROR_IS_ERR_RAISE(py_ldb_get_exception(), ret, ldb); Py_RETURN_NONE; }
/** * Make this ldb use the 'global' schema, setup to avoid having multiple copies in this process */ int dsdb_set_global_schema(struct ldb_context *ldb) { if (!global_schema) { return LDB_SUCCESS; } return dsdb_reference_schema(ldb, global_schema, false /* Don't write attributes, it's expensive */); }
/** * 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; }