You are viewing a plain text version of this content. The canonical link for it is here.
Posted to common-commits@hadoop.apache.org by ji...@apache.org on 2014/10/23 01:27:33 UTC

[4/6] YARN-2198. Remove the need to run NodeManager as privileged account for Windows Secure Container Executor. Contributed by Remus Rusanu (cherry picked from commit 3b12fd6cfbf4cc91ef8e8616c7aafa9de006cde5)

http://git-wip-us.apache.org/repos/asf/hadoop/blob/29d0164e/hadoop-common-project/hadoop-common/src/main/winutils/task.c
----------------------------------------------------------------------
diff --git a/hadoop-common-project/hadoop-common/src/main/winutils/task.c b/hadoop-common-project/hadoop-common/src/main/winutils/task.c
index 783f162..f0fc19a 100644
--- a/hadoop-common-project/hadoop-common/src/main/winutils/task.c
+++ b/hadoop-common-project/hadoop-common/src/main/winutils/task.c
@@ -18,29 +18,32 @@
 #include "winutils.h"
 #include <errno.h>
 #include <psapi.h>
-#include <malloc.h>
+#include <malloc.h>
+#include <authz.h>
+#include <sddl.h>
 
 #define PSAPI_VERSION 1
 #pragma comment(lib, "psapi.lib")
 
-#define ERROR_TASK_NOT_ALIVE 1
+#define NM_WSCE_IMPERSONATE_ALLOWED L"yarn.nodemanager.windows-secure-container-executor.impersonate.allowed"
+#define NM_WSCE_IMPERSONATE_DENIED  L"yarn.nodemanager.windows-secure-container-executor.impersonate.denied"
 
-// This exit code for killed processes is compatible with Unix, where a killed
-// process exits with 128 + signal.  For SIGKILL, this would be 128 + 9 = 137.
-#define KILLED_PROCESS_EXIT_CODE 137
+// The S4U impersonation access check mask. Arbitrary value (we use 1 for the service access check)
+#define SERVICE_IMPERSONATE_MASK 0x00000002
+
+
+// Name for tracking this logon process when registering with LSA
+static const char *LOGON_PROCESS_NAME="Hadoop Container Executor";
+// Name for token source, must be less or eq to TOKEN_SOURCE_LENGTH (currently 8) chars
+static const char *TOKEN_SOURCE_NAME = "HadoopEx";
 
-// Name for tracking this logon process when registering with LSA
-static const char *LOGON_PROCESS_NAME="Hadoop Container Executor";
-// Name for token source, must be less or eq to TOKEN_SOURCE_LENGTH (currently 8) chars
-static const char *TOKEN_SOURCE_NAME = "HadoopEx";
-
 // List of different task related command line options supported by
 // winutils.
 typedef enum TaskCommandOptionType
 {
   TaskInvalid,
   TaskCreate,
-  TaskCreateAsUser,
+  TaskCreateAsUser,
   TaskIsAlive,
   TaskKill,
   TaskProcessList
@@ -93,53 +96,524 @@ static BOOL ParseCommandLine(__in int argc,
     }
   }
 
-  if (argc >= 6) {
-    if (wcscmp(argv[1], L"createAsUser") == 0)
-    {
-      *command = TaskCreateAsUser;
-      return TRUE;
-    }
-  }
-
+  if (argc >= 6) {
+    if (wcscmp(argv[1], L"createAsUser") == 0)
+    {
+      *command = TaskCreateAsUser;
+      return TRUE;
+    }
+  }
+
   return FALSE;
 }
 
+
 //----------------------------------------------------------------------------
-// Function: CreateTaskImpl
+// Function: BuildImpersonateSecurityDescriptor
+//
+// Description:
+//  Builds the security descriptor for the S4U impersonation permissions
+//  This describes what users can be impersonated and what not
+//
+// Returns:
+//   ERROR_SUCCESS: On success
+//   GetLastError: otherwise
+//
+DWORD BuildImpersonateSecurityDescriptor(__out PSECURITY_DESCRIPTOR* ppSD) {
+  DWORD dwError = ERROR_SUCCESS;
+  size_t countAllowed = 0;
+  PSID* allowedSids = NULL;
+  size_t countDenied = 0;
+  PSID* deniedSids = NULL;
+  LPCWSTR value = NULL;
+  WCHAR** tokens = NULL;
+  size_t len = 0;
+  size_t count = 0;
+  int crt = 0;
+  PSECURITY_DESCRIPTOR pSD = NULL;
+
+  dwError = GetConfigValue(wsceConfigRelativePath, NM_WSCE_IMPERSONATE_ALLOWED, &len, &value); 
+  if (dwError) {
+    ReportErrorCode(L"GetConfigValue:1", dwError);
+    goto done;
+  }
+
+  if (0 == len) {
+    dwError = ERROR_BAD_CONFIGURATION;
+    ReportErrorCode(L"GetConfigValue:2", dwError);
+    goto done;
+  }
+  
+  dwError = SplitStringIgnoreSpaceW(len, value, L',', &count, &tokens);
+  if (dwError) {
+    ReportErrorCode(L"SplitStringIgnoreSpaceW:1", dwError);
+    goto done;
+  }
+
+  allowedSids = LocalAlloc(LPTR, sizeof(PSID) * count);
+  if (NULL == allowedSids) {
+    dwError = GetLastError();
+    ReportErrorCode(L"LocalAlloc:1", dwError);
+    goto done;
+  }
+
+  for(crt = 0; crt < count; ++crt) {
+    dwError = GetSidFromAcctNameW(tokens[crt], &allowedSids[crt]);
+    if (dwError) {
+      ReportErrorCode(L"GetSidFromAcctNameW:1", dwError);
+      goto done;
+    }
+  }
+  countAllowed = count;
+
+  LocalFree(tokens);
+  tokens = NULL;
+
+  LocalFree(value);
+  value = NULL;
+  
+  dwError = GetConfigValue(wsceConfigRelativePath, NM_WSCE_IMPERSONATE_DENIED, &len, &value); 
+  if (dwError) {
+    ReportErrorCode(L"GetConfigValue:3", dwError);
+    goto done;
+  }
+
+  if (0 != len) {
+    dwError = SplitStringIgnoreSpaceW(len, value, L',', &count, &tokens);
+    if (dwError) {
+      ReportErrorCode(L"SplitStringIgnoreSpaceW:2", dwError);
+      goto done;
+    }
+
+    deniedSids = LocalAlloc(LPTR, sizeof(PSID) * count);
+    if (NULL == allowedSids) {
+      dwError = GetLastError();
+      ReportErrorCode(L"LocalAlloc:2", dwError);
+      goto done;
+    }
+
+    for(crt = 0; crt < count; ++crt) {
+      dwError = GetSidFromAcctNameW(tokens[crt], &deniedSids[crt]);
+      if (dwError) {
+        ReportErrorCode(L"GetSidFromAcctNameW:2", dwError);
+        goto done;
+      }
+    }
+    countDenied = count;
+  }
+
+  dwError = BuildServiceSecurityDescriptor(
+    SERVICE_IMPERSONATE_MASK,
+    countAllowed, allowedSids,
+    countDenied, deniedSids,
+    NULL,
+    &pSD);
+
+  if (dwError) {
+    ReportErrorCode(L"BuildServiceSecurityDescriptor", dwError);
+    goto done;
+  }
+  
+  *ppSD = pSD;
+  pSD = NULL;
+
+done:
+  if (pSD) LocalFree(pSD);
+  if (tokens) LocalFree(tokens);
+  if (allowedSids) LocalFree(allowedSids);
+  if (deniedSids) LocalFree(deniedSids);
+  return dwError;
+}
+
+//----------------------------------------------------------------------------
+// Function: AddNodeManagerAndUserACEsToObject
+//
+// Description:
+//  Adds ACEs to grant NM and user the provided access mask over a given handle
+//
+// Returns:
+//  ERROR_SUCCESS: on success
+//
+DWORD AddNodeManagerAndUserACEsToObject(
+  __in HANDLE hObject,
+  __in LPWSTR user,
+  __in ACCESS_MASK accessMask) {
+
+  DWORD dwError = ERROR_SUCCESS;
+  int         countTokens = 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) {
+    ReportErrorCode(L"GetConfigValue", dwError);
+    goto done;
+  }
+
+  if (0 == len) {
+    dwError = ERROR_BAD_CONFIGURATION;
+    ReportErrorCode(L"GetConfigValue", dwError);
+    goto done;
+  }
+
+  dwError = SplitStringIgnoreSpaceW(len, value, L',', &countTokens, &tokens);
+  if (ERROR_SUCCESS != dwError) {
+    ReportErrorCode(L"SplitStringIgnoreSpaceW", dwError);
+    goto done;
+  }
+
+  // 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 
+  //
+  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", dwError);
+    goto done;
+  }
+
+  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;
+    }
+  }
+
+  // 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;
+  }
+
+  // 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;
+    }
+  }
+  
+  // 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
+//
+// Description:
+//  Performs the access check for S4U impersonation
+//
+// Returns:
+//   ERROR_SUCCESS: On success
+//   ERROR_ACCESS_DENIED, GetLastError: otherwise
+//
+DWORD ValidateImpersonateAccessCheck(__in HANDLE logonHandle) {
+  DWORD dwError = ERROR_SUCCESS;
+  PSECURITY_DESCRIPTOR pSD = NULL;
+  LUID luidUnused;
+  AUTHZ_ACCESS_REQUEST  request;
+  AUTHZ_ACCESS_REPLY    reply;
+  DWORD authError = ERROR_SUCCESS;
+  DWORD saclResult = 0;
+  ACCESS_MASK grantedMask = 0;
+  AUTHZ_RESOURCE_MANAGER_HANDLE hManager = NULL;
+  AUTHZ_CLIENT_CONTEXT_HANDLE hAuthzToken = NULL;
+
+  ZeroMemory(&luidUnused, sizeof(luidUnused));
+  ZeroMemory(&request, sizeof(request));
+  ZeroMemory(&reply, sizeof(reply));
+
+  dwError = BuildImpersonateSecurityDescriptor(&pSD);
+  if (dwError) {
+    ReportErrorCode(L"BuildImpersonateSecurityDescriptor", dwError);
+    goto done;
+  }
+
+  request.DesiredAccess = MAXIMUM_ALLOWED;
+  reply.Error = &authError;
+  reply.SaclEvaluationResults = &saclResult;
+  reply.ResultListLength = 1;
+  reply.GrantedAccessMask = &grantedMask;
+
+  if (!AuthzInitializeResourceManager(
+        AUTHZ_RM_FLAG_NO_AUDIT,
+        NULL,  // pfnAccessCheck
+        NULL,  // pfnComputeDynamicGroups
+        NULL,  // pfnFreeDynamicGroups
+        NULL,  // szResourceManagerName
+        &hManager)) {
+    dwError = GetLastError();
+    ReportErrorCode(L"AuthzInitializeResourceManager", dwError);
+    goto done;
+  }  
+
+  if (!AuthzInitializeContextFromToken(
+        0,
+        logonHandle,
+        hManager,
+        NULL, // expiration time
+        luidUnused, // not used
+        NULL, // callback args
+        &hAuthzToken)) {
+    dwError = GetLastError();
+    ReportErrorCode(L"AuthzInitializeContextFromToken", dwError);
+    goto done;
+  }
+
+  if (!AuthzAccessCheck(
+        0,
+        hAuthzToken,
+        &request,
+        NULL,   // AuditEvent
+        pSD,
+        NULL,  // OptionalSecurityDescriptorArray
+        0,     // OptionalSecurityDescriptorCount
+        &reply,
+        NULL  // phAccessCheckResults
+        )) {
+    dwError = GetLastError();
+    ReportErrorCode(L"AuthzAccessCheck", dwError);
+    goto done;
+  }
+
+  LogDebugMessage(L"AutzAccessCheck: Error:%d sacl:%d access:%d\n",
+    authError, saclResult, grantedMask);
+  
+  if (authError != ERROR_SUCCESS) {
+    ReportErrorCode(L"AuthzAccessCheck:REPLY:1", authError);
+    dwError = authError;
+  } 
+  else if (!(grantedMask & SERVICE_IMPERSONATE_MASK)) {
+    ReportErrorCode(L"AuthzAccessCheck:REPLY:2", ERROR_ACCESS_DENIED);
+    dwError = ERROR_ACCESS_DENIED;
+  }
+
+done:  
+  if (hAuthzToken) AuthzFreeContext(hAuthzToken);
+  if (hManager) AuthzFreeResourceManager(hManager);
+  if (pSD) LocalFree(pSD);
+  return dwError;
+}
+
+//----------------------------------------------------------------------------
+// Function: CreateTaskImpl
 //
 // Description:
 //  Creates a task via a jobobject. Outputs the
 //  appropriate information to stdout on success, or stderr on failure.
