diff options
Diffstat (limited to 'source4/scripting')
-rwxr-xr-x | source4/scripting/bin/setup_dns.sh | 2 | ||||
-rwxr-xr-x | source4/scripting/bin/upgradeprovision | 128 | ||||
-rwxr-xr-x | source4/scripting/devel/tmpfs.sh | 13 | ||||
-rw-r--r-- | source4/scripting/python/samba/__init__.py | 5 | ||||
-rw-r--r-- | source4/scripting/python/samba/ms_schema.py | 2 | ||||
-rw-r--r-- | source4/scripting/python/samba/provision.py | 49 | ||||
-rw-r--r-- | source4/scripting/python/samba/schema.py | 28 |
7 files changed, 152 insertions, 75 deletions
diff --git a/source4/scripting/bin/setup_dns.sh b/source4/scripting/bin/setup_dns.sh index f20ad145c1..de4485fc07 100755 --- a/source4/scripting/bin/setup_dns.sh +++ b/source4/scripting/bin/setup_dns.sh @@ -16,7 +16,7 @@ RSUFFIX=$(echo $DOMAIN | sed s/[\.]/,DC=/g) PRIVATEDIR=$(bin/testparm --section-name=global --parameter-name='private dir' --suppress-prompt 2> /dev/null) } -OBJECTGUID=$(bin/ldbsearch -H "$PRIVATEDIR/sam.ldb" -b "CN=NTDS Settings,CN=$HOSTNAME,CN=Servers,CN=Default-First-Site-Name,CN=Sites,CN=Configuration,DC=$RSUFFIX" objectguid|grep ^objectGUID| cut -d: -f2) +OBJECTGUID=$(bin/ldbsearch -s base -H "$PRIVATEDIR/sam.ldb" -b "CN=NTDS Settings,CN=$HOSTNAME,CN=Servers,CN=Default-First-Site-Name,CN=Sites,CN=Configuration,DC=$RSUFFIX" objectguid|grep ^objectGUID| cut -d: -f2) echo "Found objectGUID $OBJECTGUID" diff --git a/source4/scripting/bin/upgradeprovision b/source4/scripting/bin/upgradeprovision index da827ace42..23980cd3da 100755 --- a/source4/scripting/bin/upgradeprovision +++ b/source4/scripting/bin/upgradeprovision @@ -66,8 +66,10 @@ GUESS = 0x04 PROVISION = 0x08 CHANGEALL = 0xff -# Attributes that not copied from the reference provision even if they do not exists in the destination object -# This is most probably because they are populated automatcally when object is created +# Attributes that are never copied from the reference provision (even if they +# do not exist in the destination object). +# This is most probably because they are populated automatcally when object is +# created hashAttrNotCopied = { "dn": 1,"whenCreated": 1,"whenChanged": 1,"objectGUID": 1,"replPropertyMetaData": 1,"uSNChanged": 1,\ "uSNCreated": 1,"parentGUID": 1,"objectCategory": 1,"distinguishedName": 1,\ "showInAdvancedViewOnly": 1,"instanceType": 1, "cn": 1, "msDS-Behavior-Version":1, "nextRid":1,\ @@ -75,8 +77,9 @@ hashAttrNotCopied = { "dn": 1,"whenCreated": 1,"whenChanged": 1,"objectGUID": 1 "dBCSPwd":1,"supplementalCredentials":1,"gPCUserExtensionNames":1, "gPCMachineExtensionNames":1,\ "maxPwdAge":1, "mail":1, "secret":1,"possibleInferiors":1, "sAMAccountType":1} -# Usually for an object that already exists we do not overwrite attributes as they might have been changed for good -# reasons. Anyway for a few of thems it's mandatory to replace them otherwise the provision will be broken somehow. +# Usually for an object that already exists we do not overwrite attributes as +# they might have been changed for good reasons. Anyway for a few of them it's +# mandatory to replace them otherwise the provision will be broken somehow. hashOverwrittenAtt = { "prefixMap": replace, "systemMayContain": replace,"systemOnly":replace, "searchFlags":replace,\ "mayContain":replace, "systemFlags":replace,"description":replace, "oEMInformation":replace, "operatingSystemVersion":replace, "adminPropertyPages":replace, @@ -167,11 +170,13 @@ def get_paths(targetdir=None,smbconf=None): lp = param.LoadParm() lp.load(smbconf) -# Normaly we need the domain name for this function but for our needs it's pointless +# Normally we need the domain name for this function but for our needs it's +# pointless paths = provision_paths_from_lp(lp,"foo") return paths -# This function guess(fetch) informations needed to make a fresh provision from the current provision +# This function guesses (fetches) informations needed to make a fresh provision +# from the current provision # It includes: realm, workgroup, partitions, netbiosname, domain guid, ... def guess_names_from_current_provision(credentials,session_info,paths): lp = param.LoadParm() @@ -191,11 +196,13 @@ def guess_names_from_current_provision(credentials,session_info,paths): names.netbiosname = str(res[0]["sAMAccountName"]).replace("$","") names.smbconf = smbconf - #It's important here to let ldb load with the old module or it's quite certain that the LDB won't load ... + # It's important here to let ldb load with the old module or it's quite + # certain that the LDB won't load ... samdb = Ldb(paths.samdb, session_info=session_info, credentials=credentials, lp=lp, options=["modules:samba_dsdb"]) - # That's a bit simplistic but it's ok as long as we have only 3 partitions + # That's a bit simplistic but it's ok as long as we have only 3 + # partitions attrs2 = ["defaultNamingContext", "schemaNamingContext","configurationNamingContext","rootDomainNamingContext"] current = samdb.search(expression="(objectClass=*)",base="", scope=SCOPE_BASE, attrs=attrs2) @@ -311,9 +318,10 @@ def newprovision(names,setup_dir,creds,session,smbconf): ldap_dryrun_mode=None) return provdir -# This function sorts two dn in the lexicographical order and put higher level DN before -# So given the dns cn=bar,cn=foo and cn=foo the later will be return as smaller (-1) as it has less -# level +# This function sorts two DNs in the lexicographical order and put higher level +# DN before. +# So given the dns cn=bar,cn=foo and cn=foo the later will be return as smaller +# (-1) as it has less level def dn_sort(x,y): p = re.compile(r'(?<!\\),') tab1 = p.split(str(x)) @@ -343,7 +351,7 @@ def dn_sort(x,y): return -1 return ret -# check from security descriptors modifications return 1 if it is 0 otherwise +# Check for security descriptors modifications return 1 if it is and 0 otherwise # it also populate hash structure for later use in the upgrade process def handle_security_desc(ischema,att,msgElt,hashallSD,old,new): if ischema == 1 and att == "defaultSecurityDescriptor" and msgElt.flags() == ldb.FLAG_MOD_REPLACE: @@ -361,8 +369,8 @@ def handle_security_desc(ischema,att,msgElt,hashallSD,old,new): return 1 return 0 -# Hangle special cases ... That's when we want to update an attribute only -# if it has a certain value or if it's for a certain object or +# Handle special cases ... That's when we want to update a particular attribute +# only, e.g. if it has a certain value or if it's for a certain object or # a class of object. # It can be also if we want to do a merge of value instead of a simple replace def handle_special_case(att,delta,new,old,ischema): @@ -431,7 +439,8 @@ def update_secrets(newpaths,paths,creds,session): for i in range(0,len(reference)): hash_new[str(reference[i]["dn"]).lower()] = reference[i]["dn"] - # Create a hash for speeding the search of existing object in the current provision + # Create a hash for speeding the search of existing object in the + # current provision for i in range(0,len(current)): hash[str(current[i]["dn"]).lower()] = current[i]["dn"] @@ -486,9 +495,9 @@ def update_secrets(newpaths,paths,creds,session): # Check difference between the current provision and the reference provision. -# It looks for all object which base DN is name if ischema is false then scan is done in -# cross partition mode. -# If ischema is true, then special handling is done for dealing with schema +# It looks for all objects which base DN is name. If ischema is "false" then +# the scan is done in cross partition mode. +# If "ischema" is true, then special handling is done for dealing with schema def check_diff_name(newpaths,paths,creds,session,basedn,names,ischema): hash_new = {} hash = {} @@ -497,7 +506,8 @@ def check_diff_name(newpaths,paths,creds,session,basedn,names,ischema): listPresent = [] reference = [] current = [] - # Connect to the reference provision and get all the attribute in the partition referred by name + # Connect to the reference provision and get all the attribute in the + # partition referred by name newsam_ldb = Ldb(newpaths.samdb, session_info=session, credentials=creds,lp=lp) sam_ldb = Ldb(paths.samdb, session_info=session, credentials=creds,lp=lp, options=["modules:samba_dsdb"]) sam_ldb.transaction_start() @@ -513,7 +523,8 @@ def check_diff_name(newpaths,paths,creds,session,basedn,names,ischema): for i in range(0,len(reference)): hash_new[str(reference[i]["dn"]).lower()] = reference[i]["dn"] - # Create a hash for speeding the search of existing object in the current provision + # Create a hash for speeding the search of existing object in the + # current provision for i in range(0,len(current)): hash[str(current[i]["dn"]).lower()] = current[i]["dn"] @@ -523,40 +534,78 @@ def check_diff_name(newpaths,paths,creds,session,basedn,names,ischema): else: listPresent.append(hash_new[k]) - # Sort the missing object in order to have object of the lowest level first (which can be - # containers for higher level objects) + # Sort the missing object in order to have object of the lowest level + # first (which can be containers for higher level objects) listMissing.sort(dn_sort) listPresent.sort(dn_sort) if ischema: - # The following lines (up to the for loop) is to load the up to date schema into our current LDB - # a complete schema is needed as the insertion of attributes and class is done against it + # The following lines (up to the for loop) is to load the up to + # date schema into our current LDB + # a complete schema is needed as the insertion of attributes + # and class is done against it # and the schema is self validated - # The double ldb open and schema validation is taken from the initial provision script + # The double ldb open and schema validation is taken from the + # initial provision script # it's not certain that it is really needed .... sam_ldb = Ldb(session_info=session, credentials=creds, lp=lp) schema = Schema(setup_path, names.domainsid, schemadn=basedn, serverdn=str(names.serverdn)) # Load the schema from the one we computed earlier sam_ldb.set_schema_from_ldb(schema.ldb) - # And now we can connect to the DB - the schema won't be loaded from the DB + # And now we can connect to the DB - the schema won't be loaded + # from the DB sam_ldb.connect(paths.samdb) else: sam_ldb = Ldb(paths.samdb, session_info=session, credentials=creds,lp=lp, options=["modules:samba_dsdb"]) sam_ldb.transaction_start() - empty = ldb.Message() - message(SIMPLE,"There are %d missing objects"%(len(listMissing))) - for dn in listMissing: - reference = newsam_ldb.search(expression="dn=%s"%(str(dn)),base=basedn, scope=SCOPE_SUBTREE,controls=["search_options:1:2"]) - delta = sam_ldb.msg_diff(empty,reference[0]) - for att in hashAttrNotCopied.keys(): - delta.remove(att) - for att in backlinked: - delta.remove(att) - delta.dn = dn + err_num = 0 + err_msg = "" + while len(listMissing) > 0: + listMissing2 = [] + + empty = ldb.Message() + message(SIMPLE,"There are still %d objects missing"%(len(listMissing))) - sam_ldb.add(delta,["relax:0"]) + for dn in listMissing: + reference = newsam_ldb.search(expression="dn=%s" % (str(dn)), + base=basedn, scope=SCOPE_SUBTREE, + controls=["search_options:1:2"]) + delta = sam_ldb.msg_diff(empty,reference[0]) + for att in hashAttrNotCopied.keys(): + delta.remove(att) + for att in backlinked: + delta.remove(att) + delta.dn = dn + + try: + sam_ldb.add(delta,["relax:0"]) + # This is needed here since otherwise the + # "replmd_meta_data" module doesn't see the + # updated data + sam_ldb.transaction_commit() + sam_ldb.transaction_start() + except LdbError, (num, msg): + # An exception can happen if a linked object + # doesn't exist which can happen if it is also + # to be added + err_num = num + err_msg = msg + listMissing2.append(dn) + + if len(listMissing2) == len(listMissing): + # We couldn't add any object in this iteration -> + # we have to resign and hope that the user manually + # fixes the damage + + message(ERROR, "The script isn't capable to do the upgrade fully automatically!") + message(ERROR, "Often this happens when important system objects moved their location. Please look for them (for example doable using the displayed 'sAMAccountName' attribute), backup if personally changed and remove them.") + message(ERROR, "Reinvoke this script and reapply eventual modifications done before. It is possible to get this error more than once (for each problematic object).") + + raise LdbError(err_num, err_msg) + + listMissing = listMissing2 changed = 0 for dn in listPresent: @@ -626,7 +675,8 @@ def check_updated_sd(newpaths,paths,creds,session,names): print "%s new sddl/sddl in ref"%key print "%s\n%s"%(sddl,hash_new[key]) -# Simple update method for updating the SD that rely on the fact that nobody should have modified the SD +# Simple update method for updating the SD that rely on the fact that nobody +# should have modified the SD # This assumption is safe right now (alpha9) but should be removed asap def update_sd(paths,creds,session,names): sam_ldb = Ldb(paths.samdb, session_info=session, credentials=creds,lp=lp,options=["modules:samba_dsdb"]) @@ -748,7 +798,7 @@ def update_machine_account_password(paths,creds,session,names): secretsdb_self_join(secrets_ldb, domain=names.domain, realm=names.realm, - domainsid=names.domainsid, + domainsid=names.domainsid, dnsdomain=names.dnsdomain, netbiosname=names.netbiosname, machinepass=machinepass, diff --git a/source4/scripting/devel/tmpfs.sh b/source4/scripting/devel/tmpfs.sh new file mode 100755 index 0000000000..5604f68dd7 --- /dev/null +++ b/source4/scripting/devel/tmpfs.sh @@ -0,0 +1,13 @@ +#!/bin/bash + +# This sets up bin/ and st/ as tmpfs filesystems, which saves a lot of +# time waiting on the disk! + +rm -rf bin st +mkdir -p bin st || exit 1 +sudo mount -t tmpfs /dev/null bin || exit 1 +sudo chown $USER bin || exit 1 +echo "tmpfs setup for bin/" +sudo mount -t tmpfs /dev/null st || exit 1 +sudo chown $USER st || exit 1 +echo "tmpfs setup for st/" diff --git a/source4/scripting/python/samba/__init__.py b/source4/scripting/python/samba/__init__.py index 5d61c1bd8c..d7df6b979b 100644 --- a/source4/scripting/python/samba/__init__.py +++ b/source4/scripting/python/samba/__init__.py @@ -255,7 +255,10 @@ class Ldb(ldb.Ldb): :param ldif: LDIF text. """ for changetype, msg in self.parse_ldif(ldif): - self.modify(msg, controls) + if (changetype == ldb.CHANGETYPE_ADD): + self.add(msg, controls) + else: + self.modify(msg, controls) def set_domain_sid(self, sid): """Change the domain SID used by this LDB. diff --git a/source4/scripting/python/samba/ms_schema.py b/source4/scripting/python/samba/ms_schema.py index a4eed581c6..9f5ebcf8cc 100644 --- a/source4/scripting/python/samba/ms_schema.py +++ b/source4/scripting/python/samba/ms_schema.py @@ -229,6 +229,8 @@ def __transform_entry(entry, objectClass): entry.insert(1, ["objectClass", ["top", objectClass]]) entry.insert(2, ["cn", cn]) entry.insert(2, ["objectGUID", str(uuid.uuid4())]) + entry.insert(2, ["adminDescription", cn]) + entry.insert(2, ["adminDisplayName", cn]) for l in entry: key = l[0].lower() diff --git a/source4/scripting/python/samba/provision.py b/source4/scripting/python/samba/provision.py index d7d0a790ca..a71b561a86 100644 --- a/source4/scripting/python/samba/provision.py +++ b/source4/scripting/python/samba/provision.py @@ -793,9 +793,9 @@ def setup_self_join(samdb, names, "DEFAULTSITE": names.sitename, "DNSNAME": "%s.%s" % (names.hostname, names.dnsdomain), "MACHINEPASS_B64": b64encode(machinepass), - "DNSPASS_B64": b64encode(dnspass), "REALM": names.realm, "DOMAIN": names.domain, + "DOMAINSID": str(domainsid), "DNSDOMAIN": names.dnsdomain, "SAMBA_VERSION_STRING": version, "NTDSGUID": ntdsguid_line, @@ -824,7 +824,8 @@ def setup_self_join(samdb, names, "DEFAULTSITE": names.sitename, "SERVERDN": names.serverdn, "NETBIOSNAME": names.netbiosname, - "NTDSGUID": names.ntdsguid + "NTDSGUID": names.ntdsguid, + "DNSPASS_B64": b64encode(dnspass), }) @@ -892,10 +893,7 @@ def setup_samdb(path, setup_path, session_info, provision_backend, lp, samdb.set_opaque_integer("domainControllerFunctionality", domainControllerFunctionality) samdb.set_domain_sid(str(domainsid)) - if serverrole == "domain controller": - samdb.set_invocation_id(invocationid) - # NOTE: the invocationid for standalone and member server - # cases is setup in the sambd_dsdb module init function + samdb.set_invocation_id(invocationid) message("Adding DomainDN: %s" % names.domaindn) @@ -945,6 +943,14 @@ def setup_samdb(path, setup_path, session_info, provision_backend, lp, setup_add_ldif(samdb, setup_path("aggregate_schema.ldif"), {"SCHEMADN": names.schemadn}) + message("Reopening sam.ldb with new schema"); + samdb.transaction_commit() + samdb = Ldb(session_info=session_info, + credentials=provision_backend.credentials, lp=lp) + samdb.connect(path) + samdb.transaction_start() + samdb.set_invocation_id(invocationid) + message("Setting up sam.ldb configuration data") setup_add_ldif(samdb, setup_path("provision_configuration.ldif"), { "CONFIGDN": names.configdn, @@ -1003,21 +1009,20 @@ def setup_samdb(path, setup_path, session_info, provision_backend, lp, "KRBTGTPASS_B64": b64encode(krbtgtpass), }) - if serverrole == "domain controller": - message("Setting up self join") - setup_self_join(samdb, names=names, invocationid=invocationid, - dnspass=dnspass, - machinepass=machinepass, - domainsid=domainsid, policyguid=policyguid, - policyguid_dc=policyguid_dc, - setup_path=setup_path, - 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, - attribute="objectGUID", expression="", scope=SCOPE_BASE) - assert isinstance(names.ntdsguid, str) + message("Setting up self join") + setup_self_join(samdb, names=names, invocationid=invocationid, + dnspass=dnspass, + machinepass=machinepass, + domainsid=domainsid, policyguid=policyguid, + policyguid_dc=policyguid_dc, + setup_path=setup_path, + 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, + attribute="objectGUID", expression="", scope=SCOPE_BASE) + assert isinstance(names.ntdsguid, str) except: samdb.transaction_cancel() @@ -1136,7 +1141,7 @@ def provision(setup_dir, message, session_info, serverrole = lp.get("server role") assert serverrole in ("domain controller", "member server", "standalone") - if invocationid is None and serverrole == "domain controller": + if invocationid is None: invocationid = str(uuid.uuid4()) if not os.path.exists(paths.private_dir): diff --git a/source4/scripting/python/samba/schema.py b/source4/scripting/python/samba/schema.py index 8913e53b00..f702e9829f 100644 --- a/source4/scripting/python/samba/schema.py +++ b/source4/scripting/python/samba/schema.py @@ -35,16 +35,20 @@ from ldb import SCOPE_SUBTREE, SCOPE_ONELEVEL, SCOPE_BASE import os 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)" + sddl = "O:SAG:SAD:AI(OA;;CR;89e95b76-444d-4c62-991a-0facbeda640c" \ + ";;ER)(OA;;CR;1131f6aa-9c07-11d1-f79f-00c04fc2dcd2;;ER)(OA;;CR;1131f6ad-9c07-1" \ + "1d1-f79f-00c04fc2dcd2;;ER)(OA;;CR;e12b56b6-0a95-11d1-adbb-00c04fd8d5cd;;SA)(O" \ + "A;;CR;89e95b76-444d-4c62-991a-0facbeda640c;;BA)(OA;;CR;1131f6aa-9c07-11d1-f79" \ + "f-00c04fc2dcd2;;BA)(OA;;CR;1131f6ab-9c07-11d1-f79f-00c04fc2dcd2;;BA)(OA;;CR;1" \ + "131f6ac-9c07-11d1-f79f-00c04fc2dcd2;;BA)(OA;;CR;1131f6ad-9c07-11d1-f79f-00c04" \ + "fc2dcd2;;BA)(OA;;CR;89e95b76-444d-4c62-991a-0facbeda640c;;ED)(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;1131f6ad-9c07-1" \ + "1d1-f79f-00c04fc2dcd2;;ED)(A;;RPWPCCDCLCLORCWOWDSDDTSW;;;LA)(A;CI;RPWPCRCCLCL" \ + "ORCWOWDSW;;;SA)(A;CI;RPLCLORC;;;AU)(A;CI;RPWPCRCCDCLCLORCWOWDSDDTSW;;;SY)S:(O" \ + "U;SA;CR;45ec5156-db7e-47bb-b53f-dbeb2d03c40f;;WD)(OU;SA;CR;e12b56b6-0a95-11d1" \ + "-adbb-00c04fd8d5cd;;WD)(AU;SA;CR;;;DU)(AU;SA;CR;;;BA)(AU;SA;WPCCDCWOWDSDDTSW;" \ + ";;WD)(AU;CISA;WP;;;WD)" sec = security.descriptor.from_sddl(sddl, domain_sid) return ndr_pack(sec) @@ -64,8 +68,8 @@ class Schema(object): self.schemadn = schemadn self.ldb = Ldb() - self.schema_data = read_ms_schema(setup_path('ad-schema/MS-AD_Schema_2K8_Attributes.txt'), - setup_path('ad-schema/MS-AD_Schema_2K8_Classes.txt')) + self.schema_data = read_ms_schema(setup_path('ad-schema/MS-AD_Schema_2K8_R2_Attributes.txt'), + setup_path('ad-schema/MS-AD_Schema_2K8_R2_Classes.txt')) if files is not None: for file in files: |