From 21424056bb4ad914871b009aee3a7567a3efdec0 Mon Sep 17 00:00:00 2001 From: Amitay Isaacs Date: Mon, 12 Dec 2011 10:53:55 +1100 Subject: s4-provision: Do not guess partition file names, use @PARTITION record This is to avoid duplicating the logic of generating partition file names. (partition file names are encoded partially as per RFC1738). Also, use tdb_copy() instead of filesystem copy function to copy database files, which guarantees correct database copy. Autobuild-User: Amitay Isaacs Autobuild-Date: Tue Dec 13 03:28:03 CET 2011 on sn-devel-104 --- .../scripting/python/samba/provision/sambadns.py | 135 ++++++++++++--------- 1 file changed, 76 insertions(+), 59 deletions(-) (limited to 'source4') diff --git a/source4/scripting/python/samba/provision/sambadns.py b/source4/scripting/python/samba/provision/sambadns.py index 8ccb054785..335ea8d965 100644 --- a/source4/scripting/python/samba/provision/sambadns.py +++ b/source4/scripting/python/samba/provision/sambadns.py @@ -596,66 +596,88 @@ def create_zone_file(lp, logger, paths, targetdir, dnsdomain, if targetdir is None: os.system(rndc + " unfreeze " + lp.get("realm")) +def tdb_copy(logger, file1, file2): + """Copy tdb file using tdbbackup utility and rename it + """ + # Find the location of tdbbackup tool + dirs = ["bin", samba.param.bin_dir()] + for d in dirs: + toolpath = os.path.join(d, "tdbbackup") + if os.path.exists(toolpath): + break + status = os.system("%s -s '.dns' %s" % (toolpath, file1)) + if status == 0: + os.rename("%s.dns" % file1, file2) + else: + raise Exception("Error copying %s" % file1) -def create_samdb_copy(logger, paths, names, domainsid, domainguid): +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") - domainpart_file = "%s.ldb" % names.domaindn.upper() - configpart_file = "%s.ldb" % names.configdn.upper() - schemapart_file = "%s.ldb" % names.schemadn.upper() - domainzone_file = "DC=DOMAINDNSZONES,%s.ldb" % names.domaindn.upper() - forestzone_file = "DC=FORESTDNSZONES,%s.ldb" % names.rootdn.upper() - metadata_file = "metadata.tdb" - # Copy config, schema partitions, create empty domain partition + # 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: - shutil.copyfile(os.path.join(private_dir, "sam.ldb"), - os.path.join(dns_dir, "sam.ldb")) os.mkdir(dns_samldb_dir) - file(os.path.join(dns_samldb_dir, domainpart_file), 'w').close() - shutil.copyfile(os.path.join(samldb_dir, configpart_file), - os.path.join(dns_samldb_dir, configpart_file)) - shutil.copyfile(os.path.join(samldb_dir, schemapart_file), - os.path.join(dns_samldb_dir, schemapart_file)) + 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 metadata and dns partitions + # 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(samldb_dir, domainzone_file), - os.path.join(dns_samldb_dir, domainzone_file)) - os.link(os.path.join(samldb_dir, forestzone_file), - os.path.join(dns_samldb_dir, forestzone_file)) - except OSError, e: - try: - os.symlink(os.path.join(samldb_dir, metadata_file), - os.path.join(dns_samldb_dir, metadata_file)) - os.symlink(os.path.join(samldb_dir, domainzone_file), - os.path.join(dns_samldb_dir, domainzone_file)) - os.symlink(os.path.join(samldb_dir, forestzone_file), - os.path.join(dns_samldb_dir, forestzone_file)) - except OSError, e: - logger.error("Failed to setup database for BIND, AD based DNS cannot be used") - raise - - # Fill the basedn and @OPTION records in domain partition + 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: - ldb = samba.Ldb(os.path.join(dns_samldb_dir, domainpart_file)) - domainguid_line = "objectGUID: %s\n-" % domainguid - descr = b64encode(get_domain_descriptor(domainsid)) - setup_add_ldif(ldb, setup_path("provision_basedn.ldif"), { - "DOMAINDN" : names.domaindn, - "DOMAINGUID" : domainguid_line, - "DOMAINSID" : str(domainsid), - "DESCRIPTOR" : descr}) - setup_add_ldif(ldb, setup_path("provision_basedn_options.ldif"), None) + tdb_copy(logger, + os.path.join(private_dir, "sam.ldb"), + os.path.join(dns_dir, "sam.ldb")) + for nc in partfile: + pfile = partfile[nc] + tdb_copy(logger, + 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 @@ -665,22 +687,17 @@ def create_samdb_copy(logger, paths, names, domainsid, domainguid): try: os.chown(samldb_dir, -1, paths.bind_gid) os.chmod(samldb_dir, 0750) - os.chown(os.path.join(dns_dir, "sam.ldb"), -1, paths.bind_gid) - os.chmod(os.path.join(dns_dir, "sam.ldb"), 0660) - os.chown(dns_samldb_dir, -1, paths.bind_gid) - os.chmod(dns_samldb_dir, 0770) - os.chown(os.path.join(dns_samldb_dir, domainpart_file), -1, paths.bind_gid) - os.chmod(os.path.join(dns_samldb_dir, domainpart_file), 0660) - os.chown(os.path.join(dns_samldb_dir, configpart_file), -1, paths.bind_gid) - os.chmod(os.path.join(dns_samldb_dir, configpart_file), 0660) - os.chown(os.path.join(dns_samldb_dir, schemapart_file), -1, paths.bind_gid) - os.chmod(os.path.join(dns_samldb_dir, schemapart_file), 0660) - os.chown(os.path.join(samldb_dir, metadata_file), -1, paths.bind_gid) - os.chmod(os.path.join(samldb_dir, metadata_file), 0660) - os.chown(os.path.join(samldb_dir, domainzone_file), -1, paths.bind_gid) - os.chmod(os.path.join(samldb_dir, domainzone_file), 0660) - os.chown(os.path.join(samldb_dir, forestzone_file), -1, paths.bind_gid) - os.chmod(os.path.join(samldb_dir, forestzone_file), 0660) + + 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") @@ -894,7 +911,7 @@ def setup_ad_dns(samdb, secretsdb, domainsid, names, paths, lp, logger, dns_back domainguid=domainguid, ntdsguid=names.ntdsguid) if dns_backend == "BIND9_DLZ" and os_level >= DS_DOMAIN_FUNCTION_2003: - create_samdb_copy(logger, paths, names, domainsid, domainguid) + create_samdb_copy(samdb, logger, paths, names, domainsid, domainguid) create_named_conf(paths, realm=names.realm, dnsdomain=names.dnsdomain, dns_backend=dns_backend) -- cgit