Ejemplo n.º 1
0
Archivo: drs.py Proyecto: szaydel/samba
class cmd_drs_clone_dc_database(Command):
    """Replicate an initial clone of domain, but DO NOT JOIN it."""

    synopsis = "%prog <dnsdomain> [options]"

    takes_optiongroups = {
        "sambaopts": options.SambaOptions,
        "versionopts": options.VersionOptions,
        "credopts": options.CredentialsOptions,
    }

    takes_options = [
        Option("--server", help="DC to join", type=str),
        Option("--targetdir", help="where to store provision (required)", type=str),
        Option("-q", "--quiet", help="Be quiet", action="store_true"),
        Option("--include-secrets", help="Also replicate secret values", action="store_true"),
        Option("--backend-store", type="choice", metavar="BACKENDSTORE",
               choices=["tdb", "mdb"],
               help="Specify the database backend to be used "
                    "(default is %s)" % get_default_backend_store()),
        Option("--backend-store-size", type="bytes", metavar="SIZE",
               help="Specify the size of the backend database, currently" +
                    "only supported by lmdb backends (default is 8 Gb).")
    ]

    takes_args = ["domain"]

    def run(self, domain, sambaopts=None, credopts=None,
            versionopts=None, server=None, targetdir=None,
            quiet=False, verbose=False, include_secrets=False,
            backend_store=None, backend_store_size=None):
        lp = sambaopts.get_loadparm()
        creds = credopts.get_credentials(lp)

        logger = self.get_logger(verbose=verbose, quiet=quiet)

        if targetdir is None:
            raise CommandError("--targetdir option must be specified")

        join_clone(logger=logger, server=server, creds=creds, lp=lp,
                   domain=domain, dns_backend='SAMBA_INTERNAL',
                   targetdir=targetdir, include_secrets=include_secrets,
                   backend_store=backend_store,
                   backend_store_size=backend_store_size)
