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_conf(paths, realm, dnsdomain, dns_backend, logger): """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 :param logger: Logger object """ # TODO: This really should have been done as a top level import. # It is done here to avoid a depencency loop. That is, we move # ProvisioningError to another file, and have all the provision # scripts import it from there. from samba.provision import ProvisioningError 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": bind_info = subprocess.Popen(['named -V'], shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, cwd='.').communicate()[0] bind9_8 = '#' bind9_9 = '#' bind9_10 = '#' bind9_11 = '#' if bind_info.upper().find('BIND 9.8') != -1: bind9_8 = '' elif bind_info.upper().find('BIND 9.9') != -1: bind9_9 = '' elif bind_info.upper().find('BIND 9.10') != -1: bind9_10 = '' elif bind_info.upper().find('BIND 9.11') != -1: bind9_11 = '' elif bind_info.upper().find('BIND 9.7') != -1: raise ProvisioningError("DLZ option incompatible with BIND 9.7.") else: logger.warning("BIND version unknown, please modify %s manually." % paths.namedconf) setup_file(setup_path("named.conf.dlz"), paths.namedconf, { "NAMED_CONF": paths.namedconf, "MODULESDIR" : samba.param.modules_dir(), "BIND9_8" : bind9_8, "BIND9_9" : bind9_9, "BIND9_10" : bind9_10, "BIND9_11" : bind9_11 })
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_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 = "" 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, 0o664) except OSError: if 'SAMBA_SELFTEST' not in os.environ: logger.error("Failed to chown %s to bind gid %u" % ( paths.dns, paths.bind_gid))
def secretsdb_setup_dns(secretsdb, names, private_dir, realm, dnsdomain, dns_keytab_path, dnspass, key_version_number): """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 if key_version_number is None: key_version_number = 1 setup_ldb( secretsdb, setup_path("secrets_dns.ldif"), { "REALM": realm, "DNSDOMAIN": dnsdomain, "DNS_KEYTAB": dns_keytab_path, "DNSPASS_B64": b64encode(dnspass.encode('utf-8')), "KEY_VERSION_NUMBER": str(key_version_number), "HOSTNAME": names.hostname, "DNSNAME": '%s.%s' % (names.netbiosname.lower(), names.dnsdomain.lower()) })
def secretsdb_setup_dns(secretsdb, names, private_dir, binddns_dir, realm, dnsdomain, dns_keytab_path, dnspass, key_version_number): """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)) os.unlink(os.path.join(binddns_dir, dns_keytab_path)) except OSError: pass if key_version_number is None: key_version_number = 1 # This will create the dns.keytab file in the private_dir when it is # commited! setup_ldb(secretsdb, setup_path("secrets_dns.ldif"), { "REALM": realm, "DNSDOMAIN": dnsdomain, "DNS_KEYTAB": dns_keytab_path, "DNSPASS_B64": b64encode(dnspass.encode('utf-8')).decode('utf8'), "KEY_VERSION_NUMBER": str(key_version_number), "HOSTNAME": names.hostname, "DNSNAME" : '%s.%s' % ( names.netbiosname.lower(), names.dnsdomain.lower()) })
def secretsdb_setup_dns(secretsdb, names, private_dir, realm, dnsdomain, dns_keytab_path, dnspass, key_version_number): """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 if key_version_number is None: key_version_number = 1 setup_ldb(secretsdb, setup_path("secrets_dns.ldif"), { "REALM": realm, "DNSDOMAIN": dnsdomain, "DNS_KEYTAB": dns_keytab_path, "DNSPASS_B64": b64encode(dnspass), "KEY_VERSION_NUMBER": str(key_version_number), "HOSTNAME": names.hostname, "DNSNAME" : '{0!s}.{1!s}'.format( names.netbiosname.lower(), names.dnsdomain.lower()) })
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 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 __init__(self, samdb, verbose=False, fix=False, add_update_container=True): """ :param samdb: LDB database :param verbose: Show the ldif changes :param fix: Apply the update if the container is missing :param add_update_container: Add the container at the end of the change :raise ForestUpdateException: """ from samba.ms_forest_updates_markdown import read_ms_markdown self.samdb = samdb self.fix = fix self.verbose = verbose self.add_update_container = add_update_container # TODO In future we should check for inconsistencies when it claims it has been done self.check_update_applied = False self.config_dn = self.samdb.get_config_basedn() self.domain_dn = self.samdb.domain_dn() self.schema_dn = self.samdb.get_schema_basedn() self.sd_utils = sd_utils.SDUtils(samdb) self.domain_sid = security.dom_sid(samdb.get_domain_sid()) self.forestupdate_container = self.samdb.get_config_basedn() if not self.forestupdate_container.add_child( "CN=Operations,CN=ForestUpdates"): raise ForestUpdateException( "Failed to add forest update container child") self.revision_object = self.samdb.get_config_basedn() if not self.revision_object.add_child( "CN=ActiveDirectoryUpdate,CN=ForestUpdates"): raise ForestUpdateException("Failed to add revision object child") # Store the result of parsing the markdown in a dictionary self.stored_ldif = {} read_ms_markdown( setup_path("adprep/WindowsServerDocs/Forest-Wide-Updates.md"), out_dict=self.stored_ldif)
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 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 __init__(self, samdb, verbose=False, fix=False, add_update_container=True): """ :param samdb: LDB database :param verbose: Show the ldif changes :param fix: Apply the update if the container is missing :param add_update_container: Add the container at the end of the change :raise ForestUpdateException: """ from samba.ms_forest_updates_markdown import read_ms_markdown self.samdb = samdb self.fix = fix self.verbose = verbose self.add_update_container = add_update_container # TODO In future we should check for inconsistencies when it claims it has been done self.check_update_applied = False self.config_dn = self.samdb.get_config_basedn() self.domain_dn = self.samdb.domain_dn() self.schema_dn = self.samdb.get_schema_basedn() self.sd_utils = sd_utils.SDUtils(samdb) self.domain_sid = security.dom_sid(samdb.get_domain_sid()) self.forestupdate_container = self.samdb.get_config_basedn() if not self.forestupdate_container.add_child("CN=Operations,CN=ForestUpdates"): raise ForestUpdateException("Failed to add forest update container child") self.revision_object = self.samdb.get_config_basedn() if not self.revision_object.add_child("CN=ActiveDirectoryUpdate,CN=ForestUpdates"): raise ForestUpdateException("Failed to add revision object child") # Store the result of parsing the markdown in a dictionary self.stored_ldif = {} read_ms_markdown(setup_path("adprep/WindowsServerDocs/Forest-Wide-Updates.md"), out_dict=self.stored_ldif)
msg = samdb.search(base=names.domaindn, scope=samba.ldb.SCOPE_DEFAULT, expression='(sAMAccountName=dns-%s)' % (names.hostname), attrs=['clearTextPassword']) if msg: print "removing sAMAccountName=dns-%s" % (names.hostname) dn = msg[0].dn samdb.delete(dn) except Exception: print "exception while removing sAMAccountName=dns-%s" % ( names.hostname) pass setup_add_ldif( secretsdb, setup_path("secrets_dns.ldif"), { "REALM": names.realm, "DNSDOMAIN": names.dnsdomain, "DNS_KEYTAB": dns_keytab_path, "DNSPASS_B64": b64encode(dnspass), "HOSTNAME": names.hostname, "DNSNAME": '%s.%s' % (names.netbiosname.lower(), names.dnsdomain.lower()) }) account_created = False
except Exception: print "Adding dns-%s account" % names.hostname try: msg = samdb.search(base=names.domaindn, scope=samba.ldb.SCOPE_DEFAULT, expression='(sAMAccountName=dns-%s)' % (names.hostname), attrs=['clearTextPassword']) if msg: print "removing sAMAccountName=dns-%s" % (names.hostname) dn = msg[0].dn samdb.delete(dn) except Exception: print "exception while removing sAMAccountName=dns-%s" % (names.hostname) pass setup_add_ldif(secretsdb, setup_path("secrets_dns.ldif"), { "REALM": names.realm, "DNSDOMAIN": names.dnsdomain, "DNS_KEYTAB": dns_keytab_path, "DNSPASS_B64": b64encode(dnspass), "HOSTNAME": names.hostname, "DNSNAME" : '%s.%s' % ( names.netbiosname.lower(), names.dnsdomain.lower()) }) account_created = False count = 0 while not account_created: try: setup_add_ldif(samdb, setup_path("provision_dns_add_samba.ldif"), { "DNSDOMAIN": names.dnsdomain,
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_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_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 add_dns_accounts(samdb, domaindn): setup_add_ldif(samdb, setup_path("provision_dns_accounts_add.ldif"), { "DOMAINDN": domaindn, })
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 # This line is critical to the security of the whole scheme. # We assume there is no secret data in the (to be left out of # date and essentially read-only) config, schema and metadata partitions. # # Only the stub of the domain partition is created above. # # That way, things like the krbtgt key do not leak. 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.get(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)) if forestzone_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] if forestzone_file: 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_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", "backendStore"]) for tmp in res[0]["partition"]: (nc, fname) = tmp.split(':') partfile[nc.upper()] = fname backend_store = get_default_backend_store() if "backendStore" in res[0]: backend_store = res[0]["backendStore"][0] # Create empty domain partition domaindn = names.domaindn.upper() domainpart_file = os.path.join(dns_dir, partfile[domaindn]) try: os.mkdir(dns_samldb_dir) open(domainpart_file, 'w').close() # Fill the basedn and @OPTION records in domain partition dom_url = "%s://%s" % (backend_store, domainpart_file) dom_ldb = samba.Ldb(dom_url) # We need the dummy main-domain DB to have the correct @INDEXLIST index_res = samdb.search(base="@INDEXLIST", scope=ldb.SCOPE_BASE) dom_ldb.add(index_res[0]) domainguid_line = "objectGUID: %s\n-" % domainguid descr = b64encode(get_domain_descriptor(domainsid)).decode('utf8') 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 # This line is critical to the security of the whole scheme. # We assume there is no secret data in the (to be left out of # date and essentially read-only) config, schema and metadata partitions. # # Only the stub of the domain partition is created above. # # That way, things like the krbtgt key do not leak. 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.get(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)) if forestzone_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] if forestzone_file: 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] if backend_store == "mdb": mdb_copy(os.path.join(private_dir, pfile), os.path.join(dns_dir, pfile)) else: 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: 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, 0o770) for f in files: if f.endswith(('.ldb', '.tdb', 'ldb-lock')): fpath = os.path.join(dirname, f) os.chown(fpath, -1, paths.bind_gid) os.chmod(fpath, 0o660) 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""")