s4:dsdb Handle dc/domain/forest functional levels properly
authorAndrew Bartlett <abartlet@samba.org>
Mon, 13 Jul 2009 22:15:50 +0000 (08:15 +1000)
committerAndrew Bartlett <abartlet@samba.org>
Wed, 15 Jul 2009 23:23:35 +0000 (09:23 +1000)
Rather than have the functional levels scattered in 4 different,
unconnected locations, the provision script now sets it, and the
rootdse module maintains it's copy only as a cached view onto the
original values.

We also use the functional level to determine if we should store AES
Kerberos keys.

Andrew Bartlett

source4/dsdb/samdb/ldb_modules/password_hash.c
source4/dsdb/samdb/ldb_modules/rootdse.c
source4/scripting/python/pyglue.c
source4/scripting/python/samba/__init__.py
source4/scripting/python/samba/provision.py
source4/setup/provision_basedn_modify.ldif
source4/setup/provision_configuration.ldif
source4/setup/provision_rootdse_add.ldif
source4/setup/provision_self_join.ldif

index a28ca1d56895af53ad996b2679608b21259eaca9..ef641ac18bf69dc2880a9a7ef647002fc5999f85 100644 (file)
@@ -1026,6 +1026,7 @@ static int setup_supplemental_field(struct setup_password_fields_io *io)
        uint8_t zero16[16];
        bool do_newer_keys = false;
        bool do_cleartext = false;
+       int *domainFunctionality;
 
        ZERO_STRUCT(zero16);
        ZERO_STRUCT(names);
@@ -1064,10 +1065,10 @@ static int setup_supplemental_field(struct setup_password_fields_io *io)
                                               _old_scb.sub.signature, SUPPLEMENTAL_CREDENTIALS_SIGNATURE);
                }
        }
+       /* Per MS-SAMR 3.1.1.8.11.6 we create AES keys if our domain functionality level is 2008 or higher */
+       domainFunctionality = talloc_get_type(ldb_get_opaque(ldb, "domainFunctionality"), int);
 