Ejemplo n.º 2
0
class cmd_domain_backup_rename(samba.netcmd.Command):
    '''Copy a running DC's DB to backup file, renaming the domain in the process.

    Where <new-domain> is the new domain's NetBIOS name, and <new-dnsrealm> is
    the new domain's realm in DNS form.

    This is similar to 'samba-tool backup online' in that it clones the DB of a
    running DC. However, this option also renames all the domain entries in the
    DB. Renaming the domain makes it possible to restore and start a new Samba
    DC without it interfering with the existing Samba domain. In other words,
    you could use this option to clone your production samba domain and restore
    it to a separate pre-production environment that won't overlap or interfere
    with the existing production Samba domain.

    Note that:
    - it's recommended to run 'samba-tool dbcheck' before taking a backup-file
      and fix any errors it reports.
    - all the domain's secrets are included in the backup file.
    - although the DB contents can be untarred and examined manually, you need
      to run 'samba-tool domain backup restore' before you can start a Samba DC
      from the backup file.
    - GPO and sysvol information will still refer to the old realm and will
      need to be updated manually.
    - if you specify 'keep-dns-realm', then the DNS records will need updating
      in order to work (they will still refer to the old DC's IP instead of the
      new DC's address).
    - we recommend that you only use this option if you know what you're doing.
    '''

    synopsis = ("%prog <new-domain> <new-dnsrealm> --server=<DC-to-backup> "
                "--targetdir=<output-dir>")
    takes_optiongroups = {
        "sambaopts": options.SambaOptions,
        "credopts": options.CredentialsOptions,
    }

    takes_options = [
        Option("--server", help="The DC to backup", type=str),
        Option("--targetdir", help="Directory to write the backup file",
               type=str),
        Option("--keep-dns-realm", action="store_true", default=False,
               help="Retain the DNS entries for the old realm in the backup"),
        Option("--no-secrets", action="store_true", default=False,
               help="Exclude secret values from the backup created"),
        Option("--backend-store", type="choice", metavar="BACKENDSTORE",
               choices=["tdb", "mdb"],
               help="Specify the database backend to be used "
               "(default is %s)" % get_default_backend_store()),
    ]

    takes_args = ["new_domain_name", "new_dns_realm"]

    def update_dns_root(self, logger, samdb, old_realm, delete_old_dns):
        '''Updates dnsRoot for the partition objects to reflect the rename'''

        # lookup the crossRef objects that hold the old realm's dnsRoot
        partitions_dn = samdb.get_partitions_dn()
        res = samdb.search(base=partitions_dn, scope=ldb.SCOPE_ONELEVEL,
                           attrs=["dnsRoot"],
                           expression='(&(objectClass=crossRef)(dnsRoot=*))')
        new_realm = samdb.domain_dns_name()

        # go through and add the new realm
        for res_msg in res:
            # dnsRoot can be multi-valued, so only look for the old realm
            for dns_root in res_msg["dnsRoot"]:
                dns_root = str(dns_root)
                dn = res_msg.dn
                if old_realm in dns_root:
                    new_dns_root = re.sub('%s$' % old_realm, new_realm,
                                          dns_root)
                    logger.info("Adding %s dnsRoot to %s" % (new_dns_root, dn))

                    m = ldb.Message()
                    m.dn = dn
                    m["dnsRoot"] = ldb.MessageElement(new_dns_root,
                                                      ldb.FLAG_MOD_ADD,
                                                      "dnsRoot")
                    samdb.modify(m)

                    # optionally remove the dnsRoot for the old realm
                    if delete_old_dns:
                        logger.info("Removing %s dnsRoot from %s" % (dns_root,
                                                                     dn))
                        m["dnsRoot"] = ldb.MessageElement(dns_root,
                                                          ldb.FLAG_MOD_DELETE,
                                                          "dnsRoot")
                        samdb.modify(m)

    # Updates the CN=<domain>,CN=Partitions,CN=Configuration,... object to
    # reflect the domain rename
    def rename_domain_partition(self, logger, samdb, new_netbios_name):
        '''Renames the domain parition object and updates its nETBIOSName'''

        # lookup the crossRef object that holds the nETBIOSName (nCName has
        # already been updated by this point, but the netBIOS hasn't)
        base_dn = samdb.get_default_basedn()
        nc_name = ldb.binary_encode(str(base_dn))
        partitions_dn = samdb.get_partitions_dn()
        res = samdb.search(base=partitions_dn, scope=ldb.SCOPE_ONELEVEL,
                           attrs=["nETBIOSName"],
                           expression='ncName=%s' % nc_name)

        logger.info("Changing backup domain's NetBIOS name to %s" %
                    new_netbios_name)
        m = ldb.Message()
        m.dn = res[0].dn
        m["nETBIOSName"] = ldb.MessageElement(new_netbios_name,
                                              ldb.FLAG_MOD_REPLACE,
                                              "nETBIOSName")
        samdb.modify(m)

        # renames the object itself to reflect the change in domain
        new_dn = "CN=%s,%s" % (new_netbios_name, partitions_dn)
        logger.info("Renaming %s --> %s" % (res[0].dn, new_dn))
        samdb.rename(res[0].dn, new_dn, controls=['relax:0'])

    def delete_old_dns_zones(self, logger, samdb, old_realm):
        # remove the top-level DNS entries for the old realm
        basedn = samdb.get_default_basedn()
        dn = "DC=%s,CN=MicrosoftDNS,DC=DomainDnsZones,%s" % (old_realm, basedn)
        logger.info("Deleting old DNS zone %s" % dn)
        samdb.delete(dn, ["tree_delete:1"])

        forestdn = samdb.get_root_basedn().get_linearized()
        dn = "DC=_msdcs.%s,CN=MicrosoftDNS,DC=ForestDnsZones,%s" % (old_realm,
                                                                    forestdn)
        logger.info("Deleting old DNS zone %s" % dn)
        samdb.delete(dn, ["tree_delete:1"])

    def fix_old_dn_attributes(self, samdb):
        '''Fixes attributes (i.e. objectCategory) that still use the old DN'''

        samdb.transaction_start()
        # Just fix any mismatches in DN detected (leave any other errors)
        chk = dbcheck(samdb, quiet=True, fix=True, yes=False,
                      in_transaction=True)
        # fix up incorrect objectCategory/etc attributes
        setattr(chk, 'fix_all_old_dn_string_component_mismatch', 'ALL')
        cross_ncs_ctrl = 'search_options:1:2'
        controls = ['show_deleted:1', cross_ncs_ctrl]
        chk.check_database(controls=controls)
        samdb.transaction_commit()

    def run(self, new_domain_name, new_dns_realm, sambaopts=None,
            credopts=None, server=None, targetdir=None, keep_dns_realm=False,
            no_secrets=False, backend_store=None):
        logger = self.get_logger()
        logger.setLevel(logging.INFO)

        lp = sambaopts.get_loadparm()
        creds = credopts.get_credentials(lp)

        # Make sure we have all the required args.
        if server is None:
            raise CommandError('Server required')

        check_targetdir(logger, targetdir)

        delete_old_dns = not keep_dns_realm

        new_dns_realm = new_dns_realm.lower()
        new_domain_name = new_domain_name.upper()

        new_base_dn = samba.dn_from_dns_name(new_dns_realm)
        logger.info("New realm for backed up domain: %s" % new_dns_realm)
        logger.info("New base DN for backed up domain: %s" % new_base_dn)
        logger.info("New domain NetBIOS name: %s" % new_domain_name)

        tmpdir = tempfile.mkdtemp(dir=targetdir)

        # setup a join-context for cloning the remote server
        include_secrets = not no_secrets
        ctx = DCCloneAndRenameContext(new_base_dn, new_domain_name,
                                      new_dns_realm, logger=logger,
                                      creds=creds, lp=lp,
                                      include_secrets=include_secrets,
                                      dns_backend='SAMBA_INTERNAL',
                                      server=server, targetdir=tmpdir,
                                      backend_store=backend_store)

        # sanity-check we're not "renaming" the domain to the same values
        old_domain = ctx.domain_name
        if old_domain == new_domain_name:
            shutil.rmtree(tmpdir)
            raise CommandError("Cannot use the current domain NetBIOS name.")

        old_realm = ctx.realm
        if old_realm == new_dns_realm:
            shutil.rmtree(tmpdir)
            raise CommandError("Cannot use the current domain DNS realm.")

        # do the clone/rename
        ctx.do_join()

        # get the paths used for the clone, then drop the old samdb connection
        del ctx.local_samdb
        paths = ctx.paths

        # get a free RID to use as the new DC's SID (when it gets restored)
        remote_sam = SamDB(url='ldap://' + server, credentials=creds,
                           session_info=system_session(), lp=lp)
        new_sid = get_sid_for_restore(remote_sam, logger)

        # Grab the remote DC's sysvol files and bundle them into a tar file.
        # Note we end up with 2 sysvol dirs - the original domain's files (that
        # use the old realm) backed here, as well as default files generated
        # for the new realm as part of the clone/join.
        sysvol_tar = os.path.join(tmpdir, 'sysvol.tar.gz')
        smb_conn = smb_sysvol_conn(server, lp, creds)
        backup_online(smb_conn, sysvol_tar, remote_sam.get_domain_sid())

        # connect to the local DB (making sure we use the new/renamed config)
        lp.load(paths.smbconf)
        samdb = SamDB(url=paths.samdb, session_info=system_session(), lp=lp)

        # Edit the cloned sam.ldb to mark it as a backup
        time_str = get_timestamp()
        add_backup_marker(samdb, "backupDate", time_str)
        add_backup_marker(samdb, "sidForRestore", new_sid)
        add_backup_marker(samdb, "backupRename", old_realm)
        add_backup_marker(samdb, "backupType", "rename")

        # fix up the DNS objects that are using the old dnsRoot value
        self.update_dns_root(logger, samdb, old_realm, delete_old_dns)

        # update the netBIOS name and the Partition object for the domain
        self.rename_domain_partition(logger, samdb, new_domain_name)

        if delete_old_dns:
            self.delete_old_dns_zones(logger, samdb, old_realm)

        logger.info("Fixing DN attributes after rename...")
        self.fix_old_dn_attributes(samdb)

        # ensure the admin user always has a password set (same as provision)
        if no_secrets:
            set_admin_password(logger, samdb)

        # Add everything in the tmpdir to the backup tar file
        backup_file = backup_filepath(targetdir, new_dns_realm, time_str)
        create_log_file(tmpdir, lp, "rename", server, include_secrets,
                        "Original domain %s (NetBIOS), %s (DNS realm)" %
                        (old_domain, old_realm))
        create_backup_tar(logger, tmpdir, backup_file)

        shutil.rmtree(tmpdir)
