Advertisement
NaZaRa

Untitled

Jan 15th, 2019
350
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 88.30 KB | None | 0 0
  1. BOOL
  2. WINAPI
  3. CreateProcessInternalW(IN HANDLE hUserToken,
  4.                        IN LPCWSTR lpApplicationName,
  5.                        IN LPWSTR lpCommandLine,
  6.                        IN LPSECURITY_ATTRIBUTES lpProcessAttributes,
  7.                        IN LPSECURITY_ATTRIBUTES lpThreadAttributes,
  8.                        IN BOOL bInheritHandles,
  9.                        IN DWORD dwCreationFlags,
  10.                        IN LPVOID lpEnvironment,
  11.                        IN LPCWSTR lpCurrentDirectory,
  12.                        IN LPSTARTUPINFOW lpStartupInfo,
  13.                        IN LPPROCESS_INFORMATION lpProcessInformation,
  14.                        OUT PHANDLE hNewToken)
  15. {
  16.     //
  17.     // Core variables used for creating the initial process and thread
  18.     //
  19.     SECURITY_ATTRIBUTES LocalThreadAttributes, LocalProcessAttributes;
  20.     OBJECT_ATTRIBUTES LocalObjectAttributes;
  21.     POBJECT_ATTRIBUTES ObjectAttributes;
  22.     SECTION_IMAGE_INFORMATION ImageInformation;
  23.     IO_STATUS_BLOCK IoStatusBlock;
  24.     CLIENT_ID ClientId;
  25.     ULONG NoWindow, RegionSize, StackSize, ErrorCode, Flags;
  26.     USHORT ImageMachine;
  27.     ULONG ParameterFlags, PrivilegeValue, HardErrorMode, ErrorResponse;
  28.     ULONG_PTR ErrorParameters[2];
  29.     BOOLEAN InJob, SaferNeeded, UseLargePages, HavePrivilege;
  30.     BOOLEAN QuerySection, SkipSaferAndAppCompat;
  31.     CONTEXT Context;
  32.     BASE_API_MESSAGE CsrMsg[2];
  33.     PBASE_CREATE_PROCESS CreateProcessMsg;
  34.     PCSR_CAPTURE_BUFFER CaptureBuffer;
  35.     PVOID BaseAddress, PrivilegeState, RealTimePrivilegeState;
  36.     HANDLE DebugHandle, TokenHandle, JobHandle, KeyHandle, ThreadHandle;
  37.     HANDLE FileHandle, SectionHandle, ProcessHandle;
  38.     ULONG ResumeCount;
  39.     PROCESS_PRIORITY_CLASS PriorityClass;
  40.     NTSTATUS Status, AppCompatStatus, SaferStatus, IFEOStatus, ImageDbgStatus;
  41.     PPEB Peb, RemotePeb;
  42.     PTEB Teb;
  43.     INITIAL_TEB InitialTeb;
  44.     PVOID TibValue;
  45.     PIMAGE_NT_HEADERS NtHeaders;
  46.     STARTUPINFOW StartupInfo;
  47.     PRTL_USER_PROCESS_PARAMETERS ProcessParameters;
  48.     UNICODE_STRING DebuggerString;
  49.     BOOL Result;
  50.     //
  51.     // Variables used for command-line and argument parsing
  52.     //
  53.     PCHAR pcScan;
  54.     SIZE_T n;
  55.     WCHAR SaveChar;
  56.     ULONG Length, FileAttribs, CmdQuoteLength;
  57.     ULONG CmdLineLength, ResultSize;
  58.     PWCHAR QuotedCmdLine, AnsiCmdCommand, ExtBuffer, CurrentDirectory;
  59.     PWCHAR NullBuffer, ScanString, NameBuffer, SearchPath, DebuggerCmdLine;
  60.     ANSI_STRING AnsiEnv;
  61.     UNICODE_STRING UnicodeEnv, PathName;
  62.     BOOLEAN SearchRetry, QuotesNeeded, CmdLineIsAppName, HasQuotes;
  63.  
  64.     //
  65.     // Variables used for Fusion/SxS (Side-by-Side Assemblies)
  66.     //
  67.     RTL_PATH_TYPE SxsPathType, PathType;
  68. #if _SXS_SUPPORT_ENABLED_
  69.     PRTL_BUFFER ByteBuffer;
  70.     PRTL_UNICODE_STRING_BUFFER ThisBuffer, Buffer, SxsStaticBuffers[5];
  71.     PRTL_UNICODE_STRING_BUFFER* BufferHead, SxsStringBuffer;
  72.     RTL_UNICODE_STRING_BUFFER SxsWin32ManifestPath, SxsNtManifestPath;
  73.     RTL_UNICODE_STRING_BUFFER SxsWin32PolicyPath, SxsNtPolicyPath;
  74.     RTL_UNICODE_STRING_BUFFER SxsWin32AssemblyDirectory;
  75.     BASE_MSG_SXS_HANDLES MappedHandles, Handles, FileHandles;
  76.     PVOID CapturedStrings[3];
  77.     SXS_WIN32_NT_PATH_PAIR ExePathPair, ManifestPathPair, PolicyPathPair;
  78.     SXS_OVERRIDE_MANIFEST OverrideManifest;
  79.     UNICODE_STRING FreeString, SxsNtExePath;
  80.     PWCHAR SxsConglomeratedBuffer, StaticBuffer;
  81.     ULONG ConglomeratedBufferSizeBytes, StaticBufferSize, i;
  82. #endif
  83.     ULONG FusionFlags;
  84.  
  85.     //
  86.     // Variables used for path conversion (and partially Fusion/SxS)
  87.     //
  88.     PWCHAR FilePart, PathBuffer, FreeBuffer;
  89.     BOOLEAN TranslationStatus;
  90.     RTL_RELATIVE_NAME_U SxsWin32RelativePath;
  91.     UNICODE_STRING PathBufferString, SxsWin32ExePath;
  92.  
  93.     //
  94.     // Variables used by Application Compatibility (and partially Fusion/SxS)
  95.     //
  96.     PVOID AppCompatSxsData, AppCompatData;
  97.     ULONG AppCompatSxsDataSize, AppCompatDataSize;
  98.     //
  99.     // Variables used by VDM (Virtual Dos Machine) and WOW32 (16-bit Support)
  100.     //
  101.     ULONG BinarySubType, VdmBinaryType, VdmTask, VdmReserve;
  102.     ULONG VdmUndoLevel;
  103.     BOOLEAN UseVdmReserve;
  104.     HANDLE VdmWaitObject;
  105.     ANSI_STRING VdmAnsiEnv;
  106.     UNICODE_STRING VdmString, VdmUnicodeEnv;
  107.     BOOLEAN IsWowApp;
  108.     PBASE_CHECK_VDM CheckVdmMsg;
  109.  
  110.     /* Zero out the initial core variables and handles */
  111.     QuerySection = FALSE;
  112.     InJob = FALSE;
  113.     SkipSaferAndAppCompat = FALSE;
  114.     ParameterFlags = 0;
  115.     Flags = 0;
  116.     DebugHandle = NULL;
  117.     JobHandle = NULL;
  118.     TokenHandle = NULL;
  119.     FileHandle = NULL;
  120.     SectionHandle = NULL;
  121.     ProcessHandle = NULL;
  122.     ThreadHandle = NULL;
  123.     BaseAddress = (PVOID)1;
  124.  
  125.     /* Zero out initial SxS and Application Compatibility state */
  126.     AppCompatData = NULL;
  127.     AppCompatDataSize = 0;
  128.     AppCompatSxsData = NULL;
  129.     AppCompatSxsDataSize = 0;
  130.     CaptureBuffer = NULL;
  131. #if _SXS_SUPPORT_ENABLED_
  132.     SxsConglomeratedBuffer = NULL;
  133. #endif
  134.     FusionFlags = 0;
  135.  
  136.     /* Zero out initial parsing variables -- others are initialized later */
  137.     DebuggerCmdLine = NULL;
  138.     PathBuffer = NULL;
  139.     SearchPath = NULL;
  140.     NullBuffer = 0;
  141.     FreeBuffer = NULL;
  142.     NameBuffer = NULL;
  143.     CurrentDirectory = NULL;
  144.     FilePart = NULL;
  145.     DebuggerString.Buffer = NULL;
  146.     HasQuotes = FALSE;
  147.     QuotedCmdLine = NULL;
  148.  
  149.     /* Zero out initial VDM state */
  150.     VdmAnsiEnv.Buffer = NULL;
  151.     VdmUnicodeEnv.Buffer = NULL;
  152.     VdmString.Buffer = NULL;
  153.     VdmTask = 0;
  154.     VdmUndoLevel = 0;
  155.     VdmBinaryType = 0;
  156.     VdmReserve = 0;
  157.     VdmWaitObject = NULL;
  158.     UseVdmReserve = FALSE;
  159.     IsWowApp = FALSE;
  160.  
  161.     /* Set message structures */
  162.     CreateProcessMsg = &CsrMsg[0].Data.CreateProcessRequest;
  163.     CheckVdmMsg = &CsrMsg[1].Data.CheckVDMRequest;
  164.  
  165.     /* Clear the more complex structures by zeroing out their entire memory */
  166.     RtlZeroMemory(&Context, sizeof(Context));
  167. #if _SXS_SUPPORT_ENABLED_
  168.     RtlZeroMemory(&FileHandles, sizeof(FileHandles));
  169.     RtlZeroMemory(&MappedHandles, sizeof(MappedHandles));
  170.     RtlZeroMemory(&Handles, sizeof(Handles));
  171. #endif
  172.     RtlZeroMemory(&CreateProcessMsg->Sxs, sizeof(CreateProcessMsg->Sxs));
  173.     RtlZeroMemory(&LocalProcessAttributes, sizeof(LocalProcessAttributes));
  174.     RtlZeroMemory(&LocalThreadAttributes, sizeof(LocalThreadAttributes));
  175.  
  176.     /* Zero out output arguments as well */
  177.     RtlZeroMemory(lpProcessInformation, sizeof(*lpProcessInformation));
  178.     if (hNewToken) *hNewToken = NULL;
  179.  
  180.     /* Capture the special window flag */
  181.     NoWindow = dwCreationFlags & CREATE_NO_WINDOW;
  182.     dwCreationFlags &= ~CREATE_NO_WINDOW;
  183.  
  184. #if _SXS_SUPPORT_ENABLED_
  185.     /* Setup the SxS static string arrays and buffers */
  186.     SxsStaticBuffers[0] = &SxsWin32ManifestPath;
  187.     SxsStaticBuffers[1] = &SxsWin32PolicyPath;
  188.     SxsStaticBuffers[2] = &SxsWin32AssemblyDirectory;
  189.     SxsStaticBuffers[3] = &SxsNtManifestPath;
  190.     SxsStaticBuffers[4] = &SxsNtPolicyPath;
  191.     ExePathPair.Win32 = &SxsWin32ExePath;
  192.     ExePathPair.Nt = &SxsNtExePath;
  193.     ManifestPathPair.Win32 = &SxsWin32ManifestPath.String;
  194.     ManifestPathPair.Nt = &SxsNtManifestPath.String;
  195.     PolicyPathPair.Win32 = &SxsWin32PolicyPath.String;
  196.     PolicyPathPair.Nt = &SxsNtPolicyPath.String;
  197. #endif
  198.  
  199.     DPRINT("CreateProcessInternalW: '%S' '%S' %lx\n", lpApplicationName, lpCommandLine, dwCreationFlags);
  200.  
  201.     /* Finally, set our TEB and PEB */
  202.     Teb = NtCurrentTeb();
  203.     Peb = NtCurrentPeb();
  204.  
  205.     /* This combination is illegal (see MSDN) */
  206.     if ((dwCreationFlags & (DETACHED_PROCESS | CREATE_NEW_CONSOLE)) ==
  207.         (DETACHED_PROCESS | CREATE_NEW_CONSOLE))
  208.     {
  209.         DPRINT1("Invalid flag combo used\n");
  210.         SetLastError(ERROR_INVALID_PARAMETER);
  211.         return FALSE;
  212.     }
  213.  
  214.     /* Convert the priority class */
  215.     if (dwCreationFlags & IDLE_PRIORITY_CLASS)
  216.     {
  217.         PriorityClass.PriorityClass = PROCESS_PRIORITY_CLASS_IDLE;
  218.     }
  219.     else if (dwCreationFlags & BELOW_NORMAL_PRIORITY_CLASS)
  220.     {
  221.         PriorityClass.PriorityClass = PROCESS_PRIORITY_CLASS_BELOW_NORMAL;
  222.     }
  223.     else if (dwCreationFlags & NORMAL_PRIORITY_CLASS)
  224.     {
  225.         PriorityClass.PriorityClass = PROCESS_PRIORITY_CLASS_NORMAL;
  226.     }
  227.     else if (dwCreationFlags & ABOVE_NORMAL_PRIORITY_CLASS)
  228.     {
  229.         PriorityClass.PriorityClass = PROCESS_PRIORITY_CLASS_ABOVE_NORMAL;
  230.     }
  231.     else if (dwCreationFlags & HIGH_PRIORITY_CLASS)
  232.     {
  233.         PriorityClass.PriorityClass = PROCESS_PRIORITY_CLASS_HIGH;
  234.     }
  235.     else if (dwCreationFlags & REALTIME_PRIORITY_CLASS)
  236.     {
  237.         PriorityClass.PriorityClass = PROCESS_PRIORITY_CLASS_HIGH;
  238.         PriorityClass.PriorityClass += (BasepIsRealtimeAllowed(FALSE) != NULL);
  239.     }
  240.     else
  241.     {
  242.         PriorityClass.PriorityClass = PROCESS_PRIORITY_CLASS_INVALID;
  243.     }
  244.  
  245.     /* Done with the priority masks, so get rid of them */
  246.     PriorityClass.Foreground = FALSE;
  247.     dwCreationFlags &= ~(NORMAL_PRIORITY_CLASS |
  248.                          IDLE_PRIORITY_CLASS |
  249.                          HIGH_PRIORITY_CLASS |
  250.                          REALTIME_PRIORITY_CLASS |
  251.                          BELOW_NORMAL_PRIORITY_CLASS |
  252.                          ABOVE_NORMAL_PRIORITY_CLASS);
  253.  
  254.     /* You cannot request both a shared and a separate WoW VDM */
  255.     if ((dwCreationFlags & CREATE_SEPARATE_WOW_VDM) &&
  256.         (dwCreationFlags & CREATE_SHARED_WOW_VDM))
  257.     {
  258.         /* Fail such nonsensical attempts */
  259.         DPRINT1("Invalid WOW flags\n");
  260.         SetLastError(ERROR_INVALID_PARAMETER);
  261.         return FALSE;
  262.     }
  263.     else if (!(dwCreationFlags & CREATE_SHARED_WOW_VDM) &&
  264.              (BaseStaticServerData->DefaultSeparateVDM))
  265.     {
  266.         /* A shared WoW VDM was not requested but system enforces separation */
  267.         dwCreationFlags |= CREATE_SEPARATE_WOW_VDM;
  268.     }
  269.  
  270.     /* If a shared WoW VDM is used, make sure the process isn't in a job */
  271.     if (!(dwCreationFlags & CREATE_SEPARATE_WOW_VDM) &&
  272.         (NtIsProcessInJob(NtCurrentProcess(), NULL)))
  273.     {
  274.         /* Remove the shared flag and add the separate flag */
  275.         dwCreationFlags = (dwCreationFlags &~ CREATE_SHARED_WOW_VDM) |
  276.                                               CREATE_SEPARATE_WOW_VDM;
  277.     }
  278.  
  279.     /* Convert the environment */
  280.     if ((lpEnvironment) && !(dwCreationFlags & CREATE_UNICODE_ENVIRONMENT))
  281.     {
  282.         /* Scan the environment to calculate its Unicode size */
  283.         AnsiEnv.Buffer = pcScan = (PCHAR)lpEnvironment;
  284.         while ((*pcScan) || (*(pcScan + 1))) ++pcScan;
  285.  
  286.         /* Create our ANSI String */
  287.         AnsiEnv.Length = pcScan - (PCHAR)lpEnvironment + sizeof(ANSI_NULL);
  288.         AnsiEnv.MaximumLength = AnsiEnv.Length + sizeof(ANSI_NULL);
  289.  
  290.         /* Allocate memory for the Unicode Environment */
  291.         UnicodeEnv.Buffer = NULL;
  292.         RegionSize = AnsiEnv.MaximumLength * sizeof(WCHAR);
  293.         Status = NtAllocateVirtualMemory(NtCurrentProcess(),
  294.                                          (PVOID)&UnicodeEnv.Buffer,
  295.                                          0,
  296.                                          &RegionSize,
  297.                                          MEM_COMMIT,
  298.                                          PAGE_READWRITE);
  299.         if (!NT_SUCCESS(Status))
  300.         {
  301.             /* Fail */
  302.             BaseSetLastNTError(Status);
  303.             return FALSE;
  304.         }
  305.  
  306.         /* Use the allocated size and convert */
  307.         UnicodeEnv.MaximumLength = (USHORT)RegionSize;
  308.         Status = RtlAnsiStringToUnicodeString(&UnicodeEnv, &AnsiEnv, FALSE);
  309.         if (!NT_SUCCESS(Status))
  310.         {
  311.             /* Fail */
  312.             NtFreeVirtualMemory(NtCurrentProcess(),
  313.                                 (PVOID)&UnicodeEnv.Buffer,
  314.                                 &RegionSize,
  315.                                 MEM_RELEASE);
  316.             BaseSetLastNTError(Status);
  317.             return FALSE;
  318.         }
  319.  
  320.         /* Now set the Unicode environment as the environment string pointer */
  321.         lpEnvironment = UnicodeEnv.Buffer;
  322.     }
  323.  
  324.     /* Make a copy of the caller's startup info since we'll modify it */
  325.     StartupInfo = *lpStartupInfo;
  326.  
  327.     /* Check if private data is being sent on the same channel as std handles */
  328.     if ((StartupInfo.dwFlags & STARTF_USESTDHANDLES) &&
  329.         (StartupInfo.dwFlags & (STARTF_USEHOTKEY | STARTF_SHELLPRIVATE)))
  330.     {
  331.         /* Cannot use the std handles since we have monitor/hotkey values */
  332.         StartupInfo.dwFlags &= ~STARTF_USESTDHANDLES;
  333.     }
  334.  
  335.     /* If there's a debugger, or we have to launch cmd.exe, we go back here */
  336. AppNameRetry:
  337.     /* New iteration -- free any existing name buffer */
  338.     if (NameBuffer)
  339.     {
  340.         RtlFreeHeap(RtlGetProcessHeap(), 0, NameBuffer);
  341.         NameBuffer = NULL;
  342.     }
  343.  
  344.     /* New iteration -- free any existing free buffer */
  345.     if (FreeBuffer)
  346.     {
  347.         RtlFreeHeap(RtlGetProcessHeap(), 0, FreeBuffer);
  348.         FreeBuffer = NULL;
  349.     }
  350.  
  351.     /* New iteration -- close any existing file handle */
  352.     if (FileHandle)
  353.     {
  354.         NtClose(FileHandle);
  355.         FileHandle = NULL;
  356.     }
  357.  
  358.     /* Set the initial parsing state. This code can loop -- don't move this! */
  359.     ErrorCode = 0;
  360.     SearchRetry = TRUE;
  361.     QuotesNeeded = FALSE;
  362.     CmdLineIsAppName = FALSE;
  363.  
  364.     /* First check if we don't have an application name */
  365.     if (!lpApplicationName)
  366.     {
  367.         /* This should be the first time we attempt creating one */
  368.         ASSERT(NameBuffer == NULL);
  369.  
  370.         /* Allocate a buffer to hold it */
  371.         NameBuffer = RtlAllocateHeap(RtlGetProcessHeap(),
  372.                                      0,
  373.                                      MAX_PATH * sizeof(WCHAR));
  374.         if (!NameBuffer)
  375.         {
  376.             SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  377.             Result = FALSE;
  378.             goto Quickie;
  379.         }
  380.  
  381.         /* Initialize the application name and our parsing parameters */
  382.         lpApplicationName = NullBuffer = ScanString = lpCommandLine;
  383.  
  384.         /* Check for an initial quote*/
  385.         if (*lpCommandLine == L'\"')
  386.         {
  387.             /* We found a quote, keep searching for another one */
  388.             SearchRetry = FALSE;
  389.             ScanString++;
  390.             lpApplicationName = ScanString;
  391.             while (*ScanString)
  392.             {
  393.                 /* Have we found the terminating quote? */
  394.                 if (*ScanString == L'\"')
  395.                 {
  396.                     /* We're done, get out of here */
  397.                     NullBuffer = ScanString;
  398.                     HasQuotes = TRUE;
  399.                     break;
  400.                 }
  401.  
  402.                 /* Keep searching for the quote */
  403.                 ScanString++;
  404.                 NullBuffer = ScanString;
  405.             }
  406.         }
  407.         else
  408.         {
  409. StartScan:
  410.             /* We simply make the application name be the command line*/
  411.             lpApplicationName = lpCommandLine;
  412.             while (*ScanString)
  413.             {
  414.                 /* Check if it starts with a space or tab */
  415.                 if ((*ScanString == L' ') || (*ScanString == L'\t'))
  416.                 {
  417.                     /* Break out of the search loop */
  418.                     NullBuffer = ScanString;
  419.                     break;
  420.                 }
  421.  
  422.                 /* Keep searching for a space or tab */
  423.                 ScanString++;
  424.                 NullBuffer = ScanString;
  425.             }
  426.         }
  427.  
  428.         /* We have found the end of the application name, terminate it */
  429.         SaveChar = *NullBuffer;
  430.         *NullBuffer = UNICODE_NULL;
  431.  
  432.         /* New iteration -- free any existing saved path */
  433.         if (SearchPath)
  434.         {
  435.             RtlFreeHeap(RtlGetProcessHeap(), 0, SearchPath);
  436.             SearchPath = NULL;
  437.         }
  438.  
  439.         /* Now compute the final EXE path based on the name */
  440.         SearchPath = BaseComputeProcessExePath((LPWSTR)lpApplicationName);
  441.         DPRINT("Search Path: %S\n", SearchPath);
  442.         if (!SearchPath)
  443.         {
  444.             SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  445.             Result = FALSE;
  446.             goto Quickie;
  447.         }
  448.  
  449.         /* And search for the executable in the search path */
  450.         Length = SearchPathW(SearchPath,
  451.                              lpApplicationName,
  452.                              L".exe",
  453.                              MAX_PATH,
  454.                              NameBuffer,
  455.                              NULL);
  456.  
  457.         /* Did we find it? */
  458.         if ((Length) && (Length < MAX_PATH))
  459.         {
  460.             /* Get file attributes */
  461.             FileAttribs = GetFileAttributesW(NameBuffer);
  462.             if ((FileAttribs != INVALID_FILE_ATTRIBUTES) &&
  463.                 (FileAttribs & FILE_ATTRIBUTE_DIRECTORY))
  464.             {
  465.                 /* This was a directory, fail later on */
  466.                 Length = 0;
  467.             }
  468.             else
  469.             {
  470.                 /* It's a file! */
  471.                 Length++;
  472.             }
  473.         }
  474.  
  475.         DPRINT("Length: %lu Buffer: %S\n", Length, NameBuffer);
  476.  
  477.         /* Check if there was a failure in SearchPathW */
  478.         if ((Length) && (Length < MAX_PATH))
  479.         {
  480.             /* Everything looks good, restore the name */
  481.             *NullBuffer = SaveChar;
  482.             lpApplicationName = NameBuffer;
  483.         }
  484.         else
  485.         {
  486.             /* Check if this was a relative path, which would explain it */
  487.             PathType = RtlDetermineDosPathNameType_U(lpApplicationName);
  488.             if (PathType != RtlPathTypeRelative)
  489.             {
  490.                 /* This should fail, and give us a detailed LastError */
  491.                 FileHandle = CreateFileW(lpApplicationName,
  492.                                          GENERIC_READ,
  493.                                          FILE_SHARE_READ |
  494.                                          FILE_SHARE_WRITE,
  495.                                          NULL,
  496.                                          OPEN_EXISTING,
  497.                                          FILE_ATTRIBUTE_NORMAL,
  498.                                          NULL);
  499.                 if (FileHandle != INVALID_HANDLE_VALUE)
  500.                 {
  501.                     /* It worked? Return a generic error */
  502.                     CloseHandle(FileHandle);
  503.                     FileHandle = NULL;
  504.                     BaseSetLastNTError(STATUS_OBJECT_NAME_NOT_FOUND);
  505.                 }
  506.             }
  507.             else
  508.             {
  509.                 /* Path was absolute, which means it doesn't exist */
  510.                 BaseSetLastNTError(STATUS_OBJECT_NAME_NOT_FOUND);
  511.             }
  512.  
  513.             /* Did we already fail once? */
  514.             if (ErrorCode)
  515.             {
  516.                 /* Set the error code */
  517.                 SetLastError(ErrorCode);
  518.             }
  519.             else
  520.             {
  521.                 /* Not yet, cache it */
  522.                 ErrorCode = GetLastError();
  523.             }
  524.  
  525.             /* Put back the command line */
  526.             *NullBuffer = SaveChar;
  527.             lpApplicationName = NameBuffer;
  528.  
  529.             /* It's possible there's whitespace in the directory name */
  530.             if (!(*ScanString) || !(SearchRetry))
  531.             {
  532.                 /* Not the case, give up completely */
  533.                 Result = FALSE;
  534.                 goto Quickie;
  535.             }
  536.  
  537.             /* There are spaces, so keep trying the next possibility */
  538.             ScanString++;
  539.             NullBuffer = ScanString;
  540.  
  541.             /* We will have to add a quote, since there is a space */
  542.             QuotesNeeded = TRUE;
  543.             HasQuotes = TRUE;
  544.             goto StartScan;
  545.         }
  546.     }
  547.     else if (!(lpCommandLine) || !(*lpCommandLine))
  548.     {
  549.         /* We don't have a command line, so just use the application name */
  550.         CmdLineIsAppName = TRUE;
  551.         lpCommandLine = (LPWSTR)lpApplicationName;
  552.     }
  553.  
  554.     /* Convert the application name to its NT path */
  555.     TranslationStatus = RtlDosPathNameToRelativeNtPathName_U(lpApplicationName,
  556.                                                              &PathName,
  557.                                                              NULL,
  558.                                                              &SxsWin32RelativePath);
  559.     if (!TranslationStatus)
  560.     {
  561.         /* Path must be invalid somehow, bail out */
  562.         DPRINT1("Path translation for SxS failed\n");
  563.         SetLastError(ERROR_PATH_NOT_FOUND);
  564.         Result = FALSE;
  565.         goto Quickie;
  566.     }
  567.  
  568.     /* Setup the buffer that needs to be freed at the end */
  569.     ASSERT(FreeBuffer == NULL);
  570.     FreeBuffer = PathName.Buffer;
  571.  
  572.     /* Check what kind of path the application is, for SxS (Fusion) purposes */
  573.     RtlInitUnicodeString(&SxsWin32ExePath, lpApplicationName);
  574.     SxsPathType = RtlDetermineDosPathNameType_U(lpApplicationName);
  575.     if ((SxsPathType != RtlPathTypeDriveAbsolute) &&
  576.         (SxsPathType != RtlPathTypeLocalDevice) &&
  577.         (SxsPathType != RtlPathTypeRootLocalDevice) &&
  578.         (SxsPathType != RtlPathTypeUncAbsolute))
  579.     {
  580.         /* Relative-type path, get the full path */
  581.         RtlInitEmptyUnicodeString(&PathBufferString, NULL, 0);
  582.         Status = RtlGetFullPathName_UstrEx(&SxsWin32ExePath,
  583.                                            NULL,
  584.                                            &PathBufferString,
  585.                                            NULL,
  586.                                            NULL,
  587.                                            NULL,
  588.                                            &SxsPathType,
  589.                                            NULL);
  590.         if (!NT_SUCCESS(Status))
  591.         {
  592.             /* Fail the rest of the create */
  593.             RtlReleaseRelativeName(&SxsWin32RelativePath);
  594.             BaseSetLastNTError(Status);
  595.             Result = FALSE;
  596.             goto Quickie;
  597.         }
  598.  
  599.         /* Use this full path as the SxS path */
  600.         SxsWin32ExePath = PathBufferString;
  601.         PathBuffer = PathBufferString.Buffer;
  602.         PathBufferString.Buffer = NULL;
  603.         DPRINT("SxS Path: %S\n", PathBuffer);
  604.     }
  605.  
  606.     /* Also set the .EXE path based on the path name */
  607. #if _SXS_SUPPORT_ENABLED_
  608.     SxsNtExePath = PathName;
  609. #endif
  610.     if (SxsWin32RelativePath.RelativeName.Length)
  611.     {
  612.         /* If it's relative, capture the relative name */
  613.         PathName = SxsWin32RelativePath.RelativeName;
  614.     }
  615.     else
  616.     {
  617.         /* Otherwise, it's absolute, make sure no relative dir is used */
  618.         SxsWin32RelativePath.ContainingDirectory = NULL;
  619.     }
  620.  
  621.     /* Now use the path name, and the root path, to try opening the app */
  622.     DPRINT("Path: %wZ. Dir: %p\n", &PathName, SxsWin32RelativePath.ContainingDirectory);
  623.     InitializeObjectAttributes(&LocalObjectAttributes,
  624.                                &PathName,
  625.                                OBJ_CASE_INSENSITIVE,
  626.                                SxsWin32RelativePath.ContainingDirectory,
  627.                                NULL);
  628.     Status = NtOpenFile(&FileHandle,
  629.                         SYNCHRONIZE |
  630.                         FILE_READ_ATTRIBUTES |
  631.                         FILE_READ_DATA |
  632.                         FILE_EXECUTE,
  633.                         &LocalObjectAttributes,
  634.                         &IoStatusBlock,
  635.                         FILE_SHARE_READ | FILE_SHARE_DELETE,
  636.                         FILE_SYNCHRONOUS_IO_NONALERT |
  637.                         FILE_NON_DIRECTORY_FILE);
  638.     if (!NT_SUCCESS(Status))
  639.     {
  640.         /* Try to open the app just for execute purposes instead */
  641.         Status = NtOpenFile(&FileHandle,
  642.                             SYNCHRONIZE | FILE_EXECUTE,
  643.                             &LocalObjectAttributes,
  644.                             &IoStatusBlock,
  645.                             FILE_SHARE_READ | FILE_SHARE_DELETE,
  646.                             FILE_SYNCHRONOUS_IO_NONALERT |
  647.                             FILE_NON_DIRECTORY_FILE);
  648.     }
  649.  
  650.     /* Failure path, display which file failed to open */
  651.     if (!NT_SUCCESS(Status))
  652.         DPRINT1("Open file failed: %lx (%wZ)\n", Status, &PathName);
  653.  
  654.     /* Cleanup in preparation for failure or success */
  655.     RtlReleaseRelativeName(&SxsWin32RelativePath);
  656.  
  657.     if (!NT_SUCCESS(Status))
  658.     {
  659.         /* Failure path, try to understand why */
  660.         if (RtlIsDosDeviceName_U(lpApplicationName))
  661.         {
  662.             /* If a device is being executed, return this special error code */
  663.             SetLastError(ERROR_BAD_DEVICE);
  664.             Result = FALSE;
  665.             goto Quickie;
  666.         }
  667.         else
  668.         {
  669.             /* Otherwise return the converted NT error code */
  670.             BaseSetLastNTError(Status);
  671.             Result = FALSE;
  672.             goto Quickie;
  673.         }
  674.     }
  675.  
  676.     /* Did the caller specify a desktop? */
  677.     if (!StartupInfo.lpDesktop)
  678.     {
  679.         /* Use the one from the current process */
  680.         StartupInfo.lpDesktop = Peb->ProcessParameters->DesktopInfo.Buffer;
  681.     }
  682.  
  683.     /* Create a section for this file */
  684.     Status = NtCreateSection(&SectionHandle,
  685.                              SECTION_ALL_ACCESS,
  686.                              NULL,
  687.                              NULL,
  688.                              PAGE_EXECUTE,
  689.                              SEC_IMAGE,
  690.                              FileHandle);
  691.     DPRINT("Section status: %lx\n", Status);
  692.     if (NT_SUCCESS(Status))
  693.     {
  694.         /* Are we running on Windows Embedded, Datacenter, Blade or Starter? */
  695.         if (SharedUserData->SuiteMask & (VER_SUITE_EMBEDDEDNT |
  696.                                          VER_SUITE_DATACENTER |
  697.                                          VER_SUITE_PERSONAL |
  698.                                          VER_SUITE_BLADE))
  699.         {
  700.             /* These SKUs do not allow running certain applications */
  701.             Status = BasepCheckWebBladeHashes(FileHandle);
  702.             if (Status == STATUS_ACCESS_DENIED)
  703.             {
  704.                 /* And this is one of them! */
  705.                 DPRINT1("Invalid Blade hashes!\n");
  706.                 SetLastError(ERROR_ACCESS_DISABLED_WEBBLADE);
  707.                 Result = FALSE;
  708.                 goto Quickie;
  709.             }
  710.  
  711.             /* Did we get some other failure? */
  712.             if (!NT_SUCCESS(Status))
  713.             {
  714.                 /* If we couldn't check the hashes, assume nefariousness */
  715.                 DPRINT1("Tampered Blade hashes!\n");
  716.                 SetLastError(ERROR_ACCESS_DISABLED_WEBBLADE_TAMPER);
  717.                 Result = FALSE;
  718.                 goto Quickie;
  719.             }
  720.         }
  721.  
  722.         /* Now do Winsafer, etc, checks */
  723.         Status = BasepIsProcessAllowed((LPWSTR)lpApplicationName);
  724.         if (!NT_SUCCESS(Status))
  725.         {
  726.             /* Fail if we're not allowed to launch the process */
  727.             DPRINT1("Process not allowed to launch: %lx\n", Status);
  728.             BaseSetLastNTError(Status);
  729.             if (SectionHandle)
  730.             {
  731.                 NtClose(SectionHandle);
  732.                 SectionHandle = NULL;
  733.             }
  734.             Result = FALSE;
  735.             goto Quickie;
  736.         }
  737.  
  738.         /* Is a DOS VDM being forced, but we already have a WOW32 instance ready? */
  739.         if ((dwCreationFlags & CREATE_FORCEDOS) &&
  740.             (BaseStaticServerData->IsWowTaskReady))
  741.         {
  742.             /* This request can't be satisfied, instead, a separate VDM is needed */
  743.             dwCreationFlags &= ~(CREATE_FORCEDOS | CREATE_SHARED_WOW_VDM);
  744.             dwCreationFlags |= CREATE_SEPARATE_WOW_VDM;
  745.  
  746.             /* Set a failure code, ask for VDM reservation */
  747.             Status = STATUS_INVALID_IMAGE_WIN_16;
  748.             UseVdmReserve = TRUE;
  749.  
  750.             /* Close the current handle */
  751.             NtClose(SectionHandle);
  752.             SectionHandle = NULL;
  753.  
  754.             /* Don't query the section later */
  755.             QuerySection = FALSE;
  756.         }
  757.     }
  758.  
  759.     /* Did we already do these checks? */
  760.     if (!SkipSaferAndAppCompat)
  761.     {
  762.         /* Is everything OK so far, OR do we have an non-MZ, non-DOS app? */
  763.         if ((NT_SUCCESS(Status)) ||
  764.             ((Status == STATUS_INVALID_IMAGE_NOT_MZ) &&
  765.             !(BaseIsDosApplication(&PathName, Status))))
  766.         {
  767.             /* Clear the machine type in case of failure */
  768.             ImageMachine = 0;
  769.  
  770.             /* Clean any app compat data that may have accumulated */
  771.             BasepFreeAppCompatData(AppCompatData, AppCompatSxsData);
  772.             AppCompatData = NULL;
  773.             AppCompatSxsData = NULL;
  774.  
  775.             /* Do we have a section? */
  776.             if (SectionHandle)
  777.             {
  778.                 /* Have we already queried it? */
  779.                 if (QuerySection)
  780.                 {
  781.                     /* Nothing to do */
  782.                     AppCompatStatus = STATUS_SUCCESS;
  783.                 }
  784.                 else
  785.                 {
  786.                     /* Get some information about the executable */
  787.                     AppCompatStatus = NtQuerySection(SectionHandle,
  788.                                             SectionImageInformation,
  789.                                             &ImageInformation,
  790.                                             sizeof(ImageInformation),
  791.                                             NULL);
  792.                 }
  793.  
  794.                 /* Do we have section information now? */
  795.                 if (NT_SUCCESS(AppCompatStatus))
  796.                 {
  797.                     /* Don't ask for it again, save the machine type */
  798.                     QuerySection = TRUE;
  799.                     ImageMachine = ImageInformation.Machine;
  800.                 }
  801.             }
  802.  
  803.             /* Is there a reason/Shim we shouldn't run this application? */
  804.             AppCompatStatus = BasepCheckBadapp(FileHandle,
  805.                                       FreeBuffer,
  806.                                       lpEnvironment,
  807.                                       ImageMachine,
  808.                                       &AppCompatData,
  809.                                       &AppCompatDataSize,
  810.                                       &AppCompatSxsData,
  811.                                       &AppCompatSxsDataSize,
  812.                                       &FusionFlags);
  813.             if (!NT_SUCCESS(AppCompatStatus))
  814.             {
  815.                 /* This is usually the status we get back */
  816.                 DPRINT1("App compat launch failure: %lx\n", AppCompatStatus);
  817.                 if (AppCompatStatus == STATUS_ACCESS_DENIED)
  818.                 {
  819.                     /* Convert it to something more Win32-specific */
  820.                     SetLastError(ERROR_CANCELLED);
  821.                 }
  822.                 else
  823.                 {
  824.                     /* Some other error */
  825.                     BaseSetLastNTError(AppCompatStatus);
  826.                 }
  827.  
  828.                 /* Did we have a section? */
  829.                 if (SectionHandle)
  830.                 {
  831.                     /* Clean it up */
  832.                     NtClose(SectionHandle);
  833.                     SectionHandle = NULL;
  834.                 }
  835.  
  836.                 /* Fail the call */
  837.                 Result = FALSE;
  838.                 goto Quickie;
  839.             }
  840.         }
  841.     }
  842.  
  843.     //ASSERT((dwFusionFlags & ~SXS_APPCOMPACT_FLAG_APP_RUNNING_SAFEMODE) == 0);
  844.  
  845.     /* Have we already done, and do we need to do, SRP (WinSafer) checks? */
  846.     if (!(SkipSaferAndAppCompat) &&
  847.         ~(dwCreationFlags & CREATE_PRESERVE_CODE_AUTHZ_LEVEL))
  848.     {
  849.         /* Assume yes */
  850.         SaferNeeded = TRUE;
  851.         switch (Status)
  852.         {
  853.             case STATUS_INVALID_IMAGE_NE_FORMAT:
  854.             case STATUS_INVALID_IMAGE_PROTECT:
  855.             case STATUS_INVALID_IMAGE_WIN_16:
  856.             case STATUS_FILE_IS_OFFLINE:
  857.                 /* For all DOS, 16-bit, OS/2 images, we do*/
  858.                 break;
  859.  
  860.             case STATUS_INVALID_IMAGE_NOT_MZ:
  861.                 /* For invalid files, we don't, unless it's a .BAT file */
  862.                 if (BaseIsDosApplication(&PathName, Status)) break;
  863.  
  864.             default:
  865.                 /* Any other error codes we also don't */
  866.                 if (!NT_SUCCESS(Status))
  867.                 {
  868.                     SaferNeeded = FALSE;
  869.                 }
  870.  
  871.                 /* But for success, we do */
  872.                 break;
  873.         }
  874.  
  875.         /* Okay, so what did the checks above result in? */
  876.         if (SaferNeeded)
  877.         {
  878.             /* We have to call into the WinSafer library and actually check */
  879.             SaferStatus = BasepCheckWinSaferRestrictions(hUserToken,
  880.                                                     (LPWSTR)lpApplicationName,
  881.                                                     FileHandle,
  882.                                                     &InJob,
  883.                                                     &TokenHandle,
  884.                                                     &JobHandle);
  885.             if (SaferStatus == 0xFFFFFFFF)
  886.             {
  887.                 /* Back in 2003, they didn't have an NTSTATUS for this... */
  888.                 DPRINT1("WinSafer blocking process launch\n");
  889.                 SetLastError(ERROR_ACCESS_DISABLED_BY_POLICY);
  890.                 Result = FALSE;
  891.                 goto Quickie;
  892.             }
  893.  
  894.             /* Other status codes are not-Safer related, just convert them */
  895.             if (!NT_SUCCESS(SaferStatus))
  896.             {
  897.                 DPRINT1("Error checking WinSafer: %lx\n", SaferStatus);
  898.                 BaseSetLastNTError(SaferStatus);
  899.                 Result = FALSE;
  900.                 goto Quickie;
  901.             }
  902.         }
  903.     }
  904.  
  905.     /* The last step is to figure out why the section object was not created */
  906.     switch (Status)
  907.     {
  908.         case STATUS_INVALID_IMAGE_WIN_16:
  909.         {
  910.             /* 16-bit binary. Should we use WOW or does the caller force VDM? */
  911.             if (!(dwCreationFlags & CREATE_FORCEDOS))
  912.             {
  913.                 /* Remember that we're launching WOW */
  914.                 IsWowApp = TRUE;
  915.  
  916.                 /* Create the VDM environment, it's valid for WOW too */
  917.                 Result = BaseCreateVDMEnvironment(lpEnvironment,
  918.                                                   &VdmAnsiEnv,
  919.                                                   &VdmUnicodeEnv);
  920.                 if (!Result)
  921.                 {
  922.                     DPRINT1("VDM environment for WOW app failed\n");
  923.                     goto Quickie;
  924.                 }
  925.  
  926.                 /* We're going to try this twice, so do a loop */
  927.                 while (TRUE)
  928.                 {
  929.                     /* Pick which kind of WOW mode we want to run in */
  930.                     VdmBinaryType = (dwCreationFlags &
  931.                                      CREATE_SEPARATE_WOW_VDM) ?
  932.                                      BINARY_TYPE_SEPARATE_WOW : BINARY_TYPE_WOW;
  933.  
  934.                     /* Get all the VDM settings and current status */
  935.                     Status = BaseCheckVDM(VdmBinaryType,
  936.                                           lpApplicationName,
  937.                                           lpCommandLine,
  938.                                           lpCurrentDirectory,
  939.                                           &VdmAnsiEnv,
  940.                                           &CsrMsg[1],
  941.                                           &VdmTask,
  942.                                           dwCreationFlags,
  943.                                           &StartupInfo,
  944.                                           hUserToken);
  945.  
  946.                     /* If it worked, no need to try again */
  947.                     if (NT_SUCCESS(Status)) break;
  948.  
  949.                     /* Check if it's disallowed or if it's our second time */
  950.                     BaseSetLastNTError(Status);
  951.                     if ((Status == STATUS_VDM_DISALLOWED) ||
  952.                         (VdmBinaryType == BINARY_TYPE_SEPARATE_WOW) ||
  953.                         (GetLastError() == ERROR_ACCESS_DENIED))
  954.                     {
  955.                         /* Fail the call -- we won't try again */
  956.                         DPRINT1("VDM message failure for WOW: %lx\n", Status);
  957.                         Result = FALSE;
  958.                         goto Quickie;
  959.                     }
  960.  
  961.                     /* Try one more time, but with a separate WOW instance */
  962.                     dwCreationFlags |= CREATE_SEPARATE_WOW_VDM;
  963.                 }
  964.  
  965.                 /* Check which VDM state we're currently in */
  966.                 switch (CheckVdmMsg->VDMState & (VDM_NOT_LOADED |
  967.                                                  VDM_NOT_READY |
  968.                                                  VDM_READY))
  969.                 {
  970.                     case VDM_NOT_LOADED:
  971.                         /* VDM is not fully loaded, so not that much to undo */
  972.                         VdmUndoLevel = VDM_UNDO_PARTIAL;
  973.  
  974.                         /* Reset VDM reserve if needed */
  975.                         if (UseVdmReserve) VdmReserve = 1;
  976.  
  977.                         /* Get the required parameters and names for launch */
  978.                         Result = BaseGetVdmConfigInfo(lpCommandLine,
  979.                                                       VdmTask,
  980.                                                       VdmBinaryType,
  981.                                                       &VdmString,
  982.                                                       &VdmReserve);
  983.                         if (!Result)
  984.                         {
  985.                             DPRINT1("VDM Configuration failed for WOW\n");
  986.                             BaseSetLastNTError(Status);
  987.                             goto Quickie;
  988.                         }
  989.  
  990.                         /* Update the command-line with the VDM one instead */
  991.                         lpCommandLine = VdmString.Buffer;
  992.                         lpApplicationName = NULL;
  993.  
  994.                         /* We don't want a console, detachment, nor a window */
  995.                         dwCreationFlags |= CREATE_NO_WINDOW;
  996.                         dwCreationFlags &= ~(CREATE_NEW_CONSOLE | DETACHED_PROCESS);
  997.  
  998.                         /* Force feedback on */
  999.                         StartupInfo.dwFlags |= STARTF_FORCEONFEEDBACK;
  1000.                         break;
  1001.  
  1002.  
  1003.                     case VDM_READY:
  1004.                         /* VDM is ready, so we have to undo everything */
  1005.                         VdmUndoLevel = VDM_UNDO_REUSE;
  1006.  
  1007.                         /* Check if CSRSS wants us to wait on VDM */
  1008.                         VdmWaitObject = CheckVdmMsg->WaitObjectForParent;
  1009.                         break;
  1010.  
  1011.                     case VDM_NOT_READY:
  1012.                         /* Something is wrong with VDM, we'll fail the call */
  1013.                         DPRINT1("VDM is not ready for WOW\n");
  1014.                         SetLastError(ERROR_NOT_READY);
  1015.                         Result = FALSE;
  1016.                         goto Quickie;
  1017.  
  1018.                     default:
  1019.                         break;
  1020.                 }
  1021.  
  1022.                 /* Since to get NULL, we allocate from 0x1, account for this */
  1023.                 VdmReserve--;
  1024.  
  1025.                 /* This implies VDM is ready, so skip everything else */
  1026.                 if (VdmWaitObject) goto VdmShortCircuit;
  1027.  
  1028.                 /* Don't inherit handles since we're doing VDM now */
  1029.                 bInheritHandles = FALSE;
  1030.  
  1031.                 /* Had the user passed in environment? If so, destroy it */
  1032.                 if ((lpEnvironment) &&
  1033.                     !(dwCreationFlags & CREATE_UNICODE_ENVIRONMENT))
  1034.                 {
  1035.                     RtlDestroyEnvironment(lpEnvironment);
  1036.                 }
  1037.  
  1038.                 /* We've already done all these checks, don't do them again */
  1039.                 SkipSaferAndAppCompat = TRUE;
  1040.                 goto AppNameRetry;
  1041.             }
  1042.  
  1043.             // There is no break here on purpose, so FORCEDOS drops down!
  1044.         }
  1045.  
  1046.         case STATUS_INVALID_IMAGE_PROTECT:
  1047.         case STATUS_INVALID_IMAGE_NOT_MZ:
  1048.         case STATUS_INVALID_IMAGE_NE_FORMAT:
  1049.         {
  1050.             /* We're launching an executable application */
  1051.             BinarySubType = BINARY_TYPE_EXE;
  1052.  
  1053.             /* We can drop here from other "cases" above too, so check */
  1054.             if ((Status == STATUS_INVALID_IMAGE_PROTECT) ||
  1055.                 (Status == STATUS_INVALID_IMAGE_NE_FORMAT) ||
  1056.                 (BinarySubType = BaseIsDosApplication(&PathName, Status)))
  1057.             {
  1058.                 /* We're launching a DOS application */
  1059.                 VdmBinaryType = BINARY_TYPE_DOS;
  1060.  
  1061.                 /* Based on the caller environment, create a VDM one */
  1062.                 Result = BaseCreateVDMEnvironment(lpEnvironment,
  1063.                                                   &VdmAnsiEnv,
  1064.                                                   &VdmUnicodeEnv);
  1065.                 if (!Result)
  1066.                 {
  1067.                     DPRINT1("VDM environment for DOS failed\n");
  1068.                     goto Quickie;
  1069.                 }
  1070.  
  1071.                 /* Check the current state of the VDM subsystem */
  1072.                 Status = BaseCheckVDM(VdmBinaryType | BinarySubType,
  1073.                                       lpApplicationName,
  1074.                                       lpCommandLine,
  1075.                                       lpCurrentDirectory,
  1076.                                       &VdmAnsiEnv,
  1077.                                       &CsrMsg[1],
  1078.                                       &VdmTask,
  1079.                                       dwCreationFlags,
  1080.                                       &StartupInfo,
  1081.                                       NULL);
  1082.                 if (!NT_SUCCESS(Status))
  1083.                 {
  1084.                     /* Failed to inquire about VDM, fail the call */
  1085.                     DPRINT1("VDM message failure for DOS: %lx\n", Status);
  1086.                     BaseSetLastNTError(Status);
  1087.                     Result = FALSE;
  1088.                     goto Quickie;
  1089.                 };
  1090.  
  1091.                 /* Handle possible VDM states */
  1092.                 switch (CheckVdmMsg->VDMState & (VDM_NOT_LOADED |
  1093.                                                  VDM_NOT_READY |
  1094.                                                  VDM_READY))
  1095.                 {
  1096.                     case VDM_NOT_LOADED:
  1097.                         /* If VDM is not loaded, we'll do a partial undo */
  1098.                         VdmUndoLevel = VDM_UNDO_PARTIAL;
  1099.  
  1100.                         /* A VDM process can't also be detached, so fail */
  1101.                         if (dwCreationFlags & DETACHED_PROCESS)
  1102.                         {
  1103.                             DPRINT1("Detached process but no VDM, not allowed\n");
  1104.                             SetLastError(ERROR_ACCESS_DENIED);
  1105.                             return FALSE;
  1106.                         }
  1107.  
  1108.                         /* Get the required parameters and names for launch */
  1109.                         Result = BaseGetVdmConfigInfo(lpCommandLine,
  1110.                                                       VdmTask,
  1111.                                                       VdmBinaryType,
  1112.                                                       &VdmString,
  1113.                                                       &VdmReserve);
  1114.                         if (!Result)
  1115.                         {
  1116.                             DPRINT1("VDM Configuration failed for DOS\n");
  1117.                             BaseSetLastNTError(Status);
  1118.                             goto Quickie;
  1119.                         }
  1120.  
  1121.                         /* Update the command-line to launch VDM instead */
  1122.                         lpCommandLine = VdmString.Buffer;
  1123.                         lpApplicationName = NULL;
  1124.                         break;
  1125.  
  1126.                     case VDM_READY:
  1127.                         /* VDM is ready, so we have to undo everything */
  1128.                         VdmUndoLevel = VDM_UNDO_REUSE;
  1129.  
  1130.                         /* Check if CSRSS wants us to wait on VDM */
  1131.                         VdmWaitObject = CheckVdmMsg->WaitObjectForParent;
  1132.                         break;
  1133.  
  1134.                     case VDM_NOT_READY:
  1135.                         /* Something is wrong with VDM, we'll fail the call */
  1136.                         DPRINT1("VDM is not ready for DOS\n");
  1137.                         SetLastError(ERROR_NOT_READY);
  1138.                         Result = FALSE;
  1139.                         goto Quickie;
  1140.  
  1141.                     default:
  1142.                         break;
  1143.                 }
  1144.  
  1145.                 /* Since to get NULL, we allocate from 0x1, account for this */
  1146.                 VdmReserve--;
  1147.  
  1148.                 /* This implies VDM is ready, so skip everything else */
  1149.                 if (VdmWaitObject) goto VdmShortCircuit;
  1150.  
  1151.                 /* Don't inherit handles since we're doing VDM now */
  1152.                 bInheritHandles = FALSE;
  1153.  
  1154.                 /* Had the user passed in environment? If so, destroy it */
  1155.                 if ((lpEnvironment) &&
  1156.                     !(dwCreationFlags & CREATE_UNICODE_ENVIRONMENT))
  1157.                 {
  1158.                     RtlDestroyEnvironment(lpEnvironment);
  1159.                 }
  1160.  
  1161.                 /* Use our VDM Unicode environment instead */
  1162.                 lpEnvironment = VdmUnicodeEnv.Buffer;
  1163.             }
  1164.             else
  1165.             {
  1166.                 /* It's a batch file, get the extension */
  1167.                 ExtBuffer = &PathName.Buffer[PathName.Length / sizeof(WCHAR) - 4];
  1168.  
  1169.                 /* Make sure the extensions are correct */
  1170.                 if ((PathName.Length < (4 * sizeof(WCHAR))) ||
  1171.                     ((_wcsnicmp(ExtBuffer, L".bat", 4)) &&
  1172.                      (_wcsnicmp(ExtBuffer, L".cmd", 4))))
  1173.                 {
  1174.                     DPRINT1("'%wZ': Invalid EXE, and not a batch or script file\n", &PathName);
  1175.                     SetLastError(ERROR_BAD_EXE_FORMAT);
  1176.                     Result = FALSE;
  1177.                     goto Quickie;
  1178.                 }
  1179.  
  1180.                 /* Check if we need to account for quotes around the path */
  1181.                 CmdQuoteLength = CmdLineIsAppName || HasQuotes;
  1182.                 if (!CmdLineIsAppName)
  1183.                 {
  1184.                     if (HasQuotes) CmdQuoteLength++;
  1185.                 }
  1186.                 else
  1187.                 {
  1188.                     CmdQuoteLength++;
  1189.                 }
  1190.  
  1191.                 /* Calculate the length of the command line */
  1192.                 CmdLineLength = wcslen(lpCommandLine);
  1193.                 CmdLineLength += wcslen(CMD_STRING);
  1194.                 CmdLineLength += CmdQuoteLength + sizeof(ANSI_NULL);
  1195.                 CmdLineLength *= sizeof(WCHAR);
  1196.  
  1197.                 /* Allocate space for the new command line */
  1198.                 AnsiCmdCommand = RtlAllocateHeap(RtlGetProcessHeap(),
  1199.                                                  0,
  1200.                                                  CmdLineLength);
  1201.                 if (!AnsiCmdCommand)
  1202.                 {
  1203.                     BaseSetLastNTError(STATUS_NO_MEMORY);
  1204.                     Result = FALSE;
  1205.                     goto Quickie;
  1206.                 }
  1207.  
  1208.                 /* Build it */
  1209.                 wcscpy(AnsiCmdCommand, CMD_STRING);
  1210.                 if ((CmdLineIsAppName) || (HasQuotes))
  1211.                 {
  1212.                     wcscat(AnsiCmdCommand, L"\"");
  1213.                 }
  1214.                 wcscat(AnsiCmdCommand, lpCommandLine);
  1215.                 if ((CmdLineIsAppName) || (HasQuotes))
  1216.                 {
  1217.                     wcscat(AnsiCmdCommand, L"\"");
  1218.                 }
  1219.  
  1220.                 /* Create it as a Unicode String */
  1221.                 RtlInitUnicodeString(&DebuggerString, AnsiCmdCommand);
  1222.  
  1223.                 /* Set the command line to this */
  1224.                 lpCommandLine = DebuggerString.Buffer;
  1225.                 lpApplicationName = NULL;
  1226.                 DPRINT1("Retrying with: %S\n", lpCommandLine);
  1227.             }
  1228.  
  1229.             /* We've already done all these checks, don't do them again */
  1230.             SkipSaferAndAppCompat = TRUE;
  1231.             goto AppNameRetry;
  1232.         }
  1233.  
  1234.         case STATUS_INVALID_IMAGE_WIN_64:
  1235.         {
  1236.             /* 64-bit binaries are not allowed to run on 32-bit ReactOS */
  1237.             DPRINT1("64-bit binary, failing\n");
  1238.             SetLastError(ERROR_EXE_MACHINE_TYPE_MISMATCH);
  1239.             Result = FALSE;
  1240.             goto Quickie;
  1241.         }
  1242.  
  1243.         case STATUS_FILE_IS_OFFLINE:
  1244.         {
  1245.             /* Set the correct last error for this */
  1246.             DPRINT1("File is offline, failing\n");
  1247.             SetLastError(ERROR_FILE_OFFLINE);
  1248.             break;
  1249.         }
  1250.  
  1251.         default:
  1252.         {
  1253.             /* Any other error, convert it to a generic Win32 error */
  1254.             if (!NT_SUCCESS(Status))
  1255.             {
  1256.                 DPRINT1("Failed to create section: %lx\n", Status);
  1257.                 SetLastError(ERROR_BAD_EXE_FORMAT);
  1258.                 Result = FALSE;
  1259.                 goto Quickie;
  1260.             }
  1261.  
  1262.             /* Otherwise, this must be success */
  1263.             ASSERT(Status == STATUS_SUCCESS);
  1264.             break;
  1265.         }
  1266.     }
  1267.  
  1268.     /* Is this not a WOW application, but a WOW32 VDM was requested for it? */
  1269.     if (!(IsWowApp) && (dwCreationFlags & CREATE_SEPARATE_WOW_VDM))
  1270.     {
  1271.         /* Ignore the nonsensical request */
  1272.         dwCreationFlags &= ~CREATE_SEPARATE_WOW_VDM;
  1273.     }
  1274.  
  1275.     /* Did we already check information for the section? */
  1276.     if (!QuerySection)
  1277.     {
  1278.         /* Get some information about the executable */
  1279.         Status = NtQuerySection(SectionHandle,
  1280.                                 SectionImageInformation,
  1281.                                 &ImageInformation,
  1282.                                 sizeof(ImageInformation),
  1283.                                 NULL);
  1284.         if (!NT_SUCCESS(Status))
  1285.         {
  1286.             /* We failed, bail out */
  1287.             DPRINT1("Section query failed\n");
  1288.             BaseSetLastNTError(Status);
  1289.             Result = FALSE;
  1290.             goto Quickie;
  1291.         }
  1292.  
  1293.         /* Don't check this later */
  1294.         QuerySection = TRUE;
  1295.     }
  1296.  
  1297.     /* Check if this was linked as a DLL */
  1298.     if (ImageInformation.ImageCharacteristics & IMAGE_FILE_DLL)
  1299.     {
  1300.         /* These aren't valid images to try to execute! */
  1301.         DPRINT1("Trying to launch a DLL, failing\n");
  1302.         SetLastError(ERROR_BAD_EXE_FORMAT);
  1303.         Result = FALSE;
  1304.         goto Quickie;
  1305.     }
  1306.  
  1307.     /* Don't let callers pass in this flag -- we'll only get it from IFEO */
  1308.     Flags &= ~PROCESS_CREATE_FLAGS_LARGE_PAGES;
  1309.  
  1310.     /* Clear the IFEO-missing flag, before we know for sure... */
  1311.     ParameterFlags &= ~2;
  1312.  
  1313.     /* If the process is being debugged, only read IFEO if the PEB says so */
  1314.     if (!(dwCreationFlags & (DEBUG_PROCESS | DEBUG_ONLY_THIS_PROCESS)) ||
  1315.         (NtCurrentPeb()->ReadImageFileExecOptions))
  1316.     {
  1317.         /* Let's do this! Attempt to open IFEO */
  1318.         IFEOStatus = LdrOpenImageFileOptionsKey(&PathName, 0, &KeyHandle);
  1319.         if (!NT_SUCCESS(IFEOStatus))
  1320.         {
  1321.             /* We failed, set the flag so we store this in the parameters */
  1322.             if (IFEOStatus == STATUS_OBJECT_NAME_NOT_FOUND) ParameterFlags |= 2;
  1323.         }
  1324.         else
  1325.         {
  1326.             /* Was this our first time going through this path? */
  1327.             if (!DebuggerCmdLine)
  1328.             {
  1329.                 /* Allocate a buffer for the debugger path */
  1330.                 DebuggerCmdLine = RtlAllocateHeap(RtlGetProcessHeap(),
  1331.                                                   0,
  1332.                                                   MAX_PATH * sizeof(WCHAR));
  1333.                 if (!DebuggerCmdLine)
  1334.                 {
  1335.                     /* Close IFEO on failure */
  1336.                     IFEOStatus = NtClose(KeyHandle);
  1337.                     ASSERT(NT_SUCCESS(IFEOStatus));
  1338.  
  1339.                     /* Fail the call */
  1340.                     SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  1341.                     Result = FALSE;
  1342.                     goto Quickie;
  1343.                 }
  1344.             }
  1345.  
  1346.             /* Now query for the debugger */
  1347.             IFEOStatus = LdrQueryImageFileKeyOption(KeyHandle,
  1348.                                                  L"Debugger",
  1349.                                                  REG_SZ,
  1350.                                                  DebuggerCmdLine,
  1351.                                                  MAX_PATH * sizeof(WCHAR),
  1352.                                                  &ResultSize);
  1353.             if (!(NT_SUCCESS(IFEOStatus)) ||
  1354.                 (ResultSize < sizeof(WCHAR)) ||
  1355.                 (DebuggerCmdLine[0] == UNICODE_NULL))
  1356.             {
  1357.                 /* If it's not there, or too small, or invalid, ignore it */
  1358.                 RtlFreeHeap(RtlGetProcessHeap(), 0, DebuggerCmdLine);
  1359.                 DebuggerCmdLine = NULL;
  1360.             }
  1361.  
  1362.             /* Also query if we should map with large pages */
  1363.             IFEOStatus = LdrQueryImageFileKeyOption(KeyHandle,
  1364.                                                  L"UseLargePages",
  1365.                                                  REG_DWORD,
  1366.                                                  &UseLargePages,
  1367.                                                  sizeof(UseLargePages),
  1368.                                                  NULL);
  1369.             if ((NT_SUCCESS(IFEOStatus)) && (UseLargePages))
  1370.             {
  1371.                 /* Do it! This is the only way this flag can be set */
  1372.                 Flags |= PROCESS_CREATE_FLAGS_LARGE_PAGES;
  1373.             }
  1374.  
  1375.             /* We're done with IFEO, can close it now */
  1376.             IFEOStatus = NtClose(KeyHandle);
  1377.             ASSERT(NT_SUCCESS(IFEOStatus));
  1378.         }
  1379.     }
  1380.  
  1381.     /* Make sure the image was compiled for this processor */
  1382.     if ((ImageInformation.Machine < SharedUserData->ImageNumberLow) ||
  1383.         (ImageInformation.Machine > SharedUserData->ImageNumberHigh))
  1384.     {
  1385.         /* It was not -- raise a hard error */
  1386.         ErrorResponse = ResponseOk;
  1387.         ErrorParameters[0] = (ULONG_PTR)&PathName;
  1388.         NtRaiseHardError(STATUS_IMAGE_MACHINE_TYPE_MISMATCH_EXE,
  1389.                          1,
  1390.                          1,
  1391.                          ErrorParameters,
  1392.                          OptionOk,
  1393.                          &ErrorResponse);
  1394.         if (Peb->ImageSubsystemMajorVersion <= 3)
  1395.         {
  1396.             /* If it's really old, return this error */
  1397.             SetLastError(ERROR_BAD_EXE_FORMAT);
  1398.         }
  1399.         else
  1400.         {
  1401.             /* Otherwise, return a more modern error */
  1402.             SetLastError(ERROR_EXE_MACHINE_TYPE_MISMATCH);
  1403.         }
  1404.  
  1405.         /* Go to the failure path */
  1406.         DPRINT1("Invalid image architecture: %lx\n", ImageInformation.Machine);
  1407.         Result = FALSE;
  1408.         goto Quickie;
  1409.     }
  1410.  
  1411.     /* Check if this isn't a Windows image */
  1412.     if ((ImageInformation.SubSystemType != IMAGE_SUBSYSTEM_WINDOWS_GUI) &&
  1413.         (ImageInformation.SubSystemType != IMAGE_SUBSYSTEM_WINDOWS_CUI))
  1414.     {
  1415.         /* Get rid of section-related information since we'll retry */
  1416.         NtClose(SectionHandle);
  1417.         SectionHandle = NULL;
  1418.         QuerySection = FALSE;
  1419.  
  1420.         /* The only other non-Windows image type we support here is POSIX */
  1421.         if (ImageInformation.SubSystemType != IMAGE_SUBSYSTEM_POSIX_CUI)
  1422.         {
  1423.             /* Bail out if it's something else */
  1424.             SetLastError(ERROR_CHILD_NOT_COMPLETE);
  1425.             Result = FALSE;
  1426.             goto Quickie;
  1427.         }
  1428.  
  1429.         /* Now build the command-line to have posix launch this image */
  1430.         Result = BuildSubSysCommandLine(L"POSIX /P ",
  1431.                                         lpApplicationName,
  1432.                                         lpCommandLine,
  1433.                                         &DebuggerString);
  1434.         if (!Result)
  1435.         {
  1436.             /* Bail out if that failed */
  1437.             DPRINT1("Subsystem command line failed\n");
  1438.             goto Quickie;
  1439.         }
  1440.  
  1441.         /* And re-try launching the process, with the new command-line now */
  1442.         lpCommandLine = DebuggerString.Buffer;
  1443.         lpApplicationName = NULL;
  1444.  
  1445.         /* We've already done all these checks, don't do them again */
  1446.         SkipSaferAndAppCompat = TRUE;
  1447.         DPRINT1("Retrying with: %S\n", lpCommandLine);
  1448.         goto AppNameRetry;
  1449.     }
  1450.  
  1451.     /* Was this image built for a version of Windows whose images we can run? */
  1452.     Result = BasepIsImageVersionOk(ImageInformation.SubSystemMajorVersion,
  1453.                                    ImageInformation.SubSystemMinorVersion);
  1454.     if (!Result)
  1455.     {
  1456.         /* It was not, bail out */
  1457.         DPRINT1("Invalid subsystem version: %hu.%hu\n",
  1458.                 ImageInformation.SubSystemMajorVersion,
  1459.                 ImageInformation.SubSystemMinorVersion);
  1460.         SetLastError(ERROR_BAD_EXE_FORMAT);
  1461.         goto Quickie;
  1462.     }
  1463.  
  1464.     /* Check if there is a debugger associated with the application */
  1465.     if (DebuggerCmdLine)
  1466.     {
  1467.         /* Get the length of the command line */
  1468.         n = wcslen(lpCommandLine);
  1469.         if (!n)
  1470.         {
  1471.             /* There's no command line, use the application name instead */
  1472.             lpCommandLine = (LPWSTR)lpApplicationName;
  1473.             n = wcslen(lpCommandLine);
  1474.         }
  1475.  
  1476.         /* Protect against overflow */
  1477.         if (n > UNICODE_STRING_MAX_CHARS)
  1478.         {
  1479.             BaseSetLastNTError(STATUS_NAME_TOO_LONG);
  1480.             Result = FALSE;
  1481.             goto Quickie;
  1482.         }
  1483.  
  1484.         /* Now add the length of the debugger command-line */
  1485.         n += wcslen(DebuggerCmdLine);
  1486.  
  1487.         /* Again make sure we don't overflow */
  1488.         if (n > UNICODE_STRING_MAX_CHARS)
  1489.         {
  1490.             BaseSetLastNTError(STATUS_NAME_TOO_LONG);
  1491.             Result = FALSE;
  1492.             goto Quickie;
  1493.         }
  1494.  
  1495.         /* Account for the quotes and space between the two */
  1496.         n += sizeof("\" \"") - sizeof(ANSI_NULL);
  1497.  
  1498.         /* Convert to bytes, and make sure we don't overflow */
  1499.         n *= sizeof(WCHAR);
  1500.         if (n > UNICODE_STRING_MAX_BYTES)
  1501.         {
  1502.             BaseSetLastNTError(STATUS_NAME_TOO_LONG);
  1503.             Result = FALSE;
  1504.             goto Quickie;
  1505.         }
  1506.  
  1507.         /* Allocate space for the string */
  1508.         DebuggerString.Buffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, n);
  1509.         if (!DebuggerString.Buffer)
  1510.         {
  1511.             SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  1512.             Result = FALSE;
  1513.             goto Quickie;
  1514.         }
  1515.  
  1516.         /* Set the length */
  1517.         RtlInitEmptyUnicodeString(&DebuggerString,
  1518.                                   DebuggerString.Buffer,
  1519.                                   (USHORT)n);
  1520.  
  1521.         /* Now perform the command line creation */
  1522.         ImageDbgStatus = RtlAppendUnicodeToString(&DebuggerString,
  1523.                                                   DebuggerCmdLine);
  1524.         ASSERT(NT_SUCCESS(ImageDbgStatus));
  1525.         ImageDbgStatus = RtlAppendUnicodeToString(&DebuggerString, L" ");
  1526.         ASSERT(NT_SUCCESS(ImageDbgStatus));
  1527.         ImageDbgStatus = RtlAppendUnicodeToString(&DebuggerString, lpCommandLine);
  1528.         ASSERT(NT_SUCCESS(ImageDbgStatus));
  1529.  
  1530.         /* Make sure it all looks nice */
  1531.         DbgPrint("BASE: Calling debugger with '%wZ'\n", &DebuggerString);
  1532.  
  1533.         /* Update the command line and application name */
  1534.         lpCommandLine = DebuggerString.Buffer;
  1535.         lpApplicationName = NULL;
  1536.  
  1537.         /* Close all temporary state */
  1538.         NtClose(SectionHandle);
  1539.         SectionHandle = NULL;
  1540.         QuerySection = FALSE;
  1541.  
  1542.         /* Free all temporary memory */
  1543.         RtlFreeHeap(RtlGetProcessHeap(), 0, NameBuffer);
  1544.         NameBuffer = NULL;
  1545.         RtlFreeHeap(RtlGetProcessHeap(), 0, FreeBuffer);
  1546.         FreeBuffer = NULL;
  1547.         RtlFreeHeap(RtlGetProcessHeap(), 0, DebuggerCmdLine);
  1548.         DebuggerCmdLine = NULL;
  1549.         DPRINT1("Retrying with: %S\n", lpCommandLine);
  1550.         goto AppNameRetry;
  1551.     }
  1552.  
  1553.     /* Initialize the process object attributes */
  1554.     ObjectAttributes = BaseFormatObjectAttributes(&LocalObjectAttributes,
  1555.                                                   lpProcessAttributes,
  1556.                                                   NULL);
  1557.     if ((hUserToken) && (lpProcessAttributes))
  1558.     {
  1559.         /* Augment them with information from the user */
  1560.  
  1561.         LocalProcessAttributes = *lpProcessAttributes;
  1562.         LocalProcessAttributes.lpSecurityDescriptor = NULL;
  1563.         ObjectAttributes = BaseFormatObjectAttributes(&LocalObjectAttributes,
  1564.                                                       &LocalProcessAttributes,
  1565.                                                       NULL);
  1566.     }
  1567.  
  1568.     /* Check if we're going to be debugged */
  1569.     if (dwCreationFlags & DEBUG_PROCESS)
  1570.     {
  1571.         /* Set process flag */
  1572.         Flags |= PROCESS_CREATE_FLAGS_BREAKAWAY;
  1573.     }
  1574.  
  1575.     /* Check if we're going to be debugged */
  1576.     if (dwCreationFlags & (DEBUG_PROCESS | DEBUG_ONLY_THIS_PROCESS))
  1577.     {
  1578.         /* Connect to DbgUi */
  1579.         Status = DbgUiConnectToDbg();
  1580.         if (!NT_SUCCESS(Status))
  1581.         {
  1582.             DPRINT1("Failed to connect to DbgUI!\n");
  1583.             BaseSetLastNTError(Status);
  1584.             Result = FALSE;
  1585.             goto Quickie;
  1586.         }
  1587.  
  1588.         /* Get the debug object */
  1589.         DebugHandle = DbgUiGetThreadDebugObject();
  1590.  
  1591.         /* Check if only this process will be debugged */
  1592.         if (dwCreationFlags & DEBUG_ONLY_THIS_PROCESS)
  1593.         {
  1594.             /* Set process flag */
  1595.             Flags |= PROCESS_CREATE_FLAGS_NO_DEBUG_INHERIT;
  1596.         }
  1597.     }
  1598.  
  1599.     /* Set inherit flag */
  1600.     if (bInheritHandles) Flags |= PROCESS_CREATE_FLAGS_INHERIT_HANDLES;
  1601.  
  1602.     /* Check if the process should be created with large pages */
  1603.     HavePrivilege = FALSE;
  1604.     PrivilegeState = NULL;
  1605.     if (Flags & PROCESS_CREATE_FLAGS_LARGE_PAGES)
  1606.     {
  1607.         /* Acquire the required privilege so that the kernel won't fail the call */
  1608.         PrivilegeValue = SE_LOCK_MEMORY_PRIVILEGE;
  1609.         Status = RtlAcquirePrivilege(&PrivilegeValue, 1, 0, &PrivilegeState);
  1610.         if (NT_SUCCESS(Status))
  1611.         {
  1612.             /* Remember to release it later */
  1613.             HavePrivilege = TRUE;
  1614.         }
  1615.     }
  1616.  
  1617.     /* Save the current TIB value since kernel overwrites it to store PEB */
  1618.     TibValue = Teb->NtTib.ArbitraryUserPointer;
  1619.  
  1620.     /* Tell the kernel to create the process */
  1621.     Status = NtCreateProcessEx(&ProcessHandle,
  1622.                                PROCESS_ALL_ACCESS,
  1623.                                ObjectAttributes,
  1624.                                NtCurrentProcess(),
  1625.                                Flags,
  1626.                                SectionHandle,
  1627.                                DebugHandle,
  1628.                                NULL,
  1629.                                InJob);
  1630.  
  1631.     /* Load the PEB address from the hacky location where the kernel stores it */
  1632.     RemotePeb = Teb->NtTib.ArbitraryUserPointer;
  1633.  
  1634.     /* And restore the old TIB value */
  1635.     Teb->NtTib.ArbitraryUserPointer = TibValue;
  1636.  
  1637.     /* Release the large page privilege if we had acquired it */
  1638.     if (HavePrivilege) RtlReleasePrivilege(PrivilegeState);
  1639.  
  1640.     /* And now check if the kernel failed to create the process */
  1641.     if (!NT_SUCCESS(Status))
  1642.     {
  1643.         /* Go to failure path */
  1644.         DPRINT1("Failed to create process: %lx\n", Status);
  1645.         BaseSetLastNTError(Status);
  1646.         Result = FALSE;
  1647.         goto Quickie;
  1648.     }
  1649.  
  1650.     /* Check if there is a priority class to set */
  1651.     if (PriorityClass.PriorityClass)
  1652.     {
  1653.         /* Reset current privilege state */
  1654.         RealTimePrivilegeState = NULL;
  1655.  
  1656.         /* Is realtime priority being requested? */
  1657.         if (PriorityClass.PriorityClass == PROCESS_PRIORITY_CLASS_REALTIME)
  1658.         {
  1659.             /* Check if the caller has real-time access, and enable it if so */
  1660.             RealTimePrivilegeState = BasepIsRealtimeAllowed(TRUE);
  1661.         }
  1662.  
  1663.         /* Set the new priority class and release the privilege */
  1664.         Status = NtSetInformationProcess(ProcessHandle,
  1665.                                          ProcessPriorityClass,
  1666.                                          &PriorityClass,
  1667.                                          sizeof(PROCESS_PRIORITY_CLASS));
  1668.         if (RealTimePrivilegeState) RtlReleasePrivilege(RealTimePrivilegeState);
  1669.  
  1670.         /* Check if we failed to set the priority class */
  1671.         if (!NT_SUCCESS(Status))
  1672.         {
  1673.             /* Bail out on failure */
  1674.             DPRINT1("Failed to set priority class: %lx\n", Status);
  1675.             BaseSetLastNTError(Status);
  1676.             Result = FALSE;
  1677.             goto Quickie;
  1678.         }
  1679.     }
  1680.  
  1681.     /* Check if the caller wants the default error mode */
  1682.     if (dwCreationFlags & CREATE_DEFAULT_ERROR_MODE)
  1683.     {
  1684.         /* Set Error Mode to only fail on critical errors */
  1685.         HardErrorMode = SEM_FAILCRITICALERRORS;
  1686.         NtSetInformationProcess(ProcessHandle,
  1687.                                 ProcessDefaultHardErrorMode,
  1688.                                 &HardErrorMode,
  1689.                                 sizeof(ULONG));
  1690.     }
  1691.  
  1692.     /* Check if this was a VDM binary */
  1693.     if (VdmBinaryType)
  1694.     {
  1695.         /* Update VDM by telling it the process has now been created */
  1696.         VdmWaitObject = ProcessHandle;
  1697.         Result = BaseUpdateVDMEntry(VdmEntryUpdateProcess,
  1698.                                     &VdmWaitObject,
  1699.                                     VdmTask,
  1700.                                     VdmBinaryType);
  1701.  
  1702.         if (!Result)
  1703.         {
  1704.             /* Bail out on failure */
  1705.             DPRINT1("Failed to update VDM with wait object\n");
  1706.             VdmWaitObject = NULL;
  1707.             goto Quickie;
  1708.         }
  1709.  
  1710.         /* At this point, a failure means VDM has to undo all the state */
  1711.         VdmUndoLevel |= VDM_UNDO_FULL;
  1712.     }
  1713.  
  1714.     /* Check if VDM needed reserved low-memory */
  1715.     if (VdmReserve)
  1716.     {
  1717.         /* Reserve the requested allocation */
  1718.         Status = NtAllocateVirtualMemory(ProcessHandle,
  1719.                                          &BaseAddress,
  1720.                                          0,
  1721.                                          &VdmReserve,
  1722.                                          MEM_RESERVE,
  1723.                                          PAGE_EXECUTE_READWRITE);
  1724.         if (!NT_SUCCESS(Status))
  1725.         {
  1726.             /* Bail out on failure */
  1727.             DPRINT1("Failed to reserve memory for VDM: %lx\n", Status);
  1728.             BaseSetLastNTError(Status);
  1729.             Result = FALSE;
  1730.             goto Quickie;
  1731.         }
  1732.     }
  1733.  
  1734.     /* Check if we've already queried information on the section */
  1735.     if (!QuerySection)
  1736.     {
  1737.         /* We haven't, so get some information about the executable */
  1738.         Status = NtQuerySection(SectionHandle,
  1739.                                 SectionImageInformation,
  1740.                                 &ImageInformation,
  1741.                                 sizeof(ImageInformation),
  1742.                                 NULL);
  1743.         if (!NT_SUCCESS(Status))
  1744.         {
  1745.             /* Bail out on failure */
  1746.             DPRINT1("Failed to query section: %lx\n", Status);
  1747.             BaseSetLastNTError(Status);
  1748.             Result = FALSE;
  1749.             goto Quickie;
  1750.         }
  1751.  
  1752.         /* If we encounter a restart, don't re-query this information again */
  1753.         QuerySection = TRUE;
  1754.     }
  1755.  
  1756.     /* Do we need to apply SxS to this image? */
  1757.     if (!(ImageInformation.DllCharacteristics & IMAGE_DLLCHARACTERISTICS_NO_ISOLATION))
  1758.     {
  1759.         /* Too bad, we don't support this yet */
  1760.         DPRINT1("Image should receive SxS Fusion Isolation\n");
  1761.     }
  1762.  
  1763.     /* There's some SxS flag that we need to set if fusion flags have 1 set */
  1764.     if (FusionFlags & 1) CreateProcessMsg->Sxs.Flags |= 0x10;
  1765.  
  1766.     /* Check if we have a current directory */
  1767.     if (lpCurrentDirectory)
  1768.     {
  1769.         /* Allocate a buffer so we can keep a Unicode copy */
  1770.         DPRINT("Current directory: %S\n", lpCurrentDirectory);
  1771.         CurrentDirectory = RtlAllocateHeap(RtlGetProcessHeap(),
  1772.                                            0,
  1773.                                            (MAX_PATH * sizeof(WCHAR)) +
  1774.                                            sizeof(UNICODE_NULL));
  1775.         if (!CurrentDirectory)
  1776.         {
  1777.             /* Bail out if this failed */
  1778.             BaseSetLastNTError(STATUS_NO_MEMORY);
  1779.             Result = FALSE;
  1780.             goto Quickie;
  1781.         }
  1782.  
  1783.         /* Get the length in Unicode */
  1784.         Length = GetFullPathNameW(lpCurrentDirectory,
  1785.                                   MAX_PATH,
  1786.                                   CurrentDirectory,
  1787.                                   &FilePart);
  1788.         if (Length > MAX_PATH)
  1789.         {
  1790.             /* The directory is too long, so bail out */
  1791.             SetLastError(ERROR_DIRECTORY);
  1792.             Result = FALSE;
  1793.             goto Quickie;
  1794.         }
  1795.  
  1796.         /* Make sure the directory is actually valid */
  1797.         FileAttribs = GetFileAttributesW(CurrentDirectory);
  1798.         if ((FileAttribs == INVALID_FILE_ATTRIBUTES) ||
  1799.            !(FileAttribs & FILE_ATTRIBUTE_DIRECTORY))
  1800.         {
  1801.             /* It isn't, so bail out */
  1802.             DPRINT1("Current directory is invalid\n");
  1803.             SetLastError(ERROR_DIRECTORY);
  1804.             Result = FALSE;
  1805.             goto Quickie;
  1806.         }
  1807.     }
  1808.  
  1809.     /* Insert quotes if needed */
  1810.     if ((QuotesNeeded) || (CmdLineIsAppName))
  1811.     {
  1812.         /* Allocate our buffer, plus enough space for quotes and a NULL */
  1813.         QuotedCmdLine = RtlAllocateHeap(RtlGetProcessHeap(),
  1814.                                         0,
  1815.                                         (wcslen(lpCommandLine) * sizeof(WCHAR)) +
  1816.                                         (2 * sizeof(L'\"') + sizeof(UNICODE_NULL)));
  1817.         if (QuotedCmdLine)
  1818.         {
  1819.             /* Copy the first quote */
  1820.             wcscpy(QuotedCmdLine, L"\"");
  1821.  
  1822.             /* Save the current null-character */
  1823.             if (QuotesNeeded)
  1824.             {
  1825.                 SaveChar = *NullBuffer;
  1826.                 *NullBuffer = UNICODE_NULL;
  1827.             }
  1828.  
  1829.             /* Copy the command line and the final quote */
  1830.             wcscat(QuotedCmdLine, lpCommandLine);
  1831.             wcscat(QuotedCmdLine, L"\"");
  1832.  
  1833.             /* Copy the null-char back */
  1834.             if (QuotesNeeded)
  1835.             {
  1836.                 *NullBuffer = SaveChar;
  1837.                 wcscat(QuotedCmdLine, NullBuffer);
  1838.             }
  1839.         }
  1840.         else
  1841.         {
  1842.             /* We can't put quotes around the thing, so try it anyway */
  1843.             if (QuotesNeeded) QuotesNeeded = FALSE;
  1844.             if (CmdLineIsAppName) CmdLineIsAppName = FALSE;
  1845.         }
  1846.     }
  1847.  
  1848.     /* Use isolation if needed */
  1849.     if (CreateProcessMsg->Sxs.Flags & 1) ParameterFlags |= 1;
  1850.  
  1851.     /* Set the new command-line if needed */
  1852.     if ((QuotesNeeded) || (CmdLineIsAppName)) lpCommandLine = QuotedCmdLine;
  1853.  
  1854.     /* Call the helper function in charge of RTL_USER_PROCESS_PARAMETERS */
  1855.     Result = BasePushProcessParameters(ParameterFlags,
  1856.                                        ProcessHandle,
  1857.                                        RemotePeb,
  1858.                                        lpApplicationName,
  1859.                                        CurrentDirectory,
  1860.                                        lpCommandLine,
  1861.                                        lpEnvironment,
  1862.                                        &StartupInfo,
  1863.                                        dwCreationFlags | NoWindow,
  1864.                                        bInheritHandles,
  1865.                                        IsWowApp ? IMAGE_SUBSYSTEM_WINDOWS_GUI: 0,
  1866.                                        AppCompatData,
  1867.                                        AppCompatDataSize);
  1868.     if (!Result)
  1869.     {
  1870.         /* The remote process would have an undefined state, so fail the call */
  1871.         DPRINT1("BasePushProcessParameters failed\n");
  1872.         goto Quickie;
  1873.     }
  1874.  
  1875.     /* Free the VDM command line string as it's no longer needed */
  1876.     RtlFreeUnicodeString(&VdmString);
  1877.     VdmString.Buffer = NULL;
  1878.  
  1879.     /* Non-VDM console applications usually inherit handles unless specified */
  1880.     if (!(VdmBinaryType) &&
  1881.         !(bInheritHandles) &&
  1882.         !(StartupInfo.dwFlags & STARTF_USESTDHANDLES) &&
  1883.         !(dwCreationFlags & (CREATE_NO_WINDOW |
  1884.                              CREATE_NEW_CONSOLE |
  1885.                              DETACHED_PROCESS)) &&
  1886.         (ImageInformation.SubSystemType == IMAGE_SUBSYSTEM_WINDOWS_CUI))
  1887.     {
  1888.         /* Get the remote parameters */
  1889.         Status = NtReadVirtualMemory(ProcessHandle,
  1890.                                      &RemotePeb->ProcessParameters,
  1891.                                      &ProcessParameters,
  1892.                                      sizeof(PRTL_USER_PROCESS_PARAMETERS),
  1893.                                      NULL);
  1894.         if (NT_SUCCESS(Status))
  1895.         {
  1896.             /* Duplicate standard input unless it's a console handle */
  1897.             if (!IsConsoleHandle(Peb->ProcessParameters->StandardInput))
  1898.             {
  1899.                 StuffStdHandle(ProcessHandle,
  1900.                                Peb->ProcessParameters->StandardInput,
  1901.                                &ProcessParameters->StandardInput);
  1902.             }
  1903.  
  1904.             /* Duplicate standard output unless it's a console handle */
  1905.             if (!IsConsoleHandle(Peb->ProcessParameters->StandardOutput))
  1906.             {
  1907.                 StuffStdHandle(ProcessHandle,
  1908.                                Peb->ProcessParameters->StandardOutput,
  1909.                                &ProcessParameters->StandardOutput);
  1910.             }
  1911.  
  1912.             /* Duplicate standard error unless it's a console handle */
  1913.             if (!IsConsoleHandle(Peb->ProcessParameters->StandardError))
  1914.             {
  1915.                 StuffStdHandle(ProcessHandle,
  1916.                                Peb->ProcessParameters->StandardError,
  1917.                                &ProcessParameters->StandardError);
  1918.             }
  1919.         }
  1920.     }
  1921.  
  1922.     /* Create the Thread's Stack */
  1923.     StackSize = max(256 * 1024, ImageInformation.MaximumStackSize);
  1924.     Status = BaseCreateStack(ProcessHandle,
  1925.                              ImageInformation.CommittedStackSize,
  1926.                              StackSize,
  1927.                              &InitialTeb);
  1928.     if (!NT_SUCCESS(Status))
  1929.     {
  1930.         DPRINT1("Creating the thread stack failed: %lx\n", Status);
  1931.         BaseSetLastNTError(Status);
  1932.         Result = FALSE;
  1933.         goto Quickie;
  1934.     }
  1935.  
  1936.     /* Create the Thread's Context */
  1937.     BaseInitializeContext(&Context,
  1938.                           Peb,
  1939.                           ImageInformation.TransferAddress,
  1940.                           InitialTeb.StackBase,
  1941.                           0);
  1942.  
  1943.     /* Convert the thread attributes */
  1944.     ObjectAttributes = BaseFormatObjectAttributes(&LocalObjectAttributes,
  1945.                                                   lpThreadAttributes,
  1946.                                                   NULL);
  1947.     if ((hUserToken) && (lpThreadAttributes))
  1948.     {
  1949.         /* If the caller specified a user token, zero the security descriptor */
  1950.         LocalThreadAttributes = *lpThreadAttributes;
  1951.         LocalThreadAttributes.lpSecurityDescriptor = NULL;
  1952.         ObjectAttributes = BaseFormatObjectAttributes(&LocalObjectAttributes,
  1953.                                                       &LocalThreadAttributes,
  1954.                                                       NULL);
  1955.     }
  1956.  
  1957.     /* Create the Kernel Thread Object */
  1958.     Status = NtCreateThread(&ThreadHandle,
  1959.                             THREAD_ALL_ACCESS,
  1960.                             ObjectAttributes,
  1961.                             ProcessHandle,
  1962.                             &ClientId,
  1963.                             &Context,
  1964.                             &InitialTeb,
  1965.                             TRUE);
  1966.     if (!NT_SUCCESS(Status))
  1967.     {
  1968.         /* A process is not allowed to exist without a main thread, so fail */
  1969.         DPRINT1("Creating the main thread failed: %lx\n", Status);
  1970.         BaseSetLastNTError(Status);
  1971.         Result = FALSE;
  1972.         goto Quickie;
  1973.     }
  1974.  
  1975.     /* Begin filling out the CSRSS message, first with our IDs and handles */
  1976.     CreateProcessMsg->ProcessHandle = ProcessHandle;
  1977.     CreateProcessMsg->ThreadHandle = ThreadHandle;
  1978.     CreateProcessMsg->ClientId = ClientId;
  1979.  
  1980.     /* Write the remote PEB address and clear it locally, we no longer use it */
  1981.     CreateProcessMsg->PebAddressNative = RemotePeb;
  1982.     CreateProcessMsg->PebAddressWow64 = (ULONG)RemotePeb;
  1983.     RemotePeb = NULL;
  1984.  
  1985.     /* Now check what kind of architecture this image was made for */
  1986.     switch (ImageInformation.Machine)
  1987.     {
  1988.         /* IA32, IA64 and AMD64 are supported in Server 2003 */
  1989.         case IMAGE_FILE_MACHINE_I386:
  1990.             CreateProcessMsg->ProcessorArchitecture = PROCESSOR_ARCHITECTURE_INTEL;
  1991.             break;
  1992.         case IMAGE_FILE_MACHINE_IA64:
  1993.             CreateProcessMsg->ProcessorArchitecture = PROCESSOR_ARCHITECTURE_IA64;
  1994.             break;
  1995.         case IMAGE_FILE_MACHINE_AMD64:
  1996.             CreateProcessMsg->ProcessorArchitecture = PROCESSOR_ARCHITECTURE_AMD64;
  1997.             break;
  1998.  
  1999.         /* Anything else results in image unknown -- but no failure */
  2000.         default:
  2001.             DbgPrint("kernel32: No mapping for ImageInformation.Machine == %04x\n",
  2002.                      ImageInformation.Machine);
  2003.             CreateProcessMsg->ProcessorArchitecture = PROCESSOR_ARCHITECTURE_UNKNOWN;
  2004.             break;
  2005.     }
  2006.  
  2007.     /* Write the input creation flags except any debugger-related flags */
  2008.     CreateProcessMsg->CreationFlags = dwCreationFlags &
  2009.                                       ~(DEBUG_PROCESS | DEBUG_ONLY_THIS_PROCESS);
  2010.  
  2011.     /* CSRSS needs to know if this is a GUI app or not */
  2012.     if ((ImageInformation.SubSystemType == IMAGE_SUBSYSTEM_WINDOWS_GUI) ||
  2013.         (IsWowApp))
  2014.     {
  2015.         /*
  2016.          * For GUI apps we turn on the 2nd bit. This allow CSRSS server dlls
  2017.          * (basesrv in particular) to know whether or not this is a GUI or a
  2018.          * TUI application.
  2019.          */
  2020.         AddToHandle(CreateProcessMsg->ProcessHandle, 2);
  2021.  
  2022.         /* Also check if the parent is also a GUI process */
  2023.         NtHeaders = RtlImageNtHeader(GetModuleHandle(NULL));
  2024.         if ((NtHeaders) &&
  2025.             (NtHeaders->OptionalHeader.Subsystem == IMAGE_SUBSYSTEM_WINDOWS_GUI))
  2026.         {
  2027.             /* Let it know that it should display the hourglass mouse cursor */
  2028.             AddToHandle(CreateProcessMsg->ProcessHandle, 1);
  2029.         }
  2030.     }
  2031.  
  2032.     /* For all apps, if this flag is on, the hourglass mouse cursor is shown */
  2033.     if (StartupInfo.dwFlags & STARTF_FORCEONFEEDBACK)
  2034.     {
  2035.         AddToHandle(CreateProcessMsg->ProcessHandle, 1);
  2036.     }
  2037.  
  2038.     /* Likewise, the opposite holds as well */
  2039.     if (StartupInfo.dwFlags & STARTF_FORCEOFFFEEDBACK)
  2040.     {
  2041.         RemoveFromHandle(CreateProcessMsg->ProcessHandle, 1);
  2042.     }
  2043.  
  2044.     /* Also store which kind of VDM app (if any) this is */
  2045.     CreateProcessMsg->VdmBinaryType = VdmBinaryType;
  2046.  
  2047.     /* And if it really is a VDM app... */
  2048.     if (VdmBinaryType)
  2049.     {
  2050.         /* Store the task ID and VDM console handle */
  2051.         CreateProcessMsg->hVDM = VdmTask ? 0 : Peb->ProcessParameters->ConsoleHandle;
  2052.         CreateProcessMsg->VdmTask = VdmTask;
  2053.     }
  2054.     else if (VdmReserve)
  2055.     {
  2056.         /* Extended VDM, set a flag */
  2057.         CreateProcessMsg->VdmBinaryType |= BINARY_TYPE_WOW_EX;
  2058.     }
  2059.  
  2060.     /* Check if there's side-by-side assembly data associated with the process */
  2061.     if (CreateProcessMsg->Sxs.Flags)
  2062.     {
  2063.         /* This should not happen in ReactOS yet */
  2064.         DPRINT1("This is an SxS Message -- should not happen yet\n");
  2065.         BaseSetLastNTError(STATUS_NOT_IMPLEMENTED);
  2066.         NtTerminateProcess(ProcessHandle, STATUS_NOT_IMPLEMENTED);
  2067.         Result = FALSE;
  2068.         goto Quickie;
  2069.     }
  2070.  
  2071.     /* We are finally ready to call CSRSS to tell it about our new process! */
  2072.     CsrClientCallServer((PCSR_API_MESSAGE)&CsrMsg[0],
  2073.                         CaptureBuffer,
  2074.                         CSR_CREATE_API_NUMBER(BASESRV_SERVERDLL_INDEX,
  2075.                                               BasepCreateProcess),
  2076.                         sizeof(*CreateProcessMsg));
  2077.  
  2078.     /* CSRSS has returned, free the capture buffer now if we had one */
  2079.     if (CaptureBuffer)
  2080.     {
  2081.         CsrFreeCaptureBuffer(CaptureBuffer);
  2082.         CaptureBuffer = NULL;
  2083.     }
  2084.  
  2085.     /* Check if CSRSS failed to accept ownership of the new Windows process */
  2086.     if (!NT_SUCCESS(CsrMsg[0].Status))
  2087.     {
  2088.         /* Terminate the process and enter failure path with the CSRSS status */
  2089.         DPRINT1("Failed to tell csrss about new process\n");
  2090.         BaseSetLastNTError(CsrMsg[0].Status);
  2091.         NtTerminateProcess(ProcessHandle, CsrMsg[0].Status);
  2092.         Result = FALSE;
  2093.         goto Quickie;
  2094.     }
  2095.  
  2096.     /* Check if we have a token due to Authz/Safer, not passed by the user */
  2097.     if ((TokenHandle) && !(hUserToken))
  2098.     {
  2099.         /* Replace the process and/or thread token with the one from Safer */
  2100.         Status = BasepReplaceProcessThreadTokens(TokenHandle,
  2101.                                                  ProcessHandle,
  2102.                                                  ThreadHandle);
  2103.         if (!NT_SUCCESS(Status))
  2104.         {
  2105.             /* If this failed, kill the process and enter the failure path */
  2106.             DPRINT1("Failed to update process token: %lx\n", Status);
  2107.             NtTerminateProcess(ProcessHandle, Status);
  2108.             BaseSetLastNTError(Status);
  2109.             Result = FALSE;
  2110.             goto Quickie;
  2111.         }
  2112.     }
  2113.  
  2114.     /* Check if a job was associated with this process */
  2115.     if (JobHandle)
  2116.     {
  2117.         /* Bind the process and job together now */
  2118.         Status = NtAssignProcessToJobObject(JobHandle, ProcessHandle);
  2119.         if (!NT_SUCCESS(Status))
  2120.         {
  2121.             /* Kill the process and enter the failure path if binding failed */
  2122.             DPRINT1("Failed to assign process to job: %lx\n", Status);
  2123.             NtTerminateProcess(ProcessHandle, STATUS_ACCESS_DENIED);
  2124.             BaseSetLastNTError(Status);
  2125.             Result = FALSE;
  2126.             goto Quickie;
  2127.         }
  2128.     }
  2129.  
  2130.     /* Finally, resume the thread to actually get the process started */
  2131.     if (!(dwCreationFlags & CREATE_SUSPENDED))
  2132.     {
  2133.         NtResumeThread(ThreadHandle, &ResumeCount);
  2134.     }
  2135.  
  2136. VdmShortCircuit:
  2137.     /* We made it this far, meaning we have a fully created process and thread */
  2138.     Result = TRUE;
  2139.  
  2140.     /* Anyone doing a VDM undo should now undo everything, since we are done */
  2141.     if (VdmUndoLevel) VdmUndoLevel |= VDM_UNDO_COMPLETED;
  2142.  
  2143.     /* Having a VDM wait object implies this must be a VDM process */
  2144.     if (VdmWaitObject)
  2145.     {
  2146.         /* Check if it's a 16-bit separate WOW process */
  2147.         if (VdmBinaryType == BINARY_TYPE_SEPARATE_WOW)
  2148.         {
  2149.             /* OR-in the special flag to indicate this, and return to caller */
  2150.             AddToHandle(VdmWaitObject, 2);
  2151.             lpProcessInformation->hProcess = VdmWaitObject;
  2152.  
  2153.             /* Check if this was a re-used VDM */
  2154.             if (VdmUndoLevel & VDM_UNDO_REUSE)
  2155.             {
  2156.                 /* No Client ID should be returned in this case */
  2157.                 ClientId.UniqueProcess = 0;
  2158.                 ClientId.UniqueThread = 0;
  2159.             }
  2160.         }
  2161.         else
  2162.         {
  2163.             /* OR-in the special flag to indicate this is not a separate VDM */
  2164.             AddToHandle(VdmWaitObject, 1);
  2165.  
  2166.             /* Return handle to the caller */
  2167.             lpProcessInformation->hProcess = VdmWaitObject;
  2168.         }
  2169.  
  2170.         /* Close the original process handle, since it's not needed for VDM */
  2171.         if (ProcessHandle) NtClose(ProcessHandle);
  2172.     }
  2173.     else
  2174.     {
  2175.         /* This is a regular process, so return the real process handle */
  2176.         lpProcessInformation->hProcess = ProcessHandle;
  2177.     }
  2178.  
  2179.     /* Return the rest of the process information based on what we have so far */
  2180.     lpProcessInformation->hThread = ThreadHandle;
  2181.     lpProcessInformation->dwProcessId = HandleToUlong(ClientId.UniqueProcess);
  2182.     lpProcessInformation->dwThreadId = HandleToUlong(ClientId.UniqueThread);
  2183.  
  2184.     /* NULL these out here so we know to treat this as a success scenario */
  2185.     ProcessHandle = NULL;
  2186.     ThreadHandle = NULL;
  2187.  
  2188. Quickie:
  2189.     /* Free the debugger command line if one was allocated */
  2190.     if (DebuggerCmdLine) RtlFreeHeap(RtlGetProcessHeap(), 0, DebuggerCmdLine);
  2191.  
  2192.     /* Check if an SxS full path as queried */
  2193.     if (PathBuffer)
  2194.     {
  2195.         /* Reinitialize the executable path */
  2196.         RtlInitEmptyUnicodeString(&SxsWin32ExePath, NULL, 0);
  2197.         SxsWin32ExePath.Length = 0;
  2198.  
  2199.         /* Free the path buffer */
  2200.         RtlFreeHeap(RtlGetProcessHeap(), 0, PathBuffer);
  2201.     }
  2202.  
  2203. #if _SXS_SUPPORT_ENABLED_
  2204.     /* Check if this was a non-VDM process */
  2205.     if (!VdmBinaryType)
  2206.     {
  2207.         /* Then it must've had SxS data, so close the handles used for it */
  2208.         BasepSxsCloseHandles(&Handles);
  2209.         BasepSxsCloseHandles(&FileHandles);
  2210.  
  2211.         /* Check if we built SxS byte buffers for this create process request */
  2212.         if (SxsConglomeratedBuffer)
  2213.         {
  2214.             /* Loop all of them */
  2215.             for (i = 0; i < 5; i++)
  2216.             {
  2217.                 /* Check if this one was allocated */
  2218.                 ThisBuffer = SxsStaticBuffers[i];
  2219.                 if (ThisBuffer)
  2220.                 {
  2221.                     /* Get the underlying RTL_BUFFER structure */
  2222.                     ByteBuffer = &ThisBuffer->ByteBuffer;
  2223.                     if ((ThisBuffer != (PVOID)-8) && (ByteBuffer->Buffer))
  2224.                     {
  2225.                         /* Check if it was dynamic */
  2226.                         if (ByteBuffer->Buffer != ByteBuffer->StaticBuffer)
  2227.                         {
  2228.                             /* Free it from the heap */
  2229.                             FreeString.Buffer = (PWCHAR)ByteBuffer->Buffer;
  2230.                             RtlFreeUnicodeString(&FreeString);
  2231.                         }
  2232.  
  2233.                         /* Reset the buffer to its static data */
  2234.                         ByteBuffer->Buffer = ByteBuffer->StaticBuffer;
  2235.                         ByteBuffer->Size = ByteBuffer->StaticSize;
  2236.                     }
  2237.  
  2238.                     /* Reset the string to the static buffer */
  2239.                     RtlInitEmptyUnicodeString(&ThisBuffer->String,
  2240.                                               (PWCHAR)ByteBuffer->StaticBuffer,
  2241.                                               ByteBuffer->StaticSize);
  2242.                     if (ThisBuffer->String.Buffer)
  2243.                     {
  2244.                         /* Also NULL-terminate it */
  2245.                         *ThisBuffer->String.Buffer = UNICODE_NULL;
  2246.                     }
  2247.                 }
  2248.             }
  2249.         }
  2250.     }
  2251. #endif
  2252.     /* Check if an environment was passed in */
  2253.     if ((lpEnvironment) && !(dwCreationFlags & CREATE_UNICODE_ENVIRONMENT))
  2254.     {
  2255.         /* Destroy it */
  2256.         RtlDestroyEnvironment(lpEnvironment);
  2257.  
  2258.         /* If this was the VDM environment too, clear that as well */
  2259.         if (VdmUnicodeEnv.Buffer == lpEnvironment) VdmUnicodeEnv.Buffer = NULL;
  2260.         lpEnvironment = NULL;
  2261.     }
  2262.  
  2263.     /* Unconditionally free all the name parsing buffers we always allocate */
  2264.     RtlFreeHeap(RtlGetProcessHeap(), 0, QuotedCmdLine);
  2265.     RtlFreeHeap(RtlGetProcessHeap(), 0, NameBuffer);
  2266.     RtlFreeHeap(RtlGetProcessHeap(), 0, CurrentDirectory);
  2267.     RtlFreeHeap(RtlGetProcessHeap(), 0, FreeBuffer);
  2268.  
  2269.     /* Close open file/section handles */
  2270.     if (FileHandle) NtClose(FileHandle);
  2271.     if (SectionHandle) NtClose(SectionHandle);
  2272.  
  2273.     /* If we have a thread handle, this was a failure path */
  2274.     if (ThreadHandle)
  2275.     {
  2276.         /* So kill the process and close the thread handle */
  2277.         NtTerminateProcess(ProcessHandle, 0);
  2278.         NtClose(ThreadHandle);
  2279.     }
  2280.  
  2281.     /* If we have a process handle, this was a failure path, so close it */
  2282.     if (ProcessHandle) NtClose(ProcessHandle);
  2283.  
  2284.     /* Thread/process handles, if any, are now processed. Now close this one. */
  2285.     if (JobHandle) NtClose(JobHandle);
  2286.  
  2287.     /* Check if we had created a token */
  2288.     if (TokenHandle)
  2289.     {
  2290.         /* And if the user asked for one */
  2291.         if (hUserToken)
  2292.         {
  2293.             /* Then return it */
  2294.             *hNewToken = TokenHandle;
  2295.         }
  2296.         else
  2297.         {
  2298.             /* User didn't want it, so we used it temporarily -- close it */
  2299.             NtClose(TokenHandle);
  2300.         }
  2301.     }
  2302.  
  2303.     /* Free any temporary app compatibility data, it's no longer needed */
  2304.     BasepFreeAppCompatData(AppCompatData, AppCompatSxsData);
  2305.  
  2306.     /* Free a few strings. The API takes care of these possibly being NULL */
  2307.     RtlFreeUnicodeString(&VdmString);
  2308.     RtlFreeUnicodeString(&DebuggerString);
  2309.  
  2310.     /* Check if we had built any sort of VDM environment */
  2311.     if ((VdmAnsiEnv.Buffer) || (VdmUnicodeEnv.Buffer))
  2312.     {
  2313.         /* Free it */
  2314.         BaseDestroyVDMEnvironment(&VdmAnsiEnv, &VdmUnicodeEnv);
  2315.     }
  2316.  
  2317.     /* Check if this was any kind of VDM application that we ended up creating */
  2318.     if ((VdmUndoLevel) && (!(VdmUndoLevel & VDM_UNDO_COMPLETED)))
  2319.     {
  2320.         /* Send an undo */
  2321.         BaseUpdateVDMEntry(VdmEntryUndo,
  2322.                            (PHANDLE)&VdmTask,
  2323.                            VdmUndoLevel,
  2324.                            VdmBinaryType);
  2325.  
  2326.         /* And close whatever VDM handle we were using for notifications */
  2327.         if (VdmWaitObject) NtClose(VdmWaitObject);
  2328.     }
  2329.  
  2330.     /* Check if we ended up here with an allocated search path, and free it */
  2331.     if (SearchPath) RtlFreeHeap(RtlGetProcessHeap(), 0, SearchPath);
  2332.  
  2333.     /* Finally, return the API's result */
  2334.     return Result;
  2335. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement