#!/usr/bin/env python

from samba.samdb import SamDB
from optparse import OptionParser
import samba
from samba import getopt
from samba.auth import system_session
from samba.join import DCJoinContext
from samba.dcerpc.security import dom_sid
from samba.netcmd import domain_backup
from samba.ndr import ndr_unpack
from samba.remove_dc import remove_dc
from samba import Ldb
from samba.provision import secretsdb_self_join
from samba.dcerpc import misc
from configobj import ConfigObj
import ldb
import logging
from os.path import exists
import os
from sys import exit
from time import sleep
from shutil import copytree, rmtree, move

targetdir = '/var/lib/samba'
config = ConfigObj('/etc/eole/samba4-vars.conf')
netbios = config['AD_HOST_NAME'].upper()
ad_realm = config['AD_REALM'].upper()
ad_host_keytab_file = config['AD_HOST_KEYTAB_FILE']
fake_netbios = netbios + 'RESTORE'
site = None

def fake_exists(path):
    if path == 'fake':
        print('fake exists for tarball')
        return True
    if path == targetdir:
        print('fake not exists for {}'.format(path))
        return False
    return exists(path)
os.path.exists = fake_exists
domain_backup.os = os

class fake_open:
    def extractall(self, a):
        pass

    def close(self):
        pass

class fake_tarfile:
    def open(self, path):
        print('fake tarfile for {}'.format(path))
        return fake_open()
domain_backup.tarfile = fake_tarfile()

cmd = 'systemctl stop samba-ad-dc'
os.system(cmd)
backup = domain_backup.cmd_domain_backup_restore()
parse = OptionParser()
options = getopt.SambaOptions(parse)
cred_options = getopt.CredentialsOptions(parse)
rmtree(targetdir)
copytree('/home/backup/samba/bareos/', targetdir)
backup.run(sambaopts=options,
           credopts=cred_options,
           backup_file='fake',
           targetdir='/var/lib/samba',
           newservername=fake_netbios)

lp = options.get_loadparm()
creds = cred_options.get_credentials(lp)
samdb = SamDB(session_info=system_session(), credentials=creds, lp=lp)
logger = logging.getLogger('restore')
ctx = DCJoinContext(logger, creds=creds, lp=lp, site=site,
                    forced_local_samdb=samdb,
                    netbios_name=netbios)
ctx.userAccountControl = (samba.dsdb.UF_SERVER_TRUST_ACCOUNT |
                          samba.dsdb.UF_TRUSTED_FOR_DELEGATION)
res = samdb.search(base="", scope=ldb.SCOPE_BASE,
                   attrs=['namingContexts'])
ncs = [str(r) for r in res[0].get('namingContexts')]
ctx.nc_list = ncs
ctx.full_nc_list = ncs
ctx.join_add_objects()
m = ldb.Message()
m.dn = ldb.Dn(samdb, '@ROOTDSE')
ntds_guid = str(ctx.ntds_guid)
m["dsServiceName"] = ldb.MessageElement("<GUID=%s>" % ntds_guid,
                                        ldb.FLAG_MOD_REPLACE,
                                        "dsServiceName")
samdb.modify(m)
private_dir = os.path.join(targetdir, 'private')
secrets_path = os.path.join(private_dir, 'secrets.ldb')
secrets_ldb = Ldb(secrets_path, session_info=system_session(), lp=lp)
secretsdb_self_join(secrets_ldb, domain=ctx.domain_name,
                    realm=ctx.realm, dnsdomain=ctx.dnsdomain,
                    netbiosname=ctx.myname, domainsid=ctx.domsid,
                    machinepass=ctx.acct_pass,
                    key_version_number=ctx.key_version_number,
                    secure_channel_type=misc.SEC_CHAN_BDC)

# Seize DNS roles
domain_dn = samdb.domain_dn()
forest_dn = samba.dn_from_dns_name(samdb.forest_dns_name())
domaindns_dn = ("CN=Infrastructure,DC=DomainDnsZones,", domain_dn)
forestdns_dn = ("CN=Infrastructure,DC=ForestDnsZones,", forest_dn)
for dn_prefix, dns_dn in [forestdns_dn, domaindns_dn]:
    if dns_dn not in ncs:
        continue
    full_dn = dn_prefix + dns_dn
    m = ldb.Message()
    m.dn = ldb.Dn(samdb, full_dn)
    m["fSMORoleOwner"] = ldb.MessageElement(samdb.get_dsServiceName(),
                                            ldb.FLAG_MOD_REPLACE,
                                            "fSMORoleOwner")
    samdb.modify(m)

# Seize other roles
for role in ['rid', 'pdc', 'naming', 'infrastructure', 'schema']:
    backup.seize_role(role, samdb, force=True)
search_expr = "(&(objectClass=Server)(serverReference=*)(cn={}))".format(fake_netbios)
res = samdb.search(samdb.get_config_basedn(), scope=ldb.SCOPE_SUBTREE,
                   expression=search_expr)
cn = res[0].get('cn')[0]
remove_dc(samdb, logger, cn)

# Remove the repsFrom and repsTo from each NC to ensure we do
# not try (and fail) to talk to the old DCs
for nc in ncs:
    msg = ldb.Message()
    msg.dn = ldb.Dn(samdb, nc)

    msg["repsFrom"] = ldb.MessageElement([],
                                         ldb.FLAG_MOD_REPLACE,
                                         "repsFrom")
    msg["repsTo"] = ldb.MessageElement([],
                                       ldb.FLAG_MOD_REPLACE,
                                       "repsTo")
    samdb.modify(msg)

# remove extra data in targetdir
rmtree(targetdir + '/etc')
os.unlink(targetdir + '/backup.txt')

# restore sysvol
rmtree('/home/sysvol')
move(targetdir + '/state/sysvol', '/home/sysvol')
rmtree(targetdir + '/state')

cmd = 'systemctl start samba-ad-dc'
if os.system(cmd):
    print('la commande {} est en erreur'.format(cmd))
    exit(1)

cmd = 'samba-tool domain exportkeytab "{0}" --principal="{1}@{2}" -s /etc/samba/smb.conf'.format(ad_host_keytab_file, netbios, ad_realm)
if os.system(cmd):
    print('la commande {} est en erreur'.format(cmd))
    exit(1)
