s4-python: add an option for just fixing gpo folders
authorMatthieu Patou <mat@matws.net>
Sun, 15 May 2011 12:06:18 +0000 (16:06 +0400)
committerMatthieu Patou <mat@samba.org>
Mon, 16 May 2011 22:31:09 +0000 (00:31 +0200)
source4/scripting/bin/upgradeprovision

index 8c79917d5e2f6ff507a69074ba7263ec57f87570..4e48a48b45481d06fe42a29334fc1cbac24b247e 100755 (executable)
@@ -151,6 +151,8 @@ parser.add_option("--debugall", action="store_true",
                   help="Print all available information (very verbose)")
 parser.add_option("--resetfileacl", action="store_true",
                   help="Force a reset on filesystem acls in sysvol / netlogon share")
+parser.add_option("--fixntacl", action="store_true",
+                  help="Only fix NT ACLs in sysvol / netlogon share")
 parser.add_option("--full", action="store_true",
                   help="Perform full upgrade of the samdb (schema, configuration, new objects, ...")
 
@@ -1609,80 +1611,81 @@ if __name__ == '__main__':
         adm_session = admin_session(lp, str(names.domainsid))
         # So we reget handle on objects
         # ldbs = get_ldbs(paths, creds, adm_session, lp)
+        if not opts.fixntacl:
+            if not sanitychecks(ldbs.sam, names):
+                message(SIMPLE, "Sanity checks for the upgrade have failed. "
+                        "Check the messages and correct the errors "
+                        "before rerunning upgradeprovision")
+                ldbs.groupedRollback()
+                sys.exit(1)
 
