From 271b5af92e9aada36adc648a6dd43a13c5aed340 Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Tue, 14 Jul 2009 08:15:50 +1000 Subject: s4:dsdb Handle dc/domain/forest functional levels properly 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 | 7 +- source4/dsdb/samdb/ldb_modules/rootdse.c | 140 ++++++++++++++++++++++++- source4/scripting/python/pyglue.c | 6 ++ source4/scripting/python/samba/__init__.py | 5 + source4/scripting/python/samba/provision.py | 24 ++++- source4/setup/provision_basedn_modify.ldif | 4 +- source4/setup/provision_configuration.ldif | 2 +- source4/setup/provision_rootdse_add.ldif | 3 - source4/setup/provision_self_join.ldif | 4 +- 9 files changed, 174 insertions(+), 21 deletions(-) diff --git a/source4/dsdb/samdb/ldb_modules/password_hash.c b/source4/dsdb/samdb/ldb_modules/password_hash.c index a28ca1d568..ef641ac18b 100644 --- a/source4/dsdb/samdb/ldb_modules/password_hash.c +++ b/source4/dsdb/samdb/ldb_modules/password_hash.c @@ -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)) { diff --git a/source4/dsdb/samdb/ldb_modules/rootdse.c b/source4/dsdb/samdb/ldb_modules/rootdse.c index 7080fb632f..59ea51dbce 100644 --- a/source4/dsdb/samdb/ldb_modules/rootdse.c +++ b/source4/dsdb/samdb/ldb_modules/rootdse.c @@ -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) diff --git a/source4/scripting/python/pyglue.c b/source4/scripting/python/pyglue.c index abd018f6fc..c6b731ce8b 100644 --- a/source4/scripting/python/pyglue.c +++ b/source4/scripting/python/pyglue.c @@ -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)); + } diff --git a/source4/scripting/python/samba/__init__.py b/source4/scripting/python/samba/__init__.py index 60a7919136..e3ebc4a637 100644 --- a/source4/scripting/python/samba/__init__.py +++ b/source4/scripting/python/samba/__init__.py @@ -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 diff --git a/source4/scripting/python/samba/provision.py b/source4/scripting/python/samba/provision.py index 189c93a1fc..8f57105224 100644 --- a/source4/scripting/python/samba/provision.py +++ b/source4/scripting/python/samba/provision.py @@ -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() diff --git a/source4/setup/provision_basedn_modify.ldif b/source4/setup/provision_basedn_modify.ldif index a7f3ce985c..36e80ec69c 100644 --- a/source4/setup/provision_basedn_modify.ldif +++ b/source4/setup/provision_basedn_modify.ldif @@ -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} diff --git a/source4/setup/provision_configuration.ldif b/source4/setup/provision_configuration.ldif index e84ac8517e..0dad24c705 100644 --- a/source4/setup/provision_configuration.ldif +++ b/source4/setup/provision_configuration.ldif @@ -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} diff --git a/source4/setup/provision_rootdse_add.ldif b/source4/setup/provision_rootdse_add.ldif index e4e4309a90..f9ee4e5904 100644 --- a/source4/setup/provision_rootdse_add.ldif +++ b/source4/setup/provision_rootdse_add.ldif @@ -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 diff --git a/source4/setup/provision_self_join.ldif b/source4/setup/provision_self_join.ldif index b7ca872319..b60fea6576 100644 --- a/source4/setup/provision_self_join.ldif +++ b/source4/setup/provision_self_join.ldif @@ -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} -- cgit