Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenproc.c
Go to the documentation of this file.
00001 /* $Id: proc.c 56643 2012-05-20 14:06:09Z tfaber $ 00002 * 00003 * COPYRIGHT: See COPYING in the top level directory 00004 * PROJECT: ReactOS system libraries 00005 * FILE: lib/kernel32/proc/proc.c 00006 * PURPOSE: Process functions 00007 * PROGRAMMER: Ariadne ( ariadne@xs4all.nl) 00008 * UPDATE HISTORY: 00009 * Created 01/11/98 00010 */ 00011 00012 /* INCLUDES ****************************************************************/ 00013 00014 #include <k32.h> 00015 00016 #define NDEBUG 00017 #include <debug.h> 00018 00019 /* GLOBALS *******************************************************************/ 00020 00021 WaitForInputIdleType UserWaitForInputIdleRoutine; 00022 UNICODE_STRING BaseUnicodeCommandLine; 00023 ANSI_STRING BaseAnsiCommandLine; 00024 UNICODE_STRING BasePathVariableName = RTL_CONSTANT_STRING(L"PATH"); 00025 LPSTARTUPINFOA BaseAnsiStartupInfo = NULL; 00026 PLDR_DATA_TABLE_ENTRY BasepExeLdrEntry; 00027 BOOLEAN g_AppCertInitialized; 00028 BOOLEAN g_HaveAppCerts; 00029 LIST_ENTRY BasepAppCertDllsList; 00030 RTL_CRITICAL_SECTION gcsAppCert; 00031 PBASEP_APPCERT_EMBEDDED_FUNC fEmbeddedCertFunc; 00032 NTSTATUS g_AppCertStatus; 00033 RTL_QUERY_REGISTRY_TABLE BasepAppCertTable[2] = 00034 { 00035 { 00036 BasepConfigureAppCertDlls, 00037 1, 00038 L"AppCertDlls", 00039 &BasepAppCertDllsList, 00040 0, 00041 NULL, 00042 0 00043 } 00044 }; 00045 00046 PSAFER_REPLACE_PROCESS_THREAD_TOKENS g_SaferReplaceProcessThreadTokens; 00047 HMODULE gSaferHandle = (HMODULE)-1; 00048 00049 VOID WINAPI 00050 RegisterWaitForInputIdle(WaitForInputIdleType lpfnRegisterWaitForInputIdle); 00051 00052 #define CMD_STRING L"cmd /c " 00053 00054 /* FUNCTIONS ****************************************************************/ 00055 00056 VOID 00057 WINAPI 00058 StuffStdHandle(IN HANDLE ProcessHandle, 00059 IN HANDLE StandardHandle, 00060 IN PHANDLE Address) 00061 { 00062 NTSTATUS Status; 00063 HANDLE DuplicatedHandle; 00064 SIZE_T Dummy; 00065 00066 /* Duplicate the handle */ 00067 Status = NtDuplicateObject(NtCurrentProcess(), 00068 StandardHandle, 00069 ProcessHandle, 00070 &DuplicatedHandle, 00071 DUPLICATE_SAME_ACCESS | DUPLICATE_SAME_ATTRIBUTES, 00072 0, 00073 0); 00074 if (NT_SUCCESS(Status)) 00075 { 00076 /* Write it */ 00077 NtWriteVirtualMemory(ProcessHandle, 00078 Address, 00079 &DuplicatedHandle, 00080 sizeof(HANDLE), 00081 &Dummy); 00082 } 00083 } 00084 00085 BOOLEAN 00086 WINAPI 00087 BuildSubSysCommandLine(IN LPWSTR SubsystemName, 00088 IN LPWSTR ApplicationName, 00089 IN LPWSTR CommandLine, 00090 OUT PUNICODE_STRING SubsysCommandLine) 00091 { 00092 UNICODE_STRING CommandLineString, ApplicationNameString; 00093 PWCHAR Buffer; 00094 ULONG Length; 00095 00096 /* Convert to unicode strings */ 00097 RtlInitUnicodeString(&CommandLineString, ApplicationName); 00098 RtlInitUnicodeString(&ApplicationNameString, CommandLine); 00099 00100 /* Allocate buffer for the output string */ 00101 Length = CommandLineString.MaximumLength + ApplicationNameString.MaximumLength + 32; 00102 Buffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, Length); 00103 RtlInitEmptyUnicodeString(SubsysCommandLine, Buffer, Length); 00104 if (!Buffer) 00105 { 00106 /* Fail, no memory */ 00107 BaseSetLastNTError(STATUS_NO_MEMORY); 00108 return FALSE; 00109 } 00110 00111 /* Build the final subsystem command line */ 00112 RtlAppendUnicodeToString(SubsysCommandLine, SubsystemName); 00113 RtlAppendUnicodeStringToString(SubsysCommandLine, &CommandLineString); 00114 RtlAppendUnicodeToString(SubsysCommandLine, L" /C "); 00115 RtlAppendUnicodeStringToString(SubsysCommandLine, &ApplicationNameString); 00116 return TRUE; 00117 } 00118 00119 BOOLEAN 00120 WINAPI 00121 BasepIsImageVersionOk(IN ULONG ImageMajorVersion, 00122 IN ULONG ImageMinorVersion) 00123 { 00124 /* Accept images for NT 3.1 or higher, as long as they're not newer than us */ 00125 return ((ImageMajorVersion >= 3) && 00126 ((ImageMajorVersion != 3) || 00127 (ImageMinorVersion >= 10)) && 00128 (ImageMajorVersion <= SharedUserData->NtMajorVersion) && 00129 ((ImageMajorVersion != SharedUserData->NtMajorVersion) || 00130 (ImageMinorVersion <= SharedUserData->NtMinorVersion))); 00131 } 00132 00133 NTSTATUS 00134 WINAPI 00135 BasepCheckWebBladeHashes(IN HANDLE FileHandle) 00136 { 00137 NTSTATUS Status; 00138 CHAR Hash[16]; 00139 00140 /* Get all the MD5 hashes */ 00141 Status = RtlComputeImportTableHash(FileHandle, Hash, 1); 00142 if (!NT_SUCCESS(Status)) return Status; 00143 00144 /* Depending on which suite this is, run a bsearch and block the appropriate ones */ 00145 if (SharedUserData->SuiteMask & VER_SUITE_COMPUTE_SERVER) 00146 { 00147 DPRINT1("Egad! This is a ReactOS Compute Server and we should prevent you from using certain APIs...but we won't."); 00148 } 00149 else if (SharedUserData->SuiteMask & VER_SUITE_STORAGE_SERVER) 00150 { 00151 DPRINT1("Gasp! This is a ReactOS Storage Server and we should prevent you from using certain APIs...but we won't."); 00152 } 00153 else if (SharedUserData->SuiteMask & VER_SUITE_BLADE) 00154 { 00155 DPRINT1("Golly! This is a ReactOS Web Blade Server and we should prevent you from using certain APIs...but we won't."); 00156 } 00157 00158 /* Actually, fuck it, don't block anything, we're open source */ 00159 return STATUS_SUCCESS; 00160 } 00161 00162 NTSTATUS 00163 NTAPI 00164 BasepSaveAppCertRegistryValue(IN PLIST_ENTRY List, 00165 IN PWCHAR ComponentName, 00166 IN PWCHAR DllName) 00167 { 00168 /* Pretty much the only thing this key is used for, is malware */ 00169 UNIMPLEMENTED; 00170 return STATUS_NOT_IMPLEMENTED; 00171 } 00172 00173 NTSTATUS 00174 NTAPI 00175 BasepConfigureAppCertDlls(IN PWSTR ValueName, 00176 IN ULONG ValueType, 00177 IN PVOID ValueData, 00178 IN ULONG ValueLength, 00179 IN PVOID Context, 00180 IN PVOID EntryContext) 00181 { 00182 /* Add this to the certification list */ 00183 return BasepSaveAppCertRegistryValue(Context, ValueName, ValueData); 00184 } 00185 00186 NTSTATUS 00187 WINAPI 00188 BasepIsProcessAllowed(IN PCHAR ApplicationName) 00189 { 00190 NTSTATUS Status; 00191 PWCHAR Buffer; 00192 UINT Length; 00193 HMODULE TrustLibrary; 00194 PBASEP_APPCERT_ENTRY Entry; 00195 ULONG CertFlag; 00196 PLIST_ENTRY NextEntry; 00197 HANDLE KeyHandle; 00198 UNICODE_STRING CertKey = RTL_CONSTANT_STRING(L"\\Registry\\MACHINE\\System\\CurrentControlSet\\Control\\Session Manager\\AppCertDlls"); 00199 OBJECT_ATTRIBUTES KeyAttributes = RTL_CONSTANT_OBJECT_ATTRIBUTES(&CertKey, OBJ_CASE_INSENSITIVE); 00200 00201 /* Try to initialize the certification subsystem */ 00202 while (!g_AppCertInitialized) 00203 { 00204 /* Defaults */ 00205 Status = STATUS_SUCCESS; 00206 Buffer = NULL; 00207 00208 /* Acquire the lock while initializing and see if we lost a race */ 00209 RtlEnterCriticalSection(&gcsAppCert); 00210 if (g_AppCertInitialized) break; 00211 00212 /* On embedded, there is a special DLL */ 00213 if (SharedUserData->SuiteMask & VER_SUITE_EMBEDDEDNT) 00214 { 00215 /* Allocate a buffer for the name */ 00216 Buffer = RtlAllocateHeap(RtlGetProcessHeap(), 00217 0, 00218 MAX_PATH * sizeof(WCHAR) + 00219 sizeof(UNICODE_NULL)); 00220 if (!Buffer) 00221 { 00222 /* Fail if no memory */ 00223 Status = STATUS_NO_MEMORY; 00224 } 00225 else 00226 { 00227 /* Now get the system32 directory in our buffer, make sure it fits */ 00228 Length = GetSystemDirectoryW(Buffer, MAX_PATH - sizeof("EmbdTrst.DLL")); 00229 if ((Length) && (Length <= MAX_PATH - sizeof("EmbdTrst.DLL"))) 00230 { 00231 /* Add a slash if needed, and add the embedded cert DLL name */ 00232 if (Buffer[Length - 1] != '\\') Buffer[Length++] = '\\'; 00233 RtlCopyMemory(&Buffer[Length], 00234 L"EmbdTrst.DLL", 00235 sizeof(L"EmbdTrst.DLL")); 00236 00237 /* Try to load it */ 00238 TrustLibrary = LoadLibraryW(Buffer); 00239 if (TrustLibrary) 00240 { 00241 /* And extract the special function out of it */ 00242 fEmbeddedCertFunc = (PVOID)GetProcAddress(TrustLibrary, 00243 "ImageOkToRunOnEmbeddedNT"); 00244 } 00245 } 00246 00247 /* If we didn't get this far, set a failure code */ 00248 if (!fEmbeddedCertFunc) Status = STATUS_UNSUCCESSFUL; 00249 } 00250 } 00251 else 00252 { 00253 /* Other systems have a registry entry for this */ 00254 Status = NtOpenKey(&KeyHandle, KEY_READ, &KeyAttributes); 00255 if (NT_SUCCESS(Status)) 00256 { 00257 /* Close it, we'll query it through Rtl */ 00258 NtClose(KeyHandle); 00259 00260 /* Do the query, which will call a special callback */ 00261 Status = RtlQueryRegistryValues(2, 00262 L"Session Manager", 00263 BasepAppCertTable, 00264 0, 00265 0); 00266 if (Status == 0xC0000034) Status = STATUS_SUCCESS; 00267 } 00268 } 00269 00270 /* Free any buffer if we had one */ 00271 if (Buffer) RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer); 00272 00273 /* Check for errors, or a missing embedded/custom certification DLL */ 00274 if (!NT_SUCCESS(Status) || 00275 (!(fEmbeddedCertFunc) && (IsListEmpty(&BasepAppCertDllsList)))) 00276 { 00277 /* The subsystem is not active on this machine, so give up */ 00278 g_HaveAppCerts = FALSE; 00279 g_AppCertStatus = Status; 00280 } 00281 else 00282 { 00283 /* We have certification DLLs active, remember this */ 00284 g_HaveAppCerts = TRUE; 00285 } 00286 00287 /* We are done the initialization phase, release the lock */ 00288 g_AppCertInitialized = TRUE; 00289 RtlLeaveCriticalSection(&gcsAppCert); 00290 } 00291 00292 /* If there's no certification DLLs present, return the failure code */ 00293 if (!g_HaveAppCerts) return g_AppCertStatus; 00294 00295 /* Otherwise, assume success and make sure we have *something* */ 00296 ASSERT(fEmbeddedCertFunc || !IsListEmpty(&BasepAppCertDllsList)); 00297 Status = STATUS_SUCCESS; 00298 00299 /* If the something is an embedded certification DLL, call it and return */ 00300 if (fEmbeddedCertFunc) return fEmbeddedCertFunc(ApplicationName); 00301 00302 /* Otherwise we have custom certification DLLs, parse them */ 00303 NextEntry = BasepAppCertDllsList.Flink; 00304 CertFlag = 2; 00305 while (NextEntry != &BasepAppCertDllsList) 00306 { 00307 /* Make sure the entry has a callback */ 00308 Entry = CONTAINING_RECORD(NextEntry, BASEP_APPCERT_ENTRY, Entry); 00309 ASSERT(Entry->fPluginCertFunc != NULL); 00310 00311 /* Call it and check if it failed */ 00312 Status = Entry->fPluginCertFunc(ApplicationName, 1); 00313 if (!NT_SUCCESS(Status)) CertFlag = 3; 00314 00315 /* Move on */ 00316 NextEntry = NextEntry->Flink; 00317 } 00318 00319 /* Now loop them again */ 00320 NextEntry = BasepAppCertDllsList.Flink; 00321 while (NextEntry != &BasepAppCertDllsList) 00322 { 00323 /* Make sure the entry has a callback */ 00324 Entry = CONTAINING_RECORD(NextEntry, BASEP_APPCERT_ENTRY, Entry); 00325 ASSERT(Entry->fPluginCertFunc != NULL); 00326 00327 /* Call it, this time with the flag from the loop above */ 00328 Status = Entry->fPluginCertFunc(ApplicationName, CertFlag); 00329 } 00330 00331 /* All done, return the status */ 00332 return Status; 00333 } 00334 00335 NTSTATUS 00336 WINAPI 00337 BasepReplaceProcessThreadTokens(IN HANDLE TokenHandle, 00338 IN HANDLE ProcessHandle, 00339 IN HANDLE ThreadHandle) 00340 { 00341 NTSTATUS Status; 00342 ANSI_STRING SaferiReplaceProcessThreadTokens = RTL_CONSTANT_STRING("SaferiReplaceProcessThreadTokens"); 00343 00344 /* Enter the application certification lock */ 00345 RtlEnterCriticalSection(&gcsAppCert); 00346 00347 /* Check if we already know the function */ 00348 if (g_SaferReplaceProcessThreadTokens) 00349 { 00350 /* Call it */ 00351 Status = g_SaferReplaceProcessThreadTokens(TokenHandle, 00352 ProcessHandle, 00353 ThreadHandle) ? 00354 STATUS_SUCCESS : 00355 STATUS_UNSUCCESSFUL; 00356 } 00357 else 00358 { 00359 /* Check if the app certification DLL isn't loaded */ 00360 if (!(gSaferHandle) || 00361 (gSaferHandle == (HMODULE)-1) || 00362 (gSaferHandle == (HMODULE)-2)) 00363 { 00364 /* Then we can't call the function */ 00365 Status = STATUS_ENTRYPOINT_NOT_FOUND; 00366 } 00367 else 00368 { 00369 /* We have the DLL, find the address of the Safer function */ 00370 Status = LdrGetProcedureAddress(gSaferHandle, 00371 &SaferiReplaceProcessThreadTokens, 00372 0, 00373 (PVOID*)&g_SaferReplaceProcessThreadTokens); 00374 if (NT_SUCCESS(Status)) 00375 { 00376 /* Found it, now call it */ 00377 Status = g_SaferReplaceProcessThreadTokens(TokenHandle, 00378 ProcessHandle, 00379 ThreadHandle) ? 00380 STATUS_SUCCESS : 00381 STATUS_UNSUCCESSFUL; 00382 } 00383 else 00384 { 00385 /* We couldn't find it, so this must be an unsupported DLL */ 00386 LdrUnloadDll(gSaferHandle); 00387 gSaferHandle = NULL; 00388 Status = STATUS_ENTRYPOINT_NOT_FOUND; 00389 } 00390 } 00391 } 00392 00393 /* Release the lock and return the result */ 00394 RtlLeaveCriticalSection(&gcsAppCert); 00395 return Status; 00396 } 00397 00398 VOID 00399 WINAPI 00400 BasepSxsCloseHandles(IN PBASE_MSG_SXS_HANDLES Handles) 00401 { 00402 NTSTATUS Status; 00403 00404 /* Sanity checks */ 00405 ASSERT(Handles != NULL); 00406 ASSERT(Handles->Process == NULL || Handles->Process == NtCurrentProcess()); 00407 00408 /* Close the file handle */ 00409 if (Handles->File) 00410 { 00411 Status = NtClose(Handles->File); 00412 ASSERT(NT_SUCCESS(Status)); 00413 } 00414 00415 /* Close the section handle */ 00416 if (Handles->Section) 00417 { 00418 Status = NtClose(Handles->Section); 00419 ASSERT(NT_SUCCESS(Status)); 00420 } 00421 00422 /* Unmap the section view */ 00423 if (Handles->ViewBase.QuadPart) 00424 { 00425 Status = NtUnmapViewOfSection(NtCurrentProcess(), 00426 (PVOID)Handles->ViewBase.LowPart); 00427 ASSERT(NT_SUCCESS(Status)); 00428 } 00429 } 00430 00431 static 00432 LONG BaseExceptionFilter(EXCEPTION_POINTERS *ExceptionInfo) 00433 { 00434 LONG ExceptionDisposition = EXCEPTION_EXECUTE_HANDLER; 00435 LPTOP_LEVEL_EXCEPTION_FILTER RealFilter; 00436 RealFilter = RtlDecodePointer(GlobalTopLevelExceptionFilter); 00437 00438 if (RealFilter != NULL) 00439 { 00440 _SEH2_TRY 00441 { 00442 ExceptionDisposition = RealFilter(ExceptionInfo); 00443 } 00444 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 00445 { 00446 } 00447 _SEH2_END; 00448 } 00449 if ((ExceptionDisposition == EXCEPTION_CONTINUE_SEARCH || ExceptionDisposition == EXCEPTION_EXECUTE_HANDLER) && 00450 RealFilter != UnhandledExceptionFilter) 00451 { 00452 ExceptionDisposition = UnhandledExceptionFilter(ExceptionInfo); 00453 } 00454 00455 return ExceptionDisposition; 00456 } 00457 00458 VOID 00459 WINAPI 00460 BaseProcessStartup(PPROCESS_START_ROUTINE lpStartAddress) 00461 { 00462 DPRINT("BaseProcessStartup(..) - setting up exception frame.\n"); 00463 00464 _SEH2_TRY 00465 { 00466 /* Set our Start Address */ 00467 NtSetInformationThread(NtCurrentThread(), 00468 ThreadQuerySetWin32StartAddress, 00469 &lpStartAddress, 00470 sizeof(PPROCESS_START_ROUTINE)); 00471 00472 /* Call the Start Routine */ 00473 ExitThread(lpStartAddress()); 00474 } 00475 _SEH2_EXCEPT(BaseExceptionFilter(_SEH2_GetExceptionInformation())) 00476 { 00477 /* Get the Exit code from the SEH Handler */ 00478 if (!BaseRunningInServerProcess) 00479 { 00480 /* Kill the whole process, usually */ 00481 ExitProcess(_SEH2_GetExceptionCode()); 00482 } 00483 else 00484 { 00485 /* If running inside CSRSS, kill just this thread */ 00486 ExitThread(_SEH2_GetExceptionCode()); 00487 } 00488 } 00489 _SEH2_END; 00490 } 00491 00492 NTSTATUS 00493 WINAPI 00494 BasepNotifyCsrOfThread(IN HANDLE ThreadHandle, 00495 IN PCLIENT_ID ClientId) 00496 { 00497 ULONG Request = CREATE_THREAD; 00498 CSR_API_MESSAGE CsrRequest; 00499 NTSTATUS Status; 00500 00501 DPRINT("BasepNotifyCsrOfThread: Thread: %lx, Handle %lx\n", 00502 ClientId->UniqueThread, ThreadHandle); 00503 00504 /* Fill out the request */ 00505 CsrRequest.Data.CreateThreadRequest.ClientId = *ClientId; 00506 CsrRequest.Data.CreateThreadRequest.ThreadHandle = ThreadHandle; 00507 00508 /* Call CSR */ 00509 Status = CsrClientCallServer(&CsrRequest, 00510 NULL, 00511 MAKE_CSR_API(Request, CSR_NATIVE), 00512 sizeof(CSR_API_MESSAGE)); 00513 if (!NT_SUCCESS(Status) || !NT_SUCCESS(CsrRequest.Status)) 00514 { 00515 DPRINT1("Failed to tell csrss about new thread: %lx %lx\n", Status, CsrRequest.Status); 00516 return CsrRequest.Status; 00517 } 00518 00519 /* Return Success */ 00520 return STATUS_SUCCESS; 00521 } 00522 00523 /* 00524 * Creates the first Thread in a Proces 00525 */ 00526 HANDLE 00527 WINAPI 00528 BasepCreateFirstThread(HANDLE ProcessHandle, 00529 LPSECURITY_ATTRIBUTES lpThreadAttributes, 00530 PSECTION_IMAGE_INFORMATION SectionImageInfo, 00531 PCLIENT_ID ClientId, 00532 BOOLEAN InheritHandles, 00533 DWORD dwCreationFlags) 00534 { 00535 OBJECT_ATTRIBUTES LocalObjectAttributes; 00536 POBJECT_ATTRIBUTES ObjectAttributes; 00537 CONTEXT Context; 00538 INITIAL_TEB InitialTeb; 00539 NTSTATUS Status; 00540 HANDLE hThread; 00541 ULONG Request = CREATE_PROCESS; 00542 CSR_API_MESSAGE CsrRequest; 00543 DPRINT("BasepCreateFirstThread. hProcess: %lx\n", ProcessHandle); 00544 00545 /* Create the Thread's Stack */ 00546 BaseCreateStack(ProcessHandle, 00547 SectionImageInfo->MaximumStackSize, 00548 SectionImageInfo->CommittedStackSize, 00549 &InitialTeb); 00550 00551 /* Create the Thread's Context */ 00552 BaseInitializeContext(&Context, 00553 NtCurrentPeb(), 00554 SectionImageInfo->TransferAddress, 00555 InitialTeb.StackBase, 00556 0); 00557 00558 /* Convert the thread attributes */ 00559 ObjectAttributes = BaseFormatObjectAttributes(&LocalObjectAttributes, 00560 lpThreadAttributes, 00561 NULL); 00562 00563 /* Create the Kernel Thread Object */ 00564 Status = NtCreateThread(&hThread, 00565 THREAD_ALL_ACCESS, 00566 ObjectAttributes, 00567 ProcessHandle, 00568 ClientId, 00569 &Context, 00570 &InitialTeb, 00571 TRUE); 00572 if (!NT_SUCCESS(Status)) 00573 { 00574 return NULL; 00575 } 00576 00577 /* Fill out the request to notify CSRSS */ 00578 CsrRequest.Data.CreateProcessRequest.ClientId = *ClientId; 00579 CsrRequest.Data.CreateProcessRequest.ProcessHandle = ProcessHandle; 00580 CsrRequest.Data.CreateProcessRequest.ThreadHandle = hThread; 00581 CsrRequest.Data.CreateProcessRequest.CreationFlags = dwCreationFlags; 00582 CsrRequest.Data.CreateProcessRequest.bInheritHandles = InheritHandles; 00583 00584 /* Call CSR */ 00585 Status = CsrClientCallServer(&CsrRequest, 00586 NULL, 00587 MAKE_CSR_API(Request, CSR_NATIVE), 00588 sizeof(CSR_API_MESSAGE)); 00589 if (!NT_SUCCESS(Status) || !NT_SUCCESS(CsrRequest.Status)) 00590 { 00591 DPRINT1("Failed to tell csrss about new process: %lx %lx\n", Status, CsrRequest.Status); 00592 return NULL; 00593 } 00594 00595 /* Success */ 00596 return hThread; 00597 } 00598 00599 /* 00600 * Converts ANSI to Unicode Environment 00601 */ 00602 PVOID 00603 WINAPI 00604 BasepConvertUnicodeEnvironment(OUT SIZE_T* EnvSize, 00605 IN PVOID lpEnvironment) 00606 { 00607 PCHAR pcScan; 00608 ANSI_STRING AnsiEnv; 00609 UNICODE_STRING UnicodeEnv; 00610 NTSTATUS Status; 00611 00612 DPRINT("BasepConvertUnicodeEnvironment\n"); 00613 00614 /* Scan the environment to calculate its Unicode size */ 00615 AnsiEnv.Buffer = pcScan = (PCHAR)lpEnvironment; 00616 while (*pcScan) 00617 { 00618 pcScan += strlen(pcScan) + 1; 00619 } 00620 00621 /* Create our ANSI String */ 00622 if (pcScan == (PCHAR)lpEnvironment) 00623 { 00624 AnsiEnv.Length = 2 * sizeof(CHAR); 00625 } 00626 else 00627 { 00628 00629 AnsiEnv.Length = (USHORT)((ULONG_PTR)pcScan - (ULONG_PTR)lpEnvironment + sizeof(CHAR)); 00630 } 00631 AnsiEnv.MaximumLength = AnsiEnv.Length + 1; 00632 00633 /* Allocate memory for the Unicode Environment */ 00634 UnicodeEnv.Buffer = NULL; 00635 *EnvSize = AnsiEnv.MaximumLength * sizeof(WCHAR); 00636 Status = NtAllocateVirtualMemory(NtCurrentProcess(), 00637 (PVOID)&UnicodeEnv.Buffer, 00638 0, 00639 EnvSize, 00640 MEM_COMMIT, 00641 PAGE_READWRITE); 00642 /* Failure */ 00643 if (!NT_SUCCESS(Status)) 00644 { 00645 SetLastError(Status); 00646 *EnvSize = 0; 00647 return NULL; 00648 } 00649 00650 /* Use the allocated size */ 00651 UnicodeEnv.MaximumLength = (USHORT)*EnvSize; 00652 00653 /* Convert */ 00654 RtlAnsiStringToUnicodeString(&UnicodeEnv, &AnsiEnv, FALSE); 00655 return UnicodeEnv.Buffer; 00656 } 00657 00658 /* 00659 * Converts a Win32 Priority Class to NT 00660 */ 00661 ULONG 00662 WINAPI 00663 BasepConvertPriorityClass(IN ULONG dwCreationFlags) 00664 { 00665 ULONG ReturnClass; 00666 00667 if(dwCreationFlags & IDLE_PRIORITY_CLASS) 00668 { 00669 ReturnClass = PROCESS_PRIORITY_CLASS_IDLE; 00670 } 00671 else if(dwCreationFlags & BELOW_NORMAL_PRIORITY_CLASS) 00672 { 00673 ReturnClass = PROCESS_PRIORITY_CLASS_BELOW_NORMAL; 00674 } 00675 else if(dwCreationFlags & NORMAL_PRIORITY_CLASS) 00676 { 00677 ReturnClass = PROCESS_PRIORITY_CLASS_NORMAL; 00678 } 00679 else if(dwCreationFlags & ABOVE_NORMAL_PRIORITY_CLASS) 00680 { 00681 ReturnClass = PROCESS_PRIORITY_CLASS_ABOVE_NORMAL; 00682 } 00683 else if(dwCreationFlags & HIGH_PRIORITY_CLASS) 00684 { 00685 ReturnClass = PROCESS_PRIORITY_CLASS_HIGH; 00686 } 00687 else if(dwCreationFlags & REALTIME_PRIORITY_CLASS) 00688 { 00689 /* Check for Privilege First */ 00690 if (BasepIsRealtimeAllowed(TRUE)) 00691 { 00692 ReturnClass = PROCESS_PRIORITY_CLASS_REALTIME; 00693 } 00694 else 00695 { 00696 ReturnClass = PROCESS_PRIORITY_CLASS_HIGH; 00697 } 00698 } 00699 else 00700 { 00701 ReturnClass = PROCESS_PRIORITY_CLASS_INVALID; 00702 } 00703 00704 return ReturnClass; 00705 } 00706 00707 /* 00708 * Duplicates a standard handle and writes it where requested. 00709 */ 00710 VOID 00711 WINAPI 00712 BasepDuplicateAndWriteHandle(IN HANDLE ProcessHandle, 00713 IN HANDLE StandardHandle, 00714 IN PHANDLE Address) 00715 { 00716 NTSTATUS Status; 00717 HANDLE DuplicatedHandle; 00718 SIZE_T Dummy; 00719 00720 DPRINT("BasepDuplicateAndWriteHandle. hProcess: %lx, Handle: %lx," 00721 "Address: %p\n", ProcessHandle, StandardHandle, Address); 00722 00723 /* Don't touch Console Handles */ 00724 if (IsConsoleHandle(StandardHandle)) return; 00725 00726 /* Duplicate the handle */ 00727 Status = NtDuplicateObject(NtCurrentProcess(), 00728 StandardHandle, 00729 ProcessHandle, 00730 &DuplicatedHandle, 00731 DUPLICATE_SAME_ACCESS | DUPLICATE_SAME_ATTRIBUTES, 00732 0, 00733 0); 00734 if (NT_SUCCESS(Status)) 00735 { 00736 /* Write it */ 00737 NtWriteVirtualMemory(ProcessHandle, 00738 Address, 00739 &DuplicatedHandle, 00740 sizeof(HANDLE), 00741 &Dummy); 00742 } 00743 } 00744 00745 BOOLEAN 00746 WINAPI 00747 BasePushProcessParameters(IN ULONG ParameterFlags, 00748 IN HANDLE ProcessHandle, 00749 IN PPEB RemotePeb, 00750 IN LPCWSTR ApplicationPathName, 00751 IN LPWSTR lpCurrentDirectory, 00752 IN LPWSTR lpCommandLine, 00753 IN LPVOID lpEnvironment, 00754 IN LPSTARTUPINFOW StartupInfo, 00755 IN DWORD CreationFlags, 00756 IN BOOL InheritHandles, 00757 IN ULONG ImageSubsystem, 00758 IN PVOID AppCompatData, 00759 IN ULONG AppCompatDataSize) 00760 { 00761 WCHAR FullPath[MAX_PATH + 5]; 00762 PWCHAR Remaining, DllPathString, ScanChar; 00763 PRTL_USER_PROCESS_PARAMETERS ProcessParameters, RemoteParameters; 00764 PVOID RemoteAppCompatData; 00765 UNICODE_STRING DllPath, ImageName, CommandLine, CurrentDirectory; 00766 UNICODE_STRING Desktop, Shell, Runtime, Title; 00767 NTSTATUS Status; 00768 ULONG EnviroSize; 00769 SIZE_T Size; 00770 BOOLEAN HavePebLock = FALSE, Result; 00771 PPEB Peb = NtCurrentPeb(); 00772 00773 /* Get the full path name */ 00774 Size = GetFullPathNameW(ApplicationPathName, 00775 MAX_PATH + 4, 00776 FullPath, 00777 &Remaining); 00778 if ((Size) && (Size <= (MAX_PATH + 4))) 00779 { 00780 /* Get the DLL Path */ 00781 DllPathString = BaseComputeProcessDllPath(FullPath, lpEnvironment); 00782 if (!DllPathString) 00783 { 00784 /* Fail */ 00785 SetLastError(ERROR_NOT_ENOUGH_MEMORY); 00786 return FALSE; 00787 } 00788 00789 /* Initialize Strings */ 00790 RtlInitUnicodeString(&DllPath, DllPathString); 00791 RtlInitUnicodeString(&ImageName, FullPath); 00792 } 00793 else 00794 { 00795 /* Couldn't get the path name. Just take the original path */ 00796 DllPathString = BaseComputeProcessDllPath((LPWSTR)ApplicationPathName, 00797 lpEnvironment); 00798 if (!DllPathString) 00799 { 00800 /* Fail */ 00801 SetLastError(ERROR_NOT_ENOUGH_MEMORY); 00802 return FALSE; 00803 } 00804 00805 /* Initialize Strings */ 00806 RtlInitUnicodeString(&DllPath, DllPathString); 00807 RtlInitUnicodeString(&ImageName, ApplicationPathName); 00808 } 00809 00810 /* Initialize Strings */ 00811 RtlInitUnicodeString(&CommandLine, lpCommandLine); 00812 RtlInitUnicodeString(&CurrentDirectory, lpCurrentDirectory); 00813 00814 /* Initialize more Strings from the Startup Info */ 00815 if (StartupInfo->lpDesktop) 00816 { 00817 RtlInitUnicodeString(&Desktop, StartupInfo->lpDesktop); 00818 } 00819 else 00820 { 00821 RtlInitUnicodeString(&Desktop, L""); 00822 } 00823 if (StartupInfo->lpReserved) 00824 { 00825 RtlInitUnicodeString(&Shell, StartupInfo->lpReserved); 00826 } 00827 else 00828 { 00829 RtlInitUnicodeString(&Shell, L""); 00830 } 00831 if (StartupInfo->lpTitle) 00832 { 00833 RtlInitUnicodeString(&Title, StartupInfo->lpTitle); 00834 } 00835 else 00836 { 00837 RtlInitUnicodeString(&Title, ApplicationPathName); 00838 } 00839 00840 /* This one is special because the length can differ */ 00841 Runtime.Buffer = (LPWSTR)StartupInfo->lpReserved2; 00842 Runtime.MaximumLength = Runtime.Length = StartupInfo->cbReserved2; 00843 00844 /* Enforce no app compat data if the pointer was NULL */ 00845 if (!AppCompatData) AppCompatDataSize = 0; 00846 00847 /* Create the Parameter Block */ 00848 ProcessParameters = NULL; 00849 Status = RtlCreateProcessParameters(&ProcessParameters, 00850 &ImageName, 00851 &DllPath, 00852 lpCurrentDirectory ? 00853 &CurrentDirectory : NULL, 00854 &CommandLine, 00855 lpEnvironment, 00856 &Title, 00857 &Desktop, 00858 &Shell, 00859 &Runtime); 00860 if (!NT_SUCCESS(Status)) goto FailPath; 00861 00862 /* Clear the current directory handle if not inheriting */ 00863 if (!InheritHandles) ProcessParameters->CurrentDirectory.Handle = NULL; 00864 00865 /* Check if the user passed in an environment */ 00866 if (lpEnvironment) 00867 { 00868 /* We should've made it part of the parameters block, enforce this */ 00869 ASSERT(ProcessParameters->Environment == lpEnvironment); 00870 lpEnvironment = ProcessParameters->Environment; 00871 } 00872 else 00873 { 00874 /* The user did not, so use the one from the current PEB */ 00875 HavePebLock = TRUE; 00876 RtlAcquirePebLock(); 00877 lpEnvironment = Peb->ProcessParameters->Environment; 00878 } 00879 00880 /* Save pointer and start lookup */ 00881 ScanChar = lpEnvironment; 00882 if (lpEnvironment) 00883 { 00884 /* Find the environment size */ 00885 while ((ScanChar[0]) || (ScanChar[1])) ++ScanChar; 00886 ScanChar += (2 * sizeof(UNICODE_NULL)); 00887 EnviroSize = (ULONG_PTR)ScanChar - (ULONG_PTR)lpEnvironment; 00888 00889 /* Allocate and Initialize new Environment Block */ 00890 Size = EnviroSize; 00891 ProcessParameters->Environment = NULL; 00892 Status = NtAllocateVirtualMemory(ProcessHandle, 00893 (PVOID*)&ProcessParameters->Environment, 00894 0, 00895 &Size, 00896 MEM_COMMIT, 00897 PAGE_READWRITE); 00898 if (!NT_SUCCESS(Status)) goto FailPath; 00899 00900 /* Write the Environment Block */ 00901 Status = NtWriteVirtualMemory(ProcessHandle, 00902 ProcessParameters->Environment, 00903 lpEnvironment, 00904 EnviroSize, 00905 NULL); 00906 00907 /* No longer need the PEB lock anymore */ 00908 if (HavePebLock) 00909 { 00910 /* Release it */ 00911 RtlReleasePebLock(); 00912 HavePebLock = FALSE; 00913 } 00914 00915 /* Check if the write failed */ 00916 if (!NT_SUCCESS(Status)) goto FailPath; 00917 } 00918 00919 /* Write new parameters */ 00920 ProcessParameters->StartingX = StartupInfo->dwX; 00921 ProcessParameters->StartingY = StartupInfo->dwY; 00922 ProcessParameters->CountX = StartupInfo->dwXSize; 00923 ProcessParameters->CountY = StartupInfo->dwYSize; 00924 ProcessParameters->CountCharsX = StartupInfo->dwXCountChars; 00925 ProcessParameters->CountCharsY = StartupInfo->dwYCountChars; 00926 ProcessParameters->FillAttribute = StartupInfo->dwFillAttribute; 00927 ProcessParameters->WindowFlags = StartupInfo->dwFlags; 00928 ProcessParameters->ShowWindowFlags = StartupInfo->wShowWindow; 00929 00930 /* Write the handles only if we have to */ 00931 if (StartupInfo->dwFlags & 00932 (STARTF_USESTDHANDLES | STARTF_USEHOTKEY | STARTF_SHELLPRIVATE)) 00933 { 00934 ProcessParameters->StandardInput = StartupInfo->hStdInput; 00935 ProcessParameters->StandardOutput = StartupInfo->hStdOutput; 00936 ProcessParameters->StandardError = StartupInfo->hStdError; 00937 } 00938 00939 /* Use Special Flags for ConDllInitialize in Kernel32 */ 00940 if (CreationFlags & DETACHED_PROCESS) 00941 { 00942 ProcessParameters->ConsoleHandle = HANDLE_DETACHED_PROCESS; 00943 } 00944 else if (CreationFlags & CREATE_NO_WINDOW) 00945 { 00946 ProcessParameters->ConsoleHandle = HANDLE_CREATE_NO_WINDOW; 00947 } 00948 else if (CreationFlags & CREATE_NEW_CONSOLE) 00949 { 00950 ProcessParameters->ConsoleHandle = HANDLE_CREATE_NEW_CONSOLE; 00951 } 00952 else 00953 { 00954 /* Inherit our Console Handle */ 00955 ProcessParameters->ConsoleHandle = Peb->ProcessParameters->ConsoleHandle; 00956 00957 /* Make sure that the shell isn't trampling on our handles first */ 00958 if (!(StartupInfo->dwFlags & 00959 (STARTF_USESTDHANDLES | STARTF_USEHOTKEY | STARTF_SHELLPRIVATE))) 00960 { 00961 /* Copy the handle if we are inheriting or if it's a console handle */ 00962 if ((InheritHandles) || 00963 (IsConsoleHandle(Peb->ProcessParameters->StandardInput))) 00964 { 00965 ProcessParameters->StandardInput = Peb->ProcessParameters->StandardInput; 00966 } 00967 if ((InheritHandles) || 00968 (IsConsoleHandle(Peb->ProcessParameters->StandardOutput))) 00969 { 00970 ProcessParameters->StandardOutput = Peb->ProcessParameters->StandardOutput; 00971 } 00972 if ((InheritHandles) || 00973 (IsConsoleHandle(Peb->ProcessParameters->StandardError))) 00974 { 00975 ProcessParameters->StandardError = Peb->ProcessParameters->StandardError; 00976 } 00977 } 00978 } 00979 00980 /* Also set the Console Flag */ 00981 if ((CreationFlags & CREATE_NEW_PROCESS_GROUP) && 00982 (!(CreationFlags & CREATE_NEW_CONSOLE))) 00983 { 00984 ProcessParameters->ConsoleFlags = 1; 00985 } 00986 00987 /* See if the first 1MB should be reserved */ 00988 if (ParameterFlags & 1) 00989 { 00990 ProcessParameters->Flags |= RTL_USER_PROCESS_PARAMETERS_RESERVE_1MB; 00991 } 00992 00993 /* See if the first 16MB should be reserved */ 00994 if (ParameterFlags & 2) 00995 { 00996 ProcessParameters->Flags |= RTL_USER_PROCESS_PARAMETERS_RESERVE_16MB; 00997 } 00998 00999 /* Allocate memory for the parameter block */ 01000 Size = ProcessParameters->Length; 01001 RemoteParameters = NULL; 01002 Status = NtAllocateVirtualMemory(ProcessHandle, 01003 (PVOID*)&RemoteParameters, 01004 0, 01005 &Size, 01006 MEM_COMMIT, 01007 PAGE_READWRITE); 01008 if (!NT_SUCCESS(Status)) goto FailPath; 01009 01010 /* Set the allocated size */ 01011 ProcessParameters->MaximumLength = Size; 01012 01013 /* Handle some Parameter Flags */ 01014 ProcessParameters->Flags |= (CreationFlags & PROFILE_USER) ? 01015 RTL_USER_PROCESS_PARAMETERS_PROFILE_USER : 0; 01016 ProcessParameters->Flags |= (CreationFlags & PROFILE_KERNEL) ? 01017 RTL_USER_PROCESS_PARAMETERS_PROFILE_KERNEL : 0; 01018 ProcessParameters->Flags |= (CreationFlags & PROFILE_SERVER) ? 01019 RTL_USER_PROCESS_PARAMETERS_PROFILE_SERVER : 0; 01020 ProcessParameters->Flags |= (Peb->ProcessParameters->Flags & 01021 RTL_USER_PROCESS_PARAMETERS_DISABLE_HEAP_CHECKS); 01022 01023 /* Write the Parameter Block */ 01024 Status = NtWriteVirtualMemory(ProcessHandle, 01025 RemoteParameters, 01026 ProcessParameters, 01027 ProcessParameters->Length, 01028 NULL); 01029 if (!NT_SUCCESS(Status)) goto FailPath; 01030 01031 /* Write the PEB Pointer */ 01032 Status = NtWriteVirtualMemory(ProcessHandle, 01033 &RemotePeb->ProcessParameters, 01034 &RemoteParameters, 01035 sizeof(PVOID), 01036 NULL); 01037 if (!NT_SUCCESS(Status)) goto FailPath; 01038 01039 /* Check if there's any app compat data to write */ 01040 RemoteAppCompatData = NULL; 01041 if (AppCompatData) 01042 { 01043 /* Allocate some space for the application compatibility data */ 01044 Size = AppCompatDataSize; 01045 Status = NtAllocateVirtualMemory(ProcessHandle, 01046 &RemoteAppCompatData, 01047 0, 01048 &Size, 01049 MEM_COMMIT, 01050 PAGE_READWRITE); 01051 if (!NT_SUCCESS(Status)) goto FailPath; 01052 01053 /* Write the application compatibility data */ 01054 Status = NtWriteVirtualMemory(ProcessHandle, 01055 RemoteAppCompatData, 01056 AppCompatData, 01057 AppCompatDataSize, 01058 NULL); 01059 if (!NT_SUCCESS(Status)) goto FailPath; 01060 } 01061 01062 /* Write the PEB Pointer to the app compat data (might be NULL) */ 01063 Status = NtWriteVirtualMemory(ProcessHandle, 01064 &RemotePeb->pShimData, 01065 &RemoteAppCompatData, 01066 sizeof(PVOID), 01067 NULL); 01068 if (!NT_SUCCESS(Status)) goto FailPath; 01069 01070 /* Now write Peb->ImageSubSystem */ 01071 if (ImageSubsystem) 01072 { 01073 NtWriteVirtualMemory(ProcessHandle, 01074 &RemotePeb->ImageSubsystem, 01075 &ImageSubsystem, 01076 sizeof(ImageSubsystem), 01077 NULL); 01078 } 01079 01080 /* Success path */ 01081 Result = TRUE; 01082 01083 Quickie: 01084 /* Cleanup */ 01085 if (HavePebLock) RtlReleasePebLock(); 01086 RtlFreeHeap(RtlGetProcessHeap(), 0, DllPath.Buffer); 01087 if (ProcessParameters) RtlDestroyProcessParameters(ProcessParameters); 01088 return Result; 01089 FailPath: 01090 DPRINT1("Failure to create proecss parameters: %lx\n", Status); 01091 BaseSetLastNTError(Status); 01092 Result = FALSE; 01093 goto Quickie; 01094 } 01095 01096 VOID 01097 WINAPI 01098 InitCommandLines(VOID) 01099 { 01100 NTSTATUS Status; 01101 01102 /* Read the UNICODE_STRING from the PEB */ 01103 BaseUnicodeCommandLine = NtCurrentPeb()->ProcessParameters->CommandLine; 01104 01105 /* Convert to ANSI_STRING for the *A callers */ 01106 Status = RtlUnicodeStringToAnsiString(&BaseAnsiCommandLine, 01107 &BaseUnicodeCommandLine, 01108 TRUE); 01109 if (!NT_SUCCESS(Status)) RtlInitEmptyAnsiString(&BaseAnsiCommandLine, 0, 0); 01110 } 01111 01112 /* PUBLIC FUNCTIONS ***********************************************************/ 01113 01114 /* 01115 * @implemented 01116 */ 01117 BOOL 01118 WINAPI 01119 GetProcessAffinityMask(IN HANDLE hProcess, 01120 OUT PDWORD_PTR lpProcessAffinityMask, 01121 OUT PDWORD_PTR lpSystemAffinityMask) 01122 { 01123 PROCESS_BASIC_INFORMATION ProcessInfo; 01124 NTSTATUS Status; 01125 01126 /* Query information on the process from the kernel */ 01127 Status = NtQueryInformationProcess(hProcess, 01128 ProcessBasicInformation, 01129 (PVOID)&ProcessInfo, 01130 sizeof(PROCESS_BASIC_INFORMATION), 01131 NULL); 01132 if (!NT_SUCCESS(Status)) 01133 { 01134 /* Fail */ 01135 BaseSetLastNTError(Status); 01136 return FALSE; 01137 } 01138 01139 /* Copy the affinity mask, and get the system one from our shared data */ 01140 *lpProcessAffinityMask = (DWORD)ProcessInfo.AffinityMask; 01141 *lpSystemAffinityMask = (DWORD)BaseStaticServerData->SysInfo.ActiveProcessorsAffinityMask; 01142 return TRUE; 01143 } 01144 01145 /* 01146 * @implemented 01147 */ 01148 BOOL 01149 WINAPI 01150 SetProcessAffinityMask(IN HANDLE hProcess, 01151 IN DWORD_PTR dwProcessAffinityMask) 01152 { 01153 NTSTATUS Status; 01154 01155 /* Directly set the affinity mask */ 01156 Status = NtSetInformationProcess(hProcess, 01157 ProcessAffinityMask, 01158 (PVOID)&dwProcessAffinityMask, 01159 sizeof(DWORD)); 01160 if (!NT_SUCCESS(Status)) 01161 { 01162 /* Handle failure */ 01163 BaseSetLastNTError(Status); 01164 return FALSE; 01165 } 01166 01167 /* Everything was ok */ 01168 return TRUE; 01169 } 01170 01171 /* 01172 * @implemented 01173 */ 01174 BOOL 01175 WINAPI 01176 GetProcessShutdownParameters(OUT LPDWORD lpdwLevel, 01177 OUT LPDWORD lpdwFlags) 01178 { 01179 CSR_API_MESSAGE CsrRequest; 01180 NTSTATUS Status; 01181 01182 /* Ask CSRSS for shutdown information */ 01183 Status = CsrClientCallServer(&CsrRequest, 01184 NULL, 01185 MAKE_CSR_API(GET_SHUTDOWN_PARAMETERS, CSR_NATIVE), 01186 sizeof(CSR_API_MESSAGE)); 01187 if (!(NT_SUCCESS(Status)) || !(NT_SUCCESS(CsrRequest.Status))) 01188 { 01189 /* Return the failure from CSRSS */ 01190 BaseSetLastNTError(CsrRequest.Status); 01191 return FALSE; 01192 } 01193 01194 /* Get the data out of the LCP reply */ 01195 *lpdwLevel = CsrRequest.Data.GetShutdownParametersRequest.Level; 01196 *lpdwFlags = CsrRequest.Data.GetShutdownParametersRequest.Flags; 01197 return TRUE; 01198 } 01199 01200 /* 01201 * @implemented 01202 */ 01203 BOOL 01204 WINAPI 01205 SetProcessShutdownParameters(IN DWORD dwLevel, 01206 IN DWORD dwFlags) 01207 { 01208 CSR_API_MESSAGE CsrRequest; 01209 NTSTATUS Status; 01210 01211 /* Write the data into the CSRSS request and send it */ 01212 CsrRequest.Data.SetShutdownParametersRequest.Level = dwLevel; 01213 CsrRequest.Data.SetShutdownParametersRequest.Flags = dwFlags; 01214 Status = CsrClientCallServer(&CsrRequest, 01215 NULL, 01216 MAKE_CSR_API(SET_SHUTDOWN_PARAMETERS, CSR_NATIVE), 01217 sizeof(CSR_API_MESSAGE)); 01218 if (!NT_SUCCESS(Status) || !NT_SUCCESS(CsrRequest.Status)) 01219 { 01220 /* Return the failure from CSRSS */ 01221 BaseSetLastNTError(CsrRequest.Status); 01222 return FALSE; 01223 } 01224 01225 /* All went well */ 01226 return TRUE; 01227 } 01228 01229 /* 01230 * @implemented 01231 */ 01232 BOOL 01233 WINAPI 01234 GetProcessWorkingSetSizeEx(IN HANDLE hProcess, 01235 OUT PSIZE_T lpMinimumWorkingSetSize, 01236 OUT PSIZE_T lpMaximumWorkingSetSize, 01237 OUT PDWORD Flags) 01238 { 01239 QUOTA_LIMITS_EX QuotaLimits; 01240 NTSTATUS Status; 01241 01242 /* Query the kernel about this */ 01243 Status = NtQueryInformationProcess(hProcess, 01244 ProcessQuotaLimits, 01245 &QuotaLimits, 01246 sizeof(QUOTA_LIMITS_EX), 01247 NULL); 01248 if (!NT_SUCCESS(Status)) 01249 { 01250 /* Return error */ 01251 BaseSetLastNTError(Status); 01252 return FALSE; 01253 } 01254 01255 /* Copy the quota information out */ 01256 *lpMinimumWorkingSetSize = QuotaLimits.MinimumWorkingSetSize; 01257 *lpMaximumWorkingSetSize = QuotaLimits.MaximumWorkingSetSize; 01258 *Flags = QuotaLimits.Flags; 01259 return TRUE; 01260 } 01261 01262 /* 01263 * @implemented 01264 */ 01265 BOOL 01266 WINAPI 01267 GetProcessWorkingSetSize(IN HANDLE hProcess, 01268 OUT PSIZE_T lpMinimumWorkingSetSize, 01269 OUT PSIZE_T lpMaximumWorkingSetSize) 01270 { 01271 DWORD Dummy; 01272 return GetProcessWorkingSetSizeEx(hProcess, 01273 lpMinimumWorkingSetSize, 01274 lpMaximumWorkingSetSize, 01275 &Dummy); 01276 } 01277 01278 /* 01279 * @implemented 01280 */ 01281 BOOL 01282 WINAPI 01283 SetProcessWorkingSetSizeEx(IN HANDLE hProcess, 01284 IN SIZE_T dwMinimumWorkingSetSize, 01285 IN SIZE_T dwMaximumWorkingSetSize, 01286 IN DWORD Flags) 01287 { 01288 QUOTA_LIMITS_EX QuotaLimits; 01289 NTSTATUS Status, ReturnStatus; 01290 BOOL Result; 01291 PVOID State; 01292 ULONG Privilege = SE_INC_BASE_PRIORITY_PRIVILEGE; 01293 01294 /* Zero out the input structure */ 01295 RtlZeroMemory(&QuotaLimits, sizeof(QuotaLimits)); 01296 01297 /* Check if the caller sent any limits */ 01298 if ((dwMinimumWorkingSetSize) && (dwMaximumWorkingSetSize)) 01299 { 01300 /* Write the quota information */ 01301 QuotaLimits.MinimumWorkingSetSize = dwMinimumWorkingSetSize; 01302 QuotaLimits.MaximumWorkingSetSize = dwMaximumWorkingSetSize; 01303 QuotaLimits.Flags = Flags; 01304 01305 /* Acquire the required privilege */ 01306 Status = RtlAcquirePrivilege(&Privilege, 1, 0, &State); 01307 01308 /* Request the new quotas */ 01309 ReturnStatus = NtSetInformationProcess(hProcess, 01310 ProcessQuotaLimits, 01311 &QuotaLimits, 01312 sizeof(QuotaLimits)); 01313 Result = NT_SUCCESS(ReturnStatus); 01314 if (NT_SUCCESS(Status)) 01315 { 01316 /* Release the privilege and set succes code */ 01317 ASSERT(State != NULL); 01318 RtlReleasePrivilege(State); 01319 State = NULL; 01320 } 01321 } 01322 else 01323 { 01324 /* No limits, fail the call */ 01325 ReturnStatus = STATUS_INVALID_PARAMETER; 01326 Result = FALSE; 01327 } 01328 01329 /* Return result code, set error code if this was a failure */ 01330 if (!Result) BaseSetLastNTError(ReturnStatus); 01331 return Result; 01332 } 01333 01334 /* 01335 * @implemented 01336 */ 01337 BOOL 01338 WINAPI 01339 SetProcessWorkingSetSize(IN HANDLE hProcess, 01340 IN SIZE_T dwMinimumWorkingSetSize, 01341 IN SIZE_T dwMaximumWorkingSetSize) 01342 { 01343 /* Call the newer API */ 01344 return SetProcessWorkingSetSizeEx(hProcess, 01345 dwMinimumWorkingSetSize, 01346 dwMaximumWorkingSetSize, 01347 0); 01348 } 01349 01350 /* 01351 * @implemented 01352 */ 01353 BOOL 01354 WINAPI 01355 GetProcessTimes(IN HANDLE hProcess, 01356 IN LPFILETIME lpCreationTime, 01357 IN LPFILETIME lpExitTime, 01358 IN LPFILETIME lpKernelTime, 01359 IN LPFILETIME lpUserTime) 01360 { 01361 KERNEL_USER_TIMES Kut; 01362 NTSTATUS Status; 01363 01364 /* Query the times */ 01365 Status = NtQueryInformationProcess(hProcess, 01366 ProcessTimes, 01367 &Kut, 01368 sizeof(Kut), 01369 NULL); 01370 if (!NT_SUCCESS(Status)) 01371 { 01372 /* Handle failure */ 01373 BaseSetLastNTError(Status); 01374 return FALSE; 01375 } 01376 01377 /* Copy all the times and return success */ 01378 lpCreationTime->dwLowDateTime = Kut.CreateTime.u.LowPart; 01379 lpCreationTime->dwHighDateTime = Kut.CreateTime.u.HighPart; 01380 lpExitTime->dwLowDateTime = Kut.ExitTime.u.LowPart; 01381 lpExitTime->dwHighDateTime = Kut.ExitTime.u.HighPart; 01382 lpKernelTime->dwLowDateTime = Kut.KernelTime.u.LowPart; 01383 lpKernelTime->dwHighDateTime = Kut.KernelTime.u.HighPart; 01384 lpUserTime->dwLowDateTime = Kut.UserTime.u.LowPart; 01385 lpUserTime->dwHighDateTime = Kut.UserTime.u.HighPart; 01386 return TRUE; 01387 } 01388 01389 /* 01390 * @implemented 01391 */ 01392 HANDLE 01393 WINAPI 01394 GetCurrentProcess(VOID) 01395 { 01396 return (HANDLE)NtCurrentProcess(); 01397 } 01398 01399 /* 01400 * @implemented 01401 */ 01402 HANDLE 01403 WINAPI 01404 GetCurrentThread(VOID) 01405 { 01406 return (HANDLE)NtCurrentThread(); 01407 } 01408 01409 /* 01410 * @implemented 01411 */ 01412 DWORD 01413 WINAPI 01414 GetCurrentProcessId(VOID) 01415 { 01416 return HandleToUlong(NtCurrentTeb()->ClientId.UniqueProcess); 01417 } 01418 01419 /* 01420 * @implemented 01421 */ 01422 BOOL 01423 WINAPI 01424 GetExitCodeProcess(IN HANDLE hProcess, 01425 IN LPDWORD lpExitCode) 01426 { 01427 PROCESS_BASIC_INFORMATION ProcessBasic; 01428 NTSTATUS Status; 01429 01430 /* Ask the kernel */ 01431 Status = NtQueryInformationProcess(hProcess, 01432 ProcessBasicInformation, 01433 &ProcessBasic, 01434 sizeof(PROCESS_BASIC_INFORMATION), 01435 NULL); 01436 if (!NT_SUCCESS(Status)) 01437 { 01438 /* We failed, was this because this is a VDM process? */ 01439 if (BaseCheckForVDM(hProcess, lpExitCode) == TRUE) return TRUE; 01440 01441 /* Not a VDM process, fail the call */ 01442 BaseSetLastNTError(Status); 01443 return FALSE; 01444 } 01445 01446 /* Succes case, return the exit code */ 01447 *lpExitCode = (DWORD)ProcessBasic.ExitStatus; 01448 return TRUE; 01449 } 01450 01451 /* 01452 * @implemented 01453 */ 01454 DWORD 01455 WINAPI 01456 GetProcessId(IN HANDLE Process) 01457 { 01458 PROCESS_BASIC_INFORMATION ProcessBasic; 01459 NTSTATUS Status; 01460 01461 /* Query the kernel */ 01462 Status = NtQueryInformationProcess(Process, 01463 ProcessBasicInformation, 01464 &ProcessBasic, 01465 sizeof(PROCESS_BASIC_INFORMATION), 01466 NULL); 01467 if (!NT_SUCCESS(Status)) 01468 { 01469 /* Handle failure */ 01470 BaseSetLastNTError(Status); 01471 return 0; 01472 } 01473 01474 /* Return the PID */ 01475 return (DWORD)ProcessBasic.UniqueProcessId; 01476 } 01477 01478 /* 01479 * @implemented 01480 */ 01481 HANDLE 01482 WINAPI 01483 OpenProcess(IN DWORD dwDesiredAccess, 01484 IN BOOL bInheritHandle, 01485 IN DWORD dwProcessId) 01486 { 01487 NTSTATUS Status; 01488 HANDLE ProcessHandle; 01489 OBJECT_ATTRIBUTES ObjectAttributes; 01490 CLIENT_ID ClientId; 01491 01492 /* Setup the input client ID structure */ 01493 ClientId.UniqueProcess = UlongToHandle(dwProcessId); 01494 ClientId.UniqueThread = 0; 01495 01496 /* This is needed just to define the inheritance flags */ 01497 InitializeObjectAttributes(&ObjectAttributes, 01498 NULL, 01499 (bInheritHandle ? OBJ_INHERIT : 0), 01500 NULL, 01501 NULL); 01502 01503 /* Now try to open the process */ 01504 Status = NtOpenProcess(&ProcessHandle, 01505 dwDesiredAccess, 01506 &ObjectAttributes, 01507 &ClientId); 01508 if (!NT_SUCCESS(Status)) 01509 { 01510 /* Handle failure */ 01511 BaseSetLastNTError(Status); 01512 return NULL; 01513 } 01514 01515 /* Otherwise return a handle to the process */ 01516 return ProcessHandle; 01517 } 01518 01519 /* 01520 * @implemented 01521 */ 01522 VOID 01523 WINAPI 01524 RegisterWaitForInputIdle(IN WaitForInputIdleType lpfnRegisterWaitForInputIdle) 01525 { 01526 /* Write the global function pointer */ 01527 UserWaitForInputIdleRoutine = lpfnRegisterWaitForInputIdle; 01528 } 01529 01530 /* 01531 * @implemented 01532 */ 01533 VOID 01534 WINAPI 01535 GetStartupInfoW(IN LPSTARTUPINFOW lpStartupInfo) 01536 { 01537 PRTL_USER_PROCESS_PARAMETERS Params; 01538 01539 /* Get the process parameters */ 01540 Params = NtCurrentPeb()->ProcessParameters; 01541 01542 /* Copy the data out of there */ 01543 lpStartupInfo->cb = sizeof(STARTUPINFOW); 01544 lpStartupInfo->lpReserved = Params->ShellInfo.Buffer; 01545 lpStartupInfo->lpDesktop = Params->DesktopInfo.Buffer; 01546 lpStartupInfo->lpTitle = Params->WindowTitle.Buffer; 01547 lpStartupInfo->dwX = Params->StartingX; 01548 lpStartupInfo->dwY = Params->StartingY; 01549 lpStartupInfo->dwXSize = Params->CountX; 01550 lpStartupInfo->dwYSize = Params->CountY; 01551 lpStartupInfo->dwXCountChars = Params->CountCharsX; 01552 lpStartupInfo->dwYCountChars = Params->CountCharsY; 01553 lpStartupInfo->dwFillAttribute = Params->FillAttribute; 01554 lpStartupInfo->dwFlags = Params->WindowFlags; 01555 lpStartupInfo->wShowWindow = (WORD)Params->ShowWindowFlags; 01556 lpStartupInfo->cbReserved2 = Params->RuntimeData.Length; 01557 lpStartupInfo->lpReserved2 = (LPBYTE)Params->RuntimeData.Buffer; 01558 01559 /* Check if the standard handles are being used for other features */ 01560 if (lpStartupInfo->dwFlags & (STARTF_USESTDHANDLES | 01561 STARTF_USEHOTKEY | 01562 STARTF_SHELLPRIVATE)) 01563 { 01564 /* These are, so copy the standard handles too */ 01565 lpStartupInfo->hStdInput = Params->StandardInput; 01566 lpStartupInfo->hStdOutput = Params->StandardOutput; 01567 lpStartupInfo->hStdError = Params->StandardError; 01568 } 01569 } 01570 01571 /* 01572 * @implemented 01573 */ 01574 VOID 01575 WINAPI 01576 GetStartupInfoA(IN LPSTARTUPINFOA lpStartupInfo) 01577 { 01578 PRTL_USER_PROCESS_PARAMETERS Params; 01579 ANSI_STRING TitleString, ShellString, DesktopString; 01580 LPSTARTUPINFOA StartupInfo; 01581 NTSTATUS Status; 01582 01583 /* Get the cached information as well as the PEB parameters */ 01584 StartupInfo = BaseAnsiStartupInfo; 01585 Params = NtCurrentPeb()->ProcessParameters; 01586 01587 /* Check if this is the first time we have to get the cached version */ 01588 while (!StartupInfo) 01589 { 01590 /* Create new ANSI startup info */ 01591 StartupInfo = RtlAllocateHeap(RtlGetProcessHeap(), 01592 0, 01593 sizeof(*StartupInfo)); 01594 if (StartupInfo) 01595 { 01596 /* Zero out string pointers in case we fail to create them */ 01597 StartupInfo->lpReserved = 0; 01598 StartupInfo->lpDesktop = 0; 01599 StartupInfo->lpTitle = 0; 01600 01601 /* Set the size */ 01602 StartupInfo->cb = sizeof(*StartupInfo); 01603 01604 /* Copy what's already stored in the PEB */ 01605 StartupInfo->dwX = Params->StartingX; 01606 StartupInfo->dwY = Params->StartingY; 01607 StartupInfo->dwXSize = Params->CountX; 01608 StartupInfo->dwYSize = Params->CountY; 01609 StartupInfo->dwXCountChars = Params->CountCharsX; 01610 StartupInfo->dwYCountChars = Params->CountCharsY; 01611 StartupInfo->dwFillAttribute = Params->FillAttribute; 01612 StartupInfo->dwFlags = Params->WindowFlags; 01613 StartupInfo->wShowWindow = (WORD)Params->ShowWindowFlags; 01614 StartupInfo->cbReserved2 = Params->RuntimeData.Length; 01615 StartupInfo->lpReserved2 = (LPBYTE)Params->RuntimeData.Buffer; 01616 StartupInfo->hStdInput = Params->StandardInput; 01617 StartupInfo->hStdOutput = Params->StandardOutput; 01618 StartupInfo->hStdError = Params->StandardError; 01619 01620 /* Copy shell info string */ 01621 Status = RtlUnicodeStringToAnsiString(&ShellString, 01622 &Params->ShellInfo, 01623 TRUE); 01624 if (NT_SUCCESS(Status)) 01625 { 01626 /* Save it */ 01627 StartupInfo->lpReserved = ShellString.Buffer; 01628 01629 /* Copy desktop info string */ 01630 Status = RtlUnicodeStringToAnsiString(&DesktopString, 01631 &Params->DesktopInfo, 01632 TRUE); 01633 if (NT_SUCCESS(Status)) 01634 { 01635 /* Save it */ 01636 StartupInfo->lpDesktop = DesktopString.Buffer; 01637 01638 /* Copy window title string */ 01639 Status = RtlUnicodeStringToAnsiString(&TitleString, 01640 &Params->WindowTitle, 01641 TRUE); 01642 if (NT_SUCCESS(Status)) 01643 { 01644 /* Save it */ 01645 StartupInfo->lpTitle = TitleString.Buffer; 01646 01647 /* We finished with the ANSI version, try to cache it */ 01648 if (!InterlockedCompareExchangePointer(&BaseAnsiStartupInfo, 01649 StartupInfo, 01650 NULL)) 01651 { 01652 /* We were the first thread through, use the data */ 01653 break; 01654 } 01655 01656 /* Someone beat us to it, use their data instead */ 01657 StartupInfo = BaseAnsiStartupInfo; 01658 Status = STATUS_SUCCESS; 01659 01660 /* We're going to free our own stuff, but not raise */ 01661 RtlFreeAnsiString(&TitleString); 01662 } 01663 RtlFreeAnsiString(&DesktopString); 01664 } 01665 RtlFreeAnsiString(&ShellString); 01666 } 01667 RtlFreeHeap(RtlGetProcessHeap(), 0, StartupInfo); 01668 } 01669 else 01670 { 01671 /* No memory, fail */ 01672 Status = STATUS_NO_MEMORY; 01673 } 01674 01675 /* Raise an error unless we got here due to the race condition */ 01676 if (!NT_SUCCESS(Status)) RtlRaiseStatus(Status); 01677 } 01678 01679 /* Now copy from the cached ANSI version */ 01680 lpStartupInfo->cb = StartupInfo->cb; 01681 lpStartupInfo->lpReserved = StartupInfo->lpReserved; 01682 lpStartupInfo->lpDesktop = StartupInfo->lpDesktop; 01683 lpStartupInfo->lpTitle = StartupInfo->lpTitle; 01684 lpStartupInfo->dwX = StartupInfo->dwX; 01685 lpStartupInfo->dwY = StartupInfo->dwY; 01686 lpStartupInfo->dwXSize = StartupInfo->dwXSize; 01687 lpStartupInfo->dwYSize = StartupInfo->dwYSize; 01688 lpStartupInfo->dwXCountChars = StartupInfo->dwXCountChars; 01689 lpStartupInfo->dwYCountChars = StartupInfo->dwYCountChars; 01690 lpStartupInfo->dwFillAttribute = StartupInfo->dwFillAttribute; 01691 lpStartupInfo->dwFlags = StartupInfo->dwFlags; 01692 lpStartupInfo->wShowWindow = StartupInfo->wShowWindow; 01693 lpStartupInfo->cbReserved2 = StartupInfo->cbReserved2; 01694 lpStartupInfo->lpReserved2 = StartupInfo->lpReserved2; 01695 01696 /* Check if the shell is hijacking the handles for other features */ 01697 if (lpStartupInfo->dwFlags & 01698 (STARTF_USESTDHANDLES | STARTF_USEHOTKEY | STARTF_SHELLPRIVATE)) 01699 { 01700 /* It isn't, so we can return the raw values */ 01701 lpStartupInfo->hStdInput = StartupInfo->hStdInput; 01702 lpStartupInfo->hStdOutput = StartupInfo->hStdOutput; 01703 lpStartupInfo->hStdError = StartupInfo->hStdError; 01704 } 01705 else 01706 { 01707 /* It is, so make sure nobody uses these as console handles */ 01708 lpStartupInfo->hStdInput = INVALID_HANDLE_VALUE; 01709 lpStartupInfo->hStdOutput = INVALID_HANDLE_VALUE; 01710 lpStartupInfo->hStdError = INVALID_HANDLE_VALUE; 01711 } 01712 } 01713 01714 /* 01715 * @implemented 01716 */ 01717 BOOL 01718 WINAPI 01719 FlushInstructionCache(IN HANDLE hProcess, 01720 IN LPCVOID lpBaseAddress, 01721 IN SIZE_T dwSize) 01722 { 01723 NTSTATUS Status; 01724 01725 /* Call the native function */ 01726 Status = NtFlushInstructionCache(hProcess, (PVOID)lpBaseAddress, dwSize); 01727 if (!NT_SUCCESS(Status)) 01728 { 01729 /* Handle failure case */ 01730 BaseSetLastNTError(Status); 01731 return FALSE; 01732 } 01733 01734 /* All good */ 01735 return TRUE; 01736 } 01737 01738 /* 01739 * @implemented 01740 */ 01741 VOID 01742 WINAPI 01743 ExitProcess(IN UINT uExitCode) 01744 { 01745 CSR_API_MESSAGE CsrRequest; 01746 ASSERT(!BaseRunningInServerProcess); 01747 01748 _SEH2_TRY 01749 { 01750 /* Acquire the PEB lock */ 01751 RtlAcquirePebLock(); 01752 01753 /* Kill all the threads */ 01754 NtTerminateProcess(NULL, 0); 01755 01756 /* Unload all DLLs */ 01757 LdrShutdownProcess(); 01758 01759 /* Notify Base Server of process termination */ 01760 CsrRequest.Data.TerminateProcessRequest.uExitCode = uExitCode; 01761 CsrClientCallServer(&CsrRequest, 01762 NULL, 01763 MAKE_CSR_API(TERMINATE_PROCESS, CSR_NATIVE), 01764 sizeof(CSR_API_MESSAGE)); 01765 01766 /* Now do it again */ 01767 NtTerminateProcess(NtCurrentProcess(), uExitCode); 01768 } 01769 _SEH2_FINALLY 01770 { 01771 /* Release the PEB lock */ 01772 RtlReleasePebLock(); 01773 } 01774 _SEH2_END; 01775 01776 /* should never get here */ 01777 ASSERT(0); 01778 while(1); 01779 } 01780 01781 /* 01782 * @implemented 01783 */ 01784 BOOL 01785 WINAPI 01786 TerminateProcess(IN HANDLE hProcess, 01787 IN UINT uExitCode) 01788 { 01789 NTSTATUS Status; 01790 01791 /* Check if no handle was passed in */ 01792 if (!hProcess) 01793 { 01794 /* Set error code */ 01795 SetLastError(ERROR_INVALID_HANDLE); 01796 } 01797 else 01798 { 01799 /* Otherwise, try to terminate the process */ 01800 Status = NtTerminateProcess(hProcess, uExitCode); 01801 if (NT_SUCCESS(Status)) return TRUE; 01802 01803 /* It failed, convert error code */ 01804 BaseSetLastNTError(Status); 01805 } 01806 01807 /* This is the failure path */ 01808 return FALSE; 01809 } 01810 01811 /* 01812 * @implemented 01813 */ 01814 VOID 01815 WINAPI 01816 FatalAppExitA(UINT uAction, 01817 LPCSTR lpMessageText) 01818 { 01819 PUNICODE_STRING MessageTextU; 01820 ANSI_STRING MessageText; 01821 NTSTATUS Status; 01822 01823 /* Initialize the string using the static TEB pointer */ 01824 MessageTextU = &NtCurrentTeb()->StaticUnicodeString; 01825 RtlInitAnsiString(&MessageText, (LPSTR)lpMessageText); 01826 01827 /* Convert to unicode and just exit normally if this failed */ 01828 Status = RtlAnsiStringToUnicodeString(MessageTextU, &MessageText, FALSE); 01829 if (!NT_SUCCESS(Status)) ExitProcess(0); 01830 01831 /* Call the Wide function */ 01832 FatalAppExitW(uAction, MessageTextU->Buffer); 01833 } 01834 01835 /* 01836 * @implemented 01837 */ 01838 VOID 01839 WINAPI 01840 FatalAppExitW(IN UINT uAction, 01841 IN LPCWSTR lpMessageText) 01842 { 01843 UNICODE_STRING UnicodeString; 01844 ULONG Response; 01845 NTSTATUS Status; 01846 01847 /* Setup the stirng to print out */ 01848 RtlInitUnicodeString(&UnicodeString, lpMessageText); 01849 01850 /* Display the hard error no matter what */ 01851 Status = NtRaiseHardError(STATUS_FATAL_APP_EXIT | HARDERROR_OVERRIDE_ERRORMODE, 01852 1, 01853 1, 01854 (PULONG_PTR)&UnicodeString, 01855 OptionOkCancel, 01856 &Response); 01857 01858 /* Give the user a chance to abort */ 01859 if ((NT_SUCCESS(Status)) && (Response == ResponseCancel)) return; 01860 01861 /* Otherwise kill the process */ 01862 ExitProcess(0); 01863 } 01864 01865 /* 01866 * @implemented 01867 */ 01868 VOID 01869 WINAPI 01870 FatalExit(IN int ExitCode) 01871 { 01872 #if DBG 01873 /* On Checked builds, Windows gives you a nice little debugger UI */ 01874 CHAR ch[2]; 01875 DbgPrint("FatalExit...\n"); 01876 DbgPrint("\n"); 01877 01878 while (TRUE) 01879 { 01880 DbgPrompt( "A (Abort), B (Break), I (Ignore)? ", ch, sizeof(ch)); 01881 switch (ch[0]) 01882 { 01883 case 'B': case 'b': 01884 DbgBreakPoint(); 01885 break; 01886 01887 case 'A': case 'a': 01888 ExitProcess(ExitCode); 01889 01890 case 'I': case 'i': 01891 return; 01892 } 01893 } 01894 #endif 01895 /* On other builds, just kill the process */ 01896 ExitProcess(ExitCode); 01897 } 01898 01899 /* 01900 * @implemented 01901 */ 01902 DWORD 01903 WINAPI 01904 GetPriorityClass(IN HANDLE hProcess) 01905 { 01906 NTSTATUS Status; 01907 PROCESS_PRIORITY_CLASS PriorityClass; 01908 01909 /* Query the kernel */ 01910 Status = NtQueryInformationProcess(hProcess, 01911 ProcessPriorityClass, 01912 &PriorityClass, 01913 sizeof(PROCESS_PRIORITY_CLASS), 01914 NULL); 01915 if (NT_SUCCESS(Status)) 01916 { 01917 /* Handle the conversion from NT to Win32 classes */ 01918 switch (PriorityClass.PriorityClass) 01919 { 01920 case PROCESS_PRIORITY_CLASS_IDLE: return IDLE_PRIORITY_CLASS; 01921 case PROCESS_PRIORITY_CLASS_BELOW_NORMAL: return BELOW_NORMAL_PRIORITY_CLASS; 01922 case PROCESS_PRIORITY_CLASS_ABOVE_NORMAL: return ABOVE_NORMAL_PRIORITY_CLASS; 01923 case PROCESS_PRIORITY_CLASS_HIGH: return HIGH_PRIORITY_CLASS; 01924 case PROCESS_PRIORITY_CLASS_REALTIME: return REALTIME_PRIORITY_CLASS; 01925 case PROCESS_PRIORITY_CLASS_NORMAL: default: return NORMAL_PRIORITY_CLASS; 01926 } 01927 } 01928 01929 /* Failure path */ 01930 BaseSetLastNTError(Status); 01931 return FALSE; 01932 } 01933 01934 /* 01935 * @implemented 01936 */ 01937 BOOL 01938 WINAPI 01939 SetPriorityClass(IN HANDLE hProcess, 01940 IN DWORD dwPriorityClass) 01941 { 01942 NTSTATUS Status; 01943 PVOID State = NULL; 01944 PROCESS_PRIORITY_CLASS PriorityClass; 01945 01946 /* Handle conversion from Win32 to NT priority classes */ 01947 switch (dwPriorityClass) 01948 { 01949 case IDLE_PRIORITY_CLASS: 01950 PriorityClass.PriorityClass = PROCESS_PRIORITY_CLASS_IDLE; 01951 break; 01952 01953 case BELOW_NORMAL_PRIORITY_CLASS: 01954 PriorityClass.PriorityClass = PROCESS_PRIORITY_CLASS_BELOW_NORMAL; 01955 break; 01956 01957 case NORMAL_PRIORITY_CLASS: 01958 PriorityClass.PriorityClass = PROCESS_PRIORITY_CLASS_NORMAL; 01959 break; 01960 01961 case ABOVE_NORMAL_PRIORITY_CLASS: 01962 PriorityClass.PriorityClass = PROCESS_PRIORITY_CLASS_ABOVE_NORMAL; 01963 break; 01964 01965 case HIGH_PRIORITY_CLASS: 01966 PriorityClass.PriorityClass = PROCESS_PRIORITY_CLASS_HIGH; 01967 break; 01968 01969 case REALTIME_PRIORITY_CLASS: 01970 /* Try to acquire the privilege. If it fails, just use HIGH */ 01971 State = BasepIsRealtimeAllowed(TRUE); 01972 PriorityClass.PriorityClass = PROCESS_PRIORITY_CLASS_HIGH; 01973 PriorityClass.PriorityClass += (State != NULL); 01974 break; 01975 01976 default: 01977 /* Unrecognized priority classes don't make it to the kernel */ 01978 SetLastError(ERROR_INVALID_PARAMETER); 01979 return FALSE; 01980 } 01981 01982 /* Send the request to the kernel, and don't touch the foreground flag */ 01983 PriorityClass.Foreground = FALSE; 01984 Status = NtSetInformationProcess(hProcess, 01985 ProcessPriorityClass, 01986 &PriorityClass, 01987 sizeof(PROCESS_PRIORITY_CLASS)); 01988 01989 /* Release the privilege if we had it */ 01990 if (State) RtlReleasePrivilege(State); 01991 if (!NT_SUCCESS(Status)) 01992 { 01993 /* Handle error path */ 01994 BaseSetLastNTError(Status); 01995 return FALSE; 01996 } 01997 01998 /* All done */ 01999 return TRUE; 02000 } 02001 02002 /* 02003 * @implemented 02004 */ 02005 DWORD 02006 WINAPI 02007 GetProcessVersion(IN DWORD ProcessId) 02008 { 02009 DWORD Version = 0; 02010 PIMAGE_NT_HEADERS NtHeader; 02011 PIMAGE_DOS_HEADER DosHeader; 02012 PPEB Peb; 02013 PROCESS_BASIC_INFORMATION ProcessBasicInfo; 02014 PVOID BaseAddress; 02015 ULONG e_lfanew; 02016 HANDLE ProcessHandle = NULL; 02017 NTSTATUS Status; 02018 USHORT VersionData[2]; 02019 BOOLEAN Result; 02020 02021 /* We'll be accessing stuff that can fault, so protect everything with SEH */ 02022 _SEH2_TRY 02023 { 02024 /* It this an in-process or out-of-process request? */ 02025 if (!(ProcessId) || (GetCurrentProcessId() == ProcessId)) 02026 { 02027 /* It's in-process, so just read our own header */ 02028 NtHeader = RtlImageNtHeader(NtCurrentPeb()->ImageBaseAddress); 02029 if (!NtHeader) 02030 { 02031 /* Unable to read the NT header, something is wrong here... */ 02032 Status = STATUS_INVALID_IMAGE_FORMAT; 02033 goto Error; 02034 } 02035 02036 /* Get the version straight out of the NT header */ 02037 Version = MAKELONG(NtHeader->OptionalHeader.MinorSubsystemVersion, 02038 NtHeader->OptionalHeader.MajorSubsystemVersion); 02039 } 02040 else 02041 { 02042 /* Out-of-process, so open it */ 02043 ProcessHandle = OpenProcess(PROCESS_VM_READ | PROCESS_QUERY_INFORMATION, 02044 FALSE, 02045 ProcessId); 02046 if (!ProcessHandle) return 0; 02047 02048 /* Try to find out where its PEB lives */ 02049 Status = NtQueryInformationProcess(ProcessHandle, 02050 ProcessBasicInformation, 02051 &ProcessBasicInfo, 02052 sizeof(ProcessBasicInfo), 02053 NULL); 02054 02055 if (!NT_SUCCESS(Status)) goto Error; 02056 Peb = ProcessBasicInfo.PebBaseAddress; 02057 02058 /* Now that we have the PEB, read the image base address out of it */ 02059 Result = ReadProcessMemory(ProcessHandle, 02060 &Peb->ImageBaseAddress, 02061 &BaseAddress, 02062 sizeof(BaseAddress), 02063 NULL); 02064 if (!Result) goto Error; 02065 02066 /* Now read the e_lfanew (offset to NT header) from the base */ 02067 DosHeader = BaseAddress; 02068 Result = ReadProcessMemory(ProcessHandle, 02069 &DosHeader->e_lfanew, 02070 &e_lfanew, 02071 sizeof(e_lfanew), 02072 NULL); 02073 if (!Result) goto Error; 02074 02075 /* And finally, read the NT header itself by adding the offset */ 02076 NtHeader = (PVOID)((ULONG_PTR)BaseAddress + e_lfanew); 02077 Result = ReadProcessMemory(ProcessHandle, 02078 &NtHeader->OptionalHeader.MajorSubsystemVersion, 02079 &VersionData, 02080 sizeof(VersionData), 02081 NULL); 02082 if (!Result) goto Error; 02083 02084 /* Get the version straight out of the NT header */ 02085 Version = MAKELONG(VersionData[0], VersionData[1]); 02086 02087 Error: 02088 /* If there was an error anywhere, set the last error */ 02089 if (!NT_SUCCESS(Status)) BaseSetLastNTError(Status); 02090 } 02091 } 02092 _SEH2_FINALLY 02093 { 02094 /* Close the process handle */ 02095 if (ProcessHandle) CloseHandle(ProcessHandle); 02096 } 02097 _SEH2_END; 02098 02099 /* And return the version data */ 02100 return Version; 02101 } 02102 02103 /* 02104 * @implemented 02105 */ 02106 BOOL 02107 WINAPI 02108 GetProcessIoCounters(IN HANDLE hProcess, 02109 OUT PIO_COUNTERS lpIoCounters) 02110 { 02111 NTSTATUS Status; 02112 02113 /* Query the kernel. Structures are identical, so let it do the copy too. */ 02114 Status = NtQueryInformationProcess(hProcess, 02115 ProcessIoCounters, 02116 lpIoCounters, 02117 sizeof(IO_COUNTERS), 02118 NULL); 02119 if (!NT_SUCCESS(Status)) 02120 { 02121 /* Handle error path */ 02122 BaseSetLastNTError(Status); 02123 return FALSE; 02124 } 02125 02126 /* All done */ 02127 return TRUE; 02128 } 02129 02130 /* 02131 * @implemented 02132 */ 02133 BOOL 02134 WINAPI 02135 GetProcessPriorityBoost(IN HANDLE hProcess, 02136 OUT PBOOL pDisablePriorityBoost) 02137 { 02138 NTSTATUS Status; 02139 ULONG PriorityBoost; 02140 02141 /* Query the kernel */ 02142 Status = NtQueryInformationProcess(hProcess, 02143 ProcessPriorityBoost, 02144 &PriorityBoost, 02145 sizeof(ULONG), 02146 NULL); 02147 if (NT_SUCCESS(Status)) 02148 { 02149 /* Convert from ULONG to a BOOL */ 02150 *pDisablePriorityBoost = PriorityBoost ? TRUE : FALSE; 02151 return TRUE; 02152 } 02153 02154 /* Handle error path */ 02155 BaseSetLastNTError(Status); 02156 return FALSE; 02157 } 02158 02159 /* 02160 * @implemented 02161 */ 02162 BOOL 02163 WINAPI 02164 SetProcessPriorityBoost(IN HANDLE hProcess, 02165 IN BOOL bDisablePriorityBoost) 02166 { 02167 NTSTATUS Status; 02168 ULONG PriorityBoost; 02169 02170 /* Enforce that this is a BOOL, and send it to the kernel as a ULONG */ 02171 PriorityBoost = (bDisablePriorityBoost ? TRUE : FALSE); 02172 Status = NtSetInformationProcess(hProcess, 02173 ProcessPriorityBoost, 02174 &PriorityBoost, 02175 sizeof(ULONG)); 02176 if (!NT_SUCCESS(Status)) 02177 { 02178 /* Handle error path */ 02179 BaseSetLastNTError(Status); 02180 return FALSE; 02181 } 02182 02183 /* All done */ 02184 return TRUE; 02185 } 02186 02187 /* 02188 * @implemented 02189 */ 02190 BOOL 02191 WINAPI 02192 GetProcessHandleCount(IN HANDLE hProcess, 02193 OUT PDWORD pdwHandleCount) 02194 { 02195 ULONG phc; 02196 NTSTATUS Status; 02197 02198 /* Query the kernel */ 02199 Status = NtQueryInformationProcess(hProcess, 02200 ProcessHandleCount, 02201 &phc, 02202 sizeof(ULONG), 02203 NULL); 02204 if (NT_SUCCESS(Status)) 02205 { 02206 /* Copy the count and return sucecss */ 02207 *pdwHandleCount = phc; 02208 return TRUE; 02209 } 02210 02211 /* Handle error path */ 02212 BaseSetLastNTError(Status); 02213 return FALSE; 02214 } 02215 02216 /* 02217 * @implemented 02218 */ 02219 BOOL 02220 WINAPI 02221 IsWow64Process(IN HANDLE hProcess, 02222 OUT PBOOL Wow64Process) 02223 { 02224 ULONG_PTR pbi; 02225 NTSTATUS Status; 02226 02227 /* Query the kernel */ 02228 Status = NtQueryInformationProcess(hProcess, 02229 ProcessWow64Information, 02230 &pbi, 02231 sizeof(pbi), 02232 NULL); 02233 if (!NT_SUCCESS(Status)) 02234 { 02235 /* Handle error path */ 02236 BaseSetLastNTError(Status); 02237 return FALSE; 02238 } 02239 02240 /* Enforce this is a BOOL, and return success */ 02241 *Wow64Process = (pbi != 0); 02242 return TRUE; 02243 } 02244 02245 /* 02246 * @implemented 02247 */ 02248 LPSTR 02249 WINAPI 02250 GetCommandLineA(VOID) 02251 { 02252 return BaseAnsiCommandLine.Buffer; 02253 } 02254 02255 /* 02256 * @implemented 02257 */ 02258 LPWSTR 02259 WINAPI 02260 GetCommandLineW(VOID) 02261 { 02262 return BaseUnicodeCommandLine.Buffer; 02263 } 02264 02265 /* 02266 * @implemented 02267 */ 02268 BOOL 02269 NTAPI 02270 ReadProcessMemory(IN HANDLE hProcess, 02271 IN LPCVOID lpBaseAddress, 02272 IN LPVOID lpBuffer, 02273 IN SIZE_T nSize, 02274 OUT SIZE_T* lpNumberOfBytesRead) 02275 { 02276 NTSTATUS Status; 02277 02278 /* Do the read */ 02279 Status = NtReadVirtualMemory(hProcess, 02280 (PVOID)lpBaseAddress, 02281 lpBuffer, 02282 nSize, 02283 &nSize); 02284 02285 /* In user-mode, this parameter is optional */ 02286 if (lpNumberOfBytesRead) *lpNumberOfBytesRead = nSize; 02287 if (!NT_SUCCESS(Status)) 02288 { 02289 /* We failed */ 02290 BaseSetLastNTError(Status); 02291 return FALSE; 02292 } 02293 02294 /* Return success */ 02295 return TRUE; 02296 } 02297 02298 /* 02299 * @implemented 02300 */ 02301 BOOL 02302 NTAPI 02303 WriteProcessMemory(IN HANDLE hProcess, 02304 IN LPVOID lpBaseAddress, 02305 IN LPCVOID lpBuffer, 02306 IN SIZE_T nSize, 02307 OUT SIZE_T *lpNumberOfBytesWritten) 02308 { 02309 NTSTATUS Status; 02310 ULONG OldValue; 02311 SIZE_T RegionSize; 02312 PVOID Base; 02313 BOOLEAN UnProtect; 02314 02315 /* Set parameters for protect call */ 02316 RegionSize = nSize; 02317 Base = lpBaseAddress; 02318 02319 /* Check the current status */ 02320 Status = NtProtectVirtualMemory(hProcess, 02321 &Base, 02322 &RegionSize, 02323 PAGE_EXECUTE_READWRITE, 02324 &OldValue); 02325 if (NT_SUCCESS(Status)) 02326 { 02327 /* Check if we are unprotecting */ 02328 UnProtect = OldValue & (PAGE_READWRITE | 02329 PAGE_WRITECOPY | 02330 PAGE_EXECUTE_READWRITE | 02331 PAGE_EXECUTE_WRITECOPY) ? FALSE : TRUE; 02332 if (!UnProtect) 02333 { 02334 /* Set the new protection */ 02335 Status = NtProtectVirtualMemory(hProcess, 02336 &Base, 02337 &RegionSize, 02338 OldValue, 02339 &OldValue); 02340 02341 /* Write the memory */ 02342 Status = NtWriteVirtualMemory(hProcess, 02343 lpBaseAddress, 02344 (LPVOID)lpBuffer, 02345 nSize, 02346 &nSize); 02347 02348 /* In Win32, the parameter is optional, so handle this case */ 02349 if (lpNumberOfBytesWritten) *lpNumberOfBytesWritten = nSize; 02350 02351 if (!NT_SUCCESS(Status)) 02352 { 02353 /* We failed */ 02354 BaseSetLastNTError(Status); 02355 return FALSE; 02356 } 02357 02358 /* Flush the ITLB */ 02359 NtFlushInstructionCache(hProcess, lpBaseAddress, nSize); 02360 return TRUE; 02361 } 02362 else 02363 { 02364 /* Check if we were read only */ 02365 if (OldValue & (PAGE_NOACCESS | PAGE_READONLY)) 02366 { 02367 /* Restore protection and fail */ 02368 NtProtectVirtualMemory(hProcess, 02369 &Base, 02370 &RegionSize, 02371 OldValue, 02372 &OldValue); 02373 BaseSetLastNTError(STATUS_ACCESS_VIOLATION); 02374 02375 /* Note: This is what Windows returns and code depends on it */ 02376 return STATUS_ACCESS_VIOLATION; 02377 } 02378 02379 /* Otherwise, do the write */ 02380 Status = NtWriteVirtualMemory(hProcess, 02381 lpBaseAddress, 02382 (LPVOID)lpBuffer, 02383 nSize, 02384 &nSize); 02385 02386 /* In Win32, the parameter is optional, so handle this case */ 02387 if (lpNumberOfBytesWritten) *lpNumberOfBytesWritten = nSize; 02388 02389 /* And restore the protection */ 02390 NtProtectVirtualMemory(hProcess, 02391 &Base, 02392 &RegionSize, 02393 OldValue, 02394 &OldValue); 02395 if (!NT_SUCCESS(Status)) 02396 { 02397 /* We failed */ 02398 BaseSetLastNTError(STATUS_ACCESS_VIOLATION); 02399 02400 /* Note: This is what Windows returns and code depends on it */ 02401 return STATUS_ACCESS_VIOLATION; 02402 } 02403 02404 /* Flush the ITLB */ 02405 NtFlushInstructionCache(hProcess, lpBaseAddress, nSize); 02406 return TRUE; 02407 } 02408 } 02409 else 02410 { 02411 /* We failed */ 02412 BaseSetLastNTError(Status); 02413 return FALSE; 02414 } 02415 } 02416 02417 /* 02418 * @implemented 02419 */ 02420 BOOL 02421 WINAPI 02422 ProcessIdToSessionId(IN DWORD dwProcessId, 02423 OUT PDWORD pSessionId) 02424 { 02425 PROCESS_SESSION_INFORMATION SessionInformation; 02426 OBJECT_ATTRIBUTES ObjectAttributes; 02427 CLIENT_ID ClientId; 02428 HANDLE ProcessHandle; 02429 NTSTATUS Status; 02430 02431 /* Do a quick check if the pointer is not writable */ 02432 if (IsBadWritePtr(pSessionId, sizeof(DWORD))) 02433 { 02434 /* Fail fast */ 02435 SetLastError(ERROR_INVALID_PARAMETER); 02436 return FALSE; 02437 } 02438 02439 /* Open the process passed in by ID */ 02440 ClientId.UniqueProcess = UlongToHandle(dwProcessId); 02441 ClientId.UniqueThread = 0; 02442 InitializeObjectAttributes(&ObjectAttributes, NULL, 0, NULL, NULL); 02443 Status = NtOpenProcess(&ProcessHandle, 02444 PROCESS_QUERY_INFORMATION, 02445 &ObjectAttributes, 02446 &ClientId); 02447 if (NT_SUCCESS(Status)) 02448 { 02449 /* Query the session ID from the kernel */ 02450 Status = NtQueryInformationProcess(ProcessHandle, 02451 ProcessSessionInformation, 02452 &SessionInformation, 02453 sizeof(SessionInformation), 02454 NULL); 02455 02456 /* Close the handle and check if we suceeded */ 02457 NtClose(ProcessHandle); 02458 if (NT_SUCCESS(Status)) 02459 { 02460 /* Return the session ID */ 02461 *pSessionId = SessionInformation.SessionId; 02462 return TRUE; 02463 } 02464 } 02465 02466 /* Set error code and fail */ 02467 BaseSetLastNTError(Status); 02468 return FALSE; 02469 } 02470 02471 /* 02472 * @implemented 02473 */ 02474 BOOL 02475 WINAPI 02476 CreateProcessInternalW(HANDLE hToken, 02477 LPCWSTR lpApplicationName, 02478 LPWSTR lpCommandLine, 02479 LPSECURITY_ATTRIBUTES lpProcessAttributes, 02480 LPSECURITY_ATTRIBUTES lpThreadAttributes, 02481 BOOL bInheritHandles, 02482 DWORD dwCreationFlags, 02483 LPVOID lpEnvironment, 02484 LPCWSTR lpCurrentDirectory, 02485 LPSTARTUPINFOW lpStartupInfo, 02486 LPPROCESS_INFORMATION lpProcessInformation, 02487 PHANDLE hNewToken) 02488 { 02489 NTSTATUS Status; 02490 PROCESS_PRIORITY_CLASS PriorityClass; 02491 BOOLEAN FoundQuotes = FALSE; 02492 BOOLEAN QuotesNeeded = FALSE; 02493 BOOLEAN CmdLineIsAppName = FALSE; 02494 UNICODE_STRING ApplicationName = { 0, 0, NULL }; 02495 OBJECT_ATTRIBUTES LocalObjectAttributes; 02496 POBJECT_ATTRIBUTES ObjectAttributes; 02497 HANDLE hSection = NULL, hProcess = NULL, hThread = NULL, hDebug = NULL; 02498 SECTION_IMAGE_INFORMATION SectionImageInfo; 02499 LPWSTR CurrentDirectory = NULL; 02500 LPWSTR CurrentDirectoryPart; 02501 PROCESS_BASIC_INFORMATION ProcessBasicInfo; 02502 STARTUPINFOW StartupInfo; 02503 ULONG Dummy; 02504 LPWSTR BatchCommandLine; 02505 ULONG CmdLineLength; 02506 UNICODE_STRING CommandLineString; 02507 PWCHAR Extension; 02508 LPWSTR QuotedCmdLine = NULL; 02509 LPWSTR ScanString; 02510 LPWSTR NullBuffer = NULL; 02511 LPWSTR NameBuffer = NULL; 02512 WCHAR SaveChar = 0; 02513 ULONG RetVal; 02514 UINT Error = 0; 02515 BOOLEAN SearchDone = FALSE; 02516 BOOLEAN Escape = FALSE; 02517 CLIENT_ID ClientId; 02518 PPEB OurPeb = NtCurrentPeb(); 02519 PPEB RemotePeb; 02520 SIZE_T EnvSize = 0; 02521 BOOL Ret = FALSE; 02522 02523 /* FIXME should process 02524 * HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options 02525 * key (see http://blogs.msdn.com/oldnewthing/archive/2005/12/19/505449.aspx) 02526 */ 02527 02528 DPRINT("CreateProcessW: lpApplicationName: %S lpCommandLine: %S" 02529 " lpEnvironment: %p lpCurrentDirectory: %S dwCreationFlags: %lx\n", 02530 lpApplicationName, lpCommandLine, lpEnvironment, lpCurrentDirectory, 02531 dwCreationFlags); 02532 02533 /* Flags we don't handle yet */ 02534 if (dwCreationFlags & CREATE_SEPARATE_WOW_VDM) 02535 { 02536 DPRINT1("CREATE_SEPARATE_WOW_VDM not handled\n"); 02537 } 02538 if (dwCreationFlags & CREATE_SHARED_WOW_VDM) 02539 { 02540 DPRINT1("CREATE_SHARED_WOW_VDM not handled\n"); 02541 } 02542 if (dwCreationFlags & CREATE_FORCEDOS) 02543 { 02544 DPRINT1("CREATE_FORCEDOS not handled\n"); 02545 } 02546 02547 /* Fail on this flag, it's only valid with the WithLogonW function */ 02548 if (dwCreationFlags & CREATE_PRESERVE_CODE_AUTHZ_LEVEL) 02549 { 02550 DPRINT1("Invalid flag used\n"); 02551 SetLastError(ERROR_INVALID_PARAMETER); 02552 return FALSE; 02553 } 02554 02555 /* This combination is illegal (see MSDN) */ 02556 if ((dwCreationFlags & (DETACHED_PROCESS | CREATE_NEW_CONSOLE)) == 02557 (DETACHED_PROCESS | CREATE_NEW_CONSOLE)) 02558 { 02559 DPRINT1("Invalid flag combo used\n"); 02560 SetLastError(ERROR_INVALID_PARAMETER); 02561 return FALSE; 02562 } 02563 02564 /* Another illegal combo */ 02565 if ((dwCreationFlags & (CREATE_SEPARATE_WOW_VDM | CREATE_SHARED_WOW_VDM)) == 02566 (CREATE_SEPARATE_WOW_VDM | CREATE_SHARED_WOW_VDM)) 02567 { 02568 DPRINT1("Invalid flag combo used\n"); 02569 SetLastError(ERROR_INVALID_PARAMETER); 02570 return FALSE; 02571 } 02572 02573 if (lpCurrentDirectory) 02574 { 02575 if ((GetFileAttributesW(lpCurrentDirectory) == INVALID_FILE_ATTRIBUTES) || 02576 !(GetFileAttributesW(lpCurrentDirectory) & FILE_ATTRIBUTE_DIRECTORY)) 02577 { 02578 SetLastError(ERROR_DIRECTORY); 02579 return FALSE; 02580 } 02581 } 02582 02583 /* 02584 * We're going to modify and mask out flags and stuff in lpStartupInfo, 02585 * so we'll use our own local copy for that. 02586 */ 02587 StartupInfo = *lpStartupInfo; 02588 02589 /* FIXME: Use default Separate/Shared VDM Flag */ 02590 02591 /* If we are inside a Job, use Separate VDM so it won't escape the Job */ 02592 if (!(dwCreationFlags & CREATE_SEPARATE_WOW_VDM)) 02593 { 02594 if (NtIsProcessInJob(NtCurrentProcess(), NULL)) 02595 { 02596 /* Remove the shared flag and add the separate flag. */ 02597 dwCreationFlags = (dwCreationFlags &~ CREATE_SHARED_WOW_VDM) | 02598 CREATE_SEPARATE_WOW_VDM; 02599 } 02600 } 02601 02602 /* 02603 * According to some sites, ShellExecuteEx uses an undocumented flag to 02604 * send private handle data (such as HMONITOR or HICON). See: 02605 * www.catch22.net/tuts/undoc01.asp. This implies that we can't use the 02606 * standard handles anymore since we'd be overwriting this private data 02607 */ 02608 if ((StartupInfo.dwFlags & STARTF_USESTDHANDLES) && 02609 (StartupInfo.dwFlags & (STARTF_USEHOTKEY | STARTF_SHELLPRIVATE))) 02610 { 02611 StartupInfo.dwFlags &= ~STARTF_USESTDHANDLES; 02612 } 02613 02614 /* Start by zeroing out the fields */ 02615 RtlZeroMemory(lpProcessInformation, sizeof(PROCESS_INFORMATION)); 02616 02617 /* Easy stuff first, convert the process priority class */ 02618 PriorityClass.Foreground = FALSE; 02619 PriorityClass.PriorityClass = (UCHAR)BasepConvertPriorityClass(dwCreationFlags); 02620 02621 if (lpCommandLine) 02622 { 02623 /* Search for escape sequences */ 02624 ScanString = lpCommandLine; 02625 while (NULL != (ScanString = wcschr(ScanString, L'^'))) 02626 { 02627 ScanString++; 02628 if (*ScanString == L'\"' || *ScanString == L'^' || *ScanString == L'\"') 02629 { 02630 Escape = TRUE; 02631 break; 02632 } 02633 } 02634 } 02635 02636 /* Get the application name and do all the proper formating necessary */ 02637 GetAppName: 02638 /* See if we have an application name (oh please let us have one!) */ 02639 if (!lpApplicationName) 02640 { 02641 /* The fun begins */ 02642 NameBuffer = RtlAllocateHeap(RtlGetProcessHeap(), 02643 0, 02644 MAX_PATH * sizeof(WCHAR)); 02645 if (NameBuffer == NULL) 02646 { 02647 SetLastError(ERROR_NOT_ENOUGH_MEMORY); 02648 goto Cleanup; 02649 } 02650 02651 /* This is all we have to work with :( */ 02652 lpApplicationName = lpCommandLine; 02653 02654 /* Initialize our friends at the beginning */ 02655 NullBuffer = (LPWSTR)lpApplicationName; 02656 ScanString = (LPWSTR)lpApplicationName; 02657 02658 /* We will start by looking for a quote */ 02659 if (*ScanString == L'\"') 02660 { 02661 /* That was quick */ 02662 SearchDone = TRUE; 02663 02664 /* Advance past quote */ 02665 ScanString++; 02666 lpApplicationName = ScanString; 02667 02668 /* Find the closing quote */ 02669 while (*ScanString) 02670 { 02671 if (*ScanString == L'\"' && *(ScanString - 1) != L'^') 02672 { 02673 /* Found it */ 02674 NullBuffer = ScanString; 02675 FoundQuotes = TRUE; 02676 break; 02677 } 02678 02679 /* Keep looking */ 02680 ScanString++; 02681 NullBuffer = ScanString; 02682 } 02683 } 02684 else 02685 { 02686 /* No quotes, so we'll be looking for white space */ 02687 WhiteScan: 02688 /* Reset the pointer */ 02689 lpApplicationName = lpCommandLine; 02690 02691 /* Find whitespace of Tab */ 02692 while (*ScanString) 02693 { 02694 if (*ScanString == ' ' || *ScanString == '\t') 02695 { 02696 /* Found it */ 02697 NullBuffer = ScanString; 02698 break; 02699 } 02700 02701 /* Keep looking */ 02702 ScanString++; 02703 NullBuffer = ScanString; 02704 } 02705 } 02706 02707 /* Set the Null Buffer */ 02708 SaveChar = *NullBuffer; 02709 *NullBuffer = UNICODE_NULL; 02710 02711 /* Do a search for the file */ 02712 DPRINT("Ready for SearchPathW: %S\n", lpApplicationName); 02713 RetVal = SearchPathW(NULL, 02714 lpApplicationName, 02715 L".exe", 02716 MAX_PATH, 02717 NameBuffer, 02718 NULL) * sizeof(WCHAR); 02719 02720 /* Did it find something? */ 02721 if (RetVal) 02722 { 02723 /* Get file attributes */ 02724 ULONG Attributes = GetFileAttributesW(NameBuffer); 02725 if (Attributes & FILE_ATTRIBUTE_DIRECTORY) 02726 { 02727 /* Give it a length of 0 to fail, this was a directory. */ 02728 RetVal = 0; 02729 } 02730 else 02731 { 02732 /* It's a file! */ 02733 RetVal += sizeof(WCHAR); 02734 } 02735 } 02736 02737 /* Now check if we have a file, and if the path size is OK */ 02738 if (!RetVal || RetVal >= (MAX_PATH * sizeof(WCHAR))) 02739 { 02740 ULONG PathType; 02741 HANDLE hFile; 02742 02743 /* We failed, try to get the Path Type */ 02744 DPRINT("SearchPathW failed. Retval: %ld\n", RetVal); 02745 PathType = RtlDetermineDosPathNameType_U(lpApplicationName); 02746 02747 /* If it's not relative, try to get the error */ 02748 if (PathType != RtlPathTypeRelative) 02749 { 02750 /* This should fail, and give us a detailed LastError */ 02751 hFile = CreateFileW(lpApplicationName, 02752 GENERIC_READ, 02753 FILE_SHARE_READ | FILE_SHARE_WRITE, 02754 NULL, 02755 OPEN_EXISTING, 02756 FILE_ATTRIBUTE_NORMAL, 02757 NULL); 02758 02759 /* Did it actually NOT fail? */ 02760 if (hFile != INVALID_HANDLE_VALUE) 02761 { 02762 /* Fake the error */ 02763 CloseHandle(hFile); 02764 BaseSetLastNTError(STATUS_OBJECT_NAME_NOT_FOUND); 02765 } 02766 } 02767 else 02768 { 02769 /* Immediately set the error */ 02770 BaseSetLastNTError(STATUS_OBJECT_NAME_NOT_FOUND); 02771 } 02772 02773 /* Did we already fail once? */ 02774 if (Error) 02775 { 02776 SetLastError(Error); 02777 } 02778 else 02779 { 02780 /* Not yet, cache it */ 02781 Error = GetLastError(); 02782 } 02783 02784 /* Put back the command line */ 02785 *NullBuffer = SaveChar; 02786 lpApplicationName = NameBuffer; 02787 02788 /* 02789 * If the search isn't done and we still have cmdline 02790 * then start over. Ex: c:\ha ha ha\haha.exe 02791 */ 02792 if (*ScanString && !SearchDone) 02793 { 02794 /* Move in the buffer */ 02795 ScanString++; 02796 NullBuffer = ScanString; 02797 02798 /* We will have to add a quote, since there is a space*/ 02799 QuotesNeeded = TRUE; 02800 02801 /* And we will also fake the fact we found one */ 02802 FoundQuotes = TRUE; 02803 02804 /* Start over */ 02805 goto WhiteScan; 02806 } 02807 02808 /* We totally failed */ 02809 goto Cleanup; 02810 } 02811 02812 /* Put back the command line */ 02813 *NullBuffer = SaveChar; 02814 lpApplicationName = NameBuffer; 02815 DPRINT("SearchPathW suceeded (%ld): %S\n", RetVal, NameBuffer); 02816 } 02817 else if (!lpCommandLine || *lpCommandLine == UNICODE_NULL) 02818 { 02819 /* We have an app name (good!) but no command line */ 02820 CmdLineIsAppName = TRUE; 02821 lpCommandLine = (LPWSTR)lpApplicationName; 02822 } 02823 02824 /* At this point the name has been toyed with enough to be openable */ 02825 Status = BasepMapFile(lpApplicationName, &hSection, &ApplicationName); 02826 02827 /* Check for failure */ 02828 if (!NT_SUCCESS(Status)) 02829 { 02830 /* Could be a non-PE File */ 02831 switch (Status) 02832 { 02833 /* Check if the Kernel tells us it's not even valid MZ */ 02834 case STATUS_INVALID_IMAGE_NE_FORMAT: 02835 case STATUS_INVALID_IMAGE_PROTECT: 02836 case STATUS_INVALID_IMAGE_NOT_MZ: 02837 02838 #if 0 02839 /* If it's a DOS app, use VDM */ 02840 if ((BasepCheckDosApp(&ApplicationName))) 02841 { 02842 DPRINT1("Launching VDM...\n"); 02843 RtlFreeHeap(RtlGetProcessHeap(), 0, NameBuffer); 02844 RtlFreeHeap(RtlGetProcessHeap(), 0, ApplicationName.Buffer); 02845 return CreateProcessW(L"ntvdm.exe", 02846 (LPWSTR)((ULONG_PTR)lpApplicationName), /* FIXME: Buffer must be writable!!! */ 02847 lpProcessAttributes, 02848 lpThreadAttributes, 02849 bInheritHandles, 02850 dwCreationFlags, 02851 lpEnvironment, 02852 lpCurrentDirectory, 02853 &StartupInfo, 02854 lpProcessInformation); 02855 } 02856 #endif 02857 /* It's a batch file */ 02858 Extension = &ApplicationName.Buffer[ApplicationName.Length / 02859 sizeof(WCHAR) - 4]; 02860 02861 /* Make sure the extensions are correct */ 02862 if (_wcsnicmp(Extension, L".bat", 4) && _wcsnicmp(Extension, L".cmd", 4)) 02863 { 02864 SetLastError(ERROR_BAD_EXE_FORMAT); 02865 return FALSE; 02866 } 02867 02868 /* Calculate the length of the command line */ 02869 CmdLineLength = wcslen(CMD_STRING) + wcslen(lpCommandLine) + 1; 02870 02871 /* If we found quotes, then add them into the length size */ 02872 if (CmdLineIsAppName || FoundQuotes) CmdLineLength += 2; 02873 CmdLineLength *= sizeof(WCHAR); 02874 02875 /* Allocate space for the new command line */ 02876 BatchCommandLine = RtlAllocateHeap(RtlGetProcessHeap(), 02877 0, 02878 CmdLineLength); 02879 if (BatchCommandLine == NULL) 02880 { 02881 SetLastError(ERROR_NOT_ENOUGH_MEMORY); 02882 goto Cleanup; 02883 } 02884 02885 /* Build it */ 02886 wcscpy(BatchCommandLine, CMD_STRING); 02887 if (CmdLineIsAppName || FoundQuotes) 02888 { 02889 wcscat(BatchCommandLine, L"\""); 02890 } 02891 wcscat(BatchCommandLine, lpCommandLine); 02892 if (CmdLineIsAppName || FoundQuotes) 02893 { 02894 wcscat(BatchCommandLine, L"\""); 02895 } 02896 02897 /* Create it as a Unicode String */ 02898 RtlInitUnicodeString(&CommandLineString, BatchCommandLine); 02899 02900 /* Set the command line to this */ 02901 lpCommandLine = CommandLineString.Buffer; 02902 lpApplicationName = NULL; 02903 02904 /* Free memory */ 02905 RtlFreeHeap(RtlGetProcessHeap(), 0, ApplicationName.Buffer); 02906 ApplicationName.Buffer = NULL; 02907 goto GetAppName; 02908 break; 02909 02910 case STATUS_INVALID_IMAGE_WIN_16: 02911 02912 /* It's a Win16 Image, use VDM */ 02913 DPRINT1("Launching VDM...\n"); 02914 RtlFreeHeap(RtlGetProcessHeap(), 0, NameBuffer); 02915 RtlFreeHeap(RtlGetProcessHeap(), 0, ApplicationName.Buffer); 02916 return CreateProcessW(L"ntvdm.exe", 02917 (LPWSTR)((ULONG_PTR)lpApplicationName), /* FIXME: Buffer must be writable!!! */ 02918 lpProcessAttributes, 02919 lpThreadAttributes, 02920 bInheritHandles, 02921 dwCreationFlags, 02922 lpEnvironment, 02923 lpCurrentDirectory, 02924 &StartupInfo, 02925 lpProcessInformation); 02926 02927 case STATUS_OBJECT_NAME_NOT_FOUND: 02928 case STATUS_OBJECT_PATH_NOT_FOUND: 02929 BaseSetLastNTError(Status); 02930 goto Cleanup; 02931 02932 default: 02933 /* Invalid Image Type */ 02934 SetLastError(ERROR_BAD_EXE_FORMAT); 02935 goto Cleanup; 02936 } 02937 } 02938 02939 /* Use our desktop if we didn't get any */ 02940 if (!StartupInfo.lpDesktop) 02941 { 02942 StartupInfo.lpDesktop = OurPeb->ProcessParameters->DesktopInfo.Buffer; 02943 } 02944 02945 /* FIXME: Check if Application is allowed to run */ 02946 02947 /* FIXME: Allow CREATE_SEPARATE only for WOW Apps, once we have that. */ 02948 02949 /* Get some information about the executable */ 02950 Status = NtQuerySection(hSection, 02951 SectionImageInformation, 02952 &SectionImageInfo, 02953 sizeof(SectionImageInfo), 02954 NULL); 02955 if(!NT_SUCCESS(Status)) 02956 { 02957 DPRINT1("Unable to get SectionImageInformation, status 0x%x\n", Status); 02958 BaseSetLastNTError(Status); 02959 goto Cleanup; 02960 } 02961 02962 /* Don't execute DLLs */ 02963 if (SectionImageInfo.ImageCharacteristics & IMAGE_FILE_DLL) 02964 { 02965 DPRINT1("Can't execute a DLL\n"); 02966 SetLastError(ERROR_BAD_EXE_FORMAT); 02967 goto Cleanup; 02968 } 02969 02970 /* FIXME: Check for Debugger */ 02971 02972 /* FIXME: Check if Machine Type and SubSys Version Match */ 02973 02974 /* We don't support POSIX or anything else for now */ 02975 if (IMAGE_SUBSYSTEM_WINDOWS_GUI != SectionImageInfo.SubSystemType && 02976 IMAGE_SUBSYSTEM_WINDOWS_CUI != SectionImageInfo.SubSystemType) 02977 { 02978 DPRINT1("Invalid subsystem %d\n", SectionImageInfo.SubSystemType); 02979 SetLastError(ERROR_BAD_EXE_FORMAT); 02980 goto Cleanup; 02981 } 02982 02983 if (IMAGE_SUBSYSTEM_WINDOWS_GUI == SectionImageInfo.SubSystemType) 02984 { 02985 /* Do not create a console for GUI applications */ 02986 dwCreationFlags &= ~CREATE_NEW_CONSOLE; 02987 dwCreationFlags |= DETACHED_PROCESS; 02988 } 02989 02990 /* Initialize the process object attributes */ 02991 ObjectAttributes = BaseFormatObjectAttributes(&LocalObjectAttributes, 02992 lpProcessAttributes, 02993 NULL); 02994 02995 /* Check if we're going to be debugged */ 02996 if (dwCreationFlags & DEBUG_PROCESS) 02997 { 02998 /* FIXME: Set process flag */ 02999 } 03000 03001 /* Check if we're going to be debugged */ 03002 if (dwCreationFlags & (DEBUG_PROCESS | DEBUG_ONLY_THIS_PROCESS)) 03003 { 03004 /* Connect to DbgUi */ 03005 Status = DbgUiConnectToDbg(); 03006 if (!NT_SUCCESS(Status)) 03007 { 03008 DPRINT1("Failed to connect to DbgUI!\n"); 03009 BaseSetLastNTError(Status); 03010 goto Cleanup; 03011 } 03012 03013 /* Get the debug object */ 03014 hDebug = DbgUiGetThreadDebugObject(); 03015 03016 /* Check if only this process will be debugged */ 03017 if (dwCreationFlags & DEBUG_ONLY_THIS_PROCESS) 03018 { 03019 /* Set process flag */ 03020 hDebug = (HANDLE)((ULONG_PTR)hDebug | 0x1); 03021 } 03022 } 03023 03024 /* Create the Process */ 03025 Status = NtCreateProcess(&hProcess, 03026 PROCESS_ALL_ACCESS, 03027 ObjectAttributes, 03028 NtCurrentProcess(), 03029 (BOOLEAN)bInheritHandles, 03030 hSection, 03031 hDebug, 03032 NULL); 03033 if (!NT_SUCCESS(Status)) 03034 { 03035 DPRINT1("Unable to create process, status 0x%x\n", Status); 03036 BaseSetLastNTError(Status); 03037 goto Cleanup; 03038 } 03039 03040 if (PriorityClass.PriorityClass != PROCESS_PRIORITY_CLASS_INVALID) 03041 { 03042 /* Set new class */ 03043 Status = NtSetInformationProcess(hProcess, 03044 ProcessPriorityClass, 03045 &PriorityClass, 03046 sizeof(PROCESS_PRIORITY_CLASS)); 03047 if(!NT_SUCCESS(Status)) 03048 { 03049 DPRINT1("Unable to set new process priority, status 0x%x\n", Status); 03050 BaseSetLastNTError(Status); 03051 goto Cleanup; 03052 } 03053 } 03054 03055 /* Set Error Mode */ 03056 if (dwCreationFlags & CREATE_DEFAULT_ERROR_MODE) 03057 { 03058 ULONG ErrorMode = SEM_FAILCRITICALERRORS; 03059 NtSetInformationProcess(hProcess, 03060 ProcessDefaultHardErrorMode, 03061 &ErrorMode, 03062 sizeof(ULONG)); 03063 } 03064 03065 /* Convert the directory to a full path */ 03066 if (lpCurrentDirectory) 03067 { 03068 /* Allocate a buffer */ 03069 CurrentDirectory = RtlAllocateHeap(RtlGetProcessHeap(), 03070 0, 03071 (MAX_PATH + 1) * sizeof(WCHAR)); 03072 if (CurrentDirectory == NULL) 03073 { 03074 DPRINT1("Cannot allocate memory for directory name\n"); 03075 SetLastError(ERROR_NOT_ENOUGH_MEMORY); 03076 goto Cleanup; 03077 } 03078 03079 /* Get the length */ 03080 if (GetFullPathNameW(lpCurrentDirectory, 03081 MAX_PATH, 03082 CurrentDirectory, 03083 &CurrentDirectoryPart) > MAX_PATH) 03084 { 03085 DPRINT1("Directory name too long\n"); 03086 SetLastError(ERROR_DIRECTORY); 03087 goto Cleanup; 03088 } 03089 } 03090 03091 /* Insert quotes if needed */ 03092 if (QuotesNeeded || CmdLineIsAppName) 03093 { 03094 /* Allocate a buffer */ 03095 QuotedCmdLine = RtlAllocateHeap(RtlGetProcessHeap(), 03096 0, 03097 (wcslen(lpCommandLine) + 2 + 1) * 03098 sizeof(WCHAR)); 03099 if (QuotedCmdLine == NULL) 03100 { 03101 DPRINT1("Cannot allocate memory for quoted command line\n"); 03102 SetLastError(ERROR_NOT_ENOUGH_MEMORY); 03103 goto Cleanup; 03104 } 03105 03106 /* Copy the first quote */ 03107 wcscpy(QuotedCmdLine, L"\""); 03108 03109 /* Save a null char */ 03110 if (QuotesNeeded) 03111 { 03112 SaveChar = *NullBuffer; 03113 *NullBuffer = UNICODE_NULL; 03114 } 03115 03116 /* Add the command line and the finishing quote */ 03117 wcscat(QuotedCmdLine, lpCommandLine); 03118 wcscat(QuotedCmdLine, L"\""); 03119 03120 /* Add the null char */ 03121 if (QuotesNeeded) 03122 { 03123 *NullBuffer = SaveChar; 03124 wcscat(QuotedCmdLine, NullBuffer); 03125 } 03126 03127 DPRINT("Quoted CmdLine: %S\n", QuotedCmdLine); 03128 } 03129 03130 if (Escape) 03131 { 03132 if (QuotedCmdLine == NULL) 03133 { 03134 QuotedCmdLine = RtlAllocateHeap(RtlGetProcessHeap(), 03135 0, 03136 (wcslen(lpCommandLine) + 1) * sizeof(WCHAR)); 03137 if (QuotedCmdLine == NULL) 03138 { 03139 SetLastError(ERROR_NOT_ENOUGH_MEMORY); 03140 goto Cleanup; 03141 } 03142 wcscpy(QuotedCmdLine, lpCommandLine); 03143 } 03144 03145 ScanString = QuotedCmdLine; 03146 while (NULL != (ScanString = wcschr(ScanString, L'^'))) 03147 { 03148 ScanString++; 03149 if (*ScanString == L'\"' || *ScanString == L'^' || *ScanString == L'\\') 03150 { 03151 memmove(ScanString-1, ScanString, wcslen(ScanString) * sizeof(WCHAR) + sizeof(WCHAR)); 03152 } 03153 } 03154 } 03155 03156 /* Get the Process Information */ 03157 Status = NtQueryInformationProcess(hProcess, 03158 ProcessBasicInformation, 03159 &ProcessBasicInfo, 03160 sizeof(ProcessBasicInfo), 03161 NULL); 03162 03163 /* Convert the environment */ 03164 if(lpEnvironment && !(dwCreationFlags & CREATE_UNICODE_ENVIRONMENT)) 03165 { 03166 lpEnvironment = BasepConvertUnicodeEnvironment(&EnvSize, lpEnvironment); 03167 if (!lpEnvironment) goto Cleanup; 03168 } 03169 03170 /* Create Process Environment */ 03171 RemotePeb = ProcessBasicInfo.PebBaseAddress; 03172 Ret = BasePushProcessParameters(0, 03173 hProcess, 03174 RemotePeb, 03175 (LPWSTR)lpApplicationName, 03176 CurrentDirectory, 03177 (QuotesNeeded || CmdLineIsAppName || Escape) ? 03178 QuotedCmdLine : lpCommandLine, 03179 lpEnvironment, 03180 &StartupInfo, 03181 dwCreationFlags, 03182 bInheritHandles, 03183 0, 03184 NULL, 03185 0); 03186 if (!Ret) goto Cleanup; 03187 03188 /* Cleanup Environment */ 03189 if (lpEnvironment && !(dwCreationFlags & CREATE_UNICODE_ENVIRONMENT)) 03190 { 03191 RtlDestroyEnvironment(lpEnvironment); 03192 } 03193 03194 /* Close the section */ 03195 NtClose(hSection); 03196 hSection = NULL; 03197 03198 /* Duplicate the handles if needed */ 03199 if (!bInheritHandles && !(StartupInfo.dwFlags & STARTF_USESTDHANDLES) && 03200 SectionImageInfo.SubSystemType == IMAGE_SUBSYSTEM_WINDOWS_CUI) 03201 { 03202 PRTL_USER_PROCESS_PARAMETERS RemoteParameters; 03203 03204 /* Get the remote parameters */ 03205 Status = NtReadVirtualMemory(hProcess, 03206 &RemotePeb->ProcessParameters, 03207 &RemoteParameters, 03208 sizeof(PVOID), 03209 NULL); 03210 if (!NT_SUCCESS(Status)) 03211 { 03212 DPRINT1("Failed to read memory\n"); 03213 goto Cleanup; 03214 } 03215 03216 /* Duplicate and write the handles */ 03217 BasepDuplicateAndWriteHandle(hProcess, 03218 OurPeb->ProcessParameters->StandardInput, 03219 &RemoteParameters->StandardInput); 03220 BasepDuplicateAndWriteHandle(hProcess, 03221 OurPeb->ProcessParameters->StandardOutput, 03222 &RemoteParameters->StandardOutput); 03223 BasepDuplicateAndWriteHandle(hProcess, 03224 OurPeb->ProcessParameters->StandardError, 03225 &RemoteParameters->StandardError); 03226 } 03227 03228 /* Create the first thread */ 03229 DPRINT("Creating thread for process (EntryPoint = 0x%p)\n", 03230 SectionImageInfo.TransferAddress); 03231 hThread = BasepCreateFirstThread(hProcess, 03232 lpThreadAttributes, 03233 &SectionImageInfo, 03234 &ClientId, 03235 bInheritHandles, 03236 dwCreationFlags); 03237 03238 if (hThread == NULL) 03239 { 03240 DPRINT1("Could not create Initial Thread\n"); 03241 /* FIXME - set last error code */ 03242 goto Cleanup; 03243 } 03244 03245 if (!(dwCreationFlags & CREATE_SUSPENDED)) 03246 { 03247 NtResumeThread(hThread, &Dummy); 03248 } 03249 03250 /* Return Data */ 03251 lpProcessInformation->dwProcessId = (DWORD)ClientId.UniqueProcess; 03252 lpProcessInformation->dwThreadId = (DWORD)ClientId.UniqueThread; 03253 lpProcessInformation->hProcess = hProcess; 03254 lpProcessInformation->hThread = hThread; 03255 DPRINT("hThread[%p]: %p inside hProcess[%p]: %p\n", hThread, 03256 ClientId.UniqueThread, ClientId.UniqueProcess, hProcess); 03257 hProcess = hThread = NULL; 03258 Ret = TRUE; 03259 03260 Cleanup: 03261 /* De-allocate heap strings */ 03262 if (NameBuffer) RtlFreeHeap(RtlGetProcessHeap(), 0, NameBuffer); 03263 if (ApplicationName.Buffer) 03264 RtlFreeHeap(RtlGetProcessHeap(), 0, ApplicationName.Buffer); 03265 if (CurrentDirectory) RtlFreeHeap(RtlGetProcessHeap(), 0, CurrentDirectory); 03266 if (QuotedCmdLine) RtlFreeHeap(RtlGetProcessHeap(), 0, QuotedCmdLine); 03267 03268 /* Kill any handles still alive */ 03269 if (hSection) NtClose(hSection); 03270 if (hThread) 03271 { 03272 /* We don't know any more details then this */ 03273 NtTerminateProcess(hProcess, STATUS_UNSUCCESSFUL); 03274 NtClose(hThread); 03275 } 03276 if (hProcess) NtClose(hProcess); 03277 03278 /* Return Success */ 03279 return Ret; 03280 } 03281 03282 /* 03283 * @implemented 03284 */ 03285 BOOL 03286 WINAPI 03287 CreateProcessW(LPCWSTR lpApplicationName, 03288 LPWSTR lpCommandLine, 03289 LPSECURITY_ATTRIBUTES lpProcessAttributes, 03290 LPSECURITY_ATTRIBUTES lpThreadAttributes, 03291 BOOL bInheritHandles, 03292 DWORD dwCreationFlags, 03293 LPVOID lpEnvironment, 03294 LPCWSTR lpCurrentDirectory, 03295 LPSTARTUPINFOW lpStartupInfo, 03296 LPPROCESS_INFORMATION lpProcessInformation) 03297 { 03298 /* Call the internal (but exported) version */ 03299 return CreateProcessInternalW(0, 03300 lpApplicationName, 03301 lpCommandLine, 03302 lpProcessAttributes, 03303 lpThreadAttributes, 03304 bInheritHandles, 03305 dwCreationFlags, 03306 lpEnvironment, 03307 lpCurrentDirectory, 03308 lpStartupInfo, 03309 lpProcessInformation, 03310 NULL); 03311 } 03312 03313 /* 03314 * @implemented 03315 */ 03316 BOOL 03317 WINAPI 03318 CreateProcessInternalA(HANDLE hToken, 03319 LPCSTR lpApplicationName, 03320 LPSTR lpCommandLine, 03321 LPSECURITY_ATTRIBUTES lpProcessAttributes, 03322 LPSECURITY_ATTRIBUTES lpThreadAttributes, 03323 BOOL bInheritHandles, 03324 DWORD dwCreationFlags, 03325 LPVOID lpEnvironment, 03326 LPCSTR lpCurrentDirectory, 03327 LPSTARTUPINFOA lpStartupInfo, 03328 LPPROCESS_INFORMATION lpProcessInformation, 03329 PHANDLE hNewToken) 03330 { 03331 PUNICODE_STRING CommandLine = NULL; 03332 UNICODE_STRING DummyString; 03333 UNICODE_STRING LiveCommandLine; 03334 UNICODE_STRING ApplicationName; 03335 UNICODE_STRING CurrentDirectory; 03336 BOOL bRetVal; 03337 STARTUPINFOW StartupInfo; 03338 03339 DPRINT("dwCreationFlags %x, lpEnvironment %x, lpCurrentDirectory %x, " 03340 "lpStartupInfo %x, lpProcessInformation %x\n", 03341 dwCreationFlags, lpEnvironment, lpCurrentDirectory, 03342 lpStartupInfo, lpProcessInformation); 03343 03344 /* Copy Startup Info */ 03345 RtlMoveMemory(&StartupInfo, lpStartupInfo, sizeof(*lpStartupInfo)); 03346 03347 /* Initialize all strings to nothing */ 03348 LiveCommandLine.Buffer = NULL; 03349 DummyString.Buffer = NULL; 03350 ApplicationName.Buffer = NULL; 03351 CurrentDirectory.Buffer = NULL; 03352 StartupInfo.lpDesktop = NULL; 03353 StartupInfo.lpReserved = NULL; 03354 StartupInfo.lpTitle = NULL; 03355 03356 /* Convert the Command line */ 03357 if (lpCommandLine) 03358 { 03359 /* If it's too long, then we'll have a problem */ 03360 if ((strlen(lpCommandLine) + 1) * sizeof(WCHAR) < 03361 NtCurrentTeb()->StaticUnicodeString.MaximumLength) 03362 { 03363 /* Cache it in the TEB */ 03364 CommandLine = Basep8BitStringToStaticUnicodeString(lpCommandLine); 03365 } 03366 else 03367 { 03368 /* Use a dynamic version */ 03369 Basep8BitStringToDynamicUnicodeString(&LiveCommandLine, 03370 lpCommandLine); 03371 } 03372 } 03373 else 03374 { 03375 /* The logic below will use CommandLine, so we must make it valid */ 03376 CommandLine = &DummyString; 03377 } 03378 03379 /* Convert the Name and Directory */ 03380 if (lpApplicationName) 03381 { 03382 Basep8BitStringToDynamicUnicodeString(&ApplicationName, 03383 lpApplicationName); 03384 } 03385 if (lpCurrentDirectory) 03386 { 03387 Basep8BitStringToDynamicUnicodeString(&CurrentDirectory, 03388 lpCurrentDirectory); 03389 } 03390 03391 /* Now convert Startup Strings */ 03392 if (lpStartupInfo->lpReserved) 03393 { 03394 BasepAnsiStringToHeapUnicodeString(lpStartupInfo->lpReserved, 03395 &StartupInfo.lpReserved); 03396 } 03397 if (lpStartupInfo->lpDesktop) 03398 { 03399 BasepAnsiStringToHeapUnicodeString(lpStartupInfo->lpDesktop, 03400 &StartupInfo.lpDesktop); 03401 } 03402 if (lpStartupInfo->lpTitle) 03403 { 03404 BasepAnsiStringToHeapUnicodeString(lpStartupInfo->lpTitle, 03405 &StartupInfo.lpTitle); 03406 } 03407 03408 /* Call the Unicode function */ 03409 bRetVal = CreateProcessInternalW(hToken, 03410 ApplicationName.Buffer, 03411 LiveCommandLine.Buffer ? 03412 LiveCommandLine.Buffer : CommandLine->Buffer, 03413 lpProcessAttributes, 03414 lpThreadAttributes, 03415 bInheritHandles, 03416 dwCreationFlags, 03417 lpEnvironment, 03418 CurrentDirectory.Buffer, 03419 &StartupInfo, 03420 lpProcessInformation, 03421 hNewToken); 03422 03423 /* Clean up */ 03424 RtlFreeUnicodeString(&ApplicationName); 03425 RtlFreeUnicodeString(&LiveCommandLine); 03426 RtlFreeUnicodeString(&CurrentDirectory); 03427 RtlFreeHeap(RtlGetProcessHeap(), 0, StartupInfo.lpDesktop); 03428 RtlFreeHeap(RtlGetProcessHeap(), 0, StartupInfo.lpReserved); 03429 RtlFreeHeap(RtlGetProcessHeap(), 0, StartupInfo.lpTitle); 03430 03431 /* Return what Unicode did */ 03432 return bRetVal; 03433 } 03434 03435 /* 03436 * FUNCTION: The CreateProcess function creates a new process and its 03437 * primary thread. The new process executes the specified executable file 03438 * ARGUMENTS: 03439 * 03440 * lpApplicationName = Pointer to name of executable module 03441 * lpCommandLine = Pointer to command line string 03442 * lpProcessAttributes = Process security attributes 03443 * lpThreadAttributes = Thread security attributes 03444 * bInheritHandles = Handle inheritance flag 03445 * dwCreationFlags = Creation flags 03446 * lpEnvironment = Pointer to new environment block 03447 * lpCurrentDirectory = Pointer to current directory name 03448 * lpStartupInfo = Pointer to startup info 03449 * lpProcessInformation = Pointer to process information 03450 * 03451 * @implemented 03452 */ 03453 BOOL 03454 WINAPI 03455 CreateProcessA(LPCSTR lpApplicationName, 03456 LPSTR lpCommandLine, 03457 LPSECURITY_ATTRIBUTES lpProcessAttributes, 03458 LPSECURITY_ATTRIBUTES lpThreadAttributes, 03459 BOOL bInheritHandles, 03460 DWORD dwCreationFlags, 03461 LPVOID lpEnvironment, 03462 LPCSTR lpCurrentDirectory, 03463 LPSTARTUPINFOA lpStartupInfo, 03464 LPPROCESS_INFORMATION lpProcessInformation) 03465 { 03466 /* Call the internal (but exported) version */ 03467 return CreateProcessInternalA(0, 03468 lpApplicationName, 03469 lpCommandLine, 03470 lpProcessAttributes, 03471 lpThreadAttributes, 03472 bInheritHandles, 03473 dwCreationFlags, 03474 lpEnvironment, 03475 lpCurrentDirectory, 03476 lpStartupInfo, 03477 lpProcessInformation, 03478 NULL); 03479 } 03480 03481 /* 03482 * @implemented 03483 */ 03484 UINT 03485 WINAPI 03486 WinExec(LPCSTR lpCmdLine, 03487 UINT uCmdShow) 03488 { 03489 STARTUPINFOA StartupInfo; 03490 PROCESS_INFORMATION ProcessInformation; 03491 DWORD dosErr; 03492 03493 RtlZeroMemory(&StartupInfo, sizeof(StartupInfo)); 03494 StartupInfo.cb = sizeof(STARTUPINFOA); 03495 StartupInfo.wShowWindow = (WORD)uCmdShow; 03496 StartupInfo.dwFlags = 0; 03497 03498 if (!CreateProcessA(NULL, 03499 (PVOID)lpCmdLine, 03500 NULL, 03501 NULL, 03502 FALSE, 03503 0, 03504 NULL, 03505 NULL, 03506 &StartupInfo, 03507 &ProcessInformation)) 03508 { 03509 dosErr = GetLastError(); 03510 return dosErr < 32 ? dosErr : ERROR_BAD_FORMAT; 03511 } 03512 03513 if (NULL != UserWaitForInputIdleRoutine) 03514 { 03515 UserWaitForInputIdleRoutine(ProcessInformation.hProcess, 03516 10000); 03517 } 03518 03519 NtClose(ProcessInformation.hProcess); 03520 NtClose(ProcessInformation.hThread); 03521 03522 return 33; /* Something bigger than 31 means success. */ 03523 } 03524 03525 /* EOF */ Generated on Sat May 26 2012 04:23:01 for ReactOS by
1.7.6.1
|