X-Git-Url: http://git.samba.org/?a=blobdiff_plain;f=source4%2Fscripting%2Fpython%2Fsamba%2Fprovision.py;h=fdf1fe9e61d0e316134c03ad2c773d7fb5aa3256;hb=aaca10b3e13d5a6119d7f47bc21bbf0cac3efb96;hp=065677fa68c2138a467e73ee9865c767f6020578;hpb=89f5df6fa7cca1aaec81e29b8777bab5b4068003;p=samba.git diff --git a/source4/scripting/python/samba/provision.py b/source4/scripting/python/samba/provision.py index 065677fa68c..fdf1fe9e61d 100644 --- a/source4/scripting/python/samba/provision.py +++ b/source4/scripting/python/samba/provision.py @@ -44,23 +44,20 @@ from credentials import Credentials, DONT_USE_KERBEROS from auth import system_session, admin_session from samba import version, Ldb, substitute_var, valid_netbios_name from samba import check_all_substituted -from samba import DS_DOMAIN_FUNCTION_2000, DS_DC_FUNCTION_2008_R2 +from samba import DS_DOMAIN_FUNCTION_2003, DS_DOMAIN_FUNCTION_2008, DS_DC_FUNCTION_2008 from samba.samdb import SamDB from samba.idmap import IDmapDB from samba.dcerpc import security +from samba.ndr import ndr_pack import urllib from ldb import SCOPE_SUBTREE, SCOPE_ONELEVEL, SCOPE_BASE, LdbError, timestring from ms_schema import read_ms_schema from ms_display_specifiers import read_ms_ldif from signal import SIGTERM +from dcerpc.misc import SEC_CHAN_BDC, SEC_CHAN_WKSTA __docformat__ = "restructuredText" - -class ProvisioningError(ValueError): - pass - - def find_setup_dir(): """Find the setup directory used by provision.""" dirname = os.path.dirname(__file__) @@ -76,9 +73,47 @@ def find_setup_dir(): return ret raise Exception("Unable to find setup directory.") +def get_schema_descriptor(domain_sid): + sddl = "O:SAG:SAD:(A;CI;RPLCLORC;;;AU)(A;CI;RPWPCRCCLCLORCWOWDSW;;;SA)" \ + "(A;CI;RPWPCRCCDCLCLORCWOWDSDDTSW;;;SY)" \ + "(OA;;CR;1131f6ad-9c07-11d1-f79f-00c04fc2dcd2;;ED)" \ + "(OA;;CR;89e95b76-444d-4c62-991a-0facbeda640c;;ED)" \ + "(OA;;CR;1131f6ad-9c07-11d1-f79f-00c04fc2dcd2;;BA)" \ + "(OA;;CR;89e95b76-444d-4c62-991a-0facbeda640c;;BA)" \ + "S:(AU;SA;WPCCDCWOWDSDDTSW;;;WD)" \ + "(AU;CISA;WP;;;WD)(AU;SA;CR;;;BA)" \ + "(AU;SA;CR;;;DU)(OU;SA;CR;e12b56b6-0a95-11d1-adbb-00c04fd8d5cd;;WD)" \ + "(OU;SA;CR;45ec5156-db7e-47bb-b53f-dbeb2d03c40f;;WD)" + sec = security.descriptor.from_sddl(sddl, domain_sid) + return b64encode(ndr_pack(sec)) + +def get_config_descriptor(domain_sid): + sddl = "O:EAG:EAD:(OA;;CR;1131f6aa-9c07-11d1-f79f-00c04fc2dcd2;;ED)" \ + "(OA;;CR;1131f6ab-9c07-11d1-f79f-00c04fc2dcd2;;ED)" \ + "(OA;;CR;1131f6ac-9c07-11d1-f79f-00c04fc2dcd2;;ED)" \ + "(OA;;CR;1131f6aa-9c07-11d1-f79f-00c04fc2dcd2;;BA)" \ + "(OA;;CR;1131f6ab-9c07-11d1-f79f-00c04fc2dcd2;;BA)" \ + "(OA;;CR;1131f6ac-9c07-11d1-f79f-00c04fc2dcd2;;BA)" \ + "(A;;RPLCLORC;;;AU)(A;CI;RPWPCRCCDCLCLORCWOWDSDDTSW;;;EA)" \ + "(A;;RPWPCRCCDCLCLORCWOWDSDDTSW;;;SY)(A;CIIO;RPWPCRCCLCLORCWOWDSDSW;;;DA)" \ + "(OA;;CR;1131f6ad-9c07-11d1-f79f-00c04fc2dcd2;;ED)" \ + "(OA;;CR;89e95b76-444d-4c62-991a-0facbeda640c;;ED)" \ + "(OA;;CR;1131f6ad-9c07-11d1-f79f-00c04fc2dcd2;;BA)" \ + "(OA;;CR;89e95b76-444d-4c62-991a-0facbeda640c;;BA)" \ + "(OA;;CR;1131f6aa-9c07-11d1-f79f-00c04fc2dcd2;;S-1-5-21-3191434175-1265308384-3577286990-498)" \ + "S:(AU;SA;WPWOWD;;;WD)(AU;SA;CR;;;BA)(AU;SA;CR;;;DU)" \ + "(OU;SA;CR;45ec5156-db7e-47bb-b53f-dbeb2d03c40f;;WD)" + sec = security.descriptor.from_sddl(sddl, domain_sid) + return b64encode(ndr_pack(sec)) + DEFAULTSITE = "Default-First-Site-Name" +# Exception classes + +class ProvisioningError(Exception): + """A generic provision error.""" + class InvalidNetbiosName(Exception): """A specified name was not a valid NetBIOS name.""" def __init__(self, name): @@ -109,6 +144,11 @@ class ProvisionPaths(object): self.fedoradsinf = None self.fedoradspartitions = None self.fedoradssasl = None + self.fedoradspam = None + self.fedoradsrefint = None + self.fedoradslinkedattributes = None + self.fedoradsindex = None + self.fedoradssamba = None self.olmmron = None self.olmmrserveridsconf = None self.olmmrsyncreplconf = None @@ -142,7 +182,7 @@ class ProvisionResult(object): self.samdb = None class Schema(object): - def __init__(self, setup_path, schemadn=None, + def __init__(self, setup_path, domain_sid, schemadn=None, serverdn=None, sambadn=None, ldap_backend_type=None): """Load schema for the SamDB from the AD schema files and samba4_schema.ldif @@ -165,13 +205,18 @@ class Schema(object): {"SCHEMADN": schemadn, "SERVERDN": serverdn, }) + + descr = get_schema_descriptor(domain_sid) self.schema_dn_add = read_and_sub_file(setup_path("provision_schema_basedn.ldif"), - {"SCHEMADN": schemadn + {"SCHEMADN": schemadn, + "DESCRIPTOR": descr }) prefixmap = open(setup_path("prefixMap.txt"), 'r').read() prefixmap = b64encode(prefixmap) + + # We don't actually add this ldif, just parse it prefixmap_ldif = "dn: cn=schema\nprefixMap:: %s\n\n" % prefixmap self.ldb.set_schema_from_ldif(prefixmap_ldif, self.schema_data) @@ -250,17 +295,17 @@ def read_and_sub_file(file, subst_vars): return data -def setup_add_ldif(ldb, ldif_path, subst_vars=None): +def setup_add_ldif(ldb, ldif_path, subst_vars=None,controls=["relax:0"]): """Setup a ldb in the private dir. :param ldb: LDB file to import data into :param ldif_path: Path of the LDIF file to load :param subst_vars: Optional variables to subsitute in LDIF. + :param nocontrols: Optional list of controls, can be None for no controls """ assert isinstance(ldif_path, str) - data = read_and_sub_file(ldif_path, subst_vars) - ldb.add_ldif(data) + ldb.add_ldif(data,controls) def setup_modify_ldif(ldb, ldif_path, subst_vars=None): @@ -294,7 +339,7 @@ def setup_ldb(ldb, ldif_path, subst_vars): ldb.transaction_commit() -def setup_file(template, fname, subst_vars): +def setup_file(template, fname, subst_vars=None): """Setup a file in the private dir. :param template: Path of the template file. @@ -318,7 +363,6 @@ def provision_paths_from_lp(lp, dnsdomain): """ paths = ProvisionPaths() paths.private_dir = lp.get("private dir") - paths.keytab = "secrets.keytab" paths.dns_keytab = "dns.keytab" paths.shareconf = os.path.join(paths.private_dir, "share.ldb") @@ -349,8 +393,16 @@ def provision_paths_from_lp(lp, dnsdomain): "fedorads-partitions.ldif") paths.fedoradssasl = os.path.join(paths.ldapdir, "fedorads-sasl.ldif") + paths.fedoradspam = os.path.join(paths.ldapdir, + "fedorads-pam.ldif") + paths.fedoradsrefint = os.path.join(paths.ldapdir, + "fedorads-refint.ldif") + paths.fedoradslinkedattributes = os.path.join(paths.ldapdir, + "fedorads-linked-attributes.ldif") + paths.fedoradsindex = os.path.join(paths.ldapdir, + "fedorads-index.ldif") paths.fedoradssamba = os.path.join(paths.ldapdir, - "fedorads-samba.ldif") + "fedorads-samba.ldif") paths.olmmrserveridsconf = os.path.join(paths.ldapdir, "mmr_serverids.conf") paths.olmmrsyncreplconf = os.path.join(paths.ldapdir, @@ -390,7 +442,7 @@ def guess_names(lp=None, hostname=None, domain=None, dnsdomain=None, hostname = hostname.lower() if dnsdomain is None: - dnsdomain = lp.get("realm") + dnsdomain = lp.get("realm").lower() if serverrole is None: serverrole = lp.get("server role") @@ -402,8 +454,6 @@ def guess_names(lp=None, hostname=None, domain=None, dnsdomain=None, raise Exception("realm '%s' in %s must match chosen realm '%s'" % (lp.get("realm"), lp.configfile, realm)) - dnsdomain = dnsdomain.lower() - if serverrole == "domain controller": if domain is None: domain = lp.get("workgroup") @@ -415,20 +465,21 @@ def guess_names(lp=None, hostname=None, domain=None, dnsdomain=None, else: domain = netbiosname if domaindn is None: - domaindn = "CN=" + netbiosname + domaindn = "DC=" + netbiosname assert domain is not None domain = domain.upper() + if not valid_netbios_name(domain): raise InvalidNetbiosName(domain) - if netbiosname.upper() == realm.upper(): + if netbiosname.upper() == realm: raise Exception("realm %s must not be equal to netbios domain name %s", realm, netbiosname) - if hostname.upper() == realm.upper(): + if hostname.upper() == realm: raise Exception("realm %s must not be equal to hostname %s", realm, hostname) - if domain.upper() == realm.upper(): + if domain.upper() == realm: raise Exception("realm %s must not be equal to domain name %s", realm, domain) if rootdn is None: @@ -575,7 +626,10 @@ def setup_samdb_partitions(samdb_path, setup_path, message, lp, session_info, # module when expanding the objectclass list) # - partition must be last # - each partition has its own module list then - modules_list = ["rootdse", + modules_list = ["resolve_oids", + "rootdse", + "lazy_commit", + "acl", "paged_results", "ranged_results", "anr", @@ -589,7 +643,8 @@ def setup_samdb_partitions(samdb_path, setup_path, message, lp, session_info, "samldb", "password_hash", "operational", - "kludge_acl"] + "kludge_acl", + "instancetype"] tdb_modules_list = [ "subtree_rename", "subtree_delete", @@ -609,7 +664,7 @@ def setup_samdb_partitions(samdb_path, setup_path, message, lp, session_info, if ldap_backend.ldap_backend_type == "fedora-ds": backend_modules = ["nsuniqueid", "paged_searches"] # We can handle linked attributes here, as we don't have directory-side subtree operations - tdb_modules_list = ["linked_attributes", "extended_dn_out_dereference"] + tdb_modules_list = ["extended_dn_out_dereference"] elif ldap_backend.ldap_backend_type == "openldap": backend_modules = ["entryuuid", "paged_searches"] # OpenLDAP handles subtree renames, so we don't want to do any of these things @@ -637,9 +692,9 @@ def setup_samdb_partitions(samdb_path, setup_path, message, lp, session_info, "CONFIGDN_LDB": configdn_ldb, "DOMAINDN": names.domaindn, "DOMAINDN_LDB": domaindn_ldb, - "SCHEMADN_MOD": "schema_fsmo,instancetype", - "CONFIGDN_MOD": "naming_fsmo,instancetype", - "DOMAINDN_MOD": "pdc_fsmo,instancetype", + "SCHEMADN_MOD": "schema_fsmo", + "CONFIGDN_MOD": "naming_fsmo", + "DOMAINDN_MOD": "pdc_fsmo", "MODULES_LIST": ",".join(modules_list), "TDB_MODULES_LIST": tdb_modules_list_as_string, "MODULES_LIST2": ",".join(modules_list2), @@ -657,26 +712,83 @@ def setup_samdb_partitions(samdb_path, setup_path, message, lp, session_info, samdb.transaction_commit() +def secretsdb_self_join(secretsdb, domain, + netbiosname, domainsid, machinepass, + 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"] + + + msg = ldb.Message(ldb.Dn(secretsdb, "flatname=%s,cn=Primary Domains" % domain)); + msg["secureChannelType"] = str(secure_channel_type) + msg["flatname"] = [domain] + msg["objectClass"] = ["top", "primaryDomain"] + if realm is not None: + if dnsdomain is None: + dnsdomain = realm.lower() + msg["objectClass"] = ["top", "primaryDomain", "kerberosSecret"] + msg["realm"] = realm + msg["saltPrincipal"] = "host/%s.%s@%s" % (netbiosname.lower(), dnsdomain.lower(), 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)] + msg["objectSid"] = [ndr_pack(domainsid)] + + res = secretsdb.search(base="cn=Primary Domains", + attrs=attrs, + expression=("(&(|(flatname=%s)(realm=%s)(objectSid=%s))(objectclass=primaryDomain))" % (domain, realm, str(domainsid))), + scope=SCOPE_ONELEVEL) + + for del_msg in res: + if del_msg.dn is not msg.dn: + secretsdb.delete(del_msg.dn) + + res = secretsdb.search(base=msg.dn, attrs=attrs, scope=SCOPE_BASE) + + if len(res) == 1: + msg["priorSecret"] = res[0]["secret"] + msg["priorWhenChanged"] = res[0]["whenChanged"] + + if res["privateKeytab"] is not None: + msg["privateKeytab"] = res[0]["privateKeytab"] + + if res["krb5Keytab"] is not None: + msg["krb5Keytab"] = res[0]["krb5Keytab"] + + for el in msg: + el.set_flags(ldb.FLAG_MOD_REPLACE) + secretsdb.modify(msg) + else: + secretsdb.add(msg) -def secretsdb_become_dc(secretsdb, setup_path, domain, realm, dnsdomain, - netbiosname, domainsid, keytab_path, samdb_url, - dns_keytab_path, dnspass, machinepass): - """Add DC-specific bits to a secrets database. +def secretsdb_setup_dns(secretsdb, setup_path, realm, dnsdomain, + dns_keytab_path, dnspass): + """Add DNS specific bits to a secrets database. :param secretsdb: Ldb Handle to the secrets database :param setup_path: Setup path function :param machinepass: Machine password """ - setup_ldb(secretsdb, setup_path("secrets_dc.ldif"), { - "MACHINEPASS_B64": b64encode(machinepass), - "DOMAIN": domain, + setup_ldb(secretsdb, setup_path("secrets_dns.ldif"), { "REALM": realm, "DNSDOMAIN": dnsdomain, - "DOMAINSID": str(domainsid), - "SECRETS_KEYTAB": keytab_path, - "NETBIOSNAME": netbiosname, - "SAM_LDB": samdb_url, "DNS_KEYTAB": dns_keytab_path, "DNSPASS_B64": b64encode(dnspass), }) @@ -700,6 +812,7 @@ def setup_secretsdb(path, setup_path, session_info, credentials, lp): secrets_ldb.load_ldif_file_add(setup_path("secrets_init.ldif")) secrets_ldb = Ldb(path, session_info=session_info, credentials=credentials, lp=lp) + secrets_ldb.transaction_start() secrets_ldb.load_ldif_file_add(setup_path("secrets.ldif")) if credentials is not None and credentials.authentication_requested(): @@ -777,9 +890,14 @@ def setup_samdb_rootdse(samdb, setup_path, names): def setup_self_join(samdb, names, machinepass, dnspass, domainsid, invocationid, setup_path, - policyguid, policyguid_dc, domainControllerFunctionality): + policyguid, policyguid_dc, domainControllerFunctionality, + ntdsguid): """Join a host to its own domain.""" assert isinstance(invocationid, str) + if ntdsguid is not None: + ntdsguid_line = "objectGUID: %s\n"%ntdsguid + else: + ntdsguid_line = "" setup_add_ldif(samdb, setup_path("provision_self_join.ldif"), { "CONFIGDN": names.configdn, "SCHEMADN": names.schemadn, @@ -795,6 +913,7 @@ def setup_self_join(samdb, names, "DOMAIN": names.domain, "DNSDOMAIN": names.dnsdomain, "SAMBA_VERSION_STRING": version, + "NTDSGUID": ntdsguid_line, "DOMAIN_CONTROLLER_FUNCTIONALITY": str(domainControllerFunctionality)}) setup_add_ldif(samdb, setup_path("provision_group_policy.ldif"), { @@ -828,25 +947,37 @@ def setup_samdb(path, setup_path, session_info, credentials, lp, names, message, domainsid, domainguid, policyguid, policyguid_dc, fill, adminpass, krbtgtpass, - machinepass, invocationid, dnspass, - serverrole, schema=None, ldap_backend=None): + machinepass, invocationid, dnspass, ntdsguid, + serverrole, dom_for_fun_level=None, + schema=None, ldap_backend=None): """Setup a complete SAM Database. :note: This will wipe the main SAM database file! """ - domainFunctionality = DS_DOMAIN_FUNCTION_2000 - forestFunctionality = DS_DOMAIN_FUNCTION_2000 - domainControllerFunctionality = DS_DC_FUNCTION_2008_R2 + # ATTENTION: Do NOT change these default values without discussion with the + # team and/or release manager. They have a big impact on the whole program! + domainControllerFunctionality = DS_DC_FUNCTION_2008 + + if dom_for_fun_level is None: + dom_for_fun_level = DS_DOMAIN_FUNCTION_2003 + if dom_for_fun_level < DS_DOMAIN_FUNCTION_2003: + raise ProvisioningError("You want to run SAMBA 4 on a domain and forest function level lower than Windows 2003 (Native). This isn't supported!") + + if dom_for_fun_level > domainControllerFunctionality: + raise ProvisioningError("You want to run SAMBA 4 on a domain and forest function level which itself is higher than its actual DC function level (2008). This won't work!") + + domainFunctionality = dom_for_fun_level + forestFunctionality = dom_for_fun_level # Also wipes the database setup_samdb_partitions(path, setup_path, message=message, lp=lp, credentials=credentials, session_info=session_info, - names=names, - ldap_backend=ldap_backend, serverrole=serverrole) + names=names, ldap_backend=ldap_backend, + serverrole=serverrole) if (schema == None): - schema = Schema(setup_path, schemadn=names.schemadn, serverdn=names.serverdn, + schema = Schema(setup_path, domainsid, schemadn=names.schemadn, serverdn=names.serverdn, sambadn=names.sambadn, ldap_backend_type=ldap_backend.ldap_backend_type) # Load the database, but importantly, use Ldb not SamDB as we don't want to load the global schema @@ -891,28 +1022,22 @@ def setup_samdb(path, setup_path, session_info, credentials, lp, samdb.set_invocation_id(invocationid) message("Adding DomainDN: %s" % names.domaindn) - if serverrole == "domain controller": - domain_oc = "domainDNS" - else: - domain_oc = "samba4LocalDomain" #impersonate domain admin admin_session_info = admin_session(lp, str(domainsid)) samdb.set_session_info(admin_session_info) - + if domainguid is not None: + domainguid_line = "objectGUID: %s\n-" % domainguid + else: + domainguid_line = "" setup_add_ldif(samdb, setup_path("provision_basedn.ldif"), { "DOMAINDN": names.domaindn, - "DOMAIN_OC": domain_oc + "DOMAINGUID": domainguid_line }) - message("Modifying DomainDN: " + names.domaindn + "") - if domainguid is not None: - domainguid_mod = "replace: objectGUID\nobjectGUID: %s\n-" % domainguid - else: - domainguid_mod = "" setup_modify_ldif(samdb, setup_path("provision_basedn_modify.ldif"), { - "CREATTIME": str(int(time.time()) * 1e7), # seconds -> ticks + "CREATTIME": str(int(time.time() * 1e7)), # seconds -> ticks "DOMAINSID": str(domainsid), "SCHEMADN": names.schemadn, "NETBIOSNAME": names.netbiosname, @@ -921,14 +1046,15 @@ def setup_samdb(path, setup_path, session_info, credentials, lp, "SERVERDN": names.serverdn, "POLICYGUID": policyguid, "DOMAINDN": names.domaindn, - "DOMAINGUID_MOD": domainguid_mod, "DOMAIN_FUNCTIONALITY": str(domainFunctionality), "SAMBA_VERSION_STRING": version }) message("Adding configuration container") + descr = get_config_descriptor(domainsid); setup_add_ldif(samdb, setup_path("provision_configuration_basedn.ldif"), { "CONFIGDN": names.configdn, + "DESCRIPTOR": descr, }) message("Modifying configuration container") setup_modify_ldif(samdb, setup_path("provision_configuration_basedn_modify.ldif"), { @@ -938,10 +1064,10 @@ def setup_samdb(path, setup_path, session_info, credentials, lp, # The LDIF here was created when the Schema object was constructed message("Setting up sam.ldb schema") - samdb.add_ldif(schema.schema_dn_add) + samdb.add_ldif(schema.schema_dn_add, controls=["relax:0"]) samdb.modify_ldif(schema.schema_dn_modify) samdb.write_prefixes_from_schema() - samdb.add_ldif(schema.schema_data) + samdb.add_ldif(schema.schema_data, controls=["relax:0"]) setup_add_ldif(samdb, setup_path("aggregate_schema.ldif"), {"SCHEMADN": names.schemadn}) @@ -978,7 +1104,7 @@ def setup_samdb(path, setup_path, session_info, credentials, lp, "DOMAINDN": names.domaindn}) message("Setting up sam.ldb data") setup_add_ldif(samdb, setup_path("provision.ldif"), { - "CREATTIME": str(int(time.time()) * 1e7), # seconds -> ticks + "CREATTIME": str(int(time.time() * 1e7)), # seconds -> ticks "DOMAINDN": names.domaindn, "NETBIOSNAME": names.netbiosname, "DEFAULTSITE": names.sitename, @@ -1005,7 +1131,8 @@ def setup_samdb(path, setup_path, session_info, credentials, lp, domainsid=domainsid, policyguid=policyguid, policyguid_dc=policyguid_dc, setup_path=setup_path, - domainControllerFunctionality=domainControllerFunctionality) + domainControllerFunctionality=domainControllerFunctionality, + ntdsguid=ntdsguid) ntds_dn = "CN=NTDS Settings,CN=%s,CN=Servers,CN=Default-First-Site-Name,CN=Sites,CN=Configuration,%s" % (names.hostname, names.domaindn) names.ntdsguid = samdb.searchone(basedn=ntds_dn, @@ -1034,9 +1161,10 @@ def provision(setup_dir, message, session_info, domainsid=None, adminpass=None, ldapadminpass=None, krbtgtpass=None, domainguid=None, policyguid=None, policyguid_dc=None, invocationid=None, - machinepass=None, + machinepass=None, ntdsguid=None, dnspass=None, root=None, nobody=None, users=None, - wheel=None, backup=None, aci=None, serverrole=None, + wheel=None, backup=None, aci=None, serverrole=None, + dom_for_fun_level=None, ldap_backend_extra_port=None, ldap_backend_type=None, sitename=None, ol_mmr_urls=None, ol_olc=None, @@ -1048,10 +1176,12 @@ def provision(setup_dir, message, session_info, """ def setup_path(file): - return os.path.join(setup_dir, file) + return os.path.join(setup_dir, file) if domainsid is None: - domainsid = security.random_sid() + domainsid = security.random_sid() + else: + domainsid = security.dom_sid(domainsid) # create/adapt the group policy GUIDs if policyguid is None: @@ -1128,7 +1258,7 @@ def provision(setup_dir, message, session_info, ldapi_url = "ldapi://%s" % urllib.quote(paths.s4_ldapi_path, safe="") - schema = Schema(setup_path, schemadn=names.schemadn, serverdn=names.serverdn, + schema = Schema(setup_path, domainsid, schemadn=names.schemadn, serverdn=names.serverdn, sambadn=names.sambadn, ldap_backend_type=ldap_backend_type) secrets_credentials = credentials @@ -1185,8 +1315,10 @@ def provision(setup_dir, message, session_info, fill=samdb_fill, adminpass=adminpass, krbtgtpass=krbtgtpass, invocationid=invocationid, - machinepass=machinepass, dnspass=dnspass, - serverrole=serverrole, ldap_backend=provision_backend) + machinepass=machinepass, dnspass=dnspass, + ntdsguid=ntdsguid, serverrole=serverrole, + dom_for_fun_level=dom_for_fun_level, + ldap_backend=provision_backend) if serverrole == "domain controller": if paths.netlogon is None: @@ -1232,24 +1364,26 @@ def provision(setup_dir, message, session_info, # Only make a zone file on the first DC, it should be replicated with DNS replication if serverrole == "domain controller": - secrets_ldb = Ldb(paths.secrets, session_info=session_info, - credentials=credentials, lp=lp) - secretsdb_become_dc(secrets_ldb, setup_path, domain=domain, + secretsdb_self_join(secrets_ldb, domain=domain, realm=names.realm, + dnsdomain=names.dnsdomain, netbiosname=names.netbiosname, domainsid=domainsid, - keytab_path=paths.keytab, samdb_url=paths.samdb, + machinepass=machinepass, + secure_channel_type=SEC_CHAN_BDC) + + secretsdb_setup_dns(secrets_ldb, setup_path, + realm=names.realm, dnsdomain=names.dnsdomain, dns_keytab_path=paths.dns_keytab, - dnspass=dnspass, machinepass=machinepass, - dnsdomain=names.dnsdomain) + dnspass=dnspass) domainguid = samdb.searchone(basedn=domaindn, attribute="objectGUID") assert isinstance(domainguid, str) create_zone_file(paths.dns, setup_path, dnsdomain=names.dnsdomain, - domaindn=names.domaindn, hostip=hostip, + hostip=hostip, hostip6=hostip6, hostname=names.hostname, - dnspass=dnspass, realm=names.realm, + realm=names.realm, domainguid=domainguid, ntdsguid=names.ntdsguid) create_named_conf(paths.namedconf, setup_path, realm=names.realm, @@ -1266,6 +1400,8 @@ def provision(setup_dir, message, session_info, realm=names.realm) message("A Kerberos configuration suitable for Samba 4 has been generated at %s" % paths.krb5conf) + #Now commit the secrets.ldb to disk + secrets_ldb.transaction_commit() if provision_backend is not None: if ldap_backend_type == "fedora-ds": @@ -1790,6 +1926,44 @@ def provision_fds_backend(result, paths=None, setup_path=None, names=None, {"SAMBADN": names.sambadn, }) + setup_file(setup_path("fedorads-pam.ldif"), paths.fedoradspam) + + lnkattr = get_linked_attributes(names.schemadn,schema.ldb) + + refint_config = data = open(setup_path("fedorads-refint-delete.ldif"), 'r').read() + memberof_config = "" + index_config = "" + argnum = 3 + + for attr in lnkattr.keys(): + if lnkattr[attr] is not None: + refint_config += read_and_sub_file(setup_path("fedorads-refint-add.ldif"), + { "ARG_NUMBER" : str(argnum) , + "LINK_ATTR" : attr }) + memberof_config += read_and_sub_file(setup_path("fedorads-linked-attributes.ldif"), + { "MEMBER_ATTR" : attr , + "MEMBEROF_ATTR" : lnkattr[attr] }) + index_config += read_and_sub_file(setup_path("fedorads-index.ldif"), + { "ATTR" : attr }) + argnum += 1 + + open(paths.fedoradsrefint, 'w').write(refint_config) + open(paths.fedoradslinkedattributes, 'w').write(memberof_config) + + attrs = ["lDAPDisplayName"] + res = schema.ldb.search(expression="(&(objectclass=attributeSchema)(searchFlags:1.2.840.113556.1.4.803:=1))", base=names.schemadn, scope=SCOPE_ONELEVEL, attrs=attrs) + + for i in range (0, len(res)): + attr = res[i]["lDAPDisplayName"][0] + + if attr == "objectGUID": + attr = "nsUniqueId" + + index_config += read_and_sub_file(setup_path("fedorads-index.ldif"), + { "ATTR" : attr }) + + open(paths.fedoradsindex, 'w').write(index_config) + setup_file(setup_path("fedorads-samba.ldif"), paths.fedoradssamba, {"SAMBADN": names.sambadn, "LDAPADMINPASS": ldapadminpass @@ -1850,8 +2024,8 @@ def create_phpldapadmin_config(path, setup_path, ldapi_uri): {"S4_LDAPI_URI": ldapi_uri}) -def create_zone_file(path, setup_path, dnsdomain, domaindn, - hostip, hostip6, hostname, dnspass, realm, domainguid, +def create_zone_file(path, setup_path, dnsdomain, + hostip, hostip6, hostname, realm, domainguid, ntdsguid): """Write out a DNS zone file, from the info in the current database. @@ -1862,7 +2036,6 @@ def create_zone_file(path, setup_path, dnsdomain, domaindn, :param hostip: Local IPv4 IP :param hostip6: Local IPv6 IP :param hostname: Local hostname - :param dnspass: Password for DNS :param realm: Realm name :param domainguid: GUID of the domain. :param ntdsguid: GUID of the hosts nTDSDSA record. @@ -1884,7 +2057,6 @@ def create_zone_file(path, setup_path, dnsdomain, domaindn, hostip_host_line = "" setup_file(setup_path("provision.zone"), path, { - "DNSPASS_B64": b64encode(dnspass), "HOSTNAME": hostname, "DNSDOMAIN": dnsdomain, "REALM": realm,