dynconfig: Change permission of the private dir to 0700
[samba.git] / python / samba / provision / __init__.py
index ee4cc10dca5a50dab8e741dff2badb395d0c4f4b..91d2105929c246c0f2000307a1c9582f92fb9eb7 100644 (file)
@@ -1,5 +1,5 @@
 # Unix SMB/CIFS implementation.
-# backend code for provisioning a Samba4 server
+# backend code for provisioning a Samba AD server
 
 # Copyright (C) Jelmer Vernooij <jelmer@samba.org> 2007-2012
 # Copyright (C) Andrew Bartlett <abartlet@samba.org> 2008-2009
@@ -38,6 +38,7 @@ import socket
 import urllib
 import string
 import tempfile
+import samba.dsdb
 
 import ldb
 
@@ -55,6 +56,7 @@ from samba import (
     substitute_var,
     valid_netbios_name,
     version,
+    is_heimdal_built,
     )
 from samba.dcerpc import security, misc
 from samba.dcerpc.misc import (
@@ -101,7 +103,11 @@ from samba.provision.common import (
     setup_path,
     setup_add_ldif,
     setup_modify_ldif,
-    )
+    FILL_FULL,
+    FILL_SUBDOMAIN,
+    FILL_NT4SYNC,
+    FILL_DRS
+)
 from samba.provision.sambadns import (
     get_dnsadmins_sid,
     setup_ad_dns,
@@ -113,10 +119,10 @@ import samba.registry
 from samba.schema import Schema
 from samba.samdb import SamDB
 from samba.dbchecker import dbcheck
-
+from samba.provision.kerberos import create_kdc_conf
 
 DEFAULT_POLICY_GUID = "31B2F340-016D-11D2-945F-00C04FB984F9"
-DEFAULT_DC_POLICY_GUID = "6AC1786C-016F-11D2-945F-00C04fB984F9"
+DEFAULT_DC_POLICY_GUID = "6AC1786C-016F-11D2-945F-00C04FB984F9"
 DEFAULTSITE = "Default-First-Site-Name"
 LAST_PROVISION_USN_ATTRIBUTE = "lastProvisionUSN"
 
@@ -160,6 +166,9 @@ class ProvisionNames(object):
         self.hostname = None
         self.sitename = None
         self.smbconf = None
+        self.domainsid = None
+        self.forestsid = None
+        self.domainguid = None
         self.name_map = {}
 
 
@@ -201,9 +210,8 @@ def find_provision_key_parameters(samdb, secretsdb, idmapdb, paths, smbconf,
                "configurationNamingContext","rootDomainNamingContext",
                "namingContexts"])
 
-    names.configdn = current[0]["configurationNamingContext"]
-    configdn = str(names.configdn)
-    names.schemadn = current[0]["schemaNamingContext"]
+    names.configdn = current[0]["configurationNamingContext"][0]
+    names.schemadn = current[0]["schemaNamingContext"][0]
     if not (ldb.Dn(samdb, basedn) == (ldb.Dn(samdb,
                                        current[0]["defaultNamingContext"][0]))):
         raise ProvisioningError(("basedn in %s (%s) and from %s (%s)"
@@ -211,8 +219,8 @@ def find_provision_key_parameters(samdb, secretsdb, idmapdb, paths, smbconf,
                                     str(current[0]["defaultNamingContext"][0]),
                                     paths.smbconf, basedn)))
 
-    names.domaindn=current[0]["defaultNamingContext"]
-    names.rootdn=current[0]["rootDomainNamingContext"]
+    names.domaindn=current[0]["defaultNamingContext"][0]
+    names.rootdn=current[0]["rootDomainNamingContext"][0]
     names.ncs=current[0]["namingContexts"]
     names.dnsforestdn = None
     names.dnsdomaindn = None
@@ -232,18 +240,21 @@ def find_provision_key_parameters(samdb, secretsdb, idmapdb, paths, smbconf,
 
     # default site name
     res3 = samdb.search(expression="(objectClass=site)",
-        base="CN=Sites," + configdn, scope=ldb.SCOPE_ONELEVEL, attrs=["cn"])
+        base="CN=Sites," + names.configdn, scope=ldb.SCOPE_ONELEVEL, attrs=["cn"])
     names.sitename = str(res3[0]["cn"])
 
     # dns hostname and server dn
     res4 = samdb.search(expression="(CN=%s)" % names.netbiosname,
-                            base="OU=Domain Controllers,%s" % basedn,
-                            scope=ldb.SCOPE_ONELEVEL, attrs=["dNSHostName"])
+                        base="OU=Domain Controllers,%s" % basedn,
+                        scope=ldb.SCOPE_ONELEVEL, attrs=["dNSHostName"])
+    if len(res4) == 0:
+        raise ProvisioningError("Unable to find DC called CN=%s under OU=Domain Controllers,%s" % (names.netbiosname, basedn))
+
     names.hostname = str(res4[0]["dNSHostName"]).replace("." + names.dnsdomain, "")
 
     server_res = samdb.search(expression="serverReference=%s" % res4[0].dn,
-                                attrs=[], base=configdn)
-    names.serverdn = server_res[0].dn
+                                attrs=[], base=names.configdn)
+    names.serverdn = str(server_res[0].dn)
 
     # invocation id/objectguid
     res5 = samdb.search(expression="(objectClass=*)",
@@ -259,6 +270,7 @@ def find_provision_key_parameters(samdb, secretsdb, idmapdb, paths, smbconf,
                 "objectSid","msDS-Behavior-Version" ])
     names.domainguid = str(ndr_unpack(misc.GUID, res6[0]["objectGUID"][0]))
     names.domainsid = ndr_unpack( security.dom_sid, res6[0]["objectSid"][0])
+    names.forestsid = ndr_unpack( security.dom_sid, res6[0]["objectSid"][0])
     if res6[0].get("msDS-Behavior-Version") is None or \
         int(res6[0]["msDS-Behavior-Version"][0]) < DS_DOMAIN_FUNCTION_2000:
         names.domainlevel = DS_DOMAIN_FUNCTION_2000
