Statistics
| Branch: | Tag: | Revision:

root / image_creator / os_type / windows.py @ 85e97ae0

History | View | Annotate | Download (18.9 kB)

1 121f3bc0 Nikos Skalkotos
# -*- coding: utf-8 -*-
2 121f3bc0 Nikos Skalkotos
#
3 ae48a082 Nikos Skalkotos
# Copyright 2012 GRNET S.A. All rights reserved.
4 ae48a082 Nikos Skalkotos
#
5 ae48a082 Nikos Skalkotos
# Redistribution and use in source and binary forms, with or
6 ae48a082 Nikos Skalkotos
# without modification, are permitted provided that the following
7 ae48a082 Nikos Skalkotos
# conditions are met:
8 ae48a082 Nikos Skalkotos
#
9 ae48a082 Nikos Skalkotos
#   1. Redistributions of source code must retain the above
10 ae48a082 Nikos Skalkotos
#      copyright notice, this list of conditions and the following
11 ae48a082 Nikos Skalkotos
#      disclaimer.
12 ae48a082 Nikos Skalkotos
#
13 ae48a082 Nikos Skalkotos
#   2. Redistributions in binary form must reproduce the above
14 ae48a082 Nikos Skalkotos
#      copyright notice, this list of conditions and the following
15 ae48a082 Nikos Skalkotos
#      disclaimer in the documentation and/or other materials
16 ae48a082 Nikos Skalkotos
#      provided with the distribution.
17 ae48a082 Nikos Skalkotos
#
18 ae48a082 Nikos Skalkotos
# THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
19 ae48a082 Nikos Skalkotos
# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20 ae48a082 Nikos Skalkotos
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
21 ae48a082 Nikos Skalkotos
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
22 ae48a082 Nikos Skalkotos
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 ae48a082 Nikos Skalkotos
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 ae48a082 Nikos Skalkotos
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
25 ae48a082 Nikos Skalkotos
# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
26 ae48a082 Nikos Skalkotos
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 ae48a082 Nikos Skalkotos
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
28 ae48a082 Nikos Skalkotos
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 ae48a082 Nikos Skalkotos
# POSSIBILITY OF SUCH DAMAGE.
30 ae48a082 Nikos Skalkotos
#
31 ae48a082 Nikos Skalkotos
# The views and conclusions contained in the software and
32 ae48a082 Nikos Skalkotos
# documentation are those of the authors and should not be
33 ae48a082 Nikos Skalkotos
# interpreted as representing official policies, either expressed
34 ae48a082 Nikos Skalkotos
# or implied, of GRNET S.A.
35 ae48a082 Nikos Skalkotos
36 121f3bc0 Nikos Skalkotos
"""This module hosts OS-specific code common for the various Microsoft
37 121f3bc0 Nikos Skalkotos
Windows OSs."""
38 121f3bc0 Nikos Skalkotos
39 640096fb Nikos Skalkotos
from image_creator.os_type import OSBase, sysprep
40 9ca717c4 Nikos Skalkotos
from image_creator.util import FatalError, check_guestfs_version, get_command
41 aa2062ba Nikos Skalkotos
42 76b200cf Nikos Skalkotos
import hivex
43 76b200cf Nikos Skalkotos
import tempfile
44 76b200cf Nikos Skalkotos
import os
45 9ca717c4 Nikos Skalkotos
import time
46 9ca717c4 Nikos Skalkotos
import random
47 10088af7 Nikos Skalkotos
import string
48 74780ad6 Nikos Skalkotos
import subprocess
49 85e97ae0 Nikos Skalkotos
import struct
50 9ca717c4 Nikos Skalkotos
51 9ca717c4 Nikos Skalkotos
kvm = get_command('kvm')
52 76b200cf Nikos Skalkotos
53 10088af7 Nikos Skalkotos
BOOT_TIMEOUT = 300
54 10088af7 Nikos Skalkotos
55 8c574358 Nikos Skalkotos
56 aa2062ba Nikos Skalkotos
class Windows(OSBase):
57 88f83027 Nikos Skalkotos
    """OS class for Windows"""
58 76b200cf Nikos Skalkotos
59 74780ad6 Nikos Skalkotos
    def needed_sysprep_params(self):
60 74780ad6 Nikos Skalkotos
        """Returns a list of needed sysprep parameters. Each element in the
61 74780ad6 Nikos Skalkotos
        list is a SysprepParam object.
62 74780ad6 Nikos Skalkotos
        """
63 74780ad6 Nikos Skalkotos
        password = self.SysprepParam(
64 74780ad6 Nikos Skalkotos
            'password', 'Image Administrator Password', 20, lambda x: True)
65 74780ad6 Nikos Skalkotos
66 74780ad6 Nikos Skalkotos
        return [password]
67 74780ad6 Nikos Skalkotos
68 b8d4b14a Nikos Skalkotos
    @sysprep('Disabling IPv6 privacy extensions')
69 b8d4b14a Nikos Skalkotos
    def disable_ipv6_privacy_extensions(self):
70 74780ad6 Nikos Skalkotos
        """Disable IPv6 privacy extensions"""
