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