From 0f86bd4ec58bad24bb4b1f89fdf59c855d5b9e34 Mon Sep 17 00:00:00 2001 From: Nikos Skalkotos <skalkoto@grnet.gr> Date: Thu, 10 Jul 2014 16:54:02 +0300 Subject: [PATCH] windows: Add code for enabling accounts This is needed if the Administrator account is locked --- image_creator/os_type/windows/__init__.py | 6 +++- image_creator/os_type/windows/registry.py | 43 ++++++++++++++++++++++- 2 files changed, 47 insertions(+), 2 deletions(-) diff --git a/image_creator/os_type/windows/__init__.py b/image_creator/os_type/windows/__init__.py index 91a340a..35c313e 100644 --- a/image_creator/os_type/windows/__init__.py +++ b/image_creator/os_type/windows/__init__.py @@ -466,6 +466,7 @@ class Windows(OSBase): self.out.output("Preparing media for boot ...", False) with self.mount(readonly=False, silent=True): + activated = self.registry.reset_account(admin) v_val = self.registry.reset_passwd(admin) disabled_uac = self.registry.update_uac_remote_setting(1) self._add_boot_scripts() @@ -533,9 +534,11 @@ class Windows(OSBase): if disabled_uac: self.registry.update_uac_remote_setting(0) + if not activated: + self.registry.reset_account(admin, False) + if not self.sysprepped: # Reset the old password - admin = self.sysprep_params['admin'].value self.registry.reset_passwd(admin, v_val) self.registry.update_firewalls(*firewall_states) @@ -786,6 +789,7 @@ class Windows(OSBase): with self.mount(readonly=False, silent=True): admin = self.sysprep_params['admin'].value v_val = self.registry.reset_passwd(admin) + activated = self.registry.reset_account(admin) self.registry.enable_autologon(admin) tmp = uuid.uuid4().hex diff --git a/image_creator/os_type/windows/registry.py b/image_creator/os_type/windows/registry.py index 7715bc9..ff6ba3f 100644 --- a/image_creator/os_type/windows/registry.py +++ b/image_creator/os_type/windows/registry.py @@ -330,7 +330,7 @@ class Registry(object): # http://www.beginningtoseethelight.org/ntsecurity/index.htm # #D3BC3F5643A17823 fmt = '%ds4x8s4x%ds' % (0xa0, len(v_val) - 0xb0) - new = ("\x00" * 4).join(struct.unpack(fmt, v_val)) + new = ("\x00" * 4).join(struct.unpack(fmt, v_val)) hive.node_set_value(rid_node, REG_BINARY('V', new)) hive.commit(None) @@ -341,6 +341,47 @@ class Registry(object): assert 'old' in parent, "user: `%s' does not exist" % user return parent['old'] + def reset_account(self, user, activate=True): + + # This is a hack. I cannot assign a new value to nonlocal variable. + # This is why I'm using a dict + state = {} + + # Convert byte to int + to_int = lambda b: int(b.encode('hex'), 16) + + # Under HKEY_LOCAL_MACHINE\SAM\SAM\Domains\Account\Users\%RID% there is + # an F field that contains information about this user account. Bytes + # 56 & 57 are the account type and status flags. The first bit is the + # 'account disabled' bit: + # + # http://www.beginningtoseethelight.org/ntsecurity/index.htm + # #8603CF0AFBB170DD + # + isactive = lambda f: (to_int(f[56]) & 0x01) == 0 + + def update_f_field(hive, username, rid_node): + + field = hive.node_get_value(rid_node, 'F') + f_type, f_val = hive.value_value(field) + assert f_type == 3L, "F field type (=%d) isn't REG_BINARY" % f_type + + state['old'] = isactive(f_val) + if activate is state['old']: + # nothing to do + return + + mask = (lambda b: b & 0xfe) if activate else (lambda b: b | 0x01) + new = struct.pack("56sB23s", f_val[:56], mask(to_int(f_val[56])), + f_val[57:]) + + hive.node_set_value(rid_node, REG_BINARY('F', new)) + hive.commit(None) + + self._foreach_user([user], update_f_field, write=True) + + return state['old'] + def _foreach_user(self, userlist, action, write=False): """Performs an action on the RID node of a user in the registry, for every user found in the userlist. If userlist is empty, it performs the -- GitLab