1
0
mirror of https://github.com/samba-team/samba.git synced 2025-02-01 05:47:28 +03:00

provision: allow provisioning of a different database backend

This sets the backendStore field in @PARTITION, depending on which
argument you set in the provision.

Signed-off-by: Gary Lockyer <gary@catalyst.net.nz>
Reviewed-by: Andrew Bartlett <abartlet@samba.org>
This commit is contained in:
Gary Lockyer 2018-03-20 14:38:19 +13:00 committed by Andrew Bartlett
parent 301cd5e58a
commit 34b12fbd88
5 changed files with 68 additions and 23 deletions

View File

@ -43,7 +43,7 @@ from samba.net import Net, LIBNET_JOIN_AUTOMATIC
import samba.ntacls
from samba.join import join_RODC, join_DC, join_subdomain
from samba.auth import system_session
from samba.samdb import SamDB
from samba.samdb import SamDB, get_default_backend_store
from samba.ndr import ndr_unpack, ndr_pack, ndr_print
from samba.dcerpc import drsuapi
from samba.dcerpc import drsblobs
@ -258,6 +258,10 @@ class cmd_domain_provision(Command):
Option("--plaintext-secrets", action="store_true",
help="Store secret/sensitive values as plain text on disk" +
"(default is to encrypt secret/ensitive values)"),
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()),
]
openldap_options = [
@ -328,7 +332,8 @@ class cmd_domain_provision(Command):
ldap_backend_forced_uri=None,
ldap_dryrun_mode=None,
base_schema=None,
plaintext_secrets=False):
plaintext_secrets=False,
backend_store=None):
self.logger = self.get_logger("provision")
if quiet:
@ -476,6 +481,8 @@ class cmd_domain_provision(Command):
domain_sid = security.dom_sid(domain_sid)
session = system_session()
if backend_store is None:
backend_store = get_default_backend_store()
try:
result = provision(self.logger,
session, smbconf=smbconf, targetdir=targetdir,
@ -498,7 +505,8 @@ class cmd_domain_provision(Command):
ldap_backend_forced_uri=ldap_backend_forced_uri,
nosync=ldap_backend_nosync, ldap_dryrun_mode=ldap_dryrun_mode,
base_schema=base_schema,
plaintext_secrets=plaintext_secrets)
plaintext_secrets=plaintext_secrets,
backend_store=backend_store)
except ProvisioningError as e:
raise CommandError("Provision failed", e)

View File

