summaryrefslogtreecommitdiff
path: root/source4/scripting/python/samba/provision
diff options
context:
space:
mode:
Diffstat (limited to 'source4/scripting/python/samba/provision')
-rw-r--r--source4/scripting/python/samba/provision/__init__.py2279
-rw-r--r--source4/scripting/python/samba/provision/backend.py840
-rw-r--r--source4/scripting/python/samba/provision/common.py82
-rw-r--r--source4/scripting/python/samba/provision/descriptor.py359
-rw-r--r--source4/scripting/python/samba/provision/sambadns.py1135
5 files changed, 0 insertions, 4695 deletions
diff --git a/source4/scripting/python/samba/provision/__init__.py b/source4/scripting/python/samba/provision/__init__.py
deleted file mode 100644
index aac0ee36b2..0000000000
--- a/source4/scripting/python/samba/provision/__init__.py
+++ /dev/null
@@ -1,2279 +0,0 @@
-# Unix SMB/CIFS implementation.
-# backend code for provisioning a Samba4 server
-
-# Copyright (C) Jelmer Vernooij <jelmer@samba.org> 2007-2012
-# Copyright (C) Andrew Bartlett <abartlet@samba.org> 2008-2009
-# Copyright (C) Oliver Liebel <oliver@itc.li> 2008-2009
-#
-# Based on the original in EJS:
-# Copyright (C) Andrew Tridgell <tridge@samba.org> 2005
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
-#
-
-"""Functions for setting up a Samba configuration."""
-
-__docformat__ = "restructuredText"
-
-from base64 import b64encode
-import os
-import re
-import pwd
-import grp
-import logging
-import time
-import uuid
-import socket
-import urllib
-import string
-import tempfile
-
-import ldb
-
-from samba.auth import system_session, admin_session
-import samba
-from samba.samba3 import smbd, passdb
-from samba.samba3 import param as s3param
-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,
- version,
- )
-from samba.dcerpc import security, misc
-from samba.dcerpc.misc import (
- SEC_CHAN_BDC,
- SEC_CHAN_WKSTA,
- )
-from samba.dsdb import (
- DS_DOMAIN_FUNCTION_2003,
- DS_DOMAIN_FUNCTION_2008_R2,
- ENC_ALL_TYPES,
- )
-from samba.idmap import IDmapDB
-from samba.ms_display_specifiers import read_ms_ldif
-from samba.ntacls import setntacl, getntacl, dsacl2fsacl
-from samba.ndr import ndr_pack, ndr_unpack
-from samba.provision.backend import (
- ExistingBackend,
- FDSBackend,
- LDBBackend,
- OpenLDAPBackend,
- )
-from samba.provision.descriptor import (
- get_empty_descriptor,
- get_config_descriptor,
- get_config_partitions_descriptor,
- get_config_sites_descriptor,
- get_config_ntds_quotas_descriptor,
- get_config_delete_protected1_descriptor,
- get_config_delete_protected1wd_descriptor,
- get_config_delete_protected2_descriptor,
- get_domain_descriptor,
- get_domain_infrastructure_descriptor,
- get_domain_builtin_descriptor,
- get_domain_computers_descriptor,
- get_domain_users_descriptor,
- get_domain_controllers_descriptor,
- get_domain_delete_protected1_descriptor,
- get_domain_delete_protected2_descriptor,
- get_dns_partition_descriptor,
- get_dns_forest_microsoft_dns_descriptor,
- get_dns_domain_microsoft_dns_descriptor,
- )
-from samba.provision.common import (
- setup_path,
- setup_add_ldif,
- setup_modify_ldif,
- )
-from samba.provision.sambadns import (
- get_dnsadmins_sid,
- setup_ad_dns,
- create_dns_update_list
- )
-
-import samba.param
-import samba.registry
-from samba.schema import Schema
-from samba.samdb import SamDB
-from samba.dbchecker import dbcheck
-
-
-DEFAULT_POLICY_GUID = "31B2F340-016D-11D2-945F-00C04FB984F9"
-DEFAULT_DC_POLICY_GUID = "6AC1786C-016F-11D2-945F-00C04fB984F9"
-DEFAULTSITE = "Default-First-Site-Name"
-LAST_PROVISION_USN_ATTRIBUTE = "lastProvisionUSN"
-
-
-class ProvisionPaths(object):
-
- def __init__(self):
- self.shareconf = None
- self.hklm = None
- self.hkcu = None
- self.hkcr = None
- self.hku = None
- self.hkpd = None
- self.hkpt = None
- self.samdb = None
- self.idmapdb = None
- self.secrets = None
- self.keytab = None
- self.dns_keytab = None
- self.dns = None
- self.winsdb = None
- self.private_dir = None
- self.state_dir = None
-
-
-class ProvisionNames(object):
-
- def __init__(self):
- self.ncs = None
- self.rootdn = None
- self.domaindn = None
- self.configdn = None
- self.schemadn = None
- self.dnsforestdn = None
- self.dnsdomaindn = None
- self.ldapmanagerdn = None
- self.dnsdomain = None
- self.realm = None
- self.netbiosname = None
- self.domain = None
- self.hostname = None
- self.sitename = None
- self.smbconf = None
- self.name_map = {}
-
-
-def find_provision_key_parameters(samdb, secretsdb, idmapdb, paths, smbconf,
- lp):
- """Get key provision parameters (realm, domain, ...) from a given provision
-
- :param samdb: An LDB object connected to the sam.ldb file
- :param secretsdb: An LDB object connected to the secrets.ldb file
- :param idmapdb: An LDB object connected to the idmap.ldb file
- :param paths: A list of path to provision object
- :param smbconf: Path to the smb.conf file
- :param lp: A LoadParm object
- :return: A list of key provision parameters
- """
- names = ProvisionNames()
- names.adminpass = None
-
- # NT domain, kerberos realm, root dn, domain dn, domain dns name
- names.domain = string.upper(lp.get("workgroup"))
- names.realm = lp.get("realm")
- names.dnsdomain = names.realm.lower()
- basedn = samba.dn_from_dns_name(names.dnsdomain)
- names.realm = string.upper(names.realm)
- # netbiosname
- # Get the netbiosname first (could be obtained from smb.conf in theory)
- res = secretsdb.search(expression="(flatname=%s)" %
- names.domain,base="CN=Primary Domains",
- scope=ldb.SCOPE_SUBTREE, attrs=["sAMAccountName"])
- names.netbiosname = str(res[0]["sAMAccountName"]).replace("$","")
-
- names.smbconf = smbconf
-
- # That's a bit simplistic but it's ok as long as we have only 3
- # partitions
- current = samdb.search(expression="(objectClass=*)",
- base="", scope=ldb.SCOPE_BASE,
- attrs=["defaultNamingContext", "schemaNamingContext",
- "configurationNamingContext","rootDomainNamingContext",
- "namingContexts"])
-
- names.configdn = current[0]["configurationNamingContext"]
- configdn = str(names.configdn)
- names.schemadn = current[0]["schemaNamingContext"]
- if not (ldb.Dn(samdb, basedn) == (ldb.Dn(samdb,
- current[0]["defaultNamingContext"][0]))):
- raise ProvisioningError(("basedn in %s (%s) and from %s (%s)"
- "is not the same ..." % (paths.samdb,
- str(current[0]["defaultNamingContext"][0]),
- paths.smbconf, basedn)))
-
- names.domaindn=current[0]["defaultNamingContext"]
- names.rootdn=current[0]["rootDomainNamingContext"]
- names.ncs=current[0]["namingContexts"]
- names.dnsforestdn = None
- names.dnsdomaindn = None
-
- for i in range(0, len(names.ncs)):
- nc = names.ncs[i]
-
- dnsforestdn = "DC=ForestDnsZones,%s" % (str(names.rootdn))
- if nc == dnsforestdn:
- names.dnsforestdn = dnsforestdn
- continue
-
- dnsdomaindn = "DC=DomainDnsZones,%s" % (str(names.domaindn))
- if nc == dnsdomaindn:
- names.dnsdomaindn = dnsdomaindn
- continue
-
- # default site name
- res3 = samdb.search(expression="(objectClass=site)",
- base="CN=Sites," + 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"])
- 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
-
- # invocation id/objectguid
- res5 = samdb.search(expression="(objectClass=*)",
- base="CN=NTDS Settings,%s" % str(names.serverdn),
- scope=ldb.SCOPE_BASE,
- attrs=["invocationID", "objectGUID"])
- names.invocation = str(ndr_unpack(misc.GUID, res5[0]["invocationId"][0]))
- names.ntdsguid = str(ndr_unpack(misc.GUID, res5[0]["objectGUID"][0]))
-
- # domain guid/sid
- res6 = samdb.search(expression="(objectClass=*)", base=basedn,
- scope=ldb.SCOPE_BASE, attrs=["objectGUID",
- "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])
- 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
- else:
- names.domainlevel = int(res6[0]["msDS-Behavior-Version"][0])
-
- # policy guid
- res7 = samdb.search(expression="(displayName=Default Domain Policy)",
- 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"])
- if len(res8) == 1:
- names.policyid_dc = str(res8[0]["cn"]).replace("{","").replace("}","")
- else:
- names.policyid_dc = None
-
- res9 = idmapdb.search(expression="(cn=%s-%s)" %
- (str(names.domainsid), security.DOMAIN_RID_ADMINISTRATOR),
- attrs=["xidNumber", "type"])
- if len(res9) != 1:
- raise ProvisioningError("Unable to find uid/gid for Domain Admins rid (%s-%s" % (str(names.domainsid), security.DOMAIN_RID_ADMINISTRATOR))
- if res9[0]["type"][0] == "ID_TYPE_BOTH":
- names.root_gid = res9[0]["xidNumber"][0]
- else:
- names.root_gid = pwd.getpwuid(int(res9[0]["xidNumber"][0])).pw_gid
-
- res10 = samdb.search(expression="(samaccountname=dns)",
- scope=ldb.SCOPE_SUBTREE, attrs=["dn"],
- controls=["search_options:1:2"])
- if (len(res10) > 0):
- has_legacy_dns_account = True
- else:
- has_legacy_dns_account = False
-
- res11 = samdb.search(expression="(samaccountname=dns-%s)" % names.netbiosname,
- scope=ldb.SCOPE_SUBTREE, attrs=["dn"],
- controls=["search_options:1:2"])
- if (len(res11) > 0):
- has_dns_account = True
- else:
- has_dns_account = False
-
- if names.dnsdomaindn is not None:
- if has_dns_account:
- names.dns_backend = 'BIND9_DLZ'
- else:
- names.dns_backend = 'SAMBA_INTERNAL'
- elif has_dns_account or has_legacy_dns_account:
- names.dns_backend = 'BIND9_FLATFILE'
- else:
- names.dns_backend = 'NONE'
-
- dns_admins_sid = get_dnsadmins_sid(samdb, names.domaindn)
- names.name_map['DnsAdmins'] = str(dns_admins_sid)
-
- return names
-
-
-def update_provision_usn(samdb, low, high, id, replace=False):
- """Update the field provisionUSN in sam.ldb
-
- This field is used to track range of USN modified by provision and
- upgradeprovision.
- This value is used afterward by next provision to figure out if
- the field have been modified since last provision.
-
- :param samdb: An LDB object connect to sam.ldb
- :param low: The lowest USN modified by this upgrade
- :param high: The highest USN modified by this upgrade
- :param id: The invocation id of the samba's dc
- :param replace: A boolean indicating if the range should replace any
- existing one or appended (default)
- """
-
- tab = []
- if not replace:
- entry = samdb.search(base="@PROVISION",
- scope=ldb.SCOPE_BASE,
- attrs=[LAST_PROVISION_USN_ATTRIBUTE, "dn"])
- for e in entry[0][LAST_PROVISION_USN_ATTRIBUTE]:
- if not re.search(';', e):
- e = "%s;%s" % (e, id)
- tab.append(str(e))
-
- tab.append("%s-%s;%s" % (low, high, id))
- delta = ldb.Message()
- delta.dn = ldb.Dn(samdb, "@PROVISION")
- delta[LAST_PROVISION_USN_ATTRIBUTE] = ldb.MessageElement(tab,
- ldb.FLAG_MOD_REPLACE, LAST_PROVISION_USN_ATTRIBUTE)
- entry = samdb.search(expression='provisionnerID=*',
- base="@PROVISION", scope=ldb.SCOPE_BASE,
- attrs=["provisionnerID"])
- if len(entry) == 0 or len(entry[0]) == 0:
- delta["provisionnerID"] = ldb.MessageElement(id, ldb.FLAG_MOD_ADD, "provisionnerID")
- samdb.modify(delta)
-
-
-def set_provision_usn(samdb, low, high, id):
- """Set the field provisionUSN in sam.ldb
- This field is used to track range of USN modified by provision and
- upgradeprovision.
- This value is used afterward by next provision to figure out if
- the field have been modified since last provision.
-
- :param samdb: An LDB object connect to sam.ldb
- :param low: The lowest USN modified by this upgrade
- :param high: The highest USN modified by this upgrade
- :param id: The invocationId of the provision"""
-
- tab = []
- tab.append("%s-%s;%s" % (low, high, id))
-
- delta = ldb.Message()
- delta.dn = ldb.Dn(samdb, "@PROVISION")
- delta[LAST_PROVISION_USN_ATTRIBUTE] = ldb.MessageElement(tab,
- ldb.FLAG_MOD_ADD, LAST_PROVISION_USN_ATTRIBUTE)
- samdb.add(delta)
-
-
-def get_max_usn(samdb,basedn):
- """ This function return the biggest USN present in the provision
-
- :param samdb: A LDB object pointing to the sam.ldb
- :param basedn: A string containing the base DN of the provision
- (ie. DC=foo, DC=bar)
- :return: The biggest USN in the provision"""
-
- res = samdb.search(expression="objectClass=*",base=basedn,
- scope=ldb.SCOPE_SUBTREE,attrs=["uSNChanged"],
- controls=["search_options:1:2",
- "server_sort:1:1:uSNChanged",
- "paged_results:1:1"])
- return res[0]["uSNChanged"]
-
-
-def get_last_provision_usn(sam):
- """Get USNs ranges modified by a provision or an upgradeprovision
-
- :param sam: An LDB object pointing to the sam.ldb
- :return: a dictionary which keys are invocation id and values are an array
- of integer representing the different ranges
- """
- try:
- entry = sam.search(expression="%s=*" % LAST_PROVISION_USN_ATTRIBUTE,
- base="@PROVISION", scope=ldb.SCOPE_BASE,
- attrs=[LAST_PROVISION_USN_ATTRIBUTE, "provisionnerID"])
- except ldb.LdbError, (ecode, emsg):
- if ecode == ldb.ERR_NO_SUCH_OBJECT:
- return None
- raise
- if len(entry) > 0:
- myids = []
- range = {}
- p = re.compile(r'-')
- if entry[0].get("provisionnerID"):
- for e in entry[0]["provisionnerID"]:
- myids.append(str(e))
- for r in entry[0][LAST_PROVISION_USN_ATTRIBUTE]:
- tab1 = str(r).split(';')
- if len(tab1) == 2:
- id = tab1[1]
- else:
- id = "default"
- if (len(myids) > 0 and id not in myids):
- continue
- tab2 = p.split(tab1[0])
- if range.get(id) is None:
- range[id] = []
- range[id].append(tab2[0])
- range[id].append(tab2[1])
- return range
- else:
- return None
-
-
-class ProvisionResult(object):
- """Result of a provision.
-
- :ivar server_role: The server role
- :ivar paths: ProvisionPaths instance
- :ivar domaindn: The domain dn, as string
- """
-
- def __init__(self):
- self.server_role = None
- self.paths = None
- self.domaindn = None
- self.lp = None
- self.samdb = None
- self.idmap = None
- self.names = None
- self.domainsid = None
- self.adminpass_generated = None
- self.adminpass = None
- self.backend_result = None
-
- def report_logger(self, logger):
- """Report this provision result to a logger."""
- logger.info(
- "Once the above files are installed, your Samba4 server will "
- "be ready to use")
- if self.adminpass_generated:
- logger.info("Admin password: %s", self.adminpass)
- logger.info("Server Role: %s", self.server_role)
- logger.info("Hostname: %s", self.names.hostname)
- logger.info("NetBIOS Domain: %s", self.names.domain)
- logger.info("DNS Domain: %s", self.names.dnsdomain)
- logger.info("DOMAIN SID: %s", self.domainsid)
-
- if self.backend_result:
- self.backend_result.report_logger(logger)
-
-
-def check_install(lp, session_info, credentials):
- """Check whether the current install seems ok.
-
- :param lp: Loadparm context
- :param session_info: Session information
- :param credentials: Credentials
- """
- if lp.get("realm") == "":
- raise Exception("Realm empty")
- samdb = Ldb(lp.samdb_url(), session_info=session_info,
- credentials=credentials, lp=lp)
- if len(samdb.search("(cn=Administrator)")) != 1:
- raise ProvisioningError("No administrator account found")
-
-
-def findnss(nssfn, names):
- """Find a user or group from a list of possibilities.
-
- :param nssfn: NSS Function to try (should raise KeyError if not found)
- :param names: Names to check.
- :return: Value return by first names list.
- """
- for name in names:
- try:
- return nssfn(name)
- except KeyError:
- pass
- raise KeyError("Unable to find user/group in %r" % names)
-
-
-findnss_uid = lambda names: findnss(pwd.getpwnam, names)[2]
-findnss_gid = lambda names: findnss(grp.getgrnam, names)[2]
-
-
-def provision_paths_from_lp(lp, dnsdomain):
- """Set the default paths for provisioning.
-
- :param lp: Loadparm context.
- :param dnsdomain: DNS Domain name
- """
- paths = ProvisionPaths()
- paths.private_dir = lp.get("private dir")
- paths.state_dir = lp.get("state directory")
-
- # 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, "sam.ldb")
- paths.idmapdb = os.path.join(paths.private_dir, "idmap.ldb")
- paths.secrets = os.path.join(paths.private_dir, "secrets.ldb")
- paths.privilege = os.path.join(paths.private_dir, "privilege.ldb")
- paths.dns = os.path.join(paths.private_dir, "dns", dnsdomain + ".zone")
- paths.dns_update_list = os.path.join(paths.private_dir, "dns_update_list")
- paths.spn_update_list = os.path.join(paths.private_dir, "spn_update_list")
- paths.namedconf = os.path.join(paths.private_dir, "named.conf")
- 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.winsdb = os.path.join(paths.private_dir, "wins.ldb")
- paths.s4_ldapi_path = os.path.join(paths.private_dir, "ldapi")
- paths.hklm = "hklm.ldb"
- paths.hkcr = "hkcr.ldb"
- paths.hkcu = "hkcu.ldb"
- paths.hku = "hku.ldb"
- paths.hkpd = "hkpd.ldb"
- paths.hkpt = "hkpt.ldb"
- paths.sysvol = lp.get("path", "sysvol")
- paths.netlogon = lp.get("path", "netlogon")
- paths.smbconf = lp.configfile
- return paths
-
-
-def determine_netbios_name(hostname):
- """Determine a netbios name from a hostname."""
- # 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,
- serverrole=None, rootdn=None, domaindn=None, configdn=None,
- schemadn=None, serverdn=None, sitename=None):
- """Guess configuration settings to use."""
-
- if hostname is None:
- hostname = socket.gethostname().split(".")[0]
-
- netbiosname = lp.get("netbios name")
- if netbiosname is None:
- netbiosname = determine_netbios_name(hostname)
- netbiosname = netbiosname.upper()
- if not valid_netbios_name(netbiosname):
- raise InvalidNetbiosName(netbiosname)
-
- if dnsdomain is None:
- dnsdomain = lp.get("realm")
- if dnsdomain is None or dnsdomain == "":
- raise ProvisioningError("guess_names: 'realm' not specified in supplied %s!", lp.configfile)
-
- dnsdomain = dnsdomain.lower()
-
- if serverrole is None:
- serverrole = lp.get("server role")
- if serverrole is None:
- raise ProvisioningError("guess_names: 'server role' not specified in supplied %s!" % lp.configfile)
-
- serverrole = serverrole.lower()
-
- realm = dnsdomain.upper()
-
- if lp.get("realm") == "":
- 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))
-
- 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))
-
- if serverrole == "active directory domain controller":
- if domain is None:
- # This will, for better or worse, default to 'WORKGROUP'
- domain = lp.get("workgroup")
- domain = domain.upper()
-
- if lp.get("workgroup").upper() != domain:
- 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 = samba.dn_from_dns_name(dnsdomain)
-
- if domain == netbiosname:
- raise ProvisioningError("guess_names: Domain '%s' must not be equal to short host name '%s'!" % (domain, netbiosname))
- else:
- domain = netbiosname
- if domaindn is None:
- domaindn = "DC=" + netbiosname
-
- if not valid_netbios_name(domain):
- raise InvalidNetbiosName(domain)
-
- 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 short domain name '%s'!" % (realm, domain))
-
- if rootdn is None:
- rootdn = domaindn
-
- if configdn is None:
- configdn = "CN=Configuration," + rootdn
- if schemadn is None:
- schemadn = "CN=Schema," + configdn
-
- if sitename is None:
- sitename = DEFAULTSITE
-
- names = ProvisionNames()
- names.rootdn = rootdn
- names.domaindn = domaindn
- names.configdn = configdn
- names.schemadn = schemadn
- names.ldapmanagerdn = "CN=Manager," + rootdn
- names.dnsdomain = dnsdomain
- names.domain = domain
- names.realm = realm
- names.netbiosname = netbiosname
- names.hostname = hostname
- names.sitename = sitename
- names.serverdn = "CN=%s,CN=Servers,CN=%s,CN=Sites,%s" % (
- netbiosname, sitename, configdn)
-
- return names
-
-
-def make_smbconf(smbconf, hostname, domain, realm, targetdir,
- serverrole=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)
-
- if serverrole is None:
- serverrole = "standalone server"
-
- assert domain is not None
- domain = domain.upper()
-
- assert realm is not None
- realm = realm.upper()
-
- global_settings = {
- "netbios name": netbiosname,
- "workgroup": domain,
- "realm": realm,
- "server role": serverrole,
- }
-
- if lp is None:
- lp = samba.param.LoadParm()
- #Load non-existent file
- if os.path.exists(smbconf):
- lp.load(smbconf)
-
- 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:
- 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(os.path.join(targetdir, "state"))
- global_settings["cache directory"] = os.path.abspath(os.path.join(targetdir, "cache"))
-
- lp.set("lock dir", os.path.abspath(targetdir))
- lp.set("state directory", global_settings["state directory"])
- lp.set("cache directory", global_settings["cache directory"])
-
- 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 directory")
- lp.set("xattr_tdb:file", os.path.abspath(os.path.join(statedir, "xattr.tdb")))
-
- shares = {}
- if serverrole == "active directory domain controller":
- shares["sysvol"] = os.path.join(lp.get("state directory"), "sysvol")
- shares["netlogon"] = os.path.join(shares["sysvol"], realm.lower(),
- "scripts")
- else:
- global_settings["passdb backend"] = "samba_dsdb"
-
- 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)
-
- # 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()
-
-
-def setup_name_mappings(idmap, sid, root_uid, nobody_uid,
- users_gid, root_gid):
- """setup reasonable name mappings for sam names to unix names.
-
- :param samdb: SamDB object.
- :param idmap: IDmap db object.
- :param sid: The domain sid.
- :param domaindn: The domain DN.
- :param root_uid: uid of the UNIX root user.
- :param nobody_uid: uid of the UNIX nobody user.
- :param users_gid: gid of the UNIX users group.
- :param root_gid: gid of the UNIX root group.
- """
- idmap.setup_name_mapping("S-1-5-7", idmap.TYPE_UID, nobody_uid)
-
- idmap.setup_name_mapping(sid + "-500", idmap.TYPE_UID, root_uid)
- idmap.setup_name_mapping(sid + "-513", idmap.TYPE_GID, users_gid)
-
-
-def setup_samdb_partitions(samdb_path, logger, lp, session_info,
- provision_backend, names, schema, serverrole,
- erase=False):
- """Setup the partitions for the SAM database.
-
- Alternatively, provision() may call this, and then populate the database.
-
- :note: This will wipe the Sam Database!
-
- :note: This function always removes the local SAM LDB file. The erase
- parameter controls whether to erase the existing data, which
- may not be stored locally but in LDAP.
-
- """
- assert session_info is not None
-
- # We use options=["modules:"] to stop the modules loading - we
- # just want to wipe and re-initialise the database, not start it up
-
- try:
- os.unlink(samdb_path)
- except OSError:
- pass
-
- samdb = Ldb(url=samdb_path, session_info=session_info,
- lp=lp, options=["modules:"])
-
- ldap_backend_line = "# No LDAP backend"
- if provision_backend.type != "ldb":
- ldap_backend_line = "ldapBackend: %s" % provision_backend.ldap_uri
-
- samdb.transaction_start()
- try:
- logger.info("Setting up sam.ldb partitions and settings")
- setup_add_ldif(samdb, setup_path("provision_partitions.ldif"), {
- "LDAP_BACKEND_LINE": ldap_backend_line
- })
-
-
- setup_add_ldif(samdb, setup_path("provision_init.ldif"), {
- "BACKEND_TYPE": provision_backend.type,
- "SERVER_ROLE": serverrole
- })
-
- logger.info("Setting up sam.ldb rootDSE")
- setup_samdb_rootdse(samdb, names)
- except:
- samdb.transaction_cancel()
- raise
- else:
- samdb.transaction_commit()
-
-
-def secretsdb_self_join(secretsdb, domain,
- netbiosname, machinepass, domainsid=None,
- realm=None, dnsdomain=None,
- keytab_path=None,
- key_version_number=1,
- secure_channel_type=SEC_CHAN_WKSTA):
- """Add domain join-specific bits to a secrets database.
-
- :param secretsdb: Ldb Handle to the secrets database
- :param machinepass: Machine password
- """
- attrs = ["whenChanged",
- "secret",
- "priorSecret",
- "priorChanged",
- "krb5Keytab",
- "privateKeytab"]
-
- if realm is not None:
- if dnsdomain is None:
- 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" % (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)(!(distinguishedName=%s)))" % (domain, realm, str(domainsid), str(msg.dn))),
- scope=ldb.SCOPE_ONELEVEL)
-
- for del_msg in res:
- 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"][0]]
- msg["priorWhenChanged"] = [res[0]["whenChanged"][0]]
-
- try:
- msg["privateKeytab"] = [res[0]["privateKeytab"][0]]
- except KeyError:
- pass
-
- try:
- msg["krb5Keytab"] = [res[0]["krb5Keytab"][0]]
- except KeyError:
- pass
-
- for el in 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 setup_secretsdb(paths, session_info, backend_credentials, lp):
- """Setup the secrets database.
-
- :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.
- :param session_info: Session info.
- :param credentials: Credentials
- :param lp: Loadparm context
- :return: LDB handle for the created secrets database
- """
- 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()
- secrets_ldb.load_ldif_file_add(setup_path("secrets_init.ldif"))
- secrets_ldb = Ldb(path, session_info=session_info, lp=lp)
- secrets_ldb.transaction_start()
- try:
- secrets_ldb.load_ldif_file_add(setup_path("secrets.ldif"))
-
- if (backend_credentials is not None and
- backend_credentials.authentication_requested()):
- if backend_credentials.get_bind_dn() is not None:
- setup_add_ldif(secrets_ldb,
- setup_path("secrets_simple_ldap.ldif"), {
- "LDAPMANAGERDN": backend_credentials.get_bind_dn(),
- "LDAPMANAGERPASS_B64": b64encode(backend_credentials.get_password())
- })
- else:
- setup_add_ldif(secrets_ldb,
- setup_path("secrets_sasl_ldap.ldif"), {
- "LDAPADMINUSER": backend_credentials.get_username(),
- "LDAPADMINREALM": backend_credentials.get_realm(),
- "LDAPADMINPASS_B64": b64encode(backend_credentials.get_password())
- })
- except:
- secrets_ldb.transaction_cancel()
- raise
- return secrets_ldb
-
-
-def setup_privileges(path, session_info, lp):
- """Setup the privileges database.
-
- :param path: Path to the privileges database.
- :param session_info: Session info.
- :param credentials: Credentials
- :param lp: Loadparm context
- :return: LDB handle for the created secrets database
- """
- if os.path.exists(path):
- os.unlink(path)
- privilege_ldb = Ldb(path, session_info=session_info, lp=lp)
- privilege_ldb.erase()
- privilege_ldb.load_ldif_file_add(setup_path("provision_privilege.ldif"))
-
-
-def setup_registry(path, session_info, lp):
- """Setup the registry.
-
- :param path: Path to the registry database
- :param session_info: Session information
- :param credentials: Credentials
- :param lp: Loadparm context
- """
- reg = samba.registry.Registry()
- hive = samba.registry.open_ldb(path, session_info=session_info, lp_ctx=lp)
- reg.mount_hive(hive, samba.registry.HKEY_LOCAL_MACHINE)
- provision_reg = setup_path("provision.reg")
- assert os.path.exists(provision_reg)
- reg.diff_apply(provision_reg)
-
-
-def setup_idmapdb(path, session_info, lp):
- """Setup the idmap database.
-
- :param path: path to the idmap database
- :param session_info: Session information
- :param credentials: Credentials
- :param lp: Loadparm context
- """
- if os.path.exists(path):
- os.unlink(path)
-
- idmap_ldb = IDmapDB(path, session_info=session_info, lp=lp)
- idmap_ldb.erase()
- idmap_ldb.load_ldif_file_add(setup_path("idmap_init.ldif"))
- return idmap_ldb
-
-
-def setup_samdb_rootdse(samdb, names):
- """Setup the SamDB rootdse.
-
- :param samdb: Sam Database handle
- """
- setup_add_ldif(samdb, setup_path("provision_rootdse_add.ldif"), {
- "SCHEMADN": names.schemadn,
- "DOMAINDN": names.domaindn,
- "ROOTDN" : names.rootdn,
- "CONFIGDN": names.configdn,
- "SERVERDN": names.serverdn,
- })
-
-
-def setup_self_join(samdb, admin_session_info, names, fill, machinepass,
- dns_backend, dnspass, domainsid, next_rid, invocationid,
- policyguid, policyguid_dc,
- domainControllerFunctionality, ntdsguid=None, dc_rid=None):
- """Join a host to its own domain."""
- assert isinstance(invocationid, str)
- if ntdsguid is not None:
- ntdsguid_line = "objectGUID: %s\n"%ntdsguid
- else:
- ntdsguid_line = ""
-
- if dc_rid is None:
- dc_rid = next_rid
-
- setup_add_ldif(samdb, setup_path("provision_self_join.ldif"), {
- "CONFIGDN": names.configdn,
- "SCHEMADN": names.schemadn,
- "DOMAINDN": names.domaindn,
- "SERVERDN": names.serverdn,
- "INVOCATIONID": invocationid,
- "NETBIOSNAME": names.netbiosname,
- "DNSNAME": "%s.%s" % (names.hostname, names.dnsdomain),
- "MACHINEPASS_B64": b64encode(machinepass.encode('utf-16-le')),
- "DOMAINSID": str(domainsid),
- "DCRID": str(dc_rid),
- "SAMBA_VERSION_STRING": version,
- "NTDSGUID": ntdsguid_line,
- "DOMAIN_CONTROLLER_FUNCTIONALITY": str(
- domainControllerFunctionality),
- "RIDALLOCATIONSTART": str(next_rid + 100),
- "RIDALLOCATIONEND": str(next_rid + 100 + 499)})
-
- setup_add_ldif(samdb, setup_path("provision_group_policy.ldif"), {
- "POLICYGUID": policyguid,
- "POLICYGUID_DC": policyguid_dc,
- "DNSDOMAIN": names.dnsdomain,
- "DOMAINDN": names.domaindn})
-
- # 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_add_ldif(samdb, setup_path("provision_self_join_config.ldif"), {
- "CONFIGDN": names.configdn,
- "SCHEMADN": names.schemadn,
- "DOMAINDN": names.domaindn,
- "SERVERDN": names.serverdn,
- "INVOCATIONID": invocationid,
- "NETBIOSNAME": names.netbiosname,
- "DNSNAME": "%s.%s" % (names.hostname, names.dnsdomain),
- "MACHINEPASS_B64": b64encode(machinepass.encode('utf-16-le')),
- "DOMAINSID": str(domainsid),
- "DCRID": str(dc_rid),
- "SAMBA_VERSION_STRING": version,
- "NTDSGUID": ntdsguid_line,
- "DOMAIN_CONTROLLER_FUNCTIONALITY": str(
- domainControllerFunctionality)})
-
- # Setup fSMORoleOwner entries to point at the newly created DC entry
- setup_modify_ldif(samdb,
- setup_path("provision_self_join_modify_config.ldif"), {
- "CONFIGDN": names.configdn,
- "SCHEMADN": names.schemadn,
- "DEFAULTSITE": names.sitename,
- "NETBIOSNAME": names.netbiosname,
- "SERVERDN": names.serverdn,
- })
-
- system_session_info = system_session()
- samdb.set_session_info(system_session_info)
- # Setup fSMORoleOwner entries to point at the newly created DC entry to
- # modify a serverReference under cn=config when we are a subdomain, we must
- # be system due to ACLs
- setup_modify_ldif(samdb, setup_path("provision_self_join_modify.ldif"), {
- "DOMAINDN": names.domaindn,
- "SERVERDN": names.serverdn,
- "NETBIOSNAME": names.netbiosname,
- })
-
- samdb.set_session_info(admin_session_info)
-
- if dns_backend != "SAMBA_INTERNAL":
- # This is Samba4 specific and should be replaced by the correct
- # DNS AD-style setup
- setup_add_ldif(samdb, setup_path("provision_dns_add_samba.ldif"), {
- "DNSDOMAIN": names.dnsdomain,
- "DOMAINDN": names.domaindn,
- "DNSPASS_B64": b64encode(dnspass.encode('utf-16-le')),
- "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):
- if not os.path.exists(policy_path):
- os.makedirs(policy_path, 0775)
- f = open(os.path.join(policy_path, "GPT.INI"), 'w')
- try:
- f.write("[General]\r\nVersion=0")
- finally:
- f.close()
- 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
- """
- policy_path = getpolicypath(sysvolpath,dnsdomain,policyguid)
- create_gpo_struct(policy_path)
-
- policy_path = getpolicypath(sysvolpath,dnsdomain,policyguid_dc)
- create_gpo_struct(policy_path)
-
-
-def setup_samdb(path, session_info, provision_backend, lp, names,
- logger, fill, serverrole, schema, am_rodc=False):
- """Setup a complete SAM Database.
-
- :note: This will wipe the main SAM database file!
- """
-
- # 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)
-
- # Load the database, but don's load the global schema and don't connect
- # quite yet
- samdb = SamDB(session_info=session_info, url=None, auto_connect=False,
- credentials=provision_backend.credentials, lp=lp,
- global_schema=False, am_rodc=am_rodc)
-
- logger.info("Pre-loading the Samba 4 and AD schema")
-
- # Load the schema from the one we computed earlier
- samdb.set_schema(schema, write_indices_and_attributes=False)
-
- # 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)
-
- # 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
- # the schema @ATTRIBUTES and @INDEXLIST records to the database.
- samdb.set_schema(schema, write_indices_and_attributes=True)
-
- return samdb
-
-
-def fill_samdb(samdb, lp, names, logger, domainsid, domainguid, 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):
-
- if next_rid is None:
- next_rid = 1000
-
- # Provision does not make much sense values larger than 1000000000
- # as the upper range of the rIDAvailablePool is 1073741823 and
- # we don't want to create a domain that cannot allocate rids.
- if next_rid < 1000 or next_rid > 1000000000:
- error = "You want to run SAMBA 4 with a next_rid of %u, " % (next_rid)
- error += "the valid range is %u-%u. The default is %u." % (
- 1000, 1000000000, 1000)
- raise ProvisioningError(error)
-
- # ATTENTION: Do NOT change these default values without discussion with the
- # team and/or release manager. They have a big impact on the whole program!
- domainControllerFunctionality = DS_DOMAIN_FUNCTION_2008_R2
-
- if dom_for_fun_level is None:
- dom_for_fun_level = DS_DOMAIN_FUNCTION_2003
-
- 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!")
-
- domainFunctionality = dom_for_fun_level
- forestFunctionality = dom_for_fun_level
-
- # 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.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 = ""
-
- 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
- })
-
- 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(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")
-
- except:
- samdb.transaction_cancel()
- raise
- else:
- samdb.transaction_commit()
-
- 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"), {
- "CONFIGDN": names.configdn,
- "DISPLAYSPECIFIERS_DESCRIPTOR": protected2_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"), {
- "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(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,
- "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,
- })
-
- # 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("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"), {
- "CONFIGDN": names.configdn,
- "WELLKNOWNPRINCIPALS_DESCRIPTOR": protected1wd_descr,
- })
-
- 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 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'))
- })
-
- 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
-
-
-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"
-
-def set_dir_acl(path, acl, lp, domsid, use_ntvfs, passdb, service=SYSVOL_SERVICE):
- setntacl(lp, path, acl, domsid, use_ntvfs=use_ntvfs, skip_invalid_chown=True, passdb=passdb, service=service)
- for root, dirs, files in os.walk(path, topdown=False):
- for name in files:
- setntacl(lp, os.path.join(root, name), acl, domsid,
- use_ntvfs=use_ntvfs, skip_invalid_chown=True, passdb=passdb, service=service)
- for name in dirs:
- setntacl(lp, os.path.join(root, name), acl, domsid,
- use_ntvfs=use_ntvfs, skip_invalid_chown=True, passdb=passdb, service=service)
-
-
-def set_gpos_acl(sysvol, dnsdomain, domainsid, domaindn, samdb, lp, use_ntvfs, passdb):
- """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),
- use_ntvfs=use_ntvfs, skip_invalid_chown=True, passdb=passdb, service=SYSVOL_SERVICE)
-
- 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"]))
- set_dir_acl(policy_path, dsacl2fsacl(acl, domainsid), lp,
- str(domainsid), use_ntvfs,
- passdb=passdb)
-
-
-def setsysvolacl(samdb, netlogon, sysvol, uid, gid, domainsid, dnsdomain,
- domaindn, lp, use_ntvfs):
- """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 uid: The UID of the "Administrator" user
- :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=...)
- """
- s4_passdb = None
-
- if not use_ntvfs:
- # This will ensure that the smbd code we are running when setting ACLs
- # is initialised with the smb.conf
- s3conf = s3param.get_context()
- s3conf.load(lp.configfile)
- # ensure we are using the right samba_dsdb passdb backend, no matter what
- s3conf.set("passdb backend", "samba_dsdb:%s" % samdb.url)
- passdb.reload_static_pdb()
-
- # ensure that we init the samba_dsdb backend, so the domain sid is
- # marked in secrets.tdb
- s4_passdb = passdb.PDB(s3conf.get("passdb backend"))
-
- # now ensure everything matches correctly, to avoid wierd issues
- if passdb.get_global_sam_sid() != domainsid:
- raise ProvisioningError('SID as seen by smbd [%s] does not match SID as seen by the provision script [%s]!' % (passdb.get_global_sam_sid(), domainsid))
-
- domain_info = s4_passdb.domain_info()
- if domain_info["dom_sid"] != domainsid:
- raise ProvisioningError('SID as seen by pdb_samba_dsdb [%s] does not match SID as seen by the provision script [%s]!' % (domain_info["dom_sid"], domainsid))
-
- if domain_info["dns_domain"].upper() != dnsdomain.upper():
- raise ProvisioningError('Realm as seen by pdb_samba_dsdb [%s] does not match Realm as seen by the provision script [%s]!' % (domain_info["dns_domain"].upper(), dnsdomain.upper()))
-
-
- try:
- if use_ntvfs:
- os.chown(sysvol, -1, gid)
- except OSError:
- canchown = False
- else:
- canchown = True
-
- # Set the SYSVOL_ACL on the sysvol folder and subfolder (first level)
- setntacl(lp,sysvol, SYSVOL_ACL, str(domainsid), use_ntvfs=use_ntvfs,
- skip_invalid_chown=True, passdb=s4_passdb,
- service=SYSVOL_SERVICE)
- for root, dirs, files in os.walk(sysvol, topdown=False):
- for name in files:
- if use_ntvfs and canchown:
- os.chown(os.path.join(root, name), -1, gid)
- setntacl(lp, os.path.join(root, name), SYSVOL_ACL, str(domainsid),
- use_ntvfs=use_ntvfs, skip_invalid_chown=True,
- passdb=s4_passdb, service=SYSVOL_SERVICE)
- for name in dirs:
- if use_ntvfs and canchown:
- os.chown(os.path.join(root, name), -1, gid)
- setntacl(lp, os.path.join(root, name), SYSVOL_ACL, str(domainsid),
- use_ntvfs=use_ntvfs, skip_invalid_chown=True,
- passdb=s4_passdb, service=SYSVOL_SERVICE)
-
- # Set acls on Policy folder and policies folders
- set_gpos_acl(sysvol, dnsdomain, domainsid, domaindn, samdb, lp, use_ntvfs, passdb=s4_passdb)
-
-def acl_type(direct_db_access):
- if direct_db_access:
- return "DB"
- else:
- return "VFS"
-
-def check_dir_acl(path, acl, lp, domainsid, direct_db_access):
- fsacl = getntacl(lp, path, direct_db_access=direct_db_access, service=SYSVOL_SERVICE)
- fsacl_sddl = fsacl.as_sddl(domainsid)
- if fsacl_sddl != acl:
- raise ProvisioningError('%s ACL on GPO directory %s %s does not match expected value %s from GPO object' % (acl_type(direct_db_access), path, fsacl_sddl, acl))
-
- for root, dirs, files in os.walk(path, topdown=False):
- for name in files:
- fsacl = getntacl(lp, os.path.join(root, name),
- direct_db_access=direct_db_access, service=SYSVOL_SERVICE)
- if fsacl is None:
- raise ProvisioningError('%s ACL on GPO file %s %s not found!' % (acl_type(direct_db_access), os.path.join(root, name)))
- fsacl_sddl = fsacl.as_sddl(domainsid)
- if fsacl_sddl != acl:
- raise ProvisioningError('%s ACL on GPO file %s %s does not match expected value %s from GPO object' % (acl_type(direct_db_access), os.path.join(root, name), fsacl_sddl, acl))
-
- for name in dirs:
- fsacl = getntacl(lp, os.path.join(root, name),
- direct_db_access=direct_db_access, service=SYSVOL_SERVICE)
- if fsacl is None:
- raise ProvisioningError('%s ACL on GPO directory %s %s not found!' % (acl_type(direct_db_access), os.path.join(root, name)))
- fsacl_sddl = fsacl.as_sddl(domainsid)
- if fsacl_sddl != acl:
- raise ProvisioningError('%s ACL on GPO directory %s %s does not match expected value %s from GPO object' % (acl_type(direct_db_access), os.path.join(root, name), fsacl_sddl, acl))
-
-
-def check_gpos_acl(sysvol, dnsdomain, domainsid, domaindn, samdb, lp,
- direct_db_access):
- """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")
- fsacl = getntacl(lp, root_policy_path,
- direct_db_access=direct_db_access, service=SYSVOL_SERVICE)
- if fsacl is None:
- raise ProvisioningError('DB ACL on policy root %s %s not found!' % (acl_type(direct_db_access), root_policy_path))
- fsacl_sddl = fsacl.as_sddl(domainsid)
- if fsacl_sddl != POLICIES_ACL:
- raise ProvisioningError('%s ACL on policy root %s %s does not match expected value %s from provision' % (acl_type(direct_db_access), root_policy_path, fsacl_sddl, fsacl))
- 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"]))
- check_dir_acl(policy_path, dsacl2fsacl(acl, domainsid), lp,
- domainsid, direct_db_access)
-
-
-def checksysvolacl(samdb, netlogon, sysvol, 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 uid: The UID of the "Administrator" user
- :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=...)
- """
-
- # This will ensure that the smbd code we are running when setting ACLs is initialised with the smb.conf
- s3conf = s3param.get_context()
- s3conf.load(lp.configfile)
- # ensure we are using the right samba_dsdb passdb backend, no matter what
- s3conf.set("passdb backend", "samba_dsdb:%s" % samdb.url)
- # ensure that we init the samba_dsdb backend, so the domain sid is marked in secrets.tdb
- s4_passdb = passdb.PDB(s3conf.get("passdb backend"))
-
- # now ensure everything matches correctly, to avoid wierd issues
- if passdb.get_global_sam_sid() != domainsid:
- raise ProvisioningError('SID as seen by smbd [%s] does not match SID as seen by the provision script [%s]!' % (passdb.get_global_sam_sid(), domainsid))
-
- domain_info = s4_passdb.domain_info()
- if domain_info["dom_sid"] != domainsid:
- raise ProvisioningError('SID as seen by pdb_samba_dsdb [%s] does not match SID as seen by the provision script [%s]!' % (domain_info["dom_sid"], domainsid))
-
- if domain_info["dns_domain"].upper() != dnsdomain.upper():
- raise ProvisioningError('Realm as seen by pdb_samba_dsdb [%s] does not match Realm as seen by the provision script [%s]!' % (domain_info["dns_domain"].upper(), dnsdomain.upper()))
-
- # Ensure we can read this directly, and via the smbd VFS
- for direct_db_access in [True, False]:
- # Check the SYSVOL_ACL on the sysvol folder and subfolder (first level)
- for dir_path in [os.path.join(sysvol, dnsdomain), netlogon]:
- fsacl = getntacl(lp, dir_path, direct_db_access=direct_db_access, service=SYSVOL_SERVICE)
- if fsacl is None:
- raise ProvisioningError('%s ACL on sysvol directory %s not found!' % (acl_type(direct_db_access), dir_path))
- fsacl_sddl = fsacl.as_sddl(domainsid)
- if fsacl_sddl != SYSVOL_ACL:
- raise ProvisioningError('%s ACL on sysvol directory %s %s does not match expected value %s from provision' % (acl_type(direct_db_access), dir_path, fsacl_sddl, SYSVOL_ACL))
-
- # Check acls on Policy folder and policies folders
- check_gpos_acl(sysvol, dnsdomain, domainsid, domaindn, samdb, lp,
- direct_db_access)
-
-
-def interface_ips_v4(lp):
- """return only IPv4 IPs"""
- ips = samba.interface_ips(lp, False)
- ret = []
- for i in ips:
- if i.find(':') == -1:
- ret.append(i)
- return ret
-
-
-def interface_ips_v6(lp, linklocal=False):
- """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):
- ret.append(i)
- return ret
-
-
-def provision_fill(samdb, secrets_ldb, logger, names, paths,
- domainsid, schema=None,
- targetdir=None, samdb_fill=FILL_FULL,
- hostip=None, hostip6=None,
- next_rid=1000, dc_rid=None, adminpass=None, krbtgtpass=None,
- domainguid=None, policyguid=None, policyguid_dc=None,
- invocationid=None, machinepass=None, ntdsguid=None,
- dns_backend=None, dnspass=None,
- serverrole=None, dom_for_fun_level=None,
- am_rodc=False, lp=None, use_ntvfs=False, skip_sysvolacl=False):
- # 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 = DEFAULT_POLICY_GUID
- policyguid = policyguid.upper()
- if policyguid_dc is None:
- policyguid_dc = DEFAULT_DC_POLICY_GUID
- policyguid_dc = policyguid_dc.upper()
-
- if invocationid is None:
- invocationid = str(uuid.uuid4())
-
- if krbtgtpass is None:
- krbtgtpass = samba.generate_random_password(128, 255)
- if machinepass is None:
- machinepass = samba.generate_random_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":
-
- # Set up group policies (domain policy and domain controller
- # policy)
- create_default_gpo(paths.sysvol, names.dnsdomain, policyguid,
- policyguid_dc)
- if not skip_sysvolacl:
- setsysvolacl(samdb, paths.netlogon, paths.sysvol, paths.root_uid,
- paths.root_gid, 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,
- 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, (enum, estr):
- if enum != ldb.ERR_NO_SUCH_ATTRIBUTE:
- # It might be that this attribute does not exist in this schema
- raise
-
- setup_ad_dns(samdb, secrets_ldb, domainsid, names, paths, lp, logger,
- hostip=hostip, hostip6=hostip6, dns_backend=dns_backend,
- dnspass=dnspass, os_level=dom_for_fun_level,
- targetdir=targetdir, site=DEFAULTSITE)
-
- domainguid = samdb.searchone(basedn=samdb.get_default_basedn(),
- attribute="objectGUID")
- assert isinstance(domainguid, str)
-
- lastProvisionUSNs = get_last_provision_usn(samdb)
- maxUSN = get_max_usn(samdb, str(names.rootdn))
- if lastProvisionUSNs is not None:
- update_provision_usn(samdb, 0, maxUSN, invocationid, 1)
- else:
- set_provision_usn(samdb, 0, maxUSN, invocationid)
-
- logger.info("Setting up sam.ldb rootDSE marking as synchronized")
- setup_modify_ldif(samdb, setup_path("provision_rootdse_modify.ldif"),
- { 'NTDSGUID' : names.ntdsguid })
-
- # fix any dangling GUIDs from the provision
- logger.info("Fixing provision GUIDs")
- chk = dbcheck(samdb, samdb_schema=samdb, verbose=False, fix=True, yes=True,
- quiet=True)
- samdb.transaction_start()
- try:
- # a small number of GUIDs are missing because of ordering issues in the
- # provision code
- for schema_obj in ['CN=Domain', 'CN=Organizational-Person', 'CN=Contact', 'CN=inetOrgPerson']:
- chk.check_database(DN="%s,%s" % (schema_obj, names.schemadn),
- scope=ldb.SCOPE_BASE,
- attrs=['defaultObjectCategory'])
- chk.check_database(DN="CN=IP Security,CN=System,%s" % names.domaindn,
- scope=ldb.SCOPE_ONELEVEL,
- attrs=['ipsecOwnersReference',
- 'ipsecFilterReference',
- 'ipsecISAKMPReference',
- 'ipsecNegotiationPolicyReference',
- 'ipsecNFAReference'])
- except:
- samdb.transaction_cancel()
- raise
- else:
- samdb.transaction_commit()
-
-
-_ROLES_MAP = {
- "ROLE_STANDALONE": "standalone server",
- "ROLE_DOMAIN_MEMBER": "member server",
- "ROLE_DOMAIN_BDC": "active directory domain controller",
- "ROLE_DOMAIN_PDC": "active directory domain controller",
- "dc": "active directory domain controller",
- "member": "member server",
- "domain controller": "active directory domain controller",
- "active directory domain controller": "active directory domain controller",
- "member server": "member server",
- "standalone": "standalone server",
- "standalone server": "standalone server",
- }
-
-
-def sanitize_server_role(role):
- """Sanitize a server role name.
-
- :param role: Server role
- :raise ValueError: If the role can not be interpreted
- :return: Sanitized server role (one of "member server",
- "active directory domain controller", "standalone server")
- """
- try:
- return _ROLES_MAP[role]
- except KeyError:
- raise ValueError(role)
-
-
-def provision_fake_ypserver(logger, samdb, domaindn, netbiosname, nisdomain,
- maxuid, maxgid):
- """Create AD entries for the fake ypserver.
-
- This is needed for being able to manipulate posix attrs via ADUC.
- """
- samdb.transaction_start()
- try:
- logger.info("Setting up fake yp server settings")
- setup_add_ldif(samdb, setup_path("ypServ30.ldif"), {
- "DOMAINDN": domaindn,
- "NETBIOSNAME": netbiosname,
- "NISDOMAIN": nisdomain,
- })
- except:
- samdb.transaction_cancel()
- raise
- else:
- samdb.transaction_commit()
-
-
-def provision(logger, session_info, credentials, 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,
- next_rid=1000, dc_rid=None, adminpass=None, ldapadminpass=None,
- krbtgtpass=None, domainguid=None, policyguid=None, policyguid_dc=None,
- dns_backend=None, dns_forwarder=None, dnspass=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",
- useeadb=False, am_rodc=False, lp=None, use_ntvfs=False,
- use_rfc2307=False, maxuid=None, maxgid=None, skip_sysvolacl=True):
- """Provision samba4
-
- :note: caution, this wipes all existing data!
- """
-
- try:
- serverrole = sanitize_server_role(serverrole)
- except ValueError:
- raise ProvisioningError('server role (%s) should be one of "active directory domain controller", "member server", "standalone server"' % serverrole)
-
- if ldapadminpass is None:
- # Make a new, random password between Samba and it's LDAP server
- ldapadminpass = samba.generate_random_password(128, 255)
-
- if backend_type is None:
- backend_type = "ldb"
-
- 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"])
- users_gid = findnss_gid([users or "users", 'users', 'other', 'staff'])
- root_gid = pwd.getpwuid(root_uid).pw_gid
-
- try:
- bind_gid = findnss_gid(["bind", "named"])
- except KeyError:
- bind_gid = None
-
- if targetdir is not None:
- smbconf = os.path.join(targetdir, "etc", "smb.conf")
- elif smbconf is None:
- smbconf = samba.param.default_path()
- if not os.path.exists(os.path.dirname(smbconf)):
- os.makedirs(os.path.dirname(smbconf))
-
- server_services = []
- global_param = {}
- if use_rfc2307:
- global_param["idmap_ldb:use rfc2307"] = ["yes"]
-
- if dns_backend != "SAMBA_INTERNAL":
- server_services.append("-dns")
- else:
- if dns_forwarder is not None:
- global_param["dns forwarder"] = [dns_forwarder]
-
- if 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):
- # if Samba Team members can't figure out the weird errors
- # loading an empty smb.conf gives, then we need to be smarter.
- # Pretend it just didn't exist --abartlet
- f = open(smbconf, 'r')
- try:
- data = f.read().lstrip()
- finally:
- f.close()
- if data is None or data == "":
- make_smbconf(smbconf, hostname, domain, realm,
- targetdir, serverrole=serverrole,
- eadb=useeadb, use_ntvfs=use_ntvfs,
- lp=lp, global_param=global_param)
- else:
- make_smbconf(smbconf, hostname, domain, realm, targetdir,
- serverrole=serverrole,
- eadb=useeadb, use_ntvfs=use_ntvfs, lp=lp, global_param=global_param)
-
- if lp is None:
- lp = samba.param.LoadParm()
- lp.load(smbconf)
- 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)
- paths = provision_paths_from_lp(lp, names.dnsdomain)
-
- paths.bind_gid = bind_gid
- paths.root_uid = root_uid;
- paths.root_gid = root_gid
-
- if hostip is None:
- logger.info("Looking up IPv4 addresses")
- hostips = interface_ips_v4(lp)
- if len(hostips) > 0:
- hostip = hostips[0]
- if len(hostips) > 1:
- logger.warning("More than one IPv4 address found. Using %s",
- hostip)
- if hostip == "127.0.0.1":
- hostip = None
- if hostip is None:
- logger.warning("No IPv4 address will be assigned")
-
- if hostip6 is None:
- logger.info("Looking up IPv6 addresses")
- hostips = interface_ips_v6(lp, linklocal=False)
- if hostips:
- hostip6 = hostips[0]
- if len(hostips) > 1:
- logger.warning("More than one IPv6 address found. Using %s", hostip6)
- if hostip6 is None:
- logger.warning("No IPv6 address will be assigned")
-
- names.hostip = hostip
- names.hostip6 = hostip6
-
- if serverrole is None:
- serverrole = lp.get("server role")
-
- if not os.path.exists(paths.private_dir):
- os.mkdir(paths.private_dir)
- if not os.path.exists(os.path.join(paths.private_dir, "tls")):
- os.mkdir(os.path.join(paths.private_dir, "tls"))
- 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,
- schemadn=names.schemadn)
-
- if backend_type == "ldb":
- provision_backend = LDBBackend(backend_type, paths=paths,
- lp=lp, credentials=credentials,
- 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,
- names=names, logger=logger,
- ldap_backend_forced_uri=None)
- elif backend_type == "fedora-ds":
- provision_backend = FDSBackend(backend_type, paths=paths,
- lp=lp, credentials=credentials,
- 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,
- names=names, logger=logger, domainsid=domainsid,
- schema=schema, hostname=hostname, ldapadminpass=ldapadminpass,
- slapd_path=slapd_path, ol_mmr_urls=ol_mmr_urls)
- else:
- raise ValueError("Unknown LDAP backend type selected")
-
- provision_backend.init()
- provision_backend.start()
-
- # only install a new shares config db if there is none
- if not os.path.exists(paths.shareconf):
- logger.info("Setting up share.ldb")
- share_ldb = Ldb(paths.shareconf, session_info=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,
- session_info=session_info,
- backend_credentials=provision_backend.secrets_credentials, lp=lp)
-
- try:
- logger.info("Setting up the registry")
- setup_registry(paths.hklm, session_info, lp=lp)
-
- logger.info("Setting up the privileges database")
- setup_privileges(paths.privilege, session_info, lp=lp)
-
- logger.info("Setting up idmap db")
- idmap = setup_idmapdb(paths.idmapdb, session_info=session_info, lp=lp)
-
- setup_name_mappings(idmap, sid=str(domainsid),
- root_uid=root_uid, nobody_uid=nobody_uid,
- users_gid=users_gid, root_gid=root_gid)
-
- logger.info("Setting up SAM db")
- samdb = setup_samdb(paths.samdb, session_info,
- provision_backend, lp, names, logger=logger,
- serverrole=serverrole,
- schema=schema, fill=samdb_fill, am_rodc=am_rodc)
-
- if serverrole == "active directory domain controller":
- if paths.netlogon is None:
- raise MissingShareError("netlogon", paths.smbconf)
-
- if paths.sysvol is None:
- raise MissingShareError("sysvol", paths.smbconf)
-
- if not os.path.isdir(paths.netlogon):
- os.makedirs(paths.netlogon, 0755)
-
- if adminpass is None:
- adminpass = samba.generate_random_password(12, 32)
- adminpass_generated = True
- else:
- adminpass = unicode(adminpass, 'utf-8')
- adminpass_generated = False
-
- 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,
- next_rid=next_rid, dc_rid=dc_rid, adminpass=adminpass,
- krbtgtpass=krbtgtpass, domainguid=domainguid,
- policyguid=policyguid, policyguid_dc=policyguid_dc,
- invocationid=invocationid, machinepass=machinepass,
- ntdsguid=ntdsguid, dns_backend=dns_backend,
- dnspass=dnspass, serverrole=serverrole,
- dom_for_fun_level=dom_for_fun_level, am_rodc=am_rodc,
- lp=lp, use_ntvfs=use_ntvfs,
- skip_sysvolacl=skip_sysvolacl)
-
- 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 "
- "generated at %s", paths.krb5conf)
-
- if serverrole == "active directory domain controller":
- create_dns_update_list(lp, logger, paths)
-
- backend_result = provision_backend.post_setup()
- provision_backend.shutdown()
-
- except:
- secrets_ldb.transaction_cancel()
- raise
-
- # Now commit the secrets.ldb to disk
- secrets_ldb.transaction_commit()
-
- # the commit creates the dns.keytab, now chown it
- dns_keytab_path = os.path.join(paths.private_dir, paths.dns_keytab)
- if os.path.isfile(dns_keytab_path) and paths.bind_gid is not None:
- try:
- os.chmod(dns_keytab_path, 0640)
- os.chown(dns_keytab_path, -1, paths.bind_gid)
- except OSError:
- if not os.environ.has_key('SAMBA_SELFTEST'):
- logger.info("Failed to chown %s to bind gid %u",
- dns_keytab_path, paths.bind_gid)
-
- result = ProvisionResult()
- result.server_role = serverrole
- result.domaindn = domaindn
- result.paths = paths
- result.names = names
- result.lp = lp
- result.samdb = samdb
- result.idmap = idmap
- result.domainsid = str(domainsid)
-
- if samdb_fill == FILL_FULL:
- result.adminpass_generated = adminpass_generated
- result.adminpass = adminpass
- else:
- result.adminpass_generated = False
- result.adminpass = None
-
- result.backend_result = backend_result
-
- if use_rfc2307:
- provision_fake_ypserver(logger=logger, samdb=samdb,
- domaindn=names.domaindn, netbiosname=names.netbiosname,
- nisdomain=names.domain.lower(), maxuid=maxuid, maxgid=maxgid)
-
- return result
-
-
-def provision_become_dc(smbconf=None, targetdir=None,
- realm=None, rootdn=None, domaindn=None, schemadn=None, configdn=None,
- serverdn=None, domain=None, hostname=None, domainsid=None,
- adminpass=None, krbtgtpass=None, domainguid=None, policyguid=None,
- policyguid_dc=None, invocationid=None, machinepass=None, dnspass=None,
- dns_backend=None, root=None, nobody=None, users=None,
- backup=None, serverrole=None, ldap_backend=None,
- ldap_backend_type=None, sitename=None, debuglevel=1, use_ntvfs=False):
-
- logger = logging.getLogger("provision")
- samba.set_debug_level(debuglevel)
-
- res = provision(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=None, domainsid=domainsid,
- machinepass=machinepass,
- serverrole="active directory domain controller",
- sitename=sitename, dns_backend=dns_backend, dnspass=dnspass,
- use_ntvfs=use_ntvfs)
- res.lp.set("debuglevel", str(debuglevel))
- return res
-
-
-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).
-
- :param path: Path of the new named.conf file.
- :param dnsdomain: DNS Domain name
- :param hostname: Local hostname
- :param realm: Realm name
- """
- setup_file(setup_path("krb5.conf"), path, {
- "DNSDOMAIN": dnsdomain,
- "HOSTNAME": hostname,
- "REALM": realm,
- })
-
-
-class ProvisioningError(Exception):
- """A generic provision error."""
-
- def __init__(self, value):
- self.value = value
-
- def __str__(self):
- return "ProvisioningError: " + self.value
-
-
-class InvalidNetbiosName(Exception):
- """A specified name was not a valid NetBIOS name."""
-
- 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):
- super(MissingShareError, self).__init__(
- "Existing smb.conf does not have a [%s] share, but you are "
- "configuring a DC. Please remove %s or add the share manually." %
- (name, smbconf))
diff --git a/source4/scripting/python/samba/provision/backend.py b/source4/scripting/python/samba/provision/backend.py
deleted file mode 100644
index f88b0db89c..0000000000
--- a/source4/scripting/python/samba/provision/backend.py
+++ /dev/null
@@ -1,840 +0,0 @@
-#
-# Unix SMB/CIFS implementation.
-# backend code for provisioning a Samba4 server
-
-# Copyright (C) Jelmer Vernooij <jelmer@samba.org> 2007-2008
-# Copyright (C) Andrew Bartlett <abartlet@samba.org> 2008-2009
-# Copyright (C) Oliver Liebel <oliver@itc.li> 2008-2009
-#
-# Based on the original in EJS:
-# Copyright (C) Andrew Tridgell <tridge@samba.org> 2005
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
-#
-
-"""Functions for setting up a Samba configuration (LDB and LDAP backends)."""
-
-from base64 import b64encode
-import errno
-import ldb
-import os
-import sys
-import uuid
-import time
-import shutil
-import subprocess
-import urllib
-
-from ldb import SCOPE_BASE, SCOPE_ONELEVEL, LdbError, timestring
-
-from samba import Ldb, read_and_sub_file, setup_file
-from samba.credentials import Credentials, DONT_USE_KERBEROS
-from samba.schema import Schema
-
-
-class SlapdAlreadyRunning(Exception):
-
- def __init__(self, uri):
- self.ldapi_uri = uri
- super(SlapdAlreadyRunning, self).__init__("Another slapd Instance "
- "seems already running on this host, listening to %s." %
- self.ldapi_uri)
-
-
-class BackendResult(object):
-
- def report_logger(self, logger):
- """Rerport this result to a particular logger.
-
- """
- raise NotImplementedError(self.report_logger)
-
-
-class LDAPBackendResult(BackendResult):
-
- def __init__(self, credentials, slapd_command_escaped, ldapdir):
- self.credentials = credentials
- self.slapd_command_escaped = slapd_command_escaped
- self.ldapdir = ldapdir
-
- def report_logger(self, logger):
- if self.credentials.get_bind_dn() is not None:
- logger.info("LDAP Backend Admin DN: %s" %
- self.credentials.get_bind_dn())
- else:
- logger.info("LDAP Admin User: %s" %
- self.credentials.get_username())
-
- if self.slapd_command_escaped is not None:
- # now display slapd_command_file.txt to show how slapd must be
- # started next time
- logger.info(
- "Use later the following commandline to start slapd, then Samba:")
- logger.info(self.slapd_command_escaped)
- logger.info(
- "This slapd-Commandline is also stored under: %s/ldap_backend_startup.sh",
- self.ldapdir)
-
-
-class ProvisionBackend(object):
-
- def __init__(self, backend_type, paths=None, lp=None,
- credentials=None, names=None, logger=None):
- """Provision a backend for samba4"""
- self.paths = paths
- self.lp = lp
- self.credentials = credentials
- self.names = names
- self.logger = logger
-
- self.type = backend_type
-
- # Set a default - the code for "existing" below replaces this
- self.ldap_backend_type = backend_type
-
- def init(self):
- """Initialize the backend."""
- raise NotImplementedError(self.init)
-
- def start(self):
- """Start the backend."""
- raise NotImplementedError(self.start)
-
- def shutdown(self):
- """Shutdown the backend."""
- raise NotImplementedError(self.shutdown)
-
- def post_setup(self):
- """Post setup.
-
- :return: A BackendResult or None
- """
- raise NotImplementedError(self.post_setup)
-
-
-class LDBBackend(ProvisionBackend):
-
- def init(self):
- self.credentials = None
- self.secrets_credentials = None
-
- # Wipe the old sam.ldb databases away
- shutil.rmtree(self.paths.samdb + ".d", True)
-
- def start(self):
- pass
-
- def shutdown(self):
- pass
-
- def post_setup(self):
- pass
-
-
-class ExistingBackend(ProvisionBackend):
-
- def __init__(self, backend_type, paths=None, lp=None,
- credentials=None, names=None, logger=None, ldapi_uri=None):
-
- super(ExistingBackend, self).__init__(backend_type=backend_type,
- paths=paths, lp=lp,
- credentials=credentials, names=names, logger=logger,
- ldap_backend_forced_uri=ldapi_uri)
-
- def init(self):
- # Check to see that this 'existing' LDAP backend in fact exists
- ldapi_db = Ldb(self.ldapi_uri, credentials=self.credentials)
- ldapi_db.search(base="", scope=SCOPE_BASE,
- expression="(objectClass=OpenLDAProotDSE)")
-
- # If we have got here, then we must have a valid connection to the LDAP
- # server, with valid credentials supplied This caused them to be set
- # into the long-term database later in the script.
- self.secrets_credentials = self.credentials
-
- # For now, assume existing backends at least emulate OpenLDAP
- self.ldap_backend_type = "openldap"
-
-
-class LDAPBackend(ProvisionBackend):
-
- def __init__(self, backend_type, paths=None, lp=None,
- credentials=None, names=None, logger=None, domainsid=None,
- schema=None, hostname=None, ldapadminpass=None,
- slapd_path=None, ldap_backend_extra_port=None,
- ldap_backend_forced_uri=None, ldap_dryrun_mode=True):
-
- super(LDAPBackend, self).__init__(backend_type=backend_type,
- paths=paths, lp=lp,
- credentials=credentials, names=names, logger=logger)
-
- self.domainsid = domainsid
- self.schema = schema
- self.hostname = hostname
-
- self.ldapdir = os.path.join(paths.private_dir, "ldap")
- self.ldapadminpass = ldapadminpass
-
- self.slapd_path = slapd_path
- self.slapd_command = None
- self.slapd_command_escaped = None
- self.slapd_pid = os.path.join(self.ldapdir, "slapd.pid")
-
- self.ldap_backend_extra_port = ldap_backend_extra_port
- self.ldap_dryrun_mode = ldap_dryrun_mode
-
- if ldap_backend_forced_uri is not None:
- self.ldap_uri = ldap_backend_forced_uri
- else:
- self.ldap_uri = "ldapi://%s" % urllib.quote(
- os.path.join(self.ldapdir, "ldapi"), safe="")
-
- if not os.path.exists(self.ldapdir):
- os.mkdir(self.ldapdir)
-
- def init(self):
- from samba.provision import ProvisioningError
- # we will shortly start slapd with ldapi for final provisioning. first
- # check with ldapsearch -> rootDSE via self.ldap_uri if another
- # instance of slapd is already running
- try:
- ldapi_db = Ldb(self.ldap_uri)
- ldapi_db.search(base="", scope=SCOPE_BASE,
- expression="(objectClass=OpenLDAProotDSE)")
- try:
- f = open(self.slapd_pid, "r")
- except IOError, err:
- if err != errno.ENOENT:
- raise
- else:
- try:
- p = f.read()
- finally:
- f.close()
- self.logger.info("Check for slapd process with PID: %s and terminate it manually." % p)
- raise SlapdAlreadyRunning(self.ldap_uri)
- except LdbError:
- # XXX: We should never be catching all Ldb errors
- pass
-
- # Try to print helpful messages when the user has not specified the
- # path to slapd
- if self.slapd_path is None:
- raise ProvisioningError("Warning: LDAP-Backend must be setup with path to slapd, e.g. --slapd-path=\"/usr/local/libexec/slapd\"!")
- if not os.path.exists(self.slapd_path):
- self.logger.warning("Path (%s) to slapd does not exist!",
- self.slapd_path)
-
- if not os.path.isdir(self.ldapdir):
- os.makedirs(self.ldapdir, 0700)
-
- # Put the LDIF of the schema into a database so we can search on
- # it to generate schema-dependent configurations in Fedora DS and
- # OpenLDAP
- schemadb_path = os.path.join(self.ldapdir, "schema-tmp.ldb")
- try:
- os.unlink(schemadb_path)
- except OSError:
- pass
-
- self.schema.write_to_tmp_ldb(schemadb_path)
-
- self.credentials = Credentials()
- self.credentials.guess(self.lp)
- # Kerberos to an ldapi:// backend makes no sense
- self.credentials.set_kerberos_state(DONT_USE_KERBEROS)
- self.credentials.set_password(self.ldapadminpass)
-
- self.secrets_credentials = Credentials()
- self.secrets_credentials.guess(self.lp)
- # Kerberos to an ldapi:// backend makes no sense
- self.secrets_credentials.set_kerberos_state(DONT_USE_KERBEROS)
- self.secrets_credentials.set_username("samba-admin")
- self.secrets_credentials.set_password(self.ldapadminpass)
-
- self.provision()
-
- def provision(self):
- pass
-
- def start(self):
- from samba.provision import ProvisioningError
- self.slapd_command_escaped = "\'" + "\' \'".join(self.slapd_command) + "\'"
- f = open(os.path.join(self.ldapdir, "ldap_backend_startup.sh"), 'w')
- try:
- f.write("#!/bin/sh\n" + self.slapd_command_escaped + "\n")
- finally:
- f.close()
-
- # Now start the slapd, so we can provision onto it. We keep the
- # subprocess context around, to kill this off at the successful
- # end of the script
- self.slapd = subprocess.Popen(self.slapd_provision_command,
- close_fds=True, shell=False)
-
- count = 0
- while self.slapd.poll() is None:
- # Wait until the socket appears
- try:
- ldapi_db = Ldb(self.ldap_uri, lp=self.lp, credentials=self.credentials)
- ldapi_db.search(base="", scope=SCOPE_BASE,
- expression="(objectClass=OpenLDAProotDSE)")
- # If we have got here, then we must have a valid connection to
- # the LDAP server!
- return
- except LdbError:
- time.sleep(1)
- count = count + 1
-
- if count > 15:
- self.logger.error("Could not connect to slapd started with: %s" % "\'" + "\' \'".join(self.slapd_provision_command) + "\'")
- raise ProvisioningError("slapd never accepted a connection within 15 seconds of starting")
-
- self.logger.error("Could not start slapd with: %s" % "\'" + "\' \'".join(self.slapd_provision_command) + "\'")
- raise ProvisioningError("slapd died before we could make a connection to it")
-
- def shutdown(self):
- # if an LDAP backend is in use, terminate slapd after final provision
- # and check its proper termination
- if self.slapd.poll() is None:
- # Kill the slapd
- if getattr(self.slapd, "terminate", None) is not None:
- self.slapd.terminate()
- else:
- # Older python versions don't have .terminate()
- import signal
- os.kill(self.slapd.pid, signal.SIGTERM)
-
- # and now wait for it to die
- self.slapd.communicate()
-
- def post_setup(self):
- return LDAPBackendResult(self.credentials, self.slapd_command_escaped,
- self.ldapdir)
-
-
-class OpenLDAPBackend(LDAPBackend):
-
- def __init__(self, backend_type, paths=None, lp=None,
- credentials=None, names=None, logger=None, domainsid=None,
- schema=None, hostname=None, ldapadminpass=None, slapd_path=None,
- ldap_backend_extra_port=None, ldap_dryrun_mode=True,
- ol_mmr_urls=None, nosync=False, ldap_backend_forced_uri=None):
- from samba.provision import setup_path
- super(OpenLDAPBackend, self).__init__( backend_type=backend_type,
- paths=paths, lp=lp,
- credentials=credentials, names=names, logger=logger,
- domainsid=domainsid, schema=schema, hostname=hostname,
- ldapadminpass=ldapadminpass, slapd_path=slapd_path,
- ldap_backend_extra_port=ldap_backend_extra_port,
- ldap_backend_forced_uri=ldap_backend_forced_uri,
- ldap_dryrun_mode=ldap_dryrun_mode)
-
- self.ol_mmr_urls = ol_mmr_urls
- self.nosync = nosync
-
- self.slapdconf = os.path.join(self.ldapdir, "slapd.conf")
- self.modulesconf = os.path.join(self.ldapdir, "modules.conf")
- self.memberofconf = os.path.join(self.ldapdir, "memberof.conf")
- self.olmmrserveridsconf = os.path.join(self.ldapdir, "mmr_serverids.conf")
- self.olmmrsyncreplconf = os.path.join(self.ldapdir, "mmr_syncrepl.conf")
- self.olcdir = os.path.join(self.ldapdir, "slapd.d")
- self.olcseedldif = os.path.join(self.ldapdir, "olc_seed.ldif")
-
- self.schema = Schema(self.domainsid,
- schemadn=self.names.schemadn, files=[
- setup_path("schema_samba4.ldif")])
-
- def setup_db_config(self, dbdir):
- """Setup a Berkeley database.
-
- :param dbdir: Database directory.
- """
- from samba.provision import setup_path
- if not os.path.isdir(os.path.join(dbdir, "bdb-logs")):
- os.makedirs(os.path.join(dbdir, "bdb-logs"), 0700)
- if not os.path.isdir(os.path.join(dbdir, "tmp")):
- os.makedirs(os.path.join(dbdir, "tmp"), 0700)
-
- setup_file(setup_path("DB_CONFIG"),
- os.path.join(dbdir, "DB_CONFIG"), {"LDAPDBDIR": dbdir})
-
- def provision(self):
- from samba.provision import ProvisioningError, setup_path
- # Wipe the directories so we can start
- shutil.rmtree(os.path.join(self.ldapdir, "db"), True)
-
- # Allow the test scripts to turn off fsync() for OpenLDAP as for TDB
- # and LDB
- nosync_config = ""
- if self.nosync:
- nosync_config = "dbnosync"
-
- lnkattr = self.schema.linked_attributes()
- refint_attributes = ""
- memberof_config = "# Generated from Samba4 schema\n"
- for att in lnkattr.keys():
- if lnkattr[att] is not None:
- refint_attributes = refint_attributes + " " + att
-
- memberof_config += read_and_sub_file(
- setup_path("memberof.conf"), {
- "MEMBER_ATTR": att,
- "MEMBEROF_ATTR" : lnkattr[att] })
-
- refint_config = read_and_sub_file(setup_path("refint.conf"),
- { "LINK_ATTRS" : refint_attributes})
-
- attrs = ["linkID", "lDAPDisplayName"]
- res = self.schema.ldb.search(expression="(&(objectclass=attributeSchema)(searchFlags:1.2.840.113556.1.4.803:=1))", base=self.names.schemadn, scope=SCOPE_ONELEVEL, attrs=attrs)
- index_config = ""
- for i in range (0, len(res)):
- index_attr = res[i]["lDAPDisplayName"][0]
- if index_attr == "objectGUID":
- index_attr = "entryUUID"
-
- index_config += "index " + index_attr + " eq\n"
-
- # 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 self.ol_mmr_urls is not None:
- # For now, make these equal
- mmr_pass = self.ldapadminpass
-
- url_list = filter(None,self.ol_mmr_urls.split(','))
- for url in url_list:
- self.logger.info("Using LDAP-URL: "+url)
- if len(url_list) == 1:
- raise ProvisioningError("At least 2 LDAP-URLs needed for MMR!")
-
- 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": self.names.schemadn,
- "LDAPSERVER" : url,
- "MMR_PASSWORD": mmr_pass})
-
- rid = rid + 1
- mmr_syncrepl_config_config += read_and_sub_file(
- setup_path("mmr_syncrepl.conf"), {
- "RID" : str(rid),
- "MMRDN": self.names.configdn,
- "LDAPSERVER" : url,
- "MMR_PASSWORD": mmr_pass})
-
- rid = rid + 1
- mmr_syncrepl_user_config += read_and_sub_file(
- setup_path("mmr_syncrepl.conf"), {
- "RID" : str(rid),
- "MMRDN": self.names.domaindn,
- "LDAPSERVER" : url,
- "MMR_PASSWORD": mmr_pass })
- # OpenLDAP cn=config initialisation
- olc_syncrepl_config = ""
- olc_mmr_config = ""
- # if mmr = yes, generate cn=config-replication directives
- # and olc_seed.lif for the other mmr-servers
- if self.ol_mmr_urls is not None:
- serverid = 0
- olc_serverids_config = ""
- olc_syncrepl_seed_config = ""
- olc_mmr_config += read_and_sub_file(
- setup_path("olc_mmr.conf"), {})
- rid = 500
- for url in url_list:
- serverid = serverid + 1
- olc_serverids_config += read_and_sub_file(
- setup_path("olc_serverid.conf"), {
- "SERVERID" : str(serverid), "LDAPSERVER" : url })
-
- rid = rid + 1
- olc_syncrepl_config += read_and_sub_file(
- setup_path("olc_syncrepl.conf"), {
- "RID" : str(rid), "LDAPSERVER" : url,
- "MMR_PASSWORD": mmr_pass})
-
- olc_syncrepl_seed_config += read_and_sub_file(
- setup_path("olc_syncrepl_seed.conf"), {
- "RID" : str(rid), "LDAPSERVER" : url})
-
- setup_file(setup_path("olc_seed.ldif"), self.olcseedldif,
- {"OLC_SERVER_ID_CONF": olc_serverids_config,
- "OLC_PW": self.ldapadminpass,
- "OLC_SYNCREPL_CONF": olc_syncrepl_seed_config})
- # end olc
-
- setup_file(setup_path("slapd.conf"), self.slapdconf,
- {"DNSDOMAIN": self.names.dnsdomain,
- "LDAPDIR": self.ldapdir,
- "DOMAINDN": self.names.domaindn,
- "CONFIGDN": self.names.configdn,
- "SCHEMADN": self.names.schemadn,
- "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,
- "OLC_SYNCREPL_CONFIG": olc_syncrepl_config,
- "OLC_MMR_CONFIG": olc_mmr_config,
- "REFINT_CONFIG": refint_config,
- "INDEX_CONFIG": index_config,
- "NOSYNC": nosync_config})
-
- self.setup_db_config(os.path.join(self.ldapdir, "db", "user"))
- self.setup_db_config(os.path.join(self.ldapdir, "db", "config"))
- self.setup_db_config(os.path.join(self.ldapdir, "db", "schema"))
-
- if not os.path.exists(os.path.join(self.ldapdir, "db", "samba", "cn=samba")):
- os.makedirs(os.path.join(self.ldapdir, "db", "samba", "cn=samba"), 0700)
-
- setup_file(setup_path("cn=samba.ldif"),
- os.path.join(self.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(self.ldapdir, "db", "samba", "cn=samba", "cn=samba-admin.ldif"),
- {"LDAPADMINPASS_B64": b64encode(self.ldapadminpass),
- "UUID": str(uuid.uuid4()),
- "LDAPTIME": timestring(int(time.time()))} )
-
- if self.ol_mmr_urls is not None:
- setup_file(setup_path("cn=replicator.ldif"),
- os.path.join(self.ldapdir, "db", "samba", "cn=samba", "cn=replicator.ldif"),
- {"MMR_PASSWORD_B64": b64encode(mmr_pass),
- "UUID": str(uuid.uuid4()),
- "LDAPTIME": timestring(int(time.time()))} )
-
- mapping = "schema-map-openldap-2.3"
- backend_schema = "backend-schema.schema"
-
- f = open(setup_path(mapping), 'r')
- try:
- backend_schema_data = self.schema.convert_to_openldap(
- "openldap", f.read())
- finally:
- f.close()
- assert backend_schema_data is not None
- f = open(os.path.join(self.ldapdir, backend_schema), 'w')
- try:
- f.write(backend_schema_data)
- finally:
- f.close()
-
- # now we generate the needed strings to start slapd automatically,
- if self.ldap_backend_extra_port is not None:
- # When we use MMR, we can't use 0.0.0.0 as it uses the name
- # specified there as part of it's clue as to it's own name,
- # and not to replicate to itself
- if self.ol_mmr_urls is None:
- server_port_string = "ldap://0.0.0.0:%d" % self.ldap_backend_extra_port
- else:
- server_port_string = "ldap://%s.%s:%d" (self.names.hostname,
- self.names.dnsdomain, self.ldap_backend_extra_port)
- else:
- server_port_string = ""
-
- # Prepare the 'result' information - the commands to return in
- # particular
- self.slapd_provision_command = [self.slapd_path, "-F" + self.olcdir,
- "-h"]
-
- # copy this command so we have two version, one with -d0 and only
- # ldapi (or the forced ldap_uri), and one with all the listen commands
- self.slapd_command = list(self.slapd_provision_command)
-
- self.slapd_provision_command.extend([self.ldap_uri, "-d0"])
-
- uris = self.ldap_uri
- if server_port_string is not "":
- uris = uris + " " + server_port_string
-
- self.slapd_command.append(uris)
-
- # Set the username - done here because Fedora DS still uses the admin
- # DN and simple bind
- self.credentials.set_username("samba-admin")
-
- # Wipe the old sam.ldb databases away
- shutil.rmtree(self.olcdir, True)
- os.makedirs(self.olcdir, 0770)
-
- # If we were just looking for crashes up to this point, it's a
- # good time to exit before we realise we don't have OpenLDAP on
- # this system
- if self.ldap_dryrun_mode:
- sys.exit(0)
-
- slapd_cmd = [self.slapd_path, "-Ttest", "-n", "0", "-f",
- self.slapdconf, "-F", self.olcdir]
- retcode = subprocess.call(slapd_cmd, close_fds=True, shell=False)
-
- if retcode != 0:
- self.logger.error("conversion from slapd.conf to cn=config failed slapd started with: %s" % "\'" + "\' \'".join(slapd_cmd) + "\'")
- raise ProvisioningError("conversion from slapd.conf to cn=config failed")
-
- if not os.path.exists(os.path.join(self.olcdir, "cn=config.ldif")):
- raise ProvisioningError("conversion from slapd.conf to cn=config failed")
-
- # Don't confuse the admin by leaving the slapd.conf around
- os.remove(self.slapdconf)
-
-
-class FDSBackend(LDAPBackend):
-
- def __init__(self, backend_type, paths=None, lp=None,
- credentials=None, names=None, logger=None, domainsid=None,
- schema=None, hostname=None, ldapadminpass=None, slapd_path=None,
- ldap_backend_extra_port=None, ldap_dryrun_mode=True, root=None,
- setup_ds_path=None):
-
- from samba.provision import setup_path
-
- super(FDSBackend, self).__init__(backend_type=backend_type,
- paths=paths, lp=lp,
- credentials=credentials, names=names, logger=logger,
- domainsid=domainsid, schema=schema, hostname=hostname,
- ldapadminpass=ldapadminpass, slapd_path=slapd_path,
- ldap_backend_extra_port=ldap_backend_extra_port,
- ldap_backend_forced_uri=ldap_backend_forced_uri,
- ldap_dryrun_mode=ldap_dryrun_mode)
-
- self.root = root
- self.setup_ds_path = setup_ds_path
- self.ldap_instance = self.names.netbiosname.lower()
-
- self.sambadn = "CN=Samba"
-
- self.fedoradsinf = os.path.join(self.ldapdir, "fedorads.inf")
- self.partitions_ldif = os.path.join(self.ldapdir,
- "fedorads-partitions.ldif")
- self.sasl_ldif = os.path.join(self.ldapdir, "fedorads-sasl.ldif")
- self.dna_ldif = os.path.join(self.ldapdir, "fedorads-dna.ldif")
- self.pam_ldif = os.path.join(self.ldapdir, "fedorads-pam.ldif")
- self.refint_ldif = os.path.join(self.ldapdir, "fedorads-refint.ldif")
- self.linked_attrs_ldif = os.path.join(self.ldapdir,
- "fedorads-linked-attributes.ldif")
- self.index_ldif = os.path.join(self.ldapdir, "fedorads-index.ldif")
- self.samba_ldif = os.path.join(self.ldapdir, "fedorads-samba.ldif")
-
- self.samba3_schema = setup_path(
- "../../examples/LDAP/samba.schema")
- self.samba3_ldif = os.path.join(self.ldapdir, "samba3.ldif")
-
- self.retcode = subprocess.call(["bin/oLschema2ldif",
- "-I", self.samba3_schema,
- "-O", self.samba3_ldif,
- "-b", self.names.domaindn],
- close_fds=True, shell=False)
-
- if self.retcode != 0:
- raise Exception("Unable to convert Samba 3 schema.")
-
- self.schema = Schema(
- self.domainsid,
- schemadn=self.names.schemadn,
- files=[setup_path("schema_samba4.ldif"), self.samba3_ldif],
- additional_prefixmap=["1000:1.3.6.1.4.1.7165.2.1",
- "1001:1.3.6.1.4.1.7165.2.2"])
-
- def provision(self):
- from samba.provision import ProvisioningError, setup_path
- if self.ldap_backend_extra_port is not None:
- serverport = "ServerPort=%d" % self.ldap_backend_extra_port
- else:
- serverport = ""
-
- setup_file(setup_path("fedorads.inf"), self.fedoradsinf,
- {"ROOT": self.root,
- "HOSTNAME": self.hostname,
- "DNSDOMAIN": self.names.dnsdomain,
- "LDAPDIR": self.ldapdir,
- "DOMAINDN": self.names.domaindn,
- "LDAP_INSTANCE": self.ldap_instance,
- "LDAPMANAGERDN": self.names.ldapmanagerdn,
- "LDAPMANAGERPASS": self.ldapadminpass,
- "SERVERPORT": serverport})
-
- setup_file(setup_path("fedorads-partitions.ldif"),
- self.partitions_ldif,
- {"CONFIGDN": self.names.configdn,
- "SCHEMADN": self.names.schemadn,
- "SAMBADN": self.sambadn,
- })
-
- setup_file(setup_path("fedorads-sasl.ldif"), self.sasl_ldif,
- {"SAMBADN": self.sambadn,
- })
-
- setup_file(setup_path("fedorads-dna.ldif"), self.dna_ldif,
- {"DOMAINDN": self.names.domaindn,
- "SAMBADN": self.sambadn,
- "DOMAINSID": str(self.domainsid),
- })
-
- setup_file(setup_path("fedorads-pam.ldif"), self.pam_ldif)
-
- lnkattr = self.schema.linked_attributes()
-
- f = open(setup_path("fedorads-refint-delete.ldif"), 'r')
- try:
- refint_config = f.read()
- finally:
- f.close()
- memberof_config = ""
- index_config = ""
- argnum = 3
-
- for attr in lnkattr.keys():
- if lnkattr[attr] is not None:
- refint_config += read_and_sub_file(
- setup_path("fedorads-refint-add.ldif"),
- { "ARG_NUMBER" : str(argnum),
- "LINK_ATTR" : attr })
- memberof_config += read_and_sub_file(
- setup_path("fedorads-linked-attributes.ldif"),
- { "MEMBER_ATTR" : attr,
- "MEMBEROF_ATTR" : lnkattr[attr] })
- index_config += read_and_sub_file(
- setup_path("fedorads-index.ldif"), { "ATTR" : attr })
- argnum += 1
-
- f = open(self.refint_ldif, 'w')
- try:
- f.write(refint_config)
- finally:
- f.close()
- f = open(self.linked_attrs_ldif, 'w')
- try:
- f.write(memberof_config)
- finally:
- f.close()
-
- attrs = ["lDAPDisplayName"]
- res = self.schema.ldb.search(expression="(&(objectclass=attributeSchema)(searchFlags:1.2.840.113556.1.4.803:=1))", base=self.names.schemadn, scope=SCOPE_ONELEVEL, attrs=attrs)
-
- for i in range (0, len(res)):
- attr = res[i]["lDAPDisplayName"][0]
-
- if attr == "objectGUID":
- attr = "nsUniqueId"
-
- index_config += read_and_sub_file(
- setup_path("fedorads-index.ldif"), { "ATTR" : attr })
-
- f = open(self.index_ldif, 'w')
- try:
- f.write(index_config)
- finally:
- f.close()
-
- setup_file(setup_path("fedorads-samba.ldif"), self.samba_ldif, {
- "SAMBADN": self.sambadn,
- "LDAPADMINPASS": self.ldapadminpass
- })
-
- mapping = "schema-map-fedora-ds-1.0"
- backend_schema = "99_ad.ldif"
-
- # Build a schema file in Fedora DS format
- f = open(setup_path(mapping), 'r')
- try:
- backend_schema_data = self.schema.convert_to_openldap("fedora-ds",
- f.read())
- finally:
- f.close()
- assert backend_schema_data is not None
- f = open(os.path.join(self.ldapdir, backend_schema), 'w')
- try:
- f.write(backend_schema_data)
- finally:
- f.close()
-
- self.credentials.set_bind_dn(self.names.ldapmanagerdn)
-
- # Destory the target directory, or else setup-ds.pl will complain
- fedora_ds_dir = os.path.join(self.ldapdir,
- "slapd-" + self.ldap_instance)
- shutil.rmtree(fedora_ds_dir, True)
-
- self.slapd_provision_command = [self.slapd_path, "-D", fedora_ds_dir,
- "-i", self.slapd_pid]
- # In the 'provision' command line, stay in the foreground so we can
- # easily kill it
- self.slapd_provision_command.append("-d0")
-
- #the command for the final run is the normal script
- self.slapd_command = [os.path.join(self.ldapdir,
- "slapd-" + self.ldap_instance, "start-slapd")]
-
- # If we were just looking for crashes up to this point, it's a
- # good time to exit before we realise we don't have Fedora DS on
- if self.ldap_dryrun_mode:
- sys.exit(0)
-
- # Try to print helpful messages when the user has not specified the
- # path to the setup-ds tool
- if self.setup_ds_path is None:
- raise ProvisioningError("Fedora DS LDAP-Backend must be setup with path to setup-ds, e.g. --setup-ds-path=\"/usr/sbin/setup-ds.pl\"!")
- if not os.path.exists(self.setup_ds_path):
- self.logger.warning("Path (%s) to slapd does not exist!",
- self.setup_ds_path)
-
- # Run the Fedora DS setup utility
- retcode = subprocess.call([self.setup_ds_path, "--silent", "--file",
- self.fedoradsinf], close_fds=True, shell=False)
- if retcode != 0:
- raise ProvisioningError("setup-ds failed")
-
- # Load samba-admin
- retcode = subprocess.call([
- os.path.join(self.ldapdir, "slapd-" + self.ldap_instance, "ldif2db"), "-s", self.sambadn, "-i", self.samba_ldif],
- close_fds=True, shell=False)
- if retcode != 0:
- raise ProvisioningError("ldif2db failed")
-
- def post_setup(self):
- ldapi_db = Ldb(self.ldap_uri, credentials=self.credentials)
-
- # configure in-directory access control on Fedora DS via the aci
- # attribute (over a direct ldapi:// socket)
- aci = """(targetattr = "*") (version 3.0;acl "full access to all by samba-admin";allow (all)(userdn = "ldap:///CN=samba-admin,%s");)""" % self.sambadn
-
- m = ldb.Message()
- m["aci"] = ldb.MessageElement([aci], ldb.FLAG_MOD_REPLACE, "aci")
-
- for dnstring in (self.names.domaindn, self.names.configdn,
- self.names.schemadn):
- m.dn = ldb.Dn(ldapi_db, dnstring)
- ldapi_db.modify(m)
- return LDAPBackendResult(self.credentials, self.slapd_command_escaped,
- self.ldapdir)
diff --git a/source4/scripting/python/samba/provision/common.py b/source4/scripting/python/samba/provision/common.py
deleted file mode 100644
index f96704bcce..0000000000
--- a/source4/scripting/python/samba/provision/common.py
+++ /dev/null
@@ -1,82 +0,0 @@
-
-# Unix SMB/CIFS implementation.
-# utility functions for provisioning a Samba4 server
-
-# Copyright (C) Jelmer Vernooij <jelmer@samba.org> 2007-2010
-# Copyright (C) Andrew Bartlett <abartlet@samba.org> 2008-2009
-# Copyright (C) Oliver Liebel <oliver@itc.li> 2008-2009
-#
-# Based on the original in EJS:
-# Copyright (C) Andrew Tridgell <tridge@samba.org> 2005
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
-#
-
-"""Functions for setting up a Samba configuration."""
-
-__docformat__ = "restructuredText"
-
-import os
-from samba import read_and_sub_file
-from samba.param import setup_dir
-
-
-def setup_path(file):
- """Return an absolute path to the provision tempate file specified by file"""
- return os.path.join(setup_dir(), file)
-
-
-def setup_add_ldif(ldb, ldif_path, subst_vars=None,controls=["relax:0"]):
- """Setup a ldb in the private dir.
-
- :param ldb: LDB file to import data into
- :param ldif_path: Path of the LDIF file to load
- :param subst_vars: Optional variables to subsitute in LDIF.
- :param nocontrols: Optional list of controls, can be None for no controls
- """
- assert isinstance(ldif_path, str)
- data = read_and_sub_file(ldif_path, subst_vars)
- ldb.add_ldif(data, controls)
-
-
-def setup_modify_ldif(ldb, ldif_path, subst_vars=None,controls=["relax:0"]):
- """Modify a ldb in the private dir.
-
- :param ldb: LDB object.
- :param ldif_path: LDIF file path.
- :param subst_vars: Optional dictionary with substitution variables.
- """
- data = read_and_sub_file(ldif_path, subst_vars)
- ldb.modify_ldif(data, controls)
-
-
-def setup_ldb(ldb, ldif_path, subst_vars):
- """Import a LDIF a file into a LDB handle, optionally substituting
- variables.
-
- :note: Either all LDIF data will be added or none (using transactions).
-
- :param ldb: LDB file to import into.
- :param ldif_path: Path to the LDIF file.
- :param subst_vars: Dictionary with substitution variables.
- """
- assert ldb is not None
- ldb.transaction_start()
- try:
- setup_add_ldif(ldb, ldif_path, subst_vars)
- except:
- ldb.transaction_cancel()
- raise
- else:
- ldb.transaction_commit()
diff --git a/source4/scripting/python/samba/provision/descriptor.py b/source4/scripting/python/samba/provision/descriptor.py
deleted file mode 100644
index 32e91ed2b5..0000000000
--- a/source4/scripting/python/samba/provision/descriptor.py
+++ /dev/null
@@ -1,359 +0,0 @@
-
-# Unix SMB/CIFS implementation.
-# backend code for provisioning a Samba4 server
-
-# Copyright (C) Jelmer Vernooij <jelmer@samba.org> 2007-2010
-# Copyright (C) Andrew Bartlett <abartlet@samba.org> 2008-2009
-# Copyright (C) Oliver Liebel <oliver@itc.li> 2008-2009
-# Copyright (C) Amitay Isaacs <amitay@samba.org> 2011
-#
-# Based on the original in EJS:
-# Copyright (C) Andrew Tridgell <tridge@samba.org> 2005
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
-#
-
-"""Functions for setting up a Samba configuration (security descriptors)."""
-
-from samba.dcerpc import security
-from samba.ndr import ndr_pack
-
-# Descriptors of naming contexts and other important objects
-
-def sddl2binary(sddl_in, domain_sid, name_map):
- sddl = "%s" % sddl_in
-
- for [name, sid] in name_map.items():
- sddl = sddl.replace(name, sid)
-
- sec = security.descriptor.from_sddl(sddl, domain_sid)
- return ndr_pack(sec)
-
-def get_empty_descriptor(domain_sid, name_map={}):
- sddl= ""
- return sddl2binary(sddl, domain_sid, name_map)
-
-# "get_schema_descriptor" is located in "schema.py"
-
-def get_config_descriptor(domain_sid, name_map={}):
- sddl = "O:EAG:EAD:(OA;;CR;1131f6aa-9c07-11d1-f79f-00c04fc2dcd2;;ED)" \
- "(OA;;CR;1131f6ab-9c07-11d1-f79f-00c04fc2dcd2;;ED)" \
- "(OA;;CR;1131f6ac-9c07-11d1-f79f-00c04fc2dcd2;;ED)" \
- "(OA;;CR;1131f6aa-9c07-11d1-f79f-00c04fc2dcd2;;BA)" \
- "(OA;;CR;1131f6ab-9c07-11d1-f79f-00c04fc2dcd2;;BA)" \
- "(OA;;CR;1131f6ac-9c07-11d1-f79f-00c04fc2dcd2;;BA)" \
- "(A;;RPLCLORC;;;AU)(A;CI;RPWPCRCCDCLCLORCWOWDSDDTSW;;;EA)" \
- "(A;;RPWPCRCCDCLCLORCWOWDSDDTSW;;;SY)(A;CIIO;RPWPCRCCLCLORCWOWDSDSW;;;DA)" \
- "(OA;;CR;1131f6ad-9c07-11d1-f79f-00c04fc2dcd2;;ED)" \
- "(OA;;CR;89e95b76-444d-4c62-991a-0facbeda640c;;ED)" \
- "(OA;;CR;1131f6ad-9c07-11d1-f79f-00c04fc2dcd2;;BA)" \
- "(OA;;CR;89e95b76-444d-4c62-991a-0facbeda640c;;BA)" \
- "(OA;;CR;1131f6aa-9c07-11d1-f79f-00c04fc2dcd2;;ER)" \
- "S:(AU;SA;WPWOWD;;;WD)(AU;SA;CR;;;BA)(AU;SA;CR;;;DU)" \
- "(OU;SA;CR;45ec5156-db7e-47bb-b53f-dbeb2d03c40f;;WD)"
- return sddl2binary(sddl, domain_sid, name_map)
-
-def get_config_partitions_descriptor(domain_sid, name_map={}):
- sddl = "D:" \
- "(A;;LCLORC;;;AU)" \
- "(OA;;RP;e48d0154-bcf8-11d1-8702-00c04fb96050;;AU)" \
- "(OA;;RP;d31a8757-2447-4545-8081-3bb610cacbf2;;AU)" \
- "(OA;;RP;66171887-8f3c-11d0-afda-00c04fd930c9;;AU)" \
- "(OA;;RP;032160bf-9824-11d1-aec0-0000f80367c1;;AU)" \
- "(OA;;RP;789ee1eb-8c8e-4e4c-8cec-79b31b7617b5;;AU)" \
- "(OA;;RP;5706aeaf-b940-4fb2-bcfc-5268683ad9fe;;AU)" \
- "(A;;RPWPCRCCLCLORCWOWDSW;;;EA)" \
- "(A;;RPWPCRCCDCLCLORCWOWDSDDTSW;;;SY)" \
- "(A;;CC;;;ED)" \
- "(OA;CIIO;WP;3df793df-9858-4417-a701-735a1ecebf74;bf967a8d-0de6-11d0-a285-00aa003049e2;BA)" \
- "S:" \
- "(AU;CISA;WPCRCCDCWOWDSDDT;;;WD)"
- return sddl2binary(sddl, domain_sid, name_map)
-
-def get_config_sites_descriptor(domain_sid, name_map={}):
- sddl = "D:" \
- "(A;;RPLCLORC;;;AU)" \
- "(OA;CIIO;SW;d31a8757-2447-4545-8081-3bb610cacbf2;f0f8ffab-1191-11d0-a060-00aa006c33ed;ER)" \
- "(A;;RPWPCRCCLCLORCWOWDSW;;;EA)" \
- "(A;;RPWPCRCCDCLCLORCWOWDSDDTSW;;;SY)" \
- "S:" \
- "(AU;CISA;CCDCSDDT;;;WD)" \
- "(OU;CIIOSA;CR;;f0f8ffab-1191-11d0-a060-00aa006c33ed;WD)" \
- "(OU;CIIOSA;WP;f30e3bbe-9ff0-11d1-b603-0000f80367c1;bf967ab3-0de6-11d0-a285-00aa003049e2;WD)" \
- "(OU;CIIOSA;WP;f30e3bbf-9ff0-11d1-b603-0000f80367c1;bf967ab3-0de6-11d0-a285-00aa003049e2;WD)" \
- "(OU;CIIOSA;WP;3e10944c-c354-11d0-aff8-0000f80367c1;b7b13124-b82e-11d0-afee-0000f80367c1;WD)"
- return sddl2binary(sddl, domain_sid, name_map)
-
-def get_config_ntds_quotas_descriptor(domain_sid, name_map={}):
- sddl = "D:" \
- "(A;;RPWPCRCCDCLCLORCWOWDSDDTSW;;;EA)" \
- "(A;;RPLCLORC;;;BA)" \
- "(OA;;CR;4ecc03fe-ffc0-4947-b630-eb672a8a9dbc;;WD)"
- return sddl2binary(sddl, domain_sid, name_map)
-
-def get_config_delete_protected1_descriptor(domain_sid, name_map={}):
- sddl = "D:AI" \
- "(A;;RPLCLORC;;;AU)" \
- "(A;;RPWPCRCCLCLORCWOWDSW;;;EA)" \
- "(A;;RPWPCRCCDCLCLORCWOWDSDDTSW;;;SY)"
- return sddl2binary(sddl, domain_sid, name_map)
-
-def get_config_delete_protected1wd_descriptor(domain_sid, name_map={}):
- sddl = "D:AI" \
- "(A;;RPLCLORC;;;WD)" \
- "(A;;RPWPCRCCLCLORCWOWDSW;;;EA)" \
- "(A;;RPWPCRCCDCLCLORCWOWDSDDTSW;;;SY)"
- return sddl2binary(sddl, domain_sid, name_map)
-
-def get_config_delete_protected2_descriptor(domain_sid, name_map={}):
- sddl = "D:AI" \
- "(A;;RPLCLORC;;;AU)" \
- "(A;;RPWPCRCCDCLCLORCWOWDSW;;;EA)" \
- "(A;;RPWPCRCCDCLCLORCWOWDSDDTSW;;;SY)"
- return sddl2binary(sddl, domain_sid, name_map)
-
-def get_domain_descriptor(domain_sid, name_map={}):
- sddl= "O:BAG:BAD:AI(OA;CIIO;RP;4c164200-20c0-11d0-a768-00aa006e0529;4828cc14-1437-45bc-9b07-ad6f015e5f28;RU)" \
- "(OA;CIIO;RP;4c164200-20c0-11d0-a768-00aa006e0529;bf967aba-0de6-11d0-a285-00aa003049e2;RU)" \
- "(OA;CIIO;RP;5f202010-79a5-11d0-9020-00c04fc2d4cf;4828cc14-1437-45bc-9b07-ad6f015e5f28;RU)" \
- "(OA;CIIO;RP;5f202010-79a5-11d0-9020-00c04fc2d4cf;bf967aba-0de6-11d0-a285-00aa003049e2;RU)" \
- "(OA;CIIO;RP;bc0ac240-79a9-11d0-9020-00c04fc2d4cf;4828cc14-1437-45bc-9b07-ad6f015e5f28;RU)" \
- "(OA;CIIO;RP;bc0ac240-79a9-11d0-9020-00c04fc2d4cf;bf967aba-0de6-11d0-a285-00aa003049e2;RU)" \
- "(OA;CIIO;RP;59ba2f42-79a2-11d0-9020-00c04fc2d3cf;4828cc14-1437-45bc-9b07-ad6f015e5f28;RU)" \
- "(OA;CIIO;RP;59ba2f42-79a2-11d0-9020-00c04fc2d3cf;bf967aba-0de6-11d0-a285-00aa003049e2;RU)" \
- "(OA;CIIO;RP;037088f8-0ae1-11d2-b422-00a0c968f939;4828cc14-1437-45bc-9b07-ad6f015e5f28;RU)" \
- "(OA;CIIO;RP;037088f8-0ae1-11d2-b422-00a0c968f939;bf967aba-0de6-11d0-a285-00aa003049e2;RU)" \
- "(OA;;CR;1131f6aa-9c07-11d1-f79f-00c04fc2dcd2;;ER)" \
- "(OA;;CR;1131f6ad-9c07-11d1-f79f-00c04fc2dcd2;;DD)" \
- "(OA;CIIO;RP;b7c69e6d-2cc7-11d2-854e-00a0c983f608;bf967a86-0de6-11d0-a285-00aa003049e2;ED)" \
- "(OA;CIIO;RP;b7c69e6d-2cc7-11d2-854e-00a0c983f608;bf967a9c-0de6-11d0-a285-00aa003049e2;ED)" \
- "(OA;CIIO;RP;b7c69e6d-2cc7-11d2-854e-00a0c983f608;bf967aba-0de6-11d0-a285-00aa003049e2;ED)" \
- "(OA;;CR;89e95b76-444d-4c62-991a-0facbeda640c;;BA)" \
- "(OA;;CR;1131f6aa-9c07-11d1-f79f-00c04fc2dcd2;;BA)" \
- "(OA;;CR;1131f6ab-9c07-11d1-f79f-00c04fc2dcd2;;BA)" \
- "(OA;;CR;1131f6ac-9c07-11d1-f79f-00c04fc2dcd2;;BA)" \
- "(OA;;CR;1131f6ad-9c07-11d1-f79f-00c04fc2dcd2;;BA)" \
- "(OA;;CR;1131f6ae-9c07-11d1-f79f-00c04fc2dcd2;;BA)" \
- "(OA;;CR;e2a36dc9-ae17-47c3-b58b-be34c55ba633;;IF)" \
- "(OA;;RP;c7407360-20bf-11d0-a768-00aa006e0529;;RU)" \
- "(OA;;RP;b8119fd0-04f6-4762-ab7a-4986c76b3f9a;;RU)" \
- "(OA;CIIO;RPLCLORC;;4828cc14-1437-45bc-9b07-ad6f015e5f28;RU)" \
- "(OA;CIIO;RPLCLORC;;bf967a9c-0de6-11d0-a285-00aa003049e2;RU)" \
- "(OA;CIIO;RPLCLORC;;bf967aba-0de6-11d0-a285-00aa003049e2;RU)" \
- "(OA;;CR;05c74c5e-4deb-43b4-bd9f-86664c2a7fd5;;AU)" \
- "(OA;;CR;89e95b76-444d-4c62-991a-0facbeda640c;;ED)" \
- "(OA;;CR;ccc2dc7d-a6ad-4a7a-8846-c04e3cc53501;;AU)" \
- "(OA;;CR;280f369c-67c7-438e-ae98-1d46f3c6f541;;AU)" \
- "(OA;;CR;1131f6aa-9c07-11d1-f79f-00c04fc2dcd2;;ED)" \
- "(OA;;CR;1131f6ab-9c07-11d1-f79f-00c04fc2dcd2;;ED)" \
- "(OA;;CR;1131f6ac-9c07-11d1-f79f-00c04fc2dcd2;;ED)" \
- "(OA;;CR;1131f6ae-9c07-11d1-f79f-00c04fc2dcd2;;ED)" \
- "(OA;;RP;b8119fd0-04f6-4762-ab7a-4986c76b3f9a;;AU)" \
- "(OA;CIIO;RPWPCR;91e647de-d96f-4b70-9557-d63ff4f3ccd8;;PS)" \
- "(A;;RPWPCRCCLCLORCWOWDSW;;;DA)" \
- "(A;CI;RPWPCRCCDCLCLORCWOWDSDDTSW;;;EA)" \
- "(A;;RPRC;;;RU)" \
- "(A;CI;LC;;;RU)" \
- "(A;CI;RPWPCRCCLCLORCWOWDSDSW;;;BA)" \
- "(A;;RP;;;WD)" \
- "(A;;RPLCLORC;;;ED)" \
- "(A;;RPLCLORC;;;AU)" \
- "(A;;RPWPCRCCDCLCLORCWOWDSDDTSW;;;SY)" \
- "S:AI(OU;CISA;WP;f30e3bbe-9ff0-11d1-b603-0000f80367c1;bf967aa5-0de6-11d0-a285-00aa003049e2;WD)" \
- "(OU;CISA;WP;f30e3bbf-9ff0-11d1-b603-0000f80367c1;bf967aa5-0de6-11d0-a285-00aa003049e2;WD)" \
- "(AU;SA;CR;;;DU)(AU;SA;CR;;;BA)(AU;SA;WPWOWD;;;WD)"
- return sddl2binary(sddl, domain_sid, name_map)
-
-def get_domain_infrastructure_descriptor(domain_sid, name_map={}):
- sddl = "D:" \
- "(A;;RPLCLORC;;;AU)" \
- "(A;;RPWPCRCCLCLORCWOWDSW;;;DA)" \
- "(A;;RPWPCRCCDCLCLORCWOWDSDDTSW;;;SY)" \
- "S:" \
- "(AU;SA;WPCR;;;WD)"
- return sddl2binary(sddl, domain_sid, name_map)
-
-def get_domain_builtin_descriptor(domain_sid, name_map={}):
- sddl = "D:" \
- "(OA;CIIO;RP;4c164200-20c0-11d0-a768-00aa006e0529;4828cc14-1437-45bc-9b07-ad6f015e5f28;RU)" \
- "(OA;CIIO;RP;4c164200-20c0-11d0-a768-00aa006e0529;bf967aba-0de6-11d0-a285-00aa003049e2;RU)" \
- "(OA;CIIO;RP;5f202010-79a5-11d0-9020-00c04fc2d4cf;4828cc14-1437-45bc-9b07-ad6f015e5f28;RU)" \
- "(OA;CIIO;RP;5f202010-79a5-11d0-9020-00c04fc2d4cf;bf967aba-0de6-11d0-a285-00aa003049e2;RU)" \
- "(OA;CIIO;RP;bc0ac240-79a9-11d0-9020-00c04fc2d4cf;4828cc14-1437-45bc-9b07-ad6f015e5f28;RU)" \
- "(OA;CIIO;RP;bc0ac240-79a9-11d0-9020-00c04fc2d4cf;bf967aba-0de6-11d0-a285-00aa003049e2;RU)" \
- "(OA;CIIO;RP;59ba2f42-79a2-11d0-9020-00c04fc2d3cf;4828cc14-1437-45bc-9b07-ad6f015e5f28;RU)" \
- "(OA;CIIO;RP;59ba2f42-79a2-11d0-9020-00c04fc2d3cf;bf967aba-0de6-11d0-a285-00aa003049e2;RU)" \
- "(OA;CIIO;RP;037088f8-0ae1-11d2-b422-00a0c968f939;4828cc14-1437-45bc-9b07-ad6f015e5f28;RU)" \
- "(OA;CIIO;RP;037088f8-0ae1-11d2-b422-00a0c968f939;bf967aba-0de6-11d0-a285-00aa003049e2;RU)" \
- "(OA;;CR;1131f6aa-9c07-11d1-f79f-00c04fc2dcd2;;ER)" \
- "(OA;;CR;1131f6ad-9c07-11d1-f79f-00c04fc2dcd2;;DD)" \
- "(OA;CIIO;RP;b7c69e6d-2cc7-11d2-854e-00a0c983f608;bf967a86-0de6-11d0-a285-00aa003049e2;ED)" \
- "(OA;CIIO;RP;b7c69e6d-2cc7-11d2-854e-00a0c983f608;bf967a9c-0de6-11d0-a285-00aa003049e2;ED)" \
- "(OA;CIIO;RP;b7c69e6d-2cc7-11d2-854e-00a0c983f608;bf967aba-0de6-11d0-a285-00aa003049e2;ED)" \
- "(OA;;CR;89e95b76-444d-4c62-991a-0facbeda640c;;BA)" \
- "(OA;;CR;1131f6aa-9c07-11d1-f79f-00c04fc2dcd2;;BA)" \
- "(OA;;CR;1131f6ab-9c07-11d1-f79f-00c04fc2dcd2;;BA)" \
- "(OA;;CR;1131f6ac-9c07-11d1-f79f-00c04fc2dcd2;;BA)" \
- "(OA;;CR;1131f6ad-9c07-11d1-f79f-00c04fc2dcd2;;BA)" \
- "(OA;;CR;1131f6ae-9c07-11d1-f79f-00c04fc2dcd2;;BA)" \
- "(OA;;CR;e2a36dc9-ae17-47c3-b58b-be34c55ba633;;IF)" \
- "(OA;;RP;c7407360-20bf-11d0-a768-00aa006e0529;;RU)" \
- "(OA;;RP;b8119fd0-04f6-4762-ab7a-4986c76b3f9a;;RU)" \
- "(OA;CIIO;RPLCLORC;;4828cc14-1437-45bc-9b07-ad6f015e5f28;RU)" \
- "(OA;CIIO;RPLCLORC;;bf967a9c-0de6-11d0-a285-00aa003049e2;RU)" \
- "(OA;CIIO;RPLCLORC;;bf967aba-0de6-11d0-a285-00aa003049e2;RU)" \
- "(OA;;CR;05c74c5e-4deb-43b4-bd9f-86664c2a7fd5;;AU)" \
- "(OA;;CR;89e95b76-444d-4c62-991a-0facbeda640c;;ED)" \
- "(OA;;CR;ccc2dc7d-a6ad-4a7a-8846-c04e3cc53501;;AU)" \
- "(OA;;CR;280f369c-67c7-438e-ae98-1d46f3c6f541;;AU)" \
- "(OA;;CR;1131f6aa-9c07-11d1-f79f-00c04fc2dcd2;;ED)" \
- "(OA;;CR;1131f6ab-9c07-11d1-f79f-00c04fc2dcd2;;ED)" \
- "(OA;;CR;1131f6ac-9c07-11d1-f79f-00c04fc2dcd2;;ED)" \
- "(OA;;CR;1131f6ae-9c07-11d1-f79f-00c04fc2dcd2;;ED)" \
- "(OA;;RP;b8119fd0-04f6-4762-ab7a-4986c76b3f9a;;AU)" \
- "(OA;CIIO;RPWPCR;91e647de-d96f-4b70-9557-d63ff4f3ccd8;;PS)" \
- "(A;;RPWPCRCCLCLORCWOWDSW;;;DA)" \
- "(A;CI;RPWPCRCCDCLCLORCWOWDSDDTSW;;;EA)" \
- "(A;;RPRC;;;RU)" \
- "(A;CI;LC;;;RU)" \
- "(A;CI;RPWPCRCCLCLORCWOWDSDSW;;;BA)" \
- "(A;;RP;;;WD)" \
- "(A;;RPLCLORC;;;ED)" \
- "(A;;RPLCLORC;;;AU)" \
- "(A;;RPWPCRCCDCLCLORCWOWDSDDTSW;;;SY)" \
- "S:" \
- "(OU;CISA;WP;f30e3bbe-9ff0-11d1-b603-0000f80367c1;bf967aa5-0de6-11d0-a285-00aa003049e2;WD)" \
- "(OU;CISA;WP;f30e3bbf-9ff0-11d1-b603-0000f80367c1;bf967aa5-0de6-11d0-a285-00aa003049e2;WD)" \
- "(AU;SA;CR;;;DU)" \
- "(AU;SA;CR;;;BA)" \
- "(AU;SA;WPWOWD;;;WD)"
- return sddl2binary(sddl, domain_sid, name_map)
-
-def get_domain_computers_descriptor(domain_sid, name_map={}):
- sddl = "D:" \
- "(A;;RPWPCRCCDCLCLORCWOWDSDDTSW;;;SY)" \
- "(A;;RPWPCRCCDCLCLORCWOWDSW;;;DA)" \
- "(OA;;CCDC;bf967a86-0de6-11d0-a285-00aa003049e2;;AO)" \
- "(OA;;CCDC;bf967aba-0de6-11d0-a285-00aa003049e2;;AO)" \
- "(OA;;CCDC;bf967a9c-0de6-11d0-a285-00aa003049e2;;AO)" \
- "(OA;;CCDC;bf967aa8-0de6-11d0-a285-00aa003049e2;;PO)" \
- "(A;;RPLCLORC;;;AU)" \
- "(OA;;CCDC;4828cc14-1437-45bc-9b07-ad6f015e5f28;;AO)" \
- "S:"
- return sddl2binary(sddl, domain_sid, name_map)
-
-def get_domain_users_descriptor(domain_sid, name_map={}):
- sddl = "D:" \
- "(A;;RPWPCRCCDCLCLORCWOWDSDDTSW;;;SY)" \
- "(A;;RPWPCRCCDCLCLORCWOWDSW;;;DA)" \
- "(OA;;CCDC;bf967aba-0de6-11d0-a285-00aa003049e2;;AO)" \
- "(OA;;CCDC;bf967a9c-0de6-11d0-a285-00aa003049e2;;AO)" \
- "(OA;;CCDC;bf967aa8-0de6-11d0-a285-00aa003049e2;;PO)" \
- "(A;;RPLCLORC;;;AU)" \
- "(OA;;CCDC;4828cc14-1437-45bc-9b07-ad6f015e5f28;;AO)" \
- "S:"
- return sddl2binary(sddl, domain_sid, name_map)
-
-def get_domain_controllers_descriptor(domain_sid, name_map={}):
- sddl = "D:" \
- "(A;;RPLCLORC;;;AU)" \
- "(A;;RPWPCRCCLCLORCWOWDSW;;;DA)" \
- "(A;;RPWPCRCCDCLCLORCWOWDSDDTSW;;;SY)" \
- "(A;;RPLCLORC;;;ED)" \
- "S:" \
- "(AU;SA;CCDCWOWDSDDT;;;WD)" \
- "(AU;CISA;WP;;;WD)"
- return sddl2binary(sddl, domain_sid, name_map)
-
-def get_domain_delete_protected1_descriptor(domain_sid, name_map={}):
- sddl = "D:AI" \
- "(A;;RPLCLORC;;;AU)" \
- "(A;;RPWPCRCCLCLORCWOWDSW;;;DA)" \
- "(A;;RPWPCRCCDCLCLORCWOWDSDDTSW;;;SY)"
- return sddl2binary(sddl, domain_sid, name_map)
-
-def get_domain_delete_protected2_descriptor(domain_sid, name_map={}):
- sddl = "D:AI" \
- "(A;;RPLCLORC;;;AU)" \
- "(A;;RPWPCRCCDCLCLORCWOWDSW;;;DA)" \
- "(A;;RPWPCRCCDCLCLORCWOWDSDDTSW;;;SY)"
- return sddl2binary(sddl, domain_sid, name_map)
-
-def get_dns_partition_descriptor(domain_sid, name_map={}):
- sddl = "O:SYG:BAD:AI" \
- "(OA;CIIO;RP;4c164200-20c0-11d0-a768-00aa006e0529;4828cc14-1437-45bc-9b07-ad6f015e5f28;RU)" \
- "(OA;CIIO;RP;4c164200-20c0-11d0-a768-00aa006e0529;bf967aba-0de6-11d0-a285-00aa003049e2;RU)" \
- "(OA;CIIO;RP;5f202010-79a5-11d0-9020-00c04fc2d4cf;4828cc14-1437-45bc-9b07-ad6f015e5f28;RU)" \
- "(OA;CIIO;RP;5f202010-79a5-11d0-9020-00c04fc2d4cf;bf967aba-0de6-11d0-a285-00aa003049e2;RU)" \
- "(OA;CIIO;RP;bc0ac240-79a9-11d0-9020-00c04fc2d4cf;4828cc14-1437-45bc-9b07-ad6f015e5f28;RU)" \
- "(OA;CIIO;RP;bc0ac240-79a9-11d0-9020-00c04fc2d4cf;bf967aba-0de6-11d0-a285-00aa003049e2;RU)" \
- "(OA;CIIO;RP;59ba2f42-79a2-11d0-9020-00c04fc2d3cf;4828cc14-1437-45bc-9b07-ad6f015e5f28;RU)" \
- "(OA;CIIO;RP;59ba2f42-79a2-11d0-9020-00c04fc2d3cf;bf967aba-0de6-11d0-a285-00aa003049e2;RU)" \
- "(OA;CIIO;RP;037088f8-0ae1-11d2-b422-00a0c968f939;4828cc14-1437-45bc-9b07-ad6f015e5f28;RU)" \
- "(OA;CIIO;RP;037088f8-0ae1-11d2-b422-00a0c968f939;bf967aba-0de6-11d0-a285-00aa003049e2;RU)" \
- "(OA;;CR;1131f6aa-9c07-11d1-f79f-00c04fc2dcd2;;ER)" \
- "(OA;CIIO;RP;b7c69e6d-2cc7-11d2-854e-00a0c983f608;bf967a86-0de6-11d0-a285-00aa003049e2;ED)" \
- "(OA;CIIO;RP;b7c69e6d-2cc7-11d2-854e-00a0c983f608;bf967a9c-0de6-11d0-a285-00aa003049e2;ED)" \
- "(OA;CIIO;RP;b7c69e6d-2cc7-11d2-854e-00a0c983f608;bf967aba-0de6-11d0-a285-00aa003049e2;ED)" \
- "(OA;;CR;89e95b76-444d-4c62-991a-0facbeda640c;;BA)" \
- "(OA;;CR;1131f6aa-9c07-11d1-f79f-00c04fc2dcd2;;BA)" \
- "(OA;;CR;1131f6ab-9c07-11d1-f79f-00c04fc2dcd2;;BA)" \
- "(OA;;CR;1131f6ac-9c07-11d1-f79f-00c04fc2dcd2;;BA)" \
- "(OA;;CR;1131f6ad-9c07-11d1-f79f-00c04fc2dcd2;;BA)" \
- "(OA;;CR;1131f6ae-9c07-11d1-f79f-00c04fc2dcd2;;BA)" \
- "(OA;;CR;e2a36dc9-ae17-47c3-b58b-be34c55ba633;;IF)" \
- "(OA;;RP;c7407360-20bf-11d0-a768-00aa006e0529;;RU)" \
- "(OA;;RP;b8119fd0-04f6-4762-ab7a-4986c76b3f9a;;RU)" \
- "(OA;CIIO;RPLCLORC;;4828cc14-1437-45bc-9b07-ad6f015e5f28;RU)" \
- "(OA;CIIO;RPLCLORC;;bf967a9c-0de6-11d0-a285-00aa003049e2;RU)" \
- "(OA;CIIO;RPLCLORC;;bf967aba-0de6-11d0-a285-00aa003049e2;RU)" \
- "(OA;;CR;05c74c5e-4deb-43b4-bd9f-86664c2a7fd5;;AU)" \
- "(OA;;CR;89e95b76-444d-4c62-991a-0facbeda640c;;ED)" \
- "(OA;;CR;ccc2dc7d-a6ad-4a7a-8846-c04e3cc53501;;AU)" \
- "(OA;;CR;280f369c-67c7-438e-ae98-1d46f3c6f541;;AU)" \
- "(OA;;CR;1131f6aa-9c07-11d1-f79f-00c04fc2dcd2;;ED)" \
- "(OA;;CR;1131f6ab-9c07-11d1-f79f-00c04fc2dcd2;;ED)" \
- "(OA;;CR;1131f6ac-9c07-11d1-f79f-00c04fc2dcd2;;ED)" \
- "(OA;;CR;1131f6ad-9c07-11d1-f79f-00c04fc2dcd2;;ED)" \
- "(OA;;CR;1131f6ae-9c07-11d1-f79f-00c04fc2dcd2;;ED)" \
- "(OA;;RP;b8119fd0-04f6-4762-ab7a-4986c76b3f9a;;AU)" \
- "(OA;CIIO;RPWPCR;91e647de-d96f-4b70-9557-d63ff4f3ccd8;;PS)" \
- "(A;;RPWPCRCCLCLORCWOWDSW;;;DA)" \
- "(A;CI;RPWPCRCCDCLCLORCWOWDSDDTSW;;;EA)" \
- "(A;;RPRC;;;RU)" \
- "(A;CI;LC;;;RU)" \
- "(A;CI;RPWPCRCCLCLORCWOWDSDSW;;;BA)" \
- "(A;;RP;;;WD)" \
- "(A;;RPLCLORC;;;ED)" \
- "(A;;RPLCLORC;;;AU)" \
- "(A;;RPWPCRCCDCLCLORCWOWDSDDTSW;;;SY)" \
- "S:AI" \
- "(OU;CISA;WP;f30e3bbe-9ff0-11d1-b603-0000f80367c1;bf967aa5-0de6-11d0-a285-00aa003049e2;WD)" \
- "(OU;CISA;WP;f30e3bbf-9ff0-11d1-b603-0000f80367c1;bf967aa5-0de6-11d0-a285-00aa003049e2;WD)" \
- "(AU;SA;CR;;;DU)(AU;SA;CR;;;BA)(AU;SA;WPWOWD;;;WD)"
- return sddl2binary(sddl, domain_sid, name_map)
-
-def get_dns_forest_microsoft_dns_descriptor(domain_sid, name_map={}):
- sddl = "O:SYG:SYD:AI" \
- "(A;;RPWPCRCCDCLCLORCWOWDSDDTSW;;;SY)" \
- "(A;CI;RPWPCRCCDCLCRCWOWDSDDTSW;;;ED)"
- return sddl2binary(sddl, domain_sid, name_map)
-
-def get_dns_domain_microsoft_dns_descriptor(domain_sid, name_map={}):
- sddl = "O:SYG:SYD:AI" \
- "(A;;RPWPCRCCDCLCLORCWOWDSDDTSW;;;DA)" \
- "(A;CI;RPWPCRCCDCLCRCWOWDSDDTSW;;;DnsAdmins)" \
- "(A;;RPWPCRCCDCLCLORCWOWDSDDTSW;;;SY)" \
- "(A;CI;RPWPCRCCDCLCRCWOWDSDDTSW;;;ED)"
- return sddl2binary(sddl, domain_sid, name_map)
diff --git a/source4/scripting/python/samba/provision/sambadns.py b/source4/scripting/python/samba/provision/sambadns.py
deleted file mode 100644
index 4522683fe8..0000000000
--- a/source4/scripting/python/samba/provision/sambadns.py
+++ /dev/null
@@ -1,1135 +0,0 @@
-# Unix SMB/CIFS implementation.
-# backend code for provisioning DNS for a Samba4 server
-#
-# Copyright (C) Kai Blin <kai@samba.org> 2011
-# Copyright (C) Amitay Isaacs <amitay@gmail.com> 2011
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
-#
-
-"""DNS-related provisioning"""
-
-import os
-import uuid
-import shutil
-import time
-import ldb
-from base64 import b64encode
-import samba
-from samba.tdb_util import tdb_copy
-from samba.ndr import ndr_pack, ndr_unpack
-from samba import setup_file
-from samba.dcerpc import dnsp, misc, security
-from samba.dsdb import (
- DS_DOMAIN_FUNCTION_2000,
- DS_DOMAIN_FUNCTION_2003,
- DS_DOMAIN_FUNCTION_2008_R2
- )
-from samba.provision.descriptor import (
- get_domain_descriptor,
- get_domain_delete_protected1_descriptor,
- get_domain_delete_protected2_descriptor,
- get_dns_partition_descriptor,
- get_dns_forest_microsoft_dns_descriptor,
- get_dns_domain_microsoft_dns_descriptor
- )
-from samba.provision.common import (
- setup_path,
- setup_add_ldif,
- setup_modify_ldif,
- setup_ldb
- )
-
-
-def get_domainguid(samdb, domaindn):
- res = samdb.search(base=domaindn, scope=ldb.SCOPE_BASE, attrs=["objectGUID"])
- domainguid = str(ndr_unpack(misc.GUID, res[0]["objectGUID"][0]))
- return domainguid
-
-
-def get_dnsadmins_sid(samdb, domaindn):
- res = samdb.search(base="CN=DnsAdmins,CN=Users,%s" % domaindn, scope=ldb.SCOPE_BASE,
- attrs=["objectSid"])
- dnsadmins_sid = ndr_unpack(security.dom_sid, res[0]["objectSid"][0])
- return dnsadmins_sid
-
-
-class ARecord(dnsp.DnssrvRpcRecord):
-
- def __init__(self, ip_addr, serial=1, ttl=900, rank=dnsp.DNS_RANK_ZONE):
- super(ARecord, self).__init__()
- self.wType = dnsp.DNS_TYPE_A
- self.rank = rank
- self.dwSerial = serial
- self.dwTtlSeconds = ttl
- self.data = ip_addr
-
-
-class AAAARecord(dnsp.DnssrvRpcRecord):
-
- def __init__(self, ip6_addr, serial=1, ttl=900, rank=dnsp.DNS_RANK_ZONE):
- super(AAAARecord, self).__init__()
- self.wType = dnsp.DNS_TYPE_AAAA
- self.rank = rank
- self.dwSerial = serial
- self.dwTtlSeconds = ttl
- self.data = ip6_addr
-
-
-class CNameRecord(dnsp.DnssrvRpcRecord):
-
- def __init__(self, cname, serial=1, ttl=900, rank=dnsp.DNS_RANK_ZONE):
- super(CNameRecord, self).__init__()
- self.wType = dnsp.DNS_TYPE_CNAME
- self.rank = rank
- self.dwSerial = serial
- self.dwTtlSeconds = ttl
- self.data = cname
-
-
-class NSRecord(dnsp.DnssrvRpcRecord):
-
- def __init__(self, dns_server, serial=1, ttl=900, rank=dnsp.DNS_RANK_ZONE):
- super(NSRecord, self).__init__()
- self.wType = dnsp.DNS_TYPE_NS
- self.rank = rank
- self.dwSerial = serial
- self.dwTtlSeconds = ttl
- self.data = dns_server
-
-
-class SOARecord(dnsp.DnssrvRpcRecord):
-
- def __init__(self, mname, rname, serial=1, refresh=900, retry=600,
- expire=86400, minimum=3600, ttl=3600, rank=dnsp.DNS_RANK_ZONE):
- super(SOARecord, self).__init__()
- self.wType = dnsp.DNS_TYPE_SOA
- self.rank = rank
- self.dwSerial = serial
- self.dwTtlSeconds = ttl
- soa = dnsp.soa()
- soa.serial = serial
- soa.refresh = refresh
- soa.retry = retry
- soa.expire = expire
- soa.mname = mname
- soa.rname = rname
- self.data = soa
-
-
-class SRVRecord(dnsp.DnssrvRpcRecord):
-
- def __init__(self, target, port, priority=0, weight=100, serial=1, ttl=900,
- rank=dnsp.DNS_RANK_ZONE):
- super(SRVRecord, self).__init__()
- self.wType = dnsp.DNS_TYPE_SRV
- self.rank = rank
- self.dwSerial = serial
- self.dwTtlSeconds = ttl
- srv = dnsp.srv()
- srv.nameTarget = target
- srv.wPort = port
- srv.wPriority = priority
- srv.wWeight = weight
- self.data = srv
-
-
-class TXTRecord(dnsp.DnssrvRpcRecord):
-
- def __init__(self, slist, serial=1, ttl=900, rank=dnsp.DNS_RANK_ZONE):
- super(TXTRecord, self).__init__()
- self.wType = dnsp.DNS_TYPE_TXT
- self.rank = rank
- self.dwSerial = serial
- self.dwTtlSeconds = ttl
- stringlist = dnsp.string_list()
- stringlist.count = len(slist)
- stringlist.str = slist
- self.data = stringlist
-
-
-class TypeProperty(dnsp.DnsProperty):
-
- def __init__(self, zone_type=dnsp.DNS_ZONE_TYPE_PRIMARY):
- super(TypeProperty, self).__init__()
- self.wDataLength = 1
- self.version = 1
- self.id = dnsp.DSPROPERTY_ZONE_TYPE
- self.data = zone_type
-
-
-class AllowUpdateProperty(dnsp.DnsProperty):
-
- def __init__(self, allow_update=dnsp.DNS_ZONE_UPDATE_SECURE):
- super(AllowUpdateProperty, self).__init__()
- self.wDataLength = 1
- self.version = 1
- self.id = dnsp.DSPROPERTY_ZONE_ALLOW_UPDATE
- self.data = allow_update
-
-
-class SecureTimeProperty(dnsp.DnsProperty):
-
- def __init__(self, secure_time=0):
- super(SecureTimeProperty, self).__init__()
- self.wDataLength = 1
- self.version = 1
- self.id = dnsp.DSPROPERTY_ZONE_SECURE_TIME
- self.data = secure_time
-
-
-class NorefreshIntervalProperty(dnsp.DnsProperty):
-
- def __init__(self, norefresh_interval=0):
- super(NorefreshIntervalProperty, self).__init__()
- self.wDataLength = 1
- self.version = 1
- self.id = dnsp.DSPROPERTY_ZONE_NOREFRESH_INTERVAL
- self.data = norefresh_interval
-
-
-class RefreshIntervalProperty(dnsp.DnsProperty):
-
- def __init__(self, refresh_interval=0):
- super(RefreshIntervalProperty, self).__init__()
- self.wDataLength = 1
- self.version = 1
- self.id = dnsp.DSPROPERTY_ZONE_REFRESH_INTERVAL
- self.data = refresh_interval
-
-
-class AgingStateProperty(dnsp.DnsProperty):
-
- def __init__(self, aging_enabled=0):
- super(AgingStateProperty, self).__init__()
- self.wDataLength = 1
- self.version = 1
- self.id = dnsp.DSPROPERTY_ZONE_AGING_STATE
- self.data = aging_enabled
-
-
-class AgingEnabledTimeProperty(dnsp.DnsProperty):
-
- def __init__(self, next_cycle_hours=0):
- super(AgingEnabledTimeProperty, self).__init__()
- self.wDataLength = 1
- self.version = 1;
- self.id = dnsp.DSPROPERTY_ZONE_AGING_ENABLED_TIME
- self.data = next_cycle_hours
-
-
-def setup_dns_partitions(samdb, domainsid, domaindn, forestdn, configdn,
- serverdn):
- domainzone_dn = "DC=DomainDnsZones,%s" % domaindn
- forestzone_dn = "DC=ForestDnsZones,%s" % forestdn
- descriptor = get_dns_partition_descriptor(domainsid)
- setup_add_ldif(samdb, setup_path("provision_dnszones_partitions.ldif"), {
- "DOMAINZONE_DN": domainzone_dn,
- "FORESTZONE_DN": forestzone_dn,
- "SECDESC" : b64encode(descriptor)
- })
-
- domainzone_guid = get_domainguid(samdb, domainzone_dn)
- forestzone_guid = get_domainguid(samdb, forestzone_dn)
-
- domainzone_guid = str(uuid.uuid4())
- forestzone_guid = str(uuid.uuid4())
-
- domainzone_dns = ldb.Dn(samdb, domainzone_dn).canonical_ex_str().strip()
- forestzone_dns = ldb.Dn(samdb, forestzone_dn).canonical_ex_str().strip()
-
- protected1_desc = get_domain_delete_protected1_descriptor(domainsid)
- protected2_desc = get_domain_delete_protected2_descriptor(domainsid)
- setup_add_ldif(samdb, setup_path("provision_dnszones_add.ldif"), {
- "DOMAINZONE_DN": domainzone_dn,
- "FORESTZONE_DN": forestzone_dn,
- "DOMAINZONE_GUID": domainzone_guid,
- "FORESTZONE_GUID": forestzone_guid,
- "DOMAINZONE_DNS": domainzone_dns,
- "FORESTZONE_DNS": forestzone_dns,
- "CONFIGDN": configdn,
- "SERVERDN": serverdn,
- "LOSTANDFOUND_DESCRIPTOR": b64encode(protected2_desc),
- "INFRASTRUCTURE_DESCRIPTOR": b64encode(protected1_desc),
- })
-
- setup_modify_ldif(samdb, setup_path("provision_dnszones_modify.ldif"), {
- "CONFIGDN": configdn,
- "SERVERDN": serverdn,
- "DOMAINZONE_DN": domainzone_dn,
- "FORESTZONE_DN": forestzone_dn,
- })
-
-
-def add_dns_accounts(samdb, domaindn):
- setup_add_ldif(samdb, setup_path("provision_dns_accounts_add.ldif"), {
- "DOMAINDN": domaindn,
- })
-
-
-def add_dns_container(samdb, domaindn, prefix, domain_sid, dnsadmins_sid, forest=False):
- name_map = {'DnsAdmins': str(dnsadmins_sid)}
- if forest is True:
- sd_val = get_dns_forest_microsoft_dns_descriptor(domain_sid,
- name_map=name_map)
- else:
- sd_val = get_dns_domain_microsoft_dns_descriptor(domain_sid,
- name_map=name_map)
- # CN=MicrosoftDNS,<PREFIX>,<DOMAINDN>
- msg = ldb.Message(ldb.Dn(samdb, "CN=MicrosoftDNS,%s,%s" % (prefix, domaindn)))
- msg["objectClass"] = ["top", "container"]
- msg["nTSecurityDescriptor"] = ldb.MessageElement(sd_val, ldb.FLAG_MOD_ADD,
- "nTSecurityDescriptor")
- samdb.add(msg)
-
-
-def add_rootservers(samdb, domaindn, prefix):
- rootservers = {}
- rootservers["a.root-servers.net"] = "198.41.0.4"
- rootservers["b.root-servers.net"] = "192.228.79.201"
- rootservers["c.root-servers.net"] = "192.33.4.12"
- rootservers["d.root-servers.net"] = "128.8.10.90"
- rootservers["e.root-servers.net"] = "192.203.230.10"
- rootservers["f.root-servers.net"] = "192.5.5.241"
- rootservers["g.root-servers.net"] = "192.112.36.4"
- rootservers["h.root-servers.net"] = "128.63.2.53"
- rootservers["i.root-servers.net"] = "192.36.148.17"
- rootservers["j.root-servers.net"] = "192.58.128.30"
- rootservers["k.root-servers.net"] = "193.0.14.129"
- rootservers["l.root-servers.net"] = "199.7.83.42"
- rootservers["m.root-servers.net"] = "202.12.27.33"
-
- rootservers_v6 = {}
- rootservers_v6["a.root-servers.net"] = "2001:503:ba3e::2:30"
- rootservers_v6["f.root-servers.net"] = "2001:500:2f::f"
- rootservers_v6["h.root-servers.net"] = "2001:500:1::803f:235"
- rootservers_v6["j.root-servers.net"] = "2001:503:c27::2:30"
- rootservers_v6["k.root-servers.net"] = "2001:7fd::1"
- rootservers_v6["m.root-servers.net"] = "2001:dc3::35"
-
- container_dn = "DC=RootDNSServers,CN=MicrosoftDNS,%s,%s" % (prefix, domaindn)
-
- # Add DC=RootDNSServers,CN=MicrosoftDNS,<PREFIX>,<DOMAINDN>
- msg = ldb.Message(ldb.Dn(samdb, container_dn))
- props = []
- props.append(ndr_pack(TypeProperty(zone_type=dnsp.DNS_ZONE_TYPE_CACHE)))
- props.append(ndr_pack(AllowUpdateProperty(allow_update=dnsp.DNS_ZONE_UPDATE_OFF)))
- props.append(ndr_pack(SecureTimeProperty()))
- props.append(ndr_pack(NorefreshIntervalProperty()))
- props.append(ndr_pack(RefreshIntervalProperty()))
- props.append(ndr_pack(AgingStateProperty()))
- props.append(ndr_pack(AgingEnabledTimeProperty()))
- msg["objectClass"] = ["top", "dnsZone"]
- msg["cn"] = ldb.MessageElement("Zone", ldb.FLAG_MOD_ADD, "cn")
- msg["dNSProperty"] = ldb.MessageElement(props, ldb.FLAG_MOD_ADD, "dNSProperty")
- samdb.add(msg)
-
- # Add DC=@,DC=RootDNSServers,CN=MicrosoftDNS,<PREFIX>,<DOMAINDN>
- record = []
- for rserver in rootservers:
- record.append(ndr_pack(NSRecord(rserver, serial=0, ttl=0, rank=dnsp.DNS_RANK_ROOT_HINT)))
-
- msg = ldb.Message(ldb.Dn(samdb, "DC=@,%s" % container_dn))
- msg["objectClass"] = ["top", "dnsNode"]
- msg["dnsRecord"] = ldb.MessageElement(record, ldb.FLAG_MOD_ADD, "dnsRecord")
- samdb.add(msg)
-
- # Add DC=<rootserver>,DC=RootDNSServers,CN=MicrosoftDNS,<PREFIX>,<DOMAINDN>
- for rserver in rootservers:
- record = [ndr_pack(ARecord(rootservers[rserver], serial=0, ttl=0, rank=dnsp.DNS_RANK_ROOT_HINT))]
- # Add AAAA record as well (How does W2K* add IPv6 records?)
- #if rserver in rootservers_v6:
- # record.append(ndr_pack(AAAARecord(rootservers_v6[rserver], serial=0, ttl=0)))
- msg = ldb.Message(ldb.Dn(samdb, "DC=%s,%s" % (rserver, container_dn)))
- msg["objectClass"] = ["top", "dnsNode"]
- msg["dnsRecord"] = ldb.MessageElement(record, ldb.FLAG_MOD_ADD, "dnsRecord")
- samdb.add(msg)
-
-def add_at_record(samdb, container_dn, prefix, hostname, dnsdomain, hostip, hostip6):
-
- fqdn_hostname = "%s.%s" % (hostname, dnsdomain)
-
- at_records = []
-
- # SOA record
- at_soa_record = SOARecord(fqdn_hostname, "hostmaster.%s" % dnsdomain)
- at_records.append(ndr_pack(at_soa_record))
-
- # NS record
- at_ns_record = NSRecord(fqdn_hostname)
- at_records.append(ndr_pack(at_ns_record))
-
- if hostip is not None:
- # A record
- at_a_record = ARecord(hostip)
- at_records.append(ndr_pack(at_a_record))
-
- if hostip6 is not None:
- # AAAA record
- at_aaaa_record = AAAARecord(hostip6)
- at_records.append(ndr_pack(at_aaaa_record))
-
- msg = ldb.Message(ldb.Dn(samdb, "DC=@,%s" % container_dn))
- msg["objectClass"] = ["top", "dnsNode"]
- msg["dnsRecord"] = ldb.MessageElement(at_records, ldb.FLAG_MOD_ADD, "dnsRecord")
- samdb.add(msg)
-
-
-def add_srv_record(samdb, container_dn, prefix, host, port):
- srv_record = SRVRecord(host, port)
- msg = ldb.Message(ldb.Dn(samdb, "%s,%s" % (prefix, container_dn)))
- msg["objectClass"] = ["top", "dnsNode"]
- msg["dnsRecord"] = ldb.MessageElement(ndr_pack(srv_record), ldb.FLAG_MOD_ADD, "dnsRecord")
- samdb.add(msg)
-
-
-def add_ns_record(samdb, container_dn, prefix, host):
- ns_record = NSRecord(host)
- msg = ldb.Message(ldb.Dn(samdb, "%s,%s" % (prefix, container_dn)))
- msg["objectClass"] = ["top", "dnsNode"]
- msg["dnsRecord"] = ldb.MessageElement(ndr_pack(ns_record), ldb.FLAG_MOD_ADD, "dnsRecord")
- samdb.add(msg)
-
-
-def add_ns_glue_record(samdb, container_dn, prefix, host):
- ns_record = NSRecord(host, rank=dnsp.DNS_RANK_NS_GLUE)
- msg = ldb.Message(ldb.Dn(samdb, "%s,%s" % (prefix, container_dn)))
- msg["objectClass"] = ["top", "dnsNode"]
- msg["dnsRecord"] = ldb.MessageElement(ndr_pack(ns_record), ldb.FLAG_MOD_ADD, "dnsRecord")
- samdb.add(msg)
-
-
-def add_cname_record(samdb, container_dn, prefix, host):
- cname_record = CNameRecord(host)
- msg = ldb.Message(ldb.Dn(samdb, "%s,%s" % (prefix, container_dn)))
- msg["objectClass"] = ["top", "dnsNode"]
- msg["dnsRecord"] = ldb.MessageElement(ndr_pack(cname_record), ldb.FLAG_MOD_ADD, "dnsRecord")
- samdb.add(msg)
-
-
-def add_host_record(samdb, container_dn, prefix, hostip, hostip6):
- host_records = []
- if hostip:
- a_record = ARecord(hostip)
- host_records.append(ndr_pack(a_record))
- if hostip6:
- aaaa_record = AAAARecord(hostip6)
- host_records.append(ndr_pack(aaaa_record))
- if host_records:
- msg = ldb.Message(ldb.Dn(samdb, "%s,%s" % (prefix, container_dn)))
- msg["objectClass"] = ["top", "dnsNode"]
- msg["dnsRecord"] = ldb.MessageElement(host_records, ldb.FLAG_MOD_ADD, "dnsRecord")
- samdb.add(msg)
-
-
-def add_domain_record(samdb, domaindn, prefix, dnsdomain, domainsid, dnsadmins_sid):
- # DC=<DNSDOMAIN>,CN=MicrosoftDNS,<PREFIX>,<DOMAINDN>
- sddl = "O:SYG:BAD:AI" \
- "(A;;RPWPCRCCDCLCLORCWOWDSDDTSW;;;DA)" \
- "(A;;CC;;;AU)" \
- "(A;;RPLCLORC;;;WD)" \
- "(A;;RPWPCRCCDCLCLORCWOWDSDDTSW;;;SY)" \
- "(A;CI;RPWPCRCCDCLCRCWOWDSDDTSW;;;ED)" \
- "(A;CIID;RPWPCRCCDCLCRCWOWDSDDTSW;;;%s)" \
- "(A;CIID;RPWPCRCCDCLCRCWOWDSDDTSW;;;ED)" \
- "(OA;CIID;RPWPCR;91e647de-d96f-4b70-9557-d63ff4f3ccd8;;PS)" \
- "(A;CIID;RPWPCRCCDCLCLORCWOWDSDDTSW;;;EA)" \
- "(A;CIID;LC;;;RU)" \
- "(A;CIID;RPWPCRCCLCLORCWOWDSDSW;;;BA)" \
- "S:AI" % dnsadmins_sid
- sec = security.descriptor.from_sddl(sddl, domainsid)
- props = []
- props.append(ndr_pack(TypeProperty()))
- props.append(ndr_pack(AllowUpdateProperty()))
- props.append(ndr_pack(SecureTimeProperty()))
- props.append(ndr_pack(NorefreshIntervalProperty(norefresh_interval=168)))
- props.append(ndr_pack(RefreshIntervalProperty(refresh_interval=168)))
- props.append(ndr_pack(AgingStateProperty()))
- props.append(ndr_pack(AgingEnabledTimeProperty()))
- msg = ldb.Message(ldb.Dn(samdb, "DC=%s,CN=MicrosoftDNS,%s,%s" % (dnsdomain, prefix, domaindn)))
- msg["objectClass"] = ["top", "dnsZone"]
- msg["ntSecurityDescriptor"] = ldb.MessageElement(ndr_pack(sec), ldb.FLAG_MOD_ADD,
- "nTSecurityDescriptor")
- msg["dNSProperty"] = ldb.MessageElement(props, ldb.FLAG_MOD_ADD, "dNSProperty")
- samdb.add(msg)
-
-
-def add_msdcs_record(samdb, forestdn, prefix, dnsforest):
- # DC=_msdcs.<DNSFOREST>,CN=MicrosoftDNS,<PREFIX>,<FORESTDN>
- msg = ldb.Message(ldb.Dn(samdb, "DC=_msdcs.%s,CN=MicrosoftDNS,%s,%s" %
- (dnsforest, prefix, forestdn)))
- msg["objectClass"] = ["top", "dnsZone"]
- samdb.add(msg)
-
-
-def add_dc_domain_records(samdb, domaindn, prefix, site, dnsdomain, hostname,
- hostip, hostip6):
-
- fqdn_hostname = "%s.%s" % (hostname, dnsdomain)
-
- # Set up domain container - DC=<DNSDOMAIN>,CN=MicrosoftDNS,<PREFIX>,<DOMAINDN>
- domain_container_dn = ldb.Dn(samdb, "DC=%s,CN=MicrosoftDNS,%s,%s" %
- (dnsdomain, prefix, domaindn))
-
- # DC=@ record
- add_at_record(samdb, domain_container_dn, "DC=@", hostname, dnsdomain,
- hostip, hostip6)
-
- # DC=<HOSTNAME> record
- add_host_record(samdb, domain_container_dn, "DC=%s" % hostname, hostip,
- hostip6)
-
- # DC=_kerberos._tcp record
- add_srv_record(samdb, domain_container_dn, "DC=_kerberos._tcp",
- fqdn_hostname, 88)
-
- # DC=_kerberos._tcp.<SITENAME>._sites record
- add_srv_record(samdb, domain_container_dn, "DC=_kerberos._tcp.%s._sites" %
- site, fqdn_hostname, 88)
-
- # DC=_kerberos._udp record
- add_srv_record(samdb, domain_container_dn, "DC=_kerberos._udp",
- fqdn_hostname, 88)
-
- # DC=_kpasswd._tcp record
- add_srv_record(samdb, domain_container_dn, "DC=_kpasswd._tcp",
- fqdn_hostname, 464)
-
- # DC=_kpasswd._udp record
- add_srv_record(samdb, domain_container_dn, "DC=_kpasswd._udp",
- fqdn_hostname, 464)
-
- # DC=_ldap._tcp record
- add_srv_record(samdb, domain_container_dn, "DC=_ldap._tcp", fqdn_hostname,
- 389)
-
- # DC=_ldap._tcp.<SITENAME>._sites record
- add_srv_record(samdb, domain_container_dn, "DC=_ldap._tcp.%s._sites" %
- site, fqdn_hostname, 389)
-
- # FIXME: The number of SRV records depend on the various roles this DC has.
- # _gc and _msdcs records are added if the we are the forest dc and not subdomain dc
- #
- # Assumption: current DC is GC and add all the entries
-
- # DC=_gc._tcp record
- add_srv_record(samdb, domain_container_dn, "DC=_gc._tcp", fqdn_hostname,
- 3268)
-
- # DC=_gc._tcp.<SITENAME>,_sites record
- add_srv_record(samdb, domain_container_dn, "DC=_gc._tcp.%s._sites" % site,
- fqdn_hostname, 3268)
-
- # DC=_msdcs record
- add_ns_glue_record(samdb, domain_container_dn, "DC=_msdcs", fqdn_hostname)
-
- # FIXME: Following entries are added only if DomainDnsZones and ForestDnsZones partitions
- # are created
- #
- # Assumption: Additional entries won't hurt on os_level = 2000
-
- # DC=_ldap._tcp.<SITENAME>._sites.DomainDnsZones
- add_srv_record(samdb, domain_container_dn,
- "DC=_ldap._tcp.%s._sites.DomainDnsZones" % site, fqdn_hostname,
- 389)
-
- # DC=_ldap._tcp.<SITENAME>._sites.ForestDnsZones
- add_srv_record(samdb, domain_container_dn,
- "DC=_ldap._tcp.%s._sites.ForestDnsZones" % site, fqdn_hostname,
- 389)
-
- # DC=_ldap._tcp.DomainDnsZones
- add_srv_record(samdb, domain_container_dn, "DC=_ldap._tcp.DomainDnsZones",
- fqdn_hostname, 389)
-
- # DC=_ldap._tcp.ForestDnsZones
- add_srv_record(samdb, domain_container_dn, "DC=_ldap._tcp.ForestDnsZones",
- fqdn_hostname, 389)
-
- # DC=DomainDnsZones
- add_host_record(samdb, domain_container_dn, "DC=DomainDnsZones", hostip,
- hostip6)
-
- # DC=ForestDnsZones
- add_host_record(samdb, domain_container_dn, "DC=ForestDnsZones", hostip,
- hostip6)
-
-
-def add_dc_msdcs_records(samdb, forestdn, prefix, site, dnsforest, hostname,
- hostip, hostip6, domainguid, ntdsguid):
-
- fqdn_hostname = "%s.%s" % (hostname, dnsforest)
-
- # Set up forest container - DC=<DNSDOMAIN>,CN=MicrosoftDNS,<PREFIX>,<DOMAINDN>
- forest_container_dn = ldb.Dn(samdb, "DC=_msdcs.%s,CN=MicrosoftDNS,%s,%s" %
- (dnsforest, prefix, forestdn))
-
- # DC=@ record
- add_at_record(samdb, forest_container_dn, "DC=@", hostname, dnsforest,
- None, None)
-
- # DC=_kerberos._tcp.dc record
- add_srv_record(samdb, forest_container_dn, "DC=_kerberos._tcp.dc",
- fqdn_hostname, 88)
-
- # DC=_kerberos._tcp.<SITENAME>._sites.dc record
- add_srv_record(samdb, forest_container_dn,
- "DC=_kerberos._tcp.%s._sites.dc" % site, fqdn_hostname, 88)
-
- # DC=_ldap._tcp.dc record
- add_srv_record(samdb, forest_container_dn, "DC=_ldap._tcp.dc",
- fqdn_hostname, 389)
-
- # DC=_ldap._tcp.<SITENAME>._sites.dc record
- add_srv_record(samdb, forest_container_dn, "DC=_ldap._tcp.%s._sites.dc" %
- site, fqdn_hostname, 389)
-
- # DC=_ldap._tcp.<SITENAME>._sites.gc record
- add_srv_record(samdb, forest_container_dn, "DC=_ldap._tcp.%s._sites.gc" %
- site, fqdn_hostname, 3268)
-
- # DC=_ldap._tcp.gc record
- add_srv_record(samdb, forest_container_dn, "DC=_ldap._tcp.gc",
- fqdn_hostname, 3268)
-
- # DC=_ldap._tcp.pdc record
- add_srv_record(samdb, forest_container_dn, "DC=_ldap._tcp.pdc",
- fqdn_hostname, 389)
-
- # DC=gc record
- add_host_record(samdb, forest_container_dn, "DC=gc", hostip, hostip6)
-
- # DC=_ldap._tcp.<DOMAINGUID>.domains record
- add_srv_record(samdb, forest_container_dn,
- "DC=_ldap._tcp.%s.domains" % domainguid, fqdn_hostname, 389)
-
- # DC=<NTDSGUID>
- add_cname_record(samdb, forest_container_dn, "DC=%s" % ntdsguid,
- fqdn_hostname)
-
-
-def secretsdb_setup_dns(secretsdb, names, private_dir, realm,
- dnsdomain, dns_keytab_path, dnspass):
- """Add DNS specific bits to a secrets database.
-
- :param secretsdb: Ldb Handle to the secrets database
- :param names: Names shortcut
- :param machinepass: Machine password
- """
- try:
- os.unlink(os.path.join(private_dir, dns_keytab_path))
- except OSError:
- pass
-
- setup_ldb(secretsdb, setup_path("secrets_dns.ldif"), {
- "REALM": realm,
- "DNSDOMAIN": dnsdomain,
- "DNS_KEYTAB": dns_keytab_path,
- "DNSPASS_B64": b64encode(dnspass),
- "HOSTNAME": names.hostname,
- "DNSNAME" : '%s.%s' % (
- names.netbiosname.lower(), names.dnsdomain.lower())
- })
-
-
-def create_dns_dir(logger, paths):
- """Write out a DNS zone file, from the info in the current database.
-
- :param logger: Logger object
- :param paths: paths object
- """
- dns_dir = os.path.dirname(paths.dns)
-
- try:
- shutil.rmtree(dns_dir, True)
- except OSError:
- pass
-
- os.mkdir(dns_dir, 0770)
-
- if paths.bind_gid is not None:
- try:
- os.chown(dns_dir, -1, paths.bind_gid)
- # chmod needed to cope with umask
- os.chmod(dns_dir, 0770)
- except OSError:
- if not os.environ.has_key('SAMBA_SELFTEST'):
- logger.error("Failed to chown %s to bind gid %u" % (
- dns_dir, paths.bind_gid))
-
-
-def create_zone_file(lp, logger, paths, targetdir, dnsdomain,
- hostip, hostip6, hostname, realm, domainguid,
- ntdsguid, site):
- """Write out a DNS zone file, from the info in the current database.
-
- :param paths: paths object
- :param dnsdomain: DNS Domain name
- :param domaindn: DN of the Domain
- :param hostip: Local IPv4 IP
- :param hostip6: Local IPv6 IP
- :param hostname: Local hostname
- :param realm: Realm name
- :param domainguid: GUID of the domain.
- :param ntdsguid: GUID of the hosts nTDSDSA record.
- """
- assert isinstance(domainguid, str)
-
- if hostip6 is not None:
- hostip6_base_line = " IN AAAA " + hostip6
- hostip6_host_line = hostname + " IN AAAA " + hostip6
- gc_msdcs_ip6_line = "gc._msdcs IN AAAA " + hostip6
- else:
- hostip6_base_line = ""
- hostip6_host_line = ""
- gc_msdcs_ip6_line = ""
-
- if hostip is not None:
- hostip_base_line = " IN A " + hostip
- hostip_host_line = hostname + " IN A " + hostip
- gc_msdcs_ip_line = "gc._msdcs IN A " + hostip
- else:
- hostip_base_line = ""
- hostip_host_line = ""
- gc_msdcs_ip_line = ""
-
- # we need to freeze the zone while we update the contents
- if targetdir is None:
- rndc = ' '.join(lp.get("rndc command"))
- os.system(rndc + " freeze " + lp.get("realm"))
-
- setup_file(setup_path("provision.zone"), paths.dns, {
- "HOSTNAME": hostname,
- "DNSDOMAIN": dnsdomain,
- "REALM": realm,
- "HOSTIP_BASE_LINE": hostip_base_line,
- "HOSTIP_HOST_LINE": hostip_host_line,
- "DOMAINGUID": domainguid,
- "DATESTRING": time.strftime("%Y%m%d%H"),
- "DEFAULTSITE": site,
- "NTDSGUID": ntdsguid,
- "HOSTIP6_BASE_LINE": hostip6_base_line,
- "HOSTIP6_HOST_LINE": hostip6_host_line,
- "GC_MSDCS_IP_LINE": gc_msdcs_ip_line,
- "GC_MSDCS_IP6_LINE": gc_msdcs_ip6_line,
- })
-
- if paths.bind_gid is not None:
- try:
- os.chown(paths.dns, -1, paths.bind_gid)
- # chmod needed to cope with umask
- os.chmod(paths.dns, 0664)
- except OSError:
- if not os.environ.has_key('SAMBA_SELFTEST'):
- logger.error("Failed to chown %s to bind gid %u" % (
- paths.dns, paths.bind_gid))
-
- if targetdir is None:
- os.system(rndc + " unfreeze " + lp.get("realm"))
-
-
-def create_samdb_copy(samdb, logger, paths, names, domainsid, domainguid):
- """Create a copy of samdb and give write permissions to named for dns partitions
- """
- private_dir = paths.private_dir
- samldb_dir = os.path.join(private_dir, "sam.ldb.d")
- dns_dir = os.path.dirname(paths.dns)
- dns_samldb_dir = os.path.join(dns_dir, "sam.ldb.d")
-
- # Find the partitions and corresponding filenames
- partfile = {}
- res = samdb.search(base="@PARTITION", scope=ldb.SCOPE_BASE, attrs=["partition"])
- for tmp in res[0]["partition"]:
- (nc, fname) = tmp.split(':')
- partfile[nc.upper()] = fname
-
- # Create empty domain partition
- domaindn = names.domaindn.upper()
- domainpart_file = os.path.join(dns_dir, partfile[domaindn])
- try:
- os.mkdir(dns_samldb_dir)
- file(domainpart_file, 'w').close()
-
- # Fill the basedn and @OPTION records in domain partition
- dom_ldb = samba.Ldb(domainpart_file)
- domainguid_line = "objectGUID: %s\n-" % domainguid
- descr = b64encode(get_domain_descriptor(domainsid))
- setup_add_ldif(dom_ldb, setup_path("provision_basedn.ldif"), {
- "DOMAINDN" : names.domaindn,
- "DOMAINGUID" : domainguid_line,
- "DOMAINSID" : str(domainsid),
- "DESCRIPTOR" : descr})
- setup_add_ldif(dom_ldb,
- setup_path("provision_basedn_options.ldif"), None)
- except:
- logger.error(
- "Failed to setup database for BIND, AD based DNS cannot be used")
- raise
- del partfile[domaindn]
-
- # Link dns partitions and metadata
- domainzonedn = "DC=DOMAINDNSZONES,%s" % names.domaindn.upper()
- forestzonedn = "DC=FORESTDNSZONES,%s" % names.rootdn.upper()
- domainzone_file = partfile[domainzonedn]
- forestzone_file = partfile[forestzonedn]
- metadata_file = "metadata.tdb"
- try:
- os.link(os.path.join(samldb_dir, metadata_file),
- os.path.join(dns_samldb_dir, metadata_file))
- os.link(os.path.join(private_dir, domainzone_file),
- os.path.join(dns_dir, domainzone_file))
- os.link(os.path.join(private_dir, forestzone_file),
- os.path.join(dns_dir, forestzone_file))
- except OSError:
- logger.error(
- "Failed to setup database for BIND, AD based DNS cannot be used")
- raise
- del partfile[domainzonedn]
- del partfile[forestzonedn]
-
- # Copy root, config, schema partitions (and any other if any)
- # Since samdb is open in the current process, copy them in a child process
- try:
- tdb_copy(os.path.join(private_dir, "sam.ldb"),
- os.path.join(dns_dir, "sam.ldb"))
- for nc in partfile:
- pfile = partfile[nc]
- tdb_copy(os.path.join(private_dir, pfile),
- os.path.join(dns_dir, pfile))
- except:
- logger.error(
- "Failed to setup database for BIND, AD based DNS cannot be used")
- raise
-
- # Give bind read/write permissions dns partitions
- if paths.bind_gid is not None:
- try:
- os.chown(samldb_dir, -1, paths.bind_gid)
- os.chmod(samldb_dir, 0750)
-
- for dirname, dirs, files in os.walk(dns_dir):
- for d in dirs:
- dpath = os.path.join(dirname, d)
- os.chown(dpath, -1, paths.bind_gid)
- os.chmod(dpath, 0770)
- for f in files:
- if f.endswith('.ldb') or f.endswith('.tdb'):
- fpath = os.path.join(dirname, f)
- os.chown(fpath, -1, paths.bind_gid)
- os.chmod(fpath, 0660)
- except OSError:
- if not os.environ.has_key('SAMBA_SELFTEST'):
- logger.error(
- "Failed to set permissions to sam.ldb* files, fix manually")
- else:
- if not os.environ.has_key('SAMBA_SELFTEST'):
- logger.warning("""Unable to find group id for BIND,
- set permissions to sam.ldb* files manually""")
-
-
-def create_dns_update_list(lp, logger, paths):
- """Write out a dns_update_list file"""
- # note that we use no variable substitution on this file
- # the substitution is done at runtime by samba_dnsupdate, samba_spnupdate
- setup_file(setup_path("dns_update_list"), paths.dns_update_list, None)
- setup_file(setup_path("spn_update_list"), paths.spn_update_list, None)
-
-
-def create_named_conf(paths, realm, dnsdomain, dns_backend):
- """Write out a file containing zone statements suitable for inclusion in a
- named.conf file (including GSS-TSIG configuration).
-
- :param paths: all paths
- :param realm: Realm name
- :param dnsdomain: DNS Domain name
- :param dns_backend: DNS backend type
- :param keytab_name: File name of DNS keytab file
- """
-
- if dns_backend == "BIND9_FLATFILE":
- setup_file(setup_path("named.conf"), paths.namedconf, {
- "DNSDOMAIN": dnsdomain,
- "REALM": realm,
- "ZONE_FILE": paths.dns,
- "REALM_WC": "*." + ".".join(realm.split(".")[1:]),
- "NAMED_CONF": paths.namedconf,
- "NAMED_CONF_UPDATE": paths.namedconf_update
- })
-
- setup_file(setup_path("named.conf.update"), paths.namedconf_update)
-
- elif dns_backend == "BIND9_DLZ":
- setup_file(setup_path("named.conf.dlz"), paths.namedconf, {
- "NAMED_CONF": paths.namedconf,
- "MODULESDIR" : samba.param.modules_dir(),
- })
-
-
-def create_named_txt(path, realm, dnsdomain, dnsname, 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 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,
- "DNSNAME" : dnsname,
- "REALM": realm,
- "DNS_KEYTAB": keytab_name,
- "DNS_KEYTAB_ABS": os.path.join(private_dir, keytab_name),
- "PRIVATE_DIR": private_dir
- })
-
-
-def is_valid_dns_backend(dns_backend):
- return dns_backend in ("BIND9_FLATFILE", "BIND9_DLZ", "SAMBA_INTERNAL", "NONE")
-
-
-def is_valid_os_level(os_level):
- return DS_DOMAIN_FUNCTION_2000 <= os_level <= DS_DOMAIN_FUNCTION_2008_R2
-
-
-def create_dns_legacy(samdb, domainsid, forestdn, dnsadmins_sid):
- # Set up MicrosoftDNS container
- add_dns_container(samdb, forestdn, "CN=System", domainsid, dnsadmins_sid)
- # Add root servers
- add_rootservers(samdb, forestdn, "CN=System")
-
-
-def fill_dns_data_legacy(samdb, domainsid, forestdn, dnsdomain, site, hostname,
- hostip, hostip6, dnsadmins_sid):
- # Add domain record
- add_domain_record(samdb, forestdn, "CN=System", dnsdomain, domainsid,
- dnsadmins_sid)
-
- # Add DNS records for a DC in domain
- add_dc_domain_records(samdb, forestdn, "CN=System", site, dnsdomain,
- hostname, hostip, hostip6)
-
-
-def create_dns_partitions(samdb, domainsid, names, domaindn, forestdn,
- dnsadmins_sid):
- # Set up additional partitions (DomainDnsZones, ForstDnsZones)
- setup_dns_partitions(samdb, domainsid, domaindn, forestdn,
- names.configdn, names.serverdn)
-
- # Set up MicrosoftDNS containers
- add_dns_container(samdb, domaindn, "DC=DomainDnsZones", domainsid,
- dnsadmins_sid)
- add_dns_container(samdb, forestdn, "DC=ForestDnsZones", domainsid,
- dnsadmins_sid, forest=True)
-
-
-def fill_dns_data_partitions(samdb, domainsid, site, domaindn, forestdn,
- dnsdomain, dnsforest, hostname, hostip, hostip6,
- domainguid, ntdsguid, dnsadmins_sid, autofill=True):
- """Fill data in various AD partitions
-
- :param samdb: LDB object connected to sam.ldb file
- :param domainsid: Domain SID (as dom_sid object)
- :param site: Site name to create hostnames in
- :param domaindn: DN of the domain
- :param forestdn: DN of the forest
- :param dnsdomain: DNS name of the domain
- :param dnsforest: DNS name of the forest
- :param hostname: Host name of this DC
- :param hostip: IPv4 addresses
- :param hostip6: IPv6 addresses
- :param domainguid: Domain GUID
- :param ntdsguid: NTDS GUID
- :param dnsadmins_sid: SID for DnsAdmins group
- :param autofill: Create DNS records (using fixed template)
- """
-
- ##### Set up DC=DomainDnsZones,<DOMAINDN>
- # Add rootserver records
- add_rootservers(samdb, domaindn, "DC=DomainDnsZones")
-
- # Add domain record
- add_domain_record(samdb, domaindn, "DC=DomainDnsZones", dnsdomain,
- domainsid, dnsadmins_sid)
-
- # Add DNS records for a DC in domain
- if autofill:
- add_dc_domain_records(samdb, domaindn, "DC=DomainDnsZones", site,
- dnsdomain, hostname, hostip, hostip6)
-
- ##### Set up DC=ForestDnsZones,<DOMAINDN>
- # Add _msdcs record
- add_msdcs_record(samdb, forestdn, "DC=ForestDnsZones", dnsforest)
-
- # Add DNS records for a DC in forest
- if autofill:
- add_dc_msdcs_records(samdb, forestdn, "DC=ForestDnsZones", site,
- dnsforest, hostname, hostip, hostip6,
- domainguid, ntdsguid)
-
-
-def setup_ad_dns(samdb, secretsdb, domainsid, names, paths, lp, logger,
- dns_backend, os_level, site, dnspass=None, hostip=None, hostip6=None,
- targetdir=None):
- """Provision DNS information (assuming GC role)
-
- :param samdb: LDB object connected to sam.ldb file
- :param secretsdb: LDB object connected to secrets.ldb file
- :param domainsid: Domain SID (as dom_sid object)
- :param names: Names shortcut
- :param paths: Paths shortcut
- :param lp: Loadparm object
- :param logger: Logger object
- :param dns_backend: Type of DNS backend
- :param os_level: Functional level (treated as os level)
- :param site: Site to create hostnames in
- :param dnspass: Password for bind's DNS account
- :param hostip: IPv4 address
- :param hostip6: IPv6 address
- :param targetdir: Target directory for creating DNS-related files for BIND9
- """
-
- if not is_valid_dns_backend(dns_backend):
- raise Exception("Invalid dns backend: %r" % dns_backend)
-
- if not is_valid_os_level(os_level):
- raise Exception("Invalid os level: %r" % os_level)
-
- if dns_backend == "NONE":
- logger.info("No DNS backend set, not configuring DNS")
- return
-
- # Add dns accounts (DnsAdmins, DnsUpdateProxy) in domain
- logger.info("Adding DNS accounts")
- add_dns_accounts(samdb, names.domaindn)
-
- # If dns_backend is BIND9_FLATFILE
- # Populate only CN=MicrosoftDNS,CN=System,<FORESTDN>
- #
- # If dns_backend is SAMBA_INTERNAL or BIND9_DLZ
- # Populate DNS partitions
-
- # If os_level < 2003 (DS_DOMAIN_FUNCTION_2000)
- # All dns records are in CN=MicrosoftDNS,CN=System,<FORESTDN>
- #
- # If os_level >= 2003 (DS_DOMAIN_FUNCTION_2003, DS_DOMAIN_FUNCTION_2008,
- # DS_DOMAIN_FUNCTION_2008_R2)
- # Root server records are in CN=MicrosoftDNS,CN=System,<FORESTDN>
- # Domain records are in CN=MicrosoftDNS,CN=System,<FORESTDN>
- # Domain records are in CN=MicrosoftDNS,DC=DomainDnsZones,<DOMAINDN>
- # Forest records are in CN=MicrosoftDNS,DC=ForestDnsZones,<FORESTDN>
- domaindn = names.domaindn
- forestdn = samdb.get_root_basedn().get_linearized()
-
- dnsdomain = names.dnsdomain.lower()
- dnsforest = dnsdomain
-
- hostname = names.netbiosname.lower()
-
- dnsadmins_sid = get_dnsadmins_sid(samdb, domaindn)
- domainguid = get_domainguid(samdb, domaindn)
-
- # Create CN=System
- logger.info("Creating CN=MicrosoftDNS,CN=System,%s" % forestdn)
- create_dns_legacy(samdb, domainsid, forestdn, dnsadmins_sid)
-
- if os_level == DS_DOMAIN_FUNCTION_2000:
- # Populating legacy dns
- logger.info("Populating CN=MicrosoftDNS,CN=System,%s" % forestdn)
- fill_dns_data_legacy(samdb, domainsid, forestdn, dnsdomain, site,
- hostname, hostip, hostip6, dnsadmins_sid)
-
- elif dns_backend in ("SAMBA_INTERNAL", "BIND9_DLZ") and \
- os_level >= DS_DOMAIN_FUNCTION_2003:
-
- # Create DNS partitions
- logger.info("Creating DomainDnsZones and ForestDnsZones partitions")
- create_dns_partitions(samdb, domainsid, names, domaindn, forestdn,
- dnsadmins_sid)
-
- # Populating dns partitions
- logger.info("Populating DomainDnsZones and ForestDnsZones partitions")
- fill_dns_data_partitions(samdb, domainsid, site, domaindn, forestdn,
- dnsdomain, dnsforest, hostname, hostip, hostip6,
- domainguid, names.ntdsguid, dnsadmins_sid)
-
- if dns_backend.startswith("BIND9_"):
- setup_bind9_dns(samdb, secretsdb, domainsid, names, paths, lp, logger,
- dns_backend, os_level, site=site, dnspass=dnspass, hostip=hostip,
- hostip6=hostip6, targetdir=targetdir)
-
-
-def setup_bind9_dns(samdb, secretsdb, domainsid, names, paths, lp, logger,
- dns_backend, os_level, site=None, dnspass=None, hostip=None,
- hostip6=None, targetdir=None):
- """Provision DNS information (assuming BIND9 backend in DC role)
-
- :param samdb: LDB object connected to sam.ldb file
- :param secretsdb: LDB object connected to secrets.ldb file
- :param domainsid: Domain SID (as dom_sid object)
- :param names: Names shortcut
- :param paths: Paths shortcut
- :param lp: Loadparm object
- :param logger: Logger object
- :param dns_backend: Type of DNS backend
- :param os_level: Functional level (treated as os level)
- :param site: Site to create hostnames in
- :param dnspass: Password for bind's DNS account
- :param hostip: IPv4 address
- :param hostip6: IPv6 address
- :param targetdir: Target directory for creating DNS-related files for BIND9
- """
-
- if (not is_valid_dns_backend(dns_backend) or
- not dns_backend.startswith("BIND9_")):
- raise Exception("Invalid dns backend: %r" % dns_backend)
-
- if not is_valid_os_level(os_level):
- raise Exception("Invalid os level: %r" % os_level)
-
- domaindn = names.domaindn
-
- domainguid = get_domainguid(samdb, domaindn)
-
- secretsdb_setup_dns(secretsdb, names,
- paths.private_dir, realm=names.realm,
- dnsdomain=names.dnsdomain,
- dns_keytab_path=paths.dns_keytab, dnspass=dnspass)
-
- create_dns_dir(logger, paths)
-
- if dns_backend == "BIND9_FLATFILE":
- create_zone_file(lp, logger, paths, targetdir, site=site,
- dnsdomain=names.dnsdomain, hostip=hostip,
- hostip6=hostip6, hostname=names.hostname,
- realm=names.realm, domainguid=domainguid,
- ntdsguid=names.ntdsguid)
-
- if dns_backend == "BIND9_DLZ" and os_level >= DS_DOMAIN_FUNCTION_2003:
- create_samdb_copy(samdb, logger, paths, names, domainsid, domainguid)
-
- create_named_conf(paths, realm=names.realm,
- dnsdomain=names.dnsdomain, dns_backend=dns_backend)
-
- create_named_txt(paths.namedtxt,
- realm=names.realm, dnsdomain=names.dnsdomain,
- dnsname = "%s.%s" % (names.hostname, names.dnsdomain),
- private_dir=paths.private_dir,
- keytab_name=paths.dns_keytab)
- logger.info("See %s for an example configuration include file for BIND",
- paths.namedconf)
- logger.info("and %s for further documentation required for secure DNS "
- "updates", paths.namedtxt)