[PATCH 05/10] s4: add a function for a simple upgrade of SD

Matthieu Patou mat at matws.net
Thu Nov 26 09:46:08 MST 2009


---
 source4/scripting/bin/upgradeprovision |  149 +++++++++++++++++---------------
 1 files changed, 80 insertions(+), 69 deletions(-)

diff --git a/source4/scripting/bin/upgradeprovision b/source4/scripting/bin/upgradeprovision
index 9298c02..369ba74 100755
--- a/source4/scripting/bin/upgradeprovision
+++ b/source4/scripting/bin/upgradeprovision
@@ -45,9 +45,8 @@ import ldb
 import samba.getopt as options
 from samba.samdb import SamDB
 from samba import param
-from samba.provision import  ProvisionNames,provision_paths_from_lp,find_setup_dir,FILL_FULL,provision
-from samba.provisionexceptions import ProvisioningError
-from samba.schema import get_dnsyntax_attributes, get_linked_attributes, Schema
+from samba.provision import  ProvisionNames,provision_paths_from_lp,find_setup_dir,FILL_FULL,provision, get_domain_descriptor, get_config_descriptor
+from samba.schema import get_dnsyntax_attributes, get_linked_attributes, Schema, get_schema_descriptor
 from samba.dcerpc import misc, security
 from samba.ndr import ndr_pack, ndr_unpack
 from samba.dcerpc.misc import SEC_CHAN_BDC
@@ -566,75 +565,85 @@ def check_diff_name(newpaths,paths,creds,session,basedn,names,ischema):
 	message(SIMPLE,"There are %d changed objects"%(changed))
 	return hashallSD
 
-
-# This function updates SD for AD objects.
-# As SD in the upgraded provision can be different for various reasons
-# this function check if an automatic update can be performed and do it
-# or if it can't be done.
-def update_sds(diffDefSD,diffSD,paths,creds,session,rootdn,domSIDTxt):
+# Check that SD are correct 
+def check_updated_sd(newpaths,paths,creds,session,names):
+	newsam_ldb = Ldb(newpaths.samdb, session_info=session, credentials=creds,lp=lp)
 	sam_ldb = Ldb(paths.samdb, session_info=session, credentials=creds,lp=lp)
+	domSID = security.dom_sid(names.domainsid)
+	res = newsam_ldb.search(expression="objectClass=*",base=str(names.rootdn), scope=SCOPE_SUBTREE,attrs=["dn","nTSecurityDescriptor"],controls=["search_options:1:2"])
+	res2 = sam_ldb.search(expression="objectClass=*",base=str(names.rootdn), scope=SCOPE_SUBTREE,attrs=["dn","nTSecurityDescriptor"],controls=["search_options:1:2"])
+	hash_new = {} 
+	for i in range(0,len(res)):
+		hash_new[str(res[i]["dn"]).lower()] = ndr_unpack(security.descriptor,str(res[i]["nTSecurityDescriptor"])).as_sddl(domSID)
+	
+	for i in range(0,len(res2)):
+		key = str(res2[i]["dn"]).lower()
+		if hash_new.has_key(key):
+			sddl = ndr_unpack(security.descriptor,str(res2[i]["nTSecurityDescriptor"])).as_sddl(domSID)
+			if sddl != hash_new[key]:
+				print 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 
+# This assumption is safe right now (alpha9) but should be removed asap
+def update_sd(newpaths,paths,creds,session,names):
+	domSID = security.dom_sid(names.domainsid)
+	admin_session_info = admin_session(lp, names.domainsid)
+	sam_ldb = Ldb(paths.samdb, session_info=admin_session, credentials=creds,lp=lp)
 	sam_ldb.transaction_start()
