1
0

test_win_runas.py 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625
  1. # -*- coding: utf-8 -*-
  2. from __future__ import absolute_import, unicode_literals
  3. import textwrap
  4. import subprocess
  5. import socket
  6. import inspect
  7. import io
  8. # Service manager imports
  9. import sys
  10. import os
  11. import logging
  12. import threading
  13. import traceback
  14. import time
  15. import yaml
  16. from tests.support.case import ModuleCase
  17. from tests.support.mock import Mock
  18. from tests.support.paths import CODE_DIR
  19. from tests.support.unit import skipIf
  20. from tests.support.helpers import (
  21. with_system_user,
  22. )
  23. import salt.utils.files
  24. import salt.utils.win_runas
  25. import salt.ext.six
  26. try:
  27. import win32service
  28. import win32serviceutil
  29. import win32event
  30. import servicemanager
  31. import win32api
  32. CODE_DIR = win32api.GetLongPathName(CODE_DIR)
  33. HAS_WIN32 = True
  34. except ImportError:
  35. # Mock win32serviceutil object to avoid
  36. # a stacktrace in the _ServiceManager class
  37. win32serviceutil = Mock()
  38. HAS_WIN32 = False
  39. logger = logging.getLogger(__name__)
  40. PASSWORD = 'P@ssW0rd'
  41. NOPRIV_STDERR = 'ERROR: Logged-on user does not have administrative privilege.\n'
  42. PRIV_STDOUT = (
  43. '\nINFO: The system global flag \'maintain objects list\' needs\n '
  44. 'to be enabled to see local opened files.\n See Openfiles '
  45. '/? for more information.\n\n\nFiles opened remotely via local share '
  46. 'points:\n---------------------------------------------\n\n'
  47. 'INFO: No shared open files found.\n'
  48. )
  49. RUNAS_PATH = os.path.abspath(os.path.join(CODE_DIR, 'runas.py'))
  50. RUNAS_OUT = os.path.abspath(os.path.join(CODE_DIR, 'runas.out'))
  51. def default_target(service, *args, **kwargs):
  52. while service.active:
  53. time.sleep(service.timeout)
  54. class _ServiceManager(win32serviceutil.ServiceFramework):
  55. '''
  56. A windows service manager
  57. '''
  58. _svc_name_ = "Service Manager"
  59. _svc_display_name_ = "Service Manager"
  60. _svc_description_ = "A Service Manager"
  61. run_in_foreground = False
  62. target = default_target
  63. def __init__(self, args, target=None, timeout=60, active=True):
  64. win32serviceutil.ServiceFramework.__init__(self, args)
  65. self.hWaitStop = win32event.CreateEvent(None, 0, 0, None)
  66. self.timeout = timeout
  67. self.active = active
  68. if target is not None:
  69. self.target = target
  70. @classmethod
  71. def log_error(cls, msg):
  72. if cls.run_in_foreground:
  73. logger.error(msg)
  74. servicemanager.LogErrorMsg(msg)
  75. @classmethod
  76. def log_info(cls, msg):
  77. if cls.run_in_foreground:
  78. logger.info(msg)
  79. servicemanager.LogInfoMsg(msg)
  80. @classmethod
  81. def log_exception(cls, msg):
  82. if cls.run_in_foreground:
  83. logger.exception(msg)
  84. exc_info = sys.exc_info()
  85. tb = traceback.format_tb(exc_info[2])
  86. servicemanager.LogErrorMsg("{} {} {}".format(msg, exc_info[1], tb))
  87. @property
  88. def timeout_ms(self):
  89. return self.timeout * 1000
  90. def SvcStop(self):
  91. """
  92. Stop the service by; terminating any subprocess call, notify
  93. windows internals of the stop event, set the instance's active
  94. attribute to 'False' so the run loops stop.
  95. """
  96. self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING)
  97. win32event.SetEvent(self.hWaitStop)
  98. self.active = False
  99. def SvcDoRun(self):
  100. """
  101. Run the monitor in a separete thread so the main thread is
  102. free to react to events sent to the windows service.
  103. """
  104. servicemanager.LogMsg(
  105. servicemanager.EVENTLOG_INFORMATION_TYPE,
  106. servicemanager.PYS_SERVICE_STARTED,
  107. (self._svc_name_, ''),
  108. )
  109. self.log_info("Starting Service {}".format(self._svc_name_))
  110. monitor_thread = threading.Thread(target=self.target_thread)
  111. monitor_thread.start()
  112. while self.active:
  113. rc = win32event.WaitForSingleObject(self.hWaitStop, self.timeout_ms)
  114. if rc == win32event.WAIT_OBJECT_0:
  115. # Stop signal encountered
  116. self.log_info("Stopping Service")
  117. break
  118. if not monitor_thread.is_alive():
  119. self.log_info("Update Thread Died, Stopping Service")
  120. break
  121. def target_thread(self, *args, **kwargs):
  122. """
  123. Target Thread, handles any exception in the target method and
  124. logs them.
  125. """
  126. self.log_info("Monitor")
  127. try:
  128. self.target(self, *args, **kwargs)
  129. except Exception as exc:
  130. # TODO: Add traceback info to windows event log objects
  131. self.log_exception("Exception In Target")
  132. @classmethod
  133. def install(cls, username=None, password=None, start_type=None):
  134. if hasattr(cls, '_svc_reg_class_'):
  135. svc_class = cls._svc_reg_class_
  136. else:
  137. svc_class = win32serviceutil.GetServiceClassString(cls)
  138. win32serviceutil.InstallService(
  139. svc_class,
  140. cls._svc_name_,
  141. cls._svc_display_name_,
  142. description=cls._svc_description_,
  143. userName=username,
  144. password=password,
  145. startType=start_type,
  146. )
  147. @classmethod
  148. def remove(cls):
  149. win32serviceutil.RemoveService(
  150. cls._svc_name_
  151. )
  152. @classmethod
  153. def start(cls):
  154. win32serviceutil.StartService(
  155. cls._svc_name_
  156. )
  157. @classmethod
  158. def restart(cls):
  159. win32serviceutil.RestartService(
  160. cls._svc_name_
  161. )
  162. @classmethod
  163. def stop(cls):
  164. win32serviceutil.StopService(
  165. cls._svc_name_
  166. )
  167. def service_class_factory(cls_name, name, target=default_target, display_name='', description='', run_in_foreground=False):
  168. frm = inspect.stack()[1]
  169. mod = inspect.getmodule(frm[0])
  170. if salt.ext.six.PY2:
  171. cls_name = cls_name.encode()
  172. return type(
  173. cls_name,
  174. (_ServiceManager, object),
  175. {
  176. '__module__': mod.__name__,
  177. '_svc_name_': name,
  178. '_svc_display_name_': display_name or name,
  179. '_svc_description_': description,
  180. 'run_in_foreground': run_in_foreground,
  181. 'target': target,
  182. },
  183. )
  184. if HAS_WIN32:
  185. test_service = service_class_factory('test_service', 'test service')
  186. SERVICE_SOURCE = '''
  187. from __future__ import absolute_import, unicode_literals
  188. import logging
  189. logger = logging.getLogger()
  190. logging.basicConfig(level=logging.DEBUG, format="%(message)s")
  191. from tests.integration.utils.test_win_runas import service_class_factory
  192. import salt.utils.win_runas
  193. import sys
  194. import yaml
  195. OUTPUT = {}
  196. USERNAME = '{}'
  197. PASSWORD = '{}'
  198. def target(service, *args, **kwargs):
  199. service.log_info("target start")
  200. if PASSWORD:
  201. ret = salt.utils.win_runas.runas(
  202. 'cmd.exe /C OPENFILES',
  203. username=USERNAME,
  204. password=PASSWORD,
  205. )
  206. else:
  207. ret = salt.utils.win_runas.runas(
  208. 'cmd.exe /C OPENFILES',
  209. username=USERNAME,
  210. )
  211. service.log_info("win_runas returned %s" % ret)
  212. with open(OUTPUT, 'w') as fp:
  213. yaml.dump(ret, fp)
  214. service.log_info("target stop")
  215. # This class will get imported and run as the service
  216. test_service = service_class_factory('test_service', 'test service', target=target)
  217. if __name__ == '__main__':
  218. try:
  219. test_service.stop()
  220. except Exception as exc:
  221. logger.debug("stop service failed, this is ok.")
  222. try:
  223. test_service.remove()
  224. except Exception as exc:
  225. logger.debug("remove service failed, this os ok.")
  226. test_service.install()
  227. sys.exit(0)
  228. '''
  229. def wait_for_service(name, timeout=200):
  230. start = time.time()
  231. while True:
  232. status = win32serviceutil.QueryServiceStatus(name)
  233. if status[1] == win32service.SERVICE_STOPPED:
  234. break
  235. if time.time() - start > timeout:
  236. raise TimeoutError("Timeout waiting for service") # pylint: disable=undefined-variable
  237. time.sleep(.3)
  238. @skipIf(not HAS_WIN32, 'This test runs only on windows.')
  239. class RunAsTest(ModuleCase):
  240. @classmethod
  241. def setUpClass(cls):
  242. super(RunAsTest, cls).setUpClass()
  243. cls.hostname = socket.gethostname()
  244. @with_system_user('test-runas', on_existing='delete', delete=True,
  245. password=PASSWORD)
  246. def test_runas(self, username):
  247. ret = salt.utils.win_runas.runas('cmd.exe /C OPENFILES', username, PASSWORD)
  248. self.assertEqual(ret['stdout'], '')
  249. self.assertEqual(ret['stderr'], NOPRIV_STDERR)
  250. self.assertEqual(ret['retcode'], 1)
  251. @with_system_user('test-runas', on_existing='delete', delete=True,
  252. password=PASSWORD)
  253. def test_runas_no_pass(self, username):
  254. ret = salt.utils.win_runas.runas('cmd.exe /C OPENFILES', username)
  255. self.assertEqual(ret['stdout'], '')
  256. self.assertEqual(ret['stderr'], NOPRIV_STDERR)
  257. self.assertEqual(ret['retcode'], 1)
  258. @with_system_user('test-runas-admin', on_existing='delete', delete=True,
  259. password=PASSWORD, groups=['Administrators'])
  260. def test_runas_admin(self, username):
  261. ret = salt.utils.win_runas.runas('cmd.exe /C OPENFILES', username, PASSWORD)
  262. self.assertEqual(ret['stdout'], PRIV_STDOUT)
  263. self.assertEqual(ret['stderr'], '')
  264. self.assertEqual(ret['retcode'], 0)
  265. @with_system_user('test-runas-admin', on_existing='delete', delete=True,
  266. password=PASSWORD, groups=['Administrators'])
  267. def test_runas_admin_no_pass(self, username):
  268. ret = salt.utils.win_runas.runas('cmd.exe /C OPENFILES', username)
  269. self.assertEqual(ret['stdout'], PRIV_STDOUT)
  270. self.assertEqual(ret['stderr'], '')
  271. self.assertEqual(ret['retcode'], 0)
  272. def test_runas_system_user(self):
  273. ret = salt.utils.win_runas.runas('cmd.exe /C OPENFILES', 'SYSTEM')
  274. self.assertEqual(ret['stdout'], PRIV_STDOUT)
  275. self.assertEqual(ret['stderr'], '')
  276. self.assertEqual(ret['retcode'], 0)
  277. def test_runas_network_service(self):
  278. ret = salt.utils.win_runas.runas('cmd.exe /C OPENFILES', 'NETWORK SERVICE')
  279. self.assertEqual(ret['stdout'], '')
  280. self.assertEqual(ret['stderr'], NOPRIV_STDERR)
  281. self.assertEqual(ret['retcode'], 1)
  282. def test_runas_local_service(self):
  283. ret = salt.utils.win_runas.runas('cmd.exe /C OPENFILES', 'LOCAL SERVICE')
  284. self.assertEqual(ret['stdout'], '')
  285. self.assertEqual(ret['stderr'], NOPRIV_STDERR)
  286. self.assertEqual(ret['retcode'], 1)
  287. @with_system_user('test-runas', on_existing='delete', delete=True,
  288. password=PASSWORD)
  289. def test_runas_winrs(self, username):
  290. runaspy = textwrap.dedent('''
  291. import sys
  292. import salt.utils.win_runas
  293. username = '{}'
  294. password = '{}'
  295. sys.exit(salt.utils.win_runas.runas('cmd.exe /C OPENFILES', username, password)['retcode'])
  296. '''.format(username, PASSWORD))
  297. with salt.utils.files.fopen(RUNAS_PATH, 'w') as fp:
  298. fp.write(runaspy)
  299. ret = subprocess.call("cmd.exe /C winrs /r:{} python {}".format(
  300. self.hostname, RUNAS_PATH), shell=True)
  301. self.assertEqual(ret, 1)
  302. @with_system_user('test-runas', on_existing='delete', delete=True,
  303. password=PASSWORD)
  304. def test_runas_winrs_no_pass(self, username):
  305. runaspy = textwrap.dedent('''
  306. import sys
  307. import salt.utils.win_runas
  308. username = '{}'
  309. sys.exit(salt.utils.win_runas.runas('cmd.exe /C OPENFILES', username)['retcode'])
  310. '''.format(username))
  311. with salt.utils.files.fopen(RUNAS_PATH, 'w') as fp:
  312. fp.write(runaspy)
  313. ret = subprocess.call("cmd.exe /C winrs /r:{} python {}".format(
  314. self.hostname, RUNAS_PATH), shell=True)
  315. self.assertEqual(ret, 1)
  316. @with_system_user('test-runas-admin', on_existing='delete', delete=True,
  317. password=PASSWORD, groups=['Administrators'])
  318. def test_runas_winrs_admin(self, username):
  319. runaspy = textwrap.dedent('''
  320. import sys
  321. import salt.utils.win_runas
  322. username = '{}'
  323. password = '{}'
  324. sys.exit(salt.utils.win_runas.runas('cmd.exe /C OPENFILES', username, password)['retcode'])
  325. '''.format(username, PASSWORD))
  326. with salt.utils.files.fopen(RUNAS_PATH, 'w') as fp:
  327. fp.write(runaspy)
  328. ret = subprocess.call("cmd.exe /C winrs /r:{} python {}".format(
  329. self.hostname, RUNAS_PATH), shell=True)
  330. self.assertEqual(ret, 0)
  331. @with_system_user('test-runas-admin', on_existing='delete', delete=True,
  332. password=PASSWORD, groups=['Administrators'])
  333. def test_runas_winrs_admin_no_pass(self, username):
  334. runaspy = textwrap.dedent('''
  335. import sys
  336. import salt.utils.win_runas
  337. username = '{}'
  338. sys.exit(salt.utils.win_runas.runas('cmd.exe /C OPENFILES', username)['retcode'])
  339. '''.format(username))
  340. with salt.utils.files.fopen(RUNAS_PATH, 'w') as fp:
  341. fp.write(runaspy)
  342. ret = subprocess.call("cmd.exe /C winrs /r:{} python {}".format(
  343. self.hostname, RUNAS_PATH), shell=True)
  344. self.assertEqual(ret, 0)
  345. def test_runas_winrs_system_user(self):
  346. runaspy = textwrap.dedent('''
  347. import sys
  348. import salt.utils.win_runas
  349. sys.exit(salt.utils.win_runas.runas('cmd.exe /C OPENFILES', 'SYSTEM')['retcode'])
  350. ''')
  351. with salt.utils.files.fopen(RUNAS_PATH, 'w') as fp:
  352. fp.write(runaspy)
  353. ret = subprocess.call("cmd.exe /C winrs /r:{} python {}".format(
  354. self.hostname, RUNAS_PATH), shell=True)
  355. self.assertEqual(ret, 0)
  356. def test_runas_winrs_network_service_user(self):
  357. runaspy = textwrap.dedent('''
  358. import sys
  359. import salt.utils.win_runas
  360. sys.exit(salt.utils.win_runas.runas('cmd.exe /C OPENFILES', 'NETWORK SERVICE')['retcode'])
  361. ''')
  362. with salt.utils.files.fopen(RUNAS_PATH, 'w') as fp:
  363. fp.write(runaspy)
  364. ret = subprocess.call("cmd.exe /C winrs /r:{} python {}".format(
  365. self.hostname, RUNAS_PATH), shell=True)
  366. self.assertEqual(ret, 1)
  367. def test_runas_winrs_local_service_user(self):
  368. runaspy = textwrap.dedent('''
  369. import sys
  370. import salt.utils.win_runas
  371. sys.exit(salt.utils.win_runas.runas('cmd.exe /C OPENFILES', 'LOCAL SERVICE')['retcode'])
  372. ''')
  373. with salt.utils.files.fopen(RUNAS_PATH, 'w') as fp:
  374. fp.write(runaspy)
  375. ret = subprocess.call("cmd.exe /C winrs /r:{} python {}".format(
  376. self.hostname, RUNAS_PATH), shell=True)
  377. self.assertEqual(ret, 1)
  378. @with_system_user('test-runas', on_existing='delete', delete=True,
  379. password=PASSWORD)
  380. def test_runas_powershell_remoting(self, username):
  381. psrp_wrap = (
  382. 'powershell Invoke-Command -ComputerName {} -ScriptBlock {{ {} }}'
  383. )
  384. runaspy = textwrap.dedent('''
  385. import sys
  386. import salt.utils.win_runas
  387. username = '{}'
  388. password = '{}'
  389. sys.exit(salt.utils.win_runas.runas('cmd.exe /C OPENFILES', username, password)['retcode'])
  390. '''.format(username, PASSWORD))
  391. with salt.utils.files.fopen(RUNAS_PATH, 'w') as fp:
  392. fp.write(runaspy)
  393. cmd = 'python.exe {}'.format(RUNAS_PATH)
  394. ret = subprocess.call(
  395. psrp_wrap.format(self.hostname, cmd),
  396. shell=True
  397. )
  398. self.assertEqual(ret, 1)
  399. @with_system_user('test-runas', on_existing='delete', delete=True,
  400. password=PASSWORD)
  401. def test_runas_powershell_remoting_no_pass(self, username):
  402. psrp_wrap = (
  403. 'powershell Invoke-Command -ComputerName {} -ScriptBlock {{ {} }}'
  404. )
  405. runaspy = textwrap.dedent('''
  406. import sys
  407. import salt.utils.win_runas
  408. username = '{}'
  409. sys.exit(salt.utils.win_runas.runas('cmd.exe /C OPENFILES', username)['retcode'])
  410. '''.format(username))
  411. with salt.utils.files.fopen(RUNAS_PATH, 'w') as fp:
  412. fp.write(runaspy)
  413. cmd = 'python.exe {}'.format(RUNAS_PATH)
  414. ret = subprocess.call(
  415. psrp_wrap.format(self.hostname, cmd),
  416. shell=True
  417. )
  418. self.assertEqual(ret, 1)
  419. @with_system_user('test-runas-admin', on_existing='delete', delete=True,
  420. password=PASSWORD, groups=['Administrators'])
  421. def test_runas_powershell_remoting_admin(self, username):
  422. psrp_wrap = (
  423. 'powershell Invoke-Command -ComputerName {} -ScriptBlock {{ {} }}; exit $LASTEXITCODE'
  424. )
  425. runaspy = textwrap.dedent('''
  426. import sys
  427. import salt.utils.win_runas
  428. username = '{}'
  429. password = '{}'
  430. ret = salt.utils.win_runas.runas('cmd.exe /C OPENFILES', username, password)
  431. sys.exit(ret['retcode'])
  432. '''.format(username, PASSWORD))
  433. with salt.utils.files.fopen(RUNAS_PATH, 'w') as fp:
  434. fp.write(runaspy)
  435. cmd = 'python.exe {}; exit $LASTEXITCODE'.format(RUNAS_PATH)
  436. ret = subprocess.call(
  437. psrp_wrap.format(self.hostname, cmd),
  438. shell=True
  439. )
  440. self.assertEqual(ret, 0)
  441. @with_system_user('test-runas-admin', on_existing='delete', delete=True,
  442. password=PASSWORD, groups=['Administrators'])
  443. def test_runas_powershell_remoting_admin_no_pass(self, username):
  444. psrp_wrap = (
  445. 'powershell Invoke-Command -ComputerName {} -ScriptBlock {{ {} }}; exit $LASTEXITCODE'
  446. )
  447. runaspy = textwrap.dedent('''
  448. import sys
  449. import salt.utils.win_runas
  450. username = '{}'
  451. sys.exit(salt.utils.win_runas.runas('cmd.exe /C OPENFILES', username)['retcode'])
  452. '''.format(username))
  453. with salt.utils.files.fopen(RUNAS_PATH, 'w') as fp:
  454. fp.write(runaspy)
  455. cmd = 'python.exe {}; exit $LASTEXITCODE'.format(RUNAS_PATH)
  456. ret = subprocess.call(
  457. psrp_wrap.format(self.hostname, cmd),
  458. shell=True
  459. )
  460. self.assertEqual(ret, 0)
  461. @with_system_user('test-runas', on_existing='delete', delete=True,
  462. password=PASSWORD)
  463. def test_runas_service(self, username, timeout=200):
  464. if os.path.exists(RUNAS_OUT):
  465. os.remove(RUNAS_OUT)
  466. assert not os.path.exists(RUNAS_OUT)
  467. runaspy = SERVICE_SOURCE.format(repr(RUNAS_OUT), username, PASSWORD)
  468. with io.open(RUNAS_PATH, 'w', encoding='utf-8') as fp:
  469. fp.write(runaspy)
  470. cmd = 'python.exe {}'.format(RUNAS_PATH)
  471. ret = subprocess.call(
  472. cmd,
  473. shell=True
  474. )
  475. self.assertEqual(ret, 0)
  476. win32serviceutil.StartService('test service')
  477. wait_for_service('test service')
  478. with salt.utils.files.fopen(RUNAS_OUT, 'r') as fp:
  479. ret = yaml.load(fp)
  480. assert ret['retcode'] == 1, ret
  481. @with_system_user('test-runas', on_existing='delete', delete=True,
  482. password=PASSWORD)
  483. def test_runas_service_no_pass(self, username, timeout=200):
  484. if os.path.exists(RUNAS_OUT):
  485. os.remove(RUNAS_OUT)
  486. assert not os.path.exists(RUNAS_OUT)
  487. runaspy = SERVICE_SOURCE.format(repr(RUNAS_OUT), username, '')
  488. with io.open(RUNAS_PATH, 'w', encoding='utf-8') as fp:
  489. fp.write(runaspy)
  490. cmd = 'python.exe {}'.format(RUNAS_PATH)
  491. ret = subprocess.call(
  492. cmd,
  493. shell=True
  494. )
  495. self.assertEqual(ret, 0)
  496. win32serviceutil.StartService('test service')
  497. wait_for_service('test service')
  498. with salt.utils.files.fopen(RUNAS_OUT, 'r') as fp:
  499. ret = yaml.load(fp)
  500. assert ret['retcode'] == 1, ret
  501. @with_system_user('test-runas-admin', on_existing='delete', delete=True,
  502. password=PASSWORD, groups=['Administrators'])
  503. def test_runas_service_admin(self, username, timeout=200):
  504. if os.path.exists(RUNAS_OUT):
  505. os.remove(RUNAS_OUT)
  506. assert not os.path.exists(RUNAS_OUT)
  507. runaspy = SERVICE_SOURCE.format(repr(RUNAS_OUT), username, PASSWORD)
  508. with io.open(RUNAS_PATH, 'w', encoding='utf-8') as fp:
  509. fp.write(runaspy)
  510. cmd = 'python.exe {}'.format(RUNAS_PATH)
  511. ret = subprocess.call(
  512. cmd,
  513. shell=True
  514. )
  515. self.assertEqual(ret, 0)
  516. win32serviceutil.StartService('test service')
  517. wait_for_service('test service')
  518. with salt.utils.files.fopen(RUNAS_OUT, 'r') as fp:
  519. ret = yaml.load(fp)
  520. assert ret['retcode'] == 0, ret
  521. @with_system_user('test-runas-admin', on_existing='delete', delete=True,
  522. password=PASSWORD, groups=['Administrators'])
  523. def test_runas_service_admin_no_pass(self, username, timeout=200):
  524. if os.path.exists(RUNAS_OUT):
  525. os.remove(RUNAS_OUT)
  526. assert not os.path.exists(RUNAS_OUT)
  527. runaspy = SERVICE_SOURCE.format(repr(RUNAS_OUT), username, '')
  528. with io.open(RUNAS_PATH, 'w', encoding='utf-8') as fp:
  529. fp.write(runaspy)
  530. cmd = 'python.exe {}'.format(RUNAS_PATH)
  531. ret = subprocess.call(
  532. cmd,
  533. shell=True
  534. )
  535. self.assertEqual(ret, 0)
  536. win32serviceutil.StartService('test service')
  537. wait_for_service('test service')
  538. with salt.utils.files.fopen(RUNAS_OUT, 'r') as fp:
  539. ret = yaml.load(fp)
  540. assert ret['retcode'] == 0, ret
  541. def test_runas_service_system_user(self):
  542. if os.path.exists(RUNAS_OUT):
  543. os.remove(RUNAS_OUT)
  544. assert not os.path.exists(RUNAS_OUT)
  545. runaspy = SERVICE_SOURCE.format(repr(RUNAS_OUT), 'SYSTEM', '')
  546. with io.open(RUNAS_PATH, 'w', encoding='utf-8') as fp:
  547. fp.write(runaspy)
  548. cmd = 'python.exe {}'.format(RUNAS_PATH)
  549. ret = subprocess.call(
  550. cmd,
  551. shell=True
  552. )
  553. self.assertEqual(ret, 0)
  554. win32serviceutil.StartService('test service')
  555. wait_for_service('test service')
  556. with salt.utils.files.fopen(RUNAS_OUT, 'r') as fp:
  557. ret = yaml.load(fp)
  558. assert ret['retcode'] == 0, ret