-//  logonHandle may be NULL, in this case the current logon will be utilized for the 
-//  created process
+//  logonHandle may be NULL, in this case the current logon will be utilized for the 
+//  created process
 //
 // Returns:
 // ERROR_SUCCESS: On success
 // GetLastError: otherwise
-DWORD CreateTaskImpl(__in_opt HANDLE logonHandle, __in PCWSTR jobObjName,__in PWSTR cmdLine) 
+DWORD CreateTaskImpl(__in_opt HANDLE logonHandle, __in PCWSTR jobObjName,__in PCWSTR cmdLine, 
+  __in LPCWSTR userName) 
 {
-  DWORD dwErrorCode = ERROR_SUCCESS;
+  DWORD dwErrorCode = ERROR_SUCCESS;
   DWORD exitCode = EXIT_FAILURE;
-  DWORD currDirCnt = 0;
+  DWORD currDirCnt = 0;
   STARTUPINFO si;
   PROCESS_INFORMATION pi;
   HANDLE jobObject = NULL;
   JOBOBJECT_EXTENDED_LIMIT_INFORMATION jeli = { 0 };
-  void * envBlock = NULL;
-  BOOL createProcessResult = FALSE;
-
-  wchar_t* curr_dir = NULL;
-  FILE *stream = NULL;
+  void * envBlock = NULL;
+  WCHAR secureJobNameBuffer[MAX_PATH];
+  LPCWSTR secureJobName = jobObjName;
+
+  wchar_t* curr_dir = NULL;
+  FILE *stream = NULL;
+
+  if (NULL != logonHandle) {
+    dwErrorCode = ValidateImpersonateAccessCheck(logonHandle);
+    if (dwErrorCode) {
+      ReportErrorCode(L"ValidateImpersonateAccessCheck", dwErrorCode);
+      return dwErrorCode;
+    }
+
+    dwErrorCode = GetSecureJobObjectName(jobObjName, MAX_PATH, secureJobNameBuffer);
+    if (dwErrorCode) {
+      ReportErrorCode(L"GetSecureJobObjectName", dwErrorCode);
+      return dwErrorCode;
+    }
+    secureJobName = secureJobNameBuffer;
+  }
 
   // Create un-inheritable job object handle and set job object to terminate 
   // 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(NULL, jobObjName);
-  dwErrorCode = GetLastError();
-  if(jobObject == NULL || dwErrorCode ==  ERROR_ALREADY_EXISTS)
+  jobObject = CreateJobObject(NULL, secureJobName);
+  dwErrorCode = GetLastError();
+  if(jobObject == NULL || dwErrorCode ==  ERROR_ALREADY_EXISTS)
   {
-    return dwErrorCode;
+    ReportErrorCode(L"CreateJobObject", dwErrorCode);
+    return dwErrorCode;
   }
   jeli.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE;
   if(SetInformationJobObject(jobObject, 
@@ -147,102 +621,143 @@ DWORD CreateTaskImpl(__in_opt HANDLE logonHandle, __in PCWSTR jobObjName,__in PW
                              &jeli, 
                              sizeof(jeli)) == 0)
   {
-    dwErrorCode = GetLastError();
+    dwErrorCode = GetLastError();
+    ReportErrorCode(L"SetInformationJobObject", dwErrorCode);
     CloseHandle(jobObject);
-    return dwErrorCode;
-  }      
+    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)
   {
-    dwErrorCode = GetLastError();
+    dwErrorCode = GetLastError();
+    ReportErrorCode(L"AssignProcessToJobObject", dwErrorCode);
     CloseHandle(jobObject);
-    return dwErrorCode;
+    return dwErrorCode;
   }
 
   // the child JVM uses this env var to send the task OS process identifier 
   // to the TaskTracker. We pass the job object name.
   if(SetEnvironmentVariable(L"JVM_PID", jobObjName) == 0)
   {
-    dwErrorCode = GetLastError();
-    // We have to explictly Terminate, passing in the error code
-    // simply closing the job would kill our own process with success exit status
-    TerminateJobObject(jobObject, dwErrorCode);
-    return dwErrorCode;
+    dwErrorCode = GetLastError();
+    ReportErrorCode(L"SetEnvironmentVariable", dwErrorCode);
+    // We have to explictly Terminate, passing in the error code
+    // simply closing the job would kill our own process with success exit status
+    TerminateJobObject(jobObject, dwErrorCode);
+    return dwErrorCode;
   }
 
   ZeroMemory( &si, sizeof(si) );
   si.cb = sizeof(si);
   ZeroMemory( &pi, sizeof(pi) );
 
-  if( logonHandle != NULL ) {
-    // create user environment for this logon
-    if(!CreateEnvironmentBlock(&envBlock,
-                              logonHandle,
-                              TRUE )) {
-        dwErrorCode = GetLastError();
-        // We have to explictly Terminate, passing in the error code
-        // simply closing the job would kill our own process with success exit status
-        TerminateJobObject(jobObject, dwErrorCode);
-        return dwErrorCode; 
-    }
-  }
-
-  // Get the required buffer size first
-  currDirCnt = GetCurrentDirectory(0, NULL);
-  if (0 < currDirCnt) {
-    curr_dir = (wchar_t*) alloca(currDirCnt * sizeof(wchar_t));
-    assert(curr_dir);
-    currDirCnt = GetCurrentDirectory(currDirCnt, curr_dir);
-  }
-  
-  if (0 == currDirCnt) {
-     dwErrorCode = GetLastError();
-     // We have to explictly Terminate, passing in the error code
-     // simply closing the job would kill our own process with success exit status
-     TerminateJobObject(jobObject, dwErrorCode);
-     return dwErrorCode;     
-  }
-
-  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
-                  NULL,         // 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 (FALSE == createProcessResult) {
-    dwErrorCode = GetLastError();
-    if( envBlock != NULL ) {
-      DestroyEnvironmentBlock( envBlock );
-      envBlock = NULL;
-    }
-    // We have to explictly Terminate, passing in the error code
-    // simply closing the job would kill our own process with success exit status
-    TerminateJobObject(jobObject, dwErrorCode);
-
-    // This is tehnically dead code, we cannot reach this condition
-    return dwErrorCode;
+  if( logonHandle != NULL ) {
+    // create user environment for this logon
+    if(!CreateEnvironmentBlock(&envBlock,
+                              logonHandle,
+                              TRUE )) {
+        dwErrorCode = GetLastError();
+        ReportErrorCode(L"CreateEnvironmentBlock", dwErrorCode);
+        // We have to explictly Terminate, passing in the error code
+        // simply closing the job would kill our own process with success exit status
+        TerminateJobObject(jobObject, dwErrorCode);
+        return dwErrorCode; 
+    }
+  }
+
+  // Get the required buffer size first
+  currDirCnt = GetCurrentDirectory(0, NULL);
+  if (0 < currDirCnt) {
+    curr_dir = (wchar_t*) alloca(currDirCnt * sizeof(wchar_t));
+    assert(curr_dir);
+    currDirCnt = GetCurrentDirectory(currDirCnt, curr_dir);
+  }
+  
+  if (0 == currDirCnt) {
+     dwErrorCode = GetLastError();
+     ReportErrorCode(L"GetCurrentDirectory", dwErrorCode);
+     // We have to explictly Terminate, passing in the error code
+     // simply closing the job would kill our own process with success exit status
+     TerminateJobObject(jobObject, dwErrorCode);
+     return dwErrorCode;     
+  }
+
+  dwErrorCode = ERROR_SUCCESS;
+
+  if (logonHandle == NULL) {
+    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
+  
+  // 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"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;
+    }
+    // We have to explictly Terminate, passing in the error code
+    // simply closing the job would kill our own process with success exit status
+    TerminateJobObject(jobObject, dwErrorCode);
+
+    // This is tehnically dead code, we cannot reach this condition
+    return dwErrorCode;
   }
 
   CloseHandle(pi.hThread);