71 74780ad6 Nikos Skalkotos
72 10088af7 Nikos Skalkotos
        self._guest_exec('netsh interface ipv6 set global '
73 10088af7 Nikos Skalkotos
                         'randomizeidentifiers=disabled store=persistent')
74 74780ad6 Nikos Skalkotos
75 b9e14923 Nikos Skalkotos
    @sysprep('Disabling Teredo interface')
76 b9e14923 Nikos Skalkotos
    def disable_teredo(self):
77 b9e14923 Nikos Skalkotos
        """Disable Teredo interface"""
78 b9e14923 Nikos Skalkotos
79 b9e14923 Nikos Skalkotos
        self._guest_exec('netsh interface teredo set state disabled')
80 b9e14923 Nikos Skalkotos
81 b9e14923 Nikos Skalkotos
    @sysprep('Disabling ISATAP Adapters')
82 b9e14923 Nikos Skalkotos
    def disable_isatap(self):
83 b9e14923 Nikos Skalkotos
        """Disable ISATAP Adapters"""
84 b9e14923 Nikos Skalkotos
85 b9e14923 Nikos Skalkotos
        self._guest_exec('netsh interface isa set state disabled')
86 b9e14923 Nikos Skalkotos
87 b9e14923 Nikos Skalkotos
    @sysprep('Enabling ping responses')
88 b9e14923 Nikos Skalkotos
    def enable_pings(self):
89 b9e14923 Nikos Skalkotos
        """Enable ping responces"""
90 b9e14923 Nikos Skalkotos
91 b9e14923 Nikos Skalkotos
        self._guest_exec('netsh firewall set icmpsetting 8')
92 b9e14923 Nikos Skalkotos
93 811b7149 Nikos Skalkotos
    @sysprep('Disabling hibernation support')
94 811b7149 Nikos Skalkotos
    def disable_hibernation(self):
95 811b7149 Nikos Skalkotos
        """Disable hibernation support and remove the hibernation file"""
96 811b7149 Nikos Skalkotos
97 811b7149 Nikos Skalkotos
        self._guest_exec(r'powercfg.exe /hibernate off')
98 811b7149 Nikos Skalkotos
99 b9e14923 Nikos Skalkotos
    @sysprep('Setting the system clock to UTC')
100 b9e14923 Nikos Skalkotos
    def utc(self):
101 b9e14923 Nikos Skalkotos
        """Set the hardware clock to UTC"""
102 b9e14923 Nikos Skalkotos
103 b9e14923 Nikos Skalkotos
        path = r'HKLM\SYSTEM\CurrentControlSet\Control\TimeZoneInformation'
104 b9e14923 Nikos Skalkotos
        self._guest_exec(
105 b9e14923 Nikos Skalkotos
            r'REG ADD %s /v RealTimeIsUniversal /t REG_DWORD /d 1 /f' % path)
106 b9e14923 Nikos Skalkotos
107 b8d4b14a Nikos Skalkotos
    @sysprep('Executing sysprep on the image (may take more that 10 minutes)')
108 b8d4b14a Nikos Skalkotos
    def microsoft_sysprep(self):
109 b9e14923 Nikos Skalkotos
        """Run the Microsoft System Preparation Tool. This will remove
110 b9e14923 Nikos Skalkotos
        system-specific data and will make the image ready to be deployed.
111 b9e14923 Nikos Skalkotos
        After this no other task may run.
112 74780ad6 Nikos Skalkotos
        """
113 74780ad6 Nikos Skalkotos
114 10088af7 Nikos Skalkotos
        self._guest_exec(r'C:\Windows\system32\sysprep\sysprep '
115 10088af7 Nikos Skalkotos
                         r'/quiet /generalize /oobe /shutdown')
116 74780ad6 Nikos Skalkotos
        self.syspreped = True
117 9ca717c4 Nikos Skalkotos
118 640096fb Nikos Skalkotos
    def do_sysprep(self):
119 640096fb Nikos Skalkotos
        """Prepare system for image creation."""
120 640096fb Nikos Skalkotos
121 640096fb Nikos Skalkotos
        if getattr(self, 'syspreped', False):
122 640096fb Nikos Skalkotos
            raise FatalError("Image is already syspreped!")
123 640096fb Nikos Skalkotos
124 74780ad6 Nikos Skalkotos
        txt = "System preparation parameter: `%s' is needed but missing!"
125 74780ad6 Nikos Skalkotos
        for param in self.needed_sysprep_params():
126 74780ad6 Nikos Skalkotos
            if param[0] not in self.sysprep_params:
127 74780ad6 Nikos Skalkotos
                raise FatalError(txt % param[0])
128 74780ad6 Nikos Skalkotos
129 640096fb Nikos Skalkotos
        self.mount(readonly=False)
130 640096fb Nikos Skalkotos
        try:
131 640096fb Nikos Skalkotos
            disabled_uac = self._update_uac_remote_setting(1)
132 10088af7 Nikos Skalkotos
            token = self._enable_os_monitor()
133 c2113d72 Nikos Skalkotos
134 c2113d72 Nikos Skalkotos
            # disable the firewalls
135 c2113d72 Nikos Skalkotos
            firewall_states = self._update_firewalls(0, 0, 0)
