test_win_lgpo.py 42 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926
  1. # -*- coding: utf-8 -*-
  2. from __future__ import absolute_import, print_function, unicode_literals
  3. import io
  4. import logging
  5. import os
  6. import re
  7. import pytest
  8. import salt.utils.files
  9. import salt.utils.platform
  10. import salt.utils.win_reg as reg
  11. from tests.support.case import ModuleCase
  12. from tests.support.helpers import random_string
  13. from tests.support.runtests import RUNTIME_VARS
  14. from tests.support.unit import skipIf
  15. log = logging.getLogger(__name__)
  16. @skipIf(not salt.utils.platform.is_windows(), "windows test only")
  17. class WinLgpoTest(ModuleCase):
  18. """
  19. Tests for salt.modules.win_lgpo
  20. """
  21. osrelease = None
  22. def _testRegistryPolicy(
  23. self,
  24. policy_name,
  25. policy_config,
  26. registry_value_hive,
  27. registry_value_path,
  28. registry_value_vname,
  29. expected_value_data,
  30. ):
  31. """
  32. Takes a registry based policy name and config and validates that the
  33. expected registry value exists and has the correct data
  34. policy_name
  35. name of the registry based policy to configure
  36. policy_config
  37. the configuration of the policy
  38. registry_value_hive
  39. the registry hive that the policy registry path is in
  40. registry_value_path
  41. the registry value path that the policy updates
  42. registry_value_vname
  43. the registry value name
  44. expected_value_data
  45. the expected data that the value will contain
  46. """
  47. ret = self.run_function(
  48. "lgpo.set_computer_policy", (policy_name, policy_config)
  49. )
  50. self.assertTrue(ret)
  51. val = reg.read_value(
  52. hive=registry_value_hive,
  53. key=registry_value_path,
  54. vname=registry_value_vname,
  55. )
  56. self.assertTrue(
  57. val["success"],
  58. msg="Failed to obtain the registry data for policy {0}".format(policy_name),
  59. )
  60. if val["success"]:
  61. self.assertEqual(
  62. val["vdata"],
  63. expected_value_data,
  64. "The registry value data {0} does not match the expected value {1} for policy {2}".format(
  65. val["vdata"], expected_value_data, policy_name
  66. ),
  67. )
  68. def _testSeceditPolicy(
  69. self,
  70. policy_name,
  71. policy_config,
  72. expected_regexes,
  73. cumulative_rights_assignments=True,
  74. ):
  75. """
  76. Takes a secedit policy name and config and validates that the expected
  77. output is returned from secedit
  78. policy_name
  79. name of the secedit policy to configure
  80. policy_config
  81. the configuration of the policy
  82. expected_regexes
  83. the expected regexes to be found in the secedit output file
  84. """
  85. ret = self.run_function(
  86. "lgpo.set_computer_policy",
  87. (policy_name, policy_config),
  88. cumulative_rights_assignments=cumulative_rights_assignments,
  89. )
  90. self.assertTrue(ret)
  91. secedit_output_file = os.path.join(
  92. RUNTIME_VARS.TMP, random_string("secedit-output-")
  93. )
  94. secedit_output = self.run_function(
  95. "cmd.run", (), cmd="secedit /export /cfg {0}".format(secedit_output_file)
  96. )
  97. secedit_file_content = None
  98. if secedit_output:
  99. with io.open(secedit_output_file, encoding="utf-16") as _reader:
  100. secedit_file_content = _reader.read()
  101. for expected_regex in expected_regexes:
  102. match = re.search(
  103. expected_regex, secedit_file_content, re.IGNORECASE | re.MULTILINE
  104. )
  105. self.assertIsNotNone(
  106. match,
  107. 'Failed validating policy "{0}" configuration, regex "{1}" not found in secedit output'.format(
  108. policy_name, expected_regex
  109. ),
  110. )
  111. def _testAdmxPolicy(
  112. self,
  113. policy_name,
  114. policy_config,
  115. expected_regexes,
  116. assert_true=True,
  117. policy_class="Machine",
  118. ):
  119. """
  120. Takes a ADMX policy name and config and validates that the expected
  121. output is returned from lgpo looking at the Registry.pol file
  122. policy_name
  123. name of the ADMX policy to configure
  124. policy_config
  125. the configuration of the policy
  126. expected_regexes
  127. the expected regexes to be found in the lgpo parse output
  128. assert_true
  129. set to false if expecting the module run to fail
  130. policy_class
  131. the policy class this policy belongs to, either Machine or User
  132. """
  133. lgpo_function = "set_computer_policy"
  134. lgpo_class = "/m"
  135. lgpo_folder = "Machine"
  136. if policy_class.lower() == "user":
  137. lgpo_function = "set_user_policy"
  138. lgpo_class = "/u"
  139. lgpo_folder = "User"
  140. ret = self.run_function(
  141. "lgpo.{0}".format(lgpo_function), (policy_name, policy_config)
  142. )
  143. log.debug("lgpo set_computer_policy ret == %s", ret)
  144. cmd = [
  145. "lgpo.exe",
  146. "/parse",
  147. lgpo_class,
  148. r"c:\Windows\System32\GroupPolicy\{}\Registry.pol".format(lgpo_folder),
  149. ]
  150. if assert_true:
  151. self.assertTrue(ret)
  152. lgpo_output = self.run_function("cmd.run", (), cmd=" ".join(cmd))
  153. # validate that the lgpo output doesn't say the format is invalid
  154. self.assertIsNone(
  155. re.search(r"Invalid file format\.", lgpo_output, re.IGNORECASE),
  156. msg="Failed validating Registry.pol file format",
  157. )
  158. # validate that the regexes we expect are in the output
  159. for expected_regex in expected_regexes:
  160. match = re.search(expected_regex, lgpo_output, re.IGNORECASE)
  161. self.assertIsNotNone(
  162. match,
  163. msg='Failed validating policy "{0}" configuration, regex '
  164. '"{1}" not found in lgpo output:\n{2}'
  165. "".format(policy_name, expected_regex, lgpo_output),
  166. )
  167. else:
  168. # expecting it to fail
  169. self.assertNotEqual(ret, True)
  170. def runTest(self):
  171. """
  172. runTest method
  173. """
  174. @classmethod
  175. def setUpClass(cls):
  176. """
  177. class setup function, only runs once
  178. downloads and extracts the lgpo.exe tool into c:/windows/system32
  179. for use in validating the registry.pol files
  180. gets osrelease grain for tests that are only applicable to certain
  181. windows versions
  182. """
  183. osrelease_grains = cls().run_function("grains.item", ["osrelease"])
  184. if "osrelease" in osrelease_grains:
  185. cls.osrelease = osrelease_grains["osrelease"]
  186. else:
  187. log.debug("Unable to get osrelease grain")
  188. if not os.path.exists(r"c:\windows\system32\lgpo.exe"):
  189. log.debug("lgpo.exe does not exist, attempting to download/extract")
  190. ret = cls().run_function(
  191. "state.single",
  192. ("archive.extracted", r"c:\windows\system32"),
  193. source="https://download.microsoft.com/download/8/5/C/85C25433-A1B0-4FFA-9429-7E023E7DA8D8/LGPO.zip",
  194. archive_format="zip",
  195. source_hash="sha256=6ffb6416366652993c992280e29faea3507b5b5aa661c33ba1af31f48acea9c4",
  196. enforce_toplevel=False,
  197. )
  198. log.debug("ret from archive.unzip == %s", ret)
  199. @pytest.mark.destructive_test
  200. def test_set_user_policy_point_and_print_restrictions(self):
  201. """
  202. Test setting/unsetting/changing the PointAndPrint_Restrictions user policy
  203. """
  204. # Disable Point and Print Restrictions
  205. self._testAdmxPolicy(
  206. r"Control Panel\Printers\Point and Print Restrictions",
  207. "Disabled",
  208. [
  209. r"User[\s]*Software\\Policies\\Microsoft\\Windows NT\\Printers\\PointAndPrint[\s]*Restricted[\s]*DWORD:0",
  210. r"User[\s]*Software\\Policies\\Microsoft\\Windows NT\\Printers\\PointAndPrint[\s]*TrustedServers[\s]*DELETE",
  211. r"User[\s]*Software\\Policies\\Microsoft\\Windows NT\\Printers\\PointAndPrint[\s]*ServerList[\s]*DELETE",
  212. r"User[\s]*Software\\Policies\\Microsoft\\Windows NT\\Printers\\PointAndPrint[\s]*InForest[\s]*DELETE",
  213. r"User[\s]*Software\\Policies\\Microsoft\\Windows NT\\Printers\\PointAndPrint[\s]*NoWarningNoElevationOnInstall[\s]*DELETE",
  214. r"User[\s]*Software\\Policies\\Microsoft\\Windows NT\\Printers\\PointAndPrint[\s]*UpdatePromptSettings[\s]*DELETE",
  215. ],
  216. policy_class="User",
  217. )
  218. # Enable Point and Print Restrictions
  219. self._testAdmxPolicy(
  220. r"Point and Print Restrictions",
  221. {
  222. "Users can only point and print to these servers": True,
  223. "Enter fully qualified server names separated by semicolons": "fakeserver1;fakeserver2",
  224. "Users can only point and print to machines in their forest": True,
  225. "When installing drivers for a new connection": "Show warning and elevation prompt",
  226. "When updating drivers for an existing connection": "Show warning only",
  227. },
  228. [
  229. r"User[\s]*Software\\Policies\\Microsoft\\Windows NT\\Printers\\PointAndPrint[\s]*Restricted[\s]*DWORD:1",
  230. r"User[\s]*Software\\Policies\\Microsoft\\Windows NT\\Printers\\PointAndPrint[\s]*TrustedServers[\s]*DWORD:1",
  231. r"User[\s]*Software\\Policies\\Microsoft\\Windows NT\\Printers\\PointAndPrint[\s]*ServerList[\s]*SZ:fakeserver1;fakeserver2",
  232. r"User[\s]*Software\\Policies\\Microsoft\\Windows NT\\Printers\\PointAndPrint[\s]*InForest[\s]*DWORD:1",
  233. r"User[\s]*Software\\Policies\\Microsoft\\Windows NT\\Printers\\PointAndPrint[\s]*NoWarningNoElevationOnInstall[\s]*DWORD:0",
  234. r"User[\s]*Software\\Policies\\Microsoft\\Windows NT\\Printers\\PointAndPrint[\s]*UpdatePromptSettings[\s]*DWORD:1",
  235. ],
  236. policy_class="User",
  237. )
  238. # set Point and Print Restrictions to 'Not Configured'
  239. self._testAdmxPolicy(
  240. r"Control Panel\Printers\Point and Print Restrictions",
  241. "Not Configured",
  242. [
  243. r"; Source file: c:\\windows\\system32\\grouppolicy\\user\\registry.pol[\s]*; PARSING COMPLETED."
  244. ],
  245. policy_class="User",
  246. )
  247. @pytest.mark.destructive_test
  248. def test_set_computer_policy_NTP_Client(self):
  249. """
  250. Test setting/unsetting/changing NTP Client policies
  251. """
  252. # Disable Configure NTP Client
  253. self._testAdmxPolicy(
  254. r"System\Windows Time Service\Time Providers\Configure Windows NTP Client",
  255. "Disabled",
  256. [
  257. r"Computer[\s]*Software\\Policies\\Microsoft\\W32time\\Parameters[\s]*NtpServer[\s]*DELETE",
  258. r"Computer[\s]*Software\\Policies\\Microsoft\\W32time\\Parameters[\s]*Type[\s]*DELETE",
  259. r"Computer[\s]*Software\\Policies\\Microsoft\\W32time\\TimeProviders\\NtpClient[\s]*CrossSiteSyncFlags[\s]*DELETE",
  260. r"Computer[\s]*Software\\Policies\\Microsoft\\W32time\\TimeProviders\\NtpClient[\s]*ResolvePeerBackoffMinutes[\s]*DELETE",
  261. r"Computer[\s]*Software\\Policies\\Microsoft\\W32time\\TimeProviders\\NtpClient[\s]*ResolvePeerBackoffMaxTimes[\s]*DELETE",
  262. r"Computer[\s]*Software\\Policies\\Microsoft\\W32time\\TimeProviders\\NtpClient[\s]*SpecialPollInterval[\s]*DELETE",
  263. r"Computer[\s]*Software\\Policies\\Microsoft\\W32time\\TimeProviders\\NtpClient[\s]*EventLogFlags[\s]*DELETE",
  264. ],
  265. )
  266. # Enable Configure NTP Client
  267. self._testAdmxPolicy(
  268. r"System\Windows Time Service\Time Providers\Configure Windows NTP Client",
  269. {
  270. "NtpServer": "time.windows.com,0x9",
  271. "Type": "NT5DS",
  272. "CrossSiteSyncFlags": 2,
  273. "ResolvePeerBackoffMinutes": 15,
  274. "ResolvePeerBackoffMaxTimes": 7,
  275. "W32TIME_SpecialPollInterval": 3600,
  276. "W32TIME_NtpClientEventLogFlags": 0,
  277. },
  278. [
  279. r"Computer[\s]*Software\\Policies\\Microsoft\\W32time\\Parameters[\s]*NtpServer[\s]*SZ:time.windows.com,0x9",
  280. r"Computer[\s]*Software\\Policies\\Microsoft\\W32time\\Parameters[\s]*Type[\s]*SZ:NT5DS",
  281. r"Computer[\s]*Software\\Policies\\Microsoft\\W32time\\TimeProviders\\NtpClient[\s]*CrossSiteSyncFlags[\s]*DWORD:2",
  282. r"Computer[\s]*Software\\Policies\\Microsoft\\W32time\\TimeProviders\\NtpClient[\s]*ResolvePeerBackoffMinutes[\s]*DWORD:15",
  283. r"Computer[\s]*Software\\Policies\\Microsoft\\W32time\\TimeProviders\\NtpClient[\s]*ResolvePeerBackoffMaxTimes[\s]*DWORD:7",
  284. r"Computer[\s]*Software\\Policies\\Microsoft\\W32time\\TimeProviders\\NtpClient[\s]*SpecialPollInterval[\s]*DWORD:3600",
  285. r"Computer[\s]*Software\\Policies\\Microsoft\\W32time\\TimeProviders\\NtpClient[\s]*EventLogFlags[\s]*DWORD:0",
  286. ],
  287. )
  288. # set Configure NTP Client to 'Not Configured'
  289. self._testAdmxPolicy(
  290. r"System\Windows Time Service\Time Providers\Configure Windows NTP Client",
  291. "Not Configured",
  292. [
  293. r"; Source file: c:\\windows\\system32\\grouppolicy\\machine\\registry.pol[\s]*; PARSING COMPLETED."
  294. ],
  295. )
  296. @pytest.mark.destructive_test
  297. def test_set_computer_policy_RA_Unsolicit(self):
  298. """
  299. Test setting/unsetting/changing RA_Unsolicit policy
  300. """
  301. # Disable RA_Unsolicit
  302. log.debug("Attempting to disable RA_Unsolicit")
  303. self._testAdmxPolicy(
  304. "RA_Unsolicit",
  305. "Disabled",
  306. [
  307. r"Computer[\s]*Software\\policies\\Microsoft\\Windows NT\\Terminal Services[\s]*fAllowUnsolicited[\s]*DWORD:0",
  308. r"Computer[\s]*Software\\policies\\Microsoft\\Windows NT\\Terminal Services[\s]*fAllowUnsolicitedFullControl[\s]*DELETE",
  309. r"Computer[\s]*Software\\policies\\Microsoft\\Windows NT\\Terminal Services\\RAUnsolicit[\s]*\*[\s]*DELETEALLVALUES",
  310. ],
  311. )
  312. # configure RA_Unsolicit
  313. log.debug("Attempting to configure RA_Unsolicit")
  314. self._testAdmxPolicy(
  315. "RA_Unsolicit",
  316. {
  317. "Configure Offer Remote Access": "Enabled",
  318. "Permit remote control of this computer": "Allow helpers to remotely control the computer",
  319. "Helpers": ["administrators", "user1"],
  320. },
  321. [
  322. r"Computer[\s]*Software\\policies\\Microsoft\\Windows NT\\Terminal Services\\RAUnsolicit[\s]*user1[\s]*SZ:user1[\s]*",
  323. r"Computer[\s]*Software\\policies\\Microsoft\\Windows NT\\Terminal Services\\RAUnsolicit[\s]*administrators[\s]*SZ:administrators[\s]*",
  324. r"Computer[\s]*Software\\policies\\Microsoft\\Windows NT\\Terminal Services[\s]*fAllowUnsolicited[\s]*DWORD:1",
  325. r"Computer[\s]*Software\\policies\\Microsoft\\Windows NT\\Terminal Services[\s]*fAllowUnsolicitedFullControl[\s]*DWORD:1",
  326. ],
  327. )
  328. # Not Configure RA_Unsolicit
  329. log.debug("Attempting to set RA_Unsolicit to Not Configured")
  330. self._testAdmxPolicy(
  331. "RA_Unsolicit",
  332. "Not Configured",
  333. [
  334. r"; Source file: c:\\windows\\system32\\grouppolicy\\machine\\registry.pol[\s]*; PARSING COMPLETED."
  335. ],
  336. )
  337. @pytest.mark.destructive_test
  338. def test_set_computer_policy_Pol_HardenedPaths(self):
  339. # Disable Pol_HardenedPaths
  340. log.debug("Attempting to disable Pol_HardenedPaths")
  341. self._testAdmxPolicy(
  342. "Pol_HardenedPaths",
  343. "Disabled",
  344. [
  345. r"Computer[\s]*Software\\policies\\Microsoft\\Windows\\NetworkProvider\\HardenedPaths[\s]*\*[\s]*DELETEALLVALUES"
  346. ],
  347. )
  348. # Configure Pol_HardenedPaths
  349. log.debug("Attempting to configure Pol_HardenedPaths")
  350. self._testAdmxPolicy(
  351. "Pol_HardenedPaths",
  352. {
  353. "Hardened UNC Paths": {
  354. r"\\*\NETLOGON": "RequireMutualAuthentication=1, RequireIntegrity=1",
  355. r"\\*\SYSVOL": "RequireMutualAuthentication=1, RequireIntegrity=1",
  356. }
  357. },
  358. [
  359. r"Computer[\s]*Software\\policies\\Microsoft\\Windows\\NetworkProvider\\HardenedPaths[\s]*\\\\\*\\NETLOGON[\s]*SZ:RequireMutualAuthentication=1, RequireIntegrity=1[\s]*",
  360. r"Computer[\s]*Software\\policies\\Microsoft\\Windows\\NetworkProvider\\HardenedPaths[\s]*\\\\\*\\SYSVOL[\s]*SZ:RequireMutualAuthentication=1, RequireIntegrity=1[\s]*",
  361. ],
  362. )
  363. # Not Configure Pol_HardenedPaths
  364. log.debug("Attempting to set Pol_HardenedPaths to Not Configured")
  365. self._testAdmxPolicy(
  366. "Pol_HardenedPaths",
  367. "Not Configured",
  368. [
  369. r"; Source file: c:\\windows\\system32\\grouppolicy\\machine\\registry.pol[\s]*; PARSING COMPLETED."
  370. ],
  371. )
  372. @pytest.mark.destructive_test
  373. def test_set_computer_policy_WindowsUpdate(self):
  374. """
  375. Test setting/unsetting/changing WindowsUpdate policy
  376. """
  377. # Configure Automatic Updates has different options in different builds
  378. # and releases of Windows, so we'll get the elements and add them if
  379. # they are present. Newer elements will need to be added manually as
  380. # they are released by Microsoft
  381. result = self.run_function(
  382. "lgpo.get_policy_info",
  383. ["Configure Automatic Updates"],
  384. policy_class="machine",
  385. )
  386. the_policy = {}
  387. the_policy_check_enabled = [
  388. r"Computer[\s]*Software\\Policies\\Microsoft\\Windows\\WindowsUpdate\\AU[\s]*NoAutoUpdate[\s]*DWORD:0",
  389. ]
  390. the_policy_check_disabled = [
  391. r"Computer[\s]*Software\\Policies\\Microsoft\\Windows\\WindowsUpdate\\AU[\s]*NoAutoUpdate[\s]*DWORD:1",
  392. ]
  393. for item in result["policy_elements"]:
  394. if "Configure automatic updating" in item["element_aliases"]:
  395. the_policy.update(
  396. {
  397. "Configure automatic updating": "4 - Auto download and schedule the install",
  398. }
  399. )
  400. the_policy_check_enabled.append(
  401. r"Computer[\s]*Software\\Policies\\Microsoft\\Windows\\WindowsUpdate\\AU[\s]*AUOptions[\s]*DWORD:4",
  402. )
  403. the_policy_check_disabled.append(
  404. r"Computer[\s]*Software\\Policies\\Microsoft\\Windows\\WindowsUpdate\\AU[\s]*AUOptions[\s]*DELETE",
  405. )
  406. elif "Install during automatic maintenance" in item["element_aliases"]:
  407. the_policy.update({"Install during automatic maintenance": True})
  408. the_policy_check_enabled.append(
  409. r"Computer[\s]*Software\\Policies\\Microsoft\\Windows\\WindowsUpdate\\AU[\s]*AutomaticMaintenanceEnabled[\s]*DWORD:1\s*",
  410. )
  411. the_policy_check_disabled.append(
  412. r"Computer[\s]*Software\\Policies\\Microsoft\\Windows\\WindowsUpdate\\AU[\s]*AutomaticMaintenanceEnabled[\s]*DELETE",
  413. )
  414. elif "Scheduled install day" in item["element_aliases"]:
  415. the_policy.update({"Scheduled install day": "7 - Every Saturday"})
  416. the_policy_check_enabled.append(
  417. r"Computer[\s]*Software\\Policies\\Microsoft\\Windows\\WindowsUpdate\\AU[\s]*ScheduledInstallDay[\s]*DWORD:7",
  418. )
  419. the_policy_check_disabled.append(
  420. r"Computer[\s]*Software\\Policies\\Microsoft\\Windows\\WindowsUpdate\\AU[\s]*ScheduledInstallDay[\s]*DELETE",
  421. )
  422. elif "Scheduled install time" in item["element_aliases"]:
  423. the_policy.update({"Scheduled install time": "17:00"})
  424. the_policy_check_enabled.append(
  425. r"Computer[\s]*Software\\Policies\\Microsoft\\Windows\\WindowsUpdate\\AU[\s]*ScheduledInstallTime[\s]*DWORD:17",
  426. )
  427. the_policy_check_disabled.append(
  428. r"Computer[\s]*Software\\Policies\\Microsoft\\Windows\\WindowsUpdate\\AU[\s]*ScheduledInstallTime[\s]*DELETE",
  429. )
  430. elif (
  431. "Install updates for other Microsoft products"
  432. in item["element_aliases"]
  433. ):
  434. the_policy.update(
  435. {"Install updates for other Microsoft products": True}
  436. )
  437. the_policy_check_enabled.append(
  438. r"Computer[\s]*Software\\Policies\\Microsoft\\Windows\\WindowsUpdate\\AU[\s]*AllowMUUpdateService[\s]*DWORD:1\s*"
  439. )
  440. the_policy_check_disabled.append(
  441. r"Computer[\s]*Software\\Policies\\Microsoft\\Windows\\WindowsUpdate\\AU[\s]*AllowMUUpdateService[\s]*DELETE"
  442. )
  443. elif "AutoUpdateSchEveryWeek" in item["element_aliases"]:
  444. the_policy.update({"AutoUpdateSchEveryWeek": True})
  445. the_policy_check_enabled.append(
  446. r"Computer[\s]*Software\\Policies\\Microsoft\\Windows\\WindowsUpdate\\AU[\s]*ScheduledInstallEveryWeek[\s]*DWORD:1\s*"
  447. )
  448. the_policy_check_disabled.append(
  449. r"Computer[\s]*Software\\Policies\\Microsoft\\Windows\\WindowsUpdate\\AU[\s]*ScheduledInstallEveryWeek[\s]*DELETE"
  450. )
  451. elif "First week of the month" in item["element_aliases"]:
  452. the_policy.update({"First week of the month": True})
  453. the_policy_check_enabled.append(
  454. r"Computer[\s]*Software\\Policies\\Microsoft\\Windows\\WindowsUpdate\\AU[\s]*ScheduledInstallFirstWeek[\s]*DWORD:1\s*"
  455. )
  456. the_policy_check_disabled.append(
  457. r"Computer[\s]*Software\\Policies\\Microsoft\\Windows\\WindowsUpdate\\AU[\s]*ScheduledInstallFirstWeek[\s]*DELETE"
  458. )
  459. elif "Second week of the month" in item["element_aliases"]:
  460. the_policy.update({"Second week of the month": True})
  461. the_policy_check_enabled.append(
  462. r"Computer[\s]*Software\\Policies\\Microsoft\\Windows\\WindowsUpdate\\AU[\s]*ScheduledInstallSecondWeek[\s]*DWORD:1\s*"
  463. )
  464. the_policy_check_disabled.append(
  465. r"Computer[\s]*Software\\Policies\\Microsoft\\Windows\\WindowsUpdate\\AU[\s]*ScheduledInstallSecondWeek[\s]*DELETE"
  466. )
  467. elif "Third week of the month" in item["element_aliases"]:
  468. the_policy.update({"Third week of the month": True})
  469. the_policy_check_enabled.append(
  470. r"Computer[\s]*Software\\Policies\\Microsoft\\Windows\\WindowsUpdate\\AU[\s]*ScheduledInstallThirdWeek[\s]*DWORD:1\s*"
  471. )
  472. the_policy_check_disabled.append(
  473. r"Computer[\s]*Software\\Policies\\Microsoft\\Windows\\WindowsUpdate\\AU[\s]*ScheduledInstallThirdWeek[\s]*DELETE"
  474. )
  475. elif "Fourth week of the month" in item["element_aliases"]:
  476. the_policy.update({"Fourth week of the month": True})
  477. the_policy_check_enabled.append(
  478. r"Computer[\s]*Software\\Policies\\Microsoft\\Windows\\WindowsUpdate\\AU[\s]*ScheduledInstallFourthWeek[\s]*DWORD:1\s*"
  479. )
  480. the_policy_check_disabled.append(
  481. r"Computer[\s]*Software\\Policies\\Microsoft\\Windows\\WindowsUpdate\\AU[\s]*ScheduledInstallFourthWeek[\s]*DELETE"
  482. )
  483. # enable Automatic Updates
  484. self._testAdmxPolicy(
  485. r"Windows Components\Windows Update\Configure Automatic Updates",
  486. the_policy,
  487. the_policy_check_enabled,
  488. )
  489. # disable Configure Automatic Updates
  490. self._testAdmxPolicy(
  491. r"Windows Components\Windows Update\Configure Automatic Updates",
  492. "Disabled",
  493. the_policy_check_disabled,
  494. )
  495. # set Configure Automatic Updates to 'Not Configured'
  496. self._testAdmxPolicy(
  497. r"Windows Components\Windows Update\Configure Automatic Updates",
  498. "Not Configured",
  499. [
  500. r"; Source file: c:\\windows\\system32\\grouppolicy\\machine\\registry.pol[\s]*; PARSING COMPLETED."
  501. ],
  502. )
  503. @pytest.mark.destructive_test
  504. def test_set_computer_policy_ClipboardRedirection(self):
  505. """
  506. Test setting/unsetting/changing ClipboardRedirection policy
  507. """
  508. # Enable/Disable/Not Configured "Do not allow Clipboard redirection"
  509. self._testAdmxPolicy(
  510. r"Windows Components\Remote Desktop Services\Remote Desktop Session Host\Device and Resource Redirection\Do not allow Clipboard redirection",
  511. "Enabled",
  512. [
  513. r"Computer[\s]*Software\\Policies\\Microsoft\\Windows NT\\Terminal Services[\s]*fDisableClip[\s]*DWORD:1"
  514. ],
  515. )
  516. self._testAdmxPolicy(
  517. r"Windows Components\Remote Desktop Services\Remote Desktop Session Host\Device and Resource Redirection\Do not allow Clipboard redirection",
  518. "Disabled",
  519. [
  520. r"Computer[\s]*Software\\Policies\\Microsoft\\Windows NT\\Terminal Services[\s]*fDisableClip[\s]*DWORD:0"
  521. ],
  522. )
  523. self._testAdmxPolicy(
  524. r"Windows Components\Remote Desktop Services\Remote Desktop Session Host\Device and Resource Redirection\Do not allow Clipboard redirection",
  525. "Not Configured",
  526. [
  527. r"; Source file: c:\\windows\\system32\\grouppolicy\\machine\\registry.pol[\s]*; PARSING COMPLETED."
  528. ],
  529. )
  530. @pytest.mark.destructive_test
  531. def test_set_computer_policy_GuestAccountStatus(self):
  532. """
  533. Test setting/unsetting/changing GuestAccountStatus
  534. """
  535. # disable GuestAccountStatus
  536. self._testSeceditPolicy(
  537. "GuestAccountStatus", "Disabled", [r"^EnableGuestAccount = 0"]
  538. )
  539. # enable GuestAccountStatus
  540. self._testSeceditPolicy(
  541. "GuestAccountStatus", "Enabled", [r"^EnableGuestAccount = 1"]
  542. )
  543. @pytest.mark.destructive_test
  544. def test_set_computer_policy_PasswordComplexity(self):
  545. """
  546. Test setting/unsetting/changing PasswordComplexity
  547. """
  548. # disable PasswordComplexity
  549. self._testSeceditPolicy(
  550. "Password must meet complexity requirements",
  551. "Disabled",
  552. [r"^PasswordComplexity = 0"],
  553. )
  554. # enable PasswordComplexity
  555. self._testSeceditPolicy(
  556. "PasswordComplexity", "Enabled", [r"^PasswordComplexity = 1"]
  557. )
  558. @pytest.mark.destructive_test
  559. def test_set_computer_policy_PasswordLen(self):
  560. """
  561. Test setting/unsetting/changing PasswordLength
  562. """
  563. # set Minimum password length
  564. self._testSeceditPolicy(
  565. "Minimum password length", 10, [r"^MinimumPasswordLength = 10"]
  566. )
  567. # set MinimumPasswordLength = 0
  568. self._testSeceditPolicy("MinPasswordLen", 0, [r"^MinimumPasswordLength = 0"])
  569. @pytest.mark.destructive_test
  570. def test_set_computer_policy_SeNetworkLogonRight(self):
  571. """
  572. Test setting/unsetting/changing PasswordLength
  573. """
  574. # set SeNetworkLogonRight to only Administrators
  575. self._testSeceditPolicy(
  576. "Access this computer from the network",
  577. ["Administrators"],
  578. [r"^SeNetworkLogonRight = \*S-1-5-32-544"],
  579. cumulative_rights_assignments=False,
  580. )
  581. # set SeNetworkLogonRight back to the default
  582. self._testSeceditPolicy(
  583. "SeNetworkLogonRight",
  584. ["Everyone", "Administrators", "Users", "Backup Operators"],
  585. [
  586. r"^SeNetworkLogonRight = \*S-1-1-0,\*S-1-5-32-544,\*S-1-5-32-545,\*S-1-5-32-551"
  587. ],
  588. )
  589. @pytest.mark.destructive_test
  590. def test_set_computer_policy_multipleAdmxPolicies(self):
  591. """
  592. Tests setting several ADMX policies in succession and validating the configuration w/lgop
  593. """
  594. # set one policy
  595. self._testAdmxPolicy(
  596. r"Windows Components\Remote Desktop Services\Remote Desktop Session Host\Device and Resource Redirection\Do not allow Clipboard redirection",
  597. "Disabled",
  598. [
  599. r"Computer[\s]*Software\\Policies\\Microsoft\\Windows NT\\Terminal Services[\s]*fDisableClip[\s]*DWORD:0"
  600. ],
  601. )
  602. # set another policy and make sure both this policy and the previous are okay
  603. self._testAdmxPolicy(
  604. "RA_Unsolicit",
  605. {
  606. "Configure Offer Remote Access": "Enabled",
  607. "Permit remote control of this computer": "Allow helpers to remotely control the computer",
  608. "Helpers": ["administrators", "user1"],
  609. },
  610. [
  611. r"Computer[\s]*Software\\Policies\\Microsoft\\Windows NT\\Terminal Services[\s]*fDisableClip[\s]*DWORD:0",
  612. r"Computer[\s]*Software\\policies\\Microsoft\\Windows NT\\Terminal Services\\RAUnsolicit[\s]*user1[\s]*SZ:user1[\s]*",
  613. r"Computer[\s]*Software\\policies\\Microsoft\\Windows NT\\Terminal Services\\RAUnsolicit[\s]*administrators[\s]*SZ:administrators[\s]*",
  614. r"Computer[\s]*Software\\policies\\Microsoft\\Windows NT\\Terminal Services[\s]*fAllowUnsolicited[\s]*DWORD:1",
  615. r"Computer[\s]*Software\\policies\\Microsoft\\Windows NT\\Terminal Services[\s]*fAllowUnsolicitedFullControl[\s]*DWORD:1",
  616. ],
  617. )
  618. # Configure Automatic Updates and validate everything is still okay
  619. self._testAdmxPolicy(
  620. r"Windows Components\Windows Update\Configure Automatic Updates",
  621. "Disabled",
  622. [
  623. r"Computer[\s]*Software\\Policies\\Microsoft\\Windows NT\\Terminal Services[\s]*fDisableClip[\s]*DWORD:0",
  624. r"Computer[\s]*Software\\policies\\Microsoft\\Windows NT\\Terminal Services\\RAUnsolicit[\s]*user1[\s]*SZ:user1[\s]*",
  625. r"Computer[\s]*Software\\policies\\Microsoft\\Windows NT\\Terminal Services\\RAUnsolicit[\s]*administrators[\s]*SZ:administrators[\s]*",
  626. r"Computer[\s]*Software\\policies\\Microsoft\\Windows NT\\Terminal Services[\s]*fAllowUnsolicited[\s]*DWORD:1",
  627. r"Computer[\s]*Software\\policies\\Microsoft\\Windows NT\\Terminal Services[\s]*fAllowUnsolicitedFullControl[\s]*DWORD:1",
  628. r"Computer[\s]*Software\\Policies\\Microsoft\\Windows\\WindowsUpdate\\AU[\s]*NoAutoUpdate[\s]*DWORD:1",
  629. r"Computer[\s]*Software\\Policies\\Microsoft\\Windows\\WindowsUpdate\\AU[\s]*AUOptions[\s]*DELETE",
  630. r"Computer[\s]*Software\\Policies\\Microsoft\\Windows\\WindowsUpdate\\AU[\s]*AutomaticMaintenanceEnabled[\s]*DELETE",
  631. r"Computer[\s]*Software\\Policies\\Microsoft\\Windows\\WindowsUpdate\\AU[\s]*ScheduledInstallDay[\s]*DELETE",
  632. r"Computer[\s]*Software\\Policies\\Microsoft\\Windows\\WindowsUpdate\\AU[\s]*ScheduledInstallTime[\s]*DELETE",
  633. r"Computer[\s]*Software\\Policies\\Microsoft\\Windows\\WindowsUpdate\\AU[\s]*AllowMUUpdateService[\s]*DELETE",
  634. ],
  635. )
  636. @pytest.mark.destructive_test
  637. def test_set_computer_policy_DisableDomainCreds(self):
  638. """
  639. Tests Enable/Disable of DisableDomainCreds policy
  640. """
  641. self._testRegistryPolicy(
  642. policy_name="DisableDomainCreds",
  643. policy_config="Enabled",
  644. registry_value_hive="HKEY_LOCAL_MACHINE",
  645. registry_value_path="SYSTEM\\CurrentControlSet\\Control\\Lsa",
  646. registry_value_vname="DisableDomainCreds",
  647. expected_value_data=1,
  648. )
  649. self._testRegistryPolicy(
  650. policy_name="Network access: Do not allow storage of passwords and credentials for network authentication",
  651. policy_config="Disabled",
  652. registry_value_hive="HKEY_LOCAL_MACHINE",
  653. registry_value_path="SYSTEM\\CurrentControlSet\\Control\\Lsa",
  654. registry_value_vname="DisableDomainCreds",
  655. expected_value_data=0,
  656. )
  657. @pytest.mark.destructive_test
  658. def test_set_computer_policy_ForceGuest(self):
  659. """
  660. Tests changing ForceGuest policy
  661. """
  662. self._testRegistryPolicy(
  663. policy_name="ForceGuest",
  664. policy_config="Guest only - local users authenticate as Guest",
  665. registry_value_hive="HKEY_LOCAL_MACHINE",
  666. registry_value_path="SYSTEM\\CurrentControlSet\\Control\\Lsa",
  667. registry_value_vname="ForceGuest",
  668. expected_value_data=1,
  669. )
  670. self._testRegistryPolicy(
  671. policy_name="Network access: Sharing and security model for local accounts",
  672. policy_config="Classic - local users authenticate as themselves",
  673. registry_value_hive="HKEY_LOCAL_MACHINE",
  674. registry_value_path="SYSTEM\\CurrentControlSet\\Control\\Lsa",
  675. registry_value_vname="ForceGuest",
  676. expected_value_data=0,
  677. )
  678. @pytest.mark.destructive_test
  679. def test_set_computer_policy_DisableUXWUAccess(self):
  680. """
  681. Tests changing DisableUXWUAccess
  682. #50079 shows using the 'Remove access to use all Windows Update features' failed
  683. Policy only exists on 2016
  684. """
  685. valid_osreleases = ["2016Server"]
  686. if self.osrelease not in valid_osreleases:
  687. self.skipTest(
  688. "DisableUXWUAccess policy is only applicable if the osrelease grain is {0}".format(
  689. " or ".join(valid_osreleases)
  690. )
  691. )
  692. else:
  693. self._testAdmxPolicy(
  694. r"DisableUXWUAccess",
  695. "Enabled",
  696. [
  697. r"Computer[\s]*Software\\Policies\\Microsoft\\Windows\\WindowsUpdate[\s]*SetDisableUXWUAccess[\s]*DWORD:1"
  698. ],
  699. )
  700. self._testAdmxPolicy(
  701. r"Remove access to use all Windows Update features",
  702. "Disabled",
  703. [
  704. r"Computer[\s]*Software\\Policies\\Microsoft\\Windows\\WindowsUpdate[\s]*SetDisableUXWUAccess[\s]*DWORD:0"
  705. ],
  706. )
  707. self._testAdmxPolicy(
  708. r"Windows Components\Windows Update\Remove access to use all Windows Update features",
  709. "Not Configured",
  710. [
  711. r"; Source file: c:\\windows\\system32\\grouppolicy\\machine\\registry.pol[\s]*; PARSING COMPLETED."
  712. ],
  713. )
  714. @pytest.mark.destructive_test
  715. def test_set_computer_policy_Access_data_sources_across_domains(self):
  716. """
  717. Tests that a policy that has multiple names
  718. """
  719. self._testAdmxPolicy(
  720. r"Access data sources across domains", "Enabled", [], assert_true=False
  721. )
  722. self._testAdmxPolicy(
  723. r"Windows Components\Internet Explorer\Internet Control Panel\Security Page\Internet Zone\Access data sources across domains",
  724. {"Access data sources across domains": "Prompt"},
  725. [
  726. r"Computer[\s]*Software\\Policies\\Microsoft\\Windows\\CurrentVersion\\Internet Settings\\Zones\\3[\s]*1406[\s]*DWORD:1"
  727. ],
  728. )
  729. self._testAdmxPolicy(
  730. r"Windows Components\Internet Explorer\Internet Control Panel\Security Page\Internet Zone\Access data sources across domains",
  731. {"Access data sources across domains": "Enable"},
  732. [
  733. r"Computer[\s]*Software\\Policies\\Microsoft\\Windows\\CurrentVersion\\Internet Settings\\Zones\\3[\s]*1406[\s]*DWORD:0"
  734. ],
  735. )
  736. self._testAdmxPolicy(
  737. r"Windows Components\Internet Explorer\Internet Control Panel\Security Page\Internet Zone\Access data sources across domains",
  738. "Disabled",
  739. [
  740. r"Computer[\s]*Software\\Policies\\Microsoft\\Windows\\CurrentVersion\\Internet Settings\\Zones\\3[\s]*1406[\s]*DELETE"
  741. ],
  742. )
  743. @pytest.mark.destructive_test
  744. def test_set_computer_policy_ActiveHours(self):
  745. """
  746. Test configuring the ActiveHours policy, #47784
  747. Only applies to 2016Server
  748. # activehours.sls
  749. active_hours_policy:
  750. lgpo.set:
  751. - computer_policy:
  752. 'ActiveHours':
  753. 'ActiveHoursStartTime': '8 AM'
  754. 'ActiveHoursEndTime': '7 PM'
  755. """
  756. valid_osreleases = ["2016Server"]
  757. if self.osrelease not in valid_osreleases:
  758. self.skipTest(
  759. "ActiveHours policy is only applicable if the osrelease grain is {0}".format(
  760. " or ".join(valid_osreleases)
  761. )
  762. )
  763. else:
  764. self._testAdmxPolicy(
  765. r"ActiveHours",
  766. {"ActiveHoursStartTime": "8 AM", "ActiveHoursEndTime": "7 PM"},
  767. [
  768. r"Computer[\s]*Software\\Policies\\Microsoft\\Windows\\WindowsUpdate[\s]*SetActiveHours[\s]*DWORD:1",
  769. r"Computer[\s]*Software\\Policies\\Microsoft\\Windows\\WindowsUpdate[\s]*ActiveHoursStart[\s]*DWORD:8",
  770. r"Computer[\s]*Software\\Policies\\Microsoft\\Windows\\WindowsUpdate[\s]*ActiveHoursEnd[\s]*DWORD:19",
  771. ],
  772. )
  773. self._testAdmxPolicy(
  774. r"ActiveHours",
  775. {"ActiveHoursStartTime": "5 AM", "ActiveHoursEndTime": "10 PM"},
  776. [
  777. r"Computer[\s]*Software\\Policies\\Microsoft\\Windows\\WindowsUpdate[\s]*SetActiveHours[\s]*DWORD:1",
  778. r"Computer[\s]*Software\\Policies\\Microsoft\\Windows\\WindowsUpdate[\s]*ActiveHoursStart[\s]*DWORD:5",
  779. r"Computer[\s]*Software\\Policies\\Microsoft\\Windows\\WindowsUpdate[\s]*ActiveHoursEnd[\s]*DWORD:22",
  780. ],
  781. )
  782. self._testAdmxPolicy(
  783. "Turn off auto-restart for updates during active hours",
  784. "Disabled",
  785. [
  786. r"Computer[\s]*Software\\Policies\\Microsoft\\Windows\\WindowsUpdate[\s]*SetActiveHours[\s]*DWORD:0",
  787. r"Computer[\s]*Software\\Policies\\Microsoft\\Windows\\WindowsUpdate[\s]*ActiveHoursStart[\s]*DELETE",
  788. r"Computer[\s]*Software\\Policies\\Microsoft\\Windows\\WindowsUpdate[\s]*ActiveHoursEnd[\s]*DELETE",
  789. ],
  790. )
  791. self._testAdmxPolicy(
  792. r"Windows Components\Windows Update\Turn off auto-restart for updates during active hours",
  793. "Not Configured",
  794. [
  795. r"; Source file: c:\\windows\\system32\\grouppolicy\\machine\\registry.pol[\s]*; PARSING COMPLETED."
  796. ],
  797. )
  798. @pytest.mark.destructive_test
  799. def test_set_computer_policy_AllowTelemetry(self):
  800. """
  801. Tests that a the AllowTelemetry policy is applied correctly and that it
  802. doesn't appear in subsequent group policy states as having changed
  803. """
  804. valid_osreleases = ["10", "2016Server", "2019Server"]
  805. if self.osrelease not in valid_osreleases:
  806. self.skipTest(
  807. "Allow Telemetry policy is only applicable if the "
  808. "osrelease grain is {0}".format(" or ".join(valid_osreleases))
  809. )
  810. else:
  811. self._testAdmxPolicy(
  812. "Allow Telemetry",
  813. {"AllowTelemetry": "1 - Basic"},
  814. [
  815. r"Software\\Policies\\Microsoft\\Windows\\DataCollection[\s]*AllowTelemetry[\s]*DWORD:1"
  816. ],
  817. assert_true=True,
  818. )
  819. # This policy does not exist on newer Windows builds
  820. result = self.run_function(
  821. "lgpo.get_policy_info",
  822. ["Disable pre-release features or settings"],
  823. policy_class="machine",
  824. )
  825. if result["policy_found"]:
  826. result = self.run_function(
  827. "state.single",
  828. ["lgpo.set"],
  829. name="state",
  830. computer_policy={
  831. "Disable pre-release features or settings": "Disabled"
  832. },
  833. )
  834. name = "lgpo_|-state_|-state_|-set"
  835. expected = {
  836. "new": {
  837. "Computer Configuration": {
  838. "Disable pre-release features or settings": "Disabled"
  839. }
  840. },
  841. "old": {
  842. "Computer Configuration": {
  843. "Disable pre-release features or settings": "Not Configured"
  844. }
  845. },
  846. }
  847. self.assertDictEqual(result[name]["changes"], expected)
  848. else:
  849. result = self.run_function(
  850. "lgpo.get_policy_info",
  851. ["Manage preview builds"],
  852. policy_class="machine",
  853. )
  854. if result["policy_found"]:
  855. result = self.run_function(
  856. "state.single",
  857. ["lgpo.set"],
  858. name="state",
  859. computer_policy={"Manage preview builds": "Disabled"},
  860. )
  861. name = "lgpo_|-state_|-state_|-set"
  862. expected = {
  863. "new": {
  864. "Computer Configuration": {
  865. "Manage preview builds": "Disabled"
  866. }
  867. },
  868. "old": {
  869. "Computer Configuration": {
  870. "Manage preview builds": "Not Configured"
  871. }
  872. },
  873. }
  874. self.assertDictEqual(result[name]["changes"], expected)
  875. def tearDown(self):
  876. """
  877. tearDown method, runs after each test
  878. """
  879. self.run_state(
  880. "file.absent",
  881. name="c:\\windows\\system32\\grouppolicy\\machine\\registry.pol",
  882. )
  883. self.run_state(
  884. "file.absent", name="c:\\windows\\system32\\grouppolicy\\user\\registry.pol"
  885. )