@@ -251,15 +766,15 @@ DWORD CreateTaskImpl(__in_opt HANDLE logonHandle, __in PCWSTR jobObjName,__in PW
   WaitForSingleObject( pi.hProcess, INFINITE );
   if(GetExitCodeProcess(pi.hProcess, &exitCode) == 0)
   {
-    dwErrorCode = GetLastError();
+    dwErrorCode = GetLastError();
   }
   CloseHandle( pi.hProcess );
 
-  if( envBlock != NULL ) {
-    DestroyEnvironmentBlock( envBlock );
-    envBlock = NULL;
-  }
-
+  if( envBlock != NULL ) {
+    DestroyEnvironmentBlock( envBlock );
+    envBlock = NULL;
+  }
+
   // Terminate job object so that all spawned processes are also killed.
   // This is needed because once this process closes the handle to the job 
   // object and none of the spawned objects have the handle open (via 
@@ -267,134 +782,133 @@ DWORD CreateTaskImpl(__in_opt HANDLE logonHandle, __in PCWSTR jobObjName,__in PW
   // program (say winutils task kill) to terminate this job object via its name.
   if(TerminateJobObject(jobObject, exitCode) == 0)
   {
-    dwErrorCode = GetLastError();
+    dwErrorCode = GetLastError();
   }
 
-  // comes here only on failure of TerminateJobObject
+  // comes here only on failure of TerminateJobObject
   CloseHandle(jobObject);
 
-  if(dwErrorCode != ERROR_SUCCESS)
+  if(dwErrorCode != ERROR_SUCCESS)
   {
-    return dwErrorCode;
+    return dwErrorCode;
   }
   return exitCode;
 }
 
 //----------------------------------------------------------------------------
-// Function: CreateTask
-//
-// Description:
-//  Creates a task via a jobobject. Outputs the
-//  appropriate information to stdout on success, or stderr on failure.
-//
-// Returns:
-// ERROR_SUCCESS: On success
-// GetLastError: otherwise
-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 );
-}
-//----------------------------------------------------------------------------
-// Function: CreateTask
-//
-// Description:
-//  Creates a task via a jobobject. Outputs the
-//  appropriate information to stdout on success, or stderr on failure.
-//
-// Returns:
-// ERROR_SUCCESS: On success
-// GetLastError: otherwise
-DWORD CreateTaskAsUser(__in PCWSTR jobObjName,__in PWSTR user, __in PWSTR pidFilePath, __in PWSTR cmdLine)
-{
-  DWORD err = ERROR_SUCCESS;
-  DWORD exitCode = EXIT_FAILURE;
-  ULONG authnPkgId;
-  HANDLE lsaHandle = INVALID_HANDLE_VALUE;
-  PROFILEINFO  pi;
-  BOOL profileIsLoaded = FALSE;
-  FILE* pidFile = NULL;
-
-  DWORD retLen = 0;
-  HANDLE logonHandle = NULL;
-
-  err = EnablePrivilege(SE_TCB_NAME);
-  if( err != ERROR_SUCCESS ) {
-    fwprintf(stdout, L"INFO: The user does not have SE_TCB_NAME.\n");
-    goto done;
-  }
-  err = EnablePrivilege(SE_ASSIGNPRIMARYTOKEN_NAME);
-  if( err != ERROR_SUCCESS ) {
-    fwprintf(stdout, L"INFO: The user does not have SE_ASSIGNPRIMARYTOKEN_NAME.\n");
-    goto done;
-  }
-  err = EnablePrivilege(SE_INCREASE_QUOTA_NAME);
-  if( err != ERROR_SUCCESS ) {
-    fwprintf(stdout, L"INFO: The user does not have SE_INCREASE_QUOTA_NAME.\n");
-    goto done;
-  }
-  err = EnablePrivilege(SE_RESTORE_NAME);
-  if( err != ERROR_SUCCESS ) {
-    fwprintf(stdout, L"INFO: The user does not have SE_RESTORE_NAME.\n");
-    goto done;
-  }
-
-  err = RegisterWithLsa(LOGON_PROCESS_NAME ,&lsaHandle);
-  if( err != ERROR_SUCCESS ) goto done;
-
-  err = LookupKerberosAuthenticationPackageId( lsaHandle, &authnPkgId );
-  if( err != ERROR_SUCCESS ) goto done;
-
-  err =  CreateLogonForUser(lsaHandle,
-    LOGON_PROCESS_NAME, 
-    TOKEN_SOURCE_NAME,
-    authnPkgId, 
-    user, 
-    &logonHandle); 
-  if( err != ERROR_SUCCESS ) goto done;
-
-  err = LoadUserProfileForLogon(logonHandle, &pi);
-  if( err != ERROR_SUCCESS ) goto done;
-  profileIsLoaded = TRUE; 
-
-  // Create the PID file
-
-  if (!(pidFile = _wfopen(pidFilePath, "w"))) {
-      err = GetLastError();
-      goto done;
-  }
-
-  if (0 > fprintf_s(pidFile, "%ls", jobObjName)) {
-    err = GetLastError();
-  }
-  
-  fclose(pidFile);
-    
-  if (err != ERROR_SUCCESS) {
-    goto done;
-  }
-  
-  err = CreateTaskImpl(logonHandle, jobObjName, cmdLine);
-
-done:	
-  if( profileIsLoaded ) {
-    UnloadProfileForLogon( logonHandle, &pi );
-    profileIsLoaded = FALSE;
-  }
-  if( logonHandle != NULL ) {
-    CloseHandle(logonHandle);
-  }
-
-  if (INVALID_HANDLE_VALUE != lsaHandle) {
-    UnregisterWithLsa(lsaHandle);
-  }
-
-  return err;
-}
-
-
-//----------------------------------------------------------------------------
-// Function: IsTaskAlive
+// Function: CreateTask
+//
+// Description:
+//  Creates a task via a jobobject. Outputs the
+//  appropriate information to stdout on success, or stderr on failure.
+//
+// Returns:
+// ERROR_SUCCESS: On success
+// GetLastError: otherwise
+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);
+}
+
+//----------------------------------------------------------------------------
+// Function: CreateTaskAsUser
+//
+// Description:
+//  Creates a task via a jobobject. Outputs the
+//  appropriate information to stdout on success, or stderr on failure.
+//
+// Returns:
+// ERROR_SUCCESS: On success
+// GetLastError: otherwise
+DWORD CreateTaskAsUser(__in PCWSTR jobObjName,
+  __in PCWSTR user, __in PCWSTR pidFilePath, __in PCWSTR cmdLine)
+{
+  DWORD err = ERROR_SUCCESS;
+  DWORD exitCode = EXIT_FAILURE;
+  ULONG authnPkgId;
+  HANDLE lsaHandle = INVALID_HANDLE_VALUE;
+  PROFILEINFO  pi;
+  BOOL profileIsLoaded = FALSE;
+  FILE* pidFile = NULL;
+  DWORD retLen = 0;
+  HANDLE logonHandle = NULL;
+
+  err = EnableImpersonatePrivileges();
+  if( err != ERROR_SUCCESS ) {
+    ReportErrorCode(L"EnableImpersonatePrivileges", err);
+    goto done;
+  }
+
+  err = RegisterWithLsa(LOGON_PROCESS_NAME ,&lsaHandle);
+  if( err != ERROR_SUCCESS ) {
+    ReportErrorCode(L"RegisterWithLsa", err);
+    goto done;
+  }
+
+  err = LookupKerberosAuthenticationPackageId( lsaHandle, &authnPkgId );
+  if( err != ERROR_SUCCESS ) {
+    ReportErrorCode(L"LookupKerberosAuthenticationPackageId", err);
+    goto done;
+  }
+
+  err =  CreateLogonTokenForUser(lsaHandle,
+    LOGON_PROCESS_NAME, 
+    TOKEN_SOURCE_NAME,
+    authnPkgId, 
+    user, 
+    &logonHandle); 
+  if( err != ERROR_SUCCESS ) {
+    ReportErrorCode(L"CreateLogonTokenForUser", err);
+    goto done;
+  }
+
+  err = LoadUserProfileForLogon(logonHandle, &pi);
+  if( err != ERROR_SUCCESS ) {
+    ReportErrorCode(L"LoadUserProfileForLogon", err);
+    goto done;
+  }
+  profileIsLoaded = TRUE; 
+
+  // Create the PID file
+
+  if (!(pidFile = _wfopen(pidFilePath, "w"))) {
+      err = GetLastError();
+      ReportErrorCode(L"_wfopen:pidFilePath", err);
+      goto done;
+  }
+
+  if (0 > fprintf_s(pidFile, "%ls", jobObjName)) {
+    err = GetLastError();
+  }
+  
+  fclose(pidFile);
+    
+  if (err != ERROR_SUCCESS) {
+      ReportErrorCode(L"fprintf_s:pidFilePath", err);
+      goto done;
+  }
+
+  err = CreateTaskImpl(logonHandle, jobObjName, cmdLine, user);
+
+done: 
+  if( profileIsLoaded ) {
+    UnloadProfileForLogon( logonHandle, &pi );
+    profileIsLoaded = FALSE;
+  }
+  if( logonHandle != NULL ) {
+    CloseHandle(logonHandle);
+  }
+
+  if (INVALID_HANDLE_VALUE != lsaHandle) {
+    UnregisterWithLsa(lsaHandle);
+  }
+
+  return err;
+}
+
+//----------------------------------------------------------------------------
+// Function: IsTaskAlive
 //
 // Description:
 //  Checks if a task is alive via a jobobject. Outputs the
