diff options
| author | Jelmer Vernooij <jelmer@samba.org> | 2012-12-28 15:37:14 +0100 |
|---|---|---|
| committer | Andrew Bartlett <abartlet@samba.org> | 2013-03-02 03:57:34 +0100 |
| commit | 87afc3aee1ea593069322a49355dd8780d99e123 (patch) | |
| tree | 8e1ea6678d93b53f21b34c4940b7d5a64e0f5020 /source4/scripting/python/samba/provision | |
| parent | 80fce353e740c793619005ac102ab07fb5e7d280 (diff) | |
| download | samba-87afc3aee1ea593069322a49355dd8780d99e123.tar.gz samba-87afc3aee1ea593069322a49355dd8780d99e123.tar.bz2 samba-87afc3aee1ea593069322a49355dd8780d99e123.zip | |
Move python modules from source4/scripting/python/ to python/.
Reviewed-by: Andrew Bartlett <abartlet@samba.org>
Autobuild-User(master): Andrew Bartlett <abartlet@samba.org>
Autobuild-Date(master): Sat Mar 2 03:57:34 CET 2013 on sn-devel-104
Diffstat (limited to 'source4/scripting/python/samba/provision')
| -rw-r--r-- | source4/scripting/python/samba/provision/__init__.py | 2279 | ||||
| -rw-r--r-- | source4/scripting/python/samba/provision/backend.py | 840 | ||||
| -rw-r--r-- | source4/scripting/python/samba/provision/common.py | 82 | ||||
| -rw-r--r-- | source4/scripting/python/samba/provision/descriptor.py | 359 | ||||
| -rw-r--r-- | source4/scripting/python/samba/provision/sambadns.py | 1135 |
5 files changed, 0 insertions, 4695 deletions
diff --git a/source4/scripting/python/samba/provision/__init__.py b/source4/scripting/python/samba/provision/__init__.py deleted file mode 100644 index aac0ee36b2a..00000000000 --- a/source4/scripting/python/samba/provision/__init__.py +++ /dev/null @@ -1,2279 +0,0 @@ -# Unix SMB/CIFS implementation. -# backend code for provisioning a Samba4 server - -# Copyright (C) Jelmer Vernooij <jelmer@samba.org> 2007-2012 -# Copyright (C) Andrew Bartlett <abartlet@samba.org> 2008-2009 -# Copyright (C) Oliver Liebel <oliver@itc.li> 2008-2009 -# -# Based on the original in EJS: -# Copyright (C) Andrew Tridgell <tridge@samba.org> 2005 -# -# 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 <http://www.gnu.org/licenses/>. -# - -"""Functions for setting up a Samba configuration.""" - -__docformat__ = "restructuredText" - -from base64 import b64encode -import os -import re -import pwd -import grp -import logging -import time -import uuid -import socket -import urllib -import string -import tempfile - -import ldb - -from samba.auth import system_session, admin_session -import samba -from samba.samba3 import smbd, passdb -from samba.samba3 import param as s3param -from samba.dsdb import DS_DOMAIN_FUNCTION_2000 -from samba import ( - Ldb, - MAX_NETBIOS_NAME_LEN, - check_all_substituted, - is_valid_netbios_char, - setup_file, - substitute_var, - valid_netbios_name, - version, - ) -from samba.dcerpc import security, misc -from samba.dcerpc.misc import ( - SEC_CHAN_BDC, - SEC_CHAN_WKSTA, - ) -from samba.dsdb import ( - DS_DOMAIN_FUNCTION_2003, - DS_DOMAIN_FUNCTION_2008_R2, - ENC_ALL_TYPES, - ) -from samba.idmap import IDmapDB -from samba.ms_display_specifiers import read_ms_ldif -from samba.ntacls import setntacl, getntacl, dsacl2fsacl -from samba.ndr import ndr_pack, ndr_unpack -from samba.provision.backend import ( - ExistingBackend, - FDSBackend, - LDBBackend, - OpenLDAPBackend, - ) -from samba.provision.descriptor import ( - get_empty_descriptor, - get_config_descriptor, - get_config_partitions_descriptor, - get_config_sites_descriptor, - get_config_ntds_quotas_descriptor, - get_config_delete_protected1_descriptor, - get_config_delete_protected1wd_descriptor, - get_config_delete_protected2_descriptor, - get_domain_descriptor, - get_domain_infrastructure_descriptor, - get_domain_builtin_descriptor, - get_domain_computers_descriptor, - get_domain_users_descriptor, - get_domain_controllers_descriptor, - get_domain_delete_protected1_descriptor, - get_domain_delete_protected2_descriptor, - get_dns_partition_descriptor, - get_dns_forest_microsoft_dns_descriptor, - get_dns_domain_microsoft_dns_descriptor, - ) -from samba.provision.common import ( - setup_path, - setup_add_ldif, - setup_modify_ldif, - ) -from samba.provision.sambadns import ( - get_dnsadmins_sid, - setup_ad_dns, - create_dns_update_list - ) - -import samba.param -import samba.registry -from samba.schema import Schema -from samba.samdb import SamDB -from samba.dbchecker import dbcheck - - -DEFAULT_POLICY_GUID = "31B2F340-016D-11D2-945F-00C04FB984F9" -DEFAULT_DC_POLICY_GUID = "6AC1786C-016F-11D2-945F-00C04fB984F9" -DEFAULTSITE = "Default-First-Site-Name" -LAST_PROVISION_USN_ATTRIBUTE = "lastProvisionUSN" - - -class ProvisionPaths(object): - - def __init__(self): - self.shareconf = None - self.hklm = None - self.hkcu = None - self.hkcr = None - self.hku = None - self.hkpd = None - self.hkpt = None - self.samdb = None - self.idmapdb = None - self.secrets = None - self.keytab = None - self.dns_keytab = None - self.dns = None - self.winsdb = None - self.private_dir = None - self.state_dir = None - - -class ProvisionNames(object): - - def __init__(self): - self.ncs = None - self.rootdn = None - self.domaindn = None - self.configdn = None - self.schemadn = None - self.dnsforestdn = None - self.dnsdomaindn = None - self.ldapmanagerdn = None - self.dnsdomain = None - self.realm = None - self.netbiosname = None - self.domain = None - self.hostname = None - self.sitename = None - self.smbconf = None - self.name_map = {} - - -def find_provision_key_parameters(samdb, secretsdb, idmapdb, paths, smbconf, - lp): - """Get key provision parameters (realm, domain, ...) from a given provision - - :param samdb: An LDB object connected to the sam.ldb file - :param secretsdb: An LDB object connected to the secrets.ldb file - :param idmapdb: An LDB object connected to the idmap.ldb file - :param paths: A list of path to provision object - :param smbconf: Path to the smb.conf file - :param lp: A LoadParm object - :return: A list of key provision parameters - """ - names = ProvisionNames() - names.adminpass = None - - # NT domain, kerberos realm, root dn, domain dn, domain dns name - names.domain = string.upper(lp.get("workgroup")) - names.realm = lp.get("realm") - names.dnsdomain = names.realm.lower() - basedn = samba.dn_from_dns_name(names.dnsdomain) - names.realm = string.upper(names.realm) - # netbiosname - # Get the netbiosname first (could be obtained from smb.conf in theory) - res = secretsdb.search(expression="(flatname=%s)" % - names.domain,base="CN=Primary Domains", - scope=ldb.SCOPE_SUBTREE, attrs=["sAMAccountName"]) - names.netbiosname = str(res[0]["sAMAccountName"]).replace("$","") - - names.smbconf = smbconf - - # That's a bit simplistic but it's ok as long as we have only 3 - # partitions - current = samdb.search(expression="(objectClass=*)", - base="", scope=ldb.SCOPE_BASE, - attrs=["defaultNamingContext", "schemaNamingContext", - "configurationNamingContext","rootDomainNamingContext", - "namingContexts"]) - - names.configdn = current[0]["configurationNamingContext"] - configdn = str(names.configdn) - names.schemadn = current[0]["schemaNamingContext"] - if not (ldb.Dn(samdb, basedn) == (ldb.Dn(samdb, - current[0]["defaultNamingContext"][0]))): - raise ProvisioningError(("basedn in %s (%s) and from %s (%s)" - "is not the same ..." % (paths.samdb, - str(current[0]["defaultNamingContext"][0]), - paths.smbconf, basedn))) - - names.domaindn=current[0]["defaultNamingContext"] - names.rootdn=current[0]["rootDomainNamingContext"] - names.ncs=current[0]["namingContexts"] - names.dnsforestdn = None - names.dnsdomaindn = None - - for i in range(0, len(names.ncs)): - nc = names.ncs[i] - - dnsforestdn = "DC=ForestDnsZones,%s" % (str(names.rootdn)) - if nc == dnsforestdn: - names.dnsforestdn = dnsforestdn - continue - - dnsdomaindn = "DC=DomainDnsZones,%s" % (str(names.domaindn)) - if nc == dnsdomaindn: - names.dnsdomaindn = dnsdomaindn - continue - - # default site name - res3 = samdb.search(expression="(objectClass=site)", - base="CN=Sites," + configdn, scope=ldb.SCOPE_ONELEVEL, attrs=["cn"]) - names.sitename = str(res3[0]["cn"]) - - # dns hostname and server dn - res4 = samdb.search(expression="(CN=%s)" % names.netbiosname, - base="OU=Domain Controllers,%s" % basedn, - scope=ldb.SCOPE_ONELEVEL, attrs=["dNSHostName"]) - names.hostname = str(res4[0]["dNSHostName"]).replace("." + names.dnsdomain, "") - - server_res = samdb.search(expression="serverReference=%s" % res4[0].dn, - attrs=[], base=configdn) - names.serverdn = server_res[0].dn - - # invocation id/objectguid - res5 = samdb.search(expression="(objectClass=*)", - base="CN=NTDS Settings,%s" % str(names.serverdn), - scope=ldb.SCOPE_BASE, - attrs=["invocationID", "objectGUID"]) - names.invocation = str(ndr_unpack(misc.GUID, res5[0]["invocationId"][0])) - names.ntdsguid = str(ndr_unpack(misc.GUID, res5[0]["objectGUID"][0])) - - # domain guid/sid - res6 = samdb.search(expression="(objectClass=*)", base=basedn, - scope=ldb.SCOPE_BASE, attrs=["objectGUID", - "objectSid","msDS-Behavior-Version" ]) - names.domainguid = str(ndr_unpack(misc.GUID, res6[0]["objectGUID"][0])) - names.domainsid = ndr_unpack( security.dom_sid, res6[0]["objectSid"][0]) - if res6[0].get("msDS-Behavior-Version") is None or \ - int(res6[0]["msDS-Behavior-Version"][0]) < DS_DOMAIN_FUNCTION_2000: - names.domainlevel = DS_DOMAIN_FUNCTION_2000 - else: - names.domainlevel = int(res6[0]["msDS-Behavior-Version"][0]) - - # policy guid - res7 = samdb.search(expression="(displayName=Default Domain Policy)", - base="CN=Policies,CN=System," + basedn, - scope=ldb.SCOPE_ONELEVEL, attrs=["cn","displayName"]) - names.policyid = str(res7[0]["cn"]).replace("{","").replace("}","") - # dc policy guid - res8 = samdb.search(expression="(displayName=Default Domain Controllers" - " Policy)", - base="CN=Policies,CN=System," + basedn, - scope=ldb.SCOPE_ONELEVEL, - attrs=["cn","displayName"]) - if len(res8) == 1: - names.policyid_dc = str(res8[0]["cn"]).replace("{","").replace("}","") - else: - names.policyid_dc = None - - res9 = idmapdb.search(expression="(cn=%s-%s)" % - (str(names.domainsid), security.DOMAIN_RID_ADMINISTRATOR), - attrs=["xidNumber", "type"]) - if len(res9) != 1: - raise ProvisioningError("Unable to find uid/gid for Domain Admins rid (%s-%s" % (str(names.domainsid), security.DOMAIN_RID_ADMINISTRATOR)) - if res9[0]["type"][0] == "ID_TYPE_BOTH": - names.root_gid = res9[0]["xidNumber"][0] - else: - names.root_gid = pwd.getpwuid(int(res9[0]["xidNumber"][0])).pw_gid - - res10 = samdb.search(expression="(samaccountname=dns)", - scope=ldb.SCOPE_SUBTREE, attrs=["dn"], - controls=["search_options:1:2"]) - if (len(res10) > 0): - has_legacy_dns_account = True - else: - has_legacy_dns_account = False - - res11 = samdb.search(expression="(samaccountname=dns-%s)" % names.netbiosname, - scope=ldb.SCOPE_SUBTREE, attrs=["dn"], - controls=["search_options:1:2"]) - if (len(res11) > 0): - has_dns_account = True - else: - has_dns_account = False - - if names.dnsdomaindn is not None: - if has_dns_account: - names.dns_backend = 'BIND9_DLZ' - else: - names.dns_backend = 'SAMBA_INTERNAL' - elif has_dns_account or has_legacy_dns_account: - names.dns_backend = 'BIND9_FLATFILE' - else: - names.dns_backend = 'NONE' - - dns_admins_sid = get_dnsadmins_sid(samdb, names.domaindn) - names.name_map['DnsAdmins'] = str(dns_admins_sid) - - return names - - -def update_provision_usn(samdb, low, high, id, replace=False): - """Update the field provisionUSN in sam.ldb - - This field is used to track range of USN modified by provision and - upgradeprovision. - This value is used afterward by next provision to figure out if - the field have been modified since last provision. - - :param samdb: An LDB object connect to sam.ldb - :param low: The lowest USN modified by this upgrade - :param high: The highest USN modified by this upgrade - :param id: The invocation id of the samba's dc - :param replace: A boolean indicating if the range should replace any - existing one or appended (default) - """ - - tab = [] - if not replace: - entry = samdb.search(base="@PROVISION", - scope=ldb.SCOPE_BASE, - attrs=[LAST_PROVISION_USN_ATTRIBUTE, "dn"]) - for e in entry[0][LAST_PROVISION_USN_ATTRIBUTE]: - if not re.search(';', e): - e = "%s;%s" % (e, id) - tab.append(str(e)) - - tab.append("%s-%s;%s" % (low, high, id)) - delta = ldb.Message() - delta.dn = ldb.Dn(samdb, "@PROVISION") - delta[LAST_PROVISION_USN_ATTRIBUTE] = ldb.MessageElement(tab, - ldb.FLAG_MOD_REPLACE, LAST_PROVISION_USN_ATTRIBUTE) - entry = samdb.search(expression='provisionnerID=*', - base="@PROVISION", scope=ldb.SCOPE_BASE, - attrs=["provisionnerID"]) - if len(entry) == 0 or len(entry[0]) == 0: - delta["provisionnerID"] = ldb.MessageElement(id, ldb.FLAG_MOD_ADD, "provisionnerID") - samdb.modify(delta) - - -def set_provision_usn(samdb, low, high, id): - """Set the field provisionUSN in sam.ldb - This field is used to track range of USN modified by provision and - upgradeprovision. - This value is used afterward by next provision to figure out if - the field have been modified since last provision. - - :param samdb: An LDB object connect to sam.ldb - :param low: The lowest USN modified by this upgrade - :param high: The highest USN modified by this upgrade - :param id: The invocationId of the provision""" - - tab = [] - tab.append("%s-%s;%s" % (low, high, id)) - - delta = ldb.Message() - delta.dn = ldb.Dn(samdb, "@PROVISION") - delta[LAST_PROVISION_USN_ATTRIBUTE] = ldb.MessageElement(tab, - ldb.FLAG_MOD_ADD, LAST_PROVISION_USN_ATTRIBUTE) - samdb.add(delta) - - -def get_max_usn(samdb,basedn): - """ This function return the biggest USN present in the provision - - :param samdb: A LDB object pointing to the sam.ldb - :param basedn: A string containing the base DN of the provision - (ie. DC=foo, DC=bar) - :return: The biggest USN in the provision""" - - res = samdb.search(expression="objectClass=*",base=basedn, - scope=ldb.SCOPE_SUBTREE,attrs=["uSNChanged"], - controls=["search_options:1:2", - "server_sort:1:1:uSNChanged", - "paged_results:1:1"]) - return res[0]["uSNChanged"] - - -def get_last_provision_usn(sam): - """Get USNs ranges modified by a provision or an upgradeprovision - - :param sam: An LDB object pointing to the sam.ldb - :return: a dictionary which keys are invocation id and values are an array - of integer representing the different ranges - """ - try: - entry = sam.search(expression="%s=*" % LAST_PROVISION_USN_ATTRIBUTE, - base="@PROVISION", scope=ldb.SCOPE_BASE, - attrs=[LAST_PROVISION_USN_ATTRIBUTE, "provisionnerID"]) - except ldb.LdbError, (ecode, emsg): - if ecode == ldb.ERR_NO_SUCH_OBJECT: - return None - raise - if len(entry) > 0: - myids = [] - range = {} - p = re.compile(r'-') - if entry[0].get("provisionnerID"): - for e in entry[0]["provisionnerID"]: - myids.append(str(e)) - for r in entry[0][LAST_PROVISION_USN_ATTRIBUTE]: - tab1 = str(r).split(';') - if len(tab1) == 2: - id = tab1[1] - else: - id = "default" - if (len(myids) > 0 and id not in myids): - continue - tab2 = p.split(tab1[0]) - if range.get(id) is None: - range[id] = [] - range[id].append(tab2[0]) - range[id].append(tab2[1]) - return range - else: - return None - - -class ProvisionResult(object): - """Result of a provision. - - :ivar server_role: The server role - :ivar paths: ProvisionPaths instance - :ivar domaindn: The domain dn, as string - """ - - def __init__(self): - self.server_role = None - self.paths = None - self.domaindn = None - self.lp = None - self.samdb = None - self.idmap = None - self.names = None - self.domainsid = None - self.adminpass_generated = None - self.adminpass = None - self.backend_result = None - - def report_logger(self, logger): - """Report this provision result to a logger.""" - logger.info( - "Once the above files are installed, your Samba4 server will " - "be ready to use") - if self.adminpass_generated: - logger.info("Admin password: %s", self.adminpass) - logger.info("Server Role: %s", self.server_role) - logger.info("Hostname: %s", self.names.hostname) - logger.info("NetBIOS Domain: %s", self.names.domain) - logger.info("DNS Domain: %s", self.names.dnsdomain) - logger.info("DOMAIN SID: %s", self.domainsid) - - if self.backend_result: - self.backend_result.report_logger(logger) - - -def check_install(lp, session_info, credentials): - """Check whether the current install seems ok. - - :param lp: Loadparm context - :param session_info: Session information - :param credentials: Credentials - """ - if lp.get("realm") == "": - raise Exception("Realm empty") - samdb = Ldb(lp.samdb_url(), session_info=session_info, - credentials=credentials, lp=lp) - if len(samdb.search("(cn=Administrator)")) != 1: - raise ProvisioningError("No administrator account found") - - -def findnss(nssfn, names): - """Find a user or group from a list of possibilities. - - :param nssfn: NSS Function to try (should raise KeyError if not found) - :param names: Names to check. - :return: Value return by first names list. - """ - for name in names: - try: - return nssfn(name) - except KeyError: - pass - raise KeyError("Unable to find user/group in %r" % names) - - -findnss_uid = lambda names: findnss(pwd.getpwnam, names)[2] -findnss_gid = lambda names: findnss(grp.getgrnam, names)[2] - - -def provision_paths_from_lp(lp, dnsdomain): - """Set the default paths for provisioning. - - :param lp: Loadparm context. - :param dnsdomain: DNS Domain name - """ - paths = ProvisionPaths() - paths.private_dir = lp.get("private dir") - paths.state_dir = lp.get("state directory") - - # This is stored without path prefix for the "privateKeytab" attribute in - # "secrets_dns.ldif". - paths.dns_keytab = "dns.keytab" - paths.keytab = "secrets.keytab" - - paths.shareconf = os.path.join(paths.private_dir, "share.ldb") - paths.samdb = os.path.join(paths.private_dir, "sam.ldb") - paths.idmapdb = os.path.join(paths.private_dir, "idmap.ldb") - paths.secrets = os.path.join(paths.private_dir, "secrets.ldb") - paths.privilege = os.path.join(paths.private_dir, "privilege.ldb") - paths.dns = os.path.join(paths.private_dir, "dns", dnsdomain + ".zone") - paths.dns_update_list = os.path.join(paths.private_dir, "dns_update_list") - paths.spn_update_list = os.path.join(paths.private_dir, "spn_update_list") - paths.namedconf = os.path.join(paths.private_dir, "named.conf") - paths.namedconf_update = os.path.join(paths.private_dir, "named.conf.update") - paths.namedtxt = os.path.join(paths.private_dir, "named.txt") - paths.krb5conf = os.path.join(paths.private_dir, "krb5.conf") - paths.winsdb = os.path.join(paths.private_dir, "wins.ldb") - paths.s4_ldapi_path = os.path.join(paths.private_dir, "ldapi") - paths.hklm = "hklm.ldb" - paths.hkcr = "hkcr.ldb" - paths.hkcu = "hkcu.ldb" - paths.hku = "hku.ldb" - paths.hkpd = "hkpd.ldb" - paths.hkpt = "hkpt.ldb" - paths.sysvol = lp.get("path", "sysvol") - paths.netlogon = lp.get("path", "netlogon") - paths.smbconf = lp.configfile - return paths - - -def determine_netbios_name(hostname): - """Determine a netbios name from a hostname.""" - # remove forbidden chars and force the length to be <16 - netbiosname = "".join([x for x in hostname if is_valid_netbios_char(x)]) - return netbiosname[:MAX_NETBIOS_NAME_LEN].upper() - - -def guess_names(lp=None, hostname=None, domain=None, dnsdomain=None, - serverrole=None, rootdn=None, domaindn=None, configdn=None, - schemadn=None, serverdn=None, sitename=None): - """Guess configuration settings to use.""" - - if hostname is None: - hostname = socket.gethostname().split(".")[0] - - netbiosname = lp.get("netbios name") - if netbiosname is None: - netbiosname = determine_netbios_name(hostname) - netbiosname = netbiosname.upper() - if not valid_netbios_name(netbiosname): - raise InvalidNetbiosName(netbiosname) - - if dnsdomain is None: - dnsdomain = lp.get("realm") - if dnsdomain is None or dnsdomain == "": - raise ProvisioningError("guess_names: 'realm' not specified in supplied %s!", lp.configfile) - - dnsdomain = dnsdomain.lower() - - if serverrole is None: - serverrole = lp.get("server role") - if serverrole is None: - raise ProvisioningError("guess_names: 'server role' not specified in supplied %s!" % lp.configfile) - - serverrole = serverrole.lower() - - realm = dnsdomain.upper() - - if lp.get("realm") == "": - raise ProvisioningError("guess_names: 'realm =' was not specified in supplied %s. Please remove the smb.conf file and let provision generate it" % lp.configfile) - - if lp.get("realm").upper() != realm: - raise ProvisioningError("guess_names: 'realm=%s' in %s must match chosen realm '%s'! Please remove the smb.conf file and let provision generate it" % (lp.get("realm").upper(), realm, lp.configfile)) - - if lp.get("server role").lower() != serverrole: - raise ProvisioningError("guess_names: 'server role=%s' in %s must match chosen server role '%s'! Please remove the smb.conf file and let provision generate it" % (lp.get("server role"), lp.configfile, serverrole)) - - if serverrole == "active directory domain controller": - if domain is None: - # This will, for better or worse, default to 'WORKGROUP' - domain = lp.get("workgroup") - domain = domain.upper() - - if lp.get("workgroup").upper() != domain: - raise ProvisioningError("guess_names: Workgroup '%s' in smb.conf must match chosen domain '%s'! Please remove the %s file and let provision generate it" % (lp.get("workgroup").upper(), domain, lp.configfile)) - - if domaindn is None: - domaindn = samba.dn_from_dns_name(dnsdomain) - - if domain == netbiosname: - raise ProvisioningError("guess_names: Domain '%s' must not be equal to short host name '%s'!" % (domain, netbiosname)) - else: - domain = netbiosname - if domaindn is None: - domaindn = "DC=" + netbiosname - - if not valid_netbios_name(domain): - raise InvalidNetbiosName(domain) - - if hostname.upper() == realm: - raise ProvisioningError("guess_names: Realm '%s' must not be equal to hostname '%s'!" % (realm, hostname)) - if netbiosname.upper() == realm: - raise ProvisioningError("guess_names: Realm '%s' must not be equal to netbios hostname '%s'!" % (realm, netbiosname)) - if domain == realm: - raise ProvisioningError("guess_names: Realm '%s' must not be equal to short domain name '%s'!" % (realm, domain)) - - if rootdn is None: - rootdn = domaindn - - if configdn is None: - configdn = "CN=Configuration," + rootdn - if schemadn is None: - schemadn = "CN=Schema," + configdn - - if sitename is None: - sitename = DEFAULTSITE - - names = ProvisionNames() - names.rootdn = rootdn - names.domaindn = domaindn - names.configdn = configdn - names.schemadn = schemadn - names.ldapmanagerdn = "CN=Manager," + rootdn - names.dnsdomain = dnsdomain - names.domain = domain - names.realm = realm - names.netbiosname = netbiosname - names.hostname = hostname - names.sitename = sitename - names.serverdn = "CN=%s,CN=Servers,CN=%s,CN=Sites,%s" % ( - netbiosname, sitename, configdn) - - return names - - -def make_smbconf(smbconf, hostname, domain, realm, targetdir, - serverrole=None, eadb=False, use_ntvfs=False, lp=None, - global_param=None): - """Create a new smb.conf file based on a couple of basic settings. - """ - assert smbconf is not None - - if hostname is None: - hostname = socket.gethostname().split(".")[0] - - netbiosname = determine_netbios_name(hostname) - - if serverrole is None: - serverrole = "standalone server" - - assert domain is not None - domain = domain.upper() - - assert realm is not None - realm = realm.upper() - - global_settings = { - "netbios name": netbiosname, - "workgroup": domain, - "realm": realm, - "server role": serverrole, - } - - if lp is None: - lp = samba.param.LoadParm() - #Load non-existent file - if os.path.exists(smbconf): - lp.load(smbconf) - - if global_param is not None: - for ent in global_param: - if global_param[ent] is not None: - global_settings[ent] = " ".join(global_param[ent]) - - if targetdir is not None: - global_settings["private dir"] = os.path.abspath(os.path.join(targetdir, "private")) - global_settings["lock dir"] = os.path.abspath(targetdir) - global_settings["state directory"] = os.path.abspath(os.path.join(targetdir, "state")) - global_settings["cache directory"] = os.path.abspath(os.path.join(targetdir, "cache")) - - lp.set("lock dir", os.path.abspath(targetdir)) - lp.set("state directory", global_settings["state directory"]) - lp.set("cache directory", global_settings["cache directory"]) - - if eadb: - if use_ntvfs and not lp.get("posix:eadb"): - if targetdir is not None: - privdir = os.path.join(targetdir, "private") - else: - privdir = lp.get("private dir") - lp.set("posix:eadb", os.path.abspath(os.path.join(privdir, "eadb.tdb"))) - elif not use_ntvfs and not lp.get("xattr_tdb:file"): - if targetdir is not None: - statedir = os.path.join(targetdir, "state") - else: - statedir = lp.get("state directory") - lp.set("xattr_tdb:file", os.path.abspath(os.path.join(statedir, "xattr.tdb"))) - - shares = {} - if serverrole == "active directory domain controller": - shares["sysvol"] = os.path.join(lp.get("state directory"), "sysvol") - shares["netlogon"] = os.path.join(shares["sysvol"], realm.lower(), - "scripts") - else: - global_settings["passdb backend"] = "samba_dsdb" - - f = open(smbconf, 'w') - try: - f.write("[globals]\n") - for key, val in global_settings.iteritems(): - f.write("\t%s = %s\n" % (key, val)) - f.write("\n") - - for name, path in shares.iteritems(): - f.write("[%s]\n" % name) - f.write("\tpath = %s\n" % path) - f.write("\tread only = no\n") - f.write("\n") - finally: - f.close() - # reload the smb.conf - lp.load(smbconf) - - # and dump it without any values that are the default - # this ensures that any smb.conf parameters that were set - # on the provision/join command line are set in the resulting smb.conf - f = open(smbconf, mode='w') - try: - lp.dump(f, False) - finally: - f.close() - - -def setup_name_mappings(idmap, sid, root_uid, nobody_uid, - users_gid, root_gid): - """setup reasonable name mappings for sam names to unix names. - - :param samdb: SamDB object. - :param idmap: IDmap db object. - :param sid: The domain sid. - :param domaindn: The domain DN. - :param root_uid: uid of the UNIX root user. - :param nobody_uid: uid of the UNIX nobody user. - :param users_gid: gid of the UNIX users group. - :param root_gid: gid of the UNIX root group. - """ - idmap.setup_name_mapping("S-1-5-7", idmap.TYPE_UID, nobody_uid) - - idmap.setup_name_mapping(sid + "-500", idmap.TYPE_UID, root_uid) - idmap.setup_name_mapping(sid + "-513", idmap.TYPE_GID, users_gid) - - -def setup_samdb_partitions(samdb_path, logger, lp, session_info, - provision_backend, names, schema, serverrole, - erase=False): - """Setup the partitions for the SAM database. - - Alternatively, provision() may call this, and then populate the database. - - :note: This will wipe the Sam Database! - - :note: This function always removes the local SAM LDB file. The erase - parameter controls whether to erase the existing data, which - may not be stored locally but in LDAP. - - """ - assert session_info is not None - - # We use options=["modules:"] to stop the modules loading - we - # just want to wipe and re-initialise the database, not start it up - - try: - os.unlink(samdb_path) - except OSError: - pass - - samdb = Ldb(url=samdb_path, session_info=session_info, - lp=lp, options=["modules:"]) - - ldap_backend_line = "# No LDAP backend" - if provision_backend.type != "ldb": - ldap_backend_line = "ldapBackend: %s" % provision_backend.ldap_uri - - 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 - }) - - - setup_add_ldif(samdb, setup_path("provision_init.ldif"), { - "BACKEND_TYPE": provision_backend.type, - "SERVER_ROLE": serverrole - }) - - logger.info("Setting up sam.ldb rootDSE") - setup_samdb_rootdse(samdb, names) - except: - samdb.transaction_cancel() - raise - else: - samdb.transaction_commit() - - -def secretsdb_self_join(secretsdb, domain, - netbiosname, machinepass, domainsid=None, - realm=None, dnsdomain=None, - keytab_path=None, - key_version_number=1, - secure_channel_type=SEC_CHAN_WKSTA): - """Add domain join-specific bits to a secrets database. - - :param secretsdb: Ldb Handle to the secrets database - :param machinepass: Machine password - """ - attrs = ["whenChanged", - "secret", - "priorSecret", - "priorChanged", - "krb5Keytab", - "privateKeytab"] - - if realm is not None: - if dnsdomain is None: - dnsdomain = realm.lower() - dnsname = '%s.%s' % (netbiosname.lower(), dnsdomain.lower()) - else: - dnsname = None - shortname = netbiosname.lower() - - # We don't need to set msg["flatname"] here, because rdn_name will handle - # it, and it causes problems for modifies anyway - msg = ldb.Message(ldb.Dn(secretsdb, "flatname=%s,cn=Primary Domains" % domain)) - msg["secureChannelType"] = [str(secure_channel_type)] - msg["objectClass"] = ["top", "primaryDomain"] - if dnsname is not None: - msg["objectClass"] = ["top", "primaryDomain", "kerberosSecret"] - msg["realm"] = [realm] - msg["saltPrincipal"] = ["host/%s@%s" % (dnsname, realm.upper())] - msg["msDS-KeyVersionNumber"] = [str(key_version_number)] - msg["privateKeytab"] = ["secrets.keytab"] - - msg["secret"] = [machinepass] - msg["samAccountName"] = ["%s$" % netbiosname] - msg["secureChannelType"] = [str(secure_channel_type)] - if domainsid is not None: - msg["objectSid"] = [ndr_pack(domainsid)] - - # This complex expression tries to ensure that we don't have more - # than one record for this SID, realm or netbios domain at a time, - # but we don't delete the old record that we are about to modify, - # because that would delete the keytab and previous password. - res = secretsdb.search(base="cn=Primary Domains", attrs=attrs, |