-	domSID = security.dom_sid(domSIDTxt)
-	hashClassSD = {}
-	admin_session_info = admin_session(lp, str(domSID))
+	# First update the SD for the rootdn
+	sam_ldb.set_session_info(admin_session_info)
+	res = sam_ldb.search(expression="objectClass=*",base=str(names.rootdn), scope=SCOPE_BASE,attrs=["dn","whenCreated"],controls=["search_options:1:2"])
+	delta = ldb.Message()
+	delta.dn = ldb.Dn(sam_ldb,str(res[0]["dn"]))
+	descr = get_domain_descriptor(domSID)
+	delta["nTSecurityDescriptor"] = ldb.MessageElement( descr,ldb.FLAG_MOD_REPLACE,"nTSecurityDescriptor" )
+	sam_ldb.modify(delta,["recalculate_sd:0"])
+	# Then the config dn
+	res = sam_ldb.search(expression="objectClass=*",base=str(names.configdn), scope=SCOPE_BASE,attrs=["dn","whenCreated"],controls=["search_options:1:2"])
+	delta = ldb.Message()
+	delta.dn = ldb.Dn(sam_ldb,str(res[0]["dn"]))
+	descr = get_config_descriptor(domSID)
+	delta["nTSecurityDescriptor"] = ldb.MessageElement( descr,ldb.FLAG_MOD_REPLACE,"nTSecurityDescriptor" )
+	sam_ldb.modify(delta,["recalculate_sd:0"])
+	# Then the schema dn 
+	res = sam_ldb.search(expression="objectClass=*",base=str(names.schemadn), scope=SCOPE_BASE,attrs=["dn","whenCreated"],controls=["search_options:1:2"])
+	delta = ldb.Message()
+	delta.dn = ldb.Dn(sam_ldb,str(res[0]["dn"]))
+	descr = get_schema_descriptor(domSID)
+	delta["nTSecurityDescriptor"] = ldb.MessageElement( descr,ldb.FLAG_MOD_REPLACE,"nTSecurityDescriptor" )
+	sam_ldb.modify(delta,["recalculate_sd:0"])
+	
+	# Then the rest
+	hash = {}
+	res = sam_ldb.search(expression="objectClass=*",base=str(names.rootdn), scope=SCOPE_SUBTREE,attrs=["dn","whenCreated"],controls=["search_options:1:2"])
+	for obj in res:
+		if not (str(obj["dn"]) == str(names.rootdn) or
+			str(obj["dn"]) == str(names.configdn) or \
+			str(obj["dn"]) == str(names.schemadn)):
+			hash[str(obj["dn"])] = obj["whenCreated"]
+	
+	listkeys = hash.keys()
+	listkeys.sort(dn_sort)
+
+	# SD should be created with admin but as some previous acl were so wrong that admin can't modify them we have first
+	# to recreate them with the good form and then give the ownership to admin ...
 	system_session_info = system_session()
-	upgrade = 0
-	for dn in diffSD.keys():
-		newSD = diffSD[dn]["newSD"].as_sddl(domSID)
-		oldSD = diffSD[dn]["oldSD"].as_sddl(domSID)
-		message(CHANGESD, "ntsecuritydescriptor for %s has changed old %s new %s"%(dn,oldSD,diffSD[dn]["newSD"].as_sddl(domSID)))
-		# First let's find the defaultSD for the object which SD is different from the reference one.
-		res = sam_ldb.search(expression="dn=%s"%(dn),base=rootdn, scope=SCOPE_SUBTREE,attrs=["objectClass"],controls=["search_options:1:2"])
-		classObj = res[0]["objectClass"][-1]
-		defSD = ""
-		if hashClassSD.has_key(classObj):
-			defSD = hashClassSD[classObj]
-		else:
-			res2 = sam_ldb.search(expression="lDAPDisplayName=%s"%(classObj),base=rootdn, scope=SCOPE_SUBTREE,attrs=["defaultSecurityDescriptor"],controls=["search_options:1:2"])
-			if len(res2) > 0:
-				defSD = str(res2[0]["defaultSecurityDescriptor"])
-				hashClassSD[classObj] = defSD
-		# Because somewhere between alpha8 and alpha9 samba4 changed the owner of ACLs in the AD so
-		# we check if it's the case and if so use the "old" owner to see if the ACL is a direct calculation
-		# from the defaultSecurityDescriptor
-		session = admin_session_info
-		if oldSD.startswith("O:SYG:BA"):
-			session = system_session_info
-		descr = security.descriptor.ntsd_from_defaultsd(defSD, domSID,session)
-		if descr.as_sddl(domSID) != oldSD:
-			message(SIMPLE, "nTSecurity Descriptor for %s do not directly inherit from the defaultSecurityDescriptor and is different from the one of the reference provision, therefor I can't upgrade i")
-			message(SIMPLE,"Old Descriptor: %s"%(oldSD))
-			message(SIMPLE,"New Descriptor: %s"%(newSD))
-			if diffDefSD.has_key(classObj):
-				# We have a pending modification for the defaultSecurityDescriptor of the class Object of the currently inspected object
-				# and we have a conflict so write down that we won't upgrade this defaultSD for this class object
-				diffDefSD[classObj]["noupgrade"]=1
-		else:
-			# At this point we know that the SD was directly generated from the defaultSecurityDescriptor
-			# so we can take the new SD and replace the old one
-			upgrade = upgrade +1
-			delta = ldb.Message()
-			delta.dn = ldb.Dn(sam_ldb,dn)
-			delta["nTSecurityDescriptor"] = ldb.MessageElement( ndr_pack(diffSD[dn]["newSD"]),ldb.FLAG_MOD_REPLACE,"nTSecurityDescriptor" )
-		sam_ldb.modify(delta)
-
+	sam_ldb.set_session_info(system_session_info)
+	for key in listkeys:
+		delta = ldb.Message()
+		delta.dn = ldb.Dn(sam_ldb,key)
+		delta["whenCreated"] = ldb.MessageElement( hash[key],ldb.FLAG_MOD_REPLACE,"whenCreated" )
+		sam_ldb.modify(delta,["recalculate_sd:0"])
+
+	
+	sam_ldb.set_session_info(admin_session_info)
+	for key in listkeys:
+		delta = ldb.Message()
+		delta.dn = ldb.Dn(sam_ldb,key)
+		delta["whenCreated"] = ldb.MessageElement( hash[key],ldb.FLAG_MOD_REPLACE,"whenCreated" )
+		sam_ldb.modify(delta,["recalculate_sd:0"])
 	sam_ldb.transaction_commit()