-       /* TODO: do the correct check for this, it maybe depends on the functional level? */
-       do_newer_keys = lp_parm_bool(ldb_get_opaque(ldb, "loadparm"),
-                                    NULL, "password_hash", "create_aes_key", false);
+       do_newer_keys = *domainFunctionality && (*domainFunctionality >= DS_BEHAVIOR_WIN2008);
 
        if (io->domain->store_cleartext &&
            (io->u.user_account_control & UF_ENCRYPTED_TEXT_PASSWORD_ALLOWED)) {
index 7080fb632f12172fb7528fb17ee6186acdfb15b4..59ea51dbce5d8a9e0a97fd6d4833d03ec92a62ce 100644 (file)
@@ -59,6 +59,7 @@ static int rootdse_add_dynamic(struct ldb_module *module, struct ldb_message *ms
        struct private_data *priv = talloc_get_type(ldb_module_get_private(module), struct private_data);
        char **server_sasl;
        const struct dsdb_schema *schema;
+       int *val;
 
        ldb = ldb_module_get_ctx(module);
        schema = dsdb_get_schema(ldb);
@@ -77,7 +78,7 @@ static int rootdse_add_dynamic(struct ldb_module *module, struct ldb_message *ms
                }
        }
 
-       if (do_attribute(attrs, "supportedControl")) {
+       if (priv && do_attribute(attrs, "supportedControl")) {
                int i;
                for (i = 0; i < priv->num_controls; i++) {
                        char *control = talloc_strdup(msg, priv->controls[i]);
@@ -91,7 +92,7 @@ static int rootdse_add_dynamic(struct ldb_module *module, struct ldb_message *ms
                }
        }
 
-       if (do_attribute(attrs, "namingContexts")) {
+       if (priv && do_attribute(attrs, "namingContexts")) {
                int i;
                for (i = 0; i < priv->num_partitions; i++) {
                        struct ldb_dn *dn = priv->partitions[i];
@@ -201,13 +202,37 @@ static int rootdse_add_dynamic(struct ldb_module *module, struct ldb_message *ms
                }
        }
 
-       if (schema && do_attribute_explicit(attrs, "vendorVersion")) {
+       if (do_attribute_explicit(attrs, "vendorVersion")) {
                if (ldb_msg_add_fmt(msg, "vendorVersion", 
                                    "%s", SAMBA_VERSION_STRING) != 0) {
                        goto failed;
                }
        }
 
+       if (priv && do_attribute(attrs, "domainFunctionality")
+           && (val = talloc_get_type(ldb_get_opaque(ldb, "domainFunctionality"), int))) {
+               if (ldb_msg_add_fmt(msg, "domainFunctionality", 
+                                   "%d", *val) != 0) {
+                       goto failed;
+               }
+       }
+
+       if (priv && do_attribute(attrs, "forestFunctionality")
+           && (val = talloc_get_type(ldb_get_opaque(ldb, "forestFunctionality"), int))) {
+               if (ldb_msg_add_fmt(msg, "forestFunctionality", 
+                                   "%d", *val) != 0) {
+                       goto failed;
+               }
+       }
+
+       if (priv && do_attribute(attrs, "domainControllerFunctionality")
+           && (val = talloc_get_type(ldb_get_opaque(ldb, "domainControllerFunctionality"), int))) {
+               if (ldb_msg_add_fmt(msg, "domainControllerFunctionality", 
+                                   "%d", *val) != 0) {
+                       goto failed;
+               }
+       }
+
        /* TODO: lots more dynamic attributes should be added here */
 
        return LDB_SUCCESS;
@@ -394,12 +419,17 @@ static int rootdse_request(struct ldb_module *module, struct ldb_request *req)
 
 static int rootdse_init(struct ldb_module *module)
 {
+       int ret;
        struct ldb_context *ldb;
+       struct ldb_result *res;
        struct private_data *data;
+       const char *attrs[] = { "msDS-Behavior-Version", NULL };
+       const char *ds_attrs[] = { "dsServiceName", NULL };
+       TALLOC_CTX *mem_ctx;
 
        ldb = ldb_module_get_ctx(module);
 
-       data = talloc(module, struct private_data);
+       data = talloc_zero(module, struct private_data);
        if (data == NULL) {
                return -1;
        }
@@ -412,7 +442,107 @@ static int rootdse_init(struct ldb_module *module)
 
        ldb_set_default_dns(ldb);
 
-       return ldb_next_init(module);
+       ret = ldb_next_init(module);
+
+       if (ret) {
+               return ret;
+       }
+
+       mem_ctx = talloc_new(data);
+       if (!mem_ctx) {
+               ldb_oom(ldb);
+               return LDB_ERR_OPERATIONS_ERROR;
+       }
+
+       /* Now that the partitions are set up, do a search for:
+          - domainControllerFunctionality
+          - domainFunctionality
+          - forestFunctionality
+
+          Then stuff these values into an opaque
+       */
+       ret = ldb_search(ldb, mem_ctx, &res,
+                        ldb_get_default_basedn(ldb),
+                        LDB_SCOPE_BASE, attrs, NULL);
+       if (ret == LDB_SUCCESS && res->count == 1) {
+               int domain_behaviour_version
+                       = ldb_msg_find_attr_as_int(res->msgs[0], 
+                                                  "msDS-Behavior-Version", -1);
+               if (domain_behaviour_version != -1) {
+                       int *val = talloc(ldb, int);
+                       if (!val) {
+                               ldb_oom(ldb);
+                               talloc_free(mem_ctx);
+                               return LDB_ERR_OPERATIONS_ERROR;
+                       }
+                       *val = domain_behaviour_version;
+                       ret = ldb_set_opaque(ldb, "domainFunctionality", val);
+                       if (ret != LDB_SUCCESS) {
+                               talloc_free(mem_ctx);
+                               return ret;
+                       }
+               }
+       }
+
+       ret = ldb_search(ldb, mem_ctx, &res,
+                        samdb_partitions_dn(ldb, mem_ctx),
+                        LDB_SCOPE_BASE, attrs, NULL);
+       if (ret == LDB_SUCCESS && res->count == 1) {
+               int forest_behaviour_version
+                       = ldb_msg_find_attr_as_int(res->msgs[0], 
+                                                  "msDS-Behavior-Version", -1);
+               if (forest_behaviour_version != -1) {
+                       int *val = talloc(ldb, int);
+                       if (!val) {
+                               ldb_oom(ldb);
+                               talloc_free(mem_ctx);
+                               return LDB_ERR_OPERATIONS_ERROR;
+                       }
+                       *val = forest_behaviour_version;
+                       ret = ldb_set_opaque(ldb, "forestFunctionality", val);
+                       if (ret != LDB_SUCCESS) {
+                               talloc_free(mem_ctx);
+                               return ret;
+                       }
+               }
+       }
+
+       ret = ldb_search(ldb, mem_ctx, &res,
+                        ldb_dn_new(mem_ctx, ldb, ""),
+                        LDB_SCOPE_BASE, ds_attrs, NULL);
+       if (ret == LDB_SUCCESS && res->count == 1) {
+               struct ldb_dn *ds_dn
+                       = ldb_msg_find_attr_as_dn(ldb, mem_ctx, res->msgs[0], 
+                                                 "dsServiceName");
+               if (ds_dn) {
+                       ret = ldb_search(ldb, mem_ctx, &res, ds_dn, 
+                                        LDB_SCOPE_BASE, attrs, NULL);
+                       if (ret == LDB_SUCCESS && res->count == 1) {
+                               int domain_controller_behaviour_version
+                                       = ldb_msg_find_attr_as_int(res->msgs[0], 
+                                                                  "msDS-Behavior-Version", -1);
+                               if (domain_controller_behaviour_version != -1) {
+                                       int *val = talloc(ldb, int);
+                                       if (!val) {
+                                               ldb_oom(ldb);
+                                               talloc_free(mem_ctx);
+                                       return LDB_ERR_OPERATIONS_ERROR;
+                                       }
+                                       *val = domain_controller_behaviour_version;
+                                       ret = ldb_set_opaque(ldb, 
+                                                            "domainControllerFunctionality", val);
+                                       if (ret != LDB_SUCCESS) {
+                                               talloc_free(mem_ctx);
+                                               return ret;
+                                       }
+                               }
+                       }
+               }
+       }
+
+       talloc_free(mem_ctx);
+       
+       return LDB_SUCCESS;
 }
 
 static int rootdse_modify(struct ldb_module *module, struct ldb_request *req)
index abd018f6fc67b46c6a68d810a00ac03ad68bcf2d..c6b731ce8b79263f807ea1de9aec78ea0d5d9cf9 100644 (file)
@@ -362,5 +362,11 @@ void initglue(void)
                return;
 
        PyModule_AddObject(m, "version", PyString_FromString(SAMBA_VERSION_STRING));
+
+       PyModule_AddObject(m, "DS_BEHAVIOR_WIN2000", PyInt_FromLong(DS_BEHAVIOR_WIN2000));
+       PyModule_AddObject(m, "DS_BEHAVIOR_WIN2003_INTERIM", PyInt_FromLong(DS_BEHAVIOR_WIN2003_INTERIM));
+       PyModule_AddObject(m, "DS_BEHAVIOR_WIN2003", PyInt_FromLong(DS_BEHAVIOR_WIN2003));
+       PyModule_AddObject(m, "DS_BEHAVIOR_WIN2008", PyInt_FromLong(DS_BEHAVIOR_WIN2008));
+
 }
 
index 60a7919136548dc967a1ef44d98581b69cdd7cc1..e3ebc4a637499d3c5b4e8e5e32da87830065e098 100644 (file)
@@ -242,3 +242,8 @@ def valid_netbios_name(name):
     return True
 
 version = glue.version
+
+DS_BEHAVIOR_WIN2000 = glue.DS_BEHAVIOR_WIN2000
+DS_BEHAVIOR_WIN2003_INTERIM = glue.DS_BEHAVIOR_WIN2003_INTERIM
+DS_BEHAVIOR_WIN2003 = glue.DS_BEHAVIOR_WIN2003
+DS_BEHAVIOR_WIN2008 = glue.DS_BEHAVIOR_WIN2008
index 189c93a1fcfd31fec65dba5d4e074e5a6b2d2484..8f57105224f70c63f831267c0930aaa40b2ed18b 100644 (file)
@@ -37,7 +37,8 @@ import param
 import registry
 import samba
 from auth import system_session
-from samba import Ldb, substitute_var, valid_netbios_name, check_all_substituted
+from samba import version, Ldb, substitute_var, valid_netbios_name, check_all_substituted, \
+  DS_BEHAVIOR_WIN2000, DS_BEHAVIOR_WIN2003_INTERIM, DS_BEHAVIOR_WIN2003, DS_BEHAVIOR_WIN2008
 from samba.samdb import SamDB
 from samba.idmap import IDmapDB
 from samba.dcerpc import security
@@ -729,7 +730,7 @@ def setup_samdb_rootdse(samdb, setup_path, names):
 def setup_self_join(samdb, names,
                     machinepass, dnspass, 
                     domainsid, invocationid, setup_path,
-                    policyguid):
+                    policyguid, domainControllerFunctionality):
     """Join a host to its own domain."""
     assert isinstance(invocationid, str)
     setup_add_ldif(samdb, setup_path("provision_self_join.ldif"), { 
@@ -745,7 +746,9 @@ def setup_self_join(samdb, names,
               "DNSPASS_B64": b64encode(dnspass),
               "REALM": names.realm,
               "DOMAIN": names.domain,
-              "DNSDOMAIN": names.dnsdomain})
+              "DNSDOMAIN": names.dnsdomain,
+              "SAMBA_VERSION_STRING": version,
+              "DOMAIN_CONTROLLER_FUNCTIONALITY": str(domainControllerFunctionality)})
     setup_add_ldif(samdb, setup_path("provision_group_policy.ldif"), { 
               "POLICYGUID": policyguid,
               "DNSDOMAIN": names.dnsdomain,
@@ -765,6 +768,10 @@ def setup_samdb(path, setup_path, session_info, credentials, lp,
     :note: This will wipe the main SAM database file!
     """
 
+    domainFunctionality = DS_BEHAVIOR_WIN2008
+    forestFunctionality = DS_BEHAVIOR_WIN2008
+    domainControllerFunctionality = DS_BEHAVIOR_WIN2008
+
     erase = (fill != FILL_DRS)
 
     # Also wipes the database
@@ -780,6 +787,11 @@ def setup_samdb(path, setup_path, session_info, credentials, lp,
         return samdb
 
     message("Pre-loading the Samba 4 and AD schema")
+
+    samdb.set_opaque_integer("domainFunctionality", domainFunctionality)
+    samdb.set_opaque_integer("forestFunctionality", forestFunctionality)
+    samdb.set_opaque_integer("domainControllerFunctionality", domainControllerFunctionality)
+
     samdb.set_domain_sid(str(domainsid))
     if serverrole == "domain controller":
         samdb.set_invocation_id(invocationid)
@@ -818,6 +830,7 @@ def setup_samdb(path, setup_path, session_info, credentials, lp,
             "POLICYGUID": policyguid,
             "DOMAINDN": names.domaindn,
             "DOMAINGUID_MOD": domainguid_mod,
+            "DOMAIN_FUNCTIONALITY": str(domainFunctionality)
             })
 
         message("Adding configuration container (permitted to fail)")
@@ -864,7 +877,8 @@ def setup_samdb(path, setup_path, session_info, credentials, lp,
             "DOMAIN": names.domain,
             "SCHEMADN": names.schemadn,
             "DOMAINDN": names.domaindn,
-            "SERVERDN": names.serverdn
+            "SERVERDN": names.serverdn,
+            "FOREST_FUNCTIONALALITY": str(forestFunctionality)
             })
 
         message("Setting up display specifiers")
@@ -908,7 +922,7 @@ def setup_samdb(path, setup_path, session_info, credentials, lp,
                                 dnspass=dnspass,  
                                 machinepass=machinepass, 
                                 domainsid=domainsid, policyguid=policyguid,
-                                setup_path=setup_path)
+                                setup_path=setup_path, domainControllerFunctionality=domainControllerFunctionality)
 
     except:
         samdb.transaction_cancel()
index a7f3ce985c54a8b4c55a6ca90f149024537f570a..36e80ec69c67f7b8109317985482ce1bc50a62d1 100644 (file)
@@ -47,10 +47,10 @@ replace: serverState
 serverState: 1
 -
 replace: nTMixedDomain
-nTMixedDomain: 1
+nTMixedDomain: 0
 -
 replace: msDS-Behavior-Version
-msDS-Behavior-Version: 0
+msDS-Behavior-Version: ${DOMAIN_FUNCTIONALITY}
 -
 replace: ridManagerReference
 ridManagerReference: CN=RID Manager$,CN=System,${DOMAINDN}
index e84ac8517eb4486cb1ba38d7b6a9a5ed775c76aa..0dad24c705d6cd89c2e2f9e994622f7599b03169 100644 (file)
@@ -6,7 +6,7 @@ objectClass: top
 objectClass: crossRefContainer
 cn: Partitions
 systemFlags: -2147483648
-msDS-Behavior-Version: 0
+msDS-Behavior-Version: ${FOREST_FUNCTIONALALITY}
 fSMORoleOwner: CN=NTDS Settings,${SERVERDN}
 
 dn: CN=Enterprise Configuration,CN=Partitions,${CONFIGDN}
index e4e4309a90acd4de4d0cabe68d05174e9e7a6c72..f9ee4e5904687f02d9e867a251c14350ef190f23 100644 (file)
@@ -11,9 +11,6 @@ supportedLDAPVersion: 2
 dnsHostName: ${DNSNAME}
 ldapServiceName: ${DNSDOMAIN}:${NETBIOSNAME}$@${REALM}
 serverName: ${SERVERDN}
-domainFunctionality: 0
-forestFunctionality: 0
-domainControllerFunctionality: 2
 isSynchronized: FALSE
 vendorName: Samba Team (http://samba.org)
 supportedCapabilities: 1.2.840.113556.1.4.800
index b7ca8723190408fa20f84c6fb8a4b390be5df95d..b60fea6576c055e4609c06bbcafdb39e0285794a 100644 (file)
@@ -13,7 +13,7 @@ primaryGroupID: 516
 accountExpires: 9223372036854775807
 sAMAccountName: ${NETBIOSNAME}$
 operatingSystem: Samba
-operatingSystemVersion: 4.0
+operatingSystemVersion: ${SAMBA_VERSION_STRING}
 dNSHostName: ${DNSNAME}
 isCriticalSystemObject: TRUE
 userPassword:: ${MACHINEPASS_B64}
@@ -57,7 +57,7 @@ options: 1
 systemFlags: 33554432
 dMDLocation: ${SCHEMADN}
 invocationId: ${INVOCATIONID}
-msDS-Behavior-Version: 2
+msDS-Behavior-Version: ${DOMAIN_CONTROLLER_FUNCTIONALITY}
 msDS-hasMasterNCs: ${CONFIGDN}
 msDS-hasMasterNCs: ${SCHEMADN}
 msDS-hasMasterNCs: ${DOMAINDN}