@@ -403,15 +917,32 @@ done:
 // Returns:
 // ERROR_SUCCESS: On success
 // GetLastError: otherwise
-DWORD IsTaskAlive(const WCHAR* jobObjName, int* isAlive, int* procsInJob)
+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)
   {
@@ -454,40 +985,7 @@ DWORD IsTaskAlive(const WCHAR* jobObjName, int* isAlive, int* procsInJob)
 }
 
 //----------------------------------------------------------------------------
-// Function: KillTask
-//
-// Description:
-//  Kills a task via a jobobject. Outputs the
-//  appropriate information to stdout on success, or stderr on failure.
-//
-// Returns:
-// ERROR_SUCCESS: On success
-// GetLastError: otherwise
-DWORD KillTask(PCWSTR jobObjName)
-{
-  HANDLE jobObject = OpenJobObject(JOB_OBJECT_TERMINATE, FALSE, jobObjName);
-  if(jobObject == NULL)
-  {
-    DWORD err = GetLastError();
-    if(err == ERROR_FILE_NOT_FOUND)
-    {
-      // job object does not exist. assume its not alive
-      return ERROR_SUCCESS;
-    }
-    return err;
-  }
-
-  if(TerminateJobObject(jobObject, KILLED_PROCESS_EXIT_CODE) == 0)
-  {
-    return GetLastError();
-  }
-  CloseHandle(jobObject);
-
-  return ERROR_SUCCESS;
-}
-
-//----------------------------------------------------------------------------
-// Function: PrintTaskProcessList
+// Function: PrintTaskProcessList
 //
 // Description:
 // Prints resource usage of all processes in the task jobobject
@@ -495,12 +993,26 @@ DWORD KillTask(PCWSTR jobObjName)
 // Returns:
 // ERROR_SUCCESS: On success
 // GetLastError: otherwise
