s4-provision: set 'dcerpc endpoint servers' but not 'vfs objects'
[nivanova/samba-autobuild/.git] / source4 / scripting / python / samba / provision / __init__.py
index bff3ce6bf186534c1315f5a24e0bf496484dbc59..db202eff4798f56721c4ba5327940d4267a30db7 100644 (file)
@@ -46,7 +46,9 @@ import samba
 from samba.dsdb import DS_DOMAIN_FUNCTION_2000
 from samba import (
     Ldb,
+    MAX_NETBIOS_NAME_LEN,
     check_all_substituted,
+    is_valid_netbios_char,
     setup_file,
     substitute_var,
     valid_netbios_name,
@@ -93,7 +95,6 @@ from samba.samdb import SamDB
 from samba.dbchecker import dbcheck
 
 
-VALID_NETBIOS_CHARS = " !#$%&'()-.@^_{}~"
 DEFAULT_POLICY_GUID = "31B2F340-016D-11D2-945F-00C04FB984F9"
 DEFAULT_DC_POLICY_GUID = "6AC1786C-016F-11D2-945F-00C04fB984F9"
 DEFAULTSITE = "Default-First-Site-Name"
@@ -482,14 +483,9 @@ def provision_paths_from_lp(lp, dnsdomain):
 
 def determine_netbios_name(hostname):
     """Determine a netbios name from a hostname."""
-    netbiosname = hostname
-    # remove forbidden chars
-    newnbname = ""
-    for x in netbiosname:
-        if x.isalnum() or x in VALID_NETBIOS_CHARS:
-            newnbname = "%s%c" % (newnbname, x)
-    # force the length to be <16
-    return newnbname[0:15].upper()
+    # remove forbidden chars and force the length to be <16
+    netbiosname = "".join([x for x in hostname if is_valid_netbios_char(x)])
+    return netbiosname[:MAX_NETBIOS_NAME_LEN].upper()
 
 
 def guess_names(lp=None, hostname=None, domain=None, dnsdomain=None,
@@ -503,7 +499,6 @@ def guess_names(lp=None, hostname=None, domain=None, dnsdomain=None,
     netbiosname = lp.get("netbios name")
     if netbiosname is None:
         netbiosname = determine_netbios_name(hostname)
-    assert netbiosname is not None
     netbiosname = netbiosname.upper()
     if not valid_netbios_name(netbiosname):
         raise InvalidNetbiosName(netbiosname)
@@ -531,7 +526,7 @@ def guess_names(lp=None, hostname=None, domain=None, dnsdomain=None,
         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))
 
     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"), serverrole, lp.configfile))
+        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))
 
     if serverrole == "domain controller":
         if domain is None:
@@ -571,7 +566,7 @@ def guess_names(lp=None, hostname=None, domain=None, dnsdomain=None,
         schemadn = "CN=Schema," + configdn
 
     if sitename is None:
-        sitename=DEFAULTSITE
+        sitename = DEFAULTSITE
 
     names = ProvisionNames()
     names.rootdn = rootdn
@@ -591,29 +586,21 @@ def guess_names(lp=None, hostname=None, domain=None, dnsdomain=None,
     return names
 
 
-def make_smbconf(smbconf, hostname, domain, realm, serverrole,
-                 targetdir, sid_generator="internal", eadb=False, lp=None,
-                 server_services=None):
+def make_smbconf(smbconf, hostname, domain, realm, targetdir,
+                 serverrole=None, sid_generator=None, eadb=False, use_ntvfs=False, lp=None,
+                 global_param=None):
     """Create a new smb.conf file based on a couple of basic settings.
     """
     assert smbconf is not None
+
     if hostname is None:
         hostname = socket.gethostname().split(".")[0]
-        netbiosname = determine_netbios_name(hostname)
-    else:
-        netbiosname = hostname.upper()
+
+    netbiosname = determine_netbios_name(hostname)
 
     if serverrole is None:
         serverrole = "standalone"
 
-    assert serverrole in ("domain controller", "member server", "standalone")
-    if serverrole == "domain controller":
-        smbconfsuffix = "dc"
-    elif serverrole == "member server":
-        smbconfsuffix = "member"
-    elif serverrole == "standalone":
-        smbconfsuffix = "standalone"
-
     if sid_generator is None:
         sid_generator = "internal"
 
@@ -623,56 +610,68 @@ def make_smbconf(smbconf, hostname, domain, realm, serverrole,
     assert realm is not None
     realm = realm.upper()
 
+    global_settings = {
+        "passdb backend": "samba4",
+        "netbios name": netbiosname,
+        "workgroup": domain,
+        "realm": realm,
+        "server role": serverrole,
+        }
+
     if lp is None:
         lp = samba.param.LoadParm()
     #Load non-existant file
     if os.path.exists(smbconf):
         lp.load(smbconf)
-    if eadb and not lp.get("posix:eadb"):
-        if targetdir is not None:
-            privdir = os.path.join(targetdir, "private")
-        else:
-            privdir = lp.get("private dir")
-        lp.set("posix:eadb", os.path.abspath(os.path.join(privdir, "eadb.tdb")))
+    if eadb:
+        if use_ntvfs and not lp.get("posix:eadb"):
+            if targetdir is not None:
+                privdir = os.path.join(targetdir, "private")
+            else:
+                privdir = lp.get("private dir")
+            lp.set("posix:eadb", os.path.abspath(os.path.join(privdir, "eadb.tdb")))
+        elif not use_ntvfs and not lp.get("xattr_tdb:file"):
+            if targetdir is not None:
+                statedir = os.path.join(targetdir, "state")
+            else:
+                statedir = lp.get("state dir")
+            lp.set("xattr_tdb:file", os.path.abspath(os.path.join(statedir, "xattr.tdb")))
 
-    if server_services is not None:
-        server_services_line = "server services = " + " ".join(server_services)
-    else:
-        server_services_line = ""
+    if global_param is not None:
+        for ent in global_param:
+            if global_param[ent] is not None:
+                global_settings[ent] = " ".join(global_param[ent])
 
     if targetdir is not None:
-        privatedir_line = "private dir = " + os.path.abspath(os.path.join(targetdir, "private"))
-        lockdir_line = "lock dir = " + os.path.abspath(targetdir)
-        statedir_line = "state directory = " + os.path.abspath(targetdir)
-        cachedir_line = "cache directory = " + os.path.abspath(targetdir)
+        global_settings["private dir"] = os.path.abspath(os.path.join(targetdir, "private"))
+        global_settings["lock dir"] = os.path.abspath(targetdir)
+        global_settings["state directory"] = os.path.abspath(targetdir)
+        global_settings["cache directory"] = os.path.abspath(targetdir)
 
         lp.set("lock dir", os.path.abspath(targetdir))
         lp.set("state directory", os.path.abspath(targetdir))
         lp.set("cache directory", os.path.abspath(targetdir))
-    else:
-        privatedir_line = ""
-        lockdir_line = ""
-        statedir_line = ""
-        cachedir_line = ""
-
-    sysvol = os.path.join(lp.get("state directory"), "sysvol")
-    netlogon = os.path.join(sysvol, realm.lower(), "scripts")
-
-    setup_file(setup_path("provision.smb.conf.%s" % smbconfsuffix),
-               smbconf, {
-            "NETBIOS_NAME": netbiosname,
-            "DOMAIN": domain,
-            "REALM": realm,
-            "SERVERROLE": serverrole,
-            "NETLOGONPATH": netlogon,
-            "SYSVOLPATH": sysvol,
-            "PRIVATEDIR_LINE": privatedir_line,
-            "LOCKDIR_LINE": lockdir_line,
-            "STATEDIR_LINE": statedir_line,
-            "CACHEDIR_LINE": cachedir_line,
-            "SERVER_SERVICES_LINE": server_services_line
-            })
 
+    shares = {}
+    if serverrole == "domain controller":
+        shares["sysvol"] = os.path.join(lp.get("state directory"), "sysvol")
+        shares["netlogon"] = os.path.join(shares["sysvol"], realm.lower(),
+            "scripts")
+
+    f = open(smbconf, 'w')
+    try:
+        f.write("[globals]\n")
+        for key, val in global_settings.iteritems():
+            f.write("\t%s = %s\n" % (key, val))
+        f.write("\n")
+
+        for name, path in shares.iteritems():
+            f.write("[%s]\n" % name)
+            f.write("\tpath = %s\n" % path)
+            f.write("\tread only = no\n")
+            f.write("\n")
+    finally:
+        f.close()
     # reload the smb.conf
     lp.load(smbconf)
 
@@ -808,7 +807,7 @@ def secretsdb_self_join(secretsdb, domain,
     # 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)(!(dn=%s)))" % (domain, realm, str(domainsid), str(msg.dn))),
+        expression=("(&(|(flatname=%s)(realm=%s)(objectSid=%s))(objectclass=primaryDomain)(!(distinguishedName=%s)))" % (domain, realm, str(domainsid), str(msg.dn))),
         scope=ldb.SCOPE_ONELEVEL)
 
     for del_msg in res:
@@ -1601,7 +1600,7 @@ def provision(logger, session_info, credentials, smbconf=None,
         backend_type=None, sitename=None,
         ol_mmr_urls=None, ol_olc=None, slapd_path=None,
         useeadb=False, am_rodc=False,
-        lp=None):
+        lp=None, use_ntvfs=True):
     """Provision samba4
 
     :note: caution, this wipes all existing data!
@@ -1647,9 +1646,18 @@ def provision(logger, session_info, credentials, smbconf=None,
     if not os.path.exists(os.path.dirname(smbconf)):
         os.makedirs(os.path.dirname(smbconf))
 
-    server_services = None
+    server_services = []
+    global_param = {}
     if dns_backend == "SAMBA_INTERNAL":
-        server_services = [ "+dns" ]
+        server_services.append("+dns")
+
+    if not use_ntvfs:
+        server_services.append("-smb")
+        server_services.append("+s3fs")
+        global_param["dcerpc endpoint servers"] = ["-winreg", "-srvsvc"]
+
+    if len(server_services) > 0:
+        global_param["server services"] = server_services
 
     # only install a new smb.conf if there isn't one there already
     if os.path.exists(smbconf):
@@ -1663,12 +1671,13 @@ def provision(logger, session_info, credentials, smbconf=None,
             f.close()
         if data is None or data == "":
             make_smbconf(smbconf, hostname, domain, realm,
-                         serverrole, targetdir, sid_generator, useeadb,
-                         lp=lp, server_services=server_services)
+                         targetdir, serverrole=serverrole,
+                         sid_generator=sid_generator, eadb=useeadb, use_ntvfs=use_ntvfs,
+                         lp=lp, global_param=global_param)
     else:
-        make_smbconf(smbconf, hostname, domain, realm, serverrole,
-                     targetdir, sid_generator, useeadb, lp=lp,
-                     server_services=server_services)
+        make_smbconf(smbconf, hostname, domain, realm, targetdir,
+                     serverrole=serverrole, sid_generator=sid_generator,
+                     eadb=useeadb, use_ntvfs=use_ntvfs, lp=lp, global_param=global_param)
 
     if lp is None:
         lp = samba.param.LoadParm()
@@ -1783,17 +1792,12 @@ def provision(logger, session_info, credentials, smbconf=None,
 
         if serverrole == "domain controller":
             if paths.netlogon is None:
-                logger.info("Existing smb.conf does not have a [netlogon] share, but you are configuring a DC.")
-                logger.info("Please either remove %s or see the template at %s" %
-                        (paths.smbconf, setup_path("provision.smb.conf.dc")))
-                assert paths.netlogon is not None
+                raise MissingShareError("netlogon", paths.smbconf,
+                    setup_path("provision.smb.conf.dc"))
 
             if paths.sysvol is None:
-                logger.info("Existing smb.conf does not have a [sysvol] share, but you"
-                        " are configuring a DC.")
-                logger.info("Please either remove %s or see the template at %s" %
-                        (paths.smbconf, setup_path("provision.smb.conf.dc")))
-                assert paths.sysvol is not None
+                raise MissingShareError("sysvol", paths.smbconf,
+                    setup_path("provision.smb.conf.dc"))
 
             if not os.path.isdir(paths.netlogon):
                 os.makedirs(paths.netlogon, 0755)
@@ -1935,3 +1939,12 @@ class InvalidNetbiosName(Exception):
     def __init__(self, name):
         super(InvalidNetbiosName, self).__init__(
             "The name '%r' is not a valid NetBIOS name" % name)
+
+
+class MissingShareError(ProvisioningError):
+
+    def __init__(self, name, smbconf, smbconf_template):
+        super(MissingShareError, self).__init__(
+            "Existing smb.conf does not have a [%s] share, but you are "
+            "configuring a DC. Please either remove %s or see the template "
+            "at %s" % (name, smbconf, smbconf_template))