-        if not sanitychecks(ldbs.sam, names):
-            message(SIMPLE, "Sanity checks for the upgrade have failed. "
-                            "Check the messages and correct the errors "
-                            "before rerunning upgradeprovision")
-            sys.exit(1)
-
-        # Let's see provision parameters
-        print_provision_key_parameters(names)
-
-        # 5) With all this information let's create a fresh new provision used as
-        # reference
-        message(SIMPLE, "Creating a reference provision")
-        provisiondir = tempfile.mkdtemp(dir=paths.private_dir,
-                                        prefix="referenceprovision")
-        newprovision(names, creds, session, smbconf, provisiondir,
-                        provision_logger)
-
-        # TODO
-        # 6) and 7)
-        # We need to get a list of object which SD is directly computed from
-        # defaultSecurityDescriptor.
-        # This will allow us to know which object we can rebuild the SD in case
-        # of change of the parent's SD or of the defaultSD.
-        # Get file paths of this new provision
-        newpaths = get_paths(param, targetdir=provisiondir)
-        new_ldbs = get_ldbs(newpaths, creds, session, lp)
-        new_ldbs.startTransactions()
-
-        # 8) Populate some associative array to ease the update process
-        # List of attribute which are link and backlink
-        populate_links(new_ldbs.sam, names.schemadn)
-        # List of attribute with ASN DN synthax)
-        populate_dnsyntax(new_ldbs.sam, names.schemadn)
-        # 9)
-        update_privilege(newpaths.private_dir, paths.private_dir)
-        # 10)
-        oem = getOEMInfo(ldbs.sam, str(names.rootdn))
-        # Do some modification on sam.ldb
-        ldbs.groupedCommit()
-        new_ldbs.groupedCommit()
-        deltaattr = None
-# 11)
-        if re.match(".*alpha((9)|(\d\d+)).*", str(oem)):
-            # 11) A
-            # Starting from alpha9 we can consider that the structure is quite ok
-            # and that we should do only dela
-            deltaattr = delta_update_basesamdb(newpaths.samdb,
-                                                paths.samdb,
-                                                creds,
-                                                session,
-                                                lp,
-                                                message)
-        else:
-            # 11) B
-            simple_update_basesamdb(newpaths, paths, names)
-            ldbs = get_ldbs(paths, creds, session, lp)
-            removeProvisionUSN(ldbs.sam)
-
-        ldbs.startTransactions()
-        minUSN = int(str(get_max_usn(ldbs.sam, str(names.rootdn)))) + 1
-        new_ldbs.startTransactions()
-
-        # 12)
-        schema = Schema(names.domainsid, schemadn=str(names.schemadn))
-        # We create a closure that will be invoked just before schema reload
-        def schemareloadclosure():
-            basesam = Ldb(paths.samdb, session_info=session, credentials=creds, lp=lp,
-                            options=["modules:"])
-            doit = False
-            if deltaattr is not None and len(deltaattr) > 1:
-                doit = True
-            if doit:
-                deltaattr.remove("dn")
+            # Let's see provision parameters
+            print_provision_key_parameters(names)
+
+            # 5) With all this information let's create a fresh new provision used as
+            # reference
+            message(SIMPLE, "Creating a reference provision")
+            provisiondir = tempfile.mkdtemp(dir=paths.private_dir,
+                            prefix="referenceprovision")
+            newprovision(names, creds, session, smbconf, provisiondir,
+                    provision_logger)
+
+            # TODO
+            # 6) and 7)
+            # We need to get a list of object which SD is directly computed from
+            # defaultSecurityDescriptor.
+            # This will allow us to know which object we can rebuild the SD in case
+            # of change of the parent's SD or of the defaultSD.
+            # Get file paths of this new provision
+            newpaths = get_paths(param, targetdir=provisiondir)
+            new_ldbs = get_ldbs(newpaths, creds, session, lp)
+            new_ldbs.startTransactions()
+
+            # 8) Populate some associative array to ease the update process
+            # List of attribute which are link and backlink
+            populate_links(new_ldbs.sam, names.schemadn)
+            # List of attribute with ASN DN synthax)
+            populate_dnsyntax(new_ldbs.sam, names.schemadn)
+            # 9)
+            update_privilege(newpaths.private_dir, paths.private_dir)
+            # 10)
+            oem = getOEMInfo(ldbs.sam, str(names.rootdn))
+            # Do some modification on sam.ldb
+            ldbs.groupedCommit()
+            new_ldbs.groupedCommit()
+            deltaattr = None
+        # 11)
+            if re.match(".*alpha((9)|(\d\d+)).*", str(oem)):
+                # 11) A
+                # Starting from alpha9 we can consider that the structure is quite ok
+                # and that we should do only dela
+                deltaattr = delta_update_basesamdb(newpaths.samdb,
+                                paths.samdb,
+                                creds,
+                                session,
+                                lp,
+                                message)
+            else:
+                # 11) B
+                simple_update_basesamdb(newpaths, paths, names)
+                ldbs = get_ldbs(paths, creds, session, lp)
+                removeProvisionUSN(ldbs.sam)
+
+            ldbs.startTransactions()
+            minUSN = int(str(get_max_usn(ldbs.sam, str(names.rootdn)))) + 1
+            new_ldbs.startTransactions()
+
+            # 12)
+            schema = Schema(names.domainsid, schemadn=str(names.schemadn))
+            # We create a closure that will be invoked just before schema reload
+            def schemareloadclosure():
+                basesam = Ldb(paths.samdb, session_info=session, credentials=creds, lp=lp,
+                        options=["modules:"])
+                doit = False
+                if deltaattr is not None and len(deltaattr) > 1:
+                    doit = True
+                if doit:
+                    deltaattr.remove("dn")
                 for att in deltaattr:
                     if att.lower() == "dn":
                         continue
@@ -1691,112 +1694,112 @@ if __name__ == '__main__':
                         doit = False
                     elif deltaattr.get(att) is None:
                         doit = False
-            if doit:
-                message(CHANGE, "Applying delta to @ATTRIBUTES")
-                deltaattr.dn = ldb.Dn(basesam, "@ATTRIBUTES")
-                basesam.modify(deltaattr)
+                if doit:
+                    message(CHANGE, "Applying delta to @ATTRIBUTES")
+                    deltaattr.dn = ldb.Dn(basesam, "@ATTRIBUTES")
+                    basesam.modify(deltaattr)
+                else:
+                    message(CHANGE, "Not applying delta to @ATTRIBUTES because "
+                        "there is not only add")
+            # 13)
+            if opts.full:
+                if not update_samdb(new_ldbs.sam, ldbs.sam, names, lastProvisionUSNs,
+                        schema, schemareloadclosure):
+                    message(SIMPLE, "Rolling back all changes. Check the cause"
+                            " of the problem")
+                    message(SIMPLE, "Your system is as it was before the upgrade")
+                    ldbs.groupedRollback()
+                    new_ldbs.groupedRollback()
+                    shutil.rmtree(provisiondir)
+                    sys.exit(1)
             else:
-                message(CHANGE, "Not applying delta to @ATTRIBUTES because "
-                                "there is not only add")
-        # 13)
-        if opts.full:
-            if not update_samdb(new_ldbs.sam, ldbs.sam, names, lastProvisionUSNs,
-                                schema, schemareloadclosure):
-                message(SIMPLE, "Rolling back all changes. Check the cause"
-                                " of the problem")
-                message(SIMPLE, "Your system is as it was before the upgrade")
-                ldbs.groupedRollback()
-                new_ldbs.groupedRollback()
-                shutil.rmtree(provisiondir)
-                sys.exit(1)
-        else:
-            # Try to reapply the change also when we do not change the sam
-            # as the delta_upgrade
-            schemareloadclosure()
-            sync_calculated_attributes(ldbs.sam, names)
+                # Try to reapply the change also when we do not change the sam
+                # as the delta_upgrade
+                schemareloadclosure()
+                sync_calculated_attributes(ldbs.sam, names)
+                res = ldbs.sam.search(expression="(samaccountname=dns)",
+                        scope=SCOPE_SUBTREE, attrs=["dn"],
+                        controls=["search_options:1:2"])
+                if len(res) > 0:
+                    message(SIMPLE, "You still have the old DNS object for managing "
+                            "dynamic DNS, but you didn't supply --full so "
+                            "a correct update can't be done")
+                    ldbs.groupedRollback()
+                    new_ldbs.groupedRollback()
+                    shutil.rmtree(provisiondir)
+                    sys.exit(1)
+            # 14)
+            update_secrets(new_ldbs.secrets, ldbs.secrets, message)
+            # 14bis)
             res = ldbs.sam.search(expression="(samaccountname=dns)",
-                                scope=SCOPE_SUBTREE, attrs=["dn"],
-                                controls=["search_options:1:2"])
-            if len(res) > 0:
-                message(SIMPLE, "You still have the old DNS object for managing "
-                                "dynamic DNS, but you didn't supply --full so "
-                                "a correct update can't be done")
-                ldbs.groupedRollback()
-                new_ldbs.groupedRollback()
-                shutil.rmtree(provisiondir)
-                sys.exit(1)
-        # 14)
-        update_secrets(new_ldbs.secrets, ldbs.secrets, message)
-        # 14bis)
-        res = ldbs.sam.search(expression="(samaccountname=dns)",
-                                  scope=SCOPE_SUBTREE, attrs=["dn"],
-                                  controls=["search_options:1:2"])
-
-        if (len(res) == 1):
-            ldbs.sam.delete(res[0]["dn"])
-            res2 = ldbs.secrets.search(expression="(samaccountname=dns)",
-                                  scope=SCOPE_SUBTREE, attrs=["dn"])
-            update_dns_account_password(ldbs.sam, ldbs.secrets, names)
-            message(SIMPLE, "IMPORTANT!!! "
-                            "If you were using Dynamic DNS before you need "
-                            "to update your configuration, so that the "
-                            "tkey-gssapi-credential has the following value: "
-                            "DNS/%s.%s" % (names.netbiosname.lower(),
-                                           names.realm.lower()))
-        # 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
-        # that admin can't modify them we have first to recreate them with the good
-        # form but with system account and then give the ownership to admin ...
-        if not re.match(r'.*alpha(9|\d\d+)', str(oem)):
-            message(SIMPLE, "Fixing old povision SD")
-            fix_partition_sd(ldbs.sam, names)
-            rebuild_sd(ldbs.sam, names)
-
-        # We calculate the max USN before recalculating the SD because we might
-        # touch object that have been modified after a provision and we do not
-        # want that the next upgradeprovision thinks that it has a green light
-        # to modify them
-
-        # 17)
-        maxUSN = get_max_usn(ldbs.sam, str(names.rootdn))
-
-        # 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:
-            message(SIMPLE, "Updating SD")
-            ldbs.sam.set_session_info(adm_session)
-            # Alpha10 was a bit broken still
-            if re.match(r'.*alpha(\d|10)', str(oem)):
+                        scope=SCOPE_SUBTREE, attrs=["dn"],
+                        controls=["search_options:1:2"])
+
+            if (len(res) == 1):
+                ldbs.sam.delete(res[0]["dn"])
+                res2 = ldbs.secrets.search(expression="(samaccountname=dns)",
+                        scope=SCOPE_SUBTREE, attrs=["dn"])
+                update_dns_account_password(ldbs.sam, ldbs.secrets, names)
+                message(SIMPLE, "IMPORTANT!!! "
+                        "If you were using Dynamic DNS before you need "
+                        "to update your configuration, so that the "
+                        "tkey-gssapi-credential has the following value: "
+                        "DNS/%s.%s" % (names.netbiosname.lower(),
+                            names.realm.lower()))
+            # 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
+            # that admin can't modify them we have first to recreate them with the good
+            # form but with system account and then give the ownership to admin ...
+            if not re.match(r'.*alpha(9|\d\d+)', str(oem)):
+                message(SIMPLE, "Fixing old povision SD")
                 fix_partition_sd(ldbs.sam, names)
