From f593e3337e6757fdfdc01bdca1b4258013507705 Mon Sep 17 00:00:00 2001 From: Nikos Skalkotos <skalkoto@grnet.gr> Date: Thu, 31 Jul 2014 20:04:18 +0300 Subject: [PATCH] windows: Disable UAC before booting the windows VM This is handy because this way we don't need to unlock the Administrator account if it is locked. Any user that is in the Administrators group can do the job. --- image_creator/os_type/windows/__init__.py | 52 +++++++++++++++-------- image_creator/os_type/windows/registry.py | 35 +++++++++++++++ image_creator/os_type/windows/vm.py | 4 +- 3 files changed, 71 insertions(+), 20 deletions(-) diff --git a/image_creator/os_type/windows/__init__.py b/image_creator/os_type/windows/__init__.py index 59c8321..37e10f7 100644 --- a/image_creator/os_type/windows/__init__.py +++ b/image_creator/os_type/windows/__init__.py @@ -30,6 +30,7 @@ import re import os import uuid import time +from collections import namedtuple # For more info see: http://technet.microsoft.com/en-us/library/jj612867.aspx KMS_CLIENT_SETUP_KEYS = { @@ -300,8 +301,16 @@ class Windows(OSBase): if root == self.root: self.systemdrive = drive - admin = self.usernames[ADMIN_RID] - self.vm = VM(self.image.device, self.sysprep_params, admin) + active_admins = [u for u in self.admins if u in self.active_users] + if ADMIN_RID in self.active_users or len(active_admins) == 0: + admin = ADMIN_RID + else: + active_admins.sort() + admin = active_admins[0] + + self.vm = VM( + self.image.device, self.sysprep_params, + namedtuple('User', 'rid name')(admin, self.usernames[admin])) @sysprep('Disabling IPv6 privacy extensions') def disable_ipv6_privacy_extensions(self): @@ -493,9 +502,11 @@ class Windows(OSBase): self.out.output("Preparing media for boot ...", False) with self.mount(readonly=False, silent=True): - activated = self.registry.reset_account(ADMIN_RID) - v_val = self.registry.reset_passwd(ADMIN_RID) - disabled_uac = self.registry.update_uac_remote_setting(1) + activated = self.registry.reset_account(self.vm.admin.rid) + v_val = self.registry.reset_passwd(self.vm.admin.rid) + disabled_remote_uac = self.registry.update_uac_remote_setting(1) + disabled_uac = self.registry.update_uac(0) + self._add_boot_scripts() # disable the firewalls @@ -558,15 +569,18 @@ class Windows(OSBase): self.out.warn("The boot changes cannot be reverted. " "The snapshot may be in a corrupted state.") else: - if disabled_uac: + if disabled_remote_uac: self.registry.update_uac_remote_setting(0) + if disabled_uac: + self.registry.update_uac(1) + if not activated: - self.registry.reset_account(ADMIN_RID, False) + self.registry.reset_account(self.vm.admin.rid, False) if not self.sysprepped: # Reset the old password - self.registry.reset_passwd(ADMIN_RID, v_val) + self.registry.reset_passwd(self.vm.admin.rid, v_val) self.registry.update_firewalls(*firewall_states) self.out.success("done") @@ -623,7 +637,6 @@ class Windows(OSBase): next boot. """ - admin = self.usernames[ADMIN_RID] commands = {} # Disable hibernation. This is not needed for a VM @@ -634,7 +647,7 @@ class Windows(OSBase): # This will update the password of the admin user to self.vm.password commands["UpdatePassword"] = "net user %s %s" % \ - (admin, self.vm.password) + (self.vm.admin.name, self.vm.password) # This is previously done with hivex when we executed # self.registry.update_uac_remote_setting(1). @@ -665,7 +678,7 @@ class Windows(OSBase): # defined on the server either by a Group Policy object (GPO) or by a # local policy. - self.registry.enable_autologon(admin) + self.registry.enable_autologon(self.vm.admin.name) def _do_collect_metadata(self): """Collect metadata about the OS""" @@ -821,16 +834,19 @@ class Windows(OSBase): """Upload the VirtIO drivers and installation scripts to the media. """ with self.mount(readonly=False, silent=True): - v_val = self.registry.reset_passwd(ADMIN_RID) - self._add_cleanup('virtio', - self.registry.reset_passwd, ADMIN_RID, v_val) + v_val = self.registry.reset_passwd(self.vm.admin.rid) + self._add_cleanup('virtio', self.registry.reset_passwd, + self.vm.admin.rid, v_val) + + active = self.registry.reset_account(self.vm.admin.rid) + self._add_cleanup('virtio', self.registry.reset_account, + self.vm.admin.rid, active) - active = self.registry.reset_account(ADMIN_RID) - self._add_cleanup('virtio', - self.registry.reset_account, ADMIN_RID, active) + if self.registry.update_uac(0): + self._add_cleanup('virtio', self.registry.update_uac, 1) # We disable this with powershell scripts - self.registry.enable_autologon(self.usernames[ADMIN_RID]) + self.registry.enable_autologon(self.vm.admin.name) active = self.registry.reset_first_logon_animation(False) self._add_cleanup( diff --git a/image_creator/os_type/windows/registry.py b/image_creator/os_type/windows/registry.py index 25eb939..e8650c5 100644 --- a/image_creator/os_type/windows/registry.py +++ b/image_creator/os_type/windows/registry.py @@ -283,6 +283,41 @@ class Registry(object): return True + def update_uac(self, value): + """Enable or disable the User Account Control by changing the value of + the EnableLUA registry key + + value = 1 will enable the UAC + value = 0 will disable the UAC + + 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") + + with self.open_hive('SOFTWARE', write=True) as hive: + path = 'Microsoft/Windows/CurrentVersion/Policies/System' + system = traverse(hive, path) + + enablelua = None + for val in hive.node_values(system): + if hive.value_key(val) == 'EnableLUA': + enablelua = val + + if enablelua is not None: + if value == hive.value_dword(enablelua): + return False + elif value == 1: + return False + + hive.node_set_value(system, REG_DWORD('EnableLUA', value)) + hive.commit(None) + + return True + def enum_users(self): """Returns: a map of RID->username for all users found on the system diff --git a/image_creator/os_type/windows/vm.py b/image_creator/os_type/windows/vm.py index 0b049eb..766e570 100644 --- a/image_creator/os_type/windows/vm.py +++ b/image_creator/os_type/windows/vm.py @@ -223,8 +223,8 @@ class VM(object): debug = kwargs['debug'] if 'debug' in kwargs else False uninstall = kwargs['uninstall'] if 'uninstall' in kwargs else False - winexe = WinEXE(self.admin, 'localhost', password=self.password) - winexe.runas(self.admin, self.password).no_pass() + winexe = WinEXE(self.admin.name, 'localhost', password=self.password) + winexe.no_pass() if debug: winexe.debug(9) -- GitLab