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