task.c 36 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255
  1. /**
  2. * Licensed to the Apache Software Foundation (ASF) under one or more
  3. * contributor license agreements. See the NOTICE file distributed with this
  4. * work for additional information regarding copyright ownership. The ASF
  5. * licenses this file to you under the Apache License, Version 2.0 (the
  6. * "License"); you may not use this file except in compliance with the License.
  7. * You may obtain a copy of the License at
  8. *
  9. * http://www.apache.org/licenses/LICENSE-2.0
  10. *
  11. * Unless required by applicable law or agreed to in writing, software
  12. * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
  13. * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
  14. * License for the specific language governing permissions and limitations under
  15. * the License.
  16. */
  17. #include "winutils.h"
  18. #include <errno.h>
  19. #include <psapi.h>
  20. #include <malloc.h>
  21. #include <authz.h>
  22. #include <sddl.h>
  23. #define PSAPI_VERSION 1
  24. #pragma comment(lib, "psapi.lib")
  25. #define NM_WSCE_IMPERSONATE_ALLOWED L"yarn.nodemanager.windows-secure-container-executor.impersonate.allowed"
  26. #define NM_WSCE_IMPERSONATE_DENIED L"yarn.nodemanager.windows-secure-container-executor.impersonate.denied"
  27. // The S4U impersonation access check mask. Arbitrary value (we use 1 for the service access check)
  28. #define SERVICE_IMPERSONATE_MASK 0x00000002
  29. // Name for tracking this logon process when registering with LSA
  30. static const char *LOGON_PROCESS_NAME="Hadoop Container Executor";
  31. // Name for token source, must be less or eq to TOKEN_SOURCE_LENGTH (currently 8) chars
  32. static const char *TOKEN_SOURCE_NAME = "HadoopEx";
  33. // List of different task related command line options supported by
  34. // winutils.
  35. typedef enum TaskCommandOptionType
  36. {
  37. TaskInvalid,
  38. TaskCreate,
  39. TaskCreateAsUser,
  40. TaskIsAlive,
  41. TaskKill,
  42. TaskProcessList
  43. } TaskCommandOption;
  44. //----------------------------------------------------------------------------
  45. // Function: ParseCommandLine
  46. //
  47. // Description:
  48. // Parses the given command line. On success, out param 'command' contains
  49. // the user specified command.
  50. //
  51. // Returns:
  52. // TRUE: If the command line is valid
  53. // FALSE: otherwise
  54. static BOOL ParseCommandLine(__in int argc,
  55. __in_ecount(argc) wchar_t *argv[],
  56. __out TaskCommandOption *command)
  57. {
  58. *command = TaskInvalid;
  59. if (wcscmp(argv[0], L"task") != 0 )
  60. {
  61. return FALSE;
  62. }
  63. if (argc == 3) {
  64. if (wcscmp(argv[1], L"isAlive") == 0)
  65. {
  66. *command = TaskIsAlive;
  67. return TRUE;
  68. }
  69. if (wcscmp(argv[1], L"kill") == 0)
  70. {
  71. *command = TaskKill;
  72. return TRUE;
  73. }
  74. if (wcscmp(argv[1], L"processList") == 0)
  75. {
  76. *command = TaskProcessList;
  77. return TRUE;
  78. }
  79. }
  80. if (argc == 4) {
  81. if (wcscmp(argv[1], L"create") == 0)
  82. {
  83. *command = TaskCreate;
  84. return TRUE;
  85. }
  86. }
  87. if (argc >= 6) {
  88. if (wcscmp(argv[1], L"createAsUser") == 0)
  89. {
  90. *command = TaskCreateAsUser;
  91. return TRUE;
  92. }
  93. }
  94. return FALSE;
  95. }
  96. //----------------------------------------------------------------------------
  97. // Function: BuildImpersonateSecurityDescriptor
  98. //
  99. // Description:
  100. // Builds the security descriptor for the S4U impersonation permissions
  101. // This describes what users can be impersonated and what not
  102. //
  103. // Returns:
  104. // ERROR_SUCCESS: On success
  105. // GetLastError: otherwise
  106. //
  107. DWORD BuildImpersonateSecurityDescriptor(__out PSECURITY_DESCRIPTOR* ppSD) {
  108. DWORD dwError = ERROR_SUCCESS;
  109. size_t countAllowed = 0;
  110. PSID* allowedSids = NULL;
  111. size_t countDenied = 0;
  112. PSID* deniedSids = NULL;
  113. LPCWSTR value = NULL;
  114. WCHAR** tokens = NULL;
  115. size_t len = 0;
  116. size_t count = 0;
  117. size_t crt = 0;
  118. PSECURITY_DESCRIPTOR pSD = NULL;
  119. dwError = GetConfigValue(wsceConfigRelativePath, NM_WSCE_IMPERSONATE_ALLOWED, &len, &value);
  120. if (dwError) {
  121. ReportErrorCode(L"GetConfigValue:1", dwError);
  122. goto done;
  123. }
  124. if (0 == len) {
  125. dwError = ERROR_BAD_CONFIGURATION;
  126. ReportErrorCode(L"GetConfigValue:2", dwError);
  127. goto done;
  128. }
  129. dwError = SplitStringIgnoreSpaceW(len, value, L',', &count, &tokens);
  130. if (dwError) {
  131. ReportErrorCode(L"SplitStringIgnoreSpaceW:1", dwError);
  132. goto done;
  133. }
  134. allowedSids = LocalAlloc(LPTR, sizeof(PSID) * count);
  135. if (NULL == allowedSids) {
  136. dwError = GetLastError();
  137. ReportErrorCode(L"LocalAlloc:1", dwError);
  138. goto done;
  139. }
  140. for(crt = 0; crt < count; ++crt) {
  141. dwError = GetSidFromAcctNameW(tokens[crt], &allowedSids[crt]);
  142. if (dwError) {
  143. ReportErrorCode(L"GetSidFromAcctNameW:1", dwError);
  144. goto done;
  145. }
  146. }
  147. countAllowed = count;
  148. LocalFree(tokens);
  149. tokens = NULL;
  150. LocalFree(value);
  151. value = NULL;
  152. dwError = GetConfigValue(wsceConfigRelativePath, NM_WSCE_IMPERSONATE_DENIED, &len, &value);
  153. if (dwError) {
  154. ReportErrorCode(L"GetConfigValue:3", dwError);
  155. goto done;
  156. }
  157. if (0 != len) {
  158. dwError = SplitStringIgnoreSpaceW(len, value, L',', &count, &tokens);
  159. if (dwError) {
  160. ReportErrorCode(L"SplitStringIgnoreSpaceW:2", dwError);
  161. goto done;
  162. }
  163. deniedSids = LocalAlloc(LPTR, sizeof(PSID) * count);
  164. if (NULL == allowedSids) {
  165. dwError = GetLastError();
  166. ReportErrorCode(L"LocalAlloc:2", dwError);
  167. goto done;
  168. }
  169. for(crt = 0; crt < count; ++crt) {
  170. dwError = GetSidFromAcctNameW(tokens[crt], &deniedSids[crt]);
  171. if (dwError) {
  172. ReportErrorCode(L"GetSidFromAcctNameW:2", dwError);
  173. goto done;
  174. }
  175. }
  176. countDenied = count;
  177. }
  178. dwError = BuildServiceSecurityDescriptor(
  179. SERVICE_IMPERSONATE_MASK,
  180. countAllowed, allowedSids,
  181. countDenied, deniedSids,
  182. NULL,
  183. &pSD);
  184. if (dwError) {
  185. ReportErrorCode(L"BuildServiceSecurityDescriptor", dwError);
  186. goto done;
  187. }
  188. *ppSD = pSD;
  189. pSD = NULL;
  190. done:
  191. if (pSD) LocalFree(pSD);
  192. if (tokens) LocalFree(tokens);
  193. if (allowedSids) LocalFree(allowedSids);
  194. if (deniedSids) LocalFree(deniedSids);
  195. return dwError;
  196. }
  197. //----------------------------------------------------------------------------
  198. // Function: AddNodeManagerAndUserACEsToObject
  199. //
  200. // Description:
  201. // Adds ACEs to grant NM and user the provided access mask over a given handle
  202. //
  203. // Returns:
  204. // ERROR_SUCCESS: on success
  205. //
  206. DWORD AddNodeManagerAndUserACEsToObject(
  207. __in HANDLE hObject,
  208. __in LPWSTR user,
  209. __in ACCESS_MASK accessMask) {
  210. DWORD dwError = ERROR_SUCCESS;
  211. int countTokens = 0;
  212. size_t len = 0;
  213. LPCWSTR value = NULL;
  214. WCHAR** tokens = NULL;
  215. int crt = 0;
  216. PACL pDacl = NULL;
  217. PSECURITY_DESCRIPTOR psdProcess = NULL;
  218. LPSTR lpszOldDacl = NULL, lpszNewDacl = NULL;
  219. ULONG daclLen = 0;
  220. PACL pNewDacl = NULL;
  221. ACL_SIZE_INFORMATION si;
  222. DWORD dwNewAclSize = 0;
  223. PACE_HEADER pTempAce = NULL;
  224. BYTE sidTemp[SECURITY_MAX_SID_SIZE];
  225. DWORD cbSid = SECURITY_MAX_SID_SIZE;
  226. PSID tokenSid = NULL;
  227. // These hard-coded SIDs are allways added
  228. WELL_KNOWN_SID_TYPE forcesSidTypes[] = {
  229. WinLocalSystemSid,
  230. WinBuiltinAdministratorsSid};
  231. BOOL logSDs = IsDebuggerPresent(); // Check only once to avoid attach-while-running
  232. dwError = GetSecurityInfo(hObject,
  233. SE_KERNEL_OBJECT,
  234. DACL_SECURITY_INFORMATION,
  235. NULL,
  236. NULL,
  237. &pDacl,
  238. NULL,
  239. &psdProcess);
  240. if (dwError) {
  241. ReportErrorCode(L"GetSecurityInfo", dwError);
  242. goto done;
  243. }
  244. // This is debug only output for troubleshooting
  245. if (logSDs) {
  246. if (!ConvertSecurityDescriptorToStringSecurityDescriptor(
  247. psdProcess,
  248. SDDL_REVISION_1,
  249. DACL_SECURITY_INFORMATION,
  250. &lpszOldDacl,
  251. &daclLen)) {
  252. dwError = GetLastError();
  253. ReportErrorCode(L"ConvertSecurityDescriptorToStringSecurityDescriptor", dwError);
  254. goto done;
  255. }
  256. }
  257. ZeroMemory(&si, sizeof(si));
  258. if (!GetAclInformation(pDacl, &si, sizeof(si), AclSizeInformation)) {
  259. dwError = GetLastError();
  260. ReportErrorCode(L"GetAclInformation", dwError);
  261. goto done;
  262. }
  263. dwError = GetConfigValue(wsceConfigRelativePath, NM_WSCE_ALLOWED, &len, &value);
  264. if (ERROR_SUCCESS != dwError) {
  265. ReportErrorCode(L"GetConfigValue", dwError);
  266. goto done;
  267. }
  268. if (0 == len) {
  269. dwError = ERROR_BAD_CONFIGURATION;
  270. ReportErrorCode(L"GetConfigValue", dwError);
  271. goto done;
  272. }
  273. dwError = SplitStringIgnoreSpaceW(len, value, L',', &countTokens, &tokens);
  274. if (ERROR_SUCCESS != dwError) {
  275. ReportErrorCode(L"SplitStringIgnoreSpaceW", dwError);
  276. goto done;
  277. }
  278. // We're gonna add 1 ACE for each token found, +1 for user and +1 for each forcesSidTypes[]
  279. // ACCESS_ALLOWED_ACE struct contains the first DWORD of the SID
  280. //
  281. dwNewAclSize = si.AclBytesInUse +
  282. (countTokens + 1 + sizeof(forcesSidTypes)/sizeof(forcesSidTypes[0])) *
  283. (sizeof(ACCESS_ALLOWED_ACE) + SECURITY_MAX_SID_SIZE - sizeof(DWORD));
  284. pNewDacl = (PSID) LocalAlloc(LPTR, dwNewAclSize);
  285. if (!pNewDacl) {
  286. dwError = ERROR_OUTOFMEMORY;
  287. ReportErrorCode(L"LocalAlloc", dwError);
  288. goto done;
  289. }
  290. if (!InitializeAcl(pNewDacl, dwNewAclSize, ACL_REVISION)) {
  291. dwError = ERROR_OUTOFMEMORY;
  292. ReportErrorCode(L"InitializeAcl", dwError);
  293. goto done;
  294. }
  295. // Copy over old ACEs
  296. for (crt = 0; crt < si.AceCount; ++crt) {
  297. if (!GetAce(pDacl, crt, &pTempAce)) {
  298. dwError = ERROR_OUTOFMEMORY;
  299. ReportErrorCode(L"InitializeAcl", dwError);
  300. goto done;
  301. }
  302. if (!AddAce(pNewDacl, ACL_REVISION, MAXDWORD, pTempAce, pTempAce->AceSize)) {
  303. dwError = ERROR_OUTOFMEMORY;
  304. ReportErrorCode(L"InitializeAcl", dwError);
  305. goto done;
  306. }
  307. }
  308. // Add the configured allowed SIDs
  309. for (crt = 0; crt < countTokens; ++crt) {
  310. dwError = GetSidFromAcctNameW(tokens[crt], &tokenSid);
  311. if (ERROR_SUCCESS != dwError) {
  312. ReportErrorCode(L"GetSidFromAcctNameW", dwError);
  313. goto done;
  314. }
  315. if (!AddAccessAllowedAceEx(
  316. pNewDacl,
  317. ACL_REVISION_DS,
  318. CONTAINER_INHERIT_ACE | OBJECT_INHERIT_ACE,
  319. PROCESS_ALL_ACCESS,
  320. tokenSid)) {
  321. dwError = GetLastError();
  322. ReportErrorCode(L"AddAccessAllowedAceEx:1", dwError);
  323. goto done;
  324. }
  325. LocalFree(tokenSid);
  326. tokenSid = NULL;
  327. }
  328. // add the forced SIDs ACE
  329. for (crt = 0; crt < sizeof(forcesSidTypes)/sizeof(forcesSidTypes[0]); ++crt) {
  330. cbSid = SECURITY_MAX_SID_SIZE;
  331. if (!CreateWellKnownSid(forcesSidTypes[crt], NULL, &sidTemp, &cbSid)) {
  332. dwError = GetLastError();
  333. ReportErrorCode(L"CreateWellKnownSid", dwError);
  334. goto done;
  335. }
  336. if (!AddAccessAllowedAceEx(
  337. pNewDacl,
  338. ACL_REVISION_DS,
  339. CONTAINER_INHERIT_ACE | OBJECT_INHERIT_ACE,
  340. accessMask,
  341. (PSID) sidTemp)) {
  342. dwError = GetLastError();
  343. ReportErrorCode(L"AddAccessAllowedAceEx:2", dwError);
  344. goto done;
  345. }
  346. }
  347. // add the user ACE
  348. dwError = GetSidFromAcctNameW(user, &tokenSid);
  349. if (ERROR_SUCCESS != dwError) {
  350. ReportErrorCode(L"GetSidFromAcctNameW:user", dwError);
  351. goto done;
  352. }
  353. if (!AddAccessAllowedAceEx(
  354. pNewDacl,
  355. ACL_REVISION_DS,
  356. CONTAINER_INHERIT_ACE | OBJECT_INHERIT_ACE,
  357. PROCESS_ALL_ACCESS,
  358. tokenSid)) {
  359. dwError = GetLastError();
  360. ReportErrorCode(L"AddAccessAllowedAceEx:3", dwError);
  361. goto done;
  362. }
  363. LocalFree(tokenSid);
  364. tokenSid = NULL;
  365. dwError = SetSecurityInfo(hObject,
  366. SE_KERNEL_OBJECT,
  367. DACL_SECURITY_INFORMATION,
  368. NULL,
  369. NULL,
  370. pNewDacl,
  371. NULL);
  372. if (dwError) {
  373. ReportErrorCode(L"SetSecurityInfo", dwError);
  374. goto done;
  375. }
  376. // This is debug only output for troubleshooting
  377. if (logSDs) {
  378. dwError = GetSecurityInfo(hObject,
  379. SE_KERNEL_OBJECT,
  380. DACL_SECURITY_INFORMATION,
  381. NULL,
  382. NULL,
  383. &pDacl,
  384. NULL,
  385. &psdProcess);
  386. if (dwError) {
  387. ReportErrorCode(L"GetSecurityInfo:2", dwError);
  388. goto done;
  389. }
  390. if (!ConvertSecurityDescriptorToStringSecurityDescriptor(
  391. psdProcess,
  392. SDDL_REVISION_1,
  393. DACL_SECURITY_INFORMATION,
  394. &lpszNewDacl,
  395. &daclLen)) {
  396. dwError = GetLastError();
  397. ReportErrorCode(L"ConvertSecurityDescriptorToStringSecurityDescriptor:2", dwError);
  398. goto done;
  399. }
  400. LogDebugMessage(L"Old DACL: %s\nNew DACL: %s\n", lpszOldDacl, lpszNewDacl);
  401. }
  402. done:
  403. if (tokenSid) LocalFree(tokenSid);
  404. if (pNewDacl) LocalFree(pNewDacl);
  405. if (lpszOldDacl) LocalFree(lpszOldDacl);
  406. if (lpszNewDacl) LocalFree(lpszNewDacl);
  407. if (psdProcess) LocalFree(psdProcess);
  408. return dwError;
  409. }
  410. //----------------------------------------------------------------------------
  411. // Function: ValidateImpersonateAccessCheck
  412. //
  413. // Description:
  414. // Performs the access check for S4U impersonation
  415. //
  416. // Returns:
  417. // ERROR_SUCCESS: On success
  418. // ERROR_ACCESS_DENIED, GetLastError: otherwise
  419. //
  420. DWORD ValidateImpersonateAccessCheck(__in HANDLE logonHandle) {
  421. DWORD dwError = ERROR_SUCCESS;
  422. PSECURITY_DESCRIPTOR pSD = NULL;
  423. LUID luidUnused;
  424. AUTHZ_ACCESS_REQUEST request;
  425. AUTHZ_ACCESS_REPLY reply;
  426. DWORD authError = ERROR_SUCCESS;
  427. DWORD saclResult = 0;
  428. ACCESS_MASK grantedMask = 0;
  429. AUTHZ_RESOURCE_MANAGER_HANDLE hManager = NULL;
  430. AUTHZ_CLIENT_CONTEXT_HANDLE hAuthzToken = NULL;
  431. ZeroMemory(&luidUnused, sizeof(luidUnused));
  432. ZeroMemory(&request, sizeof(request));
  433. ZeroMemory(&reply, sizeof(reply));
  434. dwError = BuildImpersonateSecurityDescriptor(&pSD);
  435. if (dwError) {
  436. ReportErrorCode(L"BuildImpersonateSecurityDescriptor", dwError);
  437. goto done;
  438. }
  439. request.DesiredAccess = MAXIMUM_ALLOWED;
  440. reply.Error = &authError;
  441. reply.SaclEvaluationResults = &saclResult;
  442. reply.ResultListLength = 1;
  443. reply.GrantedAccessMask = &grantedMask;
  444. if (!AuthzInitializeResourceManager(
  445. AUTHZ_RM_FLAG_NO_AUDIT,
  446. NULL, // pfnAccessCheck
  447. NULL, // pfnComputeDynamicGroups
  448. NULL, // pfnFreeDynamicGroups
  449. NULL, // szResourceManagerName
  450. &hManager)) {
  451. dwError = GetLastError();
  452. ReportErrorCode(L"AuthzInitializeResourceManager", dwError);
  453. goto done;
  454. }
  455. if (!AuthzInitializeContextFromToken(
  456. 0,
  457. logonHandle,
  458. hManager,
  459. NULL, // expiration time
  460. luidUnused, // not used
  461. NULL, // callback args
  462. &hAuthzToken)) {
  463. dwError = GetLastError();
  464. ReportErrorCode(L"AuthzInitializeContextFromToken", dwError);
  465. goto done;
  466. }
  467. if (!AuthzAccessCheck(
  468. 0,
  469. hAuthzToken,
  470. &request,
  471. NULL, // AuditEvent
  472. pSD,
  473. NULL, // OptionalSecurityDescriptorArray
  474. 0, // OptionalSecurityDescriptorCount
  475. &reply,
  476. NULL // phAccessCheckResults
  477. )) {
  478. dwError = GetLastError();
  479. ReportErrorCode(L"AuthzAccessCheck", dwError);
  480. goto done;
  481. }
  482. LogDebugMessage(L"AutzAccessCheck: Error:%d sacl:%d access:%d\n",
  483. authError, saclResult, grantedMask);
  484. if (authError != ERROR_SUCCESS) {
  485. ReportErrorCode(L"AuthzAccessCheck:REPLY:1", authError);
  486. dwError = authError;
  487. }
  488. else if (!(grantedMask & SERVICE_IMPERSONATE_MASK)) {
  489. ReportErrorCode(L"AuthzAccessCheck:REPLY:2", ERROR_ACCESS_DENIED);
  490. dwError = ERROR_ACCESS_DENIED;
  491. }
  492. done:
  493. if (hAuthzToken) AuthzFreeContext(hAuthzToken);
  494. if (hManager) AuthzFreeResourceManager(hManager);
  495. if (pSD) LocalFree(pSD);
  496. return dwError;
  497. }
  498. //----------------------------------------------------------------------------
  499. // Function: CreateTaskImpl
  500. //
  501. // Description:
  502. // Creates a task via a jobobject. Outputs the
  503. // appropriate information to stdout on success, or stderr on failure.
  504. // logonHandle may be NULL, in this case the current logon will be utilized for the
  505. // created process
  506. //
  507. // Returns:
  508. // ERROR_SUCCESS: On success
  509. // GetLastError: otherwise
  510. DWORD CreateTaskImpl(__in_opt HANDLE logonHandle, __in PCWSTR jobObjName,__in PCWSTR cmdLine,
  511. __in LPCWSTR userName)
  512. {
  513. DWORD dwErrorCode = ERROR_SUCCESS;
  514. DWORD exitCode = EXIT_FAILURE;
  515. DWORD currDirCnt = 0;
  516. STARTUPINFO si;
  517. PROCESS_INFORMATION pi;
  518. HANDLE jobObject = NULL;
  519. JOBOBJECT_EXTENDED_LIMIT_INFORMATION jeli = { 0 };
  520. void * envBlock = NULL;
  521. WCHAR secureJobNameBuffer[MAX_PATH];
  522. LPCWSTR secureJobName = jobObjName;
  523. wchar_t* curr_dir = NULL;
  524. FILE *stream = NULL;
  525. if (NULL != logonHandle) {
  526. dwErrorCode = ValidateImpersonateAccessCheck(logonHandle);
  527. if (dwErrorCode) {
  528. ReportErrorCode(L"ValidateImpersonateAccessCheck", dwErrorCode);
  529. return dwErrorCode;
  530. }
  531. dwErrorCode = GetSecureJobObjectName(jobObjName, MAX_PATH, secureJobNameBuffer);
  532. if (dwErrorCode) {
  533. ReportErrorCode(L"GetSecureJobObjectName", dwErrorCode);
  534. return dwErrorCode;
  535. }
  536. secureJobName = secureJobNameBuffer;
  537. }
  538. // Create un-inheritable job object handle and set job object to terminate
  539. // when last handle is closed. So winutils.exe invocation has the only open
  540. // job object handle. Exit of winutils.exe ensures termination of job object.
  541. // Either a clean exit of winutils or crash or external termination.
  542. jobObject = CreateJobObject(NULL, secureJobName);
  543. dwErrorCode = GetLastError();
  544. if(jobObject == NULL || dwErrorCode == ERROR_ALREADY_EXISTS)
  545. {
  546. ReportErrorCode(L"CreateJobObject", dwErrorCode);
  547. return dwErrorCode;
  548. }
  549. jeli.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE;
  550. if(SetInformationJobObject(jobObject,
  551. JobObjectExtendedLimitInformation,
  552. &jeli,
  553. sizeof(jeli)) == 0)
  554. {
  555. dwErrorCode = GetLastError();
  556. ReportErrorCode(L"SetInformationJobObject", dwErrorCode);
  557. CloseHandle(jobObject);
  558. return dwErrorCode;
  559. }
  560. if (logonHandle != NULL) {
  561. dwErrorCode = AddNodeManagerAndUserACEsToObject(jobObject, userName, JOB_OBJECT_ALL_ACCESS);
  562. if (dwErrorCode) {
  563. ReportErrorCode(L"AddNodeManagerAndUserACEsToObject", dwErrorCode);
  564. CloseHandle(jobObject);
  565. return dwErrorCode;
  566. }
  567. }
  568. if(AssignProcessToJobObject(jobObject, GetCurrentProcess()) == 0)
  569. {
  570. dwErrorCode = GetLastError();
  571. ReportErrorCode(L"AssignProcessToJobObject", dwErrorCode);
  572. CloseHandle(jobObject);
  573. return dwErrorCode;
  574. }
  575. // the child JVM uses this env var to send the task OS process identifier
  576. // to the TaskTracker. We pass the job object name.
  577. if(SetEnvironmentVariable(L"JVM_PID", jobObjName) == 0)
  578. {
  579. dwErrorCode = GetLastError();
  580. ReportErrorCode(L"SetEnvironmentVariable", dwErrorCode);
  581. // We have to explictly Terminate, passing in the error code
  582. // simply closing the job would kill our own process with success exit status
  583. TerminateJobObject(jobObject, dwErrorCode);
  584. return dwErrorCode;
  585. }
  586. ZeroMemory( &si, sizeof(si) );
  587. si.cb = sizeof(si);
  588. ZeroMemory( &pi, sizeof(pi) );
  589. if( logonHandle != NULL ) {
  590. // create user environment for this logon
  591. if(!CreateEnvironmentBlock(&envBlock,
  592. logonHandle,
  593. TRUE )) {
  594. dwErrorCode = GetLastError();
  595. ReportErrorCode(L"CreateEnvironmentBlock", dwErrorCode);
  596. // We have to explictly Terminate, passing in the error code
  597. // simply closing the job would kill our own process with success exit status
  598. TerminateJobObject(jobObject, dwErrorCode);
  599. return dwErrorCode;
  600. }
  601. }
  602. // Get the required buffer size first
  603. currDirCnt = GetCurrentDirectory(0, NULL);
  604. if (0 < currDirCnt) {
  605. curr_dir = (wchar_t*) alloca(currDirCnt * sizeof(wchar_t));
  606. assert(curr_dir);
  607. currDirCnt = GetCurrentDirectory(currDirCnt, curr_dir);
  608. }
  609. if (0 == currDirCnt) {
  610. dwErrorCode = GetLastError();
  611. ReportErrorCode(L"GetCurrentDirectory", dwErrorCode);
  612. // We have to explictly Terminate, passing in the error code
  613. // simply closing the job would kill our own process with success exit status
  614. TerminateJobObject(jobObject, dwErrorCode);
  615. return dwErrorCode;
  616. }
  617. dwErrorCode = ERROR_SUCCESS;
  618. if (logonHandle == NULL) {
  619. if (!CreateProcess(
  620. NULL, // ApplicationName
  621. cmdLine, // command line
  622. NULL, // process security attributes
  623. NULL, // thread security attributes
  624. TRUE, // inherit handles
  625. 0, // creation flags
  626. NULL, // environment
  627. curr_dir, // current directory
  628. &si, // startup info
  629. &pi)) { // process info
  630. dwErrorCode = GetLastError();
  631. ReportErrorCode(L"CreateProcess", dwErrorCode);
  632. }
  633. // task create (w/o createAsUser) does not need the ACEs change on the process
  634. goto create_process_done;
  635. }
  636. // From here on is the secure S4U implementation for CreateProcessAsUser
  637. // We desire to grant process access to NM so that it can interogate process status
  638. // and resource utilization. Passing in a security descriptor though results in the
  639. // S4U privilege checks being done against that SD and CreateProcessAsUser fails.
  640. // So instead we create the process suspended and then we add the desired ACEs.
  641. //
  642. if (!CreateProcessAsUser(
  643. logonHandle, // logon token handle
  644. NULL, // Application handle
  645. cmdLine, // command line
  646. NULL, // process security attributes
  647. NULL, // thread security attributes
  648. FALSE, // inherit handles
  649. CREATE_UNICODE_ENVIRONMENT | CREATE_SUSPENDED, // creation flags
  650. envBlock, // environment
  651. curr_dir, // current directory
  652. &si, // startup info
  653. &pi)) { // process info
  654. dwErrorCode = GetLastError();
  655. ReportErrorCode(L"CreateProcessAsUser", dwErrorCode);
  656. goto create_process_done;
  657. }
  658. dwErrorCode = AddNodeManagerAndUserACEsToObject(pi.hProcess, userName, PROCESS_ALL_ACCESS);
  659. if (dwErrorCode) {
  660. ReportErrorCode(L"AddNodeManagerAndUserACEsToObject", dwErrorCode);
  661. goto create_process_done;
  662. }
  663. if (-1 == ResumeThread(pi.hThread)) {
  664. dwErrorCode = GetLastError();
  665. ReportErrorCode(L"ResumeThread", dwErrorCode);
  666. goto create_process_done;
  667. }
  668. create_process_done:
  669. if (dwErrorCode) {
  670. if( envBlock != NULL ) {
  671. DestroyEnvironmentBlock( envBlock );
  672. envBlock = NULL;
  673. }
  674. // We have to explictly Terminate, passing in the error code
  675. // simply closing the job would kill our own process with success exit status
  676. TerminateJobObject(jobObject, dwErrorCode);
  677. // This is tehnically dead code, we cannot reach this condition
  678. return dwErrorCode;
  679. }
  680. CloseHandle(pi.hThread);
  681. // Wait until child process exits.
  682. WaitForSingleObject( pi.hProcess, INFINITE );
  683. if(GetExitCodeProcess(pi.hProcess, &exitCode) == 0)
  684. {
  685. dwErrorCode = GetLastError();
  686. }
  687. CloseHandle( pi.hProcess );
  688. if( envBlock != NULL ) {
  689. DestroyEnvironmentBlock( envBlock );
  690. envBlock = NULL;
  691. }
  692. // Terminate job object so that all spawned processes are also killed.
  693. // This is needed because once this process closes the handle to the job
  694. // object and none of the spawned objects have the handle open (via
  695. // inheritance on creation) then it will not be possible for any other external
  696. // program (say winutils task kill) to terminate this job object via its name.
  697. if(TerminateJobObject(jobObject, exitCode) == 0)
  698. {
  699. dwErrorCode = GetLastError();
  700. }
  701. // comes here only on failure of TerminateJobObject
  702. CloseHandle(jobObject);
  703. if(dwErrorCode != ERROR_SUCCESS)
  704. {
  705. return dwErrorCode;
  706. }
  707. return exitCode;
  708. }
  709. //----------------------------------------------------------------------------
  710. // Function: CreateTask
  711. //
  712. // Description:
  713. // Creates a task via a jobobject. Outputs the
  714. // appropriate information to stdout on success, or stderr on failure.
  715. //
  716. // Returns:
  717. // ERROR_SUCCESS: On success
  718. // GetLastError: otherwise
  719. DWORD CreateTask(__in PCWSTR jobObjName,__in PWSTR cmdLine)
  720. {
  721. // call with null logon in order to create tasks utilizing the current logon
  722. return CreateTaskImpl( NULL, jobObjName, cmdLine, NULL);
  723. }
  724. //----------------------------------------------------------------------------
  725. // Function: CreateTaskAsUser
  726. //
  727. // Description:
  728. // Creates a task via a jobobject. Outputs the
  729. // appropriate information to stdout on success, or stderr on failure.
  730. //
  731. // Returns:
  732. // ERROR_SUCCESS: On success
  733. // GetLastError: otherwise
  734. DWORD CreateTaskAsUser(__in PCWSTR jobObjName,
  735. __in PCWSTR user, __in PCWSTR pidFilePath, __in PCWSTR cmdLine)
  736. {
  737. DWORD err = ERROR_SUCCESS;
  738. DWORD exitCode = EXIT_FAILURE;
  739. ULONG authnPkgId;
  740. HANDLE lsaHandle = INVALID_HANDLE_VALUE;
  741. PROFILEINFO pi;
  742. BOOL profileIsLoaded = FALSE;
  743. FILE* pidFile = NULL;
  744. DWORD retLen = 0;
  745. HANDLE logonHandle = NULL;
  746. err = EnableImpersonatePrivileges();
  747. if( err != ERROR_SUCCESS ) {
  748. ReportErrorCode(L"EnableImpersonatePrivileges", err);
  749. goto done;
  750. }
  751. err = RegisterWithLsa(LOGON_PROCESS_NAME ,&lsaHandle);
  752. if( err != ERROR_SUCCESS ) {
  753. ReportErrorCode(L"RegisterWithLsa", err);
  754. goto done;
  755. }
  756. err = LookupKerberosAuthenticationPackageId( lsaHandle, &authnPkgId );
  757. if( err != ERROR_SUCCESS ) {
  758. ReportErrorCode(L"LookupKerberosAuthenticationPackageId", err);
  759. goto done;
  760. }
  761. err = CreateLogonTokenForUser(lsaHandle,
  762. LOGON_PROCESS_NAME,
  763. TOKEN_SOURCE_NAME,
  764. authnPkgId,
  765. user,
  766. &logonHandle);
  767. if( err != ERROR_SUCCESS ) {
  768. ReportErrorCode(L"CreateLogonTokenForUser", err);
  769. goto done;
  770. }
  771. err = LoadUserProfileForLogon(logonHandle, &pi);
  772. if( err != ERROR_SUCCESS ) {
  773. ReportErrorCode(L"LoadUserProfileForLogon", err);
  774. goto done;
  775. }
  776. profileIsLoaded = TRUE;
  777. // Create the PID file
  778. if (!(pidFile = _wfopen(pidFilePath, "w"))) {
  779. err = GetLastError();
  780. ReportErrorCode(L"_wfopen:pidFilePath", err);
  781. goto done;
  782. }
  783. if (0 > fprintf_s(pidFile, "%ls", jobObjName)) {
  784. err = GetLastError();
  785. }
  786. fclose(pidFile);
  787. if (err != ERROR_SUCCESS) {
  788. ReportErrorCode(L"fprintf_s:pidFilePath", err);
  789. goto done;
  790. }
  791. err = CreateTaskImpl(logonHandle, jobObjName, cmdLine, user);
  792. done:
  793. if( profileIsLoaded ) {
  794. UnloadProfileForLogon( logonHandle, &pi );
  795. profileIsLoaded = FALSE;
  796. }
  797. if( logonHandle != NULL ) {
  798. CloseHandle(logonHandle);
  799. }
  800. if (INVALID_HANDLE_VALUE != lsaHandle) {
  801. UnregisterWithLsa(lsaHandle);
  802. }
  803. return err;
  804. }
  805. //----------------------------------------------------------------------------
  806. // Function: IsTaskAlive
  807. //
  808. // Description:
  809. // Checks if a task is alive via a jobobject. Outputs the
  810. // appropriate information to stdout on success, or stderr on failure.
  811. //
  812. // Returns:
  813. // ERROR_SUCCESS: On success
  814. // GetLastError: otherwise
  815. DWORD IsTaskAlive(const WCHAR* jobObjName, int* isAlive, int* procsInJob)
  816. {
  817. PJOBOBJECT_BASIC_PROCESS_ID_LIST procList;
  818. HANDLE jobObject = NULL;
  819. int numProcs = 100;
  820. WCHAR secureJobNameBuffer[MAX_PATH];
  821. *isAlive = FALSE;
  822. jobObject = OpenJobObject(JOB_OBJECT_QUERY, FALSE, jobObjName);
  823. if(jobObject == NULL)
  824. {
  825. // Try Global\...
  826. DWORD err = GetSecureJobObjectName(jobObjName, MAX_PATH, secureJobNameBuffer);
  827. if (err) {
  828. ReportErrorCode(L"GetSecureJobObjectName", err);
  829. return err;
  830. }
  831. jobObject = OpenJobObject(JOB_OBJECT_QUERY, FALSE, secureJobNameBuffer);
  832. }
  833. if(jobObject == NULL)
  834. {
  835. DWORD err = GetLastError();
  836. return err;
  837. }
  838. if(jobObject == NULL)
  839. {
  840. DWORD err = GetLastError();
  841. if(err == ERROR_FILE_NOT_FOUND)
  842. {
  843. // job object does not exist. assume its not alive
  844. return ERROR_SUCCESS;
  845. }
  846. return err;
  847. }
  848. procList = (PJOBOBJECT_BASIC_PROCESS_ID_LIST) LocalAlloc(LPTR, sizeof (JOBOBJECT_BASIC_PROCESS_ID_LIST) + numProcs*32);
  849. if (!procList)
  850. {
  851. DWORD err = GetLastError();
  852. CloseHandle(jobObject);
  853. return err;
  854. }
  855. if(QueryInformationJobObject(jobObject, JobObjectBasicProcessIdList, procList, sizeof(JOBOBJECT_BASIC_PROCESS_ID_LIST)+numProcs*32, NULL) == 0)
  856. {
  857. DWORD err = GetLastError();
  858. if(err != ERROR_MORE_DATA)
  859. {
  860. CloseHandle(jobObject);
  861. LocalFree(procList);
  862. return err;
  863. }
  864. }
  865. if(procList->NumberOfAssignedProcesses > 0)
  866. {
  867. *isAlive = TRUE;
  868. *procsInJob = procList->NumberOfAssignedProcesses;
  869. }
  870. LocalFree(procList);
  871. return ERROR_SUCCESS;
  872. }
  873. //----------------------------------------------------------------------------
  874. // Function: PrintTaskProcessList
  875. //
  876. // Description:
  877. // Prints resource usage of all processes in the task jobobject
  878. //
  879. // Returns:
  880. // ERROR_SUCCESS: On success
  881. // GetLastError: otherwise
  882. DWORD PrintTaskProcessList(const WCHAR* jobObjName)
  883. {
  884. DWORD i;
  885. PJOBOBJECT_BASIC_PROCESS_ID_LIST procList;
  886. int numProcs = 100;
  887. WCHAR secureJobNameBuffer[MAX_PATH];
  888. HANDLE jobObject = NULL;
  889. jobObject = OpenJobObject(JOB_OBJECT_QUERY, FALSE, jobObjName);
  890. if(jobObject == NULL)
  891. {
  892. // Try Global\...
  893. DWORD err = GetSecureJobObjectName(jobObjName, MAX_PATH, secureJobNameBuffer);
  894. if (err) {
  895. ReportErrorCode(L"GetSecureJobObjectName", err);
  896. return err;
  897. }
  898. jobObject = OpenJobObject(JOB_OBJECT_QUERY, FALSE, secureJobNameBuffer);
  899. }
  900. if(jobObject == NULL)
  901. {
  902. DWORD err = GetLastError();
  903. return err;
  904. }
  905. procList = (PJOBOBJECT_BASIC_PROCESS_ID_LIST) LocalAlloc(LPTR, sizeof (JOBOBJECT_BASIC_PROCESS_ID_LIST) + numProcs*32);
  906. if (!procList)
  907. {
  908. DWORD err = GetLastError();
  909. CloseHandle(jobObject);
  910. return err;
  911. }
  912. while(QueryInformationJobObject(jobObject, JobObjectBasicProcessIdList, procList, sizeof(JOBOBJECT_BASIC_PROCESS_ID_LIST)+numProcs*32, NULL) == 0)
  913. {
  914. DWORD err = GetLastError();
  915. if(err != ERROR_MORE_DATA)
  916. {
  917. CloseHandle(jobObject);
  918. LocalFree(procList);
  919. return err;
  920. }
  921. numProcs = procList->NumberOfAssignedProcesses;
  922. LocalFree(procList);
  923. procList = (PJOBOBJECT_BASIC_PROCESS_ID_LIST) LocalAlloc(LPTR, sizeof (JOBOBJECT_BASIC_PROCESS_ID_LIST) + numProcs*32);
  924. if (procList == NULL)
  925. {
  926. err = GetLastError();
  927. CloseHandle(jobObject);
  928. return err;
  929. }
  930. }
  931. for(i=0; i<procList->NumberOfProcessIdsInList; ++i)
  932. {
  933. HANDLE hProcess = OpenProcess( PROCESS_QUERY_INFORMATION, FALSE, (DWORD)procList->ProcessIdList[i] );
  934. if( hProcess != NULL )
  935. {
  936. PROCESS_MEMORY_COUNTERS_EX pmc;
  937. if ( GetProcessMemoryInfo( hProcess, (PPROCESS_MEMORY_COUNTERS)&pmc, sizeof(pmc)) )
  938. {
  939. FILETIME create, exit, kernel, user;
  940. if( GetProcessTimes( hProcess, &create, &exit, &kernel, &user) )
  941. {
  942. ULARGE_INTEGER kernelTime, userTime;
  943. ULONGLONG cpuTimeMs;
  944. kernelTime.HighPart = kernel.dwHighDateTime;
  945. kernelTime.LowPart = kernel.dwLowDateTime;
  946. userTime.HighPart = user.dwHighDateTime;
  947. userTime.LowPart = user.dwLowDateTime;
  948. cpuTimeMs = (kernelTime.QuadPart+userTime.QuadPart)/10000;
  949. fwprintf_s(stdout, L"%Iu,%Iu,%Iu,%I64u\n", procList->ProcessIdList[i], pmc.PrivateUsage, pmc.WorkingSetSize, cpuTimeMs);
  950. }
  951. }
  952. CloseHandle( hProcess );
  953. }
  954. }
  955. LocalFree(procList);
  956. CloseHandle(jobObject);
  957. return ERROR_SUCCESS;
  958. }
  959. //----------------------------------------------------------------------------
  960. // Function: Task
  961. //
  962. // Description:
  963. // Manages a task via a jobobject (create/isAlive/kill). Outputs the
  964. // appropriate information to stdout on success, or stderr on failure.
  965. //
  966. // Returns:
  967. // ERROR_SUCCESS: On success
  968. // Error code otherwise: otherwise
  969. int Task(__in int argc, __in_ecount(argc) wchar_t *argv[])
  970. {
  971. DWORD dwErrorCode = ERROR_SUCCESS;
  972. TaskCommandOption command = TaskInvalid;
  973. wchar_t* cmdLine = NULL;
  974. wchar_t buffer[16*1024] = L""; // 32K max command line
  975. size_t charCountBufferLeft = sizeof(buffer)/sizeof(wchar_t);
  976. int crtArgIndex = 0;
  977. size_t argLen = 0;
  978. size_t wscatErr = 0;
  979. wchar_t* insertHere = NULL;
  980. enum {
  981. ARGC_JOBOBJECTNAME = 2,
  982. ARGC_USERNAME,
  983. ARGC_PIDFILE,
  984. ARGC_COMMAND,
  985. ARGC_COMMAND_ARGS
  986. };
  987. if (!ParseCommandLine(argc, argv, &command)) {
  988. dwErrorCode = ERROR_INVALID_COMMAND_LINE;
  989. fwprintf(stderr, L"Incorrect command line arguments.\n\n");
  990. TaskUsage();
  991. goto TaskExit;
  992. }
  993. if (command == TaskCreate)
  994. {
  995. // Create the task jobobject
  996. //
  997. dwErrorCode = CreateTask(argv[2], argv[3]);
  998. if (dwErrorCode != ERROR_SUCCESS)
  999. {
  1000. ReportErrorCode(L"CreateTask", dwErrorCode);
  1001. goto TaskExit;
  1002. }
  1003. } else if (command == TaskCreateAsUser)
  1004. {
  1005. // Create the task jobobject as a domain user
  1006. // createAsUser accepts an open list of arguments. All arguments after the command are
  1007. // to be passed as argumrnts to the command itself.Here we're concatenating all
  1008. // arguments after the command into a single arg entry.
  1009. //
  1010. cmdLine = argv[ARGC_COMMAND];
  1011. if (argc > ARGC_COMMAND_ARGS) {
  1012. crtArgIndex = ARGC_COMMAND;
  1013. insertHere = buffer;
  1014. while (crtArgIndex < argc) {
  1015. argLen = wcslen(argv[crtArgIndex]);
  1016. wscatErr = wcscat_s(insertHere, charCountBufferLeft, argv[crtArgIndex]);
  1017. switch (wscatErr) {
  1018. case 0:
  1019. // 0 means success;
  1020. break;
  1021. case EINVAL:
  1022. dwErrorCode = ERROR_INVALID_PARAMETER;
  1023. goto TaskExit;
  1024. case ERANGE:
  1025. dwErrorCode = ERROR_INSUFFICIENT_BUFFER;
  1026. goto TaskExit;
  1027. default:
  1028. // This case is not MSDN documented.
  1029. dwErrorCode = ERROR_GEN_FAILURE;
  1030. goto TaskExit;
  1031. }
  1032. insertHere += argLen;
  1033. charCountBufferLeft -= argLen;
  1034. insertHere[0] = L' ';
  1035. insertHere += 1;
  1036. charCountBufferLeft -= 1;
  1037. insertHere[0] = 0;
  1038. ++crtArgIndex;
  1039. }
  1040. cmdLine = buffer;
  1041. }
  1042. dwErrorCode = CreateTaskAsUser(
  1043. argv[ARGC_JOBOBJECTNAME], argv[ARGC_USERNAME], argv[ARGC_PIDFILE], cmdLine);
  1044. if (dwErrorCode != ERROR_SUCCESS)
  1045. {
  1046. ReportErrorCode(L"CreateTaskAsUser", dwErrorCode);
  1047. goto TaskExit;
  1048. }
  1049. } else if (command == TaskIsAlive)
  1050. {
  1051. // Check if task jobobject
  1052. //
  1053. int isAlive;
  1054. int numProcs;
  1055. dwErrorCode = IsTaskAlive(argv[2], &isAlive, &numProcs);
  1056. if (dwErrorCode != ERROR_SUCCESS)
  1057. {
  1058. ReportErrorCode(L"IsTaskAlive", dwErrorCode);
  1059. goto TaskExit;
  1060. }
  1061. // Output the result
  1062. if(isAlive == TRUE)
  1063. {
  1064. fwprintf(stdout, L"IsAlive,%d\n", numProcs);
  1065. }
  1066. else
  1067. {
  1068. dwErrorCode = ERROR_TASK_NOT_ALIVE;
  1069. ReportErrorCode(L"IsTaskAlive returned false", dwErrorCode);
  1070. goto TaskExit;
  1071. }
  1072. } else if (command == TaskKill)
  1073. {
  1074. // Check if task jobobject
  1075. //
  1076. dwErrorCode = KillTask(argv[2]);
  1077. if (dwErrorCode != ERROR_SUCCESS)
  1078. {
  1079. ReportErrorCode(L"KillTask", dwErrorCode);
  1080. goto TaskExit;
  1081. }
  1082. } else if (command == TaskProcessList)
  1083. {
  1084. // Check if task jobobject
  1085. //
  1086. dwErrorCode = PrintTaskProcessList(argv[2]);
  1087. if (dwErrorCode != ERROR_SUCCESS)
  1088. {
  1089. ReportErrorCode(L"PrintTaskProcessList", dwErrorCode);
  1090. goto TaskExit;
  1091. }
  1092. } else
  1093. {
  1094. // Should not happen
  1095. //
  1096. assert(FALSE);
  1097. }
  1098. TaskExit:
  1099. ReportErrorCode(L"TaskExit:", dwErrorCode);
  1100. return dwErrorCode;
  1101. }
  1102. void TaskUsage()
  1103. {
  1104. // Hadoop code checks for this string to determine if
  1105. // jobobject's are being used.
  1106. // ProcessTree.isSetsidSupported()
  1107. fwprintf(stdout, L"\
  1108. Usage: task create [TASKNAME] [COMMAND_LINE] |\n\
  1109. task createAsUser [TASKNAME] [USERNAME] [PIDFILE] [COMMAND_LINE] |\n\
  1110. task isAlive [TASKNAME] |\n\
  1111. task kill [TASKNAME]\n\
  1112. task processList [TASKNAME]\n\
  1113. Creates a new task jobobject with taskname\n\
  1114. Creates a new task jobobject with taskname as the user provided\n\
  1115. Checks if task jobobject is alive\n\
  1116. Kills task jobobject\n\
  1117. Prints to stdout a list of processes in the task\n\
  1118. along with their resource usage. One process per line\n\
  1119. and comma separated info per process\n\
  1120. ProcessId,VirtualMemoryCommitted(bytes),\n\
  1121. WorkingSetSize(bytes),CpuTime(Millisec,Kernel+User)\n");
  1122. }