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