136 c2113d72 Nikos Skalkotos
137 c2113d72 Nikos Skalkotos
            # Delete the pagefile. It will be recreated when the system boots
138 c2113d72 Nikos Skalkotos
            systemroot = self.g.inspect_get_windows_systemroot(self.root)
139 c2113d72 Nikos Skalkotos
            pagefile = "%s/pagefile.sys" % systemroot
140 c2113d72 Nikos Skalkotos
            self.g.rm_rf(self.g.case_sensitive_path(pagefile))
141 c2113d72 Nikos Skalkotos
142 640096fb Nikos Skalkotos
        finally:
143 640096fb Nikos Skalkotos
            self.umount()
144 640096fb Nikos Skalkotos
145 640096fb Nikos Skalkotos
        self.out.output("Shutting down helper VM ...", False)
146 640096fb Nikos Skalkotos
        self.g.sync()
147 640096fb Nikos Skalkotos
        # guestfs_shutdown which is the prefered way to shutdown the backend
148 640096fb Nikos Skalkotos
        # process was introduced in version 1.19.16
149 640096fb Nikos Skalkotos
        if check_guestfs_version(self.g, 1, 19, 16) >= 0:
150 640096fb Nikos Skalkotos
            ret = self.g.shutdown()
151 640096fb Nikos Skalkotos
        else:
152 640096fb Nikos Skalkotos
            ret = self.g.kill_subprocess()
153 640096fb Nikos Skalkotos
154 640096fb Nikos Skalkotos
        self.out.success('done')
155 10088af7 Nikos Skalkotos
156 10088af7 Nikos Skalkotos
        vm = None
157 10088af7 Nikos Skalkotos
        monitor = None
158 640096fb Nikos Skalkotos
        try:
159 9ca717c4 Nikos Skalkotos
            self.out.output("Starting windows VM ...", False)
160 10088af7 Nikos Skalkotos
            monitorfd, monitor = tempfile.mkstemp()
161 10088af7 Nikos Skalkotos
            os.close(monitorfd)
162 10088af7 Nikos Skalkotos
            vm, display = self._create_vm(monitor)
163 10088af7 Nikos Skalkotos
            self.out.success("started (console on vnc display: %d)." % display)
164 10088af7 Nikos Skalkotos
165 10088af7 Nikos Skalkotos
            self.out.output("Waiting for OS to boot ...", False)
166 10088af7 Nikos Skalkotos
            if not self._wait_on_file(monitor, token):
167 10088af7 Nikos Skalkotos
                raise FatalError("Windows booting timed out.")
168 10088af7 Nikos Skalkotos
            else:
169 10088af7 Nikos Skalkotos
                self.out.success('done')
170 10088af7 Nikos Skalkotos
171 10088af7 Nikos Skalkotos
            self.out.output("Disabling automatic logon ...", False)
172 10088af7 Nikos Skalkotos
            self._disable_autologon()
173 9ca717c4 Nikos Skalkotos
            self.out.success('done')
174 74780ad6 Nikos Skalkotos
175 10088af7 Nikos Skalkotos
            self.out.output('Preparing system from image creation:')
176 10088af7 Nikos Skalkotos
177 74780ad6 Nikos Skalkotos
            tasks = self.list_syspreps()
178 74780ad6 Nikos Skalkotos
            enabled = filter(lambda x: x.enabled, tasks)
179 74780ad6 Nikos Skalkotos
            size = len(enabled)
180 74780ad6 Nikos Skalkotos
181 74780ad6 Nikos Skalkotos
            # Make sure the ms sysprep is the last task to run if it is enabled
182 74780ad6 Nikos Skalkotos
            enabled = filter(
183 74780ad6 Nikos Skalkotos
                lambda x: x.im_func.func_name != 'microsoft_sysprep', enabled)
184 74780ad6 Nikos Skalkotos
185 74780ad6 Nikos Skalkotos
            ms_sysprep_enabled = False
186 74780ad6 Nikos Skalkotos
            if len(enabled) != size:
187 b9e14923 Nikos Skalkotos
                enabled.append(self.microsoft_sysprep)
188 74780ad6 Nikos Skalkotos
                ms_sysprep_enabled = True
189 74780ad6 Nikos Skalkotos
190 74780ad6 Nikos Skalkotos
            cnt = 0
191 74780ad6 Nikos Skalkotos
            for task in enabled:
192 74780ad6 Nikos Skalkotos
                cnt += 1
193 74780ad6 Nikos Skalkotos
                self.out.output(('(%d/%d)' % (cnt, size)).ljust(7), False)
194 74780ad6 Nikos Skalkotos
                task()
195 74780ad6 Nikos Skalkotos
                setattr(task.im_func, 'executed', True)
196 74780ad6 Nikos Skalkotos
197 c2113d72 Nikos Skalkotos
            self.out.output("Sending shut down command ...", False)
198 74780ad6 Nikos Skalkotos
            if not ms_sysprep_enabled:
199 74780ad6 Nikos Skalkotos
                self._shutdown()
200 10088af7 Nikos Skalkotos
            self.out.success("done")
201 74780ad6 Nikos Skalkotos
202 c2113d72 Nikos Skalkotos
            self.out.output("Waiting for windows to shut down ...", False)