@ -123,6 +123,7 @@ from samba.schema import Schema
from samba.samdb import SamDB
from samba.dbchecker import dbcheck
from samba.provision.kerberos import create_kdc_conf
from samba.samdb import get_default_backend_store
DEFAULT_POLICY_GUID = "31B2F340-016D-11D2-945F-00C04FB984F9"
DEFAULT_DC_POLICY_GUID = "6AC1786C-016F-11D2-945F-00C04FB984F9"
@ -814,7 +815,8 @@ def setup_name_mappings(idmap, sid, root_uid, nobody_uid,
def setup_samdb_partitions(samdb_path, logger, lp, session_info,
provision_backend, names, serverrole,
erase=False, plaintext_secrets=False):
erase=False, plaintext_secrets=False,
backend_store=None):
"""Setup the partitions for the SAM database.
Alternatively, provision() may call this, and then populate the database.
@ -847,11 +849,16 @@ def setup_samdb_partitions(samdb_path, logger, lp, session_info,
if not plaintext_secrets:
required_features = "requiredFeatures: encryptedSecrets"
if backend_store is None:
backend_store = get_default_backend_store()
backend_store_line = "backendStore: %s" % backend_store
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
"LDAP_BACKEND_LINE": ldap_backend_line,
"BACKEND_STORE": backend_store_line
})
@ -1245,7 +1252,7 @@ def create_default_gpo(sysvolpath, dnsdomain, policyguid, policyguid_dc):
def setup_samdb(path, session_info, provision_backend, lp, names,
logger, fill, serverrole, schema, am_rodc=False,
plaintext_secrets=False):
plaintext_secrets=False, backend_store=None):
"""Setup a complete SAM Database.
:note: This will wipe the main SAM database file!
@ -1254,7 +1261,8 @@ def setup_samdb(path, session_info, provision_backend, lp, names,
# Also wipes the database
setup_samdb_partitions(path, logger=logger, lp=lp,
provision_backend=provision_backend, session_info=session_info,
names=names, serverrole=serverrole, plaintext_secrets=plaintext_secrets)
names=names, serverrole=serverrole, plaintext_secrets=plaintext_secrets,
backend_store=backend_store)
# Load the database, but don's load the global schema and don't connect
# quite yet
@ -1293,7 +1301,8 @@ def setup_samdb(path, session_info, provision_backend, lp, names,
def fill_samdb(samdb, lp, names, logger, 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):
dom_for_fun_level=None, schema=None, next_rid=None, dc_rid=None,
backend_store=None):
if next_rid is None:
next_rid = 1000
@ -1831,7 +1840,8 @@ def provision_fill(samdb, secrets_ldb, logger, names, paths,
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):
am_rodc=False, lp=None, use_ntvfs=False,
skip_sysvolacl=False, backend_store=None):
# create/adapt the group policy GUIDs
# Default GUID for default policy are described at
# "How Core Group Policy Works"
@ -1863,7 +1873,8 @@ def provision_fill(samdb, secrets_ldb, logger, names, paths,
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)
next_rid=next_rid, dc_rid=dc_rid,
backend_store=backend_store)
# Set up group policies (domain policy and domain controller
# policy)
@ -1913,7 +1924,8 @@ def provision_fill(samdb, secrets_ldb, logger, names, paths,
setup_ad_dns(samdb, secrets_ldb, names, paths, lp, logger,
hostip=hostip, hostip6=hostip6, dns_backend=dns_backend,
dnspass=dnspass, os_level=dom_for_fun_level,
targetdir=targetdir, fill_level=samdb_fill)
targetdir=targetdir, fill_level=samdb_fill,
backend_store=backend_store)
domainguid = samdb.searchone(basedn=samdb.get_default_basedn(),
attribute="objectGUID")
@ -2033,7 +2045,7 @@ def provision(logger, session_info, smbconf=None,
use_rfc2307=False, maxuid=None, maxgid=None, skip_sysvolacl=True,
ldap_backend_forced_uri=None, nosync=False, ldap_dryrun_mode=False,
ldap_backend_extra_port=None, base_schema=None,
plaintext_secrets=False):
plaintext_secrets=False, backend_store=None):
"""Provision samba4
:note: caution, this wipes all existing data!
@ -2050,6 +2062,8 @@ def provision(logger, session_info, smbconf=None,
if backend_type is None:
backend_type = "ldb"
if backend_store is None:
backend_store = get_default_backend_store()
if domainsid is None:
domainsid = security.random_sid()
@ -2233,7 +2247,8 @@ def provision(logger, session_info, smbconf=None,
provision_backend, lp, names, logger=logger,
serverrole=serverrole,
schema=schema, fill=samdb_fill, am_rodc=am_rodc,
plaintext_secrets=plaintext_secrets)
plaintext_secrets=plaintext_secrets,
backend_store=backend_store)
if serverrole == "active directory domain controller":
if paths.netlogon is None:
@ -2264,7 +2279,8 @@ def provision(logger, session_info, smbconf=None,
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)
skip_sysvolacl=skip_sysvolacl,
backend_store=backend_store)
if not is_heimdal_built():
create_kdc_conf(paths.kdcconf, realm, domain, os.path.dirname(lp.get("log file")))

View File

@ -29,6 +29,7 @@ from base64 import b64encode
import subprocess
import samba
from samba.tdb_util import tdb_copy
from samba.mdb_util import mdb_copy
from samba.ndr import ndr_pack, ndr_unpack
from samba import setup_file
from samba.dcerpc import dnsp, misc, security
@ -58,6 +59,7 @@ from samba.provision.common import (
FILL_DRS,
)
from samba.samdb import get_default_backend_store
def get_domainguid(samdb, domaindn):
res = samdb.search(base=domaindn, scope=ldb.SCOPE_BASE, attrs=["objectGUID"])
@ -787,12 +789,19 @@ def create_samdb_copy(samdb, logger, paths, names, domainsid, domainguid):
# Find the partitions and corresponding filenames
partfile = {}
res = samdb.search(base="@PARTITION", scope=ldb.SCOPE_BASE, attrs=["partition"])
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:
@ -800,7 +809,8 @@ def create_samdb_copy(samdb, logger, paths, names, domainsid, domainguid):
file(domainpart_file, 'w').close()
# Fill the basedn and @OPTION records in domain partition
dom_ldb = samba.Ldb(domainpart_file)
dom_url = "%s://%s" % (backend_store, domainpart_file)
dom_ldb = samba.Ldb(dom_url)
domainguid_line = "objectGUID: %s\n-" % domainguid
descr = b64encode(get_domain_descriptor(domainsid))
setup_add_ldif(dom_ldb, setup_path("provision_basedn.ldif"), {
@ -859,8 +869,12 @@ def create_samdb_copy(samdb, logger, paths, names, domainsid, domainguid):
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))
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")
@ -875,7 +889,7 @@ def create_samdb_copy(samdb, logger, paths, names, domainsid, domainguid):
os.chown(dpath, -1, paths.bind_gid)
os.chmod(dpath, 0o770)
for f in files:
if f.endswith('.ldb') or f.endswith('.tdb'):
if f.endswith(('.ldb', '.tdb', 'ldb-lock')):
fpath = os.path.join(dirname, f)
os.chown(fpath, -1, paths.bind_gid)
os.chmod(fpath, 0o660)
@ -1069,7 +1083,7 @@ def fill_dns_data_partitions(samdb, domainsid, site, domaindn, forestdn,
def setup_ad_dns(samdb, secretsdb, names, paths, lp, logger,
dns_backend, os_level, dnspass=None, hostip=None, hostip6=None,
targetdir=None, fill_level=FILL_FULL):
targetdir=None, fill_level=FILL_FULL, backend_store=None):
"""Provision DNS information (assuming GC role)
:param samdb: LDB object connected to sam.ldb file
@ -1164,12 +1178,14 @@ def setup_ad_dns(samdb, secretsdb, names, paths, lp, logger,
if dns_backend.startswith("BIND9_"):
setup_bind9_dns(samdb, secretsdb, names, paths, lp, logger,
dns_backend, os_level, site=site, dnspass=dnspass, hostip=hostip,
hostip6=hostip6, targetdir=targetdir)
hostip6=hostip6, targetdir=targetdir,
backend_store=backend_store)
def setup_bind9_dns(samdb, secretsdb, names, paths, lp, logger,
dns_backend, os_level, site=None, dnspass=None, hostip=None,
hostip6=None, targetdir=None, key_version_number=None):
hostip6=None, targetdir=None, key_version_number=None,
backend_store=None):
"""Provision DNS information (assuming BIND9 backend in DC role)
:param samdb: LDB object connected to sam.ldb file
@ -1216,7 +1232,8 @@ def setup_bind9_dns(samdb, secretsdb, names, paths, lp, logger,
ntdsguid=names.ntdsguid)
if dns_backend == "BIND9_DLZ" and os_level >= DS_DOMAIN_FUNCTION_2003:
create_samdb_copy(samdb, logger, paths, names, names.domainsid, domainguid)
create_samdb_copy(samdb, logger, paths,
names, names.domainsid, domainguid)
create_named_conf(paths, realm=names.realm,
dnsdomain=names.dnsdomain, dns_backend=dns_backend,

View File

@ -37,6 +37,9 @@ from samba.dcerpc import security
__docformat__ = "restructuredText"
def get_default_backend_store():
return "tdb"
class SamDB(samba.Ldb):
"""The SAM database."""

View File

@ -2,5 +2,6 @@ dn: @PARTITION
replicateEntries: @ATTRIBUTES
replicateEntries: @INDEXLIST
replicateEntries: @OPTIONS
${BACKEND_STORE}
${LDAP_BACKEND_LINE}