-DWORD PrintTaskProcessList(const WCHAR* jobObjName)
+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();
@@ -579,21 +1091,21 @@ int Task(__in int argc, __in_ecount(argc) wchar_t *argv[])
 {
   DWORD dwErrorCode = ERROR_SUCCESS;
   TaskCommandOption command = TaskInvalid;
-  wchar_t* cmdLine = NULL;
-  wchar_t buffer[16*1024] = L""; // 32K max command line
-  size_t charCountBufferLeft = sizeof
(buffer)/sizeof(wchar_t);
-  int crtArgIndex = 0;
-  size_t argLen = 0;
-  size_t wscatErr = 0;
-  wchar_t* insertHere = NULL;
-
-  enum {
-               ARGC_JOBOBJECTNAME = 2,
-               ARGC_USERNAME,
-               ARGC_PIDFILE,
-               ARGC_COMMAND,
-               ARGC_COMMAND_ARGS
-       };
+  wchar_t* cmdLine = NULL;
+  wchar_t buffer[16*1024] = L""; // 32K max command line
+  size_t charCountBufferLeft = sizeof(buffer)/sizeof(wchar_t);
+  int crtArgIndex = 0;
+  size_t argLen = 0;
+  size_t wscatErr = 0;
+  wchar_t* insertHere = NULL;
+
+  enum {
+               ARGC_JOBOBJECTNAME = 2,
+               ARGC_USERNAME,
+               ARGC_PIDFILE,
+               ARGC_COMMAND,
+               ARGC_COMMAND_ARGS
+       };
 
   if (!ParseCommandLine(argc, argv, &command)) {
     dwErrorCode = ERROR_INVALID_COMMAND_LINE;
@@ -607,57 +1119,57 @@ int Task(__in int argc, __in_ecount(argc) wchar_t *argv[])
   {
     // Create the task jobobject
     //
-    dwErrorCode = CreateTask(argv[2], argv[3]);
-    if (dwErrorCode != ERROR_SUCCESS)
-    {
-      ReportErrorCode(L"CreateTask", dwErrorCode);
-      goto TaskExit;
-    }
-  } else if (command == TaskCreateAsUser)
-  {
-    // Create the task jobobject as a domain user
-    // createAsUser accepts an open list of arguments. All arguments after the command are
-    // to be passed as argumrnts to the command itself.Here we're concatenating all 
-    // arguments after the command into a single arg entry.
-    //
-    cmdLine = argv[ARGC_COMMAND];
-    if (argc > ARGC_COMMAND_ARGS) {
-        crtArgIndex = ARGC_COMMAND;
-        insertHere = buffer;
-        while (crtArgIndex < argc) {
-            argLen = wcslen(argv[crtArgIndex]);
-            wscatErr = wcscat_s(insertHere, charCountBufferLeft, argv[crtArgIndex]);
-            switch (wscatErr) {
-            case 0:
-              // 0 means success;
-              break;
-            case EINVAL:
-              dwErrorCode = ERROR_INVALID_PARAMETER;
-              goto TaskExit;
-            case ERANGE:
-              dwErrorCode = ERROR_INSUFFICIENT_BUFFER;
-              goto TaskExit;
-            default:
-              // This case is not MSDN documented.
-              dwErrorCode = ERROR_GEN_FAILURE;
-              goto TaskExit;
-            }
-            insertHere += argLen;
-            charCountBufferLeft -= argLen;
-            insertHere[0] = L' ';
-            insertHere += 1;
-            charCountBufferLeft -= 1;
-            insertHere[0] = 0;
-            ++crtArgIndex;
-        }
-        cmdLine = buffer;
-    }
-
-    dwErrorCode = CreateTaskAsUser(
-      argv[ARGC_JOBOBJECTNAME], argv[ARGC_USERNAME], argv[ARGC_PIDFILE], cmdLine);
+    dwErrorCode = CreateTask(argv[2], argv[3]);
+    if (dwErrorCode != ERROR_SUCCESS)
+    {
+      ReportErrorCode(L"CreateTask", dwErrorCode);
+      goto TaskExit;
+    }
+  } else if (command == TaskCreateAsUser)
+  {
+    // Create the task jobobject as a domain user
+    // createAsUser accepts an open list of arguments. All arguments after the command are
+    // to be passed as argumrnts to the command itself.Here we're concatenating all 
+    // arguments after the command into a single arg entry.
+    //
+    cmdLine = argv[ARGC_COMMAND];
+    if (argc > ARGC_COMMAND_ARGS) {
+        crtArgIndex = ARGC_COMMAND;
+        insertHere = buffer;
+        while (crtArgIndex < argc) {
+            argLen = wcslen(argv[crtArgIndex]);
+            wscatErr = wcscat_s(insertHere, charCountBufferLeft, argv[crtArgIndex]);
+            switch (wscatErr) {
+            case 0:
+              // 0 means success;
+              break;
+            case EINVAL:
+              dwErrorCode = ERROR_INVALID_PARAMETER;
+              goto TaskExit;
+            case ERANGE:
+              dwErrorCode = ERROR_INSUFFICIENT_BUFFER;
+              goto TaskExit;
+            default:
+              // This case is not MSDN documented.
+              dwErrorCode = ERROR_GEN_FAILURE;
+              goto TaskExit;
+            }
+            insertHere += argLen;
+            charCountBufferLeft -= argLen;
+            insertHere[0] = L' ';
+            insertHere += 1;
+            charCountBufferLeft -= 1;
+            insertHere[0] = 0;
+            ++crtArgIndex;
+        }
+        cmdLine = buffer;
+    }
+
+    dwErrorCode = CreateTaskAsUser(
+      argv[ARGC_JOBOBJECTNAME], argv[ARGC_USERNAME], argv[ARGC_PIDFILE], cmdLine);
     if (dwErrorCode != ERROR_SUCCESS)
     {
-      ReportErrorCode(L"CreateTaskAsUser", dwErrorCode);
+      ReportErrorCode(L"CreateTaskAsUser", dwErrorCode);
       goto TaskExit;
     }
   } else if (command == TaskIsAlive)
@@ -666,10 +1178,10 @@ int Task(__in int argc, __in_ecount(argc) wchar_t *argv[])
     //
     int isAlive;
     int numProcs;
-    dwErrorCode = IsTaskAlive(argv[2], &isAlive, &numProcs);
+    dwErrorCode = IsTaskAlive(argv[2], &isAlive, &numProcs);
     if (dwErrorCode != ERROR_SUCCESS)
     {
-      ReportErrorCode(L"IsTaskAlive", dwErrorCode);
+      ReportErrorCode(L"IsTaskAlive", dwErrorCode);
       goto TaskExit;
     }
 
@@ -681,27 +1193,27 @@ int Task(__in int argc, __in_ecount(argc) wchar_t *argv[])
     else
     {
       dwErrorCode = ERROR_TASK_NOT_ALIVE;
-      ReportErrorCode(L"IsTaskAlive returned false", dwErrorCode);
+      ReportErrorCode(L"IsTaskAlive returned false", dwErrorCode);
       goto TaskExit;
     }
   } else if (command == TaskKill)
   {
     // Check if task jobobject
     //
-    dwErrorCode = KillTask(argv[2]);
+    dwErrorCode = KillTask(argv[2]);
     if (dwErrorCode != ERROR_SUCCESS)
     {
-      ReportErrorCode(L"KillTask", dwErrorCode);
+      ReportErrorCode(L"KillTask", dwErrorCode);
       goto TaskExit;
     }
   } else if (command == TaskProcessList)
   {
     // Check if task jobobject
     //
-    dwErrorCode = PrintTaskProcessList(argv[2]);
+    dwErrorCode = PrintTaskProcessList(argv[2]);
     if (dwErrorCode != ERROR_SUCCESS)
     {
-      ReportErrorCode(L"PrintTaskProcessList", dwErrorCode);
+      ReportErrorCode(L"PrintTaskProcessList", dwErrorCode);
       goto TaskExit;
     }
   } else
@@ -712,6 +1224,7 @@ int Task(__in int argc, __in_ecount(argc) wchar_t *argv[])
   }
 
 TaskExit:
+  ReportErrorCode(L"TaskExit:", dwErrorCode);
   return dwErrorCode;
 }
 
