diff options
-rwxr-xr-x | source4/scripting/bin/upgradeprovision | 137 |
1 files changed, 121 insertions, 16 deletions
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) |