From: Rob van der Linde Date: Fri, 31 Mar 2023 00:28:17 +0000 (+1300) Subject: netcmd: domain: move provision command to domain/provision.py X-Git-Tag: talloc-2.4.1~1179 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=5986937d12c237121d4e62fa6dfa0f5dadec263d;p=thirdparty%2Fsamba.git netcmd: domain: move provision command to domain/provision.py Signed-off-by: Rob van der Linde Reviewed-by: Douglas Bagnall Reviewed-by: Andrew Bartlett --- diff --git a/python/samba/netcmd/domain/__init__.py b/python/samba/netcmd/domain/__init__.py index 7cae91fc76a..ae6936e6307 100644 --- a/python/samba/netcmd/domain/__init__.py +++ b/python/samba/netcmd/domain/__init__.py @@ -25,7 +25,6 @@ import samba.getopt as options import ldb import os -import sys import ctypes import tempfile import subprocess @@ -38,7 +37,7 @@ from getpass import getpass from samba.net import Net, LIBNET_JOIN_AUTOMATIC import samba.ntacls from samba.auth import system_session -from samba.samdb import SamDB, get_default_backend_store +from samba.samdb import SamDB from samba.dcerpc import drsblobs from samba.dcerpc import lsa from samba.dcerpc import netlogon @@ -52,38 +51,9 @@ from samba.netcmd import ( ) from samba.netcmd.fsmo import get_fsmo_roleowner from samba import string_to_byte_array -from samba.auth_util import system_session_unix from samba import is_ad_dc_built -from samba.dsdb import ( - DS_DOMAIN_FUNCTION_2000, - DS_DOMAIN_FUNCTION_2003, - DS_DOMAIN_FUNCTION_2003_MIXED, - DS_DOMAIN_FUNCTION_2008, - DS_DOMAIN_FUNCTION_2008_R2, - DS_DOMAIN_FUNCTION_2012, - DS_DOMAIN_FUNCTION_2012_R2, - DS_DOMAIN_FUNCTION_2016, - DS_NTDSDSA_OPT_DISABLE_OUTBOUND_REPL, - DS_NTDSDSA_OPT_DISABLE_INBOUND_REPL, - UF_WORKSTATION_TRUST_ACCOUNT, - UF_SERVER_TRUST_ACCOUNT, - UF_TRUSTED_FOR_DELEGATION, - UF_PARTIAL_SECRETS_ACCOUNT -) - -from samba.provision import ( - provision, - ProvisioningError, - DEFAULT_MIN_PWD_LENGTH, - setup_path -) - -from samba.provision.common import ( - FILL_FULL, - FILL_NT4SYNC, - FILL_DRS -) +from samba.provision import setup_path from samba.trust_utils import CreateTrustedDomainRelax @@ -100,366 +70,7 @@ from .keytab import cmd_domain_export_keytab from .leave import cmd_domain_leave from .level import cmd_domain_level from .passwordsettings import cmd_domain_passwordsettings - - -class cmd_domain_provision(Command): - """Provision a domain.""" - - synopsis = "%prog [options]" - - takes_optiongroups = { - "sambaopts": options.SambaOptions, - "versionopts": options.VersionOptions, - } - - takes_options = [ - Option("--interactive", help="Ask for names", action="store_true"), - Option("--domain", type="string", metavar="DOMAIN", - help="NetBIOS domain name to use"), - Option("--domain-guid", type="string", metavar="GUID", - help="set domainguid (otherwise random)"), - Option("--domain-sid", type="string", metavar="SID", - help="set domainsid (otherwise random)"), - Option("--ntds-guid", type="string", metavar="GUID", - help="set NTDS object GUID (otherwise random)"), - Option("--invocationid", type="string", metavar="GUID", - help="set invocationid (otherwise random)"), - Option("--host-name", type="string", metavar="HOSTNAME", - help="set hostname"), - Option("--host-ip", type="string", metavar="IPADDRESS", - help="set IPv4 ipaddress"), - Option("--host-ip6", type="string", metavar="IP6ADDRESS", - help="set IPv6 ipaddress"), - Option("--site", type="string", metavar="SITENAME", - help="set site name"), - Option("--adminpass", type="string", metavar="PASSWORD", - help="choose admin password (otherwise random)"), - Option("--krbtgtpass", type="string", metavar="PASSWORD", - help="choose krbtgt password (otherwise random)"), - Option("--dns-backend", type="choice", metavar="NAMESERVER-BACKEND", - choices=["SAMBA_INTERNAL", "BIND9_FLATFILE", "BIND9_DLZ", "NONE"], - help="The DNS server backend. SAMBA_INTERNAL is the builtin name server (default), " - "BIND9_FLATFILE uses bind9 text database to store zone information, " - "BIND9_DLZ uses samba4 AD to store zone information, " - "NONE skips the DNS setup entirely (not recommended)", - default="SAMBA_INTERNAL"), - Option("--dnspass", type="string", metavar="PASSWORD", - help="choose dns password (otherwise random)"), - Option("--root", type="string", metavar="USERNAME", - help="choose 'root' unix username"), - Option("--nobody", type="string", metavar="USERNAME", - help="choose 'nobody' user"), - Option("--users", type="string", metavar="GROUPNAME", - help="choose 'users' group"), - Option("--blank", action="store_true", - help="do not add users or groups, just the structure"), - Option("--server-role", type="choice", metavar="ROLE", - choices=["domain controller", "dc", "member server", "member", "standalone"], - help="The server role (domain controller | dc | member server | member | standalone). Default is dc.", - default="domain controller"), - Option("--function-level", type="choice", metavar="FOR-FUN-LEVEL", - choices=["2000", "2003", "2008", "2008_R2"], - help="The domain and forest function level (2000 | 2003 | 2008 | 2008_R2 - always native). Default is (Windows) 2008_R2 Native.", - default="2008_R2"), - Option("--base-schema", type="choice", metavar="BASE-SCHEMA", - choices=["2008_R2", "2008_R2_old", "2012", "2012_R2", "2016", "2019"], - help="The base schema files to use. Default is (Windows) 2019.", - default="2019"), - Option("--adprep-level", type="choice", metavar="FUNCTION_LEVEL", - choices=["SKIP", "2008_R2", "2012", "2012_R2", "2016"], - help="The highest functional level to prepare for. Default is based on --base-schema", - default=None), - Option("--next-rid", type="int", metavar="NEXTRID", default=1000, - help="The initial nextRid value (only needed for upgrades). Default is 1000."), - Option("--partitions-only", - help="Configure Samba's partitions, but do not modify them (ie, join a BDC)", action="store_true"), - Option("--use-rfc2307", action="store_true", help="Use AD to store posix attributes (default = no)"), - ] - - ntvfs_options = [ - Option("--use-xattrs", type="choice", choices=["yes", "no", "auto"], - metavar="[yes|no|auto]", - help="Define if we should use the native fs capabilities or a tdb file for " - "storing attributes likes ntacl when --use-ntvfs is set. " - "auto tries to make an inteligent guess based on the user rights and system capabilities", - default="auto") - ] - - takes_options.extend(common_provision_join_options) - - if samba.is_ntvfs_fileserver_built(): - takes_options.extend(common_ntvfs_options) - takes_options.extend(ntvfs_options) - - takes_args = [] - - def run(self, sambaopts=None, versionopts=None, - interactive=None, - domain=None, - domain_guid=None, - domain_sid=None, - ntds_guid=None, - invocationid=None, - host_name=None, - host_ip=None, - host_ip6=None, - adminpass=None, - site=None, - krbtgtpass=None, - machinepass=None, - dns_backend=None, - dns_forwarder=None, - dnspass=None, - ldapadminpass=None, - root=None, - nobody=None, - users=None, - quiet=None, - blank=None, - server_role=None, - function_level=None, - adprep_level=None, - next_rid=None, - partitions_only=None, - targetdir=None, - use_xattrs="auto", - use_ntvfs=False, - use_rfc2307=None, - base_schema=None, - plaintext_secrets=False, - backend_store=None, - backend_store_size=None): - - self.logger = self.get_logger(name="provision", quiet=quiet) - - lp = sambaopts.get_loadparm() - smbconf = lp.configfile - - if dns_forwarder is not None: - suggested_forwarder = dns_forwarder - else: - suggested_forwarder = self._get_nameserver_ip() - if suggested_forwarder is None: - suggested_forwarder = "none" - - if len(self.raw_argv) == 1: - interactive = True - - if interactive: - from getpass import getpass - import socket - - def ask(prompt, default=None): - if default is not None: - print("%s [%s]: " % (prompt, default), end=' ') - else: - print("%s: " % (prompt,), end=' ') - sys.stdout.flush() - return sys.stdin.readline().rstrip("\n") or default - - try: - default = socket.getfqdn().split(".", 1)[1].upper() - except IndexError: - default = None - realm = ask("Realm", default) - if realm in (None, ""): - raise CommandError("No realm set!") - - try: - default = realm.split(".")[0] - except IndexError: - default = None - domain = ask("Domain", default) - if domain is None: - raise CommandError("No domain set!") - - server_role = ask("Server Role (dc, member, standalone)", "dc") - - dns_backend = ask("DNS backend (SAMBA_INTERNAL, BIND9_FLATFILE, BIND9_DLZ, NONE)", "SAMBA_INTERNAL") - if dns_backend in (None, ''): - raise CommandError("No DNS backend set!") - - if dns_backend == "SAMBA_INTERNAL": - dns_forwarder = ask("DNS forwarder IP address (write 'none' to disable forwarding)", suggested_forwarder) - if dns_forwarder.lower() in (None, 'none'): - suggested_forwarder = None - dns_forwarder = None - - while True: - adminpassplain = getpass("Administrator password: ") - issue = self._adminpass_issue(adminpassplain) - if issue: - self.errf.write("%s.\n" % issue) - else: - adminpassverify = getpass("Retype password: ") - if not adminpassplain == adminpassverify: - self.errf.write("Sorry, passwords do not match.\n") - else: - adminpass = adminpassplain - break - - else: - realm = sambaopts._lp.get('realm') - if realm is None: - raise CommandError("No realm set!") - if domain is None: - raise CommandError("No domain set!") - - if adminpass: - issue = self._adminpass_issue(adminpass) - if issue: - raise CommandError(issue) - else: - self.logger.info("Administrator password will be set randomly!") - - if function_level == "2000": - dom_for_fun_level = DS_DOMAIN_FUNCTION_2000 - elif function_level == "2003": - dom_for_fun_level = DS_DOMAIN_FUNCTION_2003 - elif function_level == "2008": - dom_for_fun_level = DS_DOMAIN_FUNCTION_2008 - elif function_level == "2008_R2": - dom_for_fun_level = DS_DOMAIN_FUNCTION_2008_R2 - - if adprep_level is None: - # Select the adprep_level default based - # on what the base schema premits - if base_schema in ["2008_R2", "2008_R2_old"]: - # without explicit --adprep-level=2008_R2 - # we will skip the adprep step on - # provision - adprep_level = "SKIP" - elif base_schema in ["2012"]: - adprep_level = "2012" - elif base_schema in ["2012_R2"]: - adprep_level = "2012_R2" - else: - adprep_level = "2016" - - if adprep_level == "SKIP": - provision_adprep_level = None - elif adprep_level == "2008R2": - provision_adprep_level = DS_DOMAIN_FUNCTION_2008_R2 - elif adprep_level == "2012": - provision_adprep_level = DS_DOMAIN_FUNCTION_2012 - elif adprep_level == "2012_R2": - provision_adprep_level = DS_DOMAIN_FUNCTION_2012_R2 - elif adprep_level == "2016": - provision_adprep_level = DS_DOMAIN_FUNCTION_2016 - - if dns_backend == "SAMBA_INTERNAL" and dns_forwarder is None: - dns_forwarder = suggested_forwarder - - samdb_fill = FILL_FULL - if blank: - samdb_fill = FILL_NT4SYNC - elif partitions_only: - samdb_fill = FILL_DRS - - if targetdir is not None: - if not os.path.isdir(targetdir): - os.makedirs(targetdir) - - eadb = True - - if use_xattrs == "yes": - eadb = False - elif use_xattrs == "auto" and use_ntvfs == False: - eadb = False - elif use_ntvfs == False: - raise CommandError("--use-xattrs=no requires --use-ntvfs (not supported for production use). " - "Please re-run with --use-xattrs omitted.") - elif use_xattrs == "auto" and not lp.get("posix:eadb"): - if targetdir: - file = tempfile.NamedTemporaryFile(dir=os.path.abspath(targetdir)) - else: - file = tempfile.NamedTemporaryFile(dir=os.path.abspath(os.path.dirname(lp.get("private dir")))) - try: - try: - samba.ntacls.setntacl(lp, file.name, - "O:S-1-5-32G:S-1-5-32", - "S-1-5-32", - system_session_unix(), - "native") - eadb = False - except Exception: - self.logger.info("You are not root or your system does not support xattr, using tdb backend for attributes. ") - finally: - file.close() - - if eadb: - self.logger.info("not using extended attributes to store ACLs and other metadata. If you intend to use this provision in production, rerun the script as root on a system supporting xattrs.") - - if domain_sid is not None: - 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, - samdb_fill=samdb_fill, realm=realm, domain=domain, - domainguid=domain_guid, domainsid=domain_sid, - hostname=host_name, - hostip=host_ip, hostip6=host_ip6, - sitename=site, ntdsguid=ntds_guid, - invocationid=invocationid, adminpass=adminpass, - krbtgtpass=krbtgtpass, machinepass=machinepass, - dns_backend=dns_backend, dns_forwarder=dns_forwarder, - dnspass=dnspass, root=root, nobody=nobody, - users=users, - serverrole=server_role, dom_for_fun_level=dom_for_fun_level, - useeadb=eadb, next_rid=next_rid, lp=lp, use_ntvfs=use_ntvfs, - use_rfc2307=use_rfc2307, skip_sysvolacl=False, - base_schema=base_schema, - adprep_level=provision_adprep_level, - plaintext_secrets=plaintext_secrets, - backend_store=backend_store, - backend_store_size=backend_store_size) - - except ProvisioningError as e: - raise CommandError("Provision failed", e) - - result.report_logger(self.logger) - - def _get_nameserver_ip(self): - """Grab the nameserver IP address from /etc/resolv.conf.""" - from os import path - RESOLV_CONF = "/etc/resolv.conf" - - if not path.isfile(RESOLV_CONF): - self.logger.warning("Failed to locate %s" % RESOLV_CONF) - return None - - handle = None - try: - handle = open(RESOLV_CONF, 'r') - for line in handle: - if not line.startswith('nameserver'): - continue - # we want the last non-space continuous string of the line - return line.strip().split()[-1] - finally: - if handle is not None: - handle.close() - - self.logger.warning("No nameserver found in %s" % RESOLV_CONF) - - def _adminpass_issue(self, adminpass): - """Returns error string for a bad administrator password, - or None if acceptable""" - if isinstance(adminpass, bytes): - adminpass = adminpass.decode('utf8') - if len(adminpass) < DEFAULT_MIN_PWD_LENGTH: - return "Administrator password does not meet the default minimum" \ - " password length requirement (%d characters)" \ - % DEFAULT_MIN_PWD_LENGTH - elif not samba.check_password_quality(adminpass): - return "Administrator password does not meet the default" \ - " quality standards" - else: - return None +from .provision import cmd_domain_provision class cmd_domain_samba3upgrade(cmd_domain_classicupgrade): diff --git a/python/samba/netcmd/domain/provision.py b/python/samba/netcmd/domain/provision.py new file mode 100644 index 00000000000..a503d1a8ebd --- /dev/null +++ b/python/samba/netcmd/domain/provision.py @@ -0,0 +1,408 @@ +# domain management - domain provision +# +# Copyright Matthias Dieter Wallnoefer 2009 +# Copyright Andrew Kroeger 2009 +# Copyright Jelmer Vernooij 2007-2012 +# Copyright Giampaolo Lauria 2011 +# Copyright Matthieu Patou 2011 +# Copyright Andrew Bartlett 2008-2015 +# Copyright Stefan Metzmacher 2012 +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# + +import os +import sys +import tempfile + +import samba +import samba.getopt as options +from samba.auth import system_session +from samba.auth_util import system_session_unix +from samba.dcerpc import security +from samba.dsdb import ( + DS_DOMAIN_FUNCTION_2000, + DS_DOMAIN_FUNCTION_2003, + DS_DOMAIN_FUNCTION_2008, + DS_DOMAIN_FUNCTION_2008_R2, + DS_DOMAIN_FUNCTION_2012, + DS_DOMAIN_FUNCTION_2012_R2, + DS_DOMAIN_FUNCTION_2016 +) +from samba.netcmd import Command, CommandError, Option +from samba.provision import DEFAULT_MIN_PWD_LENGTH, ProvisioningError, provision +from samba.provision.common import FILL_DRS, FILL_FULL, FILL_NT4SYNC +from samba.samdb import get_default_backend_store + +from .common import common_ntvfs_options, common_provision_join_options + + +class cmd_domain_provision(Command): + """Provision a domain.""" + + synopsis = "%prog [options]" + + takes_optiongroups = { + "sambaopts": options.SambaOptions, + "versionopts": options.VersionOptions, + } + + takes_options = [ + Option("--interactive", help="Ask for names", action="store_true"), + Option("--domain", type="string", metavar="DOMAIN", + help="NetBIOS domain name to use"), + Option("--domain-guid", type="string", metavar="GUID", + help="set domainguid (otherwise random)"), + Option("--domain-sid", type="string", metavar="SID", + help="set domainsid (otherwise random)"), + Option("--ntds-guid", type="string", metavar="GUID", + help="set NTDS object GUID (otherwise random)"), + Option("--invocationid", type="string", metavar="GUID", + help="set invocationid (otherwise random)"), + Option("--host-name", type="string", metavar="HOSTNAME", + help="set hostname"), + Option("--host-ip", type="string", metavar="IPADDRESS", + help="set IPv4 ipaddress"), + Option("--host-ip6", type="string", metavar="IP6ADDRESS", + help="set IPv6 ipaddress"), + Option("--site", type="string", metavar="SITENAME", + help="set site name"), + Option("--adminpass", type="string", metavar="PASSWORD", + help="choose admin password (otherwise random)"), + Option("--krbtgtpass", type="string", metavar="PASSWORD", + help="choose krbtgt password (otherwise random)"), + Option("--dns-backend", type="choice", metavar="NAMESERVER-BACKEND", + choices=["SAMBA_INTERNAL", "BIND9_FLATFILE", "BIND9_DLZ", "NONE"], + help="The DNS server backend. SAMBA_INTERNAL is the builtin name server (default), " + "BIND9_FLATFILE uses bind9 text database to store zone information, " + "BIND9_DLZ uses samba4 AD to store zone information, " + "NONE skips the DNS setup entirely (not recommended)", + default="SAMBA_INTERNAL"), + Option("--dnspass", type="string", metavar="PASSWORD", + help="choose dns password (otherwise random)"), + Option("--root", type="string", metavar="USERNAME", + help="choose 'root' unix username"), + Option("--nobody", type="string", metavar="USERNAME", + help="choose 'nobody' user"), + Option("--users", type="string", metavar="GROUPNAME", + help="choose 'users' group"), + Option("--blank", action="store_true", + help="do not add users or groups, just the structure"), + Option("--server-role", type="choice", metavar="ROLE", + choices=["domain controller", "dc", "member server", "member", "standalone"], + help="The server role (domain controller | dc | member server | member | standalone). Default is dc.", + default="domain controller"), + Option("--function-level", type="choice", metavar="FOR-FUN-LEVEL", + choices=["2000", "2003", "2008", "2008_R2"], + help="The domain and forest function level (2000 | 2003 | 2008 | 2008_R2 - always native). Default is (Windows) 2008_R2 Native.", + default="2008_R2"), + Option("--base-schema", type="choice", metavar="BASE-SCHEMA", + choices=["2008_R2", "2008_R2_old", "2012", "2012_R2", "2016", "2019"], + help="The base schema files to use. Default is (Windows) 2019.", + default="2019"), + Option("--adprep-level", type="choice", metavar="FUNCTION_LEVEL", + choices=["SKIP", "2008_R2", "2012", "2012_R2", "2016"], + help="The highest functional level to prepare for. Default is based on --base-schema", + default=None), + Option("--next-rid", type="int", metavar="NEXTRID", default=1000, + help="The initial nextRid value (only needed for upgrades). Default is 1000."), + Option("--partitions-only", + help="Configure Samba's partitions, but do not modify them (ie, join a BDC)", action="store_true"), + Option("--use-rfc2307", action="store_true", help="Use AD to store posix attributes (default = no)"), + ] + + ntvfs_options = [ + Option("--use-xattrs", type="choice", choices=["yes", "no", "auto"], + metavar="[yes|no|auto]", + help="Define if we should use the native fs capabilities or a tdb file for " + "storing attributes likes ntacl when --use-ntvfs is set. " + "auto tries to make an inteligent guess based on the user rights and system capabilities", + default="auto") + ] + + takes_options.extend(common_provision_join_options) + + if samba.is_ntvfs_fileserver_built(): + takes_options.extend(common_ntvfs_options) + takes_options.extend(ntvfs_options) + + takes_args = [] + + def run(self, sambaopts=None, versionopts=None, + interactive=None, + domain=None, + domain_guid=None, + domain_sid=None, + ntds_guid=None, + invocationid=None, + host_name=None, + host_ip=None, + host_ip6=None, + adminpass=None, + site=None, + krbtgtpass=None, + machinepass=None, + dns_backend=None, + dns_forwarder=None, + dnspass=None, + ldapadminpass=None, + root=None, + nobody=None, + users=None, + quiet=None, + blank=None, + server_role=None, + function_level=None, + adprep_level=None, + next_rid=None, + partitions_only=None, + targetdir=None, + use_xattrs="auto", + use_ntvfs=False, + use_rfc2307=None, + base_schema=None, + plaintext_secrets=False, + backend_store=None, + backend_store_size=None): + + self.logger = self.get_logger(name="provision", quiet=quiet) + + lp = sambaopts.get_loadparm() + smbconf = lp.configfile + + if dns_forwarder is not None: + suggested_forwarder = dns_forwarder + else: + suggested_forwarder = self._get_nameserver_ip() + if suggested_forwarder is None: + suggested_forwarder = "none" + + if len(self.raw_argv) == 1: + interactive = True + + if interactive: + from getpass import getpass + import socket + + def ask(prompt, default=None): + if default is not None: + print("%s [%s]: " % (prompt, default), end=' ') + else: + print("%s: " % (prompt,), end=' ') + sys.stdout.flush() + return sys.stdin.readline().rstrip("\n") or default + + try: + default = socket.getfqdn().split(".", 1)[1].upper() + except IndexError: + default = None + realm = ask("Realm", default) + if realm in (None, ""): + raise CommandError("No realm set!") + + try: + default = realm.split(".")[0] + except IndexError: + default = None + domain = ask("Domain", default) + if domain is None: + raise CommandError("No domain set!") + + server_role = ask("Server Role (dc, member, standalone)", "dc") + + dns_backend = ask("DNS backend (SAMBA_INTERNAL, BIND9_FLATFILE, BIND9_DLZ, NONE)", "SAMBA_INTERNAL") + if dns_backend in (None, ''): + raise CommandError("No DNS backend set!") + + if dns_backend == "SAMBA_INTERNAL": + dns_forwarder = ask("DNS forwarder IP address (write 'none' to disable forwarding)", suggested_forwarder) + if dns_forwarder.lower() in (None, 'none'): + suggested_forwarder = None + dns_forwarder = None + + while True: + adminpassplain = getpass("Administrator password: ") + issue = self._adminpass_issue(adminpassplain) + if issue: + self.errf.write("%s.\n" % issue) + else: + adminpassverify = getpass("Retype password: ") + if not adminpassplain == adminpassverify: + self.errf.write("Sorry, passwords do not match.\n") + else: + adminpass = adminpassplain + break + + else: + realm = sambaopts._lp.get('realm') + if realm is None: + raise CommandError("No realm set!") + if domain is None: + raise CommandError("No domain set!") + + if adminpass: + issue = self._adminpass_issue(adminpass) + if issue: + raise CommandError(issue) + else: + self.logger.info("Administrator password will be set randomly!") + + if function_level == "2000": + dom_for_fun_level = DS_DOMAIN_FUNCTION_2000 + elif function_level == "2003": + dom_for_fun_level = DS_DOMAIN_FUNCTION_2003 + elif function_level == "2008": + dom_for_fun_level = DS_DOMAIN_FUNCTION_2008 + elif function_level == "2008_R2": + dom_for_fun_level = DS_DOMAIN_FUNCTION_2008_R2 + + if adprep_level is None: + # Select the adprep_level default based + # on what the base schema premits + if base_schema in ["2008_R2", "2008_R2_old"]: + # without explicit --adprep-level=2008_R2 + # we will skip the adprep step on + # provision + adprep_level = "SKIP" + elif base_schema in ["2012"]: + adprep_level = "2012" + elif base_schema in ["2012_R2"]: + adprep_level = "2012_R2" + else: + adprep_level = "2016" + + if adprep_level == "SKIP": + provision_adprep_level = None + elif adprep_level == "2008R2": + provision_adprep_level = DS_DOMAIN_FUNCTION_2008_R2 + elif adprep_level == "2012": + provision_adprep_level = DS_DOMAIN_FUNCTION_2012 + elif adprep_level == "2012_R2": + provision_adprep_level = DS_DOMAIN_FUNCTION_2012_R2 + elif adprep_level == "2016": + provision_adprep_level = DS_DOMAIN_FUNCTION_2016 + + if dns_backend == "SAMBA_INTERNAL" and dns_forwarder is None: + dns_forwarder = suggested_forwarder + + samdb_fill = FILL_FULL + if blank: + samdb_fill = FILL_NT4SYNC + elif partitions_only: + samdb_fill = FILL_DRS + + if targetdir is not None: + if not os.path.isdir(targetdir): + os.makedirs(targetdir) + + eadb = True + + if use_xattrs == "yes": + eadb = False + elif use_xattrs == "auto" and use_ntvfs == False: + eadb = False + elif use_ntvfs == False: + raise CommandError("--use-xattrs=no requires --use-ntvfs (not supported for production use). " + "Please re-run with --use-xattrs omitted.") + elif use_xattrs == "auto" and not lp.get("posix:eadb"): + if targetdir: + file = tempfile.NamedTemporaryFile(dir=os.path.abspath(targetdir)) + else: + file = tempfile.NamedTemporaryFile(dir=os.path.abspath(os.path.dirname(lp.get("private dir")))) + try: + try: + samba.ntacls.setntacl(lp, file.name, + "O:S-1-5-32G:S-1-5-32", + "S-1-5-32", + system_session_unix(), + "native") + eadb = False + except Exception: + self.logger.info("You are not root or your system does not support xattr, using tdb backend for attributes. ") + finally: + file.close() + + if eadb: + self.logger.info("not using extended attributes to store ACLs and other metadata. If you intend to use this provision in production, rerun the script as root on a system supporting xattrs.") + + if domain_sid is not None: + 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, + samdb_fill=samdb_fill, realm=realm, domain=domain, + domainguid=domain_guid, domainsid=domain_sid, + hostname=host_name, + hostip=host_ip, hostip6=host_ip6, + sitename=site, ntdsguid=ntds_guid, + invocationid=invocationid, adminpass=adminpass, + krbtgtpass=krbtgtpass, machinepass=machinepass, + dns_backend=dns_backend, dns_forwarder=dns_forwarder, + dnspass=dnspass, root=root, nobody=nobody, + users=users, + serverrole=server_role, dom_for_fun_level=dom_for_fun_level, + useeadb=eadb, next_rid=next_rid, lp=lp, use_ntvfs=use_ntvfs, + use_rfc2307=use_rfc2307, skip_sysvolacl=False, + base_schema=base_schema, + adprep_level=provision_adprep_level, + plaintext_secrets=plaintext_secrets, + backend_store=backend_store, + backend_store_size=backend_store_size) + + except ProvisioningError as e: + raise CommandError("Provision failed", e) + + result.report_logger(self.logger) + + def _get_nameserver_ip(self): + """Grab the nameserver IP address from /etc/resolv.conf.""" + from os import path + RESOLV_CONF = "/etc/resolv.conf" + + if not path.isfile(RESOLV_CONF): + self.logger.warning("Failed to locate %s" % RESOLV_CONF) + return None + + handle = None + try: + handle = open(RESOLV_CONF, 'r') + for line in handle: + if not line.startswith('nameserver'): + continue + # we want the last non-space continuous string of the line + return line.strip().split()[-1] + finally: + if handle is not None: + handle.close() + + self.logger.warning("No nameserver found in %s" % RESOLV_CONF) + + def _adminpass_issue(self, adminpass): + """Returns error string for a bad administrator password, + or None if acceptable""" + if isinstance(adminpass, bytes): + adminpass = adminpass.decode('utf8') + if len(adminpass) < DEFAULT_MIN_PWD_LENGTH: + return "Administrator password does not meet the default minimum" \ + " password length requirement (%d characters)" \ + % DEFAULT_MIN_PWD_LENGTH + elif not samba.check_password_quality(adminpass): + return "Administrator password does not meet the default" \ + " quality standards" + else: + return None