s4 upgradeprovision: fix whitespaces
[kamenim/samba.git] / source4 / scripting / bin / upgradeprovision
index f90443318a88f25fcbcd60356e091b2e9e23a633..400d6296027f9d7c969ae9c14f3d97a1dd5be434 100755 (executable)
@@ -33,6 +33,7 @@ import traceback
 # Allow to run from s4 source directory (without installing samba)
 sys.path.insert(0, "bin/python")
 
+import ldb
 import samba
 import samba.getopt as options
 from samba.credentials import DONT_USE_KERBEROS
@@ -41,22 +42,21 @@ from ldb import (SCOPE_SUBTREE, SCOPE_BASE,
                 FLAG_MOD_REPLACE, FLAG_MOD_ADD, FLAG_MOD_DELETE,
                 MessageElement, Message, Dn)
 from samba import param
-from samba.misc import messageEltFlagToString
 from samba.provision import (find_setup_dir, get_domain_descriptor,
-                            get_config_descriptor, secretsdb_self_join,
-                            ProvisioningError, getLastProvisionUSN,
-                            get_max_usn, updateProvisionUSN)
+                            get_config_descriptor,
+                            ProvisioningError, get_last_provision_usn,
+                            get_max_usn, update_provision_usn)
 from samba.schema import get_linked_attributes, Schema, get_schema_descriptor
 from samba.dcerpc import security, drsblobs
 from samba.ndr import ndr_unpack
-from samba.dcerpc.misc import SEC_CHAN_BDC
 from samba.upgradehelpers import (dn_sort, get_paths, newprovision,
                                  find_provision_key_parameters, get_ldbs,
                                  usn_in_range, identic_rename, get_diff_sddls,
                                  update_secrets, CHANGE, ERROR, SIMPLE,
                                  CHANGEALL, GUESS, CHANGESD, PROVISION,
                                  updateOEMInfo, getOEMInfo, update_gpo,
-                                 delta_update_basesamdb)
+                                 delta_update_basesamdb, update_policyids,
+                                 update_machine_account_password)
 
 replace=2**FLAG_MOD_REPLACE
 add=2**FLAG_MOD_ADD
