-/* $Id: create.c,v 1.73 2003/12/18 09:51:08 gvg Exp $
- *
+/*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS system libraries
* FILE: lib/kernel32/process/create.c
* PURPOSE: Process functions
- * PROGRAMMER: Ariadne ( ariadne@xs4all.nl)
- * UPDATE HISTORY:
- * Created 01/11/98
+ * PROGRAMMER: Alex Ionescu (alex@relsoft.net)
+ * Ariadne ( ariadne@xs4all.nl)
*/
/* INCLUDES ****************************************************************/
#include <k32.h>
#define NDEBUG
-#include <kernel32/kernel32.h>
+#include "../include/debug.h"
-/* FUNCTIONS ****************************************************************/
+#define CMD_STRING L"cmd /c "
-extern __declspec(noreturn)
-VOID CALLBACK ConsoleControlDispatcher(DWORD CodeAndFlag);
+extern __declspec(noreturn)
+VOID
+CALLBACK
+ConsoleControlDispatcher(DWORD CodeAndFlag);
-__declspec(dllimport)
-PRTL_BASE_PROCESS_START_ROUTINE RtlBaseProcessStartRoutine;
+/* INTERNAL FUNCTIONS *******************************************************/
-typedef NTSTATUS STDCALL (K32_MBSTR_TO_WCSTR)
-(
- UNICODE_STRING *,
- ANSI_STRING *,
- BOOLEAN
-);
-
-NTSTATUS STDCALL K32MbStrToWcStr
-(
- IN K32_MBSTR_TO_WCSTR * True,
- UNICODE_STRING * DestStr,
- ANSI_STRING * SourceStr,
- BOOLEAN Allocate
-)
+_SEH_FILTER(BaseExceptionFilter)
{
- if(SourceStr->Buffer == NULL)
- {
- DestStr->Length = DestStr->MaximumLength = 0;
- DestStr->Buffer = NULL;
- return STATUS_SUCCESS;
- }
-
- return True(DestStr, SourceStr, Allocate);
-}
+ EXCEPTION_POINTERS *ExceptionInfo = _SEH_GetExceptionPointers();
+ LONG ExceptionDisposition = EXCEPTION_EXECUTE_HANDLER;
-VOID STDCALL RtlRosR32AttribsToNativeAttribs
-(
- OUT OBJECT_ATTRIBUTES * NativeAttribs,
- IN SECURITY_ATTRIBUTES * Ros32Attribs OPTIONAL
-)
-{
- NativeAttribs->Length = sizeof(*NativeAttribs);
- NativeAttribs->ObjectName = NULL;
- NativeAttribs->RootDirectory = NULL;
- NativeAttribs->Attributes = 0;
- NativeAttribs->SecurityQualityOfService = NULL;
-
+ if (GlobalTopLevelExceptionFilter != NULL)
+ {
+ _SEH_TRY
+ {
+ ExceptionDisposition = GlobalTopLevelExceptionFilter(ExceptionInfo);
+ }
+ _SEH_HANDLE
+ {
+ ExceptionDisposition = UnhandledExceptionFilter(ExceptionInfo);
+ }
+ _SEH_END;
+ }
- if(Ros32Attribs != NULL && Ros32Attribs->nLength >= sizeof(*Ros32Attribs))
- {
- NativeAttribs->SecurityDescriptor = Ros32Attribs->lpSecurityDescriptor;
-
- if(Ros32Attribs->bInheritHandle)
- NativeAttribs->Attributes |= OBJ_INHERIT;
- }
- else
- NativeAttribs->SecurityDescriptor = NULL;
+ return ExceptionDisposition;
}
-VOID STDCALL RtlRosR32AttribsToNativeAttribsNamed
-(
- OUT OBJECT_ATTRIBUTES * NativeAttribs,
- IN SECURITY_ATTRIBUTES * Ros32Attribs OPTIONAL,
- OUT UNICODE_STRING * NativeName OPTIONAL,
- IN WCHAR * Ros32Name OPTIONAL,
- IN HANDLE Ros32NameRoot OPTIONAL
-)
+VOID
+STDCALL
+BaseProcessStartup(PPROCESS_START_ROUTINE lpStartAddress)
{
- if(!NativeAttribs) return;
+ UINT uExitCode = 0;
- RtlRosR32AttribsToNativeAttribs(NativeAttribs, Ros32Attribs);
+ DPRINT("BaseProcessStartup(..) - setting up exception frame.\n");
- if(Ros32Name != NULL && NativeName != NULL)
- {
- RtlInitUnicodeString(NativeName, Ros32Name);
+ _SEH_TRY
+ {
+ /* Set our Start Address */
+ NtSetInformationThread(NtCurrentThread(),
+ ThreadQuerySetWin32StartAddress,
+ &lpStartAddress,
+ sizeof(PPROCESS_START_ROUTINE));
+
+ /* Call the Start Routine */
+ uExitCode = (lpStartAddress)();
+ }
+ _SEH_EXCEPT(BaseExceptionFilter)
+ {
+ /* Get the SEH Error */
+ uExitCode = _SEH_GetExceptionCode();
+ }
+ _SEH_END;
- NativeAttribs->ObjectName = NativeName;
- NativeAttribs->RootDirectory = Ros32NameRoot;
- NativeAttribs->Attributes |= OBJ_CASE_INSENSITIVE;
- }
+ /* Exit the Process with our error */
+ ExitProcess(uExitCode);
}
-
/*
- * @implemented
+ * Tells CSR that a new process was created
*/
-BOOL STDCALL CreateProcessA
-(
- LPCSTR lpApplicationName,
- LPSTR lpCommandLine,
- LPSECURITY_ATTRIBUTES lpProcessAttributes,
- LPSECURITY_ATTRIBUTES lpThreadAttributes,
- BOOL bInheritHandles,
- DWORD dwCreationFlags,
- LPVOID lpEnvironment,
- LPCSTR lpCurrentDirectory,
- LPSTARTUPINFOA lpStartupInfo,
- LPPROCESS_INFORMATION lpProcessInformation
-)
+NTSTATUS
+STDCALL
+BasepNotifyCsrOfCreation(ULONG dwCreationFlags,
+ IN HANDLE ProcessId)
+{
+ ULONG Request = CREATE_PROCESS;
+ CSR_API_MESSAGE CsrRequest;
+ NTSTATUS Status;
+
+ DPRINT1("BasepNotifyCsrOfCreation: Process: %lx, Flags %lx\n",
+ ProcessId, dwCreationFlags);
+
+ /* Fill out the request */
+ CsrRequest.Data.CreateProcessRequest.NewProcessId = ProcessId;
+ CsrRequest.Data.CreateProcessRequest.Flags = dwCreationFlags;
+
+ /* Call CSR */
+ Status = CsrClientCallServer(&CsrRequest,
+ NULL,
+ MAKE_CSR_API(Request, CSR_NATIVE),
+ sizeof(CSR_API_MESSAGE));
+ if (!NT_SUCCESS(Status) || !NT_SUCCESS(CsrRequest.Status))
+ {
+ DPRINT1("Failed to tell csrss about new process\n");
+ return CsrRequest.Status;
+ }
+
+ /* REturn Success */
+ return STATUS_SUCCESS;
+}
+
/*
- * FUNCTION: The CreateProcess function creates a new process and its
- * primary thread. The new process executes the specified executable file
- * ARGUMENTS:
- *
- * lpApplicationName = Pointer to name of executable module
- * lpCommandLine = Pointer to command line string
- * lpProcessAttributes = Process security attributes
- * lpThreadAttributes = Thread security attributes
- * bInheritHandles = Handle inheritance flag
- * dwCreationFlags = Creation flags
- * lpEnvironment = Pointer to new environment block
- * lpCurrentDirectory = Pointer to current directory name
- * lpStartupInfo = Pointer to startup info
- * lpProcessInformation = Pointer to process information
+ * Creates the first Thread in a Proces
*/
+HANDLE
+STDCALL
+BasepCreateFirstThread(HANDLE ProcessHandle,
+ LPSECURITY_ATTRIBUTES lpThreadAttributes,
+ PSECTION_IMAGE_INFORMATION SectionImageInfo,
+ PCLIENT_ID ClientId)
{
- PWCHAR pwcEnv = NULL;
- UNICODE_STRING wstrApplicationName;
- UNICODE_STRING wstrCurrentDirectory;
- UNICODE_STRING wstrCommandLine;
- UNICODE_STRING wstrReserved;
- UNICODE_STRING wstrDesktop;
- UNICODE_STRING wstrTitle;
- ANSI_STRING strApplicationName;
- ANSI_STRING strCurrentDirectory;
- ANSI_STRING strCommandLine;
- ANSI_STRING strReserved;
- ANSI_STRING strDesktop;
- ANSI_STRING strTitle;
- BOOL bRetVal;
- STARTUPINFOW wsiStartupInfo;
-
- NTSTATUS STDCALL (*pTrue)
- (
- UNICODE_STRING *,
- ANSI_STRING *,
- BOOLEAN
- );
-
- ULONG STDCALL (*pRtlMbStringToUnicodeSize)(ANSI_STRING *);
-
- DPRINT("CreateProcessA(%s)\n", lpApplicationName);
-
- DPRINT
- (
- "dwCreationFlags %x, lpEnvironment %x, lpCurrentDirectory %x, "
- "lpStartupInfo %x, lpProcessInformation %x\n",
- dwCreationFlags,
- lpEnvironment,
- lpCurrentDirectory,
- lpStartupInfo,
- lpProcessInformation
- );
-
- /* invalid parameter */
- if(lpStartupInfo == NULL)
- {
- SetLastError(ERROR_INVALID_PARAMETER);
- return FALSE;
- }
-
- /* multibyte strings are ANSI */
- if(bIsFileApiAnsi)
- {
- pTrue = RtlAnsiStringToUnicodeString;
- pRtlMbStringToUnicodeSize = RtlAnsiStringToUnicodeSize;
- }
- /* multibyte strings are OEM */
- else
- {
- pTrue = RtlOemStringToUnicodeString;
- pRtlMbStringToUnicodeSize = RtlOemStringToUnicodeSize;
- }
-
- /* convert the environment */
- if(lpEnvironment && !(dwCreationFlags & CREATE_UNICODE_ENVIRONMENT))
- {
- PCHAR pcScan;
- SIZE_T nEnvLen = 0;
- UNICODE_STRING wstrEnvVar;
- ANSI_STRING strEnvVar;
-
- /* scan the environment to calculate its Unicode size */
- for(pcScan = lpEnvironment; *pcScan; pcScan += strEnvVar.Length + sizeof(char))
- {
- /* add the size of the current variable */
- RtlInitAnsiString(&strEnvVar, pcScan);
- nEnvLen += pRtlMbStringToUnicodeSize(&strEnvVar) + sizeof(WCHAR);
- }
-
- /* add the size of the final NUL character */
- nEnvLen += sizeof(WCHAR);
-
- /* environment too large */
- if(nEnvLen > ~((USHORT)0))
- {
- SetLastError(ERROR_OUTOFMEMORY);
- return FALSE;
- }
-
- /* allocate the Unicode environment */
- pwcEnv = (PWCHAR)RtlAllocateHeap(GetProcessHeap(), HEAP_ZERO_MEMORY, nEnvLen);
-
- /* failure */
- if(pwcEnv == NULL)
- {
- SetLastError(ERROR_OUTOFMEMORY);
- return FALSE;
- }
-
- wstrEnvVar.Buffer = pwcEnv;
- wstrEnvVar.Length = 0;
- wstrEnvVar.MaximumLength = nEnvLen;
-
- /* scan the environment to convert it */
- for(pcScan = lpEnvironment; *pcScan; pcScan += strEnvVar.Length + sizeof(char))
- {
- /* convert the current variable */
- RtlInitAnsiString(&strEnvVar, pcScan);
- K32MbStrToWcStr(pTrue, &wstrEnvVar, &strEnvVar, FALSE);
-
- /* advance the buffer to the next variable */
- wstrEnvVar.Buffer += (wstrEnvVar.Length / sizeof(WCHAR) + 1);
- wstrEnvVar.MaximumLength -= (wstrEnvVar.Length + sizeof(WCHAR));
- wstrEnvVar.Length = 0;
- }
-
- /* final NUL character */
- wstrEnvVar.Buffer[0] = 0;
- }
-
- /* convert the strings */
- RtlInitAnsiString(&strCommandLine, lpCommandLine);
- RtlInitAnsiString(&strApplicationName, (LPSTR)lpApplicationName);
- RtlInitAnsiString(&strCurrentDirectory, (LPSTR)lpCurrentDirectory);
- RtlInitAnsiString(&strReserved, (LPSTR)lpStartupInfo->lpReserved);
- RtlInitAnsiString(&strDesktop, (LPSTR)lpStartupInfo->lpDesktop);
- RtlInitAnsiString(&strTitle, (LPSTR)lpStartupInfo->lpTitle);
-
- K32MbStrToWcStr(pTrue, &wstrCommandLine, &strCommandLine, TRUE);
- K32MbStrToWcStr(pTrue, &wstrApplicationName, &strApplicationName, TRUE);
- K32MbStrToWcStr(pTrue, &wstrCurrentDirectory, &strCurrentDirectory, TRUE);
- K32MbStrToWcStr(pTrue, &wstrReserved, &strReserved, TRUE);
- K32MbStrToWcStr(pTrue, &wstrDesktop, &strDesktop, TRUE);
- K32MbStrToWcStr(pTrue, &wstrTitle, &strTitle, TRUE);
-
- /* convert the startup information */
- memcpy(&wsiStartupInfo, lpStartupInfo, sizeof(wsiStartupInfo));
-
- wsiStartupInfo.lpReserved = wstrReserved.Buffer;
- wsiStartupInfo.lpDesktop = wstrDesktop.Buffer;
- wsiStartupInfo.lpTitle = wstrTitle.Buffer;
-
- DPRINT("wstrApplicationName %wZ\n", &wstrApplicationName);
- DPRINT("wstrCommandLine %wZ\n", &wstrCommandLine);
- DPRINT("wstrCurrentDirectory %wZ\n", &wstrCurrentDirectory);
- DPRINT("wstrReserved %wZ\n", &wstrReserved);
- DPRINT("wstrDesktop %wZ\n", &wstrDesktop);
- DPRINT("wstrTitle %wZ\n", &wstrTitle);
-
- DPRINT("wstrApplicationName.Buffer %p\n", wstrApplicationName.Buffer);
- DPRINT("wstrCommandLine.Buffer %p\n", wstrCommandLine.Buffer);
- DPRINT("wstrCurrentDirectory.Buffer %p\n", wstrCurrentDirectory.Buffer);
- DPRINT("wstrReserved.Buffer %p\n", wstrReserved.Buffer);
- DPRINT("wstrDesktop.Buffer %p\n", wstrDesktop.Buffer);
- DPRINT("wstrTitle.Buffer %p\n", wstrTitle.Buffer);
-
- DPRINT("sizeof(STARTUPINFOA) %lu\n", sizeof(STARTUPINFOA));
- DPRINT("sizeof(STARTUPINFOW) %lu\n", sizeof(STARTUPINFOW));
-
- /* call the Unicode function */
- bRetVal = CreateProcessW
- (
- wstrApplicationName.Buffer,
- wstrCommandLine.Buffer,
- lpProcessAttributes,
- lpThreadAttributes,
- bInheritHandles,
- dwCreationFlags,
- dwCreationFlags & CREATE_UNICODE_ENVIRONMENT ? lpEnvironment : pwcEnv,
- wstrCurrentDirectory.Buffer,
- &wsiStartupInfo,
- lpProcessInformation
- );
-
- RtlFreeUnicodeString(&wstrApplicationName);
- RtlFreeUnicodeString(&wstrCommandLine);
- RtlFreeUnicodeString(&wstrCurrentDirectory);
- RtlFreeUnicodeString(&wstrReserved);
- RtlFreeUnicodeString(&wstrDesktop);
- RtlFreeUnicodeString(&wstrTitle);
-
- RtlFreeHeap(GetProcessHeap(), 0, pwcEnv);
-
- return bRetVal;
+ OBJECT_ATTRIBUTES LocalObjectAttributes;
+ POBJECT_ATTRIBUTES ObjectAttributes;
+ CONTEXT Context;
+ INITIAL_TEB InitialTeb;
+ NTSTATUS Status;
+ HANDLE hThread;
+
+ DPRINT("BasepCreateFirstThread. hProcess: %lx\n", ProcessHandle);
+
+ /* Create the Thread's Stack */
+ BasepCreateStack(ProcessHandle,
+ SectionImageInfo->MaximumStackSize,
+ SectionImageInfo->CommittedStackSize,
+ &InitialTeb);
+
+ /* Create the Thread's Context */
+ BasepInitializeContext(&Context,
+ NtCurrentPeb(),
+ SectionImageInfo->TransferAddress,
+ InitialTeb.StackBase,
+ 0);
+
+ /* Convert the thread attributes */
+ ObjectAttributes = BasepConvertObjectAttributes(&LocalObjectAttributes,
+ lpThreadAttributes,
+ NULL);
+
+ /* Create the Kernel Thread Object */
+ Status = NtCreateThread(&hThread,
+ THREAD_ALL_ACCESS,
+ ObjectAttributes,
+ ProcessHandle,
+ ClientId,
+ &Context,
+ &InitialTeb,
+ TRUE);
+
+ /* Success */
+ return hThread;
}
-static int _except_recursion_trap = 0;
-
-struct _CONTEXT;
-struct __EXCEPTION_RECORD;
-
-static
-EXCEPTION_DISPOSITION
-__cdecl
-_except_handler(
- struct _EXCEPTION_RECORD *ExceptionRecord,
- void * EstablisherFrame,
- struct _CONTEXT *ContextRecord,
- void * DispatcherContext )
+/*
+ * Converts ANSI to Unicode Environment
+ */
+PVOID
+STDCALL
+BasepConvertUnicodeEnvironment(IN PVOID lpEnvironment)
{
- DPRINT1("Process terminated abnormally due to unhandled exception\n");
- DPRINT1("Address: %x\n", ExceptionRecord->ExceptionAddress);
-
-#ifdef _X86_
- {
- PULONG Frame;
- DPRINT1("Frames:\n");
- Frame = (PULONG)((CONTEXT *)ContextRecord)->Ebp;
- while (Frame != NULL && Frame != (PULONG)0xdeadbeef)
- {
- DPRINT1("%x\n", (PVOID)Frame[1]);
- Frame = (PULONG)Frame[0];
- }
- }
-#endif
-
- if (3 < ++_except_recursion_trap)
+ PCHAR pcScan;
+ SIZE_T EnvSize = 0;
+ ANSI_STRING AnsiEnv;
+ UNICODE_STRING UnicodeEnv;
+ NTSTATUS Status;
+
+ DPRINT("BasepConvertUnicodeEnvironment\n");
+
+ /* Scan the environment to calculate its Unicode size */
+ AnsiEnv.Buffer = pcScan = lpEnvironment;
+ while (*pcScan) while (*pcScan++);
+
+ /* Create our ANSI String */
+ AnsiEnv.Length = (ULONG_PTR)pcScan - (ULONG_PTR)lpEnvironment + 1;
+ AnsiEnv.MaximumLength = AnsiEnv.Length + 1;
+
+ /* Allocate memory for the Unicode Environment */
+ UnicodeEnv.Buffer = NULL;
+ EnvSize = AnsiEnv.MaximumLength * sizeof(WCHAR);
+ Status = NtAllocateVirtualMemory(NtCurrentProcess(),
+ (PVOID)&UnicodeEnv.Buffer,
+ 0,
+ &EnvSize,
+ MEM_COMMIT,
+ PAGE_READWRITE);
+ /* Failure */
+ if (!NT_SUCCESS(Status))
{
- DPRINT1("_except_handler(...) appears to be recursing.\n");
- DPRINT1("Process HALTED.\n");
- for (;;)
- {
- }
+ SetLastError(Status);
+ return NULL;
}
+
+ /* Use the allocated size */
+ UnicodeEnv.MaximumLength = EnvSize;
+
+ /* Convert */
+ RtlAnsiStringToUnicodeString(&UnicodeEnv, &AnsiEnv, FALSE);
+ return UnicodeEnv.Buffer;
+}
- if (/* FIXME: */ TRUE) /* Not a service */
+/*
+ * Converts a Win32 Priority Class to NT
+ */
+ULONG
+STDCALL
+BasepConvertPriorityClass(IN ULONG dwCreationFlags)
+{
+ ULONG ReturnClass;
+
+ if(dwCreationFlags & IDLE_PRIORITY_CLASS)
+ {
+ ReturnClass = PROCESS_PRIORITY_CLASS_IDLE;
+ }
+ else if(dwCreationFlags & BELOW_NORMAL_PRIORITY_CLASS)
{
- DPRINT(" calling ExitProcess(0) no, lets try ExitThread . . .\n");
- /* ExitProcess(0); */
- ExitThread(0);
+ ReturnClass = PROCESS_PRIORITY_CLASS_BELOW_NORMAL;
}
- else
+ else if(dwCreationFlags & NORMAL_PRIORITY_CLASS)
{
- DPRINT(" calling ExitThread(0) . . .\n");
- ExitThread(0);
+ ReturnClass = PROCESS_PRIORITY_CLASS_NORMAL;
}
-
- DPRINT1(" We should not get to here !!!\n");
- /* We should not get to here */
- return ExceptionContinueSearch;
+ else if(dwCreationFlags & ABOVE_NORMAL_PRIORITY_CLASS)
+ {
+ ReturnClass = PROCESS_PRIORITY_CLASS_ABOVE_NORMAL;
+ }
+ else if(dwCreationFlags & HIGH_PRIORITY_CLASS)
+ {
+ ReturnClass = PROCESS_PRIORITY_CLASS_HIGH;
+ }
+ else if(dwCreationFlags & REALTIME_PRIORITY_CLASS)
+ {
+ /* Check for Privilege First */
+ if (BasepCheckRealTimePrivilege())
+ {
+ ReturnClass = PROCESS_PRIORITY_CLASS_REALTIME;
+ }
+ else
+ {
+ ReturnClass = PROCESS_PRIORITY_CLASS_HIGH;
+ }
+ }
+ else
+ {
+ ReturnClass = 0 /* FIXME */;
+ }
+
+ return ReturnClass;
}
-VOID STDCALL
-BaseProcessStart(LPTHREAD_START_ROUTINE lpStartAddress,
- DWORD lpParameter)
+/*
+ * Duplicates a standard handle and writes it where requested.
+ */
+VOID
+STDCALL
+BasepDuplicateAndWriteHandle(IN HANDLE ProcessHandle,
+ IN HANDLE StandardHandle,
+ IN PHANDLE Address)
{
- UINT uExitCode = 0;
-
- DPRINT("BaseProcessStart(..) - setting up exception frame.\n");
-
- __try1(_except_handler)
- {
- uExitCode = (lpStartAddress)((PVOID)lpParameter);
- } __except1
- {
- }
-
- DPRINT("BaseProcessStart(..) - cleaned up exception frame.\n");
-
- ExitThread(uExitCode);
+ NTSTATUS Status;
+ HANDLE DuplicatedHandle;
+ ULONG Dummy;
+
+ DPRINT("BasepDuplicateAndWriteHandle. hProcess: %lx, Handle: %lx,"
+ "Address: %p\n", ProcessHandle, StandardHandle, Address);
+
+ /* Don't touch Console Handles */
+ if (IsConsoleHandle(StandardHandle)) return;
+
+ /* Duplicate the handle */
+ Status = NtDuplicateObject(NtCurrentProcess(),
+ StandardHandle,
+ ProcessHandle,
+ &DuplicatedHandle,
+ DUPLICATE_SAME_ACCESS | DUPLICATE_SAME_ATTRIBUTES,
+ 0,
+ 0);
+ if (NT_SUCCESS(Status))
+ {
+ /* Write it */
+ NtWriteVirtualMemory(ProcessHandle,
+ Address,
+ &DuplicatedHandle,
+ sizeof(HANDLE),
+ &Dummy);
+ }
}
-
-HANDLE STDCALL KlCreateFirstThread
-(
- HANDLE ProcessHandle,
- LPSECURITY_ATTRIBUTES lpThreadAttributes,
- PSECTION_IMAGE_INFORMATION Sii,
- LPTHREAD_START_ROUTINE lpStartAddress,
- DWORD dwCreationFlags,
- LPDWORD lpThreadId
-)
+LPWSTR
+STDCALL
+BasepGetDllPath(LPWSTR FullPath,
+ PVOID Environment)
{
- OBJECT_ATTRIBUTES oaThreadAttribs;
- CLIENT_ID cidClientId;
- PVOID pTrueStartAddress;
- NTSTATUS nErrCode;
- HANDLE hThread;
-
- /* convert the thread attributes */
- RtlRosR32AttribsToNativeAttribs(&oaThreadAttribs, lpThreadAttributes);
-
- /* native image */
- if(Sii->Subsystem != IMAGE_SUBSYSTEM_NATIVE)
- pTrueStartAddress = (PVOID)BaseProcessStart;
- /* Win32 image */
- else
- pTrueStartAddress = (PVOID)RtlBaseProcessStartRoutine;
-
- DPRINT
- (
- "RtlRosCreateUserThreadVa\n"
- "(\n"
- " ProcessHandle %p,\n"
- " ObjectAttributes %p,\n"
- " CreateSuspended %d,\n"
- " StackZeroBits %d,\n"
- " StackReserve %lu,\n"
- " StackCommit %lu,\n"
- " StartAddress %p,\n"
- " ThreadHandle %p,\n"
- " ClientId %p,\n"
- " ParameterCount %u,\n"
- " Parameters[0] %p,\n"
- " Parameters[1] %p\n"
- ")\n",
- ProcessHandle,
- &oaThreadAttribs,
- dwCreationFlags & CREATE_SUSPENDED,
- 0,
- Sii->StackReserve,
- Sii->StackCommit,
- pTrueStartAddress,
- &hThread,
- &cidClientId,
- 2,
- lpStartAddress,
- PEB_BASE
- );
-
- /* create the first thread */
- nErrCode = RtlRosCreateUserThreadVa
- (
- ProcessHandle,
- &oaThreadAttribs,
- dwCreationFlags & CREATE_SUSPENDED,
- 0,
- &(Sii->StackReserve),
- &(Sii->StackCommit),
- pTrueStartAddress,
- &hThread,
- &cidClientId,
- 2,
- (ULONG_PTR)lpStartAddress,
- (ULONG_PTR)PEB_BASE
- );
-
- /* failure */
- if(!NT_SUCCESS(nErrCode))
- {
- SetLastErrorByStatus(nErrCode);
- return NULL;
- }
-
- DPRINT
- (
- "StackReserve %p\n"
- "StackCommit %p\n"
- "ThreadHandle %p\n"
- "ClientId.UniqueThread %p\n",
- Sii->StackReserve,
- Sii->StackCommit,
- hThread,
- cidClientId.UniqueThread
- );
-
- /* success */
- if(lpThreadId) *lpThreadId = (DWORD)cidClientId.UniqueThread;
- return hThread;
+ /* FIXME: Not yet implemented */
+ return NULL;
}
-HANDLE KlMapFile(LPCWSTR lpApplicationName)
+VOID
+STDCALL
+BasepCopyHandles(IN PRTL_USER_PROCESS_PARAMETERS Params,
+ IN PRTL_USER_PROCESS_PARAMETERS PebParams,
+ IN BOOL InheritHandles)
{
- HANDLE hFile;
- IO_STATUS_BLOCK IoStatusBlock;
- UNICODE_STRING ApplicationNameString;
- OBJECT_ATTRIBUTES ObjectAttributes;
- PSECURITY_DESCRIPTOR SecurityDescriptor = NULL;
- NTSTATUS Status;
- HANDLE hSection;
-
- hFile = NULL;
-
- /*
- * Find the application name
- */
-
- if (!RtlDosPathNameToNtPathName_U ((LPWSTR)lpApplicationName,
- &ApplicationNameString,
- NULL,
- NULL))
- return NULL;
-
- DPRINT("ApplicationName %S\n",ApplicationNameString.Buffer);
-
- InitializeObjectAttributes(&ObjectAttributes,
- &ApplicationNameString,
- OBJ_CASE_INSENSITIVE,
- NULL,
- SecurityDescriptor);
-
- /*
- * Try to open the executable
- */
-
- Status = NtOpenFile(&hFile,
- SYNCHRONIZE|FILE_EXECUTE|FILE_READ_DATA,
- &ObjectAttributes,
- &IoStatusBlock,
- FILE_SHARE_DELETE|FILE_SHARE_READ,
- FILE_SYNCHRONOUS_IO_NONALERT|FILE_NON_DIRECTORY_FILE);
-
- RtlFreeUnicodeString (&ApplicationNameString);
-
- if (!NT_SUCCESS(Status))
- {
- DPRINT("Failed to open file\n");
- SetLastErrorByStatus (Status);
- return(NULL);
- }
-
- Status = NtCreateSection(&hSection,
- SECTION_ALL_ACCESS,
- NULL,
- NULL,
- PAGE_EXECUTE,
- SEC_IMAGE,
- hFile);
- NtClose(hFile);
-
- if (!NT_SUCCESS(Status))
- {
- DPRINT("Failed to create section\n");
- SetLastErrorByStatus (Status);
- return(NULL);
- }
-
- return(hSection);
+ /* Copy the handle if we are inheriting or if it's a console handle */
+ if (InheritHandles || IsConsoleHandle(PebParams->StandardInput))
+ {
+ Params->StandardInput = PebParams->StandardInput;
+ }
+ if (InheritHandles || IsConsoleHandle(PebParams->StandardOutput))
+ {
+ Params->StandardOutput = PebParams->StandardOutput;
+ }
+ if (InheritHandles || IsConsoleHandle(PebParams->StandardError))
+ {
+ Params->StandardError = PebParams->StandardError;
+ }
}
-static NTSTATUS KlInitPeb
-(
- HANDLE ProcessHandle,
- PRTL_USER_PROCESS_PARAMETERS Ppb,
- PVOID * ImageBaseAddress
-)
+NTSTATUS
+STDCALL
+BasepInitializeEnvironment(HANDLE ProcessHandle,
+ PPEB Peb,
+ LPWSTR ApplicationPathName,
+ LPWSTR lpCurrentDirectory,
+ LPWSTR lpCommandLine,
+ LPVOID Environment,
+ LPSTARTUPINFOW StartupInfo,
+ DWORD CreationFlags,
+ BOOL InheritHandles)
{
- NTSTATUS Status;
- PVOID PpbBase;
- ULONG PpbSize;
- ULONG BytesWritten;
- ULONG Offset;
- PVOID ParentEnv = NULL;
- PVOID EnvPtr = NULL;
- PWCHAR ptr;
- ULONG EnvSize = 0, EnvSize1 = 0;
-
- /* create the Environment */
- if (Ppb->Environment != NULL)
- {
- ParentEnv = Ppb->Environment;
- ptr = ParentEnv;
- while (*ptr)
- {
- while(*ptr++);
- }
- ptr++;
- EnvSize = (PVOID)ptr - ParentEnv;
- }
- else if (NtCurrentPeb()->ProcessParameters->Environment != NULL)
- {
- MEMORY_BASIC_INFORMATION MemInfo;
- ParentEnv = NtCurrentPeb()->ProcessParameters->Environment;
-
- Status = NtQueryVirtualMemory (NtCurrentProcess (),
- ParentEnv,
- MemoryBasicInformation,
- &MemInfo,
- sizeof(MEMORY_BASIC_INFORMATION),
- NULL);
- if (!NT_SUCCESS(Status))
- {
- return Status;
- }
- EnvSize = MemInfo.RegionSize;
- }
- DPRINT("EnvironmentSize %ld\n", EnvSize);
-
- /* allocate and initialize new environment block */
- if (EnvSize != 0)
- {
- EnvSize1 = EnvSize;
- Status = NtAllocateVirtualMemory(ProcessHandle,
- &EnvPtr,
- 0,
- &EnvSize1,
- MEM_RESERVE | MEM_COMMIT,
- PAGE_READWRITE);
- if (!NT_SUCCESS(Status))
- {
- return(Status);
- }
-
- NtWriteVirtualMemory(ProcessHandle,
- EnvPtr,
- ParentEnv,
- EnvSize,
- &BytesWritten);
- }
-
- /* create the PPB */
- PpbBase = NULL;
- PpbSize = Ppb->AllocationSize;
- Status = NtAllocateVirtualMemory(ProcessHandle,
- &PpbBase,
- 0,
- &PpbSize,
- MEM_RESERVE | MEM_COMMIT,
- PAGE_READWRITE);
- if (!NT_SUCCESS(Status))
- {
- return(Status);
- }
-
- //DPRINT("Ppb->MaximumLength %x\n", Ppb->MaximumLength);
- NtWriteVirtualMemory(ProcessHandle,
- PpbBase,
- Ppb,
- Ppb->AllocationSize,
- &BytesWritten);
-
- /* write pointer to environment */
- Offset = FIELD_OFFSET(RTL_USER_PROCESS_PARAMETERS, Environment);
- NtWriteVirtualMemory(ProcessHandle,
- (PVOID)(PpbBase + Offset),
- &EnvPtr,
- sizeof(EnvPtr),
- &BytesWritten);
+ WCHAR FullPath[MAX_PATH];
+ LPWSTR Remaining;
+ LPWSTR DllPathString;
+ PRTL_USER_PROCESS_PARAMETERS ProcessParameters;
+ PRTL_USER_PROCESS_PARAMETERS RemoteParameters = NULL;
+ UNICODE_STRING DllPath, ImageName, CommandLine, CurrentDirectory;
+ UINT RetVal;
+ NTSTATUS Status;
+ PWCHAR ScanChar;
+ ULONG EnviroSize;
+ ULONG Size;
+ UNICODE_STRING Desktop, Shell, Runtime, Title;
+ PPEB OurPeb = NtCurrentPeb();
+
+ DPRINT("BasepInitializeEnvironment\n");
+
+ /* Get the full path name */
+ RetVal = GetFullPathNameW(ApplicationPathName,
+ MAX_PATH,
+ FullPath,
+ &Remaining);
+ DPRINT("ApplicationPathName: %S, FullPath: %S\n", ApplicationPathName,
+ FullPath);
+
+ /* Get the DLL Path */
+ DllPathString = BasepGetDllPath(FullPath, Environment);
+
+ /* Initialize Strings */
+ RtlInitUnicodeString(&DllPath, DllPathString);
+ RtlInitUnicodeString(&ImageName, FullPath);
+ RtlInitUnicodeString(&CommandLine, lpCommandLine);
+ RtlInitUnicodeString(&CurrentDirectory, lpCurrentDirectory);
+
+ /* Initialize more Strings from the Startup Info */
+ if (StartupInfo->lpDesktop)
+ {
+ RtlInitUnicodeString(&Desktop, StartupInfo->lpDesktop);
+ }
+ else
+ {
+ RtlInitUnicodeString(&Desktop, L"");
+ }
+ if (StartupInfo->lpReserved)
+ {
+ RtlInitUnicodeString(&Shell, StartupInfo->lpReserved);
+ }
+ else
+ {
+ RtlInitUnicodeString(&Shell, L"");
+ }
+ if (StartupInfo->lpTitle)
+ {
+ RtlInitUnicodeString(&Title, StartupInfo->lpTitle);
+ }
+ else
+ {
+ RtlInitUnicodeString(&Title, L"");
+ }
+
+ /* This one is special because the length can differ */
+ Runtime.Buffer = (LPWSTR)StartupInfo->lpReserved2;
+ Runtime.MaximumLength = Runtime.Length = StartupInfo->cbReserved2;
+
+ /* Create the Parameter Block */
+ DPRINT("Creating Process Parameters: %wZ %wZ %wZ %wZ %wZ %wZ %wZ\n",
+ &ImageName, &DllPath, &CommandLine, &Desktop, &Title, &Shell,
+ &Runtime);
+ Status = RtlCreateProcessParameters(&ProcessParameters,
+ &ImageName,
+ &DllPath,
+ lpCurrentDirectory ?
+ &CurrentDirectory : NULL,
+ &CommandLine,
+ Environment,
+ &Title,
+ &Desktop,
+ &Shell,
+ &Runtime);
+
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("Failed to create process parameters!\n");
+ return Status;
+ }
+
+ /* Check if we got an environment. If not, use ours */
+ if (Environment)
+ {
+ /* Save pointer and start lookup */
+ Environment = ScanChar = ProcessParameters->Environment;
+ }
+ else
+ {
+ /* Save pointer and start lookup */
+ Environment = ScanChar = OurPeb->ProcessParameters->Environment;
+ }
+
+ /* Find the environment size */
+ if (ScanChar)
+ {
+ while (*ScanChar) while (*ScanChar++);
+
+ /* Calculate the size of the block */
+ EnviroSize = (ULONG)((ULONG_PTR)ScanChar - (ULONG_PTR)Environment);
+ DPRINT("EnvironmentSize %ld\n", EnviroSize);
+
+ /* Allocate and Initialize new Environment Block */
+ Size = EnviroSize;
+ ProcessParameters->Environment = NULL;
+ Status = ZwAllocateVirtualMemory(ProcessHandle,
+ (PVOID*)&ProcessParameters->Environment,
+ 0,
+ &Size,
+ MEM_COMMIT,
+ PAGE_READWRITE);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("Failed to allocate Environment Block\n");
+ return(Status);
+ }
+
+ /* Write the Environment Block */
+ ZwWriteVirtualMemory(ProcessHandle,
+ ProcessParameters->Environment,
+ Environment,
+ EnviroSize,
+ NULL);
+ }
+
+ /* Write new parameters */
+ ProcessParameters->StartingX = StartupInfo->dwX;
+ ProcessParameters->StartingY = StartupInfo->dwY;
+ ProcessParameters->CountX = StartupInfo->dwXSize;
+ ProcessParameters->CountY = StartupInfo->dwYSize;
+ ProcessParameters->CountCharsX = StartupInfo->dwXCountChars;
+ ProcessParameters->CountCharsY = StartupInfo->dwYCountChars;
+ ProcessParameters->FillAttribute = StartupInfo->dwFillAttribute;
+ ProcessParameters->WindowFlags = StartupInfo->dwFlags;
+ ProcessParameters->ShowWindowFlags = StartupInfo->wShowWindow;
+
+ /* Write the handles only if we have to */
+ if (StartupInfo->dwFlags & STARTF_USESTDHANDLES)
+ {
+ ProcessParameters->StandardInput = StartupInfo->hStdInput;
+ ProcessParameters->StandardOutput = StartupInfo->hStdOutput;
+ ProcessParameters->StandardError = StartupInfo->hStdError;
+ }
+
+ /* Use Special Flags for ConDllInitialize in Kernel32 */
+ if (CreationFlags & DETACHED_PROCESS)
+ {
+ ProcessParameters->ConsoleHandle = HANDLE_DETACHED_PROCESS;
+ }
+ else if (CreationFlags & CREATE_NO_WINDOW)
+ {
+ ProcessParameters->ConsoleHandle = HANDLE_CREATE_NO_WINDOW;
+ }
+ else if (CreationFlags & CREATE_NEW_CONSOLE)
+ {
+ ProcessParameters->ConsoleHandle = HANDLE_CREATE_NEW_CONSOLE;
+ }
+ else
+ {
+ /* Inherit our Console Handle */
+ ProcessParameters->ConsoleHandle = OurPeb->ProcessParameters->ConsoleHandle;
+
+ /* Is the shell trampling on our Handles? */
+ if (!(StartupInfo->dwFlags &
+ (STARTF_USESTDHANDLES | STARTF_USEHOTKEY | STARTF_SHELLPRIVATE)))
+ {
+ /* Use handles from PEB, if inheriting or they are console */
+ BasepCopyHandles(ProcessParameters,
+ OurPeb->ProcessParameters,
+ InheritHandles);
+ }
+ }
+
+ /* Also set the Console Flag */
+ if (CreationFlags & CREATE_NEW_PROCESS_GROUP)
+ {
+ ProcessParameters->ConsoleFlags = 1;
+ }
+
+ /* Allocate memory for the parameter block */
+ Size = ProcessParameters->Length;
+ Status = NtAllocateVirtualMemory(ProcessHandle,
+ (PVOID*)&RemoteParameters,
+ 0,
+ &Size,
+ MEM_COMMIT,
+ PAGE_READWRITE);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("Failed to allocate Parameters Block\n");
+ return(Status);
+ }
+
+ /* Set the allocated size */
+ ProcessParameters->MaximumLength = Size;
+
+ /* Handle some Parameter Flags */
+ ProcessParameters->ConsoleFlags = (CreationFlags & CREATE_NEW_PROCESS_GROUP);
+ ProcessParameters->Flags |= (CreationFlags & PROFILE_USER) ?
+ PPF_PROFILE_USER : 0;
+ ProcessParameters->Flags |= (CreationFlags & PROFILE_KERNEL) ?
+ PPF_PROFILE_KERNEL : 0;
+ ProcessParameters->Flags |= (CreationFlags & PROFILE_SERVER) ?
+ PPF_PROFILE_SERVER : 0;
+ ProcessParameters->Flags |= (NtCurrentPeb()->ProcessParameters->Flags &
+ PPF_DISABLE_HEAP_CHECKS);
+
+ /* Write the Parameter Block */
+ Status = NtWriteVirtualMemory(ProcessHandle,
+ RemoteParameters,
+ ProcessParameters,
+ ProcessParameters->Length,
+ NULL);
+
+ /* Write the PEB Pointer */
+ Status = NtWriteVirtualMemory(ProcessHandle,
+ &Peb->ProcessParameters,
+ &RemoteParameters,
+ sizeof(PVOID),
+ NULL);
+
+ /* Cleanup */
+ RtlFreeHeap(GetProcessHeap(), 0, DllPath.Buffer);
+ RtlDestroyProcessParameters(ProcessParameters);
+
+ DPRINT("Completed\n");
+ return STATUS_SUCCESS;
+}
- /* write pointer to process parameter block */
- Offset = FIELD_OFFSET(PEB, ProcessParameters);
- NtWriteVirtualMemory(ProcessHandle,
- (PVOID)(PEB_BASE + Offset),
- &PpbBase,
- sizeof(PpbBase),
- &BytesWritten);
+/* FUNCTIONS ****************************************************************/
- /* Read image base address. */
- Offset = FIELD_OFFSET(PEB, ImageBaseAddress);
- NtReadVirtualMemory(ProcessHandle,
- (PVOID)(PEB_BASE + Offset),
- ImageBaseAddress,
- sizeof(PVOID),
- &BytesWritten);
+/*
+ * FUNCTION: The CreateProcess function creates a new process and its
+ * primary thread. The new process executes the specified executable file
+ * ARGUMENTS:
+ *
+ * lpApplicationName = Pointer to name of executable module
+ * lpCommandLine = Pointer to command line string
+ * lpProcessAttributes = Process security attributes
+ * lpThreadAttributes = Thread security attributes
+ * bInheritHandles = Handle inheritance flag
+ * dwCreationFlags = Creation flags
+ * lpEnvironment = Pointer to new environment block
+ * lpCurrentDirectory = Pointer to current directory name
+ * lpStartupInfo = Pointer to startup info
+ * lpProcessInformation = Pointer to process information
+ *
+ * @implemented
+ */
+BOOL
+STDCALL
+CreateProcessA(LPCSTR lpApplicationName,
+ LPSTR lpCommandLine,
+ LPSECURITY_ATTRIBUTES lpProcessAttributes,
+ LPSECURITY_ATTRIBUTES lpThreadAttributes,
+ BOOL bInheritHandles,
+ DWORD dwCreationFlags,
+ LPVOID lpEnvironment,
+ LPCSTR lpCurrentDirectory,
+ LPSTARTUPINFOA lpStartupInfo,
+ LPPROCESS_INFORMATION lpProcessInformation)
+{
+ PUNICODE_STRING CommandLine = NULL;
+ UNICODE_STRING DummyString;
+ UNICODE_STRING LiveCommandLine;
+ UNICODE_STRING ApplicationName;
+ UNICODE_STRING CurrentDirectory;
+ BOOL bRetVal;
+ STARTUPINFOW StartupInfo;
+
+ DPRINT("dwCreationFlags %x, lpEnvironment %x, lpCurrentDirectory %x, "
+ "lpStartupInfo %x, lpProcessInformation %x\n",
+ dwCreationFlags, lpEnvironment, lpCurrentDirectory,
+ lpStartupInfo, lpProcessInformation);
+
+ /* Copy Startup Info */
+ RtlMoveMemory(&StartupInfo, lpStartupInfo, sizeof(*lpStartupInfo));
+
+ /* Initialize all strings to nothing */
+ LiveCommandLine.Buffer = NULL;
+ DummyString.Buffer = NULL;
+ ApplicationName.Buffer = NULL;
+ CurrentDirectory.Buffer = NULL;
+ StartupInfo.lpDesktop = NULL;
+ StartupInfo.lpReserved = NULL;
+ StartupInfo.lpTitle = NULL;
+
+ /* Convert the Command line */
+ if (lpCommandLine)
+ {
+ /* If it's too long, then we'll have a problem */
+ if ((strlen(lpCommandLine) + 1) * sizeof(WCHAR) <
+ NtCurrentTeb()->StaticUnicodeString.MaximumLength)
+ {
+ /* Cache it in the TEB */
+ CommandLine = Basep8BitStringToCachedUnicodeString(lpCommandLine);
+ }
+ else
+ {
+ /* Use a dynamic version */
+ Basep8BitStringToHeapUnicodeString(&LiveCommandLine,
+ lpCommandLine);
+ }
+ }
+ else
+ {
+ /* The logic below will use CommandLine, so we must make it valid */
+ CommandLine = &DummyString;
+ }
+
+ /* Convert the Name and Directory */
+ if (lpApplicationName)
+ {
+ Basep8BitStringToHeapUnicodeString(&ApplicationName,
+ lpApplicationName);
+ }
+ if (lpCurrentDirectory)
+ {
+ Basep8BitStringToHeapUnicodeString(&CurrentDirectory,
+ lpCurrentDirectory);
+ }
+
+ /* Now convert Startup Strings */
+ if (lpStartupInfo->lpReserved)
+ {
+ BasepAnsiStringToHeapUnicodeString(lpStartupInfo->lpReserved,
+ &StartupInfo.lpReserved);
+ }
+ if (lpStartupInfo->lpDesktop)
+ {
+ BasepAnsiStringToHeapUnicodeString(lpStartupInfo->lpDesktop,
+ &StartupInfo.lpDesktop);
+ }
+ if (lpStartupInfo->lpTitle)
+ {
+ BasepAnsiStringToHeapUnicodeString(lpStartupInfo->lpTitle,
+ &StartupInfo.lpTitle);
+ }
- return(STATUS_SUCCESS);
+ /* Call the Unicode function */
+ bRetVal = CreateProcessW(ApplicationName.Buffer,
+ LiveCommandLine.Buffer ?
+ LiveCommandLine.Buffer : CommandLine->Buffer,
+ lpProcessAttributes,
+ lpThreadAttributes,
+ bInheritHandles,
+ dwCreationFlags,
+ lpEnvironment,
+ CurrentDirectory.Buffer,
+ &StartupInfo,
+ lpProcessInformation);
+
+ /* Clean up */
+ RtlFreeUnicodeString(&ApplicationName);
+ RtlFreeUnicodeString(&LiveCommandLine);
+ RtlFreeUnicodeString(&CurrentDirectory);
+ RtlFreeHeap(GetProcessHeap(), 0, StartupInfo.lpDesktop);
+ RtlFreeHeap(GetProcessHeap(), 0, StartupInfo.lpReserved);
+ RtlFreeHeap(GetProcessHeap(), 0, StartupInfo.lpTitle);
+
+ /* Return what Unicode did */
+ return bRetVal;
}
-
/*
* @implemented
*/
-WINBOOL STDCALL
-CreateProcessW
-(
- LPCWSTR lpApplicationName,
- LPWSTR lpCommandLine,
- LPSECURITY_ATTRIBUTES lpProcessAttributes,
- LPSECURITY_ATTRIBUTES lpThreadAttributes,
- WINBOOL bInheritHandles,
- DWORD dwCreationFlags,
- LPVOID lpEnvironment,
- LPCWSTR lpCurrentDirectory,
- LPSTARTUPINFOW lpStartupInfo,
- LPPROCESS_INFORMATION lpProcessInformation
-)
+BOOL
+STDCALL
+CreateProcessW(LPCWSTR lpApplicationName,
+ LPWSTR lpCommandLine,
+ LPSECURITY_ATTRIBUTES lpProcessAttributes,
+ LPSECURITY_ATTRIBUTES lpThreadAttributes,
+ BOOL bInheritHandles,
+ DWORD dwCreationFlags,
+ LPVOID lpEnvironment,
+ LPCWSTR lpCurrentDirectory,
+ LPSTARTUPINFOW lpStartupInfo,
+ LPPROCESS_INFORMATION lpProcessInformation)
{
- HANDLE hSection, hProcess, hThread;
- NTSTATUS Status;
- WCHAR ImagePathName[256];
- UNICODE_STRING ImagePathName_U;
- PROCESS_BASIC_INFORMATION ProcessBasicInfo;
- ULONG retlen;
- PRTL_USER_PROCESS_PARAMETERS Ppb;
- UNICODE_STRING CommandLine_U;
- CSRSS_API_REQUEST CsrRequest;
- CSRSS_API_REPLY CsrReply;
- CHAR ImageFileName[8];
- PWCHAR s, e;
- ULONG i;
- UNICODE_STRING CurrentDirectory_U;
- SECTION_IMAGE_INFORMATION Sii;
- WCHAR TempCurrentDirectoryW[256];
- WCHAR TempApplicationNameW[256];
- WCHAR TempCommandLineNameW[256];
- UNICODE_STRING RuntimeInfo_U;
- PVOID ImageBaseAddress;
- BOOL InputSet, OutputSet, ErrorSet;
- BOOL InputDup, OutputDup, ErrorDup;
-
- DPRINT("CreateProcessW(lpApplicationName '%S', lpCommandLine '%S')\n",
- lpApplicationName, lpCommandLine);
-
- if (lpApplicationName != NULL && lpApplicationName[0] != 0)
- {
- wcscpy (TempApplicationNameW, lpApplicationName);
- i = wcslen(TempApplicationNameW);
- if (TempApplicationNameW[i - 1] == L'.')
- {
- TempApplicationNameW[i - 1] = 0;
- }
- else
- {
- s = max(wcsrchr(TempApplicationNameW, L'\\'), wcsrchr(TempApplicationNameW, L'/'));
- if (s == NULL)
- {
- s = TempApplicationNameW;
- }
- else
- {
- s++;
- }
- e = wcsrchr(s, L'.');
- if (e == NULL)
- {
- wcscat(s, L".exe");
- e = wcsrchr(s, L'.');
- }
- }
- }
- else if (lpCommandLine != NULL && lpCommandLine[0] != 0)
- {
- if (lpCommandLine[0] == L'"')
- {
- wcscpy(TempApplicationNameW, lpCommandLine + 1);
- s = wcschr(TempApplicationNameW, L'"');
- if (s == NULL)
- {
- return FALSE;
- }
- *s = 0;
- }
- else
- {
- wcscpy(TempApplicationNameW, lpCommandLine);
- s = wcschr(TempApplicationNameW, L' ');
- if (s != NULL)
- {
- *s = 0;
- }
- }
- s = max(wcsrchr(TempApplicationNameW, L'\\'), wcsrchr(TempApplicationNameW, L'/'));
- if (s == NULL)
- {
- s = TempApplicationNameW;
- }
- s = wcsrchr(s, L'.');
- if (s == NULL)
- wcscat(TempApplicationNameW, L".exe");
- }
- else
- {
- return FALSE;
- }
-
- DPRINT("CreateProcessW(lpApplicationName '%S', lpCommandLine '%S')\n",
- lpApplicationName, lpCommandLine);
-
- if (!SearchPathW(NULL, TempApplicationNameW, NULL, sizeof(ImagePathName)/sizeof(WCHAR), ImagePathName, &s))
- {
- return FALSE;
- }
+ NTSTATUS Status;
+ PROCESS_PRIORITY_CLASS PriorityClass;
+ BOOLEAN FoundQuotes = FALSE;
+ BOOLEAN QuotesNeeded = FALSE;
+ BOOLEAN CmdLineIsAppName = FALSE;
+ UNICODE_STRING ApplicationName;
+ OBJECT_ATTRIBUTES LocalObjectAttributes;
+ POBJECT_ATTRIBUTES ObjectAttributes;
+ HANDLE hSection, hProcess, hThread;
+ SECTION_IMAGE_INFORMATION SectionImageInfo;
+ LPWSTR CurrentDirectory = NULL;
+ LPWSTR CurrentDirectoryPart;
+ PROCESS_BASIC_INFORMATION ProcessBasicInfo;
+ STARTUPINFOW StartupInfo;
+ ULONG Dummy;
+ LPWSTR BatchCommandLine;
+ ULONG CmdLineLength;
+ UNICODE_STRING CommandLineString;
+ LPWSTR TempBuffer;
+ PWCHAR Extension;
+ LPWSTR QuotedCmdLine = NULL;
+ LPWSTR ScanString;
+ LPWSTR NullBuffer = NULL;
+ LPWSTR NameBuffer = NULL;
+ WCHAR SaveChar = 0;
+ ULONG RetVal;
+ UINT Error = 0;
+ BOOLEAN SearchDone = FALSE;
+ CLIENT_ID ClientId;
+ PPEB OurPeb = NtCurrentPeb();
+ PPEB RemotePeb;
+
+ DPRINT("CreateProcessW: lpApplicationName: %S lpCommandLine: %S"
+ " lpEnvironment: %p lpCurrentDirectory: %S dwCreationFlags: %lx\n",
+ lpApplicationName, lpCommandLine, lpEnvironment, lpCurrentDirectory,
+ dwCreationFlags);
+
+ /* Flags we don't handle yet */
+ if (dwCreationFlags & CREATE_SEPARATE_WOW_VDM)
+ {
+ DPRINT1("CREATE_SEPARATE_WOW_VDM not handled\n");
+ }
+ if (dwCreationFlags & CREATE_SHARED_WOW_VDM)
+ {
+ DPRINT1("CREATE_SHARED_WOW_VDM not handled\n");
+ }
+ if (dwCreationFlags & CREATE_FORCEDOS)
+ {
+ DPRINT1("CREATE_FORCEDOS not handled\n");
+ }
+
+ /* Fail on this flag, it's only valid with the WithLogonW function */
+ if (dwCreationFlags & CREATE_PRESERVE_CODE_AUTHZ_LEVEL)
+ {
+ DPRINT1("Invalid flag used\n");
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return FALSE;
+ }
+
+ /* This combination is illegal (see MSDN) */
+ if ((dwCreationFlags & (DETACHED_PROCESS | CREATE_NEW_CONSOLE)) ==
+ (DETACHED_PROCESS | CREATE_NEW_CONSOLE))
+ {
+ DPRINT1("Invalid flag combo used\n");
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return FALSE;
+ }
+
+ /* Another illegal combo */
+ if ((dwCreationFlags & (CREATE_SEPARATE_WOW_VDM | CREATE_SHARED_WOW_VDM)) ==
+ (CREATE_SEPARATE_WOW_VDM | CREATE_SHARED_WOW_VDM))
+ {
+ DPRINT1("Invalid flag combo used\n");
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return FALSE;
+ }
- e = wcsrchr(s, L'.');
- if (e != NULL && (!_wcsicmp(e, L".bat") || !_wcsicmp(e, L".cmd")))
- {
- // the command is a batch file
- if (lpApplicationName != NULL && lpApplicationName[0])
- {
- // FIXME: use COMSPEC for the command interpreter
- wcscpy(TempCommandLineNameW, L"cmd /c ");
- wcscat(TempCommandLineNameW, lpApplicationName);
- lpCommandLine = TempCommandLineNameW;
- wcscpy(TempApplicationNameW, L"cmd.exe");
- if (!SearchPathW(NULL, TempApplicationNameW, NULL, sizeof(ImagePathName)/sizeof(WCHAR), ImagePathName, &s))
- {
- return FALSE;
- }
- }
- else
- {
- return FALSE;
- }
- }
+ /*
+ * We're going to modify and mask out flags and stuff in lpStartupInfo,
+ * so we'll use our own local copy for that.
+ */
+ StartupInfo = *lpStartupInfo;
+
+ /* FIXME: Use default Separate/Shared VDM Flag */
+
+ /* If we are inside a Job, use Separate VDM so it won't escape the Job */
+ if (!(dwCreationFlags & CREATE_SEPARATE_WOW_VDM))
+ {
+ if (NtIsProcessInJob(NtCurrentProcess(), NULL))
+ {
+ /* Remove the shared flag and add the separate flag. */
+ dwCreationFlags = (dwCreationFlags &~ CREATE_SHARED_WOW_VDM) |
+ CREATE_SEPARATE_WOW_VDM;
+ }
+ }
- /*
- * Store the image file name for the process
- */
- e = wcschr(s, L'.');
- if (e != NULL)
- {
- *e = 0;
- }
- for (i = 0; i < 8; i++)
- {
- ImageFileName[i] = (CHAR)(s[i]);
- }
- if (e != NULL)
- {
- *e = '.';
- }
-
- /*
- * Process the application name and command line
- */
- RtlInitUnicodeString(&ImagePathName_U, ImagePathName);
- RtlInitUnicodeString(&CommandLine_U, lpCommandLine);
+ /*
+ * According to some sites, ShellExecuteEx uses an undocumented flag to
+ * send private handle data (such as HMONITOR or HICON). See:
+ * www.catch22.net/tuts/undoc01.asp. This implies that we can't use the
+ * standard handles anymore since we'd be overwriting this private data
+ */
+ if ((StartupInfo.dwFlags & STARTF_USESTDHANDLES) &&
+ (StartupInfo.dwFlags & (STARTF_USEHOTKEY | STARTF_SHELLPRIVATE)))
+ {
+ StartupInfo.dwFlags &= ~STARTF_USESTDHANDLES;
+ }
- DPRINT("ImagePathName_U %S\n", ImagePathName_U.Buffer);
- DPRINT("CommandLine_U %S\n", CommandLine_U.Buffer);
+ /* Start by zeroing out the fields */
+ RtlZeroMemory(lpProcessInformation, sizeof(PROCESS_INFORMATION));
- /* Initialize the current directory string */
- if (lpCurrentDirectory != NULL)
- {
- RtlInitUnicodeString(&CurrentDirectory_U,
- lpCurrentDirectory);
- }
- else
- {
- GetCurrentDirectoryW(256, TempCurrentDirectoryW);
- RtlInitUnicodeString(&CurrentDirectory_U,
- TempCurrentDirectoryW);
- }
+ /* Easy stuff first, convert the process priority class */
+ PriorityClass.Foreground = FALSE;
+ PriorityClass.PriorityClass = BasepConvertPriorityClass(dwCreationFlags);
- /*
- * Create a section for the executable
- */
-
- hSection = KlMapFile (ImagePathName);
- if (hSection == NULL)
- {
-/////////////////////////////////////////
- /*
- * Inspect the image to determine executable flavour
- */
- IO_STATUS_BLOCK IoStatusBlock;
- UNICODE_STRING ApplicationNameString;
- OBJECT_ATTRIBUTES ObjectAttributes;
- PSECURITY_DESCRIPTOR SecurityDescriptor = NULL;
- IMAGE_DOS_HEADER DosHeader;
- IO_STATUS_BLOCK Iosb;
- LARGE_INTEGER Offset;
- HANDLE hFile = NULL;
-
- DPRINT("Inspecting Image Header for image type id\n");
+ /* Convert the environment */
+ if(lpEnvironment && !(dwCreationFlags & CREATE_UNICODE_ENVIRONMENT))
+ {
+ lpEnvironment = BasepConvertUnicodeEnvironment(lpEnvironment);
+ if (!lpEnvironment) return FALSE;
+ }
- // Find the application name
- if (!RtlDosPathNameToNtPathName_U((LPWSTR)lpApplicationName,
- &ApplicationNameString, NULL, NULL)) {
+ /* Get the application name and do all the proper formating necessary */
+GetAppName:
+ /* See if we have an application name (oh please let us have one!) */
+ if (!lpApplicationName)
+ {
+ /* The fun begins */
+ NameBuffer = RtlAllocateHeap(GetProcessHeap(),
+ 0,
+ MAX_PATH * sizeof(WCHAR));
+
+ /* This is all we have to work with :( */
+ lpApplicationName = lpCommandLine;
+
+ /* Initialize our friends at the beginning */
+ NullBuffer = (LPWSTR)lpApplicationName;
+ ScanString = (LPWSTR)lpApplicationName;
+
+ /* We will start by looking for a quote */
+ if (*ScanString == L'\"')
+ {
+ /* That was quick */
+ SearchDone = TRUE;
+
+ /* Advance past quote */
+ ScanString++;
+ lpApplicationName = ScanString;
+
+ /* Find the closing quote */
+ while (*ScanString)
+ {
+ if (*ScanString == L'\"')
+ {
+ /* Found it */
+ NullBuffer = ScanString;
+ FoundQuotes = TRUE;
+ break;
+ }
+
+ /* Keep looking */
+ ScanString++;
+ NullBuffer = ScanString;
+ }
+ }
+ else
+ {
+ /* No quotes, so we'll be looking for white space */
+ WhiteScan:
+ /* Reset the pointer */
+ lpApplicationName = lpCommandLine;
+
+ /* Find whitespace of Tab */
+ while (*ScanString)
+ {
+ if (*ScanString == ' ' || *ScanString == '\t')
+ {
+ /* Found it */
+ NullBuffer = ScanString;
+ break;
+ }
+
+ /* Keep looking */
+ ScanString++;
+ NullBuffer = ScanString;
+ }
+ }
+
+ /* Set the Null Buffer */
+ SaveChar = *NullBuffer;
+ *NullBuffer = UNICODE_NULL;
+
+ /* Do a search for the file */
+ DPRINT("Ready for SearchPathW: %S\n", lpApplicationName);
+ RetVal = SearchPathW(NULL,
+ lpApplicationName,
+ L".exe",
+ MAX_PATH,
+ NameBuffer,
+ NULL) * sizeof(WCHAR);
+
+ /* Did it find something? */
+ if (RetVal)
+ {
+ /* Get file attributes */
+ ULONG Attributes = GetFileAttributesW(NameBuffer);
+ if (Attributes & FILE_ATTRIBUTE_DIRECTORY)
+ {
+ /* Give it a length of 0 to fail, this was a directory. */
+ RetVal = 0;
+ }
+ else
+ {
+ /* It's a file! */
+ RetVal += sizeof(WCHAR);
+ }
+ }
+
+ /* Now check if we have a file, and if the path size is OK */
+ if (!RetVal || RetVal >= (MAX_PATH / sizeof(WCHAR)))
+ {
+ ULONG PathType;
+ HANDLE hFile;
+
+ /* We failed, try to get the Path Type */
+ DPRINT("SearchPathW failed. Retval: %ld\n", RetVal);
+ PathType = RtlDetermineDosPathNameType_U(lpApplicationName);
+
+ /* If it's not relative, try to get the error */
+ if (PathType != RELATIVE_PATH)
+ {
+ /* This should fail, and give us a detailed LastError */
+ hFile = CreateFileW(lpApplicationName,
+ GENERIC_READ,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ NULL,
+ OPEN_EXISTING,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL);
+
+ /* Did it actually NOT fail? */
+ if (hFile != INVALID_HANDLE_VALUE)
+ {
+ /* Fake the error */
+ CloseHandle(hFile);
+ SetLastErrorByStatus(STATUS_OBJECT_NAME_NOT_FOUND);
+ }
+ }
+ else
+ {
+ /* Immediately set the error */
+ SetLastErrorByStatus(STATUS_OBJECT_NAME_NOT_FOUND);
+ }
+
+ /* Did we already fail once? */
+ if (Error)
+ {
+ SetLastError(Error);
+ }
+ else
+ {
+ /* Not yet, cache it */
+ Error = GetLastError();
+ }
+
+ /* Put back the command line */
+ *NullBuffer = SaveChar;
+ lpApplicationName = NameBuffer;
+
+ /*
+ * If the search isn't done and we still have cmdline
+ * then start over. Ex: c:\ha ha ha\haha.exe
+ */
+ if (*ScanString && !SearchDone)
+ {
+ /* Move in the buffer */
+ ScanString++;
+ NullBuffer = ScanString;
+
+ /* We will have to add a quote, since there is a space*/
+ QuotesNeeded = TRUE;
+
+ /* And we will also fake the fact we found one */
+ FoundQuotes = TRUE;
+
+ /* Start over */
+ goto WhiteScan;
+ }
+
+ /* We totally failed */
return FALSE;
}
- DPRINT("ApplicationName %S\n",ApplicationNameString.Buffer);
-
- InitializeObjectAttributes(&ObjectAttributes,
- &ApplicationNameString,
- OBJ_CASE_INSENSITIVE,
- NULL,
- SecurityDescriptor);
+
+ /* Put back the command line */
+ *NullBuffer = SaveChar;
+ lpApplicationName = NameBuffer;
+ DPRINT("SearchPathW suceeded (%ld): %S\n", RetVal, NameBuffer);
+ }
+ else if (!lpCommandLine || *lpCommandLine == UNICODE_NULL)
+ {
+ /* We have an app name (good!) but no command line */
+ CmdLineIsAppName = TRUE;
+ lpCommandLine = (LPWSTR)lpApplicationName;
+ }
+
+ /* At this point the name has been toyed with enough to be openable */
+ Status = BasepMapFile(lpApplicationName, &hSection, &ApplicationName);
+
+ /* Check for failure */
+ if (!NT_SUCCESS(Status))
+ {
+ /* Could be a non-PE File */
+ switch (Status)
+ {
+ /* Check if the Kernel tells us it's not even valid MZ */
+ case STATUS_INVALID_IMAGE_NE_FORMAT:
+ case STATUS_INVALID_IMAGE_PROTECT:
+ case STATUS_INVALID_IMAGE_NOT_MZ:
+
+ /* If it's a DOS app, use VDM
+ if ((BasepCheckDosApp(&ApplicationName))) */
+ {
+ DPRINT1("Launching VDM...\n");
+ RtlFreeHeap(GetProcessHeap(), 0, NameBuffer);
+ RtlFreeHeap(GetProcessHeap(), 0, ApplicationName.Buffer);
+ return CreateProcessW(L"ntvdm.exe",
+ (LPWSTR)lpApplicationName,
+ lpProcessAttributes,
+ lpThreadAttributes,
+ bInheritHandles,
+ dwCreationFlags,
+ lpEnvironment,
+ lpCurrentDirectory,
+ lpStartupInfo,
+ lpProcessInformation);
+ }
+
+ /* It's a batch file */
+ Extension = &ApplicationName.Buffer[ApplicationName.Length /
+ sizeof(WCHAR) - 4];
+
+ /* Make sure the extensions are correct */
+ if (_wcsnicmp(Extension, L".bat", 4) && _wcsnicmp(Extension, L".cmd", 4))
+ {
+ SetLastError(ERROR_BAD_EXE_FORMAT);
+ return FALSE;
+ }
+
+ /* Calculate the length of the command line */
+ CmdLineLength = wcslen(CMD_STRING) + wcslen(lpCommandLine) + 1;
+
+ /* If we found quotes, then add them into the length size */
+ if (CmdLineIsAppName || FoundQuotes) CmdLineLength += 2;
+ CmdLineLength *= sizeof(WCHAR);
+
+ /* Allocate space for the new command line */
+ BatchCommandLine = RtlAllocateHeap(GetProcessHeap(),
+ 0,
+ CmdLineLength);
+
+ /* Build it */
+ wcscpy(BatchCommandLine, CMD_STRING);
+ if (CmdLineIsAppName || FoundQuotes)
+ {
+ wcscat(BatchCommandLine, L"\"");
+ }
+ wcscat(BatchCommandLine, lpCommandLine);
+ if (CmdLineIsAppName || FoundQuotes)
+ {
+ wcscat(BatchCommandLine, L"\"");
+ }
+
+ /* Create it as a Unicode String */
+ RtlInitUnicodeString(&CommandLineString, BatchCommandLine);
+
+ /* Set the command line to this */
+ lpCommandLine = CommandLineString.Buffer;
+ lpApplicationName = NULL;
+
+ /* Free memory */
+ RtlFreeHeap(GetProcessHeap(), 0, TempBuffer);
+ RtlFreeHeap(GetProcessHeap(), 0, ApplicationName.Buffer);
+ ApplicationName.Buffer = NULL;
+ TempBuffer = NULL;
+ goto GetAppName;
+ break;
+
+ case STATUS_INVALID_IMAGE_WIN_16:
+
+ /* It's a Win16 Image, use VDM */
+ DPRINT1("Launching VDM...\n");
+ RtlFreeHeap(GetProcessHeap(), 0, NameBuffer);
+ RtlFreeHeap(GetProcessHeap(), 0, ApplicationName.Buffer);
+ return CreateProcessW(L"ntvdm.exe",
+ (LPWSTR)lpApplicationName,
+ lpProcessAttributes,
+ lpThreadAttributes,
+ bInheritHandles,
+ dwCreationFlags,
+ lpEnvironment,
+ lpCurrentDirectory,
+ lpStartupInfo,
+ lpProcessInformation);
+
+ default:
+ /* Invalid Image Type */
+ SetLastError(ERROR_BAD_EXE_FORMAT);
+ return FALSE;
+ }
+ }
+
+ /* Use our desktop if we didn't get any */
+ if (!StartupInfo.lpDesktop)
+ {
+ StartupInfo.lpDesktop = OurPeb->ProcessParameters->DesktopInfo.Buffer;
+ }
+
+ /* FIXME: Check if Application is allowed to run */
+
+ /* FIXME: Allow CREATE_SEPARATE only for WOW Apps, once we have that. */
+
+ /* Get some information about the executable */
+ Status = ZwQuerySection(hSection,
+ SectionImageInformation,
+ &SectionImageInfo,
+ sizeof(SectionImageInfo),
+ NULL);
+ if(!NT_SUCCESS(Status))
+ {
+ NtClose(hSection);
+ DPRINT1("Unable to get SectionImageInformation, status 0x%x\n", Status);
+ SetLastErrorByStatus(Status);
+ return FALSE;
+ }
- // Try to open the executable
- Status = NtOpenFile(&hFile,
- SYNCHRONIZE|FILE_EXECUTE|FILE_READ_DATA,
- &ObjectAttributes,
- &IoStatusBlock,
- FILE_SHARE_DELETE|FILE_SHARE_READ,
- FILE_SYNCHRONOUS_IO_NONALERT|FILE_NON_DIRECTORY_FILE);
+ /* Don't execute DLLs */
+ if (SectionImageInfo.ImageCharacteristics & IMAGE_FILE_DLL)
+ {
+ NtClose(hSection);
+ DPRINT1("Can't execute a DLL\n");
+ SetLastError(ERROR_BAD_EXE_FORMAT);
+ return FALSE;
+ }
+
+ /* FIXME: Check for Debugger */
+
+ /* FIXME: Check if Machine Type and SubSys Version Match */
+
+ /* We don't support POSIX or anything else for now */
+ if (IMAGE_SUBSYSTEM_WINDOWS_GUI != SectionImageInfo.SubsystemType &&
+ IMAGE_SUBSYSTEM_WINDOWS_CUI != SectionImageInfo.SubsystemType)
+ {
+ NtClose(hSection);
+ DPRINT1("Invalid subsystem %d\n", SectionImageInfo.SubsystemType);
+ SetLastError(ERROR_BAD_EXE_FORMAT);
+ return FALSE;
+ }
- RtlFreeUnicodeString(&ApplicationNameString);
+ /* Initialize the process object attributes */
+ ObjectAttributes = BasepConvertObjectAttributes(&LocalObjectAttributes,
+ lpProcessAttributes,
+ NULL);
+
+ /* Create the Process */
+ Status = NtCreateProcess(&hProcess,
+ PROCESS_ALL_ACCESS,
+ ObjectAttributes,
+ NtCurrentProcess(),
+ bInheritHandles,
+ hSection,
+ NULL,
+ NULL);
+ if(!NT_SUCCESS(Status))
+ {
+ NtClose(hSection);
+ DPRINT1("Unable to create process, status 0x%x\n", Status);
+ SetLastErrorByStatus(Status);
+ return FALSE;
+ }
+
+ /* Set new class */
+ Status = NtSetInformationProcess(hProcess,
+ ProcessPriorityClass,
+ &PriorityClass,
+ sizeof(PROCESS_PRIORITY_CLASS));
+ if(!NT_SUCCESS(Status))
+ {
+ NtClose(hProcess);
+ NtClose(hSection);
+ DPRINT1("Unable to set new process priority, status 0x%x\n", Status);
+ SetLastErrorByStatus(Status);
+ return FALSE;
+ }
+
+ /* Set Error Mode */
+ if (dwCreationFlags & CREATE_DEFAULT_ERROR_MODE)
+ {
+ ULONG ErrorMode = SEM_FAILCRITICALERRORS;
+ NtSetInformationProcess(hProcess,
+ ProcessDefaultHardErrorMode,
+ &ErrorMode,
+ sizeof(ULONG));
+ }
- if (!NT_SUCCESS(Status)) {
- DPRINT("Failed to open file\n");
- SetLastErrorByStatus(Status);
+ /* Convert the directory to a full path */
+ if (lpCurrentDirectory)
+ {
+ /* Allocate a buffer */
+ CurrentDirectory = RtlAllocateHeap(GetProcessHeap(),
+ 0,
+ MAX_PATH * sizeof(WCHAR) + 2);
+
+ /* Get the length */
+ if (GetFullPathNameW(lpCurrentDirectory,
+ MAX_PATH,
+ CurrentDirectory,
+ &CurrentDirectoryPart) > MAX_PATH)
+ {
+ DPRINT1("Directory name too long\n");
+ SetLastError(ERROR_DIRECTORY);
return FALSE;
}
-
- // Read the dos header
- Offset.QuadPart = 0;
- Status = ZwReadFile(hFile,
- NULL,
- NULL,
- NULL,
- &Iosb,
- &DosHeader,
- sizeof(DosHeader),
- &Offset,
- 0);
-
- if (!NT_SUCCESS(Status)) {
- DPRINT("Failed to read from file\n");
- SetLastErrorByStatus(Status);
- return FALSE;
+ }
+
+ /* Insert quotes if needed */
+ if (QuotesNeeded || CmdLineIsAppName)
+ {
+ /* Allocate a buffer */
+ QuotedCmdLine = RtlAllocateHeap(GetProcessHeap(),
+ 0,
+ (wcslen(lpCommandLine) + 2 + 1) *
+ sizeof(WCHAR));
+
+ /* Copy the first quote */
+ wcscpy(QuotedCmdLine, L"\"");
+
+ /* Save a null char */
+ if (QuotesNeeded)
+ {
+ SaveChar = *NullBuffer;
+ *NullBuffer = UNICODE_NULL;
}
- if (Iosb.Information != sizeof(DosHeader)) {
- DPRINT("Failed to read dos header from file\n");
- SetLastErrorByStatus(STATUS_INVALID_IMAGE_FORMAT);
- return FALSE;
+
+ /* Add the command line and the finishing quote */
+ wcscat(QuotedCmdLine, lpCommandLine);
+ wcscat(QuotedCmdLine, L"\"");
+
+ /* Add the null char */
+ if (QuotesNeeded)
+ {
+ *NullBuffer = SaveChar;
+ wcscat(QuotedCmdLine, NullBuffer);
}
-
- // Check the DOS signature
- if (DosHeader.e_magic != IMAGE_DOS_SIGNATURE) {
- DPRINT("Failed dos magic check\n");
- SetLastErrorByStatus(STATUS_INVALID_IMAGE_FORMAT);
+
+ DPRINT("Quoted CmdLine: %S\n", QuotedCmdLine);
+ }
+
+ /* Get the Process Information */
+ Status = NtQueryInformationProcess(hProcess,
+ ProcessBasicInformation,
+ &ProcessBasicInfo,
+ sizeof(ProcessBasicInfo),
+ NULL);
+
+ /* Create Process Environment */
+ RemotePeb = ProcessBasicInfo.PebBaseAddress;
+ Status = BasepInitializeEnvironment(hProcess,
+ RemotePeb,
+ (LPWSTR)lpApplicationName,
+ CurrentDirectory,
+ (QuotesNeeded || CmdLineIsAppName) ?
+ QuotedCmdLine : lpCommandLine,
+ lpEnvironment,
+ lpStartupInfo,
+ dwCreationFlags,
+ bInheritHandles);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("Could not initialize Process Environment\n");
+ SetLastErrorByStatus(Status);
+ return FALSE;
+ }
+
+ /* Close the section */
+ NtClose(hSection);
+ hSection = NULL;
+
+ /* Duplicate the handles if needed */
+ if (!bInheritHandles && !(StartupInfo.dwFlags & STARTF_USESTDHANDLES) &&
+ SectionImageInfo.SubsystemType == IMAGE_SUBSYSTEM_WINDOWS_CUI)
+ {
+ PRTL_USER_PROCESS_PARAMETERS RemoteParameters;
+
+ /* Get the remote parameters */
+ Status = NtReadVirtualMemory(hProcess,
+ &RemotePeb->ProcessParameters,
+ &RemoteParameters,
+ sizeof(PVOID),
+ NULL);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("Failed to read memory\n");
return FALSE;
}
- NtClose(hFile);
-
- DPRINT("Launching VDM...\n");
- return CreateProcessW(L"ntvdm.exe",
- (LPWSTR)lpApplicationName,
- lpProcessAttributes,
- lpThreadAttributes,
- bInheritHandles,
- dwCreationFlags,
- lpEnvironment,
- lpCurrentDirectory,
- lpStartupInfo,
- lpProcessInformation);
- }
-/////////////////////////////////////////
- /*
- * Create a new process
- */
- Status = NtCreateProcess(&hProcess,
- PROCESS_ALL_ACCESS,
- NULL,
- NtCurrentProcess(),
- bInheritHandles,
- hSection,
- NULL,
- NULL);
- if (lpStartupInfo)
- {
- if (lpStartupInfo->lpReserved2)
- {
- /* FIXME:
- * ROUND_UP(xxx,2) + 2 is a dirty hack. RtlCreateProcessParameters assumes that
- * the runtimeinfo is a unicode string and use RtlCopyUnicodeString for duplication.
- * If is possible that this function overwrite the last information in runtimeinfo
- * with the null terminator for the unicode string.
- */
- RuntimeInfo_U.Length = RuntimeInfo_U.MaximumLength = ROUND_UP(lpStartupInfo->cbReserved2, 2) + 2;
- RuntimeInfo_U.Buffer = RtlAllocateHeap(GetProcessHeap(), 0, RuntimeInfo_U.Length);
- memcpy(RuntimeInfo_U.Buffer, lpStartupInfo->lpReserved2, lpStartupInfo->cbReserved2);
- }
- }
-
- /*
- * Create the PPB
- */
- RtlCreateProcessParameters(&Ppb,
- &ImagePathName_U,
- NULL,
- lpCurrentDirectory ? &CurrentDirectory_U : NULL,
- &CommandLine_U,
- lpEnvironment,
- NULL,
- NULL,
- NULL,
- lpStartupInfo && lpStartupInfo->lpReserved2 ? &RuntimeInfo_U : NULL);
-
- if (lpStartupInfo && lpStartupInfo->lpReserved2)
- RtlFreeHeap(GetProcessHeap(), 0, RuntimeInfo_U.Buffer);
-
-
- /*
- * Translate some handles for the new process
- */
- if (Ppb->CurrentDirectoryHandle)
- {
- Status = NtDuplicateObject (NtCurrentProcess(),
- Ppb->CurrentDirectoryHandle,
- hProcess,
- &Ppb->CurrentDirectoryHandle,
- 0,
- TRUE,
- DUPLICATE_SAME_ACCESS);
- }
-
- if (Ppb->hConsole)
- {
- Status = NtDuplicateObject (NtCurrentProcess(),
- Ppb->hConsole,
- hProcess,
- &Ppb->hConsole,
- 0,
- TRUE,
- DUPLICATE_SAME_ACCESS);
- }
-
- /*
- * Get some information about the executable
- */
- Status = ZwQuerySection(hSection,
- SectionImageInformation,
- &Sii,
- sizeof(Sii),
- &i);
- /*
- * Close the section
- */
- NtClose(hSection);
-
- /*
- * Get some information about the process
- */
- NtQueryInformationProcess(hProcess,
- ProcessBasicInformation,
- &ProcessBasicInfo,
- sizeof(ProcessBasicInfo),
- &retlen);
- DPRINT("ProcessBasicInfo.UniqueProcessId %d\n",
- ProcessBasicInfo.UniqueProcessId);
- lpProcessInformation->dwProcessId = ProcessBasicInfo.UniqueProcessId;
-
- /*
- * Tell the csrss server we are creating a new process
- */
- CsrRequest.Type = CSRSS_CREATE_PROCESS;
- CsrRequest.Data.CreateProcessRequest.NewProcessId =
- ProcessBasicInfo.UniqueProcessId;
- if (Sii.Subsystem == IMAGE_SUBSYSTEM_WINDOWS_GUI)
- {
- /* Do not create a console for GUI applications */
- dwCreationFlags &= ~CREATE_NEW_CONSOLE;
- dwCreationFlags |= DETACHED_PROCESS;
- }
- else if (Sii.Subsystem == IMAGE_SUBSYSTEM_WINDOWS_CUI)
- {
- if (NULL == Ppb->hConsole)
- {
- dwCreationFlags |= CREATE_NEW_CONSOLE;
- }
- }
- CsrRequest.Data.CreateProcessRequest.Flags = dwCreationFlags;
- CsrRequest.Data.CreateProcessRequest.CtrlDispatcher = ConsoleControlDispatcher;
- Status = CsrClientCallServer(&CsrRequest,
- &CsrReply,
- sizeof(CSRSS_API_REQUEST),
- sizeof(CSRSS_API_REPLY));
- if (!NT_SUCCESS(Status) || !NT_SUCCESS(CsrReply.Status))
- {
- DbgPrint("Failed to tell csrss about new process. Expect trouble.\n");
- }
- else if (Sii.Subsystem == IMAGE_SUBSYSTEM_WINDOWS_CUI)
- {
- Ppb->hConsole = CsrReply.Data.CreateProcessReply.Console;
- }
-
- InputSet = FALSE;
- OutputSet = FALSE;
- ErrorSet = FALSE;
-
- /* Set the child console handles */
-
- /* First check if handles were passed in startup info */
- if (lpStartupInfo && (lpStartupInfo->dwFlags & STARTF_USESTDHANDLES))
- {
- if (lpStartupInfo->hStdInput)
- {
- Ppb->hStdInput = lpStartupInfo->hStdInput;
- InputSet = TRUE;
- InputDup = TRUE;
- }
- if (lpStartupInfo->hStdOutput)
- {
- Ppb->hStdOutput = lpStartupInfo->hStdOutput;
- OutputSet = TRUE;
- OutputDup = TRUE;
- }
- if (lpStartupInfo->hStdError)
- {
- Ppb->hStdError = lpStartupInfo->hStdError;
- ErrorSet = TRUE;
- ErrorDup = TRUE;
- }
- }
-
- /* Check if new console was created, use it for input and output if
- not overridden */
- if (0 != (dwCreationFlags & CREATE_NEW_CONSOLE)
- && NT_SUCCESS(Status) && NT_SUCCESS(CsrReply.Status))
- {
- if (! InputSet)
- {
- Ppb->hStdInput = CsrReply.Data.CreateProcessReply.InputHandle;
- InputSet = TRUE;
- InputDup = FALSE;
- }
- if (! OutputSet)
- {
- Ppb->hStdOutput = CsrReply.Data.CreateProcessReply.OutputHandle;
- OutputSet = TRUE;
- OutputDup = FALSE;
- }
- if (! ErrorSet)
- {
- Ppb->hStdError = CsrReply.Data.CreateProcessReply.OutputHandle;
- ErrorSet = TRUE;
- ErrorDup = FALSE;
- }
- }
-
- /* Use existing handles otherwise */
- if (! InputSet)
- {
- Ppb->hStdInput = NtCurrentPeb()->ProcessParameters->hStdInput;
- InputDup = TRUE;
- }
- if (! OutputSet)
- {
- Ppb->hStdOutput = NtCurrentPeb()->ProcessParameters->hStdOutput;
- OutputDup = TRUE;
- }
- if (! ErrorSet)
- {
- Ppb->hStdError = NtCurrentPeb()->ProcessParameters->hStdError;
- ErrorDup = TRUE;
- }
-
- /* Now duplicate handles if required */
- if (InputDup)
- {
- if (IsConsoleHandle(Ppb->hStdInput))
- {
- Ppb->hStdInput = CsrReply.Data.CreateProcessReply.InputHandle;
- }
- else
- {
- DPRINT("Duplicate input handle\n");
- Status = NtDuplicateObject (NtCurrentProcess(),
- Ppb->hStdInput,
- hProcess,
- &Ppb->hStdInput,
- 0,
- TRUE,
- DUPLICATE_SAME_ACCESS);
- if(!NT_SUCCESS(Status))
- {
- DPRINT("NtDuplicateObject failed, status %x\n", Status);
- }
- }
- }
-
- if (OutputDup)
- {
- if (IsConsoleHandle(Ppb->hStdOutput))
- {
- Ppb->hStdOutput = CsrReply.Data.CreateProcessReply.OutputHandle;
- }
- else
- {
- DPRINT("Duplicate output handle\n");
- Status = NtDuplicateObject (NtCurrentProcess(),
- Ppb->hStdOutput,
- hProcess,
- &Ppb->hStdOutput,
- 0,
- TRUE,
- DUPLICATE_SAME_ACCESS);
- if(!NT_SUCCESS(Status))
- {
- DPRINT("NtDuplicateObject failed, status %x\n", Status);
- }
- }
- }
-
- if (ErrorDup)
- {
- if (IsConsoleHandle(Ppb->hStdError))
- {
- CsrRequest.Type = CSRSS_DUPLICATE_HANDLE;
- CsrRequest.Data.DuplicateHandleRequest.ProcessId = ProcessBasicInfo.UniqueProcessId;
- CsrRequest.Data.DuplicateHandleRequest.Handle = CsrReply.Data.CreateProcessReply.OutputHandle;
- Status = CsrClientCallServer(&CsrRequest,
- &CsrReply,
- sizeof(CSRSS_API_REQUEST),
- sizeof(CSRSS_API_REPLY));
- if (!NT_SUCCESS(Status) || !NT_SUCCESS(CsrReply.Status))
- {
- Ppb->hStdError = INVALID_HANDLE_VALUE;
- }
- else
- {
- Ppb->hStdError = CsrReply.Data.DuplicateHandleReply.Handle;
- }
- }
- else
- {
- DPRINT("Duplicate error handle\n");
- Status = NtDuplicateObject (NtCurrentProcess(),
- Ppb->hStdError,
- hProcess,
- &Ppb->hStdError,
- 0,
- TRUE,
- DUPLICATE_SAME_ACCESS);
- if(!NT_SUCCESS(Status))
- {
- DPRINT("NtDuplicateObject failed, status %x\n", Status);
- }
- }
- }
-
- /*
- * Initialize some other fields in the PPB
- */
- if (lpStartupInfo)
- {
- Ppb->dwFlags = lpStartupInfo->dwFlags;
- if (Ppb->dwFlags & STARTF_USESHOWWINDOW)
- {
- Ppb->wShowWindow = lpStartupInfo->wShowWindow;
- }
- else
- {
- Ppb->wShowWindow = SW_SHOWDEFAULT;
- }
- Ppb->dwX = lpStartupInfo->dwX;
- Ppb->dwY = lpStartupInfo->dwY;
- Ppb->dwXSize = lpStartupInfo->dwXSize;
- Ppb->dwYSize = lpStartupInfo->dwYSize;
- Ppb->dwFillAttribute = lpStartupInfo->dwFillAttribute;
- }
- else
- {
- Ppb->Flags = 0;
- }
-
- /*
- * Create Process Environment Block
- */
- DPRINT("Creating peb\n");
-
- KlInitPeb(hProcess, Ppb, &ImageBaseAddress);
+
+ /* Duplicate and write the handles */
+ BasepDuplicateAndWriteHandle(hProcess,
+ OurPeb->ProcessParameters->StandardInput,
+ &RemoteParameters->StandardInput);
+ BasepDuplicateAndWriteHandle(hProcess,
+ OurPeb->ProcessParameters->StandardOutput,
+ &RemoteParameters->StandardOutput);
+ BasepDuplicateAndWriteHandle(hProcess,
+ OurPeb->ProcessParameters->StandardError,
+ &RemoteParameters->StandardError);
+ }
+
+ /* Create the first thread */
+ DPRINT("Creating thread for process (EntryPoint = 0x%.08x)\n",
+ SectionImageInfo.TransferAddress);
+ hThread = BasepCreateFirstThread(hProcess,
+ lpThreadAttributes,
+ &SectionImageInfo,
+ &ClientId);
+
+ if (hThread == NULL)
+ {
+ DPRINT1("Could not create Initial Thread\n");
+ return FALSE;
+ }
- RtlDestroyProcessParameters (Ppb);
+
+ /* Notify CSRSS */
+ Status = BasepNotifyCsrOfCreation(dwCreationFlags,
+ (HANDLE)ProcessBasicInfo.UniqueProcessId);
- Status = NtSetInformationProcess(hProcess,
- ProcessImageFileName,
- ImageFileName,
- 8);
- /*
- * Create the thread for the kernel
- */
- DPRINT("Creating thread for process (EntryPoint = 0x%.08x)\n",
- ImageBaseAddress + (ULONG)Sii.EntryPoint);
- hThread = KlCreateFirstThread(hProcess,
- lpThreadAttributes,
- &Sii,
- ImageBaseAddress + (ULONG)Sii.EntryPoint,
- dwCreationFlags,
- &lpProcessInformation->dwThreadId);
- if (hThread == INVALID_HANDLE_VALUE)
- {
- return FALSE;
- }
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("CSR Notification Failed");
+ SetLastErrorByStatus(Status);
+ return FALSE;
+ }
+
+ if (!(dwCreationFlags & CREATE_SUSPENDED))
+ {
+ NtResumeThread(hThread, &Dummy);
+ }
+
+ /* Cleanup Environment */
+ if (lpEnvironment && !(dwCreationFlags & CREATE_UNICODE_ENVIRONMENT))
+ {
+ RtlDestroyEnvironment(lpEnvironment);
+ }
- lpProcessInformation->hProcess = hProcess;
- lpProcessInformation->hThread = hThread;
+ /* Return Data */
+ lpProcessInformation->dwProcessId = (DWORD)ClientId.UniqueProcess;
+ lpProcessInformation->dwThreadId = (DWORD)ClientId.UniqueThread;
+ lpProcessInformation->hProcess = hProcess;
+ lpProcessInformation->hThread = hThread;
+ DPRINT("hThread[%lx]: %lx inside hProcess[%lx]: %lx\n", hThread,
+ ClientId.UniqueThread, ClientId.UniqueProcess, hProcess);
+ hProcess = hThread = NULL;
+
+ /* De-allocate heap strings */
+ if (NameBuffer) RtlFreeHeap(GetProcessHeap(), 0, NameBuffer);
+ if (ApplicationName.Buffer)
+ RtlFreeHeap(GetProcessHeap(), 0, ApplicationName.Buffer);
+ if (CurrentDirectory) RtlFreeHeap(GetProcessHeap(), 0, CurrentDirectory);
+ if (QuotedCmdLine) RtlFreeHeap(GetProcessHeap(), 0, QuotedCmdLine);
+
+ /* Kill any handles still alive */
+ if (hSection) NtClose(hSection);
+ if (hThread)
+ {
+ /* We don't know any more details then this */
+ NtTerminateProcess(hProcess, STATUS_UNSUCCESSFUL);
+ NtClose(hThread);
+ }
+ if (hProcess) NtClose(hProcess);
- return TRUE;
+ /* Return Success */
+ return TRUE;
}
/* EOF */