task.c 39 KB

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