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