service.c 44 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485
  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 "winutils_msg.h"
  19. #include <Winsvc.h>
  20. #include <errno.h>
  21. #include <malloc.h>
  22. #include <strsafe.h>
  23. #include <authz.h>
  24. #include <sddl.h>
  25. #include "hadoopwinutilsvc_h.h"
  26. #pragma comment(lib, "Rpcrt4.lib")
  27. #pragma comment(lib, "advapi32.lib")
  28. #pragma comment(lib, "authz.lib")
  29. LPCWSTR NM_WSCE_ALLOWED = L"yarn.nodemanager.windows-secure-container-executor.allowed";
  30. LPCWSTR NM_WSCE_JOB_NAME = L"yarn.nodemanager.windows-secure-container-executor.job-name";
  31. LPCWSTR NM_WSCE_LOCAL_DIRS = L"yarn.nodemanager.windows-secure-container-executor.local-dirs";
  32. #define SERVICE_ACCESS_MASK 0x00000001
  33. SERVICE_STATUS gSvcStatus;
  34. SERVICE_STATUS_HANDLE gSvcStatusHandle;
  35. HANDLE ghSvcStopEvent = INVALID_HANDLE_VALUE;
  36. HANDLE ghWaitObject = INVALID_HANDLE_VALUE;
  37. HANDLE ghEventLog = INVALID_HANDLE_VALUE;
  38. BOOL isListenning = FALSE;
  39. PSECURITY_DESCRIPTOR pAllowedSD = NULL;
  40. LPWSTR* gLocalDirs = NULL;
  41. size_t gLocalDirsCount = 0;
  42. int* gCchLocalDir = NULL;
  43. LPCWSTR gJobName = NULL;
  44. VOID SvcError(DWORD dwError);
  45. VOID WINAPI SvcMain(DWORD dwArg, LPTSTR* lpszArgv);
  46. DWORD SvcInit();
  47. DWORD RpcInit();
  48. DWORD AuthInit();
  49. VOID ReportSvcStatus( DWORD dwCurrentState,
  50. DWORD dwWin32ExitCode,
  51. DWORD dwWaitHint);
  52. VOID WINAPI SvcCtrlHandler( DWORD dwCtrl );
  53. VOID CALLBACK SvcShutdown(
  54. _In_ PVOID lpParameter,
  55. _In_ BOOLEAN TimerOrWaitFired);
  56. #define CHECK_ERROR_DONE(status, expected, category, message) \
  57. if (status != expected) { \
  58. ReportSvcCheckError( \
  59. EVENTLOG_ERROR_TYPE, \
  60. category, \
  61. status, \
  62. message); \
  63. goto done; \
  64. } else { \
  65. LogDebugMessage(L"%s: OK\n", message); \
  66. }
  67. #define CHECK_RPC_STATUS_DONE(status, message) \
  68. CHECK_ERROR_DONE(status, RPC_S_OK, SERVICE_CATEGORY, message)
  69. #define CHECK_SVC_STATUS_DONE(status, message) \
  70. CHECK_ERROR_DONE(status, ERROR_SUCCESS, SERVICE_CATEGORY, message)
  71. #define CHECK_UNWIND_RPC(rpcCall) { \
  72. unwindStatus = rpcCall; \
  73. if (RPC_S_OK != unwindStatus) { \
  74. ReportSvcCheckError( \
  75. EVENTLOG_WARNING_TYPE, \
  76. SERVICE_CATEGORY, \
  77. unwindStatus, \
  78. L#rpcCall); \
  79. } \
  80. }
  81. //----------------------------------------------------------------------------
  82. // Function: ReportSvcCheckError
  83. //
  84. // Description:
  85. // Reports an error with the system event log and to debugger console (if present)
  86. //
  87. void ReportSvcCheckError(WORD type, WORD category, DWORD dwError, LPCWSTR message) {
  88. int len;
  89. LPWSTR systemMsg = NULL;
  90. LPWSTR appMsg = NULL;
  91. DWORD dwReportError;
  92. LPWSTR reportMsg = NULL;
  93. WCHAR hexError[32];
  94. LPCWSTR inserts[] = {message, NULL, NULL, NULL};
  95. HRESULT hr;
  96. hr = StringCbPrintf(hexError, sizeof(hexError), TEXT("%x"), dwError);
  97. if (SUCCEEDED(hr)) {
  98. inserts[1] = hexError;
  99. }
  100. else {
  101. inserts[1] = L"(Failed to format dwError as string)";
  102. }
  103. len = FormatMessageW(
  104. FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
  105. NULL, dwError,
  106. MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
  107. (LPWSTR)&systemMsg, 0, NULL);
  108. if (len) {
  109. inserts[2] = systemMsg;
  110. }
  111. else {
  112. inserts[2] = L"(Failed to get the system error message)";
  113. }
  114. LogDebugMessage(L"%s:%d %.*s\n", message, dwError, len, systemMsg);
  115. if (INVALID_HANDLE_VALUE != ghEventLog) {
  116. if (!ReportEvent(ghEventLog, type, category, MSG_CHECK_ERROR,
  117. NULL, // lpUserSid
  118. (WORD) 3, // wNumStrings
  119. (DWORD) 0, // dwDataSize
  120. inserts, // *lpStrings
  121. NULL // lpRawData
  122. )) {
  123. // We tried to report and failed. Send to dbg.
  124. dwReportError = GetLastError();
  125. len = FormatMessageW(
  126. FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
  127. NULL, dwReportError,
  128. MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
  129. (LPWSTR)&reportMsg, 0, NULL);
  130. LogDebugMessage(L"ReportEvent: Error:%d %.*s\n", dwReportError, reportMsg);
  131. }
  132. };
  133. if (NULL != systemMsg) LocalFree(systemMsg);
  134. if (NULL != reportMsg) LocalFree(reportMsg);
  135. }
  136. VOID ReportSvcMessage(WORD type, WORD category, DWORD msgId) {
  137. DWORD dwError;
  138. if (INVALID_HANDLE_VALUE != ghEventLog) {
  139. if (!ReportEvent(ghEventLog, type, category, msgId,
  140. NULL, // lpUserSid
  141. (WORD) 0, // wNumStrings
  142. (DWORD) 0, // dwDataSize
  143. NULL, // *lpStrings
  144. NULL // lpRawData
  145. )) {
  146. // We tried to report and failed but debugger is attached. Send to dbg.
  147. dwError = GetLastError();
  148. LogDebugMessage(L"ReportEvent: error %d\n", dwError);
  149. }
  150. }
  151. }
  152. //----------------------------------------------------------------------------
  153. // Function: IsSidInList
  154. //
  155. // Description:
  156. // Finds a SID in an array of SID*
  157. //
  158. BOOL IsSidInList(
  159. __in PSID trustee,
  160. __in size_t cAllowedSids,
  161. __in_ecount(cAllowedSids) PSID* allowedSids) {
  162. int crtSid = 0;
  163. for (crtSid = 0; crtSid < cAllowedSids; ++crtSid) {
  164. if (EqualSid(trustee, allowedSids[crtSid])) {
  165. return TRUE;
  166. }
  167. }
  168. return FALSE;
  169. }
  170. //----------------------------------------------------------------------------
  171. // Function: InitLocalDirs
  172. //
  173. // Description:
  174. // Validates that the wsceConfigRelativePath file is only writable by Administrators
  175. //
  176. DWORD ValidateConfigurationFile() {
  177. DWORD dwError = ERROR_SUCCESS;
  178. WCHAR xmlPath[MAX_PATH];
  179. PSECURITY_DESCRIPTOR pSd = NULL;
  180. BOOL daclPresent = FALSE;
  181. BOOL daclDefaulted = FALSE;
  182. PACL pDacl = NULL;
  183. int crt = 0, crtSid = 0;
  184. WELL_KNOWN_SID_TYPE allowedSidTypes[] = {
  185. WinLocalSystemSid,
  186. WinBuiltinAdministratorsSid};
  187. ACL_SIZE_INFORMATION aclInfo;
  188. DWORD cbSid = SECURITY_MAX_SID_SIZE;
  189. PSID* allowedSids = NULL;
  190. int cAllowedSids = 0;
  191. BOOL isSidDefaulted;
  192. PSID sidOwner = NULL;
  193. PSID sidGroup = NULL;
  194. allowedSids = (PSID*) LocalAlloc(
  195. LPTR,
  196. sizeof(PSID) * sizeof(allowedSidTypes) / sizeof(WELL_KNOWN_SID_TYPE));
  197. if (NULL == allowedSids) {
  198. dwError = ERROR_OUTOFMEMORY;
  199. CHECK_SVC_STATUS_DONE(dwError, L"LocalAlloc");
  200. }
  201. for(crt = 0; crt < sizeof(allowedSidTypes) / sizeof(WELL_KNOWN_SID_TYPE); ++crt) {
  202. allowedSids[crt] = LocalAlloc(LPTR, SECURITY_MAX_SID_SIZE);
  203. if (NULL == allowedSids[crt]) {
  204. dwError = ERROR_OUTOFMEMORY;
  205. CHECK_SVC_STATUS_DONE(dwError, L"LocalAlloc");
  206. }
  207. cbSid = SECURITY_MAX_SID_SIZE;
  208. if (!CreateWellKnownSid(
  209. allowedSidTypes[crt], NULL, allowedSids[crt], &cbSid)) {
  210. dwError = GetLastError();
  211. CHECK_SVC_STATUS_DONE(dwError, L"CreateWellKnownSid");
  212. }
  213. ++cAllowedSids;
  214. }
  215. dwError = BuildPathRelativeToModule(
  216. wsceConfigRelativePath,
  217. sizeof(xmlPath)/sizeof(WCHAR),
  218. xmlPath);
  219. CHECK_SVC_STATUS_DONE(dwError, L"BuildPathRelativeToModule");
  220. dwError = GetNamedSecurityInfo(
  221. xmlPath,
  222. SE_FILE_OBJECT,
  223. DACL_SECURITY_INFORMATION,
  224. NULL, NULL, NULL, NULL, &pSd);
  225. CHECK_SVC_STATUS_DONE(dwError, L"GetNamedSecurityInfo");
  226. if (!GetSecurityDescriptorDacl(
  227. pSd,
  228. &daclPresent,
  229. &pDacl,
  230. &daclDefaulted)) {
  231. dwError = GetLastError();
  232. CHECK_SVC_STATUS_DONE(dwError, L"GetSecurityDescriptorDacl");
  233. }
  234. if (!pDacl) {
  235. dwError = ERROR_BAD_CONFIGURATION;
  236. CHECK_SVC_STATUS_DONE(dwError, L"pDacl");
  237. }
  238. ZeroMemory(&aclInfo, sizeof(aclInfo));
  239. if (!GetAclInformation(pDacl, &aclInfo, sizeof(aclInfo), AclSizeInformation)) {
  240. dwError = GetLastError();
  241. CHECK_SVC_STATUS_DONE(dwError, L"GetAclInformation");
  242. }
  243. // Inspect all ACEs in the file DACL.
  244. // Look at all WRITE GRANTs. Make sure the trustee Sid is one of the approved Sid
  245. //
  246. for(crt = 0; crt < aclInfo.AceCount; ++crt) {
  247. ACE_HEADER* aceHdr = NULL;
  248. if (!GetAce(pDacl, crt, &aceHdr)) {
  249. dwError = GetLastError();
  250. CHECK_SVC_STATUS_DONE(dwError, L"GetAce");
  251. }
  252. if (ACCESS_ALLOWED_ACE_TYPE == aceHdr->AceType) {
  253. ACCESS_ALLOWED_ACE* pAce = (ACCESS_ALLOWED_ACE*) aceHdr;
  254. if (WinMasks[WIN_WRITE] & pAce->Mask) {
  255. if (!IsSidInList((PSID) &pAce->SidStart, cAllowedSids, allowedSids)) {
  256. dwError = ERROR_BAD_CONFIGURATION;
  257. CHECK_SVC_STATUS_DONE(dwError, L"!validSidFound");
  258. }
  259. }
  260. }
  261. }
  262. done:
  263. if (pSd) LocalFree(pSd);
  264. if (allowedSids) {
  265. while (cAllowedSids) {
  266. LocalFree(allowedSids[cAllowedSids--]);
  267. }
  268. LocalFree(allowedSids);
  269. }
  270. return dwError;
  271. }
  272. //----------------------------------------------------------------------------
  273. // Function: InitJobName
  274. //
  275. // Description:
  276. // Loads the job name to be used for created processes
  277. //
  278. DWORD InitJobName() {
  279. DWORD dwError = ERROR_SUCCESS;
  280. size_t len = 0;
  281. LPCWSTR value = NULL;
  282. int crt = 0;
  283. // Services can be restarted
  284. if (gJobName) LocalFree(gJobName);
  285. gJobName = NULL;
  286. dwError = GetConfigValue(
  287. wsceConfigRelativePath,
  288. NM_WSCE_JOB_NAME, &len, &value);
  289. CHECK_SVC_STATUS_DONE(dwError, L"GetConfigValue");
  290. if (len) {
  291. gJobName = value;
  292. }
  293. done:
  294. return dwError;
  295. }
  296. //----------------------------------------------------------------------------
  297. // Function: InitLocalDirs
  298. //
  299. // Description:
  300. // Loads the configured local dirs
  301. //
  302. DWORD InitLocalDirs() {
  303. DWORD dwError = ERROR_SUCCESS;
  304. size_t len = 0;
  305. LPCWSTR value = NULL;
  306. int crt = 0;
  307. dwError = GetConfigValue(
  308. wsceConfigRelativePath,
  309. NM_WSCE_LOCAL_DIRS, &len, &value);
  310. CHECK_SVC_STATUS_DONE(dwError, L"GetConfigValue");
  311. if (0 == len) {
  312. dwError = ERROR_BAD_CONFIGURATION;
  313. CHECK_SVC_STATUS_DONE(dwError, NM_WSCE_LOCAL_DIRS);
  314. }
  315. dwError = SplitStringIgnoreSpaceW(len, value, L',', &gLocalDirsCount, &gLocalDirs);
  316. CHECK_SVC_STATUS_DONE(dwError, L"SplitStringIgnoreSpaceW");
  317. if (0 == gLocalDirsCount) {
  318. dwError = ERROR_BAD_CONFIGURATION;
  319. CHECK_SVC_STATUS_DONE(dwError, NM_WSCE_LOCAL_DIRS);
  320. }
  321. gCchLocalDir = (int*) LocalAlloc(LPTR, sizeof(int) * gLocalDirsCount);
  322. if (NULL == gCchLocalDir) {
  323. dwError = ERROR_OUTOFMEMORY;
  324. CHECK_SVC_STATUS_DONE(dwError, L"LocalAlloc");
  325. }
  326. for (crt = 0; crt < gLocalDirsCount; ++crt) {
  327. gCchLocalDir[crt] = (int) wcsnlen(gLocalDirs[crt], MAX_PATH);
  328. }
  329. done:
  330. if (value) LocalFree(value);
  331. return dwError;
  332. }
  333. //----------------------------------------------------------------------------
  334. // Function: ValidateLocalPath
  335. //
  336. // Description:
  337. // Validates that a path is within the contained local dirs
  338. //
  339. DWORD ValidateLocalPath(LPCWSTR lpszPath) {
  340. DWORD dwError = ERROR_SUCCESS;
  341. int compareResult = 0;
  342. int crt = 0;
  343. int cchLocalBuffer = 0;
  344. WCHAR localBuffer[MAX_PATH+1];
  345. BOOLEAN nullFound = FALSE;
  346. // Make a copy of the path and replace / with \ in the process
  347. while(crt < MAX_PATH && !nullFound) {
  348. switch(lpszPath[crt]) {
  349. case L'/':
  350. localBuffer[crt] = L'\\';
  351. ++crt;
  352. break;
  353. case L'\0':
  354. // NULL terminator
  355. nullFound = TRUE;
  356. break;
  357. default:
  358. localBuffer[crt] = lpszPath[crt];
  359. ++crt;
  360. break;
  361. }
  362. }
  363. if (FALSE == nullFound) {
  364. dwError = ERROR_BUFFER_OVERFLOW;
  365. CHECK_SVC_STATUS_DONE(dwError, L"localBuffer");
  366. }
  367. localBuffer[crt] = 0;
  368. cchLocalBuffer = crt;
  369. for(crt = 0; crt < gLocalDirsCount; ++crt) {
  370. // use max len gCchLocalDir[crt] to see if it starts with this local dir
  371. compareResult = CompareStringEx(
  372. LOCALE_NAME_INVARIANT,
  373. NORM_IGNORECASE,
  374. localBuffer, gCchLocalDir[crt] <= cchLocalBuffer ? gCchLocalDir[crt] : cchLocalBuffer,
  375. gLocalDirs[crt], gCchLocalDir[crt],
  376. NULL, // lpVersionInformation
  377. NULL, // lpReserved
  378. NULL); // lParam
  379. if (0 == compareResult) {
  380. dwError = GetLastError();
  381. CHECK_SVC_STATUS_DONE(dwError, L"CompareStringEx");
  382. }
  383. if (CSTR_EQUAL == compareResult) {
  384. break;
  385. }
  386. }
  387. if (CSTR_EQUAL != compareResult) {
  388. LogDebugMessage(L"ValidateLocalPath bad path: %s\n", lpszPath);
  389. dwError = ERROR_BAD_PATHNAME;
  390. }
  391. done:
  392. return dwError;
  393. }
  394. //----------------------------------------------------------------------------
  395. // Function: RunService
  396. //
  397. // Description:
  398. // Registers with NT SCM and starts the service
  399. //
  400. // Returns:
  401. // ERROR_SUCCESS: On success
  402. // Error code otherwise: otherwise
  403. DWORD RunService(__in int argc, __in_ecount(argc) wchar_t *argv[])
  404. {
  405. DWORD dwError= ERROR_SUCCESS;
  406. int argStart = 1;
  407. static const SERVICE_TABLE_ENTRY serviceTable[] = {
  408. { SVCNAME, (LPSERVICE_MAIN_FUNCTION) SvcMain },
  409. { NULL, NULL }
  410. };
  411. ghEventLog = RegisterEventSource(NULL, SVCNAME);
  412. if (NULL == ghEventLog) {
  413. dwError = GetLastError();
  414. CHECK_SVC_STATUS_DONE(dwError, L"RegisterEventSource")
  415. }
  416. if (!StartServiceCtrlDispatcher(serviceTable)) {
  417. dwError = GetLastError();
  418. CHECK_SVC_STATUS_DONE(dwError, L"StartServiceCtrlDispatcher")
  419. }
  420. done:
  421. return dwError;
  422. }
  423. //----------------------------------------------------------------------------
  424. // Function: SvcMain
  425. //
  426. // Description:
  427. // Service main entry point.
  428. //
  429. VOID WINAPI SvcMain() {
  430. DWORD dwError = ERROR_SUCCESS;
  431. gSvcStatusHandle = RegisterServiceCtrlHandler(
  432. SVCNAME,
  433. SvcCtrlHandler);
  434. if( !gSvcStatusHandle ) {
  435. dwError = GetLastError();
  436. CHECK_SVC_STATUS_DONE(dwError, L"RegisterServiceCtrlHandler")
  437. }
  438. // These SERVICE_STATUS members remain as set here
  439. gSvcStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
  440. gSvcStatus.dwServiceSpecificExitCode = 0;
  441. // Report initial status to the SCM
  442. ReportSvcStatus( SERVICE_START_PENDING, NO_ERROR, 3000 );
  443. // Perform service-specific initialization and work.
  444. dwError = SvcInit();
  445. done:
  446. return;
  447. }
  448. //----------------------------------------------------------------------------
  449. // Function: SvcInit
  450. //
  451. // Description:
  452. // Initializes the service.
  453. //
  454. DWORD SvcInit() {
  455. DWORD dwError = ERROR_SUCCESS;
  456. dwError = EnableImpersonatePrivileges();
  457. if( dwError != ERROR_SUCCESS ) {
  458. ReportErrorCode(L"EnableImpersonatePrivileges", dwError);
  459. goto done;
  460. }
  461. // The recommended way to shutdown the service is to use an event
  462. // and attach a callback with RegisterWaitForSingleObject
  463. //
  464. ghSvcStopEvent = CreateEvent(
  465. NULL, // default security attributes
  466. TRUE, // manual reset event
  467. FALSE, // not signaled
  468. NULL); // no name
  469. if ( ghSvcStopEvent == NULL)
  470. {
  471. dwError = GetLastError();
  472. ReportSvcCheckError(EVENTLOG_ERROR_TYPE, SERVICE_CATEGORY,
  473. dwError, L"CreateEvent");
  474. ReportSvcStatus( SERVICE_STOPPED, dwError, 0 );
  475. goto done;
  476. }
  477. if (!RegisterWaitForSingleObject (&ghWaitObject,
  478. ghSvcStopEvent,
  479. SvcShutdown,
  480. NULL,
  481. INFINITE,
  482. WT_EXECUTEONLYONCE)) {
  483. dwError = GetLastError();
  484. ReportSvcCheckError(EVENTLOG_ERROR_TYPE, SERVICE_CATEGORY,
  485. dwError, L"RegisterWaitForSingleObject");
  486. CloseHandle(ghSvcStopEvent);
  487. ReportSvcStatus( SERVICE_STOPPED, dwError, 0 );
  488. goto done;
  489. }
  490. dwError = ValidateConfigurationFile();
  491. if (ERROR_SUCCESS != dwError) {
  492. LogDebugMessage(L"ValidateConfigurationFile failed: %d", dwError);
  493. SvcError(dwError);
  494. goto done;
  495. }
  496. dwError = AuthInit();
  497. if (ERROR_SUCCESS != dwError) {
  498. LogDebugMessage(L"AuthInit failed: %d", dwError);
  499. SvcError(dwError);
  500. goto done;
  501. }
  502. dwError = InitLocalDirs();
  503. if (ERROR_SUCCESS != dwError) {
  504. LogDebugMessage(L"InitLocalDirs failed: %d", dwError);
  505. SvcError(dwError);
  506. goto done;
  507. }
  508. dwError = InitJobName();
  509. if (ERROR_SUCCESS != dwError) {
  510. LogDebugMessage(L"InitJobName failed: %d", dwError);
  511. SvcError(dwError);
  512. goto done;
  513. }
  514. // Report running status when initialization is complete.
  515. ReportSvcStatus( SERVICE_RUNNING, NO_ERROR, 0 );
  516. dwError = RpcInit();
  517. done:
  518. return dwError;
  519. }
  520. //----------------------------------------------------------------------------
  521. // Function: RpcAuthorizeCallback
  522. //
  523. // Description:
  524. // RPC Authorization callback.
  525. //
  526. // Returns:
  527. // RPC_S_OK for access authorized
  528. // RPC_S_ACCESS_DENIED for access denied
  529. //
  530. RPC_STATUS CALLBACK RpcAuthorizeCallback (
  531. RPC_IF_HANDLE hInterface,
  532. void* pContext)
  533. {
  534. RPC_STATUS status,
  535. unwindStatus,
  536. authStatus = RPC_S_ACCESS_DENIED;
  537. DWORD dwError;
  538. LUID luidReserved2;
  539. AUTHZ_ACCESS_REQUEST request;
  540. AUTHZ_ACCESS_REPLY reply;
  541. AUTHZ_CLIENT_CONTEXT_HANDLE hClientContext = NULL;
  542. DWORD authError = ERROR_SUCCESS;
  543. DWORD saclResult = 0;
  544. ACCESS_MASK grantedMask = 0;
  545. ZeroMemory(&luidReserved2, sizeof(luidReserved2));
  546. ZeroMemory(&request, sizeof(request));
  547. ZeroMemory(&reply, sizeof(reply));
  548. status = RpcGetAuthorizationContextForClient(NULL,
  549. FALSE, // ImpersonateOnReturn
  550. NULL, // Reserved1
  551. NULL, // pExpirationTime
  552. luidReserved2, // Reserved2
  553. 0, // Reserved3
  554. NULL, // Reserved4
  555. &hClientContext);
  556. CHECK_RPC_STATUS_DONE(status, L"RpcGetAuthorizationContextForClient");
  557. request.DesiredAccess = MAXIMUM_ALLOWED;
  558. reply.Error = &authError;
  559. reply.SaclEvaluationResults = &saclResult;
  560. reply.ResultListLength = 1;
  561. reply.GrantedAccessMask = &grantedMask;
  562. if (!AuthzAccessCheck(
  563. 0,
  564. hClientContext,
  565. &request,
  566. NULL, // AuditEvent
  567. pAllowedSD,
  568. NULL, // OptionalSecurityDescriptorArray
  569. 0, // OptionalSecurityDescriptorCount
  570. &reply,
  571. NULL // phAccessCheckResults
  572. )) {
  573. dwError = GetLastError();
  574. CHECK_SVC_STATUS_DONE(dwError, L"AuthzAccessCheck");
  575. }
  576. LogDebugMessage(L"AutzAccessCheck: Error:%d sacl:%d access:%d\n",
  577. authError, saclResult, grantedMask);
  578. if (authError == ERROR_SUCCESS && (grantedMask & SERVICE_ACCESS_MASK)) {
  579. authStatus = RPC_S_OK;
  580. }
  581. done:
  582. if (NULL != hClientContext) CHECK_UNWIND_RPC(RpcFreeAuthorizationContext(&hClientContext));
  583. return authStatus;
  584. }
  585. //----------------------------------------------------------------------------
  586. // Function: AuthInit
  587. //
  588. // Description:
  589. // Initializes the authorization structures (security descriptor).
  590. //
  591. // Notes:
  592. // This is called from RunService solely for debugging purposed
  593. // so that it can be tested by wimply running winutil service from CLI (no SCM)
  594. //
  595. DWORD AuthInit() {
  596. DWORD dwError = ERROR_SUCCESS;
  597. int count = 0;
  598. int crt = 0;
  599. size_t len = 0;
  600. LPCWSTR value = NULL;
  601. WCHAR** tokens = NULL;
  602. LPWSTR lpszSD = NULL;
  603. ULONG cchSD = 0;
  604. DWORD dwBufferSize = 0;
  605. int allowedCount = 0;
  606. PSID* allowedSids = NULL;
  607. dwError = GetConfigValue(
  608. wsceConfigRelativePath,
  609. NM_WSCE_ALLOWED, &len, &value);
  610. CHECK_SVC_STATUS_DONE(dwError, L"GetConfigValue");
  611. if (0 == len) {
  612. dwError = ERROR_BAD_CONFIGURATION;
  613. CHECK_SVC_STATUS_DONE(dwError, NM_WSCE_ALLOWED);
  614. }
  615. dwError = SplitStringIgnoreSpaceW(len, value, L',', &count, &tokens);
  616. CHECK_SVC_STATUS_DONE(dwError, L"SplitStringIgnoreSpaceW");
  617. allowedSids = (PSID*) LocalAlloc(LPTR, sizeof(PSID) * count);
  618. if (NULL == allowedSids) {
  619. dwError = ERROR_OUTOFMEMORY;
  620. CHECK_SVC_STATUS_DONE(dwError, L"LocalAlloc");
  621. }
  622. for (crt = 0; crt < count; ++crt) {
  623. dwError = GetSidFromAcctNameW(tokens[crt], &allowedSids[crt]);
  624. CHECK_SVC_STATUS_DONE(dwError, L"GetSidFromAcctNameW");
  625. }
  626. allowedCount = count;
  627. dwError = BuildServiceSecurityDescriptor(SERVICE_ACCESS_MASK,
  628. allowedCount, allowedSids, 0, NULL, NULL, &pAllowedSD);
  629. CHECK_SVC_STATUS_DONE(dwError, L"BuildServiceSecurityDescriptor");
  630. done:
  631. if (lpszSD) LocalFree(lpszSD);
  632. if (value) LocalFree(value);
  633. if (tokens) LocalFree(tokens);
  634. return dwError;
  635. }
  636. //----------------------------------------------------------------------------
  637. // Function: RpcInit
  638. //
  639. // Description:
  640. // Initializes the RPC infrastructure and starts the RPC listenner.
  641. //
  642. DWORD RpcInit() {
  643. RPC_STATUS status;
  644. DWORD dwError;
  645. status = RpcServerUseProtseqIf(SVCBINDING,
  646. RPC_C_LISTEN_MAX_CALLS_DEFAULT,
  647. HadoopWinutilSvc_v1_0_s_ifspec,
  648. NULL);
  649. if (RPC_S_OK != status) {
  650. ReportSvcCheckError(EVENTLOG_ERROR_TYPE, SERVICE_CATEGORY,
  651. status, L"RpcServerUseProtseqIf");
  652. SvcError(status);
  653. dwError = status;
  654. goto done;
  655. }
  656. status = RpcServerRegisterIfEx(HadoopWinutilSvc_v1_0_s_ifspec,
  657. NULL, // MgrTypeUuid
  658. NULL, // MgrEpv
  659. RPC_IF_ALLOW_LOCAL_ONLY, // Flags
  660. RPC_C_LISTEN_MAX_CALLS_DEFAULT, // Max calls
  661. RpcAuthorizeCallback); // Auth callback
  662. if (RPC_S_OK != status) {
  663. ReportSvcCheckError(EVENTLOG_ERROR_TYPE, SERVICE_CATEGORY,
  664. status, L"RpcServerRegisterIfEx");
  665. SvcError(status);
  666. dwError = status;
  667. goto done;
  668. }
  669. status = RpcServerListen(1, RPC_C_LISTEN_MAX_CALLS_DEFAULT, TRUE);
  670. if (RPC_S_ALREADY_LISTENING == status) {
  671. ReportSvcCheckError(EVENTLOG_WARNING_TYPE, SERVICE_CATEGORY,
  672. status, L"RpcServerListen");
  673. }
  674. else if (RPC_S_OK != status) {
  675. ReportSvcCheckError(EVENTLOG_ERROR_TYPE, SERVICE_CATEGORY,
  676. status, L"RpcServerListen");
  677. SvcError(status);
  678. dwError = status;
  679. goto done;
  680. }
  681. isListenning = TRUE;
  682. ReportSvcMessage(EVENTLOG_INFORMATION_TYPE, SERVICE_CATEGORY,
  683. MSG_RPC_SERVICE_HAS_STARTED);
  684. done:
  685. return dwError;
  686. }
  687. //----------------------------------------------------------------------------
  688. // Function: RpcStop
  689. //
  690. // Description:
  691. // Tears down the RPC infrastructure and stops the RPC listenner.
  692. //
  693. VOID RpcStop() {
  694. RPC_STATUS status;
  695. if (isListenning) {
  696. status = RpcMgmtStopServerListening(NULL);
  697. isListenning = FALSE;
  698. if (RPC_S_OK != status) {
  699. ReportSvcCheckError(EVENTLOG_WARNING_TYPE, SERVICE_CATEGORY,
  700. status, L"RpcMgmtStopServerListening");
  701. }
  702. ReportSvcMessage(EVENTLOG_INFORMATION_TYPE, SERVICE_CATEGORY,
  703. MSG_RPC_SERVICE_HAS_STOPPED);
  704. }
  705. }
  706. //----------------------------------------------------------------------------
  707. // Function: CleanupHandles
  708. //
  709. // Description:
  710. // Cleans up the global service handles.
  711. //
  712. VOID CleanupHandles() {
  713. if (INVALID_HANDLE_VALUE != ghWaitObject) {
  714. UnregisterWait(ghWaitObject);
  715. ghWaitObject = INVALID_HANDLE_VALUE;
  716. }
  717. if (INVALID_HANDLE_VALUE != ghSvcStopEvent) {
  718. CloseHandle(ghSvcStopEvent);
  719. ghSvcStopEvent = INVALID_HANDLE_VALUE;
  720. }
  721. if (INVALID_HANDLE_VALUE != ghEventLog) {
  722. DeregisterEventSource(ghEventLog);
  723. ghEventLog = INVALID_HANDLE_VALUE;
  724. }
  725. }
  726. //----------------------------------------------------------------------------
  727. // Function: SvcError
  728. //
  729. // Description:
  730. // Aborts the startup sequence. Reports error, stops RPC, cleans up globals.
  731. //
  732. VOID SvcError(DWORD dwError) {
  733. RpcStop();
  734. CleanupHandles();
  735. ReportSvcStatus( SERVICE_STOPPED, dwError, 0 );
  736. }
  737. //----------------------------------------------------------------------------
  738. // Function: SvcShutdown
  739. //
  740. // Description:
  741. // Callback when the shutdown event is signaled. Stops RPC, cleans up globals.
  742. //
  743. VOID CALLBACK SvcShutdown(
  744. _In_ PVOID lpParameter,
  745. _In_ BOOLEAN TimerOrWaitFired) {
  746. RpcStop();
  747. CleanupHandles();
  748. ReportSvcStatus( SERVICE_STOPPED, NO_ERROR, 0 );
  749. }
  750. //----------------------------------------------------------------------------
  751. // Function: SvcCtrlHandler
  752. //
  753. // Description:
  754. // Callback from SCM for for service events (signals).
  755. //
  756. // Notes:
  757. // Shutdown is indirect, we set her the STOP_PENDING state and signal the stop event.
  758. // Signaling the event invokes SvcShutdown which completes the shutdown.
  759. // This two staged approach allows the SCM handler to complete fast,
  760. // not blocking the SCM big fat global lock.
  761. //
  762. VOID WINAPI SvcCtrlHandler( DWORD dwCtrl )
  763. {
  764. // Handle the requested control code.
  765. switch(dwCtrl)
  766. {
  767. case SERVICE_CONTROL_STOP:
  768. ReportSvcStatus(SERVICE_STOP_PENDING, NO_ERROR, 0);
  769. // Signal the service to stop.
  770. SetEvent(ghSvcStopEvent);
  771. return;
  772. default:
  773. break;
  774. }
  775. }
  776. //----------------------------------------------------------------------------
  777. // Function: ReportSvcStatus
  778. //
  779. // Description:
  780. // Updates the service status with the SCM.
  781. //
  782. VOID ReportSvcStatus( DWORD dwCurrentState,
  783. DWORD dwWin32ExitCode,
  784. DWORD dwWaitHint)
  785. {
  786. static DWORD dwCheckPoint = 1;
  787. DWORD dwError;
  788. // Fill in the SERVICE_STATUS structure.
  789. gSvcStatus.dwCurrentState = dwCurrentState;
  790. gSvcStatus.dwWin32ExitCode = dwWin32ExitCode;
  791. gSvcStatus.dwWaitHint = dwWaitHint;
  792. if (dwCurrentState == SERVICE_START_PENDING)
  793. gSvcStatus.dwControlsAccepted = 0;
  794. else gSvcStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP;
  795. if ( (dwCurrentState == SERVICE_RUNNING) ||
  796. (dwCurrentState == SERVICE_STOPPED) )
  797. gSvcStatus.dwCheckPoint = 0;
  798. else gSvcStatus.dwCheckPoint = dwCheckPoint++;
  799. // Report the status of the service to the SCM.
  800. if (!SetServiceStatus( gSvcStatusHandle, &gSvcStatus)) {
  801. dwError = GetLastError();
  802. ReportSvcCheckError(EVENTLOG_WARNING_TYPE, SERVICE_CATEGORY,
  803. dwError, L"SetServiceStatus");
  804. };
  805. }
  806. //----------------------------------------------------------------------------
  807. // Function: WinutilsCreateProcessAsUser
  808. //
  809. // Description:
  810. // The RPC midl declared function implementation
  811. //
  812. // Returns:
  813. // ERROR_SUCCESS: On success
  814. // Error code otherwise: otherwise
  815. //
  816. // Notes:
  817. // This is the entry point when the NodeManager does the RPC call
  818. // Note that the RPC call does not do any S4U work. Is simply spawns (suspended) wintutils
  819. // using the right command line and the handles over the spwaned process to the NM
  820. // The actual S4U work occurs in the spawned process, run and monitored by the NM
  821. //
  822. error_status_t WinutilsCreateProcessAsUser(
  823. /* [in] */ handle_t IDL_handle,
  824. /* [in] */ int nmPid,
  825. /* [in] */ CREATE_PROCESS_REQUEST *request,
  826. /* [out] */ CREATE_PROCESS_RESPONSE **response) {
  827. DWORD dwError = ERROR_SUCCESS;
  828. LPCWSTR inserts[] = {request->cwd, request->jobName, request->user, request->pidFile, request->cmdLine, NULL};
  829. WCHAR winutilsPath[MAX_PATH];
  830. WCHAR fullCmdLine[32768];
  831. HANDLE taskStdInRd = INVALID_HANDLE_VALUE, taskStdInWr = INVALID_HANDLE_VALUE,
  832. taskStdOutRd = INVALID_HANDLE_VALUE, taskStdOutWr = INVALID_HANDLE_VALUE,
  833. taskStdErrRd = INVALID_HANDLE_VALUE, taskStdErrWr = INVALID_HANDLE_VALUE,
  834. hNmProcess = INVALID_HANDLE_VALUE,
  835. hDuplicateProcess = INVALID_HANDLE_VALUE,
  836. hDuplicateThread = INVALID_HANDLE_VALUE,
  837. hDuplicateStdIn = INVALID_HANDLE_VALUE,
  838. hDuplicateStdOut = INVALID_HANDLE_VALUE,
  839. hDuplicateStdErr = INVALID_HANDLE_VALUE,
  840. hSelfProcess = INVALID_HANDLE_VALUE,
  841. hJob = INVALID_HANDLE_VALUE;
  842. BOOL fMustCleanupProcess = FALSE;
  843. HRESULT hr;
  844. STARTUPINFO si;
  845. PROCESS_INFORMATION pi;
  846. SECURITY_ATTRIBUTES saTaskStdInOutErr;
  847. ZeroMemory( &si, sizeof(si) );
  848. si.cb = sizeof(si);
  849. ZeroMemory( &pi, sizeof(pi) );
  850. pi.hProcess = INVALID_HANDLE_VALUE;
  851. pi.hThread = INVALID_HANDLE_VALUE;
  852. ZeroMemory( &saTaskStdInOutErr, sizeof(saTaskStdInOutErr));
  853. if (gJobName) {
  854. hJob = OpenJobObject(JOB_OBJECT_ASSIGN_PROCESS, FALSE, gJobName);
  855. if (!hJob) {
  856. dwError = GetLastError();
  857. ReportSvcCheckError(EVENTLOG_ERROR_TYPE, SERVICE_CATEGORY,
  858. dwError, L"OpenJobObject");
  859. goto done;
  860. }
  861. }
  862. // NB: GetCurrentProcess returns a pseudo-handle that just so happens
  863. // has the value -1, ie. INVALID_HANDLE_VALUE. It cannot fail.
  864. //
  865. hSelfProcess = GetCurrentProcess();
  866. hNmProcess = OpenProcess(PROCESS_DUP_HANDLE, FALSE, nmPid);
  867. if (NULL == hNmProcess) {
  868. dwError = GetLastError();
  869. ReportSvcCheckError(EVENTLOG_ERROR_TYPE, SERVICE_CATEGORY,
  870. dwError, L"OpenProcess");
  871. goto done;
  872. }
  873. GetModuleFileName(NULL, winutilsPath, sizeof(winutilsPath)/sizeof(WCHAR));
  874. dwError = GetLastError(); // Always check after GetModuleFileName for ERROR_INSSUFICIENT_BUFFER
  875. if (dwError) {
  876. ReportSvcCheckError(EVENTLOG_ERROR_TYPE, SERVICE_CATEGORY,
  877. dwError, L"GetModuleFileName");
  878. goto done;
  879. }
  880. // NB. We can call CreateProcess("wintuls","task create ...") or we can call
  881. // CreateProcess(NULL, "winutils task create"). Only the second form passes "task" as
  882. // argv[1], as expected by main. First form passes "task" as argv[0] and main fails.
  883. hr = StringCbPrintf(fullCmdLine, sizeof(fullCmdLine), L"\"%s\" task createAsUser %ls %ls %ls %ls",
  884. winutilsPath,
  885. request->jobName, request->user, request->pidFile, request->cmdLine);
  886. if (FAILED(hr)) {
  887. ReportSvcCheckError(EVENTLOG_ERROR_TYPE, SERVICE_CATEGORY,
  888. hr, L"StringCbPrintf:fullCmdLine");
  889. goto done;
  890. }
  891. LogDebugMessage(L"[%ls]: %ls %ls\n", request->cwd, winutilsPath, fullCmdLine);
  892. // stdin/stdout/stderr redirection is handled here
  893. // We create 3 anonymous named pipes.
  894. // Security attributes are required so that the handles can be inherited.
  895. // We assign one end of the pipe to the process (stdin gets a read end, stdout gets a write end)
  896. // We then duplicate the other end in the NM process, and we close our own handle
  897. // Finally we return the duplicate handle values to the NM
  898. // The NM will attach Java file dscriptors to the duplicated handles and
  899. // read/write them as ordinary Java InputStream/OutputStream objects
  900. si.dwFlags |= STARTF_USESTDHANDLES;
  901. saTaskStdInOutErr.nLength = sizeof(SECURITY_ATTRIBUTES);
  902. saTaskStdInOutErr.bInheritHandle = TRUE;
  903. saTaskStdInOutErr.lpSecurityDescriptor = NULL;
  904. if (!CreatePipe(&taskStdInRd, &taskStdInWr, &saTaskStdInOutErr, 0)) {
  905. dwError = GetLastError();
  906. goto done;
  907. }
  908. if (!SetHandleInformation(taskStdInWr, HANDLE_FLAG_INHERIT, FALSE)) {
  909. dwError = GetLastError();
  910. goto done;
  911. }
  912. si.hStdInput = taskStdInRd;
  913. if (!CreatePipe(&taskStdOutRd, &taskStdOutWr, &saTaskStdInOutErr, 0)) {
  914. dwError = GetLastError();
  915. goto done;
  916. }
  917. if (!SetHandleInformation(taskStdOutRd, HANDLE_FLAG_INHERIT, FALSE)) {
  918. dwError = GetLastError();
  919. goto done;
  920. }
  921. si.hStdOutput = taskStdOutWr;
  922. if (!CreatePipe(&taskStdErrRd, &taskStdErrWr, &saTaskStdInOutErr, 0)) {
  923. dwError = GetLastError();
  924. goto done;
  925. }
  926. if (!SetHandleInformation(taskStdErrRd, HANDLE_FLAG_INHERIT, FALSE)) {
  927. dwError = GetLastError();
  928. goto done;
  929. }
  930. si.hStdError = taskStdErrWr;
  931. if (!CreateProcess(
  932. NULL, // lpApplicationName,
  933. fullCmdLine, // lpCommandLine,
  934. NULL, // lpProcessAttributes,
  935. NULL, // lpThreadAttributes,
  936. TRUE, // bInheritHandles,
  937. CREATE_SUSPENDED, // dwCreationFlags,
  938. NULL, // lpEnvironment,
  939. request->cwd, // lpCurrentDirectory,
  940. &si, // lpStartupInfo
  941. &pi)) { // lpProcessInformation
  942. dwError = GetLastError();
  943. ReportSvcCheckError(EVENTLOG_ERROR_TYPE, SERVICE_CATEGORY,
  944. dwError, L"CreateProcess");
  945. goto done;
  946. }
  947. fMustCleanupProcess = TRUE;
  948. LogDebugMessage(L"CreateProcess: pid:%x\n", pi.dwProcessId);
  949. if (INVALID_HANDLE_VALUE != hJob) {
  950. if (!AssignProcessToJobObject(hJob, pi.hProcess)) {
  951. dwError = GetLastError();
  952. goto done;
  953. }
  954. }
  955. // Grant full access to the container user on the 'winutils task createAsUser ...' helper process
  956. dwError = AddNodeManagerAndUserACEsToObject(pi.hProcess, request->user, PROCESS_ALL_ACCESS);
  957. if (dwError) {
  958. LogDebugMessage(L"failed: AddNodeManagerAndUserACEsToObject\n");
  959. goto done;
  960. }
  961. if (!DuplicateHandle(hSelfProcess, pi.hProcess, hNmProcess,
  962. &hDuplicateProcess, 0, FALSE, DUPLICATE_SAME_ACCESS)) {
  963. dwError = GetLastError();
  964. LogDebugMessage(L"failed: pi.hProcess\n");
  965. goto done;
  966. }
  967. if (!DuplicateHandle(hSelfProcess, pi.hThread, hNmProcess,
  968. &hDuplicateThread, 0, FALSE, DUPLICATE_SAME_ACCESS)) {
  969. dwError = GetLastError();
  970. LogDebugMessage(L"failed: pi.hThread\n");
  971. goto done;
  972. }
  973. if (!DuplicateHandle(hSelfProcess, taskStdInWr, hNmProcess,
  974. &hDuplicateStdIn, 0, FALSE, DUPLICATE_SAME_ACCESS)) {
  975. dwError = GetLastError();
  976. LogDebugMessage(L"failed: taskStdInWr\n");
  977. goto done;
  978. }
  979. if (!DuplicateHandle(hSelfProcess, taskStdOutRd, hNmProcess,
  980. &hDuplicateStdOut, 0, FALSE, DUPLICATE_SAME_ACCESS)) {
  981. dwError = GetLastError();
  982. LogDebugMessage(L"failed: taskStdOutRd\n");
  983. goto done;
  984. }
  985. if (!DuplicateHandle(hSelfProcess, taskStdErrRd, hNmProcess,
  986. &hDuplicateStdErr, 0, FALSE, DUPLICATE_SAME_ACCESS)) {
  987. dwError = GetLastError();
  988. LogDebugMessage(L"failed: taskStdErrRd\n");
  989. goto done;
  990. }
  991. *response = (CREATE_PROCESS_RESPONSE*) MIDL_user_allocate(sizeof(CREATE_PROCESS_RESPONSE));
  992. if (NULL == *response) {
  993. dwError = ERROR_OUTOFMEMORY;
  994. LogDebugMessage(L"Failed to allocate CREATE_PROCESS_RESPONSE* response\n");
  995. goto done;
  996. }
  997. // We're now transfering ownership of the duplicated handles to the caller
  998. // If the RPC call fails *after* this point the handles are leaked inside the NM process
  999. // Note that there are no more API calls, only assignments. A failure could occur only if
  1000. // foced (process kill) or hardware error (faulty memory, processort bit flip etc).
  1001. (*response)->hProcess = hDuplicateProcess;
  1002. (*response)->hThread = hDuplicateThread;
  1003. (*response)->hStdIn = hDuplicateStdIn;
  1004. (*response)->hStdOut = hDuplicateStdOut;
  1005. (*response)->hStdErr = hDuplicateStdErr;
  1006. fMustCleanupProcess = FALSE;
  1007. done:
  1008. if (fMustCleanupProcess) {
  1009. LogDebugMessage(L"Cleaning process: %d due to error:%d\n", pi.dwProcessId, dwError);
  1010. TerminateProcess(pi.hProcess, EXIT_FAILURE);
  1011. // cleanup the duplicate handles inside the NM.
  1012. if (INVALID_HANDLE_VALUE != hDuplicateProcess) {
  1013. DuplicateHandle(hNmProcess, hDuplicateProcess, NULL, NULL, 0, FALSE, DUPLICATE_CLOSE_SOURCE);
  1014. }
  1015. if (INVALID_HANDLE_VALUE != hDuplicateThread) {
  1016. DuplicateHandle(hNmProcess, hDuplicateThread, NULL, NULL, 0, FALSE, DUPLICATE_CLOSE_SOURCE);
  1017. }
  1018. if (INVALID_HANDLE_VALUE != hDuplicateStdIn) {
  1019. DuplicateHandle(hNmProcess, hDuplicateStdIn, NULL, NULL, 0, FALSE, DUPLICATE_CLOSE_SOURCE);
  1020. }
  1021. if (INVALID_HANDLE_VALUE != hDuplicateStdOut) {
  1022. DuplicateHandle(hNmProcess, hDuplicateStdOut, NULL, NULL, 0, FALSE, DUPLICATE_CLOSE_SOURCE);
  1023. }
  1024. if (INVALID_HANDLE_VALUE != hDuplicateStdErr) {
  1025. DuplicateHandle(hNmProcess, hDuplicateStdErr, NULL, NULL, 0, FALSE, DUPLICATE_CLOSE_SOURCE);
  1026. }
  1027. }
  1028. if (INVALID_HANDLE_VALUE != hSelfProcess) CloseHandle(hSelfProcess);
  1029. if (INVALID_HANDLE_VALUE != hNmProcess) CloseHandle(hNmProcess);
  1030. if (INVALID_HANDLE_VALUE != taskStdInRd) CloseHandle(taskStdInRd);
  1031. if (INVALID_HANDLE_VALUE != taskStdInWr) CloseHandle(taskStdInWr);
  1032. if (INVALID_HANDLE_VALUE != taskStdOutRd) CloseHandle(taskStdOutRd);
  1033. if (INVALID_HANDLE_VALUE != taskStdOutWr) CloseHandle(taskStdOutWr);
  1034. if (INVALID_HANDLE_VALUE != taskStdErrRd) CloseHandle(taskStdErrRd);
  1035. if (INVALID_HANDLE_VALUE != taskStdErrWr) CloseHandle(taskStdErrWr);
  1036. // This is closing our own process/thread handles.
  1037. // If the transfer was succesfull the NM has its own duplicates (if any)
  1038. if (INVALID_HANDLE_VALUE != pi.hThread) CloseHandle(pi.hThread);
  1039. if (INVALID_HANDLE_VALUE != pi.hProcess) CloseHandle(pi.hProcess);
  1040. if (hJob) CloseHandle(hJob);
  1041. return dwError;
  1042. }
  1043. error_status_t WinutilsCreateFile(
  1044. /* [in] */ handle_t IDL_handle,
  1045. /* [in] */ int nm_pid,
  1046. /* [in] */ CREATEFILE_REQUEST *request,
  1047. /* [out] */ CREATEFILE_RESPONSE **response) {
  1048. DWORD dwError = ERROR_SUCCESS;
  1049. HANDLE hNmProcess = INVALID_HANDLE_VALUE,
  1050. hFile = INVALID_HANDLE_VALUE,
  1051. hDuplicateFile = INVALID_HANDLE_VALUE,
  1052. hSelfProcess = GetCurrentProcess();
  1053. SECURITY_ATTRIBUTES saFile;
  1054. ZeroMemory( &saFile, sizeof(saFile));
  1055. dwError = ValidateLocalPath(request->path);
  1056. CHECK_SVC_STATUS_DONE(dwError,L"ValidateLocalPath request->path");
  1057. saFile.nLength = sizeof(SECURITY_ATTRIBUTES);
  1058. saFile.bInheritHandle = TRUE;
  1059. saFile.lpSecurityDescriptor = NULL;
  1060. hFile = CreateFile(
  1061. request->path,
  1062. request->desiredAccess,
  1063. request->shareMode,
  1064. &saFile,
  1065. request->creationDisposition,
  1066. request->flags,
  1067. NULL); // hTemplate
  1068. if (INVALID_HANDLE_VALUE == hFile) {
  1069. dwError = GetLastError();
  1070. goto done;
  1071. }
  1072. hNmProcess = OpenProcess(PROCESS_DUP_HANDLE, FALSE, nm_pid);
  1073. if (NULL == hNmProcess) {
  1074. dwError = GetLastError();
  1075. goto done;
  1076. }
  1077. if (!DuplicateHandle(hSelfProcess, hFile,
  1078. hNmProcess, &hDuplicateFile,
  1079. 0, FALSE, DUPLICATE_SAME_ACCESS)) {
  1080. dwError = GetLastError();
  1081. goto done;
  1082. }
  1083. *response = (CREATEFILE_RESPONSE*) MIDL_user_allocate(sizeof(CREATEFILE_RESPONSE));
  1084. if (NULL == *response) {
  1085. dwError = ERROR_OUTOFMEMORY;
  1086. goto done;
  1087. }
  1088. (*response)->hFile = hDuplicateFile;
  1089. hDuplicateFile = INVALID_HANDLE_VALUE;
  1090. done:
  1091. if (INVALID_HANDLE_VALUE != hFile) CloseHandle(hFile);
  1092. if (INVALID_HANDLE_VALUE != hDuplicateFile) {
  1093. DuplicateHandle(hNmProcess, hDuplicateFile, NULL, NULL, 0, FALSE, DUPLICATE_CLOSE_SOURCE);
  1094. }
  1095. if (INVALID_HANDLE_VALUE != hNmProcess) CloseHandle(hNmProcess);
  1096. LogDebugMessage(L"WinutilsCreateFile: %s %d, %d, %d, %d: %d",
  1097. request->path,
  1098. request->desiredAccess,
  1099. request->shareMode,
  1100. request->creationDisposition,
  1101. request->flags,
  1102. dwError);
  1103. return dwError;
  1104. }
  1105. error_status_t WinutilsKillTask(
  1106. /* [in] */ handle_t IDL_handle,
  1107. /* [in] */ KILLTASK_REQUEST *request) {
  1108. DWORD dwError = ERROR_SUCCESS;
  1109. HRESULT hr;
  1110. WCHAR bufferName[MAX_PATH];
  1111. dwError = GetSecureJobObjectName(request->taskName, MAX_PATH, bufferName);
  1112. CHECK_SVC_STATUS_DONE(dwError, L"GetSecureJobObjectName");
  1113. dwError = KillTask(bufferName);
  1114. if (ERROR_ACCESS_DENIED == dwError) {
  1115. // This process runs as LocalSystem with debug privilege enabled
  1116. // The job has a security descriptor that explictly grants JOB_OBJECT_ALL_ACCESS to us
  1117. // If we get ACCESS DENIED it means the job is being unwound
  1118. dwError = ERROR_SUCCESS;
  1119. }
  1120. done:
  1121. LogDebugMessage(L"WinutilsKillTask: %s :%d\n", bufferName, dwError);
  1122. return dwError;
  1123. }
  1124. error_status_t WinutilsDeletePath(
  1125. /* [in] */ handle_t IDL_handle,
  1126. /* [in] */ DELETEPATH_REQUEST *request,
  1127. /* [out] */ DELETEPATH_RESPONSE **response) {
  1128. DWORD dwError = ERROR_SUCCESS;
  1129. BOOL deleted = FALSE;
  1130. dwError = ValidateLocalPath(request->path);
  1131. CHECK_SVC_STATUS_DONE(dwError,L"ValidateLocalPath request->path");
  1132. switch(request->type) {
  1133. case PATH_IS_DIR:
  1134. deleted = RemoveDirectory(request->path);
  1135. if (!deleted) {
  1136. LogDebugMessage(L"Error %d deleting directory %s\n", GetLastError(), request->path);
  1137. }
  1138. break;
  1139. case PATH_IS_FILE:
  1140. deleted = DeleteFile(request->path);
  1141. if (!deleted) {
  1142. LogDebugMessage(L"Error %d deleting file %s\n", GetLastError(), request->path);
  1143. }
  1144. break;
  1145. default:
  1146. dwError = ERROR_BAD_ARGUMENTS;
  1147. CHECK_SVC_STATUS_DONE(dwError, L"request->operation");
  1148. }
  1149. *response = (DELETEPATH_RESPONSE*) MIDL_user_allocate(sizeof(DELETEPATH_RESPONSE));
  1150. if (NULL == *response) {
  1151. dwError = ERROR_OUTOFMEMORY;
  1152. CHECK_SVC_STATUS_DONE(dwError, L"MIDL_user_allocate");
  1153. }
  1154. (*response)->deleted = deleted;
  1155. done:
  1156. LogDebugMessage(L"WinutilsDeletePath: %s %d: %d %d",
  1157. request->path,
  1158. request->type,
  1159. deleted,
  1160. dwError);
  1161. return dwError;
  1162. }
  1163. error_status_t WinutilsMkDir(
  1164. /* [in] */ handle_t IDL_handle,
  1165. /* [in] */ MKDIR_REQUEST *request) {
  1166. DWORD dwError = ERROR_SUCCESS;
  1167. dwError = ValidateLocalPath(request->filePath);
  1168. CHECK_SVC_STATUS_DONE(dwError,L"ValidateLocalPath request->filePath");
  1169. if (!CreateDirectory(request->filePath, NULL)) {
  1170. dwError = GetLastError();
  1171. CHECK_SVC_STATUS_DONE(dwError, L"CreateDirectory");
  1172. }
  1173. done:
  1174. LogDebugMessage(L"WinutilsMkDir: %s :%d\n", request->filePath, dwError);
  1175. return dwError;
  1176. }
  1177. error_status_t WinutilsChown(
  1178. /* [in] */ handle_t IDL_handle,
  1179. /* [in] */ CHOWN_REQUEST *request) {
  1180. DWORD dwError = ERROR_SUCCESS;
  1181. dwError = ValidateLocalPath(request->filePath);
  1182. CHECK_SVC_STATUS_DONE(dwError,L"ValidateLocalPath request->filePath");
  1183. dwError = ChownImpl(request->ownerName, request->groupName, request->filePath);
  1184. CHECK_SVC_STATUS_DONE(dwError, L"ChownImpl");
  1185. done:
  1186. LogDebugMessage(L"WinutilsChown: %s %s %s :%d\n",
  1187. request->ownerName, request->groupName, request->filePath, dwError);
  1188. return dwError;
  1189. }
  1190. error_status_t WinutilsChmod(
  1191. /* [in] */ handle_t IDL_handle,
  1192. /* [in] */ CHMOD_REQUEST *request) {
  1193. DWORD dwError = ERROR_SUCCESS;
  1194. dwError = ValidateLocalPath(request->filePath);
  1195. CHECK_SVC_STATUS_DONE(dwError,L"ValidateLocalPath request->filePath");
  1196. dwError = ChangeFileModeByMask(request->filePath, request->mode);
  1197. CHECK_SVC_STATUS_DONE(dwError, L"ChangeFileModeByMask");
  1198. done:
  1199. LogDebugMessage(L"WinutilsChmod: %s %o :%d\n",
  1200. request->filePath, request->mode, dwError);
  1201. return dwError;
  1202. }
  1203. error_status_t WinutilsMoveFile(
  1204. /* [in] */ handle_t IDL_handle,
  1205. /* [in] */ MOVEFILE_REQUEST *request) {
  1206. DWORD dwError = ERROR_SUCCESS;
  1207. DWORD flags = 0;
  1208. dwError = ValidateLocalPath(request->sourcePath);
  1209. CHECK_SVC_STATUS_DONE(dwError,L"ValidateLocalPath request->sourcePath");
  1210. dwError = ValidateLocalPath(request->destinationPath);
  1211. CHECK_SVC_STATUS_DONE(dwError,L"ValidateLocalPath request->destinationPath");
  1212. switch (request->operation) {
  1213. case MOVE_FILE:
  1214. flags |= MOVEFILE_COPY_ALLOWED;
  1215. if (request->replaceExisting) flags |= MOVEFILE_REPLACE_EXISTING;
  1216. if (!MoveFileEx(request->sourcePath, request->destinationPath, flags)) {
  1217. dwError = GetLastError();
  1218. CHECK_SVC_STATUS_DONE(dwError, L"MoveFileEx");
  1219. }
  1220. break;
  1221. case COPY_FILE:
  1222. if (!request->replaceExisting) flags |= COPY_FILE_FAIL_IF_EXISTS;
  1223. if (!CopyFileEx(request->sourcePath, request->destinationPath,
  1224. NULL, // lpProgressRoutine
  1225. NULL, // lpData
  1226. NULL, // pbCancel
  1227. flags)) {
  1228. dwError = GetLastError();
  1229. CHECK_SVC_STATUS_DONE(dwError, L"CopyFileEx");
  1230. }
  1231. break;
  1232. default:
  1233. dwError = ERROR_BAD_ARGUMENTS;
  1234. CHECK_SVC_STATUS_DONE(dwError, L"request->operation");
  1235. }
  1236. done:
  1237. LogDebugMessage(L"WinutilsMoveFile: %d: %s %s :%d\n",
  1238. request->operation, request->sourcePath, request->destinationPath, dwError);
  1239. return dwError;
  1240. }
  1241. //----------------------------------------------------------------------------
  1242. // Function: ServiceUsage
  1243. //
  1244. // Description:
  1245. // Prints the CLI arguments for service command.
  1246. //
  1247. void ServiceUsage()
  1248. {
  1249. fwprintf(stdout, L"\
  1250. Usage: service\n\
  1251. Starts the nodemanager Windows Secure Container Executor helper service.\n\
  1252. The service must run as a high privileged account (LocalSystem)\n\
  1253. and is used by the nodemanager WSCE to spawn secure containers on Windows.\n");
  1254. }