[PATCH 5/5] upgradeprovision: handle properly the fact that missing object might depend on some other in order to be correctly created

Matthieu Patou mat at matws.net
Tue Jan 12 09:58:32 MST 2010


---
 source4/scripting/bin/upgradeprovision |  128 ++++++++++++++++++++++++++++----
 1 files changed, 114 insertions(+), 14 deletions(-)

diff --git a/source4/scripting/bin/upgradeprovision b/source4/scripting/bin/upgradeprovision
index 212112d..49c648b 100755
--- a/source4/scripting/bin/upgradeprovision
+++ b/source4/scripting/bin/upgradeprovision
@@ -91,7 +91,7 @@ hashOverwrittenAtt = {	"prefixMap": replace, "systemMayContain": replace,"system
 
 
 backlinked = []
-
+dn_syntax_att = []
 def define_what_to_log(opts):
 	what = 0
 	if opts.debugchange:
@@ -158,7 +158,15 @@ def identic_rename(ldbobj,dn):
 # Create an array of backlinked attributes
 def populate_backlink(newpaths,creds,session,schemadn):
 	newsam_ldb = Ldb(newpaths.samdb, session_info=session, credentials=creds,lp=lp)
-	backlinked.extend(get_linked_attributes(ldb.Dn(newsam_ldb,str(schemadn)),newsam_ldb).values())
+	linkedAttHash = get_linked_attributes(ldb.Dn(newsam_ldb,str(schemadn)),newsam_ldb)
+	backlinked.extend(linkedAttHash.values())
+
+# Create an array of  attributes with a dn synthax (2.5.5.1)
+def populate_dnsyntax(newpaths,creds,session,schemadn):
+	newsam_ldb = Ldb(newpaths.samdb, session_info=session, credentials=creds,lp=lp)
+	res = newsam_ldb.search(expression="(attributeSyntax=2.5.5.1)",base=ldb.Dn(newsam_ldb,str(schemadn)), scope=SCOPE_SUBTREE, attrs=["lDAPDisplayName"])
+	for elem in res:
+		dn_syntax_att.append(elem["lDAPDisplayName"])
 
 # Get Paths for important objects (ldb, keytabs ...)
 def get_paths(targetdir=None,smbconf=None):
@@ -499,6 +507,107 @@ def update_secrets(newpaths,paths,creds,session):
 		delta.dn = current[0].dn
 		secrets_ldb.modify(delta)
 
+def dump_denied_change(dn,att,flagtxt,current,reference):
+	message(CHANGE, "dn= "+str(dn)+" "+att+" with flag "+flagtxt+" is not allowed to be changed/removed, I discard this change ...")
+	if att != "objectSid" :
+		i = 0
+		for e in range(0,len(current)):
+			message(CHANGE,"old %d : %s"%(i,str(current[e])))
+			i=i+1
+		if reference != None:
+			i = 0
+			for e in range(0,len(reference)):
+					message(CHANGE,"new %d : %s"%(i,str(reference[e])))
+					i=i+1
+	else:
+		message(CHANGE,"old : %s"%str(ndr_unpack( security.dom_sid,current[0])))
+		message(CHANGE,"new : %s"%str(ndr_unpack( security.dom_sid,reference[0])))
+
+#This function is for doing case by case treatment on special object
+
+def handle_special_add(sam_ldb,dn,names):
+	dntoremove=None
+	if str(dn).lower() == ("CN=Certificate Service DCOM Access,CN=Builtin,%s"%names.rootdn).lower():
+		#This entry was misplaced lets remove it if it exists
+		dntoremove="CN=Certificate Service DCOM Access,CN=Users,%s"%names.rootdn
+
+	if str(dn).lower() == ("CN=Cryptographic Operators,CN=Builtin,%s"%names.rootdn).lower():
+		#This entry was misplaced lets remove it if it exists
+		dntoremove="CN=Cryptographic Operators,CN=Users,%s"%names.rootdn
+
+	if str(dn).lower() == ("CN=Event Log Readers,CN=Builtin,%s"%names.rootdn).lower():
+		#This entry was misplaced lets remove it if it exists
+		dntoremove="CN=Event Log Readers,CN=Users,%s"%names.rootdn
+
+	if dntoremove != None:
+		res = sam_ldb.search(expression="objectClass=*",base=dntoremove, scope=SCOPE_BASE,attrs=["dn"],controls=["search_options:1:2"])
+		if len(res) > 0:
+			message(CHANGE,"Existing object %s must be replaced by %s, removing old object"%(dntoremove,str(dn)))
+			sam_ldb.delete(res[0]["dn"])
+
+#Check if the one of the dn in the listdn will be created after the current dn
+#hash is indexed by dn to be created, with each key is associated the creation order
+#First dn to be created has the creation order 0, second has 1, ...
+#Index contain the current creation order
+def check_dn_nottobecreated(hash,index,listdn):
+	if listdn == None:
+		return None
+	for dn in listdn:
+		key = str(dn).lower()
+		if hash.has_key(key) and hash[key] > index:
+			return str(dn)
+	return None
+
+#This function tries to add the missing object "dn" if this object depends on some others
+# the function returns 0, if the object was created 1 is returned
+def add_missing_object(newsam_ldb,sam_ldb,dn,names,basedn,hash,index):
+	handle_special_add(sam_ldb,dn,names)
+	reference = newsam_ldb.search(expression="dn=%s"%(str(dn)),base=basedn,
+					scope=SCOPE_SUBTREE,controls=["search_options:1:2"])
+	empty = ldb.Message()
+	delta = sam_ldb.msg_diff(empty,reference[0])
+	for att in hashAttrNotCopied.keys():
+		delta.remove(att)
+	for att in backlinked:
+		delta.remove(att)
+	depend_on_yettobecreated = None
+	for att in dn_syntax_att:
+		depend_on_yet_tobecreated = check_dn_nottobecreated(hash,index,delta.get(str(att)))
+		if depend_on_yet_tobecreated != None:
+			message(CHANGE,"Object %s depends on %s in attribute %s, delaying the creation"
+							%(str(dn),depend_on_yet_tobecreated,str(att)))
+			return 0
+	delta.dn = dn
+	message(CHANGE,"Object %s will be added"%dn)
+	sam_ldb.add(delta,["relax:0"])
+	return 1
+
+def gen_dn_index_hash(listMissing):
+	hash = {}
+	for i in range(0,len(listMissing)):
+		hash[str(listMissing[i]).lower()] = i
+	return hash
+
+def add_missing_entries(newsam_ldb,sam_ldb,names,basedn,list):
+	listMissing = []
+	listDefered = list
+
+	while(len(listDefered) != len(listMissing) and len(listDefered) > 0):
+		index = 0
+		listMissing = listDefered
+		listDefered = []
+		hashMissing = gen_dn_index_hash(listMissing)
+		for dn in listMissing:
+			ret =  add_missing_object(newsam_ldb,sam_ldb,dn,names,basedn,hashMissing,index)
+			index = index + 1
+			if ret == 0:
+				#DN can't be created because it depends on some other DN in the list
+				listDefered.append(dn)
+	if len(listDefered) != 0:
+		raise ProvisioningError("Unable to insert missing elements: circular references")
+
+
+
 
 # Check difference between the current provision and the reference provision.
 # It looks for all objects which base DN is name. If ischema is "false" then
@@ -536,6 +645,7 @@ def check_diff_name(newpaths,paths,creds,session,basedn,names,ischema):
 
 	for k in hash_new.keys():
 		if not hash.has_key(k):
+			print hash_new[k]
 			listMissing.append(hash_new[k])
 		else:
 			listPresent.append(hash_new[k])
@@ -566,19 +676,8 @@ def check_diff_name(newpaths,paths,creds,session,basedn,names,ischema):
 
 	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
-
-		sam_ldb.add(delta,["relax:0"])
-
+	add_missing_entries(newsam_ldb,sam_ldb,names,basedn,listMissing)
 	changed = 0
 	for dn in listPresent:
 		reference = newsam_ldb.search(expression="dn=%s"%(str(dn)),base=basedn, scope=SCOPE_SUBTREE,controls=["search_options:1:2"])
@@ -799,6 +898,7 @@ provisiondir = newprovision(names,setup_dir,creds,session,smbconf)
 # Get file paths of this new provision
 newpaths = get_paths(targetdir=provisiondir)
 populate_backlink(newpaths,creds,session,names.schemadn)
+populate_dnsyntax(newpaths,creds,session,names.schemadn)
 # Check the difference
 update_basesamdb(newpaths,paths,names)
 
-- 
1.6.3.3


--------------030303070705040303000100
Content-Type: text/x-patch;
 name="0002-s4-python-add-some-helper-for-converting-ldb_flag-to.patch"
Content-Transfer-Encoding: 7bit
Content-Disposition: attachment;
 filename*0="0002-s4-python-add-some-helper-for-converting-ldb_flag-to.pa";
 filename*1="tch"



More information about the samba-technical mailing list