Disable UAC remote restrictions in windows
authorNikos Skalkotos <skalkoto@grnet.gr>
Fri, 28 Jun 2013 09:46:53 +0000 (12:46 +0300)
committerNikos Skalkotos <skalkoto@grnet.gr>
Tue, 30 Jul 2013 13:43:58 +0000 (16:43 +0300)
Before launching the windows image with KVM, disable the UAC remote
restrictions. This is needed to make the image allow executing
command through psexec. After the VM is shut down, the restrictions
are turned back on.

image_creator/os_type/windows.py

index bf237c2..564740d 100644 (file)
@@ -36,7 +36,8 @@
 """This module hosts OS-specific code common for the various Microsoft
 Windows OSs."""
 
-from image_creator.os_type import OSBase
+from image_creator.os_type import OSBase, sysprep
+from image_creator.util import FatalError, check_guestfs_version
 
 import hivex
 import tempfile
@@ -46,6 +47,117 @@ import os
 class Windows(OSBase):
     """OS class for Windows"""
 
+    @sysprep(enabled=False)
+    def remove_user_accounts(self, print_header=True):
+        """Remove all user accounts with id greater than 1000"""
+        pass
+    def do_sysprep(self):
+        """Prepare system for image creation."""
+
+        if getattr(self, 'syspreped', False):
+            raise FatalError("Image is already syspreped!")
+
+        self.mount(readonly=False)
+        try:
+            disabled_uac = self._update_uac_remote_setting(1)
+        finally:
+            self.umount()
+
+        self.out.output("Shutting down helper VM ...", False)
+        self.g.sync()
+        # guestfs_shutdown which is the prefered way to shutdown the backend
+        # process was introduced in version 1.19.16
+        if check_guestfs_version(self.g, 1, 19, 16) >= 0:
+            ret = self.g.shutdown()
+        else:
+            ret = self.g.kill_subprocess()
+
+        self.out.success('done')
+
+        self.out.output("Starting windows VM ...", False)
+        try:
+            pass
+        finally:
+            self.out.output("Relaunching helper VM (may take a while) ...",
+                            False)
+            self.g.launch()
+            self.out.success('done')
+
+        if disabled_uac:
+            self._update_uac_remote_setting(0)
+
+        self.syspreped = True
+
+    def _registry_file_path(self, regfile):
+        """Retrieves the case sensitive path to a registry file"""
+
+        systemroot = self.g.inspect_get_windows_systemroot(self.root)
+        path = "%s/system32/config/%s" % (systemroot, regfile)
+        try:
+            path = self.g.case_sensitive_path(path)
+        except RuntimeError as e:
+            raise FatalError("Unable to retrieve registry file: %s. Reason: %s"
+                             % (regfile, str(e)))
+        return path
+
+    def _update_uac_remote_setting(self, value):
+        """Updates the registry key value:
+        [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies
+        \System]"LocalAccountTokenFilterPolicy"
+
+        value = 1 will disable the UAC remote restrictions
+        value = 0 will enable the UAC remote restrictions
+
+        For more info see here: http://support.microsoft.com/kb/951016
+
+        Returns:
+            True if the key is changed
+            False if the key is unchanged
+        """
+
+        if value not in (0, 1):
+            raise ValueError("Valid values for value parameter are 0 and 1")
+
+        path = self._registry_file_path('SOFTWARE')
+        softwarefd, software = tempfile.mkstemp()
+        try:
+            os.close(softwarefd)
+            self.g.download(path, software)
+
+            h = hivex.Hivex(software, write=True)
+
+            key = h.root()
+            for child in ('Microsoft', 'Windows', 'CurrentVersion', 'Policies',
+                          'System'):
+                key = h.node_get_child(key, child)
+
+            policy = None
+            for val in h.node_values(key):
+                if h.value_key(val) == "LocalAccountTokenFilterPolicy":
+                    policy = val
+
+            if policy is not None:
+                dword = h.value_dword(policy)
+                if dword == value:
+                    return False
+            elif value == 0:
+                return False
+
+            new_value = {
+                'key': "LocalAccountTokenFilterPolicy", 't': 4L,
+                'value': '%s\x00\x00\x00' % '\x00' if value == 0 else '\x01'}
+
+            h.node_set_value(key, new_value)
+            h.commit(None)
+
+            self.g.upload(software, path)
+
+        finally:
+            os.unlink(software)
+
+        return True
+
     def _do_collect_metadata(self):
         """Collect metadata about the OS"""
         super(Windows, self)._do_collect_metadata()
@@ -53,17 +165,15 @@ class Windows(OSBase):
 
     def _get_users(self):
         """Returns a list of users found in the images"""
+        path = self._registry_file_path('SAM')
         samfd, sam = tempfile.mkstemp()
         try:
-            systemroot = self.g.inspect_get_windows_systemroot(self.root)
-            path = "%s/system32/config/sam" % systemroot
-            path = self.g.case_sensitive_path(path)
+            os.close(samfd)
             self.g.download(path, sam)
 
             h = hivex.Hivex(sam)
 
             key = h.root()
-
             # Navigate to /SAM/Domains/Account/Users/Names
             for child in ('SAM', 'Domains', 'Account', 'Users', 'Names'):
                 key = h.node_get_child(key, child)