-	message(SIMPLE,"%d nTSecurityDescriptor attribute(s) have been updated"%(upgrade))
-	sam_ldb.transaction_start()
-	upgrade = 0
-	for dn in diffDefSD:
-		message(CHANGESD, "DefaultSecurityDescriptor for class object %s has changed"%(dn))
-		if not diffDefSD[dn].has_key("noupgrade"):
-			upgrade = upgrade +1
-			delta = ldb.Message()
-			delta.dn = ldb.Dn(sam_ldb,dn)
-			delta["defaultSecurityDescriptor"] = ldb.MessageElement(diffDefSD[dn]["newSD"],ldb.FLAG_MOD_REPLACE,"defaultSecurityDescriptor" )
-			sam_ldb.modify(delta)
-		else:
-			message(CHANGESD,"Not updating the defaultSecurityDescriptor for class object %s as one or more dependant object hasn't been upgraded"%(dn))
-
-	sam_ldb.transaction_commit()
-	message(SIMPLE,"%d defaultSecurityDescriptor attribute(s) have been updated"%(upgrade))
 
 def rmall(topdir):
 	for root, dirs, files in os.walk(topdir, topdown=False):
@@ -681,7 +690,6 @@ def update_samdb(newpaths,paths,creds,session,names):
 	message(SIMPLE,"Scanning whole provision for updates and additions")
 	hashSD = check_diff_name(newpaths,paths,creds,session,str(names.rootdn),names,0)
 	message(SIMPLE,"Done with scanning")
-#	update_sds(hashdef,hashSD,paths,creds,session,str(names.rootdn),names.domainsid)
 
 def update_machine_account_password(newpaths,paths,creds,session,names):
 
@@ -740,8 +748,11 @@ update_basesamdb(newpaths,paths,names)
 update_secrets(newpaths,paths,creds,session)
 update_privilege(newpaths,paths)
 update_machine_account_password(newpaths,paths,creds,session,names)
+
 if opts.full:
 	update_samdb(newpaths,paths,creds,session,names)
+update_sd(newpaths,paths,creds,session,names)
+check_updated_sd(newpaths,paths,creds,session,names)
 message(SIMPLE,"Upgrade finished !")
 # remove reference provision now that everything is done !
 rmall(provisiondir)
-- 
1.6.3.3


--------------000902080109040405080503
Content-Type: text/x-patch;
 name="0006-s4-fix-problems.patch"
Content-Transfer-Encoding: 7bit
Content-Disposition: attachment;
 filename="0006-s4-fix-problems.patch"



More information about the samba-technical mailing list