@@ -722,12 +1235,12 @@ void TaskUsage()
   // ProcessTree.isSetsidSupported()
   fwprintf(stdout, L"\
     Usage: task create [TASKNAME] [COMMAND_LINE] |\n\
-          task createAsUser [TASKNAME] [USERNAME] [PIDFILE] [COMMAND_LINE] |\n\
+          task createAsUser [TASKNAME] [USERNAME] [PIDFILE] [COMMAND_LINE] |\n\
           task isAlive [TASKNAME] |\n\
           task kill [TASKNAME]\n\
           task processList [TASKNAME]\n\
     Creates a new task jobobject with taskname\n\
-    Creates a new task jobobject with taskname as the user provided\n\
+    Creates a new task jobobject with taskname as the user provided\n\
     Checks if task jobobject is alive\n\
     Kills task jobobject\n\
     Prints to stdout a list of processes in the task\n\

http://git-wip-us.apache.org/repos/asf/hadoop/blob/29d0164e/hadoop-common-project/hadoop-common/src/main/winutils/winutils.mc
----------------------------------------------------------------------
diff --git a/hadoop-common-project/hadoop-common/src/main/winutils/winutils.mc b/hadoop-common-project/hadoop-common/src/main/winutils/winutils.mc
new file mode 100644
index 0000000..2add064
--- /dev/null
+++ b/hadoop-common-project/hadoop-common/src/main/winutils/winutils.mc
@@ -0,0 +1,64 @@
+;/*
+; * Licensed to the Apache Software Foundation (ASF) under one
+; * or more contributor license agreements.  See the NOTICE file
+; * distributed with this work for additional information
+; * regarding copyright ownership.  The ASF licenses this file
+; * to you under the Apache License, Version 2.0 (the
+; * "License"); you may not use this file except in compliance
+; * with the License.  You may obtain a copy of the License at
+; *
+; *     http://www.apache.org/licenses/LICENSE-2.0
+; *
+; * Unless required by applicable law or agreed to in writing, software
+; * distributed under the License is distributed on an "AS IS" BASIS,
+; * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+; * See the License for the specific language governing permissions and
+; * limitations under the License.
+; */
+
+; // winutils.mc 
+
+; // EventLog messages for Hadoop winutils service.
+
+
+LanguageNames=(English=0x409:MSG00409)
+
+
+; // The following are the categories of events.
+
+MessageIdTypedef=WORD
+
+MessageId=0x1
+SymbolicName=SERVICE_CATEGORY
+Language=English
+Service Events
+.
+
+MessageId=0x2
+SymbolicName=LOG_CATEGORY
+Language=English
+Task Events
+.
+
+; // The following are the message definitions.
+
+MessageIdTypedef=DWORD
+
+MessageId=0x80
+SymbolicName=MSG_CHECK_ERROR
+Language=English
+%1. Error %2: %3.
+.
+
+MessageId=0x100
+SymbolicName=MSG_RPC_SERVICE_HAS_STARTED
+Language=English
+The LPC server is listenning.
+.
+
+MessageId=0x200
+SymbolicName=MSG_RPC_SERVICE_HAS_STOPPED
+Language=English
+The LPC server has stopped listenning.
+.
+

http://git-wip-us.apache.org/repos/asf/hadoop/blob/29d0164e/hadoop-common-project/hadoop-common/src/main/winutils/winutils.sln
----------------------------------------------------------------------
diff --git a/hadoop-common-project/hadoop-common/src/main/winutils/winutils.sln b/hadoop-common-project/hadoop-common/src/main/winutils/winutils.sln
index d4e019e..d2784b8 100644
--- a/hadoop-common-project/hadoop-common/src/main/winutils/winutils.sln
+++ b/hadoop-common-project/hadoop-common/src/main/winutils/winutils.sln
@@ -26,26 +26,16 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libwinutils", "libwinutils.
 EndProject
 Global
 	GlobalSection(SolutionConfigurationPlatforms) = preSolution
-		Debug|Win32 = Debug|Win32
 		Debug|x64 = Debug|x64
-		Release|Win32 = Release|Win32
 		Release|x64 = Release|x64
 	EndGlobalSection
 	GlobalSection(ProjectConfigurationPlatforms) = postSolution
-		{D94B3BD7-39CC-47A0-AE9A-353FDE506F33}.Debug|Win32.ActiveCfg = Debug|x64
-		{D94B3BD7-39CC-47A0-AE9A-353FDE506F33}.Debug|Win32.Build.0 = Debug|x64
-		{D94B3BD7-39CC-47A0-AE9A-353FDE506F33}.Debug|x64.ActiveCfg = Debug|x64
-		{D94B3BD7-39CC-47A0-AE9A-353FDE506F33}.Debug|x64.Build.0 = Debug|x64
-		{D94B3BD7-39CC-47A0-AE9A-353FDE506F33}.Release|Win32.ActiveCfg = Release|Win32
-		{D94B3BD7-39CC-47A0-AE9A-353FDE506F33}.Release|Win32.Build.0 = Release|Win32
+		{D94B3BD7-39CC-47A0-AE9A-353FDE506F33}.Debug|x64.ActiveCfg = Release|x64
+		{D94B3BD7-39CC-47A0-AE9A-353FDE506F33}.Debug|x64.Build.0 = Release|x64
 		{D94B3BD7-39CC-47A0-AE9A-353FDE506F33}.Release|x64.ActiveCfg = Release|x64
 		{D94B3BD7-39CC-47A0-AE9A-353FDE506F33}.Release|x64.Build.0 = Release|x64
-		{12131AA7-902E-4A6D-9CE3-043261D22A12}.Debug|Win32.ActiveCfg = Debug|x64
-		{12131AA7-902E-4A6D-9CE3-043261D22A12}.Debug|Win32.Build.0 = Debug|x64
-		{12131AA7-902E-4A6D-9CE3-043261D22A12}.Debug|x64.ActiveCfg = Debug|x64
-		{12131AA7-902E-4A6D-9CE3-043261D22A12}.Debug|x64.Build.0 = Debug|x64
-		{12131AA7-902E-4A6D-9CE3-043261D22A12}.Release|Win32.ActiveCfg = Release|Win32
-		{12131AA7-902E-4A6D-9CE3-043261D22A12}.Release|Win32.Build.0 = Release|Win32
+		{12131AA7-902E-4A6D-9CE3-043261D22A12}.Debug|x64.ActiveCfg = Release|x64
+		{12131AA7-902E-4A6D-9CE3-043261D22A12}.Debug|x64.Build.0 = Release|x64
 		{12131AA7-902E-4A6D-9CE3-043261D22A12}.Release|x64.ActiveCfg = Release|x64
 		{12131AA7-902E-4A6D-9CE3-043261D22A12}.Release|x64.Build.0 = Release|x64
 	EndGlobalSection

http://git-wip-us.apache.org/repos/asf/hadoop/blob/29d0164e/hadoop-common-project/hadoop-common/src/main/winutils/winutils.vcxproj
----------------------------------------------------------------------
diff --git a/hadoop-common-project/hadoop-common/src/main/winutils/winutils.vcxproj b/hadoop-common-project/hadoop-common/src/main/winutils/winutils.vcxproj
index 5b9a195..d736084 100644
--- a/hadoop-common-project/hadoop-common/src/main/winutils/winutils.vcxproj
+++ b/hadoop-common-project/hadoop-common/src/main/winutils/winutils.vcxproj
@@ -19,18 +19,10 @@
 
 <Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
   <ItemGroup Label="ProjectConfigurations">
-    <ProjectConfiguration Include="Debug|Win32">
-      <Configuration>Debug</Configuration>
-      <Platform>Win32</Platform>
-    </ProjectConfiguration>
     <ProjectConfiguration Include="Debug|x64">
       <Configuration>Debug</Configuration>
       <Platform>x64</Platform>
     </ProjectConfiguration>
-    <ProjectConfiguration Include="Release|Win32">
-      <Configuration>Release</Configuration>
-      <Platform>Win32</Platform>
-    </ProjectConfiguration>
     <ProjectConfiguration Include="Release|x64">
       <Configuration>Release</Configuration>
       <Platform>x64</Platform>
@@ -42,22 +34,11 @@
     <RootNamespace>winutils</RootNamespace>
   </PropertyGroup>
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
-  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
-    <ConfigurationType>Application</ConfigurationType>
-    <UseDebugLibraries>true</UseDebugLibraries>
-    <CharacterSet>Unicode</CharacterSet>
-  </PropertyGroup>
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
     <ConfigurationType>Application</ConfigurationType>
     <UseDebugLibraries>true</UseDebugLibraries>
     <CharacterSet>Unicode</CharacterSet>
   </PropertyGroup>
-  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
-    <ConfigurationType>Application</ConfigurationType>
-    <UseDebugLibraries>false</UseDebugLibraries>
-    <WholeProgramOptimization>true</WholeProgramOptimization>
-    <CharacterSet>Unicode</CharacterSet>
-  </PropertyGroup>
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
     <ConfigurationType>Application</ConfigurationType>
     <UseDebugLibraries>false</UseDebugLibraries>
@@ -67,15 +48,9 @@
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
   <ImportGroup Label="ExtensionSettings">
   </ImportGroup>
-  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
-    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
-  </ImportGroup>
   <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
     <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
   </ImportGroup>
-  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
-    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
-  </ImportGroup>
   <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
     <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
   </ImportGroup>
@@ -83,57 +58,32 @@
   <PropertyGroup>
     <IncludePath>include;$(IncludePath)</IncludePath>
   </PropertyGroup>
-  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
-    <LinkIncremental>true</LinkIncremental>
-  </PropertyGroup>
-  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
-    <LinkIncremental>true</LinkIncremental>
-    <OutDir />
-    <IntDir>..\..\..\target\winutils\$(Configuration)\</IntDir>
-  </PropertyGroup>
-  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
-    <LinkIncremental>false</LinkIncremental>
-  </PropertyGroup>
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
     <LinkIncremental>false</LinkIncremental>
-    <IntDir>..\..\..\target\winutils\$(Platform)\$(Configuration)\</IntDir>
-    <OutDir>..\..\..\target\bin\</OutDir>
   </PropertyGroup>
-  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
-    <ClCompile>
-      <PrecompiledHeader>
-      </PrecompiledHeader>
-      <WarningLevel>Level3</WarningLevel>
-      <Optimization>Disabled</Optimization>
-      <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
-    </ClCompile>
-    <Link>
-      <SubSystem>Console</SubSystem>
-      <GenerateDebugInformation>true</GenerateDebugInformation>
-    </Link>
-  </ItemDefinitionGroup>
   <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
     <ClCompile>
       <PrecompiledHeader>
       </PrecompiledHeader>
       <WarningLevel>Level4</WarningLevel>
       <Optimization>Disabled</Optimization>
-      <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <PreprocessorDefinitions>WIN32;_CONSOLE;_DEBUG;_UNICODE;UNICODE;WSCE_CONFIG_DIR=$(WsceConfigDir);WSCE_CONFIG_FILE=$(WsceConfigFile);%(PreprocessorDefinitions)</PreprocessorDefinitions>
     </ClCompile>
     <Link>
       <SubSystem>Console</SubSystem>
       <GenerateDebugInformation>true</GenerateDebugInformation>
     </Link>
   </ItemDefinitionGroup>
-  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
     <ClCompile>
       <WarningLevel>Level3</WarningLevel>
       <PrecompiledHeader>
       </PrecompiledHeader>
-      <Optimization>MaxSpeed</Optimization>
+      <!-- <Optimization>MaxSpeed</Optimization> -->
+      <Optimization>Disabled</Optimization>
       <FunctionLevelLinking>true</FunctionLevelLinking>
       <IntrinsicFunctions>true</IntrinsicFunctions>
-      <PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <PreprocessorDefinitions>WIN32;_CONSOLE;NDEBUG;_UNICODE;UNICODE;WSCE_CONFIG_DIR=$(WsceConfigDir);WSCE_CONFIG_FILE=$(WsceConfigFile);%(PreprocessorDefinitions)</PreprocessorDefinitions>
     </ClCompile>
     <Link>
       <SubSystem>Console</SubSystem>
@@ -142,24 +92,40 @@
       <OptimizeReferences>true</OptimizeReferences>
     </Link>
   </ItemDefinitionGroup>
-  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+  <ItemDefinitionGroup>
     <ClCompile>
-      <WarningLevel>Level3</WarningLevel>
-      <PrecompiledHeader>
-      </PrecompiledHeader>
-      <Optimization>MaxSpeed</Optimization>
-      <FunctionLevelLinking>true</FunctionLevelLinking>
-      <IntrinsicFunctions>true</IntrinsicFunctions>
-      <PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <AdditionalIncludeDirectories>$(IntermediateOutputPath)</AdditionalIncludeDirectories>
     </ClCompile>
-    <Link>
-      <SubSystem>Console</SubSystem>
-      <GenerateDebugInformation>true</GenerateDebugInformation>
-      <EnableCOMDATFolding>true</EnableCOMDATFolding>
-      <OptimizeReferences>true</OptimizeReferences>
-    </Link>
+    <CustomBuildStep>
+      <Message>Compiling Messages</Message>
+      <Command>mc.exe $(TargetName).mc -z $(TargetName)_msg -r $(IntermediateOutputPath) -h $(IntermediateOutputPath) -U</Command>
+      <Outputs>$(IntermediateOutputPath)$(TargetName)_msg.rc;$(IntermediateOutputPath)$(TargetName)_msg.h</Outputs>
+    </CustomBuildStep>
+    <Midl>
+      <ApplicationConfigurationMode>true</ApplicationConfigurationMode>
+      <TargetEnvironment>X64</TargetEnvironment>
+      <OutputDirectory>$(IntermediateOutputPath)</OutputDirectory>
+      <GenerateStublessProxies>true</GenerateStublessProxies>
+      <ValidateAllParameters>true</ValidateAllParameters>
+      <WarnAsError>true</WarnAsError>
+      <WarningLevel>2</WarningLevel>
+    </Midl>
   </ItemDefinitionGroup>
+  <PropertyGroup>
+    <CustomBuildAfterTargets>Midl</CustomBuildAfterTargets>
+    <CustomBuildBeforeTargets>ClCompile,ResourceCompile</CustomBuildBeforeTargets>
+  </PropertyGroup>
+  <ItemGroup>
+    <Midl Include="hadoopwinutilsvc.idl" />
+  </ItemGroup>
+  <ItemGroup>
+    <ResourceCompile Include="$(IntermediateOutputPath)$(TargetName)_msg.rc" />
+  </ItemGroup>
+  <ItemGroup>
+    <ClCompile Include="$(IntermediateOutputPath)\hadoopwinutilsvc_s.c" />
+  </ItemGroup>
   <ItemGroup>
+    <ClCompile Include="service.c" />
     <ClCompile Include="readlink.c" />
     <ClCompile Include="symlink.c" />
     <ClCompile Include="systeminfo.c" />
@@ -179,4 +145,4 @@
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
   <ImportGroup Label="ExtensionTargets">
   </ImportGroup>
-</Project>
\ No newline at end of file
+</Project>

http://git-wip-us.apache.org/repos/asf/hadoop/blob/29d0164e/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-core/src/main/java/org/apache/hadoop/mapreduce/util/ProcessTree.java
----------------------------------------------------------------------
diff --git a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-core/src/main/java/org/apache/hadoop/mapreduce/util/ProcessTree.java b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-core/src/main/java/org/apache/hadoop/mapreduce/util/ProcessTree.java
index 2f8b84d..1e2d16e 100644
--- a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-core/src/main/java/org/apache/hadoop/mapreduce/util/ProcessTree.java
+++ b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-core/src/main/java/org/apache/hadoop/mapreduce/util/ProcessTree.java
@@ -296,7 +296,7 @@ public class ProcessTree {
       return false;
     } catch (IOException ioe) {
       LOG.warn("Error executing shell command "
-          + Arrays.toString(shexec.getExecString()) + ioe);
+          + shexec.toString() + ioe);
       return false;
     }
     return (shexec.getExitCode() == 0 ? true : false);
