s4-provision: Reset "debuglevel" after "provision" take place
[mat/samba.git] / source4 / scripting / python / samba / provision.py
index bb8b93e26822762f9cce911b1faafba4f3ea5832..99e2e13c32a33e2033af0425bde88352a52ed9ee 100644 (file)
@@ -43,7 +43,7 @@ from samba.auth import system_session, admin_session
 import samba
 from samba import version, Ldb, substitute_var, valid_netbios_name
 from samba import check_all_substituted, read_and_sub_file, setup_file
-from samba.dsdb import DS_DOMAIN_FUNCTION_2003, DS_DOMAIN_FUNCTION_2008_R2
+from samba.dsdb import DS_DOMAIN_FUNCTION_2003, DS_DOMAIN_FUNCTION_2008_R2, ENC_ALL_TYPES
 from samba.dcerpc import security
 from samba.dcerpc.misc import SEC_CHAN_BDC, SEC_CHAN_WKSTA
 from samba.idmap import IDmapDB
@@ -62,6 +62,8 @@ from samba.schema import Schema
 from samba.samdb import SamDB
 
 __docformat__ = "restructuredText"
+DEFAULT_POLICY_GUID = "31B2F340-016D-11D2-945F-00C04FB984F9"
+DEFAULT_DC_POLICY_GUID = "6AC1786C-016F-11D2-945F-00C04fB984F9"
 
 def find_setup_dir():
     """Find the setup directory used by provision."""
@@ -387,6 +389,7 @@ def provision_paths_from_lp(lp, dnsdomain):
     # This is stored without path prefix for the "privateKeytab" attribute in
     # "secrets_dns.ldif".
     paths.dns_keytab = "dns.keytab"
+    paths.keytab = "secrets.keytab"
 
     paths.shareconf = os.path.join(paths.private_dir, "share.ldb")
     paths.samdb = os.path.join(paths.private_dir, lp.get("sam database") or "samdb.ldb")
