From 929dbf8ef817cb1646a5f82b9a0f0eece4ab84ee Mon Sep 17 00:00:00 2001 From: Matthieu Patou Date: Tue, 19 Jan 2010 01:53:01 +0300 Subject: upgradeprovision: mark rIDAvailablePool never upgraded handle properly the fact that missing object might depend on some other in order to be correctly created debug change also if we are in debugall mode --- source4/scripting/bin/upgradeprovision | 137 +++++++++++++++++++++++++++++---- 1 file changed, 121 insertions(+), 16 deletions(-) (limited to 'source4') diff --git a/source4/scripting/bin/upgradeprovision b/source4/scripting/bin/upgradeprovision index 0c33ee358e..1c70e377ae 100755 --- a/source4/scripting/bin/upgradeprovision +++ b/source4/scripting/bin/upgradeprovision @@ -54,6 +54,7 @@ from samba.dcerpc import misc, security from samba.ndr import ndr_pack, ndr_unpack from samba.dcerpc.misc import SEC_CHAN_BDC +never=0 replace=2^ldb.FLAG_MOD_REPLACE add=2^ldb.FLAG_MOD_ADD delete=2^ldb.FLAG_MOD_DELETE @@ -85,11 +86,12 @@ hashAttrNotCopied = { "dn": 1,"whenCreated": 1,"whenChanged": 1,"objectGUID": 1 hashOverwrittenAtt = { "prefixMap": replace, "systemMayContain": replace,"systemOnly":replace, "searchFlags":replace, "mayContain":replace, "systemFlags":replace,"description":replace, "oEMInformation":replace, "operatingSystemVersion":replace, "adminPropertyPages":replace, - "defaultSecurityDescriptor": replace,"wellKnownObjects":replace,"privilege":delete,"groupType":replace} + "defaultSecurityDescriptor": replace,"wellKnownObjects":replace,"privilege":delete,"groupType":replace, + "rIDAvailablePool": never} backlinked = [] - +dn_syntax_att = [] def define_what_to_log(opts): what = 0 if opts.debugchange: @@ -156,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): @@ -497,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 @@ -534,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]) @@ -564,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"]) @@ -605,9 +706,12 @@ def check_diff_name(newpaths,paths,creds,session,basedn,names,ischema): delta.remove(att) continue if (not hashOverwrittenAtt.has_key(att) or not (hashOverwrittenAtt.get(att)&2^msgElt.flags())): + if hashOverwrittenAtt.has_key(att) and hashOverwrittenAtt.get(att)==never: + delta.remove(att) + continue if handle_special_case(att,delta,reference,current,ischema)==0 and msgElt.flags()!=ldb.FLAG_MOD_ADD: i = 0 - if opts.debugchange: + if opts.debugchange or opts.debugall: try: dump_denied_change(dn,att,messageEltFlagToString(msgElt.flags()),current[0][att],reference[0][att]) except: @@ -794,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) -- cgit