Use DIGEST-MD5 authentication for OpenLDAP replication
[kai/samba.git] / source4 / scripting / python / samba / provision.py
index 93a4c8f50222e6fe76a7c22e31aeea7f11300013..f37d09d5e09811f082546997d28a39b3d20f8d22 100644 (file)
@@ -53,7 +53,7 @@ class InvalidNetbiosName(Exception):
         super(InvalidNetbiosName, self).__init__("The name '%r' is not a valid NetBIOS name" % name)
 
 
-class ProvisionPaths:
+class ProvisionPaths(object):
     def __init__(self):
         self.shareconf = None
         self.hklm = None
@@ -76,8 +76,11 @@ class ProvisionPaths:
         self.memberofconf = None
         self.fedoradsinf = None
         self.fedoradspartitions = None
-class ProvisionNames:
+       self.olmmron = None
+       self.olmmrserveridsconf = None
+       self.olmmrsyncreplconf = None
+
+class ProvisionNames(object):
     def __init__(self):
         self.rootdn = None
         self.domaindn = None
@@ -92,7 +95,8 @@ class ProvisionNames:
         self.sitename = None
         self.smbconf = None
     
-class ProvisionResult:
+
+class ProvisionResult(object):
     def __init__(self):
         self.paths = None
         self.domaindn = None
@@ -133,24 +137,17 @@ findnss_uid = lambda names: findnss(pwd.getpwnam, names)[2]
 findnss_gid = lambda names: findnss(grp.getgrnam, names)[2]
 
 
-def open_ldb(session_info, credentials, lp, dbname):
-    """Open a LDB, thrashing it if it is corrupt.
-
-    :param session_info: auth session information
-    :param credentials: credentials
-    :param lp: Loadparm context
-    :param dbname: Path of the database to open.
-    :return: a Ldb object
+def read_and_sub_file(file, subst_vars):
+    """Read a file and sub in variables found in it
+    
+    :param file: File to be read (typically from setup directory)
+     param subst_vars: Optional variables to subsitute in the file.
     """
-    assert session_info is not None
-    try:
-        return Ldb(dbname, session_info=session_info, credentials=credentials, 
-                   lp=lp)
-    except LdbError, e:
-        print e
-        os.unlink(dbname)
-        return Ldb(dbname, session_info=session_info, credentials=credentials,
-                   lp=lp)
+    data = open(file, 'r').read()
+    if subst_vars is not None:
+        data = substitute_var(data, subst_vars)
+    check_all_substituted(data)
+    return data
 
 
 def setup_add_ldif(ldb, ldif_path, subst_vars=None):
@@ -162,27 +159,18 @@ def setup_add_ldif(ldb, ldif_path, subst_vars=None):
     """
     assert isinstance(ldif_path, str)
 
-    data = open(ldif_path, 'r').read()
-    if subst_vars is not None:
-        data = substitute_var(data, subst_vars)
-
-    check_all_substituted(data)
-
+    data = read_and_sub_file(ldif_path, subst_vars)
     ldb.add_ldif(data)
 
 
-def setup_modify_ldif(ldb, ldif_path, substvars=None):
+def setup_modify_ldif(ldb, ldif_path, subst_vars=None):
     """Modify a ldb in the private dir.
     
     :param ldb: LDB object.
     :param ldif_path: LDIF file path.
-    :param substvars: Optional dictionary with substitution variables.
+    :param subst_vars: Optional dictionary with substitution variables.
     """
-    data = open(ldif_path, 'r').read()
-    if substvars is not None:
-        data = substitute_var(data, substvars)
-
-    check_all_substituted(data)
+    data = read_and_sub_file(ldif_path, subst_vars)
 
     ldb.modify_ldif(data)
 
@@ -206,23 +194,19 @@ def setup_ldb(ldb, ldif_path, subst_vars):
     ldb.transaction_commit()
 
 
-def setup_file(template, fname, substvars):
+def setup_file(template, fname, subst_vars):
     """Setup a file in the private dir.
 
     :param template: Path of the template file.
     :param fname: Path of the file to create.
-    :param substvars: Substitution variables.
+    :param subst_vars: Substitution variables.
     """
     f = fname
 
     if os.path.exists(f):
         os.unlink(f)
 