@@ -464,7 +467,7 @@ def guess_names(lp=None, hostname=None, domain=None, dnsdomain=None,
         domain = domain.upper()
 
         if lp.get("workgroup").upper() != domain:
-            raise ProvisioningError("guess_names: Workgroup '%s' in %s must match chosen domain '%s'!  Please remove the %s file and let provision generate it" % (lp.get("workgroup").upper(), domain, lp.configfile))
+            raise ProvisioningError("guess_names: Workgroup '%s' in smb.conf must match chosen domain '%s'!  Please remove the %s file and let provision generate it" % (lp.get("workgroup").upper(), domain, lp.configfile))
 
         if domaindn is None:
             domaindn = "DC=" + dnsdomain.replace(".", ",DC=")
@@ -567,6 +570,13 @@ def make_smbconf(smbconf, setup_path, hostname, domain, realm, serverrole,
     else:
         sid_generator_line = "sid generator = " + sid_generator
 
+    used_setup_dir = setup_path("")
+    default_setup_dir = default_lp.get("setup directory")
+    setupdir_line = ""
+    if used_setup_dir != default_setup_dir:
+        setupdir_line = "setup directory = %s" % used_setup_dir
+        default_lp.set("setup directory", used_setup_dir)
+
     sysvol = os.path.join(default_lp.get("lock dir"), "sysvol")
     netlogon = os.path.join(sysvol, realm.lower(), "scripts")
 
@@ -578,6 +588,7 @@ def make_smbconf(smbconf, setup_path, hostname, domain, realm, serverrole,
             "SERVERROLE": serverrole,
             "NETLOGONPATH": netlogon,
             "SYSVOLPATH": sysvol,
+            "SETUPDIRECTORY_LINE": setupdir_line,
             "SIDGENERATOR_LINE": sid_generator_line,
             "PRIVATEDIR_LINE": privatedir_line,
             "LOCKDIR_LINE": lockdir_line,
@@ -677,57 +688,77 @@ def secretsdb_self_join(secretsdb, domain,
            "priorChanged",
            "krb5Keytab",
            "privateKeytab"]
-    
 
-    msg = ldb.Message(ldb.Dn(secretsdb, "flatname=%s,cn=Primary Domains" % domain))
-    msg["secureChannelType"] = str(secure_channel_type)
-    msg["flatname"] = [domain]
-    msg["objectClass"] = ["top", "primaryDomain"]
     if realm is not None:
       if dnsdomain is None:
-        dnsdomain = realm.lower()
+          dnsdomain = realm.lower()
+      dnsname = '%s.%s' % (netbiosname.lower(), dnsdomain.lower())
+    else:
+      dnsname = None
+    shortname = netbiosname.lower()
+    
+    #We don't need to set msg["flatname"] here, because rdn_name will handle it, and it causes problems for modifies anyway
+    msg = ldb.Message(ldb.Dn(secretsdb, "flatname=%s,cn=Primary Domains" % domain))
+    msg["secureChannelType"] = [str(secure_channel_type)]
+    msg["objectClass"] = ["top", "primaryDomain"]
+    if dnsname is not None:
       msg["objectClass"] = ["top", "primaryDomain", "kerberosSecret"]
-      msg["realm"] = realm
-      msg["saltPrincipal"] = "host/%s.%s@%s" % (netbiosname.lower(), dnsdomain.lower(), realm.upper())
+      msg["realm"] = [realm]
+      msg["saltPrincipal"] = ["host/%s@%s" % (dnsname, realm.upper())]
       msg["msDS-KeyVersionNumber"] = [str(key_version_number)]
       msg["privateKeytab"] = ["secrets.keytab"]
 
-
     msg["secret"] = [machinepass]
     msg["samAccountName"] = ["%s$" % netbiosname]
     msg["secureChannelType"] = [str(secure_channel_type)]
     if domainsid is not None:
         msg["objectSid"] = [ndr_pack(domainsid)]
     
+    # This complex expression tries to ensure that we don't have more
+    # than one record for this SID, realm or netbios domain at a time,
+    # but we don't delete the old record that we are about to modify,
+    # because that would delete the keytab and previous password.
     res = secretsdb.search(base="cn=Primary Domains", 
                            attrs=attrs, 
-                           expression=("(&(|(flatname=%s)(realm=%s)(objectSid=%s))(objectclass=primaryDomain))" % (domain, realm, str(domainsid))), 
+                           expression=("(&(|(flatname=%s)(realm=%s)(objectSid=%s))(objectclass=primaryDomain)(!(dn=%s)))" % (domain, realm, str(domainsid), str(msg.dn))),
                            scope=ldb.SCOPE_ONELEVEL)
     
     for del_msg in res:
-      if del_msg.dn is not msg.dn:
         secretsdb.delete(del_msg.dn)
 
     res = secretsdb.search(base=msg.dn, attrs=attrs, scope=ldb.SCOPE_BASE)
 
     if len(res) == 1:
-      msg["priorSecret"] = res[0]["secret"]
-      msg["priorWhenChanged"] = res[0]["whenChanged"]
+      msg["priorSecret"] = [res[0]["secret"][0]]
+      msg["priorWhenChanged"] = [res[0]["whenChanged"][0]]
 
-      if res["privateKeytab"] is not None:
-        msg["privateKeytab"] = res[0]["privateKeytab"]
+      try:
+        msg["privateKeytab"] = [res[0]["privateKeytab"][0]]
+      except KeyError:
+        pass
 
-      if res["krb5Keytab"] is not None:
-        msg["krb5Keytab"] = res[0]["krb5Keytab"]
+      try:
+        msg["krb5Keytab"] = [res[0]["krb5Keytab"][0]]
+      except KeyError:
+        pass
 
       for el in msg:
-        el.set_flags(ldb.FLAG_MOD_REPLACE)
-        secretsdb.modify(msg)
+          if el != 'dn':
+              msg[el].set_flags(ldb.FLAG_MOD_REPLACE)
+      secretsdb.modify(msg)
+      secretsdb.rename(res[0].dn, msg.dn)
     else:
+      spn = [ 'HOST/%s' % shortname ]
+      if secure_channel_type == SEC_CHAN_BDC and dnsname is not None:
+          # we are a domain controller then we add servicePrincipalName entries
+          # for the keytab code to update
+          spn.extend([ 'HOST/%s' % dnsname ])
+      msg["servicePrincipalName"] = spn
+
       secretsdb.add(msg)
 
 
-def secretsdb_setup_dns(secretsdb, setup_path, private_dir,
+def secretsdb_setup_dns(secretsdb, setup_path, names, private_dir,
                         realm, dnsdomain,
                         dns_keytab_path, dnspass):
     """Add DNS specific bits to a secrets database.
@@ -746,10 +777,12 @@ def secretsdb_setup_dns(secretsdb, setup_path, private_dir,
             "DNSDOMAIN": dnsdomain,
             "DNS_KEYTAB": dns_keytab_path,
             "DNSPASS_B64": b64encode(dnspass),
+            "HOSTNAME": names.hostname,
+            "DNSNAME" : '%s.%s' % (names.netbiosname.lower(), names.dnsdomain.lower())
             })
 
 
-def setup_secretsdb(path, setup_path, session_info, backend_credentials, lp):
+def setup_secretsdb(paths, setup_path, session_info, backend_credentials, lp):
     """Setup the secrets database.
 
    :note: This function does not handle exceptions and transaction on purpose,
@@ -762,8 +795,19 @@ def setup_secretsdb(path, setup_path, session_info, backend_credentials, lp):
     :param lp: Loadparm context
     :return: LDB handle for the created secrets database
     """
-    if os.path.exists(path):
-        os.unlink(path)
+    if os.path.exists(paths.secrets):
+        os.unlink(paths.secrets)
+
+    keytab_path = os.path.join(paths.private_dir, paths.keytab)
+    if os.path.exists(keytab_path):
+        os.unlink(keytab_path)
+
+    dns_keytab_path = os.path.join(paths.private_dir, paths.dns_keytab)
+    if os.path.exists(dns_keytab_path):
+        os.unlink(dns_keytab_path)
+
+    path = paths.secrets
+
     secrets_ldb = Ldb(path, session_info=session_info, 
                       lp=lp)
     secrets_ldb.erase()
@@ -855,10 +899,6 @@ def setup_samdb_rootdse(samdb, setup_path, names):
     """
     setup_add_ldif(samdb, setup_path("provision_rootdse_add.ldif"), {
         "SCHEMADN": names.schemadn, 
-        "NETBIOSNAME": names.netbiosname,
-        "DNSDOMAIN": names.dnsdomain,
-        "REALM": names.realm,
-        "DNSNAME": "%s.%s" % (names.hostname, names.dnsdomain),
         "DOMAINDN": names.domaindn,
         "ROOTDN": names.rootdn,
         "CONFIGDN": names.configdn,
@@ -904,7 +944,7 @@ def setup_self_join(samdb, names,
               "DOMAINDN": names.domaindn})
     
     # add the NTDSGUID based SPNs
-    ntds_dn = "CN=NTDS Settings,CN=%s,CN=Servers,CN=%s,CN=Sites,CN=Configuration,%s" % (names.hostname, names.sitename, names.domaindn)
+    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)
@@ -920,26 +960,56 @@ def setup_self_join(samdb, names,
               "SERVERDN": names.serverdn,
               "NETBIOSNAME": names.netbiosname,
               "NTDSGUID": names.ntdsguid,
-              "DNSPASS_B64": b64encode(dnspass),
               "RIDALLOCATIONSTART": str(next_rid + 100),
               "RIDALLOCATIONEND": str(next_rid + 100 + 499),
               })
 
+    # This is partially Samba4 specific and should be replaced by the correct
+    # DNS AD-style setup
+    setup_add_ldif(samdb, setup_path("provision_dns_add.ldif"), {
+              "DNSDOMAIN": names.dnsdomain,
+              "DOMAINDN": names.domaindn,
+              "DNSPASS_B64": b64encode(dnspass),
+              "HOSTNAME" : names.hostname,
+              "DNSNAME" : '%s.%s' % (names.netbiosname.lower(), names.dnsdomain.lower())
+              })
+
 def getpolicypath(sysvolpath, dnsdomain, guid):
+    """Return the physical path of policy given its guid.
+
+    :param sysvolpath: Path to the sysvol folder
+    :param dnsdomain: DNS name of the AD domain
+    :param guid: The GUID of the policy
+    :return: A string with the complete path to the policy folder
+    """
+
     if guid[0] != "{":
         guid = "{%s}" % guid
     policy_path = os.path.join(sysvolpath, dnsdomain, "Policies", guid)
     return policy_path
 
 def create_gpo_struct(policy_path):
-    os.makedirs(policy_path, 0755)
+    if not os.path.exists(policy_path):
+        os.makedirs(policy_path, 0775)
     open(os.path.join(policy_path, "GPT.INI"), 'w').write(
-                      "[General]\r\nVersion=65543")
-    os.makedirs(os.path.join(policy_path, "MACHINE"), 0755)
-    os.makedirs(os.path.join(policy_path, "USER"), 0755)
-
+                      "[General]\r\nVersion=0")
+    p = os.path.join(policy_path, "MACHINE")
+    if not os.path.exists(p):
+        os.makedirs(p, 0775)
+    p = os.path.join(policy_path, "USER")
+    if not os.path.exists(p):
+        os.makedirs(p, 0775)
+
+
+def create_default_gpo(sysvolpath, dnsdomain, policyguid, policyguid_dc):
+    """Create the default GPO for a domain
+
+        :param sysvolpath: Physical path for the sysvol folder
+        :param dnsdomain: DNS domain name of the AD domain
+        :param policyguid: GUID of the default domain policy
+        :param policyguid_dc: GUID of the default domain controler policy
+    """
 
-def setup_gpo(sysvolpath, dnsdomain, policyguid, policyguid_dc):
     policy_path = getpolicypath(sysvolpath,dnsdomain,policyguid)
     create_gpo_struct(policy_path)
 
@@ -997,6 +1067,10 @@ def setup_samdb(path, setup_path, session_info, provision_backend, lp, names,
     # Load the schema from the one we computed earlier
     samdb.set_schema(schema)
 
+    # Set the NTDS settings DN manually - in order to have it already around
+    # before the provisioned tree exists and we connect
+    samdb.set_ntds_settings_dn("CN=NTDS Settings,%s" % names.serverdn)
+
     # And now we can connect to the DB - the schema won't be loaded from the DB
     samdb.connect(path)
 
@@ -1017,7 +1091,6 @@ def setup_samdb(path, setup_path, session_info, provision_backend, lp, names,
 
         samdb.set_domain_sid(str(domainsid))
         samdb.set_invocation_id(invocationid)
-        samdb.set_ntds_settings_dn("CN=NTDS Settings,%s" % names.serverdn)
 
         logger.info("Adding DomainDN: %s" % names.domaindn)
 
@@ -1075,10 +1148,16 @@ def setup_samdb(path, setup_path, session_info, provision_backend, lp, names,
     else:
         samdb.transaction_commit()
 
-    samdb = SamDB(session_info=admin_session_info,
+    samdb = SamDB(session_info=admin_session_info, auto_connect=False,
                 credentials=provision_backend.credentials, lp=lp,
                 global_schema=False, am_rodc=am_rodc)
+
+    # Set the NTDS settings DN manually - in order to have it already around
+    # before the provisioned tree exists and we connect
+    samdb.set_ntds_settings_dn("CN=NTDS Settings,%s" % names.serverdn)
+
     samdb.connect(path)
+
     samdb.transaction_start()
     try:
         samdb.invocation_id = invocationid
@@ -1155,7 +1234,7 @@ def setup_samdb(path, setup_path, session_info, provision_backend, lp, names,
                             domainControllerFunctionality=domainControllerFunctionality,
                             ntdsguid=ntdsguid)
 
-            ntds_dn = "CN=NTDS Settings,CN=%s,CN=Servers,CN=%s,CN=Sites,CN=Configuration,%s" % (names.hostname, names.sitename, names.domaindn)
+            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)
@@ -1182,23 +1261,46 @@ def set_dir_acl(path, acl, lp, domsid):
             setntacl(lp, os.path.join(root, name), acl, domsid)
 
 
-def set_gpo_acl(sysvol, dnsdomain, domainsid, domaindn, samdb, lp):
-    # Set ACL for GPO
-    policy_path = os.path.join(sysvol, dnsdomain, "Policies")
-    set_dir_acl(policy_path,dsacl2fsacl(POLICIES_ACL, str(domainsid)), 
-        lp, str(domainsid))
+def set_gpos_acl(sysvol, dnsdomain, domainsid, domaindn, samdb, lp):
+    """Set ACL on the sysvol/<dnsname>/Policies folder and the policy
+    folders beneath.
+
+    :param sysvol: Physical path for the sysvol folder
+    :param dnsdomain: The DNS name of the domain
+    :param domainsid: The SID of the domain
+    :param domaindn: The DN of the domain (ie. DC=...)
+    :param samdb: An LDB object on the SAM db
+    :param lp: an LP object
+    """
+
+    # Set ACL for GPO root folder
+    root_policy_path = os.path.join(sysvol, dnsdomain, "Policies")
+    setntacl(lp, root_policy_path, POLICIES_ACL, str(domainsid))
+
     res = samdb.search(base="CN=Policies,CN=System,%s"%(domaindn),
                         attrs=["cn", "nTSecurityDescriptor"],
                         expression="", scope=ldb.SCOPE_ONELEVEL)
+
     for policy in res:
         acl = ndr_unpack(security.descriptor, 
                          str(policy["nTSecurityDescriptor"])).as_sddl()
-        policy_path = getpolicypath(sysvol,dnsdomain,str(policy["cn"]))
+        policy_path = getpolicypath(sysvol, dnsdomain, str(policy["cn"]))
         set_dir_acl(policy_path, dsacl2fsacl(acl, str(domainsid)), lp, 
                     str(domainsid))
 
 def setsysvolacl(samdb, netlogon, sysvol, gid, domainsid, dnsdomain, domaindn,
     lp):
+    """Set the ACL for the sysvol share and the subfolders
+
+    :param samdb: An LDB object on the SAM db
+    :param netlogon: Physical path for the netlogon folder
+    :param sysvol: Physical path for the sysvol folder
+    :param gid: The GID of the "Domain adminstrators" group
+    :param domainsid: The SID of the domain
+    :param dnsdomain: The DNS name of the domain
+    :param domaindn: The DN of the domain (ie. DC=...)
+    """
+
     try:
         os.chown(sysvol,-1,gid)
     except:
@@ -1206,17 +1308,20 @@ def setsysvolacl(samdb, netlogon, sysvol, gid, domainsid, dnsdomain, domaindn,
     else:
         canchown = True
 
-    setntacl(lp,sysvol,SYSVOL_ACL,str(domainsid))
+    # Set the SYSVOL_ACL on the sysvol folder and subfolder (first level)
+    setntacl(lp,sysvol, SYSVOL_ACL, str(domainsid))
     for root, dirs, files in os.walk(sysvol, topdown=False):
         for name in files:
             if canchown:
-                os.chown(os.path.join(root, name),-1,gid)
-            setntacl(lp,os.path.join(root, name),SYSVOL_ACL,str(domainsid))
+                os.chown(os.path.join(root, name), -1, gid)
+            setntacl(lp, os.path.join(root, name), SYSVOL_ACL, str(domainsid))
         for name in dirs:
             if canchown:
-                os.chown(os.path.join(root, name),-1,gid)
-            setntacl(lp,os.path.join(root, name),SYSVOL_ACL,str(domainsid))
-    set_gpo_acl(sysvol,dnsdomain,domainsid,domaindn,samdb,lp)
+                os.chown(os.path.join(root, name), -1, gid)
+            setntacl(lp, os.path.join(root, name), SYSVOL_ACL, str(domainsid))
+
+    # Set acls on Policy folder and policies folders
+    set_gpos_acl(sysvol, dnsdomain, domainsid, domaindn, samdb, lp)
 
 
 def provision(setup_dir, logger, session_info, 
@@ -1252,11 +1357,14 @@ def provision(setup_dir, logger, session_info,
       domainsid = security.dom_sid(domainsid)
 
     # create/adapt the group policy GUIDs
+    # Default GUID for default policy are described at
+    # "How Core Group Policy Works"
+    # http://technet.microsoft.com/en-us/library/cc784268%28WS.10%29.aspx
     if policyguid is None:
-        policyguid = str(uuid.uuid4())
+        policyguid = DEFAULT_POLICY_GUID
     policyguid = policyguid.upper()
     if policyguid_dc is None:
-        policyguid_dc = str(uuid.uuid4())
+        policyguid_dc = DEFAULT_DC_POLICY_GUID
     policyguid_dc = policyguid_dc.upper()
 
     if adminpass is None:
@@ -1416,9 +1524,8 @@ def provision(setup_dir, logger, session_info,
                         lp=lp)
         share_ldb.load_ldif_file_add(setup_path("share.ldif"))
 
-     
     logger.info("Setting up secrets.ldb")
-    secrets_ldb = setup_secretsdb(paths.secrets, setup_path, 
+    secrets_ldb = setup_secretsdb(paths, setup_path,
         session_info=session_info,
         backend_credentials=provision_backend.secrets_credentials, lp=lp)
 
@@ -1473,7 +1580,7 @@ def provision(setup_dir, logger, session_info,
 
             if serverrole == "domain controller":
                 # Set up group policies (domain policy and domain controller policy)
-                setup_gpo(paths.sysvol, names.dnsdomain, policyguid, policyguid_dc)
+                create_default_gpo(paths.sysvol, names.dnsdomain, policyguid, policyguid_dc)
                 setsysvolacl(samdb, paths.netlogon, paths.sysvol, wheel_gid, 
                              domainsid, names.dnsdomain, names.domaindn, lp)
 
@@ -1488,8 +1595,23 @@ def provision(setup_dir, logger, session_info,
                                 machinepass=machinepass,
                                 secure_channel_type=SEC_CHAN_BDC)
 
+            # Now set up the right msDS-SupportedEncryptionTypes into the DB
+            # In future, this might be determined from some configuration
+            kerberos_enctypes = str(ENC_ALL_TYPES)
+
+            try:
+                msg = ldb.Message(ldb.Dn(samdb, samdb.searchone("distinguishedName", expression="samAccountName=%s$" % names.netbiosname, scope=ldb.SCOPE_SUBTREE)))
+                msg["msDS-SupportedEncryptionTypes"] = ldb.MessageElement(elements=kerberos_enctypes, 
+                                                                          flags=ldb.FLAG_MOD_REPLACE, 
+                                                                          name="msDS-SupportedEncryptionTypes")
+                samdb.modify(msg)
+            except ldb.LdbError, (ldb.ERR_NO_SUCH_ATTRIBUTE, _):
+                # It might be that this attribute does not exist in this schema
+                pass
+
+
             if serverrole == "domain controller":
-                secretsdb_setup_dns(secrets_ldb, setup_path,
+                secretsdb_setup_dns(secrets_ldb, setup_path, names,
                                     paths.private_dir,
                                     realm=names.realm, dnsdomain=names.dnsdomain,
                                     dns_keytab_path=paths.dns_keytab,
@@ -1515,12 +1637,6 @@ def provision(setup_dir, logger, session_info,
                 logger.info("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)
-                logger.info("A Kerberos configuration suitable for Samba 4 has been "
-                        "generated at %s", paths.krb5conf)
-
             lastProvisionUSNs = get_last_provision_usn(samdb)
             maxUSN = get_max_usn(samdb, str(names.rootdn))
             if lastProvisionUSNs is not None:
@@ -1528,12 +1644,18 @@ def provision(setup_dir, logger, session_info,
             else:
                 set_provision_usn(samdb, 0, maxUSN)
 
+        create_krb5_conf(paths.krb5conf, setup_path,
+                         dnsdomain=names.dnsdomain, hostname=names.hostname,
+                         realm=names.realm)
+        logger.info("A Kerberos configuration suitable for Samba 4 has been "
+                    "generated at %s", paths.krb5conf)
+
         if serverrole == "domain controller":
             create_dns_update_list(lp, logger, paths, setup_path)
 
         provision_backend.post_setup()
         provision_backend.shutdown()
-        
+
         create_phpldapadmin_config(paths.phpldapadminconfig, setup_path, 
                                    ldapi_url)
     except:
@@ -1550,8 +1672,9 @@ def provision(setup_dir, logger, session_info,
             os.chmod(dns_keytab_path, 0640)
             os.chown(dns_keytab_path, -1, paths.bind_gid)
         except OSError:
-            logger.info("Failed to chown %s to bind gid %u", dns_keytab_path,
-                paths.bind_gid)
+            if not os.environ.has_key('SAMBA_SELFTEST'):
+                logger.info("Failed to chown %s to bind gid %u", dns_keytab_path,
+                            paths.bind_gid)
 
 
     logger.info("Please install the phpLDAPadmin configuration located at %s into /etc/phpldapadmin/config.php",
@@ -1604,13 +1727,15 @@ def provision_become_dc(setup_dir=None,
     logger = logging.getLogger("provision")
     samba.set_debug_level(debuglevel)
 
-    return provision(setup_dir, logger, system_session(), None,
-              smbconf=smbconf, targetdir=targetdir, samdb_fill=FILL_DRS,
-              realm=realm, rootdn=rootdn, domaindn=domaindn, schemadn=schemadn,
-              configdn=configdn, serverdn=serverdn, domain=domain,
-              hostname=hostname, hostip="127.0.0.1", domainsid=domainsid,
-              machinepass=machinepass, serverrole="domain controller",
-              sitename=sitename)
+    res = provision(setup_dir, logger, system_session(), None,
+                    smbconf=smbconf, targetdir=targetdir, samdb_fill=FILL_DRS,
+                    realm=realm, rootdn=rootdn, domaindn=domaindn, schemadn=schemadn,
+                    configdn=configdn, serverdn=serverdn, domain=domain,
+                    hostname=hostname, hostip="127.0.0.1", domainsid=domainsid,
+                    machinepass=machinepass, serverrole="domain controller",
+                    sitename=sitename)
+    res.lp.set("debuglevel", str(debuglevel))
+    return res
 
 
 def create_phpldapadmin_config(path, setup_path, ldapi_uri):
@@ -1704,7 +1829,8 @@ def create_zone_file(lp, logger, paths, targetdir, setup_path, dnsdomain,
             os.chmod(dns_dir, 0775)
             os.chmod(paths.dns, 0664)
         except OSError:
-            logger.error("Failed to chown %s to bind gid %u" % (dns_dir, paths.bind_gid))
+            if not os.environ.has_key('SAMBA_SELFTEST'):
+                logger.error("Failed to chown %s to bind gid %u" % (dns_dir, paths.bind_gid))
 
     if targetdir is None:
         os.system(rndc + " unfreeze " + lp.get("realm"))