ReactOS  0.4.10-dev-486-g11b7619
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)(ULONG_PTR)Handles->ViewBase.QuadPart);
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 = NULL;
1399  StartupInfo->lpDesktop = NULL;
1400  StartupInfo->lpTitle = NULL;
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, StackSize, ErrorCode, Flags;
2315  USHORT ImageMachine;
2316  ULONG ParameterFlags, PrivilegeValue, HardErrorMode, ErrorResponse;
2317  ULONG_PTR ErrorParameters[2];
2318  BOOLEAN InJob, SaferNeeded, UseLargePages, HavePrivilege;
2319  BOOLEAN QuerySection, SkipSaferAndAppCompat;
2320  CONTEXT Context;
2321  BASE_API_MESSAGE CsrMsg[2];
2322  PBASE_CREATE_PROCESS CreateProcessMsg;
2323  PCSR_CAPTURE_BUFFER CaptureBuffer;
2324  PVOID BaseAddress, PrivilegeState, RealTimePrivilegeState;
2325  HANDLE DebugHandle, TokenHandle, JobHandle, KeyHandle, ThreadHandle;
2326  HANDLE FileHandle, SectionHandle, ProcessHandle;
2328  PROCESS_PRIORITY_CLASS PriorityClass;
2329  NTSTATUS Status, AppCompatStatus, SaferStatus, IFEOStatus, ImageDbgStatus;
2330  PPEB Peb, RemotePeb;
2331  PTEB Teb;
2332  INITIAL_TEB InitialTeb;
2333  PVOID TibValue;
2334  PIMAGE_NT_HEADERS NtHeaders;
2335  STARTUPINFOW StartupInfo;
2336  PRTL_USER_PROCESS_PARAMETERS ProcessParameters;
2337  UNICODE_STRING DebuggerString;
2338  BOOL Result;
2339  //
2340  // Variables used for command-line and argument parsing
2341  //
2342  PCHAR pcScan;
2343  SIZE_T n;
2344  WCHAR SaveChar;
2345  ULONG Length, FileAttribs, CmdQuoteLength;
2346  ULONG ResultSize;
2347  SIZE_T EnvironmentLength, CmdLineLength;
2348  PWCHAR QuotedCmdLine, AnsiCmdCommand, ExtBuffer, CurrentDirectory;
2349  PWCHAR NullBuffer, ScanString, NameBuffer, SearchPath, DebuggerCmdLine;
2350  ANSI_STRING AnsiEnv;
2351  UNICODE_STRING UnicodeEnv, PathName;
2352  BOOLEAN SearchRetry, QuotesNeeded, CmdLineIsAppName, HasQuotes;
2353 
2354  //
2355  // Variables used for Fusion/SxS (Side-by-Side Assemblies)
2356  //
2357  RTL_PATH_TYPE SxsPathType, PathType;
2358 #if _SXS_SUPPORT_ENABLED_
2359  PRTL_BUFFER ByteBuffer;
2360  PRTL_UNICODE_STRING_BUFFER ThisBuffer, Buffer, SxsStaticBuffers[5];
2361  PRTL_UNICODE_STRING_BUFFER* BufferHead, SxsStringBuffer;
2362  RTL_UNICODE_STRING_BUFFER SxsWin32ManifestPath, SxsNtManifestPath;
2363  RTL_UNICODE_STRING_BUFFER SxsWin32PolicyPath, SxsNtPolicyPath;
2364  RTL_UNICODE_STRING_BUFFER SxsWin32AssemblyDirectory;
2365  BASE_MSG_SXS_HANDLES MappedHandles, Handles, FileHandles;
2366  PVOID CapturedStrings[3];
2367  SXS_WIN32_NT_PATH_PAIR ExePathPair, ManifestPathPair, PolicyPathPair;
2368  SXS_OVERRIDE_MANIFEST OverrideManifest;
2369  UNICODE_STRING FreeString, SxsNtExePath;
2370  PWCHAR SxsConglomeratedBuffer, StaticBuffer;
2371  ULONG ConglomeratedBufferSizeBytes, StaticBufferSize, i;
2372 #endif
2374 
2375  //
2376  // Variables used for path conversion (and partially Fusion/SxS)
2377  //
2378  PWCHAR FilePart, PathBuffer, FreeBuffer;
2379  BOOLEAN TranslationStatus;
2380  RTL_RELATIVE_NAME_U SxsWin32RelativePath;
2381  UNICODE_STRING PathBufferString, SxsWin32ExePath;
2382 
2383  //
2384  // Variables used by Application Compatibility (and partially Fusion/SxS)
2385  //
2386  PVOID AppCompatSxsData, AppCompatData;
2387  ULONG AppCompatSxsDataSize, AppCompatDataSize;
2388  //
2389  // Variables used by VDM (Virtual Dos Machine) and WOW32 (16-bit Support)
2390  //
2391  ULONG BinarySubType, VdmBinaryType, VdmTask, VdmReserve;
2392  ULONG VdmUndoLevel;
2393  BOOLEAN UseVdmReserve;
2394  HANDLE VdmWaitObject;
2395  ANSI_STRING VdmAnsiEnv;
2396  UNICODE_STRING VdmString, VdmUnicodeEnv;
2397  BOOLEAN IsWowApp;
2398  PBASE_CHECK_VDM CheckVdmMsg;
2399 
2400  /* Zero out the initial core variables and handles */
2401  QuerySection = FALSE;
2402  InJob = FALSE;
2403  SkipSaferAndAppCompat = FALSE;
2404  ParameterFlags = 0;
2405  Flags = 0;
2406  DebugHandle = NULL;
2407  JobHandle = NULL;
2408  TokenHandle = NULL;
2409  FileHandle = NULL;
2410  SectionHandle = NULL;
2411  ProcessHandle = NULL;
2412  ThreadHandle = NULL;
2413  BaseAddress = (PVOID)1;
2414 
2415  /* Zero out initial SxS and Application Compatibility state */
2416  AppCompatData = NULL;
2417  AppCompatDataSize = 0;
2418  AppCompatSxsData = NULL;
2419  AppCompatSxsDataSize = 0;
2420  CaptureBuffer = NULL;
2421 #if _SXS_SUPPORT_ENABLED_
2422  SxsConglomeratedBuffer = NULL;
2423 #endif
2424  FusionFlags = 0;
2425 
2426  /* Zero out initial parsing variables -- others are initialized later */
2427  DebuggerCmdLine = NULL;
2428  PathBuffer = NULL;
2429  SearchPath = NULL;
2430  NullBuffer = NULL;
2431  FreeBuffer = NULL;
2432  NameBuffer = NULL;
2433  CurrentDirectory = NULL;
2434  FilePart = NULL;
2435  DebuggerString.Buffer = NULL;
2436  HasQuotes = FALSE;
2437  QuotedCmdLine = NULL;
2438 
2439  /* Zero out initial VDM state */
2440  VdmAnsiEnv.Buffer = NULL;
2441  VdmUnicodeEnv.Buffer = NULL;
2442  VdmString.Buffer = NULL;
2443  VdmTask = 0;
2444  VdmUndoLevel = 0;
2445  VdmBinaryType = 0;
2446  VdmReserve = 0;
2447  VdmWaitObject = NULL;
2448  UseVdmReserve = FALSE;
2449  IsWowApp = FALSE;
2450 
2451  /* Set message structures */
2452  CreateProcessMsg = &CsrMsg[0].Data.CreateProcessRequest;
2453  CheckVdmMsg = &CsrMsg[1].Data.CheckVDMRequest;
2454 
2455  /* Clear the more complex structures by zeroing out their entire memory */
2456  RtlZeroMemory(&Context, sizeof(Context));
2457 #if _SXS_SUPPORT_ENABLED_
2458  RtlZeroMemory(&FileHandles, sizeof(FileHandles));
2459  RtlZeroMemory(&MappedHandles, sizeof(MappedHandles));
2460  RtlZeroMemory(&Handles, sizeof(Handles));
2461 #endif
2462  RtlZeroMemory(&CreateProcessMsg->Sxs, sizeof(CreateProcessMsg->Sxs));
2463  RtlZeroMemory(&LocalProcessAttributes, sizeof(LocalProcessAttributes));
2464  RtlZeroMemory(&LocalThreadAttributes, sizeof(LocalThreadAttributes));
2465 
2466  /* Zero out output arguments as well */
2467  RtlZeroMemory(lpProcessInformation, sizeof(*lpProcessInformation));
2468  if (hNewToken) *hNewToken = NULL;
2469 
2470  /* Capture the special window flag */
2471  NoWindow = dwCreationFlags & CREATE_NO_WINDOW;
2472  dwCreationFlags &= ~CREATE_NO_WINDOW;
2473 
2474 #if _SXS_SUPPORT_ENABLED_
2475  /* Setup the SxS static string arrays and buffers */
2476  SxsStaticBuffers[0] = &SxsWin32ManifestPath;
2477  SxsStaticBuffers[1] = &SxsWin32PolicyPath;
2478  SxsStaticBuffers[2] = &SxsWin32AssemblyDirectory;
2479  SxsStaticBuffers[3] = &SxsNtManifestPath;
2480  SxsStaticBuffers[4] = &SxsNtPolicyPath;
2481  ExePathPair.Win32 = &SxsWin32ExePath;
2482  ExePathPair.Nt = &SxsNtExePath;
2483  ManifestPathPair.Win32 = &SxsWin32ManifestPath.String;
2484  ManifestPathPair.Nt = &SxsNtManifestPath.String;
2485  PolicyPathPair.Win32 = &SxsWin32PolicyPath.String;
2486  PolicyPathPair.Nt = &SxsNtPolicyPath.String;
2487 #endif
2488 
2489  DPRINT("CreateProcessInternalW: '%S' '%S' %lx\n", lpApplicationName, lpCommandLine, dwCreationFlags);
2490 
2491  /* Finally, set our TEB and PEB */
2492  Teb = NtCurrentTeb();
2493  Peb = NtCurrentPeb();
2494 
2495  /* This combination is illegal (see MSDN) */
2496  if ((dwCreationFlags & (DETACHED_PROCESS | CREATE_NEW_CONSOLE)) ==
2498  {
2499  DPRINT1("Invalid flag combo used\n");
2501  return FALSE;
2502  }
2503 
2504  /* Convert the priority class */
2505  if (dwCreationFlags & IDLE_PRIORITY_CLASS)
2506  {
2508  }
2509  else if (dwCreationFlags & BELOW_NORMAL_PRIORITY_CLASS)
2510  {
2512  }
2513  else if (dwCreationFlags & NORMAL_PRIORITY_CLASS)
2514  {
2516  }
2517  else if (dwCreationFlags & ABOVE_NORMAL_PRIORITY_CLASS)
2518  {
2520  }
2521  else if (dwCreationFlags & HIGH_PRIORITY_CLASS)
2522  {
2524  }
2525  else if (dwCreationFlags & REALTIME_PRIORITY_CLASS)
2526  {
2528  PriorityClass.PriorityClass += (BasepIsRealtimeAllowed(FALSE) != NULL);
2529  }
2530  else
2531  {
2533  }
2534 
2535  /* Done with the priority masks, so get rid of them */
2536  PriorityClass.Foreground = FALSE;
2537  dwCreationFlags &= ~(NORMAL_PRIORITY_CLASS |
2538  IDLE_PRIORITY_CLASS |
2539  HIGH_PRIORITY_CLASS |
2540  REALTIME_PRIORITY_CLASS |
2541  BELOW_NORMAL_PRIORITY_CLASS |
2543 
2544  /* You cannot request both a shared and a separate WoW VDM */
2545  if ((dwCreationFlags & CREATE_SEPARATE_WOW_VDM) &&
2546  (dwCreationFlags & CREATE_SHARED_WOW_VDM))
2547  {
2548  /* Fail such nonsensical attempts */
2549  DPRINT1("Invalid WOW flags\n");
2551  return FALSE;
2552  }
2553  else if (!(dwCreationFlags & CREATE_SHARED_WOW_VDM) &&
2555  {
2556  /* A shared WoW VDM was not requested but system enforces separation */
2557  dwCreationFlags |= CREATE_SEPARATE_WOW_VDM;
2558  }
2559 
2560  /* If a shared WoW VDM is used, make sure the process isn't in a job */
2561  if (!(dwCreationFlags & CREATE_SEPARATE_WOW_VDM) &&
2563  {
2564  /* Remove the shared flag and add the separate flag */
2565  dwCreationFlags = (dwCreationFlags &~ CREATE_SHARED_WOW_VDM) |
2566  CREATE_SEPARATE_WOW_VDM;
2567  }
2568 
2569  /* Convert the environment */
2570  if ((lpEnvironment) && !(dwCreationFlags & CREATE_UNICODE_ENVIRONMENT))
2571  {
2572  /* Scan the environment to calculate its Unicode size */
2573  AnsiEnv.Buffer = pcScan = (PCHAR)lpEnvironment;
2574  while ((*pcScan) || (*(pcScan + 1))) ++pcScan;
2575 
2576  /* Make sure the environment is not too large */
2577  EnvironmentLength = (pcScan + sizeof(ANSI_NULL) - (PCHAR)lpEnvironment);
2578  if (EnvironmentLength > MAXUSHORT)
2579  {
2580  /* Fail */
2582  return FALSE;
2583  }
2584 
2585  /* Create our ANSI String */
2586  AnsiEnv.Length = (USHORT)EnvironmentLength;
2587  AnsiEnv.MaximumLength = AnsiEnv.Length + sizeof(ANSI_NULL);
2588 
2589  /* Allocate memory for the Unicode Environment */
2590  UnicodeEnv.Buffer = NULL;
2591  RegionSize = AnsiEnv.MaximumLength * sizeof(WCHAR);
2593  (PVOID)&UnicodeEnv.Buffer,
2594  0,
2595  &RegionSize,
2596  MEM_COMMIT,
2597  PAGE_READWRITE);
2598  if (!NT_SUCCESS(Status))
2599  {
2600  /* Fail */
2601  BaseSetLastNTError(Status);
2602  return FALSE;
2603  }
2604 
2605  /* Use the allocated size and convert */
2606  UnicodeEnv.MaximumLength = (USHORT)RegionSize;
2607  Status = RtlAnsiStringToUnicodeString(&UnicodeEnv, &AnsiEnv, FALSE);
2608  if (!NT_SUCCESS(Status))
2609  {
2610  /* Fail */
2612  (PVOID)&UnicodeEnv.Buffer,
2613  &RegionSize,
2614  MEM_RELEASE);
2615  BaseSetLastNTError(Status);
2616  return FALSE;
2617  }
2618 
2619  /* Now set the Unicode environment as the environment string pointer */
2620  lpEnvironment = UnicodeEnv.Buffer;
2621  }
2622 
2623  /* Make a copy of the caller's startup info since we'll modify it */
2624  StartupInfo = *lpStartupInfo;
2625 
2626  /* Check if private data is being sent on the same channel as std handles */
2627  if ((StartupInfo.dwFlags & STARTF_USESTDHANDLES) &&
2628  (StartupInfo.dwFlags & (STARTF_USEHOTKEY | STARTF_SHELLPRIVATE)))
2629  {
2630  /* Cannot use the std handles since we have monitor/hotkey values */
2631  StartupInfo.dwFlags &= ~STARTF_USESTDHANDLES;
2632  }
2633 
2634  /* If there's a debugger, or we have to launch cmd.exe, we go back here */
2635 AppNameRetry:
2636  /* New iteration -- free any existing name buffer */
2637  if (NameBuffer)
2638  {
2639  RtlFreeHeap(RtlGetProcessHeap(), 0, NameBuffer);
2640  NameBuffer = NULL;
2641  }
2642 
2643  /* New iteration -- free any existing free buffer */
2644  if (FreeBuffer)
2645  {
2646  RtlFreeHeap(RtlGetProcessHeap(), 0, FreeBuffer);
2647  FreeBuffer = NULL;
2648  }
2649 
2650  /* New iteration -- close any existing file handle */
2651  if (FileHandle)
2652  {
2653  NtClose(FileHandle);
2654  FileHandle = NULL;
2655  }
2656 
2657  /* Set the initial parsing state. This code can loop -- don't move this! */
2658  ErrorCode = 0;
2659  SearchRetry = TRUE;
2660  QuotesNeeded = FALSE;
2661  CmdLineIsAppName = FALSE;
2662 
2663  /* First check if we don't have an application name */
2664  if (!lpApplicationName)
2665  {
2666  /* This should be the first time we attempt creating one */
2667  ASSERT(NameBuffer == NULL);
2668 
2669  /* Allocate a buffer to hold it */
2670  NameBuffer = RtlAllocateHeap(RtlGetProcessHeap(),
2671  0,
2672  MAX_PATH * sizeof(WCHAR));
2673  if (!NameBuffer)
2674  {
2676  Result = FALSE;
2677  goto Quickie;
2678  }
2679 
2680  /* Initialize the application name and our parsing parameters */
2681  lpApplicationName = NullBuffer = ScanString = lpCommandLine;
2682 
2683  /* Check for an initial quote*/
2684  if (*lpCommandLine == L'\"')
2685  {
2686  /* We found a quote, keep searching for another one */
2687  SearchRetry = FALSE;
2688  ScanString++;
2689  lpApplicationName = ScanString;
2690  while (*ScanString)
2691  {
2692  /* Have we found the terminating quote? */
2693  if (*ScanString == L'\"')
2694  {
2695  /* We're done, get out of here */
2696  NullBuffer = ScanString;
2697  HasQuotes = TRUE;
2698  break;
2699  }
2700 
2701  /* Keep searching for the quote */
2702  ScanString++;
2703  NullBuffer = ScanString;
2704  }
2705  }
2706  else
2707  {
2708 StartScan:
2709  /* We simply make the application name be the command line*/
2710  lpApplicationName = lpCommandLine;
2711  while (*ScanString)
2712  {
2713  /* Check if it starts with a space or tab */
2714  if ((*ScanString == L' ') || (*ScanString == L'\t'))
2715  {
2716  /* Break out of the search loop */
2717  NullBuffer = ScanString;
2718  break;
2719  }
2720 
2721  /* Keep searching for a space or tab */
2722  ScanString++;
2723  NullBuffer = ScanString;
2724  }
2725  }
2726 
2727  /* We have found the end of the application name, terminate it */
2728  SaveChar = *NullBuffer;
2729  *NullBuffer = UNICODE_NULL;
2730 
2731  /* New iteration -- free any existing saved path */
2732  if (SearchPath)
2733  {
2734  RtlFreeHeap(RtlGetProcessHeap(), 0, SearchPath);
2735  SearchPath = NULL;
2736  }
2737 
2738  /* Now compute the final EXE path based on the name */
2739  SearchPath = BaseComputeProcessExePath((LPWSTR)lpApplicationName);
2740  DPRINT("Search Path: %S\n", SearchPath);
2741  if (!SearchPath)
2742  {
2744  Result = FALSE;
2745  goto Quickie;
2746  }
2747 
2748  /* And search for the executable in the search path */
2749  Length = SearchPathW(SearchPath,
2750  lpApplicationName,
2751  L".exe",
2752  MAX_PATH,
2753  NameBuffer,
2754  NULL);
2755 
2756  /* Did we find it? */
2757  if ((Length) && (Length < MAX_PATH))
2758  {
2759  /* Get file attributes */
2760  FileAttribs = GetFileAttributesW(NameBuffer);
2761  if ((FileAttribs != INVALID_FILE_ATTRIBUTES) &&
2762  (FileAttribs & FILE_ATTRIBUTE_DIRECTORY))
2763  {
2764  /* This was a directory, fail later on */
2765  Length = 0;
2766  }
2767  else
2768  {
2769  /* It's a file! */
2770  Length++;
2771  }
2772  }
2773 
2774  DPRINT("Length: %lu Buffer: %S\n", Length, NameBuffer);
2775 
2776  /* Check if there was a failure in SearchPathW */
2777  if ((Length) && (Length < MAX_PATH))
2778  {
2779  /* Everything looks good, restore the name */
2780  *NullBuffer = SaveChar;
2781  lpApplicationName = NameBuffer;
2782  }
2783  else
2784  {
2785  /* Check if this was a relative path, which would explain it */
2786  PathType = RtlDetermineDosPathNameType_U(lpApplicationName);
2787  if (PathType != RtlPathTypeRelative)
2788  {
2789  /* This should fail, and give us a detailed LastError */
2790  FileHandle = CreateFileW(lpApplicationName,
2791  GENERIC_READ,
2792  FILE_SHARE_READ |
2794  NULL,
2795  OPEN_EXISTING,
2797  NULL);
2798  if (FileHandle != INVALID_HANDLE_VALUE)
2799  {
2800  /* It worked? Return a generic error */
2801  CloseHandle(FileHandle);
2802  FileHandle = NULL;
2804  }
2805  }
2806  else
2807  {
2808  /* Path was absolute, which means it doesn't exist */
2810  }
2811 
2812  /* Did we already fail once? */
2813  if (ErrorCode)
2814  {
2815  /* Set the error code */
2816  SetLastError(ErrorCode);
2817  }
2818  else
2819  {
2820  /* Not yet, cache it */
2821  ErrorCode = GetLastError();
2822  }
2823 
2824  /* Put back the command line */
2825  *NullBuffer = SaveChar;
2826  lpApplicationName = NameBuffer;
2827 
2828  /* It's possible there's whitespace in the directory name */
2829  if (!(*ScanString) || !(SearchRetry))
2830  {
2831  /* Not the case, give up completely */
2832  Result = FALSE;
2833  goto Quickie;
2834  }
2835 
2836  /* There are spaces, so keep trying the next possibility */
2837  ScanString++;
2838  NullBuffer = ScanString;
2839 
2840  /* We will have to add a quote, since there is a space */
2841  QuotesNeeded = TRUE;
2842  HasQuotes = TRUE;
2843  goto StartScan;
2844  }
2845  }
2846  else if (!(lpCommandLine) || !(*lpCommandLine))
2847  {
2848  /* We don't have a command line, so just use the application name */
2849  CmdLineIsAppName = TRUE;
2850  lpCommandLine = (LPWSTR)lpApplicationName;
2851  }
2852 
2853  /* Convert the application name to its NT path */
2854  TranslationStatus = RtlDosPathNameToRelativeNtPathName_U(lpApplicationName,
2855  &PathName,
2856  NULL,
2857  &SxsWin32RelativePath);
2858  if (!TranslationStatus)
2859  {
2860  /* Path must be invalid somehow, bail out */
2861  DPRINT1("Path translation for SxS failed\n");
2863  Result = FALSE;
2864  goto Quickie;
2865  }
2866 
2867  /* Setup the buffer that needs to be freed at the end */
2868  ASSERT(FreeBuffer == NULL);
2869  FreeBuffer = PathName.Buffer;
2870 
2871  /* Check what kind of path the application is, for SxS (Fusion) purposes */
2872  RtlInitUnicodeString(&SxsWin32ExePath, lpApplicationName);
2873  SxsPathType = RtlDetermineDosPathNameType_U(lpApplicationName);
2874  if ((SxsPathType != RtlPathTypeDriveAbsolute) &&
2875  (SxsPathType != RtlPathTypeLocalDevice) &&
2876  (SxsPathType != RtlPathTypeRootLocalDevice) &&
2877  (SxsPathType != RtlPathTypeUncAbsolute))
2878  {
2879  /* Relative-type path, get the full path */
2880  RtlInitEmptyUnicodeString(&PathBufferString, NULL, 0);
2881  Status = RtlGetFullPathName_UstrEx(&SxsWin32ExePath,
2882  NULL,
2883  &PathBufferString,
2884  NULL,
2885  NULL,
2886  NULL,
2887  &SxsPathType,
2888  NULL);
2889  if (!NT_SUCCESS(Status))
2890  {
2891  /* Fail the rest of the create */
2892  RtlReleaseRelativeName(&SxsWin32RelativePath);
2893  BaseSetLastNTError(Status);
2894  Result = FALSE;
2895  goto Quickie;
2896  }
2897 
2898  /* Use this full path as the SxS path */
2899  SxsWin32ExePath = PathBufferString;
2900  PathBuffer = PathBufferString.Buffer;
2901  PathBufferString.Buffer = NULL;
2902  DPRINT("SxS Path: %S\n", PathBuffer);
2903  }
2904 
2905  /* Also set the .EXE path based on the path name */
2906 #if _SXS_SUPPORT_ENABLED_
2907  SxsNtExePath = PathName;
2908 #endif
2909  if (SxsWin32RelativePath.RelativeName.Length)
2910  {
2911  /* If it's relative, capture the relative name */
2912  PathName = SxsWin32RelativePath.RelativeName;
2913  }
2914  else
2915  {
2916  /* Otherwise, it's absolute, make sure no relative dir is used */
2917  SxsWin32RelativePath.ContainingDirectory = NULL;
2918  }
2919 
2920  /* Now use the path name, and the root path, to try opening the app */
2921  DPRINT("Path: %wZ. Dir: %p\n", &PathName, SxsWin32RelativePath.ContainingDirectory);
2922  InitializeObjectAttributes(&LocalObjectAttributes,
2923  &PathName,
2925  SxsWin32RelativePath.ContainingDirectory,
2926  NULL);
2927  Status = NtOpenFile(&FileHandle,
2928  SYNCHRONIZE |
2930  FILE_READ_DATA |
2931  FILE_EXECUTE,
2932  &LocalObjectAttributes,
2933  &IoStatusBlock,
2937  if (!NT_SUCCESS(Status))
2938  {
2939  /* Try to open the app just for execute purposes instead */
2940  Status = NtOpenFile(&FileHandle,
2942  &LocalObjectAttributes,
2943  &IoStatusBlock,
2947  }
2948 
2949  /* Failure path, display which file failed to open */
2950  if (!NT_SUCCESS(Status))
2951  DPRINT1("Open file failed: %lx (%wZ)\n", Status, &PathName);
2952 
2953  /* Cleanup in preparation for failure or success */
2954  RtlReleaseRelativeName(&SxsWin32RelativePath);
2955 
2956  if (!NT_SUCCESS(Status))
2957  {
2958  /* Failure path, try to understand why */
2959  if (RtlIsDosDeviceName_U(lpApplicationName))
2960  {
2961  /* If a device is being executed, return this special error code */
2963  Result = FALSE;
2964  goto Quickie;
2965  }
2966  else
2967  {
2968  /* Otherwise return the converted NT error code */
2969  BaseSetLastNTError(Status);
2970  Result = FALSE;
2971  goto Quickie;
2972  }
2973  }
2974 
2975  /* Did the caller specify a desktop? */
2976  if (!StartupInfo.lpDesktop)
2977  {
2978  /* Use the one from the current process */
2979  StartupInfo.lpDesktop = Peb->ProcessParameters->DesktopInfo.Buffer;
2980  }
2981 
2982  /* Create a section for this file */
2983  Status = NtCreateSection(&SectionHandle,
2985  NULL,
2986  NULL,
2987  PAGE_EXECUTE,
2988  SEC_IMAGE,
2989  FileHandle);
2990  DPRINT("Section status: %lx\n", Status);
2991  if (NT_SUCCESS(Status))
2992  {
2993  /* Are we running on Windows Embedded, Datacenter, Blade or Starter? */
2994  if (SharedUserData->SuiteMask & (VER_SUITE_EMBEDDEDNT |
2997  VER_SUITE_BLADE))
2998  {
2999  /* These SKUs do not allow running certain applications */
3000  Status = BasepCheckWebBladeHashes(FileHandle);
3001  if (Status == STATUS_ACCESS_DENIED)
3002  {
3003  /* And this is one of them! */
3004  DPRINT1("Invalid Blade hashes!\n");
3006  Result = FALSE;
3007  goto Quickie;
3008  }
3009 
3010  /* Did we get some other failure? */
3011  if (!NT_SUCCESS(Status))
3012  {
3013  /* If we couldn't check the hashes, assume nefariousness */
3014  DPRINT1("Tampered Blade hashes!\n");
3016  Result = FALSE;
3017  goto Quickie;
3018  }
3019  }
3020 
3021  /* Now do Winsafer, etc, checks */
3022  Status = BasepIsProcessAllowed((LPWSTR)lpApplicationName);
3023  if (!NT_SUCCESS(Status))
3024  {
3025  /* Fail if we're not allowed to launch the process */
3026  DPRINT1("Process not allowed to launch: %lx\n", Status);
3027  BaseSetLastNTError(Status);
3028  if (SectionHandle)
3029  {
3030  NtClose(SectionHandle);
3031  SectionHandle = NULL;
3032  }
3033  Result = FALSE;
3034  goto Quickie;
3035  }
3036 
3037  /* Is a DOS VDM being forced, but we already have a WOW32 instance ready? */
3038  if ((dwCreationFlags & CREATE_FORCEDOS) &&
3040  {
3041  /* This request can't be satisfied, instead, a separate VDM is needed */
3042  dwCreationFlags &= ~(CREATE_FORCEDOS | CREATE_SHARED_WOW_VDM);
3043  dwCreationFlags |= CREATE_SEPARATE_WOW_VDM;
3044 
3045  /* Set a failure code, ask for VDM reservation */
3046  Status = STATUS_INVALID_IMAGE_WIN_16;
3047  UseVdmReserve = TRUE;
3048 
3049  /* Close the current handle */
3050  NtClose(SectionHandle);
3051  SectionHandle = NULL;
3052 
3053  /* Don't query the section later */
3054  QuerySection = FALSE;
3055  }
3056  }
3057 
3058  /* Did we already do these checks? */
3059  if (!SkipSaferAndAppCompat)
3060  {
3061  /* Is everything OK so far, OR do we have an non-MZ, non-DOS app? */
3062  if ((NT_SUCCESS(Status)) ||
3063  ((Status == STATUS_INVALID_IMAGE_NOT_MZ) &&
3064  !(BaseIsDosApplication(&PathName, Status))))
3065  {
3066  /* Clear the machine type in case of failure */
3067  ImageMachine = 0;
3068 
3069  /* Clean any app compat data that may have accumulated */
3070  BasepFreeAppCompatData(AppCompatData, AppCompatSxsData);
3071  AppCompatData = NULL;
3072  AppCompatSxsData = NULL;
3073 
3074  /* Do we have a section? */
3075  if (SectionHandle)
3076  {
3077  /* Have we already queried it? */
3078  if (QuerySection)
3079  {
3080  /* Nothing to do */
3081  AppCompatStatus = STATUS_SUCCESS;
3082  }
3083  else
3084  {
3085  /* Get some information about the executable */
3086  AppCompatStatus = NtQuerySection(SectionHandle,
3088  &ImageInformation,
3089  sizeof(ImageInformation),
3090  NULL);
3091  }
3092 
3093  /* Do we have section information now? */
3094  if (NT_SUCCESS(AppCompatStatus))
3095  {
3096  /* Don't ask for it again, save the machine type */
3097  QuerySection = TRUE;
3098  ImageMachine = ImageInformation.Machine;
3099  }
3100  }
3101 
3102  /* Is there a reason/Shim we shouldn't run this application? */
3103  AppCompatStatus = BasepCheckBadapp(FileHandle,
3104  FreeBuffer,
3105  lpEnvironment,
3106  ImageMachine,
3107  &AppCompatData,
3108  &AppCompatDataSize,
3109  &AppCompatSxsData,
3110  &AppCompatSxsDataSize,
3111  &FusionFlags);
3112  if (!NT_SUCCESS(AppCompatStatus))
3113  {
3114  /* This is usually the status we get back */
3115  DPRINT1("App compat launch failure: %lx\n", AppCompatStatus);
3116  if (AppCompatStatus == STATUS_ACCESS_DENIED)
3117  {
3118  /* Convert it to something more Win32-specific */
3120  }
3121  else
3122  {
3123  /* Some other error */
3124  BaseSetLastNTError(AppCompatStatus);
3125  }
3126 
3127  /* Did we have a section? */
3128  if (SectionHandle)
3129  {
3130  /* Clean it up */
3131  NtClose(SectionHandle);
3132  SectionHandle = NULL;
3133  }
3134 
3135  /* Fail the call */
3136  Result = FALSE;
3137  goto Quickie;
3138  }
3139  }
3140  }
3141 
3142  //ASSERT((dwFusionFlags & ~SXS_APPCOMPACT_FLAG_APP_RUNNING_SAFEMODE) == 0);
3143 
3144  /* Have we already done, and do we need to do, SRP (WinSafer) checks? */
3145  if (!(SkipSaferAndAppCompat) &&
3146  ~(dwCreationFlags & CREATE_PRESERVE_CODE_AUTHZ_LEVEL))
3147  {
3148  /* Assume yes */
3149  SaferNeeded = TRUE;
3150  switch (Status)
3151  {
3156  /* For all DOS, 16-bit, OS/2 images, we do*/
3157  break;
3158 
3160  /* For invalid files, we don't, unless it's a .BAT file */
3161  if (BaseIsDosApplication(&PathName, Status)) break;
3162 
3163  default:
3164  /* Any other error codes we also don't */
3165  if (!NT_SUCCESS(Status))
3166  {
3167  SaferNeeded = FALSE;
3168  }
3169 
3170  /* But for success, we do */
3171  break;
3172  }
3173 
3174  /* Okay, so what did the checks above result in? */
3175  if (SaferNeeded)
3176  {
3177  /* We have to call into the WinSafer library and actually check */
3178  SaferStatus = BasepCheckWinSaferRestrictions(hUserToken,
3179  (LPWSTR)lpApplicationName,
3180  FileHandle,
3181  &InJob,
3182  &TokenHandle,
3183  &JobHandle);
3184  if (SaferStatus == 0xFFFFFFFF)
3185  {
3186  /* Back in 2003, they didn't have an NTSTATUS for this... */
3187  DPRINT1("WinSafer blocking process launch\n");
3189  Result = FALSE;
3190  goto Quickie;
3191  }
3192 
3193  /* Other status codes are not-Safer related, just convert them */
3194  if (!NT_SUCCESS(SaferStatus))
3195  {
3196  DPRINT1("Error checking WinSafer: %lx\n", SaferStatus);
3197  BaseSetLastNTError(SaferStatus);
3198  Result = FALSE;
3199  goto Quickie;
3200  }
3201  }
3202  }
3203 
3204  /* The last step is to figure out why the section object was not created */
3205  switch (Status)
3206  {
3208  {
3209  /* 16-bit binary. Should we use WOW or does the caller force VDM? */
3210  if (!(dwCreationFlags & CREATE_FORCEDOS))
3211  {
3212  /* Remember that we're launching WOW */
3213  IsWowApp = TRUE;
3214 
3215  /* Create the VDM environment, it's valid for WOW too */
3216  Result = BaseCreateVDMEnvironment(lpEnvironment,
3217  &VdmAnsiEnv,
3218  &VdmUnicodeEnv);
3219  if (!Result)
3220  {
3221  DPRINT1("VDM environment for WOW app failed\n");
3222  goto Quickie;
3223  }
3224 
3225  /* We're going to try this twice, so do a loop */
3226  while (TRUE)
3227  {
3228  /* Pick which kind of WOW mode we want to run in */
3229  VdmBinaryType = (dwCreationFlags &
3232 
3233  /* Get all the VDM settings and current status */
3234  Status = BaseCheckVDM(VdmBinaryType,
3235  lpApplicationName,
3236  lpCommandLine,
3237  lpCurrentDirectory,
3238  &VdmAnsiEnv,
3239  &CsrMsg[1],
3240  &VdmTask,
3241  dwCreationFlags,
3242  &StartupInfo,
3243  hUserToken);
3244 
3245  /* If it worked, no need to try again */
3246  if (NT_SUCCESS(Status)) break;
3247 
3248  /* Check if it's disallowed or if it's our second time */
3249  BaseSetLastNTError(Status);
3250  if ((Status == STATUS_VDM_DISALLOWED) ||
3251  (VdmBinaryType == BINARY_TYPE_SEPARATE_WOW) ||
3253  {
3254  /* Fail the call -- we won't try again */
3255  DPRINT1("VDM message failure for WOW: %lx\n", Status);
3256  Result = FALSE;
3257  goto Quickie;
3258  }
3259 
3260  /* Try one more time, but with a separate WOW instance */
3261  dwCreationFlags |= CREATE_SEPARATE_WOW_VDM;
3262  }
3263 
3264  /* Check which VDM state we're currently in */
3265  switch (CheckVdmMsg->VDMState & (VDM_NOT_LOADED |
3266  VDM_NOT_READY |
3267  VDM_READY))
3268  {
3269  case VDM_NOT_LOADED:
3270  /* VDM is not fully loaded, so not that much to undo */
3271  VdmUndoLevel = VDM_UNDO_PARTIAL;
3272 
3273  /* Reset VDM reserve if needed */
3274  if (UseVdmReserve) VdmReserve = 1;
3275 
3276  /* Get the required parameters and names for launch */
3277  Result = BaseGetVdmConfigInfo(lpCommandLine,
3278  VdmTask,
3279  VdmBinaryType,
3280  &VdmString,
3281  &VdmReserve);
3282  if (!Result)
3283  {
3284  DPRINT1("VDM Configuration failed for WOW\n");
3285  BaseSetLastNTError(Status);
3286  goto Quickie;
3287  }
3288 
3289  /* Update the command-line with the VDM one instead */
3290  lpCommandLine = VdmString.Buffer;
3291  lpApplicationName = NULL;
3292 
3293  /* We don't want a console, detachment, nor a window */
3294  dwCreationFlags |= CREATE_NO_WINDOW;
3295  dwCreationFlags &= ~(CREATE_NEW_CONSOLE | DETACHED_PROCESS);
3296 
3297  /* Force feedback on */
3298  StartupInfo.dwFlags |= STARTF_FORCEONFEEDBACK;
3299  break;
3300 
3301 
3302  case VDM_READY:
3303  /* VDM is ready, so we have to undo everything */
3304  VdmUndoLevel = VDM_UNDO_REUSE;
3305 
3306  /* Check if CSRSS wants us to wait on VDM */
3307  VdmWaitObject = CheckVdmMsg->WaitObjectForParent;
3308  break;
3309 
3310  case VDM_NOT_READY:
3311  /* Something is wrong with VDM, we'll fail the call */
3312  DPRINT1("VDM is not ready for WOW\n");
3314  Result = FALSE;
3315  goto Quickie;
3316 
3317  default:
3318  break;
3319  }
3320 
3321  /* Since to get NULL, we allocate from 0x1, account for this */
3322  VdmReserve--;
3323 
3324  /* This implies VDM is ready, so skip everything else */
3325  if (VdmWaitObject) goto VdmShortCircuit;
3326 
3327  /* Don't inherit handles since we're doing VDM now */
3328  bInheritHandles = FALSE;
3329 
3330  /* Had the user passed in environment? If so, destroy it */
3331  if ((lpEnvironment) &&
3332  !(dwCreationFlags & CREATE_UNICODE_ENVIRONMENT))
3333  {
3334  RtlDestroyEnvironment(lpEnvironment);
3335  }
3336 
3337  /* We've already done all these checks, don't do them again */
3338  SkipSaferAndAppCompat = TRUE;
3339  goto AppNameRetry;
3340  }
3341 
3342  // There is no break here on purpose, so FORCEDOS drops down!
3343  }
3344 
3348  {
3349  /* We're launching an executable application */
3350  BinarySubType = BINARY_TYPE_EXE;
3351 
3352  /* We can drop here from other "cases" above too, so check */
3353  if ((Status == STATUS_INVALID_IMAGE_PROTECT) ||
3354  (Status == STATUS_INVALID_IMAGE_NE_FORMAT) ||
3355  (BinarySubType = BaseIsDosApplication(&PathName, Status)))
3356  {
3357  /* We're launching a DOS application */
3358  VdmBinaryType = BINARY_TYPE_DOS;
3359 
3360  /* Based on the caller environment, create a VDM one */
3361  Result = BaseCreateVDMEnvironment(lpEnvironment,
3362  &VdmAnsiEnv,
3363  &VdmUnicodeEnv);
3364  if (!Result)
3365  {
3366  DPRINT1("VDM environment for DOS failed\n");
3367  goto Quickie;
3368  }
3369 
3370  /* Check the current state of the VDM subsystem */
3371  Status = BaseCheckVDM(VdmBinaryType | BinarySubType,
3372  lpApplicationName,
3373  lpCommandLine,
3374  lpCurrentDirectory,
3375  &VdmAnsiEnv,
3376  &CsrMsg[1],
3377  &VdmTask,
3378  dwCreationFlags,
3379  &StartupInfo,
3380  NULL);
3381  if (!NT_SUCCESS(Status))
3382  {
3383  /* Failed to inquire about VDM, fail the call */
3384  DPRINT1("VDM message failure for DOS: %lx\n", Status);
3385  BaseSetLastNTError(Status);
3386  Result = FALSE;
3387  goto Quickie;
3388  };
3389 
3390  /* Handle possible VDM states */
3391  switch (CheckVdmMsg->VDMState & (VDM_NOT_LOADED |
3392  VDM_NOT_READY |
3393  VDM_READY))
3394  {
3395  case VDM_NOT_LOADED:
3396  /* If VDM is not loaded, we'll do a partial undo */
3397  VdmUndoLevel = VDM_UNDO_PARTIAL;
3398 
3399  /* A VDM process can't also be detached, so fail */
3400  if (dwCreationFlags & DETACHED_PROCESS)
3401  {
3402  DPRINT1("Detached process but no VDM, not allowed\n");
3404  return FALSE;
3405  }
3406 
3407  /* Get the required parameters and names for launch */
3408  Result = BaseGetVdmConfigInfo(lpCommandLine,
3409  VdmTask,
3410  VdmBinaryType,
3411  &VdmString,
3412  &VdmReserve);
3413  if (!Result)
3414  {
3415  DPRINT1("VDM Configuration failed for DOS\n");
3416  BaseSetLastNTError(Status);
3417  goto Quickie;
3418  }
3419 
3420  /* Update the command-line to launch VDM instead */
3421  lpCommandLine = VdmString.Buffer;
3422  lpApplicationName = NULL;
3423  break;
3424 
3425  case VDM_READY:
3426  /* VDM is ready, so we have to undo everything */
3427  VdmUndoLevel = VDM_UNDO_REUSE;
3428 
3429  /* Check if CSRSS wants us to wait on VDM */
3430  VdmWaitObject = CheckVdmMsg->WaitObjectForParent;
3431  break;
3432 
3433  case VDM_NOT_READY:
3434  /* Something is wrong with VDM, we'll fail the call */
3435  DPRINT1("VDM is not ready for DOS\n");
3437  Result = FALSE;
3438  goto Quickie;
3439 
3440  default:
3441  break;
3442  }
3443 
3444  /* Since to get NULL, we allocate from 0x1, account for this */
3445  VdmReserve--;
3446 
3447  /* This implies VDM is ready, so skip everything else */
3448  if (VdmWaitObject) goto VdmShortCircuit;
3449 
3450  /* Don't inherit handles since we're doing VDM now */
3451  bInheritHandles = FALSE;
3452 
3453  /* Had the user passed in environment? If so, destroy it */
3454  if ((lpEnvironment) &&
3455  !(dwCreationFlags & CREATE_UNICODE_ENVIRONMENT))
3456  {
3457  RtlDestroyEnvironment(lpEnvironment);
3458  }
3459 
3460  /* Use our VDM Unicode environment instead */
3461  lpEnvironment = VdmUnicodeEnv.Buffer;
3462  }
3463  else
3464  {
3465  /* It's a batch file, get the extension */
3466  ExtBuffer = &PathName.Buffer[PathName.Length / sizeof(WCHAR) - 4];
3467 
3468  /* Make sure the extensions are correct */
3469  if ((PathName.Length < (4 * sizeof(WCHAR))) ||
3470  ((_wcsnicmp(ExtBuffer, L".bat", 4)) &&
3471  (_wcsnicmp(ExtBuffer, L".cmd", 4))))
3472  {
3473  DPRINT1("'%wZ': Invalid EXE, and not a batch or script file\n", &PathName);
3475  Result = FALSE;
3476  goto Quickie;
3477  }
3478 
3479  /* Check if we need to account for quotes around the path */
3480  CmdQuoteLength = CmdLineIsAppName || HasQuotes;
3481  if (!CmdLineIsAppName)
3482  {
3483  if (HasQuotes) CmdQuoteLength++;
3484  }
3485  else
3486  {
3487  CmdQuoteLength++;
3488  }
3489 
3490  /* Calculate the length of the command line */
3491  CmdLineLength = wcslen(lpCommandLine);
3492  CmdLineLength += wcslen(CMD_STRING);
3493  CmdLineLength += CmdQuoteLength + sizeof(ANSI_NULL);
3494  CmdLineLength *= sizeof(WCHAR);
3495 
3496  /* Allocate space for the new command line */
3497  AnsiCmdCommand = RtlAllocateHeap(RtlGetProcessHeap(),
3498  0,
3499  CmdLineLength);
3500  if (!AnsiCmdCommand)
3501  {
3503  Result = FALSE;
3504  goto Quickie;
3505  }
3506 
3507  /* Build it */
3508  wcscpy(AnsiCmdCommand, CMD_STRING);
3509  if ((CmdLineIsAppName) || (HasQuotes))
3510  {
3511  wcscat(AnsiCmdCommand, L"\"");
3512  }
3513  wcscat(AnsiCmdCommand, lpCommandLine);
3514  if ((CmdLineIsAppName) || (HasQuotes))
3515  {
3516  wcscat(AnsiCmdCommand, L"\"");
3517  }
3518 
3519  /* Create it as a Unicode String */
3520  RtlInitUnicodeString(&DebuggerString, AnsiCmdCommand);
3521 
3522  /* Set the command line to this */
3523  lpCommandLine = DebuggerString.Buffer;
3524  lpApplicationName = NULL;
3525  DPRINT1("Retrying with: %S\n", lpCommandLine);
3526  }
3527 
3528  /* We've already done all these checks, don't do them again */
3529  SkipSaferAndAppCompat = TRUE;
3530  goto AppNameRetry;
3531  }
3532 
3534  {
3535  /* 64-bit binaries are not allowed to run on 32-bit ReactOS */
3536  DPRINT1("64-bit binary, failing\n");
3538  Result = FALSE;
3539  goto Quickie;
3540  }
3541 
3543  {
3544  /* Set the correct last error for this */
3545  DPRINT1("File is offline, failing\n");
3547  break;
3548  }
3549 
3550  default:
3551  {
3552  /* Any other error, convert it to a generic Win32 error */
3553  if (!NT_SUCCESS(Status))
3554  {
3555  DPRINT1("Failed to create section: %lx\n", Status);
3557  Result = FALSE;
3558  goto Quickie;
3559  }
3560 
3561  /* Otherwise, this must be success */
3562  ASSERT(Status == STATUS_SUCCESS);
3563  break;
3564  }
3565  }
3566 
3567  /* Is this not a WOW application, but a WOW32 VDM was requested for it? */
3568  if (!(IsWowApp) && (dwCreationFlags & CREATE_SEPARATE_WOW_VDM))
3569  {
3570  /* Ignore the nonsensical request */
3571  dwCreationFlags &= ~CREATE_SEPARATE_WOW_VDM;
3572  }
3573 
3574  /* Did we already check information for the section? */
3575  if (!QuerySection)
3576  {
3577  /* Get some information about the executable */
3578  Status = NtQuerySection(SectionHandle,
3580  &ImageInformation,
3581  sizeof(ImageInformation),
3582  NULL);
3583  if (!NT_SUCCESS(Status))
3584  {
3585  /* We failed, bail out */
3586  DPRINT1("Section query failed\n");
3587  BaseSetLastNTError(Status);
3588  Result = FALSE;
3589  goto Quickie;
3590  }
3591 
3592  /* Don't check this later */
3593  QuerySection = TRUE;
3594  }
3595 
3596  /* Check if this was linked as a DLL */
3597  if (ImageInformation.ImageCharacteristics & IMAGE_FILE_DLL)
3598  {
3599  /* These aren't valid images to try to execute! */
3600  DPRINT1("Trying to launch a DLL, failing\n");
3602  Result = FALSE;
3603  goto Quickie;
3604  }
3605 
3606  /* Don't let callers pass in this flag -- we'll only get it from IFEO */
3608 
3609  /* Clear the IFEO-missing flag, before we know for sure... */
3610  ParameterFlags &= ~2;
3611 
3612  /* If the process is being debugged, only read IFEO if the PEB says so */
3613  if (!(dwCreationFlags & (DEBUG_PROCESS | DEBUG_ONLY_THIS_PROCESS)) ||
3614  (NtCurrentPeb()->ReadImageFileExecOptions))
3615  {
3616  /* Let's do this! Attempt to open IFEO */
3617  IFEOStatus = LdrOpenImageFileOptionsKey(&PathName, 0, &KeyHandle);
3618  if (!NT_SUCCESS(IFEOStatus))
3619  {
3620  /* We failed, set the flag so we store this in the parameters */
3621  if (IFEOStatus == STATUS_OBJECT_NAME_NOT_FOUND) ParameterFlags |= 2;
3622  }
3623  else
3624  {
3625  /* Was this our first time going through this path? */
3626  if (!DebuggerCmdLine)
3627  {
3628  /* Allocate a buffer for the debugger path */
3629  DebuggerCmdLine = RtlAllocateHeap(RtlGetProcessHeap(),
3630  0,
3631  MAX_PATH * sizeof(WCHAR));
3632  if (!DebuggerCmdLine)
3633  {
3634  /* Close IFEO on failure */
3635  IFEOStatus = NtClose(KeyHandle);
3636  ASSERT(NT_SUCCESS(IFEOStatus));
3637 
3638  /* Fail the call */
3640  Result = FALSE;
3641  goto Quickie;
3642  }
3643  }
3644 
3645  /* Now query for the debugger */
3646  IFEOStatus = LdrQueryImageFileKeyOption(KeyHandle,
3647  L"Debugger",
3648  REG_SZ,
3649  DebuggerCmdLine,
3650  MAX_PATH * sizeof(WCHAR),
3651  &ResultSize);
3652  if (!(NT_SUCCESS(IFEOStatus)) ||
3653  (ResultSize < sizeof(WCHAR)) ||
3654  (DebuggerCmdLine[0] == UNICODE_NULL))
3655  {
3656  /* If it's not there, or too small, or invalid, ignore it */
3657  RtlFreeHeap(RtlGetProcessHeap(), 0, DebuggerCmdLine);
3658  DebuggerCmdLine = NULL;
3659  }
3660 
3661  /* Also query if we should map with large pages */
3662  IFEOStatus = LdrQueryImageFileKeyOption(KeyHandle,
3663  L"UseLargePages",
3664  REG_DWORD,
3665  &UseLargePages,
3666  sizeof(UseLargePages),
3667  NULL);
3668  if ((NT_SUCCESS(IFEOStatus)) && (UseLargePages))
3669  {
3670  /* Do it! This is the only way this flag can be set */
3672  }
3673 
3674  /* We're done with IFEO, can close it now */
3675  IFEOStatus = NtClose(KeyHandle);
3676  ASSERT(NT_SUCCESS(IFEOStatus));
3677  }
3678  }
3679 
3680  /* Make sure the image was compiled for this processor */
3681  if ((ImageInformation.Machine < SharedUserData->ImageNumberLow) ||
3682  (ImageInformation.Machine > SharedUserData->ImageNumberHigh))
3683  {
3684  /* It was not -- raise a hard error */
3685  ErrorResponse = ResponseOk;
3686  ErrorParameters[0] = (ULONG_PTR)&PathName;
3688  1,
3689  1,
3690  ErrorParameters,
3691  OptionOk,
3692  &ErrorResponse);
3693  if (Peb->ImageSubsystemMajorVersion <= 3)
3694  {
3695  /* If it's really old, return this error */
3697  }
3698  else
3699  {
3700  /* Otherwise, return a more modern error */
3702  }
3703 
3704  /* Go to the failure path */
3705  DPRINT1("Invalid image architecture: %lx\n", ImageInformation.Machine);
3706  Result = FALSE;
3707  goto Quickie;
3708  }
3709 
3710  /* Check if this isn't a Windows image */
3711  if ((ImageInformation.SubSystemType != IMAGE_SUBSYSTEM_WINDOWS_GUI) &&
3712  (ImageInformation.SubSystemType != IMAGE_SUBSYSTEM_WINDOWS_CUI))
3713  {
3714  /* Get rid of section-related information since we'll retry */
3715  NtClose(SectionHandle);
3716  SectionHandle = NULL;
3717  QuerySection = FALSE;
3718 
3719  /* The only other non-Windows image type we support here is POSIX */
3720  if (ImageInformation.SubSystemType != IMAGE_SUBSYSTEM_POSIX_CUI)
3721  {
3722  /* Bail out if it's something else */
3724  Result = FALSE;
3725  goto Quickie;
3726  }
3727 
3728  /* Now build the command-line to have posix launch this image */
3729  Result = BuildSubSysCommandLine(L"POSIX /P ",
3730  lpApplicationName,
3731  lpCommandLine,
3732  &DebuggerString);
3733  if (!Result)
3734  {
3735  /* Bail out if that failed */
3736  DPRINT1("Subsystem command line failed\n");
3737  goto Quickie;
3738  }
3739 
3740  /* And re-try launching the process, with the new command-line now */
3741  lpCommandLine = DebuggerString.Buffer;
3742  lpApplicationName = NULL;
3743 
3744  /* We've already done all these checks, don't do them again */
3745  SkipSaferAndAppCompat = TRUE;
3746  DPRINT1("Retrying with: %S\n", lpCommandLine);
3747  goto AppNameRetry;
3748  }
3749 
3750  /* Was this image built for a version of Windows whose images we can run? */
3751  Result = BasepIsImageVersionOk(ImageInformation.SubSystemMajorVersion,
3752  ImageInformation.SubSystemMinorVersion);
3753  if (!Result)
3754  {
3755  /* It was not, bail out */
3756  DPRINT1("Invalid subsystem version: %hu.%hu\n",
3757  ImageInformation.SubSystemMajorVersion,
3758  ImageInformation.SubSystemMinorVersion);
3760  goto Quickie;
3761  }
3762 
3763  /* Check if there is a debugger associated with the application */
3764  if (DebuggerCmdLine)
3765  {
3766  /* Get the length of the command line */
3767  n = wcslen(lpCommandLine);
3768  if (!n)
3769  {
3770  /* There's no command line, use the application name instead */
3771  lpCommandLine = (LPWSTR)lpApplicationName;
3772  n = wcslen(lpCommandLine);
3773  }
3774 
3775  /* Protect against overflow */
3776  if (n > UNICODE_STRING_MAX_CHARS)
3777  {
3779  Result = FALSE;
3780  goto Quickie;
3781  }
3782 
3783  /* Now add the length of the debugger command-line */
3784  n += wcslen(DebuggerCmdLine);
3785 
3786  /* Again make sure we don't overflow */
3787  if (n > UNICODE_STRING_MAX_CHARS)
3788  {
3790  Result = FALSE;
3791  goto Quickie;
3792  }
3793 
3794  /* Account for the quotes and space between the two */
3795  n += sizeof("\" \"") - sizeof(ANSI_NULL);
3796 
3797  /* Convert to bytes, and make sure we don't overflow */
3798  n *= sizeof(WCHAR);
3799  if (n > UNICODE_STRING_MAX_BYTES)
3800  {
3802  Result = FALSE;
3803  goto Quickie;
3804  }
3805 
3806  /* Allocate space for the string */
3807  DebuggerString.Buffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, n);
3808  if (!DebuggerString.Buffer)
3809  {
3811  Result = FALSE;
3812  goto Quickie;
3813  }
3814 
3815  /* Set the length */
3816  RtlInitEmptyUnicodeString(&DebuggerString,
3817  DebuggerString.Buffer,
3818  (USHORT)n);
3819 
3820  /* Now perform the command line creation */
3821  ImageDbgStatus = RtlAppendUnicodeToString(&DebuggerString,
3822  DebuggerCmdLine);
3823  ASSERT(NT_SUCCESS(ImageDbgStatus));
3824  ImageDbgStatus = RtlAppendUnicodeToString(&DebuggerString, L" ");
3825  ASSERT(NT_SUCCESS(ImageDbgStatus));
3826  ImageDbgStatus = RtlAppendUnicodeToString(&DebuggerString, lpCommandLine);
3827  ASSERT(NT_SUCCESS(ImageDbgStatus));
3828 
3829  /* Make sure it all looks nice */
3830  DbgPrint("BASE: Calling debugger with '%wZ'\n", &DebuggerString);
3831 
3832  /* Update the command line and application name */
3833  lpCommandLine = DebuggerString.Buffer;
3834  lpApplicationName = NULL;
3835 
3836  /* Close all temporary state */
3837  NtClose(SectionHandle);
3838  SectionHandle = NULL;
3839  QuerySection = FALSE;
3840 
3841  /* Free all temporary memory */
3842  RtlFreeHeap(RtlGetProcessHeap(), 0, NameBuffer);
3843  NameBuffer = NULL;
3844  RtlFreeHeap(RtlGetProcessHeap(), 0, FreeBuffer);
3845  FreeBuffer = NULL;
3846  RtlFreeHeap(RtlGetProcessHeap(), 0, DebuggerCmdLine);
3847  DebuggerCmdLine = NULL;
3848  DPRINT1("Retrying with: %S\n", lpCommandLine);
3849  goto AppNameRetry;
3850  }
3851 
3852  /* Initialize the process object attributes */
3853  ObjectAttributes = BaseFormatObjectAttributes(&LocalObjectAttributes,
3854  lpProcessAttributes,
3855  NULL);
3856  if ((hUserToken) && (lpProcessAttributes))
3857  {
3858  /* Augment them with information from the user */
3859 
3860  LocalProcessAttributes = *lpProcessAttributes;
3861  LocalProcessAttributes.lpSecurityDescriptor = NULL;
3862  ObjectAttributes = BaseFormatObjectAttributes(&LocalObjectAttributes,
3863  &LocalProcessAttributes,
3864  NULL);
3865  }
3866 
3867  /* Check if we're going to be debugged */
3868  if (dwCreationFlags & DEBUG_PROCESS)
3869  {
3870  /* Set process flag */
3872  }
3873 
3874  /* Check if we're going to be debugged */
3875  if (dwCreationFlags & (DEBUG_PROCESS | DEBUG_ONLY_THIS_PROCESS))
3876  {
3877  /* Connect to DbgUi */
3878  Status = DbgUiConnectToDbg();
3879  if (!NT_SUCCESS(Status))
3880  {
3881  DPRINT1("Failed to connect to DbgUI!\n");
3882  BaseSetLastNTError(Status);
3883  Result = FALSE;
3884  goto Quickie;
3885  }
3886 
3887  /* Get the debug object */
3888  DebugHandle = DbgUiGetThreadDebugObject();
3889 
3890  /* Check if only this process will be debugged */
3891  if (dwCreationFlags & DEBUG_ONLY_THIS_PROCESS)
3892  {
3893  /* Set process flag */
3895  }
3896  }
3897 
3898  /* Set inherit flag */
3899  if (bInheritHandles) Flags |= PROCESS_CREATE_FLAGS_INHERIT_HANDLES;
3900 
3901  /* Check if the process should be created with large pages */
3902  HavePrivilege = FALSE;
3903  PrivilegeState = NULL;
3905  {
3906  /* Acquire the required privilege so that the kernel won't fail the call */
3907  PrivilegeValue = SE_LOCK_MEMORY_PRIVILEGE;
3908  Status = RtlAcquirePrivilege(&PrivilegeValue, 1, 0, &PrivilegeState);
3909  if (NT_SUCCESS(Status))
3910  {
3911  /* Remember to release it later */
3912  HavePrivilege = TRUE;
3913  }
3914  }
3915 
3916  /* Save the current TIB value since kernel overwrites it to store PEB */
3917  TibValue = Teb->NtTib.ArbitraryUserPointer;
3918 
3919  /* Tell the kernel to create the process */
3920  Status = NtCreateProcessEx(&ProcessHandle,
3922  ObjectAttributes,
3923  NtCurrentProcess(),
3924  Flags,
3925  SectionHandle,
3926  DebugHandle,
3927  NULL,
3928  InJob);
3929 
3930  /* Load the PEB address from the hacky location where the kernel stores it */
3931  RemotePeb = Teb->NtTib.ArbitraryUserPointer;
3932 
3933  /* And restore the old TIB value */
3934  Teb->NtTib.ArbitraryUserPointer = TibValue;
3935 
3936  /* Release the large page privilege if we had acquired it */
3937  if (HavePrivilege) RtlReleasePrivilege(PrivilegeState);
3938 
3939  /* And now check if the kernel failed to create the process */
3940  if (!NT_SUCCESS(Status))
3941  {
3942  /* Go to failure path */
3943  DPRINT1("Failed to create process: %lx\n", Status);
3944  BaseSetLastNTError(Status);
3945  Result = FALSE;
3946  goto Quickie;
3947  }
3948 
3949  /* Check if there is a priority class to set */
3950  if (PriorityClass.PriorityClass)
3951  {
3952  /* Reset current privilege state */
3953  RealTimePrivilegeState = NULL;
3954 
3955  /* Is realtime priority being requested? */
3956  if (PriorityClass.PriorityClass == PROCESS_PRIORITY_CLASS_REALTIME)
3957  {
3958  /* Check if the caller has real-time access, and enable it if so */
3959  RealTimePrivilegeState = BasepIsRealtimeAllowed(TRUE);
3960  }
3961 
3962  /* Set the new priority class and release the privilege */
3963  Status = NtSetInformationProcess(ProcessHandle,
3965  &PriorityClass,
3966  sizeof(PROCESS_PRIORITY_CLASS));
3967  if (RealTimePrivilegeState) RtlReleasePrivilege(RealTimePrivilegeState);
3968 
3969  /* Check if we failed to set the priority class */
3970  if (!NT_SUCCESS(Status))
3971  {
3972  /* Bail out on failure */
3973  DPRINT1("Failed to set priority class: %lx\n", Status);
3974  BaseSetLastNTError(Status);
3975  Result = FALSE;
3976  goto Quickie;
3977  }
3978  }
3979 
3980  /* Check if the caller wants the default error mode */
3981  if (dwCreationFlags & CREATE_DEFAULT_ERROR_MODE)
3982  {
3983  /* Set Error Mode to only fail on critical errors */
3984  HardErrorMode = SEM_FAILCRITICALERRORS;
3985  NtSetInformationProcess(ProcessHandle,
3987  &HardErrorMode,
3988  sizeof(ULONG));
3989  }
3990 
3991  /* Check if this was a VDM binary */
3992  if (VdmBinaryType)
3993  {
3994  /* Update VDM by telling it the process has now been created */
3995  VdmWaitObject = ProcessHandle;
3997  &VdmWaitObject,
3998  VdmTask,
3999  VdmBinaryType);
4000 
4001  if (!Result)
4002  {
4003  /* Bail out on failure */
4004  DPRINT1("Failed to update VDM with wait object\n");
4005  VdmWaitObject = NULL;
4006  goto Quickie;
4007  }
4008 
4009  /* At this point, a failure means VDM has to undo all the state */
4010  VdmUndoLevel |= VDM_UNDO_FULL;
4011  }
4012 
4013  /* Check if VDM needed reserved low-memory */
4014  if (VdmReserve)
4015  {
4016  /* Reserve the requested allocation */
4017  RegionSize = VdmReserve;
4018  Status = NtAllocateVirtualMemory(ProcessHandle,
4019  &BaseAddress,
4020  0,
4021  &RegionSize,
4022  MEM_RESERVE,
4024  if (!NT_SUCCESS(Status))
4025  {
4026  /* Bail out on failure */
4027  DPRINT1("Failed to reserve memory for VDM: %lx\n", Status);
4028  BaseSetLastNTError(Status);
4029  Result = FALSE;
4030  goto Quickie;
4031  }
4032 
4033  VdmReserve = (ULONG)RegionSize;
4034  }
4035 
4036  /* Check if we've already queried information on the section */
4037  if (!QuerySection)
4038  {
4039  /* We haven't, so get some information about the executable */
4040  Status = NtQuerySection(SectionHandle,
4042  &ImageInformation,
4043  sizeof(ImageInformation),
4044  NULL);
4045  if (!NT_SUCCESS(Status))
4046  {
4047  /* Bail out on failure */
4048  DPRINT1("Failed to query section: %lx\n", Status);
4049  BaseSetLastNTError(Status);
4050  Result = FALSE;
4051  goto Quickie;
4052  }
4053 
4054  /* If we encounter a restart, don't re-query this information again */
4055  QuerySection = TRUE;
4056  }
4057 
4058  /* Do we need to apply SxS to this image? */
4060  {
4061  /* Too bad, we don't support this yet */
4062  DPRINT1("Image should receive SxS Fusion Isolation\n");
4063  }
4064 
4065  /* There's some SxS flag that we need to set if fusion flags have 1 set */
4066  if (FusionFlags & 1) CreateProcessMsg->Sxs.Flags |= 0x10;
4067 
4068  /* Check if we have a current directory */
4069  if (lpCurrentDirectory)
4070  {
4071  /* Allocate a buffer so we can keep a Unicode copy */
4072  DPRINT("Current directory: %S\n", lpCurrentDirectory);
4073  CurrentDirectory = RtlAllocateHeap(RtlGetProcessHeap(),
4074  0,
4075  (MAX_PATH * sizeof(WCHAR)) +
4076  sizeof(UNICODE_NULL));
4077  if (!CurrentDirectory)
4078  {
4079  /* Bail out if this failed */
4081  Result = FALSE;
4082  goto Quickie;
4083  }
4084 
4085  /* Get the length in Unicode */
4086  Length = GetFullPathNameW(lpCurrentDirectory,
4087  MAX_PATH,
4088  CurrentDirectory,
4089  &FilePart);
4090  if (Length > MAX_PATH)
4091  {
4092  /* The directory is too long, so bail out */
4094  Result = FALSE;
4095  goto Quickie;
4096  }
4097 
4098  /* Make sure the directory is actually valid */
4099  FileAttribs = GetFileAttributesW(CurrentDirectory);
4100  if ((FileAttribs == INVALID_FILE_ATTRIBUTES) ||
4101  !(FileAttribs & FILE_ATTRIBUTE_DIRECTORY))
4102  {
4103  /* It isn't, so bail out */
4104  DPRINT1("Current directory is invalid\n");
4106  Result = FALSE;
4107  goto Quickie;
4108  }
4109  }
4110 
4111  /* Insert quotes if needed */
4112  if ((QuotesNeeded) || (CmdLineIsAppName))
4113  {
4114  /* Allocate our buffer, plus enough space for quotes and a NULL */
4115  QuotedCmdLine = RtlAllocateHeap(RtlGetProcessHeap(),
4116  0,
4117  (wcslen(lpCommandLine) * sizeof(WCHAR)) +
4118  (2 * sizeof(L'\"') + sizeof(UNICODE_NULL)));
4119  if (QuotedCmdLine)
4120  {
4121  /* Copy the first quote */
4122  wcscpy(QuotedCmdLine, L"\"");
4123 
4124  /* Save the current null-character */
4125  if (QuotesNeeded)
4126  {
4127  SaveChar = *NullBuffer;
4128  *NullBuffer = UNICODE_NULL;
4129  }
4130 
4131  /* Copy the command line and the final quote */
4132  wcscat(QuotedCmdLine, lpCommandLine);
4133  wcscat(QuotedCmdLine, L"\"");
4134 
4135  /* Copy the null-char back */
4136  if (QuotesNeeded)
4137  {
4138  *NullBuffer = SaveChar;
4139  wcscat(QuotedCmdLine, NullBuffer);
4140  }
4141  }
4142  else
4143  {
4144  /* We can't put quotes around the thing, so try it anyway */
4145  if (QuotesNeeded) QuotesNeeded = FALSE;
4146  if (CmdLineIsAppName) CmdLineIsAppName = FALSE;
4147  }
4148  }
4149 
4150  /* Use isolation if needed */
4151  if (CreateProcessMsg->Sxs.Flags & 1) ParameterFlags |= 1;
4152 
4153  /* Set the new command-line if needed */
4154  if ((QuotesNeeded) || (CmdLineIsAppName)) lpCommandLine = QuotedCmdLine;
4155 
4156  /* Call the helper function in charge of RTL_USER_PROCESS_PARAMETERS */
4157  Result = BasePushProcessParameters(ParameterFlags,
4158  ProcessHandle,
4159  RemotePeb,
4160  lpApplicationName,
4161  CurrentDirectory,
4162  lpCommandLine,
4163  lpEnvironment,
4164  &StartupInfo,
4165  dwCreationFlags | NoWindow,
4166  bInheritHandles,
4167  IsWowApp ? IMAGE_SUBSYSTEM_WINDOWS_GUI: 0,
4168  AppCompatData,
4169  AppCompatDataSize);
4170  if (!Result)
4171  {
4172  /* The remote process would have an undefined state, so fail the call */
4173  DPRINT1("BasePushProcessParameters failed\n");
4174  goto Quickie;
4175  }
4176 
4177  /* Free the VDM command line string as it's no longer needed */
4178  RtlFreeUnicodeString(&VdmString);
4179  VdmString.Buffer = NULL;
4180 
4181  /* Non-VDM console applications usually inherit handles unless specified */
4182  if (!(VdmBinaryType) &&
4183  !(bInheritHandles) &&
4184  !(StartupInfo.dwFlags & STARTF_USESTDHANDLES) &&
4185  !(dwCreationFlags & (CREATE_NO_WINDOW |
4187  DETACHED_PROCESS)) &&
4188  (ImageInformation.SubSystemType == IMAGE_SUBSYSTEM_WINDOWS_CUI))
4189  {
4190  /* Get the remote parameters */
4191  Status = NtReadVirtualMemory(ProcessHandle,
4192  &RemotePeb->ProcessParameters,
4193  &ProcessParameters,
4195  NULL);
4196  if (NT_SUCCESS(Status))
4197  {
4198  /* Duplicate standard input unless it's a console handle */
4200  {
4201  StuffStdHandle(ProcessHandle,
4203  &ProcessParameters->StandardInput);
4204  }
4205 
4206  /* Duplicate standard output unless it's a console handle */
4208  {
4209  StuffStdHandle(ProcessHandle,
4211  &ProcessParameters->StandardOutput);
4212  }
4213 
4214  /* Duplicate standard error unless it's a console handle */
4216  {
4217  StuffStdHandle(ProcessHandle,
4219  &ProcessParameters->StandardError);
4220  }
4221  }
4222  }
4223 
4224  /* Create the Thread's Stack */
4225  StackSize = max(256 * 1024, ImageInformation.MaximumStackSize);
4226  Status = BaseCreateStack(ProcessHandle,
4227  ImageInformation.CommittedStackSize,
4228  StackSize,
4229  &InitialTeb);
4230  if (!NT_SUCCESS(Status))
4231  {
4232  DPRINT1("Creating the thread stack failed: %lx\n", Status);
4233  BaseSetLastNTError(Status);
4234  Result = FALSE;
4235  goto Quickie;
4236  }
4237 
4238  /* Create the Thread's Context */
4239  BaseInitializeContext(&Context,
4240  Peb,
4241  ImageInformation.TransferAddress,
4242  InitialTeb.StackBase,
4243  0);
4244 
4245  /* Convert the thread attributes */
4246  ObjectAttributes = BaseFormatObjectAttributes(&LocalObjectAttributes,
4247  lpThreadAttributes,
4248  NULL);
4249  if ((hUserToken) && (lpThreadAttributes))
4250  {
4251  /* If the caller specified a user token, zero the security descriptor */
4252  LocalThreadAttributes = *lpThreadAttributes;
4253  LocalThreadAttributes.lpSecurityDescriptor = NULL;
4254  ObjectAttributes = BaseFormatObjectAttributes(&LocalObjectAttributes,
4255  &LocalThreadAttributes,
4256  NULL);
4257  }
4258 
4259  /* Create the Kernel Thread Object */
4260  Status = NtCreateThread(&ThreadHandle,
4262  ObjectAttributes,
4263  ProcessHandle,
4264  &ClientId,
4265  &Context,
4266  &InitialTeb,
4267  TRUE);
4268  if (!NT_SUCCESS(Status))
4269  {
4270  /* A process is not allowed to exist without a main thread, so fail */
4271  DPRINT1("Creating the main thread failed: %lx\n", Status);
4272  BaseSetLastNTError(Status);
4273  Result = FALSE;
4274  goto Quickie;
4275  }
4276 
4277  /* Begin filling out the CSRSS message, first with our IDs and handles */
4278  CreateProcessMsg->ProcessHandle = ProcessHandle;
4279  CreateProcessMsg->ThreadHandle = ThreadHandle;
4280  CreateProcessMsg->ClientId = ClientId;
4281 
4282  /* Write the remote PEB address and clear it locally, we no longer use it */
4283  CreateProcessMsg->PebAddressNative = RemotePeb;
4284 #ifdef _WIN64
4285  DPRINT1("TODO: WOW64 is not supported yet\n");
4286  CreateProcessMsg->PebAddressWow64 = 0;
4287 #else
4288  CreateProcessMsg->PebAddressWow64 = (ULONG)RemotePeb;
4289 #endif
4290  RemotePeb = NULL;
4291 
4292  /* Now check what kind of architecture this image was made for */
4293  switch (ImageInformation.Machine)
4294  {
4295  /* IA32, IA64 and AMD64 are supported in Server 2003 */
4298  break;
4301  break;
4304  break;
4305 
4306  /* Anything else results in image unknown -- but no failure */
4307  default:
4308  DbgPrint("kernel32: No mapping for ImageInformation.Machine == %04x\n",
4309  ImageInformation.Machine);
4311  break;
4312  }
4313 
4314  /* Write the input creation flags except any debugger-related flags */
4315  CreateProcessMsg->CreationFlags = dwCreationFlags &
4316  ~(DEBUG_PROCESS | DEBUG_ONLY_THIS_PROCESS);
4317 
4318  /* CSRSS needs to know if this is a GUI app or not */
4319  if ((ImageInformation.SubSystemType == IMAGE_SUBSYSTEM_WINDOWS_GUI) ||
4320  (IsWowApp))
4321  {
4322  /*
4323  * For GUI apps we turn on the 2nd bit. This allow CSRSS server dlls
4324  * (basesrv in particular) to know whether or not this is a GUI or a
4325  * TUI application.
4326  */
4327  AddToHandle(CreateProcessMsg->ProcessHandle, 2);
4328 
4329  /* Also check if the parent is also a GUI process */
4330  NtHeaders = RtlImageNtHeader(GetModuleHandle(NULL));
4331  if ((NtHeaders) &&
4332  (NtHeaders->OptionalHeader.Subsystem == IMAGE_SUBSYSTEM_WINDOWS_GUI))
4333  {
4334  /* Let it know that it should display the hourglass mouse cursor */
4335  AddToHandle(CreateProcessMsg->ProcessHandle, 1);
4336  }
4337  }
4338 
4339  /* For all apps, if this flag is on, the hourglass mouse cursor is shown */
4340  if (StartupInfo.dwFlags & STARTF_FORCEONFEEDBACK)
4341  {
4342  AddToHandle(CreateProcessMsg->ProcessHandle, 1);
4343  }
4344 
4345  /* Likewise, the opposite holds as well */
4346  if (StartupInfo.dwFlags & STARTF_FORCEOFFFEEDBACK)
4347  {
4348  RemoveFromHandle(CreateProcessMsg->ProcessHandle, 1);
4349  }
4350 
4351  /* Also store which kind of VDM app (if any) this is */
4352  CreateProcessMsg->VdmBinaryType = VdmBinaryType;
4353 
4354  /* And if it really is a VDM app... */
4355  if (VdmBinaryType)
4356  {
4357  /* Store the task ID and VDM console handle */
4358  CreateProcessMsg->hVDM = VdmTask ? 0 : Peb->ProcessParameters->ConsoleHandle;
4359  CreateProcessMsg->VdmTask = VdmTask;
4360  }
4361  else if (VdmReserve)
4362  {
4363  /* Extended VDM, set a flag */
4364  CreateProcessMsg->VdmBinaryType |= BINARY_TYPE_WOW_EX;
4365  }
4366 
4367  /* Check if there's side-by-side assembly data associated with the process */
4368  if (CreateProcessMsg->Sxs.Flags)
4369  {
4370  /* This should not happen in ReactOS yet */
4371  DPRINT1("This is an SxS Message -- should not happen yet\n");
4374  Result = FALSE;
4375  goto Quickie;
4376  }
4377 
4378  /* We are finally ready to call CSRSS to tell it about our new process! */
4380  CaptureBuffer,
4383  sizeof(*CreateProcessMsg));
4384 
4385  /* CSRSS has returned, free the capture buffer now if we had one */
4386  if (CaptureBuffer)
4387  {
4388  CsrFreeCaptureBuffer(CaptureBuffer);
4389  CaptureBuffer = NULL;
4390  }
4391 
4392  /* Check if CSRSS failed to accept ownership of the new Windows process */
4393  if (!NT_SUCCESS(CsrMsg[0].Status))
4394  {
4395  /* Terminate the process and enter failure path with the CSRSS status */
4396  DPRINT1("Failed to tell csrss about new process\n");
4397  BaseSetLastNTError(CsrMsg[0].Status);
4398  NtTerminateProcess(ProcessHandle, CsrMsg[0].Status);
4399  Result = FALSE;
4400  goto Quickie;
4401  }
4402 
4403  /* Check if we have a token due to Authz/Safer, not passed by the user */
4404  if ((TokenHandle) && !(hUserToken))
4405  {
4406  /* Replace the process and/or thread token with the one from Safer */
4407  Status = BasepReplaceProcessThreadTokens(TokenHandle,
4408  ProcessHandle,
4409  ThreadHandle);
4410  if (!NT_SUCCESS(Status))
4411  {
4412  /* If this failed, kill the process and enter the failure path */
4413  DPRINT1("Failed to update process token: %lx\n", Status);
4414  NtTerminateProcess(ProcessHandle, Status);
4415  BaseSetLastNTError(Status);
4416  Result = FALSE;
4417  goto Quickie;
4418  }
4419  }
4420 
4421  /* Check if a job was associated with this process */
4422  if (JobHandle)
4423  {
4424  /* Bind the process and job together now */
4425  Status = NtAssignProcessToJobObject(JobHandle, ProcessHandle);
4426  if (!NT_SUCCESS(Status))
4427  {
4428  /* Kill the process and enter the failure path if binding failed */
4429  DPRINT1("Failed to assign process to job: %lx\n", Status);
4430  NtTerminateProcess(ProcessHandle, STATUS_ACCESS_DENIED);
4431  BaseSetLastNTError(Status);
4432  Result = FALSE;
4433  goto Quickie;
4434  }
4435  }
4436 
4437  /* Finally, resume the thread to actually get the process started */
4438  if (!(dwCreationFlags & CREATE_SUSPENDED))
4439  {
4440  NtResumeThread(ThreadHandle, &ResumeCount);
4441  }
4442 
4443 VdmShortCircuit:
4444  /* We made it this far, meaning we have a fully created process and thread */
4445  Result = TRUE;
4446 
4447  /* Anyone doing a VDM undo should now undo everything, since we are done */
4448  if (VdmUndoLevel) VdmUndoLevel |= VDM_UNDO_COMPLETED;
4449 
4450  /* Having a VDM wait object implies this must be a VDM process */
4451  if (VdmWaitObject)
4452  {
4453  /* Check if it's a 16-bit separate WOW process */
4454  if (VdmBinaryType == BINARY_TYPE_SEPARATE_WOW)
4455  {
4456  /* OR-in the special flag to indicate this, and return to caller */
4457  AddToHandle(VdmWaitObject, 2);
4458  lpProcessInformation->hProcess = VdmWaitObject;
4459 
4460  /* Check if this was a re-used VDM */
4461  if (VdmUndoLevel & VDM_UNDO_REUSE)
4462  {
4463  /* No Client ID should be returned in this case */
4464  ClientId.UniqueProcess = 0;
4465  ClientId.UniqueThread = 0;
4466  }
4467  }
4468  else
4469  {
4470  /* OR-in the special flag to indicate this is not a separate VDM */
4471  AddToHandle(VdmWaitObject, 1);
4472 
4473  /* Return handle to the caller */
4474  lpProcessInformation->hProcess = VdmWaitObject;
4475  }
4476 
4477  /* Close the original process handle, since it's not needed for VDM */
4478  if (ProcessHandle) NtClose(ProcessHandle);
4479  }
4480  else
4481  {
4482  /* This is a regular process, so return the real process handle */
4483  lpProcessInformation->hProcess = ProcessHandle;
4484  }
4485 
4486  /* Return the rest of the process information based on what we have so far */
4487  lpProcessInformation->hThread = ThreadHandle;
4488  lpProcessInformation->dwProcessId = HandleToUlong(ClientId.UniqueProcess);
4489  lpProcessInformation->dwThreadId = HandleToUlong(ClientId.UniqueThread);
4490 
4491  /* NULL these out here so we know to treat this as a success scenario */
4492  ProcessHandle = NULL;
4493  ThreadHandle = NULL;
4494 
4495 Quickie:
4496  /* Free the debugger command line if one was allocated */
4497  if (DebuggerCmdLine) RtlFreeHeap(RtlGetProcessHeap(), 0, DebuggerCmdLine);
4498 
4499  /* Check if an SxS full path as queried */
4500  if (PathBuffer)
4501  {
4502  /* Reinitialize the executable path */
4503  RtlInitEmptyUnicodeString(&SxsWin32ExePath, NULL, 0);
4504  SxsWin32ExePath.Length = 0;
4505 
4506  /* Free the path buffer */
4507  RtlFreeHeap(RtlGetProcessHeap(), 0, PathBuffer);
4508  }
4509 
4510 #if _SXS_SUPPORT_ENABLED_
4511  /* Check if this was a non-VDM process */
4512  if (!VdmBinaryType)
4513  {
4514  /* Then it must've had SxS data, so close the handles used for it */
4515  BasepSxsCloseHandles(&Handles);
4516  BasepSxsCloseHandles(&FileHandles);
4517 
4518  /* Check if we built SxS byte buffers for this create process request */
4519  if (SxsConglomeratedBuffer)
4520  {
4521  /* Loop all of them */
4522  for (i = 0; i < 5; i++)
4523  {
4524  /* Check if this one was allocated */
4525  ThisBuffer = SxsStaticBuffers[i];
4526  if (ThisBuffer)
4527  {
4528  /* Get the underlying RTL_BUFFER structure */
4529  ByteBuffer = &ThisBuffer->ByteBuffer;
4530  if ((ThisBuffer != (PVOID)-8) && (ByteBuffer->Buffer))
4531  {
4532  /* Check if it was dynamic */
4533  if (ByteBuffer->Buffer != ByteBuffer->StaticBuffer)
4534  {
4535  /* Free it from the heap */
4536  FreeString.Buffer = (PWCHAR)ByteBuffer->Buffer;
4537  RtlFreeUnicodeString(&FreeString);
4538  }
4539 
4540  /* Reset the buffer to its static data */
4541  ByteBuffer->Buffer = ByteBuffer->StaticBuffer;
4542  ByteBuffer->Size = ByteBuffer->StaticSize;
4543  }
4544 
4545  /* Reset the string to the static buffer */
4546  RtlInitEmptyUnicodeString(&ThisBuffer->String,
4547  (PWCHAR)ByteBuffer->StaticBuffer,
4548  ByteBuffer->StaticSize);
4549  if (ThisBuffer->String.Buffer)
4550  {
4551  /* Also NULL-terminate it */
4552  *ThisBuffer->String.Buffer = UNICODE_NULL;
4553  }
4554  }
4555  }
4556  }
4557  }
4558 #endif
4559  /* Check if an environment was passed in */
4560  if ((lpEnvironment) && !(dwCreationFlags & CREATE_UNICODE_ENVIRONMENT))
4561  {
4562  /* Destroy it */
4563  RtlDestroyEnvironment(lpEnvironment);
4564 
4565  /* If this was the VDM environment too, clear that as well */
4566  if (VdmUnicodeEnv.Buffer == lpEnvironment) VdmUnicodeEnv.Buffer = NULL;
4567  lpEnvironment = NULL;
4568  }
4569 
4570  /* Unconditionally free all the name parsing buffers we always allocate */
4571  RtlFreeHeap(RtlGetProcessHeap(), 0, QuotedCmdLine);
4572  RtlFreeHeap(RtlGetProcessHeap(), 0, NameBuffer);
4573  RtlFreeHeap(RtlGetProcessHeap(), 0, CurrentDirectory);
4574  RtlFreeHeap(RtlGetProcessHeap(), 0, FreeBuffer);
4575 
4576  /* Close open file/section handles */
4577  if (FileHandle) NtClose(FileHandle);
4578  if (SectionHandle) NtClose(SectionHandle);
4579 
4580  /* If we have a thread handle, this was a failure path */
4581  if (ThreadHandle)
4582  {
4583  /* So kill the process and close the thread handle */
4584  NtTerminateProcess(ProcessHandle, 0);
4585  NtClose(ThreadHandle);
4586  }
4587 
4588  /* If we have a process handle, this was a failure path, so close it */
4589  if (ProcessHandle) NtClose(ProcessHandle);
4590 
4591  /* Thread/process handles, if any, are now processed. Now close this one. */
4592  if (JobHandle) NtClose(JobHandle);
4593 
4594  /* Check if we had created a token */
4595  if (TokenHandle)
4596  {
4597  /* And if the user asked for one */
4598  if (hUserToken)
4599  {
4600  /* Then return it */
4601  *hNewToken = TokenHandle;
4602  }
4603  else
4604  {
4605  /* User didn't want it, so we used it temporarily -- close it */
4606  NtClose(TokenHandle);
4607  }
4608  }
4609 
4610  /* Free any temporary app compatibility data, it's no longer needed */
4611  BasepFreeAppCompatData(AppCompatData, AppCompatSxsData);
4612 
4613  /* Free a few strings. The API takes care of these possibly being NULL */
4614  RtlFreeUnicodeString(&VdmString);
4615  RtlFreeUnicodeString(&DebuggerString);
4616 
4617  /* Check if we had built any sort of VDM environment */
4618  if ((VdmAnsiEnv.Buffer) || (VdmUnicodeEnv.Buffer))
4619  {
4620  /* Free it */
4621  BaseDestroyVDMEnvironment(&VdmAnsiEnv, &VdmUnicodeEnv);
4622  }
4623 
4624  /* Check if this was any kind of VDM application that we ended up creating */
4625  if ((VdmUndoLevel) && (!(VdmUndoLevel & VDM_UNDO_COMPLETED)))
4626  {
4627  /* Send an undo */
4629  (PHANDLE)&VdmTask,
4630  VdmUndoLevel,
4631  VdmBinaryType);
4632 
4633  /* And close whatever VDM handle we were using for notifications */
4634  if (VdmWaitObject) NtClose(VdmWaitObject);
4635  }
4636 
4637  /* Check if we ended up here with an allocated search path, and free it */
4638  if (SearchPath) RtlFreeHeap(RtlGetProcessHeap(), 0, SearchPath);
4639 
4640  /* Finally, return the API's result */
4641  return Result;
4642 }
4643 
4644 /*
4645  * @implemented
4646  */
4647 BOOL
4648 WINAPI
4650 CreateProcessW(LPCWSTR lpApplicationName,
4651  LPWSTR lpCommandLine,
4652  LPSECURITY_ATTRIBUTES lpProcessAttributes,
4653  LPSECURITY_ATTRIBUTES lpThreadAttributes,
4654  BOOL bInheritHandles,
4655  DWORD dwCreationFlags,
4656  LPVOID lpEnvironment,
4657  LPCWSTR lpCurrentDirectory,
4658  LPSTARTUPINFOW lpStartupInfo,
4659  LPPROCESS_INFORMATION lpProcessInformation)
4660 {
4661  /* Call the internal (but exported) version */
4663  lpApplicationName,
4664  lpCommandLine,
4665  lpProcessAttributes,
4666  lpThreadAttributes,
4667  bInheritHandles,
4668  dwCreationFlags,
4669  lpEnvironment,
4670  lpCurrentDirectory,
4671  lpStartupInfo,
4672  lpProcessInformation,
4673  NULL);
4674 }
4675 
4676 /*
4677  * @implemented
4678  */
4679 BOOL
4680 WINAPI
4682  LPCSTR lpApplicationName,
4683  LPSTR lpCommandLine,
4684  LPSECURITY_ATTRIBUTES lpProcessAttributes,
4685  LPSECURITY_ATTRIBUTES lpThreadAttributes,
4686  BOOL bInheritHandles,
4687  DWORD dwCreationFlags,
4688  LPVOID lpEnvironment,
4689  LPCSTR lpCurrentDirectory,
4690  LPSTARTUPINFOA lpStartupInfo,
4691  LPPROCESS_INFORMATION lpProcessInformation,
4692  PHANDLE hNewToken)
4693 {
4694  UNICODE_STRING CommandLine;
4697  BOOL bRetVal;
4698  STARTUPINFOW StartupInfo;
4699 
4700  DPRINT("dwCreationFlags %x, lpEnvironment %p, lpCurrentDirectory %p, "
4701  "lpStartupInfo %p, lpProcessInformation %p\n",
4702  dwCreationFlags, lpEnvironment, lpCurrentDirectory,
4703  lpStartupInfo, lpProcessInformation);
4704 
4705  /* Copy Startup Info */
4706  RtlMoveMemory(&StartupInfo, lpStartupInfo, sizeof(*lpStartupInfo));
4707 
4708  /* Initialize all strings to nothing */
4709  CommandLine.Buffer = NULL;
4710  ApplicationName.Buffer = NULL;
4711  CurrentDirectory.Buffer = NULL;
4712  StartupInfo.lpDesktop = NULL;
4713  StartupInfo.lpReserved = NULL;
4714  StartupInfo.lpTitle = NULL;
4715 
4716  /* Convert the Command line */
4717  if (lpCommandLine)
4718  {
4720  lpCommandLine);
4721  }
4722 
4723  /* Convert the Name and Directory */
4724  if (lpApplicationName)
4725  {
4726  Basep8BitStringToDynamicUnicodeString(&ApplicationName,
4727  lpApplicationName);
4728  }
4729  if (lpCurrentDirectory)
4730  {
4731  Basep8BitStringToDynamicUnicodeString(&CurrentDirectory,
4732  lpCurrentDirectory);
4733  }
4734 
4735  /* Now convert Startup Strings */
4736  if (lpStartupInfo->lpReserved)
4737  {
4739  &StartupInfo.lpReserved);
4740  }
4741  if (lpStartupInfo->lpDesktop)
4742  {
4744  &StartupInfo.lpDesktop);
4745  }
4746  if (lpStartupInfo->lpTitle)
4747  {
4749  &StartupInfo.lpTitle);
4750  }
4751 
4752  /* Call the Unicode function */
4753  bRetVal = CreateProcessInternalW(hToken,
4754  ApplicationName.Buffer,
4755  CommandLine.Buffer,
4756  lpProcessAttributes,
4757  lpThreadAttributes,
4758  bInheritHandles,
4759  dwCreationFlags,
4760  lpEnvironment,
4761  CurrentDirectory.Buffer,
4762  &StartupInfo,
4763  lpProcessInformation,
4764  hNewToken);
4765 
4766  /* Clean up */
4767  RtlFreeUnicodeString(&ApplicationName);
4768  RtlFreeUnicodeString(&CommandLine);
4769  RtlFreeUnicodeString(&CurrentDirectory);
4770  RtlFreeHeap(RtlGetProcessHeap(), 0, StartupInfo.lpDesktop);
4771  RtlFreeHeap(RtlGetProcessHeap(), 0, StartupInfo.lpReserved);
4772  RtlFreeHeap(RtlGetProcessHeap(), 0, StartupInfo.lpTitle);
4773 
4774  /* Return what Unicode did */
4775  return bRetVal;
4776 }
4777 
4778 /*
4779  * FUNCTION: The CreateProcess function creates a new process and its
4780  * primary thread. The new process executes the specified executable file
4781  * ARGUMENTS:
4782  *
4783  * lpApplicationName = Pointer to name of executable module
4784  * lpCommandLine = Pointer to command line string
4785  * lpProcessAttributes = Process security attributes
4786  * lpThreadAttributes = Thread security attributes
4787  * bInheritHandles = Handle inheritance flag
4788  * dwCreationFlags = Creation flags
4789  * lpEnvironment = Pointer to new environment block
4790  * lpCurrentDirectory = Pointer to current directory name
4791  * lpStartupInfo = Pointer to startup info
4792  * lpProcessInformation = Pointer to process information
4793  *
4794  * @implemented
4795  */
4796 BOOL
4797 WINAPI
4799 CreateProcessA(LPCSTR lpApplicationName,
4800  LPSTR lpCommandLine,
4801  LPSECURITY_ATTRIBUTES lpProcessAttributes,
4802  LPSECURITY_ATTRIBUTES lpThreadAttributes,
4803  BOOL bInheritHandles,
4804  DWORD dwCreationFlags,
4805  LPVOID lpEnvironment,
4806  LPCSTR lpCurrentDirectory,
4807  LPSTARTUPINFOA lpStartupInfo,
4808  LPPROCESS_INFORMATION lpProcessInformation)
4809 {
4810  /* Call the internal (but exported) version */
4812  lpApplicationName,
4813  lpCommandLine,
4814  lpProcessAttributes,
4815  lpThreadAttributes,
4816  bInheritHandles,
4817  dwCreationFlags,
4818  lpEnvironment,
4819  lpCurrentDirectory,
4820  lpStartupInfo,
4821  lpProcessInformation,
4822  NULL);
4823 }
4824 
4825 /*
4826  * @implemented
4827  */
4828 UINT
4829 WINAPI
4831 WinExec(LPCSTR lpCmdLine,
4832  UINT uCmdShow)
4833 {
4834  STARTUPINFOA StartupInfo;
4835  PROCESS_INFORMATION ProcessInformation;
4836  DWORD dosErr;
4837 
4838  RtlZeroMemory(&StartupInfo, sizeof(StartupInfo));
4839  StartupInfo.cb = sizeof(STARTUPINFOA);
4840  StartupInfo.wShowWindow = (WORD)uCmdShow;
4841  StartupInfo.dwFlags = 0;
4842 
4843  if (!CreateProcessA(NULL,
4844  (PVOID)lpCmdLine,
4845  NULL,
4846  NULL,
4847  FALSE,
4848  0,
4849  NULL,
4850  NULL,
4851  &StartupInfo,
4852  &ProcessInformation))
4853  {
4854  dosErr = GetLastError();
4855  return dosErr < 32 ? dosErr : ERROR_BAD_FORMAT;
4856  }
4857 
4858  if (NULL != UserWaitForInputIdleRoutine)
4859  {
4860  UserWaitForInputIdleRoutine(ProcessInformation.hProcess,
4861  10000);
4862  }
4863 
4864  NtClose(ProcessInformation.hProcess);
4865  NtClose(ProcessInformation.hThread);
4866 
4867  return 33; /* Something bigger than 31 means success. */
4868 }
4869 
4870 /* EOF */
HANDLE NTAPI DbgUiGetThreadDebugObject(VOID)
Definition: dbgui.c:333
DWORD *typedef PVOID
Definition: winlogon.h:60
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:885
LPSTR lpTitle
Definition: winbase.h:799
#define DBG
Definition: t_vertex.c:30
#define PROCESS_PRIORITY_CLASS_INVALID
Definition: pstypes.h:106
#define PROCESS_ALL_ACCESS
Definition: nt_native.h:1324
#define RTL_USER_PROCESS_PARAMETERS_IMAGE_KEY_MISSING
Definition: rtltypes.h:54
NTSTATUS NTAPI NtCreateSection(OUT PHANDLE SectionHandle, IN ACCESS_MASK DesiredAccess, IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL, IN PLARGE_INTEGER MaximumSize OPTIONAL, IN ULONG SectionPageProtection OPTIONAL, IN ULONG AllocationAttributes, IN HANDLE FileHandle OPTIONAL)
Definition: section.c:3369
NTSTATUS NTAPI LdrShutdownProcess(VOID)
Definition: ldrinit.c:928
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:1798
PBASE_STATIC_SERVER_DATA BaseStaticServerData
Definition: dllmain.c:19
USHORT MaximumLength
Definition: env_spec_w32.h:370
#define CREATE_SEPARATE_WOW_VDM
Definition: winbase.h:187
PBASEP_APPCERT_PLUGIN_FUNC fPluginCertFunc
Definition: kernel32.h:385
#define CREATE_UNICODE_ENVIRONMENT
Definition: winbase.h:186
#define PROCESSOR_ARCHITECTURE_UNKNOWN
Definition: ketypes.h:115
#define HANDLE_DETACHED_PROCESS
Definition: console.h:13
#define HANDLE_CREATE_NO_WINDOW
Definition: console.h:15
WCHAR CurrentDirectory[1024]
Definition: chkdsk.c: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:1026
#define ERROR_INVALID_HANDLE
Definition: compat.h:88
VOID NTAPI RtlReleaseRelativeName(_In_ PRTL_RELATIVE_NAME_U RelativeName)
NTSTATUS WINAPI BasepNotifyCsrOfThread(IN HANDLE ThreadHandle, IN PCLIENT_ID ClientId)
Definition: proc.c: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:1063
BOOLEAN NTAPI RtlFreeHeap(IN PVOID HeapHandle, IN ULONG Flags, IN PVOID HeapBase)
Definition: heap.c:603
#define HandleToUlong(h)
Definition: basetsd.h:79
NTSTATUS NTAPI NtQueryInformationProcess(IN HANDLE ProcessHandle, IN PROCESSINFOCLASS ProcessInformationClass, OUT PVOID ProcessInformation, IN ULONG ProcessInformationLength, OUT PULONG ReturnLength OPTIONAL)
Definition: query.c:59
_In_opt_ ULONG Base
Definition: rtlfuncs.h:2327
SIZE_T LPPROCESS_INFORMATION
Definition: cordebug.idl:86
#define NtCurrentThread()
_Check_return_ _CRTIMP int __cdecl _wcsnicmp(_In_reads_or_z_(_MaxCount) const wchar_t *_Str1, _In_reads_or_z_(_MaxCount) const wchar_t *_Str2, _In_ size_t _MaxCount)
#define PROFILE_KERNEL
Definition: winbase.h:197
PVOID *typedef PWSTR
Definition: winlogon.h:65
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:1059
BOOL WINAPI BaseCheckForVDM(IN HANDLE ProcessHandle, OUT LPDWORD ExitCode)
Definition: vdm.c:610
DWORD WINAPI GetFullPathNameW(IN LPCWSTR lpFileName, IN DWORD nBufferLength, OUT LPWSTR lpBuffer, OUT LPWSTR *lpFilePart)
Definition: path.c:1105
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:4831
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
_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:83
#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:1061
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:4681
#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