static PyObject *py_dsdb_set_global_schema(PyObject *self, PyObject *args) { PyObject *py_ldb; struct ldb_context *ldb; int ret; if (!PyArg_ParseTuple(args, "O", &py_ldb)) return NULL; PyErr_LDB_OR_RAISE(py_ldb, ldb); ret = dsdb_set_global_schema(ldb); PyErr_LDB_ERROR_IS_ERR_RAISE(py_ldb_get_exception(), ret, ldb); Py_RETURN_NONE; }
void dsdb_make_schema_global(struct ldb_context *ldb, struct dsdb_schema *schema) { if (!schema) { return; } if (global_schema) { talloc_unlink(talloc_autofree_context(), global_schema); } /* we want the schema to be around permanently */ talloc_reparent(ldb, talloc_autofree_context(), schema); global_schema = schema; /* This calls the talloc_reference() of the global schema back onto the ldb */ dsdb_set_global_schema(ldb); }
void dsdb_make_schema_global(struct ldb_context *ldb) { struct dsdb_schema *schema = dsdb_get_schema(ldb); if (!schema) { return; } if (global_schema) { talloc_unlink(talloc_autofree_context(), global_schema); } /* we want the schema to be around permanently */ talloc_reparent(talloc_parent(schema), talloc_autofree_context(), schema); global_schema = schema; dsdb_set_global_schema(ldb); }
/* wrapped connection to a ldb database to close just talloc_free() the returned ldb_context TODO: We need an error_string parameter */ struct ldb_context *ldb_wrap_connect(TALLOC_CTX *mem_ctx, struct tevent_context *ev, struct loadparm_context *lp_ctx, const char *url, struct auth_session_info *session_info, struct cli_credentials *credentials, unsigned int flags) { struct ldb_context *ldb; int ret; char *real_url = NULL; struct ldb_wrap *w; struct ldb_wrap_context c; c.url = url; c.ev = ev; c.lp_ctx = lp_ctx; c.session_info = session_info; c.credentials = credentials; c.flags = flags; /* see if we can re-use an existing ldb */ for (w=ldb_wrap_list; w; w=w->next) { if (ldb_wrap_same_context(&c, &w->context)) { return talloc_reference(mem_ctx, w->ldb); } } /* we want to use the existing event context if possible. This relies on the fact that in smbd, everything is a child of the main event_context */ if (ev == NULL) { return NULL; } ldb = ldb_init(mem_ctx, ev); if (ldb == NULL) { return NULL; } ldb_set_modules_dir(ldb, talloc_asprintf(ldb, "%s/ldb", lp_modulesdir(lp_ctx))); if (ldb_set_opaque(ldb, "sessionInfo", session_info)) { talloc_free(ldb); return NULL; } if (ldb_set_opaque(ldb, "credentials", credentials)) { talloc_free(ldb); return NULL; } if (ldb_set_opaque(ldb, "loadparm", lp_ctx)) { talloc_free(ldb); return NULL; } /* This must be done before we load the schema, as these * handlers for objectSid and objectGUID etc must take * precedence over the 'binary attribute' declaration in the * schema */ ret = ldb_register_samba_handlers(ldb); if (ret == -1) { talloc_free(ldb); return NULL; } if (lp_ctx != NULL && strcmp(lp_sam_url(lp_ctx), url) == 0) { dsdb_set_global_schema(ldb); } ldb_set_debug(ldb, ldb_wrap_debug, NULL); ldb_set_utf8_fns(ldb, NULL, wrap_casefold); real_url = private_path(ldb, lp_ctx, url); if (real_url == NULL) { talloc_free(ldb); return NULL; } /* allow admins to force non-sync ldb for all databases */ if (lp_parm_bool(lp_ctx, NULL, "ldb", "nosync", false)) { flags |= LDB_FLG_NOSYNC; } if (DEBUGLVL(10)) { flags |= LDB_FLG_ENABLE_TRACING; } /* we usually want Samba databases to be private. If we later find we need one public, we will need to add a parameter to ldb_wrap_connect() */ ldb_set_create_perms(ldb, 0600); ret = ldb_connect(ldb, real_url, flags, NULL); if (ret != LDB_SUCCESS) { talloc_free(ldb); return NULL; } /* setup for leak detection */ ldb_set_opaque(ldb, "wrap_url", real_url); /* add to the list of open ldb contexts */ w = talloc(ldb, struct ldb_wrap); if (w == NULL) { talloc_free(ldb); return NULL; } w->context = c; w->context.url = talloc_strdup(w, url); if (w->context.url == NULL) { talloc_free(ldb); return NULL; } w->ldb = ldb; DLIST_ADD(ldb_wrap_list, w); /* make the resulting schema global */ if (lp_ctx != NULL && strcmp(lp_sam_url(lp_ctx), url) == 0) { dsdb_make_schema_global(ldb); } DEBUG(3,("ldb_wrap open of %s\n", url)); talloc_set_destructor(w, ldb_wrap_destructor); return ldb; }
/** * 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; }