ReactOS  r76032
proc.c
Go to the documentation of this file.
1 /*
2  * COPYRIGHT: See COPYING in the top level directory
3  * PROJECT: ReactOS system libraries
4  * FILE: dll/win32/kernel32/client/proc.c
5  * PURPOSE: Process functions
6  * PROGRAMMERS: Ariadne (ariadne@xs4all.nl)
7  * UPDATE HISTORY:
8  * Created 01/11/98
9  */
10 
11 /* INCLUDES ****************************************************************/
12 
13 #include <k32.h>
14 
15 #define NDEBUG
16 #include <debug.h>
17 
18 /* GLOBALS *******************************************************************/
19 
33 {
34  {
36  1,
37  L"AppCertDlls",
39  0,
40  NULL,
41  0
42  }
43 };
44 
47 
49 RegisterWaitForInputIdle(WaitForInputIdleType lpfnRegisterWaitForInputIdle);
50 
51 #define CMD_STRING L"cmd /c "
52 
53 /* FUNCTIONS ****************************************************************/
54 
55 VOID
56 WINAPI
58  IN HANDLE StandardHandle,
60 {
62  HANDLE DuplicatedHandle;
63  SIZE_T NumberOfBytesWritten;
64 
65  /* If there is no handle to duplicate, return immediately */
66  if (!StandardHandle) return;
67 
68  /* Duplicate the handle */
70  StandardHandle,
71  ProcessHandle,
72  &DuplicatedHandle,
73  0,
74  0,
77  if (!NT_SUCCESS(Status)) return;
78 
79  /* Write it */
80  NtWriteVirtualMemory(ProcessHandle,
81  Address,
82  &DuplicatedHandle,
83  sizeof(HANDLE),
84  &NumberOfBytesWritten);
85 }
86 
87 BOOLEAN
88 WINAPI
91  IN LPCWSTR CommandLine,
92  OUT PUNICODE_STRING SubsysCommandLine)
93 {
94  UNICODE_STRING CommandLineString, ApplicationNameString;
95  PWCHAR Buffer;
96  ULONG Length;
97 
98  /* Convert to unicode strings */
99  RtlInitUnicodeString(&CommandLineString, ApplicationName);
100  RtlInitUnicodeString(&ApplicationNameString, CommandLine);
101 
102  /* Allocate buffer for the output string */
103  Length = CommandLineString.MaximumLength + ApplicationNameString.MaximumLength + 32;
104  Buffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, Length);
105  RtlInitEmptyUnicodeString(SubsysCommandLine, Buffer, (USHORT)Length);
106  if (!Buffer)
107  {
108  /* Fail, no memory */
110  return FALSE;
111  }
112 
113  /* Build the final subsystem command line */
114  RtlAppendUnicodeToString(SubsysCommandLine, SubsystemName);
115  RtlAppendUnicodeStringToString(SubsysCommandLine, &CommandLineString);
116  RtlAppendUnicodeToString(SubsysCommandLine, L" /C ");
117  RtlAppendUnicodeStringToString(SubsysCommandLine, &ApplicationNameString);
118  return TRUE;
119 }
120 
121 BOOLEAN
122 WINAPI
123 BasepIsImageVersionOk(IN ULONG ImageMajorVersion,
124  IN ULONG ImageMinorVersion)
125 {
126  /* Accept images for NT 3.1 or higher, as long as they're not newer than us */
127  return ((ImageMajorVersion >= 3) &&
128  ((ImageMajorVersion != 3) ||
129  (ImageMinorVersion >= 10)) &&
130  (ImageMajorVersion <= SharedUserData->NtMajorVersion) &&
131  ((ImageMajorVersion != SharedUserData->NtMajorVersion) ||
132  (ImageMinorVersion <= SharedUserData->NtMinorVersion)));
133 }
134 
135 NTSTATUS
136 WINAPI
138 {
140  CHAR Hash[16];
141 
142  /* Get all the MD5 hashes */
143  Status = RtlComputeImportTableHash(FileHandle, Hash, 1);
144  if (!NT_SUCCESS(Status)) return Status;
145 
146  /* Depending on which suite this is, run a bsearch and block the appropriate ones */
147  if (SharedUserData->SuiteMask & VER_SUITE_COMPUTE_SERVER)
148  {
149  DPRINT1("Egad! This is a ReactOS Compute Server and we should prevent you from using certain APIs...but we won't.");
150  }
151  else if (SharedUserData->SuiteMask & VER_SUITE_STORAGE_SERVER)
152  {
153  DPRINT1("Gasp! This is a ReactOS Storage Server and we should prevent you from using certain APIs...but we won't.");
154  }
155  else if (SharedUserData->SuiteMask & VER_SUITE_BLADE)
156  {
157  DPRINT1("Golly! This is a ReactOS Web Blade Server and we should prevent you from using certain APIs...but we won't.");
158  }
159 
160  /* Actually, fuck it, don't block anything, we're open source */
161  return STATUS_SUCCESS;
162 }
163 
164 NTSTATUS
165 NTAPI
167  IN PWCHAR ComponentName,
168  IN PWCHAR DllName)
169 {
170  /* Pretty much the only thing this key is used for, is malware */
172  return STATUS_NOT_IMPLEMENTED;
173 }
174 
175 NTSTATUS
176 NTAPI
181  IN PVOID Context,
183 {
184  /* Add this to the certification list */
185  return BasepSaveAppCertRegistryValue(Context, ValueName, ValueData);
186 }
187 
188 NTSTATUS
189 WINAPI
191 {
192  NTSTATUS Status, Status1;
193  PWCHAR Buffer;
194  UINT Length;
195  HMODULE TrustLibrary;
197  ULONG CertFlag;
198  PLIST_ENTRY NextEntry;
200  UNICODE_STRING CertKey = RTL_CONSTANT_STRING(L"\\Registry\\MACHINE\\System\\CurrentControlSet\\Control\\Session Manager\\AppCertDlls");
202 
203  /* Try to initialize the certification subsystem */
204  while (!g_AppCertInitialized)
205  {
206  /* Defaults */
207  Status = STATUS_SUCCESS;
208  Buffer = NULL;
209 
210  /* Acquire the lock while initializing and see if we lost a race */
211  RtlEnterCriticalSection(&gcsAppCert);
212  if (g_AppCertInitialized) break;
213 
214  /* On embedded, there is a special DLL */
215  if (SharedUserData->SuiteMask & VER_SUITE_EMBEDDEDNT)
216  {
217  /* Allocate a buffer for the name */
218  Buffer = RtlAllocateHeap(RtlGetProcessHeap(),
219  0,
220  MAX_PATH * sizeof(WCHAR) +
221  sizeof(UNICODE_NULL));
222  if (!Buffer)
223  {
224  /* Fail if no memory */
225  Status = STATUS_NO_MEMORY;
226  }
227  else
228  {
229  /* Now get the system32 directory in our buffer, make sure it fits */
230  Length = GetSystemDirectoryW(Buffer, MAX_PATH - sizeof("EmbdTrst.DLL"));
231  if ((Length) && (Length <= MAX_PATH - sizeof("EmbdTrst.DLL")))
232  {
233  /* Add a slash if needed, and add the embedded cert DLL name */
234  if (Buffer[Length - 1] != '\\') Buffer[Length++] = '\\';
235  RtlCopyMemory(&Buffer[Length],
236  L"EmbdTrst.DLL",
237  sizeof(L"EmbdTrst.DLL"));
238 
239  /* Try to load it */
240  TrustLibrary = LoadLibraryW(Buffer);
241  if (TrustLibrary)
242  {
243  /* And extract the special function out of it */
244  fEmbeddedCertFunc = (PVOID)GetProcAddress(TrustLibrary,
245  "ImageOkToRunOnEmbeddedNT");
246  }
247  }
248 
249  /* If we didn't get this far, set a failure code */
250  if (!fEmbeddedCertFunc) Status = STATUS_UNSUCCESSFUL;
251  }
252  }
253  else
254  {
255  /* Other systems have a registry entry for this */
256  Status1 = NtOpenKey(&KeyHandle, KEY_READ, &KeyAttributes);
257  if (NT_SUCCESS(Status1))
258  {
259  /* Close it, we'll query it through Rtl */
260  NtClose(KeyHandle);
261 
262  /* Do the query, which will call a special callback */
264  L"Session Manager",
265  BasepAppCertTable,
266  NULL,
267  NULL);
268  if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
269  {
270  Status = STATUS_SUCCESS;
271  }
272  }
273  }
274 
275  /* Free any buffer if we had one */
276  if (Buffer) RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer);
277 
278  /* Check for errors, or a missing embedded/custom certification DLL */
279  if (!NT_SUCCESS(Status) ||
280  (!(fEmbeddedCertFunc) && (IsListEmpty(&BasepAppCertDllsList))))
281  {
282  /* The subsystem is not active on this machine, so give up */
285  }
286  else
287  {
288  /* We have certification DLLs active, remember this */
290  }
291 
292  /* We are done the initialization phase, release the lock */
294  RtlLeaveCriticalSection(&gcsAppCert);
295  }
296 
297  /* If there's no certification DLLs present, return the failure code */
298  if (!g_HaveAppCerts) return g_AppCertStatus;
299 
300  /* Otherwise, assume success and make sure we have *something* */
301  ASSERT(fEmbeddedCertFunc || !IsListEmpty(&BasepAppCertDllsList));
302  Status = STATUS_SUCCESS;
303 
304  /* If the something is an embedded certification DLL, call it and return */
305  if (fEmbeddedCertFunc) return fEmbeddedCertFunc(ApplicationName);
306 
307  /* Otherwise we have custom certification DLLs, parse them */
308  NextEntry = BasepAppCertDllsList.Flink;
309  CertFlag = 2;
310  while (NextEntry != &BasepAppCertDllsList)
311  {
312  /* Make sure the entry has a callback */
313  Entry = CONTAINING_RECORD(NextEntry, BASEP_APPCERT_ENTRY, Entry);
314  ASSERT(Entry->fPluginCertFunc != NULL);
315 
316  /* Call it and check if it failed */
317  Status = Entry->fPluginCertFunc(ApplicationName, 1);
318  if (!NT_SUCCESS(Status)) CertFlag = 3;
319 
320  /* Move on */
321  NextEntry = NextEntry->Flink;
322  }
323 
324  /* Now loop them again */
325  NextEntry = BasepAppCertDllsList.Flink;
326  while (NextEntry != &BasepAppCertDllsList)
327  {
328  /* Make sure the entry has a callback */
329  Entry = CONTAINING_RECORD(NextEntry, BASEP_APPCERT_ENTRY, Entry);
330  ASSERT(Entry->fPluginCertFunc != NULL);
331 
332  /* Call it, this time with the flag from the loop above */
333  Status = Entry->fPluginCertFunc(ApplicationName, CertFlag);
334  }
335 
336  /* All done, return the status */
337  return Status;
338 }
339 
340 NTSTATUS
341 WINAPI
344  IN HANDLE ThreadHandle)
345 {
347  ANSI_STRING SaferiReplaceProcessThreadTokens = RTL_CONSTANT_STRING("SaferiReplaceProcessThreadTokens");
348 
349  /* Enter the application certification lock */
350  RtlEnterCriticalSection(&gcsAppCert);
351 
352  /* Check if we already know the function */
354  {
355  /* Call it */
356  Status = g_SaferReplaceProcessThreadTokens(TokenHandle,
357  ProcessHandle,
358  ThreadHandle) ?
361  }
362  else
363  {
364  /* Check if the app certification DLL isn't loaded */
365  if (!(gSaferHandle) ||
366  (gSaferHandle == (HMODULE)-1) ||
367  (gSaferHandle == (HMODULE)-2))
368  {
369  /* Then we can't call the function */
371  }
372  else
373  {
374  /* We have the DLL, find the address of the Safer function */
376  &SaferiReplaceProcessThreadTokens,
377  0,
379  if (NT_SUCCESS(Status))
380  {
381  /* Found it, now call it */
382  Status = g_SaferReplaceProcessThreadTokens(TokenHandle,
383  ProcessHandle,
384  ThreadHandle) ?
387  }
388  else
389  {
390  /* We couldn't find it, so this must be an unsupported DLL */
392  gSaferHandle = NULL;
394  }
395  }
396  }
397 
398  /* Release the lock and return the result */
399  RtlLeaveCriticalSection(&gcsAppCert);
400  return Status;
401 }
402 
403 VOID
404 WINAPI
406 {
408 
409  /* Sanity checks */
410  ASSERT(Handles != NULL);
411  ASSERT(Handles->Process == NULL || Handles->Process == NtCurrentProcess());
412 
413  /* Close the file handle */
414  if (Handles->File)
415  {
416  Status = NtClose(Handles->File);
417  ASSERT(NT_SUCCESS(Status));
418  }
419 
420  /* Close the section handle */
421  if (Handles->Section)
422  {
423  Status = NtClose(Handles->Section);
424  ASSERT(NT_SUCCESS(Status));
425  }
426 
427  /* Unmap the section view */
428  if (Handles->ViewBase.QuadPart)
429  {
431  (PVOID)Handles->ViewBase.LowPart);
432  ASSERT(NT_SUCCESS(Status));
433  }
434 }
435 
436 static
438 {
439  LONG ExceptionDisposition = EXCEPTION_EXECUTE_HANDLER;
440  LPTOP_LEVEL_EXCEPTION_FILTER RealFilter;
442 
443  if (RealFilter != NULL)
444  {
445  _SEH2_TRY
446  {
447  ExceptionDisposition = RealFilter(ExceptionInfo);
448  }
450  {
451  }
452  _SEH2_END;
453  }
454  if ((ExceptionDisposition == EXCEPTION_CONTINUE_SEARCH || ExceptionDisposition == EXCEPTION_EXECUTE_HANDLER) &&
455  RealFilter != UnhandledExceptionFilter)
456  {
457  ExceptionDisposition = UnhandledExceptionFilter(ExceptionInfo);
458  }
459 
460  return ExceptionDisposition;
461 }
462 
463 VOID
464 WINAPI
466 {
467  DPRINT("BaseProcessStartup(..) - setting up exception frame.\n");
468 
469  _SEH2_TRY
470  {
471  /* Set our Start Address */
474  &lpStartAddress,
475  sizeof(PPROCESS_START_ROUTINE));
476 
477  /* Call the Start Routine */
478  ExitThread(lpStartAddress());
479  }
481  {
482  /* Get the Exit code from the SEH Handler */
484  {
485  /* Kill the whole process, usually */
487  }
488  else
489  {
490  /* If running inside CSRSS, kill just this thread */
492  }
493  }
494  _SEH2_END;
495 }
496 
497 NTSTATUS
498 WINAPI
501 {
502  BASE_API_MESSAGE ApiMessage;
503  PBASE_CREATE_THREAD CreateThreadRequest = &ApiMessage.Data.CreateThreadRequest;
504 
505  DPRINT("BasepNotifyCsrOfThread: Thread: %p, Handle %p\n",
506  ClientId->UniqueThread, ThreadHandle);
507 
508  /* Fill out the request */
509  CreateThreadRequest->ClientId = *ClientId;
510  CreateThreadRequest->ThreadHandle = ThreadHandle;
511 
512  /* Call CSR */
514  NULL,
516  sizeof(*CreateThreadRequest));
517  if (!NT_SUCCESS(ApiMessage.Status))
518  {
519  DPRINT1("Failed to tell CSRSS about new thread: %lx\n", ApiMessage.Status);
520  return ApiMessage.Status;
521  }
522 
523  /* Return Success */
524  return STATUS_SUCCESS;
525 }
526 
527 BOOLEAN
528 WINAPI
531  IN PPEB RemotePeb,
532  IN LPCWSTR ApplicationPathName,
533  IN LPWSTR lpCurrentDirectory,
534  IN LPWSTR lpCommandLine,
535  IN LPVOID lpEnvironment,
536  IN LPSTARTUPINFOW StartupInfo,
537  IN DWORD CreationFlags,
538  IN BOOL InheritHandles,
539  IN ULONG ImageSubsystem,
540  IN PVOID AppCompatData,
541  IN ULONG AppCompatDataSize)
542 {
543  WCHAR FullPath[MAX_PATH + 5];
544  PWCHAR Remaining, DllPathString, ScanChar;
545  PRTL_USER_PROCESS_PARAMETERS ProcessParameters, RemoteParameters;
546  PVOID RemoteAppCompatData;
548  UNICODE_STRING Desktop, Shell, Runtime, Title;
550  ULONG EnviroSize;
551  SIZE_T Size;
552  BOOLEAN HavePebLock = FALSE, Result;
553  PPEB Peb = NtCurrentPeb();
554 
555  /* Get the full path name */
556  Size = GetFullPathNameW(ApplicationPathName,
557  MAX_PATH + 4,
558  FullPath,
559  &Remaining);
560  if ((Size) && (Size <= (MAX_PATH + 4)))
561  {
562  /* Get the DLL Path */
563  DllPathString = BaseComputeProcessDllPath(FullPath, lpEnvironment);
564  if (!DllPathString)
565  {
566  /* Fail */
568  return FALSE;
569  }
570 
571  /* Initialize Strings */
572  RtlInitUnicodeString(&DllPath, DllPathString);
573  RtlInitUnicodeString(&ImageName, FullPath);
574  }
575  else
576  {
577  /* Couldn't get the path name. Just take the original path */
578  DllPathString = BaseComputeProcessDllPath((LPWSTR)ApplicationPathName,
579  lpEnvironment);
580  if (!DllPathString)
581  {
582  /* Fail */
584  return FALSE;
585  }
586 
587  /* Initialize Strings */
588  RtlInitUnicodeString(&DllPath, DllPathString);
589  RtlInitUnicodeString(&ImageName, ApplicationPathName);
590  }
591 
592  /* Initialize Strings */
593  RtlInitUnicodeString(&CommandLine, lpCommandLine);
594  RtlInitUnicodeString(&CurrentDirectory, lpCurrentDirectory);
595 
596  /* Initialize more Strings from the Startup Info */
597  if (StartupInfo->lpDesktop)
598  {
599  RtlInitUnicodeString(&Desktop, StartupInfo->lpDesktop);
600  }
601  else
602  {
603  RtlInitUnicodeString(&Desktop, L"");
604  }
605  if (StartupInfo->lpReserved)
606  {
607  RtlInitUnicodeString(&Shell, StartupInfo->lpReserved);
608  }
609  else
610  {
611  RtlInitUnicodeString(&Shell, L"");
612  }
613  if (StartupInfo->lpTitle)
614  {
615  RtlInitUnicodeString(&Title, StartupInfo->lpTitle);
616  }
617  else
618  {
619  RtlInitUnicodeString(&Title, ApplicationPathName);
620  }
621 
622  /* This one is special because the length can differ */
623  Runtime.Buffer = (LPWSTR)StartupInfo->lpReserved2;
624  Runtime.MaximumLength = Runtime.Length = StartupInfo->cbReserved2;
625 
626  /* Enforce no app compat data if the pointer was NULL */
627  if (!AppCompatData) AppCompatDataSize = 0;
628 
629  /* Create the Parameter Block */
630  ProcessParameters = NULL;
631  DPRINT("ImageName: '%wZ'\n", &ImageName);
632  DPRINT("DllPath : '%wZ'\n", &DllPath);
633  DPRINT("CurDir : '%wZ'\n", &CurrentDirectory);
634  DPRINT("CmdLine : '%wZ'\n", &CommandLine);
635  DPRINT("Title : '%wZ'\n", &Title);
636  DPRINT("Desktop : '%wZ'\n", &Desktop);
637  DPRINT("Shell : '%wZ'\n", &Shell);
638  DPRINT("Runtime : '%wZ'\n", &Runtime);
639  Status = RtlCreateProcessParameters(&ProcessParameters,
640  &ImageName,
641  &DllPath,
642  lpCurrentDirectory ?
643  &CurrentDirectory : NULL,
644  &CommandLine,
645  lpEnvironment,
646  &Title,
647  &Desktop,
648  &Shell,
649  &Runtime);
650  if (!NT_SUCCESS(Status)) goto FailPath;
651 
652  /* Clear the current directory handle if not inheriting */
653  if (!InheritHandles) ProcessParameters->CurrentDirectory.Handle = NULL;
654 
655  /* Check if the user passed in an environment */
656  if (lpEnvironment)
657  {
658  /* We should've made it part of the parameters block, enforce this */
659  ASSERT(ProcessParameters->Environment == lpEnvironment);
660  lpEnvironment = ProcessParameters->Environment;
661  }
662  else
663  {
664  /* The user did not, so use the one from the current PEB */
665  HavePebLock = TRUE;
667  lpEnvironment = Peb->ProcessParameters->Environment;
668  }
669 
670  /* Save pointer and start lookup */
671  ScanChar = lpEnvironment;
672  if (lpEnvironment)
673  {
674  /* Find the environment size */
675  while (*ScanChar++) while (*ScanChar++);
676  EnviroSize = (ULONG)((ULONG_PTR)ScanChar - (ULONG_PTR)lpEnvironment);
677 
678  /* Allocate and Initialize new Environment Block */
679  Size = EnviroSize;
680  ProcessParameters->Environment = NULL;
681  Status = NtAllocateVirtualMemory(ProcessHandle,
682  (PVOID*)&ProcessParameters->Environment,
683  0,
684  &Size,
685  MEM_COMMIT,
687  if (!NT_SUCCESS(Status)) goto FailPath;
688 
689  /* Write the Environment Block */
690  Status = NtWriteVirtualMemory(ProcessHandle,
691  ProcessParameters->Environment,
692  lpEnvironment,
693  EnviroSize,
694  NULL);
695 
696  /* No longer need the PEB lock anymore */
697  if (HavePebLock)
698  {
699  /* Release it */
701  HavePebLock = FALSE;
702  }
703 
704  /* Check if the write failed */
705  if (!NT_SUCCESS(Status)) goto FailPath;
706  }
707 
708  /* Write new parameters */
709  ProcessParameters->StartingX = StartupInfo->dwX;
710  ProcessParameters->StartingY = StartupInfo->dwY;
711  ProcessParameters->CountX = StartupInfo->dwXSize;
712  ProcessParameters->CountY = StartupInfo->dwYSize;
713  ProcessParameters->CountCharsX = StartupInfo->dwXCountChars;
714  ProcessParameters->CountCharsY = StartupInfo->dwYCountChars;
715  ProcessParameters->FillAttribute = StartupInfo->dwFillAttribute;
716  ProcessParameters->WindowFlags = StartupInfo->dwFlags;
717  ProcessParameters->ShowWindowFlags = StartupInfo->wShowWindow;
718 
719  /* Write the handles only if we have to */
720  if (StartupInfo->dwFlags &
721  (STARTF_USESTDHANDLES | STARTF_USEHOTKEY | STARTF_SHELLPRIVATE))
722  {
723  ProcessParameters->StandardInput = StartupInfo->hStdInput;
724  ProcessParameters->StandardOutput = StartupInfo->hStdOutput;
725  ProcessParameters->StandardError = StartupInfo->hStdError;
726  }
727 
728  /* Use Special Flags for ConDllInitialize in Kernel32 */
729  if (CreationFlags & DETACHED_PROCESS)
730  {
731  ProcessParameters->ConsoleHandle = HANDLE_DETACHED_PROCESS;
732  }
733  else if (CreationFlags & CREATE_NEW_CONSOLE)
734  {
735  ProcessParameters->ConsoleHandle = HANDLE_CREATE_NEW_CONSOLE;
736  }
737  else if (CreationFlags & CREATE_NO_WINDOW)
738  {
739  ProcessParameters->ConsoleHandle = HANDLE_CREATE_NO_WINDOW;
740  }
741  else
742  {
743  /* Inherit our Console Handle */
744  ProcessParameters->ConsoleHandle = Peb->ProcessParameters->ConsoleHandle;
745 
746  /* Make sure that the shell isn't trampling on our handles first */
747  if (!(StartupInfo->dwFlags &
748  (STARTF_USESTDHANDLES | STARTF_USEHOTKEY | STARTF_SHELLPRIVATE)))
749  {
750  /* Copy the handle if we are inheriting or if it's a console handle */
751  if ((InheritHandles) ||
753  {
754  ProcessParameters->StandardInput = Peb->ProcessParameters->StandardInput;
755  }
756  if ((InheritHandles) ||
758  {
759  ProcessParameters->StandardOutput = Peb->ProcessParameters->StandardOutput;
760  }
761  if ((InheritHandles) ||
763  {
764  ProcessParameters->StandardError = Peb->ProcessParameters->StandardError;
765  }
766  }
767  }
768 
769  /* Also set the Console Flag */
770  if ((CreationFlags & CREATE_NEW_PROCESS_GROUP) &&
771  (!(CreationFlags & CREATE_NEW_CONSOLE)))
772  {
773  ProcessParameters->ConsoleFlags = 1;
774  }
775 
776  /* Check if there's a .local file present */
777  if (ParameterFlags & 1)
778  {
780  }
781 
782  /* Check if we failed to open the IFEO key */
783  if (ParameterFlags & 2)
784  {
786  }
787 
788  /* Allocate memory for the parameter block */
789  Size = ProcessParameters->Length;
790  RemoteParameters = NULL;
791  Status = NtAllocateVirtualMemory(ProcessHandle,
792  (PVOID*)&RemoteParameters,
793  0,
794  &Size,
795  MEM_COMMIT,
797  if (!NT_SUCCESS(Status)) goto FailPath;
798 
799  /* Set the allocated size */
800  ProcessParameters->MaximumLength = Size;
801 
802  /* Handle some Parameter Flags */
803  ProcessParameters->Flags |= (CreationFlags & PROFILE_USER) ?
805  ProcessParameters->Flags |= (CreationFlags & PROFILE_KERNEL) ?
807  ProcessParameters->Flags |= (CreationFlags & PROFILE_SERVER) ?
809  ProcessParameters->Flags |= (Peb->ProcessParameters->Flags &
811 
812  /* Write the Parameter Block */
813  Status = NtWriteVirtualMemory(ProcessHandle,
814  RemoteParameters,
815  ProcessParameters,
816  ProcessParameters->Length,
817  NULL);
818  if (!NT_SUCCESS(Status)) goto FailPath;
819 
820  /* Write the PEB Pointer */
821  Status = NtWriteVirtualMemory(ProcessHandle,
822  &RemotePeb->ProcessParameters,
823  &RemoteParameters,
824  sizeof(PVOID),
825  NULL);
826  if (!NT_SUCCESS(Status)) goto FailPath;
827 
828  /* Check if there's any app compat data to write */
829  RemoteAppCompatData = NULL;
830  if (AppCompatData)
831  {
832  /* Allocate some space for the application compatibility data */
833  Size = AppCompatDataSize;
834  Status = NtAllocateVirtualMemory(ProcessHandle,
835  &RemoteAppCompatData,
836  0,
837  &Size,
838  MEM_COMMIT,
840  if (!NT_SUCCESS(Status)) goto FailPath;
841 
842  /* Write the application compatibility data */
843  Status = NtWriteVirtualMemory(ProcessHandle,
844  RemoteAppCompatData,
845  AppCompatData,
846  AppCompatDataSize,
847  NULL);
848  if (!NT_SUCCESS(Status)) goto FailPath;
849  }
850 
851  /* Write the PEB Pointer to the app compat data (might be NULL) */
852  Status = NtWriteVirtualMemory(ProcessHandle,
853  &RemotePeb->pShimData,
854  &RemoteAppCompatData,
855  sizeof(PVOID),
856  NULL);
857  if (!NT_SUCCESS(Status)) goto FailPath;
858 
859  /* Now write Peb->ImageSubSystem */
860  if (ImageSubsystem)
861  {
862  NtWriteVirtualMemory(ProcessHandle,
863  &RemotePeb->ImageSubsystem,
864  &ImageSubsystem,
865  sizeof(ImageSubsystem),
866  NULL);
867  }
868 
869  /* Success path */
870  Result = TRUE;
871 
872 Quickie:
873  /* Cleanup */
874  if (HavePebLock) RtlReleasePebLock();
875  RtlFreeHeap(RtlGetProcessHeap(), 0, DllPath.Buffer);
876  if (ProcessParameters) RtlDestroyProcessParameters(ProcessParameters);
877  return Result;
878 FailPath:
879  DPRINT1("Failure to create process parameters: %lx\n", Status);
880  BaseSetLastNTError(Status);
881  Result = FALSE;
882  goto Quickie;
883 }
884 
885 VOID
886 WINAPI
888 {
890 
891  /* Read the UNICODE_STRING from the PEB */
892  BaseUnicodeCommandLine = NtCurrentPeb()->ProcessParameters->CommandLine;
893 
894  /* Convert to ANSI_STRING for the *A callers */
895  Status = RtlUnicodeStringToAnsiString(&BaseAnsiCommandLine,
896  &BaseUnicodeCommandLine,
897  TRUE);
898  if (!NT_SUCCESS(Status)) RtlInitEmptyAnsiString(&BaseAnsiCommandLine, 0, 0);
899 }
900 
901 /* PUBLIC FUNCTIONS ***********************************************************/
902 
903 /*
904  * @implemented
905  */
906 BOOL
907 WINAPI
909  OUT PDWORD_PTR lpProcessAffinityMask,
910  OUT PDWORD_PTR lpSystemAffinityMask)
911 {
912  PROCESS_BASIC_INFORMATION ProcessInfo;
914 
915  /* Query information on the process from the kernel */
916  Status = NtQueryInformationProcess(hProcess,
918  &ProcessInfo,
919  sizeof(ProcessInfo),
920  NULL);
921  if (!NT_SUCCESS(Status))
922  {
923  /* Fail */
924  BaseSetLastNTError(Status);
925  return FALSE;
926  }
927 
928  /* Copy the affinity mask, and get the system one from our shared data */
929  *lpProcessAffinityMask = (DWORD)ProcessInfo.AffinityMask;
931  return TRUE;
932 }
933 
934 /*
935  * @implemented
936  */
937 BOOL
938 WINAPI
940  IN DWORD_PTR dwProcessAffinityMask)
941 {
943 
944  /* Directly set the affinity mask */
945  Status = NtSetInformationProcess(hProcess,
947  (PVOID)&dwProcessAffinityMask,
948  sizeof(DWORD));
949  if (!NT_SUCCESS(Status))
950  {
951  /* Handle failure */
952  BaseSetLastNTError(Status);
953  return FALSE;
954  }
955 
956  /* Everything was ok */
957  return TRUE;
958 }
959 
960 /*
961  * @implemented
962  */
963 BOOL
964 WINAPI
966  OUT LPDWORD lpdwFlags)
967 {
968  BASE_API_MESSAGE ApiMessage;
969  PBASE_GETSET_PROCESS_SHUTDOWN_PARAMS ShutdownParametersRequest = &ApiMessage.Data.ShutdownParametersRequest;
970 
971  /* Ask CSRSS for shutdown information */
973  NULL,
975  sizeof(*ShutdownParametersRequest));
976  if (!NT_SUCCESS(ApiMessage.Status))
977  {
978  /* Return the failure from CSRSS */
979  BaseSetLastNTError(ApiMessage.Status);
980  return FALSE;
981  }
982 
983  /* Get the data back */
984  *lpdwLevel = ShutdownParametersRequest->ShutdownLevel;
985  *lpdwFlags = ShutdownParametersRequest->ShutdownFlags;
986  return TRUE;
987 }
988 
989 /*
990  * @implemented
991  */
992 BOOL
993 WINAPI
995  IN DWORD dwFlags)
996 {
997  BASE_API_MESSAGE ApiMessage;
998  PBASE_GETSET_PROCESS_SHUTDOWN_PARAMS ShutdownParametersRequest = &ApiMessage.Data.ShutdownParametersRequest;
999 
1000  /* Write the data into the CSRSS request and send it */
1001  ShutdownParametersRequest->ShutdownLevel = dwLevel;
1002  ShutdownParametersRequest->ShutdownFlags = dwFlags;
1004  NULL,
1006  sizeof(*ShutdownParametersRequest));
1007  if (!NT_SUCCESS(ApiMessage.Status))
1008  {
1009  /* Return the failure from CSRSS */
1010  BaseSetLastNTError(ApiMessage.Status);
1011  return FALSE;
1012  }
1013 
1014  /* All went well */
1015  return TRUE;
1016 }
1017 
1018 /*
1019  * @implemented
1020  */
1021 BOOL
1022 WINAPI
1024  OUT PSIZE_T lpMinimumWorkingSetSize,
1025  OUT PSIZE_T lpMaximumWorkingSetSize,
1026  OUT PDWORD Flags)
1027 {
1028  QUOTA_LIMITS_EX QuotaLimits;
1029  NTSTATUS Status;
1030 
1031  /* Query the kernel about this */
1032  Status = NtQueryInformationProcess(hProcess,
1034  &QuotaLimits,
1035  sizeof(QuotaLimits),
1036  NULL);
1037  if (!NT_SUCCESS(Status))
1038  {
1039  /* Return error */
1040  BaseSetLastNTError(Status);
1041  return FALSE;
1042  }
1043 
1044  /* Copy the quota information out */
1045  *lpMinimumWorkingSetSize = QuotaLimits.MinimumWorkingSetSize;
1046  *lpMaximumWorkingSetSize = QuotaLimits.MaximumWorkingSetSize;
1047  *Flags = QuotaLimits.Flags;
1048  return TRUE;
1049 }
1050 
1051 /*
1052  * @implemented
1053  */
1054 BOOL
1055 WINAPI
1057  OUT PSIZE_T lpMinimumWorkingSetSize,
1058  OUT PSIZE_T lpMaximumWorkingSetSize)
1059 {
1060  DWORD Dummy;
1061  return GetProcessWorkingSetSizeEx(hProcess,
1062  lpMinimumWorkingSetSize,
1063  lpMaximumWorkingSetSize,
1064  &Dummy);
1065 }
1066 
1067 /*
1068  * @implemented
1069  */
1070 BOOL
1071 WINAPI
1073  IN SIZE_T dwMinimumWorkingSetSize,
1074  IN SIZE_T dwMaximumWorkingSetSize,
1075  IN DWORD Flags)
1076 {
1077  QUOTA_LIMITS_EX QuotaLimits;
1078  NTSTATUS Status, ReturnStatus;
1079  BOOL Result;
1080  PVOID State;
1082 
1083  /* Zero out the input structure */
1084  RtlZeroMemory(&QuotaLimits, sizeof(QuotaLimits));
1085 
1086  /* Check if the caller sent any limits */
1087  if ((dwMinimumWorkingSetSize) && (dwMaximumWorkingSetSize))
1088  {
1089  /* Write the quota information */
1090  QuotaLimits.MinimumWorkingSetSize = dwMinimumWorkingSetSize;
1091  QuotaLimits.MaximumWorkingSetSize = dwMaximumWorkingSetSize;
1092  QuotaLimits.Flags = Flags;
1093 
1094  /* Acquire the required privilege */
1095  Status = RtlAcquirePrivilege(&Privilege, 1, 0, &State);
1096 
1097  /* Request the new quotas */
1098  ReturnStatus = NtSetInformationProcess(hProcess,
1100  &QuotaLimits,
1101  sizeof(QuotaLimits));
1102  Result = NT_SUCCESS(ReturnStatus);
1103  if (NT_SUCCESS(Status))
1104  {
1105  /* Release the privilege and set succes code */
1106  ASSERT(State != NULL);
1107  RtlReleasePrivilege(State);
1108  State = NULL;
1109  }
1110  }
1111  else
1112  {
1113  /* No limits, fail the call */
1114  ReturnStatus = STATUS_INVALID_PARAMETER;
1115  Result = FALSE;
1116  }
1117 
1118  /* Return result code, set error code if this was a failure */
1119  if (!Result) BaseSetLastNTError(ReturnStatus);
1120  return Result;
1121 }
1122 
1123 /*
1124  * @implemented
1125  */
1126 BOOL
1127 WINAPI
1129  IN SIZE_T dwMinimumWorkingSetSize,
1130  IN SIZE_T dwMaximumWorkingSetSize)
1131 {
1132  /* Call the newer API */
1133  return SetProcessWorkingSetSizeEx(hProcess,
1134  dwMinimumWorkingSetSize,
1135  dwMaximumWorkingSetSize,
1136  0);
1137 }
1138 
1139 /*
1140  * @implemented
1141  */
1142 BOOL
1143 WINAPI
1145  IN LPFILETIME lpCreationTime,
1146  IN LPFILETIME lpExitTime,
1147  IN LPFILETIME lpKernelTime,
1148  IN LPFILETIME lpUserTime)
1149 {
1150  KERNEL_USER_TIMES Kut;
1151  NTSTATUS Status;
1152 
1153  /* Query the times */
1154  Status = NtQueryInformationProcess(hProcess,
1155  ProcessTimes,
1156  &Kut,
1157  sizeof(Kut),
1158  NULL);
1159  if (!NT_SUCCESS(Status))
1160  {
1161  /* Handle failure */
1162  BaseSetLastNTError(Status);
1163  return FALSE;
1164  }
1165 
1166  /* Copy all the times and return success */
1167  lpCreationTime->dwLowDateTime = Kut.CreateTime.u.LowPart;
1168  lpCreationTime->dwHighDateTime = Kut.CreateTime.u.HighPart;
1169  lpExitTime->dwLowDateTime = Kut.ExitTime.u.LowPart;
1170  lpExitTime->dwHighDateTime = Kut.ExitTime.u.HighPart;
1171  lpKernelTime->dwLowDateTime = Kut.KernelTime.u.LowPart;
1172  lpKernelTime->dwHighDateTime = Kut.KernelTime.u.HighPart;
1173  lpUserTime->dwLowDateTime = Kut.UserTime.u.LowPart;
1174  lpUserTime->dwHighDateTime = Kut.UserTime.u.HighPart;
1175  return TRUE;
1176 }
1177 
1178 /*
1179  * @implemented
1180  */
1181 HANDLE
1182 WINAPI
1184 {
1185  return (HANDLE)NtCurrentProcess();
1186 }
1187 
1188 /*
1189  * @implemented
1190  */
1191 HANDLE
1192 WINAPI
1194 {
1195  return (HANDLE)NtCurrentThread();
1196 }
1197 
1198 /*
1199  * @implemented
1200  */
1201 DWORD
1202 WINAPI
1204 {
1206 }
1207 
1208 /*
1209  * @implemented
1210  */
1211 BOOL
1212 WINAPI
1214  IN LPDWORD lpExitCode)
1215 {
1216  PROCESS_BASIC_INFORMATION ProcessBasic;
1217  NTSTATUS Status;
1218 
1219  /* Ask the kernel */
1220  Status = NtQueryInformationProcess(hProcess,
1222  &ProcessBasic,
1223  sizeof(ProcessBasic),
1224  NULL);
1225  if (!NT_SUCCESS(Status))
1226  {
1227  /* We failed, was this because this is a VDM process? */
1228  if (BaseCheckForVDM(hProcess, lpExitCode) != FALSE) return TRUE;
1229 
1230  /* Not a VDM process, fail the call */
1231  BaseSetLastNTError(Status);
1232  return FALSE;
1233  }
1234 
1235  /* Succes case, return the exit code */
1236  *lpExitCode = (DWORD)ProcessBasic.ExitStatus;
1237  return TRUE;
1238 }
1239 
1240 /*
1241  * @implemented
1242  */
1243 DWORD
1244 WINAPI
1246 {
1247  PROCESS_BASIC_INFORMATION ProcessBasic;
1248  NTSTATUS Status;
1249 
1250  /* Query the kernel */
1251  Status = NtQueryInformationProcess(Process,
1253  &ProcessBasic,
1254  sizeof(ProcessBasic),
1255  NULL);
1256  if (!NT_SUCCESS(Status))
1257  {
1258  /* Handle failure */
1259  BaseSetLastNTError(Status);
1260  return 0;
1261  }
1262 
1263  /* Return the PID */
1264  return (DWORD)ProcessBasic.UniqueProcessId;
1265 }
1266 
1267 /*
1268  * @implemented
1269  */
1270 HANDLE
1271 WINAPI
1272 OpenProcess(IN DWORD dwDesiredAccess,
1274  IN DWORD dwProcessId)
1275 {
1276  NTSTATUS Status;
1280 
1281  /* Setup the input client ID structure */
1282  ClientId.UniqueProcess = UlongToHandle(dwProcessId);
1283  ClientId.UniqueThread = 0;
1284 
1285  /* This is needed just to define the inheritance flags */
1286  InitializeObjectAttributes(&ObjectAttributes,
1287  NULL,
1288  (bInheritHandle ? OBJ_INHERIT : 0),
1289  NULL,
1290  NULL);
1291 
1292  /* Now try to open the process */
1293  Status = NtOpenProcess(&ProcessHandle,
1294  dwDesiredAccess,
1295  &ObjectAttributes,
1296  &ClientId);
1297  if (!NT_SUCCESS(Status))
1298  {
1299  /* Handle failure */
1300  BaseSetLastNTError(Status);
1301  return NULL;
1302  }
1303 
1304  /* Otherwise return a handle to the process */
1305  return ProcessHandle;
1306 }
1307 
1308 /*
1309  * @implemented
1310  */
1311 VOID
1312 WINAPI
1313 RegisterWaitForInputIdle(IN WaitForInputIdleType lpfnRegisterWaitForInputIdle)
1314 {
1315  /* Write the global function pointer */
1316  UserWaitForInputIdleRoutine = lpfnRegisterWaitForInputIdle;
1317 }
1318 
1319 /*
1320  * @implemented
1321  */
1322 VOID
1323 WINAPI
1325 {
1327 
1328  /* Get the process parameters */
1329  Params = NtCurrentPeb()->ProcessParameters;
1330 
1331  /* Copy the data out of there */
1332  lpStartupInfo->cb = sizeof(STARTUPINFOW);
1333  lpStartupInfo->lpReserved = Params->ShellInfo.Buffer;
1334  lpStartupInfo->lpDesktop = Params->DesktopInfo.Buffer;
1335  lpStartupInfo->lpTitle = Params->WindowTitle.Buffer;
1336  lpStartupInfo->dwX = Params->StartingX;
1337  lpStartupInfo->dwY = Params->StartingY;
1338  lpStartupInfo->dwXSize = Params->CountX;
1339  lpStartupInfo->dwYSize = Params->CountY;
1340  lpStartupInfo->dwXCountChars = Params->CountCharsX;
1341  lpStartupInfo->dwYCountChars = Params->CountCharsY;
1342  lpStartupInfo->dwFillAttribute = Params->FillAttribute;
1343  lpStartupInfo->dwFlags = Params->WindowFlags;
1344  lpStartupInfo->wShowWindow = (WORD)Params->ShowWindowFlags;
1345  lpStartupInfo->cbReserved2 = Params->RuntimeData.Length;
1346  lpStartupInfo->lpReserved2 = (LPBYTE)Params->RuntimeData.Buffer;
1347 
1348  /* Check if the standard handles are being used for other features */
1349  if (lpStartupInfo->dwFlags & (STARTF_USESTDHANDLES |
1350  STARTF_USEHOTKEY |
1352  {
1353  /* These are, so copy the standard handles too */
1354  lpStartupInfo->hStdInput = Params->StandardInput;
1355  lpStartupInfo->hStdOutput = Params->StandardOutput;
1356  lpStartupInfo->hStdError = Params->StandardError;
1357  }
1358 }
1359 
1360 /*
1361  * @implemented
1362  */
1363 VOID
1364 WINAPI
1366 {
1368  ANSI_STRING TitleString, ShellString, DesktopString;
1369  LPSTARTUPINFOA StartupInfo;
1370  NTSTATUS Status;
1371 
1372  /* Get the cached information as well as the PEB parameters */
1373  StartupInfo = BaseAnsiStartupInfo;
1374  Params = NtCurrentPeb()->ProcessParameters;
1375 
1376  /* Check if this is the first time we have to get the cached version */
1377  while (!StartupInfo)
1378  {
1379  /* Create new ANSI startup info */
1380  StartupInfo = RtlAllocateHeap(RtlGetProcessHeap(),
1381  0,
1382  sizeof(*StartupInfo));
1383  if (StartupInfo)
1384  {
1385  /* Zero out string pointers in case we fail to create them */
1386  StartupInfo->lpReserved = 0;
1387  StartupInfo->lpDesktop = 0;
1388  StartupInfo->lpTitle = 0;
1389 
1390  /* Set the size */
1391  StartupInfo->cb = sizeof(*StartupInfo);
1392 
1393  /* Copy what's already stored in the PEB */
1394  StartupInfo->dwX = Params->StartingX;
1395  StartupInfo->dwY = Params->StartingY;
1396  StartupInfo->dwXSize = Params->CountX;
1397  StartupInfo->dwYSize = Params->CountY;
1398  StartupInfo->dwXCountChars = Params->CountCharsX;
1399  StartupInfo->dwYCountChars = Params->CountCharsY;
1400  StartupInfo->dwFillAttribute = Params->FillAttribute;
1401  StartupInfo->dwFlags = Params->WindowFlags;
1402  StartupInfo->wShowWindow = (WORD)Params->ShowWindowFlags;
1403  StartupInfo->cbReserved2 = Params->RuntimeData.Length;
1404  StartupInfo->lpReserved2 = (LPBYTE)Params->RuntimeData.Buffer;
1405  StartupInfo->hStdInput = Params->StandardInput;
1406  StartupInfo->hStdOutput = Params->StandardOutput;
1407  StartupInfo->hStdError = Params->StandardError;
1408 
1409  /* Copy shell info string */
1410  Status = RtlUnicodeStringToAnsiString(&ShellString,
1411  &Params->ShellInfo,
1412  TRUE);
1413  if (NT_SUCCESS(Status))
1414  {
1415  /* Save it */
1416  StartupInfo->lpReserved = ShellString.Buffer;
1417 
1418  /* Copy desktop info string */
1419  Status = RtlUnicodeStringToAnsiString(&DesktopString,
1420  &Params->DesktopInfo,
1421  TRUE);
1422  if (NT_SUCCESS(Status))
1423  {
1424  /* Save it */
1425  StartupInfo->lpDesktop = DesktopString.Buffer;
1426 
1427  /* Copy window title string */
1428  Status = RtlUnicodeStringToAnsiString(&TitleString,
1429  &Params->WindowTitle,
1430  TRUE);
1431  if (NT_SUCCESS(Status))
1432  {
1433  /* Save it */
1434  StartupInfo->lpTitle = TitleString.Buffer;
1435 
1436  /* We finished with the ANSI version, try to cache it */
1437  if (!InterlockedCompareExchangePointer((PVOID*)&BaseAnsiStartupInfo,
1438  StartupInfo,
1439  NULL))
1440  {
1441  /* We were the first thread through, use the data */
1442  break;
1443  }
1444 
1445  /* Someone beat us to it, use their data instead */
1446  StartupInfo = BaseAnsiStartupInfo;
1447  Status = STATUS_SUCCESS;
1448 
1449  /* We're going to free our own stuff, but not raise */
1450  RtlFreeAnsiString(&TitleString);
1451  }
1452  RtlFreeAnsiString(&DesktopString);
1453  }
1454  RtlFreeAnsiString(&ShellString);
1455  }
1456  RtlFreeHeap(RtlGetProcessHeap(), 0, StartupInfo);
1457  }
1458  else
1459  {
1460  /* No memory, fail */
1461  Status = STATUS_NO_MEMORY;
1462  }
1463 
1464  /* Raise an error unless we got here due to the race condition */
1465  if (!NT_SUCCESS(Status)) RtlRaiseStatus(Status);
1466  }
1467 
1468  /* Now copy from the cached ANSI version */
1469  lpStartupInfo->cb = StartupInfo->cb;
1470  lpStartupInfo->lpReserved = StartupInfo->lpReserved;
1471  lpStartupInfo->lpDesktop = StartupInfo->lpDesktop;
1472  lpStartupInfo->lpTitle = StartupInfo->lpTitle;
1473  lpStartupInfo->dwX = StartupInfo->dwX;
1474  lpStartupInfo->dwY = StartupInfo->dwY;
1475  lpStartupInfo->dwXSize = StartupInfo->dwXSize;
1476  lpStartupInfo->dwYSize = StartupInfo->dwYSize;
1477  lpStartupInfo->dwXCountChars = StartupInfo->dwXCountChars;
1478  lpStartupInfo->dwYCountChars = StartupInfo->dwYCountChars;
1479  lpStartupInfo->dwFillAttribute = StartupInfo->dwFillAttribute;
1480  lpStartupInfo->dwFlags = StartupInfo->dwFlags;
1481  lpStartupInfo->wShowWindow = StartupInfo->wShowWindow;
1482  lpStartupInfo->cbReserved2 = StartupInfo->cbReserved2;
1483  lpStartupInfo->lpReserved2 = StartupInfo->lpReserved2;
1484 
1485  /* Check if the shell is hijacking the handles for other features */
1486  if (lpStartupInfo->dwFlags &
1487  (STARTF_USESTDHANDLES | STARTF_USEHOTKEY | STARTF_SHELLPRIVATE))
1488  {
1489  /* It isn't, so we can return the raw values */
1490  lpStartupInfo->hStdInput = StartupInfo->hStdInput;
1491  lpStartupInfo->hStdOutput = StartupInfo->hStdOutput;
1492  lpStartupInfo->hStdError = StartupInfo->hStdError;
1493  }
1494  else
1495  {
1496  /* It is, so make sure nobody uses these as console handles */
1497  lpStartupInfo->hStdInput = INVALID_HANDLE_VALUE;
1498  lpStartupInfo->hStdOutput = INVALID_HANDLE_VALUE;
1499  lpStartupInfo->hStdError = INVALID_HANDLE_VALUE;
1500  }
1501 }
1502 
1503 /*
1504  * @implemented
1505  */
1506 BOOL
1507 WINAPI
1509  IN LPCVOID lpBaseAddress,
1510  IN SIZE_T nSize)
1511 {
1512  NTSTATUS Status;
1513 
1514  /* Call the native function */
1515  Status = NtFlushInstructionCache(hProcess, (PVOID)lpBaseAddress, nSize);
1516  if (!NT_SUCCESS(Status))
1517  {
1518  /* Handle failure case */
1519  BaseSetLastNTError(Status);
1520  return FALSE;
1521  }
1522 
1523  /* All good */
1524  return TRUE;
1525 }
1526 
1527 /*
1528  * @implemented
1529  */
1530 VOID
1531 WINAPI
1532 ExitProcess(IN UINT uExitCode)
1533 {
1534  BASE_API_MESSAGE ApiMessage;
1535  PBASE_EXIT_PROCESS ExitProcessRequest = &ApiMessage.Data.ExitProcessRequest;
1536 
1538 
1539  _SEH2_TRY
1540  {
1541  /* Acquire the PEB lock */
1543 
1544  /* Kill all the threads */
1545  NtTerminateProcess(NULL, uExitCode);
1546 
1547  /* Unload all DLLs */
1549 
1550  /* Notify Base Server of process termination */
1551  ExitProcessRequest->uExitCode = uExitCode;
1553  NULL,
1555  sizeof(*ExitProcessRequest));
1556 
1557  /* Now do it again */
1558  NtTerminateProcess(NtCurrentProcess(), uExitCode);
1559  }
1561  {
1562  /* Release the PEB lock */
1564  }
1565  _SEH2_END;
1566 
1567  /* should never get here */
1568  ASSERT(0);
1569  while(1);
1570 }
1571 
1572 /*
1573  * @implemented
1574  */
1575 BOOL
1576 WINAPI
1578  IN UINT uExitCode)
1579 {
1580  NTSTATUS Status;
1581 
1582  /* Check if no handle was passed in */
1583  if (!hProcess)
1584  {
1585  /* Set error code */
1587  }
1588  else
1589  {
1590  /* Otherwise, try to terminate the process */
1591  Status = NtTerminateProcess(hProcess, uExitCode);
1592  if (NT_SUCCESS(Status)) return TRUE;
1593 
1594  /* It failed, convert error code */
1595  BaseSetLastNTError(Status);
1596  }
1597 
1598  /* This is the failure path */
1599  return FALSE;
1600 }
1601 
1602 /*
1603  * @implemented
1604  */
1605 VOID
1606 WINAPI
1608  LPCSTR lpMessageText)
1609 {
1610  PUNICODE_STRING MessageTextU;
1611  ANSI_STRING MessageText;
1612  NTSTATUS Status;
1613 
1614  /* Initialize the string using the static TEB pointer */
1615  MessageTextU = &NtCurrentTeb()->StaticUnicodeString;
1616  RtlInitAnsiString(&MessageText, (LPSTR)lpMessageText);
1617 
1618  /* Convert to unicode, or just exit normally if this failed */
1619  Status = RtlAnsiStringToUnicodeString(MessageTextU, &MessageText, FALSE);
1620  if (!NT_SUCCESS(Status)) ExitProcess(0);
1621 
1622  /* Call the Wide function */
1623  FatalAppExitW(uAction, MessageTextU->Buffer);
1624 }
1625 
1626 /*
1627  * @implemented
1628  */
1629 VOID
1630 WINAPI
1632  IN LPCWSTR lpMessageText)
1633 {
1635  ULONG Response;
1636  NTSTATUS Status;
1637 
1638  /* Setup the string to print out */
1639  RtlInitUnicodeString(&UnicodeString, lpMessageText);
1640 
1641  /* Display the hard error no matter what */
1643  1,
1644  1,
1645  (PULONG_PTR)&UnicodeString,
1646 #if DBG
1647  /* On Checked builds, Windows allows the user to cancel the operation */
1649 #else
1650  OptionOk,
1651 #endif
1652  &Response);
1653 
1654 #if DBG
1655  /* Give the user a chance to abort */
1656  if ((NT_SUCCESS(Status)) && (Response == ResponseCancel)) return;
1657 #endif
1658 
1659  /* Otherwise kill the process */
1660  ExitProcess(0);
1661 }
1662 
1663 /*
1664  * @implemented
1665  */
1666 VOID
1667 WINAPI
1668 FatalExit(IN int ExitCode)
1669 {
1670 #if DBG
1671  /* On Checked builds, Windows gives the user a nice little debugger UI */
1672  CHAR ch[2];
1673  DbgPrint("FatalExit...\n");
1674  DbgPrint("\n");
1675 
1676  while (TRUE)
1677  {
1678  DbgPrompt( "A (Abort), B (Break), I (Ignore)? ", ch, sizeof(ch));
1679  switch (ch[0])
1680  {
1681  case 'B': case 'b':
1682  DbgBreakPoint();
1683  break;
1684 
1685  case 'A': case 'a':
1686  ExitProcess(ExitCode);
1687 
1688  case 'I': case 'i':
1689  return;
1690  }
1691  }
1692 #endif
1693  /* On other builds, just kill the process */
1694  ExitProcess(ExitCode);
1695 }
1696 
1697 /*
1698  * @implemented
1699  */
1700 DWORD
1701 WINAPI
1703 {
1704  NTSTATUS Status;
1705  PROCESS_PRIORITY_CLASS PriorityClass;
1706 
1707  /* Query the kernel */
1708  Status = NtQueryInformationProcess(hProcess,
1710  &PriorityClass,
1711  sizeof(PriorityClass),
1712  NULL);
1713  if (NT_SUCCESS(Status))
1714  {
1715  /* Handle the conversion from NT to Win32 classes */
1716  switch (PriorityClass.PriorityClass)
1717  {
1724  }
1725  }
1726 
1727  /* Failure path */
1728  BaseSetLastNTError(Status);
1729  return FALSE;
1730 }
1731 
1732 /*
1733  * @implemented
1734  */
1735 BOOL
1736 WINAPI
1738  IN DWORD dwPriorityClass)
1739 {
1740  NTSTATUS Status;
1741  PVOID State = NULL;
1742  PROCESS_PRIORITY_CLASS PriorityClass;
1743 
1744  /* Handle conversion from Win32 to NT priority classes */
1745  switch (dwPriorityClass)
1746  {
1747  case IDLE_PRIORITY_CLASS:
1749  break;
1750 
1753  break;
1754 
1755  case NORMAL_PRIORITY_CLASS:
1757  break;
1758 
1761  break;
1762 
1763  case HIGH_PRIORITY_CLASS:
1765  break;
1766 
1768  /* Try to acquire the privilege. If it fails, just use HIGH */
1769  State = BasepIsRealtimeAllowed(TRUE);
1771  PriorityClass.PriorityClass += (State != NULL);
1772  break;
1773 
1774  default:
1775  /* Unrecognized priority classes don't make it to the kernel */
1777  return FALSE;
1778  }
1779 
1780  /* Send the request to the kernel, and don't touch the foreground flag */
1781  PriorityClass.Foreground = FALSE;
1782  Status = NtSetInformationProcess(hProcess,
1784  &PriorityClass,
1785  sizeof(PROCESS_PRIORITY_CLASS));
1786 
1787  /* Release the privilege if we had it */
1788  if (State) RtlReleasePrivilege(State);
1789  if (!NT_SUCCESS(Status))
1790  {
1791  /* Handle error path */
1792  BaseSetLastNTError(Status);
1793  return FALSE;
1794  }
1795 
1796  /* All done */
1797  return TRUE;
1798 }
1799 
1800 /*
1801  * @implemented
1802  */
1803 DWORD
1804 WINAPI
1806 {
1807  DWORD Version = 0;
1808  PIMAGE_NT_HEADERS NtHeader;
1809  PIMAGE_DOS_HEADER DosHeader;
1810  PPEB Peb;
1811  PROCESS_BASIC_INFORMATION ProcessBasicInfo;
1813  ULONG e_lfanew;
1815  NTSTATUS Status;
1816  USHORT VersionData[2];
1817  BOOLEAN Result;
1818 
1819  /* We'll be accessing stuff that can fault, so protect everything with SEH */
1820  _SEH2_TRY
1821  {
1822  /* It this an in-process or out-of-process request? */
1823  if (!(ProcessId) || (GetCurrentProcessId() == ProcessId))
1824  {
1825  /* It's in-process, so just read our own header */
1826  NtHeader = RtlImageNtHeader(NtCurrentPeb()->ImageBaseAddress);
1827  if (!NtHeader)
1828  {
1829  /* Unable to read the NT header, something is wrong here... */
1830  Status = STATUS_INVALID_IMAGE_FORMAT;
1831  goto Error;
1832  }
1833 
1834  /* Get the version straight out of the NT header */
1835  Version = MAKELONG(NtHeader->OptionalHeader.MinorSubsystemVersion,
1837  }
1838  else
1839  {
1840  /* Out-of-process, so open it */
1842  FALSE,
1843  ProcessId);
1844  if (!ProcessHandle) _SEH2_YIELD(return 0);
1845 
1846  /* Try to find out where its PEB lives */
1847  Status = NtQueryInformationProcess(ProcessHandle,
1849  &ProcessBasicInfo,
1850  sizeof(ProcessBasicInfo),
1851  NULL);
1852 
1853  if (!NT_SUCCESS(Status)) goto Error;
1854  Peb = ProcessBasicInfo.PebBaseAddress;
1855 
1856  /* Now that we have the PEB, read the image base address out of it */
1857  Result = ReadProcessMemory(ProcessHandle,
1858  &Peb->ImageBaseAddress,
1859  &BaseAddress,
1860  sizeof(BaseAddress),
1861  NULL);
1862  if (!Result) goto Error;
1863 
1864  /* Now read the e_lfanew (offset to NT header) from the base */
1865  DosHeader = BaseAddress;
1866  Result = ReadProcessMemory(ProcessHandle,
1867  &DosHeader->e_lfanew,
1868  &e_lfanew,
1869  sizeof(e_lfanew),
1870  NULL);
1871  if (!Result) goto Error;
1872 
1873  /* And finally, read the NT header itself by adding the offset */
1874  NtHeader = (PVOID)((ULONG_PTR)BaseAddress + e_lfanew);
1875  Result = ReadProcessMemory(ProcessHandle,
1877  &VersionData,
1878  sizeof(VersionData),
1879  NULL);
1880  if (!Result) goto Error;
1881 
1882  /* Get the version straight out of the NT header */
1883  Version = MAKELONG(VersionData[0], VersionData[1]);
1884 
1885 Error:
1886  /* If there was an error anywhere, set the last error */
1887  if (!NT_SUCCESS(Status)) BaseSetLastNTError(Status);
1888  }
1889  }
1891  {
1892  /* Close the process handle */
1893  if (ProcessHandle) CloseHandle(ProcessHandle);
1894  }
1895  _SEH2_END;
1896 
1897  /* And return the version data */
1898  return Version;
1899 }
1900 
1901 /*
1902  * @implemented
1903  */
1904 BOOL
1905 WINAPI
1907  OUT PIO_COUNTERS lpIoCounters)
1908 {
1909  NTSTATUS Status;
1910 
1911  /* Query the kernel. Structures are identical, so let it do the copy too. */
1912  Status = NtQueryInformationProcess(hProcess,
1914  lpIoCounters,
1915  sizeof(IO_COUNTERS),
1916  NULL);
1917  if (!NT_SUCCESS(Status))
1918  {
1919  /* Handle error path */
1920  BaseSetLastNTError(Status);
1921  return FALSE;
1922  }
1923 
1924  /* All done */
1925  return TRUE;
1926 }
1927 
1928 /*
1929  * @implemented
1930  */
1931 BOOL
1932 WINAPI
1934  OUT PBOOL pDisablePriorityBoost)
1935 {
1936  NTSTATUS Status;
1938 
1939  /* Query the kernel */
1940  Status = NtQueryInformationProcess(hProcess,
1942  &PriorityBoost,
1943  sizeof(PriorityBoost),
1944  NULL);
1945  if (NT_SUCCESS(Status))
1946  {
1947  /* Convert from ULONG to a BOOL */
1948  *pDisablePriorityBoost = PriorityBoost ? TRUE : FALSE;
1949  return TRUE;
1950  }
1951 
1952  /* Handle error path */
1953  BaseSetLastNTError(Status);
1954  return FALSE;
1955 }
1956 
1957 /*
1958  * @implemented
1959  */
1960 BOOL
1961 WINAPI
1963  IN BOOL bDisablePriorityBoost)
1964 {
1965  NTSTATUS Status;
1967 
1968  /* Enforce that this is a BOOL, and send it to the kernel as a ULONG */
1969  PriorityBoost = (bDisablePriorityBoost ? TRUE : FALSE);
1970  Status = NtSetInformationProcess(hProcess,
1972  &PriorityBoost,
1973  sizeof(ULONG));
1974  if (!NT_SUCCESS(Status))
1975  {
1976  /* Handle error path */
1977  BaseSetLastNTError(Status);
1978  return FALSE;
1979  }
1980 
1981  /* All done */
1982  return TRUE;
1983 }
1984 
1985 /*
1986  * @implemented
1987  */
1988 BOOL
1989 WINAPI
1991  OUT PDWORD pdwHandleCount)
1992 {
1993  ULONG phc;
1994  NTSTATUS Status;
1995 
1996  /* Query the kernel */
1997  Status = NtQueryInformationProcess(hProcess,
1999  &phc,
2000  sizeof(phc),
2001  NULL);
2002  if (NT_SUCCESS(Status))
2003  {
2004  /* Copy the count and return success */
2005  *pdwHandleCount = phc;
2006  return TRUE;
2007  }
2008 
2009  /* Handle error path */
2010  BaseSetLastNTError(Status);
2011  return FALSE;
2012 }
2013 
2014 /*
2015  * @implemented
2016  */
2017 BOOL
2018 WINAPI
2020  OUT PBOOL Wow64Process)
2021 {
2022  ULONG_PTR pbi;
2023  NTSTATUS Status;
2024 
2025  /* Query the kernel */
2026  Status = NtQueryInformationProcess(hProcess,
2028  &pbi,
2029  sizeof(pbi),
2030  NULL);
2031  if (!NT_SUCCESS(Status))
2032  {
2033  /* Handle error path */
2034  BaseSetLastNTError(Status);
2035  return FALSE;
2036  }
2037 
2038  /* Enforce this is a BOOL, and return success */
2039  *Wow64Process = (pbi != 0);
2040  return TRUE;
2041 }
2042 
2043 /*
2044  * @implemented
2045  */
2046 LPSTR
2047 WINAPI
2049 {
2050  return BaseAnsiCommandLine.Buffer;
2051 }
2052 
2053 /*
2054  * @implemented
2055  */
2056 LPWSTR
2057 WINAPI
2059 {
2060  return BaseUnicodeCommandLine.Buffer;
2061 }
2062 
2063 /*
2064  * @implemented
2065  */
2066 BOOL
2067 NTAPI
2069  IN LPCVOID lpBaseAddress,
2070  IN LPVOID lpBuffer,
2071  IN SIZE_T nSize,
2072  OUT SIZE_T* lpNumberOfBytesRead)
2073 {
2074  NTSTATUS Status;
2075 
2076  /* Do the read */
2077  Status = NtReadVirtualMemory(hProcess,
2078  (PVOID)lpBaseAddress,
2079  lpBuffer,
2080  nSize,
2081  &nSize);
2082 
2083  /* In user-mode, this parameter is optional */
2084  if (lpNumberOfBytesRead) *lpNumberOfBytesRead = nSize;
2085  if (!NT_SUCCESS(Status))
2086  {
2087  /* We failed */
2088  BaseSetLastNTError(Status);
2089  return FALSE;
2090  }
2091 
2092  /* Return success */
2093  return TRUE;
2094 }
2095 
2096 /*
2097  * @implemented
2098  */
2099 BOOL
2100 NTAPI
2102  IN LPVOID lpBaseAddress,
2104  IN SIZE_T nSize,
2105  OUT SIZE_T *lpNumberOfBytesWritten)
2106 {
2107  NTSTATUS Status;
2108  ULONG OldValue;
2110  PVOID Base;
2112 
2113  /* Set parameters for protect call */
2114  RegionSize = nSize;
2115  Base = lpBaseAddress;
2116 
2117  /* Check the current status */
2118  Status = NtProtectVirtualMemory(hProcess,
2119  &Base,
2120  &RegionSize,
2122  &OldValue);
2123  if (NT_SUCCESS(Status))
2124  {
2125  /* Check if we are unprotecting */
2126  UnProtect = OldValue & (PAGE_READWRITE |
2127  PAGE_WRITECOPY |
2130  if (!UnProtect)
2131  {
2132  /* Set the new protection */
2133  Status = NtProtectVirtualMemory(hProcess,
2134  &Base,
2135  &RegionSize,
2136  OldValue,
2137  &OldValue);
2138 
2139  /* Write the memory */
2140  Status = NtWriteVirtualMemory(hProcess,
2141  lpBaseAddress,
2142  (LPVOID)lpBuffer,
2143  nSize,
2144  &nSize);
2145 
2146  /* In Win32, the parameter is optional, so handle this case */
2147  if (lpNumberOfBytesWritten) *lpNumberOfBytesWritten = nSize;
2148 
2149  if (!NT_SUCCESS(Status))
2150  {
2151  /* We failed */
2152  BaseSetLastNTError(Status);
2153  return FALSE;
2154  }
2155 
2156  /* Flush the ITLB */
2157  NtFlushInstructionCache(hProcess, lpBaseAddress, nSize);
2158  return TRUE;
2159  }
2160  else
2161  {
2162  /* Check if we were read only */
2163  if (OldValue & (PAGE_NOACCESS | PAGE_READONLY))
2164  {
2165  /* Restore protection and fail */
2166  NtProtectVirtualMemory(hProcess,
2167  &Base,
2168  &RegionSize,
2169  OldValue,
2170  &OldValue);
2172 
2173  /* Note: This is what Windows returns and code depends on it */
2174  return STATUS_ACCESS_VIOLATION;
2175  }
2176 
2177  /* Otherwise, do the write */
2178  Status = NtWriteVirtualMemory(hProcess,
2179  lpBaseAddress,
2180  (LPVOID)lpBuffer,
2181  nSize,
2182  &nSize);
2183 
2184  /* In Win32, the parameter is optional, so handle this case */
2185  if (lpNumberOfBytesWritten) *lpNumberOfBytesWritten = nSize;
2186 
2187  /* And restore the protection */
2188  NtProtectVirtualMemory(hProcess,
2189  &Base,
2190  &RegionSize,
2191  OldValue,
2192  &OldValue);
2193  if (!NT_SUCCESS(Status))
2194  {
2195  /* We failed */
2197 
2198  /* Note: This is what Windows returns and code depends on it */
2199  return STATUS_ACCESS_VIOLATION;
2200  }
2201 
2202  /* Flush the ITLB */
2203  NtFlushInstructionCache(hProcess, lpBaseAddress, nSize);
2204  return TRUE;
2205  }
2206  }
2207  else
2208  {
2209  /* We failed */
2210  BaseSetLastNTError(Status);
2211  return FALSE;
2212  }
2213 }
2214 
2215 /*
2216  * @implemented
2217  */
2218 BOOL
2219 WINAPI
2221  OUT PDWORD pSessionId)
2222 {
2223  PROCESS_SESSION_INFORMATION SessionInformation;
2227  NTSTATUS Status;
2228 
2229  /* Do a quick check if the pointer is not writable */
2230  if (IsBadWritePtr(pSessionId, sizeof(DWORD)))
2231  {
2232  /* Fail fast */
2234  return FALSE;
2235  }
2236 
2237  /* Open the process passed in by ID */
2238  ClientId.UniqueProcess = UlongToHandle(dwProcessId);
2239  ClientId.UniqueThread = 0;
2240  InitializeObjectAttributes(&ObjectAttributes, NULL, 0, NULL, NULL);
2241  Status = NtOpenProcess(&ProcessHandle,
2243  &ObjectAttributes,
2244  &ClientId);
2245  if (NT_SUCCESS(Status))
2246  {
2247  /* Query the session ID from the kernel */
2248  Status = NtQueryInformationProcess(ProcessHandle,
2250  &SessionInformation,
2251  sizeof(SessionInformation),
2252  NULL);
2253 
2254  /* Close the handle and check if we succeeded */
2255  NtClose(ProcessHandle);
2256  if (NT_SUCCESS(Status))
2257  {
2258  /* Return the session ID */
2259  *pSessionId = SessionInformation.SessionId;
2260  return TRUE;
2261  }
2262  }
2263 
2264  /* Set error code and fail */
2265  BaseSetLastNTError(Status);
2266  return FALSE;
2267 }
2268 
2269 
2270 #define AddToHandle(x,y) (x) = (HANDLE)((ULONG_PTR)(x) | (y));
2271 #define RemoveFromHandle(x,y) (x) = (HANDLE)((ULONG_PTR)(x) & ~(y));
2273 
2274 /*
2275  * @implemented
2276  */
2277 BOOL
2278 WINAPI
2280  IN LPCWSTR lpApplicationName,
2281  IN LPWSTR lpCommandLine,
2282  IN LPSECURITY_ATTRIBUTES lpProcessAttributes,
2283  IN LPSECURITY_ATTRIBUTES lpThreadAttributes,
2284  IN BOOL bInheritHandles,
2285  IN DWORD dwCreationFlags,
2286  IN LPVOID lpEnvironment,
2287  IN LPCWSTR lpCurrentDirectory,
2288  IN LPSTARTUPINFOW lpStartupInfo,
2289  IN LPPROCESS_INFORMATION lpProcessInformation,
2290  OUT PHANDLE hNewToken)
2291 {
2292  //
2293  // Core variables used for creating the initial process and thread
2294  //
2295  SECURITY_ATTRIBUTES LocalThreadAttributes, LocalProcessAttributes;
2296  OBJECT_ATTRIBUTES LocalObjectAttributes;
2298  SECTION_IMAGE_INFORMATION ImageInformation;
2301  ULONG NoWindow, RegionSize, StackSize, ErrorCode, Flags;
2302  USHORT ImageMachine;
2303  ULONG ParameterFlags, PrivilegeValue, HardErrorMode, ErrorResponse;
2304  ULONG_PTR ErrorParameters[2];
2305  BOOLEAN InJob, SaferNeeded, UseLargePages, HavePrivilege;
2306  BOOLEAN QuerySection, SkipSaferAndAppCompat;
2307  CONTEXT Context;
2308  BASE_API_MESSAGE CsrMsg[2];
2309  PBASE_CREATE_PROCESS CreateProcessMsg;
2310  PCSR_CAPTURE_BUFFER CaptureBuffer;
2311  PVOID BaseAddress, PrivilegeState, RealTimePrivilegeState;
2312  HANDLE DebugHandle, TokenHandle, JobHandle, KeyHandle, ThreadHandle;
2313  HANDLE FileHandle, SectionHandle, ProcessHandle;
2315  PROCESS_PRIORITY_CLASS PriorityClass;
2316  NTSTATUS Status, AppCompatStatus, SaferStatus, IFEOStatus, ImageDbgStatus;
2317  PPEB Peb, RemotePeb;
2318  PTEB Teb;
2319  INITIAL_TEB InitialTeb;
2320  PVOID TibValue;
2321  PIMAGE_NT_HEADERS NtHeaders;
2322  STARTUPINFOW StartupInfo;
2323  PRTL_USER_PROCESS_PARAMETERS ProcessParameters;
2324  UNICODE_STRING DebuggerString;
2325  BOOL Result;
2326  //
2327  // Variables used for command-line and argument parsing
2328  //
2329  PCHAR pcScan;
2330  SIZE_T n;
2331  WCHAR SaveChar;
2332  ULONG Length, FileAttribs, CmdQuoteLength;
2333  ULONG CmdLineLength, ResultSize;
2334  PWCHAR QuotedCmdLine, AnsiCmdCommand, ExtBuffer, CurrentDirectory;
2335  PWCHAR NullBuffer, ScanString, NameBuffer, SearchPath, DebuggerCmdLine;
2336  ANSI_STRING AnsiEnv;
2337  UNICODE_STRING UnicodeEnv, PathName;
2338  BOOLEAN SearchRetry, QuotesNeeded, CmdLineIsAppName, HasQuotes;
2339 
2340  //
2341  // Variables used for Fusion/SxS (Side-by-Side Assemblies)
2342  //
2343  RTL_PATH_TYPE SxsPathType, PathType;
2344 #if _SXS_SUPPORT_ENABLED_
2345  PRTL_BUFFER ByteBuffer;
2346  PRTL_UNICODE_STRING_BUFFER ThisBuffer, Buffer, SxsStaticBuffers[5];
2347  PRTL_UNICODE_STRING_BUFFER* BufferHead, SxsStringBuffer;
2348  RTL_UNICODE_STRING_BUFFER SxsWin32ManifestPath, SxsNtManifestPath;
2349  RTL_UNICODE_STRING_BUFFER SxsWin32PolicyPath, SxsNtPolicyPath;
2350  RTL_UNICODE_STRING_BUFFER SxsWin32AssemblyDirectory;
2351  BASE_MSG_SXS_HANDLES MappedHandles, Handles, FileHandles;
2352  PVOID CapturedStrings[3];
2353  SXS_WIN32_NT_PATH_PAIR ExePathPair, ManifestPathPair, PolicyPathPair;
2354  SXS_OVERRIDE_MANIFEST OverrideManifest;
2355  UNICODE_STRING FreeString, SxsNtExePath;
2356  PWCHAR SxsConglomeratedBuffer, StaticBuffer;
2357  ULONG ConglomeratedBufferSizeBytes, StaticBufferSize, i;
2358 #endif
2360 
2361  //
2362  // Variables used for path conversion (and partially Fusion/SxS)
2363  //
2364  PWCHAR FilePart, PathBuffer, FreeBuffer;
2365  BOOLEAN TranslationStatus;
2366  RTL_RELATIVE_NAME_U SxsWin32RelativePath;
2367  UNICODE_STRING PathBufferString, SxsWin32ExePath;
2368 
2369  //
2370  // Variables used by Application Compatibility (and partially Fusion/SxS)
2371  //
2372  PVOID AppCompatSxsData, AppCompatData;
2373  ULONG AppCompatSxsDataSize, AppCompatDataSize;
2374  //
2375  // Variables used by VDM (Virtual Dos Machine) and WOW32 (16-bit Support)
2376  //
2377  ULONG BinarySubType, VdmBinaryType, VdmTask, VdmReserve;
2378  ULONG VdmUndoLevel;
2379  BOOLEAN UseVdmReserve;
2380  HANDLE VdmWaitObject;
2381  ANSI_STRING VdmAnsiEnv;
2382  UNICODE_STRING VdmString, VdmUnicodeEnv;
2383  BOOLEAN IsWowApp;
2384  PBASE_CHECK_VDM CheckVdmMsg;
2385 
2386  /* Zero out the initial core variables and handles */
2387  QuerySection = FALSE;
2388  InJob = FALSE;
2389  SkipSaferAndAppCompat = FALSE;
2390  ParameterFlags = 0;
2391  Flags = 0;
2392  DebugHandle = NULL;
2393  JobHandle = NULL;
2394  TokenHandle = NULL;
2395  FileHandle = NULL;
2396  SectionHandle = NULL;
2397  ProcessHandle = NULL;
2398  ThreadHandle = NULL;
2399  BaseAddress = (PVOID)1;
2400 
2401  /* Zero out initial SxS and Application Compatibility state */
2402  AppCompatData = NULL;
2403  AppCompatDataSize = 0;
2404  AppCompatSxsData = NULL;
2405  AppCompatSxsDataSize = 0;
2406  CaptureBuffer = NULL;
2407 #if _SXS_SUPPORT_ENABLED_
2408  SxsConglomeratedBuffer = NULL;
2409 #endif
2410  FusionFlags = 0;
2411 
2412  /* Zero out initial parsing variables -- others are initialized later */
2413  DebuggerCmdLine = NULL;
2414  PathBuffer = NULL;
2415  SearchPath = NULL;
2416  NullBuffer = 0;
2417  FreeBuffer = NULL;
2418  NameBuffer = NULL;
2419  CurrentDirectory = NULL;
2420  FilePart = NULL;
2421  DebuggerString.Buffer = NULL;
2422  HasQuotes = FALSE;
2423  QuotedCmdLine = NULL;
2424 
2425  /* Zero out initial VDM state */
2426  VdmAnsiEnv.Buffer = NULL;
2427  VdmUnicodeEnv.Buffer = NULL;
2428  VdmString.Buffer = NULL;
2429  VdmTask = 0;
2430  VdmUndoLevel = 0;
2431  VdmBinaryType = 0;
2432  VdmReserve = 0;
2433  VdmWaitObject = NULL;
2434  UseVdmReserve = FALSE;
2435  IsWowApp = FALSE;
2436 
2437  /* Set message structures */
2438  CreateProcessMsg = &CsrMsg[0].Data.CreateProcessRequest;
2439  CheckVdmMsg = &CsrMsg[1].Data.CheckVDMRequest;
2440 
2441  /* Clear the more complex structures by zeroing out their entire memory */
2442  RtlZeroMemory(&Context, sizeof(Context));
2443 #if _SXS_SUPPORT_ENABLED_
2444  RtlZeroMemory(&FileHandles, sizeof(FileHandles));
2445  RtlZeroMemory(&MappedHandles, sizeof(MappedHandles));
2446  RtlZeroMemory(&Handles, sizeof(Handles));
2447 #endif
2448  RtlZeroMemory(&CreateProcessMsg->Sxs, sizeof(CreateProcessMsg->Sxs));
2449  RtlZeroMemory(&LocalProcessAttributes, sizeof(LocalProcessAttributes));
2450  RtlZeroMemory(&LocalThreadAttributes, sizeof(LocalThreadAttributes));
2451 
2452  /* Zero out output arguments as well */
2453  RtlZeroMemory(lpProcessInformation, sizeof(*lpProcessInformation));
2454  if (hNewToken) *hNewToken = NULL;
2455 
2456  /* Capture the special window flag */
2457  NoWindow = dwCreationFlags & CREATE_NO_WINDOW;
2458  dwCreationFlags &= ~CREATE_NO_WINDOW;
2459 
2460 #if _SXS_SUPPORT_ENABLED_
2461  /* Setup the SxS static string arrays and buffers */
2462  SxsStaticBuffers[0] = &SxsWin32ManifestPath;
2463  SxsStaticBuffers[1] = &SxsWin32PolicyPath;
2464  SxsStaticBuffers[2] = &SxsWin32AssemblyDirectory;
2465  SxsStaticBuffers[3] = &SxsNtManifestPath;
2466  SxsStaticBuffers[4] = &SxsNtPolicyPath;
2467  ExePathPair.Win32 = &SxsWin32ExePath;
2468  ExePathPair.Nt = &SxsNtExePath;
2469  ManifestPathPair.Win32 = &SxsWin32ManifestPath.String;
2470  ManifestPathPair.Nt = &SxsNtManifestPath.String;
2471  PolicyPathPair.Win32 = &SxsWin32PolicyPath.String;
2472  PolicyPathPair.Nt = &SxsNtPolicyPath.String;
2473 #endif
2474 
2475  DPRINT("CreateProcessInternalW: '%S' '%S' %lx\n", lpApplicationName, lpCommandLine, dwCreationFlags);
2476 
2477  /* Finally, set our TEB and PEB */
2478  Teb = NtCurrentTeb();
2479  Peb = NtCurrentPeb();
2480 
2481  /* This combination is illegal (see MSDN) */
2482  if ((dwCreationFlags & (DETACHED_PROCESS | CREATE_NEW_CONSOLE)) ==
2484  {
2485  DPRINT1("Invalid flag combo used\n");
2487  return FALSE;
2488  }
2489 
2490  /* Convert the priority class */
2491  if (dwCreationFlags & IDLE_PRIORITY_CLASS)
2492  {
2494  }
2495  else if (dwCreationFlags & BELOW_NORMAL_PRIORITY_CLASS)
2496  {
2498  }
2499  else if (dwCreationFlags & NORMAL_PRIORITY_CLASS)
2500  {
2502  }
2503  else if (dwCreationFlags & ABOVE_NORMAL_PRIORITY_CLASS)
2504  {
2506  }
2507  else if (dwCreationFlags & HIGH_PRIORITY_CLASS)
2508  {
2510  }
2511  else if (dwCreationFlags & REALTIME_PRIORITY_CLASS)
2512  {
2514  PriorityClass.PriorityClass += (BasepIsRealtimeAllowed(FALSE) != NULL);
2515  }
2516  else
2517  {
2519  }
2520 
2521  /* Done with the priority masks, so get rid of them */
2522  PriorityClass.Foreground = FALSE;
2523  dwCreationFlags &= ~(NORMAL_PRIORITY_CLASS |
2524  IDLE_PRIORITY_CLASS |
2525  HIGH_PRIORITY_CLASS |
2526  REALTIME_PRIORITY_CLASS |
2527  BELOW_NORMAL_PRIORITY_CLASS |
2529 
2530  /* You cannot request both a shared and a separate WoW VDM */
2531  if ((dwCreationFlags & CREATE_SEPARATE_WOW_VDM) &&
2532  (dwCreationFlags & CREATE_SHARED_WOW_VDM))
2533  {
2534  /* Fail such nonsensical attempts */
2535  DPRINT1("Invalid WOW flags\n");
2537  return FALSE;
2538  }
2539  else if (!(dwCreationFlags & CREATE_SHARED_WOW_VDM) &&
2541  {
2542  /* A shared WoW VDM was not requested but system enforces separation */
2543  dwCreationFlags |= CREATE_SEPARATE_WOW_VDM;
2544  }
2545 
2546  /* If a shared WoW VDM is used, make sure the process isn't in a job */
2547  if (!(dwCreationFlags & CREATE_SEPARATE_WOW_VDM) &&
2549  {
2550  /* Remove the shared flag and add the separate flag */
2551  dwCreationFlags = (dwCreationFlags &~ CREATE_SHARED_WOW_VDM) |
2552  CREATE_SEPARATE_WOW_VDM;
2553  }
2554 
2555  /* Convert the environment */
2556  if ((lpEnvironment) && !(dwCreationFlags & CREATE_UNICODE_ENVIRONMENT))
2557  {
2558  /* Scan the environment to calculate its Unicode size */
2559  AnsiEnv.Buffer = pcScan = (PCHAR)lpEnvironment;
2560  while ((*pcScan) || (*(pcScan + 1))) ++pcScan;
2561 
2562  /* Create our ANSI String */
2563  AnsiEnv.Length = pcScan - (PCHAR)lpEnvironment + sizeof(ANSI_NULL);
2564  AnsiEnv.MaximumLength = AnsiEnv.Length + sizeof(ANSI_NULL);
2565 
2566  /* Allocate memory for the Unicode Environment */
2567  UnicodeEnv.Buffer = NULL;
2568  RegionSize = AnsiEnv.MaximumLength * sizeof(WCHAR);
2570  (PVOID)&UnicodeEnv.Buffer,
2571  0,
2572  &RegionSize,
2573  MEM_COMMIT,
2574  PAGE_READWRITE);
2575  if (!NT_SUCCESS(Status))
2576  {
2577  /* Fail */
2578  BaseSetLastNTError(Status);
2579  return FALSE;
2580  }
2581 
2582  /* Use the allocated size and convert */
2583  UnicodeEnv.MaximumLength = (USHORT)RegionSize;
2584  Status = RtlAnsiStringToUnicodeString(&UnicodeEnv, &AnsiEnv, FALSE);
2585  if (!NT_SUCCESS(Status))
2586  {
2587  /* Fail */
2589  (PVOID)&UnicodeEnv.Buffer,
2590  &RegionSize,
2591  MEM_RELEASE);
2592  BaseSetLastNTError(Status);
2593  return FALSE;
2594  }
2595 
2596  /* Now set the Unicode environment as the environment string pointer */
2597  lpEnvironment = UnicodeEnv.Buffer;
2598  }
2599 
2600  /* Make a copy of the caller's startup info since we'll modify it */
2601  StartupInfo = *lpStartupInfo;
2602 
2603  /* Check if private data is being sent on the same channel as std handles */
2604  if ((StartupInfo.dwFlags & STARTF_USESTDHANDLES) &&
2605  (StartupInfo.dwFlags & (STARTF_USEHOTKEY | STARTF_SHELLPRIVATE)))
2606  {
2607  /* Cannot use the std handles since we have monitor/hotkey values */
2608  StartupInfo.dwFlags &= ~STARTF_USESTDHANDLES;
2609  }
2610 
2611  /* If there's a debugger, or we have to launch cmd.exe, we go back here */
2612 AppNameRetry:
2613  /* New iteration -- free any existing name buffer */
2614  if (NameBuffer)
2615  {
2616  RtlFreeHeap(RtlGetProcessHeap(), 0, NameBuffer);
2617  NameBuffer = NULL;
2618  }
2619 
2620  /* New iteration -- free any existing free buffer */
2621  if (FreeBuffer)
2622  {
2623  RtlFreeHeap(RtlGetProcessHeap(), 0, FreeBuffer);
2624  FreeBuffer = NULL;
2625  }
2626 
2627  /* New iteration -- close any existing file handle */
2628  if (FileHandle)
2629  {
2630  NtClose(FileHandle);
2631  FileHandle = NULL;
2632  }
2633 
2634  /* Set the initial parsing state. This code can loop -- don't move this! */
2635  ErrorCode = 0;
2636  SearchRetry = TRUE;
2637  QuotesNeeded = FALSE;
2638  CmdLineIsAppName = FALSE;
2639 
2640  /* First check if we don't have an application name */
2641  if (!lpApplicationName)
2642  {
2643  /* This should be the first time we attempt creating one */
2644  ASSERT(NameBuffer == NULL);
2645 
2646  /* Allocate a buffer to hold it */
2647  NameBuffer = RtlAllocateHeap(RtlGetProcessHeap(),
2648  0,
2649  MAX_PATH * sizeof(WCHAR));
2650  if (!NameBuffer)
2651  {
2653  Result = FALSE;
2654  goto Quickie;
2655  }
2656 
2657  /* Initialize the application name and our parsing parameters */
2658  lpApplicationName = NullBuffer = ScanString = lpCommandLine;
2659 
2660  /* Check for an initial quote*/
2661  if (*lpCommandLine == L'\"')
2662  {
2663  /* We found a quote, keep searching for another one */
2664  SearchRetry = FALSE;
2665  ScanString++;
2666  lpApplicationName = ScanString;
2667  while (*ScanString)
2668  {
2669  /* Have we found the terminating quote? */
2670  if (*ScanString == L'\"')
2671  {
2672  /* We're done, get out of here */
2673  NullBuffer = ScanString;
2674  HasQuotes = TRUE;
2675  break;
2676  }
2677 
2678  /* Keep searching for the quote */
2679  ScanString++;
2680  NullBuffer = ScanString;
2681  }
2682  }
2683  else
2684  {
2685 StartScan:
2686  /* We simply make the application name be the command line*/
2687  lpApplicationName = lpCommandLine;
2688  while (*ScanString)
2689  {
2690  /* Check if it starts with a space or tab */
2691  if ((*ScanString == L' ') || (*ScanString == L'\t'))
2692  {
2693  /* Break out of the search loop */
2694  NullBuffer = ScanString;
2695  break;
2696  }
2697 
2698  /* Keep searching for a space or tab */
2699  ScanString++;
2700  NullBuffer = ScanString;
2701  }
2702  }
2703 
2704  /* We have found the end of the application name, terminate it */
2705  SaveChar = *NullBuffer;
2706  *NullBuffer = UNICODE_NULL;
2707 
2708  /* New iteration -- free any existing saved path */
2709  if (SearchPath)
2710  {
2711  RtlFreeHeap(RtlGetProcessHeap(), 0, SearchPath);
2712  SearchPath = NULL;
2713  }
2714 
2715  /* Now compute the final EXE path based on the name */
2716  SearchPath = BaseComputeProcessExePath((LPWSTR)lpApplicationName);
2717  DPRINT("Search Path: %S\n", SearchPath);
2718  if (!SearchPath)
2719  {
2721  Result = FALSE;
2722  goto Quickie;
2723  }
2724 
2725  /* And search for the executable in the search path */
2726  Length = SearchPathW(SearchPath,
2727  lpApplicationName,
2728  L".exe",
2729  MAX_PATH,
2730  NameBuffer,
2731  NULL);
2732 
2733  /* Did we find it? */
2734  if ((Length) && (Length < MAX_PATH))
2735  {
2736  /* Get file attributes */
2737  FileAttribs = GetFileAttributesW(NameBuffer);
2738  if ((FileAttribs != INVALID_FILE_ATTRIBUTES) &&
2739  (FileAttribs & FILE_ATTRIBUTE_DIRECTORY))
2740  {
2741  /* This was a directory, fail later on */
2742  Length = 0;
2743  }
2744  else
2745  {
2746  /* It's a file! */
2747  Length++;
2748  }
2749  }
2750 
2751  DPRINT("Length: %lu Buffer: %S\n", Length, NameBuffer);
2752 
2753  /* Check if there was a failure in SearchPathW */
2754  if ((Length) && (Length < MAX_PATH))
2755  {
2756  /* Everything looks good, restore the name */
2757  *NullBuffer = SaveChar;
2758  lpApplicationName = NameBuffer;
2759  }
2760  else
2761  {
2762  /* Check if this was a relative path, which would explain it */
2763  PathType = RtlDetermineDosPathNameType_U(lpApplicationName);
2764  if (PathType != RtlPathTypeRelative)
2765  {
2766  /* This should fail, and give us a detailed LastError */
2767  FileHandle = CreateFileW(lpApplicationName,
2768  GENERIC_READ,
2769  FILE_SHARE_READ |
2771  NULL,
2772  OPEN_EXISTING,
2774  NULL);
2775  if (FileHandle != INVALID_HANDLE_VALUE)
2776  {
2777  /* It worked? Return a generic error */
2778  CloseHandle(FileHandle);
2779  FileHandle = NULL;
2781  }
2782  }
2783  else
2784  {
2785  /* Path was absolute, which means it doesn't exist */
2787  }
2788 
2789  /* Did we already fail once? */
2790  if (ErrorCode)
2791  {
2792  /* Set the error code */
2793  SetLastError(ErrorCode);
2794  }
2795  else
2796  {
2797  /* Not yet, cache it */
2798  ErrorCode = GetLastError();
2799  }
2800 
2801  /* Put back the command line */
2802  *NullBuffer = SaveChar;
2803  lpApplicationName = NameBuffer;
2804 
2805  /* It's possible there's whitespace in the directory name */
2806  if (!(*ScanString) || !(SearchRetry))
2807  {
2808  /* Not the case, give up completely */
2809  Result = FALSE;
2810  goto Quickie;
2811  }
2812 
2813  /* There are spaces, so keep trying the next possibility */
2814  ScanString++;
2815  NullBuffer = ScanString;
2816 
2817  /* We will have to add a quote, since there is a space */
2818  QuotesNeeded = TRUE;
2819  HasQuotes = TRUE;
2820  goto StartScan;
2821  }
2822  }
2823  else if (!(lpCommandLine) || !(*lpCommandLine))
2824  {
2825  /* We don't have a command line, so just use the application name */
2826  CmdLineIsAppName = TRUE;
2827  lpCommandLine = (LPWSTR)lpApplicationName;
2828  }
2829 
2830  /* Convert the application name to its NT path */
2831  TranslationStatus = RtlDosPathNameToRelativeNtPathName_U(lpApplicationName,
2832  &PathName,
2833  NULL,
2834  &SxsWin32RelativePath);
2835  if (!TranslationStatus)
2836  {
2837  /* Path must be invalid somehow, bail out */
2838  DPRINT1("Path translation for SxS failed\n");
2840  Result = FALSE;
2841  goto Quickie;
2842  }
2843 
2844  /* Setup the buffer that needs to be freed at the end */
2845  ASSERT(FreeBuffer == NULL);
2846  FreeBuffer = PathName.Buffer;
2847 
2848  /* Check what kind of path the application is, for SxS (Fusion) purposes */
2849  RtlInitUnicodeString(&SxsWin32ExePath, lpApplicationName);
2850  SxsPathType = RtlDetermineDosPathNameType_U(lpApplicationName);
2851  if ((SxsPathType != RtlPathTypeDriveAbsolute) &&
2852  (SxsPathType != RtlPathTypeLocalDevice) &&
2853  (SxsPathType != RtlPathTypeRootLocalDevice) &&
2854  (SxsPathType != RtlPathTypeUncAbsolute))
2855  {
2856  /* Relative-type path, get the full path */
2857  RtlInitEmptyUnicodeString(&PathBufferString, NULL, 0);
2858  Status = RtlGetFullPathName_UstrEx(&SxsWin32ExePath,
2859  NULL,
2860  &PathBufferString,
2861  NULL,
2862  NULL,
2863  NULL,
2864  &SxsPathType,
2865  NULL);
2866  if (!NT_SUCCESS(Status))
2867  {
2868  /* Fail the rest of the create */
2869  RtlReleaseRelativeName(&SxsWin32RelativePath);
2870  BaseSetLastNTError(Status);
2871  Result = FALSE;
2872  goto Quickie;
2873  }
2874 
2875  /* Use this full path as the SxS path */
2876  SxsWin32ExePath = PathBufferString;
2877  PathBuffer = PathBufferString.Buffer;
2878  PathBufferString.Buffer = NULL;
2879  DPRINT("SxS Path: %S\n", PathBuffer);
2880  }
2881 
2882  /* Also set the .EXE path based on the path name */
2883 #if _SXS_SUPPORT_ENABLED_
2884  SxsNtExePath = PathName;
2885 #endif
2886  if (SxsWin32RelativePath.RelativeName.Length)
2887  {
2888  /* If it's relative, capture the relative name */
2889  PathName = SxsWin32RelativePath.RelativeName;
2890  }
2891  else
2892  {
2893  /* Otherwise, it's absolute, make sure no relative dir is used */
2894  SxsWin32RelativePath.ContainingDirectory = NULL;
2895  }
2896 
2897  /* Now use the path name, and the root path, to try opening the app */
2898  DPRINT("Path: %wZ. Dir: %p\n", &PathName, SxsWin32RelativePath.ContainingDirectory);
2899  InitializeObjectAttributes(&LocalObjectAttributes,
2900  &PathName,
2902  SxsWin32RelativePath.ContainingDirectory,
2903  NULL);
2904  Status = NtOpenFile(&FileHandle,
2905  SYNCHRONIZE |
2907  FILE_READ_DATA |
2908  FILE_EXECUTE,
2909  &LocalObjectAttributes,
2910  &IoStatusBlock,
2914  if (!NT_SUCCESS(Status))
2915  {
2916  /* Try to open the app just for execute purposes instead */
2917  Status = NtOpenFile(&FileHandle,
2919  &LocalObjectAttributes,
2920  &IoStatusBlock,
2924  }
2925 
2926  /* Failure path, display which file failed to open */
2927  if (!NT_SUCCESS(Status))
2928  DPRINT1("Open file failed: %lx (%wZ)\n", Status, &PathName);
2929 
2930  /* Cleanup in preparation for failure or success */
2931  RtlReleaseRelativeName(&SxsWin32RelativePath);
2932 
2933  if (!NT_SUCCESS(Status))
2934  {
2935  /* Failure path, try to understand why */
2936  if (RtlIsDosDeviceName_U(lpApplicationName))
2937  {
2938  /* If a device is being executed, return this special error code */
2940  Result = FALSE;
2941  goto Quickie;
2942  }
2943  else
2944  {
2945  /* Otherwise return the converted NT error code */
2946  BaseSetLastNTError(Status);
2947  Result = FALSE;
2948  goto Quickie;
2949  }
2950  }
2951 
2952  /* Did the caller specify a desktop? */
2953  if (!StartupInfo.lpDesktop)
2954  {
2955  /* Use the one from the current process */
2956  StartupInfo.lpDesktop = Peb->ProcessParameters->DesktopInfo.Buffer;
2957  }
2958 
2959  /* Create a section for this file */
2960  Status = NtCreateSection(&SectionHandle,
2962  NULL,
2963  NULL,
2964  PAGE_EXECUTE,
2965  SEC_IMAGE,
2966  FileHandle);
2967  DPRINT("Section status: %lx\n", Status);
2968  if (NT_SUCCESS(Status))
2969  {
2970  /* Are we running on Windows Embedded, Datacenter, Blade or Starter? */
2971  if (SharedUserData->SuiteMask & (VER_SUITE_EMBEDDEDNT |
2974  VER_SUITE_BLADE))
2975  {
2976  /* These SKUs do not allow running certain applications */
2977  Status = BasepCheckWebBladeHashes(FileHandle);
2978  if (Status == STATUS_ACCESS_DENIED)
2979  {
2980  /* And this is one of them! */
2981  DPRINT1("Invalid Blade hashes!\n");
2983  Result = FALSE;
2984  goto Quickie;
2985  }
2986 
2987  /* Did we get some other failure? */
2988  if (!NT_SUCCESS(Status))
2989  {
2990  /* If we couldn't check the hashes, assume nefariousness */
2991  DPRINT1("Tampered Blade hashes!\n");
2993  Result = FALSE;
2994  goto Quickie;
2995  }
2996  }
2997 
2998  /* Now do Winsafer, etc, checks */
2999  Status = BasepIsProcessAllowed((LPWSTR)lpApplicationName);
3000  if (!NT_SUCCESS(Status))
3001  {
3002  /* Fail if we're not allowed to launch the process */
3003  DPRINT1("Process not allowed to launch: %lx\n", Status);
3004  BaseSetLastNTError(Status);
3005  if (SectionHandle)
3006  {
3007  NtClose(SectionHandle);
3008  SectionHandle = NULL;
3009  }
3010  Result = FALSE;
3011  goto Quickie;
3012  }
3013 
3014  /* Is a DOS VDM being forced, but we already have a WOW32 instance ready? */
3015  if ((dwCreationFlags & CREATE_FORCEDOS) &&
3017  {
3018  /* This request can't be satisfied, instead, a separate VDM is needed */
3019  dwCreationFlags &= ~(CREATE_FORCEDOS | CREATE_SHARED_WOW_VDM);
3020  dwCreationFlags |= CREATE_SEPARATE_WOW_VDM;
3021 
3022  /* Set a failure code, ask for VDM reservation */
3023  Status = STATUS_INVALID_IMAGE_WIN_16;
3024  UseVdmReserve = TRUE;
3025 
3026  /* Close the current handle */
3027  NtClose(SectionHandle);
3028  SectionHandle = NULL;
3029 
3030  /* Don't query the section later */
3031  QuerySection = FALSE;
3032  }
3033  }
3034 
3035  /* Did we already do these checks? */
3036  if (!SkipSaferAndAppCompat)
3037  {
3038  /* Is everything OK so far, OR do we have an non-MZ, non-DOS app? */
3039  if ((NT_SUCCESS(Status)) ||
3040  ((Status == STATUS_INVALID_IMAGE_NOT_MZ) &&
3041  !(BaseIsDosApplication(&PathName, Status))))
3042  {
3043  /* Clear the machine type in case of failure */
3044  ImageMachine = 0;
3045 
3046  /* Clean any app compat data that may have accumulated */
3047  BasepFreeAppCompatData(AppCompatData, AppCompatSxsData);
3048  AppCompatData = NULL;
3049  AppCompatSxsData = NULL;
3050 
3051  /* Do we have a section? */
3052  if (SectionHandle)
3053  {
3054  /* Have we already queried it? */
3055  if (QuerySection)
3056  {
3057  /* Nothing to do */
3058  AppCompatStatus = STATUS_SUCCESS;
3059  }
3060  else
3061  {
3062  /* Get some information about the executable */
3063  AppCompatStatus = NtQuerySection(SectionHandle,
3065  &ImageInformation,
3066  sizeof(ImageInformation),
3067  NULL);
3068  }
3069 
3070  /* Do we have section information now? */
3071  if (NT_SUCCESS(AppCompatStatus))
3072  {
3073  /* Don't ask for it again, save the machine type */
3074  QuerySection = TRUE;
3075  ImageMachine = ImageInformation.Machine;
3076  }
3077  }
3078 
3079  /* Is there a reason/Shim we shouldn't run this application? */
3080  AppCompatStatus = BasepCheckBadapp(FileHandle,
3081  FreeBuffer,
3082  lpEnvironment,
3083  ImageMachine,
3084  &AppCompatData,
3085  &AppCompatDataSize,
3086  &AppCompatSxsData,
3087  &AppCompatSxsDataSize,
3088  &FusionFlags);
3089  if (!NT_SUCCESS(AppCompatStatus))
3090  {
3091  /* This is usually the status we get back */
3092  DPRINT1("App compat launch failure: %lx\n", AppCompatStatus);
3093  if (AppCompatStatus == STATUS_ACCESS_DENIED)
3094  {
3095  /* Convert it to something more Win32-specific */
3097  }
3098  else
3099  {
3100  /* Some other error */
3101  BaseSetLastNTError(AppCompatStatus);
3102  }
3103 
3104  /* Did we have a section? */
3105  if (SectionHandle)
3106  {
3107  /* Clean it up */
3108  NtClose(SectionHandle);
3109  SectionHandle = NULL;
3110  }
3111 
3112  /* Fail the call */
3113  Result = FALSE;
3114  goto Quickie;
3115  }
3116  }
3117  }
3118 
3119  //ASSERT((dwFusionFlags & ~SXS_APPCOMPACT_FLAG_APP_RUNNING_SAFEMODE) == 0);
3120 
3121  /* Have we already done, and do we need to do, SRP (WinSafer) checks? */
3122  if (!(SkipSaferAndAppCompat) &&
3123  ~(dwCreationFlags & CREATE_PRESERVE_CODE_AUTHZ_LEVEL))
3124  {
3125  /* Assume yes */
3126  SaferNeeded = TRUE;
3127  switch (Status)
3128  {
3133  /* For all DOS, 16-bit, OS/2 images, we do*/
3134  break;
3135 
3137  /* For invalid files, we don't, unless it's a .BAT file */
3138  if (BaseIsDosApplication(&PathName, Status)) break;
3139 
3140  default:
3141  /* Any other error codes we also don't */
3142  if (!NT_SUCCESS(Status))
3143  {
3144  SaferNeeded = FALSE;
3145  }
3146 
3147  /* But for success, we do */
3148  break;
3149  }
3150 
3151  /* Okay, so what did the checks above result in? */
3152  if (SaferNeeded)
3153  {
3154  /* We have to call into the WinSafer library and actually check */
3155  SaferStatus = BasepCheckWinSaferRestrictions(hUserToken,
3156  (LPWSTR)lpApplicationName,
3157  FileHandle,
3158  &InJob,
3159  &TokenHandle,
3160  &JobHandle);
3161  if (SaferStatus == 0xFFFFFFFF)
3162  {
3163  /* Back in 2003, they didn't have an NTSTATUS for this... */
3164  DPRINT1("WinSafer blocking process launch\n");
3166  Result = FALSE;
3167  goto Quickie;
3168  }
3169 
3170  /* Other status codes are not-Safer related, just convert them */
3171  if (!NT_SUCCESS(SaferStatus))
3172  {
3173  DPRINT1("Error checking WinSafer: %lx\n", SaferStatus);
3174  BaseSetLastNTError(SaferStatus);
3175  Result = FALSE;
3176  goto Quickie;
3177  }
3178  }
3179  }
3180 
3181  /* The last step is to figure out why the section object was not created */
3182  switch (Status)
3183  {
3185  {
3186  /* 16-bit binary. Should we use WOW or does the caller force VDM? */
3187  if (!(dwCreationFlags & CREATE_FORCEDOS))
3188  {
3189  /* Remember that we're launching WOW */
3190  IsWowApp = TRUE;
3191 
3192  /* Create the VDM environment, it's valid for WOW too */
3193  Result = BaseCreateVDMEnvironment(lpEnvironment,
3194  &VdmAnsiEnv,
3195  &VdmUnicodeEnv);
3196  if (!Result)
3197  {
3198  DPRINT1("VDM environment for WOW app failed\n");
3199  goto Quickie;
3200  }
3201 
3202  /* We're going to try this twice, so do a loop */
3203  while (TRUE)
3204  {
3205  /* Pick which kind of WOW mode we want to run in */
3206  VdmBinaryType = (dwCreationFlags &
3209 
3210  /* Get all the VDM settings and current status */
3211  Status = BaseCheckVDM(VdmBinaryType,
3212  lpApplicationName,
3213  lpCommandLine,
3214  lpCurrentDirectory,
3215  &VdmAnsiEnv,
3216  &CsrMsg[1],
3217  &VdmTask,
3218  dwCreationFlags,
3219  &StartupInfo,
3220  hUserToken);
3221 
3222  /* If it worked, no need to try again */
3223  if (NT_SUCCESS(Status)) break;
3224 
3225  /* Check if it's disallowed or if it's our second time */
3226  BaseSetLastNTError(Status);
3227  if ((Status == STATUS_VDM_DISALLOWED) ||
3228  (VdmBinaryType == BINARY_TYPE_SEPARATE_WOW) ||
3230  {
3231  /* Fail the call -- we won't try again */
3232  DPRINT1("VDM message failure for WOW: %lx\n", Status);
3233  Result = FALSE;
3234  goto Quickie;
3235  }
3236 
3237  /* Try one more time, but with a separate WOW instance */
3238  dwCreationFlags |= CREATE_SEPARATE_WOW_VDM;
3239  }
3240 
3241  /* Check which VDM state we're currently in */
3242  switch (CheckVdmMsg->VDMState & (VDM_NOT_LOADED |
3243  VDM_NOT_READY |
3244  VDM_READY))
3245  {
3246  case VDM_NOT_LOADED:
3247  /* VDM is not fully loaded, so not that much to undo */
3248  VdmUndoLevel = VDM_UNDO_PARTIAL;
3249 
3250  /* Reset VDM reserve if needed */
3251  if (UseVdmReserve) VdmReserve = 1;
3252 
3253  /* Get the required parameters and names for launch */
3254  Result = BaseGetVdmConfigInfo(lpCommandLine,
3255  VdmTask,
3256  VdmBinaryType,
3257  &VdmString,
3258  &VdmReserve);
3259  if (!Result)
3260  {
3261  DPRINT1("VDM Configuration failed for WOW\n");
3262  BaseSetLastNTError(Status);
3263  goto Quickie;
3264  }
3265 
3266  /* Update the command-line with the VDM one instead */
3267  lpCommandLine = VdmString.Buffer;
3268  lpApplicationName = NULL;
3269 
3270  /* We don't want a console, detachment, nor a window */
3271  dwCreationFlags |= CREATE_NO_WINDOW;
3272  dwCreationFlags &= ~(CREATE_NEW_CONSOLE | DETACHED_PROCESS);
3273 
3274  /* Force feedback on */
3275  StartupInfo.dwFlags |= STARTF_FORCEONFEEDBACK;
3276  break;
3277 
3278 
3279  case VDM_READY:
3280  /* VDM is ready, so we have to undo everything */
3281  VdmUndoLevel = VDM_UNDO_REUSE;
3282 
3283  /* Check if CSRSS wants us to wait on VDM */
3284  VdmWaitObject = CheckVdmMsg->WaitObjectForParent;
3285  break;
3286 
3287  case VDM_NOT_READY:
3288  /* Something is wrong with VDM, we'll fail the call */
3289  DPRINT1("VDM is not ready for WOW\n");
3291  Result = FALSE;
3292  goto Quickie;
3293 
3294  default:
3295  break;
3296  }
3297 
3298  /* Since to get NULL, we allocate from 0x1, account for this */
3299  VdmReserve--;
3300 
3301  /* This implies VDM is ready, so skip everything else */
3302  if (VdmWaitObject) goto VdmShortCircuit;
3303 
3304  /* Don't inherit handles since we're doing VDM now */
3305  bInheritHandles = FALSE;
3306 
3307  /* Had the user passed in environment? If so, destroy it */
3308  if ((lpEnvironment) &&
3309  !(dwCreationFlags & CREATE_UNICODE_ENVIRONMENT))
3310  {
3311  RtlDestroyEnvironment(lpEnvironment);
3312  }
3313 
3314  /* We've already done all these checks, don't do them again */
3315  SkipSaferAndAppCompat = TRUE;
3316  goto AppNameRetry;
3317  }
3318 
3319  // There is no break here on purpose, so FORCEDOS drops down!
3320  }
3321 
3325  {
3326  /* We're launching an executable application */
3327  BinarySubType = BINARY_TYPE_EXE;
3328 
3329  /* We can drop here from other "cases" above too, so check */
3330  if ((Status == STATUS_INVALID_IMAGE_PROTECT) ||
3331  (Status == STATUS_INVALID_IMAGE_NE_FORMAT) ||
3332  (BinarySubType = BaseIsDosApplication(&PathName, Status)))
3333  {
3334  /* We're launching a DOS application */
3335  VdmBinaryType = BINARY_TYPE_DOS;
3336 
3337  /* Based on the caller environment, create a VDM one */
3338  Result = BaseCreateVDMEnvironment(lpEnvironment,
3339  &VdmAnsiEnv,
3340  &VdmUnicodeEnv);
3341  if (!Result)
3342  {
3343  DPRINT1("VDM environment for DOS failed\n");
3344  goto Quickie;
3345  }
3346 
3347  /* Check the current state of the VDM subsystem */
3348  Status = BaseCheckVDM(VdmBinaryType | BinarySubType,
3349  lpApplicationName,
3350  lpCommandLine,
3351  lpCurrentDirectory,
3352  &VdmAnsiEnv,
3353  &CsrMsg[1],
3354  &VdmTask,
3355  dwCreationFlags,
3356  &StartupInfo,
3357  NULL);
3358  if (!NT_SUCCESS(Status))
3359  {
3360  /* Failed to inquire about VDM, fail the call */
3361  DPRINT1("VDM message failure for DOS: %lx\n", Status);
3362  BaseSetLastNTError(Status);
3363  Result = FALSE;
3364  goto Quickie;
3365  };
3366 
3367  /* Handle possible VDM states */
3368  switch (CheckVdmMsg->VDMState & (VDM_NOT_LOADED |
3369  VDM_NOT_READY |
3370  VDM_READY))
3371  {
3372  case VDM_NOT_LOADED:
3373  /* If VDM is not loaded, we'll do a partial undo */
3374  VdmUndoLevel = VDM_UNDO_PARTIAL;
3375 
3376  /* A VDM process can't also be detached, so fail */
3377  if (dwCreationFlags & DETACHED_PROCESS)
3378  {
3379  DPRINT1("Detached process but no VDM, not allowed\n");
3381  return FALSE;
3382  }
3383 
3384  /* Get the required parameters and names for launch */
3385  Result = BaseGetVdmConfigInfo(lpCommandLine,
3386  VdmTask,
3387  VdmBinaryType,
3388  &VdmString,
3389  &VdmReserve);
3390  if (!Result)
3391  {
3392  DPRINT1("VDM Configuration failed for DOS\n");
3393  BaseSetLastNTError(Status);
3394  goto Quickie;
3395  }
3396 
3397  /* Update the command-line to launch VDM instead */
3398  lpCommandLine = VdmString.Buffer;
3399  lpApplicationName = NULL;
3400  break;
3401 
3402  case VDM_READY:
3403  /* VDM is ready, so we have to undo everything */
3404  VdmUndoLevel = VDM_UNDO_REUSE;
3405 
3406  /* Check if CSRSS wants us to wait on VDM */
3407  VdmWaitObject = CheckVdmMsg->WaitObjectForParent;
3408  break;
3409 
3410  case VDM_NOT_READY:
3411  /* Something is wrong with VDM, we'll fail the call */
3412  DPRINT1("VDM is not ready for DOS\n");
3414  Result = FALSE;
3415  goto Quickie;
3416 
3417  default:
3418  break;
3419  }
3420 
3421  /* Since to get NULL, we allocate from 0x1, account for this */
3422  VdmReserve--;
3423 
3424  /* This implies VDM is ready, so skip everything else */
3425  if (VdmWaitObject) goto VdmShortCircuit;
3426 
3427  /* Don't inherit handles since we're doing VDM now */
3428  bInheritHandles = FALSE;
3429 
3430  /* Had the user passed in environment? If so, destroy it */
3431  if ((lpEnvironment) &&
3432  !(dwCreationFlags & CREATE_UNICODE_ENVIRONMENT))
3433  {
3434  RtlDestroyEnvironment(lpEnvironment);
3435  }
3436 
3437  /* Use our VDM Unicode environment instead */
3438  lpEnvironment = VdmUnicodeEnv.Buffer;
3439  }
3440  else
3441  {
3442  /* It's a batch file, get the extension */
3443  ExtBuffer = &PathName.Buffer[PathName.Length / sizeof(WCHAR) - 4];
3444 
3445  /* Make sure the extensions are correct */
3446  if ((PathName.Length < (4 * sizeof(WCHAR))) ||
3447  ((_wcsnicmp(ExtBuffer, L".bat", 4)) &&
3448  (_wcsnicmp(ExtBuffer, L".cmd", 4))))
3449  {
3450  DPRINT1("'%wZ': Invalid EXE, and not a batch or script file\n", &PathName);
3452  Result = FALSE;
3453  goto Quickie;
3454  }
3455 
3456  /* Check if we need to account for quotes around the path */
3457  CmdQuoteLength = CmdLineIsAppName || HasQuotes;
3458  if (!CmdLineIsAppName)
3459  {
3460  if (HasQuotes) CmdQuoteLength++;
3461  }
3462  else
3463  {
3464  CmdQuoteLength++;
3465  }
3466 
3467  /* Calculate the length of the command line */
3468  CmdLineLength = wcslen(lpCommandLine);
3469  CmdLineLength += wcslen(CMD_STRING);
3470  CmdLineLength += CmdQuoteLength + sizeof(ANSI_NULL);
3471  CmdLineLength *= sizeof(WCHAR);
3472 
3473  /* Allocate space for the new command line */
3474  AnsiCmdCommand = RtlAllocateHeap(RtlGetProcessHeap(),
3475  0,
3476  CmdLineLength);
3477  if (!AnsiCmdCommand)
3478  {
3480  Result = FALSE;
3481  goto Quickie;
3482  }
3483 
3484  /* Build it */
3485  wcscpy(AnsiCmdCommand, CMD_STRING);
3486  if ((CmdLineIsAppName) || (HasQuotes))
3487  {
3488  wcscat(AnsiCmdCommand, L"\"");
3489  }
3490  wcscat(AnsiCmdCommand, lpCommandLine);
3491  if ((CmdLineIsAppName) || (HasQuotes))
3492  {
3493  wcscat(AnsiCmdCommand, L"\"");
3494  }
3495 
3496  /* Create it as a Unicode String */
3497  RtlInitUnicodeString(&DebuggerString, AnsiCmdCommand);
3498 
3499  /* Set the command line to this */
3500  lpCommandLine = DebuggerString.Buffer;
3501  lpApplicationName = NULL;
3502  DPRINT1("Retrying with: %S\n", lpCommandLine);
3503  }
3504 
3505  /* We've already done all these checks, don't do them again */
3506  SkipSaferAndAppCompat = TRUE;
3507  goto AppNameRetry;
3508  }
3509 
3511  {
3512  /* 64-bit binaries are not allowed to run on 32-bit ReactOS */
3513  DPRINT1("64-bit binary, failing\n");
3515  Result = FALSE;
3516  goto Quickie;
3517  }
3518 
3520  {
3521  /* Set the correct last error for this */
3522  DPRINT1("File is offline, failing\n");
3524  break;
3525  }
3526 
3527  default:
3528  {
3529  /* Any other error, convert it to a generic Win32 error */
3530  if (!NT_SUCCESS(Status))
3531  {
3532  DPRINT1("Failed to create section: %lx\n", Status);
3534  Result = FALSE;
3535  goto Quickie;
3536  }
3537 
3538  /* Otherwise, this must be success */
3539  ASSERT(Status == STATUS_SUCCESS);
3540  break;
3541  }
3542  }
3543 
3544  /* Is this not a WOW application, but a WOW32 VDM was requested for it? */
3545  if (!(IsWowApp) && (dwCreationFlags & CREATE_SEPARATE_WOW_VDM))
3546  {
3547  /* Ignore the nonsensical request */
3548  dwCreationFlags &= ~CREATE_SEPARATE_WOW_VDM;
3549  }
3550 
3551  /* Did we already check information for the section? */
3552  if (!QuerySection)
3553  {
3554  /* Get some information about the executable */
3555  Status = NtQuerySection(SectionHandle,
3557  &ImageInformation,
3558  sizeof(ImageInformation),
3559  NULL);
3560  if (!NT_SUCCESS(Status))
3561  {
3562  /* We failed, bail out */
3563  DPRINT1("Section query failed\n");
3564  BaseSetLastNTError(Status);
3565  Result = FALSE;
3566  goto Quickie;
3567  }
3568 
3569  /* Don't check this later */
3570  QuerySection = TRUE;
3571  }
3572 
3573  /* Check if this was linked as a DLL */
3574  if (ImageInformation.ImageCharacteristics & IMAGE_FILE_DLL)
3575  {
3576  /* These aren't valid images to try to execute! */
3577  DPRINT1("Trying to launch a DLL, failing\n");
3579  Result = FALSE;
3580  goto Quickie;
3581  }
3582 
3583  /* Don't let callers pass in this flag -- we'll only get it from IFEO */
3585 
3586  /* Clear the IFEO-missing flag, before we know for sure... */
3587  ParameterFlags &= ~2;
3588 
3589  /* If the process is being debugged, only read IFEO if the PEB says so */
3590  if (!(dwCreationFlags & (DEBUG_PROCESS | DEBUG_ONLY_THIS_PROCESS)) ||
3591  (NtCurrentPeb()->ReadImageFileExecOptions))
3592  {
3593  /* Let's do this! Attempt to open IFEO */
3594  IFEOStatus = LdrOpenImageFileOptionsKey(&PathName, 0, &KeyHandle);
3595  if (!NT_SUCCESS(IFEOStatus))
3596  {
3597  /* We failed, set the flag so we store this in the parameters */
3598  if (IFEOStatus == STATUS_OBJECT_NAME_NOT_FOUND) ParameterFlags |= 2;
3599  }
3600  else
3601  {
3602  /* Was this our first time going through this path? */
3603  if (!DebuggerCmdLine)
3604  {
3605  /* Allocate a buffer for the debugger path */
3606  DebuggerCmdLine = RtlAllocateHeap(RtlGetProcessHeap(),
3607  0,
3608  MAX_PATH * sizeof(WCHAR));
3609  if (!DebuggerCmdLine)
3610  {
3611  /* Close IFEO on failure */
3612  IFEOStatus = NtClose(KeyHandle);
3613  ASSERT(NT_SUCCESS(IFEOStatus));
3614 
3615  /* Fail the call */
3617  Result = FALSE;
3618  goto Quickie;
3619  }
3620  }
3621 
3622  /* Now query for the debugger */
3623  IFEOStatus = LdrQueryImageFileKeyOption(KeyHandle,
3624  L"Debugger",
3625  REG_SZ,
3626  DebuggerCmdLine,
3627  MAX_PATH * sizeof(WCHAR),
3628  &ResultSize);
3629  if (!(NT_SUCCESS(IFEOStatus)) ||
3630  (ResultSize < sizeof(WCHAR)) ||
3631  (DebuggerCmdLine[0] == UNICODE_NULL))
3632  {
3633  /* If it's not there, or too small, or invalid, ignore it */
3634  RtlFreeHeap(RtlGetProcessHeap(), 0, DebuggerCmdLine);
3635  DebuggerCmdLine = NULL;
3636  }
3637 
3638  /* Also query if we should map with large pages */
3639  IFEOStatus = LdrQueryImageFileKeyOption(KeyHandle,
3640  L"UseLargePages",
3641  REG_DWORD,
3642  &UseLargePages,
3643  sizeof(UseLargePages),
3644  NULL);
3645  if ((NT_SUCCESS(IFEOStatus)) && (UseLargePages))
3646  {
3647  /* Do it! This is the only way this flag can be set */
3649  }
3650 
3651  /* We're done with IFEO, can close it now */
3652  IFEOStatus = NtClose(KeyHandle);
3653  ASSERT(NT_SUCCESS(IFEOStatus));
3654  }
3655  }
3656 
3657  /* Make sure the image was compiled for this processor */
3658  if ((ImageInformation.Machine < SharedUserData->ImageNumberLow) ||
3659  (ImageInformation.Machine > SharedUserData->ImageNumberHigh))
3660  {
3661  /* It was not -- raise a hard error */
3662  ErrorResponse = ResponseOk;
3663  ErrorParameters[0] = (ULONG_PTR)&PathName;
3665  1,
3666  1,
3667  ErrorParameters,
3668  OptionOk,
3669  &ErrorResponse);
3670  if (Peb->ImageSubsystemMajorVersion <= 3)
3671  {
3672  /* If it's really old, return this error */
3674  }
3675  else
3676  {
3677  /* Otherwise, return a more modern error */
3679  }
3680 
3681  /* Go to the failure path */
3682  DPRINT1("Invalid image architecture: %lx\n", ImageInformation.Machine);
3683  Result = FALSE;
3684  goto Quickie;
3685  }
3686 
3687  /* Check if this isn't a Windows image */
3688  if ((ImageInformation.SubSystemType != IMAGE_SUBSYSTEM_WINDOWS_GUI) &&
3689  (ImageInformation.SubSystemType != IMAGE_SUBSYSTEM_WINDOWS_CUI))
3690  {
3691  /* Get rid of section-related information since we'll retry */
3692  NtClose(SectionHandle);
3693  SectionHandle = NULL;
3694  QuerySection = FALSE;
3695 
3696  /* The only other non-Windows image type we support here is POSIX */
3697  if (ImageInformation.SubSystemType != IMAGE_SUBSYSTEM_POSIX_CUI)
3698  {
3699  /* Bail out if it's something else */
3701  Result = FALSE;
3702  goto Quickie;
3703  }
3704 
3705  /* Now build the command-line to have posix launch this image */
3706  Result = BuildSubSysCommandLine(L"POSIX /P ",
3707  lpApplicationName,
3708  lpCommandLine,
3709  &DebuggerString);
3710  if (!Result)
3711  {
3712  /* Bail out if that failed */
3713  DPRINT1("Subsystem command line failed\n");
3714  goto Quickie;
3715  }
3716 
3717  /* And re-try launching the process, with the new command-line now */
3718  lpCommandLine = DebuggerString.Buffer;
3719  lpApplicationName = NULL;
3720 
3721  /* We've already done all these checks, don't do them again */
3722  SkipSaferAndAppCompat = TRUE;
3723  DPRINT1("Retrying with: %S\n", lpCommandLine);
3724  goto AppNameRetry;
3725  }
3726 
3727  /* Was this image built for a version of Windows whose images we can run? */
3728  Result = BasepIsImageVersionOk(ImageInformation.SubSystemMajorVersion,
3729  ImageInformation.SubSystemMinorVersion);
3730  if (!Result)
3731  {
3732  /* It was not, bail out */
3733  DPRINT1("Invalid subsystem version: %hu.%hu\n",
3734  ImageInformation.SubSystemMajorVersion,
3735  ImageInformation.SubSystemMinorVersion);
3737  goto Quickie;
3738  }
3739 
3740  /* Check if there is a debugger associated with the application */
3741  if (DebuggerCmdLine)
3742  {
3743  /* Get the length of the command line */
3744  n = wcslen(lpCommandLine);
3745  if (!n)
3746  {
3747  /* There's no command line, use the application name instead */
3748  lpCommandLine = (LPWSTR)lpApplicationName;
3749  n = wcslen(lpCommandLine);
3750  }
3751 
3752  /* Protect against overflow */
3753  if (n > UNICODE_STRING_MAX_CHARS)
3754  {
3756  Result = FALSE;
3757  goto Quickie;
3758  }
3759 
3760  /* Now add the length of the debugger command-line */
3761  n += wcslen(DebuggerCmdLine);
3762 
3763  /* Again make sure we don't overflow */
3764  if (n > UNICODE_STRING_MAX_CHARS)
3765  {
3767  Result = FALSE;
3768  goto Quickie;
3769  }
3770 
3771  /* Account for the quotes and space between the two */
3772  n += sizeof("\" \"") - sizeof(ANSI_NULL);
3773 
3774  /* Convert to bytes, and make sure we don't overflow */
3775  n *= sizeof(WCHAR);
3776  if (n > UNICODE_STRING_MAX_BYTES)
3777  {
3779  Result = FALSE;
3780  goto Quickie;
3781  }
3782 
3783  /* Allocate space for the string */
3784  DebuggerString.Buffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, n);
3785  if (!DebuggerString.Buffer)
3786  {
3788  Result = FALSE;
3789  goto Quickie;
3790  }
3791 
3792  /* Set the length */
3793  RtlInitEmptyUnicodeString(&DebuggerString,
3794  DebuggerString.Buffer,
3795  (USHORT)n);
3796 
3797  /* Now perform the command line creation */
3798  ImageDbgStatus = RtlAppendUnicodeToString(&DebuggerString,
3799  DebuggerCmdLine);
3800  ASSERT(NT_SUCCESS(ImageDbgStatus));
3801  ImageDbgStatus = RtlAppendUnicodeToString(&DebuggerString, L" ");
3802  ASSERT(NT_SUCCESS(ImageDbgStatus));
3803  ImageDbgStatus = RtlAppendUnicodeToString(&DebuggerString, lpCommandLine);
3804  ASSERT(NT_SUCCESS(ImageDbgStatus));
3805 
3806  /* Make sure it all looks nice */
3807  DbgPrint("BASE: Calling debugger with '%wZ'\n", &DebuggerString);
3808 
3809  /* Update the command line and application name */
3810  lpCommandLine = DebuggerString.Buffer;
3811  lpApplicationName = NULL;
3812 
3813  /* Close all temporary state */
3814  NtClose(SectionHandle);
3815  SectionHandle = NULL;
3816  QuerySection = FALSE;
3817 
3818  /* Free all temporary memory */
3819  RtlFreeHeap(RtlGetProcessHeap(), 0, NameBuffer);
3820  NameBuffer = NULL;
3821  RtlFreeHeap(RtlGetProcessHeap(), 0, FreeBuffer);
3822  FreeBuffer = NULL;
3823  RtlFreeHeap(RtlGetProcessHeap(), 0, DebuggerCmdLine);
3824  DebuggerCmdLine = NULL;
3825  DPRINT1("Retrying with: %S\n", lpCommandLine);
3826  goto AppNameRetry;
3827  }
3828 
3829  /* Initialize the process object attributes */
3830  ObjectAttributes = BaseFormatObjectAttributes(&LocalObjectAttributes,
3831  lpProcessAttributes,
3832  NULL);
3833  if ((hUserToken) && (lpProcessAttributes))
3834  {
3835  /* Augment them with information from the user */
3836 
3837  LocalProcessAttributes = *lpProcessAttributes;
3838  LocalProcessAttributes.lpSecurityDescriptor = NULL;
3839  ObjectAttributes = BaseFormatObjectAttributes(&LocalObjectAttributes,
3840  &LocalProcessAttributes,
3841  NULL);
3842  }
3843 
3844  /* Check if we're going to be debugged */
3845  if (dwCreationFlags & DEBUG_PROCESS)
3846  {
3847  /* Set process flag */
3849  }
3850 
3851  /* Check if we're going to be debugged */
3852  if (dwCreationFlags & (DEBUG_PROCESS | DEBUG_ONLY_THIS_PROCESS))
3853  {
3854  /* Connect to DbgUi */
3855  Status = DbgUiConnectToDbg();
3856  if (!NT_SUCCESS(Status))
3857  {
3858  DPRINT1("Failed to connect to DbgUI!\n");
3859  BaseSetLastNTError(Status);
3860  Result = FALSE;
3861  goto Quickie;
3862  }
3863 
3864  /* Get the debug object */
3865  DebugHandle = DbgUiGetThreadDebugObject();
3866 
3867  /* Check if only this process will be debugged */
3868  if (dwCreationFlags & DEBUG_ONLY_THIS_PROCESS)
3869  {
3870  /* Set process flag */
3872  }
3873  }
3874 
3875  /* Set inherit flag */
3876  if (bInheritHandles) Flags |= PROCESS_CREATE_FLAGS_INHERIT_HANDLES;
3877 
3878  /* Check if the process should be created with large pages */
3879  HavePrivilege = FALSE;
3880  PrivilegeState = NULL;
3882  {
3883  /* Acquire the required privilege so that the kernel won't fail the call */
3884  PrivilegeValue = SE_LOCK_MEMORY_PRIVILEGE;
3885  Status = RtlAcquirePrivilege(&PrivilegeValue, 1, 0, &PrivilegeState);
3886  if (NT_SUCCESS(Status))
3887  {
3888  /* Remember to release it later */
3889  HavePrivilege = TRUE;
3890  }
3891  }
3892 
3893  /* Save the current TIB value since kernel overwrites it to store PEB */
3894  TibValue = Teb->NtTib.ArbitraryUserPointer;
3895 
3896  /* Tell the kernel to create the process */
3897  Status = NtCreateProcessEx(&ProcessHandle,
3899  ObjectAttributes,
3900  NtCurrentProcess(),
3901  Flags,
3902  SectionHandle,
3903  DebugHandle,
3904  NULL,
3905  InJob);
3906 
3907  /* Load the PEB address from the hacky location where the kernel stores it */
3908  RemotePeb = Teb->NtTib.ArbitraryUserPointer;
3909 
3910  /* And restore the old TIB value */
3911  Teb->NtTib.ArbitraryUserPointer = TibValue;
3912 
3913  /* Release the large page privilege if we had acquired it */
3914  if (HavePrivilege) RtlReleasePrivilege(PrivilegeState);
3915 
3916  /* And now check if the kernel failed to create the process */
3917  if (!NT_SUCCESS(Status))
3918  {
3919  /* Go to failure path */
3920  DPRINT1("Failed to create process: %lx\n", Status);
3921  BaseSetLastNTError(Status);
3922  Result = FALSE;
3923  goto Quickie;
3924  }
3925 
3926  /* Check if there is a priority class to set */
3927  if (PriorityClass.PriorityClass)
3928  {
3929  /* Reset current privilege state */
3930  RealTimePrivilegeState = NULL;
3931 
3932  /* Is realtime priority being requested? */
3933  if (PriorityClass.PriorityClass == PROCESS_PRIORITY_CLASS_REALTIME)
3934  {
3935  /* Check if the caller has real-time access, and enable it if so */
3936  RealTimePrivilegeState = BasepIsRealtimeAllowed(TRUE);
3937  }
3938 
3939  /* Set the new priority class and release the privilege */
3940  Status = NtSetInformationProcess(ProcessHandle,
3942  &PriorityClass,
3943  sizeof(PROCESS_PRIORITY_CLASS));
3944  if (RealTimePrivilegeState) RtlReleasePrivilege(RealTimePrivilegeState);
3945 
3946  /* Check if we failed to set the priority class */
3947  if (!NT_SUCCESS(Status))
3948  {
3949  /* Bail out on failure */
3950  DPRINT1("Failed to set priority class: %lx\n", Status);
3951  BaseSetLastNTError(Status);
3952  Result = FALSE;
3953  goto Quickie;
3954  }
3955  }
3956 
3957  /* Check if the caller wants the default error mode */
3958  if (dwCreationFlags & CREATE_DEFAULT_ERROR_MODE)
3959  {
3960  /* Set Error Mode to only fail on critical errors */
3961  HardErrorMode = SEM_FAILCRITICALERRORS;
3962  NtSetInformationProcess(ProcessHandle,
3964  &HardErrorMode,
3965  sizeof(ULONG));
3966  }
3967 
3968  /* Check if this was a VDM binary */
3969  if (VdmBinaryType)
3970  {
3971  /* Update VDM by telling it the process has now been created */
3972  VdmWaitObject = ProcessHandle;
3974  &VdmWaitObject,
3975  VdmTask,
3976  VdmBinaryType);
3977 
3978  if (!Result)
3979  {
3980  /* Bail out on failure */
3981  DPRINT1("Failed to update VDM with wait object\n");
3982  VdmWaitObject = NULL;
3983  goto Quickie;
3984  }
3985 
3986  /* At this point, a failure means VDM has to undo all the state */
3987  VdmUndoLevel |= VDM_UNDO_FULL;
3988  }
3989 
3990  /* Check if VDM needed reserved low-memory */
3991  if (VdmReserve)
3992  {
3993  /* Reserve the requested allocation */
3994  Status = NtAllocateVirtualMemory(ProcessHandle,
3995  &BaseAddress,
3996  0,
3997  &VdmReserve,
3998  MEM_RESERVE,
4000  if (!NT_SUCCESS(Status))
4001  {
4002  /* Bail out on failure */
4003  DPRINT1("Failed to reserve memory for VDM: %lx\n", Status);
4004  BaseSetLastNTError(Status);
4005  Result = FALSE;
4006  goto Quickie;
4007  }
4008  }
4009 
4010  /* Check if we've already queried information on the section */
4011  if (!QuerySection)
4012  {
4013  /* We haven't, so get some information about the executable */
4014  Status = NtQuerySection(SectionHandle,
4016  &ImageInformation,
4017  sizeof(ImageInformation),
4018  NULL);
4019  if (!NT_SUCCESS(Status))
4020  {
4021  /* Bail out on failure */
4022  DPRINT1("Failed to query section: %lx\n", Status);
4023  BaseSetLastNTError(Status);
4024  Result = FALSE;
4025  goto Quickie;
4026  }
4027 
4028  /* If we encounter a restart, don't re-query this information again */
4029  QuerySection = TRUE;
4030  }
4031 
4032  /* Do we need to apply SxS to this image? */
4034  {
4035  /* Too bad, we don't support this yet */
4036  DPRINT1("Image should receive SxS Fusion Isolation\n");
4037  }
4038 
4039  /* There's some SxS flag that we need to set if fusion flags have 1 set */
4040  if (FusionFlags & 1) CreateProcessMsg->Sxs.Flags |= 0x10;
4041 
4042  /* Check if we have a current directory */
4043  if (lpCurrentDirectory)
4044  {
4045  /* Allocate a buffer so we can keep a Unicode copy */
4046  DPRINT("Current directory: %S\n", lpCurrentDirectory);
4047  CurrentDirectory = RtlAllocateHeap(RtlGetProcessHeap(),
4048  0,
4049  (MAX_PATH * sizeof(WCHAR)) +
4050  sizeof(UNICODE_NULL));
4051  if (!CurrentDirectory)
4052  {
4053  /* Bail out if this failed */
4055  Result = FALSE;
4056  goto Quickie;
4057  }
4058 
4059  /* Get the length in Unicode */
4060  Length = GetFullPathNameW(lpCurrentDirectory,
4061  MAX_PATH,
4062  CurrentDirectory,
4063  &FilePart);
4064  if (Length > MAX_PATH)
4065  {
4066  /* The directory is too long, so bail out */
4068  Result = FALSE;
4069  goto Quickie;
4070  }
4071 
4072  /* Make sure the directory is actually valid */
4073  FileAttribs = GetFileAttributesW(CurrentDirectory);
4074  if ((FileAttribs == INVALID_FILE_ATTRIBUTES) ||
4075  !(FileAttribs & FILE_ATTRIBUTE_DIRECTORY))
4076  {
4077  /* It isn't, so bail out */
4078  DPRINT1("Current directory is invalid\n");
4080  Result = FALSE;
4081  goto Quickie;
4082  }
4083  }
4084 
4085  /* Insert quotes if needed */
4086  if ((QuotesNeeded) || (CmdLineIsAppName))
4087  {
4088  /* Allocate our buffer, plus enough space for quotes and a NULL */
4089  QuotedCmdLine = RtlAllocateHeap(RtlGetProcessHeap(),
4090  0,
4091  (wcslen(lpCommandLine) * sizeof(WCHAR)) +
4092  (2 * sizeof(L'\"') + sizeof(UNICODE_NULL)));
4093  if (QuotedCmdLine)
4094  {
4095  /* Copy the first quote */
4096  wcscpy(QuotedCmdLine, L"\"");
4097 
4098  /* Save the current null-character */
4099  if (QuotesNeeded)
4100  {
4101  SaveChar = *NullBuffer;
4102  *NullBuffer = UNICODE_NULL;
4103  }
4104 
4105  /* Copy the command line and the final quote */
4106  wcscat(QuotedCmdLine, lpCommandLine);
4107  wcscat(QuotedCmdLine, L"\"");
4108 
4109  /* Copy the null-char back */
4110  if (QuotesNeeded)
4111  {
4112  *NullBuffer = SaveChar;
4113  wcscat(QuotedCmdLine, NullBuffer);
4114  }
4115  }
4116  else
4117  {
4118  /* We can't put quotes around the thing, so try it anyway */
4119  if (QuotesNeeded) QuotesNeeded = FALSE;
4120  if (CmdLineIsAppName) CmdLineIsAppName = FALSE;
4121  }
4122  }
4123 
4124  /* Use isolation if needed */
4125  if (CreateProcessMsg->Sxs.Flags & 1) ParameterFlags |= 1;
4126 
4127  /* Set the new command-line if needed */
4128  if ((QuotesNeeded) || (CmdLineIsAppName)) lpCommandLine = QuotedCmdLine;
4129 
4130  /* Call the helper function in charge of RTL_USER_PROCESS_PARAMETERS */
4131  Result = BasePushProcessParameters(ParameterFlags,
4132  ProcessHandle,
4133  RemotePeb,
4134  lpApplicationName,
4135  CurrentDirectory,
4136  lpCommandLine,
4137  lpEnvironment,
4138  &StartupInfo,
4139  dwCreationFlags | NoWindow,
4140  bInheritHandles,
4141  IsWowApp ? IMAGE_SUBSYSTEM_WINDOWS_GUI: 0,
4142  AppCompatData,
4143  AppCompatDataSize);
4144  if (!Result)
4145  {
4146  /* The remote process would have an undefined state, so fail the call */
4147  DPRINT1("BasePushProcessParameters failed\n");
4148  goto Quickie;
4149  }
4150 
4151  /* Free the VDM command line string as it's no longer needed */
4152  RtlFreeUnicodeString(&VdmString);
4153  VdmString.Buffer = NULL;
4154 
4155  /* Non-VDM console applications usually inherit handles unless specified */
4156  if (!(VdmBinaryType) &&
4157  !(bInheritHandles) &&
4158  !(StartupInfo.dwFlags & STARTF_USESTDHANDLES) &&
4159  !(dwCreationFlags & (CREATE_NO_WINDOW |
4161  DETACHED_PROCESS)) &&
4162  (ImageInformation.SubSystemType == IMAGE_SUBSYSTEM_WINDOWS_CUI))
4163  {
4164  /* Get the remote parameters */
4165  Status = NtReadVirtualMemory(ProcessHandle,
4166  &RemotePeb->ProcessParameters,
4167  &ProcessParameters,
4169  NULL);
4170  if (NT_SUCCESS(Status))
4171  {
4172  /* Duplicate standard input unless it's a console handle */
4174  {
4175  StuffStdHandle(ProcessHandle,
4177  &ProcessParameters->StandardInput);
4178  }
4179 
4180  /* Duplicate standard output unless it's a console handle */
4182  {
4183  StuffStdHandle(ProcessHandle,
4185  &ProcessParameters->StandardOutput);
4186  }
4187 
4188  /* Duplicate standard error unless it's a console handle */
4190  {
4191  StuffStdHandle(ProcessHandle,
4193  &ProcessParameters->StandardError);
4194  }
4195  }
4196  }
4197 
4198  /* Create the Thread's Stack */
4199  StackSize = max(256 * 1024, ImageInformation.MaximumStackSize);
4200  Status = BaseCreateStack(ProcessHandle,
4201  ImageInformation.CommittedStackSize,
4202  StackSize,
4203  &InitialTeb);
4204  if (!NT_SUCCESS(Status))
4205  {
4206  DPRINT1("Creating the thread stack failed: %lx\n", Status);
4207  BaseSetLastNTError(Status);
4208  Result = FALSE;
4209  goto Quickie;
4210  }
4211 
4212  /* Create the Thread's Context */
4213  BaseInitializeContext(&Context,
4214  Peb,
4215  ImageInformation.TransferAddress,
4216  InitialTeb.StackBase,
4217  0);
4218 
4219  /* Convert the thread attributes */
4220  ObjectAttributes = BaseFormatObjectAttributes(&LocalObjectAttributes,
4221  lpThreadAttributes,
4222  NULL);
4223  if ((hUserToken) && (lpThreadAttributes))
4224  {
4225  /* If the caller specified a user token, zero the security descriptor */
4226  LocalThreadAttributes = *lpThreadAttributes;
4227  LocalThreadAttributes.lpSecurityDescriptor = NULL;
4228  ObjectAttributes = BaseFormatObjectAttributes(&LocalObjectAttributes,
4229  &LocalThreadAttributes,
4230  NULL);
4231  }
4232 
4233  /* Create the Kernel Thread Object */
4234  Status = NtCreateThread(&ThreadHandle,
4236  ObjectAttributes,
4237  ProcessHandle,
4238  &ClientId,
4239  &Context,
4240  &InitialTeb,
4241  TRUE);
4242  if (!NT_SUCCESS(Status))
4243  {
4244  /* A process is not allowed to exist without a main thread, so fail */
4245  DPRINT1("Creating the main thread failed: %lx\n", Status);
4246  BaseSetLastNTError(Status);
4247  Result = FALSE;
4248  goto Quickie;
4249  }
4250 
4251  /* Begin filling out the CSRSS message, first with our IDs and handles */
4252  CreateProcessMsg->ProcessHandle = ProcessHandle;
4253  CreateProcessMsg->ThreadHandle = ThreadHandle;
4254  CreateProcessMsg->ClientId = ClientId;
4255 
4256  /* Write the remote PEB address and clear it locally, we no longer use it */
4257  CreateProcessMsg->PebAddressNative = RemotePeb;
4258  CreateProcessMsg->PebAddressWow64 = (ULONG)RemotePeb;
4259  RemotePeb = NULL;
4260 
4261  /* Now check what kind of architecture this image was made for */
4262  switch (ImageInformation.Machine)
4263  {
4264  /* IA32, IA64 and AMD64 are supported in Server 2003 */
4267  break;
4270  break;
4273  break;
4274 
4275  /* Anything else results in image unknown -- but no failure */
4276  default:
4277  DbgPrint("kernel32: No mapping for ImageInformation.Machine == %04x\n",
4278  ImageInformation.Machine);
4280  break;
4281  }
4282 
4283  /* Write the input creation flags except any debugger-related flags */
4284  CreateProcessMsg->CreationFlags = dwCreationFlags &
4285  ~(DEBUG_PROCESS | DEBUG_ONLY_THIS_PROCESS);
4286 
4287  /* CSRSS needs to know if this is a GUI app or not */
4288  if ((ImageInformation.SubSystemType == IMAGE_SUBSYSTEM_WINDOWS_GUI) ||
4289  (IsWowApp))
4290  {
4291  /*
4292  * For GUI apps we turn on the 2nd bit. This allow CSRSS server dlls
4293  * (basesrv in particular) to know whether or not this is a GUI or a
4294  * TUI application.
4295  */
4296  AddToHandle(CreateProcessMsg->ProcessHandle, 2);
4297 
4298  /* Also check if the parent is also a GUI process */
4299  NtHeaders = RtlImageNtHeader(GetModuleHandle(NULL));
4300  if ((NtHeaders) &&
4301  (NtHeaders->OptionalHeader.Subsystem == IMAGE_SUBSYSTEM_WINDOWS_GUI))
4302  {
4303  /* Let it know that it should display the hourglass mouse cursor */
4304  AddToHandle(CreateProcessMsg->ProcessHandle, 1);
4305  }
4306  }
4307 
4308  /* For all apps, if this flag is on, the hourglass mouse cursor is shown */
4309  if (StartupInfo.dwFlags & STARTF_FORCEONFEEDBACK)
4310  {
4311  AddToHandle(CreateProcessMsg->ProcessHandle, 1);
4312  }
4313 
4314  /* Likewise, the opposite holds as well */
4315  if (StartupInfo.dwFlags & STARTF_FORCEOFFFEEDBACK)
4316  {
4317  RemoveFromHandle(CreateProcessMsg->ProcessHandle, 1);
4318  }
4319 
4320  /* Also store which kind of VDM app (if any) this is */
4321  CreateProcessMsg->VdmBinaryType = VdmBinaryType;
4322 
4323  /* And if it really is a VDM app... */
4324  if (VdmBinaryType)
4325  {
4326  /* Store the task ID and VDM console handle */
4327  CreateProcessMsg->hVDM = VdmTask ? 0 : Peb->ProcessParameters->ConsoleHandle;
4328  CreateProcessMsg->VdmTask = VdmTask;
4329  }
4330  else if (VdmReserve)
4331  {
4332  /* Extended VDM, set a flag */
4333  CreateProcessMsg->VdmBinaryType |= BINARY_TYPE_WOW_EX;
4334  }
4335 
4336  /* Check if there's side-by-side assembly data associated with the process */
4337  if (CreateProcessMsg->Sxs.Flags)
4338  {
4339  /* This should not happen in ReactOS yet */
4340  DPRINT1("This is an SxS Message -- should not happen yet\n");
4343  Result = FALSE;
4344  goto Quickie;
4345  }
4346 
4347  /* We are finally ready to call CSRSS to tell it about our new process! */
4349  CaptureBuffer,
4352  sizeof(*CreateProcessMsg));
4353 
4354  /* CSRSS has returned, free the capture buffer now if we had one */
4355  if (CaptureBuffer)
4356  {
4357  CsrFreeCaptureBuffer(CaptureBuffer);
4358  CaptureBuffer = NULL;
4359  }
4360 
4361  /* Check if CSRSS failed to accept ownership of the new Windows process */
4362  if (!NT_SUCCESS(CsrMsg[0].Status))
4363  {
4364  /* Terminate the process and enter failure path with the CSRSS status */
4365  DPRINT1("Failed to tell csrss about new process\n");
4366  BaseSetLastNTError(CsrMsg[0].Status);
4367  NtTerminateProcess(ProcessHandle, CsrMsg[0].Status);
4368  Result = FALSE;
4369  goto Quickie;
4370  }
4371 
4372  /* Check if we have a token due to Authz/Safer, not passed by the user */
4373  if ((TokenHandle) && !(hUserToken))
4374  {
4375  /* Replace the process and/or thread token with the one from Safer */
4376  Status = BasepReplaceProcessThreadTokens(TokenHandle,
4377  ProcessHandle,
4378  ThreadHandle);
4379  if (!NT_SUCCESS(Status))
4380  {
4381  /* If this failed, kill the process and enter the failure path */
4382  DPRINT1("Failed to update process token: %lx\n", Status);
4383  NtTerminateProcess(ProcessHandle, Status);
4384  BaseSetLastNTError(Status);
4385  Result = FALSE;
4386  goto Quickie;
4387  }
4388  }
4389 
4390  /* Check if a job was associated with this process */
4391  if (JobHandle)
4392  {
4393  /* Bind the process and job together now */
4394  Status = NtAssignProcessToJobObject(JobHandle, ProcessHandle);
4395  if (!NT_SUCCESS(Status))
4396  {
4397  /* Kill the process and enter the failure path if binding failed */
4398  DPRINT1("Failed to assign process to job: %lx\n", Status);
4399  NtTerminateProcess(ProcessHandle, STATUS_ACCESS_DENIED);
4400  BaseSetLastNTError(Status);
4401  Result = FALSE;
4402  goto Quickie;
4403  }
4404  }
4405 
4406  /* Finally, resume the thread to actually get the process started */
4407  if (!(dwCreationFlags & CREATE_SUSPENDED))
4408  {
4409  NtResumeThread(ThreadHandle, &ResumeCount);
4410  }
4411 
4412 VdmShortCircuit:
4413  /* We made it this far, meaning we have a fully created process and thread */
4414  Result = TRUE;
4415 
4416  /* Anyone doing a VDM undo should now undo everything, since we are done */
4417  if (VdmUndoLevel) VdmUndoLevel |= VDM_UNDO_COMPLETED;
4418 
4419  /* Having a VDM wait object implies this must be a VDM process */
4420  if (VdmWaitObject)
4421  {
4422  /* Check if it's a 16-bit separate WOW process */
4423  if (VdmBinaryType == BINARY_TYPE_SEPARATE_WOW)
4424  {
4425  /* OR-in the special flag to indicate this, and return to caller */
4426  AddToHandle(VdmWaitObject, 2);
4427  lpProcessInformation->hProcess = VdmWaitObject;
4428 
4429  /* Check if this was a re-used VDM */
4430  if (VdmUndoLevel & VDM_UNDO_REUSE)
4431  {
4432  /* No Client ID should be returned in this case */
4433  ClientId.UniqueProcess = 0;
4434  ClientId.UniqueThread = 0;
4435  }
4436  }
4437  else
4438  {
4439  /* OR-in the special flag to indicate this is not a separate VDM */
4440  AddToHandle(VdmWaitObject, 1);
4441 
4442  /* Return handle to the caller */
4443  lpProcessInformation->hProcess = VdmWaitObject;
4444  }
4445 
4446  /* Close the original process handle, since it's not needed for VDM */
4447  if (ProcessHandle) NtClose(ProcessHandle);
4448  }
4449  else
4450  {
4451  /* This is a regular process, so return the real process handle */
4452  lpProcessInformation->hProcess = ProcessHandle;
4453  }
4454 
4455  /* Return the rest of the process information based on what we have so far */
4456  lpProcessInformation->hThread = ThreadHandle;
4457  lpProcessInformation->dwProcessId = HandleToUlong(ClientId.UniqueProcess);
4458  lpProcessInformation->dwThreadId = HandleToUlong(ClientId.UniqueThread);
4459 
4460  /* NULL these out here so we know to treat this as a success scenario */
4461  ProcessHandle = NULL;
4462  ThreadHandle = NULL;
4463 
4464 Quickie:
4465  /* Free the debugger command line if one was allocated */
4466  if (DebuggerCmdLine) RtlFreeHeap(RtlGetProcessHeap(), 0, DebuggerCmdLine);
4467 
4468  /* Check if an SxS full path as queried */
4469  if (PathBuffer)
4470  {
4471  /* Reinitialize the executable path */
4472  RtlInitEmptyUnicodeString(&SxsWin32ExePath, NULL, 0);
4473  SxsWin32ExePath.Length = 0;
4474 
4475  /* Free the path buffer */
4476  RtlFreeHeap(RtlGetProcessHeap(), 0, PathBuffer);
4477  }
4478 
4479 #if _SXS_SUPPORT_ENABLED_
4480  /* Check if this was a non-VDM process */
4481  if (!VdmBinaryType)
4482  {
4483  /* Then it must've had SxS data, so close the handles used for it */
4484  BasepSxsCloseHandles(&Handles);
4485  BasepSxsCloseHandles(&FileHandles);
4486 
4487  /* Check if we built SxS byte buffers for this create process request */
4488  if (SxsConglomeratedBuffer)
4489  {
4490  /* Loop all of them */
4491  for (i = 0; i < 5; i++)
4492  {
4493  /* Check if this one was allocated */
4494  ThisBuffer = SxsStaticBuffers[i];
4495  if (ThisBuffer)
4496  {
4497  /* Get the underlying RTL_BUFFER structure */
4498  ByteBuffer = &ThisBuffer->ByteBuffer;
4499  if ((ThisBuffer != (PVOID)-8) && (ByteBuffer->Buffer))
4500  {
4501  /* Check if it was dynamic */
4502  if (ByteBuffer->Buffer != ByteBuffer->StaticBuffer)
4503  {
4504  /* Free it from the heap */
4505  FreeString.Buffer = (PWCHAR)ByteBuffer->Buffer;
4506  RtlFreeUnicodeString(&FreeString);
4507  }
4508 
4509  /* Reset the buffer to its static data */
4510  ByteBuffer->Buffer = ByteBuffer->StaticBuffer;
4511  ByteBuffer->Size = ByteBuffer->StaticSize;
4512  }
4513 
4514  /* Reset the string to the static buffer */
4515  RtlInitEmptyUnicodeString(&ThisBuffer->String,
4516  (PWCHAR)ByteBuffer->StaticBuffer,
4517  ByteBuffer->StaticSize);
4518  if (ThisBuffer->String.Buffer)
4519  {
4520  /* Also NULL-terminate it */
4521  *ThisBuffer->String.Buffer = UNICODE_NULL;
4522  }
4523  }
4524  }
4525  }
4526  }
4527 #endif
4528  /* Check if an environment was passed in */
4529  if ((lpEnvironment) && !(dwCreationFlags & CREATE_UNICODE_ENVIRONMENT))
4530  {
4531  /* Destroy it */
4532  RtlDestroyEnvironment(lpEnvironment);
4533 
4534  /* If this was the VDM environment too, clear that as well */
4535  if (VdmUnicodeEnv.Buffer == lpEnvironment) VdmUnicodeEnv.Buffer = NULL;
4536  lpEnvironment = NULL;
4537  }
4538 
4539  /* Unconditionally free all the name parsing buffers we always allocate */
4540  RtlFreeHeap(RtlGetProcessHeap(), 0, QuotedCmdLine);
4541  RtlFreeHeap(RtlGetProcessHeap(), 0, NameBuffer);
4542  RtlFreeHeap(RtlGetProcessHeap(), 0, CurrentDirectory);
4543  RtlFreeHeap(RtlGetProcessHeap(), 0, FreeBuffer);
4544 
4545  /* Close open file/section handles */
4546  if (FileHandle) NtClose(FileHandle);
4547  if (SectionHandle) NtClose(SectionHandle);
4548 
4549  /* If we have a thread handle, this was a failure path */
4550  if (ThreadHandle)
4551  {
4552  /* So kill the process and close the thread handle */
4553  NtTerminateProcess(ProcessHandle, 0);
4554  NtClose(ThreadHandle);
4555  }
4556 
4557  /* If we have a process handle, this was a failure path, so close it */
4558  if (ProcessHandle) NtClose(ProcessHandle);
4559 
4560  /* Thread/process handles, if any, are now processed. Now close this one. */
4561  if (JobHandle) NtClose(JobHandle);
4562 
4563  /* Check if we had created a token */
4564  if (TokenHandle)
4565  {
4566  /* And if the user asked for one */
4567  if (hUserToken)
4568  {
4569  /* Then return it */
4570  *hNewToken = TokenHandle;
4571  }
4572  else
4573  {
4574  /* User didn't want it, so we used it temporarily -- close it */
4575  NtClose(TokenHandle);
4576  }
4577  }
4578 
4579  /* Free any temporary app compatibility data, it's no longer needed */
4580  BasepFreeAppCompatData(AppCompatData, AppCompatSxsData);
4581 
4582  /* Free a few strings. The API takes care of these possibly being NULL */
4583  RtlFreeUnicodeString(&VdmString);
4584  RtlFreeUnicodeString(&DebuggerString);
4585 
4586  /* Check if we had built any sort of VDM environment */
4587  if ((VdmAnsiEnv.Buffer) || (VdmUnicodeEnv.Buffer))
4588  {
4589  /* Free it */
4590  BaseDestroyVDMEnvironment(&VdmAnsiEnv, &VdmUnicodeEnv);
4591  }
4592 
4593  /* Check if this was any kind of VDM application that we ended up creating */
4594  if ((VdmUndoLevel) && (!(VdmUndoLevel & VDM_UNDO_COMPLETED)))
4595  {
4596  /* Send an undo */
4598  (PHANDLE)&VdmTask,
4599  VdmUndoLevel,
4600  VdmBinaryType);
4601 
4602  /* And close whatever VDM handle we were using for notifications */
4603  if (VdmWaitObject) NtClose(VdmWaitObject);
4604  }
4605 
4606  /* Check if we ended up here with an allocated search path, and free it */
4607  if (SearchPath) RtlFreeHeap(RtlGetProcessHeap(), 0, SearchPath);
4608 
4609  /* Finally, return the API's result */
4610  return Result;
4611 }
4612 
4613 /*
4614  * @implemented
4615  */
4616 BOOL
4617 WINAPI
4619 CreateProcessW(LPCWSTR lpApplicationName,
4620  LPWSTR lpCommandLine,
4621  LPSECURITY_ATTRIBUTES lpProcessAttributes,
4622  LPSECURITY_ATTRIBUTES lpThreadAttributes,
4623  BOOL bInheritHandles,
4624  DWORD dwCreationFlags,
4625  LPVOID lpEnvironment,
4626  LPCWSTR lpCurrentDirectory,
4627  LPSTARTUPINFOW lpStartupInfo,
4628  LPPROCESS_INFORMATION lpProcessInformation)
4629 {
4630  /* Call the internal (but exported) version */
4632  lpApplicationName,
4633  lpCommandLine,
4634  lpProcessAttributes,
4635  lpThreadAttributes,
4636  bInheritHandles,
4637  dwCreationFlags,
4638  lpEnvironment,
4639  lpCurrentDirectory,
4640  lpStartupInfo,
4641  lpProcessInformation,
4642  NULL);
4643 }
4644 
4645 /*
4646  * @implemented
4647  */
4648 BOOL
4649 WINAPI
4651  LPCSTR lpApplicationName,
4652  LPSTR lpCommandLine,
4653  LPSECURITY_ATTRIBUTES lpProcessAttributes,
4654  LPSECURITY_ATTRIBUTES lpThreadAttributes,
4655  BOOL bInheritHandles,
4656  DWORD dwCreationFlags,
4657  LPVOID lpEnvironment,
4658  LPCSTR lpCurrentDirectory,
4659  LPSTARTUPINFOA lpStartupInfo,
4660  LPPROCESS_INFORMATION lpProcessInformation,
4661  PHANDLE hNewToken)
4662 {
4663  UNICODE_STRING CommandLine;
4666  BOOL bRetVal;
4667  STARTUPINFOW StartupInfo;
4668 
4669  DPRINT("dwCreationFlags %x, lpEnvironment %p, lpCurrentDirectory %p, "
4670  "lpStartupInfo %p, lpProcessInformation %p\n",
4671  dwCreationFlags, lpEnvironment, lpCurrentDirectory,
4672  lpStartupInfo, lpProcessInformation);
4673 
4674  /* Copy Startup Info */
4675  RtlMoveMemory(&StartupInfo, lpStartupInfo, sizeof(*lpStartupInfo));
4676 
4677  /* Initialize all strings to nothing */
4678  CommandLine.Buffer = NULL;
4679  ApplicationName.Buffer = NULL;
4680  CurrentDirectory.Buffer = NULL;
4681  StartupInfo.lpDesktop = NULL;
4682  StartupInfo.lpReserved = NULL;
4683  StartupInfo.lpTitle = NULL;
4684 
4685  /* Convert the Command line */
4686  if (lpCommandLine)
4687  {
4689  lpCommandLine);
4690  }
4691 
4692  /* Convert the Name and Directory */
4693  if (lpApplicationName)
4694  {
4695  Basep8BitStringToDynamicUnicodeString(&ApplicationName,
4696  lpApplicationName);
4697  }
4698  if (lpCurrentDirectory)
4699  {
4700  Basep8BitStringToDynamicUnicodeString(&CurrentDirectory,
4701  lpCurrentDirectory);
4702  }
4703 
4704  /* Now convert Startup Strings */
4705  if (lpStartupInfo->lpReserved)
4706  {
4708  &StartupInfo.lpReserved);
4709  }
4710  if (lpStartupInfo->lpDesktop)
4711  {
4713  &StartupInfo.lpDesktop);
4714  }
4715  if (lpStartupInfo->lpTitle)
4716  {
4718  &StartupInfo.lpTitle);
4719  }
4720 
4721  /* Call the Unicode function */
4722  bRetVal = CreateProcessInternalW(hToken,
4723  ApplicationName.Buffer,
4724  CommandLine.Buffer,
4725  lpProcessAttributes,
4726  lpThreadAttributes,
4727  bInheritHandles,
4728  dwCreationFlags,
4729  lpEnvironment,
4730  CurrentDirectory.Buffer,
4731  &StartupInfo,
4732  lpProcessInformation,
4733  hNewToken);
4734 
4735  /* Clean up */
4736  RtlFreeUnicodeString(&ApplicationName);
4737  RtlFreeUnicodeString(&CommandLine);
4738  RtlFreeUnicodeString(&CurrentDirectory);
4739  RtlFreeHeap(RtlGetProcessHeap(), 0, StartupInfo.lpDesktop);
4740  RtlFreeHeap(RtlGetProcessHeap(), 0, StartupInfo.lpReserved);
4741  RtlFreeHeap(RtlGetProcessHeap(), 0, StartupInfo.lpTitle);
4742 
4743  /* Return what Unicode did */
4744  return bRetVal;
4745 }
4746 
4747 /*
4748  * FUNCTION: The CreateProcess function creates a new process and its
4749  * primary thread. The new process executes the specified executable file
4750  * ARGUMENTS:
4751  *
4752  * lpApplicationName = Pointer to name of executable module
4753  * lpCommandLine = Pointer to command line string
4754  * lpProcessAttributes = Process security attributes
4755  * lpThreadAttributes = Thread security attributes
4756  * bInheritHandles = Handle inheritance flag
4757  * dwCreationFlags = Creation flags
4758  * lpEnvironment = Pointer to new environment block
4759  * lpCurrentDirectory = Pointer to current directory name
4760  * lpStartupInfo = Pointer to startup info
4761  * lpProcessInformation = Pointer to process information
4762  *
4763  * @implemented
4764  */
4765 BOOL
4766 WINAPI
4768 CreateProcessA(LPCSTR lpApplicationName,
4769  LPSTR lpCommandLine,
4770  LPSECURITY_ATTRIBUTES lpProcessAttributes,
4771  LPSECURITY_ATTRIBUTES lpThreadAttributes,
4772  BOOL bInheritHandles,
4773  DWORD dwCreationFlags,
4774  LPVOID lpEnvironment,
4775  LPCSTR lpCurrentDirectory,
4776  LPSTARTUPINFOA lpStartupInfo,
4777  LPPROCESS_INFORMATION lpProcessInformation)
4778 {
4779  /* Call the internal (but exported) version */
4781  lpApplicationName,
4782  lpCommandLine,
4783  lpProcessAttributes,
4784  lpThreadAttributes,
4785  bInheritHandles,
4786  dwCreationFlags,
4787  lpEnvironment,
4788  lpCurrentDirectory,
4789  lpStartupInfo,
4790  lpProcessInformation,
4791  NULL);
4792 }
4793 
4794 /*
4795  * @implemented
4796  */
4797 UINT
4798 WINAPI
4800 WinExec(LPCSTR lpCmdLine,
4801  UINT uCmdShow)
4802 {
4803  STARTUPINFOA StartupInfo;
4804  PROCESS_INFORMATION ProcessInformation;
4805  DWORD dosErr;
4806 
4807  RtlZeroMemory(&StartupInfo, sizeof(StartupInfo));
4808  StartupInfo.cb = sizeof(STARTUPINFOA);
4809  StartupInfo.wShowWindow = (WORD)uCmdShow;
4810  StartupInfo.dwFlags = 0;
4811 
4812  if (!CreateProcessA(NULL,
4813  (PVOID)lpCmdLine,
4814  NULL,
4815  NULL,
4816  FALSE,
4817  0,
4818  NULL,
4819  NULL,
4820  &StartupInfo,
4821  &ProcessInformation))
4822  {
4823  dosErr = GetLastError();
4824  return dosErr < 32 ? dosErr : ERROR_BAD_FORMAT;
4825  }
4826 
4827  if (NULL != UserWaitForInputIdleRoutine)
4828  {
4829  UserWaitForInputIdleRoutine(ProcessInformation.hProcess,
4830  10000);
4831  }
4832 
4833  NtClose(ProcessInformation.hProcess);
4834  NtClose(ProcessInformation.hThread);
4835 
4836  return 33; /* Something bigger than 31 means success. */
4837 }
4838 
4839 /* EOF */
HANDLE NTAPI DbgUiGetThreadDebugObject(VOID)
Definition: dbgui.c:334
DWORD *typedef PVOID
Definition: winlogon.h:52
#define PROCESS_PRIORITY_CLASS_IDLE
Definition: pstypes.h:108
struct _STARTUPINFOA STARTUPINFOA
BASE_SXS_CREATEPROCESS_MSG Sxs
Definition: basemsg.h:96
signed char * PCHAR
Definition: retypes.h:7
#define ERROR_INVALID_PARAMETER
Definition: compat.h:91
VOID WINAPI BasepFreeAppCompatData(IN PVOID AppCompatData, IN PVOID AppCompatSxsData)
Definition: appcache.c:336
#define ERROR_BAD_FORMAT
Definition: winerror.h:114
#define ERROR_CHILD_NOT_COMPLETE
Definition: winerror.h:201
PVOID WINAPI BasepIsRealtimeAllowed(IN BOOLEAN Keep)
Definition: utils.c:653
ULONG ImageSubsystemMajorVersion
Definition: ntddk_ex.h:309
BOOL WINAPI CreateProcessInternalW(IN HANDLE hUserToken, IN LPCWSTR lpApplicationName, IN LPWSTR lpCommandLine, IN LPSECURITY_ATTRIBUTES lpProcessAttributes, IN LPSECURITY_ATTRIBUTES lpThreadAttributes, IN BOOL bInheritHandles, IN DWORD dwCreationFlags, IN LPVOID lpEnvironment, IN LPCWSTR lpCurrentDirectory, IN LPSTARTUPINFOW lpStartupInfo, IN LPPROCESS_INFORMATION lpProcessInformation, OUT PHANDLE hNewToken)
Definition: proc.c:2279
VOID NTAPI CsrFreeCaptureBuffer(IN PCSR_CAPTURE_BUFFER CaptureBuffer)
Definition: capture.c:189
static int Hash(const char *)
Definition: reader.c:2247
IN PUNICODE_STRING IN POBJECT_ATTRIBUTES ObjectAttributes
Definition: conport.c:35
enum _RTL_PATH_TYPE RTL_PATH_TYPE
#define STATUS_INVALID_IMAGE_WIN_64
Definition: ntstatus.h:887
#define RemoveFromHandle(x, y)
Definition: proc.c:2271
BASE_CREATE_THREAD CreateThreadRequest
Definition: basemsg.h:284
NTSTATUS NTAPI DbgUiConnectToDbg(VOID)
Definition: dbgui.c:25
DWORD dwXSize
Definition: winbase.h:788
#define IN
Definition: typedefs.h:38
DECLSPEC_NORETURN NTSYSAPI VOID NTAPI RtlRaiseStatus(_In_ NTSTATUS Status)
NTSTATUS NTAPI LdrQueryImageFileKeyOption(IN HANDLE KeyHandle, IN PCWSTR ValueName, IN ULONG Type, OUT PVOID Buffer, IN ULONG BufferSize, OUT PULONG ReturnedLength OPTIONAL)
Definition: ldrinit.c:177
NTSTATUS g_AppCertStatus
Definition: proc.c:31
VOID WINAPI BaseInitializeContext(IN PCONTEXT Context, IN PVOID Parameter, IN PVOID StartAddress, IN PVOID StackAddress, IN ULONG ContextType)
Definition: utils.c:503
#define max(a, b)
Definition: svc.c:63
NTSYSAPI NTSTATUS NTAPI RtlCreateProcessParameters(_Out_ PRTL_USER_PROCESS_PARAMETERS *ProcessParameters, _In_ PUNICODE_STRING ImagePathName, _In_opt_ PUNICODE_STRING DllPath, _In_opt_ PUNICODE_STRING CurrentDirectory, _In_opt_ PUNICODE_STRING CommandLine, _In_opt_ PWSTR Environment, _In_opt_ PUNICODE_STRING WindowTitle, _In_opt_ PUNICODE_STRING DesktopInfo, _In_opt_ PUNICODE_STRING ShellInfo, _In_opt_ PUNICODE_STRING RuntimeInfo)
#define THREAD_ALL_ACCESS
Definition: nt_native.h:1339
#define PROCESS_PRIORITY_CLASS_BELOW_NORMAL
Definition: pstypes.h:112
unsigned short WORD
Definition: ntddk_ex.h:93
DWORD dwXCountChars
Definition: winbase.h:790
NTSTATUS NTAPI NtUnmapViewOfSection(IN HANDLE ProcessHandle, IN PVOID BaseAddress)
Definition: section.c:3778
PVOID PVOID PWCHAR PVOID USHORT PULONG PVOID PULONG PVOID PULONG PULONG FusionFlags
Definition: env.c:45
#define REALTIME_PRIORITY_CLASS
Definition: winbase.h:182
#define TRUE
Definition: types.h:120
NTSYSAPI VOID NTAPI RtlCopyMemory(VOID UNALIGNED *Destination, CONST VOID UNALIGNED *Source, ULONG Length)
#define CloseHandle
Definition: compat.h:398
PVOID ULONG Address
Definition: oprghdlr.h:14
#define IMAGE_SUBSYSTEM_POSIX_CUI
Definition: ntimage.h:440
NTSTATUS NTAPI BasepSaveAppCertRegistryValue(IN PLIST_ENTRY List, IN PWCHAR ComponentName, IN PWCHAR DllName)
Definition: proc.c:166
_In_ NDIS_ERROR_CODE ErrorCode
Definition: ndis.h:4417
PPEB Peb
Definition: dllmain.c:27
RTL_CRITICAL_SECTION gcsAppCert
Definition: proc.c:29
*BytesInUnicodeString PWCH UnicodeString
Definition: rtlfuncs.h:1980
#define CREATE_FORCEDOS
Definition: winbase.h:187
BOOL NTAPI IsBadWritePtr(IN LPVOID lp, IN UINT_PTR ucb)
Definition: except.c:882
LPSTR lpTitle
Definition: winbase.h:785
#define DBG
Definition: t_vertex.c:30
#define PROCESS_ALL_ACCESS
Definition: nt_native.h:1324
#define RTL_USER_PROCESS_PARAMETERS_IMAGE_KEY_MISSING
Definition: rtltypes.h:54
NTSTATUS NTAPI NtCreateSection(OUT PHANDLE SectionHandle, IN ACCESS_MASK DesiredAccess, IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL, IN PLARGE_INTEGER MaximumSize OPTIONAL, IN ULONG SectionPageProtection OPTIONAL, IN ULONG AllocationAttributes, IN HANDLE FileHandle OPTIONAL)
Definition: section.c:3369
NTSTATUS NTAPI LdrShutdownProcess(VOID)
Definition: ldrinit.c:892
struct _Entry Entry
Definition: kefuncs.h:640
#define SEM_FAILCRITICALERRORS
Definition: rtltypes.h:69
#define _SEH2_FINALLY
Definition: pseh2_64.h:10
NTSYSAPI NTSTATUS NTAPI NtCreateThread(OUT PHANDLE phThread, IN ACCESS_MASK AccessMask, IN POBJECT_ATTRIBUTES ObjectAttributes, IN HANDLE hProcess, OUT PCLIENT_ID pClientId, IN PCONTEXT pContext, OUT PSTACKINFO pStackInfo, IN BOOLEAN bSuspended)
NTSTATUS NTAPI NtRaiseHardError(IN NTSTATUS ErrorStatus, IN ULONG NumberOfParameters, IN ULONG UnicodeStringParameterMask, IN PULONG_PTR Parameters, IN ULONG ValidResponseOptions, OUT PULONG Response)
Definition: harderr.c:512
#define BINARY_TYPE_WOW
Definition: vdm.h:40
_Must_inspect_result_ _Out_ PNDIS_STATUS _In_ NDIS_HANDLE _In_ ULONG _Out_ PNDIS_STRING _Out_ PNDIS_HANDLE KeyHandle
Definition: ndis.h:4692
LPWSTR lpReserved
Definition: winbase.h:804
#define STATUS_NOT_IMPLEMENTED
Definition: ntstatus.h:225
#define DbgPrint
Definition: loader.c:26
BOOL WINAPI BaseUpdateVDMEntry(IN ULONG UpdateIndex, IN OUT PHANDLE WaitHandle, IN ULONG IndexInfo, IN ULONG BinaryType)
Definition: vdm.c:534
SIZE_T Size
Definition: rtltypes.h:1713
PBASE_STATIC_SERVER_DATA BaseStaticServerData
Definition: dllmain.c:19
USHORT MaximumLength
Definition: env_spec_w32.h:370
#define CREATE_SEPARATE_WOW_VDM
Definition: winbase.h:185
Definition: bidi.c:75
PBASEP_APPCERT_PLUGIN_FUNC fPluginCertFunc
Definition: kernel32.h:385
#define CREATE_UNICODE_ENVIRONMENT
Definition: winbase.h:184
#define PROCESSOR_ARCHITECTURE_UNKNOWN
Definition: ketypes.h:115
#define HANDLE_DETACHED_PROCESS
Definition: console.h:13
#define HANDLE_CREATE_NO_WINDOW
Definition: console.h:15
WCHAR CurrentDirectory[1024]
Definition: chkdsk.c:71
NTSYSAPI ULONG NTAPI DbgPrompt(_In_z_ PCCH Prompt, _Out_writes_bytes_(MaximumResponseLength) PCH Response, _In_ ULONG MaximumResponseLength)
NTSTATUS NTAPI BasepConfigureAppCertDlls(IN PWSTR ValueName, IN ULONG ValueType, IN PVOID ValueData, IN ULONG ValueLength, IN PVOID Context, IN PVOID EntryContext)
Definition: proc.c:177
ASSERT((InvokeOnSuccess||InvokeOnError||InvokeOnCancel)?(CompletionRoutine!=NULL):TRUE)
#define KEY_READ
Definition: nt_native.h:1023
#define SE_LOCK_MEMORY_PRIVILEGE
Definition: security.c:664
UNICODE_STRING WindowTitle
Definition: rtltypes.h:1410
#define STATUS_INVALID_PARAMETER
Definition: udferr_usr.h:135
__wchar_t WCHAR
Definition: xmlstorage.h:180
#define AddToHandle(x, y)
Definition: proc.c:2270
NTSYSAPI VOID NTAPI RtlDestroyEnvironment(_In_ PWSTR Environment)
BOOL NTAPI BaseCreateVDMEnvironment(IN PWCHAR lpEnvironment, OUT PANSI_STRING AnsiEnv, OUT PUNICODE_STRING UnicodeEnv)
Definition: vdm.c:736
VOID WINAPI BasepAnsiStringToHeapUnicodeString(IN LPCSTR AnsiString, OUT LPWSTR *UnicodeString)
Definition: utils.c:263
BOOL WINAPI GetExitCodeProcess(IN HANDLE hProcess, IN LPDWORD lpExitCode)
Definition: proc.c:1213
return STATUS_SUCCESS
Definition: btrfs.c:2664
#define INVALID_FILE_ATTRIBUTES
Definition: test.h:47
NTSTATUS WINAPI BasepCheckWinSaferRestrictions(IN HANDLE UserToken, IN LPWSTR ApplicationName, IN HANDLE FileHandle, OUT PBOOLEAN InJob, OUT PHANDLE NewToken, OUT PHANDLE JobHandle)
Definition: utils.c:909
static DWORD ResumeCount
Definition: database.c:35
NTSTATUS NTAPI CsrClientCallServer(IN OUT PCSR_API_MESSAGE ApiMessage, IN OUT PCSR_CAPTURE_BUFFER CaptureBuffer OPTIONAL, IN CSR_API_NUMBER ApiNumber, IN ULONG DataLength)
Definition: connect.c:360
unsigned char * LPBYTE
Definition: typedefs.h:52
char CHAR
Definition: xmlstorage.h:175
_In_ PCWSTR _In_z_ PCWSTR _In_ ULONG ValueType
Definition: rtlfuncs.h:4000
HANDLE ContainingDirectory
Definition: rtltypes.h:1260
struct _STARTUPINFOW STARTUPINFOW
#define VER_SUITE_BLADE
BOOL WINAPI BaseGetVdmConfigInfo(IN LPCWSTR CommandLineReserved, IN ULONG DosSeqId, IN ULONG BinaryType, IN PUNICODE_STRING CmdLineString, OUT PULONG VdmSize)
Definition: vdm.c:644
BASE_CREATE_PROCESS CreateProcessRequest
Definition: basemsg.h:283
BOOL NTAPI BaseDestroyVDMEnvironment(IN PANSI_STRING AnsiEnv, IN PUNICODE_STRING UnicodeEnv)
Definition: vdm.c:1025
#define ERROR_INVALID_HANDLE
Definition: compat.h:88
VOID NTAPI RtlReleaseRelativeName(_In_ PRTL_RELATIVE_NAME_U RelativeName)
NTSTATUS WINAPI BasepNotifyCsrOfThread(IN HANDLE ThreadHandle, IN PCLIENT_ID ClientId)
Definition: proc.c:499
NTSTATUS NTAPI NtProtectVirtualMemory(IN HANDLE ProcessHandle, IN OUT PVOID *UnsafeBaseAddress, IN OUT SIZE_T *UnsafeNumberOfBytesToProtect, IN ULONG NewAccessProtection, OUT PULONG UnsafeOldAccessProtection)
Definition: virtual.c:2986
*nSize LPSTR _Inout_ LPDWORD nSize
Definition: winbase.h:1973
BOOLEAN DefaultSeparateVDM
Definition: base.h:126
LARGE_INTEGER UserTime
Definition: winternl.h:1021
BOOLEAN NTAPI RtlFreeHeap(IN PVOID HeapHandle, IN ULONG Flags, IN PVOID HeapBase)
Definition: heap.c:603
#define HandleToUlong(h)
Definition: basetsd.h:78
NTSTATUS NTAPI NtQueryInformationProcess(IN HANDLE ProcessHandle, IN PROCESSINFOCLASS ProcessInformationClass, OUT PVOID ProcessInformation, IN ULONG ProcessInformationLength, OUT PULONG ReturnLength OPTIONAL)
Definition: query.c:56
_In_opt_ ULONG Base
Definition: rtlfuncs.h:2327
SIZE_T LPPROCESS_INFORMATION
Definition: cordebug.idl:86
#define NtCurrentThread()
_Check_return_ _CRTIMP int __cdecl _wcsnicmp(_In_reads_or_z_(_MaxCount) const wchar_t *_Str1, _In_reads_or_z_(_MaxCount) const wchar_t *_Str2, _In_ size_t _MaxCount)
#define PROFILE_KERNEL
Definition: winbase.h:195
PVOID *typedef PWSTR
Definition: winlogon.h:57
NTSYSAPI NTSTATUS NTAPI RtlDestroyProcessParameters(_In_ PRTL_USER_PROCESS_PARAMETERS ProcessParameters)
DWORD dwYCountChars
Definition: winbase.h:791
#define PROCESS_CREATE_FLAGS_NO_DEBUG_INHERIT
Definition: pstypes.h:93
BOOLEAN g_AppCertInitialized
Definition: proc.c:26
BOOL WINAPI SetPriorityClass(IN HANDLE hProcess, IN DWORD dwPriorityClass)
Definition: proc.c:1737
const WCHAR * LPCWSTR
Definition: xmlstorage.h:185
NTSYSAPI NTSTATUS NTAPI RtlEnterCriticalSection(_In_ PRTL_CRITICAL_SECTION CriticalSection)
VOID WINAPI GetStartupInfoA(IN LPSTARTUPINFOA lpStartupInfo)
Definition: proc.c:1365
#define ERROR_NOT_ENOUGH_MEMORY
Definition: dderror.h:7
#define INVALID_HANDLE_VALUE
Definition: compat.h:391
VOID WINAPI ExitProcess(IN UINT uExitCode)
Definition: proc.c:1532
DWORD WINAPI GetLastError(VOID)
Definition: except.c:1056
BOOL WINAPI BaseCheckForVDM(IN HANDLE ProcessHandle, OUT LPDWORD ExitCode)
Definition: vdm.c:610
DWORD WINAPI GetFullPathNameW(IN LPCWSTR lpFileName, IN DWORD nBufferLength, OUT LPWSTR lpBuffer, OUT LPWSTR *lpFilePart)
Definition: path.c:1105
NTSYSAPI PVOID WINAPI RtlDecodePointer(PVOID)
_In_ BOOL _In_ HANDLE hProcess
Definition: mapping.h:70
VOID NTAPI RtlReleasePebLock(VOID)
Definition: libsupp.c:82
SIZE_T LPSTARTUPINFOW
Definition: cordebug.idl:85
_In_ PLARGE_INTEGER _In_ PLARGE_INTEGER _In_ PEPROCESS ProcessId
Definition: iotypes.h:1451
DWORD dwFlags
Definition: winbase.h:793
#define ERROR_BAD_DEVICE
Definition: winerror.h:703
#define CREATE_DEFAULT_ERROR_MODE
Definition: winbase.h:192
NTSTATUS NTAPI RtlGetFullPathName_UstrEx(_In_ PUNICODE_STRING FileName, _In_opt_ PUNICODE_STRING StaticString, _In_opt_ PUNICODE_STRING DynamicString, _Out_opt_ PUNICODE_STRING *StringUsed, _Out_opt_ PSIZE_T FilePartSize, _Out_opt_ PBOOLEAN NameInvalid, _Out_ RTL_PATH_TYPE *PathType, _Out_opt_ PSIZE_T LengthNeeded)
_At_(*)(_In_ PWSK_CLIENT Client, _In_opt_ PUNICODE_STRING NodeName, _In_opt_ PUNICODE_STRING ServiceName, _In_opt_ ULONG NameSpace, _In_opt_ GUID *Provider, _In_opt_ PADDRINFOEXW Hints, _Outptr_ PADDRINFOEXW *Result, _In_opt_ PEPROCESS OwningProcess, _In_opt_ PETHREAD OwningThread, _Inout_ PIRP Irp Result)(Mem)) NTSTATUS(WSKAPI *PFN_WSK_GET_ADDRESS_INFO
Definition: wsk.h:426
UINT WINAPI DECLSPEC_HOTPATCH WinExec(LPCSTR lpCmdLine, UINT uCmdShow)
Definition: proc.c:4800
UNICODE_STRING ShellInfo
Definition: rtltypes.h:1412
#define VDM_UNDO_COMPLETED
Definition: vdm.h:30
#define PROCESS_CREATE_FLAGS_BREAKAWAY
Definition: pstypes.h:92
uint16_t * PWCHAR
Definition: typedefs.h:54
IN PVOID IN PVOID IN USHORT Version
Definition: pci.h:359
#define STARTF_FORCEONFEEDBACK
Definition: winbase.h:469
#define FILE_SHARE_WRITE
Definition: nt_native.h:681
#define RTL_REGISTRY_CONTROL
Definition: nt_native.h:163
#define NORMAL_PRIORITY_CLASS
Definition: winbase.h:179
BOOL WINAPI FlushInstructionCache(IN HANDLE hProcess, IN LPCVOID lpBaseAddress, IN SIZE_T nSize)
Definition: proc.c:1508
Definition: kernel32.h:381
*nSize LPSTR lpBuffer
Definition: winbase.h:1973
char * LPSTR
Definition: xmlstorage.h:182
HANDLE UniqueProcess
Definition: compat.h:474
UNICODE_STRING DesktopInfo
Definition: rtltypes.h:1411
#define WCHAR
Definition: msvc.h:43
void DbgBreakPoint()
Definition: mach.c:558
#define UNICODE_STRING_MAX_BYTES
#define ERROR_DIRECTORY
Definition: winerror.h:295
#define ERROR_ACCESS_DISABLED_WEBBLADE
Definition: winerror.h:774
#define CREATE_NEW_PROCESS_GROUP
Definition: winbase.h:183
#define PROCESS_PRIORITY_CLASS_ABOVE_NORMAL
Definition: pstypes.h:113
#define MEM_COMMIT
Definition: nt_native.h:1313
#define VER_SUITE_DATACENTER
#define IMAGE_FILE_MACHINE_AMD64
Definition: ntimage.h:17
NTSTATUS NTAPI NtOpenProcess(OUT PHANDLE ProcessHandle, IN ACCESS_MASK DesiredAccess, IN POBJECT_ATTRIBUTES ObjectAttributes, IN PCLIENT_ID ClientId)
Definition: process.c:1440
#define STATUS_VDM_DISALLOWED
Definition: ntstatus.h:943
#define DWORD
Definition: msvc.h:34
_Must_inspect_result_ FORCEINLINE BOOLEAN IsListEmpty(_In_ const LIST_ENTRY *ListHead)
Definition: rtlfuncs.h:57
#define VER_SUITE_PERSONAL
PVOID ArbitraryUserPointer
Definition: compat.h:379
DWORD dwY
Definition: winbase.h:787
NTSTATUS NTAPI LdrOpenImageFileOptionsKey(IN PUNICODE_STRING SubKey, IN BOOLEAN Wow64, OUT PHANDLE NewKeyHandle)
Definition: ldrinit.c:105
DWORD(* WaitForInputIdleType)(HANDLE hProcess, DWORD dwMilliseconds)
Definition: kernel32.h:113
ULONG NtMajorVersion
Definition: init.c:42
DWORD DWORD
Definition: winlogon.h:75
#define IMAGE_FILE_DLL
Definition: pedump.c:169
IMAGE_OPTIONAL_HEADER32 OptionalHeader
Definition: ntddk_ex.h:184
#define FILE_SHARE_READ
Definition: compat.h:125
#define RtlMoveMemory(Destination, Source, Length)
Definition: typedefs.h:263
#define STARTF_FORCEOFFFEEDBACK
Definition: winbase.h:470
struct _LARGE_INTEGER::@2037 u
#define PROFILE_USER
Definition: winbase.h:194
BOOL WINAPI SetProcessWorkingSetSize(IN HANDLE hProcess, IN SIZE_T dwMinimumWorkingSetSize, IN SIZE_T dwMaximumWorkingSetSize)
Definition: proc.c:1128
NTSYSAPI BOOLEAN NTAPI RtlDosPathNameToRelativeNtPathName_U(_In_ PCWSTR DosName, _Out_ PUNICODE_STRING NtName, _Out_ PCWSTR *PartName, _Out_ PRTL_RELATIVE_NAME_U RelativeName)
#define SearchPath
Definition: winbase.h:3662
BOOL NTAPI ReadProcessMemory(IN HANDLE hProcess, IN LPCVOID lpBaseAddress, IN LPVOID lpBuffer, IN SIZE_T nSize, OUT SIZE_T *lpNumberOfBytesRead)
Definition: proc.c:2068
#define ABOVE_NORMAL_PRIORITY_CLASS
Definition: winbase.h:189
#define PROCESS_VM_READ
Definition: pstypes.h:154
NTSYSAPI VOID NTAPI RtlInitAnsiString(PANSI_STRING DestinationString, PCSZ SourceString)
uint32_t ULONG_PTR
Definition: typedefs.h:63
#define PROCESSOR_ARCHITECTURE_IA64
Definition: ketypes.h:111
#define CREATE_NO_WINDOW
Definition: winbase.h:193
LARGE_INTEGER ExitTime
Definition: winternl.h:1019
BOOL WINAPI SetProcessShutdownParameters(IN DWORD dwLevel, IN DWORD dwFlags)
Definition: proc.c:994
NTSYSAPI NTSTATUS NTAPI RtlComputeImportTableHash(IN HANDLE FileHandle, OUT PCHAR Hash, IN ULONG ImportTableHashSize)
Definition: libsupp.c:695
PVOID ImageBaseAddress
Definition: ntddk_ex.h:249
HANDLE ThreadHandle
Definition: basemsg.h:90
static IN ULONG IN PWSTR OUT PCWSTR OUT PBOOLEAN OUT PATH_TYPE_AND_UNKNOWN * PathType
GLuint n
Definition: s_context.h:57
#define VDM_READY
Definition: vdm.h:48
#define HARDERROR_OVERRIDE_ERRORMODE
Definition: extypes.h:146
_In_ PUNICODE_STRING ValueName
Definition: cmfuncs.h:264
#define SECTION_ALL_ACCESS
Definition: nt_native.h:1293
#define EXCEPTION_CONTINUE_SEARCH
Definition: excpt.h:86
_Must_inspect_result_ _In_ ULONG Flags
Definition: wsk.h:170
#define VER_SUITE_STORAGE_SERVER
#define PROCESS_QUERY_INFORMATION
Definition: pstypes.h:159
GLenum GLclampf GLint i
Definition: glfuncs.h:14
NTSTATUS Status
Definition: csrmsg.h:112
BOOL WINAPI CreateProcessInternalA(HANDLE hToken, LPCSTR lpApplicationName, LPSTR lpCommandLine, LPSECURITY_ATTRIBUTES lpProcessAttributes, LPSECURITY_ATTRIBUTES lpThreadAttributes, BOOL bInheritHandles, DWORD dwCreationFlags, LPVOID lpEnvironment, LPCSTR lpCurrentDirectory, LPSTARTUPINFOA lpStartupInfo, LPPROCESS_INFORMATION lpProcessInformation, PHANDLE hNewToken)
Definition: proc.c:4650
#define CREATE_SUSPENDED
Definition: winbase.h:176
#define PAGE_EXECUTE_WRITECOPY
Definition: nt_native.h:1309
BOOLEAN WINAPI Basep8BitStringToDynamicUnicodeString(OUT PUNICODE_STRING UnicodeString, IN LPCSTR String)
Definition: utils.c:225
BASE_GETSET_PROCESS_SHUTDOWN_PARAMS ShutdownParametersRequest
Definition: basemsg.h:294
#define DUPLICATE_SAME_ACCESS
static HANDLE hUserToken
Definition: umpnpmgr.c:68
ULONG_PTR * PSIZE_T
Definition: typedefs.h:78
NTSTATUS(* NTAPI)(IN PFILE_FULL_EA_INFORMATION EaBuffer, IN ULONG EaLength, OUT PULONG ErrorOffset)
Definition: IoEaTest.cpp:117
BOOL WINAPI SetProcessWorkingSetSizeEx(IN HANDLE hProcess, IN SIZE_T dwMinimumWorkingSetSize, IN SIZE_T dwMaximumWorkingSetSize, IN DWORD Flags)
Definition: proc.c:1072
BOOLEAN g_HaveAppCerts
Definition: proc.c:27
#define FALSE
Definition: types.h:117
#define UNICODE_NULL
#define ANSI_NULL
DWORD e_lfanew
Definition: crypt.c:1156
HANDLE WINAPI GetCurrentThread(VOID)
Definition: proc.c:1193
#define ERROR_ACCESS_DENIED
Definition: compat.h:87
static BOOL bInheritHandle
Definition: pipe.c:80
BOOLEAN WINAPI BasepIsImageVersionOk(IN ULONG ImageMajorVersion, IN ULONG ImageMinorVersion)
Definition: proc.c:123
long LONG
Definition: pedump.c:60
NTSYSAPI NTSTATUS NTAPI RtlLeaveCriticalSection(_In_ PRTL_CRITICAL_SECTION CriticalSection)
NTSTATUS(NTAPI * PBASEP_APPCERT_EMBEDDED_FUNC)(IN LPWSTR ApplicationName)
Definition: kernel32.h:370
DWORD WINAPI GetFileAttributesW(LPCWSTR lpFileName)
Definition: fileinfo.c:782