203 9ca717c4 Nikos Skalkotos
            vm.wait()
204 c2113d72 Nikos Skalkotos
            self.out.success("done")
205 640096fb Nikos Skalkotos
        finally:
206 10088af7 Nikos Skalkotos
            if monitor is not None:
207 10088af7 Nikos Skalkotos
                os.unlink(monitor)
208 10088af7 Nikos Skalkotos
209 10088af7 Nikos Skalkotos
            if vm is not None:
210 10088af7 Nikos Skalkotos
                self._destroy_vm(vm)
211 74780ad6 Nikos Skalkotos
212 640096fb Nikos Skalkotos
            self.out.output("Relaunching helper VM (may take a while) ...",
213 640096fb Nikos Skalkotos
                            False)
214 640096fb Nikos Skalkotos
            self.g.launch()
215 640096fb Nikos Skalkotos
            self.out.success('done')
216 640096fb Nikos Skalkotos
217 c2113d72 Nikos Skalkotos
            self.mount(readonly=False)
218 c2113d72 Nikos Skalkotos
            try:
219 c2113d72 Nikos Skalkotos
                if disabled_uac:
220 c2113d72 Nikos Skalkotos
                    self._update_uac_remote_setting(0)
221 c2113d72 Nikos Skalkotos
222 c2113d72 Nikos Skalkotos
                self._update_firewalls(*firewall_states)
223 c2113d72 Nikos Skalkotos
            finally:
224 c2113d72 Nikos Skalkotos
                self.umount()
225 640096fb Nikos Skalkotos
226 10088af7 Nikos Skalkotos
    def _create_vm(self, monitor):
227 10088af7 Nikos Skalkotos
        """Create a VM with the image attached as the disk
228 10088af7 Nikos Skalkotos

229 10088af7 Nikos Skalkotos
            monitor: a file to be used to monitor when the OS is up
230 10088af7 Nikos Skalkotos
        """
231 10088af7 Nikos Skalkotos
232 10088af7 Nikos Skalkotos
        def random_mac():
233 10088af7 Nikos Skalkotos
            mac = [0x00, 0x16, 0x3e,
234 10088af7 Nikos Skalkotos
                   random.randint(0x00, 0x7f),
235 10088af7 Nikos Skalkotos
                   random.randint(0x00, 0xff),
236 10088af7 Nikos Skalkotos
                   random.randint(0x00, 0xff)]
237 10088af7 Nikos Skalkotos
238 10088af7 Nikos Skalkotos
            return ':'.join(map(lambda x: "%02x" % x, mac))
239 10088af7 Nikos Skalkotos
240 10088af7 Nikos Skalkotos
        # Use ganeti's VNC port range for a random vnc port
241 10088af7 Nikos Skalkotos
        vnc_port = random.randint(11000, 14999)
242 10088af7 Nikos Skalkotos
        display = vnc_port - 5900
243 10088af7 Nikos Skalkotos
244 10088af7 Nikos Skalkotos
        vm = kvm('-smp', '1', '-m', '1024', '-drive',
245 10088af7 Nikos Skalkotos
                 'file=%s,format=raw,cache=none,if=virtio' % self.image.device,
246 10088af7 Nikos Skalkotos
                 '-netdev', 'type=user,hostfwd=tcp::445-:445,id=netdev0',
247 10088af7 Nikos Skalkotos
                 '-device', 'virtio-net-pci,mac=%s,netdev=netdev0' %
248 10088af7 Nikos Skalkotos
                 random_mac(), '-vnc', ':%d' % display, '-serial',
249 10088af7 Nikos Skalkotos
                 'file:%s' % monitor, _bg=True)
250 10088af7 Nikos Skalkotos
251 10088af7 Nikos Skalkotos
        return vm, display
252 10088af7 Nikos Skalkotos
253 10088af7 Nikos Skalkotos
    def _destroy_vm(self, vm):
254 10088af7 Nikos Skalkotos
        """Destroy a VM previously created by _create_vm"""
255 10088af7 Nikos Skalkotos
        if vm.process.alive:
256 10088af7 Nikos Skalkotos
            vm.terminate()
257 10088af7 Nikos Skalkotos
258 74780ad6 Nikos Skalkotos
    def _shutdown(self):
259 74780ad6 Nikos Skalkotos
        """Shuts down the windows VM"""
260 10088af7 Nikos Skalkotos
        self._guest_exec(r'shutdown /s /t 5')
261 74780ad6 Nikos Skalkotos
262 10088af7 Nikos Skalkotos
    def _wait_on_file(self, fname, msg):
263 10088af7 Nikos Skalkotos
        """Wait until a message appears on a file"""
264 74780ad6 Nikos Skalkotos
265 10088af7 Nikos Skalkotos
        for i in range(BOOT_TIMEOUT):
266 10088af7 Nikos Skalkotos
            time.sleep(1)
267 10088af7 Nikos Skalkotos
            with open(fname) as f:
268 10088af7 Nikos Skalkotos
                for line in f:
269 10088af7 Nikos Skalkotos
                    if line.startswith(msg):
270 10088af7 Nikos Skalkotos
                        return True
271 10088af7 Nikos Skalkotos
        return False
