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,
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"
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,
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)
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:
schemadn = "CN=Schema," + configdn
if sitename is None:
- sitename=DEFAULTSITE
+ sitename = DEFAULTSITE
names = ProvisionNames()
names.rootdn = rootdn
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"
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)
# 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:
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!
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):
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()
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)
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))