Merge pull request #53900 from twangboy/fix_lgpo

Fix inconsistent full names in LGPO
This commit is contained in:
Daniel Wozniak 2019-08-09 02:15:40 -07:00 committed by GitHub
commit c0e49d9125
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 91 additions and 13 deletions

View file

@ -47,6 +47,7 @@ import re
import locale
import ctypes
import tempfile
import time
import uuid
# Import Salt libs
@ -70,6 +71,7 @@ __func_alias__ = {'set_': 'set'}
UUID = uuid.uuid4().hex
adm_policy_name_map = {True: {}, False: {}}
adm_policy_key_map = {}
HAS_WINDOWS_MODULES = False
# define some global XPATH variables that we'll set assuming all our imports are
# good
@ -84,6 +86,7 @@ VALUE_XPATH = None
TRUE_LIST_XPATH = None
FALSE_LIST_XPATH = None
REGKEY_XPATH = None
REGKEY_XPATH_MAPPED = None
POLICY_ANCESTOR_XPATH = None
ALL_CLASS_POLICY_XPATH = None
ADML_DISPLAY_NAME_XPATH = None
@ -114,6 +117,7 @@ try:
TRUE_LIST_XPATH = etree.XPath('.//*[local-name() = "trueList"]')
FALSE_LIST_XPATH = etree.XPath('.//*[local-name() = "falseList"]')
REGKEY_XPATH = etree.XPath('//*[translate(@*[local-name() = "key"], "ABCDEFGHIJKLMNOPQRSTUVWXYZ", "abcdefghijklmnopqrstuvwxyz") = $keyvalue]')
REGKEY_XPATH_MAPPED = etree.XPath('//*[@key = $keyvalue]')
POLICY_ANCESTOR_XPATH = etree.XPath('ancestor::*[local-name() = "policy"]')
ALL_CLASS_POLICY_XPATH = etree.XPath('//*[local-name() = "policy" and (@*[local-name() = "class"] = "Both" or @*[local-name() = "class"] = $registry_class)]')
ADML_DISPLAY_NAME_XPATH = etree.XPath('//*[local-name() = $displayNameType and @*[local-name() = "id"] = $displayNameId]')
@ -4861,6 +4865,7 @@ def _load_policy_definitions(path='c:\\Windows\\PolicyDefinitions',
temp_pol = _updateNamespace(temp_pol, this_namespace)
if 'key' in temp_pol.attrib:
temp_pol = _updatePolicyElements(temp_pol, temp_pol.attrib['key'])
adm_policy_key_map[temp_pol.attrib['key'].lower()] = temp_pol.attrib['key']
policydefs_policies_xpath(t_policy_definitions)[0].append(temp_pol)
policy_namespaces = xmltree.xpath(
'/{0}policyDefinitions/{0}policyNamespaces/{0}*'.format(namespace_string),
@ -5547,9 +5552,9 @@ def _getFullPolicyName(policy_item,
'''
helper function to retrieve the full policy name if needed
'''
adml_data = _get_policy_resources(language=adml_language)
if policy_name in adm_policy_name_map[return_full_policy_names]:
return adm_policy_name_map[return_full_policy_names][policy_name]
adml_data = _get_policy_resources(language=adml_language)
if return_full_policy_names and 'displayName' in policy_item.attrib:
fullPolicyName = _getAdmlDisplayName(adml_data, policy_item.attrib['displayName'])
if fullPolicyName:
@ -6084,21 +6089,41 @@ def _checkAllAdmxPolicies(policy_class,
re.sub(re.escape(module_policy_data.reg_pol_header.encode('utf-16-le')),
b'',
policy_file_data))).split(']['.encode('utf-16-le'))
log.debug('Parsing %s policies...', len(policy_filedata_split))
start_time = time.time()
# Get the policy for each item defined in Registry.pol
for policy_item in policy_filedata_split:
policy_item_key = policy_item.split('{0};'.format(chr(0)).encode('utf-16-le'))[0].decode('utf-16-le').lower()
if policy_item_key:
for admx_item in REGKEY_XPATH(admx_policy_definitions, keyvalue=policy_item_key):
# Find the policy definitions with this key
if policy_item_key in adm_policy_key_map:
# Use the faster method if possible
admx_items = REGKEY_XPATH_MAPPED(admx_policy_definitions,
keyvalue=adm_policy_key_map[policy_item_key])
log.debug('Found %s policies using the mapped method',
len(admx_items))
else:
# Fall back to this when the faster method is not feasible
admx_items = REGKEY_XPATH(admx_policy_definitions,
keyvalue=policy_item_key)
log.warning('%s not mapped', policy_item_key)
log.warning('Found %s policies using the original method',
len(admx_items))
for admx_item in admx_items:
# If this is a policy, append it to admx_policies
if etree.QName(admx_item).localname == 'policy':
if admx_item not in admx_policies:
admx_policies.append(admx_item)
else:
# If this is not a policy, find the parent policy for this item
for policy_item in POLICY_ANCESTOR_XPATH(admx_item):
if policy_item not in admx_policies:
admx_policies.append(policy_item)
log.debug('Parsing complete: %s seconds', time.time() - start_time)
log.debug('%s policies to examine', len(admx_policies))
if return_not_configured:
log.debug('returning non configured policies')
log.debug('Gathering non configured policies')
start_time = time.time()
not_configured_policies = ALL_CLASS_POLICY_XPATH(admx_policy_definitions, registry_class=policy_class)
for policy_item in admx_policies:
if policy_item in not_configured_policies:
@ -6125,6 +6150,10 @@ def _checkAllAdmxPolicies(policy_class,
policy_definition=not_configured_policy,
return_full_policy_names=return_full_policy_names,
adml_language=adml_language)
log.debug('Gathering complete: %s seconds', time.time() - start_time)
log.debug('Examining %s policies...', len(admx_policies))
start_time = time.time()
for admx_policy in admx_policies:
this_valuename = None
this_policy_setting = 'Not Configured'
@ -6449,6 +6478,16 @@ def _checkAllAdmxPolicies(policy_class,
policy_name=admx_policy.attrib['name'],
return_full_policy_names=return_full_policy_names,
adml_language=adml_language)
# Make sure the we're passing the full policy name
# This issue was found when setting the `Allow Telemetry` setting
# All following states would show a change in this setting
# When the state does it's first `lgpo.get` it would return `AllowTelemetry`
# On the second run, it would return `Allow Telemetry`
# This makes sure we're always returning the full_name when required
if admx_policy.attrib['name'] in policy_vals[this_policynamespace][this_policyname]:
full_name = full_names[this_policynamespace][this_policyname]
setting = policy_vals[this_policynamespace][this_policyname].pop(admx_policy.attrib['name'])
policy_vals[this_policynamespace][this_policyname][full_name] = setting
if this_policynamespace in policy_vals and this_policyname in policy_vals[this_policynamespace]:
if this_policynamespace not in hierarchy:
hierarchy[this_policynamespace] = {}
@ -6456,7 +6495,10 @@ def _checkAllAdmxPolicies(policy_class,
policy_definition=admx_policy,
return_full_policy_names=return_full_policy_names,
adml_language=adml_language)
log.debug('Examination complete: %s seconds', time.time() - start_time)
if policy_vals and return_full_policy_names and not hierarchical_return:
log.debug('Compiling non hierarchical return...')
start_time = time.time()
unpathed_dict = {}
pathed_dict = {}
for policy_namespace in list(policy_vals):
@ -6481,11 +6523,14 @@ def _checkAllAdmxPolicies(policy_class,
full_path_list.append(path_needed)
log.debug('full_path_list == %s', full_path_list)
policy_vals['\\'.join(full_path_list)] = policy_vals[policy_namespace].pop(path_needed)
log.debug('Compilation complete: %s seconds', time.time() - start_time)
for policy_namespace in list(policy_vals):
if policy_vals[policy_namespace] == {}:
policy_vals.pop(policy_namespace)
if policy_vals and hierarchical_return:
if hierarchy:
log.debug('Compiling hierarchical return...')
start_time = time.time()
for policy_namespace in hierarchy:
for hierarchy_item in hierarchy[policy_namespace]:
if hierarchy_item in policy_vals[policy_namespace]:
@ -6506,11 +6551,10 @@ def _checkAllAdmxPolicies(policy_class,
policy_vals = dictupdate.update(policy_vals, tdict)
if policy_namespace in policy_vals and policy_vals[policy_namespace] == {}:
policy_vals.pop(policy_namespace)
log.debug('Compilation complete: %s seconds', time.time() - start_time)
policy_vals = {
module_policy_data.admx_registry_classes[policy_class]['lgpo_section']: {
'Administrative Templates': policy_vals
}
}
module_policy_data.admx_registry_classes[policy_class]['lgpo_section']: {
'Administrative Templates': policy_vals}}
return policy_vals

View file

@ -36,7 +36,7 @@ class WinLgpoTest(ModuleCase):
registry_value_vname,
expected_value_data):
'''
Takes a registry based policy name and config and validates taht the
Takes a registry based policy name and config and validates that the
expected registry value exists and has the correct data
policy_name
@ -638,11 +638,45 @@ class WinLgpoTest(ModuleCase):
'Not Configured',
[r'; Source file: c:\\windows\\system32\\grouppolicy\\machine\\registry.pol[\s]*; PARSING COMPLETED.'])
@destructiveTest
def test_set_computer_policy_AllowTelemetry(self):
'''
Tests that a the AllowTelemetry policy is applied correctly and that it
doesn't appear in subsequent group policy states as having changed
'''
valid_osreleases = ['10', '2016Server', '2019Server']
if self.osrelease not in valid_osreleases:
self.skipTest('Allow Telemetry policy is only applicable if the '
'osrelease grain is {0}'.format(' or '.join(valid_osreleases)))
else:
self._testAdmxPolicy(
'Allow Telemetry',
{'AllowTelemetry': '1 - Basic'},
[r'Software\\Policies\\Microsoft\\Windows\\DataCollection[\s]*AllowTelemetry[\s]*DWORD:1'],
assert_true=True)
result = self.run_function(
'state.single',
['lgpo.set'],
name='state',
computer_policy={
'Disable pre-release features or settings': 'Disabled'
}
)
name = 'lgpo_|-state_|-state_|-set'
expected = {
'new': {
'Computer Configuration': {
'Windows Components\\Data Collection and Preview Builds\\Disable pre-release features or settings': 'Disabled'}},
'old': {'Computer Configuration': {}}}
self.assertDictEqual(result[name]['changes'], expected)
def tearDown(self):
'''
tearDown method, runs after each test
'''
ret = self.run_function('state.single',
('file.absent', 'c:\\windows\\system32\\grouppolicy\\machine\\registry.pol'))
ret = self.run_function('state.single',
('file.absent', 'c:\\windows\\system32\\grouppolicy\\user\\registry.pol'))
self.run_state(
'file.absent',
name='c:\\windows\\system32\\grouppolicy\\machine\\registry.pol')
self.run_state(
'file.absent',
name='c:\\windows\\system32\\grouppolicy\\user\\registry.pol')