272 74780ad6 Nikos Skalkotos
273 10088af7 Nikos Skalkotos
    def _disable_autologon(self):
274 10088af7 Nikos Skalkotos
        """Disable automatic logon on the windows image"""
275 10088af7 Nikos Skalkotos
276 10088af7 Nikos Skalkotos
        winlogon = \
277 10088af7 Nikos Skalkotos
            r'"HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon"'
278 10088af7 Nikos Skalkotos
279 10088af7 Nikos Skalkotos
        self._guest_exec('REG DELETE %s /v DefaultUserName /f' % winlogon)
280 10088af7 Nikos Skalkotos
        self._guest_exec('REG DELETE %s /v DefaultPassword /f' % winlogon)
281 10088af7 Nikos Skalkotos
        self._guest_exec('REG DELETE %s /v AutoAdminLogon /f' % winlogon)
282 640096fb Nikos Skalkotos
283 640096fb Nikos Skalkotos
    def _registry_file_path(self, regfile):
284 640096fb Nikos Skalkotos
        """Retrieves the case sensitive path to a registry file"""
285 640096fb Nikos Skalkotos
286 640096fb Nikos Skalkotos
        systemroot = self.g.inspect_get_windows_systemroot(self.root)
287 640096fb Nikos Skalkotos
        path = "%s/system32/config/%s" % (systemroot, regfile)
288 640096fb Nikos Skalkotos
        try:
289 640096fb Nikos Skalkotos
            path = self.g.case_sensitive_path(path)
290 640096fb Nikos Skalkotos
        except RuntimeError as e:
291 640096fb Nikos Skalkotos
            raise FatalError("Unable to retrieve registry file: %s. Reason: %s"
292 640096fb Nikos Skalkotos
                             % (regfile, str(e)))
293 640096fb Nikos Skalkotos
        return path
294 640096fb Nikos Skalkotos
295 10088af7 Nikos Skalkotos
    def _enable_os_monitor(self):
296 10088af7 Nikos Skalkotos
        """Add a script in the registry that will send a random string to the
297 10088af7 Nikos Skalkotos
        first serial port when the windows image finishes booting.
298 10088af7 Nikos Skalkotos
        """
299 10088af7 Nikos Skalkotos
300 10088af7 Nikos Skalkotos
        token = "".join(random.choice(string.ascii_letters) for x in range(16))
301 10088af7 Nikos Skalkotos
302 10088af7 Nikos Skalkotos
        path = self._registry_file_path('SOFTWARE')
303 10088af7 Nikos Skalkotos
        softwarefd, software = tempfile.mkstemp()
304 10088af7 Nikos Skalkotos
        try:
305 10088af7 Nikos Skalkotos
            os.close(softwarefd)
306 10088af7 Nikos Skalkotos
            self.g.download(path, software)
307 10088af7 Nikos Skalkotos
308 10088af7 Nikos Skalkotos
            h = hivex.Hivex(software, write=True)
309 10088af7 Nikos Skalkotos
310 10088af7 Nikos Skalkotos
            # Enable automatic logon.
311 10088af7 Nikos Skalkotos
            # This is needed because we need to execute a script that we add in
312 10088af7 Nikos Skalkotos
            # the RunOnce registry entry and those programs only get executed
313 10088af7 Nikos Skalkotos
            # when a user logs on. There is a RunServicesOnce registry entry
314 10088af7 Nikos Skalkotos
            # whose keys get executed in the background when the logon dialog
315 10088af7 Nikos Skalkotos
            # box first appears, but they seem to only work with services and
316 10088af7 Nikos Skalkotos
            # not arbitrary command line expressions :-(
317 10088af7 Nikos Skalkotos
            #
318 10088af7 Nikos Skalkotos
            # Instructions on how to turn on automatic logon in Windows can be
319 10088af7 Nikos Skalkotos
            # found here: http://support.microsoft.com/kb/324737
320 10088af7 Nikos Skalkotos
            #
321 10088af7 Nikos Skalkotos
            # Warning: Registry change will not work if the โ€œLogon Bannerโ€ is
322 10088af7 Nikos Skalkotos
            # defined on the server either by a Group Policy object (GPO) or by
323 10088af7 Nikos Skalkotos
            # a local policy.
324 10088af7 Nikos Skalkotos
325 10088af7 Nikos Skalkotos
            winlogon = h.root()
326 10088af7 Nikos Skalkotos
            for child in ('Microsoft', 'Windows NT', 'CurrentVersion',
327 10088af7 Nikos Skalkotos
                          'Winlogon'):
328 10088af7 Nikos Skalkotos
                winlogon = h.node_get_child(winlogon, child)
329 10088af7 Nikos Skalkotos
330 10088af7 Nikos Skalkotos
            h.node_set_value(
331 10088af7 Nikos Skalkotos
                winlogon,
332 10088af7 Nikos Skalkotos
                {'key': 'DefaultUserName', 't': 1,
333 10088af7 Nikos Skalkotos
                 'value': "Administrator".encode('utf-16le')})
