diff --git hadoop-common-project/hadoop-common/src/main/winutils/include/winutils.h hadoop-common-project/hadoop-common/src/main/winutils/include/winutils.h index 0f09a63..f672996 100644 --- hadoop-common-project/hadoop-common/src/main/winutils/include/winutils.h +++ hadoop-common-project/hadoop-common/src/main/winutils/include/winutils.h @@ -191,6 +191,8 @@ DWORD LoadUserProfileForLogon(__in HANDLE logonHandle, __out PROFILEINFO * pi); DWORD UnloadProfileForLogon(__in HANDLE logonHandle, __in PROFILEINFO * pi); +DWORD EnableImpersonatePrivileges(); + DWORD RunService(__in int argc, __in_ecount(argc) wchar_t *argv[]); void ServiceUsage(); @@ -236,8 +238,14 @@ DWORD BuildServiceSecurityDescriptor( __in_ecount(grantSidCount) PSID* pGrantSids, __in size_t denySidCount, __in_ecount(denySidCount) PSID* pDenySids, + __in_opt PSID pOwner, __out PSECURITY_DESCRIPTOR* pSD); +DWORD AddNodeManagerAndUserACEsToObject( + __in HANDLE hProcess, + __in LPWSTR user); + + DWORD GetSecureJobObjectName( __in LPCWSTR jobName, __in size_t cchSecureJobName, diff --git hadoop-common-project/hadoop-common/src/main/winutils/libwinutils.c hadoop-common-project/hadoop-common/src/main/winutils/libwinutils.c index 6c20f43..357d3c1 100644 --- hadoop-common-project/hadoop-common/src/main/winutils/libwinutils.c +++ hadoop-common-project/hadoop-common/src/main/winutils/libwinutils.c @@ -1688,8 +1688,8 @@ DWORD EnablePrivilege(__in LPCWSTR privilegeName) // As stated on MSDN, we need to use GetLastError() to check if // AdjustTokenPrivileges() adjusted all of the specified privileges. // - if( !AdjustTokenPrivileges(hToken, FALSE, &tp, 0, NULL, NULL) ) { - dwErrCode = GetLastError(); + if (!AdjustTokenPrivileges(hToken, FALSE, &tp, 0, NULL, NULL)) { + dwErrCode = GetLastError(); } CloseHandle(hToken); @@ -2179,6 +2179,44 @@ DWORD GetSecureJobObjectName( return ERROR_SUCCESS; } +//----------------------------------------------------------------------------- +// Function: EnableImpersonatePrivileges +// +// Description: +// Enables the required privileges for S4U impersonation +// +// Returns: +// ERROR_SUCCESS: On success +// +DWORD EnableImpersonatePrivileges() { + DWORD dwError = ERROR_SUCCESS; + LPCWSTR privilege = NULL; + int crt = 0; + + LPCWSTR privileges[] = { + SE_IMPERSONATE_NAME, + SE_TCB_NAME, + SE_ASSIGNPRIMARYTOKEN_NAME, + SE_INCREASE_QUOTA_NAME, + SE_RESTORE_NAME, + SE_DEBUG_NAME, + SE_SECURITY_NAME, + }; + + for (crt = 0; crt < sizeof(privileges)/sizeof(LPCWSTR); ++crt) { + LPCWSTR privilege = privileges[crt]; + dwError = EnablePrivilege(privilege); + if( dwError != ERROR_SUCCESS ) { + LogDebugMessage(L"Failed to enable privilege: %s\n", privilege); + ReportErrorCode(L"EnablePrivilege", dwError); + goto done; + } + } + +done: + return dwError; +} + //----------------------------------------------------------------------------- // Function: KillTask @@ -2485,6 +2523,7 @@ DWORD BuildServiceSecurityDescriptor( __in_ecount(grantSidCount) PSID* pGrantSids, __in size_t denySidCount, __in_ecount(denySidCount) PSID* pDenySids, + __in_opt PSID pOwner, __out PSECURITY_DESCRIPTOR* pSD) { DWORD dwError = ERROR_SUCCESS; @@ -2506,65 +2545,82 @@ DWORD BuildServiceSecurityDescriptor( // We'll need our own SID to add as SD owner if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken)) { dwError = GetLastError(); + LogDebugMessage(L"OpenProcessToken: %d\n", dwError); goto done; } - if (!GetTokenInformation(hToken, TokenUser, NULL, 0, &dwBufferSize)) { - dwError = GetLastError(); - if (ERROR_INSUFFICIENT_BUFFER != dwError) { + if (NULL == pOwner) { + if (!GetTokenInformation(hToken, TokenUser, NULL, 0, &dwBufferSize)) { + dwError = GetLastError(); + if (ERROR_INSUFFICIENT_BUFFER != dwError) { + LogDebugMessage(L"GetTokenInformation: %d\n", dwError); + goto done; + } + } + + pTokenUser = (PTOKEN_USER) LocalAlloc(LPTR, dwBufferSize); + if (NULL == pTokenUser) { + dwError = GetLastError(); + LogDebugMessage(L"LocalAlloc:pTokenUser: %d\n", dwError); + goto done; + } + + if (!GetTokenInformation(hToken, TokenUser, pTokenUser, dwBufferSize, &dwBufferSize)) { + dwError = GetLastError(); + LogDebugMessage(L"GetTokenInformation: %d\n", dwError); + goto done; + } + + if (!IsValidSid(pTokenUser->User.Sid)) { + dwError = ERROR_INVALID_PARAMETER; + LogDebugMessage(L"IsValidSid: %d\n", dwError); goto done; } - } - - pTokenUser = (PTOKEN_USER) LocalAlloc(LPTR, dwBufferSize); - if (NULL == pTokenUser) { - dwError = GetLastError(); - goto done; - } - - if (!GetTokenInformation(hToken, TokenUser, pTokenUser, dwBufferSize, &dwBufferSize)) { - dwError = GetLastError(); - goto done; - } - - if (!IsValidSid(pTokenUser->User.Sid)) { - dwError = ERROR_INVALID_PARAMETER; - goto done; + pOwner = pTokenUser->User.Sid; } dwBufferSize = 0; if (!GetTokenInformation(hToken, TokenPrimaryGroup, NULL, 0, &dwBufferSize)) { dwError = GetLastError(); if (ERROR_INSUFFICIENT_BUFFER != dwError) { + LogDebugMessage(L"GetTokenInformation: %d\n", dwError); goto done; } } pTokenGroup = (PTOKEN_USER) LocalAlloc(LPTR, dwBufferSize); - if (NULL == pTokenUser) { + if (NULL == pTokenGroup) { dwError = GetLastError(); + LogDebugMessage(L"LocalAlloc:pTokenGroup: %d\n", dwError); goto done; } if (!GetTokenInformation(hToken, TokenPrimaryGroup, pTokenGroup, dwBufferSize, &dwBufferSize)) { dwError = GetLastError(); + LogDebugMessage(L"GetTokenInformation: %d\n", dwError); goto done; } if (!IsValidSid(pTokenGroup->PrimaryGroup)) { dwError = ERROR_INVALID_PARAMETER; + LogDebugMessage(L"IsValidSid: %d\n", dwError); goto done; } owner.TrusteeForm = TRUSTEE_IS_SID; owner.TrusteeType = TRUSTEE_IS_UNKNOWN; - owner.ptstrName = (LPCWSTR) pTokenUser->User.Sid; + owner.ptstrName = (LPCWSTR) pOwner; group.TrusteeForm = TRUSTEE_IS_SID; group.TrusteeType = TRUSTEE_IS_UNKNOWN; group.ptstrName = (LPCWSTR) pTokenGroup->PrimaryGroup; eas = (EXPLICIT_ACCESS*) LocalAlloc(LPTR, sizeof(EXPLICIT_ACCESS) * (grantSidCount + denySidCount)); + if (NULL == eas) { + dwError = ERROR_OUTOFMEMORY; + LogDebugMessage(L"LocalAlloc: %d\n", dwError); + goto done; + } // Build the granted list for (crt = 0; crt < grantSidCount; ++crt) { @@ -2601,6 +2657,7 @@ DWORD BuildServiceSecurityDescriptor( &cbSD, &pTempSD); if (ERROR_SUCCESS != dwError) { + LogDebugMessage(L"BuildSecurityDescriptor: %d\n", dwError); goto done; } @@ -2625,7 +2682,6 @@ done: return dwError; } - //---------------------------------------------------------------------------- // Function: MIDL_user_allocate // diff --git hadoop-common-project/hadoop-common/src/main/winutils/service.c hadoop-common-project/hadoop-common/src/main/winutils/service.c index 51fa37d..b90203f 100644 --- hadoop-common-project/hadoop-common/src/main/winutils/service.c +++ hadoop-common-project/hadoop-common/src/main/winutils/service.c @@ -503,8 +503,9 @@ done: DWORD SvcInit() { DWORD dwError = ERROR_SUCCESS; - dwError = EnablePrivilege(SE_DEBUG_NAME); + dwError = EnableImpersonatePrivileges(); if( dwError != ERROR_SUCCESS ) { + ReportErrorCode(L"EnableImpersonatePrivileges", dwError); goto done; } @@ -656,7 +657,7 @@ DWORD AuthInit() { DWORD dwError = ERROR_SUCCESS; int count = 0; int crt = 0; - int len = 0; + size_t len = 0; LPCWSTR value = NULL; WCHAR** tokens = NULL; LPWSTR lpszSD = NULL; @@ -693,7 +694,7 @@ DWORD AuthInit() { allowedCount = count; dwError = BuildServiceSecurityDescriptor(SERVICE_ACCESS_MASK, - allowedCount, allowedSids, 0, NULL, &pAllowedSD); + allowedCount, allowedSids, 0, NULL, NULL, &pAllowedSD); CHECK_SVC_STATUS_DONE(dwError, L"BuildServiceSecurityDescriptor"); done: @@ -1052,6 +1053,13 @@ error_status_t WinutilsCreateProcessAsUser( LogDebugMessage(L"CreateProcess: pid:%x\n", pi.dwProcessId); + // Grant full access to the container user on the 'winutils task createAsUser ...' helper process + dwError = AddNodeManagerAndUserACEsToObject(pi.hProcess, request->user, PROCESS_ALL_ACCESS); + if (dwError) { + LogDebugMessage(L"failed: AddNodeManagerAndUserACEsToObject\n"); + goto done; + } + if (!DuplicateHandle(hSelfProcess, pi.hProcess, hNmProcess, &hDuplicateProcess, 0, FALSE, DUPLICATE_SAME_ACCESS)) { dwError = GetLastError(); @@ -1144,7 +1152,7 @@ done: // If the transfer was succesfull the NM has its own duplicates (if any) if (INVALID_HANDLE_VALUE != pi.hThread) CloseHandle(pi.hThread); if (INVALID_HANDLE_VALUE != pi.hProcess) CloseHandle(pi.hProcess); - + return dwError; } diff --git hadoop-common-project/hadoop-common/src/main/winutils/task.c hadoop-common-project/hadoop-common/src/main/winutils/task.c index 03a0c45..68a0988 100644 --- hadoop-common-project/hadoop-common/src/main/winutils/task.c +++ hadoop-common-project/hadoop-common/src/main/winutils/task.c @@ -20,6 +20,7 @@ #include #include #include +#include #define PSAPI_VERSION 1 #pragma comment(lib, "psapi.lib") @@ -205,6 +206,7 @@ DWORD BuildImpersonateSecurityDescriptor(__out PSECURITY_DESCRIPTOR* ppSD) { SERVICE_IMPERSONATE_MASK, countAllowed, allowedSids, countDenied, deniedSids, + NULL, &pSD); if (dwError) { @@ -224,34 +226,76 @@ done: } //---------------------------------------------------------------------------- -// Function: BuildNodeManagerSecurityDescriptor +// Function: AddNodeManagerAndUserACEsToObject // // Description: -// Builds the security descriptor for NT job object that contains the task -// Both the nodemanager and the container user require access to the job object -// The ACEs grant full controll to NM, container job and LocalSystem (the WSCE winutils service) +// Adds ACEs to grant NM and user the provided access mask over a given handle // // Returns: -// ERROR_SUCCESS: On success -// GetLastError: otherwise +// ERROR_SUCCESS: on success // -DWORD BuildNodeManagerSecurityDescriptor( - __in ACCESS_MASK accessMask, - __out PSECURITY_DESCRIPTOR* pSD) { +DWORD AddNodeManagerAndUserACEsToObject( + __in HANDLE hObject, + __in LPWSTR user, + __in ACCESS_MASK accessMask) { - DWORD dwError; - - DWORD cbSid = SECURITY_MAX_SID_SIZE; - PSID pSidNodeManager = NULL; - PSID pSidLocalSystem = NULL; - PSID pSidUser = NULL; - PSID* allowedSids = NULL; - int countSids = 0; + DWORD dwError = ERROR_SUCCESS; int countTokens = 0; - int len = 0; + size_t len = 0; LPCWSTR value = NULL; WCHAR** tokens = NULL; int crt = 0; + PACL pDacl = NULL; + PSECURITY_DESCRIPTOR psdProcess = NULL; + LPSTR lpszOldDacl = NULL, lpszNewDacl = NULL; + ULONG daclLen = 0; + PACL pNewDacl = NULL; + ACL_SIZE_INFORMATION si; + DWORD dwNewAclSize = 0; + PACE_HEADER pTempAce = NULL; + BYTE sidTemp[SECURITY_MAX_SID_SIZE]; + DWORD cbSid = SECURITY_MAX_SID_SIZE; + PSID tokenSid = NULL; + // These hard-coded SIDs are allways added + WELL_KNOWN_SID_TYPE forcesSidTypes[] = { + WinLocalSystemSid, + WinBuiltinAdministratorsSid}; + BOOL logSDs = IsDebuggerPresent(); // Check only once to avoid attach-while-running + + + dwError = GetSecurityInfo(hObject, + SE_KERNEL_OBJECT, + DACL_SECURITY_INFORMATION, + NULL, + NULL, + &pDacl, + NULL, + &psdProcess); + if (dwError) { + ReportErrorCode(L"GetSecurityInfo", dwError); + goto done; + } + + // This is debug only output for troubleshooting + if (logSDs) { + if (!ConvertSecurityDescriptorToStringSecurityDescriptor( + psdProcess, + SDDL_REVISION_1, + DACL_SECURITY_INFORMATION, + &lpszOldDacl, + &daclLen)) { + dwError = GetLastError(); + ReportErrorCode(L"ConvertSecurityDescriptorToStringSecurityDescriptor", dwError); + goto done; + } + } + + ZeroMemory(&si, sizeof(si)); + if (!GetAclInformation(pDacl, &si, sizeof(si), AclSizeInformation)) { + dwError = GetLastError(); + ReportErrorCode(L"GetAclInformation", dwError); + goto done; + } dwError = GetConfigValue(wsceConfigRelativePath, NM_WSCE_ALLOWED, &len, &value); if (ERROR_SUCCESS != dwError) { @@ -271,55 +315,153 @@ DWORD BuildNodeManagerSecurityDescriptor( goto done; } - // allocate for all the configure granted users (ie. NM service account) - // +1 for LocalSystem + // We're gonna add 1 ACE for each token found, +1 for user and +1 for each forcesSidTypes[] + // ACCESS_ALLOWED_ACE struct contains the first DWORD of the SID // - allowedSids = (PSID*) LocalAlloc(LPTR, sizeof(PSID) * (countTokens + 1)); - if (NULL == allowedSids) { + dwNewAclSize = si.AclBytesInUse + + (countTokens + 1 + sizeof(forcesSidTypes)/sizeof(forcesSidTypes[0])) * + (sizeof(ACCESS_ALLOWED_ACE) + SECURITY_MAX_SID_SIZE - sizeof(DWORD)); + + pNewDacl = (PSID) LocalAlloc(LPTR, dwNewAclSize); + if (!pNewDacl) { dwError = ERROR_OUTOFMEMORY; - ReportErrorCode(L"LocalAlloc:pSidLocalSystem", dwError); + ReportErrorCode(L"LocalAlloc", dwError); goto done; } - for (crt = 0; crt < countTokens; ++crt) { - dwError = GetSidFromAcctNameW(tokens[crt], &allowedSids[crt]); - if (ERROR_SUCCESS != dwError) { - ReportErrorCode(L"GetSidFromAcctNameW", dwError); + if (!InitializeAcl(pNewDacl, dwNewAclSize, ACL_REVISION)) { + dwError = ERROR_OUTOFMEMORY; + ReportErrorCode(L"InitializeAcl", dwError); + goto done; + } + + // Copy over old ACEs + for (crt = 0; crt < si.AceCount; ++crt) { + if (!GetAce(pDacl, crt, &pTempAce)) { + dwError = ERROR_OUTOFMEMORY; + ReportErrorCode(L"InitializeAcl", dwError); + goto done; + } + if (!AddAce(pNewDacl, ACL_REVISION, MAXDWORD, pTempAce, pTempAce->AceSize)) { + dwError = ERROR_OUTOFMEMORY; + ReportErrorCode(L"InitializeAcl", dwError); goto done; } } - allowedSids[crt] = (PSID) LocalAlloc(LPTR, SECURITY_MAX_SID_SIZE); - if (NULL == allowedSids[crt]) { - dwError = ERROR_OUTOFMEMORY; - ReportErrorCode(L"LocalAlloc:pSidLocalSystem", dwError); - goto done; - } - cbSid = SECURITY_MAX_SID_SIZE; - if (!CreateWellKnownSid(WinLocalSystemSid, NULL, allowedSids[crt], &cbSid)) { - dwError = GetLastError(); - ReportErrorCode(L"CreateWellKnownSid", dwError); - goto done; + // Add the configured allowed SIDs + for (crt = 0; crt < countTokens; ++crt) { + dwError = GetSidFromAcctNameW(tokens[crt], &tokenSid); + if (ERROR_SUCCESS != dwError) { + ReportErrorCode(L"GetSidFromAcctNameW", dwError); + goto done; + } + if (!AddAccessAllowedAceEx( + pNewDacl, + ACL_REVISION_DS, + CONTAINER_INHERIT_ACE | OBJECT_INHERIT_ACE, + PROCESS_ALL_ACCESS, + tokenSid)) { + dwError = GetLastError(); + ReportErrorCode(L"AddAccessAllowedAceEx:1", dwError); + goto done; + } + LocalFree(tokenSid); + tokenSid = NULL; } - dwError = BuildServiceSecurityDescriptor(accessMask, crt, allowedSids, 0, NULL, pSD); - if (ERROR_SUCCESS != dwError) { - goto done; + // add the forced SIDs ACE + for (crt = 0; crt < sizeof(forcesSidTypes)/sizeof(forcesSidTypes[0]); ++crt) { + cbSid = SECURITY_MAX_SID_SIZE; + if (!CreateWellKnownSid(forcesSidTypes[crt], NULL, &sidTemp, &cbSid)) { + dwError = GetLastError(); + ReportErrorCode(L"CreateWellKnownSid", dwError); + goto done; + } + if (!AddAccessAllowedAceEx( + pNewDacl, + ACL_REVISION_DS, + CONTAINER_INHERIT_ACE | OBJECT_INHERIT_ACE, + accessMask, + (PSID) sidTemp)) { + dwError = GetLastError(); + ReportErrorCode(L"AddAccessAllowedAceEx:2", dwError); + goto done; + } } - -done: - do { - if (allowedSids && allowedSids[crt]) LocalFree(allowedSids[crt]); - --crt; - } while (crt); - if (allowedSids) LocalFree(allowedSids); - if (value) LocalFree(value); + // add the user ACE + dwError = GetSidFromAcctNameW(user, &tokenSid); + if (ERROR_SUCCESS != dwError) { + ReportErrorCode(L"GetSidFromAcctNameW:user", dwError); + goto done; + } + + if (!AddAccessAllowedAceEx( + pNewDacl, + ACL_REVISION_DS, + CONTAINER_INHERIT_ACE | OBJECT_INHERIT_ACE, + PROCESS_ALL_ACCESS, + tokenSid)) { + dwError = GetLastError(); + ReportErrorCode(L"AddAccessAllowedAceEx:3", dwError); + goto done; + } + + LocalFree(tokenSid); + tokenSid = NULL; + + dwError = SetSecurityInfo(hObject, + SE_KERNEL_OBJECT, + DACL_SECURITY_INFORMATION, + NULL, + NULL, + pNewDacl, + NULL); + if (dwError) { + ReportErrorCode(L"SetSecurityInfo", dwError); + goto done; + } + + // This is debug only output for troubleshooting + if (logSDs) { + dwError = GetSecurityInfo(hObject, + SE_KERNEL_OBJECT, + DACL_SECURITY_INFORMATION, + NULL, + NULL, + &pDacl, + NULL, + &psdProcess); + if (dwError) { + ReportErrorCode(L"GetSecurityInfo:2", dwError); + goto done; + } + + if (!ConvertSecurityDescriptorToStringSecurityDescriptor( + psdProcess, + SDDL_REVISION_1, + DACL_SECURITY_INFORMATION, + &lpszNewDacl, + &daclLen)) { + dwError = GetLastError(); + ReportErrorCode(L"ConvertSecurityDescriptorToStringSecurityDescriptor:2", dwError); + goto done; + } + + LogDebugMessage(L"Old DACL: %s\nNew DACL: %s\n", lpszOldDacl, lpszNewDacl); + } + +done: + if (tokenSid) LocalFree(tokenSid); + if (pNewDacl) LocalFree(pNewDacl); + if (lpszOldDacl) LocalFree(lpszOldDacl); + if (lpszNewDacl) LocalFree(lpszNewDacl); + if (psdProcess) LocalFree(psdProcess); + return dwError; } - - //---------------------------------------------------------------------------- // Function: ValidateImpersonateAccessCheck // @@ -431,8 +573,7 @@ done: // ERROR_SUCCESS: On success // GetLastError: otherwise DWORD CreateTaskImpl(__in_opt HANDLE logonHandle, __in PCWSTR jobObjName,__in PCWSTR cmdLine, - __in SECURITY_DESCRIPTOR* pSdJob, - __in SECURITY_DESCRIPTOR* pSdProcess) + __in LPCWSTR userName) { DWORD dwErrorCode = ERROR_SUCCESS; DWORD exitCode = EXIT_FAILURE; @@ -442,11 +583,6 @@ DWORD CreateTaskImpl(__in_opt HANDLE logonHandle, __in PCWSTR jobObjName,__in PC HANDLE jobObject = NULL; JOBOBJECT_EXTENDED_LIMIT_INFORMATION jeli = { 0 }; void * envBlock = NULL; - BOOL createProcessResult = FALSE; - SECURITY_ATTRIBUTES saJob; - SECURITY_ATTRIBUTES* psaJob = NULL; - SECURITY_ATTRIBUTES saProcess; - SECURITY_ATTRIBUTES* psaProcess = NULL; WCHAR secureJobNameBuffer[MAX_PATH]; LPCWSTR secureJobName = jobObjName; @@ -460,17 +596,6 @@ DWORD CreateTaskImpl(__in_opt HANDLE logonHandle, __in PCWSTR jobObjName,__in PC return dwErrorCode; } - // We need to create a security descripto for the job so that the task can query it - ZeroMemory(&saJob, sizeof(saJob)); - saJob.nLength = sizeof(saJob); - saJob.lpSecurityDescriptor = pSdJob; - psaJob = &saJob; - - ZeroMemory(&saProcess, sizeof(saProcess)); - saProcess.nLength = sizeof(saProcess); - saJob.lpSecurityDescriptor = pSdProcess; - psaProcess = &saProcess; - dwErrorCode = GetSecureJobObjectName(jobObjName, MAX_PATH, secureJobNameBuffer); if (dwErrorCode) { ReportErrorCode(L"GetSecureJobObjectName", dwErrorCode); @@ -483,7 +608,7 @@ DWORD CreateTaskImpl(__in_opt HANDLE logonHandle, __in PCWSTR jobObjName,__in PC // when last handle is closed. So winutils.exe invocation has the only open // job object handle. Exit of winutils.exe ensures termination of job object. // Either a clean exit of winutils or crash or external termination. - jobObject = CreateJobObject(psaJob, secureJobName); + jobObject = CreateJobObject(NULL, secureJobName); dwErrorCode = GetLastError(); if(jobObject == NULL || dwErrorCode == ERROR_ALREADY_EXISTS) { @@ -500,7 +625,14 @@ DWORD CreateTaskImpl(__in_opt HANDLE logonHandle, __in PCWSTR jobObjName,__in PC ReportErrorCode(L"SetInformationJobObject", dwErrorCode); CloseHandle(jobObject); return dwErrorCode; - } + } + + dwErrorCode = AddNodeManagerAndUserACEsToObject(jobObject, userName, JOB_OBJECT_ALL_ACCESS); + if (dwErrorCode) { + ReportErrorCode(L"AddNodeManagerAndUserACEsToObject", dwErrorCode); + CloseHandle(jobObject); + return dwErrorCode; + } if(AssignProcessToJobObject(jobObject, GetCurrentProcess()) == 0) { @@ -557,37 +689,65 @@ DWORD CreateTaskImpl(__in_opt HANDLE logonHandle, __in PCWSTR jobObjName,__in PC return dwErrorCode; } + dwErrorCode = ERROR_SUCCESS; + if (logonHandle == NULL) { - createProcessResult = CreateProcess( - NULL, // ApplicationName - cmdLine, // command line - NULL, // process security attributes - NULL, // thread security attributes - TRUE, // inherit handles - 0, // creation flags - NULL, // environment - curr_dir, // current directory - &si, // startup info - &pi); // process info - } - else { - createProcessResult = CreateProcessAsUser( - logonHandle, // logon token handle - NULL, // Application handle - cmdLine, // command line - psaProcess, // process security attributes - NULL, // thread security attributes - FALSE, // inherit handles - CREATE_UNICODE_ENVIRONMENT, // creation flags - envBlock, // environment - curr_dir, // current directory - &si, // startup info - &pi); // process info + if (!CreateProcess( + NULL, // ApplicationName + cmdLine, // command line + NULL, // process security attributes + NULL, // thread security attributes + TRUE, // inherit handles + 0, // creation flags + NULL, // environment + curr_dir, // current directory + &si, // startup info + &pi)) { // process info + dwErrorCode = GetLastError(); + ReportErrorCode(L"CreateProcess", dwErrorCode); + } + goto create_process_done; } + + // From here on is the secure S4U implementation for CreateProcessAsUser - if (FALSE == createProcessResult) { + // We desire to grant process access to NM so that it can interogate process status + // and resource utilization. Passing in a security descriptor though results in the + // S4U privilege checks being done against that SD and CreateProcessAsUser fails. + // So instead we create the process suspended and then we add the desired ACEs. + // + if (!CreateProcessAsUser( + logonHandle, // logon token handle + NULL, // Application handle + cmdLine, // command line + NULL, // process security attributes + NULL, // thread security attributes + FALSE, // inherit handles + CREATE_UNICODE_ENVIRONMENT | CREATE_SUSPENDED, // creation flags + envBlock, // environment + curr_dir, // current directory + &si, // startup info + &pi)) { // process info dwErrorCode = GetLastError(); - ReportErrorCode(L"CreateProcess/AsUser", dwErrorCode); + ReportErrorCode(L"CreateProcessAsUser", dwErrorCode); + goto create_process_done; + } + + dwErrorCode = AddNodeManagerAndUserACEsToObject(pi.hProcess, userName, PROCESS_ALL_ACCESS); + if (dwErrorCode) { + ReportErrorCode(L"AddNodeManagerAndUserACEsToObject", dwErrorCode); + goto create_process_done; + } + + if (-1 == ResumeThread(pi.hThread)) { + dwErrorCode = GetLastError(); + ReportErrorCode(L"ResumeThread", dwErrorCode); + goto create_process_done; + } + +create_process_done: + + if (dwErrorCode) { if( envBlock != NULL ) { DestroyEnvironmentBlock( envBlock ); envBlock = NULL; @@ -602,8 +762,6 @@ DWORD CreateTaskImpl(__in_opt HANDLE logonHandle, __in PCWSTR jobObjName,__in PC CloseHandle(pi.hThread); - ReportErrorCode(L"CreateTaskImpl", ERROR_SUCCESS); - // Wait until child process exits. WaitForSingleObject( pi.hProcess, INFINITE ); if(GetExitCodeProcess(pi.hProcess, &exitCode) == 0) @@ -650,7 +808,7 @@ DWORD CreateTaskImpl(__in_opt HANDLE logonHandle, __in PCWSTR jobObjName,__in PC DWORD CreateTask(__in PCWSTR jobObjName,__in PWSTR cmdLine) { // call with null logon in order to create tasks utilizing the current logon - return CreateTaskImpl( NULL, jobObjName, cmdLine, NULL, NULL); + return CreateTaskImpl( NULL, jobObjName, cmdLine, NULL); } //---------------------------------------------------------------------------- @@ -673,35 +831,12 @@ DWORD CreateTaskAsUser(__in PCWSTR jobObjName, PROFILEINFO pi; BOOL profileIsLoaded = FALSE; FILE* pidFile = NULL; - SECURITY_DESCRIPTOR* pSdJob = NULL; - SECURITY_DESCRIPTOR* pSdProcess = NULL; DWORD retLen = 0; HANDLE logonHandle = NULL; - err = EnablePrivilege(SE_TCB_NAME); + err = EnableImpersonatePrivileges(); if( err != ERROR_SUCCESS ) { - ReportErrorCode(L"EnablePrivilege:SE_TCB_NAME", err); - goto done; - } - err = EnablePrivilege(SE_ASSIGNPRIMARYTOKEN_NAME); - if( err != ERROR_SUCCESS ) { - ReportErrorCode(L"EnablePrivilege:SE_ASSIGNPRIMARYTOKEN_NAME", err); - goto done; - } - err = EnablePrivilege(SE_INCREASE_QUOTA_NAME); - if( err != ERROR_SUCCESS ) { - ReportErrorCode(L"EnablePrivilege:SE_INCREASE_QUOTA_NAME", err); - goto done; - } - err = EnablePrivilege(SE_RESTORE_NAME); - if( err != ERROR_SUCCESS ) { - ReportErrorCode(L"EnablePrivilege:SE_RESTORE_NAME", err); - goto done; - } - - err = EnablePrivilege(SE_SECURITY_NAME); - if( err != ERROR_SUCCESS ) { - ReportErrorCode(L"EnablePrivilege:SE_SECURITY_NAME", err); + ReportErrorCode(L"EnableImpersonatePrivileges", err); goto done; } @@ -754,25 +889,9 @@ DWORD CreateTaskAsUser(__in PCWSTR jobObjName, goto done; } - err = BuildNodeManagerSecurityDescriptor(JOB_OBJECT_ALL_ACCESS, &pSdJob); - if (ERROR_SUCCESS != err) { - ReportErrorCode(L"BuildJobSecurityDescriptor", err); - goto done; - } - - err = BuildNodeManagerSecurityDescriptor(PROCESS_ALL_ACCESS, &pSdProcess); - if (ERROR_SUCCESS != err) { - ReportErrorCode(L"BuildJobSecurityDescriptor", err); - goto done; - } - - err = CreateTaskImpl(logonHandle, jobObjName, cmdLine, pSdJob, pSdProcess); + err = CreateTaskImpl(logonHandle, jobObjName, cmdLine, user); done: -if (pSdProcess) LocalFree(pSdProcess); - - if (pSdJob) LocalFree(pSdJob); - if( profileIsLoaded ) { UnloadProfileForLogon( logonHandle, &pi ); profileIsLoaded = FALSE; @@ -803,10 +922,27 @@ DWORD IsTaskAlive(const WCHAR* jobObjName, int* isAlive, int* procsInJob) PJOBOBJECT_BASIC_PROCESS_ID_LIST procList; HANDLE jobObject = NULL; int numProcs = 100; + WCHAR secureJobNameBuffer[MAX_PATH]; *isAlive = FALSE; jobObject = OpenJobObject(JOB_OBJECT_QUERY, FALSE, jobObjName); + if(jobObject == NULL) + { + // Try Global\... + DWORD err = GetSecureJobObjectName(jobObjName, MAX_PATH, secureJobNameBuffer); + if (err) { + ReportErrorCode(L"GetSecureJobObjectName", err); + return err; + } + jobObject = OpenJobObject(JOB_OBJECT_QUERY, FALSE, secureJobNameBuffer); + } + + if(jobObject == NULL) + { + DWORD err = GetLastError(); + return err; + } if(jobObject == NULL) { @@ -862,7 +998,21 @@ DWORD PrintTaskProcessList(const WCHAR* jobObjName) DWORD i; PJOBOBJECT_BASIC_PROCESS_ID_LIST procList; int numProcs = 100; - HANDLE jobObject = OpenJobObject(JOB_OBJECT_QUERY, FALSE, jobObjName); + WCHAR secureJobNameBuffer[MAX_PATH]; + HANDLE jobObject = NULL; + + jobObject = OpenJobObject(JOB_OBJECT_QUERY, FALSE, jobObjName); + if(jobObject == NULL) + { + // Try Global\... + DWORD err = GetSecureJobObjectName(jobObjName, MAX_PATH, secureJobNameBuffer); + if (err) { + ReportErrorCode(L"GetSecureJobObjectName", err); + return err; + } + jobObject = OpenJobObject(JOB_OBJECT_QUERY, FALSE, secureJobNameBuffer); + } + if(jobObject == NULL) { DWORD err = GetLastError();