1
0
mirror of https://github.com/samba-team/samba.git synced 2024-12-22 13:34:15 +03:00

dsdb: Add routine to check the DB vs lp functional levels

This will be called at server startup (as well as from Python tests)

Signed-off-by: Andrew Bartlett <abartlet@samba.org>
Reviewed-by: Douglas Bagnall <douglas.bagnall@catalyst.net.nz>
This commit is contained in:
Andrew Bartlett 2023-05-31 14:33:08 +12:00
parent 4919e8d808
commit b8a613b4b1
2 changed files with 155 additions and 0 deletions

View File

@ -3994,6 +3994,123 @@ int dsdb_dc_functional_level(struct ldb_context *ldb)
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
*/

View File

@ -1426,6 +1426,38 @@ static PyObject *py_dsdb_user_account_control_flag_bit_to_string(PyObject *self,
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"},
@ -1512,6 +1544,12 @@ static PyMethodDef py_dsdb_methods[] = {
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}
};