334 10088af7 Nikos Skalkotos
            h.node_set_value(
335 10088af7 Nikos Skalkotos
                winlogon,
336 10088af7 Nikos Skalkotos
                {'key': 'DefaultPassword', 't': 1,
337 10088af7 Nikos Skalkotos
                 'value':  self.sysprep_params['password'].encode('utf-16le')})
338 10088af7 Nikos Skalkotos
            h.node_set_value(
339 10088af7 Nikos Skalkotos
                winlogon,
340 10088af7 Nikos Skalkotos
                {'key': 'AutoAdminLogon', 't': 1,
341 10088af7 Nikos Skalkotos
                 'value': "1".encode('utf-16le')})
342 10088af7 Nikos Skalkotos
343 10088af7 Nikos Skalkotos
            key = h.root()
344 10088af7 Nikos Skalkotos
            for child in ('Microsoft', 'Windows', 'CurrentVersion'):
345 10088af7 Nikos Skalkotos
                key = h.node_get_child(key, child)
346 10088af7 Nikos Skalkotos
347 10088af7 Nikos Skalkotos
            runonce = h.node_get_child(key, "RunOnce")
348 10088af7 Nikos Skalkotos
            if runonce is None:
349 10088af7 Nikos Skalkotos
                runonce = h.node_add_child(key, "RunOnce")
350 10088af7 Nikos Skalkotos
351 10088af7 Nikos Skalkotos
            value = (
352 10088af7 Nikos Skalkotos
                r'C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe '
353 10088af7 Nikos Skalkotos
                r'-ExecutionPolicy RemoteSigned '
354 10088af7 Nikos Skalkotos
                r'"&{$port=new-Object System.IO.Ports.SerialPort COM1,9600,'
355 10088af7 Nikos Skalkotos
                r'None,8,one;$port.open();$port.WriteLine(\"' + token + r'\");'
356 10088af7 Nikos Skalkotos
                r'$port.Close()}"').encode('utf-16le')
357 10088af7 Nikos Skalkotos
358 10088af7 Nikos Skalkotos
            h.node_set_value(runonce,
359 10088af7 Nikos Skalkotos
                             {'key': "BootMonitor", 't': 1, 'value': value})
360 10088af7 Nikos Skalkotos
361 85e97ae0 Nikos Skalkotos
            value = (
362 85e97ae0 Nikos Skalkotos
                r'REG ADD HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion'
363 85e97ae0 Nikos Skalkotos
                r'\policies\system /v LocalAccountTokenFilterPolicy'
364 85e97ae0 Nikos Skalkotos
                r' /t REG_DWORD /d 1 /f').encode('utf-16le')
365 85e97ae0 Nikos Skalkotos
366 85e97ae0 Nikos Skalkotos
            h.node_set_value(runonce,
367 85e97ae0 Nikos Skalkotos
                             {'key': "UpdateRegistry", 't': 1, 'value': value})
368 85e97ae0 Nikos Skalkotos
369 10088af7 Nikos Skalkotos
            h.commit(None)
370 10088af7 Nikos Skalkotos
371 10088af7 Nikos Skalkotos
            self.g.upload(software, path)
372 10088af7 Nikos Skalkotos
        finally:
373 10088af7 Nikos Skalkotos
            os.unlink(software)
374 10088af7 Nikos Skalkotos
375 10088af7 Nikos Skalkotos
        return token
376 10088af7 Nikos Skalkotos
377 c2113d72 Nikos Skalkotos
    def _update_firewalls(self, domain, public, standard):
378 c2113d72 Nikos Skalkotos
        """Enables or disables the firewall for the Domain, the Public and the
379 c2113d72 Nikos Skalkotos
        Standard profile. Returns a triplete with the old values.
380 c2113d72 Nikos Skalkotos

381 c2113d72 Nikos Skalkotos
        1 will enable a firewall and 0 will disable it
382 c2113d72 Nikos Skalkotos
        """
383 c2113d72 Nikos Skalkotos
384 c2113d72 Nikos Skalkotos
        if domain not in (0, 1):
385 c2113d72 Nikos Skalkotos
            raise ValueError("Valid values for domain parameter are 0 and 1")
386 c2113d72 Nikos Skalkotos
387 c2113d72 Nikos Skalkotos
        if public not in (0, 1):
388 c2113d72 Nikos Skalkotos
            raise ValueError("Valid values for public parameter are 0 and 1")
389 c2113d72 Nikos Skalkotos
390 c2113d72 Nikos Skalkotos
        if standard not in (0, 1):
391 c2113d72 Nikos Skalkotos
            raise ValueError("Valid values for standard parameter are 0 and 1")
392 c2113d72 Nikos Skalkotos
393 c2113d72 Nikos Skalkotos
        path = self._registry_file_path("SYSTEM")
394 c2113d72 Nikos Skalkotos
        systemfd, system = tempfile.mkstemp()
395 c2113d72 Nikos Skalkotos
        try:
396 c2113d72 Nikos Skalkotos
            os.close(systemfd)
397 c2113d72 Nikos Skalkotos
            self.g.download(path, system)
398 c2113d72 Nikos Skalkotos
399 c2113d72 Nikos Skalkotos
            h = hivex.Hivex(system, write=True)
400 c2113d72 Nikos Skalkotos
401 c2113d72 Nikos Skalkotos
            select = h.node_get_child(h.root(), 'Select')