-    data = open(template, 'r').read()
-    if substvars:
-        data = substitute_var(data, substvars)
-    check_all_substituted(data)
-
+    data = read_and_sub_file(template, subst_vars)
     open(f, 'w').write(data)
 
 
@@ -244,6 +228,7 @@ def provision_paths_from_lp(lp, dnsdomain):
     paths.templates = os.path.join(paths.private_dir, "templates.ldb")
     paths.dns = os.path.join(paths.private_dir, dnsdomain + ".zone")
     paths.namedconf = os.path.join(paths.private_dir, "named.conf")
+    paths.namedtxt = os.path.join(paths.private_dir, "named.txt")
     paths.krb5conf = os.path.join(paths.private_dir, "krb5.conf")
     paths.winsdb = os.path.join(paths.private_dir, "wins.ldb")
     paths.s4_ldapi_path = os.path.join(paths.private_dir, "ldapi")
@@ -258,9 +243,13 @@ def provision_paths_from_lp(lp, dnsdomain):
     paths.memberofconf = os.path.join(paths.ldapdir, 
                                       "memberof.conf")
     paths.fedoradsinf = os.path.join(paths.ldapdir, 
-                                   "fedorads.inf")
+                                     "fedorads.inf")
     paths.fedoradspartitions = os.path.join(paths.ldapdir, 
                                             "fedorads-partitions.ldif")
+    paths.olmmrserveridsconf = os.path.join(paths.ldapdir, 
+                                            "mmr_serverids.conf")
+    paths.olmmrsyncreplconf = os.path.join(paths.ldapdir, 
+                                           "mmr_syncrepl.conf")
     paths.hklm = "hklm.ldb"
     paths.hkcr = "hkcr.ldb"
     paths.hkcu = "hkcu.ldb"
