4 # Copyright (C) Matthieu Patou <mat@matws.net> 2009
6 # Based on provision a Samba4 server by
7 # Copyright (C) Jelmer Vernooij <jelmer@samba.org> 2007-2008
8 # Copyright (C) Andrew Bartlett <abartlet@samba.org> 2008
11 # This program is free software; you can redistribute it and/or modify
12 # it under the terms of the GNU General Public License as published by
13 # the Free Software Foundation; either version 3 of the License, or
14 # (at your option) any later version.
16 # This program is distributed in the hope that it will be useful,
17 # but WITHOUT ANY WARRANTY; without even the implied warranty of
18 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 # GNU General Public License for more details.
21 # You should have received a copy of the GNU General Public License
22 # along with this program. If not, see <http://www.gnu.org/licenses/>.
33 # Allow to run from s4 source directory (without installing samba)
34 sys.path.insert(0, "bin/python")
37 import samba.getopt as options
38 from samba.credentials import DONT_USE_KERBEROS
39 from samba.auth import system_session, admin_session
40 from samba import Ldb, version
41 from ldb import SCOPE_ONELEVEL, SCOPE_SUBTREE, SCOPE_BASE,\
42 FLAG_MOD_REPLACE, FLAG_MOD_ADD, FLAG_MOD_DELETE,\
43 MessageElement, Message, Dn
44 from samba import param
45 from samba.misc import messageEltFlagToString
46 from samba.provision import find_setup_dir, get_domain_descriptor,\
47 get_config_descriptor, secretsdb_self_join,\
48 set_gpo_acl, getpolicypath,create_gpo_struct,\
49 ProvisioningError, getLastProvisionUSN,\
50 get_max_usn, updateProvisionUSN
51 from samba.schema import get_linked_attributes, Schema, get_schema_descriptor
52 from samba.dcerpc import security, drsblobs
53 from samba.ndr import ndr_unpack
54 from samba.dcerpc.misc import SEC_CHAN_BDC
55 from samba.upgradehelpers import dn_sort, get_paths, newprovision,\
56 find_provision_key_parameters, get_ldbs,\
57 usn_in_range, identic_rename, get_diff_sddls
59 replace=2**FLAG_MOD_REPLACE
61 delete=2**FLAG_MOD_DELETE
65 # Will be modified during provision to tell if default sd has been modified
68 #Errors are always logged
77 __docformat__ = "restructuredText"
79 # Attributes that are never copied from the reference provision (even if they
80 # do not exist in the destination object).
81 # This is most probably because they are populated automatcally when object is
83 # This also apply to imported object from reference provision
84 hashAttrNotCopied = { "dn": 1, "whenCreated": 1, "whenChanged": 1,
85 "objectGUID": 1, "uSNCreated": 1,
86 "replPropertyMetaData": 1, "uSNChanged": 1,
87 "parentGUID": 1, "objectCategory": 1,
88 "distinguishedName": 1, "nTMixedDomain": 1,
89 "showInAdvancedViewOnly": 1, "instanceType": 1,
90 "msDS-Behavior-Version":1, "nextRid":1, "cn": 1,
91 "versionNumber":1, "lmPwdHistory":1, "pwdLastSet": 1,
92 "ntPwdHistory":1, "unicodePwd":1,"dBCSPwd":1,
93 "supplementalCredentials":1, "gPCUserExtensionNames":1,
94 "gPCMachineExtensionNames":1,"maxPwdAge":1, "secret":1,
95 "possibleInferiors":1, "privilege":1,
98 # Usually for an object that already exists we do not overwrite attributes as
99 # they might have been changed for good reasons. Anyway for a few of them it's
100 # mandatory to replace them otherwise the provision will be broken somehow.
101 # But for attribute that are just missing we do not have to specify them as the default
102 # behavior is to add missing attribute
103 hashOverwrittenAtt = { "prefixMap": replace, "systemMayContain": replace,
104 "systemOnly":replace, "searchFlags":replace,
105 "mayContain":replace, "systemFlags":replace+add,
106 "description":replace, "operatingSystemVersion":replace,
107 "adminPropertyPages":replace, "groupType":replace,
108 "wellKnownObjects":replace, "privilege":never,
109 "defaultSecurityDescriptor": replace,
110 "rIDAvailablePool": never,
111 "defaultSecurityDescriptor": replace + add }
117 def define_what_to_log(opts):
121 if opts.debugchangesd:
122 what = what | CHANGESD
125 if opts.debugprovision:
126 what = what | PROVISION
128 what = what | CHANGEALL
132 parser = optparse.OptionParser("provision [options]")
133 sambaopts = options.SambaOptions(parser)
134 parser.add_option_group(sambaopts)
135 parser.add_option_group(options.VersionOptions(parser))
136 credopts = options.CredentialsOptions(parser)
137 parser.add_option_group(credopts)
138 parser.add_option("--setupdir", type="string", metavar="DIR",
139 help="directory with setup files")
140 parser.add_option("--debugprovision", help="Debug provision", action="store_true")
141 parser.add_option("--debugguess", action="store_true",
142 help="Print information on what is different but won't be changed")
143 parser.add_option("--debugchange", action="store_true",
144 help="Print information on what is different but won't be changed")
145 parser.add_option("--debugchangesd", action="store_true",
146 help="Print information security descriptors differences")
147 parser.add_option("--debugall", action="store_true",
148 help="Print all available information (very verbose)")
149 parser.add_option("--full", action="store_true",
150 help="Perform full upgrade of the samdb (schema, configuration, new objects, ...")
152 opts = parser.parse_args()[0]
154 handler = logging.StreamHandler(sys.stdout)
155 upgrade_logger = logging.getLogger("upgradeprovision")
156 upgrade_logger.addHandler(handler)
158 provision_logger = logging.getLogger("provision")
159 provision_logger.addHandler(handler)
161 whatToLog = define_what_to_log(opts)
163 def message(what, text):
164 """Print a message if this message type has been selected to be printed
166 :param what: Category of the message
167 :param text: Message to print """
168 if (whatToLog & what) or what <= 0:
169 upgrade_logger.info("%s", text)
171 if len(sys.argv) == 1:
172 opts.interactive = True
173 lp = sambaopts.get_loadparm()
174 smbconf = lp.configfile
176 creds = credopts.get_credentials(lp)
177 creds.set_kerberos_state(DONT_USE_KERBEROS)
178 setup_dir = opts.setupdir
179 if setup_dir is None:
180 setup_dir = find_setup_dir()
184 def check_for_DNS(refprivate, private):
185 """Check if the provision has already the requirement for dynamic dns
187 :param refprivate: The path to the private directory of the reference
189 :param private: The path to the private directory of the upgraded
192 spnfile = "%s/spn_update_list" % private
193 namedfile = lp.get("dnsupdate:path")
196 namedfile = "%s/named.conf.update" % private
198 if not os.path.exists(spnfile):
199 shutil.copy("%s/spn_update_list" % refprivate, "%s" % spnfile)
201 destdir = "%s/new_dns" % private
202 dnsdir = "%s/dns" % private
204 if not os.path.exists(namedfile):
205 if not os.path.exists(destdir):
207 if not os.path.exists(dnsdir):
209 shutil.copy("%s/named.conf" % refprivate, "%s/named.conf" % destdir)
210 shutil.copy("%s/named.txt" % refprivate, "%s/named.txt" % destdir)
211 message(SIMPLE, "It seems that you provision didn't integrate new rules "
212 "for dynamic dns update of domain related entries")
213 message(SIMPLE, "A copy of the new bind configuration files and "
214 "template as been put in %s, you should read them and configure dynamic "
215 " dns update" % destdir)
218 def populate_links(samdb, schemadn):
219 """Populate an array with all the back linked attributes
221 This attributes that are modified automaticaly when
222 front attibutes are changed
224 :param samdb: A LDB object for sam.ldb file
225 :param schemadn: DN of the schema for the partition"""
226 linkedAttHash = get_linked_attributes(Dn(samdb, str(schemadn)), samdb)
227 backlinked.extend(linkedAttHash.values())
228 for t in linkedAttHash.keys():
231 def populate_dnsyntax(samdb, schemadn):
232 """Populate an array with all the attributes that have DN synthax
235 :param samdb: A LDB object for sam.ldb file
236 :param schemadn: DN of the schema for the partition"""
237 res = samdb.search(expression="(attributeSyntax=2.5.5.1)", base=Dn(samdb,
238 str(schemadn)), scope=SCOPE_SUBTREE,
239 attrs=["lDAPDisplayName"])
241 dn_syntax_att.append(elem["lDAPDisplayName"])
244 def sanitychecks(samdb, names):
245 """Make some checks before trying to update
247 :param samdb: An LDB object opened on sam.ldb
248 :param names: list of key provision parameters
249 :return: Status of check (1 for Ok, 0 for not Ok) """
250 res = samdb.search(expression="objectClass=ntdsdsa", base=str(names.configdn),
251 scope=SCOPE_SUBTREE, attrs=["dn"],
252 controls=["search_options:1:2"])
254 print "No DC found, your provision is most probably hardly broken !"
257 print "Found %d domain controllers, for the moment upgradeprovision" \
258 "is not able to handle upgrade on domain with more than one DC, please demote" \
259 " the other(s) DC(s) before upgrading" % len(res)
265 def print_provision_key_parameters(names):
266 """Do a a pretty print of provision parameters
268 :param names: list of key provision parameters """
269 message(GUESS, "rootdn :" + str(names.rootdn))
270 message(GUESS, "configdn :" + str(names.configdn))
271 message(GUESS, "schemadn :" + str(names.schemadn))
272 message(GUESS, "serverdn :" + str(names.serverdn))
273 message(GUESS, "netbiosname :" + names.netbiosname)
274 message(GUESS, "defaultsite :" + names.sitename)
275 message(GUESS, "dnsdomain :" + names.dnsdomain)
276 message(GUESS, "hostname :" + names.hostname)
277 message(GUESS, "domain :" + names.domain)
278 message(GUESS, "realm :" + names.realm)
279 message(GUESS, "invocationid:" + names.invocation)
280 message(GUESS, "policyguid :" + names.policyid)
281 message(GUESS, "policyguiddc:" + str(names.policyid_dc))
282 message(GUESS, "domainsid :" + str(names.domainsid))
283 message(GUESS, "domainguid :" + names.domainguid)
284 message(GUESS, "ntdsguid :" + names.ntdsguid)
285 message(GUESS, "domainlevel :" + str(names.domainlevel))
288 def handle_special_case(att, delta, new, old, usn):
289 """Define more complicate update rules for some attributes
291 :param att: The attribute to be updated
292 :param delta: A messageElement object that correspond to the difference
293 between the updated object and the reference one
294 :param new: The reference object
295 :param old: The Updated object
296 :param usn: The highest usn modified by a previous (upgrade)provision
297 :return: True to indicate that the attribute should be kept, False for
300 flag = delta.get(att).flags()
301 # We do most of the special case handle if we do not have the
302 # highest usn as otherwise the replPropertyMetaData will guide us more
305 if (att == "member" and flag == FLAG_MOD_REPLACE):
309 for elem in old[0][att]:
311 newval.append(str(elem))
313 for elem in new[0][att]:
314 if not hash.has_key(str(elem)):
316 newval.append(str(elem))
318 delta[att] = MessageElement(newval, FLAG_MOD_REPLACE, att)
323 if (att == "gPLink" or att == "gPCFileSysPath") and \
324 flag == FLAG_MOD_REPLACE and\
325 str(new[0].dn).lower() == str(old[0].dn).lower():
329 if att == "forceLogoff":
330 ref=0x8000000000000000
331 oldval=int(old[0][att][0])
332 newval=int(new[0][att][0])
333 ref == old and ref == abs(new)
336 if (att == "adminDisplayName" or att == "adminDescription"):
339 if (str(old[0].dn) == "CN=Samba4-Local-Domain, %s" % (str(names.schemadn))\
340 and att == "defaultObjectCategory" and flag == FLAG_MOD_REPLACE):
343 if (str(old[0].dn) == "CN=Title, %s" % (str(names.schemadn)) and
344 att == "rangeUpper" and flag == FLAG_MOD_REPLACE):
347 if (str(old[0].dn) == "%s" % (str(names.rootdn))
348 and att == "subRefs" and flag == FLAG_MOD_REPLACE):
351 if str(delta.dn).endswith("CN=DisplaySpecifiers, %s" % names.configdn):
354 # This is a bit of special animal as we might have added
355 # already SPN entries to the list that has to be modified
356 # So we go in detail to try to find out what has to be added ...
357 if ( att == "servicePrincipalName" and flag == FLAG_MOD_REPLACE):
361 for elem in old[0][att]:
363 newval.append(str(elem))
365 for elem in new[0][att]:
366 if not hash.has_key(str(elem)):
368 newval.append(str(elem))
370 delta[att] = MessageElement(newval, FLAG_MOD_REPLACE, att)
377 def update_secrets(newsecrets_ldb, secrets_ldb):
378 """Update secrets.ldb
380 :param newsecrets_ldb: An LDB object that is connected to the secrets.ldb
381 of the reference provision
382 :param secrets_ldb: An LDB object that is connected to the secrets.ldb
383 of the updated provision"""
385 message(SIMPLE, "update secrets.ldb")
386 reference = newsecrets_ldb.search(expression="dn=@MODULES", base="",
388 current = secrets_ldb.search(expression="dn=@MODULES", base="",
390 delta = secrets_ldb.msg_diff(current[0], reference[0])
391 delta.dn = current[0].dn
392 secrets_ldb.modify(delta)
394 reference = newsecrets_ldb.search(expression="objectClass=top", base="",
395 scope=SCOPE_SUBTREE, attrs=["dn"])
396 current = secrets_ldb.search(expression="objectClass=top", base="",
397 scope=SCOPE_SUBTREE, attrs=["dn"])
404 for i in range(0, len(reference)):
405 hash_new[str(reference[i]["dn"]).lower()] = reference[i]["dn"]
407 # Create a hash for speeding the search of existing object in the
409 for i in range(0, len(current)):
410 hash[str(current[i]["dn"]).lower()] = current[i]["dn"]
412 for k in hash_new.keys():
413 if not hash.has_key(k):
414 listMissing.append(hash_new[k])
416 listPresent.append(hash_new[k])
418 for entry in listMissing:
419 reference = newsecrets_ldb.search(expression="dn=%s"%entry,base="", scope=SCOPE_SUBTREE)
420 current = secrets_ldb.search(expression="dn=%s"%entry,base="", scope=SCOPE_SUBTREE)
421 delta = secrets_ldb.msg_diff(empty,reference[0])
422 for att in hashAttrNotCopied.keys():
424 message(CHANGE, "Entry %s is missing from secrets.ldb"%reference[0].dn)
426 message(CHANGE, " Adding attribute %s"%att)
427 delta.dn = reference[0].dn
428 secrets_ldb.add(delta)
430 for entry in listPresent:
431 reference = newsecrets_ldb.search(expression="dn=%s"%entry,base="", scope=SCOPE_SUBTREE)
432 current = secrets_ldb.search(expression="dn=%s"%entry,base="", scope=SCOPE_SUBTREE)
433 delta = secrets_ldb.msg_diff(current[0],reference[0])
434 for att in hashAttrNotCopied.keys():
438 message(CHANGE, "Found attribute name on %s, must rename the DN "%(current[0].dn))
439 identic_rename(secrets_ldb,reference[0].dn)
443 for entry in listPresent:
444 reference = newsecrets_ldb.search(expression="dn=%s"%entry,base="", scope=SCOPE_SUBTREE)
445 current = secrets_ldb.search(expression="dn=%s"%entry,base="", scope=SCOPE_SUBTREE)
446 delta = secrets_ldb.msg_diff(current[0],reference[0])
447 for att in hashAttrNotCopied.keys():
451 message(CHANGE, " Adding/Changing attribute %s to %s"%(att,current[0].dn))
453 delta.dn = current[0].dn
454 secrets_ldb.modify(delta)
457 def dump_denied_change(dn, att, flagtxt, current, reference):
458 """Print detailed information about why a changed is denied
460 :param dn: DN of the object which attribute is denied
461 :param att: Attribute that was supposed to be upgraded
462 :param flagtxt: Type of the update that should be performed
463 (add, change, remove, ...)
464 :param current: Value(s) of the current attribute
465 :param reference: Value(s) of the reference attribute"""
467 message(CHANGE, "dn= " + str(dn)+" " + att+" with flag " + flagtxt
468 +" is not allowed to be changed/removed, I discard this change")
469 if att != "objectSid" :
471 for e in range(0, len(current)):
472 message(CHANGE, "old %d : %s" % (i, str(current[e])))
474 if reference != None:
476 for e in range(0, len(reference)):
477 message(CHANGE, "new %d : %s" % (i, str(reference[e])))
480 message(CHANGE, "old : %s" % str(ndr_unpack( security.dom_sid, current[0])))
481 message(CHANGE, "new : %s" % str(ndr_unpack( security.dom_sid, reference[0])))
484 def handle_special_add(samdb, dn, names):
485 """Handle special operation (like remove) on some object needed during
488 This is mostly due to wrong creation of the object in previous provision.
489 :param samdb: An Ldb object representing the SAM database
490 :param dn: DN of the object to inspect
491 :param names: list of key provision parameters"""
494 if str(dn).lower() == ("CN=IIS_IUSRS, CN=Builtin, %s" % names.rootdn).lower():
495 #This entry was misplaced lets remove it if it exists
496 dntoremove = "CN=IIS_IUSRS, CN=Users, %s" % names.rootdn
498 objname = "CN=Certificate Service DCOM Access, CN=Builtin, %s" % names.rootdn
499 if str(dn).lower() == objname.lower():
500 #This entry was misplaced lets remove it if it exists
501 dntoremove = "CN=Certificate Service DCOM Access,"\
502 "CN=Users, %s" % names.rootdn
504 objname = "CN=Cryptographic Operators, CN=Builtin, %s" % names.rootdn
505 if str(dn).lower() == objname.lower():
506 #This entry was misplaced lets remove it if it exists
507 dntoremove = "CN=Cryptographic Operators, CN=Users, %s" % names.rootdn
509 objname = "CN=Event Log Readers, CN=Builtin, %s" % names.rootdn
510 if str(dn).lower() == objname.lower():
511 #This entry was misplaced lets remove it if it exists
512 dntoremove = "CN=Event Log Readers, CN=Users, %s" % names.rootdn
514 if dntoremove != None:
515 res = samdb.search(expression="(dn=%s)" % dntoremove,
516 base=str(names.rootdn),
517 scope=SCOPE_SUBTREE, attrs=["dn"],
518 controls=["search_options:1:2"])
520 message(CHANGE, "Existing object %s must be replaced by %s,"\
521 "removing old object" % (dntoremove, str(dn)))
522 samdb.delete(res[0]["dn"])
525 def check_dn_nottobecreated(hash, index, listdn):
526 """Check if one of the DN present in the list has a creation order
527 greater than the current.
529 Hash is indexed by dn to be created, with each key
530 is associated the creation order.
532 First dn to be created has the creation order 0, second has 1, ...
533 Index contain the current creation order
535 :param hash: Hash holding the different DN of the object to be
537 :param index: Current creation order
538 :param listdn: List of DNs on which the current DN depends on
539 :return: None if the current object do not depend on other
540 object or if all object have been created before."""
544 key = str(dn).lower()
545 if hash.has_key(key) and hash[key] > index:
551 def add_missing_object(ref_samdb, samdb, dn, names, basedn, hash, index):
552 """Add a new object if the dependencies are satisfied
554 The function add the object if the object on which it depends are already
557 :param ref_samdb: Ldb object representing the SAM db of the reference
559 :param samdb: Ldb object representing the SAM db of the upgraded
561 :param dn: DN of the object to be added
562 :param names: List of key provision parameters
563 :param basedn: DN of the partition to be updated
564 :param hash: Hash holding the different DN of the object to be
566 :param index: Current creation order
567 :return: True if the object was created False otherwise"""
569 handle_special_add(samdb, dn, names)
570 reference = ref_samdb.search(expression="dn=%s" % (str(dn)), base=basedn,
571 scope=SCOPE_SUBTREE, controls=["search_options:1:2"])
573 delta = samdb.msg_diff(empty, reference[0])
575 for att in hashAttrNotCopied.keys():
577 for att in backlinked:
579 depend_on_yettobecreated = None
580 for att in dn_syntax_att:
581 depend_on_yet_tobecreated = check_dn_nottobecreated(hash, index,
583 if depend_on_yet_tobecreated != None:
584 message(CHANGE, "Object %s depends on %s in attribute %s," \
585 "delaying the creation" % (str(dn), \
586 depend_on_yet_tobecreated, str(att)))
590 message(CHANGE,"Object %s will be added" % dn)
591 samdb.add(delta, ["relax:0"])
594 def gen_dn_index_hash(listMissing):
595 """Generate a hash associating the DN to its creation order
597 :param listMissing: List of DN
598 :return: Hash with DN as keys and creation order as values"""
600 for i in range(0, len(listMissing)):
601 hash[str(listMissing[i]).lower()] = i
604 def add_deletedobj_containers(ref_samdb, samdb, names):
605 """Add the object containter: CN=Deleted Objects
607 This function create the container for each partition that need one and
608 then reference the object into the root of the partition
610 :param ref_samdb: Ldb object representing the SAM db of the reference
612 :param samdb: Ldb object representing the SAM db of the upgraded provision
613 :param names: List of key provision parameters"""
616 wkoPrefix = "B:32:18E2EA80684F11D2B9AA00C04F79F805"
617 partitions = [str(names.rootdn), str(names.configdn)]
618 for part in partitions:
619 ref_delObjCnt = ref_samdb.search(expression="(cn=Deleted Objects)",
620 base=part, scope=SCOPE_SUBTREE,
622 controls=["show_deleted:0"])
623 delObjCnt = samdb.search(expression="(cn=Deleted Objects)",
624 base=part, scope=SCOPE_SUBTREE,
626 controls=["show_deleted:0"])
627 if len(ref_delObjCnt) > len(delObjCnt):
628 reference = ref_samdb.search(expression="cn=Deleted Objects",
629 base=part, scope=SCOPE_SUBTREE,
630 controls=["show_deleted:0"])
632 delta = samdb.msg_diff(empty, reference[0])
634 delta.dn = Dn(samdb, str(reference[0]["dn"]))
635 for att in hashAttrNotCopied.keys():
640 res = samdb.search(expression="(objectClass=*)", base=part,
642 attrs=["dn", "wellKnownObjects"])
644 targetWKO = "%s:%s" % (wkoPrefix, str(reference[0]["dn"]))
648 wko = res[0]["wellKnownObjects"]
650 # The wellKnownObject that we want to add.
652 if str(o) == targetWKO:
654 listwko.append(str(o))
657 listwko.append(targetWKO)
660 delta.dn = Dn(samdb, str(res[0]["dn"]))
661 delta["wellKnownObjects"] = MessageElement(listwko,
666 def add_missing_entries(ref_samdb, samdb, names, basedn, list):
667 """Add the missing object whose DN is the list
669 The function add the object if the objects on which it depends are
672 :param ref_samdb: Ldb object representing the SAM db of the reference
674 :param samdb: Ldb object representing the SAM db of the upgraded
676 :param dn: DN of the object to be added
677 :param names: List of key provision parameters
678 :param basedn: DN of the partition to be updated
679 :param list: List of DN to be added in the upgraded provision"""
684 while(len(listDefered) != len(listMissing) and len(listDefered) > 0):
686 listMissing = listDefered
688 hashMissing = gen_dn_index_hash(listMissing)
689 for dn in listMissing:
690 ret = add_missing_object(ref_samdb, samdb, dn, names, basedn,
694 # DN can't be created because it depends on some
695 # other DN in the list
696 listDefered.append(dn)
697 if len(listDefered) != 0:
698 raise ProvisioningError("Unable to insert missing elements:" \
699 "circular references")
701 def handle_links(samdb, att, basedn, dn, value, ref_value, delta):
702 """This function handle updates on links
704 :param samdb: An LDB object pointing to the updated provision
705 :param att: Attribute to update
706 :param basedn: The root DN of the provision
707 :param dn: The DN of the inspected object
708 :param value: The value of the attribute
709 :param ref_value: The value of this attribute in the reference provision
710 :param delta: The MessageElement object that will be applied for
711 transforming the current provision"""
713 res = samdb.search(expression="dn=%s" % dn, base=basedn,
714 controls=["search_options:1:2", "reveal:1"],
722 newlinklist.extend(value)
726 # for w2k domain level the reveal won't reveal anything ...
727 # it means that we can readd links that were removed on purpose ...
728 # Also this function in fact just accept add not removal
730 for e in res[0][att]:
731 if not hash.has_key(e):
732 # We put in the blacklist all the element that are in the "revealed"
733 # result and not in the "standard" result
734 # This element are links that were removed before and so that
735 # we don't wan't to readd
739 if not blacklist.has_key(e) and not hash.has_key(e):
740 newlinklist.append(str(e))
743 delta[att] = MessageElement(newlinklist, FLAG_MOD_REPLACE, att)
747 def update_present(ref_samdb, samdb, basedn, listPresent, usns, invocationid):
748 """ This function updates the object that are already present in the
751 :param ref_samdb: An LDB object pointing to the reference provision
752 :param samdb: An LDB object pointing to the updated provision
753 :param basedn: A string with the value of the base DN for the provision
755 :param listPresent: A list of object that is present in the provision
756 :param usns: A list of USN range modified by previous provision and
758 :param invocationid: The value of the invocationid for the current DC"""
761 # This hash is meant to speedup lookup of attribute name from an oid,
762 # it's for the replPropertyMetaData handling
764 res = samdb.search(expression="objectClass=attributeSchema", base=basedn,
765 controls=["search_options:1:2"], attrs=["attributeID",
769 strDisplay = str(e.get("lDAPDisplayName"))
770 hash_oid_name[str(e.get("attributeID"))] = strDisplay
772 msg = "Unable to insert missing elements: circular references"
773 raise ProvisioningError(msg)
776 controls = ["search_options:1:2", "sd_flags:1:2"]
777 for dn in listPresent:
778 reference = ref_samdb.search(expression="dn=%s" % (str(dn)), base=basedn,
781 current = samdb.search(expression="dn=%s" % (str(dn)), base=basedn,
782 scope=SCOPE_SUBTREE, controls=controls)
785 (str(current[0].dn) != str(reference[0].dn)) and
786 (str(current[0].dn).upper() == str(reference[0].dn).upper())
788 message(CHANGE, "Name are the same but case change,"\
789 "let's rename %s to %s" % (str(current[0].dn),
790 str(reference[0].dn)))
791 identic_rename(samdb, reference[0].dn)
792 current = samdb.search(expression="dn=%s" % (str(dn)), base=basedn,
794 controls=["search_options:1:2"])
796 delta = samdb.msg_diff(current[0], reference[0])
798 for att in hashAttrNotCopied.keys():
801 for att in backlinked:
806 if len(delta.items()) > 1 and usns != None:
807 # Fetch the replPropertyMetaData
808 res = samdb.search(expression="dn=%s" % (str(dn)), base=basedn,
809 scope=SCOPE_SUBTREE, controls=controls,
810 attrs=["replPropertyMetaData"])
811 ctr = ndr_unpack(drsblobs.replPropertyMetaDataBlob,
812 str(res[0]["replPropertyMetaData"])).ctr
816 # We put in this hash only modification
817 # made on the current host
818 att = hash_oid_name[samdb.get_oid_from_attid(o.attid)]
819 if str(o.originating_invocation_id) == str(invocationid):
820 hash_attr_usn[att] = o.originating_usn
822 hash_attr_usn[att] = -1
828 if forwardlinked.has_key(att):
829 handle_links(samdb, att, basedn, current[0]["dn"],
830 current[0][att], reference[0][att], delta)
832 if isFirst == 0 and len(delta.items())>1:
834 txt = "%s\n" % (str(dn))
837 if att == "rIDAvailablePool":
840 if att == "objectSid":
843 if att == "creationTime":
846 if att == "oEMInformation":
849 if att == "msDs-KeyVersionNumber":
852 if handle_special_case(att, delta, reference, current, usns):
853 # This attribute is "complicated" to handle and handling
854 # was done in handle_special_case
856 attrUSN = hash_attr_usn.get(att)
857 if att == "forceLogoff" and attrUSN == None:
864 # This attribute was last modified by another DC forget
866 message(CHANGE, "%sAttribute: %s has been" \
867 "created/modified/deleted by another DC,"
868 " do nothing" % (txt, att ))
872 elif usn_in_range(int(attrUSN), usns) == 0:
873 message(CHANGE, "%sAttribute: %s has been" \
874 "created/modified/deleted not during a" \
875 " provision or upgradeprovision: current" \
876 " usn %d , do nothing" % (txt, att, attrUSN))
881 if att == "defaultSecurityDescriptor":
884 message(CHANGE, "%sAttribute: %s will be modified" \
885 "/deleted it was last modified" \
886 "during a provision, current usn:" \
887 "%d" % (txt, att, attrUSN))
890 message(CHANGE, "%sAttribute: %s will be added because" \
891 " it hasn't existed before " % (txt, att))
896 # Old school way of handling things for pre alpha12 upgrade
898 msgElt = delta.get(att)
900 if att == "nTSecurityDescriptor":
907 if not hashOverwrittenAtt.has_key(att):
908 if msgElt.flags() != FLAG_MOD_ADD:
909 if not handle_special_case(att, delta, reference, current,
911 if opts.debugchange or opts.debugall:
913 dump_denied_change(dn, att,
914 messageEltFlagToString(msgElt.flags()),
915 current[0][att], reference[0][att])
917 dump_denied_change(dn, att,
918 messageEltFlagToString(msgElt.flags()),
919 current[0][att], None)
923 if hashOverwrittenAtt.get(att)&2**msgElt.flags() :
925 elif hashOverwrittenAtt.get(att)==never:
930 if len(delta.items()) >1:
931 attributes=", ".join(delta.keys())
932 message(CHANGE, "%s is different from the reference one, changed" \
933 " attributes: %s\n" % (dn, attributes))
934 changed = changed + 1
938 def update_partition(ref_samdb, samdb, basedn, names, schema, provisionUSNs):
939 """Check differences between the reference provision and the upgraded one.
941 It looks for all objects which base DN is name.
943 This function will also add the missing object and update existing object
944 to add or remove attributes that were missing.
946 :param ref_sambdb: An LDB object conntected to the sam.ldb of the
948 :param samdb: An LDB object connected to the sam.ldb of the update
950 :param basedn: String value of the DN of the partition
951 :param names: List of key provision parameters
952 :param schema: A Schema object
953 :param provisionUSNs: The USNs modified by provision/upgradeprovision
963 # Connect to the reference provision and get all the attribute in the
964 # partition referred by name
965 reference = ref_samdb.search(expression="objectClass=*", base=basedn,
966 scope=SCOPE_SUBTREE, attrs=["dn"],
967 controls=["search_options:1:2"])
969 current = samdb.search(expression="objectClass=*", base=basedn,
970 scope=SCOPE_SUBTREE, attrs=["dn"],
971 controls=["search_options:1:2"])
972 # Create a hash for speeding the search of new object
973 for i in range(0, len(reference)):
974 hash_new[str(reference[i]["dn"]).lower()] = reference[i]["dn"]
976 # Create a hash for speeding the search of existing object in the
978 for i in range(0, len(current)):
979 hash[str(current[i]["dn"]).lower()] = current[i]["dn"]
982 for k in hash_new.keys():
983 if not hash.has_key(k):
984 if not str(hash_new[k]) == "CN=Deleted Objects, %s" % names.rootdn:
985 listMissing.append(hash_new[k])
987 listPresent.append(hash_new[k])
989 # Sort the missing object in order to have object of the lowest level
990 # first (which can be containers for higher level objects)
991 listMissing.sort(dn_sort)
992 listPresent.sort(dn_sort)
994 # The following lines is to load the up to
995 # date schema into our current LDB
996 # a complete schema is needed as the insertion of attributes
997 # and class is done against it
998 # and the schema is self validated
999 samdb.set_schema_from_ldb(schema.ldb)
1001 message(SIMPLE, "There are %d missing objects" % (len(listMissing)))
1002 add_deletedobj_containers(ref_samdb, samdb, names)
1004 add_missing_entries(ref_samdb, samdb, names, basedn, listMissing)
1005 changed = update_present(ref_samdb, samdb, basedn, listPresent,
1006 provisionUSNs, names.invocation)
1007 message(SIMPLE, "There are %d changed objects" % (changed))
1010 except StandardError, err:
1011 message(ERROR, "Exception during upgrade of samdb:")
1012 (typ, val, tb) = sys.exc_info()
1013 traceback.print_exception(typ, val, tb)
1018 def check_updated_sd(ref_sam, cur_sam, names):
1019 """Check if the security descriptor in the upgraded provision are the same
1022 :param ref_sam: A LDB object connected to the sam.ldb file used as
1023 the reference provision
1024 :param cur_sam: A LDB object connected to the sam.ldb file used as
1026 :param names: List of key provision parameters"""
1027 reference = ref_sam.search(expression="objectClass=*", base=str(names.rootdn),
1028 scope=SCOPE_SUBTREE,
1029 attrs=["dn", "nTSecurityDescriptor"],
1030 controls=["search_options:1:2"])
1031 current = cur_sam.search(expression="objectClass=*", base=str(names.rootdn),
1032 scope=SCOPE_SUBTREE,
1033 attrs=["dn", "nTSecurityDescriptor"],
1034 controls=["search_options:1:2"])
1036 for i in range(0, len(reference)):
1037 refsd = ndr_unpack(security.descriptor,
1038 str(reference[i]["nTSecurityDescriptor"]))
1039 hash[str(reference[i]["dn"]).lower()] = refsd.as_sddl(names.domainsid)
1041 for i in range(0, len(current)):
1042 key = str(current[i]["dn"]).lower()
1043 if hash.has_key(key):
1044 cursd = ndr_unpack(security.descriptor,
1045 str(current[i]["nTSecurityDescriptor"]))
1046 sddl = cursd.as_sddl(names.domainsid)
1047 if sddl != hash[key]:
1048 txt = get_diff_sddls(hash[key], sddl)
1050 message(CHANGESD, "On object %s ACL is different"\
1051 " \n%s" % (current[i]["dn"], txt))
1055 def fix_partition_sd(samdb, names):
1056 """This function fix the SD for partition containers (basedn, configdn, ...)
1057 This is needed because some provision use to have broken SD on containers
1059 :param samdb: An LDB object pointing to the sam of the current provision
1060 :param names: A list of key provision parameters
1062 # First update the SD for the rootdn
1063 res = samdb.search(expression="objectClass=*", base=str(names.rootdn),
1064 scope=SCOPE_BASE, attrs=["dn", "whenCreated"],
1065 controls=["search_options:1:2"])
1067 delta.dn = Dn(samdb, str(res[0]["dn"]))
1068 descr = get_domain_descriptor(names.domainsid)
1069 delta["nTSecurityDescriptor"] = MessageElement(descr, FLAG_MOD_REPLACE,
1070 "nTSecurityDescriptor")
1071 samdb.modify(delta, ["recalculate_sd:0"])
1072 # Then the config dn
1073 res = samdb.search(expression="objectClass=*", base=str(names.configdn),
1074 scope=SCOPE_BASE, attrs=["dn", "whenCreated"],
1075 controls=["search_options:1:2"])
1077 delta.dn = Dn(samdb, str(res[0]["dn"]))
1078 descr = get_config_descriptor(names.domainsid)
1079 delta["nTSecurityDescriptor"] = MessageElement(descr, FLAG_MOD_REPLACE,
1080 "nTSecurityDescriptor" )
1081 samdb.modify(delta, ["recalculate_sd:0"])
1082 # Then the schema dn
1083 res = samdb.search(expression="objectClass=*", base=str(names.schemadn),
1084 scope=SCOPE_BASE, attrs=["dn", "whenCreated"],
1085 controls=["search_options:1:2"])
1088 delta.dn = Dn(samdb, str(res[0]["dn"]))
1089 descr = get_schema_descriptor(names.domainsid)
1090 delta["nTSecurityDescriptor"] = MessageElement(descr, FLAG_MOD_REPLACE,
1091 "nTSecurityDescriptor" )
1092 samdb.modify(delta, ["recalculate_sd:0"])
1094 def rebuild_sd(samdb, names):
1095 """Rebuild security descriptor of the current provision from scratch
1097 During the different pre release of samba4 security descriptors (SD)
1098 were notarly broken (up to alpha11 included)
1099 This function allow to get them back in order, this function make the
1100 assumption that nobody has modified manualy an SD
1101 and so SD can be safely recalculated from scratch to get them right.
1103 :param names: List of key provision parameters"""
1107 res = samdb.search(expression="objectClass=*", base=str(names.rootdn),
1108 scope=SCOPE_SUBTREE, attrs=["dn", "whenCreated"],
1109 controls=["search_options:1:2"])
1111 if not (str(obj["dn"]) == str(names.rootdn) or
1112 str(obj["dn"]) == str(names.configdn) or \
1113 str(obj["dn"]) == str(names.schemadn)):
1114 hash[str(obj["dn"])] = obj["whenCreated"]
1116 listkeys = hash.keys()
1117 listkeys.sort(dn_sort)
1119 for key in listkeys:
1122 delta.dn = Dn(samdb, key)
1123 delta["whenCreated"] = MessageElement(hash[key], FLAG_MOD_REPLACE,
1125 samdb.modify(delta, ["recalculate_sd:0"])
1127 # XXX: We should always catch an explicit exception.
1128 # What could go wrong here?
1129 samdb.transaction_cancel()
1130 res = samdb.search(expression="objectClass=*", base=str(names.rootdn),
1131 scope=SCOPE_SUBTREE,
1132 attrs=["dn", "nTSecurityDescriptor"],
1133 controls=["search_options:1:2"])
1134 badsd = ndr_unpack(security.descriptor,
1135 str(res[0]["nTSecurityDescriptor"]))
1136 print "bad stuff %s"%badsd.as_sddl(names.domainsid)
1139 def removeProvisionUSN(samdb):
1140 attrs = [samba.provision.LAST_PROVISION_USN_ATTRIBUTE, "dn"]
1141 entry = samdb.search(expression="dn=@PROVISION", base = "",
1142 scope=SCOPE_SUBTREE,
1143 controls=["search_options:1:2"],
1146 empty.dn = entry[0].dn
1147 delta = samdb.msg_diff(entry[0], empty)
1149 delta.dn = entry[0].dn
1152 def delta_update_basesamdb(refpaths, paths, creds, session, lp):
1153 """Update the provision container db: sam.ldb
1154 This function is aimed for alpha9 and newer;
1156 :param refpaths: An object holding the different importants paths for
1157 reference provision object
1158 :param paths: An object holding the different importants paths for
1159 upgraded provision object
1160 :param creds: Credential used for openning LDB files
1161 :param session: Session to use for openning LDB files
1162 :param lp: A loadparam object"""
1165 "Update base samdb by searching difference with reference one")
1166 refsam = Ldb(refpaths.samdb, session_info=session, credentials=creds,
1167 lp=lp, options=["modules:"])
1168 sam = Ldb(paths.samdb, session_info=session, credentials=creds, lp=lp,
1169 options=["modules:"])
1173 reference = refsam.search(expression="")
1175 for refentry in reference:
1176 entry = sam.search(expression="dn=%s" % refentry["dn"],
1177 scope=SCOPE_SUBTREE)
1179 message(CHANGE, "Adding %s to sam db" % str(delta.dn))
1180 delta = sam.msg_diff(empty, refentry)
1181 if str(refentry.dn) == "@PROVISION" and\
1182 delta.get(samba.provision.LAST_PROVISION_USN_ATTRIBUTE):
1183 delta.remove(samba.provision.LAST_PROVISION_USN_ATTRIBUTE)
1184 delta.dn = refentry.dn
1187 delta = sam.msg_diff(entry[0], refentry)
1188 if str(refentry.dn) == "@PROVISION" and\
1189 delta.get(samba.provision.LAST_PROVISION_USN_ATTRIBUTE):
1190 delta.remove(samba.provision.LAST_PROVISION_USN_ATTRIBUTE)
1191 if len(delta.items()) > 1:
1192 delta.dn = refentry.dn
1196 def simple_update_basesamdb(newpaths, paths, names):
1197 """Update the provision container db: sam.ldb
1198 This function is aimed at very old provision (before alpha9)
1200 :param newpaths: List of paths for different provision objects
1201 from the reference provision
1202 :param paths: List of paths for different provision objects
1203 from the upgraded provision
1204 :param names: List of key provision parameters"""
1206 message(SIMPLE, "Copy samdb")
1207 shutil.copy(newpaths.samdb, paths.samdb)
1209 message(SIMPLE, "Update partitions filename if needed")
1210 schemaldb = os.path.join(paths.private_dir, "schema.ldb")
1211 configldb = os.path.join(paths.private_dir, "configuration.ldb")
1212 usersldb = os.path.join(paths.private_dir, "users.ldb")
1213 samldbdir = os.path.join(paths.private_dir, "sam.ldb.d")
1215 if not os.path.isdir(samldbdir):
1217 os.chmod(samldbdir, 0700)
1218 if os.path.isfile(schemaldb):
1219 shutil.copy(schemaldb, os.path.join(samldbdir,
1220 "%s.ldb"%str(names.schemadn).upper()))
1221 os.remove(schemaldb)
1222 if os.path.isfile(usersldb):
1223 shutil.copy(usersldb, os.path.join(samldbdir,
1224 "%s.ldb"%str(names.rootdn).upper()))
1226 if os.path.isfile(configldb):
1227 shutil.copy(configldb, os.path.join(samldbdir,
1228 "%s.ldb"%str(names.configdn).upper()))
1229 os.remove(configldb)
1232 def update_privilege(ref_private_path, cur_private_path):
1233 """Update the privilege database
1235 :param ref_private_path: Path to the private directory of the reference
1237 :param cur_private_path: Path to the private directory of the current
1238 (and to be updated) provision."""
1239 message(SIMPLE, "Copy privilege")
1240 shutil.copy(os.path.join(ref_private_path, "privilege.ldb"),
1241 os.path.join(cur_private_path, "privilege.ldb"))
1244 def update_samdb(ref_samdb, samdb, names, highestUSN, schema):
1245 """Upgrade the SAM DB contents for all the provision partitions
1247 :param ref_sambdb: An LDB object conntected to the sam.ldb of the reference
1249 :param samdb: An LDB object connected to the sam.ldb of the update
1251 :param names: List of key provision parameters
1252 :param highestUSN: The highest USN modified by provision/upgradeprovision
1254 :param schema: A Schema object that represent the schema of the provision"""
1256 message(SIMPLE, "Starting update of samdb")
1257 ret = update_partition(ref_samdb, samdb, str(names.rootdn), names,
1260 message(SIMPLE, "Update of samdb finished")
1263 message(SIMPLE, "Update failed")
1267 def update_machine_account_password(samdb, secrets_ldb, names):
1268 """Update (change) the password of the current DC both in the SAM db and in
1271 :param samdb: An LDB object related to the sam.ldb file of a given provision
1272 :param secrets_ldb: An LDB object related to the secrets.ldb file of a given
1274 :param names: List of key provision parameters"""
1276 message(SIMPLE, "Update machine account")
1277 expression = "samAccountName=%s$" % names.netbiosname
1278 secrets_msg = secrets_ldb.search(expression=expression,
1279 attrs=["secureChannelType"])
1280 if int(secrets_msg[0]["secureChannelType"][0]) == SEC_CHAN_BDC:
1281 res = samdb.search(expression=expression, attrs=[])
1282 assert(len(res) == 1)
1284 msg = Message(res[0].dn)
1285 machinepass = samba.generate_random_password(128, 255)
1286 msg["userPassword"] = MessageElement(machinepass, FLAG_MOD_REPLACE,
1290 res = samdb.search(expression=("samAccountName=%s$" % names.netbiosname),
1291 attrs=["msDs-keyVersionNumber"])
1292 assert(len(res) == 1)
1293 kvno = int(str(res[0]["msDs-keyVersionNumber"]))
1294 secChanType = int(secrets_msg[0]["secureChannelType"][0])
1296 secretsdb_self_join(secrets_ldb, domain=names.domain,
1297 realm=names.realm or sambaopts._lp.get('realm'),
1298 domainsid=names.domainsid,
1299 dnsdomain=names.dnsdomain,
1300 netbiosname=names.netbiosname,
1301 machinepass=machinepass,
1302 key_version_number=kvno,
1303 secure_channel_type=secChanType)
1305 raise ProvisioningError("Unable to find a Secure Channel" \
1306 "of type SEC_CHAN_BDC")
1309 def update_gpo(paths, creds, session, names):
1310 """Create missing GPO file object if needed
1312 Set ACL correctly also.
1314 dir = getpolicypath(paths.sysvol, names.dnsdomain, names.policyid)
1315 if not os.path.isdir(dir):
1316 create_gpo_struct(dir)
1318 dir = getpolicypath(paths.sysvol, names.dnsdomain, names.policyid_dc)
1319 if not os.path.isdir(dir):
1320 create_gpo_struct(dir)
1321 samdb = Ldb(paths.samdb, session_info=session, credentials=creds, lp=lp)
1322 set_gpo_acl(paths.sysvol, names.dnsdomain, names.domainsid,
1323 names.domaindn, samdb, lp)
1326 def getOEMInfo(samdb, rootdn):
1327 """Return OEM Information on the top level
1328 Samba4 use to store version info in this field
1330 :param samdb: An LDB object connect to sam.ldb
1331 :param rootdn: Root DN of the domain
1332 :return: The content of the field oEMInformation (if any)"""
1333 res = samdb.search(expression="(objectClass=*)", base=str(rootdn),
1334 scope=SCOPE_BASE, attrs=["dn", "oEMInformation"])
1336 info = res[0]["oEMInformation"]
1341 def updateOEMInfo(samdb, names):
1342 res = samdb.search(expression="(objectClass=*)", base=str(names.rootdn),
1343 scope=SCOPE_BASE, attrs=["dn", "oEMInformation"])
1345 info = res[0]["oEMInformation"]
1346 info = "%s, upgrade to %s" % (info, version)
1348 delta.dn = Dn(samdb, str(res[0]["dn"]))
1349 delta["oEMInformation"] = MessageElement(info, FLAG_MOD_REPLACE,
1354 def setup_path(file):
1355 return os.path.join(setup_dir, file)
1358 if __name__ == '__main__':
1359 global defSDmodified
1361 # From here start the big steps of the program
1362 # First get files paths
1363 paths = get_paths(param, smbconf=smbconf)
1364 paths.setup = setup_dir
1365 # Get ldbs with the system session, it is needed for searching
1366 # provision parameters
1367 session = system_session()
1369 # This variable will hold the last provision USN once if it exists.
1372 ldbs = get_ldbs(paths, creds, session, lp)
1373 ldbs.startTransactions()
1375 # Guess all the needed names (variables in fact) from the current
1377 names = find_provision_key_parameters(ldbs.sam, ldbs.secrets, paths,
1379 lastProvisionUSNs = getLastProvisionUSN(ldbs.sam)
1380 if lastProvisionUSNs != None:
1382 "Find a last provision USN, %d range(s)" % len(lastProvisionUSNs))
1384 # Objects will be created with the admin session
1385 # (not anymore system session)
1386 adm_session = admin_session(lp, str(names.domainsid))
1387 # So we reget handle on objects
1388 # ldbs = get_ldbs(paths, creds, adm_session, lp)
1390 if not sanitychecks(ldbs.sam, names):
1391 message(SIMPLE, "Sanity checks for the upgrade fails, checks messages" \
1392 " and correct them before rerunning upgradeprovision")
1395 # Let's see provision parameters
1396 print_provision_key_parameters(names)
1398 # 5) With all this information let's create a fresh new provision used as
1400 message(SIMPLE, "Creating a reference provision")
1401 provisiondir = tempfile.mkdtemp(dir=paths.private_dir,
1402 prefix="referenceprovision")
1403 newprovision(names, setup_dir, creds, session, smbconf, provisiondir,
1407 # We need to get a list of object which SD is directly computed from
1408 # defaultSecurityDescriptor.
1409 # This will allow us to know which object we can rebuild the SD in case
1410 # of change of the parent's SD or of the defaultSD.
1411 # Get file paths of this new provision
1412 newpaths = get_paths(param, targetdir=provisiondir)
1413 new_ldbs = get_ldbs(newpaths, creds, session, lp)
1414 new_ldbs.startTransactions()
1416 # Populate some associative array to ease the update process
1417 # List of attribute which are link and backlink
1418 populate_links(new_ldbs.sam, names.schemadn)
1419 # List of attribute with ASN DN synthax)
1420 populate_dnsyntax(new_ldbs.sam, names.schemadn)
1422 update_privilege(newpaths.private_dir, paths.private_dir)
1423 oem = getOEMInfo(ldbs.sam, names.rootdn)
1424 # Do some modification on sam.ldb
1425 ldbs.groupedCommit()
1426 if re.match(".*alpha((9)|(\d\d+)).*", str(oem)):
1427 # Starting from alpha9 we can consider that the structure is quite ok
1428 # and that we should do only dela
1429 new_ldbs.groupedCommit()
1430 delta_update_basesamdb(newpaths, paths, creds, session, lp)
1431 ldbs.startTransactions()
1432 minUSN = get_max_usn(ldbs.sam, str(names.rootdn)) + 1
1433 new_ldbs.startTransactions()
1435 simple_update_basesamdb(newpaths, paths, names)
1436 ldbs = get_ldbs(paths, creds, session, lp)
1437 ldbs.startTransactions()
1438 removeProvisionUSN(ldbs.sam)
1440 schema = Schema(setup_path, names.domainsid, schemadn=str(names.schemadn),
1441 serverdn=str(names.serverdn))
1444 if not update_samdb(new_ldbs.sam, ldbs.sam, names, lastProvisionUSNs,
1446 message(SIMPLE, "Rollbacking every changes. Check the reason" \
1448 message(SIMPLE, "In any case your system as it was before" \
1450 ldbs.groupedRollback()
1451 new_ldbs.groupedRollback()
1452 shutil.rmtree(provisiondir)
1455 update_secrets(new_ldbs.secrets, ldbs.secrets)
1456 update_machine_account_password(ldbs.sam, ldbs.secrets, names)
1458 # SD should be created with admin but as some previous acl were so wrong
1459 # that admin can't modify them we have first to recreate them with the good
1460 # form but with system account and then give the ownership to admin ...
1461 if not re.match(r'.*alpha(9|\d\d+)', str(oem)):
1462 message(SIMPLE, "Fixing old povision SD")
1463 fix_partition_sd(ldbs.sam, names)
1464 rebuild_sd(ldbs.sam, names)
1466 # We calculate the max USN before recalculating the SD because we might
1467 # touch object that have been modified after a provision and we do not
1468 # want that the next upgradeprovision thinks that it has a green light
1471 maxUSN = get_max_usn(ldbs.sam, str(names.rootdn))
1473 # We rebuild SD only if defaultSecurityDescriptor is modified
1474 # But in fact we should do it also if one object has its SD modified as
1475 # child might need rebuild
1476 if defSDmodified == 1:
1477 message(SIMPLE, "Updating SD")
1478 ldbs.sam.set_session_info(adm_session)
1479 # Alpha10 was a bit broken still
1480 if re.match(r'.*alpha(\d|10)', str(oem)):
1481 fix_partition_sd(ldbs.sam, names)
1482 rebuild_sd(ldbs.sam, names)
1484 # Now we are quite confident in the recalculate process of the SD, we make
1486 # Also the check must be done in a clever way as for the moment we just
1488 if opts.debugchangesd:
1489 check_updated_sd(new_ldbs.sam, ldbs.sam, names)
1491 updateOEMInfo(ldbs.sam, names)
1492 check_for_DNS(newpaths.private_dir, paths.private_dir)
1493 if lastProvisionUSNs != None:
1494 updateProvisionUSN(ldbs.sam, minUSN, maxUSN)
1495 ldbs.groupedCommit()
1496 new_ldbs.groupedCommit()
1497 message(SIMPLE, "Upgrade finished !")
1498 # remove reference provision now that everything is done !
1499 shutil.rmtree(provisiondir)