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)
11 /* INCLUDES ****************************************************************/
18 /* GLOBALS *******************************************************************/
20 WaitForInputIdleType UserWaitForInputIdleRoutine
;
21 UNICODE_STRING BaseUnicodeCommandLine
;
22 ANSI_STRING BaseAnsiCommandLine
;
23 UNICODE_STRING BasePathVariableName
= RTL_CONSTANT_STRING(L
"PATH");
24 LPSTARTUPINFOA BaseAnsiStartupInfo
= NULL
;
25 PLDR_DATA_TABLE_ENTRY BasepExeLdrEntry
;
26 BOOLEAN g_AppCertInitialized
;
27 BOOLEAN g_HaveAppCerts
;
28 LIST_ENTRY BasepAppCertDllsList
;
29 RTL_CRITICAL_SECTION gcsAppCert
;
30 PBASEP_APPCERT_EMBEDDED_FUNC fEmbeddedCertFunc
;
31 NTSTATUS g_AppCertStatus
;
32 RTL_QUERY_REGISTRY_TABLE BasepAppCertTable
[2] =
35 BasepConfigureAppCertDlls
,
38 &BasepAppCertDllsList
,
45 PSAFER_REPLACE_PROCESS_THREAD_TOKENS g_SaferReplaceProcessThreadTokens
;
46 HMODULE gSaferHandle
= (HMODULE
)-1;
49 RegisterWaitForInputIdle(WaitForInputIdleType lpfnRegisterWaitForInputIdle
);
51 #define CMD_STRING L"cmd /c "
53 /* FUNCTIONS ****************************************************************/
57 StuffStdHandle(IN HANDLE ProcessHandle
,
58 IN HANDLE StandardHandle
,
62 HANDLE DuplicatedHandle
;
63 SIZE_T NumberOfBytesWritten
;
65 /* If there is no handle to duplicate, return immediately */
66 if (!StandardHandle
) return;
68 /* Duplicate the handle */
69 Status
= NtDuplicateObject(NtCurrentProcess(),
75 DUPLICATE_SAME_ACCESS
|
76 DUPLICATE_SAME_ATTRIBUTES
);
77 if (!NT_SUCCESS(Status
)) return;
80 NtWriteVirtualMemory(ProcessHandle
,
84 &NumberOfBytesWritten
);
89 BuildSubSysCommandLine(IN LPCWSTR SubsystemName
,
90 IN LPCWSTR ApplicationName
,
91 IN LPCWSTR CommandLine
,
92 OUT PUNICODE_STRING SubsysCommandLine
)
94 UNICODE_STRING CommandLineString
, ApplicationNameString
;
98 /* Convert to unicode strings */
99 RtlInitUnicodeString(&CommandLineString
, ApplicationName
);
100 RtlInitUnicodeString(&ApplicationNameString
, CommandLine
);
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
);
108 /* Fail, no memory */
109 BaseSetLastNTError(STATUS_NO_MEMORY
);
113 /* Build the final subsystem command line */
114 RtlAppendUnicodeToString(SubsysCommandLine
, SubsystemName
);
115 RtlAppendUnicodeStringToString(SubsysCommandLine
, &CommandLineString
);
116 RtlAppendUnicodeToString(SubsysCommandLine
, L
" /C ");
117 RtlAppendUnicodeStringToString(SubsysCommandLine
, &ApplicationNameString
);
123 BasepIsImageVersionOk(IN ULONG ImageMajorVersion
,
124 IN ULONG ImageMinorVersion
)
126 /* Accept images for NT 3.1 or higher, as long as they're not newer than us */
127 return ((ImageMajorVersion
>= 3) &&
128 ((ImageMajorVersion
!= 3) ||
129 (ImageMinorVersion
>= 10)) &&
130 (ImageMajorVersion
<= SharedUserData
->NtMajorVersion
) &&
131 ((ImageMajorVersion
!= SharedUserData
->NtMajorVersion
) ||
132 (ImageMinorVersion
<= SharedUserData
->NtMinorVersion
)));
137 BasepCheckWebBladeHashes(IN HANDLE FileHandle
)
142 /* Get all the MD5 hashes */
143 Status
= RtlComputeImportTableHash(FileHandle
, Hash
, 1);
144 if (!NT_SUCCESS(Status
)) return Status
;
146 /* Depending on which suite this is, run a bsearch and block the appropriate ones */
147 if (SharedUserData
->SuiteMask
& VER_SUITE_COMPUTE_SERVER
)
149 DPRINT1("Egad! This is a ReactOS Compute Server and we should prevent you from using certain APIs...but we won't.");
151 else if (SharedUserData
->SuiteMask
& VER_SUITE_STORAGE_SERVER
)
153 DPRINT1("Gasp! This is a ReactOS Storage Server and we should prevent you from using certain APIs...but we won't.");
155 else if (SharedUserData
->SuiteMask
& VER_SUITE_BLADE
)
157 DPRINT1("Golly! This is a ReactOS Web Blade Server and we should prevent you from using certain APIs...but we won't.");
160 /* Actually, fuck it, don't block anything, we're open source */
161 return STATUS_SUCCESS
;
166 BasepSaveAppCertRegistryValue(IN PLIST_ENTRY List
,
167 IN PWCHAR ComponentName
,
170 /* Pretty much the only thing this key is used for, is malware */
172 return STATUS_NOT_IMPLEMENTED
;
177 BasepConfigureAppCertDlls(IN PWSTR ValueName
,
180 IN ULONG ValueLength
,
182 IN PVOID EntryContext
)
184 /* Add this to the certification list */
185 return BasepSaveAppCertRegistryValue(Context
, ValueName
, ValueData
);
190 BasepIsProcessAllowed(IN LPWSTR ApplicationName
)
192 NTSTATUS Status
, Status1
;
195 HMODULE TrustLibrary
;
196 PBASEP_APPCERT_ENTRY Entry
;
198 PLIST_ENTRY NextEntry
;
200 UNICODE_STRING CertKey
= RTL_CONSTANT_STRING(L
"\\Registry\\MACHINE\\System\\CurrentControlSet\\Control\\Session Manager\\AppCertDlls");
201 OBJECT_ATTRIBUTES KeyAttributes
= RTL_CONSTANT_OBJECT_ATTRIBUTES(&CertKey
, OBJ_CASE_INSENSITIVE
);
203 /* Try to initialize the certification subsystem */
204 while (!g_AppCertInitialized
)
207 Status
= STATUS_SUCCESS
;
210 /* Acquire the lock while initializing and see if we lost a race */
211 RtlEnterCriticalSection(&gcsAppCert
);
212 if (g_AppCertInitialized
) break;
214 /* On embedded, there is a special DLL */
215 if (SharedUserData
->SuiteMask
& VER_SUITE_EMBEDDEDNT
)
217 /* Allocate a buffer for the name */
218 Buffer
= RtlAllocateHeap(RtlGetProcessHeap(),
220 MAX_PATH
* sizeof(WCHAR
) +
221 sizeof(UNICODE_NULL
));
224 /* Fail if no memory */
225 Status
= STATUS_NO_MEMORY
;
229 /* Now get the system32 directory in our buffer, make sure it fits */
230 Length
= GetSystemDirectoryW(Buffer
, MAX_PATH
- sizeof("EmbdTrst.DLL"));
231 if ((Length
) && (Length
<= MAX_PATH
- sizeof("EmbdTrst.DLL")))
233 /* Add a slash if needed, and add the embedded cert DLL name */
234 if (Buffer
[Length
- 1] != '\\') Buffer
[Length
++] = '\\';
235 RtlCopyMemory(&Buffer
[Length
],
237 sizeof(L
"EmbdTrst.DLL"));
240 TrustLibrary
= LoadLibraryW(Buffer
);
243 /* And extract the special function out of it */
244 fEmbeddedCertFunc
= (PVOID
)GetProcAddress(TrustLibrary
,
245 "ImageOkToRunOnEmbeddedNT");
249 /* If we didn't get this far, set a failure code */
250 if (!fEmbeddedCertFunc
) Status
= STATUS_UNSUCCESSFUL
;
255 /* Other systems have a registry entry for this */
256 Status1
= NtOpenKey(&KeyHandle
, KEY_READ
, &KeyAttributes
);
257 if (NT_SUCCESS(Status1
))
259 /* Close it, we'll query it through Rtl */
262 /* Do the query, which will call a special callback */
263 Status
= RtlQueryRegistryValues(RTL_REGISTRY_CONTROL
,
268 if (Status
== STATUS_OBJECT_NAME_NOT_FOUND
)
270 Status
= STATUS_SUCCESS
;
275 /* Free any buffer if we had one */
276 if (Buffer
) RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer
);
278 /* Check for errors, or a missing embedded/custom certification DLL */
279 if (!NT_SUCCESS(Status
) ||
280 (!(fEmbeddedCertFunc
) && (IsListEmpty(&BasepAppCertDllsList
))))
282 /* The subsystem is not active on this machine, so give up */
283 g_HaveAppCerts
= FALSE
;
284 g_AppCertStatus
= Status
;
288 /* We have certification DLLs active, remember this */
289 g_HaveAppCerts
= TRUE
;
292 /* We are done the initialization phase, release the lock */
293 g_AppCertInitialized
= TRUE
;
294 RtlLeaveCriticalSection(&gcsAppCert
);
297 /* If there's no certification DLLs present, return the failure code */
298 if (!g_HaveAppCerts
) return g_AppCertStatus
;
300 /* Otherwise, assume success and make sure we have *something* */
301 ASSERT(fEmbeddedCertFunc
|| !IsListEmpty(&BasepAppCertDllsList
));
302 Status
= STATUS_SUCCESS
;
304 /* If the something is an embedded certification DLL, call it and return */
305 if (fEmbeddedCertFunc
) return fEmbeddedCertFunc(ApplicationName
);
307 /* Otherwise we have custom certification DLLs, parse them */
308 NextEntry
= BasepAppCertDllsList
.Flink
;
310 while (NextEntry
!= &BasepAppCertDllsList
)
312 /* Make sure the entry has a callback */
313 Entry
= CONTAINING_RECORD(NextEntry
, BASEP_APPCERT_ENTRY
, Entry
);
314 ASSERT(Entry
->fPluginCertFunc
!= NULL
);
316 /* Call it and check if it failed */
317 Status
= Entry
->fPluginCertFunc(ApplicationName
, 1);
318 if (!NT_SUCCESS(Status
)) CertFlag
= 3;
321 NextEntry
= NextEntry
->Flink
;
324 /* Now loop them again */
325 NextEntry
= BasepAppCertDllsList
.Flink
;
326 while (NextEntry
!= &BasepAppCertDllsList
)
328 /* Make sure the entry has a callback */
329 Entry
= CONTAINING_RECORD(NextEntry
, BASEP_APPCERT_ENTRY
, Entry
);
330 ASSERT(Entry
->fPluginCertFunc
!= NULL
);
332 /* Call it, this time with the flag from the loop above */
333 Status
= Entry
->fPluginCertFunc(ApplicationName
, CertFlag
);
336 /* All done, return the status */
342 BasepReplaceProcessThreadTokens(IN HANDLE TokenHandle
,
343 IN HANDLE ProcessHandle
,
344 IN HANDLE ThreadHandle
)
347 ANSI_STRING SaferiReplaceProcessThreadTokens
= RTL_CONSTANT_STRING("SaferiReplaceProcessThreadTokens");
349 /* Enter the application certification lock */
350 RtlEnterCriticalSection(&gcsAppCert
);
352 /* Check if we already know the function */
353 if (g_SaferReplaceProcessThreadTokens
)
356 Status
= g_SaferReplaceProcessThreadTokens(TokenHandle
,
364 /* Check if the app certification DLL isn't loaded */
365 if (!(gSaferHandle
) ||
366 (gSaferHandle
== (HMODULE
)-1) ||
367 (gSaferHandle
== (HMODULE
)-2))
369 /* Then we can't call the function */
370 Status
= STATUS_ENTRYPOINT_NOT_FOUND
;
374 /* We have the DLL, find the address of the Safer function */
375 Status
= LdrGetProcedureAddress(gSaferHandle
,
376 &SaferiReplaceProcessThreadTokens
,
378 (PVOID
*)&g_SaferReplaceProcessThreadTokens
);
379 if (NT_SUCCESS(Status
))
381 /* Found it, now call it */
382 Status
= g_SaferReplaceProcessThreadTokens(TokenHandle
,
390 /* We couldn't find it, so this must be an unsupported DLL */
391 LdrUnloadDll(gSaferHandle
);
393 Status
= STATUS_ENTRYPOINT_NOT_FOUND
;
398 /* Release the lock and return the result */
399 RtlLeaveCriticalSection(&gcsAppCert
);
405 BasepSxsCloseHandles(IN PBASE_MSG_SXS_HANDLES Handles
)
410 ASSERT(Handles
!= NULL
);
411 ASSERT(Handles
->Process
== NULL
|| Handles
->Process
== NtCurrentProcess());
413 /* Close the file handle */
416 Status
= NtClose(Handles
->File
);
417 ASSERT(NT_SUCCESS(Status
));
420 /* Close the section handle */
421 if (Handles
->Section
)
423 Status
= NtClose(Handles
->Section
);
424 ASSERT(NT_SUCCESS(Status
));
427 /* Unmap the section view */
428 if (Handles
->ViewBase
.QuadPart
)
430 Status
= NtUnmapViewOfSection(NtCurrentProcess(),
431 (PVOID
)Handles
->ViewBase
.LowPart
);
432 ASSERT(NT_SUCCESS(Status
));
437 LONG
BaseExceptionFilter(EXCEPTION_POINTERS
*ExceptionInfo
)
439 LONG ExceptionDisposition
= EXCEPTION_EXECUTE_HANDLER
;
440 LPTOP_LEVEL_EXCEPTION_FILTER RealFilter
;
441 RealFilter
= RtlDecodePointer(GlobalTopLevelExceptionFilter
);
443 if (RealFilter
!= NULL
)
447 ExceptionDisposition
= RealFilter(ExceptionInfo
);
449 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
454 if ((ExceptionDisposition
== EXCEPTION_CONTINUE_SEARCH
|| ExceptionDisposition
== EXCEPTION_EXECUTE_HANDLER
) &&
455 RealFilter
!= UnhandledExceptionFilter
)
457 ExceptionDisposition
= UnhandledExceptionFilter(ExceptionInfo
);
460 return ExceptionDisposition
;
465 BaseProcessStartup(PPROCESS_START_ROUTINE lpStartAddress
)
467 DPRINT("BaseProcessStartup(..) - setting up exception frame.\n");
471 /* Set our Start Address */
472 NtSetInformationThread(NtCurrentThread(),
473 ThreadQuerySetWin32StartAddress
,
475 sizeof(PPROCESS_START_ROUTINE
));
477 /* Call the Start Routine */
478 ExitThread(lpStartAddress());
480 _SEH2_EXCEPT(BaseExceptionFilter(_SEH2_GetExceptionInformation()))
482 /* Get the Exit code from the SEH Handler */
483 if (!BaseRunningInServerProcess
)
485 /* Kill the whole process, usually */
486 ExitProcess(_SEH2_GetExceptionCode());
490 /* If running inside CSRSS, kill just this thread */
491 ExitThread(_SEH2_GetExceptionCode());
499 BasepNotifyCsrOfThread(IN HANDLE ThreadHandle
,
500 IN PCLIENT_ID ClientId
)
502 BASE_API_MESSAGE ApiMessage
;
503 PBASE_CREATE_THREAD CreateThreadRequest
= &ApiMessage
.Data
.CreateThreadRequest
;
505 DPRINT("BasepNotifyCsrOfThread: Thread: %p, Handle %p\n",
506 ClientId
->UniqueThread
, ThreadHandle
);
508 /* Fill out the request */
509 CreateThreadRequest
->ClientId
= *ClientId
;
510 CreateThreadRequest
->ThreadHandle
= ThreadHandle
;
513 CsrClientCallServer((PCSR_API_MESSAGE
)&ApiMessage
,
515 CSR_CREATE_API_NUMBER(BASESRV_SERVERDLL_INDEX
, BasepCreateThread
),
516 sizeof(*CreateThreadRequest
));
517 if (!NT_SUCCESS(ApiMessage
.Status
))
519 DPRINT1("Failed to tell CSRSS about new thread: %lx\n", ApiMessage
.Status
);
520 return ApiMessage
.Status
;
524 return STATUS_SUCCESS
;
529 BasePushProcessParameters(IN ULONG ParameterFlags
,
530 IN HANDLE ProcessHandle
,
532 IN LPCWSTR ApplicationPathName
,
533 IN LPWSTR lpCurrentDirectory
,
534 IN LPWSTR lpCommandLine
,
535 IN LPVOID lpEnvironment
,
536 IN LPSTARTUPINFOW StartupInfo
,
537 IN DWORD CreationFlags
,
538 IN BOOL InheritHandles
,
539 IN ULONG ImageSubsystem
,
540 IN PVOID AppCompatData
,
541 IN ULONG AppCompatDataSize
)
543 WCHAR FullPath
[MAX_PATH
+ 5];
544 PWCHAR Remaining
, DllPathString
, ScanChar
;
545 PRTL_USER_PROCESS_PARAMETERS ProcessParameters
, RemoteParameters
;
546 PVOID RemoteAppCompatData
;
547 UNICODE_STRING DllPath
, ImageName
, CommandLine
, CurrentDirectory
;
548 UNICODE_STRING Desktop
, Shell
, Runtime
, Title
;
552 BOOLEAN HavePebLock
= FALSE
, Result
;
553 PPEB Peb
= NtCurrentPeb();
555 /* Get the full path name */
556 Size
= GetFullPathNameW(ApplicationPathName
,
560 if ((Size
) && (Size
<= (MAX_PATH
+ 4)))
562 /* Get the DLL Path */
563 DllPathString
= BaseComputeProcessDllPath(FullPath
, lpEnvironment
);
567 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
571 /* Initialize Strings */
572 RtlInitUnicodeString(&DllPath
, DllPathString
);
573 RtlInitUnicodeString(&ImageName
, FullPath
);
577 /* Couldn't get the path name. Just take the original path */
578 DllPathString
= BaseComputeProcessDllPath((LPWSTR
)ApplicationPathName
,
583 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
587 /* Initialize Strings */
588 RtlInitUnicodeString(&DllPath
, DllPathString
);
589 RtlInitUnicodeString(&ImageName
, ApplicationPathName
);
592 /* Initialize Strings */
593 RtlInitUnicodeString(&CommandLine
, lpCommandLine
);
594 RtlInitUnicodeString(&CurrentDirectory
, lpCurrentDirectory
);
596 /* Initialize more Strings from the Startup Info */
597 if (StartupInfo
->lpDesktop
)
599 RtlInitUnicodeString(&Desktop
, StartupInfo
->lpDesktop
);
603 RtlInitUnicodeString(&Desktop
, L
"");
605 if (StartupInfo
->lpReserved
)
607 RtlInitUnicodeString(&Shell
, StartupInfo
->lpReserved
);
611 RtlInitUnicodeString(&Shell
, L
"");
613 if (StartupInfo
->lpTitle
)
615 RtlInitUnicodeString(&Title
, StartupInfo
->lpTitle
);
619 RtlInitUnicodeString(&Title
, ApplicationPathName
);
622 /* This one is special because the length can differ */
623 Runtime
.Buffer
= (LPWSTR
)StartupInfo
->lpReserved2
;
624 Runtime
.MaximumLength
= Runtime
.Length
= StartupInfo
->cbReserved2
;
626 /* Enforce no app compat data if the pointer was NULL */
627 if (!AppCompatData
) AppCompatDataSize
= 0;
629 /* Create the Parameter Block */
630 ProcessParameters
= NULL
;
631 DPRINT("ImageName: '%wZ'\n", &ImageName
);
632 DPRINT("DllPath : '%wZ'\n", &DllPath
);
633 DPRINT("CurDir : '%wZ'\n", &CurrentDirectory
);
634 DPRINT("CmdLine : '%wZ'\n", &CommandLine
);
635 DPRINT("Title : '%wZ'\n", &Title
);
636 DPRINT("Desktop : '%wZ'\n", &Desktop
);
637 DPRINT("Shell : '%wZ'\n", &Shell
);
638 DPRINT("Runtime : '%wZ'\n", &Runtime
);
639 Status
= RtlCreateProcessParameters(&ProcessParameters
,
643 &CurrentDirectory
: NULL
,
650 if (!NT_SUCCESS(Status
)) goto FailPath
;
652 /* Clear the current directory handle if not inheriting */
653 if (!InheritHandles
) ProcessParameters
->CurrentDirectory
.Handle
= NULL
;
655 /* Check if the user passed in an environment */
658 /* We should've made it part of the parameters block, enforce this */
659 ASSERT(ProcessParameters
->Environment
== lpEnvironment
);
660 lpEnvironment
= ProcessParameters
->Environment
;
664 /* The user did not, so use the one from the current PEB */
667 lpEnvironment
= Peb
->ProcessParameters
->Environment
;
670 /* Save pointer and start lookup */
671 ScanChar
= lpEnvironment
;
674 /* Find the environment size */
675 while (*ScanChar
++) while (*ScanChar
++);
676 EnviroSize
= (ULONG
)((ULONG_PTR
)ScanChar
- (ULONG_PTR
)lpEnvironment
);
678 /* Allocate and Initialize new Environment Block */
680 ProcessParameters
->Environment
= NULL
;
681 Status
= NtAllocateVirtualMemory(ProcessHandle
,
682 (PVOID
*)&ProcessParameters
->Environment
,
687 if (!NT_SUCCESS(Status
)) goto FailPath
;
689 /* Write the Environment Block */
690 Status
= NtWriteVirtualMemory(ProcessHandle
,
691 ProcessParameters
->Environment
,
696 /* No longer need the PEB lock anymore */
704 /* Check if the write failed */
705 if (!NT_SUCCESS(Status
)) goto FailPath
;
708 /* Write new parameters */
709 ProcessParameters
->StartingX
= StartupInfo
->dwX
;
710 ProcessParameters
->StartingY
= StartupInfo
->dwY
;
711 ProcessParameters
->CountX
= StartupInfo
->dwXSize
;
712 ProcessParameters
->CountY
= StartupInfo
->dwYSize
;
713 ProcessParameters
->CountCharsX
= StartupInfo
->dwXCountChars
;
714 ProcessParameters
->CountCharsY
= StartupInfo
->dwYCountChars
;
715 ProcessParameters
->FillAttribute
= StartupInfo
->dwFillAttribute
;
716 ProcessParameters
->WindowFlags
= StartupInfo
->dwFlags
;
717 ProcessParameters
->ShowWindowFlags
= StartupInfo
->wShowWindow
;
719 /* Write the handles only if we have to */
720 if (StartupInfo
->dwFlags
&
721 (STARTF_USESTDHANDLES
| STARTF_USEHOTKEY
| STARTF_SHELLPRIVATE
))
723 ProcessParameters
->StandardInput
= StartupInfo
->hStdInput
;
724 ProcessParameters
->StandardOutput
= StartupInfo
->hStdOutput
;
725 ProcessParameters
->StandardError
= StartupInfo
->hStdError
;
728 /* Use Special Flags for ConDllInitialize in Kernel32 */
729 if (CreationFlags
& DETACHED_PROCESS
)
731 ProcessParameters
->ConsoleHandle
= HANDLE_DETACHED_PROCESS
;
733 else if (CreationFlags
& CREATE_NEW_CONSOLE
)
735 ProcessParameters
->ConsoleHandle
= HANDLE_CREATE_NEW_CONSOLE
;
737 else if (CreationFlags
& CREATE_NO_WINDOW
)
739 ProcessParameters
->ConsoleHandle
= HANDLE_CREATE_NO_WINDOW
;
743 /* Inherit our Console Handle */
744 ProcessParameters
->ConsoleHandle
= Peb
->ProcessParameters
->ConsoleHandle
;
746 /* Make sure that the shell isn't trampling on our handles first */
747 if (!(StartupInfo
->dwFlags
&
748 (STARTF_USESTDHANDLES
| STARTF_USEHOTKEY
| STARTF_SHELLPRIVATE
)))
750 /* Copy the handle if we are inheriting or if it's a console handle */
751 if ((InheritHandles
) ||
752 (IsConsoleHandle(Peb
->ProcessParameters
->StandardInput
)))
754 ProcessParameters
->StandardInput
= Peb
->ProcessParameters
->StandardInput
;
756 if ((InheritHandles
) ||
757 (IsConsoleHandle(Peb
->ProcessParameters
->StandardOutput
)))
759 ProcessParameters
->StandardOutput
= Peb
->ProcessParameters
->StandardOutput
;
761 if ((InheritHandles
) ||
762 (IsConsoleHandle(Peb
->ProcessParameters
->StandardError
)))
764 ProcessParameters
->StandardError
= Peb
->ProcessParameters
->StandardError
;
769 /* Also set the Console Flag */
770 if ((CreationFlags
& CREATE_NEW_PROCESS_GROUP
) &&
771 (!(CreationFlags
& CREATE_NEW_CONSOLE
)))
773 ProcessParameters
->ConsoleFlags
= 1;
776 /* Check if there's a .local file present */
777 if (ParameterFlags
& 1)
779 ProcessParameters
->Flags
|= RTL_USER_PROCESS_PARAMETERS_LOCAL_DLL_PATH
;
782 /* Check if we failed to open the IFEO key */
783 if (ParameterFlags
& 2)
785 ProcessParameters
->Flags
|= RTL_USER_PROCESS_PARAMETERS_IMAGE_KEY_MISSING
;
788 /* Allocate memory for the parameter block */
789 Size
= ProcessParameters
->Length
;
790 RemoteParameters
= NULL
;
791 Status
= NtAllocateVirtualMemory(ProcessHandle
,
792 (PVOID
*)&RemoteParameters
,
797 if (!NT_SUCCESS(Status
)) goto FailPath
;
799 /* Set the allocated size */
800 ProcessParameters
->MaximumLength
= Size
;
802 /* Handle some Parameter Flags */
803 ProcessParameters
->Flags
|= (CreationFlags
& PROFILE_USER
) ?
804 RTL_USER_PROCESS_PARAMETERS_PROFILE_USER
: 0;
805 ProcessParameters
->Flags
|= (CreationFlags
& PROFILE_KERNEL
) ?
806 RTL_USER_PROCESS_PARAMETERS_PROFILE_KERNEL
: 0;
807 ProcessParameters
->Flags
|= (CreationFlags
& PROFILE_SERVER
) ?
808 RTL_USER_PROCESS_PARAMETERS_PROFILE_SERVER
: 0;
809 ProcessParameters
->Flags
|= (Peb
->ProcessParameters
->Flags
&
810 RTL_USER_PROCESS_PARAMETERS_DISABLE_HEAP_CHECKS
);
812 /* Write the Parameter Block */
813 Status
= NtWriteVirtualMemory(ProcessHandle
,
816 ProcessParameters
->Length
,
818 if (!NT_SUCCESS(Status
)) goto FailPath
;
820 /* Write the PEB Pointer */
821 Status
= NtWriteVirtualMemory(ProcessHandle
,
822 &RemotePeb
->ProcessParameters
,
826 if (!NT_SUCCESS(Status
)) goto FailPath
;
828 /* Check if there's any app compat data to write */
829 RemoteAppCompatData
= NULL
;
832 /* Allocate some space for the application compatibility data */
833 Size
= AppCompatDataSize
;
834 Status
= NtAllocateVirtualMemory(ProcessHandle
,
835 &RemoteAppCompatData
,
840 if (!NT_SUCCESS(Status
)) goto FailPath
;
842 /* Write the application compatibility data */
843 Status
= NtWriteVirtualMemory(ProcessHandle
,
848 if (!NT_SUCCESS(Status
)) goto FailPath
;
851 /* Write the PEB Pointer to the app compat data (might be NULL) */
852 Status
= NtWriteVirtualMemory(ProcessHandle
,
853 &RemotePeb
->pShimData
,
854 &RemoteAppCompatData
,
857 if (!NT_SUCCESS(Status
)) goto FailPath
;
859 /* Now write Peb->ImageSubSystem */
862 NtWriteVirtualMemory(ProcessHandle
,
863 &RemotePeb
->ImageSubsystem
,
865 sizeof(ImageSubsystem
),
874 if (HavePebLock
) RtlReleasePebLock();
875 RtlFreeHeap(RtlGetProcessHeap(), 0, DllPath
.Buffer
);
876 if (ProcessParameters
) RtlDestroyProcessParameters(ProcessParameters
);
879 DPRINT1("Failure to create process parameters: %lx\n", Status
);
880 BaseSetLastNTError(Status
);
887 InitCommandLines(VOID
)
891 /* Read the UNICODE_STRING from the PEB */
892 BaseUnicodeCommandLine
= NtCurrentPeb()->ProcessParameters
->CommandLine
;
894 /* Convert to ANSI_STRING for the *A callers */
895 Status
= RtlUnicodeStringToAnsiString(&BaseAnsiCommandLine
,
896 &BaseUnicodeCommandLine
,
898 if (!NT_SUCCESS(Status
)) RtlInitEmptyAnsiString(&BaseAnsiCommandLine
, 0, 0);
901 /* PUBLIC FUNCTIONS ***********************************************************/
908 GetProcessAffinityMask(IN HANDLE hProcess
,
909 OUT PDWORD_PTR lpProcessAffinityMask
,
910 OUT PDWORD_PTR lpSystemAffinityMask
)
912 PROCESS_BASIC_INFORMATION ProcessInfo
;
915 /* Query information on the process from the kernel */
916 Status
= NtQueryInformationProcess(hProcess
,
917 ProcessBasicInformation
,
921 if (!NT_SUCCESS(Status
))
924 BaseSetLastNTError(Status
);
928 /* Copy the affinity mask, and get the system one from our shared data */
929 *lpProcessAffinityMask
= (DWORD
)ProcessInfo
.AffinityMask
;
930 *lpSystemAffinityMask
= (DWORD
)BaseStaticServerData
->SysInfo
.ActiveProcessorsAffinityMask
;
939 SetProcessAffinityMask(IN HANDLE hProcess
,
940 IN DWORD_PTR dwProcessAffinityMask
)
944 /* Directly set the affinity mask */
945 Status
= NtSetInformationProcess(hProcess
,
947 (PVOID
)&dwProcessAffinityMask
,
949 if (!NT_SUCCESS(Status
))
952 BaseSetLastNTError(Status
);
956 /* Everything was ok */
965 GetProcessShutdownParameters(OUT LPDWORD lpdwLevel
,
966 OUT LPDWORD lpdwFlags
)
968 BASE_API_MESSAGE ApiMessage
;
969 PBASE_GETSET_PROCESS_SHUTDOWN_PARAMS ShutdownParametersRequest
= &ApiMessage
.Data
.ShutdownParametersRequest
;
971 /* Ask CSRSS for shutdown information */
972 CsrClientCallServer((PCSR_API_MESSAGE
)&ApiMessage
,
974 CSR_CREATE_API_NUMBER(BASESRV_SERVERDLL_INDEX
, BasepGetProcessShutdownParam
),
975 sizeof(*ShutdownParametersRequest
));
976 if (!NT_SUCCESS(ApiMessage
.Status
))
978 /* Return the failure from CSRSS */
979 BaseSetLastNTError(ApiMessage
.Status
);
983 /* Get the data back */
984 *lpdwLevel
= ShutdownParametersRequest
->ShutdownLevel
;
985 *lpdwFlags
= ShutdownParametersRequest
->ShutdownFlags
;
994 SetProcessShutdownParameters(IN DWORD dwLevel
,
997 BASE_API_MESSAGE ApiMessage
;
998 PBASE_GETSET_PROCESS_SHUTDOWN_PARAMS ShutdownParametersRequest
= &ApiMessage
.Data
.ShutdownParametersRequest
;
1000 /* Write the data into the CSRSS request and send it */
1001 ShutdownParametersRequest
->ShutdownLevel
= dwLevel
;
1002 ShutdownParametersRequest
->ShutdownFlags
= dwFlags
;
1003 CsrClientCallServer((PCSR_API_MESSAGE
)&ApiMessage
,
1005 CSR_CREATE_API_NUMBER(BASESRV_SERVERDLL_INDEX
, BasepSetProcessShutdownParam
),
1006 sizeof(*ShutdownParametersRequest
));
1007 if (!NT_SUCCESS(ApiMessage
.Status
))
1009 /* Return the failure from CSRSS */
1010 BaseSetLastNTError(ApiMessage
.Status
);
1023 GetProcessWorkingSetSizeEx(IN HANDLE hProcess
,
1024 OUT PSIZE_T lpMinimumWorkingSetSize
,
1025 OUT PSIZE_T lpMaximumWorkingSetSize
,
1028 QUOTA_LIMITS_EX QuotaLimits
;
1031 /* Query the kernel about this */
1032 Status
= NtQueryInformationProcess(hProcess
,
1035 sizeof(QuotaLimits
),
1037 if (!NT_SUCCESS(Status
))
1040 BaseSetLastNTError(Status
);
1044 /* Copy the quota information out */
1045 *lpMinimumWorkingSetSize
= QuotaLimits
.MinimumWorkingSetSize
;
1046 *lpMaximumWorkingSetSize
= QuotaLimits
.MaximumWorkingSetSize
;
1047 *Flags
= QuotaLimits
.Flags
;
1056 GetProcessWorkingSetSize(IN HANDLE hProcess
,
1057 OUT PSIZE_T lpMinimumWorkingSetSize
,
1058 OUT PSIZE_T lpMaximumWorkingSetSize
)
1061 return GetProcessWorkingSetSizeEx(hProcess
,
1062 lpMinimumWorkingSetSize
,
1063 lpMaximumWorkingSetSize
,
1072 SetProcessWorkingSetSizeEx(IN HANDLE hProcess
,
1073 IN SIZE_T dwMinimumWorkingSetSize
,
1074 IN SIZE_T dwMaximumWorkingSetSize
,
1077 QUOTA_LIMITS_EX QuotaLimits
;
1078 NTSTATUS Status
, ReturnStatus
;
1081 ULONG Privilege
= SE_INC_BASE_PRIORITY_PRIVILEGE
;
1083 /* Zero out the input structure */
1084 RtlZeroMemory(&QuotaLimits
, sizeof(QuotaLimits
));
1086 /* Check if the caller sent any limits */
1087 if ((dwMinimumWorkingSetSize
) && (dwMaximumWorkingSetSize
))
1089 /* Write the quota information */
1090 QuotaLimits
.MinimumWorkingSetSize
= dwMinimumWorkingSetSize
;
1091 QuotaLimits
.MaximumWorkingSetSize
= dwMaximumWorkingSetSize
;
1092 QuotaLimits
.Flags
= Flags
;
1094 /* Acquire the required privilege */
1095 Status
= RtlAcquirePrivilege(&Privilege
, 1, 0, &State
);
1097 /* Request the new quotas */
1098 ReturnStatus
= NtSetInformationProcess(hProcess
,
1101 sizeof(QuotaLimits
));
1102 Result
= NT_SUCCESS(ReturnStatus
);
1103 if (NT_SUCCESS(Status
))
1105 /* Release the privilege and set succes code */
1106 ASSERT(State
!= NULL
);
1107 RtlReleasePrivilege(State
);
1113 /* No limits, fail the call */
1114 ReturnStatus
= STATUS_INVALID_PARAMETER
;
1118 /* Return result code, set error code if this was a failure */
1119 if (!Result
) BaseSetLastNTError(ReturnStatus
);
1128 SetProcessWorkingSetSize(IN HANDLE hProcess
,
1129 IN SIZE_T dwMinimumWorkingSetSize
,
1130 IN SIZE_T dwMaximumWorkingSetSize
)
1132 /* Call the newer API */
1133 return SetProcessWorkingSetSizeEx(hProcess
,
1134 dwMinimumWorkingSetSize
,
1135 dwMaximumWorkingSetSize
,
1144 GetProcessTimes(IN HANDLE hProcess
,
1145 IN LPFILETIME lpCreationTime
,
1146 IN LPFILETIME lpExitTime
,
1147 IN LPFILETIME lpKernelTime
,
1148 IN LPFILETIME lpUserTime
)
1150 KERNEL_USER_TIMES Kut
;
1153 /* Query the times */
1154 Status
= NtQueryInformationProcess(hProcess
,
1159 if (!NT_SUCCESS(Status
))
1161 /* Handle failure */
1162 BaseSetLastNTError(Status
);
1166 /* Copy all the times and return success */
1167 lpCreationTime
->dwLowDateTime
= Kut
.CreateTime
.u
.LowPart
;
1168 lpCreationTime
->dwHighDateTime
= Kut
.CreateTime
.u
.HighPart
;
1169 lpExitTime
->dwLowDateTime
= Kut
.ExitTime
.u
.LowPart
;
1170 lpExitTime
->dwHighDateTime
= Kut
.ExitTime
.u
.HighPart
;
1171 lpKernelTime
->dwLowDateTime
= Kut
.KernelTime
.u
.LowPart
;
1172 lpKernelTime
->dwHighDateTime
= Kut
.KernelTime
.u
.HighPart
;
1173 lpUserTime
->dwLowDateTime
= Kut
.UserTime
.u
.LowPart
;
1174 lpUserTime
->dwHighDateTime
= Kut
.UserTime
.u
.HighPart
;
1183 GetCurrentProcess(VOID
)
1185 return (HANDLE
)NtCurrentProcess();
1193 GetCurrentThread(VOID
)
1195 return (HANDLE
)NtCurrentThread();
1203 GetCurrentProcessId(VOID
)
1205 return HandleToUlong(NtCurrentTeb()->ClientId
.UniqueProcess
);
1213 GetExitCodeProcess(IN HANDLE hProcess
,
1214 IN LPDWORD lpExitCode
)
1216 PROCESS_BASIC_INFORMATION ProcessBasic
;
1219 /* Ask the kernel */
1220 Status
= NtQueryInformationProcess(hProcess
,
1221 ProcessBasicInformation
,
1223 sizeof(ProcessBasic
),
1225 if (!NT_SUCCESS(Status
))
1227 /* We failed, was this because this is a VDM process? */
1228 if (BaseCheckForVDM(hProcess
, lpExitCode
) == TRUE
) return TRUE
;
1230 /* Not a VDM process, fail the call */
1231 BaseSetLastNTError(Status
);
1235 /* Succes case, return the exit code */
1236 *lpExitCode
= (DWORD
)ProcessBasic
.ExitStatus
;
1245 GetProcessId(IN HANDLE Process
)
1247 PROCESS_BASIC_INFORMATION ProcessBasic
;
1250 /* Query the kernel */
1251 Status
= NtQueryInformationProcess(Process
,
1252 ProcessBasicInformation
,
1254 sizeof(ProcessBasic
),
1256 if (!NT_SUCCESS(Status
))
1258 /* Handle failure */
1259 BaseSetLastNTError(Status
);
1263 /* Return the PID */
1264 return (DWORD
)ProcessBasic
.UniqueProcessId
;
1272 OpenProcess(IN DWORD dwDesiredAccess
,
1273 IN BOOL bInheritHandle
,
1274 IN DWORD dwProcessId
)
1277 HANDLE ProcessHandle
;
1278 OBJECT_ATTRIBUTES ObjectAttributes
;
1281 /* Setup the input client ID structure */
1282 ClientId
.UniqueProcess
= UlongToHandle(dwProcessId
);
1283 ClientId
.UniqueThread
= 0;
1285 /* This is needed just to define the inheritance flags */
1286 InitializeObjectAttributes(&ObjectAttributes
,
1288 (bInheritHandle
? OBJ_INHERIT
: 0),
1292 /* Now try to open the process */
1293 Status
= NtOpenProcess(&ProcessHandle
,
1297 if (!NT_SUCCESS(Status
))
1299 /* Handle failure */
1300 BaseSetLastNTError(Status
);
1304 /* Otherwise return a handle to the process */
1305 return ProcessHandle
;
1313 RegisterWaitForInputIdle(IN WaitForInputIdleType lpfnRegisterWaitForInputIdle
)
1315 /* Write the global function pointer */
1316 UserWaitForInputIdleRoutine
= lpfnRegisterWaitForInputIdle
;
1324 GetStartupInfoW(IN LPSTARTUPINFOW lpStartupInfo
)
1326 PRTL_USER_PROCESS_PARAMETERS Params
;
1328 /* Get the process parameters */
1329 Params
= NtCurrentPeb()->ProcessParameters
;
1331 /* Copy the data out of there */
1332 lpStartupInfo
->cb
= sizeof(STARTUPINFOW
);
1333 lpStartupInfo
->lpReserved
= Params
->ShellInfo
.Buffer
;
1334 lpStartupInfo
->lpDesktop
= Params
->DesktopInfo
.Buffer
;
1335 lpStartupInfo
->lpTitle
= Params
->WindowTitle
.Buffer
;
1336 lpStartupInfo
->dwX
= Params
->StartingX
;
1337 lpStartupInfo
->dwY
= Params
->StartingY
;
1338 lpStartupInfo
->dwXSize
= Params
->CountX
;
1339 lpStartupInfo
->dwYSize
= Params
->CountY
;
1340 lpStartupInfo
->dwXCountChars
= Params
->CountCharsX
;
1341 lpStartupInfo
->dwYCountChars
= Params
->CountCharsY
;
1342 lpStartupInfo
->dwFillAttribute
= Params
->FillAttribute
;
1343 lpStartupInfo
->dwFlags
= Params
->WindowFlags
;
1344 lpStartupInfo
->wShowWindow
= (WORD
)Params
->ShowWindowFlags
;
1345 lpStartupInfo
->cbReserved2
= Params
->RuntimeData
.Length
;
1346 lpStartupInfo
->lpReserved2
= (LPBYTE
)Params
->RuntimeData
.Buffer
;
1348 /* Check if the standard handles are being used for other features */
1349 if (lpStartupInfo
->dwFlags
& (STARTF_USESTDHANDLES
|
1351 STARTF_SHELLPRIVATE
))
1353 /* These are, so copy the standard handles too */
1354 lpStartupInfo
->hStdInput
= Params
->StandardInput
;
1355 lpStartupInfo
->hStdOutput
= Params
->StandardOutput
;
1356 lpStartupInfo
->hStdError
= Params
->StandardError
;
1365 GetStartupInfoA(IN LPSTARTUPINFOA lpStartupInfo
)
1367 PRTL_USER_PROCESS_PARAMETERS Params
;
1368 ANSI_STRING TitleString
, ShellString
, DesktopString
;
1369 LPSTARTUPINFOA StartupInfo
;
1372 /* Get the cached information as well as the PEB parameters */
1373 StartupInfo
= BaseAnsiStartupInfo
;
1374 Params
= NtCurrentPeb()->ProcessParameters
;
1376 /* Check if this is the first time we have to get the cached version */
1377 while (!StartupInfo
)
1379 /* Create new ANSI startup info */
1380 StartupInfo
= RtlAllocateHeap(RtlGetProcessHeap(),
1382 sizeof(*StartupInfo
));
1385 /* Zero out string pointers in case we fail to create them */
1386 StartupInfo
->lpReserved
= 0;
1387 StartupInfo
->lpDesktop
= 0;
1388 StartupInfo
->lpTitle
= 0;
1391 StartupInfo
->cb
= sizeof(*StartupInfo
);
1393 /* Copy what's already stored in the PEB */
1394 StartupInfo
->dwX
= Params
->StartingX
;
1395 StartupInfo
->dwY
= Params
->StartingY
;
1396 StartupInfo
->dwXSize
= Params
->CountX
;
1397 StartupInfo
->dwYSize
= Params
->CountY
;
1398 StartupInfo
->dwXCountChars
= Params
->CountCharsX
;
1399 StartupInfo
->dwYCountChars
= Params
->CountCharsY
;
1400 StartupInfo
->dwFillAttribute
= Params
->FillAttribute
;
1401 StartupInfo
->dwFlags
= Params
->WindowFlags
;
1402 StartupInfo
->wShowWindow
= (WORD
)Params
->ShowWindowFlags
;
1403 StartupInfo
->cbReserved2
= Params
->RuntimeData
.Length
;
1404 StartupInfo
->lpReserved2
= (LPBYTE
)Params
->RuntimeData
.Buffer
;
1405 StartupInfo
->hStdInput
= Params
->StandardInput
;
1406 StartupInfo
->hStdOutput
= Params
->StandardOutput
;
1407 StartupInfo
->hStdError
= Params
->StandardError
;
1409 /* Copy shell info string */
1410 Status
= RtlUnicodeStringToAnsiString(&ShellString
,
1413 if (NT_SUCCESS(Status
))
1416 StartupInfo
->lpReserved
= ShellString
.Buffer
;
1418 /* Copy desktop info string */
1419 Status
= RtlUnicodeStringToAnsiString(&DesktopString
,
1420 &Params
->DesktopInfo
,
1422 if (NT_SUCCESS(Status
))
1425 StartupInfo
->lpDesktop
= DesktopString
.Buffer
;
1427 /* Copy window title string */
1428 Status
= RtlUnicodeStringToAnsiString(&TitleString
,
1429 &Params
->WindowTitle
,
1431 if (NT_SUCCESS(Status
))
1434 StartupInfo
->lpTitle
= TitleString
.Buffer
;
1436 /* We finished with the ANSI version, try to cache it */
1437 if (!InterlockedCompareExchangePointer((PVOID
*)&BaseAnsiStartupInfo
,
1441 /* We were the first thread through, use the data */
1445 /* Someone beat us to it, use their data instead */
1446 StartupInfo
= BaseAnsiStartupInfo
;
1447 Status
= STATUS_SUCCESS
;
1449 /* We're going to free our own stuff, but not raise */
1450 RtlFreeAnsiString(&TitleString
);
1452 RtlFreeAnsiString(&DesktopString
);
1454 RtlFreeAnsiString(&ShellString
);
1456 RtlFreeHeap(RtlGetProcessHeap(), 0, StartupInfo
);
1460 /* No memory, fail */
1461 Status
= STATUS_NO_MEMORY
;
1464 /* Raise an error unless we got here due to the race condition */
1465 if (!NT_SUCCESS(Status
)) RtlRaiseStatus(Status
);
1468 /* Now copy from the cached ANSI version */
1469 lpStartupInfo
->cb
= StartupInfo
->cb
;
1470 lpStartupInfo
->lpReserved
= StartupInfo
->lpReserved
;
1471 lpStartupInfo
->lpDesktop
= StartupInfo
->lpDesktop
;
1472 lpStartupInfo
->lpTitle
= StartupInfo
->lpTitle
;
1473 lpStartupInfo
->dwX
= StartupInfo
->dwX
;
1474 lpStartupInfo
->dwY
= StartupInfo
->dwY
;
1475 lpStartupInfo
->dwXSize
= StartupInfo
->dwXSize
;
1476 lpStartupInfo
->dwYSize
= StartupInfo
->dwYSize
;
1477 lpStartupInfo
->dwXCountChars
= StartupInfo
->dwXCountChars
;
1478 lpStartupInfo
->dwYCountChars
= StartupInfo
->dwYCountChars
;
1479 lpStartupInfo
->dwFillAttribute
= StartupInfo
->dwFillAttribute
;
1480 lpStartupInfo
->dwFlags
= StartupInfo
->dwFlags
;
1481 lpStartupInfo
->wShowWindow
= StartupInfo
->wShowWindow
;
1482 lpStartupInfo
->cbReserved2
= StartupInfo
->cbReserved2
;
1483 lpStartupInfo
->lpReserved2
= StartupInfo
->lpReserved2
;
1485 /* Check if the shell is hijacking the handles for other features */
1486 if (lpStartupInfo
->dwFlags
&
1487 (STARTF_USESTDHANDLES
| STARTF_USEHOTKEY
| STARTF_SHELLPRIVATE
))
1489 /* It isn't, so we can return the raw values */
1490 lpStartupInfo
->hStdInput
= StartupInfo
->hStdInput
;
1491 lpStartupInfo
->hStdOutput
= StartupInfo
->hStdOutput
;
1492 lpStartupInfo
->hStdError
= StartupInfo
->hStdError
;
1496 /* It is, so make sure nobody uses these as console handles */
1497 lpStartupInfo
->hStdInput
= INVALID_HANDLE_VALUE
;
1498 lpStartupInfo
->hStdOutput
= INVALID_HANDLE_VALUE
;
1499 lpStartupInfo
->hStdError
= INVALID_HANDLE_VALUE
;
1508 FlushInstructionCache(IN HANDLE hProcess
,
1509 IN LPCVOID lpBaseAddress
,
1514 /* Call the native function */
1515 Status
= NtFlushInstructionCache(hProcess
, (PVOID
)lpBaseAddress
, nSize
);
1516 if (!NT_SUCCESS(Status
))
1518 /* Handle failure case */
1519 BaseSetLastNTError(Status
);
1532 ExitProcess(IN UINT uExitCode
)
1534 BASE_API_MESSAGE ApiMessage
;
1535 PBASE_EXIT_PROCESS ExitProcessRequest
= &ApiMessage
.Data
.ExitProcessRequest
;
1537 ASSERT(!BaseRunningInServerProcess
);
1541 /* Acquire the PEB lock */
1542 RtlAcquirePebLock();
1544 /* Kill all the threads */
1545 NtTerminateProcess(NULL
, uExitCode
);
1547 /* Unload all DLLs */
1548 LdrShutdownProcess();
1550 /* Notify Base Server of process termination */
1551 ExitProcessRequest
->uExitCode
= uExitCode
;
1552 CsrClientCallServer((PCSR_API_MESSAGE
)&ApiMessage
,
1554 CSR_CREATE_API_NUMBER(BASESRV_SERVERDLL_INDEX
, BasepExitProcess
),
1555 sizeof(*ExitProcessRequest
));
1557 /* Now do it again */
1558 NtTerminateProcess(NtCurrentProcess(), uExitCode
);
1562 /* Release the PEB lock */
1563 RtlReleasePebLock();
1567 /* should never get here */
1577 TerminateProcess(IN HANDLE hProcess
,
1582 /* Check if no handle was passed in */
1585 /* Set error code */
1586 SetLastError(ERROR_INVALID_HANDLE
);
1590 /* Otherwise, try to terminate the process */
1591 Status
= NtTerminateProcess(hProcess
, uExitCode
);
1592 if (NT_SUCCESS(Status
)) return TRUE
;
1594 /* It failed, convert error code */
1595 BaseSetLastNTError(Status
);
1598 /* This is the failure path */
1607 FatalAppExitA(UINT uAction
,
1608 LPCSTR lpMessageText
)
1610 PUNICODE_STRING MessageTextU
;
1611 ANSI_STRING MessageText
;
1614 /* Initialize the string using the static TEB pointer */
1615 MessageTextU
= &NtCurrentTeb()->StaticUnicodeString
;
1616 RtlInitAnsiString(&MessageText
, (LPSTR
)lpMessageText
);
1618 /* Convert to unicode, or just exit normally if this failed */
1619 Status
= RtlAnsiStringToUnicodeString(MessageTextU
, &MessageText
, FALSE
);
1620 if (!NT_SUCCESS(Status
)) ExitProcess(0);
1622 /* Call the Wide function */
1623 FatalAppExitW(uAction
, MessageTextU
->Buffer
);
1631 FatalAppExitW(IN UINT uAction
,
1632 IN LPCWSTR lpMessageText
)
1634 UNICODE_STRING UnicodeString
;
1638 /* Setup the string to print out */
1639 RtlInitUnicodeString(&UnicodeString
, lpMessageText
);
1641 /* Display the hard error no matter what */
1642 Status
= NtRaiseHardError(STATUS_FATAL_APP_EXIT
| HARDERROR_OVERRIDE_ERRORMODE
,
1645 (PULONG_PTR
)&UnicodeString
,
1647 /* On Checked builds, Windows allows the user to cancel the operation */
1655 /* Give the user a chance to abort */
1656 if ((NT_SUCCESS(Status
)) && (Response
== ResponseCancel
)) return;
1659 /* Otherwise kill the process */
1668 FatalExit(IN
int ExitCode
)
1671 /* On Checked builds, Windows gives the user a nice little debugger UI */
1673 DbgPrint("FatalExit...\n");
1678 DbgPrompt( "A (Abort), B (Break), I (Ignore)? ", ch
, sizeof(ch
));
1686 ExitProcess(ExitCode
);
1693 /* On other builds, just kill the process */
1694 ExitProcess(ExitCode
);
1702 GetPriorityClass(IN HANDLE hProcess
)
1705 PROCESS_PRIORITY_CLASS PriorityClass
;
1707 /* Query the kernel */
1708 Status
= NtQueryInformationProcess(hProcess
,
1709 ProcessPriorityClass
,
1711 sizeof(PriorityClass
),
1713 if (NT_SUCCESS(Status
))
1715 /* Handle the conversion from NT to Win32 classes */
1716 switch (PriorityClass
.PriorityClass
)
1718 case PROCESS_PRIORITY_CLASS_IDLE
: return IDLE_PRIORITY_CLASS
;
1719 case PROCESS_PRIORITY_CLASS_BELOW_NORMAL
: return BELOW_NORMAL_PRIORITY_CLASS
;
1720 case PROCESS_PRIORITY_CLASS_ABOVE_NORMAL
: return ABOVE_NORMAL_PRIORITY_CLASS
;
1721 case PROCESS_PRIORITY_CLASS_HIGH
: return HIGH_PRIORITY_CLASS
;
1722 case PROCESS_PRIORITY_CLASS_REALTIME
: return REALTIME_PRIORITY_CLASS
;
1723 case PROCESS_PRIORITY_CLASS_NORMAL
: default: return NORMAL_PRIORITY_CLASS
;
1728 BaseSetLastNTError(Status
);
1737 SetPriorityClass(IN HANDLE hProcess
,
1738 IN DWORD dwPriorityClass
)
1742 PROCESS_PRIORITY_CLASS PriorityClass
;
1744 /* Handle conversion from Win32 to NT priority classes */
1745 switch (dwPriorityClass
)
1747 case IDLE_PRIORITY_CLASS
:
1748 PriorityClass
.PriorityClass
= PROCESS_PRIORITY_CLASS_IDLE
;
1751 case BELOW_NORMAL_PRIORITY_CLASS
:
1752 PriorityClass
.PriorityClass
= PROCESS_PRIORITY_CLASS_BELOW_NORMAL
;
1755 case NORMAL_PRIORITY_CLASS
:
1756 PriorityClass
.PriorityClass
= PROCESS_PRIORITY_CLASS_NORMAL
;
1759 case ABOVE_NORMAL_PRIORITY_CLASS
:
1760 PriorityClass
.PriorityClass
= PROCESS_PRIORITY_CLASS_ABOVE_NORMAL
;
1763 case HIGH_PRIORITY_CLASS
:
1764 PriorityClass
.PriorityClass
= PROCESS_PRIORITY_CLASS_HIGH
;
1767 case REALTIME_PRIORITY_CLASS
:
1768 /* Try to acquire the privilege. If it fails, just use HIGH */
1769 State
= BasepIsRealtimeAllowed(TRUE
);
1770 PriorityClass
.PriorityClass
= PROCESS_PRIORITY_CLASS_HIGH
;
1771 PriorityClass
.PriorityClass
+= (State
!= NULL
);
1775 /* Unrecognized priority classes don't make it to the kernel */
1776 SetLastError(ERROR_INVALID_PARAMETER
);
1780 /* Send the request to the kernel, and don't touch the foreground flag */
1781 PriorityClass
.Foreground
= FALSE
;
1782 Status
= NtSetInformationProcess(hProcess
,
1783 ProcessPriorityClass
,
1785 sizeof(PROCESS_PRIORITY_CLASS
));
1787 /* Release the privilege if we had it */
1788 if (State
) RtlReleasePrivilege(State
);
1789 if (!NT_SUCCESS(Status
))
1791 /* Handle error path */
1792 BaseSetLastNTError(Status
);
1805 GetProcessVersion(IN DWORD ProcessId
)
1808 PIMAGE_NT_HEADERS NtHeader
;
1809 PIMAGE_DOS_HEADER DosHeader
;
1811 PROCESS_BASIC_INFORMATION ProcessBasicInfo
;
1814 HANDLE ProcessHandle
= NULL
;
1816 USHORT VersionData
[2];
1819 /* We'll be accessing stuff that can fault, so protect everything with SEH */
1822 /* It this an in-process or out-of-process request? */
1823 if (!(ProcessId
) || (GetCurrentProcessId() == ProcessId
))
1825 /* It's in-process, so just read our own header */
1826 NtHeader
= RtlImageNtHeader(NtCurrentPeb()->ImageBaseAddress
);
1829 /* Unable to read the NT header, something is wrong here... */
1830 Status
= STATUS_INVALID_IMAGE_FORMAT
;
1834 /* Get the version straight out of the NT header */
1835 Version
= MAKELONG(NtHeader
->OptionalHeader
.MinorSubsystemVersion
,
1836 NtHeader
->OptionalHeader
.MajorSubsystemVersion
);
1840 /* Out-of-process, so open it */
1841 ProcessHandle
= OpenProcess(PROCESS_VM_READ
| PROCESS_QUERY_INFORMATION
,
1844 if (!ProcessHandle
) _SEH2_YIELD(return 0);
1846 /* Try to find out where its PEB lives */
1847 Status
= NtQueryInformationProcess(ProcessHandle
,
1848 ProcessBasicInformation
,
1850 sizeof(ProcessBasicInfo
),
1853 if (!NT_SUCCESS(Status
)) goto Error
;
1854 Peb
= ProcessBasicInfo
.PebBaseAddress
;
1856 /* Now that we have the PEB, read the image base address out of it */
1857 Result
= ReadProcessMemory(ProcessHandle
,
1858 &Peb
->ImageBaseAddress
,
1860 sizeof(BaseAddress
),
1862 if (!Result
) goto Error
;
1864 /* Now read the e_lfanew (offset to NT header) from the base */
1865 DosHeader
= BaseAddress
;
1866 Result
= ReadProcessMemory(ProcessHandle
,
1867 &DosHeader
->e_lfanew
,
1871 if (!Result
) goto Error
;
1873 /* And finally, read the NT header itself by adding the offset */
1874 NtHeader
= (PVOID
)((ULONG_PTR
)BaseAddress
+ e_lfanew
);
1875 Result
= ReadProcessMemory(ProcessHandle
,
1876 &NtHeader
->OptionalHeader
.MajorSubsystemVersion
,
1878 sizeof(VersionData
),
1880 if (!Result
) goto Error
;
1882 /* Get the version straight out of the NT header */
1883 Version
= MAKELONG(VersionData
[0], VersionData
[1]);
1886 /* If there was an error anywhere, set the last error */
1887 if (!NT_SUCCESS(Status
)) BaseSetLastNTError(Status
);
1892 /* Close the process handle */
1893 if (ProcessHandle
) CloseHandle(ProcessHandle
);
1897 /* And return the version data */
1906 GetProcessIoCounters(IN HANDLE hProcess
,
1907 OUT PIO_COUNTERS lpIoCounters
)
1911 /* Query the kernel. Structures are identical, so let it do the copy too. */
1912 Status
= NtQueryInformationProcess(hProcess
,
1915 sizeof(IO_COUNTERS
),
1917 if (!NT_SUCCESS(Status
))
1919 /* Handle error path */
1920 BaseSetLastNTError(Status
);
1933 GetProcessPriorityBoost(IN HANDLE hProcess
,
1934 OUT PBOOL pDisablePriorityBoost
)
1937 ULONG PriorityBoost
;
1939 /* Query the kernel */
1940 Status
= NtQueryInformationProcess(hProcess
,
1941 ProcessPriorityBoost
,
1943 sizeof(PriorityBoost
),
1945 if (NT_SUCCESS(Status
))
1947 /* Convert from ULONG to a BOOL */
1948 *pDisablePriorityBoost
= PriorityBoost
? TRUE
: FALSE
;
1952 /* Handle error path */
1953 BaseSetLastNTError(Status
);
1962 SetProcessPriorityBoost(IN HANDLE hProcess
,
1963 IN BOOL bDisablePriorityBoost
)
1966 ULONG PriorityBoost
;
1968 /* Enforce that this is a BOOL, and send it to the kernel as a ULONG */
1969 PriorityBoost
= (bDisablePriorityBoost
? TRUE
: FALSE
);
1970 Status
= NtSetInformationProcess(hProcess
,
1971 ProcessPriorityBoost
,
1974 if (!NT_SUCCESS(Status
))
1976 /* Handle error path */
1977 BaseSetLastNTError(Status
);
1990 GetProcessHandleCount(IN HANDLE hProcess
,
1991 OUT PDWORD pdwHandleCount
)
1996 /* Query the kernel */
1997 Status
= NtQueryInformationProcess(hProcess
,
2002 if (NT_SUCCESS(Status
))
2004 /* Copy the count and return success */
2005 *pdwHandleCount
= phc
;
2009 /* Handle error path */
2010 BaseSetLastNTError(Status
);
2019 IsWow64Process(IN HANDLE hProcess
,
2020 OUT PBOOL Wow64Process
)
2025 /* Query the kernel */
2026 Status
= NtQueryInformationProcess(hProcess
,
2027 ProcessWow64Information
,
2031 if (!NT_SUCCESS(Status
))
2033 /* Handle error path */
2034 BaseSetLastNTError(Status
);
2038 /* Enforce this is a BOOL, and return success */
2039 *Wow64Process
= (pbi
!= 0);
2048 GetCommandLineA(VOID
)
2050 return BaseAnsiCommandLine
.Buffer
;
2058 GetCommandLineW(VOID
)
2060 return BaseUnicodeCommandLine
.Buffer
;
2068 ReadProcessMemory(IN HANDLE hProcess
,
2069 IN LPCVOID lpBaseAddress
,
2072 OUT SIZE_T
* lpNumberOfBytesRead
)
2077 Status
= NtReadVirtualMemory(hProcess
,
2078 (PVOID
)lpBaseAddress
,
2083 /* In user-mode, this parameter is optional */
2084 if (lpNumberOfBytesRead
) *lpNumberOfBytesRead
= nSize
;
2085 if (!NT_SUCCESS(Status
))
2088 BaseSetLastNTError(Status
);
2092 /* Return success */
2101 WriteProcessMemory(IN HANDLE hProcess
,
2102 IN LPVOID lpBaseAddress
,
2103 IN LPCVOID lpBuffer
,
2105 OUT SIZE_T
*lpNumberOfBytesWritten
)
2113 /* Set parameters for protect call */
2115 Base
= lpBaseAddress
;
2117 /* Check the current status */
2118 Status
= NtProtectVirtualMemory(hProcess
,
2121 PAGE_EXECUTE_READWRITE
,
2123 if (NT_SUCCESS(Status
))
2125 /* Check if we are unprotecting */
2126 UnProtect
= OldValue
& (PAGE_READWRITE
|
2128 PAGE_EXECUTE_READWRITE
|
2129 PAGE_EXECUTE_WRITECOPY
) ? FALSE
: TRUE
;
2132 /* Set the new protection */
2133 Status
= NtProtectVirtualMemory(hProcess
,
2139 /* Write the memory */
2140 Status
= NtWriteVirtualMemory(hProcess
,
2146 /* In Win32, the parameter is optional, so handle this case */
2147 if (lpNumberOfBytesWritten
) *lpNumberOfBytesWritten
= nSize
;
2149 if (!NT_SUCCESS(Status
))
2152 BaseSetLastNTError(Status
);
2156 /* Flush the ITLB */
2157 NtFlushInstructionCache(hProcess
, lpBaseAddress
, nSize
);
2162 /* Check if we were read only */
2163 if (OldValue
& (PAGE_NOACCESS
| PAGE_READONLY
))
2165 /* Restore protection and fail */
2166 NtProtectVirtualMemory(hProcess
,
2171 BaseSetLastNTError(STATUS_ACCESS_VIOLATION
);
2173 /* Note: This is what Windows returns and code depends on it */
2174 return STATUS_ACCESS_VIOLATION
;
2177 /* Otherwise, do the write */
2178 Status
= NtWriteVirtualMemory(hProcess
,
2184 /* In Win32, the parameter is optional, so handle this case */
2185 if (lpNumberOfBytesWritten
) *lpNumberOfBytesWritten
= nSize
;
2187 /* And restore the protection */
2188 NtProtectVirtualMemory(hProcess
,
2193 if (!NT_SUCCESS(Status
))
2196 BaseSetLastNTError(STATUS_ACCESS_VIOLATION
);
2198 /* Note: This is what Windows returns and code depends on it */
2199 return STATUS_ACCESS_VIOLATION
;
2202 /* Flush the ITLB */
2203 NtFlushInstructionCache(hProcess
, lpBaseAddress
, nSize
);
2210 BaseSetLastNTError(Status
);
2220 ProcessIdToSessionId(IN DWORD dwProcessId
,
2221 OUT PDWORD pSessionId
)
2223 PROCESS_SESSION_INFORMATION SessionInformation
;
2224 OBJECT_ATTRIBUTES ObjectAttributes
;
2226 HANDLE ProcessHandle
;
2229 /* Do a quick check if the pointer is not writable */
2230 if (IsBadWritePtr(pSessionId
, sizeof(DWORD
)))
2233 SetLastError(ERROR_INVALID_PARAMETER
);
2237 /* Open the process passed in by ID */
2238 ClientId
.UniqueProcess
= UlongToHandle(dwProcessId
);
2239 ClientId
.UniqueThread
= 0;
2240 InitializeObjectAttributes(&ObjectAttributes
, NULL
, 0, NULL
, NULL
);
2241 Status
= NtOpenProcess(&ProcessHandle
,
2242 PROCESS_QUERY_INFORMATION
,
2245 if (NT_SUCCESS(Status
))
2247 /* Query the session ID from the kernel */
2248 Status
= NtQueryInformationProcess(ProcessHandle
,
2249 ProcessSessionInformation
,
2250 &SessionInformation
,
2251 sizeof(SessionInformation
),
2254 /* Close the handle and check if we succeeded */
2255 NtClose(ProcessHandle
);
2256 if (NT_SUCCESS(Status
))
2258 /* Return the session ID */
2259 *pSessionId
= SessionInformation
.SessionId
;
2264 /* Set error code and fail */
2265 BaseSetLastNTError(Status
);
2270 #define AddToHandle(x,y) (x) = (HANDLE)((ULONG_PTR)(x) | (y));
2271 #define RemoveFromHandle(x,y) (x) = (HANDLE)((ULONG_PTR)(x) & ~(y));
2272 C_ASSERT(PROCESS_PRIORITY_CLASS_REALTIME
== (PROCESS_PRIORITY_CLASS_HIGH
+ 1));
2279 CreateProcessInternalW(IN HANDLE hUserToken
,
2280 IN LPCWSTR lpApplicationName
,
2281 IN LPWSTR lpCommandLine
,
2282 IN LPSECURITY_ATTRIBUTES lpProcessAttributes
,
2283 IN LPSECURITY_ATTRIBUTES lpThreadAttributes
,
2284 IN BOOL bInheritHandles
,
2285 IN DWORD dwCreationFlags
,
2286 IN LPVOID lpEnvironment
,
2287 IN LPCWSTR lpCurrentDirectory
,
2288 IN LPSTARTUPINFOW lpStartupInfo
,
2289 IN LPPROCESS_INFORMATION lpProcessInformation
,
2290 OUT PHANDLE hNewToken
)
2293 // Core variables used for creating the initial process and thread
2295 SECURITY_ATTRIBUTES LocalThreadAttributes
, LocalProcessAttributes
;
2296 OBJECT_ATTRIBUTES LocalObjectAttributes
;
2297 POBJECT_ATTRIBUTES ObjectAttributes
;
2298 SECTION_IMAGE_INFORMATION ImageInformation
;
2299 IO_STATUS_BLOCK IoStatusBlock
;
2301 ULONG NoWindow
, RegionSize
, StackSize
, ErrorCode
, Flags
;
2302 USHORT ImageMachine
;
2303 ULONG ParameterFlags
, PrivilegeValue
, HardErrorMode
, ErrorResponse
;
2304 ULONG_PTR ErrorParameters
[2];
2305 BOOLEAN InJob
, SaferNeeded
, UseLargePages
, HavePrivilege
;
2306 BOOLEAN QuerySection
, SkipSaferAndAppCompat
;
2308 BASE_API_MESSAGE CsrMsg
[2];
2309 PBASE_CREATE_PROCESS CreateProcessMsg
;
2310 PCSR_CAPTURE_BUFFER CaptureBuffer
;
2311 PVOID BaseAddress
, PrivilegeState
, RealTimePrivilegeState
;
2312 HANDLE DebugHandle
, TokenHandle
, JobHandle
, KeyHandle
, ThreadHandle
;
2313 HANDLE FileHandle
, SectionHandle
, ProcessHandle
;
2315 PROCESS_PRIORITY_CLASS PriorityClass
;
2316 NTSTATUS Status
, AppCompatStatus
, SaferStatus
, IFEOStatus
, ImageDbgStatus
;
2317 PPEB Peb
, RemotePeb
;
2319 INITIAL_TEB InitialTeb
;
2321 PIMAGE_NT_HEADERS NtHeaders
;
2322 STARTUPINFOW StartupInfo
;
2323 PRTL_USER_PROCESS_PARAMETERS ProcessParameters
;
2324 UNICODE_STRING DebuggerString
;
2327 // Variables used for command-line and argument parsing
2332 ULONG Length
, FileAttribs
, CmdQuoteLength
;
2333 ULONG CmdLineLength
, ResultSize
;
2334 PWCHAR QuotedCmdLine
, AnsiCmdCommand
, ExtBuffer
, CurrentDirectory
;
2335 PWCHAR NullBuffer
, ScanString
, NameBuffer
, SearchPath
, DebuggerCmdLine
;
2336 ANSI_STRING AnsiEnv
;
2337 UNICODE_STRING UnicodeEnv
, PathName
;
2338 BOOLEAN SearchRetry
, QuotesNeeded
, CmdLineIsAppName
, HasQuotes
;
2341 // Variables used for Fusion/SxS (Side-by-Side Assemblies)
2343 RTL_PATH_TYPE SxsPathType
, PathType
;
2344 #if _SXS_SUPPORT_ENABLED_
2345 PRTL_BUFFER ByteBuffer
;
2346 PRTL_UNICODE_STRING_BUFFER ThisBuffer
, Buffer
, SxsStaticBuffers
[5];
2347 PRTL_UNICODE_STRING_BUFFER
* BufferHead
, SxsStringBuffer
;
2348 RTL_UNICODE_STRING_BUFFER SxsWin32ManifestPath
, SxsNtManifestPath
;
2349 RTL_UNICODE_STRING_BUFFER SxsWin32PolicyPath
, SxsNtPolicyPath
;
2350 RTL_UNICODE_STRING_BUFFER SxsWin32AssemblyDirectory
;
2351 BASE_MSG_SXS_HANDLES MappedHandles
, Handles
, FileHandles
;
2352 PVOID CapturedStrings
[3];
2353 SXS_WIN32_NT_PATH_PAIR ExePathPair
, ManifestPathPair
, PolicyPathPair
;
2354 SXS_OVERRIDE_MANIFEST OverrideManifest
;
2355 UNICODE_STRING FreeString
, SxsNtExePath
;
2356 PWCHAR SxsConglomeratedBuffer
, StaticBuffer
;
2357 ULONG ConglomeratedBufferSizeBytes
, StaticBufferSize
, i
;
2362 // Variables used for path conversion (and partially Fusion/SxS)
2364 PWCHAR FilePart
, PathBuffer
, FreeBuffer
;
2365 BOOLEAN TranslationStatus
;
2366 RTL_RELATIVE_NAME_U SxsWin32RelativePath
;
2367 UNICODE_STRING PathBufferString
, SxsWin32ExePath
;
2370 // Variables used by Application Compatibility (and partially Fusion/SxS)
2372 PVOID AppCompatSxsData
, AppCompatData
;
2373 ULONG AppCompatSxsDataSize
, AppCompatDataSize
;
2375 // Variables used by VDM (Virtual Dos Machine) and WOW32 (16-bit Support)
2377 ULONG BinarySubType
, VdmBinaryType
, VdmTask
, VdmReserve
;
2379 BOOLEAN UseVdmReserve
;
2380 HANDLE VdmWaitObject
;
2381 ANSI_STRING VdmAnsiEnv
;
2382 UNICODE_STRING VdmString
, VdmUnicodeEnv
;
2384 PBASE_CHECK_VDM CheckVdmMsg
;
2386 /* Zero out the initial core variables and handles */
2387 QuerySection
= FALSE
;
2389 SkipSaferAndAppCompat
= FALSE
;
2396 SectionHandle
= NULL
;
2397 ProcessHandle
= NULL
;
2398 ThreadHandle
= NULL
;
2399 BaseAddress
= (PVOID
)1;
2401 /* Zero out initial SxS and Application Compatibility state */
2402 AppCompatData
= NULL
;
2403 AppCompatDataSize
= 0;
2404 AppCompatSxsData
= NULL
;
2405 AppCompatSxsDataSize
= 0;
2406 CaptureBuffer
= NULL
;
2407 #if _SXS_SUPPORT_ENABLED_
2408 SxsConglomeratedBuffer
= NULL
;
2412 /* Zero out initial parsing variables -- others are initialized later */
2413 DebuggerCmdLine
= NULL
;
2419 CurrentDirectory
= NULL
;
2421 DebuggerString
.Buffer
= NULL
;
2423 QuotedCmdLine
= NULL
;
2425 /* Zero out initial VDM state */
2426 VdmAnsiEnv
.Buffer
= NULL
;
2427 VdmUnicodeEnv
.Buffer
= NULL
;
2428 VdmString
.Buffer
= NULL
;
2433 VdmWaitObject
= NULL
;
2434 UseVdmReserve
= FALSE
;
2437 /* Set message structures */
2438 CreateProcessMsg
= &CsrMsg
[0].Data
.CreateProcessRequest
;
2439 CheckVdmMsg
= &CsrMsg
[1].Data
.CheckVDMRequest
;
2441 /* Clear the more complex structures by zeroing out their entire memory */
2442 RtlZeroMemory(&Context
, sizeof(Context
));
2443 #if _SXS_SUPPORT_ENABLED_
2444 RtlZeroMemory(&FileHandles
, sizeof(FileHandles
));
2445 RtlZeroMemory(&MappedHandles
, sizeof(MappedHandles
));
2446 RtlZeroMemory(&Handles
, sizeof(Handles
));
2448 RtlZeroMemory(&CreateProcessMsg
->Sxs
, sizeof(CreateProcessMsg
->Sxs
));
2449 RtlZeroMemory(&LocalProcessAttributes
, sizeof(LocalProcessAttributes
));
2450 RtlZeroMemory(&LocalThreadAttributes
, sizeof(LocalThreadAttributes
));
2452 /* Zero out output arguments as well */
2453 RtlZeroMemory(lpProcessInformation
, sizeof(*lpProcessInformation
));
2454 if (hNewToken
) *hNewToken
= NULL
;
2456 /* Capture the special window flag */
2457 NoWindow
= dwCreationFlags
& CREATE_NO_WINDOW
;
2458 dwCreationFlags
&= ~CREATE_NO_WINDOW
;
2460 #if _SXS_SUPPORT_ENABLED_
2461 /* Setup the SxS static string arrays and buffers */
2462 SxsStaticBuffers
[0] = &SxsWin32ManifestPath
;
2463 SxsStaticBuffers
[1] = &SxsWin32PolicyPath
;
2464 SxsStaticBuffers
[2] = &SxsWin32AssemblyDirectory
;
2465 SxsStaticBuffers
[3] = &SxsNtManifestPath
;
2466 SxsStaticBuffers
[4] = &SxsNtPolicyPath
;
2467 ExePathPair
.Win32
= &SxsWin32ExePath
;
2468 ExePathPair
.Nt
= &SxsNtExePath
;
2469 ManifestPathPair
.Win32
= &SxsWin32ManifestPath
.String
;
2470 ManifestPathPair
.Nt
= &SxsNtManifestPath
.String
;
2471 PolicyPathPair
.Win32
= &SxsWin32PolicyPath
.String
;
2472 PolicyPathPair
.Nt
= &SxsNtPolicyPath
.String
;
2475 DPRINT("CreateProcessInternalW: '%S' '%S' %lx\n", lpApplicationName
, lpCommandLine
, dwCreationFlags
);
2477 /* Finally, set our TEB and PEB */
2478 Teb
= NtCurrentTeb();
2479 Peb
= NtCurrentPeb();
2481 /* This combination is illegal (see MSDN) */
2482 if ((dwCreationFlags
& (DETACHED_PROCESS
| CREATE_NEW_CONSOLE
)) ==
2483 (DETACHED_PROCESS
| CREATE_NEW_CONSOLE
))
2485 DPRINT1("Invalid flag combo used\n");
2486 SetLastError(ERROR_INVALID_PARAMETER
);
2490 /* Convert the priority class */
2491 if (dwCreationFlags
& IDLE_PRIORITY_CLASS
)
2493 PriorityClass
.PriorityClass
= PROCESS_PRIORITY_CLASS_IDLE
;
2495 else if (dwCreationFlags
& BELOW_NORMAL_PRIORITY_CLASS
)
2497 PriorityClass
.PriorityClass
= PROCESS_PRIORITY_CLASS_BELOW_NORMAL
;
2499 else if (dwCreationFlags
& NORMAL_PRIORITY_CLASS
)
2501 PriorityClass
.PriorityClass
= PROCESS_PRIORITY_CLASS_NORMAL
;
2503 else if (dwCreationFlags
& ABOVE_NORMAL_PRIORITY_CLASS
)
2505 PriorityClass
.PriorityClass
= PROCESS_PRIORITY_CLASS_ABOVE_NORMAL
;
2507 else if (dwCreationFlags
& HIGH_PRIORITY_CLASS
)
2509 PriorityClass
.PriorityClass
= PROCESS_PRIORITY_CLASS_HIGH
;
2511 else if (dwCreationFlags
& REALTIME_PRIORITY_CLASS
)
2513 PriorityClass
.PriorityClass
= PROCESS_PRIORITY_CLASS_HIGH
;
2514 PriorityClass
.PriorityClass
+= (BasepIsRealtimeAllowed(FALSE
) != NULL
);
2518 PriorityClass
.PriorityClass
= PROCESS_PRIORITY_CLASS_INVALID
;
2521 /* Done with the priority masks, so get rid of them */
2522 PriorityClass
.Foreground
= FALSE
;
2523 dwCreationFlags
&= ~(NORMAL_PRIORITY_CLASS
|
2524 IDLE_PRIORITY_CLASS
|
2525 HIGH_PRIORITY_CLASS
|
2526 REALTIME_PRIORITY_CLASS
|
2527 BELOW_NORMAL_PRIORITY_CLASS
|
2528 ABOVE_NORMAL_PRIORITY_CLASS
);
2530 /* You cannot request both a shared and a separate WoW VDM */
2531 if ((dwCreationFlags
& CREATE_SEPARATE_WOW_VDM
) &&
2532 (dwCreationFlags
& CREATE_SHARED_WOW_VDM
))
2534 /* Fail such nonsensical attempts */
2535 DPRINT1("Invalid WOW flags\n");
2536 SetLastError(ERROR_INVALID_PARAMETER
);
2539 else if (!(dwCreationFlags
& CREATE_SHARED_WOW_VDM
) &&
2540 (BaseStaticServerData
->DefaultSeparateVDM
))
2542 /* A shared WoW VDM was not requested but system enforces separation */
2543 dwCreationFlags
|= CREATE_SEPARATE_WOW_VDM
;
2546 /* If a shared WoW VDM is used, make sure the process isn't in a job */
2547 if (!(dwCreationFlags
& CREATE_SEPARATE_WOW_VDM
) &&
2548 (NtIsProcessInJob(NtCurrentProcess(), NULL
)))
2550 /* Remove the shared flag and add the separate flag */
2551 dwCreationFlags
= (dwCreationFlags
&~ CREATE_SHARED_WOW_VDM
) |
2552 CREATE_SEPARATE_WOW_VDM
;
2555 /* Convert the environment */
2556 if ((lpEnvironment
) && !(dwCreationFlags
& CREATE_UNICODE_ENVIRONMENT
))
2558 /* Scan the environment to calculate its Unicode size */
2559 AnsiEnv
.Buffer
= pcScan
= (PCHAR
)lpEnvironment
;
2560 while ((*pcScan
) || (*(pcScan
+ 1))) ++pcScan
;
2562 /* Create our ANSI String */
2563 AnsiEnv
.Length
= pcScan
- (PCHAR
)lpEnvironment
+ sizeof(ANSI_NULL
);
2564 AnsiEnv
.MaximumLength
= AnsiEnv
.Length
+ sizeof(ANSI_NULL
);
2566 /* Allocate memory for the Unicode Environment */
2567 UnicodeEnv
.Buffer
= NULL
;
2568 RegionSize
= AnsiEnv
.MaximumLength
* sizeof(WCHAR
);
2569 Status
= NtAllocateVirtualMemory(NtCurrentProcess(),
2570 (PVOID
)&UnicodeEnv
.Buffer
,
2575 if (!NT_SUCCESS(Status
))
2578 BaseSetLastNTError(Status
);
2582 /* Use the allocated size and convert */
2583 UnicodeEnv
.MaximumLength
= (USHORT
)RegionSize
;
2584 Status
= RtlAnsiStringToUnicodeString(&UnicodeEnv
, &AnsiEnv
, FALSE
);
2585 if (!NT_SUCCESS(Status
))
2588 NtFreeVirtualMemory(NtCurrentProcess(),
2589 (PVOID
)&UnicodeEnv
.Buffer
,
2592 BaseSetLastNTError(Status
);
2596 /* Now set the Unicode environment as the environment string pointer */
2597 lpEnvironment
= UnicodeEnv
.Buffer
;
2600 /* Make a copy of the caller's startup info since we'll modify it */
2601 StartupInfo
= *lpStartupInfo
;
2603 /* Check if private data is being sent on the same channel as std handles */
2604 if ((StartupInfo
.dwFlags
& STARTF_USESTDHANDLES
) &&
2605 (StartupInfo
.dwFlags
& (STARTF_USEHOTKEY
| STARTF_SHELLPRIVATE
)))
2607 /* Cannot use the std handles since we have monitor/hotkey values */
2608 StartupInfo
.dwFlags
&= ~STARTF_USESTDHANDLES
;
2611 /* If there's a debugger, or we have to launch cmd.exe, we go back here */
2613 /* New iteration -- free any existing name buffer */
2616 RtlFreeHeap(RtlGetProcessHeap(), 0, NameBuffer
);
2620 /* New iteration -- free any existing free buffer */
2623 RtlFreeHeap(RtlGetProcessHeap(), 0, FreeBuffer
);
2627 /* New iteration -- close any existing file handle */
2630 NtClose(FileHandle
);
2634 /* Set the initial parsing state. This code can loop -- don't move this! */
2637 QuotesNeeded
= FALSE
;
2638 CmdLineIsAppName
= FALSE
;
2640 /* First check if we don't have an application name */
2641 if (!lpApplicationName
)
2643 /* This should be the first time we attempt creating one */
2644 ASSERT(NameBuffer
== NULL
);
2646 /* Allocate a buffer to hold it */
2647 NameBuffer
= RtlAllocateHeap(RtlGetProcessHeap(),
2649 MAX_PATH
* sizeof(WCHAR
));
2652 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
2657 /* Initialize the application name and our parsing parameters */
2658 lpApplicationName
= NullBuffer
= ScanString
= lpCommandLine
;
2660 /* Check for an initial quote*/
2661 if (*lpCommandLine
== L
'\"')
2663 /* We found a quote, keep searching for another one */
2664 SearchRetry
= FALSE
;
2666 lpApplicationName
= ScanString
;
2669 /* Have we found the terminating quote? */
2670 if (*ScanString
== L
'\"')
2672 /* We're done, get out of here */
2673 NullBuffer
= ScanString
;
2678 /* Keep searching for the quote */
2680 NullBuffer
= ScanString
;
2686 /* We simply make the application name be the command line*/
2687 lpApplicationName
= lpCommandLine
;
2690 /* Check if it starts with a space or tab */
2691 if ((*ScanString
== L
' ') || (*ScanString
== L
'\t'))
2693 /* Break out of the search loop */
2694 NullBuffer
= ScanString
;
2698 /* Keep searching for a space or tab */
2700 NullBuffer
= ScanString
;
2704 /* We have found the end of the application name, terminate it */
2705 SaveChar
= *NullBuffer
;
2706 *NullBuffer
= UNICODE_NULL
;
2708 /* New iteration -- free any existing saved path */
2711 RtlFreeHeap(RtlGetProcessHeap(), 0, SearchPath
);
2715 /* Now compute the final EXE path based on the name */
2716 SearchPath
= BaseComputeProcessExePath((LPWSTR
)lpApplicationName
);
2717 DPRINT("Search Path: %S\n", SearchPath
);
2720 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
2725 /* And search for the executable in the search path */
2726 Length
= SearchPathW(SearchPath
,
2733 /* Did we find it? */
2734 if ((Length
) && (Length
< MAX_PATH
))
2736 /* Get file attributes */
2737 FileAttribs
= GetFileAttributesW(NameBuffer
);
2738 if ((FileAttribs
!= INVALID_FILE_ATTRIBUTES
) &&
2739 (FileAttribs
& FILE_ATTRIBUTE_DIRECTORY
))
2741 /* This was a directory, fail later on */
2751 DPRINT("Length: %lu Buffer: %S\n", Length
, NameBuffer
);
2753 /* Check if there was a failure in SearchPathW */
2754 if ((Length
) && (Length
< MAX_PATH
))
2756 /* Everything looks good, restore the name */
2757 *NullBuffer
= SaveChar
;
2758 lpApplicationName
= NameBuffer
;
2762 /* Check if this was a relative path, which would explain it */
2763 PathType
= RtlDetermineDosPathNameType_U(lpApplicationName
);
2764 if (PathType
!= RtlPathTypeRelative
)
2766 /* This should fail, and give us a detailed LastError */
2767 FileHandle
= CreateFileW(lpApplicationName
,
2773 FILE_ATTRIBUTE_NORMAL
,
2775 if (FileHandle
!= INVALID_HANDLE_VALUE
)
2777 /* It worked? Return a generic error */
2778 CloseHandle(FileHandle
);
2780 BaseSetLastNTError(STATUS_OBJECT_NAME_NOT_FOUND
);
2785 /* Path was absolute, which means it doesn't exist */
2786 BaseSetLastNTError(STATUS_OBJECT_NAME_NOT_FOUND
);
2789 /* Did we already fail once? */
2792 /* Set the error code */
2793 SetLastError(ErrorCode
);
2797 /* Not yet, cache it */
2798 ErrorCode
= GetLastError();
2801 /* Put back the command line */
2802 *NullBuffer
= SaveChar
;
2803 lpApplicationName
= NameBuffer
;
2805 /* It's possible there's whitespace in the directory name */
2806 if (!(*ScanString
) || !(SearchRetry
))
2808 /* Not the case, give up completely */
2813 /* There are spaces, so keep trying the next possibility */
2815 NullBuffer
= ScanString
;
2817 /* We will have to add a quote, since there is a space */
2818 QuotesNeeded
= TRUE
;
2823 else if (!(lpCommandLine
) || !(*lpCommandLine
))
2825 /* We don't have a command line, so just use the application name */
2826 CmdLineIsAppName
= TRUE
;
2827 lpCommandLine
= (LPWSTR
)lpApplicationName
;
2830 /* Convert the application name to its NT path */
2831 TranslationStatus
= RtlDosPathNameToRelativeNtPathName_U(lpApplicationName
,
2834 &SxsWin32RelativePath
);
2835 if (!TranslationStatus
)
2837 /* Path must be invalid somehow, bail out */
2838 DPRINT1("Path translation for SxS failed\n");
2839 SetLastError(ERROR_PATH_NOT_FOUND
);
2844 /* Setup the buffer that needs to be freed at the end */
2845 ASSERT(FreeBuffer
== NULL
);
2846 FreeBuffer
= PathName
.Buffer
;
2848 /* Check what kind of path the application is, for SxS (Fusion) purposes */
2849 RtlInitUnicodeString(&SxsWin32ExePath
, lpApplicationName
);
2850 SxsPathType
= RtlDetermineDosPathNameType_U(lpApplicationName
);
2851 if ((SxsPathType
!= RtlPathTypeDriveAbsolute
) &&
2852 (SxsPathType
!= RtlPathTypeLocalDevice
) &&
2853 (SxsPathType
!= RtlPathTypeRootLocalDevice
) &&
2854 (SxsPathType
!= RtlPathTypeUncAbsolute
))
2856 /* Relative-type path, get the full path */
2857 RtlInitEmptyUnicodeString(&PathBufferString
, NULL
, 0);
2858 Status
= RtlGetFullPathName_UstrEx(&SxsWin32ExePath
,
2866 if (!NT_SUCCESS(Status
))
2868 /* Fail the rest of the create */
2869 RtlReleaseRelativeName(&SxsWin32RelativePath
);
2870 BaseSetLastNTError(Status
);
2875 /* Use this full path as the SxS path */
2876 SxsWin32ExePath
= PathBufferString
;
2877 PathBuffer
= PathBufferString
.Buffer
;
2878 PathBufferString
.Buffer
= NULL
;
2879 DPRINT("SxS Path: %S\n", PathBuffer
);
2882 /* Also set the .EXE path based on the path name */
2883 #if _SXS_SUPPORT_ENABLED_
2884 SxsNtExePath
= PathName
;
2886 if (SxsWin32RelativePath
.RelativeName
.Length
)
2888 /* If it's relative, capture the relative name */
2889 PathName
= SxsWin32RelativePath
.RelativeName
;
2893 /* Otherwise, it's absolute, make sure no relative dir is used */
2894 SxsWin32RelativePath
.ContainingDirectory
= NULL
;
2897 /* Now use the path name, and the root path, to try opening the app */
2898 DPRINT("Path: %wZ. Dir: %p\n", &PathName
, SxsWin32RelativePath
.ContainingDirectory
);
2899 InitializeObjectAttributes(&LocalObjectAttributes
,
2901 OBJ_CASE_INSENSITIVE
,
2902 SxsWin32RelativePath
.ContainingDirectory
,
2904 Status
= NtOpenFile(&FileHandle
,
2906 FILE_READ_ATTRIBUTES
|
2909 &LocalObjectAttributes
,
2911 FILE_SHARE_READ
| FILE_SHARE_DELETE
,
2912 FILE_SYNCHRONOUS_IO_NONALERT
|
2913 FILE_NON_DIRECTORY_FILE
);
2914 if (!NT_SUCCESS(Status
))
2916 /* Try to open the app just for execute purposes instead */
2917 Status
= NtOpenFile(&FileHandle
,
2918 SYNCHRONIZE
| FILE_EXECUTE
,
2919 &LocalObjectAttributes
,
2921 FILE_SHARE_READ
| FILE_SHARE_DELETE
,
2922 FILE_SYNCHRONOUS_IO_NONALERT
|
2923 FILE_NON_DIRECTORY_FILE
);
2926 /* Failure path, display which file failed to open */
2927 if (!NT_SUCCESS(Status
))
2928 DPRINT1("Open file failed: %lx (%wZ)\n", Status
, &PathName
);
2930 /* Cleanup in preparation for failure or success */
2931 RtlReleaseRelativeName(&SxsWin32RelativePath
);
2933 if (!NT_SUCCESS(Status
))
2935 /* Failure path, try to understand why */
2936 if (RtlIsDosDeviceName_U(lpApplicationName
))
2938 /* If a device is being executed, return this special error code */
2939 SetLastError(ERROR_BAD_DEVICE
);
2945 /* Otherwise return the converted NT error code */
2946 BaseSetLastNTError(Status
);
2952 /* Did the caller specify a desktop? */
2953 if (!StartupInfo
.lpDesktop
)
2955 /* Use the one from the current process */
2956 StartupInfo
.lpDesktop
= Peb
->ProcessParameters
->DesktopInfo
.Buffer
;
2959 /* Create a section for this file */
2960 Status
= NtCreateSection(&SectionHandle
,
2967 DPRINT("Section status: %lx\n", Status
);
2968 if (NT_SUCCESS(Status
))
2970 /* Are we running on Windows Embedded, Datacenter, Blade or Starter? */
2971 if (SharedUserData
->SuiteMask
& (VER_SUITE_EMBEDDEDNT
|
2972 VER_SUITE_DATACENTER
|
2973 VER_SUITE_PERSONAL
|
2976 /* These SKUs do not allow running certain applications */
2977 Status
= BasepCheckWebBladeHashes(FileHandle
);
2978 if (Status
== STATUS_ACCESS_DENIED
)
2980 /* And this is one of them! */
2981 DPRINT1("Invalid Blade hashes!\n");
2982 SetLastError(ERROR_ACCESS_DISABLED_WEBBLADE
);
2987 /* Did we get some other failure? */
2988 if (!NT_SUCCESS(Status
))
2990 /* If we couldn't check the hashes, assume nefariousness */
2991 DPRINT1("Tampered Blade hashes!\n");
2992 SetLastError(ERROR_ACCESS_DISABLED_WEBBLADE_TAMPER
);
2998 /* Now do Winsafer, etc, checks */
2999 Status
= BasepIsProcessAllowed((LPWSTR
)lpApplicationName
);
3000 if (!NT_SUCCESS(Status
))
3002 /* Fail if we're not allowed to launch the process */
3003 DPRINT1("Process not allowed to launch: %lx\n", Status
);
3004 BaseSetLastNTError(Status
);
3007 NtClose(SectionHandle
);
3008 SectionHandle
= NULL
;
3014 /* Is a DOS VDM being forced, but we already have a WOW32 instance ready? */
3015 if ((dwCreationFlags
& CREATE_FORCEDOS
) &&
3016 (BaseStaticServerData
->IsWowTaskReady
))
3018 /* This request can't be satisfied, instead, a separate VDM is needed */
3019 dwCreationFlags
&= ~(CREATE_FORCEDOS
| CREATE_SHARED_WOW_VDM
);
3020 dwCreationFlags
|= CREATE_SEPARATE_WOW_VDM
;
3022 /* Set a failure code, ask for VDM reservation */
3023 Status
= STATUS_INVALID_IMAGE_WIN_16
;
3024 UseVdmReserve
= TRUE
;
3026 /* Close the current handle */
3027 NtClose(SectionHandle
);
3028 SectionHandle
= NULL
;
3030 /* Don't query the section later */
3031 QuerySection
= FALSE
;
3035 /* Did we already do these checks? */
3036 if (!SkipSaferAndAppCompat
)
3038 /* Is everything OK so far, OR do we have an non-MZ, non-DOS app? */
3039 if ((NT_SUCCESS(Status
)) ||
3040 ((Status
== STATUS_INVALID_IMAGE_NOT_MZ
) &&
3041 !(BaseIsDosApplication(&PathName
, Status
))))
3043 /* Clear the machine type in case of failure */
3046 /* Clean any app compat data that may have accumulated */
3047 BasepFreeAppCompatData(AppCompatData
, AppCompatSxsData
);
3048 AppCompatData
= NULL
;
3049 AppCompatSxsData
= NULL
;
3051 /* Do we have a section? */
3054 /* Have we already queried it? */
3058 AppCompatStatus
= STATUS_SUCCESS
;
3062 /* Get some information about the executable */
3063 AppCompatStatus
= NtQuerySection(SectionHandle
,
3064 SectionImageInformation
,
3066 sizeof(ImageInformation
),
3070 /* Do we have section information now? */
3071 if (NT_SUCCESS(AppCompatStatus
))
3073 /* Don't ask for it again, save the machine type */
3074 QuerySection
= TRUE
;
3075 ImageMachine
= ImageInformation
.Machine
;
3079 /* Is there a reason/Shim we shouldn't run this application? */
3080 AppCompatStatus
= BasepCheckBadapp(FileHandle
,
3087 &AppCompatSxsDataSize
,
3089 if (!NT_SUCCESS(AppCompatStatus
))
3091 /* This is usually the status we get back */
3092 DPRINT1("App compat launch failure: %lx\n", AppCompatStatus
);
3093 if (AppCompatStatus
== STATUS_ACCESS_DENIED
)
3095 /* Convert it to something more Win32-specific */
3096 SetLastError(ERROR_CANCELLED
);
3100 /* Some other error */
3101 BaseSetLastNTError(AppCompatStatus
);
3104 /* Did we have a section? */
3108 NtClose(SectionHandle
);
3109 SectionHandle
= NULL
;
3119 //ASSERT((dwFusionFlags & ~SXS_APPCOMPACT_FLAG_APP_RUNNING_SAFEMODE) == 0);
3121 /* Have we already done, and do we need to do, SRP (WinSafer) checks? */
3122 if (!(SkipSaferAndAppCompat
) &&
3123 ~(dwCreationFlags
& CREATE_PRESERVE_CODE_AUTHZ_LEVEL
))
3129 case STATUS_INVALID_IMAGE_NE_FORMAT
:
3130 case STATUS_INVALID_IMAGE_PROTECT
:
3131 case STATUS_INVALID_IMAGE_WIN_16
:
3132 case STATUS_FILE_IS_OFFLINE
:
3133 /* For all DOS, 16-bit, OS/2 images, we do*/
3136 case STATUS_INVALID_IMAGE_NOT_MZ
:
3137 /* For invalid files, we don't, unless it's a .BAT file */
3138 if (BaseIsDosApplication(&PathName
, Status
)) break;
3141 /* Any other error codes we also don't */
3142 if (!NT_SUCCESS(Status
))
3144 SaferNeeded
= FALSE
;
3147 /* But for success, we do */
3151 /* Okay, so what did the checks above result in? */
3154 /* We have to call into the WinSafer library and actually check */
3155 SaferStatus
= BasepCheckWinSaferRestrictions(hUserToken
,
3156 (LPWSTR
)lpApplicationName
,
3161 if (SaferStatus
== 0xFFFFFFFF)
3163 /* Back in 2003, they didn't have an NTSTATUS for this... */
3164 DPRINT1("WinSafer blocking process launch\n");
3165 SetLastError(ERROR_ACCESS_DISABLED_BY_POLICY
);
3170 /* Other status codes are not-Safer related, just convert them */
3171 if (!NT_SUCCESS(SaferStatus
))
3173 DPRINT1("Error checking WinSafer: %lx\n", SaferStatus
);
3174 BaseSetLastNTError(SaferStatus
);
3181 /* The last step is to figure out why the section object was not created */
3184 case STATUS_INVALID_IMAGE_WIN_16
:
3186 /* 16-bit binary. Should we use WOW or does the caller force VDM? */
3187 if (!(dwCreationFlags
& CREATE_FORCEDOS
))
3189 /* Remember that we're launching WOW */
3192 /* Create the VDM environment, it's valid for WOW too */
3193 Result
= BaseCreateVDMEnvironment(lpEnvironment
,
3198 DPRINT1("VDM environment for WOW app failed\n");
3202 /* We're going to try this twice, so do a loop */
3205 /* Pick which kind of WOW mode we want to run in */
3206 VdmBinaryType
= (dwCreationFlags
&
3207 CREATE_SEPARATE_WOW_VDM
) ?
3208 BINARY_TYPE_SEPARATE_WOW
: BINARY_TYPE_WOW
;
3210 /* Get all the VDM settings and current status */
3211 Status
= BaseCheckVDM(VdmBinaryType
,
3222 /* If it worked, no need to try again */
3223 if (NT_SUCCESS(Status
)) break;
3225 /* Check if it's disallowed or if it's our second time */
3226 BaseSetLastNTError(Status
);
3227 if ((Status
== STATUS_VDM_DISALLOWED
) ||
3228 (VdmBinaryType
== BINARY_TYPE_SEPARATE_WOW
) ||
3229 (GetLastError() == ERROR_ACCESS_DENIED
))
3231 /* Fail the call -- we won't try again */
3232 DPRINT1("VDM message failure for WOW: %lx\n", Status
);
3237 /* Try one more time, but with a separate WOW instance */
3238 dwCreationFlags
|= CREATE_SEPARATE_WOW_VDM
;
3241 /* Check which VDM state we're currently in */
3242 switch (CheckVdmMsg
->VDMState
& (VDM_NOT_LOADED
|
3246 case VDM_NOT_LOADED
:
3247 /* VDM is not fully loaded, so not that much to undo */
3248 VdmUndoLevel
= VDM_UNDO_PARTIAL
;
3250 /* Reset VDM reserve if needed */
3251 if (UseVdmReserve
) VdmReserve
= 1;
3253 /* Get the required parameters and names for launch */
3254 Result
= BaseGetVdmConfigInfo(lpCommandLine
,
3261 DPRINT1("VDM Configuration failed for WOW\n");
3262 BaseSetLastNTError(Status
);
3266 /* Update the command-line with the VDM one instead */
3267 lpCommandLine
= VdmString
.Buffer
;
3268 lpApplicationName
= NULL
;
3270 /* We don't want a console, detachment, nor a window */
3271 dwCreationFlags
|= CREATE_NO_WINDOW
;
3272 dwCreationFlags
&= ~(CREATE_NEW_CONSOLE
| DETACHED_PROCESS
);
3274 /* Force feedback on */
3275 StartupInfo
.dwFlags
|= STARTF_FORCEONFEEDBACK
;
3280 /* VDM is ready, so we have to undo everything */
3281 VdmUndoLevel
= VDM_UNDO_REUSE
;
3283 /* Check if CSRSS wants us to wait on VDM */
3284 VdmWaitObject
= CheckVdmMsg
->WaitObjectForParent
;
3288 /* Something is wrong with VDM, we'll fail the call */
3289 DPRINT1("VDM is not ready for WOW\n");
3290 SetLastError(ERROR_NOT_READY
);
3298 /* Since to get NULL, we allocate from 0x1, account for this */
3301 /* This implies VDM is ready, so skip everything else */
3302 if (VdmWaitObject
) goto VdmShortCircuit
;
3304 /* Don't inherit handles since we're doing VDM now */
3305 bInheritHandles
= FALSE
;
3307 /* Had the user passed in environment? If so, destroy it */
3308 if ((lpEnvironment
) &&
3309 !(dwCreationFlags
& CREATE_UNICODE_ENVIRONMENT
))
3311 RtlDestroyEnvironment(lpEnvironment
);
3314 /* We've already done all these checks, don't do them again */
3315 SkipSaferAndAppCompat
= TRUE
;
3319 // There is no break here on purpose, so FORCEDOS drops down!
3322 case STATUS_INVALID_IMAGE_PROTECT
:
3323 case STATUS_INVALID_IMAGE_NOT_MZ
:
3324 case STATUS_INVALID_IMAGE_NE_FORMAT
:
3326 /* We're launching an executable application */
3327 BinarySubType
= BINARY_TYPE_EXE
;
3329 /* We can drop here from other "cases" above too, so check */
3330 if ((Status
== STATUS_INVALID_IMAGE_PROTECT
) ||
3331 (Status
== STATUS_INVALID_IMAGE_NE_FORMAT
) ||
3332 (BinarySubType
= BaseIsDosApplication(&PathName
, Status
)))
3334 /* We're launching a DOS application */
3335 VdmBinaryType
= BINARY_TYPE_DOS
;
3337 /* Based on the caller environment, create a VDM one */
3338 Result
= BaseCreateVDMEnvironment(lpEnvironment
,
3343 DPRINT1("VDM environment for DOS failed\n");
3347 /* Check the current state of the VDM subsystem */
3348 Status
= BaseCheckVDM(VdmBinaryType
| BinarySubType
,
3358 if (!NT_SUCCESS(Status
))
3360 /* Failed to inquire about VDM, fail the call */
3361 DPRINT1("VDM message failure for DOS: %lx\n", Status
);
3362 BaseSetLastNTError(Status
);
3367 /* Handle possible VDM states */
3368 switch (CheckVdmMsg
->VDMState
& (VDM_NOT_LOADED
|
3372 case VDM_NOT_LOADED
:
3373 /* If VDM is not loaded, we'll do a partial undo */
3374 VdmUndoLevel
= VDM_UNDO_PARTIAL
;
3376 /* A VDM process can't also be detached, so fail */
3377 if (dwCreationFlags
& DETACHED_PROCESS
)
3379 DPRINT1("Detached process but no VDM, not allowed\n");
3380 SetLastError(ERROR_ACCESS_DENIED
);
3384 /* Get the required parameters and names for launch */
3385 Result
= BaseGetVdmConfigInfo(lpCommandLine
,
3392 DPRINT1("VDM Configuration failed for DOS\n");
3393 BaseSetLastNTError(Status
);
3397 /* Update the command-line to launch VDM instead */
3398 lpCommandLine
= VdmString
.Buffer
;
3399 lpApplicationName
= NULL
;
3403 /* VDM is ready, so we have to undo everything */
3404 VdmUndoLevel
= VDM_UNDO_REUSE
;
3406 /* Check if CSRSS wants us to wait on VDM */
3407 VdmWaitObject
= CheckVdmMsg
->WaitObjectForParent
;
3411 /* Something is wrong with VDM, we'll fail the call */
3412 DPRINT1("VDM is not ready for DOS\n");
3413 SetLastError(ERROR_NOT_READY
);
3421 /* Since to get NULL, we allocate from 0x1, account for this */
3424 /* This implies VDM is ready, so skip everything else */
3425 if (VdmWaitObject
) goto VdmShortCircuit
;
3427 /* Don't inherit handles since we're doing VDM now */
3428 bInheritHandles
= FALSE
;
3430 /* Had the user passed in environment? If so, destroy it */
3431 if ((lpEnvironment
) &&
3432 !(dwCreationFlags
& CREATE_UNICODE_ENVIRONMENT
))
3434 RtlDestroyEnvironment(lpEnvironment
);
3437 /* Use our VDM Unicode environment instead */
3438 lpEnvironment
= VdmUnicodeEnv
.Buffer
;
3442 /* It's a batch file, get the extension */
3443 ExtBuffer
= &PathName
.Buffer
[PathName
.Length
/ sizeof(WCHAR
) - 4];
3445 /* Make sure the extensions are correct */
3446 if ((PathName
.Length
< (4 * sizeof(WCHAR
))) ||
3447 ((_wcsnicmp(ExtBuffer
, L
".bat", 4)) &&
3448 (_wcsnicmp(ExtBuffer
, L
".cmd", 4))))
3450 DPRINT1("'%wZ': Invalid EXE, and not a batch or script file\n", &PathName
);
3451 SetLastError(ERROR_BAD_EXE_FORMAT
);
3456 /* Check if we need to account for quotes around the path */
3457 CmdQuoteLength
= CmdLineIsAppName
|| HasQuotes
;
3458 if (!CmdLineIsAppName
)
3460 if (HasQuotes
) CmdQuoteLength
++;
3467 /* Calculate the length of the command line */
3468 CmdLineLength
= wcslen(lpCommandLine
);
3469 CmdLineLength
+= wcslen(CMD_STRING
);
3470 CmdLineLength
+= CmdQuoteLength
+ sizeof(ANSI_NULL
);
3471 CmdLineLength
*= sizeof(WCHAR
);
3473 /* Allocate space for the new command line */
3474 AnsiCmdCommand
= RtlAllocateHeap(RtlGetProcessHeap(),
3477 if (!AnsiCmdCommand
)
3479 BaseSetLastNTError(STATUS_NO_MEMORY
);
3485 wcscpy(AnsiCmdCommand
, CMD_STRING
);
3486 if ((CmdLineIsAppName
) || (HasQuotes
))
3488 wcscat(AnsiCmdCommand
, L
"\"");
3490 wcscat(AnsiCmdCommand
, lpCommandLine
);
3491 if ((CmdLineIsAppName
) || (HasQuotes
))
3493 wcscat(AnsiCmdCommand
, L
"\"");
3496 /* Create it as a Unicode String */
3497 RtlInitUnicodeString(&DebuggerString
, AnsiCmdCommand
);
3499 /* Set the command line to this */
3500 lpCommandLine
= DebuggerString
.Buffer
;
3501 lpApplicationName
= NULL
;
3502 DPRINT1("Retrying with: %S\n", lpCommandLine
);
3505 /* We've already done all these checks, don't do them again */
3506 SkipSaferAndAppCompat
= TRUE
;
3510 case STATUS_INVALID_IMAGE_WIN_64
:
3512 /* 64-bit binaries are not allowed to run on 32-bit ReactOS */
3513 DPRINT1("64-bit binary, failing\n");
3514 SetLastError(ERROR_EXE_MACHINE_TYPE_MISMATCH
);
3519 case STATUS_FILE_IS_OFFLINE
:
3521 /* Set the correct last error for this */
3522 DPRINT1("File is offline, failing\n");
3523 SetLastError(ERROR_FILE_OFFLINE
);
3529 /* Any other error, convert it to a generic Win32 error */
3530 if (!NT_SUCCESS(Status
))
3532 DPRINT1("Failed to create section: %lx\n", Status
);
3533 SetLastError(ERROR_BAD_EXE_FORMAT
);
3538 /* Otherwise, this must be success */
3539 ASSERT(Status
== STATUS_SUCCESS
);
3544 /* Is this not a WOW application, but a WOW32 VDM was requested for it? */
3545 if (!(IsWowApp
) && (dwCreationFlags
& CREATE_SEPARATE_WOW_VDM
))
3547 /* Ignore the nonsensical request */
3548 dwCreationFlags
&= ~CREATE_SEPARATE_WOW_VDM
;
3551 /* Did we already check information for the section? */
3554 /* Get some information about the executable */
3555 Status
= NtQuerySection(SectionHandle
,
3556 SectionImageInformation
,
3558 sizeof(ImageInformation
),
3560 if (!NT_SUCCESS(Status
))
3562 /* We failed, bail out */
3563 DPRINT1("Section query failed\n");
3564 BaseSetLastNTError(Status
);
3569 /* Don't check this later */
3570 QuerySection
= TRUE
;
3573 /* Check if this was linked as a DLL */
3574 if (ImageInformation
.ImageCharacteristics
& IMAGE_FILE_DLL
)
3576 /* These aren't valid images to try to execute! */
3577 DPRINT1("Trying to launch a DLL, failing\n");
3578 SetLastError(ERROR_BAD_EXE_FORMAT
);
3583 /* Don't let callers pass in this flag -- we'll only get it from IFEO */
3584 Flags
&= ~PROCESS_CREATE_FLAGS_LARGE_PAGES
;
3586 /* Clear the IFEO-missing flag, before we know for sure... */
3587 ParameterFlags
&= ~2;
3589 /* If the process is being debugged, only read IFEO if the PEB says so */
3590 if (!(dwCreationFlags
& (DEBUG_PROCESS
| DEBUG_ONLY_THIS_PROCESS
)) ||
3591 (NtCurrentPeb()->ReadImageFileExecOptions
))
3593 /* Let's do this! Attempt to open IFEO */
3594 IFEOStatus
= LdrOpenImageFileOptionsKey(&PathName
, 0, &KeyHandle
);
3595 if (!NT_SUCCESS(IFEOStatus
))
3597 /* We failed, set the flag so we store this in the parameters */
3598 if (IFEOStatus
== STATUS_OBJECT_NAME_NOT_FOUND
) ParameterFlags
|= 2;
3602 /* Was this our first time going through this path? */
3603 if (!DebuggerCmdLine
)
3605 /* Allocate a buffer for the debugger path */
3606 DebuggerCmdLine
= RtlAllocateHeap(RtlGetProcessHeap(),
3608 MAX_PATH
* sizeof(WCHAR
));
3609 if (!DebuggerCmdLine
)
3611 /* Close IFEO on failure */
3612 IFEOStatus
= NtClose(KeyHandle
);
3613 ASSERT(NT_SUCCESS(IFEOStatus
));
3616 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
3622 /* Now query for the debugger */
3623 IFEOStatus
= LdrQueryImageFileKeyOption(KeyHandle
,
3627 MAX_PATH
* sizeof(WCHAR
),
3629 if (!(NT_SUCCESS(IFEOStatus
)) ||
3630 (ResultSize
< sizeof(WCHAR
)) ||
3631 (DebuggerCmdLine
[0] == UNICODE_NULL
))
3633 /* If it's not there, or too small, or invalid, ignore it */
3634 RtlFreeHeap(RtlGetProcessHeap(), 0, DebuggerCmdLine
);
3635 DebuggerCmdLine
= NULL
;
3638 /* Also query if we should map with large pages */
3639 IFEOStatus
= LdrQueryImageFileKeyOption(KeyHandle
,
3643 sizeof(UseLargePages
),
3645 if ((NT_SUCCESS(IFEOStatus
)) && (UseLargePages
))
3647 /* Do it! This is the only way this flag can be set */
3648 Flags
|= PROCESS_CREATE_FLAGS_LARGE_PAGES
;
3651 /* We're done with IFEO, can close it now */
3652 IFEOStatus
= NtClose(KeyHandle
);
3653 ASSERT(NT_SUCCESS(IFEOStatus
));
3657 /* Make sure the image was compiled for this processor */
3658 if ((ImageInformation
.Machine
< SharedUserData
->ImageNumberLow
) ||
3659 (ImageInformation
.Machine
> SharedUserData
->ImageNumberHigh
))
3661 /* It was not -- raise a hard error */
3662 ErrorResponse
= ResponseOk
;
3663 ErrorParameters
[0] = (ULONG_PTR
)&PathName
;
3664 NtRaiseHardError(STATUS_IMAGE_MACHINE_TYPE_MISMATCH_EXE
,
3670 if (Peb
->ImageSubsystemMajorVersion
<= 3)
3672 /* If it's really old, return this error */
3673 SetLastError(ERROR_BAD_EXE_FORMAT
);
3677 /* Otherwise, return a more modern error */
3678 SetLastError(ERROR_EXE_MACHINE_TYPE_MISMATCH
);
3681 /* Go to the failure path */
3682 DPRINT1("Invalid image architecture: %lx\n", ImageInformation
.Machine
);
3687 /* Check if this isn't a Windows image */
3688 if ((ImageInformation
.SubSystemType
!= IMAGE_SUBSYSTEM_WINDOWS_GUI
) &&
3689 (ImageInformation
.SubSystemType
!= IMAGE_SUBSYSTEM_WINDOWS_CUI
))
3691 /* Get rid of section-related information since we'll retry */
3692 NtClose(SectionHandle
);
3693 SectionHandle
= NULL
;
3694 QuerySection
= FALSE
;
3696 /* The only other non-Windows image type we support here is POSIX */
3697 if (ImageInformation
.SubSystemType
!= IMAGE_SUBSYSTEM_POSIX_CUI
)
3699 /* Bail out if it's something else */
3700 SetLastError(ERROR_CHILD_NOT_COMPLETE
);
3705 /* Now build the command-line to have posix launch this image */
3706 Result
= BuildSubSysCommandLine(L
"POSIX /P ",
3712 /* Bail out if that failed */
3713 DPRINT1("Subsystem command line failed\n");
3717 /* And re-try launching the process, with the new command-line now */
3718 lpCommandLine
= DebuggerString
.Buffer
;
3719 lpApplicationName
= NULL
;
3721 /* We've already done all these checks, don't do them again */
3722 SkipSaferAndAppCompat
= TRUE
;
3723 DPRINT1("Retrying with: %S\n", lpCommandLine
);
3727 /* Was this image built for a version of Windows whose images we can run? */
3728 Result
= BasepIsImageVersionOk(ImageInformation
.SubSystemMajorVersion
,
3729 ImageInformation
.SubSystemMinorVersion
);
3732 /* It was not, bail out */
3733 DPRINT1("Invalid subsystem version: %hu.%hu\n",
3734 ImageInformation
.SubSystemMajorVersion
,
3735 ImageInformation
.SubSystemMinorVersion
);
3736 SetLastError(ERROR_BAD_EXE_FORMAT
);
3740 /* Check if there is a debugger associated with the application */
3741 if (DebuggerCmdLine
)
3743 /* Get the length of the command line */
3744 n
= wcslen(lpCommandLine
);
3747 /* There's no command line, use the application name instead */
3748 lpCommandLine
= (LPWSTR
)lpApplicationName
;
3749 n
= wcslen(lpCommandLine
);
3752 /* Protect against overflow */
3753 if (n
> UNICODE_STRING_MAX_CHARS
)
3755 BaseSetLastNTError(STATUS_NAME_TOO_LONG
);
3760 /* Now add the length of the debugger command-line */
3761 n
+= wcslen(DebuggerCmdLine
);
3763 /* Again make sure we don't overflow */
3764 if (n
> UNICODE_STRING_MAX_CHARS
)
3766 BaseSetLastNTError(STATUS_NAME_TOO_LONG
);
3771 /* Account for the quotes and space between the two */
3772 n
+= sizeof("\" \"") - sizeof(ANSI_NULL
);
3774 /* Convert to bytes, and make sure we don't overflow */
3776 if (n
> UNICODE_STRING_MAX_BYTES
)
3778 BaseSetLastNTError(STATUS_NAME_TOO_LONG
);
3783 /* Allocate space for the string */
3784 DebuggerString
.Buffer
= RtlAllocateHeap(RtlGetProcessHeap(), 0, n
);
3785 if (!DebuggerString
.Buffer
)
3787 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
3792 /* Set the length */
3793 RtlInitEmptyUnicodeString(&DebuggerString
,
3794 DebuggerString
.Buffer
,
3797 /* Now perform the command line creation */
3798 ImageDbgStatus
= RtlAppendUnicodeToString(&DebuggerString
,
3800 ASSERT(NT_SUCCESS(ImageDbgStatus
));
3801 ImageDbgStatus
= RtlAppendUnicodeToString(&DebuggerString
, L
" ");
3802 ASSERT(NT_SUCCESS(ImageDbgStatus
));
3803 ImageDbgStatus
= RtlAppendUnicodeToString(&DebuggerString
, lpCommandLine
);
3804 ASSERT(NT_SUCCESS(ImageDbgStatus
));
3806 /* Make sure it all looks nice */
3807 DbgPrint("BASE: Calling debugger with '%wZ'\n", &DebuggerString
);
3809 /* Update the command line and application name */
3810 lpCommandLine
= DebuggerString
.Buffer
;
3811 lpApplicationName
= NULL
;
3813 /* Close all temporary state */
3814 NtClose(SectionHandle
);
3815 SectionHandle
= NULL
;
3816 QuerySection
= FALSE
;
3818 /* Free all temporary memory */
3819 RtlFreeHeap(RtlGetProcessHeap(), 0, NameBuffer
);
3821 RtlFreeHeap(RtlGetProcessHeap(), 0, FreeBuffer
);
3823 RtlFreeHeap(RtlGetProcessHeap(), 0, DebuggerCmdLine
);
3824 DebuggerCmdLine
= NULL
;
3825 DPRINT1("Retrying with: %S\n", lpCommandLine
);
3829 /* Initialize the process object attributes */
3830 ObjectAttributes
= BaseFormatObjectAttributes(&LocalObjectAttributes
,
3831 lpProcessAttributes
,
3833 if ((hUserToken
) && (lpProcessAttributes
))
3835 /* Augment them with information from the user */
3837 LocalProcessAttributes
= *lpProcessAttributes
;
3838 LocalProcessAttributes
.lpSecurityDescriptor
= NULL
;
3839 ObjectAttributes
= BaseFormatObjectAttributes(&LocalObjectAttributes
,
3840 &LocalProcessAttributes
,
3844 /* Check if we're going to be debugged */
3845 if (dwCreationFlags
& DEBUG_PROCESS
)
3847 /* Set process flag */
3848 Flags
|= PROCESS_CREATE_FLAGS_BREAKAWAY
;
<