402 c2113d72 Nikos Skalkotos
            current_value = h.node_get_value(select, 'Current')
403 c2113d72 Nikos Skalkotos
404 c2113d72 Nikos Skalkotos
            # expecting a little endian dword
405 c2113d72 Nikos Skalkotos
            assert h.value_type(current_value)[1] == 4
406 c2113d72 Nikos Skalkotos
            current = "%03d" % h.value_dword(current_value)
407 c2113d72 Nikos Skalkotos
408 c2113d72 Nikos Skalkotos
            firewall_policy = h.root()
409 c2113d72 Nikos Skalkotos
            for child in ('ControlSet%s' % current, 'services', 'SharedAccess',
410 c2113d72 Nikos Skalkotos
                          'Parameters', 'FirewallPolicy'):
411 c2113d72 Nikos Skalkotos
                firewall_policy = h.node_get_child(firewall_policy, child)
412 c2113d72 Nikos Skalkotos
413 c2113d72 Nikos Skalkotos
            old_values = []
414 c2113d72 Nikos Skalkotos
            new_values = [domain, public, standard]
415 c2113d72 Nikos Skalkotos
            for profile in ('Domain', 'Public', 'Standard'):
416 c2113d72 Nikos Skalkotos
                node = h.node_get_child(firewall_policy, '%sProfile' % profile)
417 c2113d72 Nikos Skalkotos
418 c2113d72 Nikos Skalkotos
                old_value = h.node_get_value(node, 'EnableFirewall')
419 c2113d72 Nikos Skalkotos
420 c2113d72 Nikos Skalkotos
                # expecting a little endian dword
421 c2113d72 Nikos Skalkotos
                assert h.value_type(old_value)[1] == 4
422 c2113d72 Nikos Skalkotos
                old_values.append(h.value_dword(old_value))
423 c2113d72 Nikos Skalkotos
424 85e97ae0 Nikos Skalkotos
                h.node_set_value(
425 85e97ae0 Nikos Skalkotos
                    node, {'key': 'EnableFirewall', 't': 4L,
426 85e97ae0 Nikos Skalkotos
                           'value': struct.pack("<I", new_values.pop(0))})
427 c2113d72 Nikos Skalkotos
428 c2113d72 Nikos Skalkotos
            h.commit(None)
429 c2113d72 Nikos Skalkotos
            self.g.upload(system, path)
430 c2113d72 Nikos Skalkotos
431 c2113d72 Nikos Skalkotos
        finally:
432 c2113d72 Nikos Skalkotos
            os.unlink(system)
433 c2113d72 Nikos Skalkotos
434 c2113d72 Nikos Skalkotos
        return old_values
435 c2113d72 Nikos Skalkotos
436 640096fb Nikos Skalkotos
    def _update_uac_remote_setting(self, value):
437 640096fb Nikos Skalkotos
        """Updates the registry key value:
438 640096fb Nikos Skalkotos
        [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies
439 640096fb Nikos Skalkotos
        \System]"LocalAccountTokenFilterPolicy"
440 640096fb Nikos Skalkotos

441 640096fb Nikos Skalkotos
        value = 1 will disable the UAC remote restrictions
442 640096fb Nikos Skalkotos
        value = 0 will enable the UAC remote restrictions
443 640096fb Nikos Skalkotos

444 640096fb Nikos Skalkotos
        For more info see here: http://support.microsoft.com/kb/951016
445 640096fb Nikos Skalkotos

446 640096fb Nikos Skalkotos
        Returns:
447 640096fb Nikos Skalkotos
            True if the key is changed
448 640096fb Nikos Skalkotos
            False if the key is unchanged
449 640096fb Nikos Skalkotos
        """
450 640096fb Nikos Skalkotos
451 640096fb Nikos Skalkotos
        if value not in (0, 1):
452 640096fb Nikos Skalkotos
            raise ValueError("Valid values for value parameter are 0 and 1")
453 640096fb Nikos Skalkotos
454 640096fb Nikos Skalkotos
        path = self._registry_file_path('SOFTWARE')
455 640096fb Nikos Skalkotos
        softwarefd, software = tempfile.mkstemp()
456 640096fb Nikos Skalkotos
        try:
457 640096fb Nikos Skalkotos
            os.close(softwarefd)
458 640096fb Nikos Skalkotos
            self.g.download(path, software)
459 640096fb Nikos Skalkotos
460 640096fb Nikos Skalkotos
            h = hivex.Hivex(software, write=True)
461 640096fb Nikos Skalkotos
462 640096fb Nikos Skalkotos
            key = h.root()
463 640096fb Nikos Skalkotos
            for child in ('Microsoft', 'Windows', 'CurrentVersion', 'Policies',
464 640096fb Nikos Skalkotos
                          'System'):
465 640096fb Nikos Skalkotos
                key = h.node_get_child(key, child)
466 640096fb Nikos Skalkotos
467 640096fb Nikos Skalkotos
            policy = None
468 640096fb Nikos Skalkotos
            for val in h.node_values(key):
469 640096fb Nikos Skalkotos
                if h.value_key(val) == "LocalAccountTokenFilterPolicy":
470 640096fb Nikos Skalkotos
                    policy = val
