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