@@ -107,7 +107,7 @@ hashOverwrittenAtt = {  "prefixMap": replace, "systemMayContain": replace,
 
 
 backlinked = []
-forwardlinked = {}
+forwardlinked = set()
 dn_syntax_att = []
 def define_what_to_log(opts):
     what = 0
@@ -150,6 +150,8 @@ opts = parser.parse_args()[0]
 
 handler = logging.StreamHandler(sys.stdout)
 upgrade_logger = logging.getLogger("upgradeprovision")
+upgrade_logger.setLevel(logging.INFO)
+
 upgrade_logger.addHandler(handler)
 
 provision_logger = logging.getLogger("provision")
@@ -223,7 +225,8 @@ def populate_links(samdb, schemadn):
     linkedAttHash = get_linked_attributes(Dn(samdb, str(schemadn)), samdb)
     backlinked.extend(linkedAttHash.values())
     for t in linkedAttHash.keys():
-        forwardlinked[t] = 1
+        forwardlinked.add(t)
+
 
 def populate_dnsyntax(samdb, schemadn):
     """Populate an array with all the attributes that have DN synthax
@@ -298,7 +301,7 @@ def handle_special_case(att, delta, new, old, usn):
     # We do most of the special case handle if we do not have the
     # highest usn as otherwise the replPropertyMetaData will guide us more
     # correctly
-    if usn == None:
+    if usn is None:
         if (att == "member" and flag == FLAG_MOD_REPLACE):
             hash = {}
             newval = []
@@ -317,9 +320,9 @@ def handle_special_case(att, delta, new, old, usn):
                 delta.remove(att)
             return True
 
-        if (att == "gPLink" or att == "gPCFileSysPath") and \
-            flag == FLAG_MOD_REPLACE and\
-            str(new[0].dn).lower() == str(old[0].dn).lower():
+        if (att in ("gPLink", "gPCFileSysPath") and
+            flag == FLAG_MOD_REPLACE and
+            str(new[0].dn).lower() == str(old[0].dn).lower()):
             delta.remove(att)
             return True
 
@@ -330,10 +333,10 @@ def handle_special_case(att, delta, new, old, usn):
             ref == old and ref == abs(new)
             return True
 
-        if (att == "adminDisplayName" or att == "adminDescription"):
+        if att in ("adminDisplayName", "adminDescription"):
             return True
 
-        if (str(old[0].dn) == "CN=Samba4-Local-Domain, %s" % (str(names.schemadn))\
+        if (str(old[0].dn) == "CN=Samba4-Local-Domain, %s" % (names.schemadn)
             and att == "defaultObjectCategory" and flag == FLAG_MOD_REPLACE):
             return True
 
@@ -351,7 +354,7 @@ def handle_special_case(att, delta, new, old, usn):
     # This is a bit of special animal as we might have added
     # already SPN entries to the list that has to be modified
     # So we go in detail to try to find out what has to be added ...
-    if ( att == "servicePrincipalName" and flag == FLAG_MOD_REPLACE):
+    if (att == "servicePrincipalName" and flag == FLAG_MOD_REPLACE):
         hash = {}
         newval = []
         changeDelta=0
@@ -388,24 +391,25 @@ def dump_denied_change(dn, att, flagtxt, current, reference):
         for e in range(0, len(current)):
             message(CHANGE, "old %d : %s" % (i, str(current[e])))
             i+=1
-        if reference != None:
+        if reference is not None:
             i = 0
             for e in range(0, len(reference)):
                 message(CHANGE, "new %d : %s" % (i, str(reference[e])))
                 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])))
+        message(CHANGE, "old : %s" % ndr_unpack(security.dom_sid, current[0]))
+        message(CHANGE, "new : %s" % ndr_unpack(security.dom_sid, reference[0]))
 
 
 def handle_special_add(samdb, dn, names):
     """Handle special operation (like remove) on some object needed during
-       upgrade
+    upgrade
 
     This is mostly due to wrong creation of the object in previous provision.
     :param samdb: An Ldb object representing the SAM database
     :param dn: DN of the object to inspect
-    :param names: list of key provision parameters"""
+    :param names: list of key provision parameters
+    """
 
     dntoremove = None
     objDn = Dn(samdb, "CN=IIS_IUSRS, CN=Builtin, %s" % names.rootdn)
@@ -431,11 +435,11 @@ def handle_special_add(samdb, dn, names):
         #This entry was misplaced lets remove it if it exists
         dntoremove = "CN=Event Log Readers, CN=Users, %s" % names.rootdn
 
-    objDn = Dn(samdb,"CN=System,CN=WellKnown Security Principals,"\
+    objDn = Dn(samdb,"CN=System,CN=WellKnown Security Principals,"
                      "CN=Configuration,%s" % names.rootdn)
     if dn == objDn:
-        oldDn = Dn(samdb,"CN=Well-Known-Security-Id-System,"\
-                         "CN=WellKnown Security Principals,"\
+        oldDn = Dn(samdb,"CN=Well-Known-Security-Id-System,"
+                         "CN=WellKnown Security Principals,"
                          "CN=Configuration,%s" % names.rootdn)
 
         res = samdb.search(expression="(dn=%s)" % oldDn,
@@ -443,23 +447,24 @@ def handle_special_add(samdb, dn, names):
                             scope=SCOPE_SUBTREE, attrs=["dn"],
                             controls=["search_options:1:2"])
         if len(res) > 0:
-            message(CHANGE, "Existing object %s must be replaced by %s,"\
+            message(CHANGE, "Existing object %s must be replaced by %s,"
                             "Renaming old object" % (str(oldDn), str(dn)))
             samdb.rename(oldDn, objDn)
 
         return 1
 
-    if dntoremove != None:
+    if dntoremove is not None:
         res = samdb.search(expression="(dn=%s)" % dntoremove,
                             base=str(names.rootdn),
                             scope=SCOPE_SUBTREE, attrs=["dn"],
                             controls=["search_options:1:2"])
         if len(res) > 0:
-            message(CHANGE, "Existing object %s must be replaced by %s,"\
+            message(CHANGE, "Existing object %s must be replaced by %s,"
                             "removing old object" % (dntoremove, str(dn)))
             samdb.delete(res[0]["dn"])
     return 0
 
+
 def check_dn_nottobecreated(hash, index, listdn):
     """Check if one of the DN present in the list has a creation order
        greater than the current.
@@ -476,7 +481,7 @@ def check_dn_nottobecreated(hash, index, listdn):
     :param listdn: List of DNs on which the current DN depends on
     :return: None if the current object do not depend on other
               object or if all object have been created before."""
-    if listdn == None:
+    if listdn is None:
         return None
     for dn in listdn:
         key = str(dn).lower()
@@ -511,6 +516,11 @@ def add_missing_object(ref_samdb, samdb, dn, names, basedn, hash, index):
     empty = Message()
     delta = samdb.msg_diff(empty, reference[0])
     delta.dn
+    if delta.get("objectSid"):
+        sid = str(ndr_unpack(security.dom_sid, str(reference[0]["objectSid"])))
+        m = re.match(r".*-(\d+)$", sid)
+        if m and int(m.group(1))>999:
+            delta.remove("objectSid")
     for att in hashAttrNotCopied.keys():
         delta.remove(att)
     for att in backlinked:
@@ -519,15 +529,16 @@ def add_missing_object(ref_samdb, samdb, dn, names, basedn, hash, index):
     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)))
+        if depend_on_yet_tobecreated is not None:
+            message(CHANGE, "Object %s depends on %s in attribute %s,"
+                            "delaying the creation" % (dn,
+                                      depend_on_yet_tobecreated, att))
             return False
 
     delta.dn = dn
     message(CHANGE,"Object %s will be added" % dn)
     samdb.add(delta, ["relax:0"])
+
     return True
 
 def gen_dn_index_hash(listMissing):
@@ -581,7 +592,7 @@ def add_deletedobj_containers(ref_samdb, samdb, names):
                                attrs=["dn", "wellKnownObjects"])
 
             targetWKO = "%s:%s" % (wkoPrefix, str(reference[0]["dn"]))
-            found = 0
+            found = False
 
             if len(res[0]) > 0:
                 wko = res[0]["wellKnownObjects"]
@@ -589,7 +600,7 @@ def add_deletedobj_containers(ref_samdb, samdb, names):
                 # The wellKnownObject that we want to add.
                 for o in wko:
                     if str(o) == targetWKO:
-                        found = 1
+                        found = True
                     listwko.append(str(o))
 
             if not found:
@@ -656,7 +667,7 @@ def handle_links(samdb, att, basedn, dn, value, ref_value, delta):
     blacklist = {}
     hash = {}
     newlinklist = []
-    changed = 0
+    changed = False
 
     newlinklist.extend(value)
 
@@ -677,12 +688,19 @@ def handle_links(samdb, att, basedn, dn, value, ref_value, delta):
     for e in ref_value:
         if not blacklist.has_key(e) and not hash.has_key(e):
             newlinklist.append(str(e))
-            changed = 1
+            changed = True
     if changed:
         delta[att] = MessageElement(newlinklist, FLAG_MOD_REPLACE, att)
     else:
         delta.remove(att)
 
+
+msg_elt_flag_strs = {
+    ldb.FLAG_MOD_ADD: "MOD_ADD",
+    ldb.FLAG_MOD_REPLACE: "MOD_REPLACE",
+    ldb.FLAG_MOD_DELETE: "MOD_DELETE" }
+
+
 def update_present(ref_samdb, samdb, basedn, listPresent, usns, invocationid):
     """ This function updates the object that are already present in the
         provision
@@ -742,7 +760,7 @@ def update_present(ref_samdb, samdb, basedn, listPresent, usns, invocationid):
 
         delta.remove("name")
 
-        if len(delta.items()) > 1 and usns != None:
+        if len(delta.items()) > 1 and usns is not None:
             # Fetch the replPropertyMetaData
             res = samdb.search(expression="dn=%s" % (str(dn)), base=basedn,
                                 scope=SCOPE_SUBTREE, controls=controls,
@@ -765,10 +783,10 @@ def update_present(ref_samdb, samdb, basedn, listPresent, usns, invocationid):
         txt = ""
 
         for att in delta:
-            if usns != None:
+            if usns is not None:
                 # We have updated by provision usn information so let's exploit
                 # replMetadataProperties
-                if forwardlinked.has_key(att):
+                if att in forwardlinked:
                     handle_links(samdb, att, basedn, current[0]["dn"],
                                     current[0][att], reference[0][att], delta)
 
@@ -800,47 +818,47 @@ def update_present(ref_samdb, samdb, basedn, listPresent, usns, invocationid):
                     # was done in handle_special_case
                     continue
                 attrUSN = hash_attr_usn.get(att)
-                if att == "forceLogoff" and attrUSN == None:
+                if att == "forceLogoff" and attrUSN is None:
                     continue
-                if  attrUSN == None:
+                if  attrUSN is None:
                     delta.remove(att)
                     continue
 
                 if attrUSN == -1:
                     # This attribute was last modified by another DC forget
                     # about it
-                    message(CHANGE, "%sAttribute: %s has been" \
+                    message(CHANGE, "%sAttribute: %s has been"
                             "created/modified/deleted  by another DC,"
                             " do nothing" % (txt, att ))
                     txt = ""
                     delta.remove(att)
                     continue
-                elif usn_in_range(int(attrUSN), usns) == 0:
-                    message(CHANGE, "%sAttribute: %s has been" \
-                                    "created/modified/deleted not during a" \
-                                    " provision or upgradeprovision: current" \
+                elif not usn_in_range(int(attrUSN), usns):
+                    message(CHANGE, "%sAttribute: %s has been"
+                                    "created/modified/deleted not during a"
+                                    " provision or upgradeprovision: current"
                                     " usn %d , do nothing" % (txt, att, attrUSN))
                     txt = ""
                     delta.remove(att)
                     continue
                 else:
                     if att == "defaultSecurityDescriptor":
-                        defSDmodified = 1
+                        defSDmodified = True
                     if attrUSN:
-                        message(CHANGE, "%sAttribute: %s will be modified" \
-                                        "/deleted it was last modified" \
-                                        "during a provision, current usn:" \
+                        message(CHANGE, "%sAttribute: %s will be modified"
+                                        "/deleted it was last modified"
+                                        "during a provision, current usn:"
                                         "%d" % (txt, att,  attrUSN))
                         txt = ""
                     else:
-                        message(CHANGE, "%sAttribute: %s will be added because" \
+                        message(CHANGE, "%sAttribute: %s will be added because"
                                         " it hasn't existed before " % (txt, att))
                         txt = ""
                     continue
 
             else:
             # Old school way of handling things for pre alpha12 upgrade
-                defSDmodified = 1
+                defSDmodified = True
                 msgElt = delta.get(att)
 
                 if att == "nTSecurityDescriptor":
@@ -857,11 +875,11 @@ def update_present(ref_samdb, samdb, basedn, listPresent, usns, invocationid):
                             if opts.debugchange or opts.debugall:
                                 try:
                                     dump_denied_change(dn, att,
-                                        messageEltFlagToString(msgElt.flags()),
+                                        msg_elt_flag_strs[msgElt.flags()],
                                         current[0][att], reference[0][att])
                                 except KeyError:
                                     dump_denied_change(dn, att,
-                                        messageEltFlagToString(msgElt.flags()),
+                                        msg_elt_flag_strs[msgElt.flags()],
                                         current[0][att], None)
                             delta.remove(att)
                         continue
@@ -875,12 +893,13 @@ def update_present(ref_samdb, samdb, basedn, listPresent, usns, invocationid):
         delta.dn = dn
         if len(delta.items()) >1:
             attributes=", ".join(delta.keys())
-            message(CHANGE, "%s is different from the reference one, changed" \
+            message(CHANGE, "%s is different from the reference one, changed"
                             " attributes: %s\n" % (dn, attributes))
-            changed = changed + 1
+            changed += 1
             samdb.modify(delta)
     return changed
 
+
 def update_partition(ref_samdb, samdb, basedn, names, schema, provisionUSNs):
     """Check differences between the reference provision and the upgraded one.
 
@@ -942,7 +961,7 @@ def update_partition(ref_samdb, samdb, basedn, names, schema, provisionUSNs):
     # a complete schema is needed as the insertion of attributes
     # and class is done against it
     # and the schema is self validated
-    samdb.set_schema_from_ldb(schema.ldb)
+    samdb.set_schema(schema)
     try:
         message(SIMPLE, "There are %d missing objects" % (len(listMissing)))
         add_deletedobj_containers(ref_samdb, samdb, names)
@@ -960,7 +979,6 @@ def update_partition(ref_samdb, samdb, basedn, names, schema, provisionUSNs):
         return 0
 
 
-
 def check_updated_sd(ref_sam, cur_sam, names):
     """Check if the security descriptor in the upgraded provision are the same
        as the reference
@@ -993,7 +1011,7 @@ def check_updated_sd(ref_sam, cur_sam, names):
             if sddl != hash[key]:
                 txt = get_diff_sddls(hash[key], sddl)
                 if txt != "":
-                    message(CHANGESD, "On object %s ACL is different"\
+                    message(CHANGESD, "On object %s ACL is different"
                                       " \n%s" % (current[i]["dn"], txt))
 
 
@@ -1055,7 +1073,7 @@ def rebuild_sd(samdb, names):
                         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.configdn) or
             str(obj["dn"]) == str(names.schemadn)):
             hash[str(obj["dn"])] = obj["whenCreated"]
 
@@ -1167,48 +1185,6 @@ def update_samdb(ref_samdb, samdb, names, highestUSN, schema):
         return 0
 
 
-def update_machine_account_password(samdb, secrets_ldb, names):
-    """Update (change) the password of the current DC both in the SAM db and in
-       secret one
-
-    :param samdb: An LDB object related to the sam.ldb file of a given provision
-    :param secrets_ldb: An LDB object related to the secrets.ldb file of a given
-                        provision
-    :param names: List of key provision parameters"""
-
-    message(SIMPLE, "Update machine account")
-    expression = "samAccountName=%s$" % names.netbiosname
-    secrets_msg = secrets_ldb.search(expression=expression,
-                                        attrs=["secureChannelType"])
-    if int(secrets_msg[0]["secureChannelType"][0]) == SEC_CHAN_BDC:
-        res = samdb.search(expression=expression, attrs=[])
-        assert(len(res) == 1)
-
-        msg = Message(res[0].dn)
-        machinepass = samba.generate_random_password(128, 255)
-        msg["userPassword"] = MessageElement(machinepass, FLAG_MOD_REPLACE,
-                                                "userPassword")
-        samdb.modify(msg)
-
-        res = samdb.search(expression=("samAccountName=%s$" % names.netbiosname),
-                     attrs=["msDs-keyVersionNumber"])
-        assert(len(res) == 1)
-        kvno = int(str(res[0]["msDs-keyVersionNumber"]))
-        secChanType = int(secrets_msg[0]["secureChannelType"][0])
-
-        secretsdb_self_join(secrets_ldb, domain=names.domain,
-                    realm=names.realm or sambaopts._lp.get('realm'),
-                    domainsid=names.domainsid,
-                    dnsdomain=names.dnsdomain,
-                    netbiosname=names.netbiosname,
-                    machinepass=machinepass,
-                    key_version_number=kvno,
-                    secure_channel_type=secChanType)
-    else:
-        raise ProvisioningError("Unable to find a Secure Channel" \
-                                "of type SEC_CHAN_BDC")
-
-
 
 def setup_path(file):
     return os.path.join(setup_dir, file)
@@ -1349,7 +1325,7 @@ def setup_path(file):
 
 if __name__ == '__main__':
     global defSDmodified
-    defSDmodified = 0
+    defSDmodified = False
     # From here start the big steps of the program
     # 1) First get files paths
     paths = get_paths(param, smbconf=smbconf)
@@ -1369,8 +1345,8 @@ if __name__ == '__main__':
     names = find_provision_key_parameters(ldbs.sam, ldbs.secrets, ldbs.idmap,
                                             paths, smbconf, lp)
     # 4)
-    lastProvisionUSNs = getLastProvisionUSN(ldbs.sam)
-    if lastProvisionUSNs != None:
+    lastProvisionUSNs = get_last_provision_usn(ldbs.sam)
+    if lastProvisionUSNs is not None:
         message(CHANGE,
             "Find a last provision USN, %d range(s)" % len(lastProvisionUSNs))
 
@@ -1381,7 +1357,7 @@ if __name__ == '__main__':
     # ldbs = get_ldbs(paths, creds, adm_session, lp)
 
     if not sanitychecks(ldbs.sam, names):
-        message(SIMPLE, "Sanity checks for the upgrade fails, checks messages" \
+        message(SIMPLE, "Sanity checks for the upgrade fails, checks messages" 
                         " and correct them before rerunning upgradeprovision")
         sys.exit(1)
 
@@ -1432,19 +1408,19 @@ if __name__ == '__main__':
         # 11) B
         simple_update_basesamdb(newpaths, paths, names)
         ldbs = get_ldbs(paths, creds, session, lp)
-        ldbs.startTransactions()
         removeProvisionUSN(ldbs.sam)
+        ldbs.startTransactions()
 
     # 12)
     schema = Schema(setup_path, names.domainsid, schemadn=str(names.schemadn),
-                    serverdn=str(names.serverdn))
+                     serverdn=str(names.serverdn))
     # 13)
     if opts.full:
         if not update_samdb(new_ldbs.sam, ldbs.sam, names, lastProvisionUSNs,
                             schema):
-            message(SIMPLE, "Rollbacking every changes. Check the reason" \
+            message(SIMPLE, "Rollbacking every changes. Check the reason"
                             " of the problem")
-            message(SIMPLE, "In any case your system as it was before" \
+            message(SIMPLE, "In any case your system as it was before"
                             " the upgrade")
             ldbs.groupedRollback()
             new_ldbs.groupedRollback()
@@ -1453,6 +1429,7 @@ if __name__ == '__main__':
     # 14)
     update_secrets(new_ldbs.secrets, ldbs.secrets, message)
     # 15)
+    message(SIMPLE, "Update machine account")
     update_machine_account_password(ldbs.sam, ldbs.secrets, names)
 
     # 16) SD should be created with admin but as some previous acl were so wrong
@@ -1474,7 +1451,7 @@ if __name__ == '__main__':
     # 18) We rebuild SD only if defaultSecurityDescriptor is modified
     # But in fact we should do it also if one object has its SD modified as
     # child might need rebuild
-    if defSDmodified == 1:
+    if defSDmodified:
         message(SIMPLE, "Updating SD")
         ldbs.sam.set_session_info(adm_session)
         # Alpha10 was a bit broken still
@@ -1495,12 +1472,22 @@ if __name__ == '__main__':
     # 21)
     check_for_DNS(newpaths.private_dir, paths.private_dir)
     # 22)
-    if lastProvisionUSNs != None:
-        updateProvisionUSN(ldbs.sam, minUSN, maxUSN)
+    if lastProvisionUSNs is not None:
+        update_provision_usn(ldbs.sam, minUSN, maxUSN)
+    if opts.full and (names.policyid is None or names.policyid_dc is None):
+        update_policyids(names, ldbs.sam)
     if opts.full or opts.resetfileacl:
-        update_gpo(paths, ldbs.sam, names, lp, message, 1)
+        try:
+            update_gpo(paths, ldbs.sam, names, lp, message, 1)
+        except ProvisioningError, e:
+            message(ERROR, "The policy for domain controller is missing," 
+                           " you should restart upgradeprovision with --full")
     else:
-        update_gpo(paths, ldbs.sam, names, lp, message, 0)
+        try:
+            update_gpo(paths, ldbs.sam, names, lp, message, 0)
+        except ProvisioningError, e:
+            message(ERROR, "The policy for domain controller is missing," 
+                           " you should restart upgradeprovision with --full")
     ldbs.groupedCommit()
     new_ldbs.groupedCommit()
     message(SIMPLE, "Upgrade finished !")