@@ -348,7 +337,7 @@ def guess_names(lp=None, hostname=None, domain=None, dnsdomain=None, serverrole=
     names.hostname = hostname
     names.sitename = sitename
     names.serverdn = "CN=%s,CN=Servers,CN=%s,CN=Sites,%s" % (netbiosname, sitename, configdn)
-    
     return names
     
 
@@ -503,6 +492,8 @@ def setup_samdb_partitions(samdb_path, setup_path, message, lp, session_info,
         backend_modules = ["normalise", "entryuuid", "paged_searches"]
         # OpenLDAP handles subtree renames, so we don't want to do any of these things
         tdb_modules_list = None
+    elif ldap_backend is not None:
+        raise "LDAP Backend specified, but LDAP Backend Type not specified"
     elif serverrole == "domain controller":
         backend_modules = ["repl_meta_data"]
     else:
@@ -604,6 +595,20 @@ def setup_secretsdb(path, setup_path, session_info, credentials, lp):
     secrets_ldb = Ldb(path, session_info=session_info, credentials=credentials,
                       lp=lp)
     secrets_ldb.load_ldif_file_add(setup_path("secrets.ldif"))
+
+    if credentials is not None and credentials.authentication_requested():
+        if credentials.get_bind_dn() is not None:
+            setup_add_ldif(secrets_ldb, setup_path("secrets_simple_ldap.ldif"), {
+                    "LDAPMANAGERDN": credentials.get_bind_dn(),
+                    "LDAPMANAGERPASS_B64": b64encode(credentials.get_password())
+                    })
+        else:
+            setup_add_ldif(secrets_ldb, setup_path("secrets_sasl_ldap.ldif"), {
+                    "LDAPADMINUSER": credentials.get_username(),
+                    "LDAPADMINREALM": credentials.get_realm(),
+                    "LDAPADMINPASS_B64": b64encode(credentials.get_password())
+                    })
+
     return secrets_ldb
 
 
@@ -618,7 +623,17 @@ def setup_templatesdb(path, setup_path, session_info, credentials, lp):
     """
     templates_ldb = SamDB(path, session_info=session_info,
                           credentials=credentials, lp=lp)
-    templates_ldb.erase()
+    # Wipes the database
+    try:
+        templates_ldb.erase()
+    except:
+        os.unlink(path)
+
+    templates_ldb.load_ldif_file_add(setup_path("provision_templates_init.ldif"))
+
+    templates_ldb = SamDB(path, session_info=session_info,
+                          credentials=credentials, lp=lp)
+
     templates_ldb.load_ldif_file_add(setup_path("provision_templates.ldif"))
 
 
@@ -730,19 +745,14 @@ def setup_samdb(path, setup_path, session_info, credentials, lp,
     samdb = SamDB(path, session_info=session_info, 
                   credentials=credentials, lp=lp)
 
-    if fill == FILL_DRS:
-       # We want to finish here, but setup the index before we do so
-        message("Setting up sam.ldb index")
-        samdb.load_ldif_file_add(setup_path("provision_index.ldif"))
-        return samdb
-
     message("Pre-loading the Samba 4 and AD schema")
     samdb.set_domain_sid(domainsid)
     if serverrole == "domain controller":
         samdb.set_invocation_id(invocationid)
 
     load_schema(setup_path, samdb, names.schemadn, names.netbiosname, 
-                names.configdn, names.sitename)
+                names.configdn, names.sitename, names.serverdn,
+                names.hostname)
 
     samdb.transaction_start()
         
@@ -754,10 +764,10 @@ def setup_samdb(path, setup_path, session_info, credentials, lp,
             domain_oc = "samba4LocalDomain"
 
         setup_add_ldif(samdb, setup_path("provision_basedn.ldif"), {
-            "DOMAINDN": names.domaindn,
-            "ACI": aci,
-            "DOMAIN_OC": domain_oc
-            })
+                "DOMAINDN": names.domaindn,
+                "ACI": aci,
+                "DOMAIN_OC": domain_oc
+                })
 
         message("Modifying DomainDN: " + names.domaindn + "")
         if domainguid is not None:
@@ -782,7 +792,6 @@ def setup_samdb(path, setup_path, session_info, credentials, lp,
         setup_add_ldif(samdb, setup_path("provision_configuration_basedn.ldif"), {
             "CONFIGDN": names.configdn, 
             "ACI": aci,
-            "EXTENSIBLEOBJECT": "# no objectClass: extensibleObject for local ldb",
             })
         message("Modifying configuration container")
         setup_modify_ldif(samdb, setup_path("provision_configuration_basedn_modify.ldif"), {
@@ -794,7 +803,6 @@ def setup_samdb(path, setup_path, session_info, credentials, lp,
         setup_add_ldif(samdb, setup_path("provision_schema_basedn.ldif"), {
             "SCHEMADN": names.schemadn,
             "ACI": aci,
-            "EXTENSIBLEOBJECT": "# no objectClass: extensibleObject for local ldb"
             })
         message("Modifying schema container")
 
@@ -872,9 +880,6 @@ def setup_samdb(path, setup_path, session_info, credentials, lp,
                                 domainsid=domainsid, policyguid=policyguid,
                                 setup_path=setup_path)
 
-    #We want to setup the index last, as adds are faster unindexed
-        message("Setting up sam.ldb index")
-        samdb.load_ldif_file_add(setup_path("provision_index.ldif"))
     except:
         samdb.transaction_cancel()
         raise
@@ -1029,6 +1034,7 @@ def provision(setup_dir, message, session_info,
         policy_path = os.path.join(paths.sysvol, names.dnsdomain, "Policies", 
                                    "{" + policyguid + "}")
         os.makedirs(policy_path, 0755)
+        open(os.path.join(policy_path, "GPT.INI"), 'w').write("")
         os.makedirs(os.path.join(policy_path, "Machine"), 0755)
         os.makedirs(os.path.join(policy_path, "User"), 0755)
         if not os.path.isdir(paths.netlogon):
@@ -1067,12 +1073,15 @@ def provision(setup_dir, message, session_info,
                              hostip6=hostip6, hostname=names.hostname,
                              dnspass=dnspass, realm=names.realm,
                              domainguid=domainguid, hostguid=hostguid)
-            message("Please install the zone located in %s into your DNS server" % paths.dns)
 
             create_named_conf(paths.namedconf, setup_path, realm=names.realm,
+                              dnsdomain=names.dnsdomain, private_dir=paths.private_dir)
+
+            create_named_txt(paths.namedtxt, setup_path, realm=names.realm,
                               dnsdomain=names.dnsdomain, private_dir=paths.private_dir,
                               keytab_name=paths.dns_keytab)
-            message("See %s for example configuration statements for secure GSS-TSIG updates" % paths.namedconf)
+            message("See %s for an example configuration include file for BIND" % paths.namedconf)
+            message("and %s for further documentation required for secure DNS updates" % paths.namedtxt)
 
             create_krb5_conf(paths.krb5conf, setup_path, dnsdomain=names.dnsdomain,
                              hostname=names.hostname, realm=names.realm)
@@ -1139,7 +1148,8 @@ def provision_backend(setup_dir=None, message=None,
                       smbconf=None, targetdir=None, realm=None, 
                       rootdn=None, domaindn=None, schemadn=None, configdn=None,
                       domain=None, hostname=None, adminpass=None, root=None, serverrole=None, 
-                      ldap_backend_type=None, ldap_backend_port=None):
+                      ldap_backend_type=None, ldap_backend_port=None,
+                     ol_mmr_urls=None):
 
     def setup_path(file):
         return os.path.join(setup_dir, file)
@@ -1150,15 +1160,18 @@ def provision_backend(setup_dir=None, message=None,
     if root is None:
         root = findnss(pwd.getpwnam, ["root"])[0]
 
-    if smbconf is None:
-        etcdir = os.path.join(targetdir, "etc")
-        os.makedirs(etcdir)
-        smbconf = os.path.join(etcdir, "smb.conf")
+    if adminpass is None:
+        adminpass = misc.random_password(12)
+
+    if targetdir is not None:
+        if (not os.path.exists(os.path.join(targetdir, "etc"))):
+            os.makedirs(os.path.join(targetdir, "etc"))
+        smbconf = os.path.join(targetdir, "etc", "smb.conf")
 
     # only install a new smb.conf if there isn't one there already
     if not os.path.exists(smbconf):
-        make_smbconf(smbconf, setup_path, hostname, domain, realm, 
-                              serverrole, targetdir)
+        make_smbconf(smbconf, setup_path, hostname, domain, realm, serverrole, 
+                     targetdir)
 
     lp = param.LoadParm()
     lp.load(smbconf)
@@ -1171,7 +1184,7 @@ def provision_backend(setup_dir=None, message=None,
     paths = provision_paths_from_lp(lp, names.dnsdomain)
 
     if not os.path.isdir(paths.ldapdir):
-        os.makedirs(paths.ldapdir)
+        os.makedirs(paths.ldapdir, 0700)
     schemadb_path = os.path.join(paths.ldapdir, "schema-tmp.ldb")
     try:
         os.unlink(schemadb_path)
@@ -1185,7 +1198,6 @@ def provision_backend(setup_dir=None, message=None,
     setup_add_ldif(schemadb, setup_path("provision_schema_basedn.ldif"), 
                    {"SCHEMADN": names.schemadn,
                     "ACI": "#",
-                    "EXTENSIBLEOBJECT": "# no objectClass: extensibleObject for local ldb"
                     })
     setup_modify_ldif(schemadb, 
                       setup_path("provision_schema_basedn_modify.ldif"), \
@@ -1228,13 +1240,15 @@ def provision_backend(setup_dir=None, message=None,
         
         slapdcommand="Initailise Fedora DS with: setup-ds.pl --file=%s" % paths.fedoradsinf
        
+        ldapuser = "--simple-bind-dn=" + names.ldapmanagerdn
+
     elif ldap_backend_type == "openldap":
         attrs = ["linkID", "lDAPDisplayName"]
-    res = schemadb.search(expression="(&(&(linkID=*)(!(linkID:1.2.840.113556.1.4.803:=1)))(objectclass=attributeSchema))", base=names.schemadn, scope=SCOPE_SUBTREE, attrs=attrs)
+        res = schemadb.search(expression="(&(&(linkID=*)(!(linkID:1.2.840.113556.1.4.803:=1)))(objectclass=attributeSchema))", base=names.schemadn, scope=SCOPE_SUBTREE, attrs=attrs)
 
-    memberof_config = "# Generated from schema in %s\n" % schemadb_path
-    refint_attributes = ""
-    for i in range (0, len(res)):
+        memberof_config = "# Generated from schema in %s\n" % schemadb_path
+        refint_attributes = ""
+        for i in range (0, len(res)):
             expression = "(&(objectclass=attributeSchema)(linkID=%d))" % (int(res[i]["linkID"][0])+1)
             target = schemadb.searchone(basedn=names.schemadn, 
                                         expression=expression, 
@@ -1242,59 +1256,135 @@ def provision_backend(setup_dir=None, message=None,
                                         scope=SCOPE_SUBTREE)
             if target is not None:
                 refint_attributes = refint_attributes + " " + target + " " + res[i]["lDAPDisplayName"][0]
-                memberof_config += """overlay memberof
-memberof-dangling error
-memberof-refint TRUE
-memberof-group-oc top
-memberof-member-ad """ + res[i]["lDAPDisplayName"][0] + """
-memberof-memberof-ad """ + target + """
-memberof-dangling-error 32
-
-"""
-
-    memberof_config += """
-overlay refint
-refint_attributes""" + refint_attributes + "\n"
-    
-    setup_file(setup_path("slapd.conf"), paths.slapdconf,
+            
+                memberof_config += read_and_sub_file(setup_path("memberof.conf"),
+                                                     { "MEMBER_ATTR" : str(res[i]["lDAPDisplayName"][0]),
+                                                       "MEMBEROF_ATTR" : str(target) })
+
+        refint_config = read_and_sub_file(setup_path("refint.conf"),
+                                            { "LINK_ATTRS" : refint_attributes})
+
+# generate serverids, ldap-urls and syncrepl-blocks for mmr hosts
+       mmr_on_config = ""
+       mmr_replicator_acl = ""
+       mmr_serverids_config = ""
+        mmr_syncrepl_schema_config = "" 
+       mmr_syncrepl_config_config = "" 
+       mmr_syncrepl_user_config = "" 
+       
+       if ol_mmr_urls is not None:
+               url_list=filter(None,ol_mmr_urls.split(' ')) 
+                if (len(url_list) == 1):
+                    url_list=filter(None,ol_mmr_urls.split(',')) 
+                     
+
+               mmr_on_config = "MirrorMode On"
+               mmr_replicator_acl = "  by dn=cn=replicator,cn=samba read"
+               serverid=0
+               for url in url_list:
+                       serverid=serverid+1
+                       mmr_serverids_config += read_and_sub_file(setup_path("mmr_serverids.conf"),
+                                                                    { "SERVERID" : str(serverid),
+                                                                      "LDAPSERVER" : url })
+                        rid=serverid*10
+                       rid=rid+1
+                       mmr_syncrepl_schema_config += read_and_sub_file(setup_path("mmr_syncrepl.conf"),
+                                                                    {  "RID" : str(rid),
+                                                                       "MMRDN": names.schemadn,
+                                                                       "LDAPSERVER" : url,
+                                                                        "MMR_PASSWORD": adminpass})
+
+                       rid=rid+1
+                       mmr_syncrepl_config_config += read_and_sub_file(setup_path("mmr_syncrepl.conf"),
+                                                                    {  "RID" : str(rid),
+                                                                       "MMRDN": names.configdn,
+                                                                       "LDAPSERVER" : url,
+                                                                        "MMR_PASSWORD": adminpass})
+
+                       rid=rid+1
+                       mmr_syncrepl_user_config += read_and_sub_file(setup_path("mmr_syncrepl.conf"),
+                                                                    {  "RID" : str(rid),
+                                                                       "MMRDN": names.domaindn,
+                                                                       "LDAPSERVER" : url,
+                                                                        "MMR_PASSWORD": adminpass })
+
+
+        setup_file(setup_path("slapd.conf"), paths.slapdconf,
                    {"DNSDOMAIN": names.dnsdomain,
                     "LDAPDIR": paths.ldapdir,
                     "DOMAINDN": names.domaindn,
                     "CONFIGDN": names.configdn,
                     "SCHEMADN": names.schemadn,
-                    "LDAPMANAGERDN": names.ldapmanagerdn,
-                    "LDAPMANAGERPASS": adminpass,
-                    "MEMBEROF_CONFIG": memberof_config})
-    setup_file(setup_path("modules.conf"), paths.modulesconf,
+                    "MEMBEROF_CONFIG": memberof_config,
+                    "MIRRORMODE": mmr_on_config,
+                    "REPLICATOR_ACL": mmr_replicator_acl,
+                    "MMR_SERVERIDS_CONFIG": mmr_serverids_config,
+                    "MMR_SYNCREPL_SCHEMA_CONFIG": mmr_syncrepl_schema_config,
+                    "MMR_SYNCREPL_CONFIG_CONFIG": mmr_syncrepl_config_config,
+                    "MMR_SYNCREPL_USER_CONFIG": mmr_syncrepl_user_config,
+                    "MMR_PASSWORD": adminpass,
+                    "REFINT_CONFIG": refint_config})
+       setup_file(setup_path("modules.conf"), paths.modulesconf,
                    {"REALM": names.realm})
         
-    setup_db_config(setup_path, os.path.join(paths.ldapdir, os.path.join("db", "user")))
-    setup_db_config(setup_path, os.path.join(paths.ldapdir, os.path.join("db", "config")))
-    setup_db_config(setup_path, os.path.join(paths.ldapdir, os.path.join("db", "schema")))
-    mapping = "schema-map-openldap-2.3"
-    backend_schema = "backend-schema.schema"
-
-    ldapi_uri = "ldapi://" + urllib.quote(os.path.join(paths.private_dir, "ldap", "ldapi"), safe="")
-    if ldap_backend_port is not None:
-        server_port_string = " -h ldap://0.0.0.0:%d" % ldap_backend_port
-    else:
-        server_port_string = ""
-    slapdcommand="Start slapd with:    slapd -f " + paths.ldapdir + "/slapd.conf -h " + ldapi_uri + server_port_string
+        setup_db_config(setup_path, os.path.join(paths.ldapdir, "db", "user"))
+        setup_db_config(setup_path, os.path.join(paths.ldapdir, "db", "config"))
+        setup_db_config(setup_path, os.path.join(paths.ldapdir, "db", "schema"))
+
+        if not os.path.exists(os.path.join(paths.ldapdir, "db", "samba",  "cn=samba")):
+            os.makedirs(os.path.join(paths.ldapdir, "db", "samba",  "cn=samba"), 0700)
+
+        setup_file(setup_path("cn=samba.ldif"), 
+                   os.path.join(paths.ldapdir, "db", "samba",  "cn=samba.ldif"),
+                   { "UUID": str(uuid.uuid4()), 
+                     "LDAPTIME": timestring(int(time.time()))} )
+        setup_file(setup_path("cn=samba-admin.ldif"), 
+                              os.path.join(paths.ldapdir, "db", "samba",  "cn=samba", "cn=samba-admin.ldif"),
+                              {"LDAPADMINPASS_B64": b64encode(adminpass),
+                               "UUID": str(uuid.uuid4()), 
+                               "LDAPTIME": timestring(int(time.time()))} )
+       
+       if ol_mmr_urls is not None:
+          setup_file(setup_path("cn=replicator.ldif"),
+                              os.path.join(paths.ldapdir, "db", "samba",  "cn=samba", "cn=replicator.ldif"),
+                              {"LDAPADMINPASS_B64": b64encode(adminpass),
+                               "UUID": str(uuid.uuid4()),
+                               "LDAPTIME": timestring(int(time.time()))} )
+
+
+
+        mapping = "schema-map-openldap-2.3"
+        backend_schema = "backend-schema.schema"
+
+        ldapi_uri = "ldapi://" + urllib.quote(os.path.join(paths.private_dir, "ldap", "ldapi"), safe="")
+        if ldap_backend_port is not None:
+            server_port_string = " -h ldap://0.0.0.0:%d" % ldap_backend_port
+        else:
+            server_port_string = ""
 
-    schema_command = "bin/ad2oLschema --option=convert:target=" + ldap_backend_type + " -I " + setup_path(mapping) + " -H tdb://" + schemadb_path + " -O " + os.path.join(paths.ldapdir, backend_schema)
+        slapdcommand="Start slapd with:    slapd -f " + paths.ldapdir + "/slapd.conf -h " + ldapi_uri + server_port_string
 
-    os.system(schema_command)
+        ldapuser = "--username=samba-admin"
 
+            
+    schema_command = "bin/ad2oLschema --option=convert:target=" + ldap_backend_type + " -I " + setup_path(mapping) + " -H tdb://" + schemadb_path + " -O " + os.path.join(paths.ldapdir, backend_schema)
+            
+    os.system(schema_command)
 
     message("Your %s Backend for Samba4 is now configured, and is ready to be started" % ldap_backend_type)
     message("Server Role:         %s" % serverrole)
     message("Hostname:            %s" % names.hostname)
     message("DNS Domain:          %s" % names.dnsdomain)
     message("Base DN:             %s" % names.domaindn)
-    message("LDAP admin DN:       %s" % names.ldapmanagerdn)
+
+    if ldap_backend_type == "openldap":
+        message("LDAP admin user:     samba-admin")
+    else:
+        message("LDAP admin DN:       %s" % names.ldapmanagerdn)
+
     message("LDAP admin password: %s" % adminpass)
     message(slapdcommand)
-
+    message("Run provision with:  --ldap-backend=ldapi --ldap-backend-type=" + ldap_backend_type + " --password=" + adminpass + " " + ldapuser)
 
 def create_phpldapadmin_config(path, setup_path, ldapi_uri):
     """Create a PHP LDAP admin configuration file.
@@ -1347,7 +1437,7 @@ def create_zone_file(path, setup_path, dnsdomain, domaindn,
 
 
 def create_named_conf(path, setup_path, realm, dnsdomain,
-                      private_dir, keytab_name):
+                      private_dir):
     """Write out a file containing zone statements suitable for inclusion in a
     named.conf file (including GSS-TSIG configuration).
     
@@ -1363,8 +1453,28 @@ def create_named_conf(path, setup_path, realm, dnsdomain,
             "DNSDOMAIN": dnsdomain,
             "REALM": realm,
             "REALM_WC": "*." + ".".join(realm.split(".")[1:]),
+            "PRIVATE_DIR": private_dir
+            })
+
+def create_named_txt(path, setup_path, realm, dnsdomain,
+                      private_dir, keytab_name):
+    """Write out a file containing zone statements suitable for inclusion in a
+    named.conf file (including GSS-TSIG configuration).
+    
+    :param path: Path of the new named.conf file.
+    :param setup_path: Setup path function.
+    :param realm: Realm name
+    :param dnsdomain: DNS Domain name
+    :param private_dir: Path to private directory
+    :param keytab_name: File name of DNS keytab file
+    """
+
+    setup_file(setup_path("named.txt"), path, {
+            "DNSDOMAIN": dnsdomain,
+            "REALM": realm,
             "DNS_KEYTAB": keytab_name,
             "DNS_KEYTAB_ABS": os.path.join(private_dir, keytab_name),
+            "PRIVATE_DIR": private_dir
         })
 
 def create_krb5_conf(path, setup_path, dnsdomain, hostname, realm):
@@ -1385,7 +1495,8 @@ def create_krb5_conf(path, setup_path, dnsdomain, hostname, realm):
         })
 
 
-def load_schema(setup_path, samdb, schemadn, netbiosname, configdn, sitename):
+def load_schema(setup_path, samdb, schemadn, netbiosname, configdn, sitename,
+                serverdn, servername):
     """Load schema for the SamDB.
     
     :param samdb: Load a schema into a SamDB.
@@ -1393,10 +1504,13 @@ def load_schema(setup_path, samdb, schemadn, netbiosname, configdn, sitename):
     :param schemadn: DN of the schema
     :param netbiosname: NetBIOS name of the host.
     :param configdn: DN of the configuration
+    :param serverdn: DN of the server
+    :param servername: Host name of the server
     """
     schema_data = open(setup_path("schema.ldif"), 'r').read()
     schema_data += open(setup_path("schema_samba4.ldif"), 'r').read()
     schema_data = substitute_var(schema_data, {"SCHEMADN": schemadn})
+    check_all_substituted(schema_data)
     prefixmap = open(setup_path("prefixMap.txt"), 'r').read()
     prefixmap = b64encode(prefixmap)
 
@@ -1405,8 +1519,11 @@ def load_schema(setup_path, samdb, schemadn, netbiosname, configdn, sitename):
                     "SCHEMADN": schemadn,
                     "NETBIOSNAME": netbiosname,
                     "CONFIGDN": configdn,
-                    "DEFAULTSITE":sitename,
-                    "PREFIXMAP_B64":prefixmap
+                    "DEFAULTSITE": sitename,
+                    "PREFIXMAP_B64": prefixmap,
+                    "SERVERDN": serverdn,
+                    "SERVERNAME": servername,
     })
+    check_all_substituted(head_data)
     samdb.attach_schema_from_ldif(head_data, schema_data)