s4:dsdb: let dsdb_check_and_update_fl() also operatingSystem[Version]
authorStefan Metzmacher <metze@samba.org>
Fri, 7 Jul 2023 12:18:14 +0000 (14:18 +0200)
committerAndrew Bartlett <abartlet@samba.org>
Wed, 19 Jul 2023 03:31:30 +0000 (03:31 +0000)
Some clients (e.g. an exchange server) check operatingSystemVersion
in order to check if a domain controller is new enough.

So we better use a value matching the dc functional level.

While we also fixed operatingSystem[Version] at provision time,
we do it also in dsdb_check_and_update_fl() in order to
handle old provisions and systems joined to an existing domain.

Signed-off-by: Stefan Metzmacher <metze@samba.org>
Reviewed-by: Andrew Bartlett <abartlet@samba.org>
source4/dsdb/common/util.c
source4/dsdb/wscript_build

index 050ec42ea8c53d1074ec9ed0584533ead21ad20a..fbc8ffe5ce57345c00f9d8ad6d7fef70bf49dae2 100644 (file)
@@ -3994,6 +3994,34 @@ int dsdb_dc_functional_level(struct ldb_context *ldb)
        return *dcFunctionality;
 }
 
+const char *dsdb_dc_operatingSystemVersion(int dc_functional_level)
+{
+       const char *operatingSystemVersion = NULL;
+
+       /*
+        * While we are there also update
+        * operatingSystem and operatingSystemVersion
+        * as at least operatingSystemVersion is really
+        * important for some clients/applications (like exchange).
+        */
+
+       if (dc_functional_level >= DS_DOMAIN_FUNCTION_2016) {
+               /* Pretend Windows 2016 */
+               operatingSystemVersion = "10.0 (14393)";
+       } else if (dc_functional_level >= DS_DOMAIN_FUNCTION_2012_R2) {
+               /* Pretend Windows 2012 R2 */
+               operatingSystemVersion = "6.3 (9600)";
+       } else if (dc_functional_level >= DS_DOMAIN_FUNCTION_2012) {
+               /* Pretend Windows 2012 */
+               operatingSystemVersion = "6.2 (9200)";
+       } else {
+               /* Pretend Windows 2008 R2 */
+               operatingSystemVersion = "6.1 (7600)";
+       }
+
+       return operatingSystemVersion;
+}
+
 int dsdb_check_and_update_fl(struct ldb_context *ldb_ctx, struct loadparm_context *lp_ctx)
 {
        TALLOC_CTX *frame = talloc_stackframe();
@@ -4006,7 +4034,9 @@ int dsdb_check_and_update_fl(struct ldb_context *ldb_ctx, struct loadparm_contex
        bool am_rodc;
        struct ldb_message *msg = NULL;
        struct ldb_dn *dc_ntds_settings_dn = NULL;
-
+       struct ldb_dn *dc_computer_dn = NULL;
+       const char *operatingSystem = NULL;
+       const char *operatingSystemVersion = NULL;
 
        db_dc_functional_level = dsdb_dc_functional_level(ldb_ctx);
        db_domain_functional_level = dsdb_functional_level(ldb_ctx);
@@ -4030,6 +4060,14 @@ int dsdb_check_and_update_fl(struct ldb_context *ldb_ctx, struct loadparm_contex
 
        /* Check if we need to update the DB */
        if (db_dc_functional_level == lp_dc_functional_level) {
+               /*
+                * Note that this early return means
+                * we're not updating operatingSystem and
+                * operatingSystemVersion.
+                *
+                * But at least for now that's
+                * exactly what we want.
+                */
                TALLOC_FREE(frame);
                return LDB_SUCCESS;
        }
@@ -4044,8 +4082,9 @@ int dsdb_check_and_update_fl(struct ldb_context *ldb_ctx, struct loadparm_contex
 
        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);
+                           "(from %d to %d) and operatingSystem[Version] "
+                           "as we are an RODC\n",
+                           db_dc_functional_level, lp_dc_functional_level);
                TALLOC_FREE(frame);
                return LDB_SUCCESS;
        }
@@ -4106,6 +4145,66 @@ int dsdb_check_and_update_fl(struct ldb_context *ldb_ctx, struct loadparm_contex
                }
        }
 
+       /*
+        * While we are there also update
+        * operatingSystem and operatingSystemVersion
+        * as at least operatingSystemVersion is really
+        * important for some clients/applications (like exchange).
+        */
+
+       operatingSystem = talloc_asprintf(frame, "Samba-%s",
+                                         samba_version_string());
+       if (operatingSystem == NULL) {
+               TALLOC_FREE(frame);
+               return ldb_oom(ldb_ctx);
+       }
+
+       operatingSystemVersion = dsdb_dc_operatingSystemVersion(db_dc_functional_level);
+
+       ret = samdb_server_reference_dn(ldb_ctx, frame, &dc_computer_dn);
+       if (ret != LDB_SUCCESS) {
+               DBG_ERR("Failed get the dc_computer_dn: %s\n",
+                       ldb_errstring(ldb_ctx));
+               TALLOC_FREE(frame);
+               return ret;
+       }
+
+       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_computer_dn;
+
+       ret = samdb_msg_add_addval(ldb_ctx, frame, msg,
+                                  "operatingSystem",
+                                  operatingSystem);
+       if (ret != LDB_SUCCESS) {
+               DBG_ERR("Failed to set new operatingSystem on message\n");
+               TALLOC_FREE(frame);
+               return ldb_operr(ldb_ctx);
+       }
+
+       ret = samdb_msg_add_addval(ldb_ctx, frame, msg,
+                                  "operatingSystemVersion",
+                                  operatingSystemVersion);
+       if (ret != LDB_SUCCESS) {
+               DBG_ERR("Failed to set new operatingSystemVersion on message\n");
+               TALLOC_FREE(frame);
+               return ldb_operr(ldb_ctx);
+       }
+
+       ret = dsdb_replace(ldb_ctx, msg, 0);
+       if (ret != LDB_SUCCESS) {
+               DBG_ERR("Failed to update DB with new operatingSystem[Version] on %s: %s\n",
+                       ldb_dn_get_linearized(dc_computer_dn),
+                       ldb_errstring(ldb_ctx));
+               TALLOC_FREE(frame);
+               return ret;
+       }
+
        TALLOC_FREE(frame);
        return LDB_SUCCESS;
 }
index 7f9b8fe78748182d5a3b9f21475958996483d178..766342fad8ee0e3215229f326d5ae2d7df26024e 100644 (file)
@@ -16,7 +16,7 @@ bld.SAMBA_LIBRARY('samdb-common',
        source='common/util.c common/util_trusts.c common/util_groups.c common/util_samr.c common/dsdb_dn.c common/dsdb_access.c common/util_links.c common/rodc_helper.c',
        autoproto='common/proto.h',
        private_library=True,
-       deps='ldb NDR_DRSBLOBS util_ldb LIBCLI_AUTH samba-hostconfig samba_socket cli-ldap-common flag_mapping UTIL_RUNCMD'
+       deps='ldb NDR_DRSBLOBS util_ldb LIBCLI_AUTH samba-hostconfig samba_socket cli-ldap-common flag_mapping UTIL_RUNCMD SAMBA_VERSION'
        )