@@ -266,16 +278,15 @@ def find_provision_key_parameters(samdb, secretsdb, idmapdb, paths, smbconf,
         names.domainlevel = int(res6[0]["msDS-Behavior-Version"][0])
 
     # policy guid
-    res7 = samdb.search(expression="(displayName=Default Domain Policy)",
+    res7 = samdb.search(expression="(name={%s})" % DEFAULT_POLICY_GUID,
                         base="CN=Policies,CN=System," + basedn,
                         scope=ldb.SCOPE_ONELEVEL, attrs=["cn","displayName"])
     names.policyid = str(res7[0]["cn"]).replace("{","").replace("}","")
     # dc policy guid
-    res8 = samdb.search(expression="(displayName=Default Domain Controllers"
-                                   " Policy)",
-                            base="CN=Policies,CN=System," + basedn,
-                            scope=ldb.SCOPE_ONELEVEL,
-                            attrs=["cn","displayName"])
+    res8 = samdb.search(expression="(name={%s})" % DEFAULT_DC_POLICY_GUID,
+                        base="CN=Policies,CN=System," + basedn,
+                        scope=ldb.SCOPE_ONELEVEL,
+                        attrs=["cn","displayName"])
     if len(res8) == 1:
         names.policyid_dc = str(res8[0]["cn"]).replace("{","").replace("}","")
     else:
@@ -464,7 +475,7 @@ class ProvisionResult(object):
     def report_logger(self, logger):
         """Report this provision result to a logger."""
         logger.info(
-            "Once the above files are installed, your Samba4 server will "
+            "Once the above files are installed, your Samba AD server will "
             "be ready to use")
         if self.adminpass_generated:
             logger.info("Admin password:        %s", self.adminpass)
@@ -539,6 +550,7 @@ def provision_paths_from_lp(lp, dnsdomain):
     paths.namedconf_update = os.path.join(paths.private_dir, "named.conf.update")
     paths.namedtxt = os.path.join(paths.private_dir, "named.txt")
     paths.krb5conf = os.path.join(paths.private_dir, "krb5.conf")
+    paths.kdcconf = os.path.join(paths.private_dir, "kdc.conf")
     paths.winsdb = os.path.join(paths.private_dir, "wins.ldb")
     paths.s4_ldapi_path = os.path.join(paths.private_dir, "ldapi")
     paths.hklm = "hklm.ldb"
@@ -562,7 +574,8 @@ def determine_netbios_name(hostname):
 
 def guess_names(lp=None, hostname=None, domain=None, dnsdomain=None,
                 serverrole=None, rootdn=None, domaindn=None, configdn=None,
-                schemadn=None, serverdn=None, sitename=None):
+                schemadn=None, serverdn=None, sitename=None,
+                domain_names_forced=False):
     """Guess configuration settings to use."""
 
     if hostname is None:
@@ -595,7 +608,7 @@ def guess_names(lp=None, hostname=None, domain=None, dnsdomain=None,
         raise ProvisioningError("guess_names: 'realm =' was not specified in supplied %s.  Please remove the smb.conf file and let provision generate it" % lp.configfile)
 
     if lp.get("realm").upper() != realm:
-        raise ProvisioningError("guess_names: 'realm=%s' in %s must match chosen realm '%s'!  Please remove the smb.conf file and let provision generate it" % (lp.get("realm").upper(), realm, lp.configfile))
+        raise ProvisioningError("guess_names: 'realm=%s' in %s must match chosen realm '%s'!  Please remove the smb.conf file and let provision generate it" % (lp.get("realm").upper(), lp.configfile, realm))
 
     if lp.get("server role").lower() != serverrole:
         raise ProvisioningError("guess_names: 'server role=%s' in %s must match chosen server role '%s'!  Please remove the smb.conf file and let provision generate it" % (lp.get("server role"), lp.configfile, serverrole))
@@ -625,8 +638,8 @@ def guess_names(lp=None, hostname=None, domain=None, dnsdomain=None,
     if hostname.upper() == realm:
         raise ProvisioningError("guess_names: Realm '%s' must not be equal to hostname '%s'!" % (realm, hostname))
     if netbiosname.upper() == realm:
-        raise ProvisioningError("guess_names: Realm '%s' must not be equal to netbios hostname '%s'!" % (realm, netbiosname))
-    if domain == realm:
+        raise ProvisioningError("guess_names: Realm '%s' must not be equal to NetBIOS hostname '%s'!" % (realm, netbiosname))
+    if domain == realm and not domain_names_forced:
         raise ProvisioningError("guess_names: Realm '%s' must not be equal to short domain name '%s'!" % (realm, domain))
 
     if rootdn is None:
@@ -657,7 +670,6 @@ def guess_names(lp=None, hostname=None, domain=None, dnsdomain=None,
 
     return names
 
-
 def make_smbconf(smbconf, hostname, domain, realm, targetdir,
                  serverrole=None, eadb=False, use_ntvfs=False, lp=None,
                  global_param=None):
@@ -749,11 +761,7 @@ def make_smbconf(smbconf, hostname, domain, realm, targetdir,
     # and dump it without any values that are the default
     # this ensures that any smb.conf parameters that were set
     # on the provision/join command line are set in the resulting smb.conf
-    f = open(smbconf, mode='w')
-    try:
-        lp.dump(f, False)
-    finally:
-        f.close()
+    lp.dump(False, smbconf)
 
 
 def setup_name_mappings(idmap, sid, root_uid, nobody_uid,
@@ -776,7 +784,7 @@ def setup_name_mappings(idmap, sid, root_uid, nobody_uid,
 
 
 def setup_samdb_partitions(samdb_path, logger, lp, session_info,
-                           provision_backend, names, schema, serverrole,
+                           provision_backend, names, serverrole,
                            erase=False):
     """Setup the partitions for the SAM database.
 
@@ -866,7 +874,7 @@ def secretsdb_self_join(secretsdb, domain,
         msg["msDS-KeyVersionNumber"] = [str(key_version_number)]
         msg["privateKeytab"] = ["secrets.keytab"]
 
-    msg["secret"] = [machinepass]
+    msg["secret"] = [machinepass.encode('utf-8')]
     msg["samAccountName"] = ["%s$" % netbiosname]
     msg["secureChannelType"] = [str(secure_channel_type)]
     if domainsid is not None:
@@ -887,7 +895,10 @@ def secretsdb_self_join(secretsdb, domain,
 
     if len(res) == 1:
         msg["priorSecret"] = [res[0]["secret"][0]]
-        msg["priorWhenChanged"] = [res[0]["whenChanged"][0]]
+        try:
+            msg["priorWhenChanged"] = [res[0]["whenChanged"][0]]
+        except KeyError:
+            pass
 
         try:
             msg["privateKeytab"] = [res[0]["privateKeytab"][0]]
@@ -918,7 +929,7 @@ def secretsdb_self_join(secretsdb, domain,
 def setup_secretsdb(paths, session_info, backend_credentials, lp):
     """Setup the secrets database.
 
-   :note: This function does not handle exceptions and transaction on purpose,
+    :note: This function does not handle exceptions and transaction on purpose,
        it's up to the caller to do this job.
 
     :param path: Path to the secrets database.
@@ -1180,7 +1191,7 @@ def setup_samdb(path, session_info, provision_backend, lp, names,
     # Also wipes the database
     setup_samdb_partitions(path, logger=logger, lp=lp,
         provision_backend=provision_backend, session_info=session_info,
-        names=names, serverrole=serverrole, schema=schema)
+        names=names, serverrole=serverrole)
 
     # Load the database, but don's load the global schema and don't connect
     # quite yet
@@ -1199,7 +1210,13 @@ def setup_samdb(path, session_info, provision_backend, lp, names,
 
     # And now we can connect to the DB - the schema won't be loaded from the
     # DB
-    samdb.connect(path)
+    try:
+        samdb.connect(path)
+    except ldb.LdbError, (num, string_error):
+        if (num == ldb.ERR_INSUFFICIENT_ACCESS_RIGHTS):
+            raise ProvisioningError("Permission denied connecting to %s, are you running as root?" % path)
+        else:
+            raise
 
     # But we have to give it one more kick to have it use the schema
     # during provision - it needs, now that it is connected, to write
@@ -1209,7 +1226,7 @@ def setup_samdb(path, session_info, provision_backend, lp, names,
     return samdb
 
 
-def fill_samdb(samdb, lp, names, logger, domainsid, domainguid, policyguid,
+def fill_samdb(samdb, lp, names, logger, policyguid,
         policyguid_dc, fill, adminpass, krbtgtpass, machinepass, dns_backend,
         dnspass, invocationid, ntdsguid, serverrole, am_rodc=False,
         dom_for_fun_level=None, schema=None, next_rid=None, dc_rid=None):
@@ -1231,7 +1248,7 @@ def fill_samdb(samdb, lp, names, logger, domainsid, domainguid, policyguid,
     domainControllerFunctionality = DS_DOMAIN_FUNCTION_2008_R2
 
     if dom_for_fun_level is None:
-        dom_for_fun_level = DS_DOMAIN_FUNCTION_2003
+        dom_for_fun_level = DS_DOMAIN_FUNCTION_2008_R2
 
     if dom_for_fun_level > domainControllerFunctionality:
         raise ProvisioningError("You want to run SAMBA 4 on a domain and forest function level which itself is higher than its actual DC function level (2008_R2). This won't work!")
@@ -1243,229 +1260,215 @@ def fill_samdb(samdb, lp, names, logger, domainsid, domainguid, policyguid,
     # before the provisioned tree exists and we connect
     samdb.set_ntds_settings_dn("CN=NTDS Settings,%s" % names.serverdn)
 
-    samdb.transaction_start()
-    try:
-        # Set the domain functionality levels onto the database.
-        # Various module (the password_hash module in particular) need
-        # to know what level of AD we are emulating.
-
-        # These will be fixed into the database via the database
-        # modifictions below, but we need them set from the start.
-        samdb.set_opaque_integer("domainFunctionality", domainFunctionality)
-        samdb.set_opaque_integer("forestFunctionality", forestFunctionality)
-        samdb.set_opaque_integer("domainControllerFunctionality",
-            domainControllerFunctionality)
-
-        samdb.set_domain_sid(str(domainsid))
-        samdb.set_invocation_id(invocationid)
-
-        logger.info("Adding DomainDN: %s" % names.domaindn)
-
-        # impersonate domain admin
-        admin_session_info = admin_session(lp, str(domainsid))
-        samdb.set_session_info(admin_session_info)
-        if domainguid is not None:
-            domainguid_line = "objectGUID: %s\n-" % domainguid
-        else:
-            domainguid_line = ""
+    # Set the domain functionality levels onto the database.
+    # Various module (the password_hash module in particular) need
+    # to know what level of AD we are emulating.
 
-        descr = b64encode(get_domain_descriptor(domainsid))
-        setup_add_ldif(samdb, setup_path("provision_basedn.ldif"), {
-                "DOMAINDN": names.domaindn,
-                "DOMAINSID": str(domainsid),
-                "DESCRIPTOR": descr,
-                "DOMAINGUID": domainguid_line
-                })
+    # These will be fixed into the database via the database
+    # modifictions below, but we need them set from the start.
+    samdb.set_opaque_integer("domainFunctionality", domainFunctionality)
+    samdb.set_opaque_integer("forestFunctionality", forestFunctionality)
+    samdb.set_opaque_integer("domainControllerFunctionality",
+        domainControllerFunctionality)
 
-        setup_modify_ldif(samdb, setup_path("provision_basedn_modify.ldif"), {
-            "DOMAINDN": names.domaindn,
-            "CREATTIME": str(samba.unix2nttime(int(time.time()))),
-            "NEXTRID": str(next_rid),
-            "DEFAULTSITE": names.sitename,
-            "CONFIGDN": names.configdn,
-            "POLICYGUID": policyguid,
-            "DOMAIN_FUNCTIONALITY": str(domainFunctionality),
-            "SAMBA_VERSION_STRING": version
-            })
+    samdb.set_domain_sid(str(names.domainsid))
+    samdb.set_invocation_id(invocationid)
 
-        # If we are setting up a subdomain, then this has been replicated in, so we don't need to add it
-        if fill == FILL_FULL:
-            logger.info("Adding configuration container")
-            descr = b64encode(get_config_descriptor(domainsid))
-            setup_add_ldif(samdb, setup_path("provision_configuration_basedn.ldif"), {
-                    "CONFIGDN": names.configdn,
-                    "DESCRIPTOR": descr,
-                    })
-
-            # The LDIF here was created when the Schema object was constructed
-            logger.info("Setting up sam.ldb schema")
-            samdb.add_ldif(schema.schema_dn_add, controls=["relax:0"])
-            samdb.modify_ldif(schema.schema_dn_modify)
-            samdb.write_prefixes_from_schema()
-            samdb.add_ldif(schema.schema_data, controls=["relax:0"])
-            setup_add_ldif(samdb, setup_path("aggregate_schema.ldif"),
-                           {"SCHEMADN": names.schemadn})
-
-        # Now register this container in the root of the forest
-        msg = ldb.Message(ldb.Dn(samdb, names.domaindn))
-        msg["subRefs"] = ldb.MessageElement(names.configdn , ldb.FLAG_MOD_ADD,
-                    "subRefs")
+    logger.info("Adding DomainDN: %s" % names.domaindn)
 
-    except:
-        samdb.transaction_cancel()
-        raise
+    # impersonate domain admin
+    admin_session_info = admin_session(lp, str(names.domainsid))
+    samdb.set_session_info(admin_session_info)
+    if names.domainguid is not None:
+        domainguid_line = "objectGUID: %s\n-" % names.domainguid
     else:
-        samdb.transaction_commit()
+        domainguid_line = ""
 
-    samdb.transaction_start()
-    try:
-        samdb.invocation_id = invocationid
-
-        # If we are setting up a subdomain, then this has been replicated in, so we don't need to add it
-        if fill == FILL_FULL:
-            logger.info("Setting up sam.ldb configuration data")
-
-            partitions_descr = b64encode(get_config_partitions_descriptor(domainsid))
-            sites_descr = b64encode(get_config_sites_descriptor(domainsid))
-            ntdsquotas_descr = b64encode(get_config_ntds_quotas_descriptor(domainsid))
-            protected1_descr = b64encode(get_config_delete_protected1_descriptor(domainsid))
-            protected1wd_descr = b64encode(get_config_delete_protected1wd_descriptor(domainsid))
-            protected2_descr = b64encode(get_config_delete_protected2_descriptor(domainsid))
-
-            setup_add_ldif(samdb, setup_path("provision_configuration.ldif"), {
-                    "CONFIGDN": names.configdn,
-                    "NETBIOSNAME": names.netbiosname,
-                    "DEFAULTSITE": names.sitename,
-                    "DNSDOMAIN": names.dnsdomain,
-                    "DOMAIN": names.domain,
-                    "SCHEMADN": names.schemadn,
-                    "DOMAINDN": names.domaindn,
-                    "SERVERDN": names.serverdn,
-                    "FOREST_FUNCTIONALITY": str(forestFunctionality),
-                    "DOMAIN_FUNCTIONALITY": str(domainFunctionality),
-                    "NTDSQUOTAS_DESCRIPTOR": ntdsquotas_descr,
-                    "LOSTANDFOUND_DESCRIPTOR": protected1wd_descr,
-                    "SERVICES_DESCRIPTOR": protected1_descr,
-                    "PHYSICALLOCATIONS_DESCRIPTOR": protected1wd_descr,
-                    "FORESTUPDATES_DESCRIPTOR": protected1wd_descr,
-                    "EXTENDEDRIGHTS_DESCRIPTOR": protected2_descr,
-                    "PARTITIONS_DESCRIPTOR": partitions_descr,
-                    "SITES_DESCRIPTOR": sites_descr,
-                    })
-
-            logger.info("Setting up display specifiers")
-            display_specifiers_ldif = read_ms_ldif(
-                setup_path('display-specifiers/DisplaySpecifiers-Win2k8R2.txt'))
-            display_specifiers_ldif = substitute_var(display_specifiers_ldif,
-                                                     {"CONFIGDN": names.configdn})
-            check_all_substituted(display_specifiers_ldif)
-            samdb.add_ldif(display_specifiers_ldif)
-
-            logger.info("Modifying display specifiers")
-            setup_modify_ldif(samdb,
-                setup_path("provision_configuration_modify.ldif"), {
+    descr = b64encode(get_domain_descriptor(names.domainsid))
+    setup_add_ldif(samdb, setup_path("provision_basedn.ldif"), {
+            "DOMAINDN": names.domaindn,
+            "DOMAINSID": str(names.domainsid),
+            "DESCRIPTOR": descr,
+            "DOMAINGUID": domainguid_line
+            })
+
+    setup_modify_ldif(samdb, setup_path("provision_basedn_modify.ldif"), {
+        "DOMAINDN": names.domaindn,
+        "CREATTIME": str(samba.unix2nttime(int(time.time()))),
+        "NEXTRID": str(next_rid),
+        "DEFAULTSITE": names.sitename,
+        "CONFIGDN": names.configdn,
+        "POLICYGUID": policyguid,
+        "DOMAIN_FUNCTIONALITY": str(domainFunctionality),
+        "SAMBA_VERSION_STRING": version
+        })
+
+    # If we are setting up a subdomain, then this has been replicated in, so we don't need to add it
+    if fill == FILL_FULL:
+        logger.info("Adding configuration container")
+        descr = b64encode(get_config_descriptor(names.domainsid))
+        setup_add_ldif(samdb, setup_path("provision_configuration_basedn.ldif"), {
                 "CONFIGDN": names.configdn,
-                "DISPLAYSPECIFIERS_DESCRIPTOR": protected2_descr
+                "DESCRIPTOR": descr,
                 })
 
-        logger.info("Adding users container")
-        users_desc = b64encode(get_domain_users_descriptor(domainsid))
-        setup_add_ldif(samdb, setup_path("provision_users_add.ldif"), {
-                "DOMAINDN": names.domaindn,
-                "USERS_DESCRIPTOR": users_desc
-                })
-        logger.info("Modifying users container")
-        setup_modify_ldif(samdb, setup_path("provision_users_modify.ldif"), {
-                "DOMAINDN": names.domaindn})
-        logger.info("Adding computers container")
-        computers_desc = b64encode(get_domain_computers_descriptor(domainsid))
-        setup_add_ldif(samdb, setup_path("provision_computers_add.ldif"), {
+        # The LDIF here was created when the Schema object was constructed
+        ignore_checks_oid = "local_oid:%s:0" % samba.dsdb.DSDB_CONTROL_SKIP_DUPLICATES_CHECK_OID
+        logger.info("Setting up sam.ldb schema")
+        samdb.add_ldif(schema.schema_dn_add,
+                       controls=["relax:0", ignore_checks_oid])
+        samdb.modify_ldif(schema.schema_dn_modify,
+                          controls=[ignore_checks_oid])
+        samdb.write_prefixes_from_schema()
+        samdb.add_ldif(schema.schema_data, controls=["relax:0", ignore_checks_oid])
+        setup_add_ldif(samdb, setup_path("aggregate_schema.ldif"),
+                       {"SCHEMADN": names.schemadn},
+                       controls=["relax:0", ignore_checks_oid])
+
+    # Now register this container in the root of the forest
+    msg = ldb.Message(ldb.Dn(samdb, names.domaindn))
+    msg["subRefs"] = ldb.MessageElement(names.configdn , ldb.FLAG_MOD_ADD,
+                "subRefs")
+
+    samdb.invocation_id = invocationid
+
+    # If we are setting up a subdomain, then this has been replicated in, so we don't need to add it
+    if fill == FILL_FULL:
+        logger.info("Setting up sam.ldb configuration data")
+
+        partitions_descr = b64encode(get_config_partitions_descriptor(names.domainsid))
+        sites_descr = b64encode(get_config_sites_descriptor(names.domainsid))
+        ntdsquotas_descr = b64encode(get_config_ntds_quotas_descriptor(names.domainsid))
+        protected1_descr = b64encode(get_config_delete_protected1_descriptor(names.domainsid))
+        protected1wd_descr = b64encode(get_config_delete_protected1wd_descriptor(names.domainsid))
+        protected2_descr = b64encode(get_config_delete_protected2_descriptor(names.domainsid))
+
+        setup_add_ldif(samdb, setup_path("provision_configuration.ldif"), {
+                "CONFIGDN": names.configdn,
+                "NETBIOSNAME": names.netbiosname,
+                "DEFAULTSITE": names.sitename,
+                "DNSDOMAIN": names.dnsdomain,
+                "DOMAIN": names.domain,
+                "SCHEMADN": names.schemadn,
                 "DOMAINDN": names.domaindn,
-                "COMPUTERS_DESCRIPTOR": computers_desc
+                "SERVERDN": names.serverdn,
+                "FOREST_FUNCTIONALITY": str(forestFunctionality),
+                "DOMAIN_FUNCTIONALITY": str(domainFunctionality),
+                "NTDSQUOTAS_DESCRIPTOR": ntdsquotas_descr,
+                "LOSTANDFOUND_DESCRIPTOR": protected1wd_descr,
+                "SERVICES_DESCRIPTOR": protected1_descr,
+                "PHYSICALLOCATIONS_DESCRIPTOR": protected1wd_descr,
+                "FORESTUPDATES_DESCRIPTOR": protected1wd_descr,
+                "EXTENDEDRIGHTS_DESCRIPTOR": protected2_descr,
+                "PARTITIONS_DESCRIPTOR": partitions_descr,
+                "SITES_DESCRIPTOR": sites_descr,
                 })
-        logger.info("Modifying computers container")
+
+        logger.info("Setting up display specifiers")
+        display_specifiers_ldif = read_ms_ldif(
+            setup_path('display-specifiers/DisplaySpecifiers-Win2k8R2.txt'))
+        display_specifiers_ldif = substitute_var(display_specifiers_ldif,
+                                                 {"CONFIGDN": names.configdn})
+        check_all_substituted(display_specifiers_ldif)
+        samdb.add_ldif(display_specifiers_ldif)
+
+        logger.info("Modifying display specifiers")
         setup_modify_ldif(samdb,
-            setup_path("provision_computers_modify.ldif"), {
-                "DOMAINDN": names.domaindn})
-        logger.info("Setting up sam.ldb data")
-        infrastructure_desc = b64encode(get_domain_infrastructure_descriptor(domainsid))
-        lostandfound_desc = b64encode(get_domain_delete_protected2_descriptor(domainsid))
-        system_desc = b64encode(get_domain_delete_protected1_descriptor(domainsid))
-        builtin_desc = b64encode(get_domain_builtin_descriptor(domainsid))
-        controllers_desc = b64encode(get_domain_controllers_descriptor(domainsid))
-        setup_add_ldif(samdb, setup_path("provision.ldif"), {
-            "CREATTIME": str(samba.unix2nttime(int(time.time()))),
-            "DOMAINDN": names.domaindn,
-            "NETBIOSNAME": names.netbiosname,
-            "DEFAULTSITE": names.sitename,
+            setup_path("provision_configuration_modify.ldif"), {
             "CONFIGDN": names.configdn,
-            "SERVERDN": names.serverdn,
-            "RIDAVAILABLESTART": str(next_rid + 600),
-            "POLICYGUID_DC": policyguid_dc,
-            "INFRASTRUCTURE_DESCRIPTOR": infrastructure_desc,
-            "LOSTANDFOUND_DESCRIPTOR": lostandfound_desc,
-            "SYSTEM_DESCRIPTOR": system_desc,
-            "BUILTIN_DESCRIPTOR": builtin_desc,
-            "DOMAIN_CONTROLLERS_DESCRIPTOR": controllers_desc,
+            "DISPLAYSPECIFIERS_DESCRIPTOR": protected2_descr
             })
 
-        # If we are setting up a subdomain, then this has been replicated in, so we don't need to add it
-        if fill == FILL_FULL:
-            setup_modify_ldif(samdb,
-                              setup_path("provision_configuration_references.ldif"), {
-                    "CONFIGDN": names.configdn,
-                    "SCHEMADN": names.schemadn})
+    logger.info("Adding users container")
+    users_desc = b64encode(get_domain_users_descriptor(names.domainsid))
+    setup_add_ldif(samdb, setup_path("provision_users_add.ldif"), {
+            "DOMAINDN": names.domaindn,
+            "USERS_DESCRIPTOR": users_desc
+            })
+    logger.info("Modifying users container")
+    setup_modify_ldif(samdb, setup_path("provision_users_modify.ldif"), {
+            "DOMAINDN": names.domaindn})
+    logger.info("Adding computers container")
+    computers_desc = b64encode(get_domain_computers_descriptor(names.domainsid))
+    setup_add_ldif(samdb, setup_path("provision_computers_add.ldif"), {
+            "DOMAINDN": names.domaindn,
+            "COMPUTERS_DESCRIPTOR": computers_desc
+            })
+    logger.info("Modifying computers container")
+    setup_modify_ldif(samdb,
+        setup_path("provision_computers_modify.ldif"), {
+            "DOMAINDN": names.domaindn})
+    logger.info("Setting up sam.ldb data")
+    infrastructure_desc = b64encode(get_domain_infrastructure_descriptor(names.domainsid))
+    lostandfound_desc = b64encode(get_domain_delete_protected2_descriptor(names.domainsid))
+    system_desc = b64encode(get_domain_delete_protected1_descriptor(names.domainsid))
+    builtin_desc = b64encode(get_domain_builtin_descriptor(names.domainsid))
+    controllers_desc = b64encode(get_domain_controllers_descriptor(names.domainsid))
+    setup_add_ldif(samdb, setup_path("provision.ldif"), {
+        "CREATTIME": str(samba.unix2nttime(int(time.time()))),
+        "DOMAINDN": names.domaindn,
+        "NETBIOSNAME": names.netbiosname,
+        "DEFAULTSITE": names.sitename,
+        "CONFIGDN": names.configdn,
+        "SERVERDN": names.serverdn,
+        "RIDAVAILABLESTART": str(next_rid + 600),
+        "POLICYGUID_DC": policyguid_dc,
+        "INFRASTRUCTURE_DESCRIPTOR": infrastructure_desc,
+        "LOSTANDFOUND_DESCRIPTOR": lostandfound_desc,
+        "SYSTEM_DESCRIPTOR": system_desc,
+        "BUILTIN_DESCRIPTOR": builtin_desc,
+        "DOMAIN_CONTROLLERS_DESCRIPTOR": controllers_desc,
+        })
 
-            logger.info("Setting up well known security principals")
-            protected1wd_descr = b64encode(get_config_delete_protected1wd_descriptor(domainsid))
-            setup_add_ldif(samdb, setup_path("provision_well_known_sec_princ.ldif"), {
+    # If we are setting up a subdomain, then this has been replicated in, so we don't need to add it
+    if fill == FILL_FULL:
+        setup_modify_ldif(samdb,
+                          setup_path("provision_configuration_references.ldif"), {
                 "CONFIGDN": names.configdn,
-                "WELLKNOWNPRINCIPALS_DESCRIPTOR": protected1wd_descr,
-                })
+                "SCHEMADN": names.schemadn})
 
-        if fill == FILL_FULL or fill == FILL_SUBDOMAIN:
-            setup_modify_ldif(samdb,
-                              setup_path("provision_basedn_references.ldif"),
-                              {"DOMAINDN": names.domaindn})
+        logger.info("Setting up well known security principals")
+        protected1wd_descr = b64encode(get_config_delete_protected1wd_descriptor(names.domainsid))
+        setup_add_ldif(samdb, setup_path("provision_well_known_sec_princ.ldif"), {
+            "CONFIGDN": names.configdn,
+            "WELLKNOWNPRINCIPALS_DESCRIPTOR": protected1wd_descr,
+            })
 
-            logger.info("Setting up sam.ldb users and groups")
-            setup_add_ldif(samdb, setup_path("provision_users.ldif"), {
-                "DOMAINDN": names.domaindn,
-                "DOMAINSID": str(domainsid),
-                "ADMINPASS_B64": b64encode(adminpass.encode('utf-16-le')),
-                "KRBTGTPASS_B64": b64encode(krbtgtpass.encode('utf-16-le'))
-                })
+    if fill == FILL_FULL or fill == FILL_SUBDOMAIN:
+        setup_modify_ldif(samdb,
+                          setup_path("provision_basedn_references.ldif"),
+                          {"DOMAINDN": names.domaindn})
 
-            logger.info("Setting up self join")
-            setup_self_join(samdb, admin_session_info, names=names, fill=fill,
-                invocationid=invocationid,
-                dns_backend=dns_backend,
-                dnspass=dnspass,
-                machinepass=machinepass,
-                domainsid=domainsid,
-                next_rid=next_rid,
-                dc_rid=dc_rid,
-                policyguid=policyguid,
-                policyguid_dc=policyguid_dc,
-                domainControllerFunctionality=domainControllerFunctionality,
-                ntdsguid=ntdsguid)
-
-            ntds_dn = "CN=NTDS Settings,%s" % names.serverdn
-            names.ntdsguid = samdb.searchone(basedn=ntds_dn,
-                attribute="objectGUID", expression="", scope=ldb.SCOPE_BASE)
-            assert isinstance(names.ntdsguid, str)
-    except:
-        samdb.transaction_cancel()
-        raise
-    else:
-        samdb.transaction_commit()
-        return samdb
+        logger.info("Setting up sam.ldb users and groups")
+        setup_add_ldif(samdb, setup_path("provision_users.ldif"), {
+            "DOMAINDN": names.domaindn,
+            "DOMAINSID": str(names.domainsid),
+            "ADMINPASS_B64": b64encode(adminpass.encode('utf-16-le')),
+            "KRBTGTPASS_B64": b64encode(krbtgtpass.encode('utf-16-le'))
+            })
+
+        logger.info("Setting up self join")
+        setup_self_join(samdb, admin_session_info, names=names, fill=fill,
+            invocationid=invocationid,
+            dns_backend=dns_backend,
+            dnspass=dnspass,
+            machinepass=machinepass,
+            domainsid=names.domainsid,
+            next_rid=next_rid,
+            dc_rid=dc_rid,
+            policyguid=policyguid,
+            policyguid_dc=policyguid_dc,
+            domainControllerFunctionality=domainControllerFunctionality,
+            ntdsguid=ntdsguid)
+
+        ntds_dn = "CN=NTDS Settings,%s" % names.serverdn
+        names.ntdsguid = samdb.searchone(basedn=ntds_dn,
+            attribute="objectGUID", expression="", scope=ldb.SCOPE_BASE)
+        assert isinstance(names.ntdsguid, str)
+
+    return samdb
 
 
-FILL_FULL = "FULL"
-FILL_SUBDOMAIN = "SUBDOMAIN"
-FILL_NT4SYNC = "NT4SYNC"
-FILL_DRS = "DRS"
 SYSVOL_ACL = "O:LAG:BAD:P(A;OICI;0x001f01ff;;;BA)(A;OICI;0x001200a9;;;SO)(A;OICI;0x001f01ff;;;SY)(A;OICI;0x001200a9;;;AU)"
 POLICIES_ACL = "O:LAG:BAD:P(A;OICI;0x001f01ff;;;BA)(A;OICI;0x001200a9;;;SO)(A;OICI;0x001f01ff;;;SY)(A;OICI;0x001200a9;;;AU)(A;OICI;0x001301bf;;;PA)"
 SYSVOL_SERVICE="sysvol"
@@ -1527,6 +1530,31 @@ def setsysvolacl(samdb, netlogon, sysvol, uid, gid, domainsid, dnsdomain,
     s4_passdb = None
 
     if not use_ntvfs:
+        s3conf = s3param.get_context()
+        s3conf.load(lp.configfile)
+
+        file = tempfile.NamedTemporaryFile(dir=os.path.abspath(sysvol))
+        try:
+            try:
+                smbd.set_simple_acl(file.name, 0755, gid)
+            except OSError:
+                if not smbd.have_posix_acls():
+                    # This clue is only strictly correct for RPM and
+                    # Debian-like Linux systems, but hopefully other users
+                    # will get enough clue from it.
+                    raise ProvisioningError("Samba was compiled without the posix ACL support that s3fs requires.  "
+                                            "Try installing libacl1-dev or libacl-devel, then re-run configure and make.")
+
+                raise ProvisioningError("Your filesystem or build does not support posix ACLs, which s3fs requires.  "
+                                        "Try the mounting the filesystem with the 'acl' option.")
+            try:
+                smbd.chown(file.name, uid, gid)
+            except OSError:
+                raise ProvisioningError("Unable to chown a file on your filesystem.  "
+                                        "You may not be running provision as root.")
+        finally:
+            file.close()
+
         # This will ensure that the smbd code we are running when setting ACLs
         # is initialised with the smb.conf
         s3conf = s3param.get_context()
@@ -1705,18 +1733,18 @@ def interface_ips_v4(lp):
     return ret
 
 
-def interface_ips_v6(lp, linklocal=False):
+def interface_ips_v6(lp):
     """return only IPv6 IPs"""
     ips = samba.interface_ips(lp, False)
     ret = []
     for i in ips:
-        if i.find(':') != -1 and (linklocal or i.find('%') == -1):
+        if i.find(':') != -1:
             ret.append(i)
     return ret
 
 
 def provision_fill(samdb, secrets_ldb, logger, names, paths,
-                   domainsid, schema=None,
+                   schema=None,
                    targetdir=None, samdb_fill=FILL_FULL,
                    hostip=None, hostip6=None,
                    next_rid=1000, dc_rid=None, adminpass=None, krbtgtpass=None,
@@ -1740,38 +1768,48 @@ def provision_fill(samdb, secrets_ldb, logger, names, paths,
         invocationid = str(uuid.uuid4())
 
     if krbtgtpass is None:
-        krbtgtpass = samba.generate_random_password(128, 255)
+        krbtgtpass = samba.generate_random_machine_password(128, 255)
     if machinepass is None:
-        machinepass  = samba.generate_random_password(128, 255)
+        machinepass = samba.generate_random_machine_password(128, 255)
     if dnspass is None:
         dnspass = samba.generate_random_password(128, 255)
 
-    samdb = fill_samdb(samdb, lp, names, logger=logger,
-                   domainsid=domainsid, schema=schema, domainguid=domainguid,
-                   policyguid=policyguid, policyguid_dc=policyguid_dc,
-                   fill=samdb_fill, adminpass=adminpass, krbtgtpass=krbtgtpass,
-                   invocationid=invocationid, machinepass=machinepass,
-                   dns_backend=dns_backend, dnspass=dnspass,
-                   ntdsguid=ntdsguid, serverrole=serverrole,
-                   dom_for_fun_level=dom_for_fun_level, am_rodc=am_rodc,
-                   next_rid=next_rid, dc_rid=dc_rid)
-
-    if serverrole == "active directory domain controller":
+    samdb.transaction_start()
+    try:
+        samdb = fill_samdb(samdb, lp, names, logger=logger,
+                       schema=schema,
+                       policyguid=policyguid, policyguid_dc=policyguid_dc,
+                       fill=samdb_fill, adminpass=adminpass, krbtgtpass=krbtgtpass,
+                       invocationid=invocationid, machinepass=machinepass,
+                       dns_backend=dns_backend, dnspass=dnspass,
+                       ntdsguid=ntdsguid, serverrole=serverrole,
+                       dom_for_fun_level=dom_for_fun_level, am_rodc=am_rodc,
+                       next_rid=next_rid, dc_rid=dc_rid)
 
         # Set up group policies (domain policy and domain controller
         # policy)
-        create_default_gpo(paths.sysvol, names.dnsdomain, policyguid,
-                           policyguid_dc)
+        if serverrole == "active directory domain controller":
+            create_default_gpo(paths.sysvol, names.dnsdomain, policyguid,
+                               policyguid_dc)
+    except:
+        samdb.transaction_cancel()
+        raise
+    else:
+        samdb.transaction_commit()
+
+    if serverrole == "active directory domain controller":
+        # Continue setting up sysvol for GPO. This appears to require being
+        # outside a transaction.
         if not skip_sysvolacl:
             setsysvolacl(samdb, paths.netlogon, paths.sysvol, paths.root_uid,
-                         paths.root_gid, domainsid, names.dnsdomain,
+                         paths.root_gid, names.domainsid, names.dnsdomain,
                          names.domaindn, lp, use_ntvfs)
         else:
             logger.info("Setting acl on sysvol skipped")
 
         secretsdb_self_join(secrets_ldb, domain=names.domain,
                 realm=names.realm, dnsdomain=names.dnsdomain,
-                netbiosname=names.netbiosname, domainsid=domainsid,
+                netbiosname=names.netbiosname, domainsid=names.domainsid,
                 machinepass=machinepass, secure_channel_type=SEC_CHAN_BDC)
 
         # Now set up the right msDS-SupportedEncryptionTypes into the DB
@@ -1792,10 +1830,10 @@ def provision_fill(samdb, secrets_ldb, logger, names, paths,
                 # It might be that this attribute does not exist in this schema
                 raise
 
-        setup_ad_dns(samdb, secrets_ldb, domainsid, names, paths, lp, logger,
+        setup_ad_dns(samdb, secrets_ldb, names, paths, lp, logger,
                      hostip=hostip, hostip6=hostip6, dns_backend=dns_backend,
                      dnspass=dnspass, os_level=dom_for_fun_level,
-                     targetdir=targetdir, site=DEFAULTSITE)
+                     targetdir=targetdir, fill_level=samdb_fill)
 
         domainguid = samdb.searchone(basedn=samdb.get_default_basedn(),
                                      attribute="objectGUID")
@@ -1831,6 +1869,9 @@ def provision_fill(samdb, secrets_ldb, logger, names, paths,
                                   'ipsecISAKMPReference',
                                   'ipsecNegotiationPolicyReference',
                                   'ipsecNFAReference'])
+        if chk.check_database(DN=names.schemadn, scope=ldb.SCOPE_SUBTREE,
+                attrs=['attributeId', 'governsId']) != 0:
+            raise ProvisioningError("Duplicate attributeId or governsId in schema. Must be fixed manually!!")
     except:
         samdb.transaction_cancel()
         raise
@@ -1888,7 +1929,7 @@ def provision_fake_ypserver(logger, samdb, domaindn, netbiosname, nisdomain,
         samdb.transaction_commit()
 
 
-def provision(logger, session_info, credentials, smbconf=None,
+def provision(logger, session_info, smbconf=None,
         targetdir=None, samdb_fill=FILL_FULL, realm=None, rootdn=None,
         domaindn=None, schemadn=None, configdn=None, serverdn=None,
         domain=None, hostname=None, hostip=None, hostip6=None, domainsid=None,
@@ -1898,9 +1939,10 @@ def provision(logger, session_info, credentials, smbconf=None,
         invocationid=None, machinepass=None, ntdsguid=None,
         root=None, nobody=None, users=None, backup=None, aci=None,
         serverrole=None, dom_for_fun_level=None, backend_type=None,
-        sitename=None, ol_mmr_urls=None, ol_olc=None, slapd_path="/bin/false",
+        sitename=None, ol_mmr_urls=None, ol_olc=None, slapd_path=None,
         useeadb=False, am_rodc=False, lp=None, use_ntvfs=False,
-        use_rfc2307=False, maxuid=None, maxgid=None, skip_sysvolacl=True):
+        use_rfc2307=False, maxuid=None, maxgid=None, skip_sysvolacl=True,
+        ldap_backend_forced_uri=None, nosync=False, ldap_dryrun_mode=False, ldap_backend_extra_port=None):
     """Provision samba4
 
     :note: caution, this wipes all existing data!
@@ -1920,8 +1962,6 @@ def provision(logger, session_info, credentials, smbconf=None,
 
     if domainsid is None:
         domainsid = security.random_sid()
-    else:
-        domainsid = security.dom_sid(domainsid)
 
     root_uid = findnss_uid([root or "root"])
     nobody_uid = findnss_uid([nobody or "nobody"])
@@ -1985,7 +2025,7 @@ def provision(logger, session_info, credentials, smbconf=None,
     names = guess_names(lp=lp, hostname=hostname, domain=domain,
         dnsdomain=realm, serverrole=serverrole, domaindn=domaindn,
         configdn=configdn, schemadn=schemadn, serverdn=serverdn,
-        sitename=sitename, rootdn=rootdn)
+        sitename=sitename, rootdn=rootdn, domain_names_forced=(samdb_fill == FILL_DRS))
     paths = provision_paths_from_lp(lp, names.dnsdomain)
 
     paths.bind_gid = bind_gid
@@ -2007,7 +2047,7 @@ def provision(logger, session_info, credentials, smbconf=None,
 
     if hostip6 is None:
         logger.info("Looking up IPv6 addresses")
-        hostips = interface_ips_v6(lp, linklocal=False)
+        hostips = interface_ips_v6(lp)
         if hostips:
             hostip6 = hostips[0]
         if len(hostips) > 1:
@@ -2017,46 +2057,23 @@ def provision(logger, session_info, credentials, smbconf=None,
 
     names.hostip = hostip
     names.hostip6 = hostip6
+    names.domainguid = domainguid
+    names.domainsid = domainsid
+    names.forestsid = domainsid
 
     if serverrole is None:
         serverrole = lp.get("server role")
 
     if not os.path.exists(paths.private_dir):
-        os.mkdir(paths.private_dir)
+        os.mkdir(paths.private_dir, 0o700)
     if not os.path.exists(os.path.join(paths.private_dir, "tls")):
-        os.mkdir(os.path.join(paths.private_dir, "tls"))
+        os.makedirs(os.path.join(paths.private_dir, "tls"), 0700)
     if not os.path.exists(paths.state_dir):
         os.mkdir(paths.state_dir)
 
     if paths.sysvol and not os.path.exists(paths.sysvol):
         os.makedirs(paths.sysvol, 0775)
 
-    if not use_ntvfs and serverrole == "active directory domain controller":
-        s3conf = s3param.get_context()
-        s3conf.load(lp.configfile)
-
-        if paths.sysvol is None:
-            raise MissingShareError("sysvol", paths.smbconf)
-
-        file = tempfile.NamedTemporaryFile(dir=os.path.abspath(paths.sysvol))
-        try:
-            try:
-                smbd.set_simple_acl(file.name, 0755, root_gid)
-            except Exception:
-                if not smbd.have_posix_acls():
-                    # This clue is only strictly correct for RPM and
-                    # Debian-like Linux systems, but hopefully other users
-                    # will get enough clue from it.
-                    raise ProvisioningError("Samba was compiled without the posix ACL support that s3fs requires.  Try installing libacl1-dev or libacl-devel, then re-run configure and make.")
-
-                raise ProvisioningError("Your filesystem or build does not support posix ACLs, which s3fs requires.  Try the mounting the filesystem with the 'acl' option.")
-            try:
-                smbd.chown(file.name, root_uid, root_gid)
-            except Exception:
-                raise ProvisioningError("Unable to chown a file on your filesystem.  You may not be running provision as root.")
-        finally:
-            file.close()
-
     ldapi_url = "ldapi://%s" % urllib.quote(paths.s4_ldapi_path, safe="")
 
     schema = Schema(domainsid, invocationid=invocationid,
@@ -2064,28 +2081,31 @@ def provision(logger, session_info, credentials, smbconf=None,
 
     if backend_type == "ldb":
         provision_backend = LDBBackend(backend_type, paths=paths,
-            lp=lp, credentials=credentials,
+            lp=lp,
             names=names, logger=logger)
     elif backend_type == "existing":
         # If support for this is ever added back, then the URI will need to be
         # specified again
         provision_backend = ExistingBackend(backend_type, paths=paths,
-            lp=lp, credentials=credentials,
+            lp=lp,
             names=names, logger=logger,
-            ldap_backend_forced_uri=None)
+            ldap_backend_forced_uri=ldap_backend_forced_uri)
     elif backend_type == "fedora-ds":
         provision_backend = FDSBackend(backend_type, paths=paths,
-            lp=lp, credentials=credentials,
+            lp=lp,
             names=names, logger=logger, domainsid=domainsid,
             schema=schema, hostname=hostname, ldapadminpass=ldapadminpass,
             slapd_path=slapd_path,
             root=root)
     elif backend_type == "openldap":
         provision_backend = OpenLDAPBackend(backend_type, paths=paths,
-            lp=lp, credentials=credentials,
+            lp=lp,
             names=names, logger=logger, domainsid=domainsid,
             schema=schema, hostname=hostname, ldapadminpass=ldapadminpass,
-            slapd_path=slapd_path, ol_mmr_urls=ol_mmr_urls)
+            slapd_path=slapd_path, ol_mmr_urls=ol_mmr_urls,
+            ldap_backend_extra_port=ldap_backend_extra_port,
+            ldap_dryrun_mode=ldap_dryrun_mode, nosync=nosync,
+            ldap_backend_forced_uri=ldap_backend_forced_uri)
     else:
         raise ValueError("Unknown LDAP backend type selected")
 
@@ -2101,7 +2121,7 @@ def provision(logger, session_info, credentials, smbconf=None,
     logger.info("Setting up secrets.ldb")
     secrets_ldb = setup_secretsdb(paths,
         session_info=session_info,
-        backend_credentials=provision_backend.secrets_credentials, lp=lp)
+        backend_credentials=provision_backend.credentials, lp=lp)
 
     try:
         logger.info("Setting up the registry")
@@ -2143,9 +2163,9 @@ def provision(logger, session_info, credentials, smbconf=None,
         if samdb_fill == FILL_FULL:
             provision_fill(samdb, secrets_ldb, logger, names, paths,
                     schema=schema, targetdir=targetdir, samdb_fill=samdb_fill,
-                    hostip=hostip, hostip6=hostip6, domainsid=domainsid,
+                    hostip=hostip, hostip6=hostip6,
                     next_rid=next_rid, dc_rid=dc_rid, adminpass=adminpass,
-                    krbtgtpass=krbtgtpass, domainguid=domainguid,
+                    krbtgtpass=krbtgtpass,
                     policyguid=policyguid, policyguid_dc=policyguid_dc,
                     invocationid=invocationid, machinepass=machinepass,
                     ntdsguid=ntdsguid, dns_backend=dns_backend,
@@ -2154,10 +2174,15 @@ def provision(logger, session_info, credentials, smbconf=None,
                     lp=lp, use_ntvfs=use_ntvfs,
                            skip_sysvolacl=skip_sysvolacl)
 
+        if not is_heimdal_built():
+            create_kdc_conf(paths.kdcconf, realm, domain, os.path.dirname(lp.get("log file")))
+            logger.info("The Kerberos KDC configuration for Samba AD is "
+                        "located at %s", paths.kdcconf)
+
         create_krb5_conf(paths.krb5conf,
                          dnsdomain=names.dnsdomain, hostname=names.hostname,
                          realm=names.realm)
-        logger.info("A Kerberos configuration suitable for Samba 4 has been "
+        logger.info("A Kerberos configuration suitable for Samba AD has been "
                     "generated at %s", paths.krb5conf)
 
         if serverrole == "active directory domain controller":
@@ -2223,7 +2248,7 @@ def provision_become_dc(smbconf=None, targetdir=None,
     logger = logging.getLogger("provision")
     samba.set_debug_level(debuglevel)
 
-    res = provision(logger, system_session(), None,
+    res = provision(logger, system_session(),
         smbconf=smbconf, targetdir=targetdir, samdb_fill=FILL_DRS,
         realm=realm, rootdn=rootdn, domaindn=domaindn, schemadn=schemadn,
         configdn=configdn, serverdn=serverdn, domain=domain,
@@ -2237,10 +2262,9 @@ def provision_become_dc(smbconf=None, targetdir=None,
 
 
 def create_krb5_conf(path, dnsdomain, hostname, realm):
-    """Write out a file containing zone statements suitable for inclusion in a
-    named.conf file (including GSS-TSIG configuration).
+    """Write out a file containing a valid krb5.conf file
 
-    :param path: Path of the new named.conf file.
+    :param path: Path of the new krb5.conf file.
     :param dnsdomain: DNS Domain name
     :param hostname: Local hostname
     :param realm: Realm name