@@ -321,7 +321,7 @@ public class ProcessTree {
       return false;
     } catch (IOException ioe) {
       LOG.warn("Error executing shell command "
-          + Arrays.toString(shexec.getExecString()) + ioe);
+          + shexec.toString() + ioe);
       return false;
     }
     return (shexec.getExitCode() == 0 ? true : false);

http://git-wip-us.apache.org/repos/asf/hadoop/blob/29d0164e/hadoop-yarn-project/CHANGES.txt
----------------------------------------------------------------------
diff --git a/hadoop-yarn-project/CHANGES.txt b/hadoop-yarn-project/CHANGES.txt
index df22042..d44e1ca 100644
--- a/hadoop-yarn-project/CHANGES.txt
+++ b/hadoop-yarn-project/CHANGES.txt
@@ -117,6 +117,9 @@ Release 2.6.0 - UNRELEASED
     YARN-1972. Added a secure container-executor for Windows. (Remus Rusanu via
     vinodkv)
 
+    YARN-2198. Remove the need to run NodeManager as privileged account for
+    Windows Secure Container Executor. (Remus Rusanu via jianhe)
+
   IMPROVEMENTS
 
     YARN-2242. Improve exception information on AM launch crashes. (Li Lu 

http://git-wip-us.apache.org/repos/asf/hadoop/blob/29d0164e/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/ContainerExecutor.java
----------------------------------------------------------------------
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/ContainerExecutor.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/ContainerExecutor.java
index f5e63ba..3b866d3 100644
--- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/ContainerExecutor.java
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/ContainerExecutor.java
@@ -79,19 +79,23 @@ public abstract class ContainerExecutor implements Configurable {
   public abstract void init() throws IOException;
 
   /**
-   * On Windows the ContainerLaunch creates a temporary empty jar to workaround the CLASSPATH length
-   * In a  secure cluster this jar must be localized so that the container has access to it
+   * On Windows the ContainerLaunch creates a temporary special jar manifest of 
+   * other jars to workaround the CLASSPATH length. In a  secure cluster this 
+   * jar must be localized so that the container has access to it. 
    * This function localizes on-demand the jar.
    * 
    * @param classPathJar
    * @param owner
    * @throws IOException
    */
-  public void localizeClasspathJar(Path classPathJar, String owner) throws IOException {
-    // For the default container this is a no-op
-    // The WindowsSecureContainerExecutor overrides this
+  public Path localizeClasspathJar(Path classPathJar, Path pwd, String owner) 
+      throws IOException {
+    // Non-secure executor simply use the classpath created 
+    // in the NM fprivate folder
+    return classPathJar;
   }
-
+  
+  
   /**
    * Prepare the environment for containers in this application to execute.
    * For $x in local.dirs
@@ -105,14 +109,13 @@ public abstract class ContainerExecutor implements Configurable {
    * @param appId id of the application
    * @param nmPrivateContainerTokens path to localized credentials, rsrc by NM
    * @param nmAddr RPC address to contact NM
-   * @param localDirs nm-local-dirs
-   * @param logDirs nm-log-dirs
+   * @param dirsHandler NM local dirs service, for nm-local-dirs and nm-log-dirs
    * @throws IOException For most application init failures
    * @throws InterruptedException If application init thread is halted by NM
    */
   public abstract void startLocalizer(Path nmPrivateContainerTokens,
       InetSocketAddress nmAddr, String user, String appId, String locId,
-      List<String> localDirs, List<String> logDirs)
+      LocalDirsHandlerService dirsHandler)
     throws IOException, InterruptedException;
 
 
@@ -132,8 +135,8 @@ public abstract class ContainerExecutor implements Configurable {
    */
   public abstract int launchContainer(Container container,
       Path nmPrivateContainerScriptPath, Path nmPrivateTokensPath,
-      String user, String appId, Path containerWorkDir, List<String> localDirs,
-      List<String> logDirs) throws IOException;
+      String user, String appId, Path containerWorkDir, 
+      List<String> localDirs, List<String> logDirs) throws IOException;
 
   public abstract boolean signalContainer(String user, String pid,
       Signal signal)

http://git-wip-us.apache.org/repos/asf/hadoop/blob/29d0164e/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/DefaultContainerExecutor.java
----------------------------------------------------------------------
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/DefaultContainerExecutor.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/DefaultContainerExecutor.java
index 76603ca..3e212bf 100644
--- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/DefaultContainerExecutor.java
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/DefaultContainerExecutor.java
@@ -19,6 +19,7 @@
 package org.apache.hadoop.yarn.server.nodemanager;
 
 import com.google.common.base.Optional;
+
 import static org.apache.hadoop.fs.CreateFlag.CREATE;
 import static org.apache.hadoop.fs.CreateFlag.OVERWRITE;
 
@@ -32,9 +33,11 @@ import java.util.Arrays;
 import java.util.EnumSet;
 import java.util.List;
 import java.util.Random;
+import java.util.Map;
 
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
+import org.apache.hadoop.conf.Configuration;
 import org.apache.hadoop.fs.FileContext;
 import org.apache.hadoop.fs.Path;
 import org.apache.hadoop.fs.UnsupportedFileSystemException;
@@ -42,6 +45,7 @@ import org.apache.hadoop.fs.permission.FsPermission;
 import org.apache.hadoop.io.IOUtils;
 import org.apache.hadoop.util.Shell;
 import org.apache.hadoop.util.Shell.ExitCodeException;
+import org.apache.hadoop.util.Shell.CommandExecutor;
 import org.apache.hadoop.util.Shell.ShellCommandExecutor;
 import org.apache.hadoop.util.StringUtils;
 import org.apache.hadoop.yarn.api.records.ContainerId;
@@ -92,13 +96,16 @@ public class DefaultContainerExecutor extends ContainerExecutor {
   @Override
   public synchronized void startLocalizer(Path nmPrivateContainerTokensPath,
       InetSocketAddress nmAddr, String user, String appId, String locId,
-      List<String> localDirs, List<String> logDirs)
+      LocalDirsHandlerService dirsHandler)
       throws IOException, InterruptedException {
 
+    List<String> localDirs = dirsHandler.getLocalDirs();
+    List<String> logDirs = dirsHandler.getLogDirs();
+    
     ContainerLocalizer localizer =
         new ContainerLocalizer(lfs, user, appId, locId, getPaths(localDirs),
             RecordFactoryProvider.getRecordFactory(getConf()));
-
+    
     createUserLocalDirs(localDirs, user);
     createUserCacheDirs(localDirs, user);
     createAppDirs(localDirs, user, appId);
@@ -120,9 +127,9 @@ public class DefaultContainerExecutor extends ContainerExecutor {
   @Override
   public int launchContainer(Container container,
       Path nmPrivateContainerScriptPath, Path nmPrivateTokensPath,
-      String userName, String appId, Path containerWorkDir,
+      String user, String appId, Path containerWorkDir,
       List<String> localDirs, List<String> logDirs) throws IOException {
-
+    
     FsPermission dirPerm = new FsPermission(APPDIR_PERM);
     ContainerId containerId = container.getContainerId();
 
@@ -134,29 +141,30 @@ public class DefaultContainerExecutor extends ContainerExecutor {
                 getApplicationId());
     for (String sLocalDir : localDirs) {
       Path usersdir = new Path(sLocalDir, ContainerLocalizer.USERCACHE);
-      Path userdir = new Path(usersdir, userName);
+      Path userdir = new Path(usersdir, user);
       Path appCacheDir = new Path(userdir, ContainerLocalizer.APPCACHE);
       Path appDir = new Path(appCacheDir, appIdStr);
       Path containerDir = new Path(appDir, containerIdStr);
-      createDir(containerDir, dirPerm, true, userName);
+      createDir(containerDir, dirPerm, true, user);
     }
 
     // Create the container log-dirs on all disks
-    createContainerLogDirs(appIdStr, containerIdStr, logDirs, userName);
+    createContainerLogDirs(appIdStr, containerIdStr, logDirs, user);
 
     Path tmpDir = new Path(containerWorkDir,
         YarnConfiguration.DEFAULT_CONTAINER_TEMP_DIR);
-    createDir(tmpDir, dirPerm, false, userName);
+    createDir(tmpDir, dirPerm, false, user);
 
-    // copy launch script to work dir
-    Path launchDst =
-        new Path(containerWorkDir, ContainerLaunch.CONTAINER_SCRIPT);
-    copyFile(nmPrivateContainerScriptPath, launchDst, userName);
 
     // copy container tokens to work dir
     Path tokenDst =
       new Path(containerWorkDir, ContainerLaunch.FINAL_CONTAINER_TOKENS_FILE);
-    copyFile(nmPrivateTokensPath, tokenDst, userName);
+    copyFile(nmPrivateTokensPath, tokenDst, user);
+
+    // copy launch script to work dir
+    Path launchDst =
+        new Path(containerWorkDir, ContainerLaunch.CONTAINER_SCRIPT);
+    copyFile(nmPrivateContainerScriptPath, launchDst, user);
 
     // Create new local launch wrapper script
     LocalWrapperScriptBuilder sb = getLocalWrapperScriptBuilder(
@@ -181,23 +189,19 @@ public class DefaultContainerExecutor extends ContainerExecutor {
           + " was marked as inactive. Returning terminated error");
       return ExitCode.TERMINATED.getExitCode();
     }
-
+    
     // create log dir under app
     // fork script
-    ShellCommandExecutor shExec = null;
+    Shell.CommandExecutor shExec = null;
     try {
-      setScriptExecutable(launchDst, userName);
-      setScriptExecutable(sb.getWrapperScriptPath(), userName);
-
-      // Setup command to run
-      String[] command = getRunCommand(sb.getWrapperScriptPath().toString(),
-        containerIdStr, userName, pidFile, this.getConf());
+      setScriptExecutable(launchDst, user);
+      setScriptExecutable(sb.getWrapperScriptPath(), user);
 
-      LOG.info("launchContainer: " + Arrays.toString(command));
-      shExec = new ShellCommandExecutor(
-          command,
+      shExec = buildCommandExecutor(sb.getWrapperScriptPath().toString(),
+          containerIdStr, user, pidFile,
           new File(containerWorkDir.toUri().getPath()),
-          container.getLaunchContext().getEnvironment());      // sanitized env
+          container.getLaunchContext().getEnvironment());
+      
       if (isContainerActive(containerId)) {
         shExec.execute();
       }
@@ -242,11 +246,26 @@ public class DefaultContainerExecutor extends ContainerExecutor {
       }
       return exitCode;
     } finally {
-      ; //
+      if (shExec != null) shExec.close();
     }
     return 0;
   }
 
+  protected CommandExecutor buildCommandExecutor(String wrapperScriptPath, 
+      String containerIdStr, String user, Path pidFile, File wordDir, 
+      Map<String, String> environment) 
+          throws IOException {
+    
+    String[] command = getRunCommand(wrapperScriptPath,
+        containerIdStr, user, pidFile, this.getConf());
+
+      LOG.info("launchContainer: " + Arrays.toString(command));
+      return new ShellCommandExecutor(
+          command,
+          wordDir,
+          environment); 
+  }
+
   protected LocalWrapperScriptBuilder getLocalWrapperScriptBuilder(
       String containerIdStr, Path containerWorkDir) {
    return  Shell.WINDOWS ?
@@ -421,7 +440,7 @@ public class DefaultContainerExecutor extends ContainerExecutor {
    * @param signal signal to send
    * (for logging).
    */
-  private void killContainer(String pid, Signal signal) throws IOException {
+  protected void killContainer(String pid, Signal signal) throws IOException {
     new ShellCommandExecutor(Shell.getSignalKillCommand(signal.getValue(), pid))
       .execute();
   }

http://git-wip-us.apache.org/repos/asf/hadoop/blob/29d0164e/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/LinuxContainerExecutor.java
----------------------------------------------------------------------
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/LinuxContainerExecutor.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/LinuxContainerExecutor.java
index d628b1c..884a16a 100644
--- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/LinuxContainerExecutor.java
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/LinuxContainerExecutor.java
@@ -194,9 +194,12 @@ public class LinuxContainerExecutor extends ContainerExecutor {
   @Override
   public void startLocalizer(Path nmPrivateContainerTokensPath,
       InetSocketAddress nmAddr, String user, String appId, String locId,
-      List<String> localDirs, List<String> logDirs)
+      LocalDirsHandlerService dirsHandler)
       throws IOException, InterruptedException {
 
+    List<String> localDirs = dirsHandler.getLocalDirs();
+    List<String> logDirs = dirsHandler.getLogDirs();
+    
     verifyUsernamePattern(user);
     String runAsUser = getRunAsUser(user);
     List<String> command = new ArrayList<String>();