-            rebuild_sd(ldbs.sam, names)
-
-        # 19)
-        # Now we are quite confident in the recalculate process of the SD, we make
-        # it optional.
-        # Also the check must be done in a clever way as for the moment we just
-        # compare SDDL
-        if opts.debugchangesd:
-            check_updated_sd(new_ldbs.sam, ldbs.sam, names)
-
-        # 20)
-        updateOEMInfo(ldbs.sam, str(names.rootdn))
-        # 21)
-        check_for_DNS(newpaths.private_dir, paths.private_dir)
-        # 22)
-        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:
+                rebuild_sd(ldbs.sam, names)
+
+            # We calculate the max USN before recalculating the SD because we might
+            # touch object that have been modified after a provision and we do not
+            # want that the next upgradeprovision thinks that it has a green light
+            # to modify them
+
+            # 17)
+            maxUSN = get_max_usn(ldbs.sam, str(names.rootdn))
+
+            # 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:
+                message(SIMPLE, "Updating SD")
+                ldbs.sam.set_session_info(adm_session)
+                # Alpha10 was a bit broken still
+                if re.match(r'.*alpha(\d|10)', str(oem)):
+                    fix_partition_sd(ldbs.sam, names)
+                    rebuild_sd(ldbs.sam, names)
+
+            # 19)
+            # Now we are quite confident in the recalculate process of the SD, we make
+            # it optional.
+            # Also the check must be done in a clever way as for the moment we just
+            # compare SDDL
+            if opts.debugchangesd:
+                check_updated_sd(new_ldbs.sam, ldbs.sam, names)
+
+            # 20)
+            updateOEMInfo(ldbs.sam, str(names.rootdn))
+            # 21)
+            check_for_DNS(newpaths.private_dir, paths.private_dir)
+            # 22)
+            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 or opts.fixntacl:
             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")
+                            "You should restart upgradeprovision with --full")
             except IOError, e:
                 message(ERROR, "Setting ACL not supported on your filesystem")
         else:
@@ -1804,25 +1807,29 @@ if __name__ == '__main__':
                 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!")
-        # remove reference provision now that everything is done !
-        # So we have reindexed first if need when the merged schema was reloaded
-        # (as new attributes could have quick in)
-        # But the second part of the update (when we update existing objects
-        # can also have an influence on indexing as some attribute might have their
-        # searchflag modificated
-        message(SIMPLE, "Reopenning samdb to trigger reindexing if needed "
-                        "after modification")
-        samdb = Ldb(paths.samdb, session_info=session, credentials=creds, lp=lp)
-        message(SIMPLE, "Reindexing finished")
-
-        shutil.rmtree(provisiondir)
+                            "You should restart upgradeprovision with --full")
+        if not opts.fixntacl:
+            ldbs.groupedCommit()
+            new_ldbs.groupedCommit()
+            message(SIMPLE, "Upgrade finished!")
+            # remove reference provision now that everything is done !
+            # So we have reindexed first if need when the merged schema was reloaded
+            # (as new attributes could have quick in)
+            # But the second part of the update (when we update existing objects
+            # can also have an influence on indexing as some attribute might have their
+            # searchflag modificated
+            message(SIMPLE, "Reopenning samdb to trigger reindexing if needed "
+                    "after modification")
+            samdb = Ldb(paths.samdb, session_info=session, credentials=creds, lp=lp)
+            message(SIMPLE, "Reindexing finished")
+
+            shutil.rmtree(provisiondir)
+        else:
+            ldbs.groupedRollback()
+            message(SIMPLE, "ACLs fixed !")
     except StandardError, err:
         message(ERROR, "A problem occurred while trying to upgrade your "
-                       "provision. A full backup is located at %s" % backupdir)
+                   "provision. A full backup is located at %s" % backupdir)
         if opts.debugall or opts.debugchange:
             (typ, val, tb) = sys.exc_info()
             traceback.print_exception(typ, val, tb)