return *dcFunctionality;
}
+int dsdb_check_and_update_fl(struct ldb_context *ldb_ctx, struct loadparm_context *lp_ctx)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ int ret;
+
+ int db_dc_functional_level;
+ int db_domain_functional_level;
+ int db_forest_functional_level;
+ int lp_dc_functional_level = lpcfg_ad_dc_functional_level(lp_ctx);
+ bool am_rodc;
+ struct ldb_message *msg = NULL;
+ struct ldb_dn *dc_ntds_settings_dn = NULL;
+
+
+ db_dc_functional_level = dsdb_dc_functional_level(ldb_ctx);
+ db_domain_functional_level = dsdb_functional_level(ldb_ctx);
+ db_forest_functional_level = dsdb_forest_functional_level(ldb_ctx);
+
+ if (lp_dc_functional_level < db_domain_functional_level) {
+ DBG_ERR("Refusing to start as smb.conf 'ad dc functional level' maps to %d, "
+ "which is less than the domain functional level of %d\n",
+ lp_dc_functional_level, db_domain_functional_level);
+ TALLOC_FREE(frame);
+ return LDB_ERR_CONSTRAINT_VIOLATION;
+ }
+
+ if (lp_dc_functional_level < db_forest_functional_level) {
+ DBG_ERR("Refusing to start as smb.conf 'ad dc functional level' maps to %d, "
+ "which is less than the forest functional level of %d\n",
+ lp_dc_functional_level, db_forest_functional_level);
+ TALLOC_FREE(frame);
+ return LDB_ERR_CONSTRAINT_VIOLATION;
+ }
+
+ /* Check if we need to update the DB */
+ if (db_dc_functional_level == lp_dc_functional_level) {
+ TALLOC_FREE(frame);
+ return LDB_SUCCESS;
+ }
+
+ /* Confirm we are not an RODC before we try a modify */
+ ret = samdb_rodc(ldb_ctx, &am_rodc);
+ if (ret != LDB_SUCCESS) {
+ DBG_ERR("Failed to determine if this server is an RODC\n");
+ TALLOC_FREE(frame);
+ return ret;
+ }
+
+ if (am_rodc) {
+ DBG_WARNING("Unable to update DC's msDS-Behavior-Version "
+ "to correct value (%d from %d) as we are an RODC\n",
+ db_forest_functional_level, lp_dc_functional_level);
+ TALLOC_FREE(frame);
+ return LDB_SUCCESS;
+ }
+
+ dc_ntds_settings_dn = samdb_ntds_settings_dn(ldb_ctx, frame);
+
+ if (dc_ntds_settings_dn == NULL) {
+ DBG_ERR("Failed to find own NTDS Settings DN\n");
+ TALLOC_FREE(frame);
+ return LDB_ERR_NO_SUCH_OBJECT;
+ }
+
+ /* Now update our msDS-Behavior-Version */
+
+ msg = ldb_msg_new(frame);
+ if (msg == NULL) {
+ DBG_ERR("Failed to allocate message to update msDS-Behavior-Version\n");
+ TALLOC_FREE(frame);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ msg->dn = dc_ntds_settings_dn;
+
+ ret = samdb_msg_add_int(ldb_ctx, frame, msg, "msDS-Behavior-Version", lp_dc_functional_level);
+ if (ret != LDB_SUCCESS) {
+ DBG_ERR("Failed to set new msDS-Behavior-Version on message\n");
+ TALLOC_FREE(frame);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ ret = dsdb_replace(ldb_ctx, msg, 0);
+ if (ret != LDB_SUCCESS) {
+ DBG_ERR("Failed to update DB with new msDS-Behavior-Version on %s: %s\n",
+ ldb_dn_get_linearized(dc_ntds_settings_dn),
+ ldb_errstring(ldb_ctx));
+ TALLOC_FREE(frame);
+ return ret;
+ }
+
+ /*
+ * We have to update the opaque because this particular ldb_context
+ * will not re-read the DB
+ */
+ {
+ int *val = talloc(ldb_ctx, int);
+ if (!val) {
+ TALLOC_FREE(frame);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ *val = lp_dc_functional_level;
+ ret = ldb_set_opaque(ldb_ctx,
+ "domainControllerFunctionality", val);
+ if (ret != LDB_SUCCESS) {
+ DBG_ERR("Failed to re-set domainControllerFunctionality opaque\n");
+ TALLOC_FREE(val);
+ TALLOC_FREE(frame);
+ return ret;
+ }
+ }
+
+ TALLOC_FREE(frame);
+ return LDB_SUCCESS;
+}
+
+
/*
set a GUID in an extended DN structure
*/
return PyUnicode_FromString(str);
}
+static PyObject *py_dsdb_check_and_update_fl(PyObject *self, PyObject *args)
+{
+ TALLOC_CTX *frame = NULL;
+
+ PyObject *py_ldb = NULL, *py_lp = NULL;
+ struct ldb_context *ldb = NULL;
+ struct loadparm_context *lp_ctx = NULL;
+
+ int ret;
+
+ if (!PyArg_ParseTuple(args, "OO", &py_ldb, &py_lp)) {
+ return NULL;
+ }
+
+ PyErr_LDB_OR_RAISE(py_ldb, ldb);
+
+ frame = talloc_stackframe();
+
+ lp_ctx = lpcfg_from_py_object(frame, py_lp);
+ if (lp_ctx == NULL) {
+ TALLOC_FREE(frame);
+ return NULL;
+ }
+
+ ret = dsdb_check_and_update_fl(ldb, lp_ctx);
+ TALLOC_FREE(frame);
+
+ PyErr_LDB_ERROR_IS_ERR_RAISE(py_ldb_get_exception(), ret, ldb);
+
+ Py_RETURN_NONE;
+}
+
static PyMethodDef py_dsdb_methods[] = {
{ "_samdb_server_site_name", (PyCFunction)py_samdb_server_site_name,
METH_VARARGS, "Get the server site name as a string"},
METH_VARARGS,
"user_account_control_flag_bit_to_string(bit)"
" -> string name" },
+ { "check_and_update_fl",
+ (PyCFunction)py_dsdb_check_and_update_fl,
+ METH_VARARGS,
+ "check_and_update_fl(ldb, lp) -> None\n"
+ "Hook to run in testing the code run on samba server startup "
+ "to validate and update DC functional levels"},
{0}
};