Ejemplo n.º 3
0
class cmd_domain_backup_online(samba.netcmd.Command):
    '''Copy a running DC's current DB into a backup tar file.

    Takes a backup copy of the current domain from a running DC. If the domain
    were to undergo a catastrophic failure, then the backup file can be used to
    recover the domain. The backup created is similar to the DB that a new DC
    would receive when it joins the domain.

    Note that:
    - it's recommended to run 'samba-tool dbcheck' before taking a backup-file
      and fix any errors it reports.
    - all the domain's secrets are included in the backup file.
    - although the DB contents can be untarred and examined manually, you need
      to run 'samba-tool domain backup restore' before you can start a Samba DC
      from the backup file.'''

    synopsis = "%prog --server=<DC-to-backup> --targetdir=<output-dir>"
    takes_optiongroups = {
        "sambaopts": options.SambaOptions,
        "credopts": options.CredentialsOptions,
    }

    takes_options = [
        Option("--server", help="The DC to backup", type=str),
        Option("--targetdir", type=str,
               help="Directory to write the backup file to"),
        Option("--no-secrets", action="store_true", default=False,
               help="Exclude secret values from the backup created"),
        Option("--backend-store", type="choice", metavar="BACKENDSTORE",
               choices=["tdb", "mdb"],
               help="Specify the database backend to be used "
               "(default is %s)" % get_default_backend_store()),
    ]

    def run(self, sambaopts=None, credopts=None, server=None, targetdir=None,
            no_secrets=False, backend_store=None):
        logger = self.get_logger()
        logger.setLevel(logging.DEBUG)

        lp = sambaopts.get_loadparm()
        creds = credopts.get_credentials(lp)

        # Make sure we have all the required args.
        if server is None:
            raise CommandError('Server required')

        check_targetdir(logger, targetdir)

        tmpdir = tempfile.mkdtemp(dir=targetdir)

        # Run a clone join on the remote
        include_secrets = not no_secrets
        ctx = join_clone(logger=logger, creds=creds, lp=lp,
                         include_secrets=include_secrets, server=server,
                         dns_backend='SAMBA_INTERNAL', targetdir=tmpdir,
                         backend_store=backend_store)

        # get the paths used for the clone, then drop the old samdb connection
        paths = ctx.paths
        del ctx

        # Get a free RID to use as the new DC's SID (when it gets restored)
        remote_sam = SamDB(url='ldap://' + server, credentials=creds,
                           session_info=system_session(), lp=lp)
        new_sid = get_sid_for_restore(remote_sam, logger)
        realm = remote_sam.domain_dns_name()

        # Grab the remote DC's sysvol files and bundle them into a tar file
        sysvol_tar = os.path.join(tmpdir, 'sysvol.tar.gz')
        smb_conn = smb_sysvol_conn(server, lp, creds)
        backup_online(smb_conn, sysvol_tar, remote_sam.get_domain_sid())

        # remove the default sysvol files created by the clone (we want to
        # make sure we restore the sysvol.tar.gz files instead)
        shutil.rmtree(paths.sysvol)

        # Edit the downloaded sam.ldb to mark it as a backup
        samdb = SamDB(url=paths.samdb, session_info=system_session(), lp=lp)
        time_str = get_timestamp()
        add_backup_marker(samdb, "backupDate", time_str)
        add_backup_marker(samdb, "sidForRestore", new_sid)
        add_backup_marker(samdb, "backupType", "online")

        # ensure the admin user always has a password set (same as provision)
        if no_secrets:
            set_admin_password(logger, samdb)

        # Add everything in the tmpdir to the backup tar file
        backup_file = backup_filepath(targetdir, realm, time_str)
        create_log_file(tmpdir, lp, "online", server, include_secrets)
        create_backup_tar(logger, tmpdir, backup_file)

        shutil.rmtree(tmpdir)
Ejemplo n.º 4
0
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""")
Ejemplo n.º 5
0
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) = str(tmp).split(':')
        partfile[nc.upper()] = fname

    backend_store = get_default_backend_store()
    if "backendStore" in res[0]:
        backend_store = str(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 backend_store == "mdb":
            # If the file is an lmdb data file need to link the
            # lock file as well
            os.link(os.path.join(private_dir, domainzone_file + "-lock"),
                    os.path.join(dns_dir, domainzone_file + "-lock"))
        if forestzone_file:
            os.link(os.path.join(private_dir, forestzone_file),
                    os.path.join(dns_dir, forestzone_file))
            if backend_store == "mdb":
                # If the database file is an lmdb data file need to link the
                # lock file as well
                os.link(os.path.join(private_dir, forestzone_file + "-lock"),
                        os.path.join(dns_dir, forestzone_file + "-lock"))
    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 'SAMBA_SELFTEST' not in os.environ:
                logger.error(
                    "Failed to set permissions to sam.ldb* files, fix manually")
    else:
        if 'SAMBA_SELFTEST' not in os.environ:
            logger.warning("""Unable to find group id for BIND,
                set permissions to sam.ldb* files manually""")