471 640096fb Nikos Skalkotos
472 640096fb Nikos Skalkotos
            if policy is not None:
473 640096fb Nikos Skalkotos
                dword = h.value_dword(policy)
474 640096fb Nikos Skalkotos
                if dword == value:
475 640096fb Nikos Skalkotos
                    return False
476 640096fb Nikos Skalkotos
            elif value == 0:
477 640096fb Nikos Skalkotos
                return False
478 640096fb Nikos Skalkotos
479 85e97ae0 Nikos Skalkotos
            new_value = {'key': "LocalAccountTokenFilterPolicy", 't': 4L,
480 85e97ae0 Nikos Skalkotos
                         'value': struct.pack("<I", value)}
481 640096fb Nikos Skalkotos
482 640096fb Nikos Skalkotos
            h.node_set_value(key, new_value)
483 640096fb Nikos Skalkotos
            h.commit(None)
484 640096fb Nikos Skalkotos
485 640096fb Nikos Skalkotos
            self.g.upload(software, path)
486 640096fb Nikos Skalkotos
487 640096fb Nikos Skalkotos
        finally:
488 640096fb Nikos Skalkotos
            os.unlink(software)
489 640096fb Nikos Skalkotos
490 640096fb Nikos Skalkotos
        return True
491 640096fb Nikos Skalkotos
492 b8c0848c Nikos Skalkotos
    def _do_collect_metadata(self):
493 b8c0848c Nikos Skalkotos
        """Collect metadata about the OS"""
494 b8c0848c Nikos Skalkotos
        super(Windows, self)._do_collect_metadata()
495 76b200cf Nikos Skalkotos
        self.meta["USERS"] = " ".join(self._get_users())
496 76b200cf Nikos Skalkotos
497 76b200cf Nikos Skalkotos
    def _get_users(self):
498 121f3bc0 Nikos Skalkotos
        """Returns a list of users found in the images"""
499 640096fb Nikos Skalkotos
        path = self._registry_file_path('SAM')
500 76b200cf Nikos Skalkotos
        samfd, sam = tempfile.mkstemp()
501 76b200cf Nikos Skalkotos
        try:
502 640096fb Nikos Skalkotos
            os.close(samfd)
503 76b200cf Nikos Skalkotos
            self.g.download(path, sam)
504 76b200cf Nikos Skalkotos
505 76b200cf Nikos Skalkotos
            h = hivex.Hivex(sam)
506 76b200cf Nikos Skalkotos
507 76b200cf Nikos Skalkotos
            key = h.root()
508 76b200cf Nikos Skalkotos
            # Navigate to /SAM/Domains/Account/Users/Names
509 76b200cf Nikos Skalkotos
            for child in ('SAM', 'Domains', 'Account', 'Users', 'Names'):
510 76b200cf Nikos Skalkotos
                key = h.node_get_child(key, child)
511 76b200cf Nikos Skalkotos
512 76b200cf Nikos Skalkotos
            users = [h.node_name(x) for x in h.node_children(key)]
513 76b200cf Nikos Skalkotos
514 76b200cf Nikos Skalkotos
        finally:
515 76b200cf Nikos Skalkotos
            os.unlink(sam)
516 76b200cf Nikos Skalkotos
517 76b200cf Nikos Skalkotos
        # Filter out the guest account
518 76b200cf Nikos Skalkotos
        return filter(lambda x: x != "Guest", users)
519 aa2062ba Nikos Skalkotos
520 10088af7 Nikos Skalkotos
    def _guest_exec(self, command, fatal=True):
521 10088af7 Nikos Skalkotos
        """Execute a command on a windows VM"""
522 10088af7 Nikos Skalkotos
523 74780ad6 Nikos Skalkotos
        user = "Administrator%" + self.sysprep_params['password']
524 74780ad6 Nikos Skalkotos
        addr = 'localhost'
525 74780ad6 Nikos Skalkotos
        runas = '--runas=%s' % user
526 74780ad6 Nikos Skalkotos
        winexe = subprocess.Popen(
527 74780ad6 Nikos Skalkotos
            ['winexe', '-U', user, "//%s" % addr, runas, command],
528 74780ad6 Nikos Skalkotos
            stdout=subprocess.PIPE, stderr=subprocess.PIPE)
529 74780ad6 Nikos Skalkotos
530 10088af7 Nikos Skalkotos
        stdout, stderr = winexe.communicate()
531 74780ad6 Nikos Skalkotos
        rc = winexe.poll()
532 74780ad6 Nikos Skalkotos
533 10088af7 Nikos Skalkotos
        if rc != 0 and fatal:
534 10088af7 Nikos Skalkotos
            reason = stderr if len(stderr) else stdout
535 10088af7 Nikos Skalkotos
            raise FatalError("Command: `%s' failed. Reason: %s" %
536 10088af7 Nikos Skalkotos
                             (command, reason))
537 10088af7 Nikos Skalkotos
538 10088af7 Nikos Skalkotos
        return (stdout, stderr, rc)
539 74780ad6 Nikos Skalkotos
540 aa2062ba Nikos Skalkotos
# vim: set sta sts=4